feat 云闪付对账处理

This commit is contained in:
xxm1995
2024-03-25 17:42:52 +08:00
parent 9bf5c701ef
commit 3eb0f4589f
15 changed files with 111 additions and 57 deletions

View File

@@ -56,6 +56,12 @@ public interface UnionPayCode {
/** 对账单下载类型编码 */
String RECONCILE_BILL_TYPE = "00";
/** 文件内容 */
String FILE_CONTENT = "fileContent";
/** 明细对账单文件前缀 */
String RECONCILE_FILE_PREFIX = "INN";
/* 对账单交易代码 */
/** 消费 */
String RECONCILE_TYPE_PAY = "S22";

View File

@@ -1,6 +1,7 @@
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.ReconcileOrder;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -15,6 +16,9 @@ import java.util.List;
@Accessors(chain = true)
public class ReconcileLocal {
/** 对账订单 */
private ReconcileOrder reconcileOrder;
/** 通用支付对账记录 */
private List<ReconcileDetail> reconcileDetails;

View File

@@ -0,0 +1,18 @@
package cn.bootx.platform.daxpay.service.core.channel.union.dao;
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
import cn.bootx.platform.daxpay.service.core.channel.union.entity.UnionReconcileBillDetail;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;
/**
*
* @author xxm
* @since 2024/3/25
*/
@Slf4j
@Repository
@RequiredArgsConstructor
public class UnionReconcileBillDetailManager extends BaseManager<UnionReconcileBillDetailMapper, UnionReconcileBillDetail> {
}

View File

@@ -0,0 +1,14 @@
package cn.bootx.platform.daxpay.service.core.channel.union.dao;
import cn.bootx.platform.daxpay.service.core.channel.union.entity.UnionReconcileBillDetail;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
*
* @author xxm
* @since 2024/3/25
*/
@Mapper
public interface UnionReconcileBillDetailMapper extends BaseMapper<UnionReconcileBillDetail> {
}

View File

@@ -1,6 +1,8 @@
package cn.bootx.platform.daxpay.service.core.channel.union.entity;
import cn.bootx.table.modify.annotation.DbColumn;
import cn.bootx.table.modify.annotation.DbTable;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -11,27 +13,34 @@ import lombok.experimental.Accessors;
*/
@Data
@Accessors(chain = true)
@DbTable(comment = "云闪付业务明细对账单")
@TableName("pay_union_reconcile_bill_detail")
public class UnionReconcileBillDetail {
/** 关联对账订单ID */
@DbColumn(comment = "关联对账订单ID")
private Long recordOrderId;
/** 交易代码 */
@DbColumn(comment = "交易代码")
private String tradeType;
/** 代理机构标识码 */
/** 发送机构标识码 */
/** 系统跟踪号 */
/** 交易传输时间 */
@DbColumn(comment = "交易传输时间")
private String txnTime;
/** 帐号 */
/** 交易金额 */
@DbColumn(comment = "交易金额")
private String txnAmt;
/** 商户类别 */
/** 终端类型 */
/** 查询流水号 */
@DbColumn(comment = "查询流水号")
private String queryId;
/** 支付方式(旧) */
/** 商户订单号 */
@DbColumn(comment = "商户订单号")
private String orderId;
/** 支付卡类型 */
/** 原始交易的系统跟踪号 */

View File

@@ -2,11 +2,14 @@ package cn.bootx.platform.daxpay.service.core.channel.union.service;
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
import cn.bootx.platform.daxpay.code.ReconcileTradeEnum;
import cn.bootx.platform.daxpay.exception.pay.PayFailureException;
import cn.bootx.platform.daxpay.service.code.UnionPayCode;
import cn.bootx.platform.daxpay.service.code.UnionReconcileFieldEnum;
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.entity.ReconcileDetail;
import cn.bootx.platform.daxpay.service.core.order.reconcile.entity.ReconcileOrder;
import cn.bootx.platform.daxpay.service.sdk.union.api.UnionPayKit;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.codec.Base64;
@@ -14,6 +17,7 @@ import cn.hutool.core.compress.Deflate;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import com.egzosn.pay.union.bean.SDKConstants;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
@@ -21,12 +25,12 @@ import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.springframework.stereotype.Service;
import java.io.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import static cn.bootx.platform.daxpay.service.code.UnionPayCode.RECONCILE_BILL_SPLIT;
import static cn.bootx.platform.daxpay.service.code.UnionPayCode.RECONCILE_BILL_TYPE;
import static cn.bootx.platform.daxpay.service.code.UnionPayCode.*;
/**
* 云闪付对账
@@ -38,16 +42,22 @@ import static cn.bootx.platform.daxpay.service.code.UnionPayCode.RECONCILE_BILL_
@RequiredArgsConstructor
public class UnionPayReconcileService {
private final UnionReconcileBillDetailManager unionReconcileBillDetailManager;
/**
* 下载对账单
*/
public void downAndSave(Date date, Long recordOrderId, UnionPayKit unionPayKit){
// 下载对账单
Map<String, Object> stringObjectMap = unionPayKit.downloadBill(date, RECONCILE_BILL_TYPE);
Map<String, Object> map = unionPayKit.downloadBill(date, RECONCILE_BILL_TYPE);
String fileContent = map.get(FILE_CONTENT).toString();
// 判断是否成功
if (!SDKConstants.OK_RESP_CODE.equals(map.get(SDKConstants.param_respCode))) {
log.warn("云闪付获取对账文件失败");
throw new PayFailureException("云闪付获取对账文件失败");
}
String fileContent = stringObjectMap.get("fileContent").toString();
try {
// 先解base64再DEFLATE解压为zip流
byte[] decode = Base64.decode(fileContent);
ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -61,9 +71,8 @@ public class UnionPayReconcileService {
ZipArchiveEntry entry;
List<UnionReconcileBillDetail> billDetails = new ArrayList<>();
while ((entry= zipArchiveInputStream.getNextZipEntry()) != null){
System.out.println(StrUtil.startWith(entry.getName(), "INN"));
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(zipArchiveInputStream,"GBK"));
if (StrUtil.startWith(entry.getName(), "INN")){
if (StrUtil.startWith(entry.getName(), RECONCILE_FILE_PREFIX)){
// 明细解析
List<String> strings = IoUtil.readLines(bufferedReader, new ArrayList<>());
billDetails = this.parseDetail(strings);
@@ -73,13 +82,8 @@ public class UnionPayReconcileService {
}
// 保存原始对账记录
this.save(billDetails, recordOrderId);
// 将原始交易明细对账记录转换通用结构并保存到上下文中
// 转换为通用对账记录对象
this.convertAndSave(billDetails);
// Reader bufferedReader = new BufferedReader(new InputStreamReader(Files.newInputStream(Paths.get("D:/data/INN24031100ZM_777290058206553.txt"))));
// List<String> strings = IoUtil.readLines(bufferedReader, new ArrayList<>());
// List<UnionReconcileBillDetail> unionReconcileBillDetails = this.parseDetail(strings);
// System.out.println(unionReconcileBillDetails);
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -102,13 +106,12 @@ public class UnionPayReconcileService {
Map<String,String> zmDataMap = new HashMap<>();
//左侧游标
int leftIndex = 0;
//右侧游标
int rightIndex = 0;
for(int i=0;i<RECONCILE_BILL_SPLIT.length;i++){
rightIndex = leftIndex + RECONCILE_BILL_SPLIT[i];
//右侧游标
int rightIndex = leftIndex + RECONCILE_BILL_SPLIT[i];
String filed = StrUtil.sub(line, leftIndex, rightIndex);
leftIndex = rightIndex+1;
// 映射到数据对象
UnionReconcileFieldEnum fieldEnum = UnionReconcileFieldEnum.findByNo(i);
if (Objects.nonNull(fieldEnum)){
zmDataMap.put(fieldEnum.getFiled(), filed.trim());
@@ -123,17 +126,20 @@ public class UnionPayReconcileService {
private void convertAndSave(List<UnionReconcileBillDetail> billDetails){
List<ReconcileDetail> collect = billDetails.stream()
.map(this::convert)
// 只处理支付和退款的对账记录
.filter(Objects::nonNull)
.collect(Collectors.toList());
// 写入到上下文中
PaymentContextLocal.get().getReconcileInfo().setReconcileDetails(collect);
}
/**
* 转换为通用对账记录对象
*/
private ReconcileDetail convert(UnionReconcileBillDetail billDetail){
ReconcileOrder reconcileOrder = PaymentContextLocal.get()
.getReconcileInfo()
.getReconcileOrder();
// 金额
String orderAmount = billDetail.getTxnAmt();
int amount = Integer.parseInt(orderAmount);
@@ -146,10 +152,13 @@ public class UnionPayReconcileService {
.setAmount(amount)
.setGatewayOrderNo(billDetail.getQueryId());
// 时间
String txnTime = billDetail.getTxnTime();
// 时间, 从对账订单获取年份
LocalDate date = reconcileOrder.getDate();
String year = LocalDateTimeUtil.format(date, DatePattern.NORM_YEAR_PATTERN);
String txnTime = year + billDetail.getTxnTime();
if (StrUtil.isNotBlank(txnTime)) {
LocalDateTime time = LocalDateTimeUtil.parse(txnTime, DatePattern.NORM_DATETIME_PATTERN);
LocalDateTime time = LocalDateTimeUtil.parse(txnTime, DatePattern.PURE_DATETIME_PATTERN);
reconcileDetail.setOrderTime(time);
}
@@ -165,6 +174,6 @@ public class UnionPayReconcileService {
*/
private void save(List<UnionReconcileBillDetail> billDetails, Long recordOrderId){
billDetails.forEach(o->o.setRecordOrderId(recordOrderId));
unionReconcileBillDetailManager.saveAll(billDetails);
}
}

View File

@@ -7,6 +7,8 @@ import cn.bootx.platform.daxpay.service.dto.order.reconcile.ReconcileOrderDto;
import cn.bootx.table.modify.annotation.DbColumn;
import cn.bootx.table.modify.annotation.DbTable;
import cn.bootx.table.modify.mysql.annotation.DbMySqlIndex;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -53,6 +55,7 @@ public class ReconcileOrder extends MpCreateEntity implements EntityBaseFunction
/** 错误信息 */
@DbColumn(comment = "错误信息")
@TableField(updateStrategy = FieldStrategy.ALWAYS)
private String errorMsg;
@Override

View File

@@ -21,7 +21,6 @@ import java.util.Optional;
@RequiredArgsConstructor
public class ReconcileOrderService {
private final ReconcileOrderManager reconcileOrderManager;
private final Sequence sequence;
/**
* 更新, 开启一个新事务进行更新

View File

@@ -89,13 +89,17 @@ public class ReconcileService {
* 下载对账单并进行保存
*/
public void downAndSave(ReconcileOrder reconcileOrder) {
// 将对账订单写入到上下文中
PaymentContextLocal.get().getReconcileInfo().setReconcileOrder(reconcileOrder);
// 构建对账策略
AbsReconcileStrategy reconcileStrategy = ReconcileStrategyFactory.create(reconcileOrder.getChannel());
reconcileStrategy.setRecordOrder(reconcileOrder);
reconcileStrategy.doBeforeHandler();
try {
reconcileStrategy.downAndSave();
reconcileOrder.setDown(true);
reconcileOrder.setDown(true)
.setErrorMsg(null);
reconcileOrderService.update(reconcileOrder);
} catch (Exception e) {
log.error("下载对账单异常", e);

View File

@@ -11,11 +11,10 @@ import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayConfig
import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayReconcileService;
import cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.GeneralReconcileRecord;
import cn.bootx.platform.daxpay.service.func.AbsReconcileStrategy;
import cn.bootx.platform.daxpay.service.handler.sequence.DaxPaySequenceHandler;
import cn.hutool.core.date.DatePattern;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
@@ -43,9 +42,7 @@ public class AlipayReconcileStrategy extends AbsReconcileStrategy {
private final AliPayConfigService configService;
@Getter
@Qualifier("alipayReconcileSequence")
private final Sequence sequence;
private final DaxPaySequenceHandler daxPaySequenceHandler;
private AliPayConfig config;
@@ -67,8 +64,10 @@ public class AlipayReconcileStrategy extends AbsReconcileStrategy {
*/
@Override
public String generateSequence(LocalDate date) {
String prefix = getChannel().getReconcilePrefix();
String dateStr = LocalDateTimeUtil.format(date, DatePattern.PURE_DATE_PATTERN);
Sequence sequence = daxPaySequenceHandler.alipayReconcileSequence(dateStr);
String key = String.format("%02d", sequence.next());
return prefix + dateStr + key;
}

View File

@@ -1,6 +1,5 @@
package cn.bootx.platform.daxpay.service.core.payment.reconcile.strategy;
import cn.bootx.platform.common.core.exception.BizException;
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
import cn.bootx.platform.common.sequence.func.Sequence;
import cn.bootx.platform.daxpay.code.PayChannelEnum;
@@ -12,12 +11,12 @@ import cn.bootx.platform.daxpay.service.core.channel.union.service.UnionPayConfi
import cn.bootx.platform.daxpay.service.core.channel.union.service.UnionPayReconcileService;
import cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.GeneralReconcileRecord;
import cn.bootx.platform.daxpay.service.func.AbsReconcileStrategy;
import cn.bootx.platform.daxpay.service.handler.sequence.DaxPaySequenceHandler;
import cn.bootx.platform.daxpay.service.sdk.union.api.UnionPayKit;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
@@ -46,8 +45,7 @@ public class UnionPayReconcileStrategy extends AbsReconcileStrategy {
private final UnionPayRecordManager recordManager;
@Qualifier("unionPayReconcileSequence")
private final Sequence sequence;
private final DaxPaySequenceHandler daxPaySequenceHandler;
private UnionPayKit unionPayKit;
@@ -58,6 +56,7 @@ public class UnionPayReconcileStrategy extends AbsReconcileStrategy {
public String generateSequence(LocalDate date) {
String prefix = getChannel().getReconcilePrefix();
String dateStr = LocalDateTimeUtil.format(date, DatePattern.PURE_DATE_PATTERN);
Sequence sequence = daxPaySequenceHandler.unionPayReconcileSequence(dateStr);
String key = String.format("%02d", sequence.next());
return prefix + dateStr + key;
}
@@ -82,7 +81,6 @@ public class UnionPayReconcileStrategy extends AbsReconcileStrategy {
public void downAndSave() {
Date date = DateUtil.date(this.getRecordOrder().getDate());
reconcileService.downAndSave(date, this.getRecordOrder().getId(), this.unionPayKit);
throw new BizException("123");
}
/**

View File

@@ -11,10 +11,10 @@ import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WeChatPayCon
import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WechatPayReconcileService;
import cn.bootx.platform.daxpay.service.core.payment.reconcile.domain.GeneralReconcileRecord;
import cn.bootx.platform.daxpay.service.func.AbsReconcileStrategy;
import cn.bootx.platform.daxpay.service.handler.sequence.DaxPaySequenceHandler;
import cn.hutool.core.date.DatePattern;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
@@ -42,8 +42,7 @@ public class WechatPayReconcileStrategy extends AbsReconcileStrategy {
private final WeChatPayRecordManager recordManager;
@Qualifier("wechatReconcileSequence")
private final Sequence sequence;
private final DaxPaySequenceHandler daxPaySequenceHandler;
private WeChatPayConfig config;
@@ -67,6 +66,7 @@ public class WechatPayReconcileStrategy extends AbsReconcileStrategy {
public String generateSequence(LocalDate date) {
String prefix = getChannel().getReconcilePrefix();
String dateStr = LocalDateTimeUtil.format(date, DatePattern.PURE_DATE_PATTERN);
Sequence sequence = daxPaySequenceHandler.wechatReconcileSequence(dateStr);
String key = String.format("%02d", sequence.next());
return prefix + dateStr + key;
}

View File

@@ -1,10 +1,8 @@
package cn.bootx.platform.daxpay.service.configuration.sequence;
package cn.bootx.platform.daxpay.service.handler.sequence;
import cn.bootx.platform.common.sequence.func.Sequence;
import cn.bootx.platform.common.sequence.range.SeqRangeManager;
import cn.bootx.platform.common.sequence.util.SequenceUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
@@ -14,29 +12,26 @@ import org.springframework.context.annotation.Configuration;
*/
@Configuration
@RequiredArgsConstructor
public class DaxPaySequenceConfiguration {
public class DaxPaySequenceHandler {
/**
* 支付宝对账单序列生成器
*/
@Bean
public Sequence alipayReconcileSequence(SeqRangeManager seqRangeManager) {
return SequenceUtil.create(1,1,1,"AlipayReconcileSequence");
public Sequence alipayReconcileSequence(String date) {
return SequenceUtil.create(1,1,1,"AlipayReconcileSequence"+date);
}
/**
* 微信对账单序列生成器
*/
@Bean
public Sequence wechatReconcileSequence(SeqRangeManager seqRangeManager) {
return SequenceUtil.create(1,1,1,"WechatReconcileSequence");
public Sequence wechatReconcileSequence(String date) {
return SequenceUtil.create(1,1,1,"WechatReconcileSequence"+date);
}
/**
* 云闪付对账单序列生成器
*/
@Bean
public Sequence unionPayReconcileSequence(SeqRangeManager seqRangeManager) {
return SequenceUtil.create(1,1,1,"UnionPayReconcileSequence");
public Sequence unionPayReconcileSequence(String date) {
return SequenceUtil.create(1,1,1,"UnionPayReconcileSequence"+date);
}
}

View File

@@ -194,8 +194,6 @@ public class UnionPayKit extends UnionPayService {
@Deprecated
@Override
public boolean verify(Map<String, Object> result) {
return verify(new NoticeParams(result));
}