feat: 正式结算单支持结算调整重推克隆与金蝶同步回填
This commit is contained in:
+27
@@ -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<FormalSettlement>
|
||||
String applyPayment(FormalSettlementPaymentRequest request);
|
||||
List<String> 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<Long, Long> detailIdMap, Map<Long, Long> feeIdMap) {
|
||||
}
|
||||
}
|
||||
|
||||
+109
-3
@@ -344,7 +344,7 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
|
||||
vo.setAdjustments(settlementAdjustmentMapper.selectList(Wrappers.<SettlementAdjustment>lambdaQuery()
|
||||
.eq(SettlementAdjustment::getFormalSettlementId, id)
|
||||
.orderByDesc(SettlementAdjustment::getCreateTime)).stream()
|
||||
.map(item -> toAdjustmentVO(item, settlement.getKingdeeBillNo())).toList());
|
||||
.map(this::toAdjustmentVO).toList());
|
||||
vo.setChangeRecords(changeRecordMapper.selectList(Wrappers.<FormalSettlementChangeRecord>lambdaQuery()
|
||||
.eq(FormalSettlementChangeRecord::getFormalSettlementId, id)
|
||||
.orderByDesc(FormalSettlementChangeRecord::getChangeTime)));
|
||||
@@ -636,6 +636,102 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl<FormalSettlemen
|
||||
changeRecordMapper.insert(record);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public CloneResult cloneFormalSettlement(Long sourceSettlementId) {
|
||||
FormalSettlement source = existing(sourceSettlementId);
|
||||
FormalSettlement clone = Objects.requireNonNull(BeanUtil.copyProperties(source, FormalSettlement.class));
|
||||
// 新单头:新号、直接审批通过、未同步金蝶、来源原单号;不动原单
|
||||
resetAuditFields(clone);
|
||||
clone.setFormalSettlementNo(nextNo(source.getSettlementType()));
|
||||
clone.setApprovalStatus(TransportBusiConstant.APPROVED);
|
||||
clone.setCurrentNode("审批通过");
|
||||
clone.setCurrentProcessor(AuthUtil.getUserName());
|
||||
clone.setApprovedTime(LocalDateTime.now());
|
||||
clone.setKingdeeBillNo(null);
|
||||
clone.setKingdeeBillId(null);
|
||||
clone.setKingdeeSyncStatus(KingdeeBfiConstant.KINGDEE_STATUS_UNSYNCED);
|
||||
clone.setSyncedTime(null);
|
||||
clone.setVoidReason(null);
|
||||
clone.setOriginFormalSettlementNo(source.getFormalSettlementNo());
|
||||
clone.setAdjustStatus(null);
|
||||
// 下游关联(开票申请/收款认领/对账)不迁移:发票/收付款口径归零,新单为全新独立单
|
||||
clone.setInvoiceStatus("unreceived");
|
||||
clone.setPaymentStatus("unpaid");
|
||||
clone.setInvoiceAmount(BigDecimal.ZERO.setScale(2));
|
||||
clone.setAppliedPaymentAmount(BigDecimal.ZERO.setScale(2));
|
||||
clone.setPaidAmount(BigDecimal.ZERO.setScale(2));
|
||||
clone.setRemainingPayableAmount(money(source.getSettlementAmount()));
|
||||
save(clone);
|
||||
|
||||
// 明细与明细费项克隆,记录 原id->新id 映射(调整明细应用到新单时按映射定位)
|
||||
Map<Long, Long> detailIdMap = new HashMap<>();
|
||||
Map<Long, Long> feeIdMap = new HashMap<>();
|
||||
List<FormalSettlementDetail> details = detailMapper.selectList(Wrappers.<FormalSettlementDetail>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.<FormalSettlementDetailFee>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.<FormalSettlementSource>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.<FormalSettlement>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<FormalSettlemen
|
||||
.ne(FormalSettlement::getKingdeeSyncStatus, KingdeeBfiConstant.KINGDEE_STATUS_SYNCED)
|
||||
.set(FormalSettlement::getKingdeeSyncStatus, KingdeeBfiConstant.KINGDEE_STATUS_FAILED));
|
||||
if (updated > 0) {
|
||||
// 结算调整单回填:未推送场景审批通过后自动推送失败,调整单置 failed 供「推送金蝶」重试
|
||||
settlementAdjustmentMapper.update(null, Wrappers.<SettlementAdjustment>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 BaseServiceImpl<FormalSettlemen
|
||||
settlement.setSyncedTime(LocalDateTime.now());
|
||||
updateById(settlement);
|
||||
saveChange(settlement.getId(), "结算单基本信息", null, "调整", changeDesc, "");
|
||||
// 结算调整单回填:未推送场景审批通过后自动推送成功,回填挂在本单的已审批调整单(重推场景调整单已改挂新单,不受影响)
|
||||
settlementAdjustmentMapper.update(null, Wrappers.<SettlementAdjustment>lambdaUpdate()
|
||||
.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<FormalSettlemen
|
||||
List<FormalSettlementSource> 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;
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -45,6 +45,7 @@ public class FormalSettlementWrapper extends BaseEntityWrapper<FormalSettlement,
|
||||
case "voided" -> "已作废";
|
||||
default -> entity.getApprovalStatus();
|
||||
});
|
||||
vo.setAdjustStatusName("adjusted".equals(entity.getAdjustStatus()) ? "已调整" : null);
|
||||
return vo;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user