diff --git a/_doc/Task.md b/_doc/Task.md index 36b9d049..ed8f520b 100644 --- a/_doc/Task.md +++ b/_doc/Task.md @@ -6,11 +6,13 @@ - [ ] 同步 - [ ] 对账 - [ ] 回调 +- [ ] 统一关闭接口增加使用撤销关闭订单 - [x] 手动触发通知消息发送 - [x] 退款操作支持重试 - [x] 通知任务增加订单的状态类型,例如订单关闭、成功、失败等 - [ ] 支付流程也改为先落库后支付情况, 避免极端情况导致掉单 - [ ] 优化发起请求时IP的获取逻辑 +- [ ] 增加定时同步退款中的退款订单 2.0.x 版本内容 - [ ] 增加各类日志记录,例如钱包的各项操作 diff --git a/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/code/PayWayEnum.java b/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/code/PayWayEnum.java index ec9a1780..33708cb1 100644 --- a/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/code/PayWayEnum.java +++ b/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/code/PayWayEnum.java @@ -23,7 +23,11 @@ public enum PayWayEnum { WEB("web", "web支付"), QRCODE("qrcode", "扫码支付"), BARCODE("barcode", "付款码"), - JSAPI("jsapi", "公众号/小程序支付"); + // 通用 + JSAPI("jsapi", "公众号/小程序支付"), + // 在非支付宝和微信中, 但支持这两类支付的时候, 需要进行区分 + JSAPI_WX_PAY("jsapi_wx_pay", "微信JS支付"), + JSAPI_ALI_PAY("jsapi_ali_pay", "支付宝JS支付"); /** 编码 */ private final String code; diff --git a/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/channel/UnionPayParam.java b/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/channel/UnionPayParam.java index cf8cb5b3..268ceed7 100644 --- a/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/channel/UnionPayParam.java +++ b/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/channel/UnionPayParam.java @@ -17,4 +17,38 @@ public class UnionPayParam { @Schema(description = "授权码(主动扫描用户的付款码)") private String authCode; + + /** + * 银联JS支付时进行传输 + */ + @Schema(description = "用户ID") + private String userId; + + /** + * 用户的外网ip,需要与访问银联支付页面的ip一致,银联会进行校验 + */ + @Schema(description = "用户ip") + private String customerIp; + + /** + * 商户app对应的微信开放平台移动应用APPID + * 微信APP支付时进行传输 + */ + @Schema(description = "移动应用APPID") + private String appId; + + /** + * 微信开放平台审核通过的移动应用AppID + * 微信APP支付时进行传输 + */ + @Schema(description = "移动应用AppID") + private String subAppId; + + /** + * 买家支付宝用户ID + * 支付宝服务窗时传输 + */ + @Schema(description = "微信支付授权码") + private String buyerId; + } diff --git a/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/pay/PayCloseParam.java b/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/pay/PayCloseParam.java index a47f90af..a58e5612 100644 --- a/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/pay/PayCloseParam.java +++ b/daxpay-single/daxpay-single-core/src/main/java/cn/bootx/platform/daxpay/param/pay/PayCloseParam.java @@ -21,4 +21,7 @@ public class PayCloseParam extends PaymentCommonParam { @Schema(description = "业务号") private String businessNo; + @Schema(description = "使用撤销来关闭订单") + private Boolean cancel; + } diff --git a/daxpay-single/daxpay-single-gateway/src/main/java/cn/bootx/platform/daxpay/gateway/controller/PayCallbackController.java b/daxpay-single/daxpay-single-gateway/src/main/java/cn/bootx/platform/daxpay/gateway/controller/PayCallbackController.java index 3404a2f2..0baac59a 100644 --- a/daxpay-single/daxpay-single-gateway/src/main/java/cn/bootx/platform/daxpay/gateway/controller/PayCallbackController.java +++ b/daxpay-single/daxpay-single-gateway/src/main/java/cn/bootx/platform/daxpay/gateway/controller/PayCallbackController.java @@ -2,6 +2,7 @@ package cn.bootx.platform.daxpay.gateway.controller; import cn.bootx.platform.common.core.annotation.IgnoreAuth; import cn.bootx.platform.daxpay.service.core.channel.alipay.service.AliPayCallbackService; +import cn.bootx.platform.daxpay.service.core.channel.union.service.UnionPayCallbackService; import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WeChatPayCallbackService; import com.ijpay.alipay.AliPayApi; import com.ijpay.core.kit.HttpKit; @@ -35,6 +36,8 @@ public class PayCallbackController { private final WeChatPayCallbackService weChatPayCallbackService; + private final UnionPayCallbackService unionPayCallbackService; + @SneakyThrows @Operation(summary = "支付宝信息回调") @PostMapping("/alipay") @@ -51,4 +54,13 @@ public class PayCallbackController { Map params = WxPayKit.xmlToMap(xmlMsg); return weChatPayCallbackService.callback(params); } + + @SneakyThrows + @Operation(summary = "云闪付支付信息回调") + @PostMapping("/union") + public String unionPayNotify(HttpServletRequest request) { + String xmlMsg = HttpKit.readData(request); + Map params = WxPayKit.xmlToMap(xmlMsg); + return unionPayCallbackService.callback(params); + } } diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/code/UnionPayCode.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/code/UnionPayCode.java new file mode 100644 index 00000000..7813fd1a --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/code/UnionPayCode.java @@ -0,0 +1,67 @@ +package cn.bootx.platform.daxpay.service.code; + +/** + * 云闪付常量 + * @author xxm + * @since 2024/3/7 + */ +public interface UnionPayCode { + + + /** 成功状态 */ + String SUCCESS = "0"; + + /** 状态 0表示成功 */ + String STATUS = "status"; + + /** 业务结果 0表示成功,非0表示失败 */ + String RESULT_CODE = "result_code"; + + /** 网关订单号 */ + String TRANSACTION_ID = "transaction_id"; + + /** 第三方订单号 */ + String OUT_TRANSACTION_ID = "out_transaction_id"; + + /** 退款ID */ + String REFUND_ID = "refund_id"; + + + /** + * 支付完成时间 + * 格式: yyyyMMddHHmmss + */ + String TIME_END = "time_end"; + + /** 支付结果 */ + String PAY_RESULT = "pay_result"; + + /** 总金额 */ + String TOTAL_FEE = "total_fee"; + + /** 交易状态 */ + String TRADE_STATE = "trade_state"; + + /** 支付成功 */ + String TRADE_SUCCESS = "SUCCESS"; + + /** 转入退款 */ + String TRADE_REFUND = "REFUND"; + + /** 未支付 */ + String TRADE_NOT_PAY = "NOTPAY"; + + /** 已关闭 */ + String TRADE_CLOSED = "CLOSED"; + + /** 支付失败(其他原因,如银行返回失败) */ + String TRADE_PAY_ERROR = "PAYERROR"; + + /** 返回信息 */ + String MESSAGE = "message"; + + /** 错误代码描述 */ + String ERR_MSG = "err_msg"; + + +} diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/code/UnionPayRecordTypeEnum.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/code/UnionPayRecordTypeEnum.java new file mode 100644 index 00000000..42b6d3cd --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/code/UnionPayRecordTypeEnum.java @@ -0,0 +1,22 @@ +package cn.bootx.platform.daxpay.service.code; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 云闪付 + * @author xxm + * @since 2024/3/7 + */ +@Getter +@AllArgsConstructor +public enum UnionPayRecordTypeEnum { + + /** 支付 */ + PAY("pay", "支付"), + /** 退款 */ + REFUND("refund", "退款"); + + private final String code; + private final String name; +} diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/code/WeChatPayCode.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/code/WeChatPayCode.java index 0047ef22..8529cf90 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/code/WeChatPayCode.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/code/WeChatPayCode.java @@ -14,8 +14,6 @@ public interface WeChatPayCode { String API_V3 = "apiV3"; // 请求参数 - /** jsapi发起获取AuthCode时的重定向参数 */ - String JSAPI_REDIRECT_URL = "JsapiRedirectUrl"; // 返回参数 /** 二维码链接 */ diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/common/entity/BasePayOrder.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/common/entity/BasePayOrder.java deleted file mode 100644 index be7960d4..00000000 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/common/entity/BasePayOrder.java +++ /dev/null @@ -1,51 +0,0 @@ -package cn.bootx.platform.daxpay.service.common.entity; - -import cn.bootx.platform.common.mybatisplus.base.MpIdEntity; -import cn.bootx.platform.daxpay.code.PayStatusEnum; -import cn.bootx.table.modify.annotation.DbColumn; -import cn.bootx.table.modify.mysql.annotation.DbMySqlIndex; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.experimental.Accessors; - -import java.time.LocalDateTime; - -/** - * 基础支付订单信息类 - * @author xxm - * @since 2023/12/18 - */ -@EqualsAndHashCode(callSuper = true) -@Data -@Accessors(chain = true) -public class BasePayOrder extends MpIdEntity { - - /** 交易记录ID */ - @DbColumn(comment = "交易记录ID") - @DbMySqlIndex(comment = "交易记录ID") - private Long paymentId; - - /** 关联的业务号 */ - @DbMySqlIndex(comment = "业务号索引") - @DbColumn(comment = "关联的业务号") - private String businessNo; - - /** 交易金额 */ - @DbColumn(comment = "交易金额") - private Integer amount; - - /** 可退款金额 */ - @DbColumn(comment = "可退款金额") - private Integer refundableBalance; - - /** - * 支付状态 - * @see PayStatusEnum - */ - @DbColumn(comment = "支付状态") - private String status; - - /** 支付时间 */ - @DbColumn(comment = "支付时间") - private LocalDateTime payTime; -} diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/alipay/dao/AliPayRecordManager.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/alipay/dao/AliPayRecordManager.java index 467a8b7c..8989a4fd 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/alipay/dao/AliPayRecordManager.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/alipay/dao/AliPayRecordManager.java @@ -25,7 +25,6 @@ import java.util.List; @RequiredArgsConstructor public class AliPayRecordManager extends BaseManager { - /** * 分页 */ diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/convert/UnionPayConvert.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/convert/UnionPayConvert.java index ca262be4..81f27622 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/convert/UnionPayConvert.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/convert/UnionPayConvert.java @@ -1,7 +1,9 @@ package cn.bootx.platform.daxpay.service.core.channel.union.convert; import cn.bootx.platform.daxpay.service.core.channel.union.entity.UnionPayConfig; +import cn.bootx.platform.daxpay.service.core.channel.union.entity.UnionPayRecord; import cn.bootx.platform.daxpay.service.dto.channel.union.UnionPayConfigDto; +import cn.bootx.platform.daxpay.service.dto.channel.union.UnionPayRecordDto; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @@ -16,4 +18,6 @@ public interface UnionPayConvert { UnionPayConfigDto convert(UnionPayConfig in); + UnionPayRecordDto convert(UnionPayRecord in); + } diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/dao/UnionPayRecordManager.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/dao/UnionPayRecordManager.java index a253d9a0..a053391a 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/dao/UnionPayRecordManager.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/dao/UnionPayRecordManager.java @@ -1,11 +1,20 @@ package cn.bootx.platform.daxpay.service.core.channel.union.dao; +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.channel.union.entity.UnionPayRecord; +import cn.bootx.platform.daxpay.service.param.channel.union.UnionPayRecordQuery; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Repository; +import java.time.LocalDateTime; +import java.util.List; + /** * @author xxm * @since 2022/3/11 @@ -15,4 +24,21 @@ import org.springframework.stereotype.Repository; @RequiredArgsConstructor public class UnionPayRecordManager extends BaseManager { + /** + * 分页 + */ + public Page page(PageParam pageParam, UnionPayRecordQuery param){ + Page mpPage = MpUtil.getMpPage(pageParam, UnionPayRecord.class); + QueryWrapper generator = QueryGenerator.generator(param); + return this.page(mpPage, generator); + } + + /** + * 按时间范围查询 + */ + public List findByDate(LocalDateTime startDate, LocalDateTime endDate){ + return this.lambdaQuery() + .between(UnionPayRecord::getGatewayTime, startDate, endDate) + .list(); + } } diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/entity/UnionPayRecord.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/entity/UnionPayRecord.java index d3295269..6e30e324 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/entity/UnionPayRecord.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/entity/UnionPayRecord.java @@ -1,12 +1,18 @@ package cn.bootx.platform.daxpay.service.core.channel.union.entity; -import cn.bootx.platform.daxpay.service.common.entity.BasePayOrder; +import cn.bootx.platform.common.core.function.EntityBaseFunction; +import cn.bootx.platform.common.mybatisplus.base.MpCreateEntity; +import cn.bootx.platform.daxpay.service.code.UnionPayRecordTypeEnum; +import cn.bootx.platform.daxpay.service.dto.channel.union.UnionPayRecordDto; +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.EqualsAndHashCode; import lombok.experimental.Accessors; +import java.time.LocalDateTime; + /** * 云闪付流水记录 * @author xxm @@ -17,6 +23,40 @@ import lombok.experimental.Accessors; @DbTable(comment = "云闪付流水记录") @Accessors(chain = true) @TableName("pay_union_pay_record") -public class UnionPayRecord extends BasePayOrder { +public class UnionPayRecord extends MpCreateEntity implements EntityBaseFunction { + /** 标题 */ + @DbColumn(comment = "标题") + private String title; + + /** 金额 */ + @DbColumn(comment = "金额") + private Integer amount; + + /** + * 业务类型 + * @see UnionPayRecordTypeEnum + */ + @DbColumn(comment = "业务类型") + private String type; + + /** 本地订单号 */ + @DbColumn(comment = "本地订单号") + private Long orderId; + + /** 网关订单号 */ + @DbColumn(comment = "网关订单号") + private String gatewayOrderNo; + + /** 网关完成时间 */ + @DbColumn(comment = "网关完成时间") + private LocalDateTime gatewayTime; + + /** + * 转换 + */ + @Override + public UnionPayRecordDto toDto() { + return null; + } } diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/service/UnionPayCallbackService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/service/UnionPayCallbackService.java new file mode 100644 index 00000000..ff278d35 --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/service/UnionPayCallbackService.java @@ -0,0 +1,128 @@ +package cn.bootx.platform.daxpay.service.core.channel.union.service; + +import cn.bootx.platform.common.core.util.LocalDateTimeUtil; +import cn.bootx.platform.daxpay.code.PayChannelEnum; +import cn.bootx.platform.daxpay.code.PayStatusEnum; +import cn.bootx.platform.daxpay.service.code.PaymentTypeEnum; +import cn.bootx.platform.daxpay.service.common.context.CallbackLocal; +import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal; +import cn.bootx.platform.daxpay.service.core.channel.union.entity.UnionPayConfig; +import cn.bootx.platform.daxpay.service.func.AbsCallbackStrategy; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.ijpay.core.enums.SignType; +import com.ijpay.core.kit.WxPayKit; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Map; +import java.util.Objects; + +import static cn.bootx.platform.daxpay.service.code.UnionPayCode.*; + +/** + * 云闪付回调处理 + * @author xxm + * @since 2024/3/7 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class UnionPayCallbackService extends AbsCallbackStrategy { + + @Resource + private UnionPayConfigService unionPayConfigService; + + /** + * 验证信息格式 + */ + @Override + public boolean verifyNotify() { + CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo(); + Map params = callbackInfo.getCallbackParam(); + String callReq = JSONUtil.toJsonStr(params); + log.info("云闪付发起回调 报文: {}", callReq); + + String status = params.get(STATUS); + String returnCode = params.get(RESULT_CODE); + + // 处理失败 + if (!Objects.equals(SUCCESS, status)||!Objects.equals(SUCCESS, returnCode)){ + return false; + } + + // 支付回调信息校验 + UnionPayConfig config = unionPayConfigService.getConfig(); + if (Objects.isNull(config)) { + log.warn("云闪付支付配置不存在"); + return false; + } + + // 注意此处签名方式需与统一下单的签名类型一致 + return WxPayKit.verifyNotify(params, config.getAppKey(), SignType.MD5); + } + + /** + * 判断类型 支付回调/退款回调, 云闪付只有支付回调 + * + * @see PaymentTypeEnum + */ + @Override + public PaymentTypeEnum getCallbackType() { + return PaymentTypeEnum.PAY; + } + + /** + * 解析支付回调数据并放到上下文中 + */ + @Override + public void resolvePayData() { + CallbackLocal callbackInfo = PaymentContextLocal.get().getCallbackInfo(); + Map callbackParam = callbackInfo.getCallbackParam(); + + // 网关订单号 + callbackInfo.setGatewayOrderNo(callbackParam.get(TRANSACTION_ID)); + // 支付订单ID + callbackInfo.setOrderId(Long.valueOf(callbackParam.get(OUT_TRANSACTION_ID))); + // 支付结果 + PayStatusEnum payStatus = WxPayKit.codeIsOk(callbackParam.get(PAY_RESULT)) ? PayStatusEnum.SUCCESS : PayStatusEnum.FAIL; + callbackInfo.setGatewayStatus(payStatus.getCode()); + // 支付金额 + callbackInfo.setAmount(callbackParam.get(TOTAL_FEE)); + String timeEnd = callbackParam.get(TIME_END); + if (StrUtil.isNotBlank(timeEnd)) { + LocalDateTime time = LocalDateTimeUtil.parse(timeEnd, DatePattern.PURE_DATETIME_PATTERN); + callbackInfo.setFinishTime(time); + } else { + callbackInfo.setFinishTime(LocalDateTime.now()); + } + } + + /** + * 解析退款回调数据并放到上下文中 + */ + @Override + public void resolveRefundData() { + + } + + /** + * 返回响应结果 + */ + @Override + public String getReturnMsg() { + return "success"; + } + + /** + * 策略标识 + */ + @Override + public PayChannelEnum getChannel() { + return PayChannelEnum.UNION_PAY; + } +} diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/service/UnionPayCloseService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/service/UnionPayCloseService.java new file mode 100644 index 00000000..7f10649d --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/service/UnionPayCloseService.java @@ -0,0 +1,65 @@ +package cn.bootx.platform.daxpay.service.core.channel.union.service; + +import cn.bootx.platform.daxpay.exception.pay.PayFailureException; +import cn.bootx.platform.daxpay.service.code.UnionPayCode; +import cn.bootx.platform.daxpay.service.core.channel.union.entity.UnionPayConfig; +import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder; +import cn.hutool.core.util.StrUtil; +import com.ijpay.core.enums.SignType; +import com.ijpay.core.kit.WxPayKit; +import com.ijpay.unionpay.enums.ServiceEnum; +import com.ijpay.unionpay.model.CloseOrderModel; +import com.ijpay.wxpay.WxPayApi; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Map; +import java.util.Objects; + +import static cn.bootx.platform.daxpay.service.code.UnionPayCode.*; + +/** + * 云闪付支付关闭 + * @author xxm + * @since 2024/3/7 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class UnionPayCloseService { + + /** + * 关闭订单 + */ + public void close(PayOrder payOrder, UnionPayConfig unionPayConfig) { + Map params = CloseOrderModel.builder() + .service(ServiceEnum.CLOSE.toString()) + .mch_id(unionPayConfig.getMachId()) + .out_trade_no(String.valueOf(payOrder.getId())) + .nonce_str(WxPayKit.generateStr()) + .build() + .createSign(unionPayConfig.getAppKey(), SignType.HMACSHA256); + String xmlResult = WxPayApi.closeOrder(params); + Map result = WxPayKit.xmlToMap(xmlResult); + this.verifyErrorMsg(result); + } + + /** + * 验证错误信息 + */ + private void verifyErrorMsg(Map result) { + String status = result.get(UnionPayCode.STATUS); + String returnCode = result.get(UnionPayCode.RESULT_CODE); + + // 判断查询是否成功 + if (!(Objects.equals(SUCCESS, status) && Objects.equals(SUCCESS, returnCode))){ + String errorMsg = result.get(ERR_MSG); + if (StrUtil.isBlank(errorMsg)) { + errorMsg = result.get(MESSAGE); + } + log.error("订单关闭失败 {}", errorMsg); + throw new PayFailureException(errorMsg); + } + } +} diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/service/UnionPayReconcileService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/service/UnionPayReconcileService.java new file mode 100644 index 00000000..7deb0a9f --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/service/UnionPayReconcileService.java @@ -0,0 +1,17 @@ +package cn.bootx.platform.daxpay.service.core.channel.union.service; + +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/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/service/UnionPayRecordService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/service/UnionPayRecordService.java new file mode 100644 index 00000000..c7b4214f --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/service/UnionPayRecordService.java @@ -0,0 +1,72 @@ +package cn.bootx.platform.daxpay.service.core.channel.union.service; + +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.code.UnionPayRecordTypeEnum; +import cn.bootx.platform.daxpay.service.core.channel.union.dao.UnionPayRecordManager; +import cn.bootx.platform.daxpay.service.core.channel.union.entity.UnionPayRecord; +import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder; +import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder; +import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundChannelOrder; +import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrder; +import cn.bootx.platform.daxpay.service.dto.channel.union.UnionPayRecordDto; +import cn.bootx.platform.daxpay.service.param.channel.union.UnionPayRecordQuery; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +/** + * 云闪付支付记录服务 + * @author xxm + * @since 2024/3/7 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class UnionPayRecordService { + private final UnionPayRecordManager unionPayRecordManager; + + /** + * 支付 + */ + public void pay(PayOrder order, PayChannelOrder channelOrder){ + UnionPayRecord unionPayRecord = new UnionPayRecord() + .setType(UnionPayRecordTypeEnum.PAY.getCode()) + .setTitle(order.getTitle()) + .setOrderId(order.getId()) + .setAmount(channelOrder.getAmount()) + .setGatewayOrderNo(order.getGatewayOrderNo()) + .setGatewayTime(channelOrder.getPayTime()); + unionPayRecordManager.save(unionPayRecord); + } + + /** + * 退款 + */ + public void refund(RefundOrder order, RefundChannelOrder channelOrder){ + UnionPayRecord unionPayRecord = new UnionPayRecord() + .setType(UnionPayRecordTypeEnum.REFUND.getCode()) + .setTitle(order.getTitle()) + .setOrderId(order.getId()) + .setAmount(channelOrder.getAmount()) + .setGatewayOrderNo(order.getGatewayOrderNo()) + .setGatewayTime(channelOrder.getRefundTime()); + unionPayRecordManager.save(unionPayRecord); + } + + /** + * 分页 + */ + public PageResult page(PageParam pageParam, UnionPayRecordQuery param){ + return MpUtil.convert2DtoPageResult(unionPayRecordManager.page(pageParam, param)); + } + + /** + * 查询详情 + */ + public UnionPayRecordDto findById(Long id){ + return unionPayRecordManager.findById(id).map(UnionPayRecord::toDto).orElseThrow(DataNotExistException::new); + } +} diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/service/UnionPayRefundService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/service/UnionPayRefundService.java new file mode 100644 index 00000000..4e277619 --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/service/UnionPayRefundService.java @@ -0,0 +1,83 @@ +package cn.bootx.platform.daxpay.service.core.channel.union.service; + +import cn.bootx.platform.daxpay.code.RefundStatusEnum; +import cn.bootx.platform.daxpay.exception.pay.PayFailureException; +import cn.bootx.platform.daxpay.service.code.UnionPayCode; +import cn.bootx.platform.daxpay.service.common.context.RefundLocal; +import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal; +import cn.bootx.platform.daxpay.service.core.channel.union.entity.UnionPayConfig; +import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder; +import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrder; +import cn.hutool.core.util.StrUtil; +import com.ijpay.core.enums.SignType; +import com.ijpay.core.kit.WxPayKit; +import com.ijpay.unionpay.UnionPayApi; +import com.ijpay.unionpay.enums.ServiceEnum; +import com.ijpay.unionpay.model.RefundModel; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +import static cn.bootx.platform.daxpay.service.code.UnionPayCode.*; + +/** + * 云闪付退款操作 + * @author xxm + * @since 2024/3/7 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class UnionPayRefundService { + + + /** + * 退款方法 + */ + public void refund(RefundOrder refundOrder, int amount, PayChannelOrder channelOrder, UnionPayConfig unionPayConfig) { + Map params = RefundModel.builder() + .service(ServiceEnum.REFUND.toString()) + .mch_id(unionPayConfig.getMachId()) + .out_trade_no(String.valueOf(refundOrder.getPaymentId())) + .out_refund_no(String.valueOf(refundOrder.getId())) + .total_fee(String.valueOf(channelOrder.getAmount())) + .refund_fee(String.valueOf(amount)) + .op_user_id(unionPayConfig.getMachId()) + .nonce_str(WxPayKit.generateStr()) + .build() + .createSign(unionPayConfig.getAppKey(), SignType.MD5); + + String xmlResult = UnionPayApi.execution(unionPayConfig.getServerUrl(), params); + Map result = WxPayKit.xmlToMap(xmlResult); + this.verifyErrorMsg(result); + // 云闪付退款是否成功需要查询状态, 所以设置为退款中状态 + RefundLocal refundInfo = PaymentContextLocal.get().getRefundInfo(); + refundInfo.setStatus(RefundStatusEnum.PROGRESS) + .setGatewayOrderNo(result.get(REFUND_ID)); + } + + /** + * 验证错误信息 + */ + private void verifyErrorMsg(Map result) { + String status = result.get(UnionPayCode.STATUS); + String returnCode = result.get(UnionPayCode.RESULT_CODE); + + // 判断查询是否成功 + if (!(Objects.equals(SUCCESS, status) && Objects.equals(SUCCESS, returnCode))){ + String errorMsg = result.get(ERR_MSG); + if (StrUtil.isBlank(errorMsg)) { + errorMsg = result.get(MESSAGE); + } + log.error("订单退款失败 {}", errorMsg); + RefundLocal refundInfo = PaymentContextLocal.get().getRefundInfo(); + refundInfo.setErrorMsg(errorMsg); + refundInfo.setErrorCode(Optional.ofNullable(returnCode).orElse(returnCode)); + throw new PayFailureException(errorMsg); + } + } +} diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/service/UnionPayService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/service/UnionPayService.java index 652d842c..c024d7ac 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/service/UnionPayService.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/service/UnionPayService.java @@ -5,24 +5,30 @@ import cn.bootx.platform.daxpay.exception.pay.PayFailureException; import cn.bootx.platform.daxpay.param.channel.UnionPayParam; import cn.bootx.platform.daxpay.param.pay.PayChannelParam; import cn.bootx.platform.daxpay.service.code.AliPayWay; +import cn.bootx.platform.daxpay.service.code.UnionPayCode; import cn.bootx.platform.daxpay.service.common.context.PayLocal; import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal; import cn.bootx.platform.daxpay.service.core.channel.union.entity.UnionPayConfig; import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder; import cn.bootx.platform.daxpay.util.PayUtil; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; import com.ijpay.core.enums.SignType; import com.ijpay.core.kit.WxPayKit; import com.ijpay.unionpay.UnionPayApi; import com.ijpay.unionpay.enums.ServiceEnum; +import com.ijpay.unionpay.model.MicroPayModel; import com.ijpay.unionpay.model.UnifiedOrderModel; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import java.util.Map; +import java.util.Objects; import java.util.Optional; +import static cn.bootx.platform.daxpay.service.code.UnionPayCode.*; + /** * 云闪付支付 * @author xxm @@ -33,45 +39,6 @@ import java.util.Optional; @RequiredArgsConstructor public class UnionPayService { - /** - * 支付接口 - */ - public void pay(PayOrder payOrder, PayChannelParam payChannelParam, UnionPayParam unionPayParam, UnionPayConfig config){ - - Integer amount = payChannelParam.getAmount(); - String totalFee = String.valueOf(amount); - PayLocal asyncPayInfo = PaymentContextLocal.get().getPayInfo();; - String payBody = null; - PayWayEnum payWayEnum = PayWayEnum.findByCode(payChannelParam.getWay()); - - // 二维码支付 - if (payWayEnum == PayWayEnum.QRCODE){ - payBody = this.qrCodePay(totalFee, payOrder, config); - } - - asyncPayInfo.setPayBody(payBody); - } - - /** - * 扫码支付 - */ - public String qrCodePay(String totalFee, PayOrder payOrder, UnionPayConfig config){ - Map params = UnifiedOrderModel.builder() - .service(ServiceEnum.NATIVE.toString()) - .mch_id(config.getMachId()) - .out_trade_no(String.valueOf(payOrder.getId())) - .body(payOrder.getTitle()) - .total_fee(totalFee) - .time_expire(PayUtil.getUnionExpiredTime(payOrder.getExpiredTime())) - .mch_create_ip("127.0.0.1") - .notify_url(config.getNotifyUrl()) - .nonce_str(WxPayKit.generateStr()) - .build() - .createSign(config.getAppKey(), SignType.MD5); - String xmlResult = UnionPayApi.execution(config.getServerUrl(), params); - Map result = WxPayKit.xmlToMap(xmlResult); - return result.get("code_url"); - } /** * 支付前检查支付方式是否可用 @@ -88,4 +55,203 @@ public class UnionPayService { throw new PayFailureException("该云闪付支付方式不可用"); } } + + /** + * 支付接口 + */ + public void pay(PayOrder payOrder, PayChannelParam payChannelParam, UnionPayParam unionPayParam, UnionPayConfig unionPayConfig){ + Integer amount = payChannelParam.getAmount(); + String totalFee = String.valueOf(amount); + PayLocal asyncPayInfo = PaymentContextLocal.get().getPayInfo();; + String payBody = null; + PayWayEnum payWayEnum = PayWayEnum.findByCode(payChannelParam.getWay()); + + // 微信APP支付 + if (payWayEnum == PayWayEnum.APP) { + payBody = this.wxAppPay(totalFee, payOrder, unionPayParam, unionPayConfig); + } + // 微信公众号支付或者小程序支付 + else if (payWayEnum == PayWayEnum.JSAPI_WX_PAY) { + payBody = this.wxJsPay(totalFee, payOrder, unionPayParam.getOpenId(), unionPayConfig); + } + // 支付宝JS支付 + else if (payWayEnum == PayWayEnum.JSAPI_ALI_PAY) { + payBody = this.aliJsPay(totalFee, payOrder, unionPayParam, unionPayConfig); + } + // 银联JS支付 + else if (payWayEnum == PayWayEnum.JSAPI) { + payBody = this.unionJsPay(totalFee, payOrder, unionPayParam, unionPayConfig); + } + // 二维码支付 + else if (payWayEnum == PayWayEnum.QRCODE) { + payBody = this.qrCodePay(totalFee, payOrder, unionPayConfig); + } + // 付款码支付 + else if (payWayEnum == PayWayEnum.BARCODE) { + this.barCodePay(totalFee, payOrder, unionPayParam.getAuthCode(), unionPayConfig); + } + + asyncPayInfo.setPayBody(payBody); + } + + /** + * 支付宝生活号支付 + */ + private String aliJsPay(String amount, PayOrder payOrder, UnionPayParam unionPayParam, UnionPayConfig unionPayConfig) { + Map params = UnifiedOrderModel.builder() + .service(ServiceEnum.ALI_PAY_JS_PAY.toString()) + .mch_id(unionPayConfig.getMachId()) + .out_trade_no(WxPayKit.generateStr()) + .body(payOrder.getTitle()) + .total_fee(amount) + .mch_create_ip("127.0.0.15") + .notify_url(unionPayConfig.getNotifyUrl()) + .nonce_str(WxPayKit.generateStr()) + .buyer_id(unionPayParam.getBuyerId()) + .build() + .createSign(unionPayConfig.getAppKey(), SignType.MD5); + + String xmlResult = UnionPayApi.execution(unionPayConfig.getServerUrl(), params); + Map result = WxPayKit.xmlToMap(xmlResult); + this.verifyErrorMsg(result); + return null; + } + + /** + * 银联JS支付 + */ + private String unionJsPay(String amount, PayOrder payOrder, UnionPayParam unionPayParam, UnionPayConfig unionPayConfig) { + Map params = UnifiedOrderModel.builder() + .service(ServiceEnum.UNION_JS_PAY.toString()) + .mch_id(unionPayConfig.getMachId()) + .out_trade_no(WxPayKit.generateStr()) + .body(payOrder.getTitle()) + .user_id(unionPayParam.getUserId()) + .customer_ip(unionPayParam.getCustomerIp()) + .total_fee(amount) + .mch_create_ip("127.0.0.1") + .notify_url(unionPayConfig.getNotifyUrl()) + .nonce_str(WxPayKit.generateStr()) + .build() + .createSign(unionPayConfig.getAppKey(), SignType.MD5); + + System.out.println(params); + + String xmlResult = UnionPayApi.execution(unionPayConfig.getServerUrl(), params); + Map result = WxPayKit.xmlToMap(xmlResult); + this.verifyErrorMsg(result); + return null; + } + + /** + * 微信APP支付 + */ + private String wxAppPay(String amount, PayOrder payOrder, UnionPayParam unionPayParam, UnionPayConfig unionPayConfig) { + Map params = UnifiedOrderModel.builder() + .service(ServiceEnum.WEI_XIN_APP_PAY.toString()) + .mch_id(unionPayConfig.getMachId()) + .appid(unionPayParam.getAppId()) + .sub_appid(unionPayParam.getSubAppId()) + .out_trade_no(WxPayKit.generateStr()) + .body(payOrder.getTitle()) + .attach("聚合支付 SDK") + .total_fee(amount) + .mch_create_ip("127.0.0.1") + .notify_url(unionPayConfig.getNotifyUrl()) + .nonce_str(WxPayKit.generateStr()) + .build() + .createSign(unionPayConfig.getAppKey(), SignType.MD5); + + String xmlResult = UnionPayApi.execution(unionPayConfig.getServerUrl(), params); + Map result = WxPayKit.xmlToMap(xmlResult); + this.verifyErrorMsg(result); + return null; + } + + /** + * 微信公众号支付或者小程序支付 + */ + private String wxJsPay(String amount, PayOrder payOrder, String openId, UnionPayConfig unionPayConfig) { + + Map params = UnifiedOrderModel.builder() + .service(ServiceEnum.WEI_XIN_JS_PAY.toString()) + .mch_id(unionPayConfig.getMachId()) + // 原生JS 值为1 + .is_raw("1") + .out_trade_no(WxPayKit.generateStr()) + .body(payOrder.getTitle()) + .sub_openid(openId) + .total_fee(amount) + .mch_create_ip("127.0.0.1") + .notify_url(unionPayConfig.getNotifyUrl()) + .nonce_str(WxPayKit.generateStr()) + .build() + .createSign(unionPayConfig.getAppKey(), SignType.MD5); + String xmlResult = UnionPayApi.execution(unionPayConfig.getServerUrl(), params); + Map result = WxPayKit.xmlToMap(xmlResult); + this.verifyErrorMsg(result); + return null; + } + + /** + * 扫码支付 + */ + private String qrCodePay(String amount, PayOrder payOrder, UnionPayConfig config){ + Map params = UnifiedOrderModel.builder() + .service(ServiceEnum.NATIVE.toString()) + .mch_id(config.getMachId()) + .out_trade_no(String.valueOf(payOrder.getId())) + .body(payOrder.getTitle()) + .total_fee(amount) + .time_expire(PayUtil.getUnionExpiredTime(payOrder.getExpiredTime())) + .mch_create_ip("127.0.0.1") + .notify_url(config.getNotifyUrl()) + .nonce_str(WxPayKit.generateStr()) + .build() + .createSign(config.getAppKey(), SignType.MD5); + String xmlResult = UnionPayApi.execution(config.getServerUrl(), params); + Map result = WxPayKit.xmlToMap(xmlResult); + this.verifyErrorMsg(result); + return result.get("code_url"); + } + + /** + * 付款码支付 + */ + private void barCodePay(String amount, PayOrder payOrder, String authCode, UnionPayConfig unionPayConfig) { + Map params = MicroPayModel.builder() + .service(ServiceEnum.MICRO_PAY.toString()) + .mch_id(unionPayConfig.getMachId()) + .out_trade_no(WxPayKit.generateStr()) + .body(payOrder.getTitle()) + .total_fee(amount) + .op_device_id("daxpay") + .mch_create_ip("127.0.0.1") + .auth_code(authCode) + .nonce_str(WxPayKit.generateStr()) + .build() + .createSign(unionPayConfig.getAppKey(), SignType.MD5); + + String xmlResult = UnionPayApi.execution(unionPayConfig.getServerUrl(), params); + + } + + /** + * 验证错误信息 + */ + private void verifyErrorMsg(Map result) { + String status = result.get(UnionPayCode.STATUS); + String returnCode = result.get(UnionPayCode.RESULT_CODE); + + // 判断查询是否成功 + if (!(Objects.equals(SUCCESS, status) && Objects.equals(SUCCESS, returnCode))){ + String errorMsg = result.get(ERR_MSG); + if (StrUtil.isBlank(errorMsg)) { + errorMsg = result.get(MESSAGE); + } + log.error("订单关闭失败 {}", errorMsg); + throw new PayFailureException(errorMsg); + } + } + } diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/service/UnionPaySyncService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/service/UnionPaySyncService.java new file mode 100644 index 00000000..59f22413 --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/union/service/UnionPaySyncService.java @@ -0,0 +1,154 @@ +package cn.bootx.platform.daxpay.service.core.channel.union.service; + +import cn.bootx.platform.common.core.util.LocalDateTimeUtil; +import cn.bootx.platform.daxpay.code.PaySyncStatusEnum; +import cn.bootx.platform.daxpay.code.RefundSyncStatusEnum; +import cn.bootx.platform.daxpay.service.code.UnionPayCode; +import cn.bootx.platform.daxpay.service.core.channel.union.entity.UnionPayConfig; +import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder; +import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrder; +import cn.bootx.platform.daxpay.service.core.payment.sync.result.PayGatewaySyncResult; +import cn.bootx.platform.daxpay.service.core.payment.sync.result.RefundGatewaySyncResult; +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONUtil; +import com.ijpay.core.enums.SignType; +import com.ijpay.core.kit.WxPayKit; +import com.ijpay.unionpay.UnionPayApi; +import com.ijpay.unionpay.enums.ServiceEnum; +import com.ijpay.unionpay.model.OrderQueryModel; +import com.ijpay.unionpay.model.RefundQueryModel; +import com.ijpay.wxpay.WxPayApi; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.Map; +import java.util.Objects; + +import static cn.bootx.platform.daxpay.service.code.UnionPayCode.*; + +/** + * 云闪付支付同步 + * @author xxm + * @since 2024/3/7 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class UnionPaySyncService { + + /** + * 支付信息查询 + */ + public PayGatewaySyncResult syncPayStatus(PayOrder order, UnionPayConfig unionPayConfig) { + PayGatewaySyncResult syncResult = new PayGatewaySyncResult().setSyncStatus(PaySyncStatusEnum.FAIL); + Map params = OrderQueryModel.builder() + .service(ServiceEnum.QUERY.toString()) + .mch_id(unionPayConfig.getMachId()) + .out_trade_no(String.valueOf(order.getId())) + .nonce_str(WxPayKit.generateStr()) + .build() + .createSign(unionPayConfig.getAppKey(), SignType.MD5); + + String xmlResult = UnionPayApi.execution(unionPayConfig.getServerUrl(), params); + Map result = WxPayKit.xmlToMap(xmlResult); + syncResult.setSyncInfo(JSONUtil.toJsonStr(result)); + + String status = result.get(STATUS); + String returnCode = result.get(RESULT_CODE); + + // 判断查询是否成功 + if (!(Objects.equals(SUCCESS, status) && Objects.equals(SUCCESS, returnCode))){ + log.warn("查询云闪付订单失败:{}", result); + return syncResult; + } + + // 设置微信支付网关订单号 + syncResult.setGatewayOrderNo(result.get(TRANSACTION_ID)); + // 查询到订单的状态 + String tradeStatus = result.get(TRADE_STATE); + // 支付完成 + if (Objects.equals(tradeStatus, SUCCESS)) { + String timeEnd = result.get(TIME_END); + LocalDateTime time = LocalDateTimeUtil.parse(timeEnd, DatePattern.PURE_DATETIME_PATTERN); + return syncResult.setPayTime(time).setSyncStatus(PaySyncStatusEnum.SUCCESS); + } + // 待支付 + if (Objects.equals(tradeStatus, TRADE_NOT_PAY)) { + return syncResult.setSyncStatus(PaySyncStatusEnum.PROGRESS); + } + + // 已退款/退款中 + if (Objects.equals(tradeStatus, TRADE_REFUND)) { + return syncResult.setSyncStatus(PaySyncStatusEnum.REFUND); + } + // 已关闭 + if (Objects.equals(tradeStatus, TRADE_CLOSED)) { + return syncResult.setSyncStatus(PaySyncStatusEnum.CLOSED); + } + + return syncResult; + } + + /** + * 退款信息查询 + */ + public RefundGatewaySyncResult syncRefundStatus(RefundOrder refundOrder, UnionPayConfig unionPayConfig){ + RefundGatewaySyncResult syncResult = new RefundGatewaySyncResult(); + Map params = RefundQueryModel.builder() + .service(ServiceEnum.REFUND_QUERY.toString()) + .mch_id(unionPayConfig.getMachId()) + .refund_id(refundOrder.getGatewayOrderNo()) + .nonce_str(WxPayKit.generateStr()) + .build() + .createSign(unionPayConfig.getAppKey(), SignType.MD5); + + try { + String xmlResult = WxPayApi.orderRefundQuery(false, params); + Map result = WxPayKit.xmlToMap(xmlResult); + syncResult.setSyncInfo(JSONUtil.toJsonStr(result)); + + // 设置微信支付网关订单号 + syncResult.setGatewayOrderNo(result.get(UnionPayCode.REFUND_ID)); + // 状态 +// String tradeStatus = result.get(UnionPayCode.REFUND_STATUS); +// // 退款成功 +// if (Objects.equals(tradeStatus, UnionPayCode.REFUND_SUCCESS)) { +// String timeEnd = result.get(UnionPayCode.REFUND_SUCCESS_TIME); +// LocalDateTime time = LocalDateTimeUtil.parse(timeEnd, DatePattern.NORM_DATETIME_PATTERN); +// return syncResult.setRefundTime(time).setSyncStatus(RefundSyncStatusEnum.SUCCESS); +// } +// // 退款中 +// if (Objects.equals(tradeStatus, UnionPayCode.REFUND_PROCESSING)) { +// return syncResult.setSyncStatus(RefundSyncStatusEnum.PROGRESS); +// } + String errorMsg = this.getErrorMsg(result); + return syncResult.setSyncStatus(RefundSyncStatusEnum.FAIL).setErrorMsg(errorMsg); + } catch (Exception e) { + log.error("查询退款订单失败:", e); + syncResult.setSyncStatus(RefundSyncStatusEnum.PROGRESS).setErrorMsg(e.getMessage()); + } + return syncResult; + } + + /** + * 验证错误信息 + */ + private String getErrorMsg(Map result) { + String status = result.get(UnionPayCode.STATUS); + String returnCode = result.get(UnionPayCode.RESULT_CODE); + + // 判断查询是否成功 + if (!(Objects.equals(SUCCESS, status) && Objects.equals(SUCCESS, returnCode))){ + String errorMsg = result.get(ERR_MSG); + if (StrUtil.isBlank(errorMsg)) { + errorMsg = result.get(MESSAGE); + } + log.error("订单查询失败 {}", errorMsg); + return errorMsg; + } + return null; + } +} diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wechat/service/WeChatPayCloseService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wechat/service/WeChatPayCloseService.java index a79940ea..6508ceab 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wechat/service/WeChatPayCloseService.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wechat/service/WeChatPayCloseService.java @@ -1,12 +1,10 @@ package cn.bootx.platform.daxpay.service.core.channel.wechat.service; import cn.bootx.platform.common.spring.exception.RetryableException; +import cn.bootx.platform.daxpay.exception.pay.PayFailureException; import cn.bootx.platform.daxpay.service.code.WeChatPayCode; -import cn.bootx.platform.daxpay.service.common.context.RefundLocal; -import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal; import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConfig; import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayOrder; -import cn.bootx.platform.daxpay.exception.pay.PayFailureException; import cn.hutool.core.util.StrUtil; import com.ijpay.core.enums.SignType; import com.ijpay.core.kit.WxPayKit; @@ -18,7 +16,6 @@ import org.springframework.retry.annotation.Retryable; import org.springframework.stereotype.Service; import java.util.Map; -import java.util.Optional; /** * 微信支付关闭和退款 @@ -62,9 +59,6 @@ public class WeChatPayCloseService { errorMsg = result.get(WeChatPayCode.RETURN_MSG); } log.error("订单关闭失败 {}", errorMsg); - RefundLocal refundInfo = PaymentContextLocal.get().getRefundInfo(); - refundInfo.setErrorMsg(errorMsg); - refundInfo.setErrorCode(Optional.ofNullable(resultCode).orElse(returnCode)); throw new PayFailureException(errorMsg); } } diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wechat/service/WeChatPayService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wechat/service/WeChatPayService.java index 0506d845..0875cd51 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wechat/service/WeChatPayService.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wechat/service/WeChatPayService.java @@ -101,7 +101,7 @@ public class WeChatPayService { } // 付款码支付 else if (payWayEnum == PayWayEnum.BARCODE) { - this.barCode(totalFee, payOrder, weChatPayParam.getAuthCode(), weChatPayConfig); + this.barCodePay(totalFee, payOrder, weChatPayParam.getAuthCode(), weChatPayConfig); } asyncPayInfo.setPayBody(payBody); } @@ -172,7 +172,7 @@ public class WeChatPayService { /** * 付款码支付 */ - private void barCode(String amount, PayOrder payment, String authCode, WeChatPayConfig weChatPayConfig) { + private void barCodePay(String amount, PayOrder payment, String authCode, WeChatPayConfig weChatPayConfig) { PayLocal asyncPayInfo = PaymentContextLocal.get().getPayInfo(); Map params = MicroPayModel.builder() diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wechat/service/WeChatPaySyncService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wechat/service/WeChatPaySyncService.java index 7a82d25d..75aa616f 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wechat/service/WeChatPaySyncService.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wechat/service/WeChatPaySyncService.java @@ -142,9 +142,6 @@ public class WeChatPaySyncService { return syncResult; } - /** - * 错误处理 - */ /** * 验证错误信息 */ diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wechat/service/WechatRefundService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wechat/service/WechatPayRefundService.java similarity index 86% rename from daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wechat/service/WechatRefundService.java rename to daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wechat/service/WechatPayRefundService.java index a5dc9c1e..6bef8033 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wechat/service/WechatRefundService.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wechat/service/WechatPayRefundService.java @@ -2,11 +2,9 @@ package cn.bootx.platform.daxpay.service.core.channel.wechat.service; import cn.bootx.platform.daxpay.code.RefundStatusEnum; import cn.bootx.platform.daxpay.exception.pay.PayFailureException; -import cn.bootx.platform.daxpay.service.code.WeChatPayCode; import cn.bootx.platform.daxpay.service.common.context.RefundLocal; import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal; import cn.bootx.platform.daxpay.service.core.channel.wechat.entity.WeChatPayConfig; -import cn.bootx.platform.daxpay.service.core.order.pay.dao.PayChannelOrderManager; import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder; import cn.bootx.platform.daxpay.service.core.order.refund.entity.RefundOrder; import cn.hutool.core.codec.Base64; @@ -23,6 +21,8 @@ import java.io.ByteArrayInputStream; import java.util.Map; import java.util.Optional; +import static cn.bootx.platform.daxpay.service.code.WeChatPayCode.*; + /** * 微信退款服务 * @author xxm @@ -31,9 +31,7 @@ import java.util.Optional; @Slf4j @Service @RequiredArgsConstructor -public class WechatRefundService { - - private final PayChannelOrderManager payChannelOrderManager; +public class WechatPayRefundService { /** * 退款方法 @@ -70,19 +68,19 @@ public class WechatRefundService { this.verifyErrorMsg(result); // 微信退款是否成功需要查询状态或者回调, 所以设置为退款中状态 refundInfo.setStatus(RefundStatusEnum.PROGRESS) - .setGatewayOrderNo(result.get("refund_id")); + .setGatewayOrderNo(result.get(CALLBACK_REFUND_ID)); } /** * 验证错误信息 */ private void verifyErrorMsg(Map result) { - String returnCode = result.get(WeChatPayCode.RETURN_CODE); - String resultCode = result.get(WeChatPayCode.RESULT_CODE); + String returnCode = result.get(RETURN_CODE); + String resultCode = result.get(RESULT_CODE); if (!WxPayKit.codeIsOk(returnCode) || !WxPayKit.codeIsOk(resultCode)) { - String errorMsg = result.get(WeChatPayCode.ERR_CODE_DES); + String errorMsg = result.get(ERR_CODE_DES); if (StrUtil.isBlank(errorMsg)) { - errorMsg = result.get(WeChatPayCode.RETURN_MSG); + errorMsg = result.get(RETURN_MSG); } log.error("订单退款失败 {}", errorMsg); RefundLocal refundInfo = PaymentContextLocal.get().getRefundInfo(); diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/close/strategy/UnionPayCloseStrategy.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/close/strategy/UnionPayCloseStrategy.java index 02ec2e03..86a054b1 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/close/strategy/UnionPayCloseStrategy.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/close/strategy/UnionPayCloseStrategy.java @@ -1,6 +1,9 @@ package cn.bootx.platform.daxpay.service.core.payment.close.strategy; import cn.bootx.platform.daxpay.code.PayChannelEnum; +import cn.bootx.platform.daxpay.service.core.channel.union.entity.UnionPayConfig; +import cn.bootx.platform.daxpay.service.core.channel.union.service.UnionPayCloseService; +import cn.bootx.platform.daxpay.service.core.channel.union.service.UnionPayConfigService; import cn.bootx.platform.daxpay.service.func.AbsPayCloseStrategy; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -20,17 +23,31 @@ import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROT @RequiredArgsConstructor public class UnionPayCloseStrategy extends AbsPayCloseStrategy { + private final UnionPayCloseService unionPayCloseService; + + private final UnionPayConfigService unionPayConfigService; + + private UnionPayConfig unionPayConfig; + @Override public PayChannelEnum getChannel() { return PayChannelEnum.UNION_PAY; } + /** + * 关闭前的处理方式 + */ + @Override + public void doBeforeCloseHandler() { + this.unionPayConfig = unionPayConfigService.getConfig(); + } + /** * 关闭操作 */ @Override public void doCloseHandler() { - + unionPayCloseService.close(this.getOrder(), this.unionPayConfig); } } diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/UnionPayStrategy.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/UnionPayStrategy.java index 864f5e18..7a3c9bd4 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/UnionPayStrategy.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/UnionPayStrategy.java @@ -9,6 +9,7 @@ import cn.bootx.platform.daxpay.service.common.context.PayLocal; import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal; 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.UnionPayRecordService; import cn.bootx.platform.daxpay.service.core.channel.union.service.UnionPayService; import cn.bootx.platform.daxpay.service.core.order.pay.entity.PayChannelOrder; import cn.bootx.platform.daxpay.service.core.order.pay.service.PayChannelOrderService; @@ -38,10 +39,13 @@ import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROT public class UnionPayStrategy extends AbsPayStrategy { private final PayChannelOrderService channelOrderService; + private final UnionPayService unionPayService; private final UnionPayConfigService unionPayConfigService; + private final UnionPayRecordService unionPayRecordService; + private UnionPayParam unionPayParam; private UnionPayConfig unionPayConfig; @@ -56,7 +60,7 @@ public class UnionPayStrategy extends AbsPayStrategy { @Override public void doBeforePayHandler() { try { - // 支付宝参数验证 + // 云闪付参数验证 Map channelParam = this.getPayChannelParam().getChannelParam(); if (CollUtil.isNotEmpty(channelParam)) { this.unionPayParam = BeanUtil.toBean(channelParam, UnionPayParam.class); @@ -73,7 +77,7 @@ public class UnionPayStrategy extends AbsPayStrategy { if (payMode.getAmount() <= 0) { throw new PayAmountAbnormalException(); } - // 检查并获取支付宝支付配置 + // 检查并获取云闪付支付配置 this.unionPayConfig = unionPayConfigService.getAndCheckConfig(); unionPayService.validation(this.getPayChannelParam(), unionPayConfig); } @@ -103,7 +107,7 @@ public class UnionPayStrategy extends AbsPayStrategy { PayChannelOrder payChannelOrder = channelOrderService.switchAsyncPayChannel(this.getOrder(), this.getPayChannelParam()); // 支付完成, 保存记录 if (asyncPayInfo.isPayComplete()) { -// aliRecordService.pay(this.getOrder(), payChannelOrder); + unionPayRecordService.pay(this.getOrder(), payChannelOrder); } } diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/refund/strategy/UnionRefundStrategy.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/refund/strategy/UnionRefundStrategy.java index dfd5b1a4..a417c5bb 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/refund/strategy/UnionRefundStrategy.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/refund/strategy/UnionRefundStrategy.java @@ -1,11 +1,20 @@ package cn.bootx.platform.daxpay.service.core.payment.refund.strategy; import cn.bootx.platform.daxpay.code.PayChannelEnum; +import cn.bootx.platform.daxpay.code.RefundStatusEnum; +import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal; +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.UnionPayRecordService; +import cn.bootx.platform.daxpay.service.core.channel.union.service.UnionPayRefundService; +import cn.bootx.platform.daxpay.service.core.order.pay.service.PayChannelOrderService; import cn.bootx.platform.daxpay.service.func.AbsRefundStrategy; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; +import java.util.Objects; + import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE; /** @@ -17,6 +26,17 @@ import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROT @Component @RequiredArgsConstructor public class UnionRefundStrategy extends AbsRefundStrategy { + + private final UnionPayRefundService unionPayRefundService; + + private final UnionPayConfigService unionPayConfigService; + + private final UnionPayRecordService unionPayRecordService; + + private final PayChannelOrderService payChannelOrderService; + + private UnionPayConfig unionPayConfig; + /** * 策略标识 * @@ -28,11 +48,39 @@ public class UnionRefundStrategy extends AbsRefundStrategy { } /** - * 退款 + * 退款前对处理, 初始化微信支付配置 + */ + @Override + public void doBeforeRefundHandler() { + this.unionPayConfig = unionPayConfigService.getAndCheckConfig(); + } + + + /** + * 退款操作 */ @Override public void doRefundHandler() { + unionPayRefundService.refund(this.getRefundOrder(), this.getRefundChannelParam().getAmount(), this.getPayChannelOrder(), this.unionPayConfig); + } + /** + * 退款发起成功操作 + */ + @Override + public void doSuccessHandler() { + // 更新退款订单数据状态 + RefundStatusEnum refundStatusEnum = PaymentContextLocal.get() + .getRefundInfo() + .getStatus(); + this.getRefundChannelOrder().setStatus(refundStatusEnum.getCode()); + + // 更新支付通道订单中的属性 + payChannelOrderService.updateAsyncPayRefund(this.getPayChannelOrder(), this.getRefundChannelOrder()); + // 如果退款完成, 保存流水记录 + if (Objects.equals(RefundStatusEnum.SUCCESS.getCode(), refundStatusEnum.getCode())) { + unionPayRecordService.refund(this.getRefundOrder(), this.getRefundChannelOrder()); + } } } diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/refund/strategy/WeChatRefundStrategy.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/refund/strategy/WeChatRefundStrategy.java index 3bef73d1..bbcd4d7d 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/refund/strategy/WeChatRefundStrategy.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/refund/strategy/WeChatRefundStrategy.java @@ -6,7 +6,7 @@ import cn.bootx.platform.daxpay.service.common.local.PaymentContextLocal; 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.WeChatPayRecordService; -import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WechatRefundService; +import cn.bootx.platform.daxpay.service.core.channel.wechat.service.WechatPayRefundService; import cn.bootx.platform.daxpay.service.core.order.pay.service.PayChannelOrderService; import cn.bootx.platform.daxpay.service.func.AbsRefundStrategy; import lombok.RequiredArgsConstructor; @@ -29,7 +29,7 @@ public class WeChatRefundStrategy extends AbsRefundStrategy { private final WeChatPayConfigService weChatPayConfigService; - private final WechatRefundService wechatRefundService; + private final WechatPayRefundService wechatPayRefundService; private final WeChatPayRecordService weChatPayRecordService; @@ -61,7 +61,7 @@ public class WeChatRefundStrategy extends AbsRefundStrategy { */ @Override public void doRefundHandler() { - wechatRefundService.refund(this.getRefundOrder(), this.getRefundChannelParam().getAmount(), this.getPayChannelOrder(), this.weChatPayConfig); + wechatPayRefundService.refund(this.getRefundOrder(), this.getRefundChannelParam().getAmount(), this.getPayChannelOrder(), this.weChatPayConfig); } /** diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/sync/factory/PaySyncStrategyFactory.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/sync/factory/PaySyncStrategyFactory.java index e5620b12..6c9417b8 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/sync/factory/PaySyncStrategyFactory.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/sync/factory/PaySyncStrategyFactory.java @@ -2,10 +2,11 @@ package cn.bootx.platform.daxpay.service.core.payment.sync.factory; import cn.bootx.platform.daxpay.code.PayChannelEnum; -import cn.bootx.platform.daxpay.service.func.AbsPaySyncStrategy; -import cn.bootx.platform.daxpay.service.core.payment.sync.strategy.pay.AliPaySyncStrategy; -import cn.bootx.platform.daxpay.service.core.payment.sync.strategy.pay.WeChatPaySyncStrategy; import cn.bootx.platform.daxpay.exception.pay.PayUnsupportedMethodException; +import cn.bootx.platform.daxpay.service.core.payment.sync.strategy.pay.AliPaySyncStrategy; +import cn.bootx.platform.daxpay.service.core.payment.sync.strategy.pay.UnionPaySyncStrategy; +import cn.bootx.platform.daxpay.service.core.payment.sync.strategy.pay.WeChatPaySyncStrategy; +import cn.bootx.platform.daxpay.service.func.AbsPaySyncStrategy; import cn.hutool.extra.spring.SpringUtil; /** @@ -29,6 +30,9 @@ public class PaySyncStrategyFactory { case WECHAT: strategy = SpringUtil.getBean(WeChatPaySyncStrategy.class); break; + case UNION_PAY: + strategy = SpringUtil.getBean(UnionPaySyncStrategy.class); + break; default: throw new PayUnsupportedMethodException(); } diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/sync/strategy/pay/UnionPaySyncStrategy.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/sync/strategy/pay/UnionPaySyncStrategy.java new file mode 100644 index 00000000..f7a06dbd --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/sync/strategy/pay/UnionPaySyncStrategy.java @@ -0,0 +1,48 @@ +package cn.bootx.platform.daxpay.service.core.payment.sync.strategy.pay; + +import cn.bootx.platform.daxpay.code.PayChannelEnum; +import cn.bootx.platform.daxpay.code.PaySyncStatusEnum; +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.UnionPaySyncService; +import cn.bootx.platform.daxpay.service.core.payment.sync.result.PayGatewaySyncResult; +import cn.bootx.platform.daxpay.service.func.AbsPaySyncStrategy; +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE; + +/** + * 云闪付支付同步接口 + * @author xxm + * @since 2024/3/7 + */ +@Scope(SCOPE_PROTOTYPE) +@Component +@RequiredArgsConstructor +public class UnionPaySyncStrategy extends AbsPaySyncStrategy { + + private final UnionPaySyncService unionPaySyncService; + + private final UnionPayConfigService unionPayConfigService; + + /** + * 异步支付单与支付网关进行状态比对后的结果 + * + * @see PaySyncStatusEnum + */ + @Override + public PayGatewaySyncResult doSyncStatus() { + UnionPayConfig config = unionPayConfigService.getConfig(); + return unionPaySyncService.syncPayStatus(this.getOrder(),config); + } + + /** + * 策略标识 + */ + @Override + public PayChannelEnum getChannel() { + return PayChannelEnum.UNION_PAY; + } +} diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/dto/channel/alipay/AliPaymentDto.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/dto/channel/alipay/AliPaymentDto.java deleted file mode 100644 index 4df5f480..00000000 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/dto/channel/alipay/AliPaymentDto.java +++ /dev/null @@ -1,26 +0,0 @@ -package cn.bootx.platform.daxpay.service.dto.channel.alipay; - -import cn.bootx.platform.daxpay.service.dto.order.pay.PayOrderDto; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.experimental.Accessors; - -import java.io.Serializable; - -/** - * @author xxm - * @since 2021/2/27 - */ -@EqualsAndHashCode(callSuper = true) -@Data -@Accessors(chain = true) -@Schema(title = "支付宝支付记录") -public class AliPaymentDto extends PayOrderDto implements Serializable { - - private static final long serialVersionUID = 6883103229754466130L; - - @Schema(description = "支付宝交易号") - private String tradeNo; - -} diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/dto/channel/union/UnionPayRecordDto.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/dto/channel/union/UnionPayRecordDto.java new file mode 100644 index 00000000..c255c045 --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/dto/channel/union/UnionPayRecordDto.java @@ -0,0 +1,49 @@ +package cn.bootx.platform.daxpay.service.dto.channel.union; + +import cn.bootx.platform.common.core.rest.dto.BaseDto; +import cn.bootx.platform.daxpay.service.code.UnionPayRecordTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +/** + * 云闪付流水记录 + * @author xxm + * @since 2024/3/7 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@Accessors(chain = true) +@Schema(title = "云闪付流水记录") +public class UnionPayRecordDto extends BaseDto { + + /** 标题 */ + @Schema(description = "标题") + private String title; + + /** 金额 */ + @Schema(description = "金额") + private Integer amount; + + /** + * 业务类型 + * @see UnionPayRecordTypeEnum + */ + @Schema(description = "业务类型") + private String type; + + /** 本地订单号 */ + @Schema(description = "本地订单号") + private Long orderId; + + /** 网关订单号 */ + @Schema(description = "网关订单号") + private String gatewayOrderNo; + + /** 网关完成时间 */ + @Schema(description = "网关完成时间") + private LocalDateTime gatewayTime; +} diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/param/channel/union/UnionPayRecordQuery.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/param/channel/union/UnionPayRecordQuery.java new file mode 100644 index 00000000..75f4813a --- /dev/null +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/param/channel/union/UnionPayRecordQuery.java @@ -0,0 +1,33 @@ +package cn.bootx.platform.daxpay.service.param.channel.union; + +import cn.bootx.platform.common.core.annotation.QueryParam; +import cn.bootx.platform.common.core.rest.param.QueryOrder; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; + +/** + * 云闪付流水查询参数 + * @author xxm + * @since 2024/3/7 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@Accessors(chain = true) +@Schema(title = "云闪付流水查询参数") +public class UnionPayRecordQuery extends QueryOrder { + + @QueryParam(type = QueryParam.CompareTypeEnum.LIKE) + @Schema(description = "标题") + private String title; + + @Schema(description = "类型") + private String type; + + @Schema(description = "本地订单ID") + private Long orderId; + + @Schema(description = "网关订单号") + private String gatewayOrderNo; +}