mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-06 21:26:26 +08:00
ref 对账改造,支持原始对账单保存和下载
This commit is contained in:
@@ -18,12 +18,13 @@
|
||||
- [x] 支付接口优化
|
||||
- [x] 前端查询条件适配
|
||||
- [x] paymentId替换
|
||||
- [ ] 支付订单和退款订单页面添加实时金额汇总展示
|
||||
- [ ] 对账单改造
|
||||
- [x] 去除对账单明细按钮
|
||||
- [x] 增加对账结果计算和显示
|
||||
- [ ] 增加下载原始对账单功能
|
||||
- [ ] 保存原始的文件
|
||||
- [ ] 微信
|
||||
- [ ] 增加下载原始对账单功能(保证将明细文件进行储存)
|
||||
- [x] 保存原始的文件
|
||||
- [x] 微信
|
||||
- [x] 支付宝
|
||||
- [x] 云闪付
|
||||
- [ ] 解析原有文件, 可以转换为指定格式进行下载
|
||||
|
||||
@@ -8,16 +8,14 @@ import cn.bootx.platform.common.core.util.ValidationUtil;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.service.ReconcileDiffService;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.service.ReconcileQueryService;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.reconcile.service.ReconcileService;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.reconcile.ReconcileDetailDto;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.reconcile.ReconcileDiffRecordDto;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.reconcile.ReconcileTradeDetailDto;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.reconcile.ReconcileDiffDto;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.reconcile.ReconcileOrderDto;
|
||||
import cn.bootx.platform.daxpay.service.param.reconcile.ReconcileDetailQuery;
|
||||
import cn.bootx.platform.daxpay.service.param.reconcile.ReconcileDiffQuery;
|
||||
import cn.bootx.platform.daxpay.service.param.reconcile.ReconcileOrderCreate;
|
||||
import cn.bootx.platform.daxpay.service.param.reconcile.ReconcileOrderQuery;
|
||||
import cn.bootx.platform.daxpay.service.param.reconcile.*;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@@ -50,27 +48,34 @@ public class ReconcileOrderController {
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "手动上传对账单文件")
|
||||
@Operation(summary = "手动上传交易对账单文件")
|
||||
@PostMapping("/upload")
|
||||
public ResResult<Void> upload(Long id, MultipartFile file){
|
||||
reconcileService.upload(id,file);
|
||||
public ResResult<Void> upload(ReconcileUploadParam param, MultipartFile file){
|
||||
ValidationUtil.validateParam(param);
|
||||
reconcileService.upload(param,file);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "手动触发对账单比对")
|
||||
@Operation(summary = "手动触发交易对账单比对")
|
||||
@PostMapping("/compare")
|
||||
public ResResult<Void> compare(Long id){
|
||||
reconcileService.compare(id);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "订单分页")
|
||||
@Operation(summary = "下载原始交易对账单文件")
|
||||
@GetMapping("/downOriginal")
|
||||
public ResponseEntity<byte[]> downOriginal(Long id){
|
||||
return reconcileService.downOriginal(id);
|
||||
}
|
||||
|
||||
@Operation(summary = "对账单分页")
|
||||
@GetMapping("/page")
|
||||
public ResResult<PageResult<ReconcileOrderDto>> page(PageParam pageParam, ReconcileOrderQuery query){
|
||||
return Res.ok(reconcileQueryService.page(pageParam, query));
|
||||
}
|
||||
|
||||
@Operation(summary = "订单详情")
|
||||
@Operation(summary = "对账单详情")
|
||||
@GetMapping("/findById")
|
||||
public ResResult<ReconcileOrderDto> findById(Long id){
|
||||
return Res.ok(reconcileQueryService.findById(id));
|
||||
@@ -78,25 +83,25 @@ public class ReconcileOrderController {
|
||||
|
||||
@Operation(summary = "对账明细分页")
|
||||
@GetMapping("/detail/page")
|
||||
public ResResult<PageResult<ReconcileDetailDto>> pageDetail(PageParam pageParam, ReconcileDetailQuery query){
|
||||
public ResResult<PageResult<ReconcileTradeDetailDto>> pageDetail(PageParam pageParam, ReconcileDetailQuery query){
|
||||
return Res.ok(reconcileQueryService.pageDetail(pageParam, query));
|
||||
}
|
||||
|
||||
@Operation(summary = "对账明细详情")
|
||||
@GetMapping("/detail/findById")
|
||||
public ResResult<ReconcileDetailDto> findDetailById(Long id){
|
||||
public ResResult<ReconcileTradeDetailDto> findDetailById(Long id){
|
||||
return Res.ok(reconcileQueryService.findDetailById(id));
|
||||
}
|
||||
|
||||
@Operation(summary = "对账差异分页")
|
||||
@GetMapping("/diff/page")
|
||||
public ResResult<PageResult<ReconcileDiffRecordDto>> pageDiff(PageParam pageParam, ReconcileDiffQuery query){
|
||||
public ResResult<PageResult<ReconcileDiffDto>> pageDiff(PageParam pageParam, ReconcileDiffQuery query){
|
||||
return Res.ok(reconcileDiffService.page(pageParam, query));
|
||||
}
|
||||
|
||||
@Operation(summary = "对账差异详情")
|
||||
@GetMapping("/diff/findById")
|
||||
public ResResult<ReconcileDiffRecordDto> findDiffById(Long id){
|
||||
public ResResult<ReconcileDiffDto> findDiffById(Long id){
|
||||
return Res.ok(reconcileDiffService.findById(id));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package cn.bootx.platform.daxpay.service.code;
|
||||
|
||||
import cn.bootx.platform.common.core.exception.DataNotExistException;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 对账单文件
|
||||
* @author xxm
|
||||
@@ -12,11 +16,18 @@ import lombok.Getter;
|
||||
@AllArgsConstructor
|
||||
public enum ReconcileFileTypeEnum {
|
||||
|
||||
TOTAL("total", "汇总"),
|
||||
DETAIL("detail", "明细"),
|
||||
FUNDS("funds", "资金对账"),
|
||||
TRADE("trade", "交易对账"),
|
||||
ZIP("zip", "压缩包"),
|
||||
;
|
||||
|
||||
private final String code;
|
||||
private final String name;
|
||||
|
||||
public static ReconcileFileTypeEnum findByCode(String code){
|
||||
return Arrays.stream(values())
|
||||
.filter(value -> Objects.equals(value.getCode(), code))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new DataNotExistException("未知的对账文件类型"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.service.common.context;
|
||||
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileTradeDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileOrder;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
@@ -20,6 +20,6 @@ public class ReconcileLocal {
|
||||
private ReconcileOrder reconcileOrder;
|
||||
|
||||
/** 通用支付对账记录 */
|
||||
private List<ReconcileDetail> reconcileDetails;
|
||||
private List<ReconcileTradeDetail> reconcileTradeDetails;
|
||||
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import cn.bootx.platform.daxpay.service.core.channel.alipay.dao.AliReconcileBill
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.entity.AliReconcileBillDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.entity.AliReconcileBillTotal;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.dao.ReconcileFileManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileTradeDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileFile;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileOrder;
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
@@ -87,14 +87,15 @@ public class AliPayReconcileService {
|
||||
|
||||
// 获取对账单下载地址并下载
|
||||
String url = response.getBillDownloadUrl();
|
||||
byte[] bytes = HttpUtil.downloadBytes(url);
|
||||
byte[] zipBytes = HttpUtil.downloadBytes(url);
|
||||
// 使用 Apache commons-compress 包装流, 读取返回的对账CSV文件
|
||||
ZipArchiveInputStream zipArchiveInputStream = new ZipArchiveInputStream(new ByteArrayInputStream(bytes),"GBK");
|
||||
ZipArchiveInputStream zipArchiveInputStream = new ZipArchiveInputStream(new ByteArrayInputStream(zipBytes),"GBK");
|
||||
ZipArchiveEntry entry;
|
||||
List<AliReconcileBillDetail> billDetails = new ArrayList<>();
|
||||
List<AliReconcileBillTotal> billTotals = new ArrayList<>();
|
||||
while ((entry= zipArchiveInputStream.getNextZipEntry()) != null){
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(zipArchiveInputStream,"GBK"));
|
||||
byte[] bytes = IoUtil.readBytes(zipArchiveInputStream);
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bytes),"GBK"));
|
||||
List<String> strings = IoUtil.readLines(bufferedReader, new ArrayList<>());
|
||||
String name = entry.getName();
|
||||
if (StrUtil.endWith(name,"_业务明细(汇总).csv")){
|
||||
@@ -104,12 +105,11 @@ public class AliPayReconcileService {
|
||||
// 明细
|
||||
billDetails = this.parseDetail(strings);
|
||||
}
|
||||
// 保存原始对账文件
|
||||
this.saveOriginalFile(recordOrder, bytes);
|
||||
}
|
||||
// 保存原始对账文件
|
||||
this.saveOriginalFile(recordOrder, bytes);
|
||||
// 保存原始对账记录
|
||||
this.save(billDetails, billTotals);
|
||||
|
||||
// 将原始交易明细对账记录转换通用结构并保存到上下文中
|
||||
this.convertAndSave(billDetails);
|
||||
|
||||
@@ -162,25 +162,24 @@ public class AliPayReconcileService {
|
||||
* 转换为通用对账记录对象
|
||||
*/
|
||||
private void convertAndSave(List<AliReconcileBillDetail> billDetails){
|
||||
List<ReconcileDetail> collect = billDetails.stream()
|
||||
List<ReconcileTradeDetail> collect = billDetails.stream()
|
||||
.map(this::convert)
|
||||
.collect(Collectors.toList());
|
||||
// 写入到上下文中
|
||||
PaymentContextLocal.get().getReconcileInfo().setReconcileDetails(collect);
|
||||
PaymentContextLocal.get().getReconcileInfo().setReconcileTradeDetails(collect);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为通用对账记录对象
|
||||
*/
|
||||
private ReconcileDetail convert(AliReconcileBillDetail billDetail){
|
||||
private ReconcileTradeDetail convert(AliReconcileBillDetail billDetail){
|
||||
// 金额
|
||||
String orderAmount = billDetail.getOrderAmount();
|
||||
double v = Double.parseDouble(orderAmount) * 100;
|
||||
int amount = Math.abs(((int) v));
|
||||
|
||||
|
||||
// 默认为支付对账记录
|
||||
ReconcileDetail reconcileDetail = new ReconcileDetail()
|
||||
ReconcileTradeDetail reconcileTradeDetail = new ReconcileTradeDetail()
|
||||
.setReconcileId(billDetail.getReconcileId())
|
||||
.setTradeNo(billDetail.getOutTradeNo())
|
||||
.setType(ReconcileTradeEnum.PAY.getCode())
|
||||
@@ -192,15 +191,15 @@ public class AliPayReconcileService {
|
||||
String endTime = billDetail.getEndTime();
|
||||
if (StrUtil.isNotBlank(endTime)) {
|
||||
LocalDateTime time = LocalDateTimeUtil.parse(endTime, DatePattern.NORM_DATETIME_PATTERN);
|
||||
reconcileDetail.setTradeTime(time);
|
||||
reconcileTradeDetail.setTradeTime(time);
|
||||
}
|
||||
|
||||
// 退款覆盖更新对应的字段
|
||||
if (Objects.equals(billDetail.getTradeType(), "退款")){
|
||||
reconcileDetail.setTradeNo(billDetail.getBatchNo())
|
||||
reconcileTradeDetail.setTradeNo(billDetail.getBatchNo())
|
||||
.setType(ReconcileTradeEnum.REFUND.getCode());
|
||||
}
|
||||
return reconcileDetail;
|
||||
return reconcileTradeDetail;
|
||||
}
|
||||
|
||||
|
||||
@@ -243,7 +242,7 @@ public class AliPayReconcileService {
|
||||
PayChannelEnum channelEnum = PayChannelEnum.findByCode(reconcileOrder.getChannel());
|
||||
String date = LocalDateTimeUtil.format(reconcileOrder.getDate(), DatePattern.PURE_DATE_PATTERN);
|
||||
// 将原始文件进行保存 通道-日期
|
||||
String fileName = StrUtil.format("{}-{}.zip", channelEnum.getName(),date);
|
||||
String fileName = StrUtil.format("交易对账单-{}-{}.csv", channelEnum.getName(),date);
|
||||
UploadPretreatment uploadPretreatment = fileStorageService.of(bytes);
|
||||
if (StrUtil.isNotBlank(fileName)) {
|
||||
uploadPretreatment.setOriginalFilename(fileName);
|
||||
@@ -252,7 +251,7 @@ public class AliPayReconcileService {
|
||||
String fileId = upload.getId();
|
||||
ReconcileFile reconcileFile = new ReconcileFile().setFileId(Long.valueOf(fileId))
|
||||
.setReconcileId(reconcileOrder.getId())
|
||||
.setType(ReconcileFileTypeEnum.ZIP.getCode());
|
||||
.setType(ReconcileFileTypeEnum.TRADE.getCode());
|
||||
reconcileFileManager.save(reconcileFile);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.union.dao.UnionReconcileBillDetailManager;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.union.entity.UnionReconcileBillDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.dao.ReconcileFileManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileTradeDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileFile;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileOrder;
|
||||
import cn.bootx.platform.daxpay.service.sdk.union.api.UnionPayKit;
|
||||
@@ -81,17 +81,18 @@ public class UnionPayReconcileService {
|
||||
ZipArchiveEntry entry;
|
||||
List<UnionReconcileBillDetail> billDetails = new ArrayList<>();
|
||||
while ((entry= zipArchiveInputStream.getNextZipEntry()) != null){
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(zipArchiveInputStream,"GBK"));
|
||||
if (StrUtil.startWith(entry.getName(), RECONCILE_FILE_PREFIX)){
|
||||
byte[] bytes = IoUtil.readBytes(zipArchiveInputStream);
|
||||
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bytes),"GBK"));
|
||||
// 明细解析
|
||||
List<String> strings = IoUtil.readLines(bufferedReader, new ArrayList<>());
|
||||
billDetails = this.parseDetail(strings);
|
||||
// 保存原始对账记录文件
|
||||
this.saveOriginalFile(reconcileOrder,bytes);
|
||||
} else {
|
||||
// 汇总目前不进行处理
|
||||
}
|
||||
}
|
||||
// 保存原始对账记录文件
|
||||
this.saveOriginalFile(reconcileOrder,zipBytes);
|
||||
// 保存原始对账记录
|
||||
this.save(billDetails);
|
||||
// 转换为通用对账记录对象
|
||||
@@ -151,19 +152,19 @@ public class UnionPayReconcileService {
|
||||
* 转换为通用对账记录对象
|
||||
*/
|
||||
private void convertAndSave(List<UnionReconcileBillDetail> billDetails){
|
||||
List<ReconcileDetail> collect = billDetails.stream()
|
||||
List<ReconcileTradeDetail> collect = billDetails.stream()
|
||||
.map(this::convert)
|
||||
// 只处理支付和退款的对账记录
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
// 写入到上下文中
|
||||
PaymentContextLocal.get().getReconcileInfo().setReconcileDetails(collect);
|
||||
PaymentContextLocal.get().getReconcileInfo().setReconcileTradeDetails(collect);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为通用对账记录对象
|
||||
*/
|
||||
private ReconcileDetail convert(UnionReconcileBillDetail billDetail){
|
||||
private ReconcileTradeDetail convert(UnionReconcileBillDetail billDetail){
|
||||
ReconcileOrder reconcileOrder = PaymentContextLocal.get()
|
||||
.getReconcileInfo()
|
||||
.getReconcileOrder();
|
||||
@@ -172,7 +173,7 @@ public class UnionPayReconcileService {
|
||||
int amount = Integer.parseInt(orderAmount);
|
||||
|
||||
// 默认为支付对账记录
|
||||
ReconcileDetail reconcileDetail = new ReconcileDetail()
|
||||
ReconcileTradeDetail reconcileTradeDetail = new ReconcileTradeDetail()
|
||||
.setTitle("未知")
|
||||
.setReconcileId(billDetail.getReconcileId())
|
||||
.setTradeNo(billDetail.getOrderId())
|
||||
@@ -187,14 +188,14 @@ public class UnionPayReconcileService {
|
||||
String txnTime = year + billDetail.getTxnTime();
|
||||
if (StrUtil.isNotBlank(txnTime)) {
|
||||
LocalDateTime time = LocalDateTimeUtil.parse(txnTime, DatePattern.PURE_DATETIME_PATTERN);
|
||||
reconcileDetail.setTradeTime(time);
|
||||
reconcileTradeDetail.setTradeTime(time);
|
||||
}
|
||||
|
||||
// 退款覆盖更新对应的字段
|
||||
if (Objects.equals(billDetail.getTradeType(), UnionPayCode.RECONCILE_TYPE_REFUND)){
|
||||
reconcileDetail.setType(ReconcileTradeEnum.REFUND.getCode());
|
||||
reconcileTradeDetail.setType(ReconcileTradeEnum.REFUND.getCode());
|
||||
}
|
||||
return reconcileDetail;
|
||||
return reconcileTradeDetail;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,7 +214,7 @@ public class UnionPayReconcileService {
|
||||
PayChannelEnum channelEnum = PayChannelEnum.findByCode(reconcileOrder.getChannel());
|
||||
String date = LocalDateTimeUtil.format(reconcileOrder.getDate(), DatePattern.PURE_DATE_PATTERN);
|
||||
// 将原始文件进行保存 通道-日期
|
||||
String fileName = StrUtil.format("{}-{}.zip", channelEnum.getName(),date);
|
||||
String fileName = StrUtil.format("交易对账单-{}-{}.txt", channelEnum.getName(),date);
|
||||
UploadPretreatment uploadPretreatment = fileStorageService.of(bytes);
|
||||
if (StrUtil.isNotBlank(fileName)) {
|
||||
uploadPretreatment.setOriginalFilename(fileName);
|
||||
@@ -222,7 +223,7 @@ public class UnionPayReconcileService {
|
||||
String fileId = upload.getId();
|
||||
ReconcileFile reconcileFile = new ReconcileFile().setFileId(Long.valueOf(fileId))
|
||||
.setReconcileId(reconcileOrder.getId())
|
||||
.setType(ReconcileFileTypeEnum.ZIP.getCode());
|
||||
.setType(ReconcileFileTypeEnum.TRADE.getCode());
|
||||
reconcileFileManager.save(reconcileFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WxReconcileBi
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WxReconcileBillTotal;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WxReconcileFundFlowDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.dao.ReconcileFileManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileTradeDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileFile;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileOrder;
|
||||
import cn.hutool.core.codec.Base64;
|
||||
@@ -66,23 +66,24 @@ public class WechatPayReconcileService{
|
||||
|
||||
/**
|
||||
* 下载对账单并保存
|
||||
* @param date 对账日期 yyyyMMdd 格式
|
||||
*
|
||||
* @param recordOrder 对账订单
|
||||
* @param date 对账日期 yyyyMMdd 格式
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void downAndSave(String date, WeChatPayConfig config) {
|
||||
// TODO 修改为现将对账单全部下载下来, 然后再进行保存和解析
|
||||
|
||||
this.downBill(date, config);
|
||||
public void downAndSave(ReconcileOrder recordOrder, String date, WeChatPayConfig config) {
|
||||
this.downBill(recordOrder, date, config);
|
||||
// 资金对账单先不启用
|
||||
this.downFundFlow(date, config);
|
||||
// this.downFundFlow(date, config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载交易账单
|
||||
*
|
||||
* @param date 对账日期 yyyyMMdd 格式
|
||||
* @param recordOrder 对账订单
|
||||
* @param date 对账日期 yyyyMMdd 格式
|
||||
*/
|
||||
public void downBill(String date, WeChatPayConfig config){
|
||||
public void downBill(ReconcileOrder recordOrder, String date, WeChatPayConfig config){
|
||||
// 下载交易账单
|
||||
Map<String, String> params = DownloadBillModel.builder()
|
||||
.mch_id(config.getWxMchId())
|
||||
@@ -94,6 +95,9 @@ public class WechatPayReconcileService{
|
||||
.createSign(config.getApiKeyV2(), SignType.HMACSHA256);
|
||||
String result = WxPayApi.downloadBill(config.isSandbox(), params);
|
||||
|
||||
// 保存原始对账单文件
|
||||
this.saveOriginalFile(recordOrder, result);
|
||||
|
||||
// 验证返回数据是否成功
|
||||
this.verifyBillMsg(result);
|
||||
|
||||
@@ -153,30 +157,30 @@ public class WechatPayReconcileService{
|
||||
.collect(Collectors.toList());
|
||||
|
||||
billDetails.forEach(o->o.setRecordOrderId(reconcileOrder.getId()));
|
||||
// 保存原始对账单明细
|
||||
reconcileBillDetailManager.saveAll(billDetails);
|
||||
|
||||
// 将原始交易明细对账记录转换通用结构并保存到上下文中
|
||||
this.convertAndSave(billDetails);
|
||||
// 保存原始对账单明细
|
||||
reconcileBillDetailManager.saveAll(billDetails);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为通用对账记录对象
|
||||
*/
|
||||
public void convertAndSave(List<WxReconcileBillDetail> billDetails){
|
||||
List<ReconcileDetail> collect = billDetails.stream()
|
||||
List<ReconcileTradeDetail> collect = billDetails.stream()
|
||||
.map(this::convert)
|
||||
.collect(Collectors.toList());
|
||||
// 写入到上下文中
|
||||
PaymentContextLocal.get().getReconcileInfo().setReconcileDetails(collect);
|
||||
PaymentContextLocal.get().getReconcileInfo().setReconcileTradeDetails(collect);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为通用对账记录对象
|
||||
*/
|
||||
public ReconcileDetail convert(WxReconcileBillDetail billDetail){
|
||||
public ReconcileTradeDetail convert(WxReconcileBillDetail billDetail){
|
||||
// 默认为支付对账记录
|
||||
ReconcileDetail reconcileDetail = new ReconcileDetail()
|
||||
ReconcileTradeDetail reconcileTradeDetail = new ReconcileTradeDetail()
|
||||
.setReconcileId(billDetail.getRecordOrderId())
|
||||
.setTradeNo(billDetail.getMchOrderNo())
|
||||
.setTitle(billDetail.getSubject())
|
||||
@@ -185,7 +189,7 @@ public class WechatPayReconcileService{
|
||||
String transactionTime = billDetail.getTransactionTime();
|
||||
if (StrUtil.isNotBlank(transactionTime)) {
|
||||
LocalDateTime time = LocalDateTimeUtil.parse(transactionTime, DatePattern.NORM_DATETIME_PATTERN);
|
||||
reconcileDetail.setTradeTime(time);
|
||||
reconcileTradeDetail.setTradeTime(time);
|
||||
}
|
||||
|
||||
// 支付
|
||||
@@ -194,7 +198,7 @@ public class WechatPayReconcileService{
|
||||
String orderAmount = billDetail.getOrderAmount();
|
||||
double v = Double.parseDouble(orderAmount) * 100;
|
||||
int amount = Math.abs(((int) v));
|
||||
reconcileDetail.setType(ReconcileTradeEnum.PAY.getCode())
|
||||
reconcileTradeDetail.setType(ReconcileTradeEnum.PAY.getCode())
|
||||
.setAmount(amount);
|
||||
}
|
||||
// 退款
|
||||
@@ -203,7 +207,7 @@ public class WechatPayReconcileService{
|
||||
String refundAmount = billDetail.getApplyRefundAmount();
|
||||
double v = Double.parseDouble(refundAmount) * 100;
|
||||
int amount = Math.abs(((int) v));
|
||||
reconcileDetail.setType(ReconcileTradeEnum.REFUND.getCode())
|
||||
reconcileTradeDetail.setType(ReconcileTradeEnum.REFUND.getCode())
|
||||
.setAmount(amount)
|
||||
.setTradeNo(billDetail.getMchRefundNo());
|
||||
}
|
||||
@@ -211,7 +215,7 @@ public class WechatPayReconcileService{
|
||||
if (Objects.equals(billDetail.getStatus(), "REVOKED")){
|
||||
log.warn("对账出现已撤销记录, 后续进行处理");
|
||||
}
|
||||
return reconcileDetail;
|
||||
return reconcileTradeDetail;
|
||||
}
|
||||
|
||||
|
||||
@@ -314,12 +318,12 @@ public class WechatPayReconcileService{
|
||||
/**
|
||||
* 保存下载的原始对账文件
|
||||
*/
|
||||
private void saveOriginalFile(ReconcileOrder reconcileOrder,String text, ReconcileFileTypeEnum fileType) {
|
||||
private void saveOriginalFile(ReconcileOrder reconcileOrder, String text) {
|
||||
// 微信接收结果转换为 byte[]
|
||||
PayChannelEnum channelEnum = PayChannelEnum.findByCode(reconcileOrder.getChannel());
|
||||
String date = LocalDateTimeUtil.format(reconcileOrder.getDate(), DatePattern.PURE_DATE_PATTERN);
|
||||
// 将原始文件进行保存 通道-日期
|
||||
String fileName = StrUtil.format("{}-{}-{}.text", channelEnum.getName(),date,fileType.getName());
|
||||
String fileName = StrUtil.format("交易对账单-{}-{}.txt", channelEnum.getName(),date);
|
||||
byte[] bytes = StrUtil.bytes(text, CharsetUtil.CHARSET_UTF_8);
|
||||
UploadPretreatment uploadPretreatment = fileStorageService.of(bytes);
|
||||
if (StrUtil.isNotBlank(fileName)) {
|
||||
@@ -329,7 +333,7 @@ public class WechatPayReconcileService{
|
||||
String fileId = upload.getId();
|
||||
ReconcileFile reconcileFile = new ReconcileFile().setFileId(Long.valueOf(fileId))
|
||||
.setReconcileId(reconcileOrder.getId())
|
||||
.setType(fileType.getCode());
|
||||
.setType(ReconcileFileTypeEnum.TRADE.getCode());
|
||||
reconcileFileManager.save(reconcileFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package cn.bootx.platform.daxpay.service.core.order.reconcile.conver;
|
||||
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileDiffRecord;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileTradeDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileDiff;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileOrder;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.reconcile.ReconcileDetailDto;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.reconcile.ReconcileDiffRecordDto;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.reconcile.ReconcileTradeDetailDto;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.reconcile.ReconcileDiffDto;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.reconcile.ReconcileOrderDto;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
@@ -18,9 +18,9 @@ import org.mapstruct.factory.Mappers;
|
||||
public interface ReconcileConvert {
|
||||
ReconcileConvert CONVERT = Mappers.getMapper(ReconcileConvert.class);
|
||||
|
||||
ReconcileDetailDto convert(ReconcileDetail in);
|
||||
ReconcileTradeDetailDto convert(ReconcileTradeDetail in);
|
||||
|
||||
ReconcileDiffRecordDto convert(ReconcileDiffRecord in);
|
||||
ReconcileDiffDto convert(ReconcileDiff in);
|
||||
|
||||
ReconcileOrderDto convert(ReconcileOrder in);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import cn.bootx.platform.common.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.common.query.generator.QueryGenerator;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileDiffRecord;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileDiff;
|
||||
import cn.bootx.platform.daxpay.service.param.reconcile.ReconcileDiffQuery;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
@@ -20,14 +20,14 @@ import org.springframework.stereotype.Repository;
|
||||
@Slf4j
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class ReconcileDiffRecordManager extends BaseManager<ReconcileDiffRecordMapper, ReconcileDiffRecord> {
|
||||
public class ReconcileDiffManager extends BaseManager<ReconcileDiffMapper, ReconcileDiff> {
|
||||
|
||||
/**
|
||||
* 分页
|
||||
*/
|
||||
public Page<ReconcileDiffRecord> page(PageParam pageParam, ReconcileDiffQuery query){
|
||||
Page<ReconcileDiffRecord> mpPage = MpUtil.getMpPage(pageParam, ReconcileDiffRecord.class);
|
||||
QueryWrapper<ReconcileDiffRecord> generator = QueryGenerator.generator(query);
|
||||
public Page<ReconcileDiff> page(PageParam pageParam, ReconcileDiffQuery query){
|
||||
Page<ReconcileDiff> mpPage = MpUtil.getMpPage(pageParam, ReconcileDiff.class);
|
||||
QueryWrapper<ReconcileDiff> generator = QueryGenerator.generator(query);
|
||||
return this.page(mpPage,generator);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.service.core.order.reconcile.dao;
|
||||
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileDiffRecord;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileDiff;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@@ -10,5 +10,5 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
* @since 2024/2/28
|
||||
*/
|
||||
@Mapper
|
||||
public interface ReconcileDiffRecordMapper extends BaseMapper<ReconcileDiffRecord> {
|
||||
public interface ReconcileDiffMapper extends BaseMapper<ReconcileDiff> {
|
||||
}
|
||||
@@ -5,6 +5,8 @@ import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileFil
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author xxm
|
||||
@@ -13,4 +15,11 @@ import org.springframework.stereotype.Repository;
|
||||
@Slf4j
|
||||
@Repository
|
||||
public class ReconcileFileManager extends BaseManager<ReconcileFileMapper, ReconcileFile> {
|
||||
|
||||
/**
|
||||
* 根据对账单ID查询对账单文件
|
||||
*/
|
||||
public List<ReconcileFile> findAllByReconcileId(Long reconcileId) {
|
||||
return findAllByField(ReconcileFile::getReconcileId, reconcileId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import cn.bootx.platform.common.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.common.query.generator.QueryGenerator;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileTradeDetail;
|
||||
import cn.bootx.platform.daxpay.service.param.reconcile.ReconcileDetailQuery;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
@@ -22,22 +22,23 @@ import java.util.List;
|
||||
@Slf4j
|
||||
@Repository
|
||||
@RequiredArgsConstructor
|
||||
public class ReconcileDetailManager extends BaseManager<ReconcileDetailMapper, ReconcileDetail> {
|
||||
public class ReconcileTradeDetailManager extends BaseManager<ReconcileTradeDetailMapper, ReconcileTradeDetail> {
|
||||
|
||||
|
||||
/**
|
||||
* 根据订单id查询
|
||||
*/
|
||||
public List<ReconcileDetail> findAllByReconcileId(Long reconcileId){
|
||||
return this.findAllByField(ReconcileDetail::getReconcileId, reconcileId);
|
||||
public List<ReconcileTradeDetail> findAllByReconcileId(Long reconcileId){
|
||||
return this.findAllByField(ReconcileTradeDetail::getReconcileId, reconcileId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页
|
||||
*/
|
||||
public Page<ReconcileDetail> page(PageParam pageParam, ReconcileDetailQuery query){
|
||||
Page<ReconcileDetail> mpPage = MpUtil.getMpPage(pageParam, ReconcileDetail.class);
|
||||
QueryWrapper<ReconcileDetail> generator = QueryGenerator.generator(query);
|
||||
public Page<ReconcileTradeDetail> page(PageParam pageParam, ReconcileDetailQuery query){
|
||||
Page<ReconcileTradeDetail> mpPage = MpUtil.getMpPage(pageParam, ReconcileTradeDetail.class);
|
||||
QueryWrapper<ReconcileTradeDetail> generator = QueryGenerator.generator(query);
|
||||
return this.page(mpPage,generator);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.service.core.order.reconcile.dao;
|
||||
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileTradeDetail;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@@ -10,5 +10,5 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
* @since 2024/1/20
|
||||
*/
|
||||
@Mapper
|
||||
public interface ReconcileDetailMapper extends BaseMapper<ReconcileDetail> {
|
||||
public interface ReconcileTradeDetailMapper extends BaseMapper<ReconcileTradeDetail> {
|
||||
}
|
||||
@@ -6,8 +6,7 @@ import cn.bootx.platform.daxpay.code.ReconcileTradeEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.ReconcileDiffTypeEnum;
|
||||
import cn.bootx.platform.daxpay.service.common.typehandler.ReconcileDiffTypeHandler;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.conver.ReconcileConvert;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.ReconcileDiff;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.reconcile.ReconcileDiffRecordDto;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.reconcile.ReconcileDiffDto;
|
||||
import cn.bootx.table.modify.annotation.DbColumn;
|
||||
import cn.bootx.table.modify.annotation.DbTable;
|
||||
import cn.bootx.table.modify.mysql.annotation.DbMySqlFieldType;
|
||||
@@ -31,16 +30,24 @@ import java.util.List;
|
||||
@Accessors(chain = true)
|
||||
@DbTable(comment = "对账差异单")
|
||||
@TableName(value = "pay_reconcile_diff_record",autoResultMap = true)
|
||||
public class ReconcileDiffRecord extends MpBaseEntity implements EntityBaseFunction<ReconcileDiffRecordDto> {
|
||||
public class ReconcileDiff extends MpBaseEntity implements EntityBaseFunction<ReconcileDiffDto> {
|
||||
|
||||
/** 对账单ID */
|
||||
@DbColumn(comment = "对账单ID")
|
||||
private Long reconcileId;
|
||||
|
||||
/** 对账号 */
|
||||
@DbColumn(comment = "对账号")
|
||||
private String reconcileNo;
|
||||
|
||||
/** 对账单明细ID */
|
||||
@DbColumn(comment = "对账单明细ID")
|
||||
private Long detailId;
|
||||
|
||||
/** 对账日期 */
|
||||
@DbColumn(comment = "对账日期")
|
||||
private LocalDateTime reconcileDate;
|
||||
|
||||
/** 本地交易号 */
|
||||
@DbColumn(comment = "本地交易号")
|
||||
private String tradeNo;
|
||||
@@ -67,11 +74,11 @@ public class ReconcileDiffRecord extends MpBaseEntity implements EntityBaseFunct
|
||||
private Integer outAmount;
|
||||
|
||||
/**
|
||||
* 订单类型
|
||||
* 交易类型
|
||||
* @see ReconcileTradeEnum
|
||||
*/
|
||||
@DbColumn(comment = "订单类型")
|
||||
private String orderType;
|
||||
@DbColumn(comment = "交易类型")
|
||||
private String tradeType;
|
||||
|
||||
/**
|
||||
* 差异类型
|
||||
@@ -83,15 +90,15 @@ public class ReconcileDiffRecord extends MpBaseEntity implements EntityBaseFunct
|
||||
/**
|
||||
* 差异内容, 存储json字符串, 格式为
|
||||
* {属性: '标题', 本地字段值:'标题1', 网关字段值: '标题2'}
|
||||
* @see ReconcileDiff
|
||||
* @see cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.ReconcileDiff
|
||||
*/
|
||||
@DbColumn(comment = "差异内容")
|
||||
@TableField(typeHandler = ReconcileDiffTypeHandler.class)
|
||||
@DbMySqlFieldType(MySqlFieldTypeEnum.LONGTEXT)
|
||||
private List<ReconcileDiff> diffs;
|
||||
private List<cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.ReconcileDiff> diffs;
|
||||
|
||||
@Override
|
||||
public ReconcileDiffRecordDto toDto() {
|
||||
public ReconcileDiffDto toDto() {
|
||||
return ReconcileConvert.CONVERT.convert(this);
|
||||
}
|
||||
}
|
||||
@@ -10,14 +10,14 @@ import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
*
|
||||
* 原始对账单文件
|
||||
* @author xxm
|
||||
* @since 2024/5/3
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@DbTable(comment = "对账单文件")
|
||||
@DbTable(comment = "原始对账单文件")
|
||||
@TableName("pay_reconcile_file")
|
||||
public class ReconcileFile extends MpIdEntity {
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ import lombok.experimental.Accessors;
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
* 支付对账单订单
|
||||
* 支付对账单订单(交易对账单, 不包括资金对账)
|
||||
* @author xxm
|
||||
* @since 2024/1/18
|
||||
*/
|
||||
@@ -44,24 +44,16 @@ public class ReconcileOrder extends MpCreateEntity implements EntityBaseFunction
|
||||
@DbColumn(comment = "通道")
|
||||
private String channel;
|
||||
|
||||
/** 明细对账文件是否下载成功 */
|
||||
/** 交易对账文件是否下载成功 */
|
||||
@DbColumn(comment = "明细对账单下载")
|
||||
private boolean detailDown;
|
||||
private boolean downOrUpload;
|
||||
|
||||
/** 明细是否比对完成 */
|
||||
/** 交易对账文件是否比对完成 */
|
||||
@DbColumn(comment = "明细对账单比对")
|
||||
private boolean detailCompare;
|
||||
|
||||
/** 汇总对账文件是否下载成功 */
|
||||
@DbColumn(comment = "汇总对账单下载")
|
||||
private boolean totalDown;
|
||||
|
||||
/** 汇总是否比对完成 */
|
||||
@DbColumn(comment = "汇总对账单比对")
|
||||
private boolean totalCompare;
|
||||
private boolean compare;
|
||||
|
||||
/**
|
||||
* 对账结果
|
||||
* 交易对账结果
|
||||
* @see ReconcileResultEnum
|
||||
*/
|
||||
@DbColumn(comment = "对账结果")
|
||||
|
||||
@@ -4,7 +4,7 @@ import cn.bootx.platform.common.core.function.EntityBaseFunction;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpCreateEntity;
|
||||
import cn.bootx.platform.daxpay.service.code.PaymentTypeEnum;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.conver.ReconcileConvert;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.reconcile.ReconcileDetailDto;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.reconcile.ReconcileTradeDetailDto;
|
||||
import cn.bootx.table.modify.annotation.DbColumn;
|
||||
import cn.bootx.table.modify.annotation.DbTable;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
@@ -15,16 +15,16 @@ import lombok.experimental.Accessors;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 通用支付对账记录, 从三方系统下载的交易记录
|
||||
* 对账-第三方交易明细, 从三方系统下载的交易记录
|
||||
* @author xxm
|
||||
* @since 2024/1/18
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@DbTable(comment = "支付对账记录")
|
||||
@TableName("pay_reconcile_detail")
|
||||
public class ReconcileDetail extends MpCreateEntity implements EntityBaseFunction<ReconcileDetailDto> {
|
||||
@DbTable(comment = "对账-第三方交易明细")
|
||||
@TableName("pay_reconcile_trade_detail")
|
||||
public class ReconcileTradeDetail extends MpCreateEntity implements EntityBaseFunction<ReconcileTradeDetailDto> {
|
||||
|
||||
/** 关联对账订单ID */
|
||||
@DbColumn(comment = "关联对账订单ID")
|
||||
@@ -59,7 +59,7 @@ public class ReconcileDetail extends MpCreateEntity implements EntityBaseFunctio
|
||||
|
||||
|
||||
@Override
|
||||
public ReconcileDetailDto toDto() {
|
||||
public ReconcileTradeDetailDto toDto() {
|
||||
return ReconcileConvert.CONVERT.convert(this);
|
||||
}
|
||||
}
|
||||
@@ -4,9 +4,9 @@ import cn.bootx.platform.common.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.common.core.rest.PageResult;
|
||||
import cn.bootx.platform.common.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.dao.ReconcileDiffRecordManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileDiffRecord;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.reconcile.ReconcileDiffRecordDto;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.dao.ReconcileDiffManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileDiff;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.reconcile.ReconcileDiffDto;
|
||||
import cn.bootx.platform.daxpay.service.param.reconcile.ReconcileDiffQuery;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -23,27 +23,26 @@ import java.util.List;
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ReconcileDiffService {
|
||||
private final ReconcileDiffRecordManager recordManager;
|
||||
|
||||
private final ReconcileDiffManager recordManager;
|
||||
|
||||
/**
|
||||
* 批量保存
|
||||
*/
|
||||
public void saveAll(List<ReconcileDiffRecord> diffRecords) {
|
||||
public void saveAll(List<ReconcileDiff> diffRecords) {
|
||||
recordManager.saveAll(diffRecords);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*/
|
||||
public PageResult<ReconcileDiffRecordDto> page(PageParam pageParam, ReconcileDiffQuery query) {
|
||||
public PageResult<ReconcileDiffDto> page(PageParam pageParam, ReconcileDiffQuery query) {
|
||||
return MpUtil.convert2DtoPageResult(recordManager.page(pageParam, query));
|
||||
}
|
||||
|
||||
/**
|
||||
* 详情查询
|
||||
*/
|
||||
public ReconcileDiffRecordDto findById(Long id) {
|
||||
return recordManager.findById(id).map(ReconcileDiffRecord::toDto).orElseThrow(() -> new DataNotExistException("不存在的对账差异单"));
|
||||
public ReconcileDiffDto findById(Long id) {
|
||||
return recordManager.findById(id).map(ReconcileDiff::toDto).orElseThrow(() -> new DataNotExistException("不存在的对账差异单"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,12 @@ import cn.bootx.platform.common.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.common.core.rest.PageResult;
|
||||
import cn.bootx.platform.common.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.dao.ReconcileDetailManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.dao.ReconcileOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.dao.ReconcileTradeDetailManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileOrder;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.reconcile.ReconcileDetailDto;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileTradeDetail;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.reconcile.ReconcileOrderDto;
|
||||
import cn.bootx.platform.daxpay.service.dto.order.reconcile.ReconcileTradeDetailDto;
|
||||
import cn.bootx.platform.daxpay.service.param.reconcile.ReconcileDetailQuery;
|
||||
import cn.bootx.platform.daxpay.service.param.reconcile.ReconcileOrderQuery;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -26,7 +26,7 @@ import org.springframework.stereotype.Service;
|
||||
@RequiredArgsConstructor
|
||||
public class ReconcileQueryService {
|
||||
private final ReconcileOrderManager orderManager;
|
||||
private final ReconcileDetailManager detailManager;
|
||||
private final ReconcileTradeDetailManager detailManager;
|
||||
|
||||
/**
|
||||
* 分页
|
||||
@@ -46,16 +46,15 @@ public class ReconcileQueryService {
|
||||
/**
|
||||
* 明细分页
|
||||
*/
|
||||
public PageResult<ReconcileDetailDto> pageDetail(PageParam pageParam, ReconcileDetailQuery query){
|
||||
public PageResult<ReconcileTradeDetailDto> pageDetail(PageParam pageParam, ReconcileDetailQuery query){
|
||||
return MpUtil.convert2DtoPageResult(detailManager.page(pageParam, query));
|
||||
}
|
||||
|
||||
/**
|
||||
* 明细详情
|
||||
*/
|
||||
public ReconcileDetailDto findDetailById(Long id){
|
||||
return detailManager.findById(id).map(ReconcileDetail::toDto)
|
||||
public ReconcileTradeDetailDto findDetailById(Long id){
|
||||
return detailManager.findById(id).map(ReconcileTradeDetail::toDto)
|
||||
.orElseThrow(()->new DataNotExistException("对账详情不存在"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.reconcile.service;
|
||||
|
||||
import cn.bootx.platform.common.core.function.CollectorsFunction;
|
||||
import cn.bootx.platform.common.core.util.CollUtil;
|
||||
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.ReconcileTradeEnum;
|
||||
import cn.bootx.platform.daxpay.code.RefundStatusEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.PaymentTypeEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.ReconcileDiffTypeEnum;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileTradeDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileDiff;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.dao.RefundOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.GeneralTradeInfo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 对账支撑服务
|
||||
* @author xxm
|
||||
* @since 2024/5/4
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ReconcileAssistService {
|
||||
|
||||
private final PayOrderManager payOrderManager;
|
||||
|
||||
private final RefundOrderManager refundOrderManager;
|
||||
|
||||
|
||||
/**
|
||||
* 获取通用对账对象, 将支付/退款订单转换为对账对象
|
||||
*/
|
||||
public List<GeneralTradeInfo> getGeneralTradeInfoList(ReconcileOrder reconcileOrder){
|
||||
List<GeneralTradeInfo> generalTradeInfoList = new ArrayList<>();
|
||||
// 查询流水
|
||||
LocalDateTime localDateTime = LocalDateTimeUtil.date2DateTime(reconcileOrder.getDate());
|
||||
LocalDateTime start = LocalDateTimeUtil.beginOfDay(localDateTime);
|
||||
LocalDateTime end = LocalDateTimeUtil.endOfDay(localDateTime);
|
||||
|
||||
// 下载支付订单
|
||||
List<PayOrder> payOrders = payOrderManager.findReconcile(reconcileOrder.getChannel(), start, end, PayStatusEnum.SUCCESS, PayStatusEnum.PARTIAL_REFUND, PayStatusEnum.REFUNDING, PayStatusEnum.REFUNDED);
|
||||
List<RefundOrder> refundOrders = refundOrderManager.findReconcile(reconcileOrder.getChannel(), start, end, RefundStatusEnum.SUCCESS);
|
||||
for (PayOrder payOrder : payOrders) {
|
||||
generalTradeInfoList.add(new GeneralTradeInfo()
|
||||
.setTitle(payOrder.getTitle())
|
||||
.setTradeNo(payOrder.getOrderNo())
|
||||
.setOutTradeNo(payOrder.getOutOrderNo())
|
||||
.setFinishTime(payOrder.getPayTime())
|
||||
.setType(PaymentTypeEnum.PAY.getCode())
|
||||
.setAmount(payOrder.getAmount())
|
||||
);
|
||||
}
|
||||
for (RefundOrder refundOrder : refundOrders) {
|
||||
generalTradeInfoList.add(new GeneralTradeInfo()
|
||||
.setTitle(refundOrder.getTitle())
|
||||
.setTradeNo(refundOrder.getOrderNo())
|
||||
.setOutTradeNo(refundOrder.getOutOrderNo())
|
||||
.setFinishTime(refundOrder.getFinishTime())
|
||||
.setType(PaymentTypeEnum.REFUND.getCode())
|
||||
.setAmount(refundOrder.getAmount()));
|
||||
}
|
||||
return generalTradeInfoList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 比对生成对账差异单
|
||||
* 1. 远程有, 本地无
|
||||
* 2. 远程无, 本地有
|
||||
* 3. 远程有, 本地有, 但状态不一致
|
||||
*
|
||||
* @param reconcileOrder 对账单
|
||||
* @param localTrades 本地交易订单
|
||||
* @param outDetails 远程对账明细
|
||||
*/
|
||||
public List<ReconcileDiff> generateDiffRecord(ReconcileOrder reconcileOrder,
|
||||
List<GeneralTradeInfo> localTrades,
|
||||
List<ReconcileTradeDetail> outDetails){
|
||||
if (CollUtil.isEmpty(outDetails) || CollUtil.isEmpty(localTrades)){
|
||||
return new ArrayList<>();
|
||||
}
|
||||
// 差异内容
|
||||
List<ReconcileDiff> diffRecords = new ArrayList<>();
|
||||
|
||||
// 三方对账订单
|
||||
Map<String, ReconcileTradeDetail> outDetailMap = outDetails.stream()
|
||||
.collect(Collectors.toMap(ReconcileTradeDetail::getTradeNo, Function.identity(), CollectorsFunction::retainLatest));
|
||||
// 本地订单记录
|
||||
Map<String, GeneralTradeInfo> localTradeMap = localTrades.stream()
|
||||
.collect(Collectors.toMap(GeneralTradeInfo::getTradeNo, Function.identity(), CollectorsFunction::retainLatest));
|
||||
// 对账与比对
|
||||
for (ReconcileTradeDetail outDetail : outDetails) {
|
||||
// 判断本地有没有记录, 流水没有记录查询本地订单
|
||||
GeneralTradeInfo localTrade = localTradeMap.get(outDetail.getTradeNo());
|
||||
if (Objects.isNull(localTrade)){
|
||||
log.info("本地订单不存在: {}", outDetail.getTradeNo());
|
||||
ReconcileDiff diffRecord = new ReconcileDiff()
|
||||
.setDiffType(ReconcileDiffTypeEnum.LOCAL_NOT_EXISTS.getCode())
|
||||
.setTradeNo(outDetail.getTradeNo())
|
||||
.setDetailId(outDetail.getId())
|
||||
.setReconcileId(reconcileOrder.getId())
|
||||
.setTitle(outDetail.getTitle())
|
||||
.setOrderType(outDetail.getType())
|
||||
.setOutOrderNo(outDetail.getOutTradeNo())
|
||||
.setOutAmount(outDetail.getAmount())
|
||||
.setTradeTime(outDetail.getTradeTime());
|
||||
diffRecords.add(diffRecord);
|
||||
continue;
|
||||
}
|
||||
// 如果远程和本地都存在, 比对差异
|
||||
List<cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.ReconcileDiff> reconcileDiffs = this.reconcileDiff(outDetail, localTrade);
|
||||
if (CollUtil.isNotEmpty(reconcileDiffs)) {
|
||||
ReconcileDiff diffRecord = new ReconcileDiff()
|
||||
.setReconcileId(reconcileOrder.getId())
|
||||
.setDetailId(outDetail.getId())
|
||||
.setDiffType(ReconcileDiffTypeEnum.NOT_MATCH.getCode())
|
||||
.setTradeNo(outDetail.getTradeNo())
|
||||
.setTitle(outDetail.getTitle())
|
||||
.setOrderType(outDetail.getType())
|
||||
.setOutOrderNo(outDetail.getOutTradeNo())
|
||||
.setOutAmount(outDetail.getAmount())
|
||||
.setAmount(localTrade.getAmount())
|
||||
.setDiffs(reconcileDiffs)
|
||||
.setTradeTime(outDetail.getTradeTime());
|
||||
diffRecords.add(diffRecord);
|
||||
}
|
||||
}
|
||||
// 本地与对账单比对, 找出本地有, 远程没有的记录
|
||||
for (GeneralTradeInfo localTrade : localTrades) {
|
||||
ReconcileTradeDetail outDetail = outDetailMap.get(localTrade.getTradeNo());
|
||||
if (Objects.isNull(outDetail)){
|
||||
ReconcileDiff diffRecord = new ReconcileDiff()
|
||||
.setDiffType(ReconcileDiffTypeEnum.LOCAL_NOT_EXISTS.getCode())
|
||||
.setTradeNo(localTrade.getTradeNo())
|
||||
.setReconcileId(reconcileOrder.getId())
|
||||
.setDetailId(null)
|
||||
.setTitle(localTrade.getTitle())
|
||||
.setOrderType(localTrade.getType())
|
||||
.setOutOrderNo(localTrade.getOutTradeNo())
|
||||
.setAmount(localTrade.getAmount())
|
||||
.setTradeTime(localTrade.getFinishTime());
|
||||
diffRecords.add(diffRecord);
|
||||
log.info("远程订单不存在: {}", localTrade.getTradeNo());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return diffRecords;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断订单之间存在哪些差异
|
||||
* @param outDetail 下载的对账订单
|
||||
* @param localTrade 本地交易订单
|
||||
*/
|
||||
private List<cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.ReconcileDiff> reconcileDiff(ReconcileTradeDetail outDetail, GeneralTradeInfo localTrade){
|
||||
List<cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.ReconcileDiff> diffs = new ArrayList<>();
|
||||
|
||||
// 判断类型是否相同
|
||||
if (Objects.equals(outDetail.getType(), ReconcileTradeEnum.PAY.getCode())
|
||||
&& !Objects.equals(localTrade.getType(), PaymentTypeEnum.PAY.getCode())){
|
||||
log.warn("订单类型不一致: {},{}", outDetail.getType(), localTrade.getType());
|
||||
diffs.add(new cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.ReconcileDiff().setFieldName("订单类型").setLocalValue(outDetail.getType()).setOutValue(localTrade.getType()));
|
||||
}
|
||||
if (Objects.equals(outDetail.getType(), ReconcileTradeEnum.REFUND.getCode())
|
||||
&& !Objects.equals(localTrade.getType(), PaymentTypeEnum.REFUND.getCode())){
|
||||
log.warn("订单类型不一致: {},{}", outDetail.getType(), localTrade.getType());
|
||||
diffs.add(new cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.ReconcileDiff().setFieldName("订单类型").setLocalValue(outDetail.getType()).setOutValue(localTrade.getType()));
|
||||
}
|
||||
|
||||
// 判断名称是否一致
|
||||
if (!Objects.equals(outDetail.getTitle(), localTrade.getTitle())){
|
||||
log.warn("订单名称不一致: {},{}", outDetail.getTitle(), localTrade.getTitle());
|
||||
diffs.add(new cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.ReconcileDiff().setFieldName("订单名称").setLocalValue(outDetail.getTitle()).setOutValue(localTrade.getTitle()));
|
||||
}
|
||||
|
||||
// 判断金额是否一致
|
||||
if (!Objects.equals(outDetail.getAmount(), localTrade.getAmount())){
|
||||
log.warn("订单金额不一致: {},{}", outDetail.getAmount(), localTrade.getAmount());
|
||||
diffs.add(new cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.ReconcileDiff().setFieldName("订单金额")
|
||||
.setLocalValue(String.valueOf(outDetail.getAmount()))
|
||||
.setOutValue(String.valueOf(localTrade.getAmount())));
|
||||
}
|
||||
return diffs;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,51 +1,46 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.reconcile.service;
|
||||
|
||||
import cn.bootx.platform.common.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.common.core.function.CollectorsFunction;
|
||||
import cn.bootx.platform.common.core.util.CollUtil;
|
||||
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
|
||||
import cn.bootx.platform.daxpay.code.PayStatusEnum;
|
||||
import cn.bootx.platform.daxpay.code.ReconcileTradeEnum;
|
||||
import cn.bootx.platform.daxpay.code.RefundStatusEnum;
|
||||
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.service.code.PaymentTypeEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.ReconcileDiffTypeEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.ReconcileFileTypeEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.ReconcileResultEnum;
|
||||
import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.dao.ReconcileDetailManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.dao.ReconcileFileManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.dao.ReconcileTradeDetailManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.dao.ReconcileOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileDiffRecord;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileFile;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileTradeDetail;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileDiff;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.service.ReconcileDiffService;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.service.ReconcileOrderService;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.dao.RefundOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrder;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.GeneralTradeInfo;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.ReconcileDiff;
|
||||
import cn.bootx.platform.daxpay.service.core.payment.reconcile.factory.ReconcileStrategyFactory;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsReconcileStrategy;
|
||||
import cn.bootx.platform.daxpay.service.param.reconcile.ReconcileUploadParam;
|
||||
import cn.bootx.platform.daxpay.util.OrderNoGenerateUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.dromara.x.file.storage.core.FileInfo;
|
||||
import org.dromara.x.file.storage.core.FileStorageService;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 对账服务
|
||||
* 对账服务,
|
||||
* @author xxm
|
||||
* @since 2024/1/17
|
||||
*/
|
||||
@@ -59,11 +54,13 @@ public class ReconcileService {
|
||||
|
||||
private final ReconcileOrderManager reconcileOrderManager;
|
||||
|
||||
private final ReconcileDetailManager reconcileDetailManager;
|
||||
private final ReconcileTradeDetailManager reconcileTradeDetailManager;
|
||||
|
||||
private final PayOrderManager payOrderManager;
|
||||
private final ReconcileAssistService reconcileAssistService;
|
||||
|
||||
private final RefundOrderManager refundOrderManager;
|
||||
private final ReconcileFileManager reconcileFileManager;
|
||||
|
||||
private final FileStorageService fileStorageService;
|
||||
|
||||
/**
|
||||
* 创建对账订单
|
||||
@@ -88,11 +85,11 @@ public class ReconcileService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载对账单并进行保存
|
||||
* 下载交易对账单并进行保存
|
||||
*/
|
||||
public void downAndSave(ReconcileOrder reconcileOrder) {
|
||||
// 如果对账单已经存在
|
||||
if (reconcileOrder.isDetailDown() && reconcileOrder.isTotalDown()){
|
||||
if (reconcileOrder.isDownOrUpload()){
|
||||
throw new PayFailureException("对账单文件已经下载或上传");
|
||||
}
|
||||
// 将对账订单写入到上下文中
|
||||
@@ -103,8 +100,7 @@ public class ReconcileService {
|
||||
reconcileStrategy.doBeforeHandler();
|
||||
try {
|
||||
reconcileStrategy.downAndSave();
|
||||
reconcileOrder.setDetailDown(true)
|
||||
.setTotalDown(true)
|
||||
reconcileOrder.setDownOrUpload(true)
|
||||
.setErrorMsg(null);
|
||||
reconcileOrderService.update(reconcileOrder);
|
||||
} catch (Exception e) {
|
||||
@@ -115,29 +111,29 @@ public class ReconcileService {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
// 保存转换后的通用结构对账单
|
||||
List<ReconcileDetail> reconcileDetails = PaymentContextLocal.get()
|
||||
List<ReconcileTradeDetail> reconcileTradeDetails = PaymentContextLocal.get()
|
||||
.getReconcileInfo()
|
||||
.getReconcileDetails();
|
||||
reconcileDetailManager.saveAll(reconcileDetails);
|
||||
.getReconcileTradeDetails();
|
||||
reconcileTradeDetailManager.saveAll(reconcileTradeDetails);
|
||||
}
|
||||
|
||||
/**
|
||||
* 手动传输对账单
|
||||
* @param id 对账单ID
|
||||
* @param file 文件
|
||||
* 手动传输交易对账单
|
||||
*/
|
||||
public void upload(Long id, MultipartFile file) {
|
||||
ReconcileOrder reconcileOrder = reconcileOrderService.findById(id)
|
||||
public void upload(ReconcileUploadParam param, MultipartFile file) {
|
||||
ReconcileOrder reconcileOrder = reconcileOrderService.findById(param.getId())
|
||||
.orElseThrow(() -> new DataNotExistException("未找到对账订单"));
|
||||
// 将对账订单写入到上下文中
|
||||
PaymentContextLocal.get().getReconcileInfo().setReconcileOrder(reconcileOrder);
|
||||
AbsReconcileStrategy reconcileStrategy = ReconcileStrategyFactory.create(reconcileOrder.getChannel());
|
||||
reconcileStrategy.setRecordOrder(reconcileOrder);
|
||||
reconcileStrategy.doBeforeHandler();
|
||||
|
||||
// 上传类型
|
||||
ReconcileFileTypeEnum fileType = ReconcileFileTypeEnum.findByCode(param.getFileType());
|
||||
try {
|
||||
reconcileStrategy.upload(file);
|
||||
reconcileOrder.setDownOrUpload(true)
|
||||
.setErrorMsg(null);
|
||||
reconcileStrategy.upload(file, fileType);
|
||||
reconcileOrder.setErrorMsg(null);
|
||||
reconcileOrderService.update(reconcileOrder);
|
||||
} catch (Exception e) {
|
||||
log.error("上传对账单异常", e);
|
||||
@@ -146,25 +142,25 @@ public class ReconcileService {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
// 保存转换后的通用结构对账单
|
||||
List<ReconcileDetail> reconcileDetails = PaymentContextLocal.get()
|
||||
List<ReconcileTradeDetail> reconcileTradeDetails = PaymentContextLocal.get()
|
||||
.getReconcileInfo()
|
||||
.getReconcileDetails();
|
||||
reconcileDetailManager.saveAll(reconcileDetails);
|
||||
.getReconcileTradeDetails();
|
||||
reconcileTradeDetailManager.saveAll(reconcileTradeDetails);
|
||||
}
|
||||
/**
|
||||
* 对账单比对
|
||||
* 对账单明细比对
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void compareDetail(Long reconcileOrderId){
|
||||
public void compare(Long reconcileOrderId){
|
||||
ReconcileOrder reconcileOrder = reconcileOrderService.findById(reconcileOrderId)
|
||||
.orElseThrow(() -> new DataNotExistException("未找到对账订单"));
|
||||
this.compareDetail(reconcileOrder);
|
||||
this.compare(reconcileOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* 对账单比对
|
||||
* 交易对账比对
|
||||
*/
|
||||
public void compareDetail(ReconcileOrder reconcileOrder){
|
||||
public void compare(ReconcileOrder reconcileOrder){
|
||||
// 判断是否已经下载了对账单明细
|
||||
if (!reconcileOrder.isDownOrUpload()){
|
||||
throw new PayFailureException("请先下载对账单");
|
||||
@@ -174,7 +170,7 @@ public class ReconcileService {
|
||||
throw new PayFailureException("对账单比对已经完成");
|
||||
}
|
||||
// 查询对账单
|
||||
List<ReconcileDetail> reconcileDetails = reconcileDetailManager.findAllByReconcileId(reconcileOrder.getId());
|
||||
List<ReconcileTradeDetail> reconcileTradeDetails = reconcileTradeDetailManager.findAllByReconcileId(reconcileOrder.getId());
|
||||
// 构建对账策略
|
||||
AbsReconcileStrategy reconcileStrategy = ReconcileStrategyFactory.create(reconcileOrder.getChannel());
|
||||
// 初始化参数
|
||||
@@ -182,8 +178,8 @@ public class ReconcileService {
|
||||
|
||||
try {
|
||||
// 执行比对任务, 获取对账差异记录并保存
|
||||
List<GeneralTradeInfo> generalTradeInfo = this.getGeneralTradeInfoList(reconcileOrder);
|
||||
List<ReconcileDiffRecord> diffRecords = this.generateDiffRecord(reconcileOrder, generalTradeInfo,reconcileDetails);
|
||||
List<GeneralTradeInfo> generalTradeInfo = reconcileAssistService.getGeneralTradeInfoList(reconcileOrder);
|
||||
List<ReconcileDiff> diffRecords = reconcileAssistService.generateDiffRecord(reconcileOrder, generalTradeInfo, reconcileTradeDetails);
|
||||
// 判断是否有差异
|
||||
if (CollUtil.isNotEmpty(diffRecords)){
|
||||
reconcileOrder.setResult(ReconcileResultEnum.INCONSISTENT.getCode());
|
||||
@@ -200,174 +196,46 @@ public class ReconcileService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载原始对账单文件
|
||||
* 下载原始对交易对账单文件
|
||||
*/
|
||||
public void downOriginal(Long id){
|
||||
@SneakyThrows
|
||||
public ResponseEntity<byte[]> downOriginal(Long id){
|
||||
if (!reconcileOrderManager.existedById(id)) {
|
||||
throw new DataNotExistException("未找到对账订单");
|
||||
}
|
||||
// 获取对账单文件ID
|
||||
List<ReconcileFile> reconcileFiles = reconcileFileManager.findAllByReconcileId(id);
|
||||
if (CollUtil.isEmpty(reconcileFiles)){
|
||||
throw new DataNotExistException("未找到对账文件");
|
||||
}
|
||||
|
||||
// 查询文件
|
||||
FileInfo fileInfo = fileStorageService.getFileInfoByUrl(String.valueOf(reconcileFiles.get(0).getFileId()));
|
||||
byte[] bytes = fileStorageService.download(fileInfo).bytes();
|
||||
// 设置header信息
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
|
||||
String fileName = fileInfo.getOriginalFilename();
|
||||
headers.setContentDispositionFormData("attachment", URLEncoder.encode(fileName, CharsetUtil.UTF_8));
|
||||
return new ResponseEntity<>(bytes,headers, HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载基于原始对账单数据转换的对账单文件, 例如csv, json方式
|
||||
* 下载基于原始交易对账单数据转换的对账单文件, 例如csv, json方式
|
||||
*/
|
||||
public void downTransfer(Long id){
|
||||
ReconcileOrder reconcileOrderOriginal = reconcileOrderService.findById(id)
|
||||
public void downOriginal2Csv(Long id){
|
||||
ReconcileOrder reconcileOrder = reconcileOrderService.findById(id)
|
||||
.orElseThrow(() -> new DataNotExistException("未找到对账订单"));
|
||||
// 获取
|
||||
// 查询对账-第三方交易明细
|
||||
List<ReconcileTradeDetail> reconcileTradeDetails = reconcileTradeDetailManager.findAllByReconcileId(reconcileOrder.getId());
|
||||
|
||||
// 转换为csv文件
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取通用对账对象, 将支付/退款订单转换为对账对象
|
||||
* 下载对账单(本系统中的订单)
|
||||
*/
|
||||
private List<GeneralTradeInfo> getGeneralTradeInfoList(ReconcileOrder reconcileOrder){
|
||||
List<GeneralTradeInfo> generalTradeInfoList = new ArrayList<>();
|
||||
// 查询流水
|
||||
LocalDateTime localDateTime = LocalDateTimeUtil.date2DateTime(reconcileOrder.getDate());
|
||||
LocalDateTime start = LocalDateTimeUtil.beginOfDay(localDateTime);
|
||||
LocalDateTime end = LocalDateTimeUtil.endOfDay(localDateTime);
|
||||
|
||||
// 下载支付订单
|
||||
List<PayOrder> payOrders = payOrderManager.findReconcile(reconcileOrder.getChannel(), start, end, PayStatusEnum.SUCCESS, PayStatusEnum.PARTIAL_REFUND, PayStatusEnum.REFUNDING, PayStatusEnum.REFUNDED);
|
||||
List<RefundOrder> refundOrders = refundOrderManager.findReconcile(reconcileOrder.getChannel(), start, end, RefundStatusEnum.SUCCESS);
|
||||
for (PayOrder payOrder : payOrders) {
|
||||
generalTradeInfoList.add(new GeneralTradeInfo()
|
||||
.setTitle(payOrder.getTitle())
|
||||
.setTradeNo(payOrder.getOrderNo())
|
||||
.setOutTradeNo(payOrder.getOutOrderNo())
|
||||
.setFinishTime(payOrder.getPayTime())
|
||||
.setType(PaymentTypeEnum.PAY.getCode())
|
||||
.setAmount(payOrder.getAmount())
|
||||
);
|
||||
}
|
||||
for (RefundOrder refundOrder : refundOrders) {
|
||||
generalTradeInfoList.add(new GeneralTradeInfo()
|
||||
.setTitle(refundOrder.getTitle())
|
||||
.setTradeNo(refundOrder.getOrderNo())
|
||||
.setOutTradeNo(refundOrder.getOutOrderNo())
|
||||
.setFinishTime(refundOrder.getFinishTime())
|
||||
.setType(PaymentTypeEnum.REFUND.getCode())
|
||||
.setAmount(refundOrder.getAmount()));
|
||||
}
|
||||
return generalTradeInfoList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 比对生成对账差异单
|
||||
* 1. 远程有, 本地无
|
||||
* 2. 远程无, 本地有
|
||||
* 3. 远程有, 本地有, 但状态不一致
|
||||
*
|
||||
* @param reconcileOrder 对账单
|
||||
* @param localTrades 本地交易订单
|
||||
* @param outDetails 远程对账明细
|
||||
*/
|
||||
private List<ReconcileDiffRecord> generateDiffRecord(ReconcileOrder reconcileOrder,
|
||||
List<GeneralTradeInfo> localTrades,
|
||||
List<ReconcileDetail> outDetails){
|
||||
if (CollUtil.isEmpty(outDetails) || CollUtil.isEmpty(localTrades)){
|
||||
return new ArrayList<>();
|
||||
}
|
||||
// 差异内容
|
||||
List<ReconcileDiffRecord> diffRecords = new ArrayList<>();
|
||||
|
||||
// 三方对账订单
|
||||
Map<String, ReconcileDetail> outDetailMap = outDetails.stream()
|
||||
.collect(Collectors.toMap(ReconcileDetail::getTradeNo, Function.identity(), CollectorsFunction::retainLatest));
|
||||
// 本地订单记录
|
||||
Map<String, GeneralTradeInfo> localTradeMap = localTrades.stream()
|
||||
.collect(Collectors.toMap(GeneralTradeInfo::getTradeNo, Function.identity(), CollectorsFunction::retainLatest));
|
||||
// 对账与比对
|
||||
for (ReconcileDetail outDetail : outDetails) {
|
||||
// 判断本地有没有记录, 流水没有记录查询本地订单
|
||||
GeneralTradeInfo localTrade = localTradeMap.get(outDetail.getTradeNo());
|
||||
if (Objects.isNull(localTrade)){
|
||||
log.info("本地订单不存在: {}", outDetail.getTradeNo());
|
||||
ReconcileDiffRecord diffRecord = new ReconcileDiffRecord()
|
||||
.setDiffType(ReconcileDiffTypeEnum.LOCAL_NOT_EXISTS.getCode())
|
||||
.setTradeNo(outDetail.getTradeNo())
|
||||
.setDetailId(outDetail.getId())
|
||||
.setReconcileId(reconcileOrder.getId())
|
||||
.setTitle(outDetail.getTitle())
|
||||
.setOrderType(outDetail.getType())
|
||||
.setOutOrderNo(outDetail.getOutTradeNo())
|
||||
.setOutAmount(outDetail.getAmount())
|
||||
.setTradeTime(outDetail.getTradeTime());
|
||||
diffRecords.add(diffRecord);
|
||||
continue;
|
||||
}
|
||||
// 如果远程和本地都存在, 比对差异
|
||||
List<ReconcileDiff> reconcileDiffs = this.reconcileDiff(outDetail, localTrade);
|
||||
if (CollUtil.isNotEmpty(reconcileDiffs)) {
|
||||
ReconcileDiffRecord diffRecord = new ReconcileDiffRecord()
|
||||
.setReconcileId(reconcileOrder.getId())
|
||||
.setDetailId(outDetail.getId())
|
||||
.setDiffType(ReconcileDiffTypeEnum.NOT_MATCH.getCode())
|
||||
.setTradeNo(outDetail.getTradeNo())
|
||||
.setTitle(outDetail.getTitle())
|
||||
.setOrderType(outDetail.getType())
|
||||
.setOutOrderNo(outDetail.getOutTradeNo())
|
||||
.setOutAmount(outDetail.getAmount())
|
||||
.setAmount(localTrade.getAmount())
|
||||
.setDiffs(reconcileDiffs)
|
||||
.setTradeTime(outDetail.getTradeTime());
|
||||
diffRecords.add(diffRecord);
|
||||
}
|
||||
}
|
||||
// 本地与对账单比对, 找出本地有, 远程没有的记录
|
||||
for (GeneralTradeInfo localTrade : localTrades) {
|
||||
ReconcileDetail outDetail = outDetailMap.get(localTrade.getTradeNo());
|
||||
if (Objects.isNull(outDetail)){
|
||||
ReconcileDiffRecord diffRecord = new ReconcileDiffRecord()
|
||||
.setDiffType(ReconcileDiffTypeEnum.LOCAL_NOT_EXISTS.getCode())
|
||||
.setTradeNo(localTrade.getTradeNo())
|
||||
.setReconcileId(reconcileOrder.getId())
|
||||
.setDetailId(null)
|
||||
.setTitle(localTrade.getTitle())
|
||||
.setOrderType(localTrade.getType())
|
||||
.setOutOrderNo(localTrade.getOutTradeNo())
|
||||
.setAmount(localTrade.getAmount())
|
||||
.setTradeTime(localTrade.getFinishTime());
|
||||
diffRecords.add(diffRecord);
|
||||
log.info("远程订单不存在: {}", localTrade.getTradeNo());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return diffRecords;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断订单之间存在哪些差异
|
||||
* @param outDetail 下载的对账订单
|
||||
* @param localTrade 本地交易订单
|
||||
*/
|
||||
private List<ReconcileDiff> reconcileDiff(ReconcileDetail outDetail, GeneralTradeInfo localTrade){
|
||||
List<ReconcileDiff> diffs = new ArrayList<>();
|
||||
|
||||
// 判断类型是否相同
|
||||
if (Objects.equals(outDetail.getType(), ReconcileTradeEnum.PAY.getCode())
|
||||
&& !Objects.equals(localTrade.getType(), PaymentTypeEnum.PAY.getCode())){
|
||||
log.warn("订单类型不一致: {},{}", outDetail.getType(), localTrade.getType());
|
||||
diffs.add(new ReconcileDiff().setFieldName("订单类型").setLocalValue(outDetail.getType()).setOutValue(localTrade.getType()));
|
||||
}
|
||||
if (Objects.equals(outDetail.getType(), ReconcileTradeEnum.REFUND.getCode())
|
||||
&& !Objects.equals(localTrade.getType(), PaymentTypeEnum.REFUND.getCode())){
|
||||
log.warn("订单类型不一致: {},{}", outDetail.getType(), localTrade.getType());
|
||||
diffs.add(new ReconcileDiff().setFieldName("订单类型").setLocalValue(outDetail.getType()).setOutValue(localTrade.getType()));
|
||||
}
|
||||
|
||||
// 判断名称是否一致
|
||||
if (!Objects.equals(outDetail.getTitle(), localTrade.getTitle())){
|
||||
log.warn("订单名称不一致: {},{}", outDetail.getTitle(), localTrade.getTitle());
|
||||
diffs.add(new ReconcileDiff().setFieldName("订单名称").setLocalValue(outDetail.getTitle()).setOutValue(localTrade.getTitle()));
|
||||
}
|
||||
|
||||
// 判断金额是否一致
|
||||
if (!Objects.equals(outDetail.getAmount(), localTrade.getAmount())){
|
||||
log.warn("订单金额不一致: {},{}", outDetail.getAmount(), localTrade.getAmount());
|
||||
diffs.add(new ReconcileDiff().setFieldName("订单金额")
|
||||
.setLocalValue(String.valueOf(outDetail.getAmount()))
|
||||
.setOutValue(String.valueOf(localTrade.getAmount())));
|
||||
}
|
||||
return diffs;
|
||||
public void downLocal(Long id){
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package cn.bootx.platform.daxpay.service.core.payment.reconcile.strategy;
|
||||
|
||||
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.ReconcileFileTypeEnum;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.entity.AliPayConfig;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayConfigService;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayReconcileService;
|
||||
@@ -55,7 +56,7 @@ public class AlipayReconcileStrategy extends AbsReconcileStrategy {
|
||||
*/
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public void upload(MultipartFile file) {
|
||||
public void upload(MultipartFile file, ReconcileFileTypeEnum fileType) {
|
||||
reconcileService.upload(file.getBytes());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package cn.bootx.platform.daxpay.service.core.payment.reconcile.strategy;
|
||||
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.ReconcileFileTypeEnum;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.union.entity.UnionPayConfig;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.union.service.UnionPayConfigService;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.union.service.UnionPayReconcileService;
|
||||
@@ -61,7 +62,7 @@ public class UnionPayReconcileStrategy extends AbsReconcileStrategy {
|
||||
*/
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public void upload(MultipartFile file) {
|
||||
public void upload(MultipartFile file, ReconcileFileTypeEnum fileType) {
|
||||
reconcileService.upload(file.getBytes());
|
||||
}
|
||||
|
||||
@@ -71,6 +72,6 @@ public class UnionPayReconcileStrategy extends AbsReconcileStrategy {
|
||||
@Override
|
||||
public void downAndSave() {
|
||||
Date date = DateUtil.date(this.getRecordOrder().getDate());
|
||||
reconcileService.downAndSave(this.getRecordOrder(),date, this.unionPayKit);
|
||||
reconcileService.downAndSave(this.getRecordOrder(), date, this.unionPayKit);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@ package cn.bootx.platform.daxpay.service.core.payment.reconcile.strategy;
|
||||
|
||||
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
|
||||
import cn.bootx.platform.daxpay.code.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.service.code.ReconcileFileTypeEnum;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConfig;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WeChatPayConfigService;
|
||||
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WechatPayReconcileService;
|
||||
import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayOrderManager;
|
||||
import cn.bootx.platform.daxpay.service.func.AbsReconcileStrategy;
|
||||
import cn.hutool.core.date.DatePattern;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -32,8 +32,6 @@ public class WechatPayReconcileStrategy extends AbsReconcileStrategy {
|
||||
|
||||
private final WeChatPayConfigService weChatPayConfigService;
|
||||
|
||||
private final PayOrderManager payOrderManager;
|
||||
|
||||
private WeChatPayConfig config;
|
||||
|
||||
/**
|
||||
@@ -59,7 +57,7 @@ public class WechatPayReconcileStrategy extends AbsReconcileStrategy {
|
||||
*/
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public void upload(MultipartFile file) {
|
||||
public void upload(MultipartFile file, ReconcileFileTypeEnum fileType) {
|
||||
reconcileService.uploadBill(file.getBytes(),this.config);
|
||||
}
|
||||
|
||||
@@ -68,8 +66,8 @@ public class WechatPayReconcileStrategy extends AbsReconcileStrategy {
|
||||
*/
|
||||
@Override
|
||||
public void downAndSave() {
|
||||
String format = LocalDateTimeUtil.format(this.getRecordOrder().getDate(), DatePattern.PURE_DATE_PATTERN);
|
||||
reconcileService.downAndSave(format, this.config);
|
||||
String date = LocalDateTimeUtil.format(this.getRecordOrder().getDate(), DatePattern.PURE_DATE_PATTERN);
|
||||
reconcileService.downAndSave(this.getRecordOrder(), date, this.config);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,16 +22,24 @@ import java.util.List;
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "对账差异单")
|
||||
public class ReconcileDiffRecordDto extends BaseDto {
|
||||
public class ReconcileDiffDto extends BaseDto {
|
||||
|
||||
/** 对账单ID */
|
||||
@Schema(description = "对账单ID")
|
||||
private Long ReconcileId;
|
||||
private Long reconcileId;
|
||||
|
||||
/** 对账号 */
|
||||
@Schema(description = "对账号")
|
||||
private String reconcileNo;
|
||||
|
||||
/** 对账单明细ID */
|
||||
@Schema(description = "对账单明细ID")
|
||||
private Long detailId;
|
||||
|
||||
/** 对账日期 */
|
||||
@Schema(description = "对账日期")
|
||||
private LocalDateTime reconcileDate;
|
||||
|
||||
/** 本地交易号 */
|
||||
@Schema(description = "本地交易号")
|
||||
private String tradeNo;
|
||||
@@ -61,7 +69,7 @@ public class ReconcileDiffRecordDto extends BaseDto {
|
||||
* @see ReconcileTradeEnum
|
||||
*/
|
||||
@Schema(description = "订单类型")
|
||||
private String orderType;
|
||||
private String tradeType;
|
||||
|
||||
/**
|
||||
* 差异类型
|
||||
@@ -18,7 +18,7 @@ import java.time.LocalDateTime;
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "对账订单详情")
|
||||
public class ReconcileDetailDto extends BaseDto {
|
||||
public class ReconcileTradeDetailDto extends BaseDto {
|
||||
|
||||
/** 关联对账订单ID */
|
||||
@Schema(description = "关联对账订单ID")
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.service.func;
|
||||
|
||||
import cn.bootx.platform.daxpay.service.code.ReconcileFileTypeEnum;
|
||||
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileOrder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -26,7 +27,7 @@ public abstract class AbsReconcileStrategy implements PayStrategy {
|
||||
/**
|
||||
* 上传对账单解析并保存
|
||||
*/
|
||||
public abstract void upload(MultipartFile file);
|
||||
public abstract void upload(MultipartFile file, ReconcileFileTypeEnum fileType);
|
||||
|
||||
/**
|
||||
* 下载对账单到本地进行保存
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package cn.bootx.platform.daxpay.service.param.reconcile;
|
||||
|
||||
import cn.bootx.platform.daxpay.service.code.ReconcileFileTypeEnum;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 对账文件上传参数
|
||||
* @author xxm
|
||||
* @since 2024/5/4
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "对账文件上传参数")
|
||||
public class ReconcileUploadParam {
|
||||
|
||||
@Schema(description = "对账订单ID")
|
||||
@NotNull(message = "对账订单ID不能为空")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* @see ReconcileFileTypeEnum
|
||||
*/
|
||||
@Schema(description = "文件类型")
|
||||
@NotNull(message = "文件类型不能为空")
|
||||
private String fileType;
|
||||
}
|
||||
@@ -30,7 +30,7 @@ public class ReconcileTaskService {
|
||||
// 2. 执行对账任务, 下载对账单并解析, 分别存储为原始数据和通用对账数据
|
||||
reconcileService.downAndSave(reconcileOrder);
|
||||
|
||||
// 3. 执行账单比对, 生成差异单
|
||||
// 3. 执行账单明细比对, 生成差异单
|
||||
reconcileService.compare(reconcileOrder);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user