From 47ed8e9265a4600a6f9eea391f2e21c8c5dcd1f3 Mon Sep 17 00:00:00 2001 From: bootx Date: Sat, 17 Feb 2024 23:48:02 +0800 Subject: [PATCH] =?UTF-8?q?feat=20=E5=90=8C=E6=AD=A5=E6=94=AF=E4=BB=98?= =?UTF-8?q?=E6=96=B9=E5=BC=8F=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- _doc/Task.md | 2 + .../channel/wallet/WalletController.java | 74 +++++++++++++++++++ .../channel/voucher/dao/VoucherManager.java | 6 ++ .../voucher/service/VoucherService.java | 4 + .../core/channel/wallet/entity/Wallet.java | 2 +- .../wallet/service/WalletQueryService.java | 33 +++++---- .../channel/wallet/service/WalletService.java | 10 +-- .../pay/strategy/WalletPayStrategy.java | 10 +++ .../service/dto/channel/wallet/WalletDto.java | 13 +--- .../channel/wallet/CreateWalletParam.java | 8 ++ ...duceParam.java => WalleteeDductParam.java} | 2 +- 12 files changed, 136 insertions(+), 32 deletions(-) create mode 100644 daxpay-single/daxpay-single-admin/src/main/java/cn/bootx/platform/daxpay/admin/controller/channel/wallet/WalletController.java rename daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/param/channel/wallet/{WalletReduceParam.java => WalleteeDductParam.java} (95%) diff --git a/README.md b/README.md index 92acd8f7c..c45e960fd 100644 --- a/README.md +++ b/README.md @@ -123,14 +123,14 @@ QQ扫码加入QQ交流群

- +

