From 34e90301649fbd6329acc8f994cd06cf394cef5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=88=98=E6=B3=89=E4=BD=B3?= <1107186916@qq.com> Date: Mon, 2 Nov 2026 18:38:11 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9F=A5=E7=9C=8B=E9=A1=B5=E9=87=8D?= =?UTF-8?q?=E6=8E=A8=E8=AE=A4=E9=A2=86=E6=94=B6=E7=A5=A8=E5=8D=95=E5=B9=B6?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E5=8C=B9=E9=85=8D=E9=87=91=E9=A2=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pojo/entity/FormalSettlementInvoice.java | 3 + .../FormalSettlementController.java | 7 ++ .../service/IFormalSettlementService.java | 11 +++ .../impl/FormalSettlementServiceImpl.java | 69 +++++++++++++++++++ 4 files changed, 90 insertions(+) diff --git a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/FormalSettlementInvoice.java b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/FormalSettlementInvoice.java index 00069def..9c303407 100644 --- a/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/FormalSettlementInvoice.java +++ b/blade-service-api/blade-transport-api/src/main/java/org/springblade/transport/pojo/entity/FormalSettlementInvoice.java @@ -43,4 +43,7 @@ public class FormalSettlementInvoice extends TenantEntity { @TableField(exist = false) @Schema(description = "收票单金蝶推送状态(unsynced未推送/pushed已保存收票单/assigned已指定应付/failed推送失败),详情回显用") private String kingdeePushStatus; + @TableField(exist = false) + @Schema(description = "收票单金蝶推送失败原因(详情失败行悬浮展示用)") + private String kingdeePushMsg; } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/FormalSettlementController.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/FormalSettlementController.java index af725976..d1e8a9b5 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/FormalSettlementController.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/controller/FormalSettlementController.java @@ -239,6 +239,13 @@ public class FormalSettlementController extends BladeController { return R.data(formalSettlementService.pushInvoiceAssignKingdee(id)); } + @PostMapping("/repush-claimed-invoice") + @ApiOperationSupport(order = 16) + @Operation(summary = "重推认领收票单(查看页入口:收票单A303-2+指定应付A302-6 一步式,failed/pushed 通吃)") + public R repushClaimedInvoice(@RequestParam Long id, @RequestParam String invoiceNo) { + return R.data(formalSettlementService.repushClaimedInvoice(id, invoiceNo)); + } + @PostMapping("/sync-kingdee-ar-result") @ApiOperationSupport(order = 15) @Operation(summary = "手动勾稽金蝶应收单(A302-4 回写纠偏)") 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 54ecb4a3..2b099a26 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 @@ -72,6 +72,17 @@ public interface IFormalSettlementService extends BaseService */ String pushInvoiceAssignKingdee(Long settlementId); + /** + * 重推本单认领的收票登记(查看页「重新推送」入口,failed/pushed 通吃,assigned 拦截): + * 前置付款结算单 + 审批通过 + 财务应付单已同步;先复用收票推送状态机重推金蝶收票单(A303-2, + * A801-3 幂等预检防重复保存),再组装应付单防重键逐单 A302-6 指定应付(幂等) + * + * @param id 正式结算单id + * @param invoiceNo 认领发票号 + * @return 重推结果描述 + */ + String repushClaimedInvoice(Long id, String invoiceNo); + /** * 独立事务落"生成失败"状态并记失败原因(在推送事务回滚、行锁释放后执行,与付款/收票口径统一); * 仅更新审批通过且未同步的单据,未审批/已同步/已删除单据自动跳过,保持原状态 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 cdc92d6f..57d244e0 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 @@ -488,6 +488,7 @@ public class FormalSettlementServiceImpl extends BaseServiceImpllambdaQuery() + .eq(InvoiceReceipt::getInvoiceNo, trimmedInvoiceNo).last("LIMIT 1")); + if (receipt == null || Objects.equals(receipt.getIsDeleted(), 1)) { + throw new ServiceException("收票登记不存在:发票" + trimmedInvoiceNo); + } + // 认领关系校验:该票必须认领在本单名下,防止跨结算单误推 + Long relationCount = invoiceReceiptSettlementMapper.selectCount(Wrappers.lambdaQuery() + .eq(InvoiceReceiptSettlement::getFormalSettlementId, id) + .eq(InvoiceReceiptSettlement::getInvoiceReceiptId, receipt.getId())); + if (relationCount == null || relationCount == 0) { + throw new ServiceException("发票" + trimmedInvoiceNo + "未认领在本结算单名下,不允许重推"); + } + String pushStatus = Func.toStrWithEmpty(receipt.getKingdeePushStatus(), KingdeeBfiConstant.RECEIVED_PUSH_UNSYNCED); + if (KingdeeBfiConstant.RECEIVED_PUSH_ASSIGNED.equals(pushStatus)) { + throw new ServiceException("发票" + trimmedInvoiceNo + "已指定应付,无需重复推送"); + } + // 第一步:复用收票推送状态机重推金蝶收票单(A303-2,A801-3 幂等预检防重复保存,单笔事务独立回滚) + String pushResult = invoiceReceiptService.pushKingdeeReceivedInvoice(List.of(receipt.getId())); + // 第二步:收票单就绪后按应付单防重键 A302-6 指定应付(幂等,已指定的跳过) + List details = detailMapper.selectList(Wrappers.lambdaQuery() + .eq(FormalSettlementDetail::getFormalSettlementId, id) + .eq(FormalSettlementDetail::getIsDeleted, 0) + .orderByAsc(FormalSettlementDetail::getLineNo)); + if (Func.isEmpty(details)) { + throw new ServiceException("推送失败:正式结算单无结算明细,无法组装财务应付单防重键"); + } + String apBillSrcCode = kingdeeApBillSyncSupport.apBillSrcCode(settlement, details); + String assignFailures = invoiceReceiptService.assignClaimedReceipts(id, apBillSrcCode); + // 复读最新状态组装结果:assigned 即成功;收票单仍未推送成功按失败报因;pushed 未指定报因可重试 + InvoiceReceipt latest = invoiceReceiptMapper.selectById(receipt.getId()); + String latestStatus = Func.toStrWithEmpty(latest.getKingdeePushStatus(), KingdeeBfiConstant.RECEIVED_PUSH_UNSYNCED); + if (KingdeeBfiConstant.RECEIVED_PUSH_ASSIGNED.equals(latestStatus)) { + log.info("正式结算单[{}]认领发票[{}]重推完成:已指定应付", settlement.getFormalSettlementNo(), trimmedInvoiceNo); + return "发票" + trimmedInvoiceNo + "重推成功:已指定应付"; + } + if (!KingdeeBfiConstant.RECEIVED_PUSH_PUSHED.equals(latestStatus)) { + throw new ServiceException("发票" + trimmedInvoiceNo + "重推收票单失败:" + pushResult); + } + if (Func.isNotBlank(assignFailures)) { + throw new ServiceException("发票" + trimmedInvoiceNo + "收票单已推送金蝶,指定应付失败:" + assignFailures + + "(已指定的自动跳过,可重试)"); + } + log.info("正式结算单[{}]认领发票[{}]重推完成:收票单已推送金蝶并指定应付", settlement.getFormalSettlementNo(), trimmedInvoiceNo); + return "发票" + trimmedInvoiceNo + "重推成功:已指定应付"; + } + @Override public String syncKingdeeArResult() { return kingdeeSyncLockSupport.runSingleFlight(AR_RESULT_SYNC_LOCK_PREFIX, bfiProperties.getArResult().getLockLeaseSeconds(), @@ -1243,6 +1303,15 @@ public class FormalSettlementServiceImpl extends BaseServiceImpl 0) { + throw new ServiceException("发票" + invoiceNo + "匹配结算单金额不能超过发票金额" + invoiceAmount); + } } // 认领闸门:确认前按票号重查金蝶复核可用性,选中到确认之间票被认领/使用/红冲在此拦截 invoiceReceiptService.assertInvoicesClaimable(invoiceNumbers);