Merge remote-tracking branch 'origin/feature/mall_product' into feature/mall_product

This commit is contained in:
YunaiV 2023-09-26 00:04:18 +08:00
commit 9e99b04375
20 changed files with 426 additions and 24 deletions

View File

@ -4,6 +4,8 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
import java.util.Map; import java.util.Map;
@ -76,4 +78,12 @@ public interface PayClient {
*/ */
PayRefundRespDTO getRefund(String outTradeNo, String outRefundNo); PayRefundRespDTO getRefund(String outTradeNo, String outRefundNo);
/**
* 调用渠道进行转账
*
* @param reqDTO 统一转账请求信息
* @return 转账信息
*/
PayTransferRespDTO unifiedTransfer(PayTransferUnifiedReqDTO reqDTO);
} }

View File

@ -0,0 +1,96 @@
package cn.iocoder.yudao.framework.pay.core.client.dto.transfer;
import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferStatusRespEnum;
import lombok.Data;
import java.time.LocalDateTime;
/**
* 统一转账 Response DTO
*
* @author jason
*/
@Data
public class PayTransferRespDTO {
/**
* 转账状态
*
* 关联 {@link PayTransferStatusRespEnum#getStatus()}
*/
private Integer status;
/**
* 外部转账单号
*
*/
private String outTransferNo;
/**
* 支付渠道编号
*/
private String channelOrderNo;
/**
* 支付成功时间
*/
private LocalDateTime successTime;
/**
* 原始的返回结果
*/
private Object rawData;
/**
* 调用渠道的错误码
*/
private String channelErrorCode;
/**
* 调用渠道报错时错误信息
*/
private String channelErrorMsg;
/**
* 创建WAITING状态的转账返回
*/
public static PayTransferRespDTO waitingOf(String channelOrderNo,
String outTransferNo, Object rawData) {
PayTransferRespDTO respDTO = new PayTransferRespDTO();
respDTO.status = PayTransferStatusRespEnum.WAITING.getStatus();
respDTO.channelOrderNo = channelOrderNo;
respDTO.outTransferNo = outTransferNo;
respDTO.rawData = rawData;
return respDTO;
}
/**
* 创建FAILURE状态的转账返回
*/
public static PayTransferRespDTO failureOf(String channelErrorCode, String channelErrorMsg,
String outTransferNo, Object rawData) {
PayTransferRespDTO respDTO = new PayTransferRespDTO();
respDTO.status = PayTransferStatusRespEnum.FAILURE.getStatus();
respDTO.channelErrorCode = channelErrorCode;
respDTO.channelErrorMsg = channelErrorMsg;
// 相对通用的字段
respDTO.outTransferNo = outTransferNo;
respDTO.rawData = rawData;
return respDTO;
}
/**
* 创建SUCCESS状态的转账返回
*/
public static PayTransferRespDTO successOf(String channelTransferNo, LocalDateTime successTime,
String outTransferNo, Object rawData) {
PayTransferRespDTO respDTO = new PayTransferRespDTO();
respDTO.status = PayTransferStatusRespEnum.SUCCESS.getStatus();
respDTO.channelOrderNo = channelTransferNo;
respDTO.successTime = successTime;
// 相对通用的字段
respDTO.outTransferNo = outTransferNo;
respDTO.rawData = rawData;
return respDTO;
}
}

View File

@ -0,0 +1,65 @@
package cn.iocoder.yudao.framework.pay.core.client.dto.transfer;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Map;
/**
* 统一转账 Request DTO
*
* @author jason
*/
@Data
public class PayTransferUnifiedReqDTO {
/**
* 转账类型
*
* 关联 {@link PayTransferTypeEnum#getType()}
*/
@NotNull(message = "转账类型不能为空")
@InEnum(PayTransferTypeEnum.class)
private Integer type;
/**
* 用户 IP
*/
@NotEmpty(message = "用户 IP 不能为空")
private String userIp;
@NotEmpty(message = "外部转账单编号不能为空")
private String outTransferNo;
/**
* 转账金额单位
*/
@NotNull(message = "转账金额不能为空")
@Min(value = 1, message = "转账金额必须大于零")
private Integer price;
/**
* 转账标题
*/
@NotEmpty(message = "转账标题不能为空")
@Length(max = 128, message = "转账标题不能超过 128")
private String title;
/**
* 收款方信息转账类型不同收款方信息不同
*/
@NotEmpty(message = "收款方信息 不能为空")
private Map<String, String> payeeInfo;
/**
* 支付渠道的额外参数
*
*/
private Map<String, String> channelExtras;
}

