feat: A303-1 开票申请推送特殊票种映射(运费票送E04、其余送00非特殊票种),hsbz统一按不含税口径送0(金蝶联调反馈)

This commit is contained in:
刘泉佳
2026-10-02 00:17:32 +08:00
parent 048bcaf8ad
commit 08d9a87e29
2 changed files with 41 additions and 2 deletions
@@ -25,6 +25,7 @@
*/
package org.springblade.transport.constant;
import java.util.List;
import java.util.Map;
/**
@@ -149,6 +150,15 @@ public final class KingdeeBfiConstant {
/** A303-1 发票种类:数电发票(增值税专用发票)。 */
public static final String BFI_INVOICE_TYPE_DIGITAL_SPECIAL = "08xdp";
/** A303-1 特殊票种:货物运输(运费/货物运输类发票)。 */
public static final String BFI_INVOICE_SPECIAL_TYPE_FREIGHT = "E04";
/** A303-1 特殊票种:非特殊票种(其余费用类发票,如其他、非货物运输的运输类)。 */
public static final String BFI_INVOICE_SPECIAL_TYPE_NONE = "00";
/** A303-1 特殊票种货物运输判定关键字:命中商品名称或商品和服务分类简称即视为货物运输类。 */
public static final List<String> BFI_INVOICE_FREIGHT_KEYWORDS = List.of("货物运输", "运费");
/** 金蝶同步状态:开票完成(A303-5 查到发票,终态,开票申请专用)。 */
public static final String KINGDEE_STATUS_INVOICED = "invoiced";
@@ -778,8 +778,10 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl<InvoiceApplic
param.setShowsalerbank(true);
// 【必填】申请价税合计:本张发票开票金额
param.setTotalamount(sheetAmount);
// 是否含税:数电普票传1(含税),其他传0(不含税)
param.setHsbz("electronic_general".equals(entity.getInvoiceType()) ? "1" : "0");
// 是否含税:金蝶要求统一按不含税口径送(联调反馈),固定 0 不含税
param.setHsbz("0");
// 特殊票种:金蝶要求映射(联调反馈)——本张发票商品行全部为货物运输(运费/货物运输)送 E04,其余(其他、非货物运输的运输类等)送 00 非特殊票种
param.setSpecialtype(this.specialTypeOf(items));
// 【必填】客户.编码:受票方客商档案客商编码
param.setCustomnameidNumber(customer.getCustomerCode());
// 【必填】项目.项目编码(联调期临时传金蝶测试档案值 999)
@@ -864,6 +866,33 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl<InvoiceApplic
return item;
}
/**
* 特殊票种映射(金蝶联调反馈):本张发票商品行全部为货物运输类送 E04(货物运输),其余送 00(非特殊票种)。
* 货物运输类按商品名称/商品和服务分类简称命中关键字({@link KingdeeBfiConstant#BFI_INVOICE_FREIGHT_KEYWORDS})判定;
* 开票端已限制运费不得与其他费用合并同张,此处按全张兜底判定,含非运费行的发票一律按非特殊票种送
*
* @param items 本张发票分录(与 A303-1 报文同源)
* @return 特殊票种编码(E04 货物运输 / 00 非特殊票种)
*/
private String specialTypeOf(List<BfiInvoiceApplySaveEntryDTO> items) {
boolean allFreight = items.stream()
.allMatch(item -> this.isFreightGoods(item.getGoodsname(), item.getGoodssimplename()));
return allFreight ? KingdeeBfiConstant.BFI_INVOICE_SPECIAL_TYPE_FREIGHT : KingdeeBfiConstant.BFI_INVOICE_SPECIAL_TYPE_NONE;
}
/**
* 商品行是否货物运输类:商品名称或商品和服务分类简称含关键字(运费/货物运输)即视为命中;
* 其他费用及非货物运输的运输类(如按简称“运输”维护的开票项目)不命中,随全张送非特殊票种 00
*
* @param goodsname 商品名称(开票项目简称,如 运费)
* @param goodssimplename 商品和服务分类简称(开票项目分类名)
* @return true 表示货物运输类
*/
private boolean isFreightGoods(String goodsname, String goodssimplename) {
String goodsText = Func.toStr(goodsname).trim() + Func.toStr(goodssimplename).trim();
return KingdeeBfiConstant.BFI_INVOICE_FREIGHT_KEYWORDS.stream().anyMatch(goodsText::contains);
}
@Override
public String syncKingdeeInvoiceResult() {
return kingdeeSyncLockSupport.runSingleFlight(INVOICE_RESULT_SYNC_LOCK_PREFIX, invoiceResultLockLeaseSeconds,