mirror of
https://gitee.com/dromara/dax-pay.git
synced 2025-09-09 13:59:05 +00:00
feat 钱包查询
This commit is contained in:
13
_doc/Task.md
13
_doc/Task.md
@@ -1,17 +1,18 @@
|
||||
1.0.1
|
||||
- 钱包支持多商户和多应用
|
||||
- 储值卡支持多商户和多应用
|
||||
- x 钱包支持多商户和多应用
|
||||
- x 储值卡支持多商户和多应用
|
||||
- x 拆分网关同步相关代码
|
||||
- x 记录网关同步记录
|
||||
- x 重构支付消息通知结构, 支持多种消息中间件
|
||||
- x 保存各通道的支付单
|
||||
- 钱包支持设置开通时的默认金额
|
||||
- 储值卡多卡支付和退款演示
|
||||
- x 储值卡信息调整
|
||||
- x 钱包支持设置开通时的默认金额
|
||||
- x 储值卡多卡支付和退款演示
|
||||
- x 储值卡批量导入
|
||||
- x 储值卡多卡退款到单卡, 不传卡号自动设置为默认卡
|
||||
1.0.2
|
||||
- 微信V3支付接口
|
||||
- 支付超时逻辑重构
|
||||
- 储值卡支持多卡合一
|
||||
- 储值卡批量导入
|
||||
- 储值卡信息调整
|
||||
- 删除应用或商户是做校验, 级联删除对应的支付配置
|
||||
- 商户关联用户
|
||||
|
@@ -5,11 +5,11 @@ import cn.bootx.platform.common.core.rest.PageResult;
|
||||
import cn.bootx.platform.common.core.rest.Res;
|
||||
import cn.bootx.platform.common.core.rest.ResResult;
|
||||
import cn.bootx.platform.common.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.daxpay.core.channel.wallet.service.WalletService;
|
||||
import cn.bootx.platform.daxpay.core.channel.wallet.service.WalletQueryService;
|
||||
import cn.bootx.platform.daxpay.core.channel.wallet.service.WalletService;
|
||||
import cn.bootx.platform.daxpay.dto.channel.wallet.WalletDto;
|
||||
import cn.bootx.platform.daxpay.dto.channel.wallet.WalletInfoDto;
|
||||
import cn.bootx.platform.daxpay.param.channel.wallet.WalletPayParam;
|
||||
import cn.bootx.platform.daxpay.param.channel.wallet.WalletQueryParam;
|
||||
import cn.bootx.platform.daxpay.param.channel.wallet.WalletRechargeParam;
|
||||
import cn.bootx.platform.iam.dto.user.UserInfoDto;
|
||||
import cn.bootx.platform.iam.param.user.UserInfoParam;
|
||||
@@ -38,15 +38,15 @@ public class WalletAdminController {
|
||||
|
||||
@Operation(summary = "开通用户钱包操作")
|
||||
@PostMapping("/createWallet")
|
||||
public ResResult<Void> createWallet(Long userId) {
|
||||
walletService.createWallet(userId);
|
||||
public ResResult<Void> createWallet(Long userId, String mchCode, String mchAppCode) {
|
||||
walletService.createWallet(userId,mchCode,mchAppCode);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "批量开通用户钱包操作")
|
||||
@PostMapping("/createWalletBatch")
|
||||
public ResResult<Void> createWalletBatch(@RequestBody List<Long> userIds) {
|
||||
walletService.createWalletBatch(userIds);
|
||||
public ResResult<Void> createWalletBatch(@RequestBody List<Long> userIds, String mchCode, String mchAppCode) {
|
||||
walletService.createWalletBatch(userIds,mchCode,mchAppCode);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public class WalletAdminController {
|
||||
|
||||
@Operation(summary = "分页")
|
||||
@GetMapping("/page")
|
||||
public ResResult<PageResult<WalletDto>> page(PageParam pageParam, WalletPayParam param) {
|
||||
public ResResult<PageResult<WalletDto>> page(PageParam pageParam, WalletQueryParam param) {
|
||||
return Res.ok(walletQueryService.page(pageParam, param));
|
||||
}
|
||||
|
||||
|
@@ -24,15 +24,15 @@ public class WalletController {
|
||||
|
||||
@Operation(summary = "根据用户查询钱包")
|
||||
@GetMapping("/findByUser")
|
||||
public ResResult<WalletDto> findByUser() {
|
||||
return Res.ok(walletQueryService.findByUser());
|
||||
public ResResult<WalletDto> findByUser(String mchAppCode) {
|
||||
return Res.ok(walletQueryService.findByUser(mchAppCode));
|
||||
}
|
||||
|
||||
@Operation(summary = "开通用户钱包操作")
|
||||
@PostMapping("/createWallet")
|
||||
public ResResult<Void> createWallet() {
|
||||
public ResResult<Void> createWallet(String mchCode,String mchAppCode) {
|
||||
Long userId = SecurityUtil.getUserId();
|
||||
walletService.createWallet(userId);
|
||||
walletService.createWallet(userId,mchCode,mchAppCode);
|
||||
return Res.ok();
|
||||
}
|
||||
}
|
||||
|
@@ -1,11 +1,12 @@
|
||||
package cn.bootx.platform.daxpay.core.channel.wallet.dao;
|
||||
|
||||
import cn.bootx.platform.common.core.rest.param.PageParam;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpIdEntity;
|
||||
import cn.bootx.platform.common.mybatisplus.impl.BaseManager;
|
||||
import cn.bootx.platform.common.mybatisplus.util.MpUtil;
|
||||
import cn.bootx.platform.common.query.generator.QueryGenerator;
|
||||
import cn.bootx.platform.daxpay.core.channel.config.entity.PayChannelConfig;
|
||||
import cn.bootx.platform.daxpay.core.channel.wallet.entity.Wallet;
|
||||
import cn.bootx.platform.daxpay.param.channel.wallet.WalletPayParam;
|
||||
import cn.bootx.platform.daxpay.param.channel.wallet.WalletQueryParam;
|
||||
import cn.bootx.platform.iam.core.user.entity.UserInfo;
|
||||
import cn.bootx.platform.iam.param.user.UserInfoParam;
|
||||
import cn.bootx.platform.starter.auth.util.SecurityUtil;
|
||||
@@ -102,24 +103,32 @@ public class WalletManager extends BaseManager<WalletMapper, Wallet> {
|
||||
/**
|
||||
* 用户钱包是否存在
|
||||
*/
|
||||
public boolean existsByUser(Long userId) {
|
||||
return existedByField(Wallet::getUserId, userId);
|
||||
public boolean existsByUser(Long userId,String mchAppCode) {
|
||||
return lambdaQuery()
|
||||
.eq(Wallet::getUserId,userId)
|
||||
.eq(Wallet::getMchAppCode,mchAppCode)
|
||||
.exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询用户的钱包
|
||||
*/
|
||||
public Optional<Wallet> findByUser(Long userId) {
|
||||
return findByField(Wallet::getUserId, userId);
|
||||
public Optional<Wallet> findByUser(Long userId,String mchAppCode) {
|
||||
return lambdaQuery()
|
||||
.eq(Wallet::getUserId,userId)
|
||||
.eq(Wallet::getMchAppCode,mchAppCode)
|
||||
.oneOpt();
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询
|
||||
*/
|
||||
public Page<Wallet> page(PageParam pageParam, WalletPayParam param) {
|
||||
|
||||
public Page<Wallet> page(PageParam pageParam, WalletQueryParam param) {
|
||||
QueryWrapper<Wallet> wrapper = QueryGenerator.generator(param);
|
||||
Page<Wallet> mpPage = MpUtil.getMpPage(pageParam, Wallet.class);
|
||||
return this.lambdaQuery().orderByDesc(MpIdEntity::getId).page(mpPage);
|
||||
wrapper.select(this.getEntityClass(), MpUtil::excludeBigField)
|
||||
.orderByDesc(MpUtil.getColumnName(PayChannelConfig::getId));
|
||||
return this.page(mpPage, wrapper);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -129,10 +138,10 @@ public class WalletManager extends BaseManager<WalletMapper, Wallet> {
|
||||
Page<UserInfo> mpPage = MpUtil.getMpPage(pageParam, UserInfo.class);
|
||||
QueryWrapper<UserInfo> wrapper = new QueryWrapper<>();
|
||||
wrapper.isNull("w.id")
|
||||
.orderByDesc("w.id")
|
||||
.orderByDesc("w.id")
|
||||
.eq("w.mch_code",mchCode)
|
||||
.like(StrUtil.isNotBlank(userInfoParam.getUsername()), "w.username", userInfoParam.getUsername())
|
||||
.like(StrUtil.isNotBlank(userInfoParam.getName()), "w.name", userInfoParam.getName());
|
||||
.like(StrUtil.isNotBlank(userInfoParam.getUsername()), "w.username", userInfoParam.getUsername())
|
||||
.like(StrUtil.isNotBlank(userInfoParam.getName()), "w.name", userInfoParam.getName());
|
||||
return walletMapper.pageByNotWallet(mpPage, wrapper);
|
||||
}
|
||||
|
||||
@@ -141,12 +150,12 @@ public class WalletManager extends BaseManager<WalletMapper, Wallet> {
|
||||
*/
|
||||
public List<Long> findExistUserIds(List<Long> userIds) {
|
||||
return this.lambdaQuery()
|
||||
.select(Wallet::getUserId)
|
||||
.in(Wallet::getUserId, userIds)
|
||||
.list()
|
||||
.stream()
|
||||
.map(Wallet::getUserId)
|
||||
.collect(Collectors.toList());
|
||||
.select(Wallet::getUserId)
|
||||
.in(Wallet::getUserId, userIds)
|
||||
.list()
|
||||
.stream()
|
||||
.map(Wallet::getUserId)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
}
|
||||
|
||||
|
@@ -7,6 +7,7 @@ import cn.bootx.platform.common.core.function.EntityBaseFunction;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
import cn.bootx.platform.daxpay.core.channel.wallet.convert.WalletConvert;
|
||||
import cn.bootx.platform.daxpay.dto.channel.wallet.WalletConfigDto;
|
||||
import cn.bootx.platform.daxpay.param.channel.wechat.WalletConfigParam;
|
||||
import com.baomidou.mybatisplus.annotation.FieldStrategy;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
@@ -25,7 +26,7 @@ import java.math.BigDecimal;
|
||||
@Data
|
||||
@DbTable(comment = "钱包配置")
|
||||
@Accessors(chain = true)
|
||||
@TableName("pay_wallet")
|
||||
@TableName("pay_wallet_config")
|
||||
public class WalletConfig extends MpBaseEntity implements EntityBaseFunction<WalletConfigDto> {
|
||||
|
||||
/** 商户编码 */
|
||||
@@ -43,6 +44,10 @@ public class WalletConfig extends MpBaseEntity implements EntityBaseFunction<Wal
|
||||
@DbColumn(comment = "默认余额")
|
||||
private BigDecimal defaultBalance;
|
||||
|
||||
/** 备注 */
|
||||
@DbColumn(comment = "备注")
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 转换
|
||||
*/
|
||||
@@ -50,4 +55,8 @@ public class WalletConfig extends MpBaseEntity implements EntityBaseFunction<Wal
|
||||
public WalletConfigDto toDto() {
|
||||
return WalletConvert.CONVERT.convert(this);
|
||||
}
|
||||
|
||||
public static WalletConfig init(WalletConfigParam in){
|
||||
return WalletConvert.CONVERT.convert(in);
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@ package cn.bootx.platform.daxpay.core.channel.wallet.service;
|
||||
|
||||
import cn.bootx.platform.common.core.exception.BizException;
|
||||
import cn.bootx.platform.common.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.daxpay.core.channel.wallet.convert.WalletConvert;
|
||||
import cn.bootx.platform.daxpay.core.channel.wallet.dao.WalletConfigManager;
|
||||
import cn.bootx.platform.daxpay.core.channel.wallet.entity.WalletConfig;
|
||||
import cn.bootx.platform.daxpay.core.merchant.service.MchAppService;
|
||||
@@ -42,7 +41,7 @@ public class WalletConfigService {
|
||||
if (!mchAppService.checkMatch(param.getMchCode(), param.getMchAppCode())) {
|
||||
throw new BizException("应用信息与商户信息不匹配");
|
||||
}
|
||||
WalletConfig walletConfig = WalletConvert.CONVERT.convert(param);
|
||||
WalletConfig walletConfig = WalletConfig.init(param);
|
||||
walletConfigManager.save(walletConfig);
|
||||
}
|
||||
|
||||
|
@@ -10,6 +10,8 @@ import cn.bootx.platform.daxpay.core.channel.wallet.entity.Wallet;
|
||||
import cn.bootx.platform.daxpay.dto.channel.wallet.WalletDto;
|
||||
import cn.bootx.platform.daxpay.dto.channel.wallet.WalletInfoDto;
|
||||
import cn.bootx.platform.daxpay.param.channel.wallet.WalletPayParam;
|
||||
import cn.bootx.platform.daxpay.param.channel.wallet.WalletQueryParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayParam;
|
||||
import cn.bootx.platform.iam.core.user.service.UserQueryService;
|
||||
import cn.bootx.platform.iam.dto.user.UserInfoDto;
|
||||
import cn.bootx.platform.iam.param.user.UserInfoParam;
|
||||
@@ -47,9 +49,9 @@ public class WalletQueryService {
|
||||
/**
|
||||
* 根据用户ID查询钱包
|
||||
*/
|
||||
public WalletDto findByUser() {
|
||||
public WalletDto findByUser(String mchAppCode) {
|
||||
Long userId = SecurityUtil.getUserId();
|
||||
return walletManager.findByUser(userId).map(Wallet::toDto).orElse(null);
|
||||
return walletManager.findByUser(userId,mchAppCode).map(Wallet::toDto).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,7 +69,7 @@ public class WalletQueryService {
|
||||
/**
|
||||
* 查询用户 分页
|
||||
*/
|
||||
public PageResult<WalletDto> page(PageParam pageParam, WalletPayParam param) {
|
||||
public PageResult<WalletDto> page(PageParam pageParam, WalletQueryParam param) {
|
||||
return MpUtil.convert2DtoPageResult(walletManager.page(pageParam, param));
|
||||
}
|
||||
|
||||
@@ -83,21 +85,22 @@ public class WalletQueryService {
|
||||
* 获取钱包, 获取顺序: 1. 显式传入的钱包ID 2. 显式传入的用户ID 3. 从系统中获取到的用户ID
|
||||
*
|
||||
*/
|
||||
public Wallet getWallet(Long walletId,Long userId){
|
||||
public Wallet getWallet(WalletPayParam walletPayParam, PayParam payParam){
|
||||
|
||||
Wallet wallet = null;
|
||||
Long userId = null;
|
||||
// 首先根据钱包ID查询
|
||||
if (Objects.nonNull(walletId)) {
|
||||
wallet = walletManager.findById(walletId).orElseThrow(null);
|
||||
if (Objects.nonNull(walletPayParam.getWalletId())) {
|
||||
wallet = walletManager.findById(walletPayParam.getWalletId()).orElseThrow(null);
|
||||
}
|
||||
if (Objects.nonNull(wallet)){
|
||||
return wallet;
|
||||
}
|
||||
// 根据用户id查询
|
||||
if (Objects.isNull(userId)){
|
||||
if (Objects.isNull(walletPayParam.getUserId())){
|
||||
userId = SecurityUtil.getCurrentUser().map(UserDetail::getId).orElse(null);
|
||||
}
|
||||
return walletManager.findByUser(userId).orElse(null);
|
||||
|
||||
return walletManager.findByUser(userId,payParam.getMchAppCode()).orElse(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -8,7 +8,9 @@ import cn.bootx.platform.daxpay.core.channel.wallet.dao.WalletConfigManager;
|
||||
import cn.bootx.platform.daxpay.core.channel.wallet.dao.WalletLogManager;
|
||||
import cn.bootx.platform.daxpay.core.channel.wallet.dao.WalletManager;
|
||||
import cn.bootx.platform.daxpay.core.channel.wallet.entity.Wallet;
|
||||
import cn.bootx.platform.daxpay.core.channel.wallet.entity.WalletConfig;
|
||||
import cn.bootx.platform.daxpay.core.channel.wallet.entity.WalletLog;
|
||||
import cn.bootx.platform.daxpay.core.merchant.service.MchAppService;
|
||||
import cn.bootx.platform.daxpay.param.channel.wallet.WalletRechargeParam;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -35,18 +37,30 @@ public class WalletService {
|
||||
|
||||
private final WalletLogManager walletLogManager;
|
||||
|
||||
private final MchAppService mchAppService;
|
||||
|
||||
/**
|
||||
* 开通操作 创建
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void createWallet(Long userId) {
|
||||
public void createWallet(Long userId, String mchCode, String mchAppCode) {
|
||||
|
||||
// 是否有管理关系判断
|
||||
if (!mchAppService.checkMatch(mchCode, mchAppCode)) {
|
||||
throw new BizException("应用信息与商户信息不匹配");
|
||||
}
|
||||
|
||||
// 钱包配置
|
||||
BigDecimal defaultBalance = walletConfigManager.findByMchCode(mchAppCode)
|
||||
.map(WalletConfig::getDefaultBalance)
|
||||
.orElse(BigDecimal.ZERO);
|
||||
|
||||
// 判断钱包是否已开通
|
||||
if (walletManager.existsByUser(userId)) {
|
||||
if (walletManager.existsByUser(userId, mchAppCode)) {
|
||||
throw new BizException("钱包已经开通");
|
||||
}
|
||||
Wallet wallet = new Wallet().setUserId(userId)
|
||||
.setBalance(BigDecimal.ZERO)
|
||||
.setBalance(defaultBalance)
|
||||
.setFreezeBalance(BigDecimal.ZERO)
|
||||
.setStatus(WalletCode.STATUS_NORMAL);
|
||||
walletManager.save(wallet);
|
||||
@@ -54,6 +68,7 @@ public class WalletService {
|
||||
WalletLog activeLog = new WalletLog().setWalletId(wallet.getId())
|
||||
.setUserId(wallet.getUserId())
|
||||
.setType(WalletCode.LOG_ACTIVE)
|
||||
.setAmount(defaultBalance)
|
||||
.setRemark("激活钱包")
|
||||
.setOperationSource(WalletCode.OPERATION_SOURCE_USER);
|
||||
walletLogManager.save(activeLog);
|
||||
@@ -63,21 +78,29 @@ public class WalletService {
|
||||
* 批量开通
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void createWalletBatch(List<Long> userIds) {
|
||||
// 查询出
|
||||
public void createWalletBatch(List<Long> userIds,String mchCode, String mchAppCode) {
|
||||
// 是否有管理关系判断
|
||||
if (!mchAppService.checkMatch(mchCode, mchAppCode)) {
|
||||
throw new BizException("应用信息与商户信息不匹配");
|
||||
}
|
||||
// 钱包配置
|
||||
BigDecimal defaultBalance = walletConfigManager.findByMchCode(mchAppCode)
|
||||
.map(WalletConfig::getDefaultBalance)
|
||||
.orElse(BigDecimal.ZERO);
|
||||
// 查询出已经开通钱包的id
|
||||
List<Long> existUserIds = walletManager.findExistUserIds(userIds);
|
||||
userIds.removeAll(existUserIds);
|
||||
List<Wallet> wallets = userIds.stream()
|
||||
.map(userId -> new Wallet().setUserId(userId)
|
||||
.setStatus(WalletCode.STATUS_NORMAL)
|
||||
.setFreezeBalance(BigDecimal.ZERO)
|
||||
.setBalance(BigDecimal.ZERO))
|
||||
.setBalance(defaultBalance))
|
||||
.collect(Collectors.toList());
|
||||
walletManager.saveAll(wallets);
|
||||
List<WalletLog> walletLogs = wallets.stream()
|
||||
.map(wallet -> new WalletLog().setWalletId(wallet.getId())
|
||||
.setUserId(wallet.getUserId())
|
||||
.setAmount(BigDecimal.ZERO)
|
||||
.setAmount(defaultBalance)
|
||||
.setType(WalletCode.LOG_ACTIVE)
|
||||
.setRemark("批量开通钱包")
|
||||
.setOperationSource(WalletCode.OPERATION_SOURCE_ADMIN))
|
||||
|
@@ -63,7 +63,10 @@ public class WalletPayStrategy extends AbsPayStrategy {
|
||||
throw new PayFailureException("支付参数错误");
|
||||
}
|
||||
// 获取钱包
|
||||
this.wallet = walletQueryService.getWallet(walletPayParam.getWalletId(),walletPayParam.getUserId());
|
||||
this.wallet = walletQueryService.getWallet(walletPayParam,getPayParam());
|
||||
if (Objects.isNull(this.wallet)){
|
||||
throw new PayFailureException("钱包不存在");
|
||||
}
|
||||
// 是否被禁用
|
||||
if (Objects.equals(WalletCode.STATUS_FORBIDDEN, this.wallet.getStatus())) {
|
||||
throw new WalletBannedException();
|
||||
|
@@ -28,4 +28,7 @@ public class WalletConfigDto extends BaseDto {
|
||||
@Schema(description = "默认余额")
|
||||
private BigDecimal defaultBalance;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,29 @@
|
||||
package cn.bootx.platform.daxpay.param.channel.wallet;
|
||||
|
||||
import cn.bootx.platform.common.core.annotation.QueryParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* @author xxm
|
||||
* @since 2020/12/8
|
||||
*/
|
||||
@Data
|
||||
@QueryParam(type = QueryParam.CompareTypeEnum.LIKE)
|
||||
@Accessors(chain = true)
|
||||
@Schema(title = "钱包查询参数")
|
||||
public class WalletQueryParam {
|
||||
|
||||
@Schema(description = "钱包ID")
|
||||
private Long walletId;
|
||||
|
||||
@Schema(description = "用户ID")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "商户编码")
|
||||
private String mchCode;
|
||||
|
||||
@Schema(description = "商户应用编码")
|
||||
private String mchAppCode;
|
||||
}
|
@@ -27,5 +27,8 @@ public class WalletConfigParam {
|
||||
@Schema(description = "默认余额")
|
||||
private BigDecimal defaultBalance;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user