|
@@ -0,0 +1,103 @@
|
|
|
|
|
+package com.payment.platform.module.payment.account.service;
|
|
|
|
|
+
|
|
|
|
|
+import com.alipay.api.AlipayClient;
|
|
|
|
|
+import com.alipay.api.response.AlipayFundTransCommonQueryResponse;
|
|
|
|
|
+import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
|
|
+import com.payment.platform.core.alipay.AlipayClientFactory;
|
|
|
|
|
+import com.payment.platform.module.payment.account.entity.TransferEntity;
|
|
|
|
|
+import com.payment.platform.module.payment.account.mapper.AccountMapper;
|
|
|
|
|
+import com.payment.platform.module.payment.account.mapper.DepositMapper;
|
|
|
|
|
+import com.payment.platform.module.payment.account.mapper.TransferMapper;
|
|
|
|
|
+import com.payment.platform.module.payment.account.mapper.WithdrawMapper;
|
|
|
|
|
+import com.payment.platform.module.payment.enterprise.mapper.EnterpriseMapper;
|
|
|
|
|
+import org.junit.jupiter.api.BeforeEach;
|
|
|
|
|
+import org.junit.jupiter.api.Test;
|
|
|
|
|
+import org.junit.jupiter.api.extension.ExtendWith;
|
|
|
|
|
+import org.mockito.Mock;
|
|
|
|
|
+import org.mockito.junit.jupiter.MockitoExtension;
|
|
|
|
|
+
|
|
|
|
|
+import java.util.List;
|
|
|
|
|
+
|
|
|
|
|
+import static org.junit.jupiter.api.Assertions.*;
|
|
|
|
|
+import static org.mockito.ArgumentMatchers.any;
|
|
|
|
|
+import static org.mockito.Mockito.*;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 「全量同步」这条腿({@code alipay.fund.trans.common.query})把单子置成终态时的字段落库。
|
|
|
|
|
+ *
|
|
|
|
|
+ * <p>它和回调腿是**两条独立的路**:回调那条在 {@code 7a2ec244} 已修,这条当时没修。
|
|
|
|
|
+ * 症状一样 —— 状态变了、失败原因两列空着,而管理端界面此前也从不渲染它们,
|
|
|
|
|
+ * 于是整整一类失败记录既查不到原因、也看不见原因(2026-09-30 用户报的就是这个)。
|
|
|
|
|
+ *
|
|
|
|
|
+ * <p>上面那条断言依据 SDK 实证:{@code AlipayFundTransCommonQueryResponse} 有
|
|
|
|
|
+ * {@code getErrorCode()} / {@code getFailReason()}(javap 4.40.865.ALL 实测),
|
|
|
|
|
+ * 所以「上游不送」不成立,是我们没读。
|
|
|
|
|
+ */
|
|
|
|
|
+@ExtendWith(MockitoExtension.class)
|
|
|
|
|
+class AlipayTransferSyncStatusTest {
|
|
|
|
|
+
|
|
|
|
|
+ @Mock private AlipayClientFactory alipayClientFactory;
|
|
|
|
|
+ @Mock private AccountMapper accountMapper;
|
|
|
|
|
+ @Mock private TransferMapper transferMapper;
|
|
|
|
|
+ @Mock private DepositMapper depositMapper;
|
|
|
|
|
+ @Mock private WithdrawMapper withdrawMapper;
|
|
|
|
|
+ @Mock private EnterpriseMapper enterpriseMapper;
|
|
|
|
|
+ @Mock private AlipayClient alipayClient;
|
|
|
|
|
+
|
|
|
|
|
+ private AlipayTransferService service;
|
|
|
|
|
+
|
|
|
|
|
+ @BeforeEach
|
|
|
|
|
+ void setUp() {
|
|
|
|
|
+ service = new AlipayTransferService(alipayClientFactory, accountMapper, transferMapper,
|
|
|
|
|
+ depositMapper, withdrawMapper, enterpriseMapper, new ObjectMapper());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /** 造一条 DEALING、且上游查询回 FAIL(带原因)的记录。 */
|
|
|
|
|
+ private TransferEntity dealingTransfer() throws Exception {
|
|
|
|
|
+ TransferEntity t = new TransferEntity();
|
|
|
|
|
+ t.setId(1L);
|
|
|
|
|
+ t.setOutBizNo("1302345790789783552");
|
|
|
|
|
+ t.setEnterpriseId("2088000000000000");
|
|
|
|
|
+ t.setStatus("DEALING");
|
|
|
|
|
+ when(transferMapper.selectList(any())).thenReturn(List.of(t));
|
|
|
|
|
+ when(alipayClientFactory.getClient("2088000000000000")).thenReturn(alipayClient);
|
|
|
|
|
+ return t;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private AlipayFundTransCommonQueryResponse queryResponse(String status, String errorCode, String failReason)
|
|
|
|
|
+ throws Exception {
|
|
|
|
|
+ AlipayFundTransCommonQueryResponse resp = new AlipayFundTransCommonQueryResponse();
|
|
|
|
|
+ resp.setCode("10000"); // isSuccess() 判的是 code == 10000
|
|
|
|
|
+ resp.setStatus(status);
|
|
|
|
|
+ resp.setErrorCode(errorCode);
|
|
|
|
|
+ resp.setFailReason(failReason);
|
|
|
|
|
+ doReturn(resp).when(alipayClient).certificateExecute(any());
|
|
|
|
|
+ return resp;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void syncAll_fail_writesErrorCodeAndReason() throws Exception {
|
|
|
|
|
+ TransferEntity t = dealingTransfer();
|
|
|
|
|
+ queryResponse("FAIL", "Ali_Err_111036", "该银行账户已冻结,请联系银行客服");
|
|
|
|
|
+
|
|
|
|
|
+ service.transferSyncAllService();
|
|
|
|
|
+
|
|
|
|
|
+ assertEquals("FAIL", t.getStatus());
|
|
|
|
|
+ assertEquals("Ali_Err_111036", t.getErrorCode());
|
|
|
|
|
+ assertEquals("该银行账户已冻结,请联系银行客服", t.getErrorMsg());
|
|
|
|
|
+ verify(transferMapper).updateById(t);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /** 正对照:成功的单子上游不送这两个字段,守卫必须一个字符都不写。 */
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void syncAll_success_leavesErrorColumnsUntouched() throws Exception {
|
|
|
|
|
+ TransferEntity t = dealingTransfer();
|
|
|
|
|
+ queryResponse("SUCCESS", null, null);
|
|
|
|
|
+
|
|
|
|
|
+ service.transferSyncAllService();
|
|
|
|
|
+
|
|
|
|
|
+ assertEquals("SUCCESS", t.getStatus());
|
|
|
|
|
+ assertNull(t.getErrorCode());
|
|
|
|
|
+ assertNull(t.getErrorMsg());
|
|
|
|
|
+ }
|
|
|
|
|
+}
|