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 f405cb740..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 @@ -3,9 +3,13 @@ package com.czg.controller; import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.IoUtil; import com.alibaba.fastjson2.JSONObject; -import com.czg.PolyPayUtils; +import com.czg.CzgPayUtils; +import com.czg.PayCst; import com.czg.constants.PayTypeConstants; -import com.czg.entity.PolyBaseResp; +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,10 +61,52 @@ 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 PolyBaseResp respParams) { - JSONObject czg = PolyPayUtils.getCzg(respParams); + public String notifyCallBack(@RequestBody CzgBaseRespParams respParams) { + JSONObject czg = CzgPayUtils.getCzg(respParams); AssertUtil.isNull(czg, "支付回调数据为空"); log.info("支付回调数据为:{}", czg); orderInfoCustomService.payCallBackOrder(czg.getString("mchOrderNo"), czg, 0); @@ -89,10 +133,10 @@ public class NotifyController { @RequestMapping("/native/wx/pay/distributionRecharge") public String nativeNotify(HttpServletRequest request) throws IOException { -// String timestamp = request.getHeader("Wechatpay-Timestamp"); -// String nonce = request.getHeader("Wechatpay-Nonce"); -// String serialNo = request.getHeader("Wechatpay-Serial"); -// String signature = request.getHeader("Wechatpay-Signature"); + String timestamp = request.getHeader("Wechatpay-Timestamp"); + String nonce = request.getHeader("Wechatpay-Nonce"); + String serialNo = request.getHeader("Wechatpay-Serial"); + String signature = request.getHeader("Wechatpay-Signature"); String result = IoUtil.readUtf8(request.getInputStream()); JSONObject jsonObject = JSONObject.parseObject(result); JSONObject resource = jsonObject.getJSONObject("resource"); @@ -127,8 +171,8 @@ public class NotifyController { @RequestMapping("/refundCallBack") - public String refundCallBack(@RequestBody PolyBaseResp respParams) { - JSONObject czg = PolyPayUtils.getCzg(respParams); + public String refundCallBack(@RequestBody CzgBaseRespParams respParams) { + JSONObject czg = CzgPayUtils.getCzg(respParams); AssertUtil.isNull(czg, "退款回调数据为空"); log.info("退款回调数据为:{}", czg); orderInfoCustomService.refundCallBackOrder(czg.getString("mchOrderNo"), czg); 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 06ea794e3..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,22 +1,78 @@ 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; +import java.util.Map; + /** * @author yjjie * @date 2026/1/9 11:24 */ public class PayManager { - public static void jsapiPay(PayParamsDto paramsDto) { + /** + * jsapi支付 + * + * @param paramsDto 参数 + * @return 结果 + */ + public static Map jsapiPay(PayParamsDto paramsDto) { paramsDto.verifyParams(); if (PayCst.Platform.WECHAT.equals(paramsDto.getPlatform())) { - WechatPayManager.jsapiPay(null, paramsDto); + return WechatPayManager.jsapiPay(null, paramsDto); } else if (PayCst.Platform.ALIPAY.equals(paramsDto.getPlatform())) { - AlipayIsvPayManager.jsapiPay(null, paramsDto); + return AlipayIsvPayManager.jsapiPay(null, paramsDto); + } else { + throw new CzgException("不支持的支付平台"); + } + } + + /** + * 条码支付 + * + * @param paramsDto 参数 + * @return 结果 + */ + public static Map barPay(PayParamsDto paramsDto) { + paramsDto.verifyParams(); + + if (PayCst.Platform.WECHAT.equals(paramsDto.getPlatform())) { + return WechatPayManager.barPay(null, paramsDto); + } else if (PayCst.Platform.ALIPAY.equals(paramsDto.getPlatform())) { + return AlipayIsvPayManager.barPay(null, paramsDto); + } else { + throw new CzgException("不支持的支付平台"); + } + } + + /** + * 查询订单状态 + */ + 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("不支持的支付平台"); } } @@ -35,10 +91,10 @@ public class PayManager { jsapiPay(new PayParamsDto() .setPlatform(PayCst.Platform.WECHAT) .setAppId("wxd88fffa983758a30") - .setOpenId("123123123") + .setOpenId("or1l86yipGvwyfPhrKIAcQuSfAV8") .setOrderNo("1111231231213") .setTitle("1213") - .setMerchantId("1665469114") + .setMerchantId("1738216504") .setBody("1213") .setAmount(1000L) .setPayParams("{\"app_auth_token\": \"ssss\"}") 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/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 56214e479..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 @@ -9,6 +9,7 @@ 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 lombok.extern.slf4j.Slf4j; @@ -26,6 +27,7 @@ public class AlipayIsvPayManager { /** * H5支付 + * * @param configDto 配置 * @param paramsDto 参数 */ @@ -41,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(); @@ -63,6 +65,7 @@ public class AlipayIsvPayManager { /** * 条码支付 + * * @param configDto 配置 * @param paramsDto 参数 */ @@ -82,6 +85,14 @@ public class AlipayIsvPayManager { } } + public static Map queryOrder(AlipayConfigDto configDto, String orderNo, String subMerchantId) { + 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/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 7061bb65f..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 @@ -4,7 +4,9 @@ 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; @@ -55,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(); @@ -99,6 +101,7 @@ public class WechatPayManager { /** * 条码支付 * 用户付款码规则:18位纯数字,前缀以10、11、12、13、14、15开头 + * * @param configDto 配置 * @param paramsDto 参数 */ @@ -195,8 +198,129 @@ 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("微信查询订单异常"); + } + } + + /** + * 退款 + * + * @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() + "/" + PayCst.Platform.WECHAT); + + 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 */ @@ -231,14 +355,26 @@ public class WechatPayManager { } public static void main(String[] args) { - barPay(null, new PayParamsDto() +// 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); + + refundOrder(null, new RefundParamsDto() .setMerchantId("1738216504") .setOrderNo("sa101293120sss1") - .setTitle("1213") - .setBody("1213") - .setAmount(1L) - .setAppId("wxd88fffa983758a30") - .setClientIp("127.0.0.1") - .setBarCode("130013153082460022")); + .setRefundOrderNo("sa101293120sss1") + .setOrderAmount(1L) + .setRefundAmount(1L) + .setRefundReason("测试") + .setRefundNotifyUrl("https://www.baidu.com")); } } 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..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; /** @@ -71,7 +69,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; } @@ -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("解密失败"); + } + } + /** * 获取随机串 */ 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())) { 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