feat 钱包查询

This commit is contained in:
xxm1995
2023-07-24 17:26:44 +08:00
parent 213403cd56
commit d9c2ed9573
12 changed files with 137 additions and 55 deletions

View File

@@ -1,17 +1,18 @@
1.0.1
- 钱包支持多商户和多应用
- 储值卡支持多商户和多应用
- x 钱包支持多商户和多应用
- x 储值卡支持多商户和多应用
- x 拆分网关同步相关代码
- x 记录网关同步记录
- x 重构支付消息通知结构, 支持多种消息中间件
- x 保存各通道的支付单
- 钱包支持设置开通时的默认金额
- 储值卡多卡支付和退款演示
- x 储值卡信息调整
- x 钱包支持设置开通时的默认金额
- x 储值卡多卡支付和退款演示
- x 储值卡批量导入
- x 储值卡多卡退款到单卡, 不传卡号自动设置为默认卡
1.0.2
- 微信V3支付接口
- 支付超时逻辑重构
- 储值卡支持多卡合一
- 储值卡批量导入
- 储值卡信息调整
- 删除应用或商户是做校验, 级联删除对应的支付配置
- 商户关联用户

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -28,4 +28,7 @@ public class WalletConfigDto extends BaseDto {
@Schema(description = "默认余额")
private BigDecimal defaultBalance;
@Schema(description = "备注")
private String remark;
}

View File

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

View File

@@ -27,5 +27,8 @@ public class WalletConfigParam {
@Schema(description = "默认余额")
private BigDecimal defaultBalance;
@Schema(description = "备注")
private String remark;
}