feat: 付款申请纳入金蝶单据锁定与解锁流程(推送后锁单-删单回调还原-作废守卫-锁状态展示)
This commit is contained in:
+18
@@ -24,12 +24,15 @@ import org.springblade.transport.constant.TransportBusiConstant;
|
||||
import org.springblade.transport.mapper.FormalSettlementMapper;
|
||||
import org.springblade.transport.mapper.InvoiceApplicationMapper;
|
||||
import org.springblade.transport.mapper.KingdeeBillLockMapper;
|
||||
import org.springblade.transport.mapper.PaymentApplicationMapper;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlement;
|
||||
import org.springblade.transport.pojo.entity.InvoiceApplication;
|
||||
import org.springblade.transport.pojo.entity.KingdeeBillLock;
|
||||
import org.springblade.transport.pojo.entity.PaymentApplication;
|
||||
import org.springblade.transport.service.IFormalSettlementService;
|
||||
import org.springblade.transport.service.IInvoiceApplicationService;
|
||||
import org.springblade.transport.service.IKingdeeBillLockService;
|
||||
import org.springblade.transport.service.IPaymentApplicationService;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -66,6 +69,7 @@ public class KingdeeBillLockServiceImpl extends ServiceImpl<KingdeeBillLockMappe
|
||||
private final BfiProperties bfiProperties;
|
||||
private final FormalSettlementMapper formalSettlementMapper;
|
||||
private final InvoiceApplicationMapper invoiceApplicationMapper;
|
||||
private final PaymentApplicationMapper paymentApplicationMapper;
|
||||
|
||||
@Override
|
||||
public String lockAfterPush(String sourceBillType, Long sourceBillId, String sourceBillNo, String targetBillType, List<String> targetBillNos) {
|
||||
@@ -210,6 +214,20 @@ public class KingdeeBillLockServiceImpl extends ServiceImpl<KingdeeBillLockMappe
|
||||
}
|
||||
SpringUtil.getBean(IInvoiceApplicationService.class).voidByKingdee(application.getId(), operator);
|
||||
}
|
||||
case KingdeeLockConstant.SOURCE_PAY_APPLY -> {
|
||||
PaymentApplication application = paymentApplicationMapper.selectById(lockRecord.getSourceBillId());
|
||||
if (application == null || Objects.equals(application.getIsDeleted(), 1)) {
|
||||
log.warn("金蝶删单回调源付款申请不存在:id={}", lockRecord.getSourceBillId());
|
||||
return;
|
||||
}
|
||||
if (TransportBusiConstant.VOIDED.equals(application.getApprovalStatus())) {
|
||||
log.info("金蝶删单回调源付款申请[{}]已作废(幂等跳过)", application.getPaymentNo());
|
||||
return;
|
||||
}
|
||||
// 复用 ADR-0005 解锁口径:不作废源单,kingdeeStatus→生成失败、清编号内码(原值留档),
|
||||
// 不自动重推,人工核实后重新推送(A103-2 勾稽预检防重复推单)
|
||||
SpringUtil.getBean(IPaymentApplicationService.class).unlockBill(application.getId(), "金蝶删单回调");
|
||||
}
|
||||
default -> log.warn("金蝶删单回调暂不支持的单据类型:targetBillType={}(映射预留)", lockRecord.getTargetBillType());
|
||||
}
|
||||
}
|
||||
|
||||
+58
-1
@@ -51,6 +51,7 @@ import org.springblade.thirdparty.bfi.util.BfiUtil;
|
||||
import org.springblade.transport.config.BfiProperties;
|
||||
import org.springblade.transport.constant.KingdeeAttachmentConstant;
|
||||
import org.springblade.transport.constant.KingdeeBfiConstant;
|
||||
import org.springblade.transport.constant.KingdeeLockConstant;
|
||||
import org.springblade.transport.constant.TransportBusiConstant;
|
||||
import org.springblade.transport.mapper.BillLedgerMapper;
|
||||
import org.springblade.transport.mapper.BillLedgerUsageMapper;
|
||||
@@ -82,6 +83,7 @@ import org.springblade.transport.pojo.entity.FormalSettlement;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlementDetail;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlementPayment;
|
||||
import org.springblade.transport.pojo.entity.FormalSettlementSource;
|
||||
import org.springblade.transport.pojo.entity.KingdeeBillLock;
|
||||
import org.springblade.transport.pojo.entity.PaymentApplication;
|
||||
import org.springblade.transport.pojo.entity.PaymentApplicationInvoice;
|
||||
import org.springblade.transport.pojo.entity.PaymentApplicationRecord;
|
||||
@@ -93,6 +95,7 @@ import org.springblade.transport.pojo.entity.TemporaryCreditLimit;
|
||||
import org.springblade.transport.pojo.vo.PaymentApplicationReferenceAmountVO;
|
||||
import org.springblade.transport.pojo.vo.PaymentApplicationVO;
|
||||
import org.springblade.transport.service.IFormalSettlementService;
|
||||
import org.springblade.transport.service.IKingdeeBillLockService;
|
||||
import org.springblade.transport.service.IPaymentApplicationService;
|
||||
import org.springblade.transport.service.KingdeeSyncContext;
|
||||
import org.springblade.transport.support.KingdeeApBillSyncSupport;
|
||||
@@ -155,6 +158,7 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
private final BillLedgerUsageMapper billLedgerUsageMapper;
|
||||
private final TemporaryCreditLimitMapper temporaryCreditLimitMapper;
|
||||
private final IFormalSettlementService formalSettlementService;
|
||||
private final IKingdeeBillLockService kingdeeBillLockService;
|
||||
private final IBfiService bfiService;
|
||||
private final KingdeeApBillSyncSupport kingdeeApBillSyncSupport;
|
||||
private final KingdeeAttachmentSyncSupport kingdeeAttachmentSyncSupport;
|
||||
@@ -193,6 +197,7 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
return vo;
|
||||
});
|
||||
fillAttachmentSyncStatus(KingdeeAttachmentConstant.BIZ_PAY_APPLICATION, voPage.getRecords());
|
||||
fillKingdeeLockStatus(voPage.getRecords());
|
||||
return voPage;
|
||||
}
|
||||
|
||||
@@ -218,10 +223,35 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充金蝶锁状态标识(locked-锁定中/failed-锁定失败;unlocked 终态不返回):
|
||||
* 锁表按本页源单一次批量查询,避免 N+1;locked 时前端可禁用编辑/作废,
|
||||
* failed 时展示失败原因(tryCount 达上限 5 提示重推同步金蝶)
|
||||
*
|
||||
* @param rows 本页 VO 列表
|
||||
*/
|
||||
private void fillKingdeeLockStatus(List<PaymentApplicationVO> rows) {
|
||||
if (Func.isEmpty(rows)) {
|
||||
return;
|
||||
}
|
||||
Map<Long, KingdeeBillLock> lockMap = kingdeeBillLockService.mapActiveLocks(KingdeeLockConstant.SOURCE_PAY_APPLY,
|
||||
rows.stream().map(PaymentApplicationVO::getId).toList());
|
||||
for (PaymentApplicationVO vo : rows) {
|
||||
KingdeeBillLock lockRecord = lockMap.get(vo.getId());
|
||||
if (lockRecord == null) {
|
||||
continue;
|
||||
}
|
||||
vo.setKingdeeLockStatus(lockRecord.getLockStatus());
|
||||
vo.setKingdeeLockFailReason(lockRecord.getFailReason());
|
||||
vo.setKingdeeTryCount(lockRecord.getTryCount());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaymentApplicationVO detail(Long id) {
|
||||
PaymentApplication entity = existing(id);
|
||||
PaymentApplicationVO vo = PaymentApplicationWrapper.build().entityVO(entity);
|
||||
fillKingdeeLockStatus(List.of(vo));
|
||||
vo.setInvoices(invoiceMapper.selectList(Wrappers.<PaymentApplicationInvoice>lambdaQuery()
|
||||
.eq(PaymentApplicationInvoice::getPaymentApplicationId, id).orderByAsc(PaymentApplicationInvoice::getLineNo)));
|
||||
vo.setPaymentRecords(recordMapper.selectList(Wrappers.<org.springblade.transport.pojo.entity.PaymentApplicationRecord>lambdaQuery()
|
||||
@@ -386,6 +416,8 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
public void voidBill(PaymentApplicationStatusRequest request) {
|
||||
PaymentApplication entity = lockedPayment(request.getId());
|
||||
if (!TransportBusiConstant.APPROVED.equals(entity.getApprovalStatus())) throw new ServiceException("仅审批通过的付款申请允许作废");
|
||||
// 金蝶锁定中禁止作废(lockBusiData 已锁单,金蝶侧未解锁前单据不可改动)
|
||||
kingdeeBillLockService.checkEditable(KingdeeLockConstant.SOURCE_PAY_APPLY, request.getId());
|
||||
if (isBillPayment(entity.getPaymentMethod())) releaseBillBalance(entity);
|
||||
entity.setApprovalStatus(TransportBusiConstant.VOIDED);
|
||||
entity.setCurrentNode("已作废");
|
||||
@@ -427,9 +459,34 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
self().markKingdeeSyncFailed(id);
|
||||
throw new ServiceException("推送金蝶付款申请失败:" + exception.getMessage());
|
||||
}
|
||||
// 主单事务提交后锁定金蝶付款申请单(lockBusiData):一张付款申请对一张金蝶付款申请单,接口1对1;
|
||||
// 失败只留 failed 锁记录由补偿任务重锁,不污染主单同步状态;锁定失败摘要拼入返回值,页面直接可见
|
||||
String lockFailSummary = lockKingdeeBillAfterPush(id);
|
||||
// 主单事务提交后联带上传附件(A902):失败只记附件同步状态,不回滚不污染主单同步状态,重推自动补传
|
||||
syncAttachmentsAfterPush(id);
|
||||
return kingdeeBillId;
|
||||
return Func.isBlank(lockFailSummary) ? kingdeeBillId
|
||||
: kingdeeBillId + ";注意:金蝶单据锁定未成功(" + lockFailSummary + "),系统将自动补偿重锁,重推同步金蝶可立即补锁";
|
||||
}
|
||||
|
||||
/**
|
||||
* 金蝶付款申请单锁定(lockBusiData):A103-1/A103-3 推送成功事务提交后调用,
|
||||
* 一张付款申请对一张金蝶付款申请单;锁定异常独立捕获,不影响主单同步结果
|
||||
*
|
||||
* @param id 付款申请id
|
||||
* @return 锁定失败的金蝶单号摘要,全部锁定成功返回 null
|
||||
*/
|
||||
private String lockKingdeeBillAfterPush(Long id) {
|
||||
try {
|
||||
PaymentApplication entity = getById(id);
|
||||
if (entity == null || Func.isBlank(entity.getKingdeeBillNo())) {
|
||||
return null;
|
||||
}
|
||||
return kingdeeBillLockService.lockAfterPush(KingdeeLockConstant.SOURCE_PAY_APPLY, id, entity.getPaymentNo(),
|
||||
KingdeeLockConstant.TARGET_PAY_APPLY, Func.toStrList(entity.getKingdeeBillNo()));
|
||||
} catch (Exception exception) {
|
||||
log.error("付款申请[{}]金蝶单据锁定联带动作异常(锁记录已落库待补偿)", id, exception);
|
||||
return "锁定动作异常,已留档待补偿";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user