View File

@ -8,6 +8,8 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.exception.PayException; import cn.iocoder.yudao.framework.pay.core.client.exception.PayException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -181,6 +183,26 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen
protected abstract PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) protected abstract PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo)
throws Throwable; throws Throwable;
@Override
public final PayTransferRespDTO unifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {
ValidationUtils.validate(reqDTO);
PayTransferRespDTO resp;
try{
resp = doUnifiedTransfer(reqDTO);
}catch (ServiceException ex) { // 业务异常都是实现类已经翻译所以直接抛出即可
throw ex;
} catch (Throwable ex) {
// 系统异常则包装成 PayException 异常抛出
log.error("[unifiedTransfer][客户端({}) request({}) 发起转账异常]",
getId(), toJsonString(reqDTO), ex);
throw buildPayException(ex);
}
return resp;
}
protected abstract PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO)
throws Throwable;
// ========== 各种工具方法 ========== // ========== 各种工具方法 ==========
private PayException buildPayException(Throwable ex) { private PayException buildPayException(Throwable ex) {

View File

@ -50,6 +50,8 @@ public class PayClientFactoryImpl implements PayClientFactory {
clientClass.put(ALIPAY_APP, AlipayAppPayClient.class); clientClass.put(ALIPAY_APP, AlipayAppPayClient.class);
clientClass.put(ALIPAY_PC, AlipayPcPayClient.class); clientClass.put(ALIPAY_PC, AlipayPcPayClient.class);
clientClass.put(ALIPAY_BAR, AlipayBarPayClient.class); clientClass.put(ALIPAY_BAR, AlipayBarPayClient.class);
// 支付包转账客户端
clientClass.put(ALIPAY_TRANSFER, AlipayTransferClient.class);
// Mock 支付客户端 // Mock 支付客户端
clientClass.put(MOCK, MockPayClient.class); clientClass.put(MOCK, MockPayClient.class);
} }

View File

@ -150,6 +150,10 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
// 2.1 执行请求 // 2.1 执行请求
AlipayTradeRefundResponse response = client.execute(request); AlipayTradeRefundResponse response = client.execute(request);
if (!response.isSuccess()) { if (!response.isSuccess()) {
// 当出现 ACQ.SYSTEM_ERROR, 退款可能成功也可能失败 返回 WAIT 状态. 后续 job 会轮询
if (ObjectUtils.equalsAny(response.getSubCode(), "ACQ.SYSTEM_ERROR", "SYSTEM_ERROR")) {
return PayRefundRespDTO.waitingOf(null, reqDTO.getOutRefundNo(), response);
}
return PayRefundRespDTO.failureOf(response.getSubCode(), response.getSubMsg(), reqDTO.getOutRefundNo(), response); return PayRefundRespDTO.failureOf(response.getSubCode(), response.getSubMsg(), reqDTO.getOutRefundNo(), response);
} }
// 2.2 创建返回结果 // 2.2 创建返回结果
@ -198,6 +202,8 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
return PayRefundRespDTO.waitingOf(null, outRefundNo, response); return PayRefundRespDTO.waitingOf(null, outRefundNo, response);
} }
// ========== 各种工具方法 ========== // ========== 各种工具方法 ==========
protected String formatAmount(Integer amount) { protected String formatAmount(Integer amount) {

View File

@ -2,6 +2,8 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayApiException;
@ -57,4 +59,8 @@ public class AlipayAppPayClient extends AbstractAlipayPayClient {
reqDTO.getOutTradeNo(), response); reqDTO.getOutTradeNo(), response);
} }
@Override
protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {
throw new UnsupportedOperationException("支付宝【App 支付】不支持转账操作");
}
} }

View File

@ -5,6 +5,8 @@ import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayApiException;
@ -75,4 +77,8 @@ public class AlipayBarPayClient extends AbstractAlipayPayClient {
reqDTO.getOutTradeNo(), response); reqDTO.getOutTradeNo(), response);
} }
@Override
protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {
throw new UnsupportedOperationException("支付宝【条码支付】不支持转账操作");
}
} }

View File

@ -4,6 +4,8 @@ import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.Method; import cn.hutool.http.Method;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayApiException;
@ -67,4 +69,8 @@ public class AlipayPcPayClient extends AbstractAlipayPayClient {
reqDTO.getOutTradeNo(), response); reqDTO.getOutTradeNo(), response);
} }
@Override
protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {
throw new UnsupportedOperationException("支付宝【PC 网站】不支持转账操作");
}
} }

