feat 云闪付相关接口对接

This commit is contained in:
DaxPay
2024-10-09 18:43:49 +08:00
parent 389665de70
commit 5101625ad2
16 changed files with 618 additions and 80 deletions

View File

@@ -0,0 +1,44 @@
package org.dromara.daxpay.channel.union.code;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 云闪付对账单字段
* @author xxm
* @since 2024/3/24
*/
@Getter
@AllArgsConstructor
public enum UnionReconcileFieldEnum {
/** 交易代码 */
TRADE_TYPE(0, "tradeType"),
/** 交易传输时间 MMDDhhmmss */
txnTime(4, "txnTime"),
/** 交易金额 */
TXN_AMT(6, "txnAmt"),
/** 查询流水号 */
QUERY_ID(9, "queryId"),
/** 商户订单号 */
ORDER_ID(11, "orderId");
/** 序号 */
private final int no;
/** 字段名 */
private final String filed;
/**
* 根据序号查询
*/
public static UnionReconcileFieldEnum findByNo(int no){
return Arrays.stream(values())
.filter(o->o.no == no)
.findFirst()
.orElse(null);
}
}

View File

@@ -1,13 +1,9 @@
package org.dromara.daxpay.channel.union.controller;
import cn.bootx.platform.core.annotation.IgnoreAuth;
import org.dromara.daxpay.service.service.assist.PaymentAssistService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.dromara.daxpay.service.service.assist.PaymentAssistService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -23,13 +19,20 @@ import org.springframework.web.bind.annotation.RestController;
@RequiredArgsConstructor
public class UnionPayCallbackController {
private final PaymentAssistService paymentAssistService;
@Operation(summary = "银联回调")
@PostMapping("/union")
public String UnionPayNotify(@PathVariable("AppId") String appId, HttpServletRequest request) {
paymentAssistService.initMchApp(appId);
return "";
}
// @Operation(summary = "云闪付支付回调")
// @PostMapping("/pay")
// public String wechatPayNotify(@PathVariable("AppId") String appId, HttpServletRequest request) {
// paymentAssistService.initMchApp(appId);
// return payCallbackService.payHandle(request);
// }
//
//
// @Operation(summary = "云闪付退款回调")
// @PostMapping("/refund")
// public String wechatRefundNotify(@PathVariable("AppId") String appId,HttpServletRequest request) {
// paymentAssistService.initMchApp(appId);
// return refundCallbackService.refundHandle(request);
// }
}

View File

@@ -0,0 +1,68 @@
package org.dromara.daxpay.channel.union.entity.reconcile;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 云闪付业务明细对账单
* @author xxm
* @since 2024/3/24
*/
@Data
@Accessors(chain = true)
public class UnionReconcileBillDetail {
/** 关联对账订单ID */
private String reconcileId;
/** 交易代码 */
private String tradeType;
/** 代理机构标识码 */
/** 发送机构标识码 */
/** 系统跟踪号 */
/** 交易传输时间 */
private String txnTime;
/** 帐号 */
/** 交易金额 */
private String txnAmt;
/** 商户类别 */
/** 终端类型 */
/** 查询流水号 */
private String queryId;
/** 支付方式(旧) */
/** 商户订单号 */
private String orderId;
/** 支付卡类型 */
/** 原始交易的系统跟踪号 */
/** 原始交易日期时间 */
/** 商户手续费 */
/** 结算金额 */
/** 支付方式 */
/** 集团商户代码 */
/** 交易类型 */
/** 交易子类 */
/** 业务类型 */
/** 帐号类型 */
/** 账单类型 */
/** 账单号码 */
/** 交互方式 */
/** 商户代码 */
/** 分账入账方式 */
/** 二级商户代码 */
/** 二级商户简称 */
/** 二级商户分账入账金额 */
/** 清算净额 */
/** 终端号 */
/** 商户自定义域 */
/** 优惠金额 */
/** 发票金额 */
/** 分期付款附加手续费 */
/** 分期付款期数 */
/** 交易介质 */
/** 原始交易订单号 */
/** 清算金额 */
/** 服务点输入方式码 */
/** 移动支付产品标志 */
/** 交易代码 */
/** 检索参考号 */
/** 保留使用 */
}

