diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InvoiceReceiptServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InvoiceReceiptServiceImpl.java index 3b699a6d..3e418c9c 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InvoiceReceiptServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/InvoiceReceiptServiceImpl.java @@ -50,7 +50,7 @@ import org.springblade.thirdparty.bfi.pojo.vo.BfiInvoicePoolVO; import org.springblade.thirdparty.bfi.pojo.vo.BfiPageVO; import org.springblade.thirdparty.bfi.pojo.vo.BfiReceivedInvoiceVO; import org.springblade.thirdparty.bfi.service.IBfiService; -import org.springblade.transport.constant.KingdeeAttachmentConstant; +import org.springblade.transport.constantq.KingdeeAttachmentConstant; import org.springblade.transport.constant.KingdeeBfiConstant; import org.springblade.transport.constant.TransportBusiConstant; import org.springblade.transport.mapper.CustomerArchiveMapper; @@ -1181,7 +1181,8 @@ public class InvoiceReceiptServiceImpl extends BaseServiceImpl 刚 upsert 的镜像 + * @return 刷新结果统计 + */ + private RefreshResult refreshBoundReceipts(int pageNo, Map mirrorMap) { + Map> receiptMap = list(Wrappers.lambdaQuery() + .in(InvoiceReceipt::getInvoiceNo, mirrorMap.keySet()) + .ne(InvoiceReceipt::getApprovalStatus, TransportBusiConstant.VOIDED)).stream() + .filter(receipt -> !Objects.equals(receipt.getIsDeleted(), 1)) + .collect(Collectors.groupingBy(InvoiceReceipt::getInvoiceNo)); + // 镜像有了却没人登记:本页不产生任何刷新,属正常(票池范围大于我方登记范围) + if (receiptMap.isEmpty()) { + return new RefreshResult(0, 0, 0); + } + List changedReceipts = new ArrayList<>(); + List syncRecords = new ArrayList<>(); + int bound = 0; + int unchanged = 0; + for (Map.Entry> entry : receiptMap.entrySet()) { + KingdeeInvoicePool mirror = mirrorMap.get(entry.getKey()); + for (InvoiceReceipt receipt : entry.getValue()) { + // 新架构登记无 kingdeeBillNo/kingdeeStatus 字段(70d5d34 已删),仅绑定关系可变: + // 已绑定且指向同一镜像的登记零写入;未绑定存量登记(罕见,人工数据)顺带补绑 + boolean unbound = receipt.getKingdeeInvoicePoolId() == null + || !Objects.equals(receipt.getKingdeeInvoicePoolId(), mirror.getId()); + if (!unbound) { + unchanged++; + continue; + } + receipt.setKingdeeInvoicePoolId(mirror.getId()); + changedReceipts.add(receipt); + syncRecords.add(this.buildPoolSyncRecord(receipt, "定时绑定金蝶票池发票")); + bound++; + } + } + if (changedReceipts.isEmpty()) { + return new RefreshResult(0, unchanged, 0); + } + try { + // 页级事务批量落库:绑定/状态批量更新 + 同步流水批量写入(JDBC batch,整页原子生效) + Db.updateBatchById(changedReceipts); + if (!syncRecords.isEmpty()) { + Db.saveBatch(syncRecords); + } + log.info("金蝶全票池同步 第{}页落库完成,补绑 {} 条,同步流水 {} 条", + pageNo, changedReceipts.size(), syncRecords.size()); + return new RefreshResult(bound, unchanged, 0); + } catch (Exception batchException) { + // 批量落库失败:整页跳过计入失败,下轮任务幂等重试,不做逐单降级(保持全批量链路) + log.error("金蝶全票池同步登记刷新批量落库异常,第{}页 {} 条跳过待下轮重试", pageNo, changedReceipts.size(), batchException); + return new RefreshResult(0, unchanged, changedReceipts.size()); + } + } + + /** 构建金蝶票池同步流水(操作人以「定时任务」名义记录) */ + private InvoiceReceiptRecord buildPoolSyncRecord(InvoiceReceipt receipt, String reason) { + InvoiceReceiptRecord syncRecord = new InvoiceReceiptRecord(); + syncRecord.setInvoiceReceiptId(receipt.getId()); + syncRecord.setActionType("sync"); + syncRecord.setActionName(reason); + syncRecord.setFromStatus(receipt.getApprovalStatus()); + syncRecord.setToStatus(receipt.getApprovalStatus()); + syncRecord.setOperatorName(AuthUtil.getUserName() == null ? "定时任务" : AuthUtil.getUserName()); + return syncRecord; + } + /** A801-1 按票池更新时间窗口分页拉取(只认正常票,不推单据使用状态,票面可用性由本地过滤) */ private List pullPoolWindowPage(LocalDateTime windowStart, LocalDateTime windowEnd, int pageNo) { BfiInvoicePoolQueryDataDTO data = new BfiInvoicePoolQueryDataDTO();