shinnosuke
2026-08-05 25729fa1ae7b630cbd4a9547a5693acd03c09c2a
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
package com.talentcard.server.business.portal;
 
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Locale;
import java.util.Map;
 
import tools.jackson.core.type.TypeReference;
import tools.jackson.databind.ObjectMapper;
 
final class ProductPriceCalculator {
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    private static final TypeReference<List<Map<String, Object>>> RIGHTS_TYPE = new TypeReference<>() {};
 
    private ProductPriceCalculator() {
    }
 
    static ProductPrice calculate(Object originalPrice, Object salePrice, Object rightsConfig, Object cardLevel) {
        return calculate(originalPrice, salePrice, rightsConfig, cardLevel, 0);
    }
 
    static ProductPrice calculate(Object originalPrice, Object salePrice, Object rightsConfig, Object cardLevel, int usedFreeCount) {
        BigDecimal fallbackSale = money(salePrice);
        BigDecimal original = money(originalPrice);
        if (original.signum() <= 0) {
            original = fallbackSale;
        }
        BigDecimal calculatedSale = fallbackSale.signum() > 0 ? fallbackSale : original;
        Map<String, Object> right = matchingRight(rightsConfig, cardLevel);
        if (right != null && original.signum() > 0) {
            boolean free = booleanValue(right.get("free"));
            int limitCount = intValue(right.get("limitCount"));
            boolean freeAvailable = free && (limitCount <= 0 || usedFreeCount < limitCount);
            if (freeAvailable) {
                calculatedSale = BigDecimal.ZERO;
            } else {
                BigDecimal discount = discountValue(right.get(free ? "exceedDiscount" : "discount"));
                if (discount.signum() > 0) {
                    calculatedSale = original.multiply(discount)
                            .divide(BigDecimal.TEN, 2, RoundingMode.HALF_UP);
                }
            }
        }
        return new ProductPrice(original, calculatedSale.setScale(2, RoundingMode.HALF_UP), right != null);
    }
 
    static ProductRight productRight(Object rightsConfig, Object cardLevel) {
        Map<String, Object> right = matchingRight(rightsConfig, cardLevel);
        if (right == null) return null;
        return new ProductRight(
                booleanValue(right.get("free")),
                intValue(right.get("limitCount")),
                text(right.get("resetCycle")));
    }
 
    private static Map<String, Object> matchingRight(Object rightsConfig, Object cardLevel) {
        String normalizedCardLevel = normalizeCardLevel(cardLevel);
        if (normalizedCardLevel.isBlank() || rightsConfig == null) return null;
        for (Map<String, Object> right : parseRights(rightsConfig)) {
            if (!booleanValue(right.get("enabled"))) continue;
            if (normalizedCardLevel.equals(normalizeCardLevel(right.get("level")))) return right;
        }
        return null;
    }
 
    private static List<Map<String, Object>> parseRights(Object value) {
        if (value instanceof List<?> list) {
            return list.stream()
                    .filter(Map.class::isInstance)
                    .map(item -> (Map<String, Object>) item)
                    .toList();
        }
        String text = String.valueOf(value).trim();
        if (text.isBlank()) return List.of();
        try {
            return OBJECT_MAPPER.readValue(text, RIGHTS_TYPE);
        } catch (Exception ignored) {
            return List.of();
        }
    }
 
    private static String normalizeCardLevel(Object value) {
        if (value == null) return "";
        String raw = String.valueOf(value).trim();
        String upper = raw.toUpperCase(Locale.ROOT);
        if (upper.contains("EXCELLENT") || raw.contains("\u5353\u8d8a")) return "EXCELLENT";
        if (upper.contains("OUTSTANDING") || raw.contains("\u6770\u51fa")) return "OUTSTANDING";
        if (upper.contains("ELITE") || raw.contains("\u83c1\u82f1") || raw.contains("\u7cbe\u82f1")) return "ELITE";
        return upper;
    }
 
    private static boolean booleanValue(Object value) {
        if (value instanceof Boolean bool) return bool;
        if (value instanceof Number number) return number.intValue() != 0;
        String text = value == null ? "" : String.valueOf(value).trim();
        return "true".equalsIgnoreCase(text) || "1".equals(text) || "yes".equalsIgnoreCase(text);
    }
 
    private static int intValue(Object value) {
        if (value instanceof Number number) return number.intValue();
        try {
            String text = value == null ? "" : String.valueOf(value).trim();
            if (text.isBlank()) return 0;
            return new BigDecimal(text).intValue();
        } catch (Exception ignored) {
            return 0;
        }
    }
 
    private static String text(Object value) {
        return value == null ? "" : String.valueOf(value).trim();
    }
 
    private static BigDecimal discountValue(Object value) {
        BigDecimal discount = money(value);
        if (discount.compareTo(BigDecimal.ZERO) <= 0 || discount.compareTo(BigDecimal.TEN) > 0) {
            return BigDecimal.ZERO;
        }
        return discount;
    }
 
    private static BigDecimal money(Object value) {
        if (value == null) return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
        try {
            if (value instanceof BigDecimal decimal) return decimal.setScale(2, RoundingMode.HALF_UP);
            return new BigDecimal(String.valueOf(value).trim()).setScale(2, RoundingMode.HALF_UP);
        } catch (Exception ignored) {
            return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP);
        }
    }
 
    record ProductPrice(BigDecimal originalPrice, BigDecimal salePrice, boolean personalized) {
    }
 
    record ProductRight(boolean free, int limitCount, String resetCycle) {
    }
}