From 242917765d2711b723e98764396054acef2a7297 Mon Sep 17 00:00:00 2001
From: yeg <1347747024@qq.com>
Date: 星期三, 16 九月 2026 00:47:50 +0800
Subject: [PATCH] feat(merchant): 分阶段开通对所有商户生效

---
 talent-card-server/src/test/java/com/talentcard/server/business/merchant/MerchantOnboardingRetryReleaseTests.java |   59 ++++++++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 44 insertions(+), 15 deletions(-)

diff --git a/talent-card-server/src/test/java/com/talentcard/server/business/merchant/MerchantOnboardingRetryReleaseTests.java b/talent-card-server/src/test/java/com/talentcard/server/business/merchant/MerchantOnboardingRetryReleaseTests.java
index 55ece67..8281e05 100644
--- a/talent-card-server/src/test/java/com/talentcard/server/business/merchant/MerchantOnboardingRetryReleaseTests.java
+++ b/talent-card-server/src/test/java/com/talentcard/server/business/merchant/MerchantOnboardingRetryReleaseTests.java
@@ -1,25 +1,28 @@
 package com.talentcard.server.business.merchant;
 
 import static org.assertj.core.api.Assertions.assertThat;
-
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
 import java.util.Map;
-
 import com.talentcard.server.business.merchant.auth.MerchantPrincipal;
+import com.talentcard.server.business.payment.huifu.HuifuOnboardingProgressGateway;
 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;
+import org.springframework.test.context.bean.override.mockito.MockitoBean;
 
 /**
- * 通道侧配置失败的进件,重新提交时要连银行卡一起收口。
+ * 通道侧配置失败的进件**不再关单重来**:保留原商户号和银行卡,失败的步骤由刷新重试。
  *
- * <p>只把进件标成 rejected 不够:银行卡校验是独立的一条,`status='pending'` 的卡本身就足以拦住复用,
- * 报「该银行卡已有审核中的进件或已通过的申请,请勿重复提交」。那张卡之所以停在 pending,
- * 正是这条失败的进件留下的——实际就踩到过这个坑,所以两者必须一起收口。
+ * <p>原先的做法是把进件和银行卡一起标成 rejected,好让商户用同一张卡整单重提;规格已明确改成
+ * 「基本进件成功后的局部失败保留原商户号和银行卡」。这类申请现在走分阶段模型,
+ * {@code closeRetryableApplication} 对它只刷新进度、不释放任何东西。
  *
- * <p>反过来,**进行中**的申请(配置还在跑或还没开始)不能被动到,否则正常流程会被重复提交搅乱。
+ * <p>例外是被通道**明确驳回基本资料**的申请:它交回旧的单状态模型({@code supports()} 对
+ * {@code rejected} 返回 false),商户端才拿得到「重新提交」入口。
  */
 @SpringBootTest
 @ActiveProfiles("test")
@@ -30,6 +33,11 @@
 
     @Autowired
     private MerchantSettlementService settlementService;
+
+    // 分阶段刷新会先推进开通步骤,这几个网关都要挡住,否则测试会真的打到汇付。
+    @MockitoBean private HuifuOnboardingProgressGateway progressGateway;
+    @MockitoBean private com.talentcard.server.business.payment.huifu.HuifuMerchantWechatConfigGateway wechatConfigGateway;
+    @MockitoBean private com.talentcard.server.business.payment.huifu.HuifuMerchantBusinessOpenGateway businessOpenGateway;
 
     private Long merchantId;
     private Long storeId;
@@ -47,24 +55,27 @@
     }
 
     @Test
-    void aFailedProvisioningReleasesBothTheApplicationAndItsBankCard() {
+    void aFailedProvisioningKeepsTheApplicationAndItsBankCard() {
         seedApplication("failed", "not_started");
+        stubProvider();
 
         settlementService.closeRetryableApplication(principal());
 
-        assertThat(status("merchant_onboarding_application", applicationId)).isEqualTo("rejected");
-        // 关键:卡也要放行,否则商户用同一张卡重新提交仍会被拦。
-        assertThat(status("merchant_bank_card", bankCardId)).isEqualTo("rejected");
+        // 关键变化:不再释放。进件与银行卡都留着,失败的开通步骤由刷新去重试——
+        // 释放掉就等于让商户整单重来,与「保留原商户号和银行卡」相悖。
+        assertThat(status("merchant_onboarding_application", applicationId)).isEqualTo("pending");
+        assertThat(status("merchant_bank_card", bankCardId)).isEqualTo("pending");
     }
 
     @Test
-    void aFailedBusinessOpenAlsoReleasesTheCard() {
+    void aFailedBusinessOpenKeepsTheCardForRetry() {
         seedApplication("approved", "failed");
+        stubProvider();
 
         settlementService.closeRetryableApplication(principal());
 
-        assertThat(status("merchant_onboarding_application", applicationId)).isEqualTo("rejected");
-        assertThat(status("merchant_bank_card", bankCardId)).isEqualTo("rejected");
+        assertThat(status("merchant_onboarding_application", applicationId)).isEqualTo("pending");
+        assertThat(status("merchant_bank_card", bankCardId)).isEqualTo("pending");
     }
 
     @Test
@@ -77,8 +88,26 @@
         assertThat(status("merchant_bank_card", bankCardId)).isEqualTo("pending");
     }
 
+    /** 被驳回的申请回到旧的单状态模型,刷新不再接管它——否则会被翻回 pending,重提入口消失。 */
+    @Test
+    void aRejectedApplicationIsLeftToTheSingleStatusModel() {
+        seedApplication("failed", "failed");
+        jdbc.update("update merchant_onboarding_application set status='rejected', reject_reason='基本资料审核未通过' where id=?", applicationId);
+
+        Map<String,Object> view = settlementService.refreshProgress(applicationId, false);
+
+        assertThat(view).containsEntry("status", "rejected");
+        verifyNoInteractions(progressGateway);
+    }
+
+    private void stubProvider() {
+        when(progressGateway.queryApplication(anyString(),anyString())).thenReturn(Map.of("resp_code","00000000","apply_status","Y","reg_status","S"));
+        when(progressGateway.queryCapabilities(anyString())).thenReturn(Map.of("resp_code","00000000","delay_flag","Y","forced_delay_flag","N"));
+        when(progressGateway.queryWechatConfig(anyString())).thenReturn(Map.of("resp_code","00000000"));
+    }
+
     private void seedApplication(String wechatConfigStatus, String businessOpenStatus) {
-        String applicationNo = "MO-RT-" + suffix;
+        String applicationNo = "MO-RT-" + suffix + "-" + wechatConfigStatus;
         jdbc.update("""
                 insert into merchant_onboarding_application(merchant_id, store_id, application_no, subject_type, subject_name,
                                                             contact_name, contact_mobile, idempotency_key, status,

--
Gitblit v1.7.1