View File

@ -2,6 +2,8 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayApiException;
@ -54,4 +56,8 @@ public class AlipayQrPayClient extends AbstractAlipayPayClient {
reqDTO.getOutTradeNo(), response); reqDTO.getOutTradeNo(), response);
} }
@Override
protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {
throw new UnsupportedOperationException("支付宝【扫码支付】不支持转账操作");
}
} }

View File

@ -0,0 +1,103 @@
package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
import com.alipay.api.AlipayApiException;
import com.alipay.api.domain.AlipayFundTransUniTransferModel;
import com.alipay.api.domain.Participant;
import com.alipay.api.request.AlipayFundTransUniTransferRequest;
import com.alipay.api.response.AlipayFundTransUniTransferResponse;
import lombok.extern.slf4j.Slf4j;
import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
/**
* 支付宝转账的 PayClient 实现类
*
* @author jason
*/
@Slf4j
public class AlipayTransferClient extends AbstractAlipayPayClient {
public AlipayTransferClient(Long channelId, AlipayPayClientConfig config) {
super(channelId, PayChannelEnum.ALIPAY_TRANSFER.getCode(), config);
}
@Override
protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) {
throw new UnsupportedOperationException("支付宝转账不支持统一下单请求");
}
@Override
protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) {
throw new UnsupportedOperationException("支付宝转账不支持统一退款请求");
}
@Override
protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) throws AlipayApiException {
// 1.1 构建 AlipayFundTransUniTransferModel
AlipayFundTransUniTransferModel model = new AlipayFundTransUniTransferModel();
// 通用的参数
model.setTransAmount(formatAmount(reqDTO.getPrice())); // 转账金额
model.setOrderTitle(reqDTO.getTitle()); // 转账业务的标题用于在支付宝用户的账单里显示
model.setOutBizNo(reqDTO.getOutTransferNo());
model.setProductCode("TRANS_ACCOUNT_NO_PWD"); // 销售产品码单笔无密转账固定为 TRANS_ACCOUNT_NO_PWD
model.setBizScene("DIRECT_TRANSFER"); // 业务场景 单笔无密转账固定为 DIRECT_TRANSFER
model.setBusinessParams(JsonUtils.toJsonString(reqDTO.getChannelExtras()));
PayTransferTypeEnum transferType = PayTransferTypeEnum.valueOf(reqDTO.getType());
switch(transferType){
case WX_BALANCE :
case WALLET_BALANCE : {
log.error("[doUnifiedTransfer],支付宝转账不支持的转账类型{}", transferType);
throw new UnsupportedOperationException(String.format("支付宝转账不支持转账类型: %s",transferType.getName()));
}
case ALIPAY_BALANCE : {
// 个性化的参数
Participant payeeInfo = new Participant();
payeeInfo.setIdentityType("ALIPAY_LOGON_ID");
String logonId = MapUtil.getStr(reqDTO.getPayeeInfo(), "ALIPAY_LOGON_ID");
if (StrUtil.isEmpty(logonId)) {
throw exception0(BAD_REQUEST.getCode(), "支付包登录 ID 不能为空");
}
String accountName = MapUtil.getStr(reqDTO.getPayeeInfo(), "ALIPAY_ACCOUNT_NAME");
if (StrUtil.isEmpty(accountName)) {
throw exception0(BAD_REQUEST.getCode(), "支付包账户名称不能为空");
}
payeeInfo.setIdentity(logonId); // 支付宝登录号
payeeInfo.setName(accountName); // 支付宝账号姓名
model.setPayeeInfo(payeeInfo);
// 1.2 构建 AlipayFundTransUniTransferRequest
AlipayFundTransUniTransferRequest request = new AlipayFundTransUniTransferRequest();
request.setBizModel(model);
// 执行请求
AlipayFundTransUniTransferResponse response = client.certificateExecute(request);
// 处理结果
if (!response.isSuccess()) {
// 当出现 SYSTEM_ERROR, 转账可能成功也可能失败 返回 WAIT 状态. 后续 job 会轮询
if (ObjectUtils.equalsAny(response.getSubCode(), "SYSTEM_ERROR", "ACQ.SYSTEM_ERROR")) {
return PayTransferRespDTO.waitingOf(null, reqDTO.getOutTransferNo(), response);
}
return PayTransferRespDTO.failureOf(response.getSubCode(), response.getSubMsg(),
reqDTO.getOutTransferNo(), response);
}
return PayTransferRespDTO.successOf(response.getOrderId(), parseTime(response.getTransDate()),
response.getOutBizNo(), response);
}
case BANK_CARD : {
Participant payeeInfo = new Participant();
payeeInfo.setIdentityType("BANKCARD_ACCOUNT");
throw new UnsupportedOperationException("待实现");
}
default: {
throw new IllegalStateException("不正确的转账类型: " + transferType);
}
}
}
}

