diff --git a/_doc/Task.md b/_doc/Task.md index dcfc7055..73da38ae 100644 --- a/_doc/Task.md +++ b/_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支付接口 - 支付超时逻辑重构 - 储值卡支持多卡合一 -- 储值卡批量导入 +- 储值卡信息调整 - 删除应用或商户是做校验, 级联删除对应的支付配置 +- 商户关联用户 diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/WalletAdminController.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/WalletAdminController.java index 360761c1..6aeae0f9 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/WalletAdminController.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/WalletAdminController.java @@ -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 createWallet(Long userId) { - walletService.createWallet(userId); + public ResResult createWallet(Long userId, String mchCode, String mchAppCode) { + walletService.createWallet(userId,mchCode,mchAppCode); return Res.ok(); } @Operation(summary = "批量开通用户钱包操作") @PostMapping("/createWalletBatch") - public ResResult createWalletBatch(@RequestBody List userIds) { - walletService.createWalletBatch(userIds); + public ResResult createWalletBatch(@RequestBody List 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> page(PageParam pageParam, WalletPayParam param) { + public ResResult> page(PageParam pageParam, WalletQueryParam param) { return Res.ok(walletQueryService.page(pageParam, param)); } diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/WalletController.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/WalletController.java index 89b0efa4..1b8950b4 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/WalletController.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/controller/WalletController.java @@ -24,15 +24,15 @@ public class WalletController { @Operation(summary = "根据用户查询钱包") @GetMapping("/findByUser") - public ResResult findByUser() { - return Res.ok(walletQueryService.findByUser()); + public ResResult findByUser(String mchAppCode) { + return Res.ok(walletQueryService.findByUser(mchAppCode)); } @Operation(summary = "开通用户钱包操作") @PostMapping("/createWallet") - public ResResult createWallet() { + public ResResult createWallet(String mchCode,String mchAppCode) { Long userId = SecurityUtil.getUserId(); - walletService.createWallet(userId); + walletService.createWallet(userId,mchCode,mchAppCode); return Res.ok(); } } diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/dao/WalletManager.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/dao/WalletManager.java index b1117af0..d15d5bea 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/dao/WalletManager.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/dao/WalletManager.java @@ -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 { /** * 用户钱包是否存在 */ - 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 findByUser(Long userId) { - return findByField(Wallet::getUserId, userId); + public Optional findByUser(Long userId,String mchAppCode) { + return lambdaQuery() + .eq(Wallet::getUserId,userId) + .eq(Wallet::getMchAppCode,mchAppCode) + .oneOpt(); } /** * 分页查询 */ - public Page page(PageParam pageParam, WalletPayParam param) { - + public Page page(PageParam pageParam, WalletQueryParam param) { + QueryWrapper wrapper = QueryGenerator.generator(param); Page 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 { Page mpPage = MpUtil.getMpPage(pageParam, UserInfo.class); QueryWrapper 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 { */ public List findExistUserIds(List 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()); } diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/entity/WalletConfig.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/entity/WalletConfig.java index bdc0aec6..5dc7ed18 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/entity/WalletConfig.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/entity/WalletConfig.java @@ -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 { /** 商户编码 */ @@ -43,6 +44,10 @@ public class WalletConfig extends MpBaseEntity implements EntityBaseFunction page(PageParam pageParam, WalletPayParam param) { + public PageResult 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); } } diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/service/WalletService.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/service/WalletService.java index c55dd7a4..f7459568 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/service/WalletService.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/channel/wallet/service/WalletService.java @@ -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 userIds) { - // 查询出 + public void createWalletBatch(List 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 existUserIds = walletManager.findExistUserIds(userIds); userIds.removeAll(existUserIds); List 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 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)) diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/strategy/WalletPayStrategy.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/strategy/WalletPayStrategy.java index 8333b6c9..4fd1ebb9 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/strategy/WalletPayStrategy.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/core/pay/strategy/WalletPayStrategy.java @@ -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(); diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/dto/channel/wallet/WalletConfigDto.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/dto/channel/wallet/WalletConfigDto.java index ae2a8a96..073e35d0 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/dto/channel/wallet/WalletConfigDto.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/dto/channel/wallet/WalletConfigDto.java @@ -28,4 +28,7 @@ public class WalletConfigDto extends BaseDto { @Schema(description = "默认余额") private BigDecimal defaultBalance; + @Schema(description = "备注") + private String remark; + } diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/param/channel/wallet/WalletQueryParam.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/param/channel/wallet/WalletQueryParam.java new file mode 100644 index 00000000..b95d0892 --- /dev/null +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/param/channel/wallet/WalletQueryParam.java @@ -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; +} diff --git a/dax-pay/src/main/java/cn/bootx/platform/daxpay/param/channel/wechat/WalletConfigParam.java b/dax-pay/src/main/java/cn/bootx/platform/daxpay/param/channel/wechat/WalletConfigParam.java index 10bf8b71..d547045a 100644 --- a/dax-pay/src/main/java/cn/bootx/platform/daxpay/param/channel/wechat/WalletConfigParam.java +++ b/dax-pay/src/main/java/cn/bootx/platform/daxpay/param/channel/wechat/WalletConfigParam.java @@ -27,5 +27,8 @@ public class WalletConfigParam { @Schema(description = "默认余额") private BigDecimal defaultBalance; + @Schema(description = "备注") + private String remark; + }