1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
package com.talentcard.server.business.payment.huifu;
 
import static org.assertj.core.api.Assertions.assertThat;
 
import java.util.LinkedHashMap;
import java.util.Map;
 
import com.talentcard.server.business.payment.huifu.HuifuDelayAccountGateway.HuifuDelayRevert;
import com.talentcard.server.business.payment.huifu.HuifuDelayAccountGateway.HuifuDelayRevert.Outcome;
import org.junit.jupiter.api.Test;
 
/**
 * 资金回退(交易确认退款)的结果分类。
 *
 * <p>这一组用例盯的是「同一个业务码在两条路径上语义不同」:交易确认把 {@code 23000003} 当作
 * 「已无未确认金额」=幂等成功(有真实回执复验过),但回退路径上没有回执证明它的含义,一律不能算成功
 * ——判成成功会让订单翻回「待核销」而钱还在商户基本户,属于资金事故。
 */
class HuifuDelayRevertClassificationTests {
 
    @Test
    void aSuccessCodeFromTheProviderIsTheOnlySuccess() {
        assertThat(outcomeOf("00000000", "S")).isEqualTo(Outcome.SUCCEEDED);
        // 顶层网关码也代表成功调用。
        assertThat(outcomeOf("10000", "S")).isEqualTo(Outcome.SUCCEEDED);
    }
 
    /**
     * 语义未定的码既不算成功也不算失败:{@code 23000003} 在确认路径上是幂等成功,
     * 在回退路径上可能是「已无已确认金额」,也可能是被拒的原因(例如余额不足)。
     */
    @Test
    void codesWithUndeterminedMeaningAreNeverSuccess() {
        assertThat(outcomeOf("23000003", "F")).isEqualTo(Outcome.NEEDS_REVIEW);
        assertThat(outcomeOf("23000004", "F")).isEqualTo(Outcome.NEEDS_REVIEW);
        assertThat(outcomeOf("23000003", "S")).isEqualTo(Outcome.NEEDS_REVIEW);
    }
 
    @Test
    void aDeclaredFailureIsAFailure() {
        assertThat(outcomeOf("22000002", "F")).isEqualTo(Outcome.FAILED);
        assertThat(outcomeOf("", "F")).isEqualTo(Outcome.FAILED);
    }
 
    @Test
    void aRequestStillInFlightIsNotASettledResult() {
        assertThat(outcomeOf("00000100", "P")).isEqualTo(Outcome.PROCESSING);
        assertThat(outcomeOf("", "")).isEqualTo(Outcome.PROCESSING);
        // 状态说成功但没有任何业务码:两个证据不一致,按未定处理,不按成功放行。
        assertThat(outcomeOf("", "S")).isEqualTo(Outcome.PROCESSING);
    }
 
    @Test
    void theProviderDescriptionIsKeptForTroubleshooting() {
        HuifuDelayRevert revert = HuifuDelayRevert.from(response("22000003", "F", "账户余额不足"));
        assertThat(revert.describe()).isEqualTo("账户余额不足");
        assertThat(revert.code()).isEqualTo("22000003");
    }
 
    private Outcome outcomeOf(String code, String transStat) {
        return HuifuDelayRevert.from(response(code, transStat, "返回描述")).outcome();
    }
 
    private Map<String, Object> response(String code, String transStat, String description) {
        Map<String, Object> response = new LinkedHashMap<>();
        response.put("sub_resp_code", code);
        response.put("sub_resp_desc", description);
        response.put("trans_stat", transStat);
        return response;
    }
}