View File

@ -3,6 +3,8 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
import cn.hutool.http.Method; import cn.hutool.http.Method;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum; import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
import com.alipay.api.AlipayApiException; import com.alipay.api.AlipayApiException;
@ -56,4 +58,8 @@ public class AlipayWapPayClient extends AbstractAlipayPayClient {
reqDTO.getOutTradeNo(), response); reqDTO.getOutTradeNo(), response);
} }
@Override
public PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {
throw new UnsupportedOperationException("支付宝【Wap 网站】不支持转账操作");
}
} }

View File

@ -4,6 +4,8 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig; import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig;
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
@ -64,4 +66,8 @@ public class MockPayClient extends AbstractPayClient<NonePayClientConfig> {
throw new UnsupportedOperationException("模拟支付无支付回调"); throw new UnsupportedOperationException("模拟支付无支付回调");
} }
@Override
protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {
throw new UnsupportedOperationException("待实现");
}
} }

View File

@ -12,6 +12,8 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; 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.order.PayOrderStatusRespEnum;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
@ -425,6 +427,10 @@ public abstract class AbstractWxPayClient extends AbstractPayClient<WxPayClientC
} }
} }
@Override
protected PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {
throw new UnsupportedOperationException("待实现");
}
// ========== 各种工具方法 ========== // ========== 各种工具方法 ==========
static String formatDateV2(LocalDateTime time) { static String formatDateV2(LocalDateTime time) {

View File

@ -28,6 +28,7 @@ public enum PayChannelEnum {
ALIPAY_APP("alipay_app", "支付宝App 支付", AlipayPayClientConfig.class), ALIPAY_APP("alipay_app", "支付宝App 支付", AlipayPayClientConfig.class),
ALIPAY_QR("alipay_qr", "支付宝扫码支付", AlipayPayClientConfig.class), ALIPAY_QR("alipay_qr", "支付宝扫码支付", AlipayPayClientConfig.class),
ALIPAY_BAR("alipay_bar", "支付宝条码支付", AlipayPayClientConfig.class), ALIPAY_BAR("alipay_bar", "支付宝条码支付", AlipayPayClientConfig.class),
ALIPAY_TRANSFER("alipay_transfer", "支付宝转账", AlipayPayClientConfig.class),
MOCK("mock", "模拟支付", NonePayClientConfig.class), MOCK("mock", "模拟支付", NonePayClientConfig.class),

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.framework.pay.core.enums.transfer;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 渠道的转账状态枚举
*
* @author jason
*/
@Getter
@AllArgsConstructor
public enum PayTransferStatusRespEnum {
WAITING(0, "等待转账"),
SUCCESS(10, "转账成功"),
FAILURE(20, "转账失败");
private final Integer status;
private final String name;
}

View File

@ -0,0 +1,36 @@
package cn.iocoder.yudao.framework.pay.core.enums.transfer;
import cn.hutool.core.util.ArrayUtil;
import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 转账类型枚举
*
* @author jason
*/
@AllArgsConstructor
@Getter
public enum PayTransferTypeEnum implements IntArrayValuable {
ALIPAY_BALANCE(1, "支付宝余额"),
WX_BALANCE(2, "微信余额"),
BANK_CARD(3, "银行卡"),
WALLET_BALANCE(4, "钱包余额");
private final Integer type;
private final String name;
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PayTransferTypeEnum::getType).toArray();
@Override
public int[] array() {
return ARRAYS;
}
public static PayTransferTypeEnum valueOf(Integer type) {
return ArrayUtil.firstMatch(item -> item.getType().equals(type), values());
}
}

View File

@ -44,23 +44,21 @@ public interface ErrorCodeConstants {
ErrorCode WALLET_NOT_FOUND = new ErrorCode(1007007000, "用户钱包不存在"); ErrorCode WALLET_NOT_FOUND = new ErrorCode(1007007000, "用户钱包不存在");
ErrorCode WALLET_BALANCE_NOT_ENOUGH = new ErrorCode(1007007001, "钱包余额不足"); ErrorCode WALLET_BALANCE_NOT_ENOUGH = new ErrorCode(1007007001, "钱包余额不足");
ErrorCode WALLET_TRANSACTION_NOT_FOUND = new ErrorCode(1007007002, "未找到对应的钱包交易"); ErrorCode WALLET_TRANSACTION_NOT_FOUND = new ErrorCode(1007007002, "未找到对应的钱包交易");
ErrorCode WALLET_REFUND_AMOUNT_ERROR = new ErrorCode(1007007003, "钱包退款金额不对"); ErrorCode WALLET_REFUND_EXIST = new ErrorCode(1007007003, "已经存在钱包退款");
ErrorCode WALLET_REFUND_EXIST = new ErrorCode(1007007004, "已经存在钱包退款"); ErrorCode WALLET_FREEZE_PRICE_NOT_ENOUGH = new ErrorCode(1007007004, "钱包冻结余额不足");
ErrorCode WALLET_FREEZE_PRICE_NOT_ENOUGH = new ErrorCode(1007007005, "钱包冻结余额不足");
// TODO @jason把钱包充值单独搞个错误码段哈 // ========== 钱包充值模块 1007008000 ==========
ErrorCode WALLET_RECHARGE_NOT_FOUND = new ErrorCode(1007008000, "钱包充值记录不存在");
ErrorCode WALLET_RECHARGE_NOT_FOUND = new ErrorCode(1007007005, "钱包充值记录不存在"); ErrorCode WALLET_RECHARGE_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1007008001, "钱包充值更新支付状态失败,钱包充值记录不是【未支付】状态");
ErrorCode WALLET_RECHARGE_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1007007006, "钱包充值更新支付状态失败,钱包充值记录不是【未支付】状态"); ErrorCode WALLET_RECHARGE_UPDATE_PAID_PAY_ORDER_ID_ERROR = new ErrorCode(1007008002, "钱包充值更新支付状态失败,支付单编号不匹配");
ErrorCode WALLET_RECHARGE_UPDATE_PAID_PAY_ORDER_ID_ERROR = new ErrorCode(1007007007, "钱包充值更新支付状态失败,支付单编号不匹配"); ErrorCode WALLET_RECHARGE_UPDATE_PAID_PAY_ORDER_STATUS_NOT_SUCCESS = new ErrorCode(1007008003, "钱包充值更新支付状态失败,支付单状态不是【支付成功】状态");
ErrorCode WALLET_RECHARGE_UPDATE_PAID_PAY_ORDER_STATUS_NOT_SUCCESS = new ErrorCode(1007007008, "钱包充值更新支付状态失败,支付单状态不是【支付成功】状态"); ErrorCode WALLET_RECHARGE_UPDATE_PAID_PAY_PRICE_NOT_MATCH = new ErrorCode(1007008004, "钱包充值更新支付状态失败,支付单金额不匹配");
ErrorCode WALLET_RECHARGE_UPDATE_PAID_PAY_PRICE_NOT_MATCH = new ErrorCode(1007007009, "钱包充值更新支付状态失败,支付单金额不匹配"); ErrorCode WALLET_RECHARGE_REFUND_FAIL_NOT_PAID = new ErrorCode(1007008005, "钱包发起退款失败,钱包充值订单未支付");
ErrorCode WALLET_RECHARGE_REFUND_FAIL_NOT_PAID = new ErrorCode(1007900010, "钱包发起退款失败,钱包充值订单未支付"); ErrorCode WALLET_RECHARGE_REFUND_FAIL_REFUNDED = new ErrorCode(1007008006, "钱包发起退款失败,钱包充值订单已退款");
ErrorCode WALLET_RECHARGE_REFUND_FAIL_REFUNDED = new ErrorCode(1007900011, "钱包发起退款失败,钱包充值订单已退款"); ErrorCode WALLET_RECHARGE_REFUND_BALANCE_NOT_ENOUGH = new ErrorCode(1007008007, "钱包发起退款失败,钱包余额不足");
ErrorCode WALLET_RECHARGE_REFUND_BALANCE_NOT_ENOUGH = new ErrorCode(1007900012, "钱包发起退款失败,钱包余额不足"); ErrorCode WALLET_RECHARGE_REFUND_FAIL_REFUND_ORDER_ID_ERROR = new ErrorCode(1007008008, "钱包退款更新失败,钱包退款单编号不匹配");
ErrorCode WALLET_RECHARGE_REFUND_FAIL_REFUND_ORDER_ID_ERROR = new ErrorCode(1007900013, "钱包退款更新失败,钱包退款单编号不匹配"); ErrorCode WALLET_RECHARGE_REFUND_FAIL_REFUND_NOT_FOUND = new ErrorCode(1007008009, "钱包退款更新失败,退款订单不存在");
ErrorCode WALLET_RECHARGE_REFUND_FAIL_REFUND_NOT_FOUND = new ErrorCode(1007900014, "钱包退款更新失败,退款订单不存在"); ErrorCode WALLET_RECHARGE_REFUND_FAIL_REFUND_PRICE_NOT_MATCH = new ErrorCode(1007008010, "钱包退款更新失败,退款单金额不匹配");
ErrorCode WALLET_RECHARGE_REFUND_FAIL_REFUND_PRICE_NOT_MATCH = new ErrorCode(1007900015, "钱包退款更新失败,退款单金额不匹配");
// ========== 示例订单 1007900000 ========== // ========== 示例订单 1007900000 ==========
ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1007900000, "示例订单不存在"); ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1007900000, "示例订单不存在");
ErrorCode DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1007900001, "示例订单更新支付状态失败,订单不是【未支付】状态"); ErrorCode DEMO_ORDER_UPDATE_PAID_STATUS_NOT_UNPAID = new ErrorCode(1007900001, "示例订单更新支付状态失败,订单不是【未支付】状态");

