Browse Source

微信转账未完成

痴货 8 months ago
parent
commit
3b9548aa2d

+ 3 - 2
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageWithdrawController.java

@@ -24,6 +24,7 @@ import java.util.Map;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
 
 @Tag(name = "管理后台 - 佣金提现")
 @RestController
@@ -41,7 +42,7 @@ public class BrokerageWithdrawController {
     @Operation(summary = "通过申请")
     @PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:audit')")
     public CommonResult<Boolean> approveBrokerageWithdraw(@RequestParam("id") Integer id) {
-        brokerageWithdrawService.auditBrokerageWithdraw(id, BrokerageWithdrawStatusEnum.AUDIT_SUCCESS, "");
+        brokerageWithdrawService.auditBrokerageWithdraw(id, BrokerageWithdrawStatusEnum.AUDIT_SUCCESS, "", getClientIP());
         return success(true);
     }
 
@@ -49,7 +50,7 @@ public class BrokerageWithdrawController {
     @Operation(summary = "驳回申请")
     @PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:audit')")
     public CommonResult<Boolean> rejectBrokerageWithdraw(@Valid @RequestBody BrokerageWithdrawRejectReqVO reqVO) {
-        brokerageWithdrawService.auditBrokerageWithdraw(reqVO.getId(), BrokerageWithdrawStatusEnum.AUDIT_FAIL, reqVO.getAuditReason());
+        brokerageWithdrawService.auditBrokerageWithdraw(reqVO.getId(), BrokerageWithdrawStatusEnum.AUDIT_FAIL, reqVO.getAuditReason(), getClientIP());
         return success(true);
     }
 

+ 1 - 1
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawService.java

@@ -28,7 +28,7 @@ public interface BrokerageWithdrawService {
      * @param status      审核状态
      * @param auditReason 驳回原因
      */
-    void auditBrokerageWithdraw(Integer id, BrokerageWithdrawStatusEnum status, String auditReason);
+    void auditBrokerageWithdraw(Integer id, BrokerageWithdrawStatusEnum status, String auditReason, String userIp);
 
     /**
      * 获得佣金提现

+ 41 - 5
yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageWithdrawServiceImpl.java

@@ -4,20 +4,29 @@ import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.LocalDateTimeUtil;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.ObjectUtil;
+import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.common.util.number.MoneyUtils;
+import cn.iocoder.yudao.module.pay.api.transfer.PayTransferApi;
+import cn.iocoder.yudao.module.pay.api.transfer.dto.PayTransferCreateReqDTO;
+import cn.iocoder.yudao.module.pay.enums.transfer.PayTransferTypeEnum;
 import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi;
 import cn.iocoder.yudao.module.system.api.notify.dto.NotifySendSingleToUserReqDTO;
+import cn.iocoder.yudao.module.system.api.social.SocialUserApi;
+import cn.iocoder.yudao.module.system.api.social.dto.SocialUserRespDTO;
+import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
 import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw.BrokerageWithdrawPageReqVO;
 import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.withdraw.AppBrokerageWithdrawCreateReqVO;
 import cn.iocoder.yudao.module.trade.convert.brokerage.BrokerageWithdrawConvert;
 import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageWithdrawDO;
 import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
 import cn.iocoder.yudao.module.trade.dal.mysql.brokerage.BrokerageWithdrawMapper;
+import cn.iocoder.yudao.module.trade.dal.redis.no.TradeNoRedisDAO;
 import cn.iocoder.yudao.module.trade.enums.MessageTemplateConstants;
 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum;
 import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum;
+import cn.iocoder.yudao.module.trade.framework.order.config.TradeOrderProperties;
 import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageWithdrawSummaryRespBO;
 import cn.iocoder.yudao.module.trade.service.config.TradeConfigService;
 import org.springframework.stereotype.Service;
@@ -27,12 +36,10 @@ import org.springframework.validation.annotation.Validated;
 import jakarta.annotation.Resource;
 import jakarta.validation.Validator;
 import java.time.LocalDateTime;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.trade.dal.redis.no.TradeNoRedisDAO.TRADE_ORDER_NO_PREFIX;
 import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;
 
 /**
@@ -46,6 +53,8 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
 
     @Resource
     private BrokerageWithdrawMapper brokerageWithdrawMapper;
+    @Resource
+    private TradeNoRedisDAO tradeNoRedisDAO;
 
     @Resource
     private BrokerageRecordService brokerageRecordService;
@@ -54,15 +63,23 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
 
     @Resource
     private NotifyMessageSendApi notifyMessageSendApi;
+    @Resource
+    private PayTransferApi payTransferApi;
+    @Resource
+    private SocialUserApi socialUserApi;
 
     @Resource
     private Validator validator;
 
+    @Resource
+    private TradeOrderProperties tradeOrderProperties;
+
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public void auditBrokerageWithdraw(Integer id, BrokerageWithdrawStatusEnum status, String auditReason) {
+    public void auditBrokerageWithdraw(Integer id, BrokerageWithdrawStatusEnum status, String auditReason, String userIp) {
         // 1.1 校验存在
         BrokerageWithdrawDO withdraw = validateBrokerageWithdrawExists(id);
+
         // 1.2 校验状态为审核中
         if (ObjectUtil.notEqual(BrokerageWithdrawStatusEnum.AUDITING.getStatus(), withdraw.getStatus())) {
             throw exception(BROKERAGE_WITHDRAW_STATUS_NOT_AUDITING);
@@ -81,6 +98,12 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
             // 3.1 通过时佣金转余额
             if (BrokerageWithdrawTypeEnum.WALLET.getType().equals(withdraw.getType())) {
                 // todo 疯狂:
+            }else if (BrokerageWithdrawTypeEnum.WECHAT.getType().equals(withdraw.getType())){
+                //获取openid
+                SocialUserRespDTO socialUser = socialUserApi.getSocialUserByUserId(UserTypeEnum.MEMBER.getValue(), withdraw.getUserId(), SocialTypeEnum.WECHAT_MINI_APP.getType());
+                // 微信提现
+                PayTransferCreateReqDTO payTransferCreateReqDTO = getPayTransferCreateReqDTO(userIp, withdraw, socialUser);
+                payTransferApi.createTransfer(payTransferCreateReqDTO);
             }
             // TODO 疯狂:调用转账接口
         } else if (BrokerageWithdrawStatusEnum.AUDIT_FAIL.equals(status)) {
@@ -102,6 +125,19 @@ public class BrokerageWithdrawServiceImpl implements BrokerageWithdrawService {
                 .setUserId(withdraw.getUserId()).setTemplateCode(templateCode).setTemplateParams(templateParams));
     }
 
+    private PayTransferCreateReqDTO getPayTransferCreateReqDTO(String userIp, BrokerageWithdrawDO withdraw, SocialUserRespDTO socialUser) {
+        PayTransferCreateReqDTO payTransferCreateReqDTO = new PayTransferCreateReqDTO();
+        payTransferCreateReqDTO.setAppKey(tradeOrderProperties.getPayAppKey());
+        payTransferCreateReqDTO.setChannelCode("wx_lite");
+        payTransferCreateReqDTO.setUserIp(userIp);
+        payTransferCreateReqDTO.setType(PayTransferTypeEnum.WX_BALANCE.getType());
+        payTransferCreateReqDTO.setMerchantTransferId(withdraw.getId().toString());
+        payTransferCreateReqDTO.setPrice(withdraw.getPrice());
+        payTransferCreateReqDTO.setSubject("佣金提现");
+        payTransferCreateReqDTO.setOpenid(socialUser.getOpenid());
+        return payTransferCreateReqDTO;
+    }
+
     private BrokerageWithdrawDO validateBrokerageWithdrawExists(Integer id) {
         BrokerageWithdrawDO withdraw = brokerageWithdrawMapper.selectById(id);
         if (withdraw == null) {

+ 3 - 1
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/transfer/PayTransferServiceImpl.java

@@ -96,13 +96,15 @@ public class PayTransferServiceImpl implements PayTransferService {
             transfer = INSTANCE.convert(reqDTO)
                     .setChannelId(channel.getId())
                     .setNo(no).setStatus(WAITING.getStatus())
-                    .setNotifyUrl(payApp.getTransferNotifyUrl());
+                    .setNotifyUrl(payApp.getTransferNotifyUrl())
+                    .setAppId(channel.getAppId());
             transferMapper.insert(transfer);
         }
         try {
             // 3. 调用三方渠道发起转账
             PayTransferUnifiedReqDTO transferUnifiedReq = INSTANCE.convert2(transfer)
                     .setOutTransferNo(transfer.getNo());
+            transferUnifiedReq.setNotifyUrl(payApp.getTransferNotifyUrl());
             PayTransferRespDTO unifiedTransferResp = client.unifiedTransfer(transferUnifiedReq);
             // 4. 通知转账结果
             getSelf().notifyTransfer(channel, unifiedTransferResp);

+ 5 - 0
yudao-module-pay/yudao-spring-boot-starter-biz-pay/pom.xml

@@ -64,6 +64,10 @@
             <groupId>com.github.binarywang</groupId>
             <artifactId>weixin-java-pay</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.github.binarywang</groupId>
+            <artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
+        </dependency>
 
         <!-- Test 测试相关 -->
         <dependency>
@@ -71,6 +75,7 @@
             <artifactId>yudao-spring-boot-starter-test</artifactId>
             <scope>test</scope>
         </dependency>
+
     </dependencies>
 
 </project>

+ 9 - 0
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/transfer/PayTransferUnifiedReqDTO.java

@@ -9,6 +9,8 @@ import jakarta.validation.constraints.Min;
 import jakarta.validation.constraints.NotBlank;
 import jakarta.validation.constraints.NotEmpty;
 import jakarta.validation.constraints.NotNull;
+import org.hibernate.validator.constraints.URL;
+
 import java.util.Map;
 
 import static cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum.*;
@@ -75,4 +77,11 @@ public class PayTransferUnifiedReqDTO {
      * 支付渠道的额外参数
      */
     private Map<String, String> channelExtras;
+
+    /**
+     * 转账结果的 notify 回调地址
+     */
+    @NotEmpty(message = "转账结果的回调地址不能为空")
+    @URL(message = "转账结果的 notify 回调地址必须是 URL 格式")
+    private String notifyUrl;
 }

+ 27 - 2
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/weixin/AbstractWxPayClient.java

@@ -17,20 +17,27 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifie
 import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
 import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum;
 import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
+import com.binarywang.spring.starter.wxjava.miniapp.properties.WxMaProperties;
 import com.github.binarywang.wxpay.bean.notify.WxPayNotifyV3Result;
 import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
 import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyResult;
 import com.github.binarywang.wxpay.bean.notify.WxPayRefundNotifyV3Result;
 import com.github.binarywang.wxpay.bean.request.*;
 import com.github.binarywang.wxpay.bean.result.*;
+import com.github.binarywang.wxpay.bean.transfer.TransferBatchesRequest;
+import com.github.binarywang.wxpay.bean.transfer.TransferBatchesResult;
 import com.github.binarywang.wxpay.config.WxPayConfig;
 import com.github.binarywang.wxpay.exception.WxPayException;
+import com.github.binarywang.wxpay.service.TransferService;
 import com.github.binarywang.wxpay.service.WxPayService;
 import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
+import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
 
 import java.time.LocalDateTime;
 import java.time.ZoneId;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 
@@ -426,8 +433,26 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
     }
 
     @Override
-    protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {
-       throw new UnsupportedOperationException("待实现");
+    protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) throws WxPayException {
+        TransferService transferService = client.getTransferService();
+        List<TransferBatchesRequest.TransferDetail> transferDetailList = new ArrayList<>();
+        transferDetailList.add(TransferBatchesRequest.TransferDetail.newBuilder()
+                .outDetailNo(reqDTO.getOutTransferNo())
+                .transferAmount(reqDTO.getPrice())
+                .transferRemark(reqDTO.getSubject())
+                .openid(reqDTO.getOpenid())
+                .build());
+        TransferBatchesRequest transferBatches = TransferBatchesRequest.newBuilder()
+                .appid(this.config.getAppId())
+                .outBatchNo(reqDTO.getOutTransferNo())
+                .batchName(reqDTO.getSubject())
+                .batchRemark(reqDTO.getSubject())
+                .totalAmount(reqDTO.getPrice())
+                .totalNum(1)
+                .transferDetailList(transferDetailList).build();
+        transferBatches.setNotifyUrl(reqDTO.getNotifyUrl());
+        TransferBatchesResult transferBatchesResult = transferService.transferBatches(transferBatches);
+        return PayTransferRespDTO.waitingOf(reqDTO.getOutTransferNo(), transferBatchesResult.getBatchId() ,transferBatchesResult);
     }
 
     @Override

+ 118 - 0
yudao-module-pay/yudao-spring-boot-starter-biz-pay/src/main/java/com/github/binarywang/wxpay/bean/transfer/TransferBatchesRequest.java

@@ -0,0 +1,118 @@
+package com.github.binarywang.wxpay.bean.transfer;
+
+import com.github.binarywang.wxpay.v3.SpecEncrypt;
+import com.google.gson.annotations.SerializedName;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 发起商家转账API参数
+ *
+ * @author zhongjun
+ * created on  2022/6/17
+ **/
+@Data
+@Builder(builderMethodName = "newBuilder")
+@NoArgsConstructor
+@AllArgsConstructor
+public class TransferBatchesRequest implements Serializable {
+    private static final long serialVersionUID = -2175582517588397426L;
+
+    /**
+     * 直连商户的appid
+     */
+    @SerializedName("appid")
+    private String appid;
+
+    /**
+     * 商家批次单号
+     */
+    @SerializedName("out_batch_no")
+    private String outBatchNo;
+
+    /**
+     * 批次名称
+     */
+    @SerializedName("batch_name")
+    private String batchName;
+
+    /**
+     * 批次备注
+     */
+    @SerializedName("batch_remark")
+    private String batchRemark;
+
+    /**
+     * 转账总金额
+     */
+    @SerializedName("total_amount")
+    private Integer totalAmount;
+
+    /**
+     * 转账总笔数
+     */
+    @SerializedName("total_num")
+    private Integer totalNum;
+
+    /**
+     * 转账明细列表
+     */
+    @SpecEncrypt
+    @SerializedName("transfer_detail_list")
+    private List<TransferDetail> transferDetailList;
+
+    /**
+     * 转账场景ID
+     */
+    @SerializedName("transfer_scene_id")
+    private String transferSceneId;
+
+    /**
+     * 通知地址 说明:异步接收微信支付结果通知的回调地址,通知url必须为公网可访问的url,必须为https,不能携带参数。
+     */
+    @SerializedName("notify_url")
+    private String notifyUrl;
+
+    @Data
+    @Builder(builderMethodName = "newBuilder")
+    @AllArgsConstructor
+    @NoArgsConstructor
+    public static class TransferDetail {
+
+        /**
+         * 商家明细单号
+         */
+        @SerializedName("out_detail_no")
+        private String outDetailNo;
+
+        /**
+         * 转账金额
+         */
+        @SerializedName("transfer_amount")
+        private Integer transferAmount;
+
+        /**
+         * 转账备注
+         */
+        @SerializedName("transfer_remark")
+        private String transferRemark;
+
+        /**
+         * 用户在直连商户应用下的用户标示
+         */
+        @SerializedName("openid")
+        private String openid;
+
+        /**
+         * 收款用户姓名
+         */
+        @SpecEncrypt
+        @SerializedName("user_name")
+        private String userName;
+    }
+}