From a74ed5dde0c8375f16a31ab6a029e9e949560f6b Mon Sep 17 00:00:00 2001 From: wangqx Date: Mon, 22 Sep 2025 18:31:55 +0800 Subject: [PATCH] =?UTF-8?q?[fix]=E4=BF=AE=E6=94=B9=E7=BA=A2=E5=8C=85?= =?UTF-8?q?=E5=92=8C=E6=8F=90=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/dromara/app/AppPayController.java | 4 +- .../app/customer/AppRedPacketController.java | 25 ++- .../src/main/resources/application.yml | 2 +- .../controller/WxPayController.java | 2 +- .../soopin/transaction/domain/po/Charge.java | 2 + .../transaction/enums/ChargeStatus.java | 5 +- .../transaction/kit/CashierSupport.java | 10 +- .../wzj/soopin/transaction/kit/Payment.java | 9 ++ .../transaction/kit/core/kit/WxPayKit.java | 8 +- .../kit/params/impl/RechargeCashier.java | 3 +- .../kit/plugin/wechat/WechatPlugin.java | 151 +++++++++++++----- .../service/RedPacketService.java | 2 +- .../service/impl/AccountBillServiceImpl.java | 3 - .../service/impl/ChargeServiceImpl.java | 10 +- .../service/impl/RedPacketServiceImpl.java | 124 ++++---------- .../service/impl/WithdrawServiceImpl.java | 58 ++++++- .../service/impl/WxPayService.java | 51 +++--- .../transaction/wechat/WechatPayConfig.java | 14 ++ script/docker/nginx/conf/nginx.conf | 23 ++- 19 files changed, 321 insertions(+), 185 deletions(-) rename ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/controller/RedPacketController.java => ruoyi-admin/src/main/java/org/dromara/app/customer/AppRedPacketController.java (68%) rename ruoyi-modules/{ruoyi-order/src/main/java/com/wzj/soopin/order => ruoyi-transaction/src/main/java/com/wzj/soopin/transaction}/service/RedPacketService.java (88%) rename ruoyi-modules/{ruoyi-order/src/main/java/com/wzj/soopin/order => ruoyi-transaction/src/main/java/com/wzj/soopin/transaction}/service/impl/RedPacketServiceImpl.java (72%) diff --git a/ruoyi-admin/src/main/java/org/dromara/app/AppPayController.java b/ruoyi-admin/src/main/java/org/dromara/app/AppPayController.java index e80ca21e2..7285d1dc5 100644 --- a/ruoyi-admin/src/main/java/org/dromara/app/AppPayController.java +++ b/ruoyi-admin/src/main/java/org/dromara/app/AppPayController.java @@ -111,8 +111,8 @@ public class AppPayController { } @Operation(summary = "查询支付结果") - @GetMapping(value = "/result") - public R paymentResult(PayParam payParam) { + @PostMapping(value = "/result") + public R paymentResult(@RequestBody PayParam payParam) { return R.ok(cashierSupport.paymentResult(payParam)); } } diff --git a/ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/controller/RedPacketController.java b/ruoyi-admin/src/main/java/org/dromara/app/customer/AppRedPacketController.java similarity index 68% rename from ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/controller/RedPacketController.java rename to ruoyi-admin/src/main/java/org/dromara/app/customer/AppRedPacketController.java index 49f9e2e22..f22add31b 100644 --- a/ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/controller/RedPacketController.java +++ b/ruoyi-admin/src/main/java/org/dromara/app/customer/AppRedPacketController.java @@ -1,14 +1,19 @@ -package com.wzj.soopin.order.controller; +package org.dromara.app.customer; import com.wzj.soopin.order.domain.query.GrabRedPacketRequest; import com.wzj.soopin.order.domain.query.SendRedPacketRequest; -import com.wzj.soopin.order.service.RedPacketService; +import com.wzj.soopin.transaction.service.RedPacketService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.dromara.common.core.domain.R; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.satoken.utils.LoginHelper; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import java.util.Map; @@ -16,9 +21,9 @@ import java.util.Map; * 红包功能控制器 */ @RestController -@RequestMapping("/api/packet") +@RequestMapping("/app/customer/packet") @Tag(name = "红包功能接口") -public class RedPacketController { +public class AppRedPacketController { @Autowired private RedPacketService redPacketService; @@ -31,6 +36,11 @@ public class RedPacketController { @PostMapping("/send") @Operation(summary = "发红包") public R> sendRedPacket(@RequestBody SendRedPacketRequest request) { + LoginUser user = LoginHelper.getLoginUser(); + if (user == null) { + return R.notLogin(); + } + request.setSenderId(user.getUserId()); Map result = redPacketService.sendRedPacket(request); return R.ok("红包发送成功", result); } @@ -42,6 +52,11 @@ public class RedPacketController { @PostMapping("/grab") @Operation(summary = "抢红包") public R> grabRedPacket(@RequestBody GrabRedPacketRequest request) { + LoginUser user = LoginHelper.getLoginUser(); + if (user == null) { + return R.notLogin(); + } + request.setMemberId(user.getUserId()); Map result = redPacketService.grabRedPacket(request); return R.ok("红包领取成功", result); } diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 0ed42cd87..cca4254c8 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -381,7 +381,7 @@ wechat: mch-serial-no: 6BA681D9B219034D6F7851F57D61BE9317AB48FD # 商户证书序列号 api-v3-key: T9iE71aHSmjtM35z4bDLuU3gFX8s2I2h # APIv3密钥 private-key-path: "classpath:cert/apiclient_key.pem" # 商户私钥文件路径 - transfer-notify-url: https://a94aeb5582c2.ngrok-free.app/no-auth/wechat/notify # 转账回调地址 + transfer-notify-url: https://wuzhongjie.com.cn/prod-api/api/transfer/callback # 转账回调地址 app-id: wxebcdaea31881caab # 应用ID secret: your_wechat_secret # 应用密钥 mini-program: diff --git a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/controller/WxPayController.java b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/controller/WxPayController.java index cebfb2ceb..0ae55ab7a 100644 --- a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/controller/WxPayController.java +++ b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/controller/WxPayController.java @@ -79,7 +79,7 @@ public class WxPayController { request.setTransferSceneReportInfos(transferDetailList); //异步接收微信支付结果通知的回调地址,通知url必须为公网可访问的URL,必须为HTTPS,不能携带参数 // 注意:此处需要填写公网可访问的服务器地址,不能携带任何参数 - request.setNotifyUrl("https://2e879e23cc0e.ngrok-free.app/api/transfer/callback"); + request.setNotifyUrl("https://wuzhongjie.com.cn/prod-api/api/transfer/callback"); try{ response = wxPayService.initiateBatchTransferNew(request); }catch (ServiceException e){ diff --git a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/domain/po/Charge.java b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/domain/po/Charge.java index e2865e9fa..aba2cb574 100644 --- a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/domain/po/Charge.java +++ b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/domain/po/Charge.java @@ -76,4 +76,6 @@ public class Charge extends BaseAudit { * 审核状态 */ private Integer auditStatus; + + private String payNo; } diff --git a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/enums/ChargeStatus.java b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/enums/ChargeStatus.java index 0a0a8e4d8..01a817166 100644 --- a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/enums/ChargeStatus.java +++ b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/enums/ChargeStatus.java @@ -5,9 +5,8 @@ import lombok.Getter; @Getter public enum ChargeStatus { WAITING(0, "未支付"), - PENDING(1, "待验证"), - SUCCESS(2, "充值成功"), - FAIL(3, "充值失败"); + SUCCESS(1, "充值成功"), + FAIL(2, "充值失败"); private Integer code; private String message; diff --git a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/kit/CashierSupport.java b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/kit/CashierSupport.java index 48e6600d7..84cc8951b 100644 --- a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/kit/CashierSupport.java +++ b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/kit/CashierSupport.java @@ -191,11 +191,9 @@ public class CashierSupport { * @return */ public Boolean paymentResult(PayParam payParam) { - for (CashierExecute cashierExecute : cashierExecuteList) { - if (cashierExecute.cashierEnum().name().equals(payParam.getOrderType())) { - return cashierExecute.paymentResult(payParam); - } - } + PaymentMethodEnum paymentMethodEnum = PaymentMethodEnum.valueOf(payParam.getPaymentMethod()); + Payment payment = (Payment) SpringUtils.getBean( paymentMethodEnum.getPlugin()); + payment.searchByOutTradeNo(payParam.getSn()); return false; } @@ -204,6 +202,8 @@ public class CashierSupport { paramInterface.paymentSuccess(payParam); log.info("订单编号{}支付成功", payParam.getReceivableNo()); } + + return true; } } diff --git a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/kit/Payment.java b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/kit/Payment.java index 5bb4992df..2abe75904 100644 --- a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/kit/Payment.java +++ b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/kit/Payment.java @@ -153,4 +153,13 @@ public interface Payment { return api + "/buyer/payment/cashierRefund/notify/" + paymentMethodEnum.name(); } + /** + * 订单查询 + * + * @param outTradeNo 订单编号 + * @return 订单详情 + */ + default R searchByOutTradeNo(String outTradeNo) { + throw new ServiceException(ResultCode.PAY_ERROR); + } } diff --git a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/kit/core/kit/WxPayKit.java b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/kit/core/kit/WxPayKit.java index ad99705c7..4185a0e38 100644 --- a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/kit/core/kit/WxPayKit.java +++ b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/kit/core/kit/WxPayKit.java @@ -124,7 +124,7 @@ public class WxPayKit { * @param params 需要签名的参数 * @return 签名后的数据 */ - public static String createAppSign(Map params, String privateKey) { + public static String createAppSign(Map params, String keyPath) { String appid = params.get("appid"); String timestamp = params.get("timestamp"); @@ -134,7 +134,7 @@ public class WxPayKit { String encrypt = appid + "\n" + timestamp + "\n" + noncestr + "\n" + prepayid + "\n"; try { - return PayKit.createSign(encrypt, privateKey); + return PayKit.createSign(encrypt, keyPath); } catch (Exception e) { throw new ServiceException(ResultCode.ERROR); } @@ -377,9 +377,9 @@ public class WxPayKit { if (signType == null) { signType = SignType.MD5; } - String packageSign = createSign(packageParams, partnerKey, signType); +// String packageSign = createSign(packageParams, partnerKey, signType); // 部分微信APP支付 提示签名错误 解开下方注释 替换上边的代码就好。 -// String packageSign = createAppSign(packageParams, partnerKey); + String packageSign = createAppSign(packageParams, partnerKey); packageParams.put("sign", packageSign); return packageParams; } diff --git a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/kit/params/impl/RechargeCashier.java b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/kit/params/impl/RechargeCashier.java index 0c9cafd50..c8613239a 100644 --- a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/kit/params/impl/RechargeCashier.java +++ b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/kit/params/impl/RechargeCashier.java @@ -66,7 +66,7 @@ public class RechargeCashier implements CashierExecute { if (!recharge.getStatus().equals(ChargeStatus.WAITING.getCode())) { throw new ServiceException(ResultCode.PAY_DOUBLE_ERROR); } - cashierParam.setPrice( recharge.getMoney().longValue()); + cashierParam.setPrice( recharge.getMoney().multiply(BigDecimal.valueOf(100)).longValue()); try { cashierParam.setTitle("在线充值"); @@ -75,6 +75,7 @@ public class RechargeCashier implements CashierExecute { } cashierParam.setDetail("余额充值"); cashierParam.setCreateTime(recharge.getCreateTime()); + cashierParam.setOrderSns(payParam.getSn()); return cashierParam; } diff --git a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/kit/plugin/wechat/WechatPlugin.java b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/kit/plugin/wechat/WechatPlugin.java index edfbb84a3..04f840405 100644 --- a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/kit/plugin/wechat/WechatPlugin.java +++ b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/kit/plugin/wechat/WechatPlugin.java @@ -29,6 +29,7 @@ import com.wzj.soopin.transaction.service.PaymentService; import com.wzj.soopin.transaction.service.RefundLogService; import com.wzj.soopin.transaction.util.CurrencyUtil; import com.wzj.soopin.transaction.util.SnowFlake; +import com.wzj.soopin.transaction.wechat.WXPayUtility; import com.wzj.soopin.transaction.wechat.WechatPayConfig; import com.wzj.soopin.transaction.wechat.WechatPayException; import jakarta.servlet.http.HttpServletRequest; @@ -255,7 +256,7 @@ public class WechatPlugin implements Payment { //支付金额 Integer fen = cashierParam.getPrice().intValue(); //第三方付款订单 - String outOrderNo = SnowFlake.getIdStr(); + String outOrderNo = cashierParam.getOrderSns(); //过期时间 ZonedDateTime zonedDateTime = LocalDateTime.now().plusMinutes(3).atZone(ZoneId.of("UTC")); @@ -263,9 +264,9 @@ public class WechatPlugin implements Payment { DateTimeFormatter rfc3339NoMillis = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX"); String timeExpire = zonedDateTime.format(rfc3339NoMillis); - Map attachMap=new HashMap<>(); - attachMap.put("orderType",payParam.getOrderType()); - attachMap.put("outOrderNo",outOrderNo); + Map attachMap = new HashMap<>(); + attachMap.put("orderType", payParam.getOrderType()); + attachMap.put("outOrderNo", outOrderNo); String attach = URLEncoder.createDefault().encode(JSONUtil.toJsonStr(attachMap), StandardCharsets.UTF_8); String appid = setting.getAppId(); @@ -273,26 +274,26 @@ public class WechatPlugin implements Payment { throw new ServiceException(ResultCode.WECHAT_PAYMENT_NOT_SETTING); } UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel() - .setAppid(appid) - .setMchid(setting.getMchId()) - .setDescription(cashierParam.getDetail()) - .setOut_trade_no(outOrderNo) - .setTime_expire(timeExpire) - .setAttach(attach) - .setNotify_url("http://cjh.wuzhongjie.com.cn/app/payment/callback/"+PaymentMethodEnum.WECHAT) - .setAmount(new Amount().setTotal(fen)); + .setAppid(appid) + .setMchid(setting.getMchId()) + .setDescription(cashierParam.getDetail()) + .setOut_trade_no(outOrderNo) + .setTime_expire(timeExpire) + .setAttach(attach) + .setNotify_url("http://cjh.wuzhongjie.com.cn/app/payment/callback/" + PaymentMethodEnum.WECHAT) + .setAmount(new Amount().setTotal(fen)); log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel)); PaymentHttpResponse response = WechatApi.v3( - RequestMethodEnums.POST, - WechatDomain.CHINA.toString(), - WechatApiEnum.APP_PAY.toString(), - setting.getMchId(), - setting.getMchSerialNo(), - setting.getMchSerialNo(), - setting.getPrivateKeyPath() , - JSONUtil.toJsonStr(unifiedOrderModel) + RequestMethodEnums.POST, + WechatDomain.CHINA.toString(), + WechatApiEnum.APP_PAY.toString(), + setting.getMchId(), + setting.getMchSerialNo(), + setting.getMchSerialNo(), + setting.getPrivateKeyPath(), + JSONUtil.toJsonStr(unifiedOrderModel) ); //根据证书序列号查询对应的证书来验证签名结果 @@ -304,11 +305,15 @@ public class WechatPlugin implements Payment { JSONObject jsonObject = JSONUtil.parseObj(response.getBody()); String prepayId = jsonObject.getStr("prepay_id"); Map map = WxPayKit.appPrepayIdCreateSign(appid, - setting.getMchId(), - prepayId, - setting.getApiclient_key(), SignType.HMACSHA256); + setting.getMchId(), + prepayId, + setting.getPrivateKeyPath(), SignType.HMACSHA256); log.info("唤起支付参数:{}", map); + + //更新订单的prepayId + + return R.ok(map); } log.error("微信支付参数验证错误,请及时处理"); @@ -499,7 +504,7 @@ public class WechatPlugin implements Payment { //校验服务器端响应¬7 String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp, - setting.getApiV3Key(), Objects.requireNonNull(getPlatformCert())); + setting.getApiV3Key(), Objects.requireNonNull(getPlatformCert())); log.info("微信支付通知明文 {}", plainText); @@ -513,16 +518,81 @@ public class WechatPlugin implements Payment { // Double totalAmount = CurrencyUtil.reversalFen(jsonObject.getJSONObject("amount").getDouble("total")); PaymentSuccessParams paymentSuccessParams = new PaymentSuccessParams( - PaymentMethodEnum.WECHAT.getCode(), - tradeNo, - 0d, - payParam + PaymentMethodEnum.WECHAT.getCode(), + tradeNo, + 0d, + payParam ); cashierSupport.paymentSuccess(paymentSuccessParams); log.info("微信支付回调:支付成功{}", plainText); } + + @Override + public R searchByOutTradeNo(String outTradeNo) { + + try { + + + String appid = setting.getAppId(); + if (appid == null) { + throw new ServiceException(ResultCode.WECHAT_PAYMENT_NOT_SETTING); + } + UnifiedOrderModel unifiedOrderModel = new UnifiedOrderModel() + .setAppid(appid) + .setMchid(setting.getMchId()) + .setOut_trade_no(outTradeNo); + String uri = WechatApiEnum.ORDER_QUERY_BY_NO.toString().formatted(outTradeNo); + Map args = new HashMap<>(); + args.put("mchid", setting.getMchId()); + + + log.info("统一下单参数 {}", JSONUtil.toJsonStr(unifiedOrderModel)); + PaymentHttpResponse response = WechatApi.v3( + RequestMethodEnums.GET, + WechatDomain.CHINA.toString(), + uri, + setting.getMchId(), + setting.getMchSerialNo(), + setting.getMchSerialNo(), + setting.getPrivateKeyPath(), + args + ); + //根据证书序列号查询对应的证书来验证签名结果 + boolean verifySignature = WxPayKit.verifySignature(response, getPlatformCert()); + log.info("verifySignature: {}", verifySignature); + log.info("统一下单响应 {}", response); + + if (verifySignature) { + JSONObject jsonObject = JSONUtil.parseObj(response.getBody()); + String tradeState = jsonObject.getStr("trade_state"); + if (tradeState.equals("SUCCESS")) { + String payParamStr = jsonObject.getStr("attach"); + String payParamJson = URLDecoder.decode(payParamStr, StandardCharsets.UTF_8); + PayParam payParam = JSONUtil.toBean(payParamJson, PayParam.class); + + String tradeNo = jsonObject.getStr("transaction_id"); + PaymentSuccessParams paymentSuccessParams = new PaymentSuccessParams( + PaymentMethodEnum.WECHAT.getCode(), + tradeNo, + 0d, + payParam + ); + + cashierSupport.paymentSuccess(paymentSuccessParams); + } + return R.ok(); + } + log.error("微信支付参数验证错误,请及时处理"); + throw new ServiceException(ResultCode.PAY_ERROR); + } catch (Exception e) { + log.error("微信退款申请失败", e); + } + + return R.ok(); + } + @Override public void refund(RefundLog refundLog) { @@ -654,14 +724,14 @@ public class WechatPlugin implements Payment { PaymentHttpResponse response = WechatApi.v3( - RequestMethodEnums.GET, - WechatDomain.CHINA.toString(), - WechatApiEnum.GET_CERTIFICATES.toString(), - setting.getMchId(), - setting.getMchSerialNo(), - null, - setting.getPrivateKeyPath(), - "" + RequestMethodEnums.GET, + WechatDomain.CHINA.toString(), + WechatApiEnum.GET_CERTIFICATES.toString(), + setting.getMchId(), + setting.getMchSerialNo(), + null, + setting.getPrivateKeyPath(), + "" ); String body = response.getBody(); log.info("获取微信平台证书body: {}", body); @@ -708,10 +778,13 @@ public class WechatPlugin implements Payment { //平台证书密文解密 //encrypt_certificate 中的 associated_data nonce ciphertext return aesUtil.decryptToString( - associatedData.getBytes(StandardCharsets.UTF_8), - nonce.getBytes(StandardCharsets.UTF_8), - cipherText + associatedData.getBytes(StandardCharsets.UTF_8), + nonce.getBytes(StandardCharsets.UTF_8), + cipherText ); } + + + } diff --git a/ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/service/RedPacketService.java b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/RedPacketService.java similarity index 88% rename from ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/service/RedPacketService.java rename to ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/RedPacketService.java index 8cb7e7027..fc735f012 100644 --- a/ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/service/RedPacketService.java +++ b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/RedPacketService.java @@ -1,4 +1,4 @@ -package com.wzj.soopin.order.service; +package com.wzj.soopin.transaction.service; import com.wzj.soopin.order.domain.query.GrabRedPacketRequest; import com.wzj.soopin.order.domain.query.SendRedPacketRequest; diff --git a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/impl/AccountBillServiceImpl.java b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/impl/AccountBillServiceImpl.java index 6071a20b7..d016b0294 100644 --- a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/impl/AccountBillServiceImpl.java +++ b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/impl/AccountBillServiceImpl.java @@ -76,10 +76,7 @@ public class AccountBillServiceImpl extends if (memberAccount == null) { throw new RuntimeException("用户不存在"); } - //检查当前用于的账户余额是否充足 BigDecimal balance = memberAccount.getWallet(); - - BigDecimal newBalance = balance.add(money); //锁定用户余额 memberAccountService.updateById(memberAccount.toBuilder().wallet(newBalance).build()); diff --git a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/impl/ChargeServiceImpl.java b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/impl/ChargeServiceImpl.java index d8aa119e3..a9aa3a664 100644 --- a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/impl/ChargeServiceImpl.java +++ b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/impl/ChargeServiceImpl.java @@ -97,9 +97,13 @@ public class ChargeServiceImpl extends ServiceImpl impleme log.error("充值记录不存在,code:{}",code); return false; } - charge.setStatus(ChargeStatus.PENDING.getCode()); -// charge.setPayNo(payNo); + charge.setStatus(ChargeStatus.SUCCESS.getCode()); + charge.setPayNo(payNo); charge.setMethod(method); - return updateById(charge); + boolean result= updateById(charge); + if (result){ + accountBillService.addMoney(charge.getActualMoney(),charge.getMemberId(),AccountBillSourceEnum.RECHARGE,"充值"); + } + return result; } } diff --git a/ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/service/impl/RedPacketServiceImpl.java b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/impl/RedPacketServiceImpl.java similarity index 72% rename from ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/service/impl/RedPacketServiceImpl.java rename to ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/impl/RedPacketServiceImpl.java index 23583dfb3..f014cca86 100644 --- a/ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/service/impl/RedPacketServiceImpl.java +++ b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/impl/RedPacketServiceImpl.java @@ -1,9 +1,7 @@ -package com.wzj.soopin.order.service.impl; +package com.wzj.soopin.transaction.service.impl; import cn.hutool.core.date.DateTime; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.wzj.soopin.member.domain.po.AccountBill; -import com.wzj.soopin.member.enums.AccountBillChangeTypeEnum; import com.wzj.soopin.member.enums.AccountBillSourceEnum; import com.wzj.soopin.member.mapper.MemberAccountMapper; import com.wzj.soopin.order.domain.entity.RedPacket; @@ -12,18 +10,23 @@ import com.wzj.soopin.order.domain.query.GrabRedPacketRequest; import com.wzj.soopin.order.domain.query.SendRedPacketRequest; import com.wzj.soopin.order.mapper.RedPacketMapper; import com.wzj.soopin.order.mapper.RedPacketReceiveMapper; -import com.wzj.soopin.order.service.RedPacketService; +import com.wzj.soopin.transaction.service.IAccountBillService; +import com.wzj.soopin.transaction.service.RedPacketService; import lombok.RequiredArgsConstructor; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.exception.base.BaseException; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; +import java.math.RoundingMode; import java.time.LocalDateTime; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Random; import java.util.concurrent.TimeUnit; @Service @@ -35,6 +38,8 @@ public class RedPacketServiceImpl extends ServiceImpl redisTemplate; + private final IAccountBillService accountBillService; + // Redis锁前缀 private static final String LOCK_PREFIX = "red_packet:lock:"; @@ -68,9 +73,8 @@ public class RedPacketServiceImpl extends ServiceImpl result = new HashMap<>(); @@ -108,17 +112,17 @@ public class RedPacketServiceImpl extends ServiceImpl 0) { - throw new RuntimeException("您已领取过该红包"); - } +// Integer received = redPacketReceiveMapper.checkReceived(packetId, memberId); +// if (received != null && received > 0) { +// throw new ServiceException("您已领取过该红包"); +// } // 计算领取金额 BigDecimal receiveAmount = calculateReceiveAmount(redPacket); @@ -131,7 +135,7 @@ public class RedPacketServiceImpl extends ServiceImpl i private final IAccountBillService accountBillService; + private final WxPayService wxPayService; + + private final IMemberService memberService; + @Override public boolean audit(WithdrawBO bo) { Withdraw withdraw = getById(bo.getId()); @@ -58,9 +70,12 @@ public class WithdrawServiceImpl extends ServiceImpl i throw new RuntimeException("提现申请已处理"); } //发起提现 - boolean chargeSuccess = easypayService.withdraw(withdraw.getMemberId(), withdraw.getMoney()); - if (!chargeSuccess) { - throw new RuntimeException("提现失败"); + + try{ + wxPayService.initiateBatchTransferNew(buildWechatPayParam(bo)); + }catch (ServiceException e){ + log.error("提现申请失败",e); + throw new RuntimeException("提现申请失败"); } withdraw = Withdraw.builder().id(bo.getId()) .auditReason(bo.getAuditReason()) @@ -72,6 +87,43 @@ public class WithdrawServiceImpl extends ServiceImpl i return true; } + + + private InitiateBatchTransferRequestNew buildWechatPayParam(WithdrawBO withdraw) { + InitiateBatchTransferRequestNew request = new InitiateBatchTransferRequestNew(); + WechatPayConfig wechatPayConfig = new WechatPayConfig(); + //商户AppID + request.setAppid(wechatPayConfig.getAppId()); + //商户单号 + request.setOutBillNo(withdraw.getCode()); + request.setTransferAmount(withdraw.getMoney().multiply(BigDecimal.valueOf(100)).intValue()); + //转账场景ID + // /** 转账场景ID 说明:该批次转账使用的转账场景,如不填写则使用商家的默认场景,如无默认场景可为空,可前往“商家转账到零钱-前往功能”中申请。 如:1001-现金营销 */ + request.setTransferSceneId("1005"); + //用户的openId + Member member=memberService.getById(withdraw.getMemberId()); + request.setOpenid(member.getOpenId()); + //收款用户姓名 + request.setUserName(member.getNickname()); + //转账备注 + request.setTransferRemark("提现"); + //转账场景报备信息 佣金的固定类型 + List transferDetailList = new ArrayList<>(); + TransferSceneReportInfoNew transferSceneReportInfoNew = new TransferSceneReportInfoNew(); + transferSceneReportInfoNew.setInfoType("岗位类型"); + transferSceneReportInfoNew.setInfoContent("代理人"); + transferDetailList.add(transferSceneReportInfoNew); + TransferSceneReportInfoNew transferSceneReportInfoNew1 = new TransferSceneReportInfoNew(); + transferSceneReportInfoNew1.setInfoType("报酬说明"); + transferSceneReportInfoNew1.setInfoContent("手续费"); + transferDetailList.add(transferSceneReportInfoNew1); + request.setTransferSceneReportInfos(transferDetailList); + //异步接收微信支付结果通知的回调地址,通知url必须为公网可访问的URL,必须为HTTPS,不能携带参数 + // 注意:此处需要填写公网可访问的服务器地址,不能携带任何参数 + request.setNotifyUrl(wechatPayConfig.getTransferNotifyUrl()); + return request; + } + @Override public boolean withdrawCallback(WithdrawBO withdraw) { MemberAccount memberAccount = memberAccountService.getMemberAccount(withdraw.getMemberId()); diff --git a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/impl/WxPayService.java b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/impl/WxPayService.java index 80e1bc781..694a35603 100644 --- a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/impl/WxPayService.java +++ b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/impl/WxPayService.java @@ -42,6 +42,8 @@ public class WxPayService { private static final Logger logger = LoggerFactory.getLogger(WxPayService.class); @Autowired private WechatPayConfig WechatPayConfig; + @Autowired + private RSAAutoCertificateConfig wxPayConfig; /** * 商家转账 - 发起转账 - 2025年1月15号之后,商户转账零线必须用户确认收款 @@ -51,30 +53,32 @@ public class WxPayService { */ public InitiateBatchTransferResponseNew initiateBatchTransferNew(InitiateBatchTransferRequestNew request) { logger.info("WxPayService.initiateBatchTransferNew request:{}", request.toString()); - Config config = new RSAAutoCertificateConfig.Builder() - .merchantId(WechatPayConfig.getMchId()) - .privateKeyFromPath(WechatPayConfig.getPrivateKeyPath()) - .merchantSerialNumber(WechatPayConfig.getMchSerialNo()) - .apiV3Key(WechatPayConfig.getApiV3Key()) - .build(); - String encryptName = config.createEncryptor().encrypt(request.getUserName()); - request.setUserName(encryptName); - String requestPath = "https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills"; - HttpHeaders headers = new HttpHeaders(); - headers.addHeader("Accept", MediaType.APPLICATION_JSON.getValue()); - headers.addHeader("Content-Type", MediaType.APPLICATION_JSON.getValue()); - headers.addHeader("Wechatpay-Serial", config.createEncryptor().getWechatpaySerial()); - HttpRequest httpRequest = + try{ + + String encryptName = wxPayConfig.createEncryptor().encrypt(request.getUserName()); + request.setUserName(encryptName); + String requestPath = "https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills"; + HttpHeaders headers = new HttpHeaders(); + headers.addHeader("Accept", MediaType.APPLICATION_JSON.getValue()); + headers.addHeader("Content-Type", MediaType.APPLICATION_JSON.getValue()); + headers.addHeader("Wechatpay-Serial", wxPayConfig.createEncryptor().getWechatpaySerial()); + HttpRequest httpRequest = new HttpRequest.Builder() - .httpMethod(HttpMethod.POST) - .url(requestPath) - .headers(headers) - .body(createRequestBody(request)) - .build(); - HttpClient httpClient = new DefaultHttpClientBuilder().config(config).build(); - HttpResponse httpResponse = httpClient.execute(httpRequest, InitiateBatchTransferResponseNew.class); - logger.info("WxPayService.initiateBatchTransferNew response:{}", httpResponse.getServiceResponse()); - return httpResponse.getServiceResponse(); + .httpMethod(HttpMethod.POST) + .url(requestPath) + .headers(headers) + .body(createRequestBody(request)) + .build(); + HttpClient httpClient = new DefaultHttpClientBuilder().config(wxPayConfig).build(); + HttpResponse httpResponse = httpClient.execute(httpRequest, InitiateBatchTransferResponseNew.class); + logger.info("WxPayService.initiateBatchTransferNew response:{}", httpResponse.getServiceResponse()); + return httpResponse.getServiceResponse(); + + }catch (Exception e){ + logger.error("WxPayService.initiateBatchTransferNew error:{}", e); + } + return null; + } /** @@ -85,6 +89,7 @@ public class WxPayService { */ public TransferDetailEntityNew getTransferDetailByOutNoNew(String outBillNo) { logger.info("WxPayService.getTransferDetailByOutNoNew request:{}", outBillNo); + Config config = new RSAAutoCertificateConfig.Builder() .merchantId(WechatPayConfig.getMchId()) .privateKeyFromPath(WechatPayConfig.getPrivateKeyPath()) diff --git a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/wechat/WechatPayConfig.java b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/wechat/WechatPayConfig.java index 23de97a34..6ebef5223 100644 --- a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/wechat/WechatPayConfig.java +++ b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/wechat/WechatPayConfig.java @@ -1,5 +1,7 @@ package com.wzj.soopin.transaction.wechat; +import com.wechat.pay.java.core.Config; +import com.wechat.pay.java.core.RSAAutoCertificateConfig; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -42,4 +44,16 @@ public class WechatPayConfig { return WXPayUtility.loadPrivateKeyFromPath(privateKeyPath); } } + + @Bean + public RSAAutoCertificateConfig wxPayConfig() throws IOException { + return new RSAAutoCertificateConfig.Builder() + .merchantId(this.getMchId()) + .privateKey(this.merchantPrivateKey()) + .merchantSerialNumber(this.getMchSerialNo()) + .apiV3Key(this.getApiV3Key()) + .build(); + } + + } diff --git a/script/docker/nginx/conf/nginx.conf b/script/docker/nginx/conf/nginx.conf index 018e80472..fa19d2026 100644 --- a/script/docker/nginx/conf/nginx.conf +++ b/script/docker/nginx/conf/nginx.conf @@ -170,7 +170,7 @@ http { # server { listen 443 ssl; - server_name wuzhongjie.com.cn www.wuzhongjie.com.cn; + server_name wuzhongjie.com.cn www.wuzhongjie.com.cn ; ssl_certificate /etc/nginx/cert/wuzhongjie.com.cn_bundle.pem; ssl_certificate_key /etc/nginx/cert/wuzhongjie.com.cn.key; @@ -199,6 +199,7 @@ http { } + location ^~ /busniess { alias /data/nginx/wzj/busniess/; index index.html; @@ -244,7 +245,27 @@ http { proxy_redirect off; } } + server { + listen 443 ssl; + ssl_certificate /etc/nginx/cert/wuzhongjie.com.cn_bundle.pem; + ssl_certificate_key /etc/nginx/cert/wuzhongjie.com.cn.key; + ssl_session_timeout 5m; + ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4; + ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; + ssl_prefer_server_ciphers on; + # 设置 gzip 压缩 + gzip on; + #gzip_static on; + gzip_types text/plain text/css application/javascript application/json; + gzip_min_length 256; + server_name cjh.wuzhongjie.com.cn; + location / { + proxy_pass http://43.143.227.203:7002; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + }