feat: 客商档案新增供应商编码字段并落库金蝶A901-1编码

This commit is contained in:
刘泉佳
2026-10-30 20:34:25 +08:00
parent 912a15e0ad
commit 0e1517df9c
9 changed files with 85 additions and 43 deletions
@@ -52,6 +52,9 @@ public class CustomerArchive extends TenantEntity {
@Schema(description = "客商编号")
private String customerCode;
@Schema(description = "供应商编码(金蝶A901-1供应商查询返回number,建档/同步时落库)")
private String supplierCode;
@Schema(description = "客商简称")
private String shortName;
@@ -51,6 +51,9 @@ public class CustomerArchiveExcel implements Serializable {
@ExcelProperty("客商编号")
private String customerCode;
@ExcelProperty("供应商编码")
private String supplierCode;
@ExcelProperty("客商简称")
private String shortName;
@@ -47,12 +47,14 @@ import org.springblade.transport.constant.HcsSyncConstant;
import org.springblade.transport.excel.CustomerArchiveExcel;
import org.springblade.thirdparty.bfi.constant.BfiConstant;
import org.springblade.thirdparty.bfi.pojo.dto.BfiCustomerQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiSupplierQueryDTO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiBillSaveResultErrorVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiBillSaveResultItemVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiBillSaveResultVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiBlacklistVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiCustomerVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiPageVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiSupplierVO;
import org.springblade.thirdparty.bfi.service.IBfiService;
import org.springblade.thirdparty.bfi.util.BfiUtil;
import org.springblade.system.cache.SysCache;
@@ -282,6 +284,12 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
if (created) {
// 新增时金蝶已有客商,前端回填金蝶客商编码,建档直接沿用;未回填则自动生成
customer.setCustomerCode(Func.isEmpty(customer.getCustomerCode()) ? this.nextCustomerCode() : customer.getCustomerCode());
// 供应商编码:A901-1 按统一社会信用代码查金蝶供应商档案落库(金蝶单据推送直接复用,不再实时查接口),查不到留空待同步补
String supplierCode = this.queryKingdeeSupplierNumber(customer.getUnifiedCreditCode());
if (Func.isNotEmpty(supplierCode)) {
customer.setSupplierCode(supplierCode);
}
log.info("新增客商A901-1供应商查询取供应商编码,unifiedCreditCode={},supplierCode={}", customer.getUnifiedCreditCode(), supplierCode);
}
CustomerArchive entity = Objects.requireNonNull(BeanUtil.copyProperties(customer, CustomerArchive.class));
// 曾审核通过后的评分替换:保存/再提交时仍沿用原生效等级与额度,待再次审核通过后再切换
@@ -523,9 +531,10 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
after.setKingdeeSyncTime(LocalDateTime.now());
BfiCustomerVO kingdeeCustomer = queryKingdeeCustomer(customer.getUnifiedCreditCode());
if (kingdeeCustomer != null && BfiConstant.BILL_STATUS_AUDITED.equals(kingdeeCustomer.getStatus())) {
// 金蝶已有已审核档案:跳过推送,客商编号采纳金蝶客商编码
// 金蝶已有已审核档案:跳过推送,客商编号采纳金蝶客商编码;供应商编码按 A901-1 供应商查询落库
after.setKingdeeStatus(KINGDEE_STATUS_EXIST);
after.setKingdeeFailReason(null);
this.fillSupplierCode(customer, after);
addChangeRecord(id, "金蝶已存在该客商档案,跳过推送" + this.adoptKingdeeCode(customer, after, kingdeeCustomer.getNumber()), customer, after);
updateById(after);
return after;
@@ -625,6 +634,39 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
return rows == null || rows.isEmpty() ? null : rows.get(0);
}
/**
* A901-1 按统一社会信用代码查询金蝶供应商档案取金蝶客商编码(返回值 number),新增/同步建档时落库客商表,
* 后续金蝶推送直接复用客商表编号不再实时查接口;接口异常返回 null 不阻断建档,金蝶无档案同样返回 null 由调用方兜底
*/
private String queryKingdeeSupplierNumber(String unifiedCreditCode) {
if (Func.isEmpty(unifiedCreditCode)) {
return null;
}
try {
BfiSupplierQueryDTO param = new BfiSupplierQueryDTO();
param.setPageNo(1);
param.setPageSize(1);
param.setEnable(BfiConstant.ENABLE_ENABLED);
param.setSocietycreditcode(List.of(unifiedCreditCode.trim()));
BfiPageVO<BfiSupplierVO> page = bfiService.querySupplier(param);
List<BfiSupplierVO> rows = page == null ? null : page.getRows();
return rows == null || rows.isEmpty() ? null : rows.get(0).getNumber();
} catch (Exception exception) {
log.warn("A901-1供应商查询金蝶客商编码失败,unifiedCreditCode={}", unifiedCreditCode, exception);
return null;
}
}
/**
* 供应商编码落库:A901-1 按统一社会信用代码查金蝶供应商档案取 number,查到才覆盖(查不到/接口异常保留原值,不影响同步主流程)
*/
private void fillSupplierCode(CustomerArchive customer, CustomerArchive after) {
String supplierCode = this.queryKingdeeSupplierNumber(customer.getUnifiedCreditCode());
if (Func.isNotEmpty(supplierCode)) {
after.setSupplierCode(supplierCode);
}
}
/**
* 金蝶已存在档案时,客商编号(customer_code)采纳金蝶客商编码,后续业务接口沿用客商编号即拿到金蝶编码;
* 金蝶编码为空或与当前编号一致时无需处理;同租户下已被其他客商占用时跳过回填,避免违反 uk_customer_archive_code 唯一约束
@@ -772,10 +814,11 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
CustomerArchive after = copyCustomer(customer);
after.setKingdeeSyncTime(LocalDateTime.now());
if (BfiConstant.BILL_STATUS_AUDITED.equals(kingdeeCustomer.getStatus())) {
// 金蝶已存在已审核档案:跳过推送直接建档,客商编号采纳金蝶客商编码
// 金蝶已存在已审核档案:跳过推送直接建档,客商编号采纳金蝶客商编码;供应商编码按 A901-1 供应商查询落库
after.setKingdeeStatus(KINGDEE_STATUS_EXIST);
after.setKingdeeFailReason(null);
existed++;
this.fillSupplierCode(customer, after);
collectChangeRecord(changeRecords, customer.getId(), "金蝶已存在该客商档案,跳过推送" + this.adoptKingdeeCode(customer, after, kingdeeCustomer.getNumber()), customer, after);
} else {
// 金蝶侧暂存/已提交:审核中,置失败待重推
@@ -2226,6 +2269,7 @@ public class CustomerArchiveServiceImpl extends BaseServiceImpl<CustomerArchiveM
private CustomerArchiveExcel buildExcel(CustomerArchive customer) {
CustomerArchiveExcel excel = new CustomerArchiveExcel();
excel.setCustomerCode(customer.getCustomerCode());
excel.setSupplierCode(customer.getSupplierCode());
excel.setShortName(customer.getShortName());
excel.setFullName(customer.getFullName());
excel.setCustomerKind(customerKindName(customer.getCustomerKind()));
@@ -838,13 +838,8 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl<InvoiceApplic
String kingdeeOrgNumber = kingdeeApBillSyncSupport.kingdeeOrgNumber(entity.getProjectId(), kingdeeContext);
String kingdeeDeptNumber = kingdeeApBillSyncSupport.kingdeeDeptNumber(entity.getProjectId(), kingdeeContext);
CustomerArchive customer = entity.getReceiverCustomerId() == null ? null : customerArchiveMapper.selectById(entity.getReceiverCustomerId());
if (customer == null || Func.isBlank(customer.getUnifiedCreditCode())) {
throw new ServiceException("推送金蝶开票申请失败:受票方客户未在客商档案中维护统一社会信用代码,请补充后重试");
}
// 金蝶客商编码:受票方统一社会信用代码 → A901-1 供应商查询取返回值 number
String receiverNumber = kingdeeApBillSyncSupport.queryKingdeeSupplierNumber(customer.getUnifiedCreditCode().trim());
if (Func.isBlank(receiverNumber)) {
throw new ServiceException("推送金蝶开票申请失败:受票方客户[" + customer.getFullName() + "]金蝶侧未查到对应供应商档案,请补充后重试");
if (customer == null || (Func.isBlank(customer.getSupplierCode()) && Func.isBlank(customer.getCustomerCode()))) {
throw new ServiceException("推送金蝶开票申请失败:受票方客户未在客商档案中维护供应商编码或客商编码,请补充后重试");
}
// 逐张发票推送金蝶开票申请单:每张发票张次一张(价税合计=本张金额,分录=本张商品行),已存在的张次幂等跳过
List<String> savedBillNos = new ArrayList<>();
@@ -872,7 +867,7 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl<InvoiceApplic
+ "]无商品行,无法组装分录");
}
BfiInvoiceApplySaveDTO param = this.buildInvoiceApplyParam(entity, sheetBillNo, seller, salerAddr, salerBank,
kingdeeDeptNumber, kingdeeOrgNumber, receiverNumber, firstArSrcCode, money(sheet.getInvoiceAmount()), items);
kingdeeDeptNumber, kingdeeOrgNumber, customer, firstArSrcCode, money(sheet.getInvoiceAmount()), items);
log.info("金蝶开票申请推送:开票申请[{}]发票张[{}],billno=[{}],价税合计=[{}],分录{}条",
entity.getApplicationNo(), sheet.getSheetNo(), sheetBillNo, sheet.getInvoiceAmount(), items.size());
BfiBillSaveResultVO saveResult = bfiService.saveInvoiceApply(param);
@@ -925,7 +920,7 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl<InvoiceApplic
* @param firstArSrcCode 上游来源单据号:首张关联结算单的金蝶应收单防重键 awrp_src_code(多张结算单取第一张)
*/
private BfiInvoiceApplySaveDTO buildInvoiceApplyParam(InvoiceApplication entity, String billNo,
CustomerArchive seller, String salerAddr, String salerBank, String deptNumber, String orgNumber, String receiverNumber,
CustomerArchive seller, String salerAddr, String salerBank, String deptNumber, String orgNumber, CustomerArchive customer,
String firstArSrcCode, BigDecimal sheetAmount, List<BfiInvoiceApplySaveEntryDTO> items) {
BfiInvoiceApplySaveDTO param = new BfiInvoiceApplySaveDTO();
// ==================== 以下为【必填】字段(BfiInvoiceApplySaveDTO 标注),非必填字段先注释保留 ====================
@@ -985,8 +980,8 @@ public class InvoiceApplicationServiceImpl extends BaseServiceImpl<InvoiceApplic
entity.getApplicationNo());
}
}
// 【必填】客户.编码:受票方统一社会信用代码经 A901-1 供应商查询取金蝶客商编码
param.setCustomnameidNumber(receiverNumber);
// 【必填】客户.编码:受票方客商档案供应商编码(A901-1 金蝶编码),未维护时兜底客商编号
param.setCustomnameidNumber(Func.isBlank(customer.getSupplierCode()) ? customer.getCustomerCode() : customer.getSupplierCode());
// 【必填】项目.项目编码(联调期临时传金蝶测试档案值 999)
param.setAwrpProjectNumber(KingdeeBfiConstant.BFI_PROJECT_NUMBER_NONE);
// ==================== 以下为非必填字段,先注释保留,联调确认后按需放开 ====================
@@ -1347,7 +1347,7 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
entry.setEPaymenttypeNumber(TransportBusiConstant.PAYMENT_TYPE_SETTLEMENT.equals(entity.getPaymentType()) ? KingdeeBfiConstant.BFI_PAYMENT_TYPE_FORMAL : KingdeeBfiConstant.BFI_PAYMENT_TYPE_PREPAY);
// 【必填】往来类型
entry.setEAsstacttype(kingdeeApBillSyncSupport.bfiAsstactType(contract));
// 【必填】往来户.编码:合同乙方统一社会信用代码经 A901-1 供应商查询取金蝶客商编码
// 【必填】往来户.编码:合同乙方关联客商档案客商编码
entry.setEAsstactNumber(kingdeeApBillSyncSupport.bfiAsstactNumber(contract, context));
// 【必填】往来账户:乙方(收款方)银行账号
entry.setEAssacct(entity.getBankAccount());
@@ -36,16 +36,12 @@ import org.springblade.system.cache.SysCache;
import org.springblade.system.feign.ISysClient;
import org.springblade.system.pojo.entity.Dept;
import org.springblade.system.pojo.entity.FeeItem;
import org.springblade.thirdparty.bfi.constant.BfiConstant;
import org.springblade.thirdparty.bfi.pojo.dto.BfiApBillQueryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiApBillSaveDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiApBillSaveEntryDTO;
import org.springblade.thirdparty.bfi.pojo.dto.BfiSupplierQueryDTO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiApBillVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiBillSaveResultItemVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiBillSaveResultVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiPageVO;
import org.springblade.thirdparty.bfi.pojo.vo.BfiSupplierVO;
import org.springblade.thirdparty.bfi.service.IBfiService;
import org.springblade.thirdparty.bfi.util.BfiUtil;
import org.springblade.transport.config.BfiProperties;
@@ -1047,45 +1043,31 @@ public class KingdeeApBillSyncSupport {
? KingdeeBfiConstant.BFI_CUSTOMER_ASSTACT_TYPE : KingdeeBfiConstant.BFI_SUPPLIER_ASSTACT_TYPE;*/
}
/** 财务应付单往来户.编码:合同乙方关联客商档案取统一社会信用代码,经 A901-1 供应商查询取金蝶客商编码,任一环节缺失时拦截 */
/** 财务应付单往来户.编码:合同乙方关联客商档案取供应商编码/客商编码,均未维护时拦截 */
public String bfiAsstactNumber(ContractManage contract, KingdeeSyncContext context) {
if (Func.isBlank(contract.getPartyB())) {
throw new ServiceException("推送金蝶财务应付单失败,合同乙方不能为空,请检查合同[" + Func.toStr(contract.getContractNo()) + "]乙方信息");
}
// 批量同步时按乙方名称缓存金蝶客商编码(同批同一乙方只查一次),单笔同步退化为直接查询
// 批量同步时按乙方名称缓存客商编码(同批同一乙方只查一次),单笔同步退化为直接查询
String customerCode = context.customerCodeCache().computeIfAbsent(contract.getPartyB(), this::queryCustomerCode);
if (Func.isBlank(customerCode)) {
throw new ServiceException("推送金蝶财务应付单失败,合同乙方[" + contract.getPartyB()
+ "]未在客商档案中维护统一社会信用代码或金蝶侧未查到对应供应商档案,请补充后重试");
throw new ServiceException("推送金蝶财务应付单失败,合同乙方[" + contract.getPartyB() + "]未在客商档案中维护供应商编码或客商编码,请补充后重试");
}
return customerCode;
}
/**
* 按乙方名称(全称或简称)查客商档案取统一社会信用代码,再经 A901-1 供应商查询取金蝶客商编码(返回值 number),
* 任一环节缺失返回 null(应收单同步组件复用:按结算单付款方查询)
* 按乙方名称(全称或简称)查询金蝶往来户编码:优先供应商编码(A901-1 金蝶编码建档/同步时落库),
* 未维护时兜底客商编号(A902-2 推送创建的金蝶档案编码即客商编号),均未维护返回 null(应收单同步组件复用:按结算单付款方查询)
*/
public String queryCustomerCode(String partyB) {
CustomerArchive customer = customerArchiveMapper.selectOne(Wrappers.<CustomerArchive>lambdaQuery()
.and(wrapper -> wrapper.eq(CustomerArchive::getFullName, partyB).or().eq(CustomerArchive::getShortName, partyB))
.eq(CustomerArchive::getIsDeleted, 0).last("limit 1"));
if (customer == null || Func.isBlank(customer.getUnifiedCreditCode())) {
if (customer == null) {
return null;
}
return this.queryKingdeeSupplierNumber(customer.getUnifiedCreditCode().trim());
}
/** A901-1 按统一社会信用代码查询金蝶供应商档案,仅取已审核且可用的档案,返回值 number 即金蝶客商编码,无数据返回 null(开票申请受票方复用) */
public String queryKingdeeSupplierNumber(String unifiedCreditCode) {
BfiSupplierQueryDTO param = new BfiSupplierQueryDTO();
param.setPageNo(1);
param.setPageSize(1);
// param.setStatus(BfiConstant.BILL_STATUS_AUDITED);
param.setEnable(BfiConstant.ENABLE_ENABLED);
param.setSocietycreditcode(List.of(unifiedCreditCode));
BfiPageVO<BfiSupplierVO> page = bfiService.querySupplier(param);
List<BfiSupplierVO> rows = page == null ? null : page.getRows();
return rows == null || rows.isEmpty() ? null : rows.get(0).getNumber();
return Func.isBlank(customer.getSupplierCode()) ? customer.getCustomerCode() : customer.getSupplierCode();
}
/**
@@ -202,15 +202,14 @@ public class KingdeeArBillSyncSupport {
String currency = kingdeeApBillSyncSupport.bfiCurrency(contract);
// 单据日期:yyyy-MM-dd HH:mm:ss(各接口统一格式),以同步当日作为应收单据日期
String billDateText = kingdeeApBillSyncSupport.bfiDateTimeText(LocalDate.now());
// 往来户.编码:应收结算单付款方(客户)关联客商档案取统一社会信用代码,经 A901-1 供应商查询取金蝶客商编码
// 往来户.编码:应收结算单付款方(客户)关联客商档案客商编码
String payerName = settlement.getPayerName();
if (Func.isBlank(payerName)) {
throw new ServiceException("推送金蝶财务应收单失败,结算单付款方不能为空,请检查正式结算单[" + Func.toStr(subject) + "]付款方信息");
}
String customerCode = context.customerCodeCache().computeIfAbsent(payerName.trim(), kingdeeApBillSyncSupport::queryCustomerCode);
if (Func.isBlank(customerCode)) {
throw new ServiceException("推送金蝶财务应收单失败,结算单付款方[" + payerName
+ "]未在客商档案中维护统一社会信用代码或金蝶侧未查到对应供应商档案,请补充后重试");
throw new ServiceException("推送金蝶财务应收单失败,结算单付款方[" + payerName + "]未在客商档案中维护客商编码,请补充后重试");
}
BfiArBillSaveDTO param = new BfiArBillSaveDTO();
// 【必填】单据类型.编码
@@ -189,7 +189,7 @@ public class KingdeeReceivedInvoiceSyncSupport {
param.setOrgNumber(kingdeeApBillSyncSupport.bfiOrgNumber(contract, context));
// 【必填】结算币别:合同结算币种
param.setCurrencyNumber(kingdeeApBillSyncSupport.bfiCurrency(contract));
// 【必填】往来户.编码:合同乙方(开票供应商)统一社会信用代码经 A901-1 供应商查询取金蝶客商编码
// 【必填】往来户.编码:合同乙方(开票供应商)客商编码
param.setReceivablessuppNumber(kingdeeApBillSyncSupport.bfiAsstactNumber(contract, context));
// 【必填】汇率表.编码
param.setExratetableNumber(BfiConstant.EXRATE_TABLE_DEFAULT);
@@ -0,0 +1,16 @@
-- 客商档案:新增供应商编码字段
-- 新增 supplier_code:金蝶A901-1供应商查询返回number,新增/同步客商时落库,金蝶单据推送直接复用,不再实时查接口
-- 以下结构升级支持重复执行
SET @ddl_sql = (
SELECT IF(COUNT(*) = 0,
'ALTER TABLE `blade_customer_archive` ADD COLUMN `supplier_code` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT ''供应商编码(金蝶A901-1供应商查询返回number)'' AFTER `customer_code`',
'SELECT 1')
FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'blade_customer_archive'
AND COLUMN_NAME = 'supplier_code'
);
PREPARE ddl_stmt FROM @ddl_sql;
EXECUTE ddl_stmt;
DEALLOCATE PREPARE ddl_stmt;