|
|
@@ -1084,7 +1084,7 @@ class AlipayBatchPayServiceTest {
|
|
|
assertEquals("ALIPAY_OPEN_ID", m.getPayerInfo().getIdentityType());
|
|
|
}
|
|
|
|
|
|
- // ==================== M3: batchClose INIT 守卫 ====================
|
|
|
+ // ==================== M3: batchClose INIT/WAIT_PAY 守卫 ====================
|
|
|
|
|
|
@Test
|
|
|
void batchClose_nonInitStatus_throwsBusinessException() throws AlipayApiException {
|
|
|
@@ -1097,10 +1097,77 @@ class AlipayBatchPayServiceTest {
|
|
|
BusinessException ex = assertThrows(BusinessException.class, () -> service.batchClose("E100", "B1"));
|
|
|
|
|
|
assertEquals(400, ex.getCode());
|
|
|
- assertTrue(ex.getMessage().contains("INIT"), ex.getMessage());
|
|
|
+ assertTrue(ex.getMessage().contains("可关闭"), ex.getMessage());
|
|
|
verify(alipayClient, never()).certificateExecute(any());
|
|
|
}
|
|
|
|
|
|
+ @Test
|
|
|
+ void batchClose_waitPayStatus_callsCloseApi() throws AlipayApiException {
|
|
|
+ // WAIT_PAY=等待支付(render 过链接未支付)应可关闭(用户实测: 本地被同步成 WAIT_PAY 后关闭按钮消失)
|
|
|
+ BatchOrderEntity order = new BatchOrderEntity();
|
|
|
+ order.setEnterpriseId("E100");
|
|
|
+ order.setOutBatchNo("B1");
|
|
|
+ order.setBatchTransId("BT1");
|
|
|
+ order.setStatus("WAIT_PAY");
|
|
|
+ when(batchOrderMapper.selectOne(any())).thenReturn(order);
|
|
|
+ when(alipayClient.certificateExecute(any(AlipayFundBatchCloseRequest.class)))
|
|
|
+ .thenReturn(new AlipayFundBatchCloseResponse());
|
|
|
+
|
|
|
+ Map<String, String> result = service.batchClose("E100", "B1");
|
|
|
+
|
|
|
+ assertEquals("DISUSE", result.get("status"));
|
|
|
+ verify(alipayClient).certificateExecute(any(AlipayFundBatchCloseRequest.class));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void batchClose_failureSyncsBackAlipayStatus() throws AlipayApiException {
|
|
|
+ // 关闭失败(支付宝侧批次已不可关闭,用户实测 BATCH_ORDER_STATUS_INVALID)→
|
|
|
+ // detail.query 回写真实状态到本地,避免残留 INIT 让用户反复点关闭
|
|
|
+ BatchOrderEntity order = new BatchOrderEntity();
|
|
|
+ order.setEnterpriseId("E100");
|
|
|
+ order.setOutBatchNo("B1");
|
|
|
+ order.setBatchTransId("BT1");
|
|
|
+ order.setStatus("INIT");
|
|
|
+ when(batchOrderMapper.selectOne(any())).thenReturn(order);
|
|
|
+ AlipayFundBatchCloseResponse closeResp = new AlipayFundBatchCloseResponse();
|
|
|
+ closeResp.setCode("40004");
|
|
|
+ closeResp.setSubCode("BATCH_ORDER_STATUS_INVALID");
|
|
|
+ closeResp.setSubMsg("批次状态不合法");
|
|
|
+ when(alipayClient.certificateExecute(any(AlipayFundBatchCloseRequest.class))).thenReturn(closeResp);
|
|
|
+ AlipayFundBatchDetailQueryResponse queryResp = new AlipayFundBatchDetailQueryResponse();
|
|
|
+ queryResp.setCode("10000");
|
|
|
+ queryResp.setBatchStatus("INVALID");
|
|
|
+ when(alipayClient.certificateExecute(any(AlipayFundBatchDetailQueryRequest.class))).thenReturn(queryResp);
|
|
|
+
|
|
|
+ BusinessException ex = assertThrows(BusinessException.class, () -> service.batchClose("E100", "B1"));
|
|
|
+
|
|
|
+ assertEquals(400, ex.getCode());
|
|
|
+ assertTrue(ex.getMessage().contains("BATCH_ORDER_STATUS_INVALID"), ex.getMessage());
|
|
|
+ // 回写: detail.query 返回 INVALID → 本地状态覆盖为 INVALID
|
|
|
+ verify(batchOrderMapper).updateById(order);
|
|
|
+ assertEquals("INVALID", order.getStatus());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void renderPay_waitPayStatus_regeneratesPayUrl() throws AlipayApiException {
|
|
|
+ // WAIT_PAY=等待支付(render 过链接未支付)应可重新生成支付链接(用户实测: 不能二次发起支付)
|
|
|
+ BatchOrderEntity order = new BatchOrderEntity();
|
|
|
+ order.setEnterpriseId("E100");
|
|
|
+ order.setOutBatchNo("B1");
|
|
|
+ order.setBatchTransId("BT1");
|
|
|
+ order.setStatus("WAIT_PAY");
|
|
|
+ when(batchOrderMapper.selectOne(any())).thenReturn(order);
|
|
|
+ AlipayFundTransRenderPayResponse resp = new AlipayFundTransRenderPayResponse();
|
|
|
+ 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("https://p.tb.cn/_2PG4jfHMVvg9vqBUdtx1HZ", result.get("pay_url"));
|
|
|
+ verify(batchOrderMapper).updateById(order);
|
|
|
+ }
|
|
|
+
|
|
|
// ==================== 二轮复核修复: 空 enterpriseId 拒绝(条件式 eq 的空值漏洞) ====================
|
|
|
|
|
|
@Test
|