shinnosuke
2026-08-21 bddcb4ef710d8bcad722a8e062ee9e0855d7042c
talent-card-server/src/main/java/com/talentcard/server/business/merchant/MerchantWorkService.java
@@ -20,10 +20,14 @@
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;
@@ -73,7 +77,8 @@
            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
@@ -314,6 +319,8 @@
   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);
@@ -326,6 +333,40 @@
      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;