转账 - 动态收款人字段修改

This commit is contained in:
jason
2023-10-24 08:44:30 +08:00
parent 9095394fed
commit 86598dd177
9 changed files with 211 additions and 102 deletions

View File

@ -1,14 +1,15 @@
package cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer;
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
import cn.iocoder.yudao.framework.common.validation.InEnum;
import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import javax.validation.Validator;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Map;
/**
* @author jason
@ -22,13 +23,50 @@ public class PayDemoTransferCreateReqVO {
@InEnum(PayTransferTypeEnum.class)
private Integer type;
@Schema(description = "转账金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
@NotNull(message = "转账金额不能为空")
@Min(value = 1, message = "转账金额必须大于零")
private Integer price;
// TODO @jason感觉这个动态字段晚点改可能要讨论下怎么搞好
@Schema(description = "收款方信息", requiredMode = Schema.RequiredMode.REQUIRED, example = "{'ALIPAY_LOGON_ID':'xxxx'}")
@NotEmpty(message = "收款方信息不能为空")
private Map<String, String> payeeInfo;
// ========== 支付宝,微信转账相关字段 ==========
@Schema(description = "支付宝登录号,支持邮箱和手机号格式", example = "test1@@sandbox.com")
@NotBlank(message = "支付宝登录号不能为空", groups = {Alipay.class})
private String alipayLogonId;
@Schema(description = "支付宝账号名称", example = "test1")
@NotBlank(message = "支付宝登录号不能为空", groups = {Alipay.class})
private String alipayAccountName;
// ========== 微信转账相关字段 ==========
@Schema(description = "微信 openId", example = "oLefc4g5Gxx")
@NotBlank(message = "微信 openId 不能为空", groups = {WxPay.class})
private String openid;
@Schema(description = "微信账号名称", example = "oLefc4g5Gjxxxxxx")
private String wxAccountName;
// ========== 转账到银行卡和钱包相关字段 待补充 ==========
public interface WxPay {
}
public interface Alipay {
}
public void validate(Validator validator) {
PayTransferTypeEnum transferType = PayTransferTypeEnum.typeOf(type);
switch (transferType) {
case ALIPAY_BALANCE: {
ValidationUtils.validate(validator, this, Alipay.class);
break;
}
case WX_BALANCE: {
ValidationUtils.validate(validator, this, WxPay.class);
break;
}
default: {
throw new UnsupportedOperationException("待实现");
}
}
}
}

View File

@ -0,0 +1,17 @@
package cn.iocoder.yudao.module.pay.convert.demo;
import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO;
import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoTransferDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* @author jason
*/
@Mapper
public interface PayDemoTransferConvert {
PayDemoTransferConvert INSTANCE = Mappers.getMapper(PayDemoTransferConvert.class);
PayDemoTransferDO convert(PayDemoTransferCreateReqVO bean);
}

View File

