feat(voucher): 增加券码适用商品类型功能

- 在 VoucherBatchCreateReq、VoucherBatchResp 和 VoucherInfo 中添加适用商品类型列表字段
- 在 PriceVoucherBatchConfig 中添加适用商品类型列表字段,并使用 ProductTypeListTypeHandler 进行 JSON 序列化和反序列化
- 实现 ProductTypeListTypeHandler 以处理商品类型列表的 JSON 序列化和反序列化
- 更新 VoucherBatchServiceImpl 和 VoucherServiceImpl 以支持适用商品类型的筛选和计算
This commit is contained in:
2025-08-30 15:31:35 +08:00
parent 57b087a4fb
commit 966568156c
7 changed files with 182 additions and 7 deletions

View File

@@ -190,6 +190,7 @@ public class VoucherBatchServiceImpl implements VoucherBatchService {
resp.setStatusName(batch.getStatus() == 1 ? "启用" : "禁用");
resp.setAvailableCount(batch.getTotalCount() - batch.getClaimedCount());
resp.setApplicableProducts(batch.getApplicableProducts());
return resp;
}

View File

@@ -3,6 +3,7 @@ package com.ycwl.basic.pricing.service.impl;
import com.ycwl.basic.pricing.dto.DiscountDetectionContext;
import com.ycwl.basic.pricing.dto.ProductItem;
import com.ycwl.basic.pricing.dto.VoucherInfo;
import com.ycwl.basic.pricing.enums.ProductType;
import com.ycwl.basic.pricing.entity.PriceVoucherBatchConfig;
import com.ycwl.basic.pricing.entity.PriceVoucherCode;
import com.ycwl.basic.pricing.enums.VoucherCodeStatus;
@@ -197,32 +198,40 @@ public class VoucherServiceImpl implements IVoucherService {
return BigDecimal.ZERO;
}
// 筛选适用的商品
List<ProductItem> applicableItems = filterApplicableProducts(context.getProducts(), voucherInfo.getApplicableProducts());
if (applicableItems.isEmpty()) {
log.debug("券码 {} 没有适用的商品", voucherInfo.getVoucherCode());
return BigDecimal.ZERO;
}
return switch (discountType) {
case FREE_ALL -> {
// 全场免费,返回当前总金额
yield context.getCurrentAmount() != null ? context.getCurrentAmount() : BigDecimal.ZERO;
// 全场免费,计算适用商品的总金额
BigDecimal applicableAmount = calculateApplicableAmount(applicableItems, context);
yield applicableAmount;
}
case REDUCE_PRICE -> {
// 商品降价,每个商品减免固定金额
// 商品降价,每个适用商品减免固定金额
if (discountValue == null || discountValue.compareTo(BigDecimal.ZERO) <= 0) {
yield BigDecimal.ZERO;
}
BigDecimal totalDiscount = BigDecimal.ZERO;
for (ProductItem product : context.getProducts()) {
for (ProductItem product : applicableItems) {
BigDecimal productDiscount = discountValue.multiply(BigDecimal.valueOf(product.getQuantity()));
totalDiscount = totalDiscount.add(productDiscount);
}
yield totalDiscount;
}
case DISCOUNT -> {
// 商品打折,按百分比计算
// 商品打折,按适用商品的金额比例计算
if (discountValue == null || discountValue.compareTo(BigDecimal.ZERO) <= 0 ||
discountValue.compareTo(BigDecimal.valueOf(100)) >= 0) {
yield BigDecimal.ZERO;
}
BigDecimal currentAmount = context.getCurrentAmount() != null ? context.getCurrentAmount() : BigDecimal.ZERO;
BigDecimal applicableAmount = calculateApplicableAmount(applicableItems, context);
BigDecimal discountRate = discountValue.divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP);
yield currentAmount.multiply(discountRate).setScale(2, RoundingMode.HALF_UP);
yield applicableAmount.multiply(discountRate).setScale(2, RoundingMode.HALF_UP);
}
};
}
@@ -267,7 +276,44 @@ public class VoucherServiceImpl implements IVoucherService {
voucherInfo.setStatus(voucherCode.getStatus());
voucherInfo.setClaimedTime(voucherCode.getClaimedTime());
voucherInfo.setUsedTime(voucherCode.getUsedTime());
voucherInfo.setApplicableProducts(batchConfig.getApplicableProducts());
return voucherInfo;
}
/**
* 筛选适用的商品
*/
private List<ProductItem> filterApplicableProducts(List<ProductItem> products, List<ProductType> applicableProducts) {
if (applicableProducts == null || applicableProducts.isEmpty()) {
// null或空列表表示适用所有商品类型
return products;
}
return products.stream()
.filter(product -> {
try {
ProductType productType = ProductType.fromCode(product.getProductType());
return applicableProducts.contains(productType);
} catch (IllegalArgumentException e) {
log.warn("未知的商品类型: {}", product.getProductType());
return false;
}
})
.collect(Collectors.toList());
}
/**
* 计算适用商品的总金额
*/
private BigDecimal calculateApplicableAmount(List<ProductItem> applicableItems, DiscountDetectionContext context) {
// 简单计算:基于商品数量和单价
// 在实际应用中可能需要更复杂的计算逻辑
BigDecimal totalAmount = BigDecimal.ZERO;
for (ProductItem item : applicableItems) {
BigDecimal itemAmount = item.getUnitPrice().multiply(BigDecimal.valueOf(item.getQuantity()));
totalAmount = totalAmount.add(itemAmount);
}
return totalAmount;
}
}