✨ 付款管理正式结算付款同步金蝶改为财务应付单保存+应付下推付款申请
This commit is contained in:
+183
-21
@@ -30,10 +30,15 @@ import org.springblade.core.secure.utils.AuthUtil;
|
||||
import org.springblade.core.tool.jackson.JsonUtil;
|
||||
import org.springblade.core.tool.utils.BeanUtil;
|
||||
import org.springblade.core.tool.utils.Func;
|
||||
import org.springblade.transport.constant.KingdeeBfiConstant;
|
||||
import org.springblade.system.cache.DictBizCache;
|
||||
import org.springblade.system.cache.SysCache;
|
||||
import org.springblade.system.pojo.entity.DictBiz;
|
||||
import org.springblade.system.pojo.entity.Dept;
|
||||
import org.springblade.thirdparty.bfi.pojo.dto.BfiApBillSaveDTO;
|
||||
import org.springblade.thirdparty.bfi.pojo.dto.BfiApBillSaveEntryDTO;
|
||||
import org.springblade.thirdparty.bfi.pojo.dto.BfiPayApplyPushDTO;
|
||||
import org.springblade.thirdparty.bfi.pojo.dto.BfiPayApplyPushEntryDTO;
|
||||
import org.springblade.thirdparty.bfi.pojo.dto.BfiPayApplySaveDTO;
|
||||
import org.springblade.thirdparty.bfi.pojo.dto.BfiPayApplySaveEntryDTO;
|
||||
import org.springblade.thirdparty.bfi.pojo.vo.BfiBillSaveResultItemVO;
|
||||
@@ -103,11 +108,6 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
private static final String APPROVED = "approved";
|
||||
private static final String RETURNED = "returned";
|
||||
private static final String VOIDED = "voided";
|
||||
private static final String BFI_SUPPLIER_ASSTACT_TYPE = "bd_supplier";
|
||||
private static final String BFI_CONTRACT_SRC_BT = "awrp_contract_info";
|
||||
private static final String BFI_PROJECT_NUMBER_NONE = "999";
|
||||
private static final String BFI_PAYMENT_TYPE_FORMAL = "201";
|
||||
private static final String BFI_PAYMENT_TYPE_PREPAY = "202";
|
||||
private final PaymentApplicationInvoiceMapper invoiceMapper;
|
||||
private final PaymentApplicationRecordMapper recordMapper;
|
||||
private final PaymentApplicationSettlementMapper settlementRelationMapper;
|
||||
@@ -333,7 +333,17 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
if ("synced".equals(entity.getKingdeeStatus())) return entity.getKingdeeBillNo();
|
||||
String kingdeeBillId;
|
||||
try {
|
||||
kingdeeBillId = pushBfiPayApply(entity);
|
||||
if ("settlement_payment".equals(entity.getPaymentType())) {
|
||||
// 单据类型路由:按正式结算单结算类型——应付对应财务应付单(A102-2),应收对应财务应收单(A302-2,推送规则待业务确认)
|
||||
requirePayableSettlement(entity);
|
||||
// 正式结算付款:先推财务应付单(A102-2,仅校验保存成功,应付单id不落库,
|
||||
// 后续如需可经 A102-4 按 awrp_src_sys + awrp_src_code 查询),再由应付下推付款申请(A103-1)
|
||||
pushBfiApBill(entity);
|
||||
kingdeeBillId = pushBfiPayApplyPush(entity);
|
||||
} else {
|
||||
// 预付款:直接推付款申请单(A103-3),不绑应付单
|
||||
kingdeeBillId = pushBfiPayApply(entity);
|
||||
}
|
||||
} catch (ServiceException exception) {
|
||||
markSyncFailed(entity);
|
||||
throw exception;
|
||||
@@ -370,7 +380,7 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送金蝶付款申请单(A103-3 付款申请保存),返回金蝶单据id
|
||||
* 推送金蝶付款申请单(A103-3 付款申请保存,预付款路径),返回金蝶单据id
|
||||
*
|
||||
* @param entity 付款申请实体
|
||||
* @return 金蝶付款申请单id
|
||||
@@ -399,15 +409,15 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
param.setAwrpTextfield1(bfiPaymentMethodLabel(entity.getPaymentMethod()));
|
||||
|
||||
// 来源单据
|
||||
param.setAwrpSrcBt(BFI_CONTRACT_SRC_BT);
|
||||
param.setAwrpSrcBt(KingdeeBfiConstant.BFI_CONTRACT_SRC_BT);
|
||||
// 有上游合同才传 awrpSrcConNo
|
||||
// if (entity.getContractId() != null) {
|
||||
// param.setAwrpSrcConNo(entity.getContractNo());
|
||||
// }
|
||||
|
||||
BfiPayApplySaveEntryDTO entry = new BfiPayApplySaveEntryDTO();
|
||||
entry.setEPaymenttypeNumber("settlement_payment".equals(entity.getPaymentType()) ? BFI_PAYMENT_TYPE_FORMAL : BFI_PAYMENT_TYPE_PREPAY);
|
||||
entry.setEAsstacttype(BFI_SUPPLIER_ASSTACT_TYPE);
|
||||
entry.setEPaymenttypeNumber("settlement_payment".equals(entity.getPaymentType()) ? KingdeeBfiConstant.BFI_PAYMENT_TYPE_FORMAL : KingdeeBfiConstant.BFI_PAYMENT_TYPE_PREPAY);
|
||||
entry.setEAsstacttype(KingdeeBfiConstant.BFI_SUPPLIER_ASSTACT_TYPE);
|
||||
// 供应商编码
|
||||
entry.setEAsstactNumber(bfiSupplierCode(entity));
|
||||
entry.setEAssacct(entity.getBankAccount());
|
||||
@@ -423,17 +433,169 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
param.setEntry(List.of(entry));
|
||||
|
||||
BfiBillSaveResultVO saveResult = bfiService.savePrePayApply(param);
|
||||
// BfiBillSaveResultVO saveResult = null;
|
||||
if (saveResult == null || Func.isEmpty(saveResult.getResult())) {
|
||||
throw new ServiceException("推送金蝶付款申请失败,金蝶未返回单据结果");
|
||||
}
|
||||
return requireBfiBillId(saveResult, "推送金蝶付款申请");
|
||||
}
|
||||
|
||||
BfiBillSaveResultItemVO item = saveResult.getResult().get(0);
|
||||
if (!Boolean.TRUE.equals(item.getBillStatus()) || item.getId() == null) {
|
||||
String errorText = Func.isEmpty(item.getErrors()) ? "未知错误" : String.join(";", item.getErrors());
|
||||
throw new ServiceException("推送金蝶付款申请失败:" + errorText);
|
||||
/**
|
||||
* 校验正式结算付款对应的结算单结算类型:应付(财务应付单 A102-2)直接放行,
|
||||
* 应收(对应财务应收单 A302-2)推送规则待业务确认,暂拦截报错。
|
||||
*
|
||||
* @param entity 付款申请实体
|
||||
*/
|
||||
private void requirePayableSettlement(PaymentApplication entity) {
|
||||
if (entity.getSettlementId() == null) {
|
||||
// 聚合多结算单场景暂按应付处理,TODO 待业务确认后细化
|
||||
return;
|
||||
}
|
||||
return String.valueOf(item.getId());
|
||||
FormalSettlement settlement = formalSettlementMapper.selectById(entity.getSettlementId());
|
||||
if (settlement != null && "receivable".equals(settlement.getSettlementType())) {
|
||||
throw new ServiceException("推送金蝶失败:结算单[" + entity.getSettlementNo() + "]结算类型为应收,对应财务应收单(A302-2),推送规则待业务确认后启用");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送金蝶财务应付单(A102-2 财务应付单保存,正式结算付款第一步),仅校验保存成功
|
||||
*
|
||||
* @param entity 付款申请实体
|
||||
*/
|
||||
private void pushBfiApBill(PaymentApplication entity) {
|
||||
if (Func.isBlank(KingdeeBfiConstant.BFI_AP_BILL_MATERIAL)) {
|
||||
throw new ServiceException("推送金蝶财务应付单失败:明细物料编码待金蝶侧确认后补充(常量 KingdeeBfiConstant.BFI_AP_BILL_MATERIAL)");
|
||||
}
|
||||
if (Func.isBlank(KingdeeBfiConstant.BFI_AP_BILL_MEASURE_UNIT)) {
|
||||
throw new ServiceException("推送金蝶财务应付单失败:明细计量单位待金蝶侧确认后补充(常量 KingdeeBfiConstant.BFI_AP_BILL_MEASURE_UNIT)");
|
||||
}
|
||||
ContractManage contract = requireContract(entity);
|
||||
// 单据类型按映射字典转换:默认服务采购应付,金蝶确认其他类型后修改 BFI_AP_BILL_BILLTYPE_NAME 即可
|
||||
String billtypeNumber = KingdeeBfiConstant.billtypeBy(KingdeeBfiConstant.AP_BILL_BILLTYPE_MAP, KingdeeBfiConstant.BFI_AP_BILL_BILLTYPE_NAME);
|
||||
if (Func.isBlank(billtypeNumber)) {
|
||||
throw new ServiceException("推送金蝶财务应付单失败:单据类型[" + KingdeeBfiConstant.BFI_AP_BILL_BILLTYPE_NAME + "]未在映射字典中维护");
|
||||
}
|
||||
String orgNumber = bfiOrgNumber(contract);
|
||||
// 币种取合同结算币种
|
||||
String currency = bfiCurrency(contract);
|
||||
// TODO 待确认:日期格式沿用现有 A103-3 的 yyyyMMdd,若金蝶校验要求 yyyy-MM-dd 再统一调整
|
||||
String billDateText = (entity.getApplyDate() == null ? LocalDate.now() : entity.getApplyDate()).format(DateTimeFormatter.BASIC_ISO_DATE);
|
||||
BigDecimal applyAmount = money(entity.getAppliedAmount()).setScale(2, RoundingMode.HALF_UP);
|
||||
BfiApBillSaveDTO param = new BfiApBillSaveDTO();
|
||||
param.setBilltypeidNumber(billtypeNumber);
|
||||
param.setOrgNumber(orgNumber);
|
||||
param.setBizdate(billDateText);
|
||||
param.setAsstacttype(KingdeeBfiConstant.BFI_SUPPLIER_ASSTACT_TYPE);
|
||||
param.setAsstactNumber(bfiSupplierCode(entity));
|
||||
param.setPurmode(KingdeeBfiConstant.BFI_AP_BILL_PUR_MODE);
|
||||
param.setCurrencyNumber(currency);
|
||||
param.setPayorgNumber(orgNumber);
|
||||
param.setPurorgNumber(orgNumber);
|
||||
param.setPaypropertyNumber(KingdeeBfiConstant.BFI_AP_BILL_PAY_PROPERTY);
|
||||
// TODO 待确认:结算方式编码(settlementtype_number)与税率编码(taxrateid_number)需金蝶侧确认后补充,当前不传
|
||||
param.setIsincludetax(true);
|
||||
param.setIspricetotal(true);
|
||||
param.setExratetableNumber(bfiPayApplyExratetable);
|
||||
param.setExratedate(billDateText);
|
||||
param.setAsstactname(entity.getPayeeName());
|
||||
param.setRemark(entity.getPaymentNo() + (Func.isEmpty(entity.getSettlementNo()) ? "" : " " + entity.getSettlementNo()));
|
||||
param.setAwrpSrcSys(bfiPayApplySrcSys);
|
||||
param.setAwrpSrcCode(entity.getPaymentNo());
|
||||
param.setAwrpSrcBt(KingdeeBfiConstant.BFI_CONTRACT_SRC_BT);
|
||||
if (Func.isNotEmpty(entity.getContractNo())) {
|
||||
param.setAwrpSrcConNo(entity.getContractNo());
|
||||
}
|
||||
param.setAwrpSrcType(KingdeeBfiConstant.BFI_AP_BILL_SRC_TYPE);
|
||||
|
||||
BfiApBillSaveEntryDTO entry = new BfiApBillSaveEntryDTO();
|
||||
entry.setMaterialNumber(KingdeeBfiConstant.BFI_AP_BILL_MATERIAL);
|
||||
entry.setMeasureunitNumber(KingdeeBfiConstant.BFI_AP_BILL_MEASURE_UNIT);
|
||||
// 无吨位数据:数量固定 1,配合 ispricetotal=true 录入总价(含税应付金额)
|
||||
entry.setQuantity(BigDecimal.ONE);
|
||||
entry.setEPricetaxtotal(applyAmount);
|
||||
entry.setProjectNumber(bfiProjectNumber(entity));
|
||||
// 应付单分录唯一标识,A103-1 下推时以 awrp_finapbill_entryid 关联此行
|
||||
entry.setAwrpEntryCode(entity.getPaymentNo() + "-1");
|
||||
entry.setERemark(entity.getRemark());
|
||||
param.setDetailentry(List.of(entry));
|
||||
|
||||
// 付款计划 planentity 不传,由金蝶按明细自动汇总生成
|
||||
// TODO 待业务确认:存在预付款抵扣时是否需传预付信息 preentry(y_billtype/y_billid/y_settleamt),本期不传、后续迭代
|
||||
|
||||
BfiBillSaveResultVO saveResult = bfiService.saveApBill(param);
|
||||
// 应付单id不落库,后续如需可经 A102-4 按防重键(awrp_src_sys + awrp_src_code)查询
|
||||
requireBfiSaveSuccess(saveResult, "推送金蝶财务应付单");
|
||||
}
|
||||
|
||||
/**
|
||||
* 推送金蝶付款申请(A103-1 应付下推付款申请,正式结算付款第二步),返回星瀚付款申请单id
|
||||
*
|
||||
* @param entity 付款申请实体
|
||||
* @return 星瀚付款申请单id
|
||||
*/
|
||||
private String pushBfiPayApplyPush(PaymentApplication entity) {
|
||||
ContractManage contract = requireContract(entity);
|
||||
String orgNumber = bfiOrgNumber(contract);
|
||||
// TODO 待确认:日期格式沿用现有 A103-3 的 yyyyMMdd,若金蝶校验要求 yyyy-MM-dd 再统一调整
|
||||
String applyDateText = (entity.getApplyDate() == null ? LocalDate.now() : entity.getApplyDate()).format(DateTimeFormatter.BASIC_ISO_DATE);
|
||||
BigDecimal applyAmount = money(entity.getAppliedAmount()).setScale(2, RoundingMode.HALF_UP);
|
||||
BfiPayApplyPushDTO param = new BfiPayApplyPushDTO();
|
||||
param.setAwrpSrcCode(entity.getPaymentNo());
|
||||
param.setAwrpSrcSys(bfiPayApplySrcSys);
|
||||
param.setApplydate(applyDateText);
|
||||
param.setPayorgNumber(orgNumber);
|
||||
param.setPurorgNumber(orgNumber);
|
||||
param.setApplycause(bfiApplyCause(entity.getPaymentType()));
|
||||
param.setExratetableNumber(bfiPayApplyExratetable);
|
||||
param.setExratedate(applyDateText);
|
||||
param.setAwrpTextfield1(bfiPaymentMethodLabel(entity.getPaymentMethod()));
|
||||
param.setCreatorName(entity.getApplicantName());
|
||||
|
||||
BfiPayApplyPushEntryDTO entry = new BfiPayApplyPushEntryDTO();
|
||||
// 正式付款固定 201
|
||||
entry.setEPaymenttypeNumber(KingdeeBfiConstant.BFI_PAYMENT_TYPE_FORMAL);
|
||||
// 关联 A102-2 财务应付单分录,对应应付单明细的 awrp_entry_code
|
||||
entry.setAwrpFinapbillEntryid(entity.getPaymentNo() + "-1");
|
||||
entry.setAwrpEntryCode(entity.getPaymentNo() + "-1");
|
||||
entry.setEAssacct(entity.getBankAccount());
|
||||
// TODO 待确认:往来银行为必填编码(e_bebank_number),当前暂传银行名称,待建立银行档案编码映射后调整
|
||||
entry.setEBebankNumber(entity.getBankName());
|
||||
entry.setEApplyamount(applyAmount);
|
||||
entry.setEExpaydate(applyDateText);
|
||||
entry.setProjectNumber(bfiProjectNumber(entity));
|
||||
entry.setERemark(entity.getRemark());
|
||||
entry.setAwrpSrcType(bfiPayApplySrcType);
|
||||
param.setEntry(List.of(entry));
|
||||
|
||||
BfiBillSaveResultVO saveResult = bfiService.pushPayApply(param);
|
||||
return requireBfiBillId(saveResult, "推送金蝶付款申请(应付下推)");
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验金蝶保存/下推返回结果(单据级失败以 errors 明细抛出)
|
||||
*
|
||||
* @param saveResult 金蝶返回结果
|
||||
* @param action 业务动作描述,用于异常提示
|
||||
*/
|
||||
private void requireBfiSaveSuccess(BfiBillSaveResultVO saveResult, String action) {
|
||||
if (saveResult == null || Func.isEmpty(saveResult.getResult())) {
|
||||
throw new ServiceException(action + "失败,金蝶未返回单据结果");
|
||||
}
|
||||
BfiBillSaveResultItemVO item = saveResult.getResult().get(0);
|
||||
if (!Boolean.TRUE.equals(item.getBillStatus())) {
|
||||
String errorText = Func.isEmpty(item.getErrors()) ? "未知错误" : String.join(";", item.getErrors());
|
||||
throw new ServiceException(action + "失败:" + errorText);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验金蝶保存/下推返回结果并取星瀚单据id(单据级失败以 errors 明细抛出)
|
||||
*
|
||||
* @param saveResult 金蝶返回结果
|
||||
* @param action 业务动作描述,用于异常提示
|
||||
* @return 星瀚单据id
|
||||
*/
|
||||
private String requireBfiBillId(BfiBillSaveResultVO saveResult, String action) {
|
||||
requireBfiSaveSuccess(saveResult, action);
|
||||
Object billId = saveResult.getResult().get(0).getId();
|
||||
if (billId == null) throw new ServiceException(action + "失败,金蝶未返回单据id");
|
||||
return String.valueOf(billId);
|
||||
}
|
||||
|
||||
private void markSyncFailed(PaymentApplication entity) {
|
||||
@@ -485,9 +647,9 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
}
|
||||
|
||||
private String bfiProjectNumber(PaymentApplication entity) {
|
||||
if (entity.getProjectId() == null) return BFI_PROJECT_NUMBER_NONE;
|
||||
if (entity.getProjectId() == null) return KingdeeBfiConstant.BFI_PROJECT_NUMBER_NONE;
|
||||
ProjectApply project = projectApplyMapper.selectById(entity.getProjectId());
|
||||
return project == null || Func.isEmpty(project.getProjectCode()) ? BFI_PROJECT_NUMBER_NONE : project.getProjectCode();
|
||||
return project == null || Func.isEmpty(project.getProjectCode()) ? KingdeeBfiConstant.BFI_PROJECT_NUMBER_NONE : project.getProjectCode();
|
||||
}
|
||||
|
||||
private void mockPaymentRecords(PaymentApplication entity) {
|
||||
|
||||
Reference in New Issue
Block a user