|
@@ -0,0 +1,146 @@
|
|
|
|
|
+package com.etotem.cfc.service;
|
|
|
|
|
+
|
|
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
|
|
+import com.etotem.cfc.common.Result;
|
|
|
|
|
+import com.etotem.cfc.entity.DiscountRule;
|
|
|
|
|
+import com.etotem.cfc.mapper.DiscountRuleMapper;
|
|
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
|
+
|
|
|
|
|
+import javax.annotation.Resource;
|
|
|
|
|
+import java.util.ArrayList;
|
|
|
|
|
+import java.util.Date;
|
|
|
|
|
+import java.util.List;
|
|
|
|
|
+
|
|
|
|
|
+@Service
|
|
|
|
|
+public class DiscountService {
|
|
|
|
|
+
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private DiscountRuleMapper discountRuleMapper;
|
|
|
|
|
+
|
|
|
|
|
+ public Result<String> create(DiscountRule rule) {
|
|
|
|
|
+ rule.setUsedCount(0);
|
|
|
|
|
+ rule.setEnabled(true);
|
|
|
|
|
+ rule.setCreatedAt(new Date());
|
|
|
|
|
+ rule.setUpdatedAt(new Date());
|
|
|
|
|
+ discountRuleMapper.insert(rule);
|
|
|
|
|
+ return Result.success("创建成功");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public Result<String> update(DiscountRule rule) {
|
|
|
|
|
+ DiscountRule existing = discountRuleMapper.selectById(rule.getId());
|
|
|
|
|
+ if (existing == null) return Result.error("规则不存在");
|
|
|
|
|
+ rule.setUpdatedAt(new Date());
|
|
|
|
|
+ discountRuleMapper.updateById(rule);
|
|
|
|
|
+ return Result.success("更新成功");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public Result<String> toggle(Long id) {
|
|
|
|
|
+ DiscountRule rule = discountRuleMapper.selectById(id);
|
|
|
|
|
+ if (rule == null) return Result.error("规则不存在");
|
|
|
|
|
+ rule.setEnabled(!Boolean.TRUE.equals(rule.getEnabled()));
|
|
|
|
|
+ rule.setUpdatedAt(new Date());
|
|
|
|
|
+ discountRuleMapper.updateById(rule);
|
|
|
|
|
+ return Result.success(rule.getEnabled() ? "已启用" : "已禁用");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public Result<List<DiscountRule>> list(Boolean enabled) {
|
|
|
|
|
+ LambdaQueryWrapper<DiscountRule> wrapper = new LambdaQueryWrapper<>();
|
|
|
|
|
+ if (enabled != null) {
|
|
|
|
|
+ wrapper.eq(DiscountRule::getEnabled, enabled);
|
|
|
|
|
+ }
|
|
|
|
|
+ wrapper.orderByDesc(DiscountRule::getCreatedAt);
|
|
|
|
|
+ return Result.success(discountRuleMapper.selectList(wrapper));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public Result<String> delete(Long id) {
|
|
|
|
|
+ DiscountRule rule = discountRuleMapper.selectById(id);
|
|
|
|
|
+ if (rule == null) return Result.error("规则不存在");
|
|
|
|
|
+ discountRuleMapper.deleteById(id);
|
|
|
|
|
+ return Result.success("删除成功");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public Result<Integer> calculateBestDiscount(Long categoryId, Long distributionSystemId,
|
|
|
|
|
+ List<Long> productIds, Integer orderAmount) {
|
|
|
|
|
+ if (orderAmount == null || orderAmount <= 0) {
|
|
|
|
|
+ return Result.success(0);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ List<DiscountRule> allRules = discountRuleMapper.selectList(
|
|
|
|
|
+ new LambdaQueryWrapper<DiscountRule>()
|
|
|
|
|
+ .eq(DiscountRule::getEnabled, true)
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ Date now = new Date();
|
|
|
|
|
+ int bestDiscount = 0;
|
|
|
|
|
+
|
|
|
|
|
+ for (DiscountRule rule : allRules) {
|
|
|
|
|
+ if (!isTimeValid(rule, now)) continue;
|
|
|
|
|
+ if (!isCategoryMatch(rule, categoryId)) continue;
|
|
|
|
|
+ if (!isDistributionMatch(rule, distributionSystemId)) continue;
|
|
|
|
|
+ if (!isProductMatch(rule, productIds)) continue;
|
|
|
|
|
+ if (!isUsageValid(rule)) continue;
|
|
|
|
|
+ if ("THRESHOLD".equals(rule.getType())
|
|
|
|
|
+ && (rule.getThresholdAmount() == null || orderAmount < rule.getThresholdAmount())) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ int discount = calculateDiscount(rule, orderAmount);
|
|
|
|
|
+ if (discount > bestDiscount) {
|
|
|
|
|
+ bestDiscount = discount;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return Result.success(bestDiscount);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private boolean isTimeValid(DiscountRule rule, Date now) {
|
|
|
|
|
+ if (rule.getStartTime() != null && now.before(rule.getStartTime())) return false;
|
|
|
|
|
+ if (rule.getEndTime() != null && now.after(rule.getEndTime())) return false;
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private boolean isCategoryMatch(DiscountRule rule, Long categoryId) {
|
|
|
|
|
+ if (rule.getCategoryId() == null) return true;
|
|
|
|
|
+ if (categoryId == null) return false;
|
|
|
|
|
+ return rule.getCategoryId().equals(categoryId);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private boolean isDistributionMatch(DiscountRule rule, Long distributionSystemId) {
|
|
|
|
|
+ if (rule.getDistributionSystemId() == null) return true;
|
|
|
|
|
+ if (distributionSystemId == null) return false;
|
|
|
|
|
+ return rule.getDistributionSystemId().equals(distributionSystemId);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private boolean isProductMatch(DiscountRule rule, List<Long> productIds) {
|
|
|
|
|
+ if (rule.getProductIds() == null || rule.getProductIds().isEmpty()) return true;
|
|
|
|
|
+ if (productIds == null || productIds.isEmpty()) return false;
|
|
|
|
|
+ String[] ruleIds = rule.getProductIds().split(",");
|
|
|
|
|
+ for (String pid : ruleIds) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ Long id = Long.valueOf(pid.trim());
|
|
|
|
|
+ if (productIds.contains(id)) return true;
|
|
|
|
|
+ } catch (NumberFormatException ignored) {
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private boolean isUsageValid(DiscountRule rule) {
|
|
|
|
|
+ if (rule.getMaxUses() == null || rule.getMaxUses() == 0) return true;
|
|
|
|
|
+ if (rule.getUsedCount() == null) return true;
|
|
|
|
|
+ return rule.getUsedCount() < rule.getMaxUses();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private int calculateDiscount(DiscountRule rule, int orderAmount) {
|
|
|
|
|
+ switch (rule.getType()) {
|
|
|
|
|
+ case "PERCENT":
|
|
|
|
|
+ return orderAmount * rule.getValue() / 100;
|
|
|
|
|
+ case "FIXED":
|
|
|
|
|
+ return rule.getValue() != null ? rule.getValue() : 0;
|
|
|
|
|
+ case "THRESHOLD":
|
|
|
|
|
+ return rule.getValue() != null ? rule.getValue() : 0;
|
|
|
|
|
+ default:
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|