From 2aabed512ca44772d16d31bce833f31184676867 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期四, 17 九月 2026 11:10:08 +0800
Subject: [PATCH] fix(merchant): 首页交易总额只统计已核销订单,退款受理后立即回落
---
talent-card-server/src/main/java/com/talentcard/server/service/MerchantSettlementStatisticsService.java | 2
talent-card-server/src/test/java/com/talentcard/server/service/MerchantSettlementStatisticsServiceTests.java | 78 +++++++++++++++++++++++++++++++++++++++
talent-card-server/src/main/java/com/talentcard/server/mapper/StatisticsQuerySql.java | 3 +
3 files changed, 82 insertions(+), 1 deletions(-)
diff --git a/talent-card-server/src/main/java/com/talentcard/server/mapper/StatisticsQuerySql.java b/talent-card-server/src/main/java/com/talentcard/server/mapper/StatisticsQuerySql.java
index 0f856d6..e5ebb0b 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/mapper/StatisticsQuerySql.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/mapper/StatisticsQuerySql.java
@@ -382,10 +382,13 @@
return sql("""
select
coalesce((
+ -- 只算已核销的实付金额:未核销的钱还扣在通道的延迟户里,核销后才分账给商户;
+ -- 退款中的订单在通道结果收敛前仍是 order_status = 1,只有「已核销」能立刻挡住它。
select sum(o.pay_amount)
from benefit_order o
where o.deleted = 0
and o.order_status = 1
+ and o.verify_status = 1
and o.merchant_id = #{merchantId}
), 0) as transactionAmountCents,
coalesce((
diff --git a/talent-card-server/src/main/java/com/talentcard/server/service/MerchantSettlementStatisticsService.java b/talent-card-server/src/main/java/com/talentcard/server/service/MerchantSettlementStatisticsService.java
index 0dc4d4e..2b0c70d 100644
--- a/talent-card-server/src/main/java/com/talentcard/server/service/MerchantSettlementStatisticsService.java
+++ b/talent-card-server/src/main/java/com/talentcard/server/service/MerchantSettlementStatisticsService.java
@@ -130,7 +130,7 @@
result.put("subsidyAmountCents", subsidyAmount);
result.put("subsidyAmount", yuan(subsidyAmount));
result.put("hasData", transactionAmount > 0 || todayVerificationCount > 0 || weekVerificationCount > 0 || subsidyAmount > 0);
- result.put("statisticsBasis", "交易总额统计已支付订单实付金额;补贴总额统计政府承担的订单补贴、政府补贴券及酒店免费入住线下补贴,商家自行让利不进入政府补贴结算");
+ result.put("statisticsBasis", "交易总额统计已支付且已核销订单的实付金额;补贴总额统计政府承担的订单补贴、政府补贴券及酒店免费入住线下补贴,商家自行让利不进入政府补贴结算");
return result;
}
diff --git a/talent-card-server/src/test/java/com/talentcard/server/service/MerchantSettlementStatisticsServiceTests.java b/talent-card-server/src/test/java/com/talentcard/server/service/MerchantSettlementStatisticsServiceTests.java
new file mode 100644
index 0000000..c7577e3
--- /dev/null
+++ b/talent-card-server/src/test/java/com/talentcard/server/service/MerchantSettlementStatisticsServiceTests.java
@@ -0,0 +1,78 @@
+package com.talentcard.server.service;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.sql.Timestamp;
+import java.time.LocalDateTime;
+import java.util.Map;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.test.context.ActiveProfiles;
+
+/**
+ * 商户首页统计卡片的取数口径。
+ *
+ * <p>「交易总额」是商户首页最显眼的数字,口径必须是**已支付且已核销**的订单实付金额:
+ * 未核销的订单钱还扣在通道的延迟户里,核销后才分账给商户,把它算进交易总额等于告诉商户
+ * 他已经收到了还没到手的钱。
+ *
+ * <p>另一个必守的性质是**退款受理后首页立刻回落**。人才端的退款受理成功只把订单置为「退款中」,
+ * 通道的最终结果要等对账任务或下一次读订单才收敛(最长十分钟),中间这段时间订单还是
+ * {@code order_status = 1}。所以统计口径不能依赖订单状态收敛,必须靠「是否核销」把这类订单挡在外面。
+ */
+@SpringBootTest
+@ActiveProfiles("test")
+class MerchantSettlementStatisticsServiceTests {
+
+ @Autowired
+ private JdbcTemplate jdbc;
+
+ @Autowired
+ private MerchantSettlementStatisticsService service;
+
+ private Long merchantId;
+ private Long talentId;
+
+ @BeforeEach
+ void prepareMerchant() {
+ String suffix = String.valueOf(System.nanoTime());
+ jdbc.update("insert into merchant(merchant_name, status, can_login_merchant_app, deleted) values (?, 1, 1, 0)",
+ "首页统计测试商户 " + suffix);
+ merchantId = jdbc.queryForObject("select max(id) from merchant", Long.class);
+ jdbc.update("insert into talent_user(openid, name, mobile, status, deleted) values (?, ?, ?, 1, 0)",
+ "dashboard-test-" + suffix, "首页统计测试人才", "13800000000");
+ talentId = jdbc.queryForObject("select max(id) from talent_user", Long.class);
+ }
+
+ @Test
+ void countsOnlyVerifiedOrdersInDashboardTransactionAmount() {
+ long verifiedPayAmount = 1000L;
+ // 已支付且已核销:钱已经确认分账给商户,计入。
+ insertOrder("VER", 1, 1, 0, verifiedPayAmount);
+ // 已支付但未核销:钱还在延迟户,未核销就不算。
+ insertOrder("UNV", 1, 0, 0, 2000L);
+ // 已支付、未核销、退款受理中:人才端刚点了退款,通道结果还没收敛,首页必须立刻回落。
+ insertOrder("REF", 1, 0, 1, 4000L);
+
+ Map<String, Object> cards = service.dashboardCards(merchantId);
+
+ assertThat(((Number) cards.get("transactionAmountCents")).longValue()).isEqualTo(verifiedPayAmount);
+ }
+
+ private void insertOrder(String marker, int orderStatus, int verifyStatus, int refundStatus, long payAmount) {
+ LocalDateTime now = LocalDateTime.now();
+ jdbc.update("""
+ insert into benefit_order(order_no, order_type, merchant_id, talent_id, product_name_snapshot,
+ order_amount, pay_amount, subsidy_amount, order_status, verify_status,
+ refund_status, created_at, updated_at, deleted)
+ values (?, 'GROUP_BUY', ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, ?, 0)
+ """,
+ "DASHBOARD-" + marker + "-" + System.nanoTime(), merchantId, talentId, "首页统计测试商品",
+ payAmount, payAmount, orderStatus, verifyStatus, refundStatus,
+ Timestamp.valueOf(now), Timestamp.valueOf(now));
+ }
+}
--
Gitblit v1.7.1