mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-10 14:56:06 +08:00
feat 钱包支持预冻结额度操作, 新增个人钱包, 储值卡调试
This commit is contained in:
@@ -9,7 +9,6 @@
|
||||
<version>1.3.0</version>
|
||||
</parent>
|
||||
|
||||
<groupId>cn.bootx.platform</groupId>
|
||||
<artifactId>dax-pay</artifactId>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -20,6 +20,9 @@ public interface PayWayExtraCode {
|
||||
/** 钱包ID */
|
||||
String WALLET_ID = "wallet_id";
|
||||
|
||||
/** 用户ID */
|
||||
String USER_ID = "user_id";
|
||||
|
||||
/** 同步通知路径 支付完成跳转的页面地址 */
|
||||
String RETURN_URL = "return_url";
|
||||
|
||||
|
||||
@@ -9,38 +9,38 @@ package cn.bootx.platform.daxpay.code.paymodel;
|
||||
public interface VoucherCode {
|
||||
|
||||
/**
|
||||
* 状态-启用
|
||||
* 状态-正常
|
||||
*/
|
||||
int STATUS_NORMAL = 1;
|
||||
String STATUS_NORMAL = "normal";
|
||||
|
||||
/**
|
||||
* 状态-停用
|
||||
*/
|
||||
int STATUS_FORBIDDEN = 2;
|
||||
String STATUS_FORBIDDEN = "forbidden";
|
||||
|
||||
/**
|
||||
* 储值卡日志-开通
|
||||
*/
|
||||
int LOG_ACTIVE = 1;
|
||||
String LOG_ACTIVE = "active";
|
||||
|
||||
/**
|
||||
* 储值卡日志-支付
|
||||
*/
|
||||
int LOG_PAY = 2;
|
||||
String LOG_PAY = "pay";
|
||||
|
||||
/**
|
||||
* 储值卡日志-退款
|
||||
*/
|
||||
int LOG_CLOSE = 3;
|
||||
String LOG_CLOSE = "close";
|
||||
|
||||
/**
|
||||
* 储值卡日志-退款
|
||||
*/
|
||||
int LOG_REFUND = 4;
|
||||
String LOG_REFUND = "refund";
|
||||
|
||||
/**
|
||||
* 储值卡日志-Admin余额变动
|
||||
*/
|
||||
int LOG_ADMIN_CHANGER = 4;
|
||||
String LOG_ADMIN_CHANGER = "changer";
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
package cn.bootx.platform.daxpay.controller;
|
||||
|
||||
import cn.bootx.platform.common.core.annotation.OperateLog;
|
||||
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.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.WalletRechargeParam;
|
||||
import cn.bootx.platform.iam.dto.user.UserInfoDto;
|
||||
import cn.bootx.platform.iam.param.user.UserInfoParam;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 钱包
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2021/2/24
|
||||
*/
|
||||
@Tag(name = "钱包相关的接口")
|
||||
@RestController
|
||||
@RequestMapping("/wallet/admin")
|
||||
@AllArgsConstructor
|
||||
public class WalletAdminController {
|
||||
|
||||
private final WalletService walletService;
|
||||
|
||||
private final WalletQueryService walletQueryService;
|
||||
|
||||
@Operation(summary = "开通用户钱包操作")
|
||||
@PostMapping("/createWallet")
|
||||
public ResResult<Void> createWallet(Long userId) {
|
||||
walletService.createWallet(userId);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "批量开通用户钱包操作")
|
||||
@PostMapping("/createWalletBatch")
|
||||
public ResResult<Void> createWalletBatch(@RequestBody List<Long> userIds) {
|
||||
walletService.createWalletBatch(userIds);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "解锁钱包")
|
||||
@OperateLog(title = "解锁钱包", businessType = OperateLog.BusinessType.UPDATE, saveParam = true)
|
||||
@PostMapping("/unlock")
|
||||
public ResResult<Void> unlock(Long walletId) {
|
||||
walletService.unlock(walletId);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "锁定钱包")
|
||||
@OperateLog(title = "锁定钱包", businessType = OperateLog.BusinessType.UPDATE, saveParam = true)
|
||||
@PostMapping("/lock")
|
||||
public ResResult<Void> lock(Long walletId) {
|
||||
walletService.lock(walletId);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "充值操作(增减余额)")
|
||||
@PostMapping("/changerBalance")
|
||||
public ResResult<Void> changerBalance(@RequestBody WalletRechargeParam param) {
|
||||
walletService.changerBalance(param);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "分页")
|
||||
@GetMapping("/page")
|
||||
public ResResult<PageResult<WalletDto>> page(PageParam pageParam, WalletPayParam param) {
|
||||
return Res.ok(walletQueryService.page(pageParam, param));
|
||||
}
|
||||
|
||||
@Operation(summary = "分页(未开通钱包的用户)")
|
||||
@GetMapping("/pageByNotWallet")
|
||||
public ResResult<PageResult<UserInfoDto>> pageByNotWallet(PageParam pageParam, UserInfoParam param) {
|
||||
return Res.ok(walletQueryService.pageByNotWallet(pageParam, param));
|
||||
}
|
||||
|
||||
@Operation(summary = "根据用户ID查询钱包")
|
||||
@GetMapping("/findByUserId")
|
||||
public ResResult<WalletDto> findByUserId(Long userId) {
|
||||
return Res.ok(walletQueryService.findByUserId(userId));
|
||||
}
|
||||
|
||||
@Operation(summary = "根据钱包ID查询钱包")
|
||||
@GetMapping("/findById")
|
||||
public ResResult<WalletDto> findById(Long walletId) {
|
||||
return Res.ok(walletQueryService.findById(walletId));
|
||||
}
|
||||
|
||||
@Operation(summary = "获取钱包综合信息")
|
||||
@GetMapping("/getWalletInfo")
|
||||
public ResResult<WalletInfoDto> getWalletInfo(Long walletId) {
|
||||
return Res.ok(walletQueryService.getWalletInfo(walletId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,89 +1,26 @@
|
||||
package cn.bootx.platform.daxpay.controller;
|
||||
|
||||
import cn.bootx.platform.common.core.rest.Res;
|
||||
import cn.bootx.platform.common.core.rest.ResResult;
|
||||
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.WalletRechargeParam;
|
||||
import cn.bootx.platform.common.core.annotation.OperateLog;
|
||||
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.iam.dto.user.UserInfoDto;
|
||||
import cn.bootx.platform.iam.param.user.UserInfoParam;
|
||||
import cn.bootx.platform.starter.auth.util.SecurityUtil;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 钱包
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2021/2/24
|
||||
*/
|
||||
@Tag(name = "钱包相关的接口")
|
||||
@RestController
|
||||
@RequestMapping("/wallet")
|
||||
@AllArgsConstructor
|
||||
public class WalletController {
|
||||
|
||||
private final WalletService walletService;
|
||||
|
||||
private final WalletQueryService walletQueryService;
|
||||
|
||||
@Operation(summary = "开通用户钱包操作")
|
||||
@PostMapping("createWallet")
|
||||
public ResResult<Void> createWallet(Long userId) {
|
||||
walletService.createWallet(userId);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "批量开通用户钱包操作")
|
||||
@PostMapping("createWalletBatch")
|
||||
public ResResult<Void> createWalletBatch(@RequestBody List<Long> userIds) {
|
||||
walletService.createWalletBatch(userIds);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "解锁钱包")
|
||||
@OperateLog(title = "解锁钱包", businessType = OperateLog.BusinessType.UPDATE, saveParam = true)
|
||||
@PostMapping("/unlock")
|
||||
public ResResult<Void> unlock(Long walletId) {
|
||||
walletService.unlock(walletId);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "锁定钱包")
|
||||
@OperateLog(title = "锁定钱包", businessType = OperateLog.BusinessType.UPDATE, saveParam = true)
|
||||
@PostMapping("/lock")
|
||||
public ResResult<Void> lock(Long walletId) {
|
||||
walletService.lock(walletId);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "充值操作(增减余额)")
|
||||
@PostMapping("/changerBalance")
|
||||
public ResResult<Void> changerBalance(@RequestBody WalletRechargeParam param) {
|
||||
walletService.changerBalance(param);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "分页")
|
||||
@GetMapping("/page")
|
||||
public ResResult<PageResult<WalletDto>> page(PageParam pageParam, WalletPayParam param) {
|
||||
return Res.ok(walletQueryService.page(pageParam, param));
|
||||
}
|
||||
|
||||
@Operation(summary = "分页")
|
||||
@GetMapping("/pageByNotWallet")
|
||||
public ResResult<PageResult<UserInfoDto>> pageByNotWallet(PageParam pageParam, UserInfoParam param) {
|
||||
return Res.ok(walletQueryService.pageByNotWallet(pageParam, param));
|
||||
}
|
||||
private final WalletService walletService;
|
||||
|
||||
@Operation(summary = "根据用户查询钱包")
|
||||
@GetMapping("/findByUser")
|
||||
@@ -91,16 +28,11 @@ public class WalletController {
|
||||
return Res.ok(walletQueryService.findByUser());
|
||||
}
|
||||
|
||||
@Operation(summary = "根据钱包ID查询钱包")
|
||||
@GetMapping("/findById")
|
||||
public ResResult<WalletDto> findById(Long walletId) {
|
||||
return Res.ok(walletQueryService.findById(walletId));
|
||||
@Operation(summary = "开通用户钱包操作")
|
||||
@PostMapping("/createWallet")
|
||||
public ResResult<Void> createWallet() {
|
||||
Long userId = SecurityUtil.getUserId();
|
||||
walletService.createWallet(userId);
|
||||
return Res.ok();
|
||||
}
|
||||
|
||||
@Operation(summary = "获取钱包综合信息")
|
||||
@GetMapping("/getWalletInfo")
|
||||
public ResResult<WalletInfoDto> getWalletInfo(Long walletId) {
|
||||
return Res.ok(walletQueryService.getWalletInfo(walletId));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -79,7 +79,6 @@ public class CashierService {
|
||||
map.put(PayWayExtraCode.AUTH_CODE, param.getAuthCode());
|
||||
map.put(PayWayExtraCode.OPEN_ID, param.getOpenId());
|
||||
map.put(PayWayExtraCode.VOUCHER_NO, param.getVoucherNo());
|
||||
map.put(PayWayExtraCode.WALLET_ID, param.getWalletId());
|
||||
String extraParamsJson = PayWaylUtil.buildExtraParamsJson(param.getPayChannel(), map);
|
||||
payWayParam.setExtraParamsJson(extraParamsJson);
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ public class VoucherLogManager extends BaseManager<VoucherLogMapper, VoucherLog>
|
||||
/**
|
||||
* 根据支付id和类型进行查询
|
||||
*/
|
||||
public List<VoucherLog> findByPaymentIdAndType(Long paymentId, int type) {
|
||||
public List<VoucherLog> findByPaymentIdAndType(Long paymentId, String type) {
|
||||
return lambdaQuery().eq(VoucherLog::getPaymentId, paymentId).eq(VoucherLog::getType, type).list();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package cn.bootx.platform.daxpay.core.channel.voucher.entity;
|
||||
|
||||
import cn.bootx.mybatis.table.modify.annotation.DbColumn;
|
||||
import cn.bootx.mybatis.table.modify.annotation.DbComment;
|
||||
import cn.bootx.mybatis.table.modify.annotation.DbTable;
|
||||
import cn.bootx.mybatis.table.modify.mybatis.mysq.annotation.DbMySqlIndex;
|
||||
import cn.bootx.platform.common.core.function.EntityBaseFunction;
|
||||
import cn.bootx.platform.common.mybatisplus.base.MpBaseEntity;
|
||||
import cn.bootx.platform.daxpay.code.paymodel.VoucherCode;
|
||||
@@ -21,36 +25,51 @@ import java.time.LocalDateTime;
|
||||
*/
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@DbTable(comment = "储值卡")
|
||||
@Accessors(chain = true)
|
||||
@TableName("pay_voucher")
|
||||
public class Voucher extends MpBaseEntity implements EntityBaseFunction<VoucherDto> {
|
||||
|
||||
/** 卡号 */
|
||||
@DbComment("卡号")
|
||||
@DbMySqlIndex(comment = "卡号索引")
|
||||
private String cardNo;
|
||||
|
||||
/** 生成批次号 */
|
||||
@DbComment("生成批次号")
|
||||
private Long batchNo;
|
||||
|
||||
/** 面值 */
|
||||
@DbComment("面值")
|
||||
private BigDecimal faceValue;
|
||||
|
||||
/** 余额 */
|
||||
@DbComment("余额")
|
||||
private BigDecimal balance;
|
||||
|
||||
/** 预冻结额度 */
|
||||
@DbColumn(comment = "预冻结额度")
|
||||
private BigDecimal freezeBalance;
|
||||
|
||||
|
||||
/** 是否长期有效 */
|
||||
private Boolean enduring;
|
||||
@DbComment("是否长期有效")
|
||||
private boolean enduring;
|
||||
|
||||
/** 开始时间 */
|
||||
@DbComment("开始时间")
|
||||
private LocalDateTime startTime;
|
||||
|
||||
/** 结束时间 */
|
||||
@DbComment("结束时间")
|
||||
private LocalDateTime endTime;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
* @see VoucherCode
|
||||
* @see VoucherCode#STATUS_FORBIDDEN
|
||||
*/
|
||||
private Integer status;
|
||||
@DbComment("状态")
|
||||
private String status;
|
||||
|
||||
@Override
|
||||
public VoucherDto toDto() {
|
||||
|
||||
@@ -32,9 +32,9 @@ public class VoucherLog extends MpBaseEntity {
|
||||
|
||||
/**
|
||||
* 类型
|
||||
* @see VoucherCode
|
||||
* @see VoucherCode#LOG_PAY
|
||||
*/
|
||||
private Integer type;
|
||||
private String type;
|
||||
|
||||
/** 交易记录ID */
|
||||
private Long paymentId;
|
||||
|
||||
@@ -5,15 +5,15 @@ import cn.bootx.platform.common.core.util.BigDecimalUtil;
|
||||
import cn.bootx.platform.common.core.util.LocalDateTimeUtil;
|
||||
import cn.bootx.platform.daxpay.code.paymodel.VoucherCode;
|
||||
import cn.bootx.platform.daxpay.core.channel.voucher.dao.VoucherLogManager;
|
||||
import cn.bootx.platform.daxpay.core.payment.entity.Payment;
|
||||
import cn.bootx.platform.daxpay.core.channel.voucher.dao.VoucherManager;
|
||||
import cn.bootx.platform.daxpay.core.channel.voucher.dao.VoucherPaymentManager;
|
||||
import cn.bootx.platform.daxpay.core.channel.voucher.entity.Voucher;
|
||||
import cn.bootx.platform.daxpay.core.channel.voucher.entity.VoucherLog;
|
||||
import cn.bootx.platform.daxpay.core.channel.voucher.entity.VoucherPayment;
|
||||
import cn.bootx.platform.daxpay.core.payment.entity.Payment;
|
||||
import cn.bootx.platform.daxpay.exception.payment.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayWayParam;
|
||||
import cn.bootx.platform.daxpay.param.channel.voucher.VoucherPayParam;
|
||||
import cn.bootx.platform.daxpay.param.pay.PayWayParam;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONException;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
@@ -82,11 +82,25 @@ public class VoucherPayService {
|
||||
throw new PayFailureException("储值卡余额不足");
|
||||
}
|
||||
|
||||
return vouchers;
|
||||
return sort(vouchers);
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付 TODO 有期限的在前面, 同样有期限到期时间短的在前面, 同样到期日金额小的在前面
|
||||
* 支付前冻结余额
|
||||
*/
|
||||
public void freezeBalance(BigDecimal amount, Payment payment, List<Voucher> vouchers){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付成功
|
||||
*/
|
||||
public void paySuccess(Long paymentId){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接支付
|
||||
*/
|
||||
public void pay(BigDecimal amount, Payment payment, List<Voucher> vouchers) {
|
||||
vouchers.sort((o1, o2) -> BigDecimalUtil.compareTo(o1.getBalance(), o2.getBalance()));
|
||||
@@ -122,15 +136,17 @@ public class VoucherPayService {
|
||||
voucherLogManager.saveAll(voucherLogs);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 取消支付
|
||||
* 取消支付, 可配置解除冻结金额
|
||||
* @param freeze 是否是冻结模式, 是的话对冻结金额进行解冻, 不是的话返还扣减的金额
|
||||
*/
|
||||
public void close(Long paymentId) {
|
||||
public void close(Long paymentId,boolean freeze) {
|
||||
// 查找支付记录日志
|
||||
List<VoucherLog> voucherLogs = voucherLogManager.findByPaymentIdAndType(paymentId, VoucherCode.LOG_PAY);
|
||||
// 查出关联的储值卡
|
||||
Map<Long, VoucherLog> voucherLogMap = voucherLogs.stream()
|
||||
.collect(Collectors.toMap(VoucherLog::getVoucherId, Function.identity()));
|
||||
.collect(Collectors.toMap(VoucherLog::getVoucherId, Function.identity()));
|
||||
List<Voucher> vouchers = voucherManager.findAllByIds(voucherLogMap.keySet());
|
||||
// 执行退款并记录日志
|
||||
List<VoucherLog> logs = new ArrayList<>();
|
||||
@@ -138,11 +154,11 @@ public class VoucherPayService {
|
||||
VoucherLog voucherLog = voucherLogMap.get(voucher.getId());
|
||||
voucher.setBalance(voucher.getBalance().add(voucherLog.getAmount()));
|
||||
VoucherLog log = new VoucherLog().setAmount(voucherLog.getAmount())
|
||||
.setPaymentId(paymentId)
|
||||
.setBusinessId(voucherLog.getBusinessId())
|
||||
.setVoucherId(voucher.getId())
|
||||
.setVoucherNo(voucher.getCardNo())
|
||||
.setType(VoucherCode.LOG_CLOSE);
|
||||
.setPaymentId(paymentId)
|
||||
.setBusinessId(voucherLog.getBusinessId())
|
||||
.setVoucherId(voucher.getId())
|
||||
.setVoucherNo(voucher.getCardNo())
|
||||
.setType(VoucherCode.LOG_CLOSE);
|
||||
logs.add(log);
|
||||
}
|
||||
voucherManager.updateAllById(vouchers);
|
||||
@@ -177,9 +193,51 @@ public class VoucherPayService {
|
||||
private boolean check(List<Voucher> vouchers) {
|
||||
// 判断有效期
|
||||
return vouchers.stream()
|
||||
.filter(voucher -> !Objects.equals(voucher.getEnduring(), true))
|
||||
.filter(voucher -> !Objects.equals(voucher.isEnduring(), true))
|
||||
.allMatch(voucher -> LocalDateTimeUtil.between(LocalDateTime.now(), voucher.getStartTime(),
|
||||
voucher.getEndTime()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 对储值卡进行排序
|
||||
* 有期限的在前面, 同样有期限到期时间短的在前面, 同样到期日余额小的在前面, 金额一样id小的前面
|
||||
*/
|
||||
private List<Voucher> sort(List<Voucher> vouchers){
|
||||
vouchers.sort(this::compareTime);
|
||||
return vouchers;
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较储值卡的期限
|
||||
*/
|
||||
private int compareTime(Voucher v1,Voucher v2){
|
||||
// 期限对比, 都为长期
|
||||
if (v1.isEnduring()&&v2.isEnduring()){
|
||||
// 比较余额
|
||||
return compareBalance(v1,v2);
|
||||
}
|
||||
// 都不为长期, 且金额一致
|
||||
if (Objects.equals(v1.getEndTime(),v2.getEndTime())){
|
||||
// 比较余额
|
||||
return compareBalance(v1,v2);
|
||||
}
|
||||
// 期限对比 其中一个为长期
|
||||
if (v1.isEnduring()^v2.isEnduring()){
|
||||
return v1.isEnduring()?1:-1;
|
||||
}
|
||||
// 比较期限
|
||||
return v1.getEndTime().compareTo(v2.getEndTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较储值卡的余额, 余额一致比较主键
|
||||
*/
|
||||
private int compareBalance(Voucher v1,Voucher v2) {
|
||||
int i = BigDecimalUtil.compareTo(v1.getBalance(), v2.getBalance());
|
||||
if (i==0){
|
||||
return Long.compare(v1.getId(),v2.getId());
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ public class Wallet extends MpBaseEntity implements EntityBaseFunction<WalletDto
|
||||
* 状态
|
||||
* @see WalletCode#STATUS_FORBIDDEN
|
||||
*/
|
||||
@DbColumn(comment = "状态")
|
||||
private String status;
|
||||
|
||||
@Override
|
||||
|
||||
@@ -38,7 +38,7 @@ public class WalletPayService {
|
||||
private final WalletLogManager walletLogManager;
|
||||
|
||||
/**
|
||||
* 支付前冻结余额操作
|
||||
* 支付前冻结余额
|
||||
* @param amount 付款金额
|
||||
* @param payment 支付记录
|
||||
* @param wallet 钱包
|
||||
@@ -63,9 +63,9 @@ public class WalletPayService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付成功更新
|
||||
* 支付成功, 进行扣款
|
||||
*/
|
||||
public void success(Long paymentId){
|
||||
public void paySuccess(Long paymentId){
|
||||
// 钱包支付记录
|
||||
walletPaymentManager.findByPaymentId(paymentId).ifPresent(walletPayment -> {
|
||||
Optional<Wallet> walletOpt = walletManager.findById(walletPayment.getWalletId());
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.bootx.platform.daxpay.core.channel.wallet.service;
|
||||
|
||||
import cn.bootx.platform.common.core.entity.UserDetail;
|
||||
import cn.bootx.platform.common.core.exception.DataNotExistException;
|
||||
import cn.bootx.platform.common.core.rest.PageResult;
|
||||
import cn.bootx.platform.common.core.rest.param.PageParam;
|
||||
@@ -18,6 +19,8 @@ import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 钱包
|
||||
*
|
||||
@@ -34,18 +37,26 @@ public class WalletQueryService {
|
||||
private final UserQueryService userQueryService;
|
||||
|
||||
/**
|
||||
* 根据ID查询Wallet
|
||||
* 根据钱包ID查询Wallet
|
||||
*/
|
||||
public WalletDto findById(Long walletId) {
|
||||
return walletManager.findById(walletId).map(Wallet::toDto).orElseThrow(DataNotExistException::new);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据用户ID查询钱包
|
||||
*/
|
||||
public WalletDto findByUserId(Long userId) {
|
||||
return walletManager.findByUser(userId).map(Wallet::toDto).orElseThrow(DataNotExistException::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户ID查询钱包
|
||||
*/
|
||||
public WalletDto findByUser() {
|
||||
Long userId = SecurityUtil.getUserId();
|
||||
return walletManager.findByUser(userId).map(Wallet::toDto).orElseThrow(DataNotExistException::new);
|
||||
return walletManager.findByUser(userId).map(Wallet::toDto).orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,4 +85,26 @@ public class WalletQueryService {
|
||||
return MpUtil.convert2DtoPageResult(walletManager.pageByNotWallet(pageParam, userInfoParam));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取钱包, 获取顺序: 1. 显式传入的钱包ID 2. 显式传入的用户ID 3. 从系统中获取到的用户ID
|
||||
*
|
||||
*/
|
||||
public Wallet getWallet(Long walletId,Long userId){
|
||||
Wallet wallet = null;
|
||||
// 首先根据钱包ID查询
|
||||
if (Objects.nonNull(walletId)) {
|
||||
wallet = walletManager.findById(walletId).orElseThrow(null);
|
||||
}
|
||||
if (Objects.nonNull(wallet)){
|
||||
return wallet;
|
||||
}
|
||||
// 根据用户id查询
|
||||
if (Objects.isNull(userId)){
|
||||
userId = SecurityUtil.getCurrentUser().map(UserDetail::getId).orElse(null);
|
||||
}
|
||||
return walletManager.findByUser(userId).orElse(null);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@ 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.WalletLog;
|
||||
import cn.bootx.platform.daxpay.exception.waller.WalletBannedException;
|
||||
import cn.bootx.platform.daxpay.exception.waller.WalletNotExistsException;
|
||||
import cn.bootx.platform.daxpay.param.channel.wallet.WalletRechargeParam;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -18,14 +16,12 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 钱包的相关操作
|
||||
*
|
||||
* @author xxm
|
||||
* @since 2020/12/8
|
||||
* @since 2023/6/26
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -79,8 +75,8 @@ public class WalletService {
|
||||
.setUserId(wallet.getUserId())
|
||||
.setAmount(BigDecimal.ZERO)
|
||||
.setType(WalletCode.LOG_ACTIVE)
|
||||
.setRemark("激活钱包")
|
||||
.setOperationSource(WalletCode.OPERATION_SOURCE_USER))
|
||||
.setRemark("批量开通钱包")
|
||||
.setOperationSource(WalletCode.OPERATION_SOURCE_ADMIN))
|
||||
.collect(Collectors.toList());
|
||||
walletLogManager.saveAll(walletLogs);
|
||||
}
|
||||
@@ -142,30 +138,4 @@ public class WalletService {
|
||||
.setOperationSource(WalletCode.OPERATION_SOURCE_ADMIN);
|
||||
walletLogManager.save(walletLog);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询钱包,如果钱包不存在或者钱包被禁用将抛出异常
|
||||
*/
|
||||
public Wallet getNormalWalletById(Long walletId) {
|
||||
// 查询Wallet
|
||||
Wallet wallet = walletManager.findById(walletId).orElseThrow(WalletNotExistsException::new);
|
||||
// 是否被禁用
|
||||
if (Objects.equals(WalletCode.STATUS_FORBIDDEN, wallet.getStatus())) {
|
||||
throw new WalletBannedException();
|
||||
}
|
||||
return wallet;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询钱包,如果钱包不存在或者钱包被禁用将抛出异常
|
||||
*/
|
||||
public Wallet getNormalWalletByUserId(Long userId) {
|
||||
// 查询Wallet
|
||||
Wallet wallet = walletManager.findByUser(userId).orElseThrow(WalletNotExistsException::new);
|
||||
// 是否被禁用
|
||||
if (Objects.equals(WalletCode.STATUS_FORBIDDEN, wallet.getStatus())) {
|
||||
throw new WalletBannedException();
|
||||
}
|
||||
return wallet;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ public class VoucherStrategy extends AbsPayStrategy {
|
||||
*/
|
||||
@Override
|
||||
public void doBeforePayHandler() {
|
||||
// 获取并校验余额
|
||||
// 获取并校验储值卡
|
||||
this.vouchers = voucherPayService.getAndCheckVoucher(this.getPayWayParam());
|
||||
}
|
||||
|
||||
@@ -54,8 +54,12 @@ public class VoucherStrategy extends AbsPayStrategy {
|
||||
*/
|
||||
@Override
|
||||
public void doPayHandler() {
|
||||
voucherPayService.pay(getPayWayParam().getAmount(), this.getPayment(), this.vouchers);
|
||||
voucherPaymentService.savePayment(getPayment(), getPayParam(), getPayWayParam(), vouchers);
|
||||
if (this.getPayment().isAsyncPayMode()){
|
||||
voucherPayService.freezeBalance(this.getPayWayParam().getAmount(), this.getPayment(), this.vouchers);
|
||||
} else {
|
||||
voucherPayService.pay(this.getPayWayParam().getAmount(), this.getPayment(), this.vouchers);
|
||||
}
|
||||
voucherPaymentService.savePayment(this.getPayment(), getPayParam(), getPayWayParam(), vouchers);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,6 +67,9 @@ public class VoucherStrategy extends AbsPayStrategy {
|
||||
*/
|
||||
@Override
|
||||
public void doSuccessHandler() {
|
||||
if (this.getPayment().isAsyncPayMode()){
|
||||
voucherPayService.paySuccess(this.getPayment().getId());
|
||||
}
|
||||
voucherPaymentService.updateSuccess(this.getPayment().getId());
|
||||
}
|
||||
|
||||
@@ -71,7 +78,7 @@ public class VoucherStrategy extends AbsPayStrategy {
|
||||
*/
|
||||
@Override
|
||||
public void doCloseHandler() {
|
||||
voucherPayService.close(this.getPayment().getId());
|
||||
voucherPayService.close(this.getPayment().getId(), this.getPayment().isAsyncPayMode());
|
||||
voucherPaymentService.updateClose(this.getPayment().getId());
|
||||
}
|
||||
|
||||
|
||||
@@ -2,13 +2,15 @@ package cn.bootx.platform.daxpay.core.pay.strategy;
|
||||
|
||||
import cn.bootx.platform.common.core.util.BigDecimalUtil;
|
||||
import cn.bootx.platform.daxpay.code.pay.PayChannelEnum;
|
||||
import cn.bootx.platform.daxpay.code.paymodel.WalletCode;
|
||||
import cn.bootx.platform.daxpay.core.channel.wallet.entity.Wallet;
|
||||
import cn.bootx.platform.daxpay.core.channel.wallet.service.WalletPayService;
|
||||
import cn.bootx.platform.daxpay.core.channel.wallet.service.WalletPaymentService;
|
||||
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.pay.func.AbsPayStrategy;
|
||||
import cn.bootx.platform.daxpay.core.payment.service.PaymentService;
|
||||
import cn.bootx.platform.daxpay.exception.payment.PayFailureException;
|
||||
import cn.bootx.platform.daxpay.exception.waller.WalletBannedException;
|
||||
import cn.bootx.platform.daxpay.exception.waller.WalletLackOfBalanceException;
|
||||
import cn.bootx.platform.daxpay.param.channel.wallet.WalletPayParam;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
@@ -18,6 +20,8 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_PROTOTYPE;
|
||||
|
||||
/**
|
||||
@@ -35,7 +39,7 @@ public class WalletPayStrategy extends AbsPayStrategy {
|
||||
|
||||
private final WalletPayService walletPayService;
|
||||
|
||||
private final WalletService walletService;
|
||||
private final WalletQueryService walletQueryService;
|
||||
|
||||
private final PaymentService paymentService;
|
||||
|
||||
@@ -51,17 +55,22 @@ public class WalletPayStrategy extends AbsPayStrategy {
|
||||
*/
|
||||
@Override
|
||||
public void doBeforePayHandler() {
|
||||
WalletPayParam walletPayParam = new WalletPayParam();
|
||||
try {
|
||||
// 钱包参数验证
|
||||
String extraParamsJson = this.getPayWayParam().getExtraParamsJson();
|
||||
if (StrUtil.isNotBlank(extraParamsJson)) {
|
||||
WalletPayParam walletPayParam = JSONUtil.toBean(extraParamsJson, WalletPayParam.class);
|
||||
this.wallet = walletService.getNormalWalletById(walletPayParam.getWalletId());
|
||||
walletPayParam = JSONUtil.toBean(extraParamsJson, WalletPayParam.class);
|
||||
}
|
||||
}
|
||||
catch (JSONException e) {
|
||||
} catch (JSONException e) {
|
||||
throw new PayFailureException("支付参数错误");
|
||||
}
|
||||
// 获取钱包
|
||||
this.wallet = walletQueryService.getWallet(walletPayParam.getWalletId(),walletPayParam.getUserId());
|
||||
// 是否被禁用
|
||||
if (Objects.equals(WalletCode.STATUS_FORBIDDEN, this.wallet.getStatus())) {
|
||||
throw new WalletBannedException();
|
||||
}
|
||||
// 判断余额
|
||||
if (BigDecimalUtil.compareTo(this.wallet.getBalance(), getPayWayParam().getAmount()) < 0) {
|
||||
throw new WalletLackOfBalanceException();
|
||||
@@ -88,7 +97,7 @@ public class WalletPayStrategy extends AbsPayStrategy {
|
||||
@Override
|
||||
public void doSuccessHandler() {
|
||||
if (this.getPayment().isAsyncPayMode()){
|
||||
walletPayService.success(this.getPayment().getId());
|
||||
walletPayService.paySuccess(this.getPayment().getId());
|
||||
}
|
||||
walletPaymentService.updateSuccess(this.getPayment().getId());
|
||||
}
|
||||
@@ -99,7 +108,7 @@ public class WalletPayStrategy extends AbsPayStrategy {
|
||||
@Override
|
||||
public void doCloseHandler() {
|
||||
if (this.getPayment().isAsyncPayMode()){
|
||||
walletPayService.success(this.getPayment().getId());
|
||||
walletPayService.paySuccess(this.getPayment().getId());
|
||||
}
|
||||
walletPayService.close(this.getPayment().getId(),this.getPayment().isAsyncPayMode());
|
||||
walletPaymentService.updateClose(this.getPayment().getId());
|
||||
|
||||
@@ -42,9 +42,9 @@ public class VoucherDto extends BaseDto {
|
||||
private LocalDateTime endTime;
|
||||
|
||||
/**
|
||||
* @see VoucherCode
|
||||
* @see VoucherCode#STATUS_FORBIDDEN
|
||||
*/
|
||||
@Schema(description = "状态")
|
||||
private Integer status;
|
||||
private String status;
|
||||
|
||||
}
|
||||
|
||||
@@ -22,4 +22,8 @@ public class WalletPayParam implements Serializable {
|
||||
@Schema(description = "钱包ID")
|
||||
private Long walletId;
|
||||
|
||||
@Schema(description = "用户ID")
|
||||
private Long userId;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -101,7 +101,11 @@ public class PayWaylUtil {
|
||||
}
|
||||
case WALLET: {
|
||||
String walletId = map.get(PayWayExtraCode.WALLET_ID);
|
||||
return JSONUtil.toJsonStr(new WalletPayParam().setWalletId(Long.valueOf(walletId)));
|
||||
String userId = map.get(PayWayExtraCode.USER_ID);
|
||||
WalletPayParam walletPayParam = new WalletPayParam()
|
||||
.setWalletId(Long.valueOf(walletId))
|
||||
.setUserId(Long.valueOf(userId));
|
||||
return JSONUtil.toJsonStr(walletPayParam);
|
||||
}
|
||||
default: {
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user