@ -1,15 +1,13 @@
package cn.iocoder.yudao.module.pay.dal.dataobject.demo;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.Map;
/**
* 示例转账订单
@ -39,15 +37,30 @@ public class PayDemoTransferDO extends BaseDO {
/**
* 转账类型
* <p>
* 枚举 {@link PayTransferTypeEnum}
*/
private Integer type;
// TODO @jason要不字段还是弄成正确的平铺开
/**
* 收款人信息,不同类型和渠道不同
* 支付宝登录号
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private Map<String, String> payeeInfo;
private String alipayLogonId;
/**
* 支付宝账号名称
*/
private String alipayAccountName;
/**
* 微信 openId
*/
private String openid;
/**
* 微信账号名称
*/
private String wxAccountName;
/**
* 转账状态

View File

@ -31,33 +31,35 @@ public class PayTransferDO extends BaseDO {
*/
@TableId
private Long id;
/**
* 转账单号
*
*/
private String no;
/**
* 应用编号
*
* 关联 {@link PayAppDO#getId()}
*/
private Long appId;
/**
* 转账渠道编号
*
* 关联 {@link PayChannelDO#getId()}
*/
private Long channelId;
/**
* 转账渠道编码
*
* 枚举 {@link PayChannelEnum}
*/
private String channelCode;
/**
* 类型
*
* 枚举 {@link PayTransferTypeEnum}
*/
private Integer type;
// ========== 商户相关字段 ==========
/**
* 商户订单编号
*
@ -65,12 +67,20 @@ public class PayTransferDO extends BaseDO {
*/
private String merchantOrderId;
// ========== 转账相关字段 ==========
/**
* 类型
*
* 枚举 {@link PayTransferTypeEnum}
*/
private Integer type;
/**
* 转账标题
*/
private String subject;
// ========== 转账相关字段 ==========
/**
* 转账金额,单位:分
*/
@ -81,26 +91,70 @@ public class PayTransferDO extends BaseDO {
* 枚举 {@link PayTransferStatusRespEnum}
*/
private Integer status;
/**
* 订单转账成功时间
*/
private LocalDateTime successTime;
// ========== 支付宝转账相关字段 ==========
/**
* 转账成功的转账拓展单编
*
* 关联 {@link PayTransferExtensionDO#getId()}
* 支付宝登录
*/
private Long extensionId;
private String alipayLogonId;
/**
* 转账成功的转账拓展单号
*
* 关联 {@link PayTransferExtensionDO#getNo()}
* 支付宝账号名称
*/
private String no;
private String alipayAccountName;
// ========== 微信转账相关字段 ==========
/**
* 收款人信息,不同类型和渠道不同
* 微信 openId
*/
private String openid;
/**
* 微信账号名称
*/
private String wxAccountName;
// ========== 其它字段 ==========
/**
* 异步通知地址
*/
private String notifyUrl;
/**
* 用户 IP
*/
private String userIp;
/**
* 渠道的额外参数
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private Map<String, String> payeeInfo;
private Map<String, String> channelExtras;
/**
* 渠道转账单号
*/
private String channelTransferNo;
/**
* 调用渠道的错误码
*/
private String channelErrorCode;
/**
* 调用渠道的错误提示
*/
private String channelErrorMsg;
/**
* 渠道的同步/异步通知的内容
*
*/
private String channelNotifyData;
}

View File

