talent-card-server/src/test/java/com/talentcard/server/business/admin/MerchantSettlementAdminServiceTests.java
@@ -6,6 +6,7 @@
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -131,6 +132,30 @@
        assertThat(recordsOf(fetch(null, null, null, "P"))).isEmpty();
    }
    /**
     * 多家商家共用同一个汇付商户号时,同一条结算流水只能出现一次。
     *
     * <p>结算流水属于**商户号**(一个收款主体),不属于商家:连锁各门店是独立商家、共用同一个收款主体,
     * 通道里就是一条流水。按商家逐家去问通道,会把同一条流水按共用它的商家数重复印出来——页面上看起来
     * 像结了 N 笔钱(7 家共用就是 7 行一模一样的流水号/金额/到账卡)。
     */
    @Test
    void oneSettlementFlowIsNotRepeatedForEveryMerchantThatSharesTheHuifuId() {
        String sharedHuifuId = "TF" + suffix + "SHARED";
        approveMerchantOn(sharedHuifuId, "Settlement chain A " + suffix, "NORMAL", "1", true, "SHARED-A", "餐饮服务", "13800000005");
        approveMerchantOn(sharedHuifuId, "Settlement chain B " + suffix, "NORMAL", "1", true, "SHARED-B", "餐饮服务", "13800000006");
        List<String> sharedFlows = recordsOf(fetch(null, null, null, null)).stream()
                .map(record -> String.valueOf(record.get("providerTransactionNo")))
                .filter(flow -> flow.endsWith(sharedHuifuId))
                .toList();
        assertThat(sharedFlows)
                .as("一条流水只该出现一次,不能按共用它的商家数重复")
                .containsExactlyInAnyOrder("TX-S-" + sharedHuifuId, "TX-F-" + sharedHuifuId);
        verify(settlementRecordGateway, times(1)).query(eq(sharedHuifuId), any(), any(), anyInt());
    }
    /** 关闭的子商户回的是通道原话;它只在真的被查到时才会成为一条失败提示。 */
    private void stubProvider() {
        when(settlementRecordGateway.query(anyString(), anyString(), anyString(), anyInt()))
@@ -161,12 +186,17 @@
    /** 建一家已进件通过的商户并写下通道能力快照,返回它的斗拱子商户号。 */
    private String approveMerchant(String merchantName, String merchantStat, String cashSwitch, boolean verified,
                                   String tag, String merchantType, String contactMobile) {
        return approveMerchantOn("TF" + suffix + tag, merchantName, merchantStat, cashSwitch, verified, tag, merchantType, contactMobile);
    }
    /** 同一个商户号可以被多家商家共用(连锁各门店各是一个独立商家),所以商户号由调用方给。 */
    private String approveMerchantOn(String huifuId, String merchantName, String merchantStat, String cashSwitch,
                                     boolean verified, String tag, String merchantType, String contactMobile) {
        jdbc.update("insert into merchant(merchant_name, merchant_type, contact_mobile, status, deleted) values (?, ?, ?, 1, 0)",
                merchantName, merchantType, contactMobile);
        Long merchantId = jdbc.queryForObject("select max(id) from merchant", Long.class);
        jdbc.update("insert into merchant_store(merchant_id, store_name, status, deleted) values (?, ?, 1, 0)", merchantId, merchantName);
        Long storeId = jdbc.queryForObject("select max(id) from merchant_store", Long.class);
        String huifuId = "TF" + suffix + tag;
        jdbc.update("""
                insert into merchant_onboarding_application(merchant_id, store_id, application_no, subject_type, subject_name,
                                                            contact_name, contact_mobile, idempotency_key, status, provider_huifu_id,