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); super.eq(column, val);
return this; 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 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_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 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 ============ //=========== 支付相关 1-002-048-000 ============
public static final ErrorCode PAY_CHANNEL_NOT_SUPPORT = new ErrorCode(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_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_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_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_GIFT_BALANCE_INSUFFICIENT = new ErrorCode(1_002_048_011, "赠送金余额不足,请选择其他支付方式!");
public static final ErrorCode PAY_PRODUCT_AVAILABLE_BALANCE_INSUFFICIENT = new ErrorCode(1_002_048_010, "可用金(现金余额+赠送金)余额不足,请选择其他支付方式!"); public static final ErrorCode PAY_PRODUCT_AVAILABLE_BALANCE_INSUFFICIENT = new ErrorCode(1_002_048_012, "可用金(现金余额+赠送金)余额不足,请选择其他支付方式!");
//=========== 产品相关 1-002-045-000 ============ //=========== 产品相关 1-002-045-000 ============
public static final ErrorCode PRODUCTS_NO_EXIST = new ErrorCode(1_002_045_001, "当前产品不存在"); 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 @AllArgsConstructor
public enum RechargeTypeEnum implements IntArrayValuable { public enum RechargeTypeEnum implements IntArrayValuable {
ONE(0, "微信、支付宝"), WECHAT_AND_ALIPAY(0, "微信、支付宝"),
TWO(1, "微信"), WECHAT(1, "微信"),
THREE(2, "支付宝"); ALIPAY(2, "支付宝");
public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(RechargeTypeEnum::getStatus).toArray(); public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(RechargeTypeEnum::getStatus).toArray();
@@ -36,15 +36,27 @@ public enum RechargeTypeEnum implements IntArrayValuable {
return ARRAYS; return ARRAYS;
} }
public static boolean isOne(String name) { public static boolean isWechatAndAlipay(String name) {
return Objects.equals(ONE.name, name); return Objects.equals(WECHAT_AND_ALIPAY.name, name);
} }
public static boolean isTwo(String name) { public static boolean isWechat(String name) {
return Objects.equals(TWO.name, name); return Objects.equals(WECHAT.name, name);
} }
public static boolean isThree(String name) { public static boolean isAlipay(String name) {
return Objects.equals(THREE.name, 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 @Resource
private RechargeActiveService productsService; private RechargeActiveService productsService;
@PostMapping("") @PutMapping("")
@Operation(summary = "新建充值活动") @Operation(summary = "新建充值活动")
@PreAuthorize("@ss.hasPermission('base:recharge-active:create')") @PreAuthorize("@ss.hasPermission('base:recharge-active:create')")
public CommonResult<Long> createRechargeActive(@Valid @RequestBody RechargeSaveReqVO createReqVO) { public CommonResult<Long> createRechargeActive(@Valid @RequestBody RechargeSaveReqVO createReqVO) {
return success(productsService.create(createReqVO)); return success(productsService.create(createReqVO));
} }
@PutMapping("") @PostMapping("")
@Operation(summary = "更新充值活动") @Operation(summary = "更新充值活动")
@PreAuthorize("@ss.hasPermission('base:recharge-active:update')") @PreAuthorize("@ss.hasPermission('base:recharge-active:update')")
public CommonResult<Boolean> updateRechargeActive(@Valid @RequestBody RechargeSaveReqVO updateReqVO) { public CommonResult<Boolean> updateRechargeActive(@Valid @RequestBody RechargeSaveReqVO updateReqVO) {
@@ -44,17 +44,17 @@ public class RechargeActiveController {
return success(true); return success(true);
} }
@DeleteMapping("") @DeleteMapping("/{id}")
@Operation(summary = "删除充值活动") @Operation(summary = "删除充值活动")
@Parameter(name = "id", description = "编号", required = true) @Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('base:recharge-active:delete')") @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); productsService.delete(id);
return success(true); return success(true);
} }
@GetMapping("/{id}") @GetMapping("/{id}")
@Operation(summary = "充值活动") @Operation(summary = "充值活动")
@Parameter(name = "id", description = "编号", required = true, example = "1024") @Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('base:recharge-active:query')") @PreAuthorize("@ss.hasPermission('base:recharge-active:query')")
public CommonResult<RechargeRespVO> getRechargeActive(@PathVariable("id") Long id) { public CommonResult<RechargeRespVO> getRechargeActive(@PathVariable("id") Long id) {
@@ -63,7 +63,7 @@ public class RechargeActiveController {
} }
@GetMapping("/page") @GetMapping("/page")
@Operation(summary = "充值活动分页") @Operation(summary = "充值活动分页")
@PreAuthorize("@ss.hasPermission('base:recharge-active:query')") @PreAuthorize("@ss.hasPermission('base:recharge-active:query')")
public CommonResult<PageResult<RechargeRespVO>> getRechargeActivePage(@Valid RechargePageReqVO pageReqVO) { public CommonResult<PageResult<RechargeRespVO>> getRechargeActivePage(@Valid RechargePageReqVO pageReqVO) {
PageResult<GiftMoneyDetailsDO> pageResult = productsService.getPage(pageReqVO); PageResult<GiftMoneyDetailsDO> pageResult = productsService.getPage(pageReqVO);
@@ -1,7 +1,7 @@
package com.cf.imes.module.system.controller.admin.funds.recharge.vo; package com.cf.imes.module.system.controller.admin.funds.recharge.vo;
import com.cf.imes.framework.common.pojo.PageParam; 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 com.cf.imes.module.system.validation.recharge.RechargeType;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
@@ -26,11 +26,11 @@ public class RechargePageReqVO extends PageParam {
@Schema(description = "活动名称", example = "赵六") @Schema(description = "活动名称", example = "赵六")
private String activityName; private String activityName;
@Schema(description = "赠送类型", example = "0满X送X 1每满X送X") @Schema(description = "赠送类型0:满X送X、1:每满X送X", example = "0")
@PurchaseType @RechargeGiftTypeValid
private Integer purchaseType; private Integer rechargeGiftType;
@Schema(description = "充值类型", example = "0微信、支付宝 1微信 2支付宝") @Schema(description = "充值类型,0:微信&支付宝、1:微信、2:支付宝", example = "0")
@RechargeType @RechargeType
private Integer rechargeType; private Integer rechargeType;
@@ -1,18 +1,15 @@
package com.cf.imes.module.system.controller.admin.funds.recharge.vo; 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.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 com.cf.imes.module.system.validation.recharge.RechargeType;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime; 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") @Schema(description = "管理后台 - 赠送金活动表 gift_money 新增/修改 Request VO")
@Data @Data
public class RechargeSaveReqVO { public class RechargeSaveReqVO {
@@ -24,12 +21,12 @@ public class RechargeSaveReqVO {
@NotNull(message = "活动名称不能为空") @NotNull(message = "活动名称不能为空")
private String activityName; 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 = "赠送类型不能为空") @NotNull(message = "赠送类型不能为空")
@PurchaseType @RechargeGiftTypeValid
private Integer purchaseType; 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 = "充值类型不能为空") @NotNull(message = "充值类型不能为空")
@RechargeType @RechargeType
private Integer rechargeType; private Integer rechargeType;
@@ -45,23 +42,14 @@ public class RechargeSaveReqVO {
private BigDecimal giftAmount; private BigDecimal giftAmount;
@Schema(description = "开始时间") @Schema(description = "开始时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@NotNull(message = "开始时间不能为空") @NotNull(message = "开始时间不能为空")
private LocalDateTime startTime; private LocalDateTime startTime;
@Schema(description = "结束时间") @Schema(description = "结束时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
@NotNull(message = "结束时间不能为空") @NotNull(message = "结束时间不能为空")
private LocalDateTime endTime; private LocalDateTime endTime;
@Schema(description = "操作时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime updateTime;
@Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") @Schema(description = "备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六")
private String remark; private String remark;
@Schema(description = "是否删除")
private Integer deleted;
} }
@@ -32,4 +32,7 @@ public class PayRechargeOrderReqVO {
@PayChannelCodeValid @PayChannelCodeValid
@NotNull(message = "支付渠道编码不能为空") @NotNull(message = "支付渠道编码不能为空")
private Integer channelCode; 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 * 赠送类型 0满X送X; 1每满X送X
*/ */
private Integer purchaseType; private Integer rechargeGiftType;
/** /**
* 充值类型 0微信、支付宝 1微信 2支付宝 * 充值类型 0微信、支付宝 1微信 2支付宝
*/ */
@@ -53,6 +53,11 @@ public class PayOrderDO extends BaseDO {
*/ */
private BigDecimal price; private BigDecimal price;
/**
* 充值赠送活动编号
*/
private Long rechargeActivityId;
/** /**
* 支付订单号:P + 当前id + 时间戳(yyyyMMddHHmmss * 支付订单号:P + 当前id + 时间戳(yyyyMMddHHmmss
*/ */
@@ -1,12 +1,16 @@
package com.cf.imes.module.system.dal.mysql.funds.recharge; 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.common.pojo.PageResult;
import com.cf.imes.framework.mybatis.core.mapper.BaseMapperX; import com.cf.imes.framework.mybatis.core.mapper.BaseMapperX;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX; 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.RechargePageReqVO;
import com.cf.imes.module.system.dal.dataobject.funds.recharge.GiftMoneyDetailsDO; 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 org.apache.ibatis.annotations.Mapper;
import java.util.Arrays;
/** /**
* 赠送金活动详情表 gift_money_details Mapper * 赠送金活动详情表 gift_money_details Mapper
* *
@@ -17,13 +21,18 @@ public interface GiftMoneyDetailsMapper extends BaseMapperX<GiftMoneyDetailsDO>
default PageResult<GiftMoneyDetailsDO> selectPage(RechargePageReqVO reqVO) { default PageResult<GiftMoneyDetailsDO> selectPage(RechargePageReqVO reqVO) {
LambdaQueryWrapperX<GiftMoneyDetailsDO> queryWrapper = new LambdaQueryWrapperX<GiftMoneyDetailsDO>() LambdaQueryWrapperX<GiftMoneyDetailsDO> queryWrapper = new LambdaQueryWrapperX<GiftMoneyDetailsDO>()
.likeIfPresent(GiftMoneyDetailsDO::getActivityName, reqVO.getActivityName()) .likeIfPresent(GiftMoneyDetailsDO::getActivityName, reqVO.getActivityName())
.eqIfPresent(GiftMoneyDetailsDO::getPurchaseType, reqVO.getPurchaseType()) .eqIfPresent(GiftMoneyDetailsDO::getRechargeGiftType, reqVO.getRechargeGiftType())
.eqIfPresent(GiftMoneyDetailsDO::getRechargeType, reqVO.getRechargeType())
.eqIfPresent(GiftMoneyDetailsDO::getGiftAmount, reqVO.getGiftAmount()) .eqIfPresent(GiftMoneyDetailsDO::getGiftAmount, reqVO.getGiftAmount())
.eqIfPresent(GiftMoneyDetailsDO::getRechargeAmount, reqVO.getRechargeAmount()) .eqIfPresent(GiftMoneyDetailsDO::getRechargeAmount, reqVO.getRechargeAmount())
.betweenIfPresent(GiftMoneyDetailsDO::getStartTime, reqVO.getStartTime()) .betweenIfPresent(GiftMoneyDetailsDO::getStartTime, reqVO.getStartTime())
.betweenIfPresent(GiftMoneyDetailsDO::getEndTime, reqVO.getEndTime()); .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) { if (reqVO.getOrder() == null) {
queryWrapper.orderByDesc(GiftMoneyDetailsDO::getId); queryWrapper.orderByDesc(GiftMoneyDetailsDO::getId);
}else { }else {
@@ -35,4 +35,24 @@ public enum PayChannelCodeEnum {
} }
return null; 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; package com.cf.imes.module.system.job.pay;
import cn.hutool.core.text.CharSequenceUtil; import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import com.cf.imes.module.system.service.pay.PayOrderService; import com.cf.imes.module.system.service.pay.PayOrderService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@@ -25,9 +25,10 @@ public interface OrganAmountService {
* *
* @param organId * @param organId
* @param amount 充值金额 * @param amount 充值金额
* @param gift 赠送金额
* @return * @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.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cf.imes.framework.common.exception.ServiceException; import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.util.Assert.AssertUtils; 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.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.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.AllOrganAmountRespVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganAmountRespVO; import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganAmountRespVO;
@@ -61,20 +61,22 @@ public class OrganAmountServiceImpl implements OrganAmountService {
} }
@Override @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)); 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::getOrganId, organId)
.eq(OrganAmountDO::getVersion, organAmountDO.getVersion()) .eq(OrganAmountDO::getVersion, organAmountDO.getVersion())
.setIfPresent(OrganAmountDO::getGiftAmount, gift)
.set(OrganAmountDO::getAmount, organAmountDO.getAmount().add(price)) .set(OrganAmountDO::getAmount, organAmountDO.getAmount().add(price))
.set(OrganAmountDO::getVersion, organAmountDO.getVersion() + 1)); .set(OrganAmountDO::getVersion, organAmountDO.getVersion() + 1));
// 1. 首次更新失败,认为出现并发,再查一次再更新 // 1. 首次更新失败,认为出现并发,再查一次再更新
if (updated == 0) { if (updated == 0) {
organAmountDO = organAmountMapper.selectOne(new LambdaQueryWrapper<OrganAmountDO>().eq(OrganAmountDO::getOrganId, organId)); 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::getOrganId, organId)
.eq(OrganAmountDO::getVersion, organAmountDO.getVersion()) .eq(OrganAmountDO::getVersion, organAmountDO.getVersion())
.setIfPresent(OrganAmountDO::getGiftAmount, gift)
.set(OrganAmountDO::getAmount, organAmountDO.getAmount().add(price)) .set(OrganAmountDO::getAmount, organAmountDO.getAmount().add(price))
.set(OrganAmountDO::getVersion, organAmountDO.getVersion() + 1)); .set(OrganAmountDO::getVersion, organAmountDO.getVersion() + 1));
// 2. 第二次更新失败,资金表可能不存在 // 2. 第二次更新失败,资金表可能不存在
@@ -37,7 +37,7 @@ public interface RechargeActiveService {
void delete(Long id); void delete(Long id);
/** /**
* 获得充值活动 * 获得充值活动,业务异常版
* *
* @param id 编号 * @param id 编号
*/ */
@@ -50,4 +50,11 @@ public interface RechargeActiveService {
*/ */
PageResult<GiftMoneyDetailsDO> getPage(RechargePageReqVO pageReqVO); 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; 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.pojo.PageResult;
import com.cf.imes.framework.common.util.Assert.AssertUtils; import com.cf.imes.framework.common.util.Assert.AssertUtils;
import com.cf.imes.framework.common.util.object.BeanUtils; 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.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.RechargePageReqVO;
import com.cf.imes.module.system.controller.admin.funds.recharge.vo.RechargeSaveReqVO; 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.dataobject.funds.recharge.GiftMoneyDetailsDO;
import com.cf.imes.module.system.dal.mysql.funds.recharge.GiftMoneyDetailsMapper; 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.stereotype.Service;
import org.springframework.validation.annotation.Validated; 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{ public class RechargeActiveServiceImpl implements RechargeActiveService{
@Resource @Resource
private SnowflakeIdWorker3rd idWorker; private MybatisIdProperties mybatisIdProperties;
@Resource @Resource
private GiftMoneyDetailsMapper giftMoneyDetailsMapper; private GiftMoneyDetailsMapper giftMoneyDetailsMapper;
@@ -36,7 +37,7 @@ public class RechargeActiveServiceImpl implements RechargeActiveService{
@Override @Override
public Long create(RechargeSaveReqVO createReqVO) { 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>() GiftMoneyDetailsDO giftMoneyDetailsDO = giftMoneyDetailsMapper.selectOne(new LambdaQueryWrapperX<GiftMoneyDetailsDO>()
.eq(GiftMoneyDetailsDO::getDeleted, false) .eq(GiftMoneyDetailsDO::getDeleted, false)
@@ -78,6 +79,10 @@ public class RechargeActiveServiceImpl implements RechargeActiveService{
return validateRechargeActiveExists(id); return validateRechargeActiveExists(id);
} }
@Override
public GiftMoneyDetailsDO getDefaultNull(Long id) {
return giftMoneyDetailsMapper.selectById(id);
}
@Override @Override
public PageResult<GiftMoneyDetailsDO> getPage(RechargePageReqVO pageReqVO) { 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.ProductsDO;
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDetailDO; 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.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.dal.dataobject.incomeandexpense.IncomeExpenseDetailsDO;
import com.cf.imes.module.system.enums.pay.IncomeExpenseTypeEnum; 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.PayChannelCodeEnum;
import com.cf.imes.module.system.enums.pay.PayConstants; 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.PayProductChannelCodeEnum;
import com.cf.imes.module.system.enums.pay.TradeTypeEnum; 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.framework.snowflake.config.MybatisIdProperties;
import com.cf.imes.module.system.service.funds.incomeandexpense.IncomeExpenseService; 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.organamount.OrganAmountService;
import com.cf.imes.module.system.service.funds.products.ProductsDetailService; 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.impl.AbstractPayHandler;
import com.cf.imes.module.system.service.pay.factory.PayHandlerFactory; import com.cf.imes.module.system.service.pay.factory.PayHandlerFactory;
import com.cf.imes.module.system.dal.dataobject.pay.PayOrderDO; import com.cf.imes.module.system.dal.dataobject.pay.PayOrderDO;
@@ -57,6 +61,7 @@ import jakarta.annotation.Resource;
import jakarta.validation.Validator; import jakarta.validation.Validator;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; 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_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_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_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; 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 @Resource
private MybatisIdProperties mybatisIdProperties; private MybatisIdProperties mybatisIdProperties;
@Resource
private RechargeActiveService rechargeActiveService;
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public PayOrderRespDTO productPay(PayProductOrderUnifiedReqVO payProductOrderUnifiedReqVO) { public PayOrderRespDTO productPay(PayProductOrderUnifiedReqVO payProductOrderUnifiedReqVO) {
@@ -205,6 +215,13 @@ public class PayOrderServiceImpl implements PayOrderService {
// 创建支付订单 // 创建支付订单
PayOrderDO payOrder = createPayOrder(payRechargeOrderReqVO.getPrice(), "imes充值", channelCode); PayOrderDO payOrder = createPayOrder(payRechargeOrderReqVO.getPrice(), "imes充值", channelCode);
// 设置赠送活动编号
Long rechargeActivityId = payRechargeOrderReqVO.getRechargeActivityId();
if(ObjectUtil.isNotNull(rechargeActivityId)) {
// 校验活动类型和渠道是否匹配
validRechargeActivity(rechargeActivityId, channelCode);
payOrder.setRechargeActivityId(rechargeActivityId);
}
payOrderMapper.insert(payOrder); 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(); String payNo = payOrderDO.getPayNo();
// 1.更新组织资金 // 1.更新组织资金
OrganRechargeAmountRespVO rechargeAmountRespVO = organAmountService.recharge(organId, price); // 检查赠送金是否存在已经是否在有效期,有效的话计入组织充值赠送金
BigDecimal giftAmount = calcGiftAmount(payOrderDO.getRechargeActivityId(), price);
// 更新
OrganRechargeAmountRespVO rechargeAmountRespVO = organAmountService.recharge(organId, price, giftAmount);
// 2.新增收支明细 // 2.新增收支明细
IncomeExpenseDetailsDO incomeExpenseDetailsDO = IncomeExpenseDetailsDO.builder() IncomeExpenseDetailsDO incomeExpenseDetailsDO = IncomeExpenseDetailsDO.builder()
@@ -430,6 +517,7 @@ public class PayOrderServiceImpl implements PayOrderService {
.tradeType(TradeTypeEnum.RECHARGE.getCode()) .tradeType(TradeTypeEnum.RECHARGE.getCode())
.incomeExpenseType(IncomeExpenseTypeEnum.INCOME.getType()) .incomeExpenseType(IncomeExpenseTypeEnum.INCOME.getType())
.cashAmountChange(price) .cashAmountChange(price)
.giftAmountChange(giftAmount)
.availableAmount(rechargeAmountRespVO.getAvailableAmount()) .availableAmount(rechargeAmountRespVO.getAvailableAmount())
.amount(rechargeAmountRespVO.getAmount()) .amount(rechargeAmountRespVO.getAmount())
.giftAmount(rechargeAmountRespVO.getGiftAmount()) .giftAmount(rechargeAmountRespVO.getGiftAmount())
@@ -13,9 +13,9 @@ import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
@Constraint( @Constraint(
validatedBy = {PurchaseTypeValidator.class} validatedBy = {RechargeGiftTypeValidator.class}
) )
public @interface PurchaseType { public @interface RechargeGiftTypeValid {
String message() default "赠送类型不合法,0:满X送X; 1:每满X送X"; String message() default "赠送类型不合法,0:满X送X; 1:每满X送X";
@@ -1,8 +1,8 @@
package com.cf.imes.module.system.validation.recharge; package com.cf.imes.module.system.validation.recharge;
import cn.hutool.core.util.ObjectUtil; 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.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext; import jakarta.validation.ConstraintValidatorContext;
import java.util.Objects; 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 @Override
public boolean isValid(Integer value, ConstraintValidatorContext context) { public boolean isValid(Integer value, ConstraintValidatorContext context) {
if (ObjectUtil.isNull(value)) { if (ObjectUtil.isNull(value)) {
return true; return true;
} }
for (PurchaseTypeEnum statusEnum : PurchaseTypeEnum.values()) { for (RechargeGiftTypeEnum statusEnum : RechargeGiftTypeEnum.values()) {
if (Objects.equals(statusEnum.getStatus(), value)) { if (Objects.equals(statusEnum.getStatus(), value)) {
return true; return true;
} }