微信转账未完成

This commit is contained in:
痴货 2024-10-01 12:16:10 +08:00
parent 2c4d8298cf
commit 3b9548aa2d
8 changed files with 207 additions and 11 deletions

View File

@ -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);
}

View File

@ -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);
/**
* 获得佣金提现

View File

@ -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) {

View File

@ -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);

View File

@ -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>

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}
}