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) {
|
}
|
}
|