1、新增充值支持赠送金;2、充值活动增删改查完善;

This commit is contained in:
gaoqr
2025-08-20 11:21:00 +08:00
parent 8229f086dd
commit e25c340782
21 changed files with 276 additions and 104 deletions
@@ -23,4 +23,14 @@ public class LambdaUpdateWrapperX<T> extends LambdaUpdateWrapper<T> {
super.eq(column, val);
return this;
}
/**
* 当条件存在时set
*/
public LambdaUpdateWrapperX<T> setIfPresent(SFunction<T, ?> column, Object val) {
if (ObjectUtil.isNotEmpty(val)) {
return (LambdaUpdateWrapperX<T>) super.set(column, val);
}
return this;
}
}
@@ -435,6 +435,8 @@ public class ErrorCodeConstants {
public static final ErrorCode IMAGE_UPLOAD_ERROR = new ErrorCode(1_002_043_023, "图片上传失败,请重试或重新选择图片");
public static final ErrorCode ORGAN_RECHARGE_AMOUNT_UPDATE_ERROR = new ErrorCode(1_002_043_024, "组织充值失败,请检查组织资金数据");
public static final ErrorCode ORGAN_PRODUCT_PAY_AMOUNT_CHANGE_ERROR = new ErrorCode(1_002_043_025, "发起产品支付失败,组织资金已发生改变,请刷新或稍后再发起支付");
public static final ErrorCode PAY_RECHARGE_ACTIVITY_CHANNEL_MISMATCH_ERROR = new ErrorCode(1_002_043_026, "充值活动类型和支付渠道不匹配,请选择其他充值活动!");
public static final ErrorCode PAY_RECHARGE_ACTIVITY_EXPIRE_ERROR = new ErrorCode(1_002_043_027, "充值活动已结束,请选择其他充值活动!");
//=========== 支付相关 1-002-048-000 ============
public static final ErrorCode PAY_CHANNEL_NOT_SUPPORT = new ErrorCode(1_002_048_000, "暂不支持的支付渠道,请使用其他支付渠道");
@@ -448,8 +450,8 @@ public class ErrorCodeConstants {
public static final ErrorCode PAY_NOTIFY_PASSBACK_NOT_EXISTS_ERROR = new ErrorCode(1_002_048_008, "支付回调缺少passback_params,请检查支付渠道");
public static final ErrorCode PAY_NOTIFY_PASSBACK_TRADETYPE_NOT_SUPPORT_ERROR = new ErrorCode(1_002_048_009, "不支持的支付回调tradeType:【{}】,请检查支付渠道");
public static final ErrorCode PAY_PRODUCT_BALANCE_INSUFFICIENT = new ErrorCode(1_002_048_010, "现金余额不足,请选择其他支付方式!");
public static final ErrorCode PAY_PRODUCT_GIFT_BALANCE_INSUFFICIENT = new ErrorCode(1_002_048_010, "赠送金余额不足,请选择其他支付方式!");
public static final ErrorCode PAY_PRODUCT_AVAILABLE_BALANCE_INSUFFICIENT = new ErrorCode(1_002_048_010, "可用金(现金余额+赠送金)余额不足,请选择其他支付方式!");
public static final ErrorCode PAY_PRODUCT_GIFT_BALANCE_INSUFFICIENT = new ErrorCode(1_002_048_011, "赠送金余额不足,请选择其他支付方式!");
public static final ErrorCode PAY_PRODUCT_AVAILABLE_BALANCE_INSUFFICIENT = new ErrorCode(1_002_048_012, "可用金(现金余额+赠送金)余额不足,请选择其他支付方式!");
//=========== 产品相关 1-002-045-000 ============
public static final ErrorCode PRODUCTS_NO_EXIST = new ErrorCode(1_002_045_001, "当前产品不存在");
@@ -1,46 +0,0 @@
package com.cf.imes.module.system.enums.recharge;
import com.cf.imes.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
import java.util.Objects;
/**
* 充值赠送类型枚举
*
* @author 晨丰科技
*/
@Getter
@AllArgsConstructor
public enum PurchaseTypeEnum implements IntArrayValuable {
ONE(0, "满X送X"),
TWO(1, "每满X送X");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(PurchaseTypeEnum::getStatus).toArray();
/**
* 状态值
*/
private final Integer status;
/**
* 状态名
*/
private final String name;
@Override
public int[] array() {
return ARRAYS;
}
public static boolean isOne(String name) {
return Objects.equals(ONE.name, name);
}
public static boolean isTwo(String name) {
return Objects.equals(TWO.name, name);
}
}
@@ -0,0 +1,67 @@
package com.cf.imes.module.system.enums.recharge;
import com.cf.imes.framework.common.core.IntArrayValuable;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
import java.util.Objects;
/**
* 充值赠送类型枚举
*
* @author 晨丰科技
*/
@Getter
@AllArgsConstructor
public enum RechargeGiftTypeEnum implements IntArrayValuable {
FULL_X_GIVE_X(0, "满X送X"),
EVERY_X_GIVE_X(1, "每满X送X");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(RechargeGiftTypeEnum::getStatus).toArray();
/**
* 状态值
*/
private final Integer status;
/**
* 状态名
*/
private final String name;
@Override
public int[] array() {
return ARRAYS;
}
/**
* 是否满X送X
*
* @param name
* @return
*/
public static boolean isFullGive(String name) {
return Objects.equals(FULL_X_GIVE_X.name, name);
}
/**
* 是否每满X送X
*
* @param name
* @return
*/
public static boolean isEveryGive(String name) {
return Objects.equals(EVERY_X_GIVE_X.name, name);
}
public static RechargeGiftTypeEnum fromStatus(Integer status) {
for (RechargeGiftTypeEnum value : values()) {
if (Objects.equals(value.status, status)) {
return value;
}
}
return null;
}
}
@@ -16,9 +16,9 @@ import java.util.Objects;
@AllArgsConstructor
public enum RechargeTypeEnum implements IntArrayValuable {
ONE(0, "微信、支付宝"),
TWO(1, "微信"),
THREE(2, "支付宝");
WECHAT_AND_ALIPAY(0, "微信、支付宝"),
WECHAT(1, "微信"),
ALIPAY(2, "支付宝");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(RechargeTypeEnum::getStatus).toArray();
@@ -36,15 +36,27 @@ public enum RechargeTypeEnum implements IntArrayValuable {
return ARRAYS;
}
public static boolean isOne(String name) {
return Objects.equals(ONE.name, name);
public static boolean isWechatAndAlipay(String name) {
return Objects.equals(WECHAT_AND_ALIPAY.name, name);
}
public static boolean isTwo(String name) {
return Objects.equals(TWO.name, name);
public static boolean isWechat(String name) {
return Objects.equals(WECHAT.name, name);
}
public static boolean isThree(String name) {
return Objects.equals(THREE.name, name);
public static boolean isAlipay(String name) {
return Objects.equals(ALIPAY.name, name);
}
public static boolean isWechatAndAlipay(Integer status) {
return Objects.equals(WECHAT_AND_ALIPAY.status, status);
}
public static boolean isWechat(Integer status) {
return Objects.equals(WECHAT.status, status);
}
public static boolean isAlipay(Integer status) {
return Objects.equals(ALIPAY.status, status);
}
}
@@ -29,14 +29,14 @@ public class RechargeActiveController {
@Resource
private RechargeActiveService productsService;
@PostMapping("")
@PutMapping("")
@Operation(summary = "新建充值活动")
@PreAuthorize("@ss.hasPermission('base:recharge-active:create')")
public CommonResult<Long> createRechargeActive(@Valid @RequestBody RechargeSaveReqVO createReqVO) {
return success(productsService.create(createReqVO));
}
@PutMapping("")
@PostMapping("")
@Operation(summary = "更新充值活动")
@PreAuthorize("@ss.hasPermission('base:recharge-active:update')")
public CommonResult<Boolean> updateRechargeActive(@Valid @RequestBody RechargeSaveReqVO updateReqVO) {
@@ -44,17 +44,17 @@ public class RechargeActiveController {
return success(true);
}
@DeleteMapping("")
@DeleteMapping("/{id}")
@Operation(summary = "删除充值活动")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('base:recharge-active:delete')")
public CommonResult<Boolean> deleteRechargeActive(@RequestParam("id") Long id) {
public CommonResult<Boolean> deleteRechargeActive(@PathVariable("id") Long id) {
productsService.delete(id);
return success(true);
}
@GetMapping("/{id}")
@Operation(summary = "充值活动")
@Operation(summary = "充值活动")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('base:recharge-active:query')")
public CommonResult<RechargeRespVO> getRechargeActive(@PathVariable("id") Long id) {
@@ -63,7 +63,7 @@ public class RechargeActiveController {
}
@GetMapping("/page")
@Operation(summary = "充值活动分页")
@Operation(summary = "充值活动分页")
@PreAuthorize("@ss.hasPermission('base:recharge-active:query')")
public CommonResult<PageResult<RechargeRespVO>> getRechargeActivePage(@Valid RechargePageReqVO pageReqVO) {
PageResult<GiftMoneyDetailsDO> pageResult = productsService.getPage(pageReqVO);
@@ -1,7 +1,7 @@
package com.cf.imes.module.system.controller.admin.funds.recharge.vo;
import com.cf.imes.framework.common.pojo.PageParam;
import com.cf.imes.module.system.validation.recharge.PurchaseType;
import com.cf.imes.module.system.validation.recharge.RechargeGiftTypeValid;
import com.cf.imes.module.system.validation.recharge.RechargeType;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@@ -26,11 +26,11 @@ public class RechargePageReqVO extends PageParam {
@Schema(description = "活动名称", example = "赵六")
private String activityName;
@Schema(description = "赠送类型", example = "0满X送X 1每满X送X")
@PurchaseType
private Integer purchaseType;
@Schema(description = "赠送类型0:满X送X、1:每满X送X", example = "0")
@RechargeGiftTypeValid
private Integer rechargeGiftType;
@Schema(description = "充值类型", example = "0微信、支付宝 1微信 2支付宝")
@Schema(description = "充值类型,0:微信&支付宝、1:微信、2:支付宝", example = "0")
@RechargeType
private Integer rechargeType;
@@ -1,18 +1,15 @@
package com.cf.imes.module.system.controller.admin.funds.recharge.vo;
import com.cf.imes.module.system.validation.recharge.MoneyValid;
import com.cf.imes.module.system.validation.recharge.PurchaseType;
import com.cf.imes.module.system.validation.recharge.RechargeGiftTypeValid;
import com.cf.imes.module.system.validation.recharge.RechargeType;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import static com.cf.imes.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 赠送金活动表 gift_money 新增/修改 Request VO")
@Data
public class RechargeSaveReqVO {
@@ -24,12 +21,12 @@ public class RechargeSaveReqVO {
@NotNull(message = "活动名称不能为空")
private String activityName;
@Schema(description = "赠送类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "0满X送X 1每满X送X")
@Schema(description = "赠送类型0:满X送X、1:每满X送X", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@NotNull(message = "赠送类型不能为空")
@PurchaseType
private Integer purchaseType;
@RechargeGiftTypeValid
private Integer rechargeGiftType;
@Schema(description = "充值类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "0微信、支付宝 1微信 2支付宝")
@Schema(description = "充值类型,0:微信&支付宝、1:微信、2:支付宝", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
@NotNull(message = "充值类型不能为空")
@RechargeType
private Integer rechargeType;
@@ -45,23 +42,14 @@ public class RechargeSaveReqVO {
private BigDecimal giftAmount;
@Schema(description = "开始时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@NotNull(message = "开始时间不能为空")
private LocalDateTime startTime;
@Schema(description = "结束时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@NotNull(message = "结束时间不能为空")
private LocalDateTime endTime;
@Schema(description = "操作时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime updateTime;
@Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
private String remark;
@Schema(description = "是否删除")
private Integer deleted;
}
@@ -32,4 +32,7 @@ public class PayRechargeOrderReqVO {
@PayChannelCodeValid
@NotNull(message = "支付渠道编码不能为空")
private Integer channelCode;
@Schema(description = "充值活动规格编号", example = "0")
private Long rechargeActivityId;
}
@@ -36,7 +36,7 @@ public class GiftMoneyDetailsDO extends BaseDO {
/**
* 赠送类型 0满X送X; 1每满X送X
*/
private Integer purchaseType;
private Integer rechargeGiftType;
/**
* 充值类型 0微信、支付宝 1微信 2支付宝
*/
@@ -53,6 +53,11 @@ public class PayOrderDO extends BaseDO {
*/
private BigDecimal price;
/**
* 充值赠送活动编号
*/
private Long rechargeActivityId;
/**
* 支付订单号:P + 当前id + 时间戳(yyyyMMddHHmmss
*/
@@ -1,12 +1,16 @@
package com.cf.imes.module.system.dal.mysql.funds.recharge;
import cn.hutool.core.util.ObjectUtil;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.mybatis.core.mapper.BaseMapperX;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.module.system.controller.admin.funds.recharge.vo.RechargePageReqVO;
import com.cf.imes.module.system.dal.dataobject.funds.recharge.GiftMoneyDetailsDO;
import com.cf.imes.module.system.enums.recharge.RechargeTypeEnum;
import org.apache.ibatis.annotations.Mapper;
import java.util.Arrays;
/**
* 赠送金活动详情表 gift_money_details Mapper
*
@@ -17,13 +21,18 @@ public interface GiftMoneyDetailsMapper extends BaseMapperX<GiftMoneyDetailsDO>
default PageResult<GiftMoneyDetailsDO> selectPage(RechargePageReqVO reqVO) {
LambdaQueryWrapperX<GiftMoneyDetailsDO> queryWrapper = new LambdaQueryWrapperX<GiftMoneyDetailsDO>()
.likeIfPresent(GiftMoneyDetailsDO::getActivityName, reqVO.getActivityName())
.eqIfPresent(GiftMoneyDetailsDO::getPurchaseType, reqVO.getPurchaseType())
.eqIfPresent(GiftMoneyDetailsDO::getRechargeType, reqVO.getRechargeType())
.eqIfPresent(GiftMoneyDetailsDO::getRechargeGiftType, reqVO.getRechargeGiftType())
.eqIfPresent(GiftMoneyDetailsDO::getGiftAmount, reqVO.getGiftAmount())
.eqIfPresent(GiftMoneyDetailsDO::getRechargeAmount, reqVO.getRechargeAmount())
.betweenIfPresent(GiftMoneyDetailsDO::getStartTime, reqVO.getStartTime())
.betweenIfPresent(GiftMoneyDetailsDO::getEndTime, reqVO.getEndTime());
Integer rechargeType = reqVO.getRechargeType();
// WECHAT_AND_ALIPAY查全部、否则查WECHAT_AND_ALIPAY+查询类型
if (ObjectUtil.isNotNull(rechargeType) && !RechargeTypeEnum.isWechatAndAlipay(rechargeType)) {
queryWrapper.in(GiftMoneyDetailsDO::getRechargeType, Arrays.asList(RechargeTypeEnum.WECHAT_AND_ALIPAY.getStatus(), rechargeType));
}
if (reqVO.getOrder() == null) {
queryWrapper.orderByDesc(GiftMoneyDetailsDO::getId);
}else {
@@ -35,4 +35,24 @@ public enum PayChannelCodeEnum {
}
return null;
}
/**
* 是否支付宝渠道
*
* @param type
* @return
*/
public static boolean isAlipay(Integer type) {
return ALIPAY_PC.code.equals(type);
}
/**
* 是否微信渠道
*
* @param type
* @return
*/
public static boolean isWechat(Integer type) {
return WECHAT_NATIVE.code.equals(type);
}
}
@@ -1,7 +1,6 @@
package com.cf.imes.module.system.job.pay;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import com.cf.imes.module.system.service.pay.PayOrderService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
@@ -25,9 +25,10 @@ public interface OrganAmountService {
*
* @param organId
* @param amount 充值金额
* @param gift 赠送金额
* @return
*/
OrganRechargeAmountRespVO recharge(Long organId, BigDecimal amount);
OrganRechargeAmountRespVO recharge(Long organId, BigDecimal amount, BigDecimal gift);
/**
* 组织购买产品
@@ -7,8 +7,8 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.util.Assert.AssertUtils;
import com.cf.imes.framework.common.util.date.DateUtils;
import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.mybatis.core.query.LambdaUpdateWrapperX;
import com.cf.imes.module.executor.api.funds.ExecutorFundsApi;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.AllOrganAmountRespVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganAmountRespVO;
@@ -61,20 +61,22 @@ public class OrganAmountServiceImpl implements OrganAmountService {
}
@Override
public OrganRechargeAmountRespVO recharge(Long organId, BigDecimal price) {
public OrganRechargeAmountRespVO recharge(Long organId, BigDecimal price, BigDecimal gift) {
OrganAmountDO organAmountDO = organAmountMapper.selectOne(new LambdaQueryWrapper<OrganAmountDO>().eq(OrganAmountDO::getOrganId, organId));
int updated = organAmountMapper.update(new LambdaUpdateWrapper<OrganAmountDO>()
int updated = organAmountMapper.update(new LambdaUpdateWrapperX<OrganAmountDO>()
.eq(OrganAmountDO::getOrganId, organId)
.eq(OrganAmountDO::getVersion, organAmountDO.getVersion())
.setIfPresent(OrganAmountDO::getGiftAmount, gift)
.set(OrganAmountDO::getAmount, organAmountDO.getAmount().add(price))
.set(OrganAmountDO::getVersion, organAmountDO.getVersion() + 1));
// 1. 首次更新失败,认为出现并发,再查一次再更新
if (updated == 0) {
organAmountDO = organAmountMapper.selectOne(new LambdaQueryWrapper<OrganAmountDO>().eq(OrganAmountDO::getOrganId, organId));
updated = organAmountMapper.update(new LambdaUpdateWrapper<OrganAmountDO>()
updated = organAmountMapper.update(new LambdaUpdateWrapperX<OrganAmountDO>()
.eq(OrganAmountDO::getOrganId, organId)
.eq(OrganAmountDO::getVersion, organAmountDO.getVersion())
.setIfPresent(OrganAmountDO::getGiftAmount, gift)
.set(OrganAmountDO::getAmount, organAmountDO.getAmount().add(price))
.set(OrganAmountDO::getVersion, organAmountDO.getVersion() + 1));
// 2. 第二次更新失败,资金表可能不存在
@@ -37,7 +37,7 @@ public interface RechargeActiveService {
void delete(Long id);
/**
* 获得充值活动
* 获得充值活动,业务异常版
*
* @param id 编号
*/
@@ -50,4 +50,11 @@ public interface RechargeActiveService {
*/
PageResult<GiftMoneyDetailsDO> getPage(RechargePageReqVO pageReqVO);
/**
* 查询充值活动,不存返回null,无业务异常
*
* @param id
* @return
*/
GiftMoneyDetailsDO getDefaultNull(Long id);
}
@@ -1,14 +1,15 @@
package com.cf.imes.module.system.service.funds.recharge;
import cn.hutool.core.util.IdUtil;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.common.util.Assert.AssertUtils;
import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.id.core.util.SnowflakeIdWorker3rd;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.module.system.controller.admin.funds.recharge.vo.RechargePageReqVO;
import com.cf.imes.module.system.controller.admin.funds.recharge.vo.RechargeSaveReqVO;
import com.cf.imes.module.system.dal.dataobject.funds.recharge.GiftMoneyDetailsDO;
import com.cf.imes.module.system.dal.mysql.funds.recharge.GiftMoneyDetailsMapper;
import com.cf.imes.module.system.framework.snowflake.config.MybatisIdProperties;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@@ -28,7 +29,7 @@ import static com.cf.imes.module.system.enums.ErrorCodeConstants.RECHARGE_ACTIVE
public class RechargeActiveServiceImpl implements RechargeActiveService{
@Resource
private SnowflakeIdWorker3rd idWorker;
private MybatisIdProperties mybatisIdProperties;
@Resource
private GiftMoneyDetailsMapper giftMoneyDetailsMapper;
@@ -36,7 +37,7 @@ public class RechargeActiveServiceImpl implements RechargeActiveService{
@Override
public Long create(RechargeSaveReqVO createReqVO) {
long id = idWorker.nextId();
long id = IdUtil.getSnowflake(mybatisIdProperties.getWorkerId(), mybatisIdProperties.getDatacenterId()).nextId();
GiftMoneyDetailsDO giftMoneyDetailsDO = giftMoneyDetailsMapper.selectOne(new LambdaQueryWrapperX<GiftMoneyDetailsDO>()
.eq(GiftMoneyDetailsDO::getDeleted, false)
@@ -78,6 +79,10 @@ public class RechargeActiveServiceImpl implements RechargeActiveService{
return validateRechargeActiveExists(id);
}
@Override
public GiftMoneyDetailsDO getDefaultNull(Long id) {
return giftMoneyDetailsMapper.selectById(id);
}
@Override
public PageResult<GiftMoneyDetailsDO> getPage(RechargePageReqVO pageReqVO) {
@@ -33,16 +33,20 @@ import com.cf.imes.module.system.dal.dataobject.funds.organamount.OrganAmountDO;
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDO;
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDetailDO;
import com.cf.imes.module.system.dal.dataobject.funds.purchase.PurchaseRecordDO;
import com.cf.imes.module.system.dal.dataobject.funds.recharge.GiftMoneyDetailsDO;
import com.cf.imes.module.system.dal.dataobject.incomeandexpense.IncomeExpenseDetailsDO;
import com.cf.imes.module.system.enums.pay.IncomeExpenseTypeEnum;
import com.cf.imes.module.system.enums.pay.PayChannelCodeEnum;
import com.cf.imes.module.system.enums.pay.PayConstants;
import com.cf.imes.module.system.enums.pay.PayProductChannelCodeEnum;
import com.cf.imes.module.system.enums.pay.TradeTypeEnum;
import com.cf.imes.module.system.enums.recharge.RechargeGiftTypeEnum;
import com.cf.imes.module.system.enums.recharge.RechargeTypeEnum;
import com.cf.imes.module.system.framework.snowflake.config.MybatisIdProperties;
import com.cf.imes.module.system.service.funds.incomeandexpense.IncomeExpenseService;
import com.cf.imes.module.system.service.funds.organamount.OrganAmountService;
import com.cf.imes.module.system.service.funds.products.ProductsDetailService;
import com.cf.imes.module.system.service.funds.recharge.RechargeActiveService;
import com.cf.imes.module.system.service.pay.factory.impl.AbstractPayHandler;
import com.cf.imes.module.system.service.pay.factory.PayHandlerFactory;
import com.cf.imes.module.system.dal.dataobject.pay.PayOrderDO;
@@ -57,6 +61,7 @@ import jakarta.annotation.Resource;
import jakarta.validation.Validator;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
@@ -72,6 +77,8 @@ import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_ORDER_NOTIF
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_ORDER_NOT_EXIST;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_WAITING;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_ORDER_SUBMIT_CHANNEL_ERROR;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_RECHARGE_ACTIVITY_CHANNEL_MISMATCH_ERROR;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_RECHARGE_ACTIVITY_EXPIRE_ERROR;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.PAY_RECHARGE_ORDER_ORGANID_CHECK_ERROR;
/**
@@ -121,6 +128,9 @@ public class PayOrderServiceImpl implements PayOrderService {
@Resource
private MybatisIdProperties mybatisIdProperties;
@Resource
private RechargeActiveService rechargeActiveService;
@Override
@Transactional(rollbackFor = Exception.class)
public PayOrderRespDTO productPay(PayProductOrderUnifiedReqVO payProductOrderUnifiedReqVO) {
@@ -205,6 +215,13 @@ public class PayOrderServiceImpl implements PayOrderService {
// 创建支付订单
PayOrderDO payOrder = createPayOrder(payRechargeOrderReqVO.getPrice(), "imes充值", channelCode);
// 设置赠送活动编号
Long rechargeActivityId = payRechargeOrderReqVO.getRechargeActivityId();
if(ObjectUtil.isNotNull(rechargeActivityId)) {
// 校验活动类型和渠道是否匹配
validRechargeActivity(rechargeActivityId, channelCode);
payOrder.setRechargeActivityId(rechargeActivityId);
}
payOrderMapper.insert(payOrder);
// 拼接充值个性化参数
@@ -224,6 +241,72 @@ public class PayOrderServiceImpl implements PayOrderService {
}
}
/**
* 校验充值活动和渠道是否匹配
*
* @param rechargeActivityId 活动id
* @param channelCode 支付渠道编码
*/
private void validRechargeActivity(Long rechargeActivityId, Integer channelCode) {
GiftMoneyDetailsDO giftMoneyDetailsDO = rechargeActiveService.get(rechargeActivityId);
Integer rechargeType = giftMoneyDetailsDO.getRechargeType();
// 当充值活动只支持微信时,渠道只能是微信
if (RechargeTypeEnum.isWechat(rechargeType) && !PayChannelCodeEnum.isWechat(channelCode)) {
throw ServiceExceptionUtil.exception(PAY_RECHARGE_ACTIVITY_CHANNEL_MISMATCH_ERROR);
}
// 当充值活动只支持支付宝,渠道只能是支付宝
if (RechargeTypeEnum.isAlipay(rechargeType) && !PayChannelCodeEnum.isAlipay(channelCode)) {
throw ServiceExceptionUtil.exception(PAY_RECHARGE_ACTIVITY_CHANNEL_MISMATCH_ERROR);
}
// 校验是否过期
if (giftMoneyDetailsDO.getEndTime().isBefore(LocalDateTime.now())) {
throw new ServiceException(PAY_RECHARGE_ACTIVITY_EXPIRE_ERROR);
}
}
/**
* 计算赠送金
*
* @param rechargeActivityId
* @param rechargeAmount
* @return
*/
private BigDecimal calcGiftAmount(Long rechargeActivityId, BigDecimal rechargeAmount) {
BigDecimal totalGift = BigDecimal.ZERO;
if (ObjectUtil.isNull(rechargeActivityId)) {
return totalGift;
}
GiftMoneyDetailsDO rechargeActivityDO = rechargeActiveService.getDefaultNull(rechargeActivityId);
if (ObjectUtil.isNotNull(rechargeActivityDO)) {
// 赠送活动已经过期
if (rechargeActivityDO.getEndTime().isBefore(LocalDateTime.now())) {
return totalGift;
}
} else {
return totalGift;
}
BigDecimal threshold = rechargeActivityDO.getRechargeAmount();
BigDecimal giftAmount = rechargeActivityDO.getGiftAmount();
switch (RechargeGiftTypeEnum.fromStatus(rechargeActivityDO.getRechargeGiftType())) {
case FULL_X_GIVE_X:
// 满 threshold 才送 giftAmount
if (rechargeAmount.compareTo(threshold) >= 0) {
totalGift = giftAmount;
}
break;
case EVERY_X_GIVE_X:
// 每满 threshold 送 giftAmount,可累计
BigDecimal times = rechargeAmount.divide(threshold, 0, RoundingMode.FLOOR);
totalGift = times.multiply(giftAmount);
break;
}
return totalGift;
}
/**
* 创建支付订单
*
@@ -421,7 +504,11 @@ public class PayOrderServiceImpl implements PayOrderService {
String payNo = payOrderDO.getPayNo();
// 1.更新组织资金
OrganRechargeAmountRespVO rechargeAmountRespVO = organAmountService.recharge(organId, price);
// 检查赠送金是否存在已经是否在有效期,有效的话计入组织充值赠送金
BigDecimal giftAmount = calcGiftAmount(payOrderDO.getRechargeActivityId(), price);
// 更新
OrganRechargeAmountRespVO rechargeAmountRespVO = organAmountService.recharge(organId, price, giftAmount);
// 2.新增收支明细
IncomeExpenseDetailsDO incomeExpenseDetailsDO = IncomeExpenseDetailsDO.builder()
@@ -430,6 +517,7 @@ public class PayOrderServiceImpl implements PayOrderService {
.tradeType(TradeTypeEnum.RECHARGE.getCode())
.incomeExpenseType(IncomeExpenseTypeEnum.INCOME.getType())
.cashAmountChange(price)
.giftAmountChange(giftAmount)
.availableAmount(rechargeAmountRespVO.getAvailableAmount())
.amount(rechargeAmountRespVO.getAmount())
.giftAmount(rechargeAmountRespVO.getGiftAmount())
@@ -13,9 +13,9 @@ import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(
validatedBy = {PurchaseTypeValidator.class}
validatedBy = {RechargeGiftTypeValidator.class}
)
public @interface PurchaseType {
public @interface RechargeGiftTypeValid {
String message() default "赠送类型不合法,0:满X送X; 1:每满X送X";
@@ -1,8 +1,8 @@
package com.cf.imes.module.system.validation.recharge;
import cn.hutool.core.util.ObjectUtil;
import com.cf.imes.module.system.enums.recharge.PurchaseTypeEnum;
import com.cf.imes.module.system.enums.recharge.RechargeGiftTypeEnum;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import java.util.Objects;
@@ -10,14 +10,14 @@ import java.util.Objects;
/**
* 赠送类型校验器
*/
public class PurchaseTypeValidator implements ConstraintValidator<PurchaseType, Integer> {
public class RechargeGiftTypeValidator implements ConstraintValidator<RechargeGiftTypeValid, Integer> {
@Override
public boolean isValid(Integer value, ConstraintValidatorContext context) {
if (ObjectUtil.isNull(value)) {
return true;
}
for (PurchaseTypeEnum statusEnum : PurchaseTypeEnum.values()) {
for (RechargeGiftTypeEnum statusEnum : RechargeGiftTypeEnum.values()) {
if (Objects.equals(statusEnum.getStatus(), value)) {
return true;
}