diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/KingdeeReceivedInvoiceSyncSupport.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/KingdeeReceivedInvoiceSyncSupport.java index 32411e80..f5f43173 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/support/KingdeeReceivedInvoiceSyncSupport.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/support/KingdeeReceivedInvoiceSyncSupport.java @@ -261,8 +261,8 @@ public class KingdeeReceivedInvoiceSyncSupport { /** * 分录组装:逐行取发票明细行(镜像 items_json 反序列化为 {@link BfiInvoicePoolItemVO}),一条明细行一条分录: * 价税合计=明细金额+税额(合计为 0 拦截);数量取 num(≤0/空/不可解析兜底 1);单价取 unitPrice(空按价税合计/数量反算); - * 物料编码与税收分类编码取行商品编码 goodsCode(缺失拦截);税率表编码="V"+整数税率(13/13%/0.13→V13, - * 缺失、0/免税行拦截提示人工);不含税金额/税额取明细金额/税额(空不送);分录标识=发票号码_seq(重推幂等候选键) + * 物料编码取行商品编码 goodsCode(缺失拦截,去尾部 0);不含税金额取明细金额(空不送); + * 税收分类编码/税率表编码/税额不送;分录标识=发票号码_seq(重推幂等候选键) * * @param receipt 收票登记(发票号码,分录标识前缀) * @param mirror 票池镜像(明细行 items_json) @@ -291,7 +291,7 @@ public class KingdeeReceivedInvoiceSyncSupport { throw new ServiceException("推送金蝶收票单失败:发票[" + receipt.getInvoiceNo() + "]分录[" + seq + "]价税合计为 0,无法推送"); } if (Func.isBlank(item.getGoodsCode())) { - throw new ServiceException("推送金蝶收票单失败:发票[" + receipt.getInvoiceNo() + "]分录[" + seq + "]缺少行商品编码,无法确定物料与税收分类编码"); + throw new ServiceException("推送金蝶收票单失败:发票[" + receipt.getInvoiceNo() + "]分录[" + seq + "]缺少行商品编码,无法确定物料编码"); } BfiReceivedInvoiceSaveEntryDTO entry = new BfiReceivedInvoiceSaveEntryDTO(); entry.setEPricetaxtotal(priceTaxTotal); @@ -299,19 +299,13 @@ public class KingdeeReceivedInvoiceSyncSupport { entry.setQuantity(this.mirrorQuantity(item.getNum())); // 【必填】单价:明细行单价(空按价税合计/数量反算;单据头 isincludetax=true,单价仅作参考) entry.setPrice(this.mirrorPrice(item.getUnitPrice(), priceTaxTotal, entry.getQuantity())); - // 【必填】物料编码.编码:行商品编码 - entry.setMaterialNumber(item.getGoodsCode().trim()); - // 税收分类编码.编码:数电票行商品编码即税收分类编码 - entry.setETaxclassNumber(item.getGoodsCode().trim()); - // 【必填】税率表.编码:"V"+整数税率(缺失、0/免税行拦截提示人工) - entry.setTaxrateidNumber(this.taxRateCode(receipt.getInvoiceNo(), seq, item.getTaxRate())); - // 金额(不含税)/税额:明细金额/税额(空不送) + // 【必填】物料编码.编码:行商品编码(金蝶档案不含末尾补零,去掉尾部 0) + String goodsCode = this.stripTrailingZeros(item.getGoodsCode().trim()); + entry.setMaterialNumber(goodsCode); + // 金额(不含税):明细金额(空不送);税收分类编码/税率表编码/税额不送,税额仅参与价税合计 if (detailAmount != null) { entry.setEAmount(kingdeeApBillSyncSupport.money(detailAmount)); } - if (taxAmount != null) { - entry.setETax(kingdeeApBillSyncSupport.money(taxAmount)); - } // 【必填】外部系统来源分录标识(候选键):发票号码_seq,重推同键幂等 entry.setAwrpEntryCode(receipt.getInvoiceNo() + "_" + seq); entries.add(entry); @@ -319,6 +313,12 @@ public class KingdeeReceivedInvoiceSyncSupport { return entries; } + /** 商品编码去尾部 0:金蝶物料编码档案不含末尾补零(如 3010102020100000000→30101020201);全 0 兜底保留原值 */ + private String stripTrailingZeros(String code) { + String stripped = code.replaceAll("0+$", ""); + return stripped.isEmpty() ? code : stripped; + } + /** 镜像明细行反序列化:items_json 解析异常按脏数据拦截(A801-1 原样落库,理论上可解析) */ private List parseMirrorItems(String invoiceNo, String itemsJson) { try { @@ -347,27 +347,6 @@ public class KingdeeReceivedInvoiceSyncSupport { return result.setScale(4, RoundingMode.HALF_UP); } - /** 镜像税率转税率表编码:"V"+整数税率(13/13%/0.13→V13);缺失、零/免税行拦截提示人工 */ - private String taxRateCode(String invoiceNo, String seq, String taxRateText) { - if (Func.isBlank(taxRateText)) { - throw new ServiceException("推送金蝶收票单失败:发票[" + invoiceNo + "]分录[" + seq + "]税率缺失,无法映射税率表,请人工核实"); - } - BigDecimal rate; - try { - rate = new BigDecimal(taxRateText.trim().replace("%", "")); - } catch (NumberFormatException exception) { - throw new ServiceException("推送金蝶收票单失败:发票[" + invoiceNo + "]分录[" + seq + "]税率[" + taxRateText.trim() + "]无法识别,请人工核实"); - } - if (rate.compareTo(BigDecimal.ZERO) <= 0) { - throw new ServiceException("推送金蝶收票单失败:发票[" + invoiceNo + "]分录[" + seq + "]为免税/零税率行,无法映射税率表,请人工核实"); - } - // 小于 1 的小数按比率换算百分比(0.13→13),"1" 按百分比(1%→V1) - if (rate.compareTo(BigDecimal.ONE) < 0) { - rate = rate.multiply(BigDecimal.valueOf(100)); - } - return "V" + rate.stripTrailingZeros().toPlainString(); - } - /** 镜像明细数值解析:空返回 null,不可解析返回 null(数量/单价有兜底,金额空不送) */ private BigDecimal parseMirrorAmountQuietly(String value) { if (Func.isBlank(value)) {