You've already forked FrameTour-BE
价格查询,待处理订单内容
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
package com.ycwl.basic.pricing.service.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ycwl.basic.pricing.dto.*;
|
||||
import com.ycwl.basic.pricing.entity.PriceCouponClaimRecord;
|
||||
import com.ycwl.basic.pricing.entity.PriceCouponConfig;
|
||||
import com.ycwl.basic.pricing.enums.CouponStatus;
|
||||
import com.ycwl.basic.pricing.enums.CouponType;
|
||||
import com.ycwl.basic.pricing.enums.ProductType;
|
||||
import com.ycwl.basic.pricing.exception.CouponInvalidException;
|
||||
import com.ycwl.basic.pricing.mapper.PriceCouponClaimRecordMapper;
|
||||
import com.ycwl.basic.pricing.mapper.PriceCouponConfigMapper;
|
||||
import com.ycwl.basic.pricing.service.ICouponService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 优惠券服务实现
|
||||
*/
|
||||
@Slf4j
|
||||
@Service("pricingCouponServiceImpl")
|
||||
@RequiredArgsConstructor
|
||||
public class CouponServiceImpl implements ICouponService {
|
||||
|
||||
private final PriceCouponConfigMapper couponConfigMapper;
|
||||
private final PriceCouponClaimRecordMapper couponClaimRecordMapper;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@Override
|
||||
public CouponInfo selectBestCoupon(Long userId, List<ProductItem> products, BigDecimal totalAmount) {
|
||||
List<PriceCouponClaimRecord> userCoupons = couponClaimRecordMapper.selectUserAvailableCoupons(userId);
|
||||
if (userCoupons.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
CouponInfo bestCoupon = null;
|
||||
BigDecimal maxDiscount = BigDecimal.ZERO;
|
||||
|
||||
for (PriceCouponClaimRecord record : userCoupons) {
|
||||
PriceCouponConfig coupon = couponConfigMapper.selectById(record.getCouponId());
|
||||
if (coupon == null || !isCouponApplicable(coupon, products, totalAmount)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
BigDecimal discount = calculateCouponDiscount(coupon, products, totalAmount);
|
||||
if (discount.compareTo(maxDiscount) > 0) {
|
||||
maxDiscount = discount;
|
||||
bestCoupon = buildCouponInfo(coupon, discount);
|
||||
}
|
||||
}
|
||||
|
||||
return bestCoupon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal calculateCouponDiscount(PriceCouponConfig coupon, List<ProductItem> products, BigDecimal totalAmount) {
|
||||
if (!isCouponApplicable(coupon, products, totalAmount)) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
BigDecimal discount;
|
||||
if (coupon.getCouponType() == CouponType.PERCENTAGE) {
|
||||
discount = totalAmount.multiply(coupon.getDiscountValue().divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_UP));
|
||||
if (coupon.getMaxDiscount() != null && discount.compareTo(coupon.getMaxDiscount()) > 0) {
|
||||
discount = coupon.getMaxDiscount();
|
||||
}
|
||||
} else {
|
||||
discount = coupon.getDiscountValue();
|
||||
}
|
||||
|
||||
return discount.setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCouponApplicable(PriceCouponConfig coupon, List<ProductItem> products, BigDecimal totalAmount) {
|
||||
if (totalAmount.compareTo(coupon.getMinAmount()) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (coupon.getApplicableProducts() == null || coupon.getApplicableProducts().isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
List<String> applicableProductTypes = objectMapper.readValue(
|
||||
coupon.getApplicableProducts(), new TypeReference<List<String>>() {});
|
||||
|
||||
for (ProductItem product : products) {
|
||||
if (applicableProductTypes.contains(product.getProductType().getCode())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
log.error("解析适用商品类型失败", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public CouponUseResult useCoupon(CouponUseRequest request) {
|
||||
PriceCouponClaimRecord record = couponClaimRecordMapper.selectUserCouponRecord(
|
||||
request.getUserId(), request.getCouponId());
|
||||
|
||||
if (record == null) {
|
||||
throw new CouponInvalidException("用户未拥有该优惠券");
|
||||
}
|
||||
|
||||
if (record.getStatus() != CouponStatus.CLAIMED) {
|
||||
throw new CouponInvalidException("优惠券状态无效: " + record.getStatus());
|
||||
}
|
||||
|
||||
int updateCount = couponConfigMapper.incrementUsedQuantity(request.getCouponId());
|
||||
if (updateCount == 0) {
|
||||
throw new CouponInvalidException("优惠券使用失败,可能已达到使用上限");
|
||||
}
|
||||
|
||||
LocalDateTime useTime = LocalDateTime.now();
|
||||
|
||||
// 设置使用时间和订单信息
|
||||
record.setStatus(CouponStatus.USED);
|
||||
record.setUseTime(useTime);
|
||||
record.setOrderId(request.getOrderId());
|
||||
record.setUpdatedTime(LocalDateTime.now());
|
||||
|
||||
couponClaimRecordMapper.updateCouponStatus(
|
||||
record.getId(), CouponStatus.USED, useTime, request.getOrderId());
|
||||
|
||||
CouponUseResult result = new CouponUseResult();
|
||||
result.setCouponId(request.getCouponId());
|
||||
result.setUserId(request.getUserId());
|
||||
result.setOrderId(request.getOrderId());
|
||||
result.setUseTime(useTime);
|
||||
result.setDiscountAmount(request.getDiscountAmount());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CouponInfo> getUserAvailableCoupons(Long userId) {
|
||||
List<PriceCouponClaimRecord> records = couponClaimRecordMapper.selectUserAvailableCoupons(userId);
|
||||
List<CouponInfo> coupons = new ArrayList<>();
|
||||
|
||||
for (PriceCouponClaimRecord record : records) {
|
||||
PriceCouponConfig config = couponConfigMapper.selectById(record.getCouponId());
|
||||
if (config != null) {
|
||||
coupons.add(buildCouponInfo(config, null));
|
||||
}
|
||||
}
|
||||
|
||||
return coupons;
|
||||
}
|
||||
|
||||
private CouponInfo buildCouponInfo(PriceCouponConfig coupon, BigDecimal actualDiscountAmount) {
|
||||
CouponInfo info = new CouponInfo();
|
||||
info.setCouponId(coupon.getId());
|
||||
info.setCouponName(coupon.getCouponName());
|
||||
info.setDiscountType(coupon.getCouponType());
|
||||
info.setDiscountValue(coupon.getDiscountValue());
|
||||
info.setActualDiscountAmount(actualDiscountAmount);
|
||||
return info;
|
||||
}
|
||||
}
|
@@ -0,0 +1,104 @@
|
||||
package com.ycwl.basic.pricing.service.impl;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.ycwl.basic.pricing.dto.ProductItem;
|
||||
import com.ycwl.basic.pricing.entity.PriceBundleConfig;
|
||||
import com.ycwl.basic.pricing.enums.ProductType;
|
||||
import com.ycwl.basic.pricing.mapper.PriceBundleConfigMapper;
|
||||
import com.ycwl.basic.pricing.service.IPriceBundleService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 一口价套餐服务实现
|
||||
*/
|
||||
@Slf4j
|
||||
@Service("pricingBundleServiceImpl")
|
||||
@RequiredArgsConstructor
|
||||
public class PriceBundleServiceImpl implements IPriceBundleService {
|
||||
|
||||
private final PriceBundleConfigMapper bundleConfigMapper;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@Override
|
||||
public boolean isBundleApplicable(List<ProductItem> products) {
|
||||
List<PriceBundleConfig> bundles = getActiveBundles();
|
||||
if (bundles.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Set<String> productTypes = new HashSet<>();
|
||||
for (ProductItem product : products) {
|
||||
productTypes.add(product.getProductType().getCode());
|
||||
}
|
||||
|
||||
for (PriceBundleConfig bundle : bundles) {
|
||||
if (isProductsMatchBundle(productTypes, bundle)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getBundlePrice(List<ProductItem> products) {
|
||||
if (!isBundleApplicable(products)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<PriceBundleConfig> bundles = getActiveBundles();
|
||||
Set<String> productTypes = new HashSet<>();
|
||||
for (ProductItem product : products) {
|
||||
productTypes.add(product.getProductType().getCode());
|
||||
}
|
||||
|
||||
for (PriceBundleConfig bundle : bundles) {
|
||||
if (isProductsMatchBundle(productTypes, bundle)) {
|
||||
return bundle.getBundlePrice();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "active-bundles")
|
||||
public List<PriceBundleConfig> getActiveBundles() {
|
||||
return bundleConfigMapper.selectActiveBundles();
|
||||
}
|
||||
|
||||
private boolean isProductsMatchBundle(Set<String> productTypes, PriceBundleConfig bundle) {
|
||||
try {
|
||||
List<String> includedProducts = objectMapper.readValue(
|
||||
bundle.getIncludedProducts(), new TypeReference<List<String>>() {});
|
||||
|
||||
Set<String> requiredProducts = new HashSet<>(includedProducts);
|
||||
|
||||
if (bundle.getExcludedProducts() != null && !bundle.getExcludedProducts().isEmpty()) {
|
||||
List<String> excludedProducts = objectMapper.readValue(
|
||||
bundle.getExcludedProducts(), new TypeReference<List<String>>() {});
|
||||
|
||||
for (String excludedProduct : excludedProducts) {
|
||||
if (productTypes.contains(excludedProduct)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return productTypes.containsAll(requiredProducts);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("解析一口价配置失败: bundleId={}", bundle.getId(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,238 @@
|
||||
package com.ycwl.basic.pricing.service.impl;
|
||||
|
||||
import com.ycwl.basic.pricing.dto.*;
|
||||
import com.ycwl.basic.pricing.entity.PriceProductConfig;
|
||||
import com.ycwl.basic.pricing.entity.PriceTierConfig;
|
||||
import com.ycwl.basic.pricing.enums.ProductType;
|
||||
import com.ycwl.basic.pricing.exception.PriceCalculationException;
|
||||
import com.ycwl.basic.pricing.service.ICouponService;
|
||||
import com.ycwl.basic.pricing.service.IPriceBundleService;
|
||||
import com.ycwl.basic.pricing.service.IPriceCalculationService;
|
||||
import com.ycwl.basic.pricing.service.IProductConfigService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 价格计算服务实现
|
||||
*/
|
||||
@Slf4j
|
||||
@Service("pricingCalculationServiceImpl")
|
||||
@RequiredArgsConstructor
|
||||
public class PriceCalculationServiceImpl implements IPriceCalculationService {
|
||||
|
||||
private final IProductConfigService productConfigService;
|
||||
private final ICouponService couponService;
|
||||
private final IPriceBundleService bundleService;
|
||||
|
||||
@Override
|
||||
public PriceCalculationResult calculatePrice(PriceCalculationRequest request) {
|
||||
if (request.getProducts() == null || request.getProducts().isEmpty()) {
|
||||
throw new PriceCalculationException("商品列表不能为空");
|
||||
}
|
||||
|
||||
// 计算商品价格和原价
|
||||
PriceDetails priceDetails = calculateProductsPriceWithOriginal(request.getProducts());
|
||||
BigDecimal totalAmount = priceDetails.getTotalAmount();
|
||||
BigDecimal originalTotalAmount = priceDetails.getOriginalTotalAmount();
|
||||
|
||||
List<DiscountDetail> discountDetails = new ArrayList<>();
|
||||
|
||||
// 添加限时立减折扣(如果原价 > 实际价格)
|
||||
BigDecimal limitedTimeDiscount = originalTotalAmount.subtract(totalAmount);
|
||||
if (limitedTimeDiscount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
discountDetails.add(DiscountDetail.createLimitedTimeDiscount(limitedTimeDiscount));
|
||||
}
|
||||
|
||||
// 检查一口价优惠
|
||||
BigDecimal bundlePrice = bundleService.getBundlePrice(request.getProducts());
|
||||
if (bundlePrice != null && bundlePrice.compareTo(totalAmount) < 0) {
|
||||
BigDecimal bundleDiscount = totalAmount.subtract(bundlePrice);
|
||||
discountDetails.add(DiscountDetail.createBundleDiscount(bundleDiscount));
|
||||
totalAmount = bundlePrice;
|
||||
log.info("使用一口价: {}, 优惠: {}", bundlePrice, bundleDiscount);
|
||||
}
|
||||
|
||||
PriceCalculationResult result = new PriceCalculationResult();
|
||||
result.setOriginalAmount(originalTotalAmount); // 原总价
|
||||
result.setSubtotalAmount(priceDetails.getTotalAmount()); // 商品小计
|
||||
result.setProductDetails(request.getProducts());
|
||||
|
||||
// 处理优惠券
|
||||
BigDecimal couponDiscountAmount = BigDecimal.ZERO;
|
||||
if (Boolean.TRUE.equals(request.getAutoUseCoupon()) && request.getUserId() != null) {
|
||||
CouponInfo bestCoupon = couponService.selectBestCoupon(
|
||||
request.getUserId(), request.getProducts(), totalAmount);
|
||||
|
||||
if (bestCoupon != null && bestCoupon.getActualDiscountAmount().compareTo(BigDecimal.ZERO) > 0) {
|
||||
result.setUsedCoupon(bestCoupon);
|
||||
couponDiscountAmount = bestCoupon.getActualDiscountAmount();
|
||||
discountDetails.add(DiscountDetail.createCouponDiscount(bestCoupon.getCouponName(), couponDiscountAmount));
|
||||
}
|
||||
}
|
||||
|
||||
// 计算总优惠金额
|
||||
BigDecimal totalDiscountAmount = discountDetails.stream()
|
||||
.map(DiscountDetail::getDiscountAmount)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
|
||||
// 按排序排列折扣明细
|
||||
discountDetails.sort(Comparator.comparing(DiscountDetail::getSortOrder));
|
||||
|
||||
result.setDiscountAmount(totalDiscountAmount);
|
||||
result.setDiscountDetails(discountDetails);
|
||||
result.setFinalAmount(originalTotalAmount.subtract(totalDiscountAmount));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private BigDecimal calculateProductsPrice(List<ProductItem> products) {
|
||||
BigDecimal totalAmount = BigDecimal.ZERO;
|
||||
|
||||
for (ProductItem product : products) {
|
||||
BigDecimal itemPrice = calculateSingleProductPrice(product);
|
||||
product.setUnitPrice(itemPrice);
|
||||
|
||||
BigDecimal subtotal = itemPrice.multiply(BigDecimal.valueOf(product.getPurchaseCount()));
|
||||
product.setSubtotal(subtotal);
|
||||
|
||||
totalAmount = totalAmount.add(subtotal);
|
||||
}
|
||||
|
||||
return totalAmount.setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private PriceDetails calculateProductsPriceWithOriginal(List<ProductItem> products) {
|
||||
BigDecimal totalAmount = BigDecimal.ZERO;
|
||||
BigDecimal originalTotalAmount = BigDecimal.ZERO;
|
||||
|
||||
for (ProductItem product : products) {
|
||||
// 计算实际价格和原价
|
||||
ProductPriceInfo priceInfo = calculateSingleProductPriceWithOriginal(product);
|
||||
|
||||
product.setUnitPrice(priceInfo.getActualPrice());
|
||||
product.setOriginalPrice(priceInfo.getOriginalPrice());
|
||||
|
||||
BigDecimal subtotal = priceInfo.getActualPrice().multiply(BigDecimal.valueOf(product.getPurchaseCount()));
|
||||
BigDecimal originalSubtotal = priceInfo.getOriginalPrice().multiply(BigDecimal.valueOf(product.getPurchaseCount()));
|
||||
|
||||
product.setSubtotal(subtotal);
|
||||
|
||||
totalAmount = totalAmount.add(subtotal);
|
||||
originalTotalAmount = originalTotalAmount.add(originalSubtotal);
|
||||
}
|
||||
|
||||
return new PriceDetails(
|
||||
totalAmount.setScale(2, RoundingMode.HALF_UP),
|
||||
originalTotalAmount.setScale(2, RoundingMode.HALF_UP)
|
||||
);
|
||||
}
|
||||
|
||||
private BigDecimal calculateSingleProductPrice(ProductItem product) {
|
||||
ProductType productType = product.getProductType();
|
||||
String productId = product.getProductId() != null ? product.getProductId() : "default";
|
||||
|
||||
// 优先使用基于product_id的阶梯定价
|
||||
PriceTierConfig tierConfig = productConfigService.getTierConfig(
|
||||
productType.getCode(), productId, product.getProductSubType(), product.getQuantity());
|
||||
|
||||
if (tierConfig != null) {
|
||||
log.debug("使用阶梯定价: productType={}, productId={}, quantity={}, price={}",
|
||||
productType.getCode(), productId, product.getQuantity(), tierConfig.getPrice());
|
||||
return tierConfig.getPrice();
|
||||
}
|
||||
|
||||
// 使用基于product_id的基础配置
|
||||
try {
|
||||
PriceProductConfig baseConfig = productConfigService.getProductConfig(productType.getCode(), productId);
|
||||
if (baseConfig != null) {
|
||||
if (productType == ProductType.PHOTO_PRINT || productType == ProductType.MACHINE_PRINT) {
|
||||
return baseConfig.getBasePrice().multiply(BigDecimal.valueOf(product.getQuantity()));
|
||||
} else {
|
||||
return baseConfig.getBasePrice();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("未找到具体商品配置: productType={}, productId={}, 尝试使用通用配置",
|
||||
productType, productId);
|
||||
}
|
||||
|
||||
// 兜底:使用通用配置(向后兼容)
|
||||
List<PriceProductConfig> configs = productConfigService.getProductConfig(productType.getCode());
|
||||
if (!configs.isEmpty()) {
|
||||
PriceProductConfig baseConfig = configs.get(0); // 使用第一个配置作为默认
|
||||
if (productType == ProductType.PHOTO_PRINT || productType == ProductType.MACHINE_PRINT) {
|
||||
return baseConfig.getBasePrice().multiply(BigDecimal.valueOf(product.getQuantity()));
|
||||
} else {
|
||||
return baseConfig.getBasePrice();
|
||||
}
|
||||
}
|
||||
|
||||
throw new PriceCalculationException("无法计算商品价格: " + productType.getDescription() + ", productId: " + productId);
|
||||
}
|
||||
|
||||
private ProductPriceInfo calculateSingleProductPriceWithOriginal(ProductItem product) {
|
||||
ProductType productType = product.getProductType();
|
||||
String productId = product.getProductId() != null ? product.getProductId() : "default";
|
||||
|
||||
BigDecimal actualPrice;
|
||||
BigDecimal originalPrice = null;
|
||||
|
||||
// 优先使用基于product_id的阶梯定价
|
||||
PriceTierConfig tierConfig = productConfigService.getTierConfig(
|
||||
productType.getCode(), productId, product.getProductSubType(), product.getQuantity());
|
||||
|
||||
if (tierConfig != null) {
|
||||
actualPrice = tierConfig.getPrice();
|
||||
originalPrice = tierConfig.getOriginalPrice();
|
||||
log.debug("使用阶梯定价: productType={}, productId={}, quantity={}, price={}, originalPrice={}",
|
||||
productType.getCode(), productId, product.getQuantity(), actualPrice, originalPrice);
|
||||
} else {
|
||||
// 使用基于product_id的基础配置
|
||||
try {
|
||||
PriceProductConfig baseConfig = productConfigService.getProductConfig(productType.getCode(), productId);
|
||||
if (baseConfig != null) {
|
||||
actualPrice = baseConfig.getBasePrice();
|
||||
originalPrice = baseConfig.getOriginalPrice();
|
||||
|
||||
if (productType == ProductType.PHOTO_PRINT || productType == ProductType.MACHINE_PRINT) {
|
||||
actualPrice = actualPrice.multiply(BigDecimal.valueOf(product.getQuantity()));
|
||||
if (originalPrice != null) {
|
||||
originalPrice = originalPrice.multiply(BigDecimal.valueOf(product.getQuantity()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new PriceCalculationException("无法找到具体商品配置");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("未找到具体商品配置: productType={}, productId={}, 尝试使用通用配置",
|
||||
productType, productId);
|
||||
|
||||
// 兜底:使用通用配置(向后兼容)
|
||||
List<PriceProductConfig> configs = productConfigService.getProductConfig(productType.getCode());
|
||||
if (!configs.isEmpty()) {
|
||||
PriceProductConfig baseConfig = configs.getFirst(); // 使用第一个配置作为默认
|
||||
actualPrice = baseConfig.getBasePrice();
|
||||
originalPrice = baseConfig.getOriginalPrice();
|
||||
|
||||
if (productType == ProductType.PHOTO_PRINT || productType == ProductType.MACHINE_PRINT) {
|
||||
actualPrice = actualPrice.multiply(BigDecimal.valueOf(product.getQuantity()));
|
||||
if (originalPrice != null) {
|
||||
originalPrice = originalPrice.multiply(BigDecimal.valueOf(product.getQuantity()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new PriceCalculationException("无法计算商品价格: " + productType.getDescription() + ", productId: " + productId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new ProductPriceInfo(actualPrice, originalPrice);
|
||||
}
|
||||
}
|
@@ -0,0 +1,107 @@
|
||||
package com.ycwl.basic.pricing.service.impl;
|
||||
|
||||
import com.ycwl.basic.pricing.entity.*;
|
||||
import com.ycwl.basic.pricing.mapper.*;
|
||||
import com.ycwl.basic.pricing.service.IPricingManagementService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 价格管理服务实现(用于配置管理,手动处理时间字段)
|
||||
*/
|
||||
@Slf4j
|
||||
@Service("pricingManagementServiceImpl")
|
||||
@RequiredArgsConstructor
|
||||
public class PricingManagementServiceImpl implements IPricingManagementService {
|
||||
|
||||
private final PriceProductConfigMapper productConfigMapper;
|
||||
private final PriceTierConfigMapper tierConfigMapper;
|
||||
private final PriceCouponConfigMapper couponConfigMapper;
|
||||
private final PriceCouponClaimRecordMapper couponClaimRecordMapper;
|
||||
private final PriceBundleConfigMapper bundleConfigMapper;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Long createProductConfig(PriceProductConfig config) {
|
||||
config.setCreatedTime(LocalDateTime.now());
|
||||
config.setUpdatedTime(LocalDateTime.now());
|
||||
productConfigMapper.insertProductConfig(config);
|
||||
return config.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean updateProductConfig(PriceProductConfig config) {
|
||||
config.setUpdatedTime(LocalDateTime.now());
|
||||
return productConfigMapper.updateProductConfig(config) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Long createTierConfig(PriceTierConfig config) {
|
||||
config.setCreatedTime(LocalDateTime.now());
|
||||
config.setUpdatedTime(LocalDateTime.now());
|
||||
tierConfigMapper.insertTierConfig(config);
|
||||
return config.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean updateTierConfig(PriceTierConfig config) {
|
||||
config.setUpdatedTime(LocalDateTime.now());
|
||||
return tierConfigMapper.updateTierConfig(config) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Long createCouponConfig(PriceCouponConfig config) {
|
||||
config.setCreatedTime(LocalDateTime.now());
|
||||
config.setUpdatedTime(LocalDateTime.now());
|
||||
couponConfigMapper.insertCoupon(config);
|
||||
return config.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean updateCouponConfig(PriceCouponConfig config) {
|
||||
config.setUpdatedTime(LocalDateTime.now());
|
||||
return couponConfigMapper.updateCoupon(config) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Long createCouponClaimRecord(PriceCouponClaimRecord record) {
|
||||
record.setClaimTime(LocalDateTime.now());
|
||||
record.setCreatedTime(LocalDateTime.now());
|
||||
record.setUpdatedTime(LocalDateTime.now());
|
||||
couponClaimRecordMapper.insertClaimRecord(record);
|
||||
return record.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean updateCouponClaimRecord(PriceCouponClaimRecord record) {
|
||||
record.setUpdatedTime(LocalDateTime.now());
|
||||
return couponClaimRecordMapper.updateClaimRecord(record) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Long createBundleConfig(PriceBundleConfig config) {
|
||||
config.setCreatedTime(LocalDateTime.now());
|
||||
config.setUpdatedTime(LocalDateTime.now());
|
||||
bundleConfigMapper.insertBundleConfig(config);
|
||||
return config.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public boolean updateBundleConfig(PriceBundleConfig config) {
|
||||
config.setUpdatedTime(LocalDateTime.now());
|
||||
return bundleConfigMapper.updateBundleConfig(config) > 0;
|
||||
}
|
||||
}
|
@@ -0,0 +1,78 @@
|
||||
package com.ycwl.basic.pricing.service.impl;
|
||||
|
||||
import com.ycwl.basic.pricing.entity.PriceProductConfig;
|
||||
import com.ycwl.basic.pricing.entity.PriceTierConfig;
|
||||
import com.ycwl.basic.pricing.exception.ProductConfigNotFoundException;
|
||||
import com.ycwl.basic.pricing.mapper.PriceProductConfigMapper;
|
||||
import com.ycwl.basic.pricing.mapper.PriceTierConfigMapper;
|
||||
import com.ycwl.basic.pricing.service.IProductConfigService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 商品配置管理服务实现
|
||||
*/
|
||||
@Slf4j
|
||||
@Service("pricingProductConfigServiceImpl")
|
||||
@RequiredArgsConstructor
|
||||
public class ProductConfigServiceImpl implements IProductConfigService {
|
||||
|
||||
private final PriceProductConfigMapper productConfigMapper;
|
||||
private final PriceTierConfigMapper tierConfigMapper;
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "product-config", key = "#productType")
|
||||
public List<PriceProductConfig> getProductConfig(String productType) {
|
||||
return productConfigMapper.selectByProductType(productType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "product-config", key = "#productType + '_' + #productId")
|
||||
public PriceProductConfig getProductConfig(String productType, String productId) {
|
||||
PriceProductConfig config = productConfigMapper.selectByProductTypeAndId(productType, productId);
|
||||
if (config == null) {
|
||||
throw new ProductConfigNotFoundException("商品配置未找到: " + productType + ", productId: " + productId);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "tier-config", key = "#productType + '_' + #productId + '_' + (#productSubType ?: 'default') + '_' + #quantity")
|
||||
public PriceTierConfig getTierConfig(String productType, String productId, String productSubType, Integer quantity) {
|
||||
PriceTierConfig config = tierConfigMapper.selectByProductTypeAndQuantity(productType, productId, productSubType, quantity);
|
||||
if (config == null) {
|
||||
log.warn("阶梯定价配置未找到: productType={}, productId={}, productSubType={}, quantity={}",
|
||||
productType, productId, productSubType, quantity);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public PriceTierConfig getTierConfig(String productType, String productSubType, Integer quantity) {
|
||||
// 兼容旧接口,使用默认productId
|
||||
return getTierConfig(productType, "default", productSubType, quantity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "active-product-configs")
|
||||
public List<PriceProductConfig> getActiveProductConfigs() {
|
||||
return productConfigMapper.selectActiveConfigs();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "tier-configs", key = "#productType")
|
||||
public List<PriceTierConfig> getTierConfigs(String productType) {
|
||||
return tierConfigMapper.selectByProductType(productType);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "tier-configs", key = "#productType + '_' + #productId")
|
||||
public List<PriceTierConfig> getTierConfigs(String productType, String productId) {
|
||||
return tierConfigMapper.selectByProductTypeAndId(productType, productId);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user