From 25729fa1ae7b630cbd4a9547a5693acd03c09c2a Mon Sep 17 00:00:00 2001
From: shinnosuke <tantao@1hoper.com>
Date: 星期三, 05 八月 2026 14:19:47 +0800
Subject: [PATCH] feat(payment): 添加汇付个人入驻功能并优化商户结算流程

---
 talent-card-server/src/main/java/com/talentcard/server/business/merchant/ManualConsumptionService.java |   77 +++++++++++++++++++++++++++++++++++---
 1 files changed, 70 insertions(+), 7 deletions(-)

diff --git a/talent-card-server/src/main/java/com/talentcard/server/business/merchant/ManualConsumptionService.java b/talent-card-server/src/main/java/com/talentcard/server/business/merchant/ManualConsumptionService.java
index c2d5c36..d7359f7 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/business/merchant/ManualConsumptionService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/business/merchant/ManualConsumptionService.java
@@ -5,8 +5,11 @@
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.util.LinkedHashMap;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+
+import com.alibaba.fastjson.JSON;
 
 import com.talentcard.server.business.BusinessIdGenerator;
 import com.talentcard.server.business.DatabaseRows;
@@ -128,6 +131,8 @@
     }
 
     private List<Map<String, Object>> rules(Long merchantId, String cardLevel) {
+        List<Map<String, Object>> configured = configuredRules(merchantId, cardLevel);
+        if (!configured.isEmpty()) return configured;
         return rows("""
                 select id, card_level, rule_name, discount_rate, subsidy_enabled
                 from merchant_store_consume_rule
@@ -144,7 +149,48 @@
         }).toList();
     }
 
+    private List<Map<String, Object>> configuredRules(Long merchantId, String cardLevel) {
+        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 || string(raw).isBlank()) return List.of();
+        List<Map<String, Object>> configs = new ArrayList<>();
+        try {
+            if (raw instanceof List<?> list) {
+                for (Object item : list) 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);
+                }
+            } else {
+                for (Object item : JSON.parseArray(string(raw), 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().filter(right -> booleanValue(right.get("enabled")) && booleanValue(right.get("consumeEnabled")) && booleanValue(right.get("storeConsume")) && matchesCardLevel(string(right.get("level")), cardLevel)).map(this::configuredRule).filter(rule -> decimal(rule.get("discountRate")).signum() > 0).toList();
+    }
+
+    private Map<String, Object> configuredRule(Map<String, Object> right) {
+        String level = normalizedCardLevel(string(right.get("level")));
+        Map<String, Object> result = new LinkedHashMap<>();
+        result.put("id", configRuleId(level));
+        result.put("cardLevel", level);
+        result.put("ruleName", string(right.get("tag")).isBlank() ? "到店消费优惠" : right.get("tag"));
+        result.put("name", result.get("ruleName"));
+        result.put("discountRate", configuredDiscountRate(right.get("discount")));
+        result.put("subsidyEnabled", booleanValue(right.get("governmentSubsidy")) ? 1 : 0);
+        result.put("consumeDesc", right.get("consumeDesc"));
+        return result;
+    }
+
     private Map<String, Object> rule(Long merchantId, String cardLevel, Long ruleId) {
+        List<Map<String, Object>> configured = configuredRules(merchantId, cardLevel);
+        for (Map<String, Object> candidate : configured) if (String.valueOf(candidate.get("id")).equals(String.valueOf(ruleId))) return candidate;
         List<Map<String, Object>> found = rows("""
                 select id, card_level, rule_name, discount_rate, subsidy_enabled
                 from merchant_store_consume_rule
@@ -152,18 +198,34 @@
                   and (valid_end is null or valid_end >= current_date)
                 limit 1
                 """, ruleId, merchantId);
-        if (found.isEmpty() || !matchesCardLevel(string(found.get(0).get("cardLevel")), cardLevel)) {
-            throw new BusinessException(ErrorCode.CONFLICT, "当前人才卡不可使用所选优惠方式");
-        }
+        if (found.isEmpty() || !matchesCardLevel(string(found.get(0).get("cardLevel")), cardLevel)) throw new BusinessException(ErrorCode.CONFLICT, "当前人才卡不可使用所选优惠方式");
         return found.get(0);
+    }
+
+    private long configRuleId(String level) {
+        return switch (level) { case "EXCELLENT" -> -1L; case "OUTSTANDING" -> -2L; case "ELITE" -> -3L; default -> -9L; };
+    }
+
+    private BigDecimal configuredDiscountRate(Object value) {
+        try {
+            BigDecimal discount = decimal(string(value));
+            return discount.signum() > 0 && discount.compareTo(BigDecimal.TEN) <= 0 ? discount.divide(BigDecimal.TEN, 4, RoundingMode.HALF_UP) : BigDecimal.ZERO;
+        } catch (Exception ignored) {
+            return BigDecimal.ZERO;
+        }
+    }
+
+    private boolean booleanValue(Object value) {
+        if (value instanceof Boolean bool) return bool;
+        if (value instanceof Number number) return number.intValue() != 0;
+        String text = string(value).toLowerCase();
+        return "true".equals(text) || "1".equals(text) || "yes".equals(text);
     }
 
     private Map<String, Object> quote(Map<String, Object> rule, BigDecimal inputAmount) {
         long originalAmount = inputAmount.movePointRight(2).setScale(0, RoundingMode.HALF_UP).longValueExact();
         BigDecimal rate = decimal(rule.get("discountRate"));
-        if (rate.signum() <= 0 || rate.compareTo(BigDecimal.ONE) > 0) {
-            throw new BusinessException(ErrorCode.CONFLICT, "商户优惠规则配置无效");
-        }
+        if (rate.signum() <= 0 || rate.compareTo(BigDecimal.ONE) > 0) throw new BusinessException(ErrorCode.CONFLICT, "商户优惠规则配置无效");
         long payAmount = BigDecimal.valueOf(originalAmount).multiply(rate).setScale(0, RoundingMode.HALF_UP).longValueExact();
         long discountAmount = originalAmount - payAmount;
         long subsidyAmount = number(rule.get("subsidyEnabled")) == 1 ? discountAmount : 0;
@@ -175,7 +237,6 @@
         result.put("ruleName", rule.get("ruleName"));
         return result;
     }
-
     private Map<String, Object> merchant(MerchantPrincipal principal) {
         List<Map<String, Object>> merchants = rows("""
                 select merchant_name, address, contact_mobile, longitude, latitude
@@ -208,6 +269,8 @@
                 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).stream().map(rule -> string(rule.get("consumeDesc"))).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("以当前商户到店消费规则为准");
     }

--
Gitblit v1.7.1