|
|
@@ -330,20 +330,21 @@ class AlipayBatchPayServiceTest {
|
|
|
order.setStatus("INIT");
|
|
|
when(batchOrderMapper.selectOne(any())).thenReturn(order);
|
|
|
AlipayFundTransRenderPayResponse resp = new AlipayFundTransRenderPayResponse();
|
|
|
- resp.setOrderId("BT1");
|
|
|
- resp.setBody("https://render.alipay.com/paypage?orderId=BT1");
|
|
|
- when(alipayClient.pageExecute(any(AlipayFundTransRenderPayRequest.class))).thenReturn(resp);
|
|
|
+ resp.setCode("10000");
|
|
|
+ resp.setInitializeCode("https://p.tb.cn/_2PG4jfHMVvg9vqBUdtx1HZ");
|
|
|
+ when(alipayClient.certificateExecute(any(AlipayFundTransRenderPayRequest.class))).thenReturn(resp);
|
|
|
|
|
|
Map<String, String> result = service.renderPay("E100", "B1");
|
|
|
|
|
|
- assertNotNull(result.get("pay_url"));
|
|
|
+ // render.pay 返回收银台短链接 initialize_code(用户实测成功响应实证),直接作为 pay_url
|
|
|
+ assertEquals("https://p.tb.cn/_2PG4jfHMVvg9vqBUdtx1HZ", result.get("pay_url"));
|
|
|
verify(batchOrderMapper).updateById(order);
|
|
|
// render.pay 必传参数必须携带(文档实证枚举值: target_terminal_type=PC / initialize_code_type=SHORT_URL),
|
|
|
// 缺失时支付宝返回 INVALID_PARAMETER 报错(用户实测: 参数[target_terminal_type]错误)
|
|
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
|
|
ArgumentCaptor<AlipayFundTransRenderPayRequest> cap =
|
|
|
ArgumentCaptor.forClass(AlipayFundTransRenderPayRequest.class);
|
|
|
- verify(alipayClient).pageExecute(cap.capture());
|
|
|
+ verify(alipayClient).certificateExecute(cap.capture());
|
|
|
AlipayFundTransRenderPayModel model =
|
|
|
(AlipayFundTransRenderPayModel) cap.getValue().getBizModel();
|
|
|
assertEquals("PC", model.getTargetTerminalType());
|
|
|
@@ -352,8 +353,8 @@ class AlipayBatchPayServiceTest {
|
|
|
|
|
|
@Test
|
|
|
void renderPay_alipayBusinessError_throwsAndNotPersists() throws AlipayApiException {
|
|
|
- // 支付宝业务失败时 pageExecute 返回错误 JSON body(非 HTML 表单)——
|
|
|
- // 必须 isSuccess 校验后抛错,否则错误 JSON 会被当 pay_url 返回、前端 document.write 出整页 JSON(用户实测路径)
|
|
|
+ // 支付宝业务失败(非 10000)必须抛错且不落库——
|
|
|
+ // 否则错误响应会被当 pay_url 返回、前端拿错误内容开新窗口(用户实测: 窗口显示整页 INVALID_PARAMETER JSON)
|
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
|
order.setEnterpriseId("E100");
|
|
|
order.setOutBatchNo("B1");
|
|
|
@@ -364,8 +365,7 @@ class AlipayBatchPayServiceTest {
|
|
|
resp.setCode("40004");
|
|
|
resp.setSubCode("INVALID_PARAMETER");
|
|
|
resp.setSubMsg("参数[target_terminal_type]错误, 原因: 必须传入参数[target_terminal_type]");
|
|
|
- resp.setBody("{\"alipay_fund_trans_render_pay_response\":{\"code\":\"40004\"}}");
|
|
|
- when(alipayClient.pageExecute(any(AlipayFundTransRenderPayRequest.class))).thenReturn(resp);
|
|
|
+ when(alipayClient.certificateExecute(any(AlipayFundTransRenderPayRequest.class))).thenReturn(resp);
|
|
|
|
|
|
BusinessException ex = assertThrows(BusinessException.class, () -> service.renderPay("E100", "B1"));
|
|
|
|
|
|
@@ -374,6 +374,26 @@ class AlipayBatchPayServiceTest {
|
|
|
verify(batchOrderMapper, never()).updateById(any());
|
|
|
}
|
|
|
|
|
|
+ @Test
|
|
|
+ void renderPay_successWithoutInitializeCode_throws() throws AlipayApiException {
|
|
|
+ // 成功响应但支付宝未返回跳转链接(防御: 不把 null 当 pay_url 返回)
|
|
|
+ BatchOrderEntity order = new BatchOrderEntity();
|
|
|
+ order.setEnterpriseId("E100");
|
|
|
+ order.setOutBatchNo("B1");
|
|
|
+ order.setBatchTransId("BT1");
|
|
|
+ order.setStatus("INIT");
|
|
|
+ when(batchOrderMapper.selectOne(any())).thenReturn(order);
|
|
|
+ AlipayFundTransRenderPayResponse resp = new AlipayFundTransRenderPayResponse();
|
|
|
+ resp.setCode("10000");
|
|
|
+ when(alipayClient.certificateExecute(any(AlipayFundTransRenderPayRequest.class))).thenReturn(resp);
|
|
|
+
|
|
|
+ BusinessException ex = assertThrows(BusinessException.class, () -> service.renderPay("E100", "B1"));
|
|
|
+
|
|
|
+ assertEquals(400, ex.getCode());
|
|
|
+ assertTrue(ex.getMessage().contains("跳转链接"), ex.getMessage());
|
|
|
+ verify(batchOrderMapper, never()).updateById(any());
|
|
|
+ }
|
|
|
+
|
|
|
@Test
|
|
|
void batchQuery_syncsBatchStatus() throws AlipayApiException {
|
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
|
@@ -657,10 +677,10 @@ class AlipayBatchPayServiceTest {
|
|
|
assertTrue(bytes.length > 0);
|
|
|
}
|
|
|
|
|
|
- // ==================== I5: pay_url 长 HTML body(>1024) ====================
|
|
|
+ // ==================== I5: pay_url 落库(render.pay 返回短链接 initialize_code) ====================
|
|
|
|
|
|
@Test
|
|
|
- void renderPay_longHtmlBody_persistsWithoutError() throws AlipayApiException {
|
|
|
+ void renderPay_initializeCode_persistsAndReturns() throws AlipayApiException {
|
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
|
order.setEnterpriseId("E100");
|
|
|
order.setOutBatchNo("B1");
|
|
|
@@ -668,15 +688,15 @@ class AlipayBatchPayServiceTest {
|
|
|
order.setStatus("INIT");
|
|
|
when(batchOrderMapper.selectOne(any())).thenReturn(order);
|
|
|
|
|
|
- // 真实 pageExecute 返回自动提交 HTML 表单(1.5-4KB),远超原 varchar(1024)
|
|
|
- String html = "<html><body><form action=\"https://render.alipay.com/paypage\">" + "x".repeat(2000) + "</form></body></html>";
|
|
|
+ // 用户实测成功响应: {"code":"10000","initialize_code":"https://p.tb.cn/_2PG4jfHMVvg9vqBUdtx1HZ",...}
|
|
|
AlipayFundTransRenderPayResponse resp = new AlipayFundTransRenderPayResponse();
|
|
|
- resp.setBody(html);
|
|
|
- when(alipayClient.pageExecute(any(AlipayFundTransRenderPayRequest.class))).thenReturn(resp);
|
|
|
+ resp.setCode("10000");
|
|
|
+ resp.setInitializeCode("https://p.tb.cn/_2PG4jfHMVvg9vqBUdtx1HZ");
|
|
|
+ when(alipayClient.certificateExecute(any(AlipayFundTransRenderPayRequest.class))).thenReturn(resp);
|
|
|
|
|
|
Map<String, String> result = service.renderPay("E100", "B1");
|
|
|
|
|
|
- assertEquals(html, result.get("pay_url"));
|
|
|
+ assertEquals("https://p.tb.cn/_2PG4jfHMVvg9vqBUdtx1HZ", result.get("pay_url"));
|
|
|
verify(batchOrderMapper).updateById(order);
|
|
|
}
|
|
|
|