| | |
| | | } |
| | | |
| | | private boolean hasStructuredRightsConfig(Long merchantId) { |
| | | List<Map<String, Object>> merchants = rows("select merchant_rights_config from merchant where id = ? and deleted = 0 limit 1", merchantId); |
| | | if (merchants.isEmpty()) return false; |
| | | Object raw = merchants.get(0).get("merchantRightsConfig"); |
| | | return raw != null && !string(raw).isBlank(); |
| | | return !rightsConfigs(merchantId).isEmpty(); |
| | | } |
| | | |
| | | private List<Map<String, Object>> configuredRules(Long merchantId, String cardLevel, String sourceAreaType) { |
| | | private List<Map<String, Object>> rightsConfigs(Long merchantId) { |
| | | List<Map<String, Object>> merchants = rows("select merchant_rights_config from merchant where id = ? and deleted = 0 limit 1", merchantId); |
| | | if (merchants.isEmpty()) return List.of(); |
| | | Object raw = merchants.get(0).get("merchantRightsConfig"); |
| | | if (raw == null) { |
| | | for (Map.Entry<String, Object> entry : merchants.get(0).entrySet()) { |
| | | if (entry.getKey() != null && entry.getKey().toLowerCase().contains("rights")) { |
| | | raw = entry.getValue(); |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | if (raw == null || string(raw).isBlank()) return List.of(); |
| | | String json = raw instanceof byte[] bytes ? new String(bytes, java.nio.charset.StandardCharsets.UTF_8) : string(raw); |
| | | List<Map<String, Object>> configs = new ArrayList<>(); |
| | | try { |
| | | if (raw instanceof List<?> list) { |
| | |
| | | configs.add(value); |
| | | } |
| | | } else { |
| | | for (Object item : JSON.parseArray(string(raw), Map.class)) if (item instanceof Map<?, ?> map) { |
| | | for (Object item : JSON.parseArray(json, Map.class)) if (item instanceof Map<?, ?> map) { |
| | | Map<String, Object> value = new LinkedHashMap<>(); |
| | | for (Map.Entry<?, ?> entry : map.entrySet()) value.put(String.valueOf(entry.getKey()), entry.getValue()); |
| | | configs.add(value); |
| | |
| | | } catch (Exception ignored) { |
| | | return List.of(); |
| | | } |
| | | return configs.stream() |
| | | return configs; |
| | | } |
| | | |
| | | private List<Map<String, Object>> configuredRules(Long merchantId, String cardLevel, String sourceAreaType) { |
| | | return rightsConfigs(merchantId).stream() |
| | | .filter(right -> booleanValue(right.get("enabled")) |
| | | && configuredStoreConsumptionEnabled(right) |
| | | && matchesConfiguredLevel(string(right.get("level")), cardLevel, sourceAreaType)) |
| | |
| | | } |
| | | |
| | | private String benefitText(Long merchantId, String cardLevel, String sourceAreaType) { |
| | | String configuredDescription = consumeDescFromRights(merchantId, cardLevel, sourceAreaType); |
| | | if (!configuredDescription.isBlank()) return configuredDescription; |
| | | List<Map<String, Object>> benefits = rows(""" |
| | | select card_level, benefit_text from merchant_card_benefit |
| | | where merchant_id = ? and status = 1 order by sort_no desc, id desc |
| | | """, merchantId); |
| | | String configuredDescription = configuredRules(merchantId, cardLevel, sourceAreaType).stream() |
| | | .map(rule -> string(rule.get("consumeDesc"))) |
| | | .filter(value -> !value.isBlank()) |
| | | .findFirst() |
| | | .orElse(""); |
| | | if (configuredDescription.isBlank()) { |
| | | configuredDescription = configuredRules(merchantId, cardLevel, sourceAreaType).stream() |
| | | .map(rule -> string(rule.get("merchantDetail"))) |
| | | .filter(value -> !value.isBlank()) |
| | | .findFirst() |
| | | .orElse(""); |
| | | } |
| | | if (configuredDescription.isBlank()) { |
| | | configuredDescription = configuredRules(merchantId, cardLevel, sourceAreaType).stream() |
| | | .map(rule -> string(rule.get("benefitText"))) |
| | | .filter(value -> !value.isBlank()) |
| | | .findFirst() |
| | | .orElse(""); |
| | | } |
| | | if (!configuredDescription.isBlank()) return configuredDescription; |
| | | return benefits.stream().filter(benefit -> matchesCardLevel(string(benefit.get("cardLevel")), cardLevel)) |
| | | .map(benefit -> string(benefit.get("benefitText"))).findFirst().orElse("以当前商户到店消费规则为准"); |
| | | } |
| | | |
| | | private String consumeDescFromRights(Long merchantId, String cardLevel, String sourceAreaType) { |
| | | List<Map<String, Object>> configs = rightsConfigs(merchantId).stream() |
| | | .filter(right -> booleanValue(right.get("enabled"))) |
| | | .toList(); |
| | | String description = firstRightsText(configs, cardLevel, sourceAreaType, "consumeDesc"); |
| | | if (!description.isBlank()) return description; |
| | | return firstRightsText(configs, cardLevel, sourceAreaType, "detail"); |
| | | } |
| | | |
| | | private String firstRightsText(List<Map<String, Object>> configs, String cardLevel, String sourceAreaType, String field) { |
| | | for (Map<String, Object> right : configs) { |
| | | if (!matchesConfiguredLevel(string(right.get("level")), cardLevel, sourceAreaType)) continue; |
| | | String text = string(right.get(field)).trim(); |
| | | if (!text.isBlank()) return text; |
| | | } |
| | | if (!sourceAreaKnown(sourceAreaType)) { |
| | | for (Map<String, Object> right : configs) { |
| | | if (!matchesCardLevel(string(right.get("level")), cardLevel)) continue; |
| | | String text = string(right.get(field)).trim(); |
| | | if (!text.isBlank()) return text; |
| | | } |
| | | } |
| | | return ""; |
| | | } |
| | | |
| | | private boolean sourceAreaKnown(String sourceAreaType) { |
| | | return localArea(sourceAreaType) || outsideArea(sourceAreaType); |
| | | } |
| | | |
| | | private boolean localArea(String sourceAreaType) { |
| | | String area = string(sourceAreaType).trim().toUpperCase(); |
| | | return area.contains("LOCAL") || area.contains("本地"); |
| | | } |
| | | |
| | | private boolean outsideArea(String sourceAreaType) { |
| | | String area = string(sourceAreaType).trim().toUpperCase(); |
| | | return area.contains("OUTSIDE") || area.contains("外地"); |
| | | } |
| | | |
| | | /** Build the displayed benefit from the same structured fields used for pricing. */ |
| | |
| | | return benefitText(merchantId, cardLevel, ""); |
| | | } |
| | | |
| | | String benefitTextForMerchant(Long merchantId, String cardLevel, String sourceAreaType) { |
| | | return benefitText(merchantId, cardLevel, sourceAreaType); |
| | | } |
| | | |
| | | boolean matchesConfiguredLevel(String configured, String actual, String sourceAreaType) { |
| | | if (!"EXCELLENT".equals(normalizedCardLevel(actual))) return matchesCardLevel(configured, actual); |
| | | String configuredUpper = configured.trim().toUpperCase(); |
| | | String areaUpper = sourceAreaType.trim().toUpperCase(); |
| | | String areaUpper = string(sourceAreaType).trim().toUpperCase(); |
| | | if (configuredUpper.contains("本地") || configuredUpper.contains("LOCAL")) { |
| | | return areaUpper.contains("LOCAL") || areaUpper.contains("本地"); |
| | | } |