TASK: 推广码 添加开始生效时间;优化数据计算类型,使用BigDecimal替换float;更新paidCommission后自动计算unpaidCommission
This commit is contained in:
@@ -81,5 +81,7 @@ public class CommonConstant {
|
||||
|
||||
public static final String TIME_FORMAT_MMM_dd_yyyy = "MMM. dd, yyyy";
|
||||
|
||||
public static final String TIME_FORMAT_yyyy_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
public static final String AFFILIATE_LINK = "https://www.aida.com.hk?ref=";
|
||||
}
|
||||
|
||||
@@ -137,9 +137,11 @@ public class StripeController {
|
||||
|
||||
@ApiOperation("更新推广码信息")
|
||||
@GetMapping("/updatePromCodeInfo")
|
||||
public Response<ProductCoupons> updateCouponsInfo(@RequestParam Long id, @RequestParam(required = false) Long paidCommission,
|
||||
@RequestParam(required = false) String cooperator, @RequestParam(required = false) String remark){
|
||||
return Response.success(stripeService.updateCouponsInfo(id, paidCommission, cooperator, remark));
|
||||
public Response<ProductCoupons> updateCouponsInfo(@RequestParam Long id, @RequestParam(required = false) String paidCommission,
|
||||
@RequestParam(required = false) String cooperator,
|
||||
@RequestParam(required = false) String remark,
|
||||
@RequestParam(required = false) Long startTime){
|
||||
return Response.success(stripeService.updateCouponsInfo(id, paidCommission, cooperator, remark, startTime));
|
||||
}
|
||||
|
||||
@ApiOperation("删除推广码")
|
||||
|
||||
@@ -7,6 +7,8 @@ import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@TableName("t_product_coupons")
|
||||
@@ -20,6 +22,8 @@ public class ProductCoupons extends BaseEntity{
|
||||
private String promotionCodeId;
|
||||
// 对应的推广码
|
||||
private String promotionCode;
|
||||
// 优惠券有效期开始时间
|
||||
private Long startTime;
|
||||
// 最大兑换次数
|
||||
private Long maxRedemptions;
|
||||
// 优惠券的折扣
|
||||
@@ -29,13 +33,13 @@ public class ProductCoupons extends BaseEntity{
|
||||
// 合作者
|
||||
private String cooperator;
|
||||
// 使用了该优惠券支付的总金额
|
||||
private float totalEarnings;
|
||||
private BigDecimal totalEarnings = BigDecimal.ZERO;
|
||||
// 佣金
|
||||
private float commission;
|
||||
private BigDecimal commission = BigDecimal.ZERO;
|
||||
// 已付佣金
|
||||
private float paidCommission;
|
||||
private BigDecimal paidCommission = BigDecimal.ZERO;
|
||||
// 未付佣金
|
||||
private float unpaidCommission;
|
||||
private BigDecimal unpaidCommission = BigDecimal.ZERO;
|
||||
// 备注
|
||||
private String remark;
|
||||
|
||||
|
||||
@@ -14,7 +14,9 @@ public class CreateCouponDTO {
|
||||
@NotNull(message = "Please set the commissionRate.")
|
||||
private Float commissionRate;
|
||||
@ApiModelProperty("推广码到期时间 秒级时间戳")
|
||||
private Long timestamp;
|
||||
private Long endTime;
|
||||
@ApiModelProperty("推广码开始时间 秒级时间戳")
|
||||
private Long startTime;
|
||||
@ApiModelProperty("推广码最大使用次数")
|
||||
private Long maxRedemptions;
|
||||
@ApiModelProperty("合作者/机构名")
|
||||
|
||||
@@ -9,7 +9,7 @@ import lombok.NoArgsConstructor;
|
||||
@NoArgsConstructor
|
||||
public class CheckCouponsVO {
|
||||
|
||||
@ApiModelProperty("expired || invalid || valid")
|
||||
@ApiModelProperty("expired 过期 || invalid 无效 || valid 有效 || pending 尚未生效")
|
||||
private String status;
|
||||
|
||||
private String message;
|
||||
|
||||
@@ -61,7 +61,7 @@ public interface StripeService {
|
||||
|
||||
CheckCouponsVO checkProductCoupon(String promotionCode, Long price);
|
||||
|
||||
ProductCoupons updateCouponsInfo(Long id, Long paidCommission, String cooperator, String remark);
|
||||
ProductCoupons updateCouponsInfo(Long id, String paidCommission, String cooperator, String remark, Long startTime);
|
||||
|
||||
ProductCoupons getProductCoupon(String promotionCode, String promotionCodeId);
|
||||
|
||||
|
||||
@@ -31,9 +31,11 @@ import org.springframework.util.CollectionUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@@ -342,49 +344,66 @@ public class AffiliateServiceImpl extends ServiceImpl<AffiliateMapper, Affiliate
|
||||
return baseMapper.selectOne(queryWrapper);
|
||||
}
|
||||
|
||||
public void calcCouponsCommission(){
|
||||
public void calcCouponsCommission() {
|
||||
String lastTime = redisUtil.getFromString(RedisUtil.PAYMENT_INFO_LAST_SCAN_TIME);
|
||||
log.info("优惠券佣金计算,上次执行时间:{}", lastTime);
|
||||
String currentTime = LocalDateTime.now().toString();
|
||||
// 1、查上次更新之后有无使用了优惠券的新订单
|
||||
|
||||
// 1. 查询新增的优惠券订单
|
||||
QueryWrapper<PaymentInfo> queryWrapper = new QueryWrapper<>();
|
||||
queryWrapper.eq("trade_state","paid")
|
||||
queryWrapper.eq("trade_state", "paid")
|
||||
.lt("create_time", currentTime)
|
||||
.isNotNull("promotion_code");
|
||||
if (!StringUtil.isNullOrEmpty(lastTime)){
|
||||
queryWrapper.gt("create_time", lastTime);
|
||||
}
|
||||
List<PaymentInfo> paymentInfos = paymentInfoService.getBaseMapper().selectList(queryWrapper);
|
||||
Optional.ofNullable(lastTime)
|
||||
.filter(time -> !time.isEmpty())
|
||||
.ifPresent(time -> queryWrapper.gt("create_time", time));
|
||||
|
||||
List<PaymentInfo> paymentInfos = paymentInfoService.list(queryWrapper);
|
||||
log.info("目前,新增使用优惠券的订单数:{}", paymentInfos.size());
|
||||
|
||||
// key:推广码, value:用户支付的金额
|
||||
HashMap<String, Float> codeAmount = new HashMap<>();
|
||||
if (!paymentInfos.isEmpty()){
|
||||
for (PaymentInfo paymentInfo : paymentInfos){
|
||||
String promotionCode = paymentInfo.getPromotionCode();
|
||||
Float sum = codeAmount.get(promotionCode);
|
||||
if (sum == null || sum == 0.0f){
|
||||
codeAmount.put(promotionCode, paymentInfo.getPayerTotal());
|
||||
}else {
|
||||
codeAmount.put(promotionCode, sum + paymentInfo.getPayerTotal());
|
||||
}
|
||||
// 2. 按推广码汇总支付金额
|
||||
Map<String, BigDecimal> codeAmount = paymentInfos.stream()
|
||||
.collect(Collectors.toMap(
|
||||
PaymentInfo::getPromotionCode,
|
||||
payment -> new BigDecimal(payment.getPayerTotal()),
|
||||
BigDecimal::add
|
||||
));
|
||||
|
||||
// 3. 更新佣金数据
|
||||
codeAmount.forEach((promotionCode, amount) -> {
|
||||
ProductCoupons coupon = stripeService.getProductCoupon(promotionCode, null);
|
||||
if (coupon != null) {
|
||||
updateCouponCommission(coupon, amount);
|
||||
productCouponsMapper.updateById(coupon);
|
||||
}
|
||||
for (Map.Entry<String, Float> entry : codeAmount.entrySet()){
|
||||
String promotionCode = entry.getKey();
|
||||
ProductCoupons productCoupons = stripeService.getProductCoupon(promotionCode, null);
|
||||
if (!Objects.isNull(productCoupons)){
|
||||
// 2、计算支付金额的总和,更新totalEarnings,commission,unpaidCommission
|
||||
float sum = productCoupons.getTotalEarnings() + entry.getValue();
|
||||
productCoupons.setTotalEarnings(sum);
|
||||
float commission = sum * productCoupons.getCommissionRate() / 100;
|
||||
productCoupons.setCommission(commission);
|
||||
productCoupons.setUnpaidCommission(commission - productCoupons.getPaidCommission());
|
||||
productCouponsMapper.updateById(productCoupons);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 4. 更新最后执行时间
|
||||
redisUtil.addToString(RedisUtil.PAYMENT_INFO_LAST_SCAN_TIME, currentTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新优惠券的佣金数据
|
||||
*/
|
||||
private void updateCouponCommission(ProductCoupons coupon, BigDecimal newAmount) {
|
||||
// 总收益 = 原收益(默认0) + 新增金额
|
||||
BigDecimal totalEarnings = Optional.ofNullable(coupon.getTotalEarnings())
|
||||
.orElse(BigDecimal.ZERO)
|
||||
.add(newAmount);
|
||||
coupon.setTotalEarnings(totalEarnings);
|
||||
|
||||
// 佣金 = 总收益 × 佣金比例(需除以100)
|
||||
BigDecimal commission = totalEarnings.multiply(
|
||||
BigDecimal.valueOf(coupon.getCommissionRate())
|
||||
.divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
|
||||
coupon.setCommission(commission);
|
||||
|
||||
// 未支付佣金 = 总佣金 - 已支付佣金(默认0)
|
||||
BigDecimal unpaidCommission = commission.subtract(
|
||||
Optional.ofNullable(coupon.getPaidCommission())
|
||||
.orElse(BigDecimal.ZERO));
|
||||
coupon.setUnpaidCommission(unpaidCommission);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1413,8 +1413,8 @@ public class StripeServiceImpl implements StripeService {
|
||||
.setDuration(CouponCreateParams.Duration.ONCE)
|
||||
// percent_off 与 amount_off 不能同时设置
|
||||
.setPercentOff(BigDecimal.valueOf(createCouponDTO.getPercentOff()));
|
||||
if (Objects.nonNull(createCouponDTO.getTimestamp())){
|
||||
couponParams.setRedeemBy(createCouponDTO.getTimestamp());
|
||||
if (Objects.nonNull(createCouponDTO.getEndTime())){
|
||||
couponParams.setRedeemBy(createCouponDTO.getEndTime());
|
||||
}
|
||||
try {
|
||||
// 1、创建优惠券
|
||||
@@ -1422,9 +1422,10 @@ public class StripeServiceImpl implements StripeService {
|
||||
// 2、创建一个推广码
|
||||
PromotionCode promotionCode = createPromotionCode(coupon.getId(), createCouponDTO.getMaxRedemptions());
|
||||
// 3、落库
|
||||
ProductCoupons productCoupons = new ProductCoupons(coupon.getId(), createCouponDTO.getTimestamp(), promotionCode.getId(),
|
||||
ProductCoupons productCoupons = new ProductCoupons(coupon.getId(), createCouponDTO.getEndTime(), promotionCode.getId(),
|
||||
promotionCode.getCode(), createCouponDTO.getMaxRedemptions(), createCouponDTO.getPercentOff(),
|
||||
createCouponDTO.getCommissionRate(), createCouponDTO.getCooperator(), createCouponDTO.getRemark());
|
||||
productCoupons.setStartTime(createCouponDTO.getStartTime());
|
||||
productCoupons.setCreateTime(LocalDateTime.now());
|
||||
productCouponsMapper.insert(productCoupons);
|
||||
|
||||
@@ -1450,7 +1451,7 @@ public class StripeServiceImpl implements StripeService {
|
||||
}
|
||||
}
|
||||
|
||||
public ProductCoupons updateCouponsInfo(Long id, Long paidCommission, String cooperator, String remark){
|
||||
public ProductCoupons updateCouponsInfo(Long id, String paidCommission, String cooperator, String remark, Long startTime){
|
||||
ProductCoupons productCoupons = productCouponsMapper.selectById(id);
|
||||
if (Objects.isNull(productCoupons)){
|
||||
throw new BusinessException("Unknown Promotion Code");
|
||||
@@ -1465,7 +1466,22 @@ public class StripeServiceImpl implements StripeService {
|
||||
flag = true;
|
||||
}
|
||||
if (Objects.nonNull(paidCommission)){
|
||||
productCoupons.setPaidCommission(paidCommission);
|
||||
// 将 paidCommission 从 String 转换为 BigDecimal
|
||||
if (!paidCommission.matches("-?\\d+(\\.\\d+)?")) {
|
||||
throw new BusinessException("Invalid paidCommission value: " + paidCommission);
|
||||
}
|
||||
BigDecimal paidCommissionBigDecimal = new BigDecimal(paidCommission);
|
||||
// 设置已支付佣金
|
||||
productCoupons.setPaidCommission(paidCommissionBigDecimal);
|
||||
BigDecimal commission = Objects.isNull(productCoupons.getCommission()) ? new BigDecimal(0) : productCoupons.getCommission();
|
||||
// 计算未支付佣金
|
||||
BigDecimal unpaidCommission = commission.subtract(paidCommissionBigDecimal);
|
||||
// 设置未支付佣金,确保其不为负数
|
||||
productCoupons.setUnpaidCommission(unpaidCommission.compareTo(BigDecimal.ZERO) > 0 ? unpaidCommission : BigDecimal.ZERO);
|
||||
flag = true;
|
||||
}
|
||||
if (Objects.nonNull(startTime)){
|
||||
productCoupons.setStartTime(startTime);
|
||||
flag = true;
|
||||
}
|
||||
if (flag){
|
||||
@@ -1478,6 +1494,7 @@ public class StripeServiceImpl implements StripeService {
|
||||
public ProductCoupons checkProductCoupon(String promotionCode){
|
||||
Stripe.apiKey = privateKey;
|
||||
Long accountId = UserContext.getUserHolder().getId();
|
||||
String language = UserContext.getUserHolder().getLanguage();
|
||||
// 1、从数据库查找promotionCode对应的promotionCodeId
|
||||
ProductCoupons productCoupons = productCouponsMapper.selectOne(new QueryWrapper<ProductCoupons>().eq("promotion_code", promotionCode));
|
||||
if (Objects.nonNull(productCoupons)){
|
||||
@@ -1486,6 +1503,11 @@ public class StripeServiceImpl implements StripeService {
|
||||
Long redeemBy = productCoupons.getRedeemBy();
|
||||
if (redeemBy < epochSecondNow){
|
||||
throw new BusinessException("this.promotion.code.has.expired");
|
||||
} else if (Objects.nonNull(productCoupons.getStartTime()) && productCoupons.getStartTime() > epochSecondNow) {
|
||||
String startTime = DateUtil.changeTimeStampFormat(productCoupons.getStartTime(), "seconds", CommonConstant.TIME_FORMAT_yyyy_MM_dd_HH_mm_ss);
|
||||
String en = "This coupon will become active on " + startTime + ". Please try again then!";
|
||||
String cn = "该优惠券尚未到生效时间,请在 " + startTime + " 后使用。";
|
||||
throw new BusinessException(language.equals("ENGLISH") ? en : cn);
|
||||
} else {
|
||||
// 判断该用户是否有成功使用过这个推广码
|
||||
List<PaymentInfo> paymentInfoByPromCode = paymentInfoService.getPaymentInfoByPromCode(accountId, promotionCode);
|
||||
@@ -1507,6 +1529,7 @@ public class StripeServiceImpl implements StripeService {
|
||||
public CheckCouponsVO checkProductCoupon(String promotionCode, Long price){
|
||||
Stripe.apiKey = privateKey;
|
||||
Long accountId = UserContext.getUserHolder().getId();
|
||||
String language = UserContext.getUserHolder().getLanguage();
|
||||
CheckCouponsVO checkCouponsVO = new CheckCouponsVO();
|
||||
// 1、从数据库查找promotionCode对应的promotionCodeId
|
||||
ProductCoupons productCoupons = productCouponsMapper.selectOne(new QueryWrapper<ProductCoupons>().eq("promotion_code", promotionCode));
|
||||
@@ -1518,7 +1541,13 @@ public class StripeServiceImpl implements StripeService {
|
||||
String msg = BusinessException.getMessageFromResource("this.promotion.code.has.expired");
|
||||
checkCouponsVO.setMessage(msg);
|
||||
checkCouponsVO.setStatus("expired");
|
||||
}else {
|
||||
}else if (Objects.nonNull(productCoupons.getStartTime()) && productCoupons.getStartTime() > epochSecondNow) {
|
||||
String startTime = DateUtil.changeTimeStampFormat(productCoupons.getStartTime(), "seconds", CommonConstant.TIME_FORMAT_yyyy_MM_dd_HH_mm_ss);
|
||||
String en = "This coupon will become active on " + startTime + ". Please try again then!";
|
||||
String cn = "该优惠券尚未到生效时间,请在 " + startTime + " 后使用。";
|
||||
checkCouponsVO.setMessage(language.equals("ENGLISH") ? en : cn);
|
||||
checkCouponsVO.setStatus("pending");
|
||||
} else {
|
||||
// 判断该用户是否有成功使用过这个推广码
|
||||
List<PaymentInfo> paymentInfoByPromCode = paymentInfoService.getPaymentInfoByPromCode(accountId, promotionCode);
|
||||
if (paymentInfoByPromCode.isEmpty()) {
|
||||
|
||||
Reference in New Issue
Block a user