feat: 付款结果回写支持指定付款单据号并按金蝶单据号查询
This commit is contained in:
+34
@@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* BladeX Commercial License Agreement
|
||||||
|
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
|
||||||
|
* <p>
|
||||||
|
* Use of this software is governed by the Commercial License Agreement obtained after purchasing a license from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 1. This software is for development use only under a valid license from BladeX.
|
||||||
|
* <p>
|
||||||
|
* 2. Redistribution of this software's source code to any third party without a commercial license is strictly prohibited.
|
||||||
|
* <p>
|
||||||
|
* 3. Licensees may copyright their own code but cannot use segments from this software for such purposes.
|
||||||
|
* Copyright of this software remains with BladeX.
|
||||||
|
* <p>
|
||||||
|
* Using this software signifies agreement to this License, and the software must not be used for illegal purposes.
|
||||||
|
* <p>
|
||||||
|
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is not liable for any claims arising from secondary or illegal development.
|
||||||
|
* <p>
|
||||||
|
* Author: Chill Zhuang (bladejava@qq.com)
|
||||||
|
*/
|
||||||
|
package org.springblade.transport.pojo.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/** 付款申请手动回写金蝶付款结果请求。 @author Chill */
|
||||||
|
@Data
|
||||||
|
public class PaymentApplicationSyncResultRequest implements Serializable {
|
||||||
|
@Serial private static final long serialVersionUID = 1L;
|
||||||
|
/** 付款单据号列表,为空回写全部待回写单据 */
|
||||||
|
private List<String> paymentNos;
|
||||||
|
}
|
||||||
+5
-2
@@ -33,6 +33,7 @@ import org.springblade.transport.constant.HcsSyncConstant;
|
|||||||
import org.springblade.transport.listener.KingdeeApprovalSyncListener;
|
import org.springblade.transport.listener.KingdeeApprovalSyncListener;
|
||||||
import org.springblade.transport.pojo.dto.PaymentApplicationSaveRequest;
|
import org.springblade.transport.pojo.dto.PaymentApplicationSaveRequest;
|
||||||
import org.springblade.transport.pojo.dto.PaymentApplicationStatusRequest;
|
import org.springblade.transport.pojo.dto.PaymentApplicationStatusRequest;
|
||||||
|
import org.springblade.transport.pojo.dto.PaymentApplicationSyncResultRequest;
|
||||||
import org.springblade.transport.pojo.entity.PaymentApplication;
|
import org.springblade.transport.pojo.entity.PaymentApplication;
|
||||||
import org.springblade.transport.pojo.vo.PaymentApplicationReferenceAmountVO;
|
import org.springblade.transport.pojo.vo.PaymentApplicationReferenceAmountVO;
|
||||||
import org.springblade.transport.pojo.vo.PaymentApplicationVO;
|
import org.springblade.transport.pojo.vo.PaymentApplicationVO;
|
||||||
@@ -142,6 +143,8 @@ public class PaymentApplicationController extends BladeController {
|
|||||||
}
|
}
|
||||||
@PostMapping("/sync-kingdee-result")
|
@PostMapping("/sync-kingdee-result")
|
||||||
@ApiOperationSupport(order = 12)
|
@ApiOperationSupport(order = 12)
|
||||||
@Operation(summary = "手动回写金蝶付款结果(A103-2/A103-4)")
|
@Operation(summary = "手动回写金蝶付款结果(A103-2/A103-4),可指定付款单据号")
|
||||||
public R<String> syncKingdeeResult() { return R.data(paymentApplicationService.syncKingdeePaymentResult()); }
|
public R<String> syncKingdeeResult(@RequestBody(required = false) PaymentApplicationSyncResultRequest request) {
|
||||||
|
return R.data(paymentApplicationService.syncKingdeePaymentResult(request == null ? null : request.getPaymentNos()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -101,11 +101,13 @@ public interface IPaymentApplicationService extends BaseService<PaymentApplicati
|
|||||||
void unlockBill(Long id, String source);
|
void unlockBill(Long id, String source);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 定时回写金蝶付款结果(A103-2 付款申请单查询 / A103-4 付款处理查询)
|
* 回写金蝶付款结果(A103-2 付款申请单查询 / A103-4 付款处理查询):
|
||||||
|
* 指定付款单据号时按金蝶单据号(billno)精确查询并仅回写指定单据,为空时回写全部待回写单据
|
||||||
*
|
*
|
||||||
|
* @param paymentNos 付款单据号列表,为空回写全部待回写单据
|
||||||
* @return 执行摘要
|
* @return 执行摘要
|
||||||
*/
|
*/
|
||||||
String syncKingdeePaymentResult();
|
String syncKingdeePaymentResult(List<String> paymentNos);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 回写单笔付款申请的金蝶付款申请单查询结果(A103-2),单据级事务
|
* 回写单笔付款申请的金蝶付款申请单查询结果(A103-2),单据级事务
|
||||||
|
|||||||
+42
-11
@@ -949,33 +949,41 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String syncKingdeePaymentResult() {
|
public String syncKingdeePaymentResult(List<String> paymentNos) {
|
||||||
return kingdeeSyncLockSupport.runSingleFlight(PAY_RESULT_SYNC_LOCK_PREFIX, bfiProperties.getPayResult().getLockLeaseSeconds(),
|
return kingdeeSyncLockSupport.runSingleFlight(PAY_RESULT_SYNC_LOCK_PREFIX, bfiProperties.getPayResult().getLockLeaseSeconds(),
|
||||||
"金蝶付款结果回写", this::executePaymentResultSync);
|
"金蝶付款结果回写", () -> this.executePaymentResultSync(paymentNos));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 金蝶付款结果回写主体,由 {@link #syncKingdeePaymentResult()} 在分布式锁保护下调用,执行流程:
|
* 金蝶付款结果回写主体,由 {@link #syncKingdeePaymentResult(List)} 在分布式锁保护下调用,执行流程:
|
||||||
* <pre>
|
* <pre>
|
||||||
* ① 圈定待回写付款申请:审批通过且金蝶状态为 已生成/付款中/生成失败(终态已付款/已关闭不再轮询),
|
* ① 圈定待回写付款申请:审批通过且金蝶状态为 已生成/付款中/生成失败(终态已付款/已关闭不再轮询),
|
||||||
* 生成失败单据一并纳入:金蝶侧已生成说明上次推送实际成功(如下推超时但远端已落单、本地事务回滚),
|
* 手动指定付款单据号(paymentNos)时仅回写指定单据;生成失败单据一并纳入:
|
||||||
|
* 金蝶侧已生成说明上次推送实际成功(如下推超时但远端已落单、本地事务回滚),
|
||||||
* 查得即回填纠正为已生成,避免人工重推产生重复单据,未查得则保持生成失败等待人工重推;
|
* 查得即回填纠正为已生成,避免人工重推产生重复单据,未查得则保持生成失败等待人工重推;
|
||||||
* ② A103-2 付款申请单查询回填:按 paymentNo(awrp_src_code)分批查询,同一来源单号取最近修改一条,
|
* ② A103-2 付款申请单查询回填:指定单据号时按金蝶单据号(billno)精确查询(无金蝶单据号兜底按来源单号),
|
||||||
|
* 定时全量回写按 paymentNo(awrp_src_code)分批查询,同一来源单号取最近修改一条,
|
||||||
* 回填金蝶单号/内码/同步状态/已付金额并联动预结算与正式结算付款记录;连续两轮查询未命中按金蝶反审核删除解锁;
|
* 回填金蝶单号/内码/同步状态/已付金额并联动预结算与正式结算付款记录;连续两轮查询未命中按金蝶反审核删除解锁;
|
||||||
* ③ A103-4 付款处理查询补付款记录:付款中/已付款单据 + 已付款无付款记录单据(补偿),
|
* ③ A103-4 付款处理查询补付款记录:付款中/已付款单据 + 已付款无付款记录单据(补偿),
|
||||||
* 按付款组织 + awrp_sourcebillno(金蝶单据号)数组精确查询,双键勾稽后回填付款记录;
|
* 按付款组织 + awrp_sourcebillno(金蝶单据号)数组精确查询,双键勾稽后回填付款记录;
|
||||||
* ④ 汇总执行摘要:各计数随流程累计,单笔失败仅计数不中断整轮
|
* ④ 汇总执行摘要:各计数随流程累计,单笔失败仅计数不中断整轮
|
||||||
* </pre>
|
* </pre>
|
||||||
*
|
*
|
||||||
|
* @param paymentNos 付款单据号列表,为空回写全部待回写单据
|
||||||
* @return 执行摘要
|
* @return 执行摘要
|
||||||
*/
|
*/
|
||||||
private String executePaymentResultSync() {
|
private String executePaymentResultSync(List<String> paymentNos) {
|
||||||
// ① 待回写付款申请:审批通过且金蝶状态为 已生成/付款中/生成失败(终态已付款/已关闭不再轮询)
|
// ① 待回写付款申请:审批通过且金蝶状态为 已生成/付款中/生成失败(终态已付款/已关闭不再轮询),
|
||||||
|
// 手动指定付款单据号时仅圈定指定单据
|
||||||
List<PaymentApplication> applications = list(Wrappers.<PaymentApplication>lambdaQuery()
|
List<PaymentApplication> applications = list(Wrappers.<PaymentApplication>lambdaQuery()
|
||||||
.eq(PaymentApplication::getApprovalStatus, TransportBusiConstant.APPROVED)
|
.eq(PaymentApplication::getApprovalStatus, TransportBusiConstant.APPROVED)
|
||||||
.in(PaymentApplication::getKingdeeStatus, KingdeeBfiConstant.KINGDEE_STATUS_SYNCED,
|
.in(PaymentApplication::getKingdeeStatus, KingdeeBfiConstant.KINGDEE_STATUS_SYNCED,
|
||||||
KingdeeBfiConstant.KINGDEE_STATUS_PAYING, KingdeeBfiConstant.KINGDEE_STATUS_FAILED)
|
KingdeeBfiConstant.KINGDEE_STATUS_PAYING, KingdeeBfiConstant.KINGDEE_STATUS_FAILED)
|
||||||
|
.in(Func.isNotEmpty(paymentNos), PaymentApplication::getPaymentNo, paymentNos)
|
||||||
.orderByAsc(PaymentApplication::getId));
|
.orderByAsc(PaymentApplication::getId));
|
||||||
|
if (Func.isNotEmpty(paymentNos)) {
|
||||||
|
log.info("手动回写金蝶付款结果, 指定付款单据号: {}, 圈定待回写单据 {} 笔", paymentNos, applications.size());
|
||||||
|
}
|
||||||
// 自代理:applyPayApplyResult/applyPayBillRecord 带单据级事务,跨方法调用确保注解生效,单笔失败仅回滚自身
|
// 自代理:applyPayApplyResult/applyPayBillRecord 带单据级事务,跨方法调用确保注解生效,单笔失败仅回滚自身
|
||||||
IPaymentApplicationService self = SpringUtil.getBean(IPaymentApplicationService.class);
|
IPaymentApplicationService self = SpringUtil.getBean(IPaymentApplicationService.class);
|
||||||
int updated = 0;
|
int updated = 0;
|
||||||
@@ -983,11 +991,17 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
|||||||
int paidCount = 0;
|
int paidCount = 0;
|
||||||
Map<String, BfiPayApplyVO> payApplyMap = new HashMap<>();
|
Map<String, BfiPayApplyVO> payApplyMap = new HashMap<>();
|
||||||
if (!applications.isEmpty()) {
|
if (!applications.isEmpty()) {
|
||||||
// ② A103-2 付款申请单查询:按 paymentNo(awrp_src_code)分批查询,同一来源单号取最近修改的一条
|
// ② A103-2 付款申请单查询:指定单据号时按金蝶单据号(billno)精确查询,无金蝶单据号的兜底按来源单号查询;
|
||||||
List<String> paymentNos = applications.stream()
|
// 定时全量回写按 paymentNo(awrp_src_code)分批查询,同一来源单号取最近修改的一条
|
||||||
|
List<String> billNos = applications.stream()
|
||||||
|
.map(PaymentApplication::getKingdeeBillNo).filter(Func::isNotEmpty).distinct().toList();
|
||||||
|
List<String> fallbackSrcCodes = applications.stream()
|
||||||
|
.filter(application -> Func.isEmpty(application.getKingdeeBillNo()))
|
||||||
.map(PaymentApplication::getPaymentNo).filter(Func::isNotEmpty).distinct().toList();
|
.map(PaymentApplication::getPaymentNo).filter(Func::isNotEmpty).distinct().toList();
|
||||||
this.batchForeach(paymentNos, PAY_RESULT_QUERY_BATCH, batch ->
|
this.batchForeach(billNos, PAY_RESULT_QUERY_BATCH,
|
||||||
payApplyMap.putAll(this.latestPayApplyBySrcCode(this.queryPayApplyPages(batch))));
|
batch -> payApplyMap.putAll(this.latestPayApplyBySrcCode(this.queryPayApplyPagesByBillNo(batch))));
|
||||||
|
this.batchForeach(fallbackSrcCodes, PAY_RESULT_QUERY_BATCH,
|
||||||
|
batch -> payApplyMap.putAll(this.latestPayApplyBySrcCode(this.queryPayApplyPages(batch))));
|
||||||
// 逐单回写:查得即回填并清零消失计数;未查得累计消失轮次(批次其余单据正常返回,排除服务整体故障)
|
// 逐单回写:查得即回填并清零消失计数;未查得累计消失轮次(批次其余单据正常返回,排除服务整体故障)
|
||||||
for (PaymentApplication application : applications) {
|
for (PaymentApplication application : applications) {
|
||||||
BfiPayApplyVO payApply = payApplyMap.get(application.getPaymentNo());
|
BfiPayApplyVO payApply = payApplyMap.get(application.getPaymentNo());
|
||||||
@@ -1195,6 +1209,23 @@ public class PaymentApplicationServiceImpl extends BaseServiceImpl<PaymentApplic
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A103-2 分页查询:金蝶单据号批量精确查询(手动指定付款单据号回写场景),自动翻页。
|
||||||
|
* 按金蝶单据号查询时不传来源单据号(awrp_src_code),单据号在金蝶侧全局唯一
|
||||||
|
*
|
||||||
|
* @param billNos 金蝶单据号批次
|
||||||
|
* @return 付款申请单列表
|
||||||
|
*/
|
||||||
|
private List<BfiPayApplyVO> queryPayApplyPagesByBillNo(List<String> billNos) {
|
||||||
|
BfiPayApplyQueryDTO param = new BfiPayApplyQueryDTO();
|
||||||
|
param.setBillno(billNos);
|
||||||
|
return BfiUtil.queryAllPages(pageNo -> {
|
||||||
|
param.setPageNo(pageNo);
|
||||||
|
param.setPageSize(PAY_RESULT_PAGE_SIZE);
|
||||||
|
return bfiService.queryPayApply(param);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A103-2 幂等预检:按来源单号查询金蝶付款申请单是否已生成,同一来源单号取最近修改的一条。
|
* A103-2 幂等预检:按来源单号查询金蝶付款申请单是否已生成,同一来源单号取最近修改的一条。
|
||||||
* 用于正式付款链路恢复场景:财务应付单已生成说明上次同步可能已保存成功而在下推/落库环节中断,
|
* 用于正式付款链路恢复场景:财务应付单已生成说明上次同步可能已保存成功而在下推/落库环节中断,
|
||||||
|
|||||||
+1
-1
@@ -67,7 +67,7 @@ public class PaymentKingdeeResultTask {
|
|||||||
}
|
}
|
||||||
// ① A103-2/A103-4 付款结果回写
|
// ① A103-2/A103-4 付款结果回写
|
||||||
try {
|
try {
|
||||||
String summary = paymentApplicationService.syncKingdeePaymentResult();
|
String summary = paymentApplicationService.syncKingdeePaymentResult(null);
|
||||||
log.info("定时回写金蝶付款结果:{}", summary);
|
log.info("定时回写金蝶付款结果:{}", summary);
|
||||||
} catch (Exception exception) {
|
} catch (Exception exception) {
|
||||||
log.error("定时回写金蝶付款结果异常", exception);
|
log.error("定时回写金蝶付款结果异常", exception);
|
||||||
|
|||||||
+2
@@ -188,6 +188,7 @@ public interface IBfiClient {
|
|||||||
* @param pageSize 页数
|
* @param pageSize 页数
|
||||||
* @param awrpSrcCode 来源单据号
|
* @param awrpSrcCode 来源单据号
|
||||||
* @param awrpSrcSys 系统编号
|
* @param awrpSrcSys 系统编号
|
||||||
|
* @param billno 金蝶单据号,按单据号精确查询时不传来源单据号
|
||||||
* @param modifytimeS 修改时间-开始
|
* @param modifytimeS 修改时间-开始
|
||||||
* @param modifytimeE 修改时间-结束
|
* @param modifytimeE 修改时间-结束
|
||||||
* @return 付款申请单分页数据
|
* @return 付款申请单分页数据
|
||||||
@@ -198,6 +199,7 @@ public interface IBfiClient {
|
|||||||
@RequestParam("pageSize") Integer pageSize,
|
@RequestParam("pageSize") Integer pageSize,
|
||||||
@RequestParam(value = "awrp_src_code", required = false) List<String> awrpSrcCode,
|
@RequestParam(value = "awrp_src_code", required = false) List<String> awrpSrcCode,
|
||||||
@RequestParam(value = "awrp_src_sys", required = false) String awrpSrcSys,
|
@RequestParam(value = "awrp_src_sys", required = false) String awrpSrcSys,
|
||||||
|
@RequestParam(value = "billno", required = false) List<String> billno,
|
||||||
@RequestParam(value = "modifytimeS", required = false) String modifytimeS,
|
@RequestParam(value = "modifytimeS", required = false) String modifytimeS,
|
||||||
@RequestParam(value = "modifytimeE", required = false) String modifytimeE);
|
@RequestParam(value = "modifytimeE", required = false) String modifytimeE);
|
||||||
|
|
||||||
|
|||||||
+4
@@ -54,6 +54,10 @@ public class BfiPayApplyQueryDTO implements Serializable {
|
|||||||
* 来源单据号,业务系统对应的单据号,高频查询需要推送该字段
|
* 来源单据号,业务系统对应的单据号,高频查询需要推送该字段
|
||||||
*/
|
*/
|
||||||
private List<String> awrpSrcCode;
|
private List<String> awrpSrcCode;
|
||||||
|
/**
|
||||||
|
* 金蝶单据号,按单据号精确查询时不传来源单据号(awrp_src_code)
|
||||||
|
*/
|
||||||
|
private List<String> billno;
|
||||||
/**
|
/**
|
||||||
* 系统编号
|
* 系统编号
|
||||||
*/
|
*/
|
||||||
|
|||||||
+2
-1
@@ -270,7 +270,8 @@ public class BfiServiceImpl implements IBfiService {
|
|||||||
}
|
}
|
||||||
String accessToken = getAccessToken();
|
String accessToken = getAccessToken();
|
||||||
BfiResultVO<BfiPageVO<BfiPayApplyVO>> result = commonCall("付款申请单查询", () -> client.payApplyQuery(accessToken,
|
BfiResultVO<BfiPageVO<BfiPayApplyVO>> result = commonCall("付款申请单查询", () -> client.payApplyQuery(accessToken,
|
||||||
param.getPageNo(), param.getPageSize(), param.getAwrpSrcCode(), param.getAwrpSrcSys(), param.getModifytimeS(), param.getModifytimeE()));
|
param.getPageNo(), param.getPageSize(), param.getAwrpSrcCode(), param.getAwrpSrcSys(), param.getBillno(),
|
||||||
|
param.getModifytimeS(), param.getModifytimeE()));
|
||||||
return result.getData();
|
return result.getData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user