diff --git a/ruoyi-admin/src/main/java/org/dromara/app/AppMemberController.java b/ruoyi-admin/src/main/java/org/dromara/app/AppMemberController.java index 2c74e3426..c1025b5df 100644 --- a/ruoyi-admin/src/main/java/org/dromara/app/AppMemberController.java +++ b/ruoyi-admin/src/main/java/org/dromara/app/AppMemberController.java @@ -24,6 +24,7 @@ import com.wzj.soopin.transaction.convert.ChargeConvert; import com.wzj.soopin.transaction.convert.WithdrawConvert; import com.wzj.soopin.transaction.domain.bo.ChargeBO; import com.wzj.soopin.transaction.domain.bo.WithdrawBO; +import com.wzj.soopin.transaction.domain.entity.InitiateBatchTransferResponseNew; import com.wzj.soopin.transaction.domain.po.Withdraw; import com.wzj.soopin.transaction.enums.WithdrawType; import com.wzj.soopin.transaction.service.IAccountBillService; @@ -204,14 +205,8 @@ public class AppMemberController { bo.setMemberId(memberId); bo.setType(WithdrawType.WALLET.getCode()); Withdraw withdraw=withdrawConvert.toPo(bo); - withdrawService.withdraw(withdraw); - //检查提现金额是否小于1元 一元以下自动审批 - if(withdraw.getMoney().compareTo(BigDecimal.ONE)<0){ - //自动审批 - bo.setId(withdraw.getId()); - withdrawService.audit(bo); - } - return R.ok(); + InitiateBatchTransferResponseNew responseNew= withdrawService.withdraw(withdraw); + return R.ok(responseNew); } 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 3b4a69846..b8c4ae645 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 @@ -1,5 +1,7 @@ package com.wzj.soopin.transaction.controller; +import com.wzj.soopin.member.domain.po.Member; +import com.wzj.soopin.member.service.IMemberService; import com.wzj.soopin.transaction.domain.entity.*; import com.wzj.soopin.transaction.service.impl.WxAuthService; import com.wzj.soopin.transaction.service.impl.WxPayService; @@ -13,9 +15,11 @@ import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.dromara.common.core.domain.R; +import org.dromara.common.core.domain.model.LoginUser; import org.dromara.common.core.exception.ServiceException; import org.dromara.common.log.annotation.Log; import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.satoken.utils.LoginHelper; import org.mapstruct.Context; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; @@ -40,6 +44,12 @@ public class WxPayController { @Autowired private WxAuthService wxAuthService; + @Autowired + private IMemberService memberService; + + @Autowired + private WechatPayConfig wechatPayConfig; + /** *商家转账 - 发起转账 * @return @@ -180,7 +190,44 @@ public class WxPayController { } } + /** + * 获取用户的openid + * + * @return 包含openid的响应对象 + */ + @Operation(summary = "拉取用户授权") + @GetMapping("/pullConfirm") + @Parameters({ + @Parameter(name = "code", description = "授权码", required = true, in = ParameterIn.QUERY) + }) + public R pullComfirm() { + try { + InitiateBatchTransferRequestNew request = new InitiateBatchTransferRequestNew(); + //商户AppID + request.setAppid(wechatPayConfig.getAppId()); + LoginUser user = LoginHelper.getLoginUser(); + Member member = memberService.getById(user.getUserId()); + //用户的openId + request.setOpenid(member.getOpenId()); + //收款用户姓名 + //转账场景ID + // /** 转账场景ID 说明:该批次转账使用的转账场景,如不填写则使用商家的默认场景,如无默认场景可为空,可前往“商家转账到零钱-前往功能”中申请。 如:1001-现金营销 */ + request.setTransferSceneId("1005"); + //【转账备注】 单条转账备注(微信用户会收到该备注),UTF8编码,最多允许32个字符 + + InitiateBatchTransferResponseNew response =null; + try{ + response = wxPayService.pullConfirm(request); + }catch (ServiceException e){ + e.printStackTrace(); + } + return R.ok(response); + } catch (Exception e) { + log.error("获取openid时发生异常: {}", e.getMessage()); + return R.fail("发起面确认收款授权时发生异常: " + e.getMessage()); + } + } diff --git a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/domain/entity/InitiateBatchTransferRequestNew.java b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/domain/entity/InitiateBatchTransferRequestNew.java index 6bb9cdd42..bb6b4b86d 100644 --- a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/domain/entity/InitiateBatchTransferRequestNew.java +++ b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/domain/entity/InitiateBatchTransferRequestNew.java @@ -58,7 +58,7 @@ public class InitiateBatchTransferRequestNew { /** 转账场景报备信息 Y 说明:各转账场景下需报备的内容,可通过 产品文档 了解 */ @SerializedName("transfer_scene_report_infos") - private List transferSceneReportInfos = new ArrayList<>(); + private List transferSceneReportInfos ; public InitiateBatchTransferRequestNew() { super(); diff --git a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/IWithdrawService.java b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/IWithdrawService.java index d91d6c981..4d1a07fad 100644 --- a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/IWithdrawService.java +++ b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/IWithdrawService.java @@ -2,6 +2,7 @@ package com.wzj.soopin.transaction.service; import com.baomidou.mybatisplus.extension.service.IService; import com.wzj.soopin.transaction.domain.bo.WithdrawBO; +import com.wzj.soopin.transaction.domain.entity.InitiateBatchTransferResponseNew; import com.wzj.soopin.transaction.domain.po.Withdraw; public interface IWithdrawService extends IService { @@ -9,6 +10,6 @@ public interface IWithdrawService extends IService { boolean withdrawCallback(WithdrawBO withdraw); - boolean withdraw (Withdraw withdraw); + InitiateBatchTransferResponseNew withdraw (Withdraw withdraw); } diff --git a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/impl/WithdrawServiceImpl.java b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/impl/WithdrawServiceImpl.java index eae5d6fb4..ec6e471a9 100644 --- a/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/impl/WithdrawServiceImpl.java +++ b/ruoyi-modules/ruoyi-transaction/src/main/java/com/wzj/soopin/transaction/service/impl/WithdrawServiceImpl.java @@ -1,5 +1,7 @@ package com.wzj.soopin.transaction.service.impl; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.wzj.soopin.content.domain.po.Comment; import com.wzj.soopin.member.domain.po.Member; @@ -7,6 +9,7 @@ import com.wzj.soopin.transaction.domain.bo.WithdrawBO; import com.wzj.soopin.member.domain.po.MemberAccount; import com.wzj.soopin.member.domain.po.AccountBill; import com.wzj.soopin.transaction.domain.entity.InitiateBatchTransferRequestNew; +import com.wzj.soopin.transaction.domain.entity.InitiateBatchTransferResponseNew; import com.wzj.soopin.transaction.domain.entity.TransferSceneReportInfoNew; import com.wzj.soopin.transaction.domain.po.Withdraw; import com.wzj.soopin.member.enums.AccountBillChangeTypeEnum; @@ -30,9 +33,11 @@ import org.dromara.common.mq.domain.MQMessage; import org.dromara.common.mq.enums.MessageActionEnum; import org.dromara.common.mq.utils.MqUtil; import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.translation.annotation.Translation; import org.dromara.system.domain.SysTenantAccount; import org.dromara.system.service.ISysTenantAccountService; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.time.LocalDateTime; @@ -76,22 +81,7 @@ public class WithdrawServiceImpl extends ServiceImpl i } //发起提现 - try{ - wxPayService.initiateBatchTransferNew(buildWechatPayParam(withdraw)); - }catch (ServiceException e){ - log.error(e.getMessage()); - throw new ServiceException(e.getMessage()); - } - withdraw = Withdraw.builder().id(bo.getId()) - .auditReason(bo.getAuditReason()) - .auditTime(LocalDateTime.now()) - .auditStatus(bo.getAuditStatus()) - .auditBy(LoginHelper.getUserId()) - .build(); - this.updateById(withdraw); - //发送成功通知 - MqUtil.sendIMMessage(buildMessage(withdraw, MessageActionEnum.ORDER_WITHDRAW_AUDIT)); return true; } @@ -188,7 +178,9 @@ public class WithdrawServiceImpl extends ServiceImpl i - public boolean withdraw (Withdraw withdraw) { + @Override + @Transactional + public InitiateBatchTransferResponseNew withdraw (Withdraw withdraw) { MemberAccount memberAccount = memberAccountService.getMemberAccount(withdraw.getMemberId()); if (memberAccount == null) { throw new RuntimeException("用户不存在"); @@ -198,6 +190,16 @@ public class WithdrawServiceImpl extends ServiceImpl i if (balance==null||balance.compareTo(withdraw.getMoney()) < 0) { throw new RuntimeException("用户余额不足"); } + //检查提现次数是否超过限制 + long count = this.count(new LambdaQueryWrapper() + .eq(Withdraw::getMemberId, withdraw.getMemberId()) + .eq(Withdraw::getStatus, WithdrawStatus.SUCCESS.getCode()) + .between(Withdraw::getCreateTime, LocalDateTime.now().minusDays(1), LocalDateTime.now()) + + ); + if (count >= 3) { + throw new RuntimeException("提现次数超过限制"); + } //生成费用 BigDecimal fee = withdraw.getMoney().multiply(new BigDecimal("0.00")); withdraw.setFee(fee); @@ -220,6 +222,23 @@ public class WithdrawServiceImpl extends ServiceImpl i .source(AccountBillSourceEnum.WITHDRAW.getCode()) .build(); accountBillService.save(memberAccountChangeRecord); - return true; + + InitiateBatchTransferResponseNew response = null; + try{ + response = wxPayService.initiateBatchTransferNew(buildWechatPayParam(withdraw)); + }catch (ServiceException e){ + log.error(e.getMessage()); + throw new ServiceException(e.getMessage()); + } + withdraw = Withdraw.builder().id(withdraw.getId()) + .auditReason(withdraw.getAuditReason()) + .auditTime(LocalDateTime.now()) + .auditStatus(withdraw.getAuditStatus()) + .build(); + this.updateById(withdraw); + + //发送成功通知 + MqUtil.sendIMMessage(buildMessage(withdraw, MessageActionEnum.ORDER_WITHDRAW_AUDIT)); + return response; } } 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 0ec6d1572..906b47459 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 @@ -3,6 +3,7 @@ package com.wzj.soopin.transaction.service.impl; import cn.hutool.core.io.IoUtil; import com.alibaba.fastjson.JSON; import com.google.gson.Gson; +import com.google.gson.GsonBuilder; import com.wechat.pay.java.core.Config; import com.wechat.pay.java.core.RSAAutoCertificateConfig; import com.wechat.pay.java.core.cipher.PrivacyDecryptor; @@ -58,7 +59,38 @@ public class WxPayService { request.setUserName(encryptName); } - String requestPath = "https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/transfer-bills/transfer"; + 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 = + 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(); + } + + /** + * 商家转账 - 发起转账 - 2025年1月15号之后,商户转账零线必须用户确认收款 + * + * @param request 请求体 + * @return + */ + public InitiateBatchTransferResponseNew pullConfirm(InitiateBatchTransferRequestNew request) { + logger.info("WxPayService.initiateBatchTransferNew request:{}", request.toString()); + if(request.getUserName() != null && !request.getUserName().isEmpty()){ + String encryptName = config.createEncryptor().encrypt(request.getUserName()); + request.setUserName(encryptName); + } + + String requestPath = "https://api.mch.weixin.qq.com/v3/fund-app/mch-transfer/user-confirm-authorization"; HttpHeaders headers = new HttpHeaders(); headers.addHeader("Accept", MediaType.APPLICATION_JSON.getValue()); headers.addHeader("Content-Type", MediaType.APPLICATION_JSON.getValue()); @@ -109,7 +141,7 @@ public class WxPayService { * @return */ private static RequestBody createRequestBody(Object request) { - return new JsonRequestBody.Builder().body(new Gson().toJson(request)).build(); + return new JsonRequestBody.Builder().body(new GsonBuilder().create().toJson(request)).build(); } /**