yeg
2026-09-14 723b7560ecaa16129210591fff3de435bd25f136
fix(merchant): 自动结算不再阻止商户收款

未核销的钱现在由延迟户兜住(官方定义「不可结算、不可取现」),只有核销确认后
才分账进基本户,因此自动结算开着也不会把未核销的钱提前结走。

原规则「自动结算必须关闭才能收款」是延迟分账之前立的,现在不但多余,还会让所有
新支付被拦住(支付路径的收款能力判定直接报「自动结算尚未关闭」)。
3个文件已修改
32 ■■■■■ 已修改文件
talent-card-server/src/main/java/com/talentcard/server/business/merchant/MerchantPaymentReadinessService.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
talent-card-server/src/test/java/com/talentcard/server/business/merchant/MerchantPaymentReadinessServiceTests.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
talent-card-server/src/test/java/com/talentcard/server/business/portal/AppOrderPortalServiceTests.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
talent-card-server/src/main/java/com/talentcard/server/business/merchant/MerchantPaymentReadinessService.java
@@ -153,7 +153,8 @@
        // The payment path never calls the provider itself: an unfilled snapshot is filled by the
        // onboarding completion, the scheduler, or an explicit admin refresh.
        if (unknown) return Readiness.blocked("商户收款能力待确认,暂时无法收款");
        if (!isAutoSettleOff(application.autoSettleStatus())) return Readiness.blocked("商户自动结算尚未关闭,暂时无法收款");
        // 不再要求「自动结算必须关闭」:未核销的钱由延迟户兜住(不可结算、不可取现),
        // 只有核销确认后才进基本户,因此自动结算开着也不会把钱提前结走。
        if (!isCashAvailable(application.cashSwitchStatus())) return Readiness.blocked("商户取现能力不可用,暂时无法收款");
        if (!isMerchantNormal(application.merchantStatus())) {
            return Readiness.blocked("斗拱子商户状态异常(" + application.merchantStatus() + "),暂时无法收款");
@@ -163,9 +164,6 @@
    /** The payment integration is switched off, so provider-side network checks cannot be required. */
    private Readiness localOnly(Application application) {
        if (!application.autoSettleStatus().isBlank() && !isAutoSettleOff(application.autoSettleStatus())) {
            return Readiness.blocked("商户自动结算尚未关闭,暂时无法收款");
        }
        if (!application.cashSwitchStatus().isBlank() && !isCashAvailable(application.cashSwitchStatus())) {
            return Readiness.blocked("商户取现能力不可用,暂时无法收款");
        }
talent-card-server/src/test/java/com/talentcard/server/business/merchant/MerchantPaymentReadinessServiceTests.java
@@ -3,6 +3,7 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mockingDetails;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@@ -98,13 +99,15 @@
        assertThat(merchant.huifuId()).isNotBlank();
    }
    /**
     * 自动结算开着不再阻止收款:未核销的钱由延迟户兜住(不可结算、不可取现),
     * 只有核销确认后才进基本户,因此自动结算不会把未核销的钱提前结走。
     */
    @Test
    void rejectsANewPaidOrderOnceAutoSettlementIsBackOn() {
    void allowsANewPaidOrderEvenWhenAutoSettlementIsOn() {
        confirmSnapshot("NORMAL", "1", "1");
        assertThatThrownBy(() -> readinessService.requireCollectingMerchant(merchantId, storeId))
                .isInstanceOf(BusinessException.class)
                .hasMessageContaining("自动结算");
        assertThat(readinessService.requireCollectingMerchant(merchantId, storeId).huifuId()).isNotBlank();
    }
    @Test
@@ -175,9 +178,10 @@
    void reusesTheConfirmedSnapshotInsteadOfQueryingTheProviderAgain() {
        confirmSnapshot("NORMAL", "0", "1");
        // 快照可能被定时刷新任务碰过,所以只断言「这次判定本身没有再查通道」。
        int before = mockingDetails(capabilityGateway).getInvocations().size();
        assertThat(readinessService.readiness(merchantId, storeId).ready()).isTrue();
        verify(capabilityGateway, times(1)).query(any(HuifuMerchantCapabilityQueryCommand.class));
        assertThat(mockingDetails(capabilityGateway).getInvocations().size()).isEqualTo(before);
    }
    @Test
talent-card-server/src/test/java/com/talentcard/server/business/portal/AppOrderPortalServiceTests.java
@@ -126,14 +126,14 @@
        assertThat(jdbc.queryForObject("select coupon_id from benefit_order where order_no = ?", Long.class, replacement.get("orderNo"))).isEqualTo(couponId);
    }
    /** 自动结算开着不再阻止下单:未核销的钱由延迟户兜住,不会被自动结算提前结走。 */
    @Test
    void refusesPaidOrderWhileMerchantSettlementCapabilityIsMissing() {
    void allowsPaidOrderEvenWhenMerchantAutoSettlementIsOn() {
        jdbc.update("update merchant_onboarding_application set auto_settle_status='1' where id=?", onboardingId);
        assertThatThrownBy(() -> appOrderPortalService.create(talentId, new AppOrderCreateRequest(merchantId, productId, null), "app-order-blocked-" + System.nanoTime()))
                .isInstanceOf(BusinessException.class)
                .hasMessageContaining("自动结算");
        assertThat(jdbc.queryForObject("select count(*) from benefit_order where merchant_id=?", Long.class, merchantId)).isZero();
        Map<String, Object> created = appOrderPortalService.create(talentId,
                new AppOrderCreateRequest(merchantId, productId, null), "app-order-auto-settle-" + System.nanoTime());
        assertThat(created.get("orderNo")).isNotNull();
    }
    @Test