| | |
| | | import org.springframework.jdbc.core.JdbcTemplate; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import tools.jackson.core.type.TypeReference; |
| | | import tools.jackson.databind.ObjectMapper; |
| | | |
| | | @Service |
| | | public class MerchantWorkService { |
| | | private static final long REVOCATION_HOURS = 3; |
| | | private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); |
| | | private static final TypeReference<List<Map<String, Object>>> RIGHTS_TYPE = new TypeReference<>() {}; |
| | | |
| | | private final JdbcTemplate jdbcTemplate; |
| | | private final ManualConsumptionService manualConsumptionService; |
| | |
| | | select o.id, o.order_no, o.talent_id, tu.name as talent_name, tu.mobile as talent_mobile, tu.gender, |
| | | o.card_id, tc.card_no, coalesce(nullif(o.card_level_snapshot, ''), tc.card_level) as card_level, |
| | | o.benefit_id, b.benefit_name, |
| | | o.merchant_id, m.merchant_name, o.product_id, o.product_name_snapshot, p.rights_config, |
| | | o.merchant_id, m.merchant_name, m.merchant_rights_config, |
| | | o.product_id, o.product_name_snapshot, p.rights_config, |
| | | o.order_type, o.order_amount, o.base_pay_amount, o.coupon_amount, |
| | | o.subsidy_amount, o.pay_amount, o.order_status, o.verify_status, o.created_at, |
| | | vr.verify_time, vr.status as verify_record_status |
| | |
| | | |
| | | private String currentBenefitText(Map<String, Object> order, String category) { |
| | | String cardLevel = text(order.get("cardLevel")); |
| | | String merchantDetail = merchantBenefitDetail(order.get("merchantRightsConfig"), cardLevel); |
| | | if (!merchantDetail.isBlank()) return merchantDetail; |
| | | if ("store".equals(category)) { |
| | | Long merchantId = number(order.get("merchantId")); |
| | | return merchantId == null ? "以当前商户到店消费规则为准" : manualConsumptionService.benefitTextForMerchant(merchantId, cardLevel); |
| | |
| | | return configured.isBlank() ? "以当前订单权益规则为准" : configured; |
| | | } |
| | | |
| | | private String merchantBenefitDetail(Object rawConfig, String cardLevel) { |
| | | if (rawConfig == null || cardLevel.isBlank()) return ""; |
| | | try { |
| | | List<Map<String, Object>> configs = rawConfig instanceof List<?> |
| | | ? ((List<?>) rawConfig).stream().filter(Map.class::isInstance) |
| | | .map(item -> (Map<String, Object>) item).toList() |
| | | : OBJECT_MAPPER.readValue(String.valueOf(rawConfig), RIGHTS_TYPE); |
| | | for (Map<String, Object> config : configs) { |
| | | if (!booleanValue(config.get("enabled")) || !sameCardLevel(config.get("level"), cardLevel)) continue; |
| | | String detail = text(config.get("detail")); |
| | | if (!detail.isBlank()) return detail; |
| | | } |
| | | } catch (Exception ignored) { |
| | | // Invalid legacy configuration should fall back to the structured rule text. |
| | | } |
| | | return ""; |
| | | } |
| | | |
| | | private boolean sameCardLevel(Object configured, String actual) { |
| | | return normalizeCardLevel(configured).equals(normalizeCardLevel(actual)); |
| | | } |
| | | |
| | | private String normalizeCardLevel(Object value) { |
| | | String raw = text(value).toUpperCase(); |
| | | if (raw.contains("卓越") || "EXCELLENT".equals(raw)) return "EXCELLENT"; |
| | | if (raw.contains("杰出") || "OUTSTANDING".equals(raw)) return "OUTSTANDING"; |
| | | if (raw.contains("菁英") || "ELITE".equals(raw)) return "ELITE"; |
| | | return raw; |
| | | } |
| | | |
| | | private boolean booleanValue(Object value) { |
| | | return value instanceof Boolean bool ? bool : "1".equals(text(value)) || "true".equalsIgnoreCase(text(value)); |
| | | } |
| | | |
| | | private String productBenefitText(ProductPriceCalculator.ProductRight right) { |
| | | String discountText = discountText(right.discount()); |
| | | if (!right.free()) return discountText.isBlank() ? "以商品配置为准" : "按市价" + discountText; |