diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IFormalSettlementService.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IFormalSettlementService.java index 3393983e..daf1d429 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IFormalSettlementService.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/IFormalSettlementService.java @@ -24,6 +24,8 @@ import org.springblade.transport.pojo.dto.FormalSettlementPaymentRequest; import org.springblade.transport.pojo.dto.FormalSettlementBatchPaymentRequest; import org.springblade.transport.pojo.dto.FormalSettlementInvoiceClaimRequest; +import java.util.Map; + /** * 正式结算单服务 * @@ -93,4 +95,29 @@ public interface IFormalSettlementService extends BaseService String applyPayment(FormalSettlementPaymentRequest request); List applyPayments(FormalSettlementBatchPaymentRequest request); void claimInvoices(FormalSettlementInvoiceClaimRequest request); + + /** + * 结算调整重推:克隆原正式结算单为新单(含明细、明细费项、汇总费项、来源预结算、附件、汇率), + * 新单置审批通过、未同步金蝶,来源原单号指向原单;下游关联(开票申请/收款认领/对账)不迁移。 + * 不推送金蝶,由调用方在事务外调用 syncKingdee 推送 + * + * @param sourceSettlementId 原正式结算单id + * @return 新单id与「原明细/原费项 -> 新明细/新费项」id映射(供调整明细应用到新单) + */ + CloneResult cloneFormalSettlement(Long sourceSettlementId); + + /** + * 结算调整重推收尾:原单标记「已调整」、旧锁解锁、追加重推变更记录(不改原单业务数据) + * + * @param settlementId 原正式结算单id + * @param adjustmentNo 结算调整单号 + * @param newSettlementNo 重推生成的新单号 + */ + void markSettlementAdjusted(Long settlementId, String adjustmentNo, String newSettlementNo); + + /** + * 克隆结果:新单id + 原明细id->新明细id + 原费项id->新费项id + */ + record CloneResult(Long settlementId, Map detailIdMap, Map feeIdMap) { + } } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/FormalSettlementServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/FormalSettlementServiceImpl.java index c68b021d..7e37cd0d 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/FormalSettlementServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/FormalSettlementServiceImpl.java @@ -344,7 +344,7 @@ public class FormalSettlementServiceImpl extends BaseServiceImpllambdaQuery() .eq(SettlementAdjustment::getFormalSettlementId, id) .orderByDesc(SettlementAdjustment::getCreateTime)).stream() - .map(item -> toAdjustmentVO(item, settlement.getKingdeeBillNo())).toList()); + .map(this::toAdjustmentVO).toList()); vo.setChangeRecords(changeRecordMapper.selectList(Wrappers.lambdaQuery() .eq(FormalSettlementChangeRecord::getFormalSettlementId, id) .orderByDesc(FormalSettlementChangeRecord::getChangeTime))); @@ -636,6 +636,102 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl新id 映射(调整明细应用到新单时按映射定位) + Map detailIdMap = new HashMap<>(); + Map feeIdMap = new HashMap<>(); + List details = detailMapper.selectList(Wrappers.lambdaQuery() + .eq(FormalSettlementDetail::getFormalSettlementId, sourceSettlementId) + .eq(FormalSettlementDetail::getIsDeleted, 0) + .orderByAsc(FormalSettlementDetail::getLineNo)); + for (FormalSettlementDetail detail : details) { + FormalSettlementDetail cloneDetail = Objects.requireNonNull(BeanUtil.copyProperties(detail, FormalSettlementDetail.class)); + resetAuditFields(cloneDetail); + cloneDetail.setFormalSettlementId(clone.getId()); + detailMapper.insert(cloneDetail); + detailIdMap.put(detail.getId(), cloneDetail.getId()); + for (FormalSettlementDetailFee fee : detailFeeMapper.selectList(Wrappers.lambdaQuery() + .eq(FormalSettlementDetailFee::getFormalSettlementDetailId, detail.getId()) + .orderByAsc(FormalSettlementDetailFee::getLineNo))) { + FormalSettlementDetailFee cloneFee = Objects.requireNonNull(BeanUtil.copyProperties(fee, FormalSettlementDetailFee.class)); + resetAuditFields(cloneFee); + cloneFee.setFormalSettlementDetailId(cloneDetail.getId()); + detailFeeMapper.insert(cloneFee); + feeIdMap.put(fee.getId(), cloneFee.getId()); + } + } + // 汇总费用项克隆 + for (FormalSettlementSummaryFee summaryFee : listSummaryFees(sourceSettlementId)) { + FormalSettlementSummaryFee cloneFee = Objects.requireNonNull(BeanUtil.copyProperties(summaryFee, FormalSettlementSummaryFee.class)); + resetAuditFields(cloneFee); + cloneFee.setFormalSettlementId(clone.getId()); + summaryFeeMapper.insert(cloneFee); + } + // 来源预结算重建(接续原单来源,不重复锁定 PreSettlement.formalSettlementNo) + for (FormalSettlementSource relation : sourceMapper.selectList(Wrappers.lambdaQuery() + .eq(FormalSettlementSource::getFormalSettlementId, sourceSettlementId))) { + FormalSettlementSource cloneRelation = Objects.requireNonNull(BeanUtil.copyProperties(relation, FormalSettlementSource.class)); + resetAuditFields(cloneRelation); + cloneRelation.setFormalSettlementId(clone.getId()); + sourceMapper.insert(cloneRelation); + } + log.info("结算调整重推克隆正式结算单:原单[{}] -> 新单[{}](明细{}条)", + source.getFormalSettlementNo(), clone.getFormalSettlementNo(), details.size()); + return new CloneResult(clone.getId(), detailIdMap, feeIdMap); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void markSettlementAdjusted(Long settlementId, String adjustmentNo, String newSettlementNo) { + existing(settlementId); + // 原单只加标记,业务字段不动 + update(Wrappers.lambdaUpdate() + .eq(FormalSettlement::getId, settlementId) + .set(FormalSettlement::getAdjustStatus, "adjusted")); + kingdeeBillLockService.unlockByAdjustRepush(KingdeeLockConstant.SOURCE_SETTLEMENT, settlementId, AuthUtil.getUserName()); + saveChange(settlementId, "结算单基本信息", null, "调整", + "结算调整单" + Func.toStr(adjustmentNo) + "重推生成新单" + Func.toStr(newSettlementNo) + ",原单标记已调整", null); + } + + /** 重推/克隆复用:清空审计与主键字段,交由 MP 自动填充 */ + private void resetAuditFields(org.springblade.core.mp.base.BaseEntity entity) { + entity.setId(null); + entity.setCreateUser(null); + entity.setCreateDept(null); + entity.setCreateTime(null); + entity.setUpdateUser(null); + entity.setUpdateTime(null); + entity.setStatus(null); + entity.setIsDeleted(null); + } + @Override public String syncKingdee(Long id) { String billNo; @@ -700,6 +796,11 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl 0) { + // 结算调整单回填:未推送场景审批通过后自动推送失败,调整单置 failed 供「推送金蝶」重试 + settlementAdjustmentMapper.update(null, Wrappers.lambdaUpdate() + .eq(SettlementAdjustment::getFormalSettlementId, id) + .eq(SettlementAdjustment::getApprovalStatus, TransportBusiConstant.APPROVED) + .set(SettlementAdjustment::getKingdeeSyncStatus, KingdeeBfiConstant.KINGDEE_STATUS_FAILED)); // 失败原因写变更记录留档(推送事务已回滚,此处独立事务);原因过长截断留档,不抛错 String failReason = Func.toStrWithEmpty(reason, "未知异常"); saveChange(id, "结算单基本信息", null, "调整", @@ -851,6 +952,12 @@ public class FormalSettlementServiceImpl extends BaseServiceImpllambdaUpdate() + .eq(SettlementAdjustment::getFormalSettlementId, settlement.getId()) + .eq(SettlementAdjustment::getApprovalStatus, TransportBusiConstant.APPROVED) + .set(SettlementAdjustment::getKingdeeSyncStatus, KingdeeBfiConstant.KINGDEE_STATUS_SYNCED) + .set(SettlementAdjustment::getKingdeeBillNo, billNo)); log.info("正式结算单[{}]同步金蝶完成:settlementType={},billNo={},billPkId={}", settlement.getFormalSettlementNo(), settlement.getSettlementType(), billNo, billPkId); return billNo; @@ -1821,13 +1928,12 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl sources, BigDecimal receiptClaimPaid) { } - private SettlementAdjustmentVO toAdjustmentVO(SettlementAdjustment entity, String kingdeeBillNo) { + private SettlementAdjustmentVO toAdjustmentVO(SettlementAdjustment entity) { SettlementAdjustmentVO vo = Objects.requireNonNull( BeanUtil.copyProperties(entity, SettlementAdjustmentVO.class)); vo.setCreateUserName(UserCache.getUserRealName(entity.getCreateUser())); vo.setApprovalStatusName(approvalStatusName(entity.getApprovalStatus())); vo.setSettlementTypeName("receivable".equals(entity.getSettlementType()) ? "应收" : "应付"); - vo.setKingdeeBillNo(kingdeeBillNo); return vo; } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/wrapper/FormalSettlementWrapper.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/wrapper/FormalSettlementWrapper.java index 4f4a331a..68142f7d 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/wrapper/FormalSettlementWrapper.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/wrapper/FormalSettlementWrapper.java @@ -45,6 +45,7 @@ public class FormalSettlementWrapper extends BaseEntityWrapper "已作废"; default -> entity.getApprovalStatus(); }); + vo.setAdjustStatusName("adjusted".equals(entity.getAdjustStatus()) ? "已调整" : null); return vo; } }