From 5101625ad2fe6cbf1b812deb23e262b39d0f9637 Mon Sep 17 00:00:00 2001 From: DaxPay Date: Wed, 9 Oct 2024 18:43:49 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E4=BA=91=E9=97=AA=E4=BB=98=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E6=8E=A5=E5=8F=A3=E5=AF=B9=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../union/code/UnionReconcileFieldEnum.java | 44 ++++ .../UnionPayCallbackController.java | 27 +-- .../reconcile/UnionReconcileBillDetail.java | 68 +++++++ .../service/config/UnionPayConfigService.java | 36 +++- .../union/service/pay/UnionPayService.java | 21 +- .../reconcile/UnionPayReconcileService.java | 17 -- .../reconcile/UnionReconcileService.java | 192 ++++++++++++++++++ ...ndService.java => UnionRefundService.java} | 6 +- .../service/sync/UnionPaySyncService.java | 70 +++++++ .../service/sync/UnionRefundSyncService.java | 78 +++++++ ...rategy.java => UnionPayCloseStrategy.java} | 40 ++-- .../union/strategy/UnionPayStrategy.java | 4 +- .../strategy/UnionReconcileStrategy.java | 68 +++++++ .../union/strategy/UnionRefundStrategy.java | 8 +- .../union/strategy/UnionSyncPayStrategy.java | 10 +- .../strategy/UnionSyncRefundStrategy.java | 9 +- 16 files changed, 618 insertions(+), 80 deletions(-) create mode 100644 daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/code/UnionReconcileFieldEnum.java create mode 100644 daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/entity/reconcile/UnionReconcileBillDetail.java delete mode 100644 daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/reconcile/UnionPayReconcileService.java create mode 100644 daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/reconcile/UnionReconcileService.java rename daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/refund/{UnionPayRefundService.java => UnionRefundService.java} (86%) create mode 100644 daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/sync/UnionRefundSyncService.java rename daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/{UnionPayReconcileStrategy.java => UnionPayCloseStrategy.java} (52%) create mode 100644 daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionReconcileStrategy.java diff --git a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/code/UnionReconcileFieldEnum.java b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/code/UnionReconcileFieldEnum.java new file mode 100644 index 000000000..9bd720dea --- /dev/null +++ b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/code/UnionReconcileFieldEnum.java @@ -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); + } +} diff --git a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/controller/UnionPayCallbackController.java b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/controller/UnionPayCallbackController.java index 146e33a93..7c7954c21 100644 --- a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/controller/UnionPayCallbackController.java +++ b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/controller/UnionPayCallbackController.java @@ -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); +// } } diff --git a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/entity/reconcile/UnionReconcileBillDetail.java b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/entity/reconcile/UnionReconcileBillDetail.java new file mode 100644 index 000000000..11f227041 --- /dev/null +++ b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/entity/reconcile/UnionReconcileBillDetail.java @@ -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; + /** 支付卡类型 */ + /** 原始交易的系统跟踪号 */ + /** 原始交易日期时间 */ + /** 商户手续费 */ + /** 结算金额 */ + /** 支付方式 */ + /** 集团商户代码 */ + /** 交易类型 */ + /** 交易子类 */ + /** 业务类型 */ + /** 帐号类型 */ + /** 账单类型 */ + /** 账单号码 */ + /** 交互方式 */ + /** 商户代码 */ + /** 分账入账方式 */ + /** 二级商户代码 */ + /** 二级商户简称 */ + /** 二级商户分账入账金额 */ + /** 清算净额 */ + /** 终端号 */ + /** 商户自定义域 */ + /** 优惠金额 */ + /** 发票金额 */ + /** 分期付款附加手续费 */ + /** 分期付款期数 */ + /** 交易介质 */ + /** 原始交易订单号 */ + /** 清算金额 */ + /** 服务点输入方式码 */ + /** 移动支付产品标志 */ + /** 交易代码 */ + /** 检索参考号 */ + /** 保留使用 */ +} diff --git a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/config/UnionPayConfigService.java b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/config/UnionPayConfigService.java index 3a682217b..d6eeccd36 100644 --- a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/config/UnionPayConfigService.java +++ b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/config/UnionPayConfigService.java @@ -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(); diff --git a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/pay/UnionPayService.java b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/pay/UnionPayService.java index 384a51889..5847f4640 100644 --- a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/pay/UnionPayService.java +++ b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/pay/UnionPayService.java @@ -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 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 result = unionPayKit.microPay(unionPayOrder); if (!unionPayKit.verify(new NoticeParams(result))) { diff --git a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/reconcile/UnionPayReconcileService.java b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/reconcile/UnionPayReconcileService.java deleted file mode 100644 index a10e47c10..000000000 --- a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/reconcile/UnionPayReconcileService.java +++ /dev/null @@ -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 { - -} diff --git a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/reconcile/UnionReconcileService.java b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/reconcile/UnionReconcileService.java new file mode 100644 index 000000000..bff4eaba8 --- /dev/null +++ b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/reconcile/UnionReconcileService.java @@ -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 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 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 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 parseDetail(List list){ + return list.stream() + .map(this::convertDetail) + .collect(Collectors.toList()); + } + + /** + * 解析明细条目 + */ + private UnionReconcileBillDetail convertDetail(String line){ + //解析的结果MAP,key为对账文件列序号,value为解析的值 + Map 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 convertAndSave(List 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(); + } +} diff --git a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/refund/UnionPayRefundService.java b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/refund/UnionRefundService.java similarity index 86% rename from daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/refund/UnionPayRefundService.java rename to daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/refund/UnionRefundService.java index 4199e81b8..be847746b 100644 --- a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/refund/UnionPayRefundService.java +++ b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/refund/UnionRefundService.java @@ -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); diff --git a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/sync/UnionPaySyncService.java b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/sync/UnionPaySyncService.java index 314902a5c..06734c36d 100644 --- a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/sync/UnionPaySyncService.java +++ b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/sync/UnionPaySyncService.java @@ -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 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; + } } diff --git a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/sync/UnionRefundSyncService.java b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/sync/UnionRefundSyncService.java new file mode 100644 index 000000000..a737176ff --- /dev/null +++ b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/service/sync/UnionRefundSyncService.java @@ -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 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; + } + +} diff --git a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionPayReconcileStrategy.java b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionPayCloseStrategy.java similarity index 52% rename from daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionPayReconcileStrategy.java rename to daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionPayCloseStrategy.java index 61582cf22..37ffac9bf 100644 --- a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionPayReconcileStrategy.java +++ b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionPayCloseStrategy.java @@ -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; + } } diff --git a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionPayStrategy.java b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionPayStrategy.java index 30df253ff..8783fbc1c 100644 --- a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionPayStrategy.java +++ b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionPayStrategy.java @@ -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); } } diff --git a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionReconcileStrategy.java b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionReconcileStrategy.java new file mode 100644 index 000000000..97951bc7f --- /dev/null +++ b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionReconcileStrategy.java @@ -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(); + } +} diff --git a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionRefundStrategy.java b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionRefundStrategy.java index ee98bce2a..ecc527e2d 100644 --- a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionRefundStrategy.java +++ b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionRefundStrategy.java @@ -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); } } diff --git a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionSyncPayStrategy.java b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionSyncPayStrategy.java index 0ea00ffdb..ec8b4b9bb 100644 --- a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionSyncPayStrategy.java +++ b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionSyncPayStrategy.java @@ -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 diff --git a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionSyncRefundStrategy.java b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionSyncRefundStrategy.java index 87a277517..7cd1b9e30 100644 --- a/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionSyncRefundStrategy.java +++ b/daxpay-single-channel/daxpay-single-union/src/main/java/org/dromara/daxpay/channel/union/strategy/UnionSyncRefundStrategy.java @@ -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