From e798781ca0e14ab400c5fc17e2e0cc98e490fbf2 Mon Sep 17 00:00:00 2001 From: gong <1157756119@qq.com> Date: Wed, 14 Jan 2026 11:28:00 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E8=AE=A2=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../czg/third/alipay/AlipayIsvPayManager.java | 5 ++ .../czg/third/wechat/WechatPayManager.java | 68 ++++++++++++++++--- .../com/czg/third/wechat/WechatReqUtils.java | 2 +- 3 files changed, 65 insertions(+), 10 deletions(-) diff --git a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/alipay/AlipayIsvPayManager.java b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/alipay/AlipayIsvPayManager.java index 56214e479..1925829fd 100644 --- a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/alipay/AlipayIsvPayManager.java +++ b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/alipay/AlipayIsvPayManager.java @@ -11,6 +11,7 @@ import com.czg.PayCst; import com.czg.dto.req.PayParamsDto; import com.czg.exception.CzgException; import com.czg.third.alipay.dto.config.AlipayConfigDto; +import com.czg.third.wechat.dto.config.WechatPayConfigDto; import lombok.extern.slf4j.Slf4j; import java.math.BigDecimal; @@ -82,6 +83,10 @@ public class AlipayIsvPayManager { } } + public static Map queryOrder(AlipayConfigDto configDto, String orderNo, String subMerchantId) { + return new HashMap<>(); + } + /** * 金额转换 */ diff --git a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatPayManager.java b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatPayManager.java index 7061bb65f..f407ca2ad 100644 --- a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatPayManager.java +++ b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatPayManager.java @@ -195,6 +195,53 @@ public class WechatPayManager { } } + /** + * 查询订单 + * @param configDto 配置 + * @param orderNo 订单号 + * @param subMerchantId 子商户号 + * SUCCESS:支付成功 + * REFUND:转入退款 + * NOTPAY:未支付 + * CLOSED:已关闭 + * REVOKED:已撤销(仅付款码支付会返回) + * USERPAYING:用户支付中(仅付款码支付会返回) + * PAYERROR:支付失败(仅付款码支付会返回) + */ + public static Map queryOrder(WechatPayConfigDto configDto, String orderNo, String subMerchantId) { + try { + if (configDto == null) { + configDto = WechatPayConfigDto.getDefaultConfig(); + } + + String resp = WechatReqUtils.getReq(configDto, "/v3/pay/partner/transactions/out-trade-no/" + orderNo, + Map.of("sp_mchid", configDto.getMerchantId(), "sub_mchid", subMerchantId)); + log.info("微信查询订单,订单号:{}, 响应:{}", orderNo, resp); + + JSONObject res = new JSONObject(); + res.put("orderNo", orderNo); + + JSONObject object = JSONObject.parseObject(resp); + String tradeState = object.getString("trade_state"); + res.put("message", object.getString("trade_state_desc")); + if (PAY_SUCCESS.equals(tradeState)) { + res.put("status", "TRADE_SUCCESS"); + return res; + } + + if ("USERPAYING".equals(tradeState)) { + res.put("status", "TRADE_AWAIT"); + return res; + } + + res.put("status", "TRADE_FAIL"); + return res; + } catch (Exception e) { + log.error("微信查询订单异常: orderNo = {}, e = {}", orderNo, e.getMessage()); + throw new CzgException("微信查询订单异常"); + } + } + /** * 将String转换为InputStream * @param str 待转换的字符串 @@ -231,14 +278,17 @@ public class WechatPayManager { } public static void main(String[] args) { - barPay(null, new PayParamsDto() - .setMerchantId("1738216504") - .setOrderNo("sa101293120sss1") - .setTitle("1213") - .setBody("1213") - .setAmount(1L) - .setAppId("wxd88fffa983758a30") - .setClientIp("127.0.0.1") - .setBarCode("130013153082460022")); +// barPay(null, new PayParamsDto() +// .setMerchantId("1738216504") +// .setOrderNo("sa101293120sss1") +// .setTitle("1213") +// .setBody("1213") +// .setAmount(1L) +// .setAppId("wxd88fffa983758a30") +// .setClientIp("127.0.0.1") +// .setBarCode("130013153082460022")); + + Map sss1 = queryOrder(null, "sa101293120sss1", "1738216504"); + System.out.println(sss1); } } diff --git a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatReqUtils.java b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatReqUtils.java index ad2885200..adc8a79f3 100644 --- a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatReqUtils.java +++ b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatReqUtils.java @@ -71,7 +71,7 @@ public class WechatReqUtils { log.info("微信支付请求:url = {} \nauthorization: {}", request.getUrl(), authorization); HttpResponse response = request.execute(); String s = response.body(); - log.info("微信支付请求:url = {}\n\tmethod: {}\n\tbody: {}\n\tresp: {}", url, method, body, s); + log.info("微信支付请求:\n\turl = {}\n\tmethod: {}\n\tbody: {}\n\tresp: {}", url, method, body, s); return s; } From f12e7f9802e0cc2d5b407a4bbb65520feece3429 Mon Sep 17 00:00:00 2001 From: gong <1157756119@qq.com> Date: Wed, 14 Jan 2026 11:32:35 +0800 Subject: [PATCH 2/5] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=BF=9B=E4=BB=B6?= =?UTF-8?q?=E8=B5=84=E6=96=99=E6=97=B6=20=E5=88=A4=E6=96=AD=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E8=BF=9B=E4=BB=B6=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/ShopDirectMerchantServiceImpl.java | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/cash-service/order-service/src/main/java/com/czg/service/order/service/impl/ShopDirectMerchantServiceImpl.java b/cash-service/order-service/src/main/java/com/czg/service/order/service/impl/ShopDirectMerchantServiceImpl.java index b8c2e5fb5..1fe1b754d 100644 --- a/cash-service/order-service/src/main/java/com/czg/service/order/service/impl/ShopDirectMerchantServiceImpl.java +++ b/cash-service/order-service/src/main/java/com/czg/service/order/service/impl/ShopDirectMerchantServiceImpl.java @@ -100,15 +100,19 @@ public class ShopDirectMerchantServiceImpl extends ServiceImpl Date: Wed, 14 Jan 2026 13:54:37 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E9=80=80=E6=AC=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/com/czg/PayManager.java | 27 +++++ .../java/com/czg/dto/req/RefundParamsDto.java | 69 +++++++++++ .../czg/third/alipay/AlipayIsvPayManager.java | 10 +- .../czg/third/wechat/WechatPayManager.java | 109 ++++++++++++++++-- 4 files changed, 202 insertions(+), 13 deletions(-) create mode 100644 cash-sdk/aggregation-pay/src/main/java/com/czg/dto/req/RefundParamsDto.java diff --git a/cash-sdk/aggregation-pay/src/main/java/com/czg/PayManager.java b/cash-sdk/aggregation-pay/src/main/java/com/czg/PayManager.java index 90f5730b3..f9410d87d 100644 --- a/cash-sdk/aggregation-pay/src/main/java/com/czg/PayManager.java +++ b/cash-sdk/aggregation-pay/src/main/java/com/czg/PayManager.java @@ -1,6 +1,7 @@ package com.czg; import com.czg.dto.req.PayParamsDto; +import com.czg.dto.req.RefundParamsDto; import com.czg.exception.CzgException; import com.czg.third.alipay.AlipayIsvPayManager; import com.czg.third.wechat.WechatPayManager; @@ -49,6 +50,32 @@ public class PayManager { } } + /** + * 查询订单状态 + */ + public static Map queryOrderStatus(String platform, String orderNo, String subMerchantId) { + if (PayCst.Platform.WECHAT.equals(platform)) { + return WechatPayManager.queryOrder(null, orderNo, subMerchantId); + } else if (PayCst.Platform.ALIPAY.equals(platform)) { + return AlipayIsvPayManager.queryOrder(null, orderNo, subMerchantId); + } else { + throw new CzgException("不支持的支付平台"); + } + } + + /** + * 退款 + */ + public static Map refund(String platform, RefundParamsDto paramsDto) { + if (PayCst.Platform.WECHAT.equals(platform)) { + return WechatPayManager.refundOrder(null, paramsDto); + } else if (PayCst.Platform.ALIPAY.equals(platform)) { + return AlipayIsvPayManager.refundOrder(null, paramsDto); + } else { + throw new CzgException("不支持的支付平台"); + } + } + public static void main(String[] args) { // jsapiPay(new PayParamsDto() // .setPlatform(PayCst.Platform.ALIPAY) diff --git a/cash-sdk/aggregation-pay/src/main/java/com/czg/dto/req/RefundParamsDto.java b/cash-sdk/aggregation-pay/src/main/java/com/czg/dto/req/RefundParamsDto.java new file mode 100644 index 000000000..b4fad4657 --- /dev/null +++ b/cash-sdk/aggregation-pay/src/main/java/com/czg/dto/req/RefundParamsDto.java @@ -0,0 +1,69 @@ +package com.czg.dto.req; + +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 退款参数 + * @author yjjie + * @date 2026/1/14 11:37 + */ +@Data +@Accessors(chain = true) +public class RefundParamsDto { + + /** + * 【必填】 + * 平台 + * {@link com.czg.PayCst.Platform} + */ + private String platform; + + /** + * 【必填】 + * 订单号 + */ + private String orderNo; + + /** + * 【必填】 + * 退款单号 + */ + private String refundOrderNo; + + /** + * 【必填】 + * 退款金额 + */ + private Long refundAmount; + + /** + * 【必填】 + * 订单原金额 + */ + private Long orderAmount; + + /** + * 【必填】 + * 退款原因 + */ + private String refundReason; + + /** + * 【必填】 + * 退款回调地址 + */ + private String refundNotifyUrl; + + /** + * 【选填】 + * 微信商户号 + */ + private String merchantId; + + /** + * 【选填】 + * 支付宝授权信息 + */ + private String alipayAuthInfo; +} diff --git a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/alipay/AlipayIsvPayManager.java b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/alipay/AlipayIsvPayManager.java index 1925829fd..493d9ae8e 100644 --- a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/alipay/AlipayIsvPayManager.java +++ b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/alipay/AlipayIsvPayManager.java @@ -9,9 +9,9 @@ import com.alipay.v3.model.ExtendParams; import com.alipay.v3.util.model.CustomizedParams; import com.czg.PayCst; import com.czg.dto.req.PayParamsDto; +import com.czg.dto.req.RefundParamsDto; import com.czg.exception.CzgException; import com.czg.third.alipay.dto.config.AlipayConfigDto; -import com.czg.third.wechat.dto.config.WechatPayConfigDto; import lombok.extern.slf4j.Slf4j; import java.math.BigDecimal; @@ -27,6 +27,7 @@ public class AlipayIsvPayManager { /** * H5支付 + * * @param configDto 配置 * @param paramsDto 参数 */ @@ -64,6 +65,7 @@ public class AlipayIsvPayManager { /** * 条码支付 + * * @param configDto 配置 * @param paramsDto 参数 */ @@ -84,7 +86,11 @@ public class AlipayIsvPayManager { } public static Map queryOrder(AlipayConfigDto configDto, String orderNo, String subMerchantId) { - return new HashMap<>(); + return new HashMap<>(); + } + + public static Map refundOrder(AlipayConfigDto configDto, RefundParamsDto paramsDto) { + return new HashMap<>(); } /** diff --git a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatPayManager.java b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatPayManager.java index f407ca2ad..2fac42701 100644 --- a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatPayManager.java +++ b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatPayManager.java @@ -4,13 +4,16 @@ import cn.hutool.core.util.StrUtil; import cn.hutool.crypto.SecureUtil; import cn.hutool.http.HttpUtil; import com.alibaba.fastjson2.JSONObject; +import com.czg.PayCst; import com.czg.dto.req.PayParamsDto; +import com.czg.dto.req.RefundParamsDto; import com.czg.exception.CzgException; import com.czg.third.wechat.dto.config.WechatPayConfigDto; import com.wechat.pay.java.core.Config; import com.wechat.pay.java.core.cipher.Signer; import com.wechat.pay.java.core.util.NonceUtil; import lombok.extern.slf4j.Slf4j; +import org.aspectj.apache.bcel.generic.RET; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; @@ -99,6 +102,7 @@ public class WechatPayManager { /** * 条码支付 * 用户付款码规则:18位纯数字,前缀以10、11、12、13、14、15开头 + * * @param configDto 配置 * @param paramsDto 参数 */ @@ -197,16 +201,17 @@ public class WechatPayManager { /** * 查询订单 - * @param configDto 配置 - * @param orderNo 订单号 + * + * @param configDto 配置 + * @param orderNo 订单号 * @param subMerchantId 子商户号 - * SUCCESS:支付成功 - * REFUND:转入退款 - * NOTPAY:未支付 - * CLOSED:已关闭 - * REVOKED:已撤销(仅付款码支付会返回) - * USERPAYING:用户支付中(仅付款码支付会返回) - * PAYERROR:支付失败(仅付款码支付会返回) + * SUCCESS:支付成功 + * REFUND:转入退款 + * NOTPAY:未支付 + * CLOSED:已关闭 + * REVOKED:已撤销(仅付款码支付会返回) + * USERPAYING:用户支付中(仅付款码支付会返回) + * PAYERROR:支付失败(仅付款码支付会返回) */ public static Map queryOrder(WechatPayConfigDto configDto, String orderNo, String subMerchantId) { try { @@ -242,8 +247,81 @@ public class WechatPayManager { } } + /** + * 退款 + * + * @param configDto 配置 + * @param paramsDto 参数 + * SUCCESS: 退款成功 + * CLOSED: 退款关闭 + * PROCESSING: 退款处理中 + * ABNORMAL: 退款异常,退款到银行发现用户的卡作废或者冻结了,导致原路退款银行卡失败,可前往服务商平台-交易中心,手动处理此笔退款 + */ + public static Map refundOrder(WechatPayConfigDto configDto, RefundParamsDto paramsDto) { + try { + if (configDto == null) { + configDto = WechatPayConfigDto.getDefaultConfig(); + } + + JSONObject refundParam = new JSONObject(); + refundParam.put("sub_mchid", paramsDto.getMerchantId()); + refundParam.put("out_trade_no", paramsDto.getOrderNo()); + refundParam.put("out_refund_no", paramsDto.getRefundOrderNo()); + refundParam.put("reason", paramsDto.getRefundReason()); + refundParam.put("notify_url", paramsDto.getRefundNotifyUrl()); + + JSONObject amount = new JSONObject(); + amount.put("total", paramsDto.getOrderAmount()); + amount.put("refund", paramsDto.getRefundAmount()); + amount.put("currency", "CNY"); + refundParam.put("amount", amount); + + String resp = WechatReqUtils.postReq(configDto, "/v3/refund/domestic/refunds", refundParam.toJSONString()); + log.info("微信退款,订单号:{}, 响应:{}", paramsDto.getOrderNo(), resp); + + JSONObject object = JSONObject.parseObject(resp); + + JSONObject res = new JSONObject(); + res.put("mchRefundNo", object.getString("out_refund_no")); + res.put("refundOrderId", object.getString("refund_id")); + res.put("oriPayOrderId", object.getString("out_trade_no")); + res.put("mercNo", paramsDto.getMerchantId()); + res.put("refundReason", paramsDto.getRefundReason()); + res.put("payType", PayCst.Platform.WECHAT); + res.put("refundTime", object.getString("success_time")); + switch (object.getString("status")) { + case "SUCCESS": + res.put("status", "SUCCESS"); + break; + case "CLOSED": + res.put("status", "CLOSED"); + break; + case "PROCESSING": + res.put("status", "ING"); + break; + case "ABNORMAL": + res.put("status", "INIT"); + break; + default: + res.put("status", "FAIL"); + break; + } + JSONObject resAmount = object.getJSONObject("amount"); + if (resAmount != null) { + res.put("refundAmt", resAmount.getLong("refund")); + res.put("oriAmount", resAmount.getLong("total")); + } + + return res; + } catch (Exception e) { + log.error("微信退款异常: orderNo = {}, e = {}", paramsDto.getOrderNo(), e.getMessage()); + throw new CzgException("微信退款异常"); + } + } + /** * 将String转换为InputStream + * * @param str 待转换的字符串 * @return 转换后的InputStream */ @@ -288,7 +366,16 @@ public class WechatPayManager { // .setClientIp("127.0.0.1") // .setBarCode("130013153082460022")); - Map sss1 = queryOrder(null, "sa101293120sss1", "1738216504"); - System.out.println(sss1); +// Map sss1 = queryOrder(null, "sa101293120sss1", "1738216504"); +// System.out.println(sss1); + + refundOrder(null, new RefundParamsDto() + .setMerchantId("1738216504") + .setOrderNo("sa101293120sss1") + .setRefundOrderNo("sa101293120sss1") + .setOrderAmount(1L) + .setRefundAmount(1L) + .setRefundReason("测试") + .setRefundNotifyUrl("https://www.baidu.com")); } } From 946fe4de4c234fd3080d7d4d6b972ecf9e7c2227 Mon Sep 17 00:00:00 2001 From: gong <1157756119@qq.com> Date: Wed, 14 Jan 2026 14:41:30 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E5=9B=9E=E8=B0=83=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/czg/controller/NotifyController.java | 52 +++++++- .../com/czg/dto/req/WechatNotifyReqDto.java | 33 +++++ .../czg/dto/req/WechatPayNotifyDataDto.java | 118 ++++++++++++++++++ .../czg/third/alipay/AlipayIsvPayManager.java | 2 +- .../com/czg/third/wechat/WechatAesUtil.java | 60 +++++++++ .../czg/third/wechat/WechatPayManager.java | 5 +- .../com/czg/third/wechat/WechatReqUtils.java | 26 +++- 7 files changed, 285 insertions(+), 11 deletions(-) create mode 100644 cash-sdk/aggregation-pay/src/main/java/com/czg/dto/req/WechatNotifyReqDto.java create mode 100644 cash-sdk/aggregation-pay/src/main/java/com/czg/dto/req/WechatPayNotifyDataDto.java create mode 100644 cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatAesUtil.java diff --git a/cash-api/order-server/src/main/java/com/czg/controller/NotifyController.java b/cash-api/order-server/src/main/java/com/czg/controller/NotifyController.java index af97cc9c7..479293715 100644 --- a/cash-api/order-server/src/main/java/com/czg/controller/NotifyController.java +++ b/cash-api/order-server/src/main/java/com/czg/controller/NotifyController.java @@ -4,8 +4,12 @@ import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.IoUtil; import com.alibaba.fastjson2.JSONObject; import com.czg.CzgPayUtils; +import com.czg.PayCst; import com.czg.constants.PayTypeConstants; +import com.czg.dto.req.WechatNotifyReqDto; +import com.czg.dto.req.WechatPayNotifyDataDto; import com.czg.entity.CzgBaseRespParams; +import com.czg.exception.CzgException; import com.czg.market.entity.MkShopConsumeDiscountRecord; import com.czg.market.service.MkDistributionUserService; import com.czg.market.service.MkShopConsumeDiscountRecordService; @@ -15,15 +19,13 @@ import com.czg.order.entity.OrderPayment; import com.czg.order.service.OrderInfoCustomService; import com.czg.order.service.OrderPaymentService; import com.czg.service.market.service.impl.AppWxServiceImpl; +import com.czg.third.wechat.WechatReqUtils; import com.czg.utils.AssertUtil; import com.mybatisflex.core.query.QueryWrapper; import jakarta.annotation.Resource; import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import java.io.IOException; @@ -59,6 +61,48 @@ public class NotifyController { return "success"; } + /** + * 原生支付回调 + */ + @RequestMapping("/native/pay/{platform}") + public String pay(@PathVariable String platform, @RequestBody JSONObject json) { + if (PayCst.Platform.WECHAT.equalsIgnoreCase(platform)) { + // 微信 + WechatNotifyReqDto reqDto = JSONObject.parseObject(json.toJSONString(), WechatNotifyReqDto.class); + log.info("【微信支付回调】收到微信支付回调 data: {}", JSONObject.toJSONString(reqDto)); + + String decrypted = WechatReqUtils.decryptRespParam(null, reqDto); + log.info("【微信支付回调】解密数据 {}", decrypted); + + WechatPayNotifyDataDto dataDto = JSONObject.parseObject(decrypted, WechatPayNotifyDataDto.class); + return "success"; + } else if (PayCst.Platform.ALIPAY.equalsIgnoreCase(platform)) { + // 支付宝 + return "success"; + } + throw new CzgException("不支持的支付平台"); + } + + /** + * 原生退款回调 + */ + @RequestMapping("/native/refund/{platform}") + public String refund(@PathVariable String platform, @RequestBody JSONObject json) { + if (PayCst.Platform.WECHAT.equalsIgnoreCase(platform)) { + // 微信 + WechatNotifyReqDto reqDto = JSONObject.parseObject(json.toJSONString(), WechatNotifyReqDto.class); + log.info("【微信退款回调】收到微信退款回调 data: {}", JSONObject.toJSONString(reqDto)); + String decrypted = WechatReqUtils.decryptRespParam(null, reqDto); + log.info("【微信退款回调】解密数据 {}", decrypted); + + return "success"; + } else if (PayCst.Platform.ALIPAY.equalsIgnoreCase(platform)) { + // 支付宝 + return "success"; + } + throw new CzgException("不支持的支付平台"); + } + @RequestMapping("/payCallBack") public String notifyCallBack(@RequestBody CzgBaseRespParams respParams) { diff --git a/cash-sdk/aggregation-pay/src/main/java/com/czg/dto/req/WechatNotifyReqDto.java b/cash-sdk/aggregation-pay/src/main/java/com/czg/dto/req/WechatNotifyReqDto.java new file mode 100644 index 000000000..71efa434e --- /dev/null +++ b/cash-sdk/aggregation-pay/src/main/java/com/czg/dto/req/WechatNotifyReqDto.java @@ -0,0 +1,33 @@ +package com.czg.dto.req; + +import com.alibaba.fastjson2.annotation.JSONField; +import lombok.Data; + +/** + * @author yjjie + * @date 2025/12/23 21:47 + */ +@Data +public class WechatNotifyReqDto { + + private String id; + @JSONField(name = "create_time") + private String createTime; + @JSONField(name = "resource_type") + private String resourceType; + @JSONField(name = "event_type") + private String eventType; + private String summary; + private Resource resource; + + @Data + public static class Resource { + @JSONField(name = "resource_type") + private String originalType; + private String algorithm; + private String ciphertext; + @JSONField(name = "associated_data") + private String associatedData; + private String nonce; + } +} diff --git a/cash-sdk/aggregation-pay/src/main/java/com/czg/dto/req/WechatPayNotifyDataDto.java b/cash-sdk/aggregation-pay/src/main/java/com/czg/dto/req/WechatPayNotifyDataDto.java new file mode 100644 index 000000000..321eb4fb4 --- /dev/null +++ b/cash-sdk/aggregation-pay/src/main/java/com/czg/dto/req/WechatPayNotifyDataDto.java @@ -0,0 +1,118 @@ +package com.czg.dto.req; + +import com.alibaba.fastjson2.annotation.JSONField; +import lombok.Data; + +/** + * @author yjjie + * @date 2025/12/23 22:21 + */ +@Data +public class WechatPayNotifyDataDto { + + /** + * 公众账号ID + */ + private String appid; + + /** + * 商户号 + */ + private String mchid; + + /** + * 商户订单号 + */ + @JSONField(name = "out_trade_no") + private String outTradeNo; + + /** + * 微信支付订单号 + */ + @JSONField(name = "transaction_id") + private String transactionId; + + /** + * 交易类型 + * JSAPI:公众号支付、小程序支付 + * NATIVE:Native支付 + * APP:APP支付 + * MICROPAY:付款码支付 + * MWEB:H5支付 + * FACEPAY:刷脸支付 + */ + @JSONField(name = "trade_type") + private String tradeType; + + /** + * 交易状态 + * SUCCESS—支付成功 + * REFUND—转入退款 + * NOTPAY—未支付 + * CLOSED—已关闭 + * REVOKED—已撤销(刷卡支付) + * USERPAYING--用户支付中 + * PAYERROR--支付失败(其他原因,如银行返回失败) + */ + @JSONField(name = "trade_state") + private String tradeState; + + /** + * 交易状态描述 + */ + @JSONField(name = "trade_state_desc") + private String tradeStateDesc; + + /** + * 付款银行 + */ + @JSONField(name = "bank_type") + private String bankType; + + /** + * 商户数据包 + */ + private String attach; + + /** + * 支付完成时间 + */ + @JSONField(name = "success_time") + private String successTime; + + /** + * 金额 + */ + private Amount amount; + + @Data + public static class Amount { + /** + * 用户支付金额 + */ + @JSONField(name = "payer_total") + private Integer payerTotal; + + /** + * 货币类型 + */ + private String currency; + + /** + * 总金额 + */ + private Integer total; + } + + public boolean isSuccess() { + return "SUCCESS".equals(tradeState); + } + + public boolean isClosed() { + return "CLOSED".equals(tradeState); + } + + public Long getPayAmount() { + return Long.valueOf(amount.getTotal()); + } +} diff --git a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/alipay/AlipayIsvPayManager.java b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/alipay/AlipayIsvPayManager.java index 493d9ae8e..3ed81c0f0 100644 --- a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/alipay/AlipayIsvPayManager.java +++ b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/alipay/AlipayIsvPayManager.java @@ -43,7 +43,7 @@ public class AlipayIsvPayManager { model.setTotalAmount(getYuanAmountByFen(paramsDto.getAmount())); model.setSubject(paramsDto.getTitle()); model.setBody(paramsDto.getBody()); - model.setNotifyUrl(paramsDto.getNotifyUrl()); + model.setNotifyUrl(paramsDto.getNotifyUrl() + "/" + PayCst.Platform.ALIPAY); model.setExtendParams(new ExtendParams()); CustomizedParams customizedParams = new CustomizedParams(); diff --git a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatAesUtil.java b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatAesUtil.java new file mode 100644 index 000000000..4e83075cd --- /dev/null +++ b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatAesUtil.java @@ -0,0 +1,60 @@ +package com.czg.third.wechat; + +import javax.crypto.AEADBadTagException; +import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Base64; + +/** + * 微信参数 AES 解密 + * @author GYJoker + */ +public class WechatAesUtil { + static final int KEY_LENGTH_BYTE = 32; + static final int TAG_LENGTH_BIT = 128; + private final byte[] aesKey; + public WechatAesUtil(byte[] key) { + if (key.length != KEY_LENGTH_BYTE) { + throw new IllegalArgumentException("无效的ApiV3Key,长度必须为32个字节"); + } + this.aesKey = key; + } + public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext) + throws GeneralSecurityException { + try { + + // 调试信息:打印参数信息 + System.out.println("associatedData长度: " + (associatedData != null ? associatedData.length : 0)); + System.out.println("nonce长度: " + (nonce != null ? nonce.length : 0)); + System.out.println("ciphertext长度: " + ciphertext.length()); + + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + SecretKeySpec key = new SecretKeySpec(aesKey, "AES"); + GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce); + cipher.init(Cipher.DECRYPT_MODE, key, spec); + + // 处理 associatedData,确保使用空数组而非 null + cipher.updateAAD(associatedData != null ? associatedData : new byte[0]); + + byte[] decodedCiphertext = Base64.getDecoder().decode(ciphertext); + System.out.println("解码后密文长度: " + decodedCiphertext.length); + + byte[] plaintext = cipher.doFinal(decodedCiphertext); + return new String(plaintext, StandardCharsets.UTF_8); + } catch (AEADBadTagException e) { + // 捕获标签不匹配异常,提供更详细的错误信息 + throw new GeneralSecurityException("解密失败: 标签不匹配,可能是密钥错误、数据被篡改或参数不匹配", e); + } catch (NoSuchAlgorithmException | NoSuchPaddingException e) { + throw new IllegalStateException(e); + } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { + throw new IllegalArgumentException("无效的密钥或参数", e); + } + } +} diff --git a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatPayManager.java b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatPayManager.java index 2fac42701..a99c698f1 100644 --- a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatPayManager.java +++ b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatPayManager.java @@ -13,7 +13,6 @@ import com.wechat.pay.java.core.Config; import com.wechat.pay.java.core.cipher.Signer; import com.wechat.pay.java.core.util.NonceUtil; import lombok.extern.slf4j.Slf4j; -import org.aspectj.apache.bcel.generic.RET; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; @@ -58,7 +57,7 @@ public class WechatPayManager { reqData.put("sub_mchid", paramsDto.getMerchantId()); reqData.put("description", paramsDto.getTitle()); reqData.put("out_trade_no", paramsDto.getOrderNo()); - reqData.put("notify_url", paramsDto.getNotifyUrl()); + reqData.put("notify_url", paramsDto.getNotifyUrl() + "/" + PayCst.Platform.WECHAT); reqData.put("attach", paramsDto.getExtData()); JSONObject amount = new JSONObject(); @@ -268,7 +267,7 @@ public class WechatPayManager { refundParam.put("out_trade_no", paramsDto.getOrderNo()); refundParam.put("out_refund_no", paramsDto.getRefundOrderNo()); refundParam.put("reason", paramsDto.getRefundReason()); - refundParam.put("notify_url", paramsDto.getRefundNotifyUrl()); + refundParam.put("notify_url", paramsDto.getRefundNotifyUrl() + "/" + PayCst.Platform.WECHAT); JSONObject amount = new JSONObject(); amount.put("total", paramsDto.getOrderAmount()); diff --git a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatReqUtils.java b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatReqUtils.java index adc8a79f3..8c1ed17cd 100644 --- a/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatReqUtils.java +++ b/cash-sdk/aggregation-pay/src/main/java/com/czg/third/wechat/WechatReqUtils.java @@ -3,12 +3,11 @@ package com.czg.third.wechat; import cn.hutool.http.HttpRequest; import cn.hutool.http.HttpResponse; import cn.hutool.http.HttpUtil; +import com.czg.dto.req.WechatNotifyReqDto; import com.czg.exception.CzgException; import com.czg.third.wechat.dto.config.WechatPayConfigDto; import com.wechat.pay.java.core.Config; import com.wechat.pay.java.core.cipher.Signer; -import com.wechat.pay.java.core.http.HttpClient; -import com.wechat.pay.java.core.http.HttpMethod; import com.wechat.pay.java.core.util.NonceUtil; import lombok.extern.slf4j.Slf4j; @@ -16,7 +15,6 @@ import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Map; -import java.util.UUID; import java.util.stream.Collectors; /** @@ -102,6 +100,28 @@ public class WechatReqUtils { return signature; } + /** + * 解密微信回调报文 + * + * @param configDto 配置 + * @param reqDto 请求报文 + * @return 解密后的报文 + */ + public static String decryptRespParam(WechatPayConfigDto configDto, WechatNotifyReqDto reqDto) { + if (configDto == null) { + configDto = WechatPayConfigDto.getDefaultConfig(); + } + WechatAesUtil aesUtil = new WechatAesUtil(configDto.getApiV3Key().getBytes(StandardCharsets.UTF_8)); + try { + return aesUtil.decryptToString( + reqDto.getResource().getAssociatedData() == null ? new byte[0] : reqDto.getResource().getAssociatedData().getBytes(StandardCharsets.UTF_8), + reqDto.getResource().getNonce().getBytes(StandardCharsets.UTF_8), reqDto.getResource().getCiphertext()); + } catch (Exception e) { + log.error("【微信支付回调】解密失败 {}", reqDto); + throw new CzgException("解密失败"); + } + } + /** * 获取随机串 */ From a5982abe20190ba310d271f765e8df390bb286ff Mon Sep 17 00:00:00 2001 From: gong <1157756119@qq.com> Date: Wed, 14 Jan 2026 15:06:21 +0800 Subject: [PATCH 5/5] =?UTF-8?q?=E5=8A=A0=E6=80=A5=E8=8F=9C=E5=93=81=20orde?= =?UTF-8?q?rDetail=20=E5=BC=80=E5=A7=8B=E8=AE=A2=E5=8D=95=E6=97=B6?= =?UTF-8?q?=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/order/service/impl/OrderInfoCustomServiceImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/cash-service/order-service/src/main/java/com/czg/service/order/service/impl/OrderInfoCustomServiceImpl.java b/cash-service/order-service/src/main/java/com/czg/service/order/service/impl/OrderInfoCustomServiceImpl.java index 7eaada20f..8a0d0e6ae 100644 --- a/cash-service/order-service/src/main/java/com/czg/service/order/service/impl/OrderInfoCustomServiceImpl.java +++ b/cash-service/order-service/src/main/java/com/czg/service/order/service/impl/OrderInfoCustomServiceImpl.java @@ -299,6 +299,7 @@ public class OrderInfoCustomServiceImpl implements OrderInfoCustomService { orderDetails.forEach(item -> { item.setUrgent(true); item.setSubStatus(TableValueConstant.OrderDetail.SubStatus.READY_TO_SERVE.getCode()); + item.setStartOrderTime(DateUtil.date().toLocalDateTime()); }); } else { switch (EnumUtil.fromString(TableValueConstant.OrderDetail.SubStatus.class, param.getSubStatus())) {