View File

@ -8,6 +8,8 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.transfer.PayTransferUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig; import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig;
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
@ -174,4 +176,8 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> {
throw new IllegalStateException(String.format("支付退款单[%s] 状态不正确", outRefundNo)); throw new IllegalStateException(String.format("支付退款单[%s] 状态不正确", outRefundNo));
} }
@Override
public PayTransferRespDTO doUnifiedTransfer(PayTransferUnifiedReqDTO reqDTO) {
throw new UnsupportedOperationException("待实现");
}
} }

View File

@ -82,7 +82,7 @@ public class PayWalletServiceImpl implements PayWalletService {
throw exception(REFUND_NOT_FOUND); throw exception(REFUND_NOT_FOUND);
} }
// 1.2 校验是否可以退款 // 1.2 校验是否可以退款
Long walletId = validateWalletCanRefund(payRefund.getId(), payRefund.getChannelOrderNo(), refundPrice); Long walletId = validateWalletCanRefund(payRefund.getId(), payRefund.getChannelOrderNo());
PayWalletDO wallet = walletMapper.selectById(walletId); PayWalletDO wallet = walletMapper.selectById(walletId);
Assert.notNull(wallet, "钱包 {} 不存在", walletId); Assert.notNull(wallet, "钱包 {} 不存在", walletId);
@ -96,18 +96,12 @@ public class PayWalletServiceImpl implements PayWalletService {
* @param refundId 支付退款单 id * @param refundId 支付退款单 id
* @param walletPayNo 钱包支付 no * @param walletPayNo 钱包支付 no
*/ */
private Long validateWalletCanRefund(Long refundId, String walletPayNo, Integer refundPrice) { private Long validateWalletCanRefund(Long refundId, String walletPayNo) {
// 1. 校验钱包支付交易存在 // 1. 校验钱包支付交易存在
PayWalletTransactionDO walletTransaction = walletTransactionService.getWalletTransactionByNo(walletPayNo); PayWalletTransactionDO walletTransaction = walletTransactionService.getWalletTransactionByNo(walletPayNo);
if (walletTransaction == null) { if (walletTransaction == null) {
throw exception(WALLET_TRANSACTION_NOT_FOUND); throw exception(WALLET_TRANSACTION_NOT_FOUND);
} }
// 原来的支付金额
// TODO @jason应该允许多次退款哈
int amount = - walletTransaction.getPrice();
if (refundPrice != amount) {
throw exception(WALLET_REFUND_AMOUNT_ERROR);
}
PayWalletTransactionDO refundTransaction = walletTransactionService.getWalletTransaction( PayWalletTransactionDO refundTransaction = walletTransactionService.getWalletTransaction(
String.valueOf(refundId), PAYMENT_REFUND); String.valueOf(refundId), PAYMENT_REFUND);
if (refundTransaction != null) { if (refundTransaction != null) {