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; /** * 资金回退(交易确认退款)的结果分类。 * *
这一组用例盯的是「同一个业务码在两条路径上语义不同」:交易确认把 {@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