## 🍻 鸣谢 感谢 JetBrains 提供的免费开源 License: -[![jetbrains](https://jsd.cdn.zzko.cn/gh/xxm1995/bootx-img@master/bootx/jetbrains.y9o7c2ydh80.webp)](https://www.jetbrains.com/?from=bootx) +[![JetBrains](_doc/images/jetbrains.png)](https://www.jetbrains.com/?from=bootx) 感谢其他提供灵感和思路的开源项目 diff --git a/_doc/Task.md b/_doc/Task.md index 471698bc5..415a66dec 100644 --- a/_doc/Task.md +++ b/_doc/Task.md @@ -4,8 +4,10 @@ - [x] 钱包支付 - [x] 储值卡支付 - [ ] 支付回调通知和退款回调通知功能 +- [ ] 个通道配置支持启用停用校验 - [x] 支付对账的序列化生成器有问题,待platform更新 2.0.x 版本内容 +- [ ] 云闪付接入 - [ ] 退款操作支持重试 - [ ] 增加各类日志记录,例如钱包的各项操作 - [ ] 支付流程也改为先落库后支付情况, 避免极端情况导致掉单 diff --git a/daxpay-single/daxpay-single-admin/src/main/java/cn/bootx/platform/daxpay/admin/controller/channel/wallet/WalletController.java b/daxpay-single/daxpay-single-admin/src/main/java/cn/bootx/platform/daxpay/admin/controller/channel/wallet/WalletController.java new file mode 100644 index 000000000..a32c4f819 --- /dev/null +++ b/daxpay-single/daxpay-single-admin/src/main/java/cn/bootx/platform/daxpay/admin/controller/channel/wallet/WalletController.java @@ -0,0 +1,74 @@ +package cn.bootx.platform.daxpay.admin.controller.channel.wallet; + +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.common.core.util.ValidationUtil; +import cn.bootx.platform.daxpay.service.core.channel.wallet.service.WalletQueryService; +import cn.bootx.platform.daxpay.service.core.channel.wallet.service.WalletService; +import cn.bootx.platform.daxpay.service.dto.channel.wallet.WalletDto; +import cn.bootx.platform.daxpay.service.param.channel.wallet.CreateWalletParam; +import cn.bootx.platform.daxpay.service.param.channel.wallet.WalletQueryParam; +import cn.bootx.platform.daxpay.service.param.channel.wallet.WalletRechargeParam; +import cn.bootx.platform.daxpay.service.param.channel.wallet.WalleteeDductParam; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +/** + * 钱包管理 + * @author xxm + * @since 2024/2/17 + */ +@Tag(name = "钱包管理") +@RestController +@RequestMapping("/wallet") +@RequiredArgsConstructor +public class WalletController { + private final WalletService walletService; + private final WalletQueryService walletQueryService; + + @Operation(summary = "创建钱包") + @PostMapping("/create") + public ResResult create(@RequestBody CreateWalletParam param){ + ValidationUtil.validateParam(param); + walletService.create(param); + return Res.ok(); + } + + @Operation(summary = "充值") + @PostMapping("/recharge") + public ResResult recharge(@RequestBody WalletRechargeParam param){ + ValidationUtil.validateParam(param); + walletService.recharge(param); + return Res.ok(); + } + + @Operation(summary = "扣减") + @PostMapping("/deduct") + public ResResult deduct(@RequestBody WalleteeDductParam param){ + ValidationUtil.validateParam(param); + walletService.deduct(param); + return Res.ok(); + } + + @Operation(summary = "分页") + @GetMapping("/page") + public ResResult> page(PageParam pageParam, WalletQueryParam query){ + return Res.ok(walletQueryService.page(pageParam, query)); + } + + @Operation(summary = "查询详情") + @GetMapping("/findById") + public ResResult findById(Long id){ + return Res.ok(walletQueryService.findById(id)); + } + + @Operation(summary = "判断用户是否开通了钱包") + @GetMapping("/existsByUserId") + public ResResult existsByUserId(String userId){ + return Res.ok(walletQueryService.existsByUserId(userId)); + } +} diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/voucher/dao/VoucherManager.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/voucher/dao/VoucherManager.java index d7ff92827..5669aaf32 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/voucher/dao/VoucherManager.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/voucher/dao/VoucherManager.java @@ -77,4 +77,10 @@ public class VoucherManager extends BaseManager { .update(); } + /** + * 卡号是否存在 + */ + public boolean existsByCardNo(String cardNo) { + return this.existedByField(Voucher::getCardNo, cardNo); + } } diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/voucher/service/VoucherService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/voucher/service/VoucherService.java index b5b273bee..80519d504 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/voucher/service/VoucherService.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/voucher/service/VoucherService.java @@ -34,6 +34,10 @@ public class VoucherService { */ public void voucherImport(VoucherImportParam param){ Voucher voucher = VoucherConvert.CONVERT.convert(param); + // 判断重复 + if (voucherManager.existsByCardNo(param.getCardNo())) { + throw new BizException("钱包已经开通"); + } voucherManager.save(voucher); } diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wallet/entity/Wallet.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wallet/entity/Wallet.java index 999e569e7..ee8cc72d5 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wallet/entity/Wallet.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wallet/entity/Wallet.java @@ -37,7 +37,7 @@ public class Wallet extends MpBaseEntity implements EntityBaseFunction page(PageParam pageParam, WalletQueryParam param) { return MpUtil.convert2DtoPageResult(walletManager.page(pageParam, param)); @@ -51,20 +58,18 @@ public class WalletQueryService { /** - * 获取钱包, 获取顺序: 1. 显式传入的钱包ID 2. 显式传入的用户ID 3. - * + * 获取钱包, 获取顺序: 1. 钱包ID 2. 用户ID */ - public Wallet getWallet(WalletPayParam walletPayParam){ + public Wallet getWallet(WalletPayParam param){ Wallet wallet = null; - // 首先根据钱包ID查询 - if (Objects.nonNull(walletPayParam.getWalletId())) { - wallet = walletManager.findById(walletPayParam.getWalletId()).orElseThrow(null); + if (Objects.nonNull(param.getWalletId())){ + wallet = walletManager.findById(param.getWalletId()).orElseThrow(DataNotExistException::new); } - if (Objects.nonNull(wallet)){ - return wallet; + if (Objects.isNull(wallet)){ + wallet = walletManager.findByUser(param.getUserId()).orElseThrow(DataNotExistException::new); } - return null; + return wallet; } } diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wallet/service/WalletService.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wallet/service/WalletService.java index 3ad5e6912..d0b05ead8 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wallet/service/WalletService.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/channel/wallet/service/WalletService.java @@ -7,7 +7,7 @@ import cn.bootx.platform.daxpay.service.core.channel.wallet.dao.WalletManager; import cn.bootx.platform.daxpay.service.core.channel.wallet.entity.Wallet; import cn.bootx.platform.daxpay.service.param.channel.wallet.CreateWalletParam; import cn.bootx.platform.daxpay.service.param.channel.wallet.WalletRechargeParam; -import cn.bootx.platform.daxpay.service.param.channel.wallet.WalletReduceParam; +import cn.bootx.platform.daxpay.service.param.channel.wallet.WalleteeDductParam; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -16,7 +16,7 @@ import org.springframework.transaction.annotation.Transactional; import java.util.Objects; /** - * + * 钱包管理接口 * @author xxm * @since 2023/6/26 */ @@ -27,10 +27,10 @@ public class WalletService { private final WalletManager walletManager; /** - * 开通钱包操作,默认为启用状态, 不传输余额则默认为0 + * 创建钱包操作,默认为启用状态, 不传输余额则默认为0 */ @Transactional(rollbackFor = Exception.class) - public void createWallet(CreateWalletParam param) { + public void create(CreateWalletParam param) { // 判断钱包是否已开通 if (walletManager.existsByUser(param.getUserId())) { throw new BizException("钱包已经开通"); @@ -85,7 +85,7 @@ public class WalletService { * 余额扣减 */ @Transactional(rollbackFor = Exception.class) - public void reduce(WalletReduceParam param) { + public void deduct(WalleteeDductParam param) { Wallet wallet = null; if (Objects.nonNull(param.getWalletId())){ wallet = walletManager.findById(param.getWalletId()).orElseThrow(DataNotExistException::new); diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/WalletPayStrategy.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/WalletPayStrategy.java index a4c3d5453..6f9699391 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/WalletPayStrategy.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/core/payment/pay/strategy/WalletPayStrategy.java @@ -7,6 +7,8 @@ import cn.bootx.platform.daxpay.exception.waller.WalletLackOfBalanceException; import cn.bootx.platform.daxpay.param.channel.WalletPayParam; import cn.bootx.platform.daxpay.service.code.WalletCode; import cn.bootx.platform.daxpay.service.core.channel.wallet.entity.Wallet; +import cn.bootx.platform.daxpay.service.core.channel.wallet.entity.WalletConfig; +import cn.bootx.platform.daxpay.service.core.channel.wallet.service.WalletConfigService; import cn.bootx.platform.daxpay.service.core.channel.wallet.service.WalletPayService; import cn.bootx.platform.daxpay.service.core.channel.wallet.service.WalletQueryService; import cn.bootx.platform.daxpay.service.func.AbsPayStrategy; @@ -33,6 +35,7 @@ import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROT @RequiredArgsConstructor public class WalletPayStrategy extends AbsPayStrategy { + private final WalletConfigService walletConfigService; private final WalletPayService walletPayService; @@ -40,6 +43,8 @@ public class WalletPayStrategy extends AbsPayStrategy { private Wallet wallet; + private WalletConfig walletConfig; + @Override public PayChannelEnum getChannel() { return PayChannelEnum.WALLET; @@ -60,6 +65,9 @@ public class WalletPayStrategy extends AbsPayStrategy { } catch (JSONException e) { throw new PayFailureException("支付参数错误"); } + + this.walletConfig = walletConfigService.getConfig(); + // 获取钱包 this.wallet = walletQueryService.getWallet(walletPayParam); if (Objects.isNull(this.wallet)){ @@ -69,6 +77,8 @@ public class WalletPayStrategy extends AbsPayStrategy { if (Objects.equals(WalletCode.STATUS_FORBIDDEN, this.wallet.getStatus())) { throw new WalletBannedException(); } + // 判断是否超过限额 + // 判断余额 if (this.wallet.getBalance() < getPayChannelParam().getAmount()) { throw new WalletLackOfBalanceException(); diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/dto/channel/wallet/WalletDto.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/dto/channel/wallet/WalletDto.java index e16dcb57b..955a1cb51 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/dto/channel/wallet/WalletDto.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/dto/channel/wallet/WalletDto.java @@ -21,17 +21,12 @@ public class WalletDto extends BaseDto implements Serializable { private static final long serialVersionUID = -1563719305334334625L; - @Schema(description = "ID,钱包的唯一标识") - private Long id; - @Schema(description = "钱包关联的账号ID") - private Long userId; + private String userId; - @Schema(description = "商户编码") - private String mchCode; - - @Schema(description = "商户应用编码") - private String mchAppCode; + /** 钱包名称 */ + @Schema(description = "钱包名称") + private String name; @Schema(description = "钱包余额") private BigDecimal balance; diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/param/channel/wallet/CreateWalletParam.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/param/channel/wallet/CreateWalletParam.java index 995e7a654..9b27e9f66 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/param/channel/wallet/CreateWalletParam.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/param/channel/wallet/CreateWalletParam.java @@ -4,6 +4,10 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.experimental.Accessors; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + /** * 开通钱包参数 * @author xxm @@ -15,12 +19,16 @@ import lombok.experimental.Accessors; public class CreateWalletParam { @Schema(description = "用户id") + @NotBlank(message = "用户ID不可为空") private String userId; @Schema(description = "钱包名称") + @NotBlank(message = "钱包名称不可为空") private String name; @Schema(description = "钱包金额") + @NotNull(message = "钱包金额不可为空") + @Min(value = 0, message = "钱包金额不可以低于0") private Integer balance; } diff --git a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/param/channel/wallet/WalletReduceParam.java b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/param/channel/wallet/WalleteeDductParam.java similarity index 95% rename from daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/param/channel/wallet/WalletReduceParam.java rename to daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/param/channel/wallet/WalleteeDductParam.java index 978994388..f3fa0dfa9 100644 --- a/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/param/channel/wallet/WalletReduceParam.java +++ b/daxpay-single/daxpay-single-service/src/main/java/cn/bootx/platform/daxpay/service/param/channel/wallet/WalleteeDductParam.java @@ -15,7 +15,7 @@ import javax.validation.constraints.NotNull; @Data @Accessors(chain = true) @Schema(title = "钱包扣减参数") -public class WalletReduceParam { +public class WalleteeDductParam { @Schema(description = "钱包ID")