钱包 review DO 类修改

This commit is contained in:
jason 2023-09-04 14:54:38 +08:00
parent 91b03e7c93
commit cc4c924717
9 changed files with 74 additions and 79 deletions

View File

@ -1,5 +1,5 @@
-- ---------------------------- -- ----------------------------
-- 支付-钱包表 -- 会员钱包表
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `pay_wallet`; DROP TABLE IF EXISTS `pay_wallet`;
CREATE TABLE `pay_wallet` CREATE TABLE `pay_wallet`
@ -17,28 +17,27 @@ CREATE TABLE `pay_wallet`
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB COMMENT='支付钱包表'; ) ENGINE=InnoDB COMMENT='会员钱包表';
-- ---------------------------- -- ----------------------------
-- 支付- 钱包余额明细 -- 会员钱包流水
-- ---------------------------- -- ----------------------------
DROP TABLE IF EXISTS `pay_wallet_transaction`; DROP TABLE IF EXISTS `pay_wallet_transaction`;
CREATE TABLE `pay_wallet_transaction` CREATE TABLE `pay_wallet_transaction`
( (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号', `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
`wallet_id` bigint NOT NULL COMMENT '会员钱包 id', `wallet_id` bigint NOT NULL COMMENT '会员钱包 id',
`biz_type` tinyint NOT NULL COMMENT '关联类型', `biz_type` tinyint NOT NULL COMMENT '关联类型',
`biz_id` bigint NOT NULL COMMENT '关联业务编号', `biz_id` varchar(64) NOT NULL COMMENT '关联业务编号',
`no` varchar(64) NOT NULL COMMENT '流水号', `no` varchar(64) NOT NULL COMMENT '流水号',
`description` varchar(255) COMMENT '操作说明', `title` varchar(128) NOT NULL COMMENT '流水标题',
`amount` int NOT NULL COMMENT '交易金额, 单位分', `price` int NOT NULL COMMENT '交易金额, 单位分',
`balance` int NOT NULL COMMENT '余额, 单位分', `balance` int NOT NULL COMMENT '余额, 单位分',
`transaction_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '交易时间', `creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
`deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
`tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB COMMENT='支付钱包余额明细'; ) ENGINE=InnoDB COMMENT='会员钱包流水';

View File

@ -37,7 +37,7 @@ public class AppPayWalletController {
@Operation(summary = "获取钱包") @Operation(summary = "获取钱包")
@PreAuthenticated @PreAuthenticated
public CommonResult<AppPayWalletRespVO> getPayWallet() { public CommonResult<AppPayWalletRespVO> getPayWallet() {
PayWalletDO wallet = payWalletService.getPayWallet(getLoginUserId(), UserTypeEnum.MEMBER.getValue()); PayWalletDO wallet = payWalletService.getOrCreatePayWallet(getLoginUserId(), UserTypeEnum.MEMBER.getValue());
return success(PayWalletConvert.INSTANCE.convert(wallet)); return success(PayWalletConvert.INSTANCE.convert(wallet));
} }

View File

@ -15,9 +15,6 @@ public class AppPayWalletTransactionRespVO {
@Schema(description = "业务分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") @Schema(description = "业务分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer bizType; private Integer bizType;
@Schema(description = "交易时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
private LocalDateTime transactionTime;
@Schema(description = "交易金额,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") @Schema(description = "交易金额,单位分", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
private Long price; private Long price;

View File

@ -7,8 +7,6 @@ import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data; import lombok.Data;
import java.time.LocalDateTime;
/** /**
* 会员钱包流水 DO * 会员钱包流水 DO
* *
@ -24,6 +22,7 @@ public class PayWalletTransactionDO extends BaseDO {
*/ */
@TableId @TableId
private Long id; private Long id;
/** /**
* 流水号 * 流水号
*/ */
@ -42,34 +41,26 @@ public class PayWalletTransactionDO extends BaseDO {
* 枚举 {@link PayWalletBizTypeEnum#getType()} * 枚举 {@link PayWalletBizTypeEnum#getType()}
*/ */
private Integer bizType; private Integer bizType;
// TODO @jason使用 string因为可能有业务是 string 接入哈
/** /**
* 关联业务编号 * 关联业务编号
*/ */
private Long bizId; private String bizId;
// TODO @jason想了下改成 title流水标题因为账户明细那会看到这个
/** /**
* 附加说明 * 流水说明
*/ */
private String description; private String title;
// TODO @jason使用 price 项目里金额都是用这个为主
/** /**
* 交易金额单位分 * 交易金额单位分
* *
* 正值表示余额增加负值表示余额减少 * 正值表示余额增加负值表示余额减少
*/ */
private Integer amount; private Integer price;
/** /**
* 交易后余额单位分 * 交易后余额单位分
*/ */
private Integer balance; private Integer balance;
// TODO @jason使用 createTime 就够啦
/**
* 交易时间
*/
private LocalDateTime transactionTime;
} }

View File

@ -18,9 +18,9 @@ public interface PayWalletTransactionMapper extends BaseMapperX<PayWalletTransac
LambdaQueryWrapperX<PayWalletTransactionDO> query = new LambdaQueryWrapperX<PayWalletTransactionDO>() LambdaQueryWrapperX<PayWalletTransactionDO> query = new LambdaQueryWrapperX<PayWalletTransactionDO>()
.eq(PayWalletTransactionDO::getWalletId, walletId); .eq(PayWalletTransactionDO::getWalletId, walletId);
if (Objects.equals(pageReqVO.getType(), AppPayWalletTransactionPageReqVO.TYPE_INCOME)) { if (Objects.equals(pageReqVO.getType(), AppPayWalletTransactionPageReqVO.TYPE_INCOME)) {
query.gt(PayWalletTransactionDO::getAmount, 0); query.gt(PayWalletTransactionDO::getPrice, 0);
} else if (Objects.equals(pageReqVO.getType(), AppPayWalletTransactionPageReqVO.TYPE_EXPENSE)) { } else if (Objects.equals(pageReqVO.getType(), AppPayWalletTransactionPageReqVO.TYPE_EXPENSE)) {
query.lt(PayWalletTransactionDO::getAmount, 0); query.lt(PayWalletTransactionDO::getPrice, 0);
} }
query.orderByDesc(PayWalletTransactionDO::getId); query.orderByDesc(PayWalletTransactionDO::getId);
return selectPage(pageReqVO, query); return selectPage(pageReqVO, query);

View File

@ -50,7 +50,7 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> {
PayWalletTransactionDO transaction = wallService.pay(Long.valueOf(userId), Integer.valueOf(userType), PayWalletTransactionDO transaction = wallService.pay(Long.valueOf(userId), Integer.valueOf(userType),
reqDTO.getOutTradeNo(), reqDTO.getPrice()); reqDTO.getOutTradeNo(), reqDTO.getPrice());
return PayOrderRespDTO.successOf(transaction.getNo(), transaction.getCreator(), return PayOrderRespDTO.successOf(transaction.getNo(), transaction.getCreator(),
transaction.getTransactionTime(), transaction.getCreateTime(),
reqDTO.getOutTradeNo(), transaction); reqDTO.getOutTradeNo(), transaction);
} catch (Throwable ex) { } catch (Throwable ex) {
log.error("[doUnifiedOrder] 失败", ex); log.error("[doUnifiedOrder] 失败", ex);
@ -81,7 +81,7 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> {
try { try {
PayWalletTransactionDO payWalletTransaction = wallService.refund(reqDTO.getOutRefundNo(), PayWalletTransactionDO payWalletTransaction = wallService.refund(reqDTO.getOutRefundNo(),
reqDTO.getRefundPrice(), reqDTO.getReason()); reqDTO.getRefundPrice(), reqDTO.getReason());
return PayRefundRespDTO.successOf(payWalletTransaction.getNo(), payWalletTransaction.getTransactionTime(), return PayRefundRespDTO.successOf(payWalletTransaction.getNo(), payWalletTransaction.getCreateTime(),
reqDTO.getOutRefundNo(), payWalletTransaction); reqDTO.getOutRefundNo(), payWalletTransaction);
} catch (Throwable ex) { } catch (Throwable ex) {
log.error("[doUnifiedRefund] 失败", ex); log.error("[doUnifiedRefund] 失败", ex);

View File

@ -11,18 +11,19 @@ import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
*/ */
public interface PayWalletService { public interface PayWalletService {
// TODO @jason改成 getOrCreateWallet因为目前解耦用户注册时不会创建钱包需要这里兜底处理
/** /**
* 获取钱包信息 * 获取钱包信息如果不存在创建钱包由于用户注册时候不会创建钱包
* *
* @param userId 用户编号 * @param userId 用户编号
* @param userType 用户类型 * @param userType 用户类型
*/ */
PayWalletDO getPayWallet(Long userId, Integer userType); PayWalletDO getOrCreatePayWallet(Long userId, Integer userType);
/** /**
* 钱包订单支付 * 钱包订单支付
* *
* @param userId 用户 id
* @param userType 用户类型
* @param outTradeNo 外部订单号 * @param outTradeNo 外部订单号
* @param price 金额 * @param price 金额
*/ */

View File

@ -57,8 +57,19 @@ public class PayWalletServiceImpl implements PayWalletService {
private PayRefundService payRefundService; private PayRefundService payRefundService;
@Override @Override
public PayWalletDO getPayWallet(Long userId, Integer userType) { public PayWalletDO getOrCreatePayWallet(Long userId, Integer userType) {
return payWalletMapper.selectByUserIdAndType(userId, userType); PayWalletDO payWalletDO = payWalletMapper.selectByUserIdAndType(userId, userType);
if (payWalletDO == null) {
payWalletDO = new PayWalletDO();
payWalletDO.setUserId(userId);
payWalletDO.setUserType(userType);
payWalletDO.setBalance(0);
payWalletDO.setTotalExpense(0L);
payWalletDO.setTotalRecharge(0L);
payWalletDO.setCreateTime(LocalDateTime.now());
payWalletMapper.insert(payWalletDO);
}
return payWalletDO;
} }
@ -76,8 +87,8 @@ public class PayWalletServiceImpl implements PayWalletService {
@Override @Override
public PayWalletTransactionDO reduceWalletBalance(Long userId, Integer userType, public PayWalletTransactionDO reduceWalletBalance(Long userId, Integer userType,
Long bizId, PayWalletBizTypeEnum bizType, Integer price) { Long bizId, PayWalletBizTypeEnum bizType, Integer price) {
// 1.1 判断钱包是否有效 // 1.1 获取钱包
PayWalletDO payWallet = validatePayWallet(userId, userType); PayWalletDO payWallet = getOrCreatePayWallet(userId, userType);
// 1.2 判断余额是否足够 // 1.2 判断余额是否足够
int afterBalance = payWallet.getBalance() - price; int afterBalance = payWallet.getBalance() - price;
if (afterBalance < 0) { if (afterBalance < 0) {
@ -90,12 +101,11 @@ public class PayWalletServiceImpl implements PayWalletService {
if (number == 0) { if (number == 0) {
throw exception(TOO_MANY_REQUESTS); throw exception(TOO_MANY_REQUESTS);
} }
// 2.2 生成钱包流水
// 2.2 生成钱包流水 TODO 根据 bizType 生成 NO String walletNo = generateWalletNo(bizType);
String walletNo = noRedisDAO.generate(WALLET_PAY_NO_PREFIX);
PayWalletTransactionDO walletTransaction = new PayWalletTransactionDO().setWalletId(payWallet.getId()) PayWalletTransactionDO walletTransaction = new PayWalletTransactionDO().setWalletId(payWallet.getId())
.setNo(walletNo).setAmount(-price).setBalance(afterBalance).setTransactionTime(LocalDateTime.now()) .setNo(walletNo).setPrice(-price).setBalance(afterBalance)
.setBizId(bizId).setBizType(bizType.getType()).setDescription(bizType.getDescription()); .setBizId(String.valueOf(bizId)).setBizType(bizType.getType()).setTitle(bizType.getDescription());
payWalletTransactionService.createWalletTransaction(walletTransaction); payWalletTransactionService.createWalletTransaction(walletTransaction);
return walletTransaction; return walletTransaction;
} }
@ -103,8 +113,8 @@ public class PayWalletServiceImpl implements PayWalletService {
@Override @Override
public PayWalletTransactionDO addWalletBalance(Long userId, Integer userType, Long bizId, public PayWalletTransactionDO addWalletBalance(Long userId, Integer userType, Long bizId,
PayWalletBizTypeEnum bizType, Integer price) { PayWalletBizTypeEnum bizType, Integer price) {
// 1.1 判断钱包是否有效 // 1.1 获取钱包
PayWalletDO payWallet = validatePayWallet(userId, userType); PayWalletDO payWallet = getOrCreatePayWallet(userId, userType);
// 2.1 增加余额 // 2.1 增加余额
int number = payWalletMapper.updateWhenIncBalance(bizType, payWallet.getBalance(), payWallet.getTotalRecharge(), int number = payWalletMapper.updateWhenIncBalance(bizType, payWallet.getBalance(), payWallet.getTotalRecharge(),
@ -113,27 +123,31 @@ public class PayWalletServiceImpl implements PayWalletService {
throw exception(TOO_MANY_REQUESTS); throw exception(TOO_MANY_REQUESTS);
} }
// 2.2 生成钱包流水 TODO 根据 bizType 生成 NO // 2.2 生成钱包流水
String walletNo = noRedisDAO.generate(WALLET_REFUND_NO_PREFIX); String walletNo = generateWalletNo(bizType);
PayWalletTransactionDO newWalletTransaction = new PayWalletTransactionDO().setWalletId(payWallet.getId()) PayWalletTransactionDO newWalletTransaction = new PayWalletTransactionDO().setWalletId(payWallet.getId())
.setNo(walletNo).setAmount(price).setBalance(payWallet.getBalance()+price).setTransactionTime(LocalDateTime.now()) .setNo(walletNo).setPrice(price).setBalance(payWallet.getBalance()+price)
.setBizId(bizId).setBizType(bizType.getType()) .setBizId(String.valueOf(bizId)).setBizType(bizType.getType())
.setDescription(bizType.getDescription()); .setTitle(bizType.getDescription());
payWalletTransactionService.createWalletTransaction(newWalletTransaction); payWalletTransactionService.createWalletTransaction(newWalletTransaction);
return newWalletTransaction; return newWalletTransaction;
} }
private String generateWalletNo(PayWalletBizTypeEnum bizType) {
private PayWalletDO validatePayWallet(Long userId, Integer userType) { String no = "";
PayWalletDO payWallet = getPayWallet(userId, userType); switch(bizType){
if (payWallet == null) { case PAYMENT :
log.error("[validatePayWallet] 用户 {} 钱包不存在", userId); no = noRedisDAO.generate(WALLET_PAY_NO_PREFIX);
throw exception(WALLET_NOT_FOUND); break;
case PAYMENT_REFUND :
no = noRedisDAO.generate(WALLET_REFUND_NO_PREFIX);
break;
default :
// TODO 待增加
} }
return payWallet; return no;
} }
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public PayWalletTransactionDO refund(String outRefundNo, Integer refundPrice, String reason) { public PayWalletTransactionDO refund(String outRefundNo, Integer refundPrice, String reason) {
@ -163,7 +177,7 @@ public class PayWalletServiceImpl implements PayWalletService {
throw exception(WALLET_TRANSACTION_NOT_FOUND); throw exception(WALLET_TRANSACTION_NOT_FOUND);
} }
// 原来的支付金额 // 原来的支付金额
int amount = - payWalletTransaction.getAmount(); int amount = - payWalletTransaction.getPrice();
if (refundPrice != amount) { if (refundPrice != amount) {
throw exception(WALLET_REFUND_AMOUNT_ERROR); throw exception(WALLET_REFUND_AMOUNT_ERROR);
} }

View File

@ -11,9 +11,6 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource; import javax.annotation.Resource;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.WALLET_NOT_FOUND;
/** /**
* 钱包流水 Service 实现类 * 钱包流水 Service 实现类
* *
@ -32,11 +29,7 @@ public class PayWalletTransactionServiceImpl implements PayWalletTransactionServ
@Override @Override
public PageResult<PayWalletTransactionDO> getWalletTransactionPage(Long userId, Integer userType, public PageResult<PayWalletTransactionDO> getWalletTransactionPage(Long userId, Integer userType,
AppPayWalletTransactionPageReqVO pageVO) { AppPayWalletTransactionPageReqVO pageVO) {
PayWalletDO wallet = payWalletService.getPayWallet(userId, userType); PayWalletDO wallet = payWalletService.getOrCreatePayWallet(userId, userType);
if (wallet == null) {
log.error("[getWalletTransactionPage][用户({}/{}) 钱包不存在", userId, userType);
throw exception(WALLET_NOT_FOUND);
}
return payWalletTransactionMapper.selectPage(wallet.getId(), pageVO); return payWalletTransactionMapper.selectPage(wallet.getId(), pageVO);
} }