✨ 结算单支持业务模式与运输方式,并修复组织合同流水号空值

预结算/正式结算主表新增业务模式、运输方式及列表导出字典翻译;组织合同初始流水号未填时不落-1,OA同步保留本地合同配置。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-21 16:41:59 +08:00
parent 417d8ff9e1
commit 167cea020c
21 changed files with 227 additions and 20 deletions
@@ -26,6 +26,10 @@ public class FormalSettlementSaveRequest implements Serializable {
private List<Long> sourcePreSettlementIds; private List<Long> sourcePreSettlementIds;
private List<Long> sourceDetailIds; private List<Long> sourceDetailIds;
private List<DetailAdjustment> detailAdjustments; private List<DetailAdjustment> detailAdjustments;
/** 业务模式(业务字典 business_model) */
private String businessModel;
/** 运输方式(业务字典 transport_type) */
private String transportType;
private LocalDate exchangeRateDate; private LocalDate exchangeRateDate;
private BigDecimal exchangeRate; private BigDecimal exchangeRate;
private String attachmentsJson; private String attachmentsJson;
@@ -55,6 +55,12 @@ public class PreSettlementSaveRequest implements Serializable {
@Schema(description = "结算类型:receivable/payable") @Schema(description = "结算类型:receivable/payable")
private String settlementType; private String settlementType;
@Schema(description = "业务模式(业务字典 business_model)")
private String businessModel;
@Schema(description = "运输方式(业务字典 transport_type)")
private String transportType;
@Schema(description = "汇率日期") @Schema(description = "汇率日期")
private LocalDate exchangeRateDate; private LocalDate exchangeRateDate;
@@ -88,6 +88,14 @@ public class FormalSettlement extends TenantEntity {
* 结算金额(结算币种,含全部合计费用) * 结算金额(结算币种,含全部合计费用)
*/ */
private BigDecimal settlementAmount; private BigDecimal settlementAmount;
/**
* 业务模式(业务字典 business_model)
*/
private String businessModel;
/**
* 运输方式(业务字典 transport_type)
*/
private String transportType;
/** /**
* 本位币,默认 RMB * 本位币,默认 RMB
*/ */
@@ -92,6 +92,12 @@ public class PreSettlement extends TenantEntity {
@Schema(description = "结算金额") @Schema(description = "结算金额")
private BigDecimal settlementAmount; private BigDecimal settlementAmount;
@Schema(description = "业务模式(业务字典 business_model)")
private String businessModel;
@Schema(description = "运输方式(业务字典 transport_type)")
private String transportType;
@Schema(description = "本位币") @Schema(description = "本位币")
private String localCurrency; private String localCurrency;
@@ -43,6 +43,8 @@ public class FormalSettlementVO extends FormalSettlement implements KingdeeUnloc
@TableField(exist = false) private String ids; @TableField(exist = false) private String ids;
@TableField(exist = false) private String approvalStatusName; @TableField(exist = false) private String approvalStatusName;
@TableField(exist = false) private String settlementTypeName; @TableField(exist = false) private String settlementTypeName;
@TableField(exist = false) @Schema(description = "业务模式名称") private String businessModelName;
@TableField(exist = false) @Schema(description = "运输方式名称") private String transportTypeName;
@TableField(exist = false) private Integer attachmentCount; @TableField(exist = false) private Integer attachmentCount;
@TableField(exist = false) private String attachmentSyncStatus; @TableField(exist = false) private String attachmentSyncStatus;
@TableField(exist = false) private String attachmentSyncStatusName; @TableField(exist = false) private String attachmentSyncStatusName;
@@ -85,6 +85,14 @@ public class PreSettlementVO extends PreSettlement {
@Schema(description = "结算类型名称") @Schema(description = "结算类型名称")
private String settlementTypeName; private String settlementTypeName;
@TableField(exist = false)
@Schema(description = "业务模式名称")
private String businessModelName;
@TableField(exist = false)
@Schema(description = "运输方式名称")
private String transportTypeName;
@TableField(exist = false) @TableField(exist = false)
@Schema(description = "结算明细") @Schema(description = "结算明细")
private List<PreSettlementDetail> details; private List<PreSettlementDetail> details;
@@ -877,7 +877,9 @@ public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements ID
private void validateContractInitialSerial(Dept dept) { private void validateContractInitialSerial(Dept dept) {
Integer serial = dept.getContractInitialSerial(); Integer serial = dept.getContractInitialSerial();
if (serial == null) { // -1 为空占位,未填写时按 null 落库,不自动保留 -1
if (serial == null || serial == -1) {
dept.setContractInitialSerial(null);
return; return;
} }
if (serial < 1 || serial > 999) { if (serial < 1 || serial > 999) {
@@ -923,7 +923,8 @@ public class OASyncServiceImpl implements IOASyncService {
.ne(Dept::getOaId, "") .ne(Dept::getOaId, "")
.select(Dept::getId, Dept::getDeptCode, Dept::getDeptName, Dept::getFullName, .select(Dept::getId, Dept::getDeptCode, Dept::getDeptName, Dept::getFullName,
Dept::getOaModified, Dept::getParentId, Dept::getOaId, Dept::getBelongCompanyCode, Dept::getOaModified, Dept::getParentId, Dept::getOaId, Dept::getBelongCompanyCode,
Dept::getParentCode, Dept::getOaSupSubComId)); Dept::getParentCode, Dept::getOaSupSubComId,
Dept::getContractCodePrefix, Dept::getContractInitialSerial));
Map<String, Dept> byOaId = new HashMap<>(); Map<String, Dept> byOaId = new HashMap<>();
for (Dept dept : deptList) { for (Dept dept : deptList) {
if (StringUtils.isNotBlank(dept.getOaId())) { if (StringUtils.isNotBlank(dept.getOaId())) {
@@ -986,6 +987,9 @@ public class OASyncServiceImpl implements IOASyncService {
} else { } else {
dept.setId(DefaultIdentifierGenerator.getInstance().nextId(null)); dept.setId(DefaultIdentifierGenerator.getInstance().nextId(null));
} }
// OA 不同步合同本地配置:保留已有值,并把 -1 空占位规范为 null,避免 ALWAYS 策略写回 -1/清空
preserveLocalContractFields(dept, existing);
normalizeContractInitialSerial(dept);
if (StringUtils.isNotBlank(dept.getDeptCode())) { if (StringUtils.isNotBlank(dept.getDeptCode())) {
deptIdByCode.put(dept.getDeptCode(), dept.getId()); deptIdByCode.put(dept.getDeptCode(), dept.getId());
} }
@@ -1046,6 +1050,35 @@ public class OASyncServiceImpl implements IOASyncService {
return new OrgSyncCount(syncedCount, skippedCount, notHandledList); return new OrgSyncCount(syncedCount, skippedCount, notHandledList);
} }
/**
* OA 同步对象不含合同本地配置,更新时保留库中已有合同编码前缀与初始流水号。
*/
private void preserveLocalContractFields(Dept incoming, Dept existing) {
if (incoming == null || existing == null) {
return;
}
if (StringUtils.isBlank(incoming.getContractCodePrefix())) {
incoming.setContractCodePrefix(existing.getContractCodePrefix());
}
Integer incomingSerial = incoming.getContractInitialSerial();
if (incomingSerial == null || incomingSerial == -1) {
incoming.setContractInitialSerial(existing.getContractInitialSerial());
}
}
/**
* 合同初始流水号 -1 为空占位,同步落库前规范为 null。
*/
private void normalizeContractInitialSerial(Dept dept) {
if (dept == null) {
return;
}
Integer serial = dept.getContractInitialSerial();
if (serial != null && serial == -1) {
dept.setContractInitialSerial(null);
}
}
/** /**
* oaModified 一致则跳过更新;任一侧为空无法确认一致,执行更新以补齐字段。 * oaModified 一致则跳过更新;任一侧为空无法确认一致,执行更新以补齐字段。
* 组织编码已按新规则重算、父子挂载不一致、或名称字段与当前映射不一致时,即使 modified 相同也要更新。 * 组织编码已按新规则重算、父子挂载不一致、或名称字段与当前映射不一致时,即使 modified 相同也要更新。
@@ -99,6 +99,8 @@ public class FormalSettlementController extends BladeController {
excel.setContractNo(vo.getContractNo()); excel.setContractNo(vo.getContractNo());
excel.setContractName(vo.getContractName()); excel.setContractName(vo.getContractName());
excel.setSettlementAmount(formatMoney(vo.getSettlementAmount(), vo.getCurrency())); excel.setSettlementAmount(formatMoney(vo.getSettlementAmount(), vo.getCurrency()));
excel.setBusinessModelName(vo.getBusinessModelName());
excel.setTransportTypeName(vo.getTransportTypeName());
excel.setLocalSettlementAmount(formatMoney(vo.getLocalSettlementAmount(), vo.getLocalCurrency())); excel.setLocalSettlementAmount(formatMoney(vo.getLocalSettlementAmount(), vo.getLocalCurrency()));
excel.setExchangeRate(vo.getExchangeRate() == null ? "" : vo.getExchangeRate().stripTrailingZeros().toPlainString()); excel.setExchangeRate(vo.getExchangeRate() == null ? "" : vo.getExchangeRate().stripTrailingZeros().toPlainString());
excel.setInvoiceStatusName(invoiceStatusName(vo.getInvoiceStatus(), vo.getSettlementType())); excel.setInvoiceStatusName(invoiceStatusName(vo.getInvoiceStatus(), vo.getSettlementType()));
@@ -250,6 +250,8 @@ public class PreSettlementController extends BladeController {
excel.setContractNo(vo.getContractNo()); excel.setContractNo(vo.getContractNo());
excel.setContractName(vo.getContractName()); excel.setContractName(vo.getContractName());
excel.setSettlementAmount(formatMoney(vo.getSettlementAmount(), vo.getCurrency())); excel.setSettlementAmount(formatMoney(vo.getSettlementAmount(), vo.getCurrency()));
excel.setBusinessModelName(vo.getBusinessModelName());
excel.setTransportTypeName(vo.getTransportTypeName());
excel.setLocalSettlementAmount(formatMoney(vo.getLocalSettlementAmount(), vo.getLocalCurrency())); excel.setLocalSettlementAmount(formatMoney(vo.getLocalSettlementAmount(), vo.getLocalCurrency()));
excel.setExchangeRate(vo.getExchangeRate() == null ? "" : vo.getExchangeRate().stripTrailingZeros().toPlainString()); excel.setExchangeRate(vo.getExchangeRate() == null ? "" : vo.getExchangeRate().stripTrailingZeros().toPlainString());
excel.setAdvanceAppliedAmount(formatMoney(vo.getAdvanceAppliedAmount(), vo.getCurrency())); excel.setAdvanceAppliedAmount(formatMoney(vo.getAdvanceAppliedAmount(), vo.getCurrency()));
@@ -39,6 +39,10 @@ public class FormalSettlementExcel implements Serializable {
private String contractName; private String contractName;
@ExcelProperty("原币结算金额") @ExcelProperty("原币结算金额")
private String settlementAmount; private String settlementAmount;
@ExcelProperty("业务模式")
private String businessModelName;
@ExcelProperty("运输方式")
private String transportTypeName;
@ExcelProperty("本位币结算金额") @ExcelProperty("本位币结算金额")
private String localSettlementAmount; private String localSettlementAmount;
@ExcelProperty("结算汇率") @ExcelProperty("结算汇率")
@@ -50,6 +50,10 @@ public class PreSettlementExcel implements Serializable {
private String contractName; private String contractName;
@ExcelProperty("原币结算金额") @ExcelProperty("原币结算金额")
private String settlementAmount; private String settlementAmount;
@ExcelProperty("业务模式")
private String businessModelName;
@ExcelProperty("运输方式")
private String transportTypeName;
@ExcelProperty("本位币结算金额") @ExcelProperty("本位币结算金额")
private String localSettlementAmount; private String localSettlementAmount;
@ExcelProperty("结算汇率") @ExcelProperty("结算汇率")
@@ -350,9 +350,14 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
.eq(SettlementAdjustment::getFormalSettlementId, id) .eq(SettlementAdjustment::getFormalSettlementId, id)
.orderByDesc(SettlementAdjustment::getCreateTime)).stream() .orderByDesc(SettlementAdjustment::getCreateTime)).stream()
.map(this::toAdjustmentVO).toList()); .map(this::toAdjustmentVO).toList());
vo.setChangeRecords(changeRecordMapper.selectList(Wrappers.<FormalSettlementChangeRecord>lambdaQuery() List<FormalSettlementChangeRecord> changeRecords = changeRecordMapper.selectList(
Wrappers.<FormalSettlementChangeRecord>lambdaQuery()
.eq(FormalSettlementChangeRecord::getFormalSettlementId, id) .eq(FormalSettlementChangeRecord::getFormalSettlementId, id)
.orderByDesc(FormalSettlementChangeRecord::getChangeTime))); .orderByDesc(FormalSettlementChangeRecord::getChangeTime));
// 审批通过/驳回类不展示在变更记录中
vo.setChangeRecords(changeRecords.stream()
.filter(record -> !isApprovalChangeContent(record.getChangeContent()))
.toList());
return vo; return vo;
} }
@@ -558,6 +563,8 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
settlement.setKingdeeSyncStatus("unsynced"); settlement.setKingdeeSyncStatus("unsynced");
} }
if (first == null) copyHeader(contract, settlementType, directDetails.get(0), settlement); else copyHeader(first, settlement); if (first == null) copyHeader(contract, settlementType, directDetails.get(0), settlement); else copyHeader(first, settlement);
settlement.setBusinessModel(limit(request.getBusinessModel(), 64));
settlement.setTransportType(limit(request.getTransportType(), 64));
settlement.setExchangeRateDate(request.getExchangeRateDate()); settlement.setExchangeRateDate(request.getExchangeRateDate());
settlement.setExchangeRate(request.getExchangeRate() == null ? BigDecimal.ONE : positive(request.getExchangeRate(), "结算汇率")); settlement.setExchangeRate(request.getExchangeRate() == null ? BigDecimal.ONE : positive(request.getExchangeRate(), "结算汇率"));
BigDecimal sourceAmount = sources.stream().map(PreSettlement::getSettlementAmount).map(this::money).reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal sourceAmount = sources.stream().map(PreSettlement::getSettlementAmount).map(this::money).reduce(BigDecimal.ZERO, BigDecimal::add);
@@ -631,7 +638,7 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
settlement.setCurrentProcessor(AuthUtil.getUserName()); settlement.setCurrentProcessor(AuthUtil.getUserName());
settlement.setApprovedTime(LocalDateTime.now()); settlement.setApprovedTime(LocalDateTime.now());
updateById(settlement); updateById(settlement);
saveChange(settlement.getId(), "结算单基本信息", null, "调整", "正式结算审批通过", request.getReason()); // 审批通过不落变更记录
// 审批事务提交后自动推送金蝶(AFTER_COMMIT 监听器消费,推送失败不影响审批结果) // 审批事务提交后自动推送金蝶(AFTER_COMMIT 监听器消费,推送失败不影响审批结果)
eventPublisher.publishEvent(new KingdeeBillApprovedEvent(KingdeeBillApprovedEvent.BIZ_FORMAL_SETTLEMENT, settlement.getId())); eventPublisher.publishEvent(new KingdeeBillApprovedEvent(KingdeeBillApprovedEvent.BIZ_FORMAL_SETTLEMENT, settlement.getId()));
} }
@@ -1268,8 +1275,30 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
} }
Map<Long, ReceivablePayableCargoFee> sourceFeeMap = receivablePayableCargoFeeMapper.selectBatchIds(sourceFeeIds).stream() Map<Long, ReceivablePayableCargoFee> sourceFeeMap = receivablePayableCargoFeeMapper.selectBatchIds(sourceFeeIds).stream()
.collect(Collectors.toMap(ReceivablePayableCargoFee::getId, Function.identity(), (left, right) -> left)); .collect(Collectors.toMap(ReceivablePayableCargoFee::getId, Function.identity(), (left, right) -> left));
// 历史数据可能把预结算费用行ID误写入 sourceFeeId,需再解析到应收应付费用行
List<Long> unresolvedIds = sourceFeeIds.stream().filter(id -> !sourceFeeMap.containsKey(id)).toList();
Map<Long, PreSettlementDetailFee> preFeeMap = unresolvedIds.isEmpty() ? Map.of()
: preDetailFeeMapper.selectBatchIds(unresolvedIds).stream()
.collect(Collectors.toMap(PreSettlementDetailFee::getId, Function.identity(), (left, right) -> left));
List<Long> receivableFeeIds = preFeeMap.values().stream().map(PreSettlementDetailFee::getSourceFeeId)
.filter(Objects::nonNull).distinct().toList();
if (!receivableFeeIds.isEmpty()) {
receivablePayableCargoFeeMapper.selectBatchIds(receivableFeeIds).forEach(item ->
sourceFeeMap.putIfAbsent(item.getId(), item));
}
fees.forEach(fee -> { fees.forEach(fee -> {
ReceivablePayableCargoFee sourceFee = sourceFeeMap.get(fee.getSourceFeeId()); Long sourceFeeId = fee.getSourceFeeId();
ReceivablePayableCargoFee sourceFee = sourceFeeMap.get(sourceFeeId);
if (sourceFee == null && sourceFeeId != null) {
PreSettlementDetailFee preFee = preFeeMap.get(sourceFeeId);
if (preFee != null && preFee.getSourceFeeId() != null) {
sourceFee = sourceFeeMap.get(preFee.getSourceFeeId());
if (sourceFee != null) {
// 仅回写响应,便于前端试算;不落库覆盖历史 sourceFeeId
fee.setSourceFeeId(preFee.getSourceFeeId());
}
}
}
if (sourceFee != null) { if (sourceFee != null) {
fee.setBillingRulesJson(sourceFee.getBillingRulesJson()); fee.setBillingRulesJson(sourceFee.getBillingRulesJson());
} }
@@ -2029,7 +2058,11 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
for (PreSettlementDetailFee item : fees) { for (PreSettlementDetailFee item : fees) {
FormalSettlementDetailFee fee = Objects.requireNonNull(BeanUtil.copyProperties(item, FormalSettlementDetailFee.class)); FormalSettlementDetailFee fee = Objects.requireNonNull(BeanUtil.copyProperties(item, FormalSettlementDetailFee.class));
fee.setTransportQuantity(money(fee.getTransportQuantity())); fee.setTransportQuantity(money(fee.getTransportQuantity()));
fee.setId(null); fee.setFormalSettlementDetailId(target.getId()); fee.setSourceFeeId(item.getId()); detailFeeMapper.insert(fee); fee.setId(null);
fee.setFormalSettlementDetailId(target.getId());
// 优先保留应收应付费用行ID,便于正式结算调整时按合同计费方案试算
fee.setSourceFeeId(item.getSourceFeeId() != null ? item.getSourceFeeId() : item.getId());
detailFeeMapper.insert(fee);
} }
if (fees.isEmpty()) createSingleFee(target); if (fees.isEmpty()) createSingleFee(target);
} }
@@ -2334,8 +2367,11 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
settlement.setApprovalStatus(target); settlement.setCurrentNode(node); settlement.setCurrentProcessor(AuthUtil.getUserName()); settlement.setApprovalStatus(target); settlement.setCurrentNode(node); settlement.setCurrentProcessor(AuthUtil.getUserName());
if (TransportBusiConstant.RETURNED.equals(target)) settlement.setVoidReason(limit(reason, 200)); if (TransportBusiConstant.RETURNED.equals(target)) settlement.setVoidReason(limit(reason, 200));
updateById(settlement); updateById(settlement);
// 审批驳回不落变更记录;提交等其它状态流转仍记录
if (!TransportBusiConstant.RETURNED.equals(target)) {
saveChange(settlement.getId(), "结算单基本信息", null, "调整", node, reason); saveChange(settlement.getId(), "结算单基本信息", null, "调整", node, reason);
} }
}
private void saveManualSummaryFeeChange(Long settlementId, boolean creating, String beforeFeeType, private void saveManualSummaryFeeChange(Long settlementId, boolean creating, String beforeFeeType,
String beforeFeeItem, BigDecimal beforeAdjustAmount, BigDecimal beforeSettlementAmount, String beforeRemark, String beforeFeeItem, BigDecimal beforeAdjustAmount, BigDecimal beforeSettlementAmount, String beforeRemark,
@@ -2393,6 +2429,14 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
} }
} }
/** 审批通过、驳回等审批流转不落变更记录。 */
private boolean isApprovalChangeContent(String content) {
if (Func.isEmpty(content)) {
return false;
}
return content.contains("审批通过") || content.contains("审批驳回") || "已驳回".equals(content);
}
private void saveChange(Long settlementId, String changeType, Integer lineNo, String operationType, private void saveChange(Long settlementId, String changeType, Integer lineNo, String operationType,
String content, String reason) { String content, String reason) {
saveChange(settlementId, changeType, lineNo, operationType, content, reason, null, null); saveChange(settlementId, changeType, lineNo, operationType, content, reason, null, null);
@@ -2400,6 +2444,9 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
private void saveChange(Long settlementId, String changeType, Integer lineNo, String operationType, private void saveChange(Long settlementId, String changeType, Integer lineNo, String operationType,
String content, String reason, Map<String, Object> beforeData, Map<String, Object> afterData) { String content, String reason, Map<String, Object> beforeData, Map<String, Object> afterData) {
if (isApprovalChangeContent(content)) {
return;
}
FormalSettlementChangeRecord record = new FormalSettlementChangeRecord(); FormalSettlementChangeRecord record = new FormalSettlementChangeRecord();
record.setFormalSettlementId(settlementId); record.setFormalSettlementId(settlementId);
record.setChangeType(changeType); record.setChangeType(changeType);
@@ -203,13 +203,15 @@ public class PreSettlementServiceImpl extends BaseServiceImpl<PreSettlementMappe
vo.setAdvances(advances); vo.setAdvances(advances);
vo.setProjectAdvanceWriteOffs(projectAdvanceWriteOffService.listBySettlement( vo.setProjectAdvanceWriteOffs(projectAdvanceWriteOffService.listBySettlement(
TransportBusiConstant.SETTLEMENT_BILL_PRE, id)); TransportBusiConstant.SETTLEMENT_BILL_PRE, id));
vo.setChangeRecords(changeRecordMapper.selectList(Wrappers.<PreSettlementChangeRecord>lambdaQuery() List<PreSettlementChangeRecord> changeRecords = changeRecordMapper.selectList(
Wrappers.<PreSettlementChangeRecord>lambdaQuery()
.eq(PreSettlementChangeRecord::getPreSettlementId, id) .eq(PreSettlementChangeRecord::getPreSettlementId, id)
.eq(PreSettlementChangeRecord::getIsDeleted, 0) .eq(PreSettlementChangeRecord::getIsDeleted, 0)
.and(wrapper -> wrapper.isNull(PreSettlementChangeRecord::getChangeContent) .orderByDesc(PreSettlementChangeRecord::getChangeTime));
.or() // 审批通过/驳回类不展示在变更记录中
.ne(PreSettlementChangeRecord::getChangeContent, "预结算审批通过")) vo.setChangeRecords(changeRecords.stream()
.orderByDesc(PreSettlementChangeRecord::getChangeTime))); .filter(record -> !isApprovalChangeContent(record.getChangeContent()))
.toList());
vo.setPrintTemplates(resolvePrintTemplates(settlement)); vo.setPrintTemplates(resolvePrintTemplates(settlement));
return vo; return vo;
} }
@@ -349,6 +351,8 @@ public class PreSettlementServiceImpl extends BaseServiceImpl<PreSettlementMappe
settlement.setLocalCurrency(LOCAL_CURRENCY); settlement.setLocalCurrency(LOCAL_CURRENCY);
} }
fillContract(settlement, contract); fillContract(settlement, contract);
settlement.setBusinessModel(limitText(request.getBusinessModel(), 64, "业务模式"));
settlement.setTransportType(limitText(request.getTransportType(), 64, "运输方式"));
settlement.setExchangeRateDate(request.getExchangeRateDate()); settlement.setExchangeRateDate(request.getExchangeRateDate());
settlement.setExchangeRate(request.getExchangeRate()); settlement.setExchangeRate(request.getExchangeRate());
settlement.setAttachmentsJson(request.getAttachmentsJson()); settlement.setAttachmentsJson(request.getAttachmentsJson());
@@ -441,7 +445,7 @@ public class PreSettlementServiceImpl extends BaseServiceImpl<PreSettlementMappe
settlement.setCurrentNode("已驳回"); settlement.setCurrentNode("已驳回");
settlement.setCurrentProcessor(AuthUtil.getUserName()); settlement.setCurrentProcessor(AuthUtil.getUserName());
updateById(settlement); updateById(settlement);
saveChange(settlement.getId(), "结算单基本信息", null, "调整", "预结算审批驳回", reason); // 审批驳回不落变更记录
} }
@Override @Override
@@ -1614,6 +1618,14 @@ public class PreSettlementServiceImpl extends BaseServiceImpl<PreSettlementMappe
return source + " " + name; return source + " " + name;
} }
/** 审批通过、驳回等审批流转不落变更记录。 */
private boolean isApprovalChangeContent(String content) {
if (Func.isEmpty(content)) {
return false;
}
return content.contains("审批通过") || content.contains("审批驳回") || "已驳回".equals(content);
}
private void saveChange(Long settlementId, String changeType, Integer lineNo, String operationType, private void saveChange(Long settlementId, String changeType, Integer lineNo, String operationType,
String content, String reason) { String content, String reason) {
saveChange(settlementId, changeType, lineNo, operationType, content, reason, null, null); saveChange(settlementId, changeType, lineNo, operationType, content, reason, null, null);
@@ -1621,6 +1633,9 @@ public class PreSettlementServiceImpl extends BaseServiceImpl<PreSettlementMappe
private void saveChange(Long settlementId, String changeType, Integer lineNo, String operationType, private void saveChange(Long settlementId, String changeType, Integer lineNo, String operationType,
String content, String reason, Map<String, Object> beforeData, Map<String, Object> afterData) { String content, String reason, Map<String, Object> beforeData, Map<String, Object> afterData) {
if (isApprovalChangeContent(content)) {
return;
}
PreSettlementChangeRecord record = new PreSettlementChangeRecord(); PreSettlementChangeRecord record = new PreSettlementChangeRecord();
record.setPreSettlementId(settlementId); record.setPreSettlementId(settlementId);
record.setChangeType(changeType); record.setChangeType(changeType);
@@ -671,8 +671,10 @@ public class ReceivablePayableDetailServiceImpl
throw new ServiceException("费用调整试算数据不能为空"); throw new ServiceException("费用调整试算数据不能为空");
} }
ReceivablePayableDetail detail = getExisting(request.getDetailId()); ReceivablePayableDetail detail = getExisting(request.getDetailId());
if (!"pending".equals(detail.getSettlementStatus())) { // 试算不落库,预结算/正式结算调整明细也需按合同计费方案重算运费及其他按量费用
throw new ServiceException("仅待结算明细允许调整试算"); String settlementStatus = Func.toStr(detail.getSettlementStatus(), "pending");
if (!List.of("pending", "pre_settled", "formal_settled").contains(settlementStatus)) {
throw new ServiceException("当前结算状态不允许费用试算");
} }
ReceivablePayableCargoFee fee = cargoFeeMapper.selectOne( ReceivablePayableCargoFee fee = cargoFeeMapper.selectOne(
Wrappers.<ReceivablePayableCargoFee>lambdaQuery() Wrappers.<ReceivablePayableCargoFee>lambdaQuery()
@@ -1309,7 +1309,8 @@ public class TransportReconciliationServiceImpl
bill.setInternalBillCount(internals.size()); bill.setExternalBillCount(externals.size()); bill.setInternalBillCount(internals.size()); bill.setExternalBillCount(externals.size());
int internalUnmatched = (int) internals.stream().filter(item -> !MATCHED.equals(item.getMatchResult())).count(); int internalUnmatched = (int) internals.stream().filter(item -> !MATCHED.equals(item.getMatchResult())).count();
int externalUnmatched = (int) externals.stream().filter(item -> !MATCHED.equals(item.getMatchStatus())).count(); int externalUnmatched = (int) externals.stream().filter(item -> !MATCHED.equals(item.getMatchStatus())).count();
bill.setMatchedCount(matched); bill.setUnmatchedCount(internalUnmatched + externalUnmatched); // 无法匹配按内部账单条数统计,不叠加外部未匹配数
bill.setMatchedCount(matched); bill.setUnmatchedCount(internalUnmatched);
bill.setDifferenceCount(Math.abs(internals.size() - externals.size()) + Math.min(internalUnmatched, externalUnmatched)); bill.setDifferenceCount(Math.abs(internals.size() - externals.size()) + Math.min(internalUnmatched, externalUnmatched));
bill.setInternalQuantity(sumInternalQuantity(internals)); bill.setExternalQuantity(sumExternalQuantity(externals)); bill.setInternalQuantity(sumInternalQuantity(internals)); bill.setExternalQuantity(sumExternalQuantity(externals));
bill.setDifferenceQuantity(bill.getInternalQuantity().subtract(bill.getExternalQuantity()).abs()); bill.setDifferenceQuantity(bill.getInternalQuantity().subtract(bill.getExternalQuantity()).abs());
@@ -10,6 +10,9 @@ package org.springblade.transport.wrapper;
import org.springblade.core.mp.support.BaseEntityWrapper; import org.springblade.core.mp.support.BaseEntityWrapper;
import org.springblade.core.tool.utils.BeanUtil; import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.system.cache.DictBizCache;
import org.springblade.system.cache.DictCache;
import org.springblade.system.cache.UserCache; import org.springblade.system.cache.UserCache;
import org.springblade.transport.pojo.entity.FormalSettlement; import org.springblade.transport.pojo.entity.FormalSettlement;
import org.springblade.transport.pojo.vo.FormalSettlementVO; import org.springblade.transport.pojo.vo.FormalSettlementVO;
@@ -46,6 +49,28 @@ public class FormalSettlementWrapper extends BaseEntityWrapper<FormalSettlement,
default -> entity.getApprovalStatus(); default -> entity.getApprovalStatus();
}); });
vo.setAdjustStatusName("adjusted".equals(entity.getAdjustStatus()) ? "已调整" : null); vo.setAdjustStatusName("adjusted".equals(entity.getAdjustStatus()) ? "已调整" : null);
vo.setBusinessModelName(dictBizName("business_model", entity.getBusinessModel()));
vo.setTransportTypeName(dictBizName("transport_type", entity.getTransportType()));
return vo; return vo;
} }
private String dictBizName(String code, String value) {
if (Func.isEmpty(value)) {
return value;
}
String name = "";
try {
name = DictBizCache.getValue(code, value);
} catch (Exception exception) {
name = "";
}
if (Func.isEmpty(name)) {
try {
name = DictCache.getValue(code, value);
} catch (Exception exception) {
name = "";
}
}
return Func.isEmpty(name) ? value : name;
}
} }
@@ -10,6 +10,9 @@ package org.springblade.transport.wrapper;
import org.springblade.core.mp.support.BaseEntityWrapper; import org.springblade.core.mp.support.BaseEntityWrapper;
import org.springblade.core.tool.utils.BeanUtil; import org.springblade.core.tool.utils.BeanUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.system.cache.DictBizCache;
import org.springblade.system.cache.DictCache;
import org.springblade.system.cache.UserCache; import org.springblade.system.cache.UserCache;
import org.springblade.transport.pojo.entity.PreSettlement; import org.springblade.transport.pojo.entity.PreSettlement;
import org.springblade.transport.pojo.vo.PreSettlementVO; import org.springblade.transport.pojo.vo.PreSettlementVO;
@@ -34,6 +37,8 @@ public class PreSettlementWrapper extends BaseEntityWrapper<PreSettlement, PreSe
vo.setUpdateUserName(UserCache.getUserRealName(entity.getUpdateUser())); vo.setUpdateUserName(UserCache.getUserRealName(entity.getUpdateUser()));
vo.setApprovalStatusName(approvalStatusName(entity.getApprovalStatus())); vo.setApprovalStatusName(approvalStatusName(entity.getApprovalStatus()));
vo.setSettlementTypeName("receivable".equals(entity.getSettlementType()) ? "应收" : "应付"); vo.setSettlementTypeName("receivable".equals(entity.getSettlementType()) ? "应收" : "应付");
vo.setBusinessModelName(dictBizName("business_model", entity.getBusinessModel()));
vo.setTransportTypeName(dictBizName("transport_type", entity.getTransportType()));
return vo; return vo;
} }
@@ -48,4 +53,24 @@ public class PreSettlementWrapper extends BaseEntityWrapper<PreSettlement, PreSe
}; };
} }
private String dictBizName(String code, String value) {
if (Func.isEmpty(value)) {
return value;
}
String name = "";
try {
name = DictBizCache.getValue(code, value);
} catch (Exception exception) {
name = "";
}
if (Func.isEmpty(name)) {
try {
name = DictCache.getValue(code, value);
} catch (Exception exception) {
name = "";
}
}
return Func.isEmpty(name) ? value : name;
}
} }
@@ -9,6 +9,7 @@ CREATE TABLE IF NOT EXISTS `blade_formal_settlement` (
`dept_id` bigint(20) DEFAULT NULL, `dept_name` varchar(100) DEFAULT NULL, `contract_id` bigint(20) NOT NULL, `dept_id` bigint(20) DEFAULT NULL, `dept_name` varchar(100) DEFAULT NULL, `contract_id` bigint(20) NOT NULL,
`contract_no` varchar(100) DEFAULT NULL, `contract_name` varchar(100) NOT NULL, `payer_name` varchar(200) DEFAULT NULL, `contract_no` varchar(100) DEFAULT NULL, `contract_name` varchar(100) NOT NULL, `payer_name` varchar(200) DEFAULT NULL,
`payee_name` varchar(200) DEFAULT NULL, `currency` varchar(20) NOT NULL DEFAULT 'RMB', `settlement_amount` decimal(18,2) NOT NULL DEFAULT '0.00', `payee_name` varchar(200) DEFAULT NULL, `currency` varchar(20) NOT NULL DEFAULT 'RMB', `settlement_amount` decimal(18,2) NOT NULL DEFAULT '0.00',
`business_model` varchar(64) DEFAULT NULL COMMENT '业务模式', `transport_type` varchar(64) DEFAULT NULL COMMENT '运输方式',
`local_currency` varchar(20) NOT NULL DEFAULT 'RMB', `local_settlement_amount` decimal(18,2) DEFAULT NULL, `local_currency` varchar(20) NOT NULL DEFAULT 'RMB', `local_settlement_amount` decimal(18,2) DEFAULT NULL,
`applied_payment_amount` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '申请付款金额含预付', `applied_payment_amount` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '申请付款金额含预付',
`paid_amount` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '已收已付合计含预付', `paid_amount` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '已收已付合计含预付',
@@ -24,6 +24,8 @@ CREATE TABLE IF NOT EXISTS `blade_pre_settlement` (
`payee_name` varchar(200) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '收款方', `payee_name` varchar(200) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '收款方',
`currency` varchar(20) COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'RMB' COMMENT '结算币种', `currency` varchar(20) COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'RMB' COMMENT '结算币种',
`settlement_amount` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '结算金额', `settlement_amount` decimal(18,2) NOT NULL DEFAULT '0.00' COMMENT '结算金额',
`business_model` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '业务模式',
`transport_type` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '运输方式',
`local_currency` varchar(20) COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'RMB' COMMENT '本位币', `local_currency` varchar(20) COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'RMB' COMMENT '本位币',
`local_settlement_amount` decimal(18,2) DEFAULT NULL COMMENT '本位币合计', `local_settlement_amount` decimal(18,2) DEFAULT NULL COMMENT '本位币合计',
`exchange_rate_date` date DEFAULT NULL COMMENT '汇率日期', `exchange_rate_date` date DEFAULT NULL COMMENT '汇率日期',
@@ -0,0 +1,8 @@
-- 预结算单、正式结算单:业务模式、运输方式(主表头字段)
ALTER TABLE `blade_pre_settlement`
ADD COLUMN `business_model` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '业务模式' AFTER `settlement_amount`,
ADD COLUMN `transport_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '运输方式' AFTER `business_model`;
ALTER TABLE `blade_formal_settlement`
ADD COLUMN `business_model` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '业务模式' AFTER `settlement_amount`,
ADD COLUMN `transport_type` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '运输方式' AFTER `business_model`;