xiaoyi
4 天以前 abf1c0a35d85d38239ff5d2ed746a4e4b797c9d1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package cn.iocoder.yudao.module.mes.service.pd.price;
 
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.module.mes.controller.admin.pd.price.vo.MesPdPriceCalcDetailRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.pd.price.vo.MesPdPriceCalcReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.pd.price.vo.MesPdPriceCalcRespVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pd.basedata.MesPdDiscountPolicyDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pd.basedata.MesPdServicePackageDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pd.basedata.MesPdTieredPriceDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pd.basedata.MesPdVoltageLevelDO;
import cn.iocoder.yudao.module.mes.dal.mysql.pd.basedata.MesPdDiscountPolicyMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.pd.basedata.MesPdTieredPriceMapper;
import cn.iocoder.yudao.module.mes.service.pd.basedata.MesPdServicePackageService;
import cn.iocoder.yudao.module.mes.service.pd.basedata.MesPdVoltageLevelService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
 
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
 
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.PD_PRICE_CALC_OBJECT_NOT_CONFIGURED;
 
/**
 * MES 阶梯电价测算 Service 实现类
 *
 * @author 超级管理员
 */
@Service
@Validated
@Slf4j
public class MesPdPriceServiceImpl implements MesPdPriceService {
 
    private static final Integer CALC_TYPE_PACKAGE = 1;
    private static final Integer CALC_TYPE_VOLTAGE = 2;
 
    @Resource
    private MesPdTieredPriceMapper tieredPriceMapper;
 
    @Resource
    private MesPdDiscountPolicyMapper discountPolicyMapper;
 
    @Resource
    private MesPdServicePackageService servicePackageService;
 
    @Resource
    private MesPdVoltageLevelService voltageLevelService;
 
    @Override
    public MesPdPriceCalcRespVO calcPrice(MesPdPriceCalcReqVO reqVO) {
        // 1. 定位阶梯电价档位
        List<MesPdTieredPriceDO> tiers = getTieredPrices(reqVO);
        if (CollUtil.isEmpty(tiers)) {
            throw exception(PD_PRICE_CALC_OBJECT_NOT_CONFIGURED);
        }
        // 2. 分档累计计算原价
        BigDecimal quantity = reqVO.getQuantity();
        BigDecimal originalPrice = BigDecimal.ZERO;
        List<MesPdPriceCalcDetailRespVO> details = new ArrayList<>();
        for (MesPdTieredPriceDO tier : tiers) {
            BigDecimal lower = tier.getStartValue();
            BigDecimal upper = tier.getEndValue();
            if (quantity.compareTo(lower) <= 0) {
                break;
            }
            BigDecimal upperBound = upper == null ? quantity : upper.min(quantity);
            BigDecimal tierQuantity = upperBound.subtract(lower);
            if (tierQuantity.signum() <= 0) {
                continue;
            }
            BigDecimal subtotal = tier.getPricePerUnit().multiply(tierQuantity);
            originalPrice = originalPrice.add(subtotal);
            MesPdPriceCalcDetailRespVO detail = new MesPdPriceCalcDetailRespVO();
            detail.setStartValue(lower);
            detail.setEndValue(upper);
            detail.setTierQuantity(tierQuantity);
            detail.setPricePerUnit(tier.getPricePerUnit());
            detail.setSubtotal(subtotal);
            details.add(detail);
            if (upper != null && quantity.compareTo(upper) <= 0) {
                break;
            }
        }
        // 3. 叠加优惠策略(目标专属 + 全局,取最优)
        BigDecimal finalPrice = originalPrice;
        Integer targetType = Objects.equals(CALC_TYPE_PACKAGE, reqVO.getCalcType()) ? 1 : 2;
        Long targetId = Objects.equals(CALC_TYPE_PACKAGE, reqVO.getCalcType()) ? reqVO.getPackageId() : reqVO.getVoltageLevelId();
        List<MesPdDiscountPolicyDO> policies = discountPolicyMapper.selectListByTarget(targetType, targetId);
        LocalDateTime now = LocalDateTime.now();
        for (MesPdDiscountPolicyDO policy : policies) {
            if (policy.getStartDate() != null && now.isBefore(policy.getStartDate())) {
                continue;
            }
            if (policy.getEndDate() != null && now.isAfter(policy.getEndDate())) {
                continue;
            }
            if (policy.getPolicyValue() == null) {
                continue;
            }
            BigDecimal candidate;
            if (Objects.equals(policy.getPolicyType(), 1)) { // 折扣
                candidate = originalPrice.multiply(policy.getPolicyValue());
            } else { // 立减
                candidate = originalPrice.subtract(policy.getPolicyValue()).max(BigDecimal.ZERO);
            }
            finalPrice = finalPrice.min(candidate);
        }
        // 4. 组装返回
        MesPdPriceCalcRespVO respVO = new MesPdPriceCalcRespVO();
        respVO.setOriginalPrice(originalPrice);
        respVO.setFinalPrice(finalPrice);
        respVO.setDiscountAmount(originalPrice.subtract(finalPrice));
        respVO.setDetails(details);
        if (reqVO.getPackageId() != null) {
            MesPdServicePackageDO pkg = servicePackageService.validateServicePackageExists(reqVO.getPackageId());
            respVO.setPackageName(pkg.getName());
        }
        if (reqVO.getVoltageLevelId() != null) {
            MesPdVoltageLevelDO level = voltageLevelService.validateVoltageLevelExists(reqVO.getVoltageLevelId());
            respVO.setVoltageLevelName(level.getName());
        }
        return respVO;
    }
 
    private List<MesPdTieredPriceDO> getTieredPrices(MesPdPriceCalcReqVO reqVO) {
        if (Objects.equals(CALC_TYPE_PACKAGE, reqVO.getCalcType()) && reqVO.getPackageId() != null) {
            return tieredPriceMapper.selectListByPackageId(reqVO.getPackageId());
        }
        if (Objects.equals(CALC_TYPE_VOLTAGE, reqVO.getCalcType()) && reqVO.getVoltageLevelId() != null) {
            return tieredPriceMapper.selectListByVoltageLevelId(reqVO.getVoltageLevelId());
        }
        return null;
    }
 
}