⚡ 调整金蝶应付单分录取数:改由应付货物费用明细逐行不聚合推送,分录标识送费用明细id
This commit is contained in:
+130
-84
@@ -72,8 +72,10 @@ import org.springblade.transport.mapper.PaymentApplicationMapper;
|
||||
import org.springblade.transport.mapper.PaymentApplicationRecordMapper;
|
||||
import org.springblade.transport.mapper.PaymentApplicationSettlementMapper;
|
||||
import org.springblade.transport.mapper.PreSettlementAdvanceMapper;
|
||||
import org.springblade.transport.mapper.PreSettlementDetailFeeMapper;
|
||||
import org.springblade.transport.mapper.PreSettlementMapper;
|
||||
import org.springblade.transport.mapper.ProjectApplyMapper;
|
||||
import org.springblade.transport.mapper.ReceivablePayableCargoFeeMapper;
|
||||
import org.springblade.transport.mapper.TemporaryCreditLimitMapper;
|
||||
import org.springblade.transport.pojo.dto.PaymentApplicationInvoiceRequest;
|
||||
import org.springblade.transport.pojo.dto.PaymentApplicationRecordRequest;
|
||||
@@ -94,7 +96,9 @@ import org.springblade.transport.pojo.entity.PaymentApplicationRecord;
|
||||
import org.springblade.transport.pojo.entity.PaymentApplicationSettlement;
|
||||
import org.springblade.transport.pojo.entity.PreSettlement;
|
||||
import org.springblade.transport.pojo.entity.PreSettlementAdvance;
|
||||
import org.springblade.transport.pojo.entity.PreSettlementDetailFee;
|
||||
import org.springblade.transport.pojo.entity.ProjectApply;
|
||||
import org.springblade.transport.pojo.entity.ReceivablePayableCargoFee;
|
||||
import org.springblade.transport.pojo.entity.TemporaryCreditLimit;
|
||||
import org.springblade.transport.pojo.vo.PaymentApplicationReferenceAmountVO;
|
||||
import org.springblade.transport.pojo.vo.PaymentApplicationVO;
|
||||
@@ -148,6 +152,8 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
private final FormalSettlementMapper formalSettlementMapper;
|
||||
private final FormalSettlementDetailMapper formalSettlementDetailMapper;
|
||||
private final FormalSettlementDetailFeeMapper formalSettlementDetailFeeMapper;
|
||||
private final PreSettlementDetailFeeMapper preSettlementDetailFeeMapper;
|
||||
private final ReceivablePayableCargoFeeMapper receivablePayableCargoFeeMapper;
|
||||
private final FormalSettlementPaymentMapper formalSettlementPaymentMapper;
|
||||
private final ProjectApplyMapper projectApplyMapper;
|
||||
private final ContractManageMapper contractManageMapper;
|
||||
@@ -405,10 +411,10 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
requirePayableSettlement(entity);
|
||||
// 正式结算付款:先推财务应付单(A102-2,仅校验保存成功,应付单id不落库,
|
||||
// 后续如需可经 A102-4 按 awrp_src_sys + awrp_src_code 查询),再由应付下推付款申请(A103-1)
|
||||
// 分录按结算明细货物编码+计量单位分组拆分(物料编码取货物类型档案编码、计量单位暂传货物单位、
|
||||
// 数量取组内运输数量合计),财务应付单 detailentry 与付款申请 entry 一一对应
|
||||
// 分录逐费用行生成不聚合(物料编码取货物类型档案编码、含税金额取应付货物费用行调整后总金额、
|
||||
// 不含税经结算货物费用行回链),财务应付单 detailentry 与付款申请 entry 一一对应
|
||||
BfiEntryGroupResult entryGroupResult = resolveBfiEntryGroups(entity, context);
|
||||
log.info("付款申请[{}]正式结算付款:开始推送金蝶财务应付单(A102-2),分录组{}条", entity.getPaymentNo(), entryGroupResult.entryGroups().size());
|
||||
log.info("付款申请[{}]正式结算付款:开始推送金蝶财务应付单(A102-2),分录{}条", entity.getPaymentNo(), entryGroupResult.entryGroups().size());
|
||||
BfiApBillPushOutcome apBillOutcome = pushBfiApBill(entity, entryGroupResult.entryGroups(), entryGroupResult.documentNos(), context);
|
||||
// 财务应付单单据编号即时回填 kingdeeBillNo(后续付款申请单编号经 A103-2 定时回写任务覆盖)
|
||||
if (Func.isNotEmpty(apBillOutcome.billNo())) {
|
||||
@@ -1039,12 +1045,12 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
* 推送前先经 A102-4 按防重键(awrp_src_sys + awrp_src_code)查询:金蝶已存在财务应付单时
|
||||
* 幂等跳过保存并返回已有单据编号(说明上次同步已在后续下推/落库环节中断,应续推而非拦截报错),
|
||||
* 由调用方先经 A103-2 预检付款申请单是否已下推成功,再决定继续下推或直接回填。
|
||||
* 明细分录按结算明细货物编码+计量单位分组推送,金额取各组结算金额(含税/不含税);
|
||||
* 明细分录逐费用行生成(不聚合),含税金额取应付货物费用行调整后总金额、不含税取结算货物费用行不含税;
|
||||
* 付款计划 planentity 暂不传(启用方案见方法内注释,取数方法 approvedSettlementPayments 已保留),
|
||||
* 当前由金蝶按明细自动汇总生成
|
||||
*
|
||||
* @param entity 付款申请实体
|
||||
* @param entryGroups 结算明细聚合出的应付单分录组
|
||||
* @param entryGroups 结算明细解析出的应付单分录
|
||||
* @param documentNos 结算明细单据号(去重),用于拼接外部系统来源单据号
|
||||
* @return 财务应付单推送结果(单据编号 + 是否金蝶已存在幂等跳过 + 付款计划勾稽标识集合)
|
||||
*/
|
||||
@@ -1117,7 +1123,7 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
// 【必填】外部单据类型
|
||||
param.setAwrpSrcType(KingdeeBfiConstant.BFI_AP_BILL_SRC_TYPE);
|
||||
|
||||
// 明细分录:按货物编码+计量单位分组(数量取组内运输数量合计,无吨位时兜底 1)
|
||||
// 明细分录:每条应付货物费用行一条(不聚合),无吨位时数量兜底 1
|
||||
List<BfiApBillSaveEntryDTO> detailentry = new ArrayList<>();
|
||||
for (int index = 0; index < entryGroups.size(); index++) {
|
||||
BfiEntryGroup entryGroup = entryGroups.get(index);
|
||||
@@ -1126,16 +1132,16 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
entry.setMaterialNumber(entryGroup.materialNumber());
|
||||
// 【必填】计量单位.编码:货物费用行运费计算单位(快照 price_unit,档案暂无编码字段暂传单位名称)
|
||||
entry.setMeasureunitNumber(entryGroup.measureunitNumber());
|
||||
// 【必填】数量:组内结算明细运输数量合计,无吨位数据时兜底 1
|
||||
// 【必填】数量:该行运输数量,无吨位数据时兜底 1
|
||||
entry.setQuantity(entryGroup.quantity().compareTo(BigDecimal.ZERO) > 0 ? entryGroup.quantity() : BigDecimal.ONE);
|
||||
// 应付金额(含税):组内结算金额(含税)合计
|
||||
// 应付金额(含税):该行应付货物费用行调整后总金额(含税)
|
||||
entry.setEPricetaxtotal(entryGroup.amount());
|
||||
// 金额(不含税):组内结算金额(不含税)合计
|
||||
// 金额(不含税):该行结算金额(不含税)(应付费用行无不含税字段,经结算货物费用行回链)
|
||||
entry.setEAmount(entryGroup.amountNoTax());
|
||||
// 【必填】项目.项目编码(联调期临时传金蝶测试档案值)
|
||||
entry.setProjectNumber(KingdeeBfiConstant.BFI_AP_BILL_PROJECT_NUMBER_TEST);
|
||||
// 【必填】外部系统来源分录标识(候选键):结算明细单据号(多行并入同组时下划线拼接),A103-1 下推时以 awrp_finapbill_entryid 关联此行
|
||||
entry.setAwrpEntryCode(entryGroup.documentNo());
|
||||
// 【必填】外部系统来源分录标识(候选键):费用明细行id(唯一),A103-1 下推时 awrp_entry_code 与此对应
|
||||
entry.setAwrpEntryCode(entryGroup.entryCode());
|
||||
|
||||
// 调试
|
||||
|
||||
@@ -1186,12 +1192,12 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
|
||||
/**
|
||||
* 推送金蝶付款申请(A103-1 应付下推付款申请,正式结算付款第二步),返回星瀚付款申请单id。
|
||||
* 付款申请分录与财务应付单明细分录一一对应,申请金额取各组结算金额(含税);
|
||||
* 付款申请分录与财务应付单明细分录一一对应,申请金额取各组含税金额;
|
||||
* awrp_finapbill_entryid 勾稽 A102-2 付款计划分录 awrp_entry_code_p:付款计划暂不传,统一经 A102-4 反查
|
||||
* 金蝶自动生成的值;付款计划启用后优先取审核通过的付款信息单据号。awrp_entry_code 填结算明细单据号
|
||||
* 金蝶自动生成的值;付款计划启用后优先取审核通过的付款信息单据号。awrp_entry_code 填费用明细行id
|
||||
*
|
||||
* @param entity 付款申请实体
|
||||
* @param entryGroups 结算明细聚合出的应付单分录组
|
||||
* @param entryGroups 结算明细解析出的应付单分录
|
||||
* @param planEntryCodes A102-2 付款计划分录 awrp_entry_code_p 集合(付款信息单据号),空表示未传付款计划
|
||||
* @param context 金蝶同步上下文(缓存载体)
|
||||
* @return 星瀚付款申请单id
|
||||
@@ -1231,7 +1237,7 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
// 申请人(非必传)
|
||||
// param.setCreatorName(entity.getApplicantName());
|
||||
|
||||
// 付款申请分录与财务应付单明细分录一一对应(awrp_finapbill_entryid 关联应付单明细 awrp_entry_code)
|
||||
// 付款申请分录与财务应付单明细分录一一对应(awrp_finapbill_entryid 关联应付单付款计划分录 awrp_entry_code_p,A102-4 反查)
|
||||
List<BfiPayApplyPushEntryDTO> entries = new ArrayList<>();
|
||||
for (int index = 0; index < entryGroups.size(); index++) {
|
||||
BfiEntryGroup entryGroup = entryGroups.get(index);
|
||||
@@ -1240,8 +1246,8 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
entry.setEPaymenttypeNumber(KingdeeBfiConstant.BFI_PAYMENT_TYPE_FORMAL);
|
||||
// 【必填】结算单分录id:A102-2 财务应付单付款计划分录的外部系统来源分录标识(awrp_entry_code_p)
|
||||
entry.setAwrpFinapbillEntryid(finapbillEntryid);
|
||||
// 【必填】对方系统唯一行id(不能重复):结算明细单据号
|
||||
entry.setAwrpEntryCode(entryGroup.documentNo());
|
||||
// 【必填】对方系统唯一行id(不能重复):费用明细行id(与应付单的勾稽走 awrp_finapbill_entryid,与本标识无关)
|
||||
entry.setAwrpEntryCode(entryGroup.entryCode());
|
||||
// 【必填】往来账户:乙方(收款方)银行账号
|
||||
entry.setEAssacct(entity.getBankAccount());
|
||||
// 【必填】往来银行.编码(联调期临时传金蝶测试档案值,待建立银行档案编码映射后调整)todo
|
||||
@@ -1265,23 +1271,23 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
}
|
||||
|
||||
/**
|
||||
* 财务应付单/付款申请分录组:结算明细按货物编码+计量单位聚合后的分录数据
|
||||
* 财务应付单/付款申请分录:每条来源费用行一条(不聚合)
|
||||
*
|
||||
* @param materialNumber 物料编码(货物类型档案货物编码)
|
||||
* @param measureunitNumber 计量单位编码(运费计算单位,档案暂无编码字段暂传单位名称)
|
||||
* @param documentNo 结算明细单据号,作为分录唯一标识(awrp_entry_code),多行并入同组时下划线拼接
|
||||
* @param quantity 组内运输数量合计
|
||||
* @param amount 组内结算金额(含税)合计,对应明细应付金额 e_pricetaxtotal
|
||||
* @param amountNoTax 组内结算金额(不含税)合计,对应明细金额 e_amount
|
||||
* @param entryCode 分录唯一标识(awrp_entry_code):费用明细行id(兜底结算明细行id),同行多货物类型拆分时追加序号
|
||||
* @param quantity 该行运输数量
|
||||
* @param amount 该行金额(含税),对应明细应付金额 e_pricetaxtotal
|
||||
* @param amountNoTax 该行金额(不含税),对应明细金额 e_amount
|
||||
*/
|
||||
private record BfiEntryGroup(String materialNumber, String measureunitNumber, String documentNo,
|
||||
private record BfiEntryGroup(String materialNumber, String measureunitNumber, String entryCode,
|
||||
BigDecimal quantity, BigDecimal amount, BigDecimal amountNoTax) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 应付单分录解析结果
|
||||
*
|
||||
* @param entryGroups 结算明细聚合出的应付单分录组(金额取结算金额含税/不含税)
|
||||
* @param entryGroups 结算明细解析出的应付单分录(不聚合,含税取应付货物费用行调整后总金额、不含税经结算费用行回链)
|
||||
* @param documentNos 结算明细单据号(去重、保持行序),用于拼接外部系统来源单据号
|
||||
*/
|
||||
private record BfiEntryGroupResult(List<BfiEntryGroup> entryGroups, List<String> documentNos) {
|
||||
@@ -1299,14 +1305,18 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析付款申请关联的正式结算明细,按货物编码+计量单位聚合为应付单分录组。
|
||||
* <p>物料编码:货物费用行/结算明细货物类型(支持“、”分隔多类型)匹配货物类型档案货物编码;
|
||||
* 计量单位:快照运费计算单位(历史快照为空时兜底数量单位),档案暂无编码字段暂以单位名称作为编码;
|
||||
* 分录唯一标识(awrp_entry_code)取所属结算明细单据号,A103-1 下推时以 awrp_finapbill_entryid 关联此行;
|
||||
* 分录金额直接取结算金额(含税/不含税),不按申请付款金额分摊。</p>
|
||||
* 解析付款申请关联的正式结算明细,逐行生成应付单分录(不聚合,每条来源费用行一条分录)。
|
||||
* <p>取数来源:应付明细货物费用行(blade_receivable_payable_cargo_fee,经结算明细 sourceDetailId 关联应付明细,
|
||||
* 每货物一条)——货物类型/计量单位/运输数量/含税金额直接取应付费用行(含税金额取调整后总金额 after_amount);
|
||||
* 应付费用行无不含税字段,不含税金额经结算货物费用行 sourceFeeId 回链(直接选明细路径 sourceFeeId=应付费用行id,
|
||||
* 预结算合并路径 sourceFeeId=预结算费用行id,经预结算费用行 sourceFeeId 回溯应付费用行id);
|
||||
* 结算明细无应付费用行时兜底结算明细行(金额取结算金额)。物料编码:货物类型(支持“、”分隔多类型)
|
||||
* 匹配货物类型档案货物编码;分录唯一标识(awrp_entry_code)取费用明细行id(雪花id天然唯一,满足 A103-1
|
||||
* 对方系统唯一行id不能重复;A103-1 与应付单的勾稽关联走 awrp_finapbill_entryid=付款计划
|
||||
* awrp_entry_code_p,与本标识无关);分录金额不按申请付款金额分摊。</p>
|
||||
*
|
||||
* @param entity 付款申请实体
|
||||
* @return 应付单分录解析结果(分录组 + 结算明细单据号)
|
||||
* @return 应付单分录解析结果(分录 + 结算明细单据号)
|
||||
*/
|
||||
private BfiEntryGroupResult resolveBfiEntryGroups(PaymentApplication entity, KingdeeSyncContext context) {
|
||||
List<FormalSettlementDetail> settlementDetails = settlementDetails(entity, context);
|
||||
@@ -1316,37 +1326,37 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
// 去重收集结算明细单据号(保持行序),用于拼接财务应付单外部系统来源单据号
|
||||
List<String> documentNos = settlementDocumentNos(settlementDetails);
|
||||
Map<String, String> cargoCodeByName = cargoCodeByName(context);
|
||||
LinkedHashMap<String, BfiEntryGroup> groupMap = new LinkedHashMap<>();
|
||||
// 优先按货物费用行逐条取数(blade_formal_settlement_detail_fee 每货物一条,金额为结算调整后的精确值)
|
||||
List<FormalSettlementDetailFee> detailFees = formalSettlementDetailFees(settlementDetails);
|
||||
if (Func.isNotEmpty(detailFees)) {
|
||||
// 结算明细id->单据号映射:货物费用行经此回溯所属结算明细单据号(作为分录唯一标识)
|
||||
Map<Long, String> detailDocumentNoMap = new LinkedHashMap<>();
|
||||
for (FormalSettlementDetail settlementDetail : settlementDetails) {
|
||||
detailDocumentNoMap.putIfAbsent(settlementDetail.getId(), settlementDetail.getDocumentNo());
|
||||
}
|
||||
for (FormalSettlementDetailFee detailFee : detailFees) {
|
||||
collectEntryGroups(groupMap, cargoCodeByName, detailFee.getCargoType(),
|
||||
resolveMeasureunitNumber(null, detailFee.getQuantityUnit()),
|
||||
detailDocumentNoMap.get(detailFee.getFormalSettlementDetailId()),
|
||||
money(detailFee.getSettlementAmountTax()), money(detailFee.getSettlementAmountNoTax()),
|
||||
money(detailFee.getTransportQuantity()),
|
||||
"货物费用[" + Func.toStr(detailFee.getCargoName()) + " 第" + Func.toStr(detailFee.getLineNo()) + "行]");
|
||||
}
|
||||
} else {
|
||||
for (FormalSettlementDetail settlementDetail : settlementDetails) {
|
||||
collectEntryGroups(groupMap, cargoCodeByName, settlementDetail.getCargoType(),
|
||||
// 应付明细id->应付货物费用行(分录主取数来源)
|
||||
Map<Long, List<ReceivablePayableCargoFee>> payableFeesByDetailId = payableCargoFeesByDetailId(settlementDetails);
|
||||
// 应付费用行id->结算金额(不含税):应付费用行无不含税字段,经结算货物费用行 sourceFeeId 回链
|
||||
Map<Long, BigDecimal> noTaxByPayableFeeId = settlementNoTaxByPayableFeeId(settlementDetails);
|
||||
List<BfiEntryGroup> entryGroups = new ArrayList<>();
|
||||
for (FormalSettlementDetail settlementDetail : settlementDetails) {
|
||||
List<ReceivablePayableCargoFee> payableFees =
|
||||
payableFeesByDetailId.getOrDefault(settlementDetail.getSourceDetailId(), List.of());
|
||||
if (Func.isNotEmpty(payableFees)) {
|
||||
for (ReceivablePayableCargoFee payableFee : payableFees) {
|
||||
appendEntryGroups(entryGroups, cargoCodeByName, payableFee.getCargoType(),
|
||||
resolveMeasureunitNumber(payableFee.getPriceUnit(), payableFee.getQuantityUnit()),
|
||||
payableFee.getId(),
|
||||
money(payableFee.getAfterAmount()),
|
||||
noTaxByPayableFeeId.getOrDefault(payableFee.getId(), BigDecimal.ZERO),
|
||||
money(payableFee.getTransportQuantity()),
|
||||
"应付货物费用[" + Func.toStr(payableFee.getCargoName()) + " 第" + Func.toStr(payableFee.getLineNo()) + "行]");
|
||||
}
|
||||
} else {
|
||||
appendEntryGroups(entryGroups, cargoCodeByName, settlementDetail.getCargoType(),
|
||||
resolveMeasureunitNumber(null, settlementDetail.getQuantityUnit()),
|
||||
settlementDetail.getDocumentNo(),
|
||||
settlementDetail.getId(),
|
||||
money(settlementDetail.getSettlementAmountTax()), money(settlementDetail.getSettlementAmountNoTax()),
|
||||
money(settlementDetail.getTransportQuantity()),
|
||||
"结算明细[" + Func.toStr(settlementDetail.getDocumentNo()) + " 第" + Func.toStr(settlementDetail.getLineNo()) + "行]");
|
||||
}
|
||||
}
|
||||
if (groupMap.isEmpty()) {
|
||||
throw new ServiceException("推送金蝶财务应付单失败:结算明细未解析出任何分录组,请检查货物类型维护");
|
||||
if (entryGroups.isEmpty()) {
|
||||
throw new ServiceException("推送金蝶财务应付单失败:结算明细未解析出任何分录,请检查货物类型维护");
|
||||
}
|
||||
return new BfiEntryGroupResult(new ArrayList<>(groupMap.values()), documentNos);
|
||||
return new BfiEntryGroupResult(entryGroups, documentNos);
|
||||
}
|
||||
|
||||
/** 结算明细单据号去重收集(保持行序),用于拼接财务应付单外部系统来源单据号 */
|
||||
@@ -1372,7 +1382,7 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
/**
|
||||
* 金蝶分录标识:付款申请号-分录序号(1 起)。
|
||||
* 现仅 A103-3 预付款直接保存路径使用(序号固定 1);正式结算链路 A102-2 明细 awrp_entry_code 与
|
||||
* A103-1 awrp_entry_code 已改为结算明细单据号(resolveBfiEntryGroups 统一解析),
|
||||
* A103-1 awrp_entry_code 已改为费用明细行id(resolveBfiEntryGroups 统一解析),
|
||||
* A103-1 awrp_finapbill_entryid 改为财务应付单付款计划 awrp_entry_code_p(A102-4 反查),禁止各接口自行拼接
|
||||
*
|
||||
* @param paymentNo 付款申请号
|
||||
@@ -1421,28 +1431,28 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
}
|
||||
|
||||
/**
|
||||
* 单条来源行(货物费用行或结算明细行)按货物类型并入分录组;一行含多种类型时金额与数量按份数均分(尾差计入最后一份)
|
||||
* 单条来源行(应付货物费用行或结算明细行)生成不聚合分录(每行一条);
|
||||
* 一行含多种货物类型时按类型拆为多条,金额与数量按份数均分(尾差计入最后一份)
|
||||
*
|
||||
* @param groupMap 分录组(按物料编码+计量单位聚合,保持行序)
|
||||
* @param entryGroups 分录集合(保持行序)
|
||||
* @param cargoCodeByName 货物类型名称->货物编码映射
|
||||
* @param cargoType 货物类型(支持“、”分隔多类型)
|
||||
* @param measureunitNumber 计量单位编码(运费计算单位,档案暂无编码字段暂传单位名称)
|
||||
* @param documentNo 结算明细单据号,作为分录唯一标识(awrp_entry_code)
|
||||
* @param amount 结算金额(含税)
|
||||
* @param amountNoTax 结算金额(不含税)
|
||||
* @param quantity 运输数量
|
||||
* @param sourceRowId 来源行id(应付货物费用行id,兜底结算明细行id),雪花id天然唯一
|
||||
* @param amount 该行金额(含税)
|
||||
* @param amountNoTax 该行金额(不含税)
|
||||
* @param quantity 该行运输数量
|
||||
* @param sourceDesc 来源行描述,用于异常提示
|
||||
*/
|
||||
private void collectEntryGroups(LinkedHashMap<String, BfiEntryGroup> groupMap, Map<String, String> cargoCodeByName,
|
||||
String cargoType, String measureunitNumber, String documentNo, BigDecimal amount, BigDecimal amountNoTax,
|
||||
BigDecimal quantity, String sourceDesc) {
|
||||
private void appendEntryGroups(List<BfiEntryGroup> entryGroups, Map<String, String> cargoCodeByName,
|
||||
String cargoType, String measureunitNumber, Long sourceRowId,
|
||||
BigDecimal amount, BigDecimal amountNoTax, BigDecimal quantity, String sourceDesc) {
|
||||
List<String> cargoNames = splitCargoTypes(cargoType);
|
||||
if (Func.isBlank(measureunitNumber)) {
|
||||
throw new ServiceException("推送金蝶财务应付单失败:" + sourceDesc + "计量单位为空,请先维护运费计算单位");
|
||||
}
|
||||
if (Func.isBlank(documentNo)) {
|
||||
throw new ServiceException("推送金蝶财务应付单失败:" + sourceDesc + "单据号为空,无法生成金蝶分录标识(awrp_entry_code)");
|
||||
}
|
||||
// 分录唯一标识(awrp_entry_code,A103-1 要求对方系统唯一行id不能重复):雪花id天然唯一,同行多类型拆分时追加序号
|
||||
String rowEntryCode = String.valueOf(sourceRowId);
|
||||
List<BigDecimal> amountShares = splitEqually(amount, cargoNames.size());
|
||||
List<BigDecimal> amountNoTaxShares = splitEqually(amountNoTax, cargoNames.size());
|
||||
List<BigDecimal> quantityShares = splitEqually(quantity, cargoNames.size());
|
||||
@@ -1452,26 +1462,16 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
if (Func.isBlank(materialNumber)) {
|
||||
throw new ServiceException("推送金蝶财务应付单失败:" + sourceDesc + "货物类型[" + cargoName + "]未在货物类型档案中维护编码,请补充后重试");
|
||||
}
|
||||
groupMap.merge(materialNumber + "/" + measureunitNumber,
|
||||
new BfiEntryGroup(materialNumber, measureunitNumber, documentNo, quantityShares.get(index), amountShares.get(index), amountNoTaxShares.get(index)),
|
||||
(left, right) -> new BfiEntryGroup(left.materialNumber(), left.measureunitNumber(),
|
||||
joinEntryDocumentNos(left.documentNo(), right.documentNo()),
|
||||
left.quantity().add(right.quantity()), left.amount().add(right.amount()), left.amountNoTax().add(right.amountNoTax())));
|
||||
String entryCode = cargoNames.size() > 1 ? rowEntryCode + "-" + (index + 1) : rowEntryCode;
|
||||
entryGroups.add(new BfiEntryGroup(materialNumber, measureunitNumber, entryCode,
|
||||
quantityShares.get(index), amountShares.get(index), amountNoTaxShares.get(index)));
|
||||
log.info("金蝶应付单分录生成:来源[{}],分录标识[{}],物料编码[{}],计量单位[{}],数量[{}],含税金额[{}],不含税金额[{}]",
|
||||
sourceDesc, entryCode, materialNumber, measureunitNumber,
|
||||
quantityShares.get(index), amountShares.get(index), amountNoTaxShares.get(index));
|
||||
}
|
||||
}
|
||||
|
||||
/** 分录组合并时结算明细单据号去重下划线拼接(保持先后顺序),与外部系统来源单据号拼接规则一致 */
|
||||
private String joinEntryDocumentNos(String left, String right) {
|
||||
if (Func.isBlank(left)) {
|
||||
return right;
|
||||
}
|
||||
if (Func.isBlank(right) || left.equals(right)) {
|
||||
return left;
|
||||
}
|
||||
return left.contains(right) ? left : right.contains(left) ? right : left + "_" + right;
|
||||
}
|
||||
|
||||
/** 付款申请关联的正式结算货物费用行(blade_formal_settlement_detail_fee,每货物一条,金额为结算调整后精确值) */
|
||||
/** 付款申请关联的正式结算货物费用行(blade_formal_settlement_detail_fee,用于不含税金额回链应付费用行) */
|
||||
private List<FormalSettlementDetailFee> formalSettlementDetailFees(List<FormalSettlementDetail> settlementDetails) {
|
||||
List<Long> settlementDetailIds = settlementDetails.stream().map(FormalSettlementDetail::getId)
|
||||
.filter(Objects::nonNull).distinct().toList();
|
||||
@@ -1484,6 +1484,52 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
||||
.orderByAsc(FormalSettlementDetailFee::getLineNo));
|
||||
}
|
||||
|
||||
/** 应付明细id->应付货物费用行(blade_receivable_payable_cargo_fee,经结算明细 sourceDetailId 关联,每货物一条,分录主取数来源) */
|
||||
private Map<Long, List<ReceivablePayableCargoFee>> payableCargoFeesByDetailId(List<FormalSettlementDetail> settlementDetails) {
|
||||
List<Long> sourceDetailIds = settlementDetails.stream()
|
||||
.map(FormalSettlementDetail::getSourceDetailId).filter(Objects::nonNull).distinct().toList();
|
||||
if (Func.isEmpty(sourceDetailIds)) {
|
||||
return Map.of();
|
||||
}
|
||||
return receivablePayableCargoFeeMapper.selectList(Wrappers.<ReceivablePayableCargoFee>lambdaQuery()
|
||||
.in(ReceivablePayableCargoFee::getDetailId, sourceDetailIds)
|
||||
.eq(ReceivablePayableCargoFee::getIsDeleted, 0)
|
||||
.orderByAsc(ReceivablePayableCargoFee::getLineNo))
|
||||
.stream().collect(Collectors.groupingBy(ReceivablePayableCargoFee::getDetailId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 应付货物费用行id->结算金额(不含税):应付费用行无不含税字段,经结算货物费用行 sourceFeeId 回链获取。
|
||||
* 直接选应收应付明细路径 sourceFeeId=应付费用行id;预结算合并路径 sourceFeeId=预结算费用行id,
|
||||
* 经预结算费用行 sourceFeeId(指向应付费用行)回溯;无对应结算费用行时无映射,调用方兜底 0
|
||||
*/
|
||||
private Map<Long, BigDecimal> settlementNoTaxByPayableFeeId(List<FormalSettlementDetail> settlementDetails) {
|
||||
List<FormalSettlementDetailFee> settlementFees = formalSettlementDetailFees(settlementDetails);
|
||||
if (Func.isEmpty(settlementFees)) {
|
||||
return Map.of();
|
||||
}
|
||||
// 上游费用行id(应付费用行id或预结算费用行id)-> 不含税合计
|
||||
Map<Long, BigDecimal> noTaxBySourceFeeId = new LinkedHashMap<>();
|
||||
for (FormalSettlementDetailFee settlementFee : settlementFees) {
|
||||
if (settlementFee.getSourceFeeId() == null) {
|
||||
continue;
|
||||
}
|
||||
noTaxBySourceFeeId.merge(settlementFee.getSourceFeeId(), money(settlementFee.getSettlementAmountNoTax()), BigDecimal::add);
|
||||
}
|
||||
if (noTaxBySourceFeeId.isEmpty()) {
|
||||
return Map.of();
|
||||
}
|
||||
// sourceFeeId 指向预结算费用行的:经预结算费用行回溯应付费用行id(直接路径无预结算费用行,保持原 id)
|
||||
Map<Long, Long> payableFeeIdByPreFeeId = preSettlementDetailFeeMapper.selectList(
|
||||
Wrappers.<PreSettlementDetailFee>lambdaQuery().in(PreSettlementDetailFee::getId, new ArrayList<>(noTaxBySourceFeeId.keySet())))
|
||||
.stream().filter(preSettlementFee -> preSettlementFee.getSourceFeeId() != null)
|
||||
.collect(Collectors.toMap(PreSettlementDetailFee::getId, PreSettlementDetailFee::getSourceFeeId, (left, right) -> left));
|
||||
Map<Long, BigDecimal> noTaxByPayableFeeId = new LinkedHashMap<>();
|
||||
noTaxBySourceFeeId.forEach((sourceFeeId, noTax) ->
|
||||
noTaxByPayableFeeId.merge(payableFeeIdByPreFeeId.getOrDefault(sourceFeeId, sourceFeeId), noTax, BigDecimal::add));
|
||||
return noTaxByPayableFeeId;
|
||||
}
|
||||
|
||||
/** 付款申请关联的正式结算明细(关联表优先,兼容仅有 settlementId 的存量数据) */
|
||||
private List<FormalSettlementDetail> formalSettlementDetails(PaymentApplication entity) {
|
||||
List<Long> settlementIds = settlementRelationMapper.selectList(Wrappers.<PaymentApplicationSettlement>lambdaQuery()
|
||||
|
||||
Reference in New Issue
Block a user