@ -1,10 +1,7 @@
package cn.iocoder.yudao.module.pay.service.demo;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum;
import cn.iocoder.yudao.module.pay.controller.admin.demo.vo.transfer.PayDemoTransferCreateReqVO;
import cn.iocoder.yudao.module.pay.convert.transfer.PayTransferConvert;
import cn.iocoder.yudao.module.pay.convert.demo.PayDemoTransferConvert;
import cn.iocoder.yudao.module.pay.dal.dataobject.demo.PayDemoTransferDO;
import cn.iocoder.yudao.module.pay.dal.mysql.demo.PayDemoTransferMapper;
import cn.iocoder.yudao.module.pay.service.transfer.PayTransferService;
@ -14,12 +11,8 @@ import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Map;
import javax.validation.Validator;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.pay.core.enums.transfer.PayTransferTypeEnum.*;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_TRANSFER_ALIPAY_ACCOUNT_NAME_IS_EMPTY;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.PAY_TRANSFER_ALIPAY_LOGIN_ID_IS_EMPTY;
import static cn.iocoder.yudao.module.pay.enums.transfer.PayTransferStatusEnum.WAITING;
/**
@ -41,49 +34,18 @@ public class PayDemoTransferServiceImpl implements PayDemoTransferService {
private PayDemoTransferMapper demoTransferMapper;
@Resource
private PayTransferService transferService;
@Resource
private Validator validator;
@Override
@Transactional(rollbackFor = Exception.class)
public Long createDemoTransfer(Long userId, @Valid PayDemoTransferCreateReqVO vo) {
// 1 校验收款账号
validatePayeeInfo(vo.getType(), vo.getPayeeInfo());
// 1 校验参数
vo.validate(validator);
// 2 保存示例转账业务表
PayDemoTransferDO demoTransfer = new PayDemoTransferDO().setUserId(userId).setType(vo.getType())
.setPrice(vo.getPrice()).setPayeeInfo(vo.getPayeeInfo())
.setTransferStatus(WAITING.getStatus());
PayDemoTransferDO demoTransfer = PayDemoTransferConvert.INSTANCE.convert(vo)
.setUserId(userId).setTransferStatus(WAITING.getStatus());
demoTransferMapper.insert(demoTransfer);
// 3.1 创建转账单
Long transferId = transferService.createTransfer(PayTransferConvert.INSTANCE.convert(vo)
.setAppId(TRANSFER_APP_ID).setTitle("示例转账")
.setMerchantOrderId(String.valueOf(demoTransfer.getId())));
// 3.2 更新转账单编号
demoTransferMapper.updateById(new PayDemoTransferDO().setId(demoTransfer.getId())
.setPayTransferId(transferId));
return demoTransfer.getId();
}
// TODO @jason可以参考 AppBrokerageWithdrawCreateReqVO 搞下字段哈,进行校验
// @jason payeeinfo 字段确定改一下
private void validatePayeeInfo(Integer transferType, Map<String, String> payeeInfo) {
PayTransferTypeEnum transferTypeEnum = typeOf(transferType);
switch (transferTypeEnum) {
case ALIPAY_BALANCE: {
if (StrUtil.isEmpty(MapUtil.getStr(payeeInfo, ALIPAY_LOGON_ID))) {
throw exception(PAY_TRANSFER_ALIPAY_LOGIN_ID_IS_EMPTY);
}
if (StrUtil.isEmpty(MapUtil.getStr(payeeInfo, ALIPAY_ACCOUNT_NAME))) {
throw exception(PAY_TRANSFER_ALIPAY_ACCOUNT_NAME_IS_EMPTY);
}
break;
}
case WX_BALANCE:
case BANK_CARD:
case WALLET_BALANCE: {
throw new UnsupportedOperationException("待实现");
}
}
}
}

View File

@ -28,7 +28,6 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.Objects;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
@ -80,7 +79,7 @@ public class PayTransferServiceImpl implements PayTransferService {
PayTransferUnifiedReqDTO transferUnifiedReq = new PayTransferUnifiedReqDTO()
.setOutTransferNo(transferExtension.getNo()).setPrice(transfer.getPrice())
.setType(transfer.getType()).setTitle(transfer.getSubject())
.setPayeeInfo(transfer.getPayeeInfo()).setUserIp(userIp)
.setUserIp(userIp)
.setChannelExtras(reqVO.getChannelExtras());
PayTransferRespDTO unifiedTransferResp = client.unifiedTransfer(transferUnifiedReq);
@ -139,10 +138,7 @@ public class PayTransferServiceImpl implements PayTransferService {
if (transfer == null) {
throw exception(PAY_TRANSFER_NOT_FOUND);
}
if (isSuccess(transfer.getStatus()) && Objects.equals(transfer.getExtensionId(), transferExtension.getId())) {
log.info("[updateTransferSuccess][transfer({}) 已经是已转账,无需更新]", transfer.getId());
return true;
}
if (!isPendingStatus(transfer.getStatus())) {
throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING);
}
@ -151,7 +147,7 @@ public class PayTransferServiceImpl implements PayTransferService {
CollUtil.newArrayList(WAITING.getStatus(), IN_PROGRESS.getStatus()),
new PayTransferDO().setStatus(SUCCESS.getStatus()).setSuccessTime(notify.getSuccessTime())
.setChannelId(channel.getId()).setChannelCode(channel.getCode())
.setExtensionId(transferExtension.getId()).setNo(transferExtension.getNo()));
.setNo(transferExtension.getNo()));
if (updateCounts == 0) {
throw exception(PAY_TRANSFER_STATUS_IS_NOT_PENDING);
}