Procházet zdrojové kódy

fix: 批量付款全链路验证修复 - 补description列、授权未完成时返回AUTHING而非报错、AUTH_INFO_NOT_EXISTS友好提示

alphaH před 5 dny
rodič
revize
c5fbab0c7d

+ 10 - 1
java/src/main/java/com/payment/platform/module/payment/batch/service/AlipayBatchPayService.java

@@ -142,8 +142,13 @@ public class AlipayBatchPayService {
             request.setBizModel(model);
             AlipayFundAuthorizeUniQueryResponse response =
                     alipayClientFactory.getClient(enterpriseId, BIZ_TYPE).certificateExecute(request);
-            if (!response.isSuccess())
+            if (!response.isSuccess()) {
+                // 未授权(协议不存在)是正常业务状态而非查询失败: 前端应展示「授权中」而不是报错
+                if ("AUTHORIZATION_NOT_EXIST".equals(response.getSubCode())) {
+                    return Map.of("agreement_no", "", "status", "AUTHING");
+                }
                 throw new BusinessException(400, "查询授权状态失败: " + response.getMsg());
+            }
 
             // 仅 AUTHED 才回写: UNBIND 也返回协议号, 直接回写会破坏本地状态机(UNBIND 由异步通知回写)
             if ("AUTHED".equals(response.getStatus())
@@ -259,6 +264,10 @@ public class AlipayBatchPayService {
                     if (existing != null)
                         return acceptedBatchResult(existing);
                 }
+                // 业务前置条件: 付款方未完成制单授权 → 提示明确动作而非透传支付宝原始文案
+                if ("AUTH_INFO_NOT_EXISTS".equals(response.getSubCode())) {
+                    throw new BusinessException(400, "付款方尚未完成制单授权,请先在「制单授权」中生成授权链接并完成授权(AUTH_INFO_NOT_EXISTS)");
+                }
                 throw new BusinessException(400, "创建批次失败: " + response.getMsg() + " (" + response.getSubCode() + ")");
             }
 

+ 4 - 0
java/src/main/resources/db/migration/V1.6__add_description_to_pay_batch_tables.sql

@@ -0,0 +1,4 @@
+-- 批量付款 3 张表补 description 列(与既有 pay_* 表对齐,PaymentBaseEntity.description 映射所需)
+ALTER TABLE pay_batch_authorize ADD COLUMN description text;
+ALTER TABLE pay_batch_order    ADD COLUMN description text;
+ALTER TABLE pay_batch_detail   ADD COLUMN description text;

+ 43 - 0
java/src/test/java/com/payment/platform/module/payment/batch/service/AlipayBatchPayServiceTest.java

@@ -364,4 +364,47 @@ class AlipayBatchPayServiceTest {
                 () -> service.batchExport("E100", null, "bad-time", null));
         assertEquals(400, ex.getCode());
     }
+
+    @Test
+    void queryAuthorize_notExist_returnsAUTHINGInsteadOfError() throws AlipayApiException {
+        // Task 8 全链路验证: 支付宝 40004 AUTHORIZATION_NOT_EXIST(未授权)是正常业务状态而非查询失败
+        AlipayFundAuthorizeUniQueryResponse resp = new AlipayFundAuthorizeUniQueryResponse();
+        resp.setCode("40004");
+        resp.setSubCode("AUTHORIZATION_NOT_EXIST");
+        resp.setMsg("Business Failed");
+        when(alipayClient.certificateExecute(any(AlipayFundAuthorizeUniQueryRequest.class))).thenReturn(resp);
+
+        Map<String, String> result = service.queryAuthorize("E100", "A1");
+
+        assertEquals("", result.get("agreement_no"));
+        assertEquals("AUTHING", result.get("status"));
+        verify(batchAuthorizeMapper, never()).updateById(any());
+    }
+
+    @Test
+    void batchCreate_authInfoNotExists_friendlyMessage() throws AlipayApiException {
+        // Task 8 全链路验证: AUTH_INFO_NOT_EXISTS(付款方未授权)应提示明确动作而非透传支付宝原文案
+        AlipayFundBatchCreateResponse resp = new AlipayFundBatchCreateResponse();
+        resp.setCode("40004");
+        resp.setSubCode("AUTH_INFO_NOT_EXISTS");
+        resp.setMsg("Business Failed");
+        when(alipayClient.certificateExecute(any(AlipayFundBatchCreateRequest.class))).thenReturn(resp);
+
+        BatchCreateDTO dto = new BatchCreateDTO();
+        dto.setEnterpriseId("E100");
+        dto.setOutBatchNo("B1");
+        dto.setOrderTitle("202608报销");
+        dto.setPayerUid("2088PAYER");
+        BatchCreateDTO.BatchDetailDTO detail = new BatchCreateDTO.BatchDetailDTO();
+        detail.setOutBizNo("D1");
+        detail.setAmount(new BigDecimal("20.11"));
+        detail.setPayeeIdentity("test@taobao.com");
+        detail.setPayeeIdentityType("ALIPAY_LOGON_ID");
+        detail.setPayeeName("张三");
+        dto.setDetails(List.of(detail));
+
+        BusinessException ex = assertThrows(BusinessException.class, () -> service.batchCreate(dto));
+        assertEquals(400, ex.getCode());
+        assertTrue(ex.getMessage().contains("制单授权"), "应提示先完成制单授权: " + ex.getMessage());
+    }
 }