View File

@@ -51,7 +51,7 @@ public class UnionPayConfigService {
return channelConfigManager.findById(id)
.map(UnionPayConfig::convertConfig)
.map(UnionPayConfig::toResult)
.orElseThrow(() -> new ConfigNotEnableException("支付宝配置不存在"));
.orElseThrow(() -> new ConfigNotEnableException("云闪付配置不存在"));
}
/**
@@ -84,8 +84,8 @@ public class UnionPayConfigService {
*/
public void update(UnionPayConfigParam param){
ChannelConfig channelConfig = channelConfigManager.findById(param.getId())
.orElseThrow(() -> new ConfigNotEnableException("支付宝配置不存在"));
// 通道配置 --转换--> 支付宝配置 ----> 从更新参数赋值 --转换--> 通道配置 ----> 保存更新
.orElseThrow(() -> new ConfigNotEnableException("云闪付配置不存在"));
// 通道配置 --转换--> 云闪付配置 ----> 从更新参数赋值 --转换--> 通道配置 ----> 保存更新
UnionPayConfig unionPayConfig = UnionPayConfig.convertConfig(channelConfig);
BeanUtil.copyProperties(param, unionPayConfig, CopyOptions.create().ignoreNullValue());
ChannelConfig channelConfigParam = unionPayConfig.toChannelConfig();
@@ -116,7 +116,7 @@ public class UnionPayConfigService {
}
/**
* 获取步通知地址
* 获取步通知地址
*/
public String getNotifyUrl() {
var mchAppInfo = PaymentContextLocal.get().getMchAppInfo();
@@ -124,6 +124,24 @@ public class UnionPayConfigService {
return StrUtil.format("{}/unipay/callback/{}/{}/union",platformInfo.getGatewayServiceUrl(),mchAppInfo.getAppId());
}
/**
* 获取支付异步通知地址
*/
public String getPayNotifyUrl() {
MchAppLocal mchAppInfo = PaymentContextLocal.get().getMchAppInfo();
var platformInfo = platformConfigService.getConfig();
return StrUtil.format("{}/unipay/callback/{}/{}/wechat/pay",platformInfo.getGatewayServiceUrl(),mchAppInfo.getAppId());
}
/**
* 获取退款异步通知地址
*/
public String getRefundNotifyUrl() {
MchAppLocal mchAppInfo = PaymentContextLocal.get().getMchAppInfo();
var platformInfo = platformConfigService.getConfig();
return StrUtil.format("{}/unipay/callback/{}/{}/wechat/refund",platformInfo.getGatewayServiceUrl(), mchAppInfo.getAppId());
}
/**
* 获取同步通知地址
*/
@@ -136,14 +154,14 @@ public class UnionPayConfigService {
/**
* 生成云闪付支付接口
*/
public UnionPayKit initPayService(){
UnionPayConfig config = this.getUnionPayConfig();
return this.initPayService(config);
public UnionPayKit initPayKit(){
UnionPayConfig config = this.getAndCheckConfig();
return this.initPayKit(config);
}
/**
* 生成云闪付支付接口
*/
public UnionPayKit initPayService(UnionPayConfig config){
public UnionPayKit initPayKit(UnionPayConfig config){
UnionPayConfigStorage unionPayConfigStorage = new UnionPayConfigStorage();
unionPayConfigStorage.setInputCharset(CharsetUtil.UTF_8);
@@ -167,8 +185,6 @@ public class UnionPayConfigService {
unionPayConfigStorage.setSignType(config.getSignType());
//是否为测试账号,沙箱环境
unionPayConfigStorage.setTest(config.isSandbox());
// 回调地址
unionPayConfigStorage.setNotifyUrl(getNotifyUrl());
// 网络请求配置
HttpConfigStorage httpConfigStorage = new HttpConfigStorage();

View File

@@ -12,6 +12,7 @@ import org.dromara.daxpay.channel.union.param.pay.UnionPayParam;
import org.dromara.daxpay.channel.union.sdk.api.UnionPayKit;
import org.dromara.daxpay.channel.union.sdk.bean.UnionPayOrder;
import org.dromara.daxpay.channel.union.sdk.bean.UnionTransactionType;
import org.dromara.daxpay.channel.union.service.config.UnionPayConfigService;
import org.dromara.daxpay.core.enums.PayMethodEnum;
import org.dromara.daxpay.core.exception.AmountExceedLimitException;
import org.dromara.daxpay.core.exception.TradeFailException;
@@ -36,6 +37,8 @@ import java.util.Objects;
@RequiredArgsConstructor
public class UnionPayService {
private final UnionPayConfigService configService;
/**
* 支付前检查支付方式是否可用
*/
@@ -91,23 +94,10 @@ public class UnionPayService {
unionPayOrder.setPrice(amount);
unionPayOrder.setExpirationTime(expiredTime);
unionPayOrder.setTransactionType(type);
unionPayOrder.setNotifyUrl(configService.getPayNotifyUrl());
return unionPayKit.toPay(unionPayOrder);
}
/**
* jsapi支付
*/
private String b2bPay(BigDecimal amount, PayOrder payOrder, UnionPayKit unionPayKit) {
Date expiredTime = DateUtil.date(payOrder.getExpiredTime());
UnionPayOrder unionPayOrder = new UnionPayOrder();
unionPayOrder.setOutTradeNo(payOrder.getOrderNo());
unionPayOrder.setSubject(payOrder.getTitle());
unionPayOrder.setPrice(amount);
unionPayOrder.setExpirationTime(expiredTime);
unionPayOrder.setTransactionType(UnionTransactionType.B2B);
return unionPayKit.toPay(unionPayOrder);
}
/**
* APP支付
@@ -122,6 +112,7 @@ public class UnionPayService {
unionPayOrder.setSubject(payOrder.getTitle());
unionPayOrder.setPrice(amount);
unionPayOrder.setExpirationTime(expiredTime);
unionPayOrder.setNotifyUrl(configService.getPayNotifyUrl());
Map<String, Object> result = unionPayKit.app(unionPayOrder);
String resultCode = MapUtil.getStr(result, UnionPayCode.RESP_CODE);
@@ -147,6 +138,7 @@ public class UnionPayService {
unionPayOrder.setSubject(payOrder.getTitle());
unionPayOrder.setPrice(amount);
unionPayOrder.setExpirationTime(expiredTime);
unionPayOrder.setNotifyUrl(configService.getPayNotifyUrl());
return unionPayKit.getQrPay(unionPayOrder);
}
@@ -162,6 +154,7 @@ public class UnionPayService {
unionPayOrder.setSubject(payOrder.getTitle());
unionPayOrder.setPrice(amount);
unionPayOrder.setExpirationTime(expiredTime);
unionPayOrder.setNotifyUrl(configService.getPayNotifyUrl());
Map<String, Object> result = unionPayKit.microPay(unionPayOrder);
if (!unionPayKit.verify(new NoticeParams(result))) {

View File

@@ -1,17 +0,0 @@
package org.dromara.daxpay.channel.union.service.reconcile;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* 云闪付对账
* @author xxm
* @since 2024/3/7
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class UnionPayReconcileService {
}

View File

@@ -0,0 +1,192 @@
package org.dromara.daxpay.channel.union.service.reconcile;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.compress.Deflate;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.dromara.daxpay.channel.union.code.UnionPayCode;
import org.dromara.daxpay.channel.union.code.UnionReconcileFieldEnum;
import org.dromara.daxpay.channel.union.entity.reconcile.UnionReconcileBillDetail;
import org.dromara.daxpay.channel.union.sdk.api.UnionPayKit;
import org.dromara.daxpay.channel.union.sdk.bean.SDKConstants;
import org.dromara.daxpay.core.enums.TradeStatusEnum;
import org.dromara.daxpay.core.enums.TradeTypeEnum;
import org.dromara.daxpay.core.exception.OperationFailException;
import org.dromara.daxpay.core.util.PayUtil;
import org.dromara.daxpay.service.bo.reconcile.ChannelReconcileTradeBo;
import org.dromara.daxpay.service.bo.reconcile.ReconcileResolveResultBo;
import org.dromara.daxpay.service.entity.reconcile.ReconcileStatement;
import org.dromara.x.file.storage.core.FileInfo;
import org.dromara.x.file.storage.core.FileStorageService;
import org.springframework.stereotype.Service;
import java.io.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
/**
* 云闪付对账
* @author xxm
* @since 2024/3/7
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class UnionReconcileService {
private final FileStorageService fileStorageService;
/**
* 下载对账单
*/
public ReconcileResolveResultBo downAndResolve(ReconcileStatement statement, Date date, UnionPayKit unionPayKit){
// 下载对账单
Map<String, Object> map = unionPayKit.downloadBill(date, UnionPayCode.RECONCILE_BILL_TYPE);
Object o = map.get(UnionPayCode.FILE_CONTENT);
if (o == null) {
log.warn("云闪付获取对账文件失败");
throw new OperationFailException("云闪付获取对账文件失败");
}
String fileContent = o.toString();
// 判断是否成功
if (!SDKConstants.OK_RESP_CODE.equals(map.get(SDKConstants.param_respCode))) {
log.warn("云闪付获取对账文件失败");
throw new OperationFailException("云闪付获取对账文件失败");
}
try {
// 先解base64再DEFLATE解压为zip流
byte[] decode = Base64.decode(fileContent);
ByteArrayOutputStream out = new ByteArrayOutputStream();
Deflate deflate = Deflate.of(new ByteArrayInputStream(decode), out, false);
deflate.inflater();
deflate.close();
// 读取zip文件, 解析出对账单内容
byte[] zipBytes = out.toByteArray();
ZipArchiveInputStream zipArchiveInputStream = new ZipArchiveInputStream(new ByteArrayInputStream(zipBytes),"GBK");
ZipArchiveEntry entry;
List<UnionReconcileBillDetail> billDetails = new ArrayList<>();
byte[] bytes = null;
while ((entry= zipArchiveInputStream.getNextZipEntry()) != null){
if (StrUtil.startWith(entry.getName(), UnionPayCode.RECONCILE_FILE_PREFIX)){
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);
}
}
// 保存原始对账文件
String originalFile = this.saveOriginalFile(statement, bytes);
// 解析账单文件
var tradeBos = this.convertAndSave(billDetails, statement);
return new ReconcileResolveResultBo()
.setOriginalFileUrl(originalFile)
.setChannelTrades(tradeBos);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 解析对账单明细
*/
private List<UnionReconcileBillDetail> parseDetail(List<String> list){
return list.stream()
.map(this::convertDetail)
.collect(Collectors.toList());
}
/**
* 解析明细条目
*/
private UnionReconcileBillDetail convertDetail(String line){
//解析的结果MAPkey为对账文件列序号value为解析的值
Map<String,String> zmDataMap = new HashMap<>();
//左侧游标
int leftIndex = 0;
for(int i = 0; i < UnionPayCode.RECONCILE_BILL_SPLIT.length; i++){
//右侧游标
int rightIndex = leftIndex + UnionPayCode.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());
}
}
return BeanUtil.toBean(zmDataMap, UnionReconcileBillDetail.class);
}
/**
* 转换为通用对账记录对象
*/
private List<ChannelReconcileTradeBo> convertAndSave(List<UnionReconcileBillDetail> billDetails, ReconcileStatement statement){
// 只处理支付和退款的对账记录
return billDetails.stream()
.map(billDetail->this.convert(billDetail, statement))
// 只处理支付和退款的对账记录
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
/**
* 转换为通用对账记录对象
*/
private ChannelReconcileTradeBo convert(UnionReconcileBillDetail billDetail, ReconcileStatement statement){
// 金额
String orderAmount = billDetail.getTxnAmt();
int amount = Integer.parseInt(orderAmount);
// 默认为支付对账记录
ChannelReconcileTradeBo reconcileTradeDetail = new ChannelReconcileTradeBo()
.setTradeType(TradeTypeEnum.PAY.getCode())
.setAmount(PayUtil.conversionAmount(amount))
.setTradeStatus(TradeStatusEnum.SUCCESS.getCode())
.setTradeNo(billDetail.getOrderId())
.setOutTradeNo(billDetail.getQueryId());
// 时间, 从对账订单获取年份
LocalDate date = statement.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.PURE_DATETIME_PATTERN);
reconcileTradeDetail.setTradeTime(time);
}
// 退款覆盖更新对应的字段
if (Objects.equals(billDetail.getTradeType(), UnionPayCode.RECONCILE_TYPE_REFUND)){
reconcileTradeDetail.setTradeType(TradeTypeEnum.REFUND.getCode());
}
return reconcileTradeDetail;
}
/**
* 保存下载的原始对账文件
*/
private String saveOriginalFile(ReconcileStatement statement, byte[] bytes) {
String date = LocalDateTimeUtil.format(statement.getDate(), DatePattern.PURE_DATE_PATTERN);
// 将原始文件进行保存 通道-日期
String fileName = StrUtil.format("交易对账单-云闪付-{}.csv",date);
var uploadPretreatment = fileStorageService.of(bytes);
if (StrUtil.isNotBlank(fileName)) {
uploadPretreatment.setOriginalFilename(fileName);
}
FileInfo upload = uploadPretreatment.upload();
return upload.getUrl();
}
}

View File

@@ -6,6 +6,7 @@ import org.dromara.daxpay.channel.union.code.UnionPayCode;
import org.dromara.daxpay.channel.union.sdk.api.UnionPayKit;
import org.dromara.daxpay.channel.union.sdk.bean.UnionRefundOrder;
import org.dromara.daxpay.channel.union.sdk.bean.UnionRefundResult;
import org.dromara.daxpay.channel.union.service.config.UnionPayConfigService;
import org.dromara.daxpay.core.enums.RefundStatusEnum;
import org.dromara.daxpay.service.bo.trade.RefundResultBo;
import org.dromara.daxpay.service.entity.order.refund.RefundOrder;
@@ -21,14 +22,14 @@ import java.math.BigDecimal;
@Slf4j
@Service
@RequiredArgsConstructor
public class UnionPayRefundService {
public class UnionRefundService {
private final UnionPayConfigService unionPayConfigService;
/**
* 退款方法
*/
public RefundResultBo refund(RefundOrder refundOrder, UnionPayKit unionPayKit) {
// 金额转换
BigDecimal refundAmount = refundOrder.getAmount();
BigDecimal orderAmount = refundOrder.getOrderAmount();
@@ -37,6 +38,7 @@ public class UnionPayRefundService {
unionRefundOrder.setTradeNo(refundOrder.getOutOrderNo());
unionRefundOrder.setRefundAmount(refundAmount);
unionRefundOrder.setTotalAmount(orderAmount);
unionRefundOrder.setNotifyUrl(unionPayConfigService.getRefundNotifyUrl());
UnionRefundResult refund = unionPayKit.refund(unionRefundOrder);
String outRefundNo = (String) refund.getAttr(UnionPayCode.QUERY_ID);

View File

@@ -1,9 +1,25 @@
package org.dromara.daxpay.channel.union.service.sync;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.daxpay.channel.union.code.UnionPayCode;
import org.dromara.daxpay.channel.union.sdk.api.UnionPayKit;
import org.dromara.daxpay.channel.union.sdk.bean.SDKConstants;
import org.dromara.daxpay.core.enums.PayStatusEnum;
import org.dromara.daxpay.service.bo.sync.PaySyncResultBo;
import org.dromara.daxpay.service.entity.order.pay.PayOrder;
import org.dromara.daxpay.unisdk.common.bean.AssistOrder;
import org.dromara.daxpay.unisdk.common.bean.NoticeParams;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;
/**
* 云闪付支付同步
* @author xxm
@@ -13,5 +29,59 @@ import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class UnionPaySyncService {
/**
* 同步
*/
public PaySyncResultBo sync(PayOrder order, UnionPayKit unionPayKit) {
PaySyncResultBo syncResult = new PaySyncResultBo();
AssistOrder query = new AssistOrder();
query.setOutTradeNo(order.getOrderNo());
Map<String, Object> result = unionPayKit.query(query);
syncResult.setSyncData(JSONUtil.toJsonStr(result));
if (!unionPayKit.verify(new NoticeParams(result))) {
log.warn("查询云闪付订单验签失败:{}", result);
return syncResult.setSyncSuccess(false).setSyncErrorMsg("查询订单验签失败");
}
String resultCode = MapUtil.getStr(result, UnionPayCode.RESP_CODE);
// 订单不存在
if (Objects.equals(resultCode, "34")) {
return syncResult.setPayStatus(PayStatusEnum.CLOSE);
}
// 查询失败
if (!UnionPayCode.RESP_SUCCESS.equals(resultCode)) {
log.warn("查询云闪付订单失败:{}", result);
return syncResult.setSyncErrorMsg(MapUtil.getStr(result, SDKConstants.param_respMsg)).setSyncSuccess(false);
}
// 状态响应码
String origRespCode = MapUtil.getStr(result, SDKConstants.param_origRespCode);
// 成功
if (Objects.equals(origRespCode, UnionPayCode.RESP_SUCCESS)) {
// 查询流水号, 相当于网关订单号
String queryId = MapUtil.getStr(result, UnionPayCode.QUERY_ID);
String timeEnd = MapUtil.getStr(result, UnionPayCode.TXN_TIME);
LocalDateTime time = LocalDateTimeUtil.parse(timeEnd, DatePattern.PURE_DATETIME_PATTERN);
return syncResult.setOutOrderNo(queryId).setFinishTime(time).setPayStatus(PayStatusEnum.SUCCESS);
}
// 支付超时 交易不在受理时间范围内
if (Objects.equals(origRespCode, "39")) {
return syncResult.setPayStatus(PayStatusEnum.CLOSE);
}
// 待支付
if (Objects.equals(origRespCode, "05")) {
return syncResult.setPayStatus(PayStatusEnum.PROGRESS);
}
// 二维码支付无效
if (Objects.equals(origRespCode, "86")) {
return syncResult.setPayStatus(PayStatusEnum.CLOSE);
}
return syncResult;
}
}

View File

@@ -0,0 +1,78 @@
package org.dromara.daxpay.channel.union.service.sync;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.map.MapUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.daxpay.channel.union.code.UnionPayCode;
import org.dromara.daxpay.channel.union.sdk.api.UnionPayKit;
import org.dromara.daxpay.channel.union.sdk.bean.SDKConstants;
import org.dromara.daxpay.core.enums.RefundStatusEnum;
import org.dromara.daxpay.service.bo.sync.RefundSyncResultBo;
import org.dromara.daxpay.service.entity.order.refund.RefundOrder;
import org.dromara.daxpay.unisdk.common.bean.AssistOrder;
import org.dromara.daxpay.unisdk.common.bean.NoticeParams;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;
/**
* 云闪付退款同步
* @author xxm
* @since 2024/10/9
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class UnionRefundSyncService {
/**
* 同步
*/
public RefundSyncResultBo sync(RefundOrder refundOrder, UnionPayKit unionPayKit) {
RefundSyncResultBo syncResult = new RefundSyncResultBo();
AssistOrder query = new AssistOrder();
query.setOutTradeNo(String.valueOf(refundOrder.getRefundNo()));
Map<String, Object> result = unionPayKit.query(query);
if (!unionPayKit.verify(new NoticeParams(result))) {
log.warn("查询云闪付订单验签失败:{}", result);
return syncResult.setSyncErrorMsg("查询订单验签失败").setSyncSuccess(false);
}
String resultCode = MapUtil.getStr(result, UnionPayCode.RESP_CODE);
// 订单不存在
if (Objects.equals(resultCode, "34")) {
return syncResult.setRefundStatus(RefundStatusEnum.CLOSE);
}
// 查询失败
if (!UnionPayCode.RESP_SUCCESS.equals(resultCode)) {
log.warn("查询云闪付订单失败:{}", result);
return syncResult.setSyncErrorMsg(MapUtil.getStr(result, SDKConstants.param_respMsg)).setSyncSuccess(false);
}
// 状态响应码
String origRespCode = MapUtil.getStr(result, SDKConstants.param_origRespCode);
// 成功
if (Objects.equals(origRespCode, UnionPayCode.RESP_SUCCESS)) {
// 查询流水号, 相当于网关订单号
String queryId = MapUtil.getStr(result, UnionPayCode.QUERY_ID);
String timeEnd = MapUtil.getStr(result, UnionPayCode.TXN_TIME);
LocalDateTime time = LocalDateTimeUtil.parse(timeEnd, DatePattern.PURE_DATETIME_PATTERN);
return syncResult.setOutRefundNo(queryId).setFinishTime(time).setRefundStatus(RefundStatusEnum.SUCCESS);
}
// 退款中
if (Objects.equals(origRespCode, "05")) {
return syncResult.setRefundStatus(RefundStatusEnum.PROGRESS);
}
return syncResult;
}
}

View File

@@ -3,38 +3,44 @@ package org.dromara.daxpay.channel.union.strategy;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.daxpay.core.enums.ChannelEnum;
import org.dromara.daxpay.service.bo.reconcile.ReconcileResolveResultBo;
import org.dromara.daxpay.service.enums.ReconcileFileTypeEnum;
import org.dromara.daxpay.service.strategy.AbsReconcileStrategy;
import org.dromara.daxpay.core.enums.CloseTypeEnum;
import org.dromara.daxpay.core.exception.UnsupportedAbilityException;
import org.dromara.daxpay.service.strategy.AbsPayCloseStrategy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
/**
* 银联对账
* 云闪付, 云闪付的关闭使用冲正
* @author xxm
* @since 2024/3/8
* @since 2023/12/30
*/
@Slf4j
@Service
@Scope(SCOPE_PROTOTYPE)
@Service
@RequiredArgsConstructor
public class UnionPayReconcileStrategy extends AbsReconcileStrategy {
public class UnionPayCloseStrategy extends AbsPayCloseStrategy {
@Override
public ReconcileResolveResultBo uploadAndResolve(MultipartFile file, ReconcileFileTypeEnum fileType) {
return null;
}
@Override
public ReconcileResolveResultBo downAndResolve() {
return null;
}
@Override
public String getChannel() {
return ChannelEnum.UNION_PAY.getCode();
}
/**
* 关闭前的处理方式
*/
@Override
public void doBeforeCloseHandler() {
throw new UnsupportedAbilityException("云闪付没有关闭订单功能!");
}
/**
* 关闭操作
*/
@Override
public CloseTypeEnum doCloseHandler() {
return null;
}
}

View File

@@ -20,7 +20,7 @@ import org.springframework.stereotype.Service;
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
/**
* 云闪付
* 云闪付支付
*
* @author xxm
* @since 2022/3/8
@@ -71,7 +71,7 @@ public class UnionPayStrategy extends AbsPayStrategy {
*/
@Override
public PayResultBo doPayHandler() {
UnionPayKit unionPayKit = unionPayConfigService.initPayService();
UnionPayKit unionPayKit = unionPayConfigService.initPayKit(unionPayConfig);
return unionPayService.pay(this.getOrder(), this.unionPayParam, unionPayKit);
}
}

View File

@@ -0,0 +1,68 @@
package org.dromara.daxpay.channel.union.strategy;
import cn.hutool.core.date.DateUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.daxpay.channel.union.entity.config.UnionPayConfig;
import org.dromara.daxpay.channel.union.sdk.api.UnionPayKit;
import org.dromara.daxpay.channel.union.service.config.UnionPayConfigService;
import org.dromara.daxpay.channel.union.service.reconcile.UnionReconcileService;
import org.dromara.daxpay.core.enums.ChannelEnum;
import org.dromara.daxpay.service.bo.reconcile.ReconcileResolveResultBo;
import org.dromara.daxpay.service.enums.ReconcileFileTypeEnum;
import org.dromara.daxpay.service.strategy.AbsReconcileStrategy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.util.Date;
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
/**
* 银联对账
* @author xxm
* @since 2024/3/8
*/
@Slf4j
@Service
@Scope(SCOPE_PROTOTYPE)
@RequiredArgsConstructor
public class UnionReconcileStrategy extends AbsReconcileStrategy {
private final UnionReconcileService reconcileService;
private final UnionPayConfigService unionPayConfigService;
private UnionPayConfig config;
/**
* 对账前处理, 主要是初始化支付SDK配置
*/
@Override
public void doBeforeHandler() {
UnionPayConfig config = unionPayConfigService.getAndCheckConfig();
// 测试环境使用测试号
if (config.isSandbox()) {
config.setUnionMachId("700000000000001");
}
this.config = config;
}
@Override
public ReconcileResolveResultBo uploadAndResolve(MultipartFile file, ReconcileFileTypeEnum fileType) {
return null;
}
@Override
public ReconcileResolveResultBo downAndResolve() {
Date date = DateUtil.date(this.getStatement().getDate());
UnionPayKit unionPayKit = unionPayConfigService.initPayKit(config);
return reconcileService.downAndResolve(this.getStatement(), date, unionPayKit);
}
@Override
public String getChannel() {
return ChannelEnum.UNION_PAY.getCode();
}
}

View File

@@ -3,7 +3,7 @@ package org.dromara.daxpay.channel.union.strategy;
import lombok.RequiredArgsConstructor;
import org.dromara.daxpay.channel.union.sdk.api.UnionPayKit;
import org.dromara.daxpay.channel.union.service.config.UnionPayConfigService;
import org.dromara.daxpay.channel.union.service.refund.UnionPayRefundService;
import org.dromara.daxpay.channel.union.service.refund.UnionRefundService;
import org.dromara.daxpay.core.enums.ChannelEnum;
import org.dromara.daxpay.service.bo.trade.RefundResultBo;
import org.dromara.daxpay.service.strategy.AbsRefundStrategy;
@@ -22,7 +22,7 @@ import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROT
@RequiredArgsConstructor
public class UnionRefundStrategy extends AbsRefundStrategy {
private final UnionPayRefundService unionPayRefundService;
private final UnionRefundService unionRefundService;
private final UnionPayConfigService unionPayConfigService;
@@ -41,7 +41,7 @@ public class UnionRefundStrategy extends AbsRefundStrategy {
*/
@Override
public RefundResultBo doRefundHandler() {
UnionPayKit unionPayKit = unionPayConfigService.initPayService();
return unionPayRefundService.refund(this.getRefundOrder(), unionPayKit);
UnionPayKit unionPayKit = unionPayConfigService.initPayKit();
return unionRefundService.refund(this.getRefundOrder(), unionPayKit);
}
}

View File

@@ -1,6 +1,9 @@
package org.dromara.daxpay.channel.union.strategy;
import lombok.RequiredArgsConstructor;
import org.dromara.daxpay.channel.union.sdk.api.UnionPayKit;
import org.dromara.daxpay.channel.union.service.config.UnionPayConfigService;
import org.dromara.daxpay.channel.union.service.sync.UnionPaySyncService;
import org.dromara.daxpay.core.enums.ChannelEnum;
import org.dromara.daxpay.service.bo.sync.PaySyncResultBo;
import org.dromara.daxpay.service.strategy.AbsSyncPayOrderStrategy;
@@ -19,9 +22,14 @@ import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROT
@RequiredArgsConstructor
public class UnionSyncPayStrategy extends AbsSyncPayOrderStrategy {
private final UnionPayConfigService unionPayConfigService;
private final UnionPaySyncService unionPaySyncService;
@Override
public PaySyncResultBo doSync() {
return null;
UnionPayKit unionPayKit = unionPayConfigService.initPayKit();
return unionPaySyncService.sync(this.getOrder(),unionPayKit);
}
@Override

View File

@@ -1,6 +1,9 @@
package org.dromara.daxpay.channel.union.strategy;
import lombok.RequiredArgsConstructor;
import org.dromara.daxpay.channel.union.sdk.api.UnionPayKit;
import org.dromara.daxpay.channel.union.service.config.UnionPayConfigService;
import org.dromara.daxpay.channel.union.service.sync.UnionRefundSyncService;
import org.dromara.daxpay.core.enums.ChannelEnum;
import org.dromara.daxpay.service.bo.sync.RefundSyncResultBo;
import org.dromara.daxpay.service.strategy.AbsSyncRefundOrderStrategy;
@@ -18,9 +21,13 @@ import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROT
@Component
@RequiredArgsConstructor
public class UnionSyncRefundStrategy extends AbsSyncRefundOrderStrategy {
private final UnionPayConfigService unionPayConfigService;
private final UnionRefundSyncService unionSyncRefundService;
@Override
public RefundSyncResultBo doSync() {
return null;
UnionPayKit unionPayKit = unionPayConfigService.initPayKit();
return unionSyncRefundService.sync(this.getRefundOrder(),unionPayKit);
}
@Override