|
@@ -27,8 +27,6 @@ import com.payment.platform.module.payment.batch.entity.BatchOrderEntity;
|
|
|
import com.payment.platform.module.payment.batch.mapper.BatchAuthorizeMapper;
|
|
import com.payment.platform.module.payment.batch.mapper.BatchAuthorizeMapper;
|
|
|
import com.payment.platform.module.payment.batch.mapper.BatchDetailMapper;
|
|
import com.payment.platform.module.payment.batch.mapper.BatchDetailMapper;
|
|
|
import com.payment.platform.module.payment.batch.mapper.BatchOrderMapper;
|
|
import com.payment.platform.module.payment.batch.mapper.BatchOrderMapper;
|
|
|
-import com.payment.platform.module.payment.enterprise.entity.EnterpriseEntity;
|
|
|
|
|
-import com.payment.platform.module.payment.enterprise.mapper.EnterpriseMapper;
|
|
|
|
|
import jakarta.validation.ConstraintViolation;
|
|
import jakarta.validation.ConstraintViolation;
|
|
|
import jakarta.validation.Validation;
|
|
import jakarta.validation.Validation;
|
|
|
import jakarta.validation.Validator;
|
|
import jakarta.validation.Validator;
|
|
@@ -59,19 +57,15 @@ class AlipayBatchPayServiceTest {
|
|
|
@Mock private BatchAuthorizeMapper batchAuthorizeMapper;
|
|
@Mock private BatchAuthorizeMapper batchAuthorizeMapper;
|
|
|
@Mock private BatchOrderMapper batchOrderMapper;
|
|
@Mock private BatchOrderMapper batchOrderMapper;
|
|
|
@Mock private BatchDetailMapper batchDetailMapper;
|
|
@Mock private BatchDetailMapper batchDetailMapper;
|
|
|
- @Mock private EnterpriseMapper enterpriseMapper;
|
|
|
|
|
private AlipayBatchPayService service;
|
|
private AlipayBatchPayService service;
|
|
|
|
|
|
|
|
@BeforeEach
|
|
@BeforeEach
|
|
|
void setUp() {
|
|
void setUp() {
|
|
|
service = new AlipayBatchPayService(alipayClientFactory, batchAuthorizeMapper, batchOrderMapper,
|
|
service = new AlipayBatchPayService(alipayClientFactory, batchAuthorizeMapper, batchOrderMapper,
|
|
|
- batchDetailMapper, enterpriseMapper);
|
|
|
|
|
- // lenient: 重复授权预检测试用例在到达 getClient 前即抛异常,该 stub 不会被使用
|
|
|
|
|
- lenient().when(alipayClientFactory.getClient("E100", "BATCH_PAY")).thenReturn(alipayClient);
|
|
|
|
|
- // 付款方身份解析: E100 企业无 identity → 回退 enterprise_id(createOnboard 惯例);identity 有值用例单独 stub
|
|
|
|
|
- EnterpriseEntity ent = new EnterpriseEntity();
|
|
|
|
|
- ent.setEnterpriseId("E100");
|
|
|
|
|
- lenient().when(enterpriseMapper.selectByEnterpriseIdIgnoreTenant("E100")).thenReturn(ent);
|
|
|
|
|
|
|
+ batchDetailMapper);
|
|
|
|
|
+ // lenient: 预检拦截/本地不存在的用例在到达 getClient 前即抛异常,该 stub 不会被使用
|
|
|
|
|
+ // 账号级: client 按订单冗余的 service_provider_id 解析(订单 mock 统一 setServiceProviderId(1L))
|
|
|
|
|
+ lenient().when(alipayClientFactory.getClientByProvider(1L, "BATCH_PAY")).thenReturn(alipayClient);
|
|
|
// 初始化 MyBatis-Plus lambda 元数据缓存,使 LambdaQueryWrapper.getSqlSegment() 可在无 Spring 上下文的单测中工作
|
|
// 初始化 MyBatis-Plus lambda 元数据缓存,使 LambdaQueryWrapper.getSqlSegment() 可在无 Spring 上下文的单测中工作
|
|
|
MybatisConfiguration configuration = new MybatisConfiguration();
|
|
MybatisConfiguration configuration = new MybatisConfiguration();
|
|
|
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(configuration, ""), BatchOrderEntity.class);
|
|
TableInfoHelper.initTableInfo(new MapperBuilderAssistant(configuration, ""), BatchOrderEntity.class);
|
|
@@ -89,11 +83,12 @@ class AlipayBatchPayServiceTest {
|
|
|
// 制单预检: 已有 AUTHED 授权(协议号由系统自动带出,不接受客户端指定)
|
|
// 制单预检: 已有 AUTHED 授权(协议号由系统自动带出,不接受客户端指定)
|
|
|
BatchAuthorizeEntity authed = new BatchAuthorizeEntity();
|
|
BatchAuthorizeEntity authed = new BatchAuthorizeEntity();
|
|
|
authed.setStatus("AUTHED");
|
|
authed.setStatus("AUTHED");
|
|
|
|
|
+ authed.setServiceProviderId(1L);
|
|
|
authed.setAgreementNo("AGMT001");
|
|
authed.setAgreementNo("AGMT001");
|
|
|
when(batchAuthorizeMapper.selectOne(any())).thenReturn(authed);
|
|
when(batchAuthorizeMapper.selectOne(any())).thenReturn(authed);
|
|
|
|
|
|
|
|
BatchCreateDTO dto = new BatchCreateDTO();
|
|
BatchCreateDTO dto = new BatchCreateDTO();
|
|
|
- dto.setEnterpriseId("E100");
|
|
|
|
|
|
|
+ dto.setParticipantId("2088111122223333");
|
|
|
dto.setOutBatchNo("B1");
|
|
dto.setOutBatchNo("B1");
|
|
|
dto.setOrderTitle("202608报销");
|
|
dto.setOrderTitle("202608报销");
|
|
|
dto.setTransferSceneName("佣金报酬");
|
|
dto.setTransferSceneName("佣金报酬");
|
|
@@ -174,11 +169,12 @@ class AlipayBatchPayServiceTest {
|
|
|
when(batchOrderMapper.selectOne(any())).thenReturn(existing);
|
|
when(batchOrderMapper.selectOne(any())).thenReturn(existing);
|
|
|
BatchAuthorizeEntity authed = new BatchAuthorizeEntity();
|
|
BatchAuthorizeEntity authed = new BatchAuthorizeEntity();
|
|
|
authed.setStatus("AUTHED");
|
|
authed.setStatus("AUTHED");
|
|
|
|
|
+ authed.setServiceProviderId(1L);
|
|
|
authed.setAgreementNo("AGMT001");
|
|
authed.setAgreementNo("AGMT001");
|
|
|
when(batchAuthorizeMapper.selectOne(any())).thenReturn(authed);
|
|
when(batchAuthorizeMapper.selectOne(any())).thenReturn(authed);
|
|
|
|
|
|
|
|
BatchCreateDTO dto = new BatchCreateDTO();
|
|
BatchCreateDTO dto = new BatchCreateDTO();
|
|
|
- dto.setEnterpriseId("E100");
|
|
|
|
|
|
|
+ dto.setParticipantId("2088111122223333");
|
|
|
dto.setOutBatchNo("B1");
|
|
dto.setOutBatchNo("B1");
|
|
|
dto.setOrderTitle("t");
|
|
dto.setOrderTitle("t");
|
|
|
BatchCreateDTO.BatchDetailDTO detail = new BatchCreateDTO.BatchDetailDTO();
|
|
BatchCreateDTO.BatchDetailDTO detail = new BatchCreateDTO.BatchDetailDTO();
|
|
@@ -201,7 +197,7 @@ class AlipayBatchPayServiceTest {
|
|
|
void batchCreate_duplicateDetailOutBizNo_throwsBusinessException() throws AlipayApiException {
|
|
void batchCreate_duplicateDetailOutBizNo_throwsBusinessException() throws AlipayApiException {
|
|
|
// Ruling 5-2: 每笔 out_biz_no 批内唯一
|
|
// Ruling 5-2: 每笔 out_biz_no 批内唯一
|
|
|
BatchCreateDTO dto = new BatchCreateDTO();
|
|
BatchCreateDTO dto = new BatchCreateDTO();
|
|
|
- dto.setEnterpriseId("E100");
|
|
|
|
|
|
|
+ dto.setParticipantId("2088111122223333");
|
|
|
dto.setOutBatchNo("B1");
|
|
dto.setOutBatchNo("B1");
|
|
|
dto.setOrderTitle("t");
|
|
dto.setOrderTitle("t");
|
|
|
BatchCreateDTO.BatchDetailDTO d1 = new BatchCreateDTO.BatchDetailDTO();
|
|
BatchCreateDTO.BatchDetailDTO d1 = new BatchCreateDTO.BatchDetailDTO();
|
|
@@ -228,7 +224,7 @@ class AlipayBatchPayServiceTest {
|
|
|
@Test
|
|
@Test
|
|
|
void renderPay_returnsPayUrl() throws AlipayApiException {
|
|
void renderPay_returnsPayUrl() throws AlipayApiException {
|
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
|
- order.setEnterpriseId("E100");
|
|
|
|
|
|
|
+ order.setServiceProviderId(1L);
|
|
|
order.setOutBatchNo("B1");
|
|
order.setOutBatchNo("B1");
|
|
|
order.setBatchTransId("BT1");
|
|
order.setBatchTransId("BT1");
|
|
|
order.setStatus("INIT");
|
|
order.setStatus("INIT");
|
|
@@ -238,7 +234,7 @@ class AlipayBatchPayServiceTest {
|
|
|
resp.setInitializeCode("https://p.tb.cn/_2PG4jfHMVvg9vqBUdtx1HZ");
|
|
resp.setInitializeCode("https://p.tb.cn/_2PG4jfHMVvg9vqBUdtx1HZ");
|
|
|
when(alipayClient.certificateExecute(any(AlipayFundTransRenderPayRequest.class))).thenReturn(resp);
|
|
when(alipayClient.certificateExecute(any(AlipayFundTransRenderPayRequest.class))).thenReturn(resp);
|
|
|
|
|
|
|
|
- Map<String, String> result = service.renderPay("E100", "B1");
|
|
|
|
|
|
|
+ Map<String, String> result = service.renderPay("B1");
|
|
|
|
|
|
|
|
// render.pay 返回收银台短链接 initialize_code(用户实测成功响应实证),直接作为 pay_url
|
|
// render.pay 返回收银台短链接 initialize_code(用户实测成功响应实证),直接作为 pay_url
|
|
|
assertEquals("https://p.tb.cn/_2PG4jfHMVvg9vqBUdtx1HZ", result.get("pay_url"));
|
|
assertEquals("https://p.tb.cn/_2PG4jfHMVvg9vqBUdtx1HZ", result.get("pay_url"));
|
|
@@ -260,7 +256,7 @@ class AlipayBatchPayServiceTest {
|
|
|
// 支付宝业务失败(非 10000)必须抛错且不落库——
|
|
// 支付宝业务失败(非 10000)必须抛错且不落库——
|
|
|
// 否则错误响应会被当 pay_url 返回、前端拿错误内容开新窗口(用户实测: 窗口显示整页 INVALID_PARAMETER JSON)
|
|
// 否则错误响应会被当 pay_url 返回、前端拿错误内容开新窗口(用户实测: 窗口显示整页 INVALID_PARAMETER JSON)
|
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
|
- order.setEnterpriseId("E100");
|
|
|
|
|
|
|
+ order.setServiceProviderId(1L);
|
|
|
order.setOutBatchNo("B1");
|
|
order.setOutBatchNo("B1");
|
|
|
order.setBatchTransId("BT1");
|
|
order.setBatchTransId("BT1");
|
|
|
order.setStatus("INIT");
|
|
order.setStatus("INIT");
|
|
@@ -271,7 +267,7 @@ class AlipayBatchPayServiceTest {
|
|
|
resp.setSubMsg("参数[target_terminal_type]错误, 原因: 必须传入参数[target_terminal_type]");
|
|
resp.setSubMsg("参数[target_terminal_type]错误, 原因: 必须传入参数[target_terminal_type]");
|
|
|
when(alipayClient.certificateExecute(any(AlipayFundTransRenderPayRequest.class))).thenReturn(resp);
|
|
when(alipayClient.certificateExecute(any(AlipayFundTransRenderPayRequest.class))).thenReturn(resp);
|
|
|
|
|
|
|
|
- BusinessException ex = assertThrows(BusinessException.class, () -> service.renderPay("E100", "B1"));
|
|
|
|
|
|
|
+ BusinessException ex = assertThrows(BusinessException.class, () -> service.renderPay("B1"));
|
|
|
|
|
|
|
|
assertEquals(400, ex.getCode());
|
|
assertEquals(400, ex.getCode());
|
|
|
assertTrue(ex.getMessage().contains("INVALID_PARAMETER"), ex.getMessage());
|
|
assertTrue(ex.getMessage().contains("INVALID_PARAMETER"), ex.getMessage());
|
|
@@ -282,7 +278,7 @@ class AlipayBatchPayServiceTest {
|
|
|
void renderPay_successWithoutInitializeCode_throws() throws AlipayApiException {
|
|
void renderPay_successWithoutInitializeCode_throws() throws AlipayApiException {
|
|
|
// 成功响应但支付宝未返回跳转链接(防御: 不把 null 当 pay_url 返回)
|
|
// 成功响应但支付宝未返回跳转链接(防御: 不把 null 当 pay_url 返回)
|
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
|
- order.setEnterpriseId("E100");
|
|
|
|
|
|
|
+ order.setServiceProviderId(1L);
|
|
|
order.setOutBatchNo("B1");
|
|
order.setOutBatchNo("B1");
|
|
|
order.setBatchTransId("BT1");
|
|
order.setBatchTransId("BT1");
|
|
|
order.setStatus("INIT");
|
|
order.setStatus("INIT");
|
|
@@ -291,7 +287,7 @@ class AlipayBatchPayServiceTest {
|
|
|
resp.setCode("10000");
|
|
resp.setCode("10000");
|
|
|
when(alipayClient.certificateExecute(any(AlipayFundTransRenderPayRequest.class))).thenReturn(resp);
|
|
when(alipayClient.certificateExecute(any(AlipayFundTransRenderPayRequest.class))).thenReturn(resp);
|
|
|
|
|
|
|
|
- BusinessException ex = assertThrows(BusinessException.class, () -> service.renderPay("E100", "B1"));
|
|
|
|
|
|
|
+ BusinessException ex = assertThrows(BusinessException.class, () -> service.renderPay("B1"));
|
|
|
|
|
|
|
|
assertEquals(400, ex.getCode());
|
|
assertEquals(400, ex.getCode());
|
|
|
assertTrue(ex.getMessage().contains("跳转链接"), ex.getMessage());
|
|
assertTrue(ex.getMessage().contains("跳转链接"), ex.getMessage());
|
|
@@ -302,7 +298,7 @@ class AlipayBatchPayServiceTest {
|
|
|
void batchQuery_syncsBatchStatus() throws AlipayApiException {
|
|
void batchQuery_syncsBatchStatus() throws AlipayApiException {
|
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
|
order.setId(1L);
|
|
order.setId(1L);
|
|
|
- order.setEnterpriseId("E100");
|
|
|
|
|
|
|
+ order.setServiceProviderId(1L);
|
|
|
order.setOutBatchNo("B1");
|
|
order.setOutBatchNo("B1");
|
|
|
order.setBatchTransId("BT1");
|
|
order.setBatchTransId("BT1");
|
|
|
order.setStatus("INIT");
|
|
order.setStatus("INIT");
|
|
@@ -312,7 +308,7 @@ class AlipayBatchPayServiceTest {
|
|
|
resp.setBatchStatus("SUCCESS");
|
|
resp.setBatchStatus("SUCCESS");
|
|
|
when(alipayClient.certificateExecute(any(AlipayFundBatchDetailQueryRequest.class))).thenReturn(resp);
|
|
when(alipayClient.certificateExecute(any(AlipayFundBatchDetailQueryRequest.class))).thenReturn(resp);
|
|
|
|
|
|
|
|
- Map<String, Object> result = service.batchQuery("E100", "B1");
|
|
|
|
|
|
|
+ Map<String, Object> result = service.batchQuery("B1");
|
|
|
|
|
|
|
|
assertEquals("SUCCESS", result.get("status"));
|
|
assertEquals("SUCCESS", result.get("status"));
|
|
|
assertEquals("SUCCESS", order.getStatus());
|
|
assertEquals("SUCCESS", order.getStatus());
|
|
@@ -322,7 +318,7 @@ class AlipayBatchPayServiceTest {
|
|
|
@Test
|
|
@Test
|
|
|
void batchClose_callsCloseApi() throws AlipayApiException {
|
|
void batchClose_callsCloseApi() throws AlipayApiException {
|
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
|
- order.setEnterpriseId("E100");
|
|
|
|
|
|
|
+ order.setServiceProviderId(1L);
|
|
|
order.setOutBatchNo("B1");
|
|
order.setOutBatchNo("B1");
|
|
|
order.setBatchTransId("BT1");
|
|
order.setBatchTransId("BT1");
|
|
|
order.setStatus("INIT");
|
|
order.setStatus("INIT");
|
|
@@ -330,7 +326,7 @@ class AlipayBatchPayServiceTest {
|
|
|
when(alipayClient.certificateExecute(any(AlipayFundBatchCloseRequest.class)))
|
|
when(alipayClient.certificateExecute(any(AlipayFundBatchCloseRequest.class)))
|
|
|
.thenReturn(new AlipayFundBatchCloseResponse());
|
|
.thenReturn(new AlipayFundBatchCloseResponse());
|
|
|
|
|
|
|
|
- service.batchClose("E100", "B1");
|
|
|
|
|
|
|
+ service.batchClose("B1");
|
|
|
verify(alipayClient).certificateExecute(any(AlipayFundBatchCloseRequest.class));
|
|
verify(alipayClient).certificateExecute(any(AlipayFundBatchCloseRequest.class));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -338,11 +334,11 @@ class AlipayBatchPayServiceTest {
|
|
|
void batchList_invalidTime_throwsBusinessException() {
|
|
void batchList_invalidTime_throwsBusinessException() {
|
|
|
// Ruling 5-3: 非法时间输入应抛 400 而非 DateTimeParseException→500
|
|
// Ruling 5-3: 非法时间输入应抛 400 而非 DateTimeParseException→500
|
|
|
BusinessException ex = assertThrows(BusinessException.class,
|
|
BusinessException ex = assertThrows(BusinessException.class,
|
|
|
- () -> service.batchList("E100", null, "2026-13-45 99:99", null, 1, 20));
|
|
|
|
|
|
|
+ () -> service.batchList(null, null, "2026-13-45 99:99", null, 1, 20));
|
|
|
assertEquals(400, ex.getCode());
|
|
assertEquals(400, ex.getCode());
|
|
|
|
|
|
|
|
BusinessException ex2 = assertThrows(BusinessException.class,
|
|
BusinessException ex2 = assertThrows(BusinessException.class,
|
|
|
- () -> service.batchList("E100", null, null, "2026-08-25 25:61", 1, 20));
|
|
|
|
|
|
|
+ () -> service.batchList(null, null, null, "2026-08-25 25:61", 1, 20));
|
|
|
assertEquals(400, ex2.getCode());
|
|
assertEquals(400, ex2.getCode());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -350,7 +346,7 @@ class AlipayBatchPayServiceTest {
|
|
|
void batchExport_invalidTime_throwsBusinessException() {
|
|
void batchExport_invalidTime_throwsBusinessException() {
|
|
|
// Ruling 5-3: 导出 catch-all 需区分 DateTimeParseException 抛 400
|
|
// Ruling 5-3: 导出 catch-all 需区分 DateTimeParseException 抛 400
|
|
|
BusinessException ex = assertThrows(BusinessException.class,
|
|
BusinessException ex = assertThrows(BusinessException.class,
|
|
|
- () -> service.batchExport("E100", null, "bad-time", null));
|
|
|
|
|
|
|
+ () -> service.batchExport(null, null, "bad-time", null));
|
|
|
assertEquals(400, ex.getCode());
|
|
assertEquals(400, ex.getCode());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -365,11 +361,12 @@ class AlipayBatchPayServiceTest {
|
|
|
// 本地预检通过(有 AUTHED 记录)后仍触发支付宝侧 AUTH_INFO_NOT_EXISTS 兜底路径
|
|
// 本地预检通过(有 AUTHED 记录)后仍触发支付宝侧 AUTH_INFO_NOT_EXISTS 兜底路径
|
|
|
BatchAuthorizeEntity authed = new BatchAuthorizeEntity();
|
|
BatchAuthorizeEntity authed = new BatchAuthorizeEntity();
|
|
|
authed.setStatus("AUTHED");
|
|
authed.setStatus("AUTHED");
|
|
|
|
|
+ authed.setServiceProviderId(1L);
|
|
|
authed.setAgreementNo("AGMT001");
|
|
authed.setAgreementNo("AGMT001");
|
|
|
when(batchAuthorizeMapper.selectOne(any())).thenReturn(authed);
|
|
when(batchAuthorizeMapper.selectOne(any())).thenReturn(authed);
|
|
|
|
|
|
|
|
BatchCreateDTO dto = new BatchCreateDTO();
|
|
BatchCreateDTO dto = new BatchCreateDTO();
|
|
|
- dto.setEnterpriseId("E100");
|
|
|
|
|
|
|
+ dto.setParticipantId("2088111122223333");
|
|
|
dto.setOutBatchNo("B1");
|
|
dto.setOutBatchNo("B1");
|
|
|
dto.setOrderTitle("202608报销");
|
|
dto.setOrderTitle("202608报销");
|
|
|
BatchCreateDTO.BatchDetailDTO detail = new BatchCreateDTO.BatchDetailDTO();
|
|
BatchCreateDTO.BatchDetailDTO detail = new BatchCreateDTO.BatchDetailDTO();
|
|
@@ -385,50 +382,50 @@ class AlipayBatchPayServiceTest {
|
|
|
assertTrue(ex.getMessage().contains("制单授权"), "应提示先完成制单授权: " + ex.getMessage());
|
|
assertTrue(ex.getMessage().contains("制单授权"), "应提示先完成制单授权: " + ex.getMessage());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // ==================== C2: 租户隔离(renderPay/batchQuery/batchClose 缺 enterpriseId 条件) ====================
|
|
|
|
|
|
|
+ // ==================== C2: 批次不存在(本地查不到 → 404,租户隔离由 TenantInnerInterceptor 自动追加) ====================
|
|
|
|
|
|
|
|
@Test
|
|
@Test
|
|
|
- void renderPay_otherEnterpriseBatch_notFound() {
|
|
|
|
|
- // 他人批次: selectOne 带 enterpriseId 条件查不到 → 404
|
|
|
|
|
|
|
+ void renderPay_batchNotFound_throws404() {
|
|
|
|
|
+ // 本地批次不存在(他租户批次或被拦截器过滤)→ 404
|
|
|
when(batchOrderMapper.selectOne(any())).thenReturn(null);
|
|
when(batchOrderMapper.selectOne(any())).thenReturn(null);
|
|
|
|
|
|
|
|
- BusinessException ex = assertThrows(BusinessException.class, () -> service.renderPay("E999", "B1"));
|
|
|
|
|
|
|
+ BusinessException ex = assertThrows(BusinessException.class, () -> service.renderPay("B1"));
|
|
|
|
|
|
|
|
assertEquals(404, ex.getCode());
|
|
assertEquals(404, ex.getCode());
|
|
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
|
|
ArgumentCaptor<LambdaQueryWrapper<BatchOrderEntity>> cap = ArgumentCaptor.forClass(LambdaQueryWrapper.class);
|
|
ArgumentCaptor<LambdaQueryWrapper<BatchOrderEntity>> cap = ArgumentCaptor.forClass(LambdaQueryWrapper.class);
|
|
|
verify(batchOrderMapper).selectOne(cap.capture());
|
|
verify(batchOrderMapper).selectOne(cap.capture());
|
|
|
- assertTrue(cap.getValue().getSqlSegment().contains("enterprise_id"),
|
|
|
|
|
- "renderPay 查询必须带 enterpriseId 条件: " + cap.getValue().getSqlSegment());
|
|
|
|
|
|
|
+ assertTrue(cap.getValue().getSqlSegment().contains("out_batch_no"),
|
|
|
|
|
+ "renderPay 查询必须按 out_batch_no: " + cap.getValue().getSqlSegment());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
@Test
|
|
|
- void batchQuery_otherEnterpriseBatch_notFound() {
|
|
|
|
|
|
|
+ void batchQuery_batchNotFound_throws404() {
|
|
|
when(batchOrderMapper.selectOne(any())).thenReturn(null);
|
|
when(batchOrderMapper.selectOne(any())).thenReturn(null);
|
|
|
|
|
|
|
|
- BusinessException ex = assertThrows(BusinessException.class, () -> service.batchQuery("E999", "B1"));
|
|
|
|
|
|
|
+ BusinessException ex = assertThrows(BusinessException.class, () -> service.batchQuery("B1"));
|
|
|
|
|
|
|
|
assertEquals(404, ex.getCode());
|
|
assertEquals(404, ex.getCode());
|
|
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
|
|
ArgumentCaptor<LambdaQueryWrapper<BatchOrderEntity>> cap = ArgumentCaptor.forClass(LambdaQueryWrapper.class);
|
|
ArgumentCaptor<LambdaQueryWrapper<BatchOrderEntity>> cap = ArgumentCaptor.forClass(LambdaQueryWrapper.class);
|
|
|
verify(batchOrderMapper).selectOne(cap.capture());
|
|
verify(batchOrderMapper).selectOne(cap.capture());
|
|
|
- assertTrue(cap.getValue().getSqlSegment().contains("enterprise_id"),
|
|
|
|
|
- "batchQuery 查询必须带 enterpriseId 条件: " + cap.getValue().getSqlSegment());
|
|
|
|
|
|
|
+ assertTrue(cap.getValue().getSqlSegment().contains("out_batch_no"),
|
|
|
|
|
+ "batchQuery 查询必须按 out_batch_no: " + cap.getValue().getSqlSegment());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
@Test
|
|
|
- void batchClose_otherEnterpriseBatch_notFound() throws AlipayApiException {
|
|
|
|
|
|
|
+ void batchClose_batchNotFound_throws404() throws AlipayApiException {
|
|
|
when(batchOrderMapper.selectOne(any())).thenReturn(null);
|
|
when(batchOrderMapper.selectOne(any())).thenReturn(null);
|
|
|
|
|
|
|
|
- BusinessException ex = assertThrows(BusinessException.class, () -> service.batchClose("E999", "B1"));
|
|
|
|
|
|
|
+ BusinessException ex = assertThrows(BusinessException.class, () -> service.batchClose("B1"));
|
|
|
|
|
|
|
|
assertEquals(404, ex.getCode());
|
|
assertEquals(404, ex.getCode());
|
|
|
verify(alipayClient, never()).certificateExecute(any());
|
|
verify(alipayClient, never()).certificateExecute(any());
|
|
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
|
|
ArgumentCaptor<LambdaQueryWrapper<BatchOrderEntity>> cap = ArgumentCaptor.forClass(LambdaQueryWrapper.class);
|
|
ArgumentCaptor<LambdaQueryWrapper<BatchOrderEntity>> cap = ArgumentCaptor.forClass(LambdaQueryWrapper.class);
|
|
|
verify(batchOrderMapper).selectOne(cap.capture());
|
|
verify(batchOrderMapper).selectOne(cap.capture());
|
|
|
- assertTrue(cap.getValue().getSqlSegment().contains("enterprise_id"),
|
|
|
|
|
- "batchClose 查询必须带 enterpriseId 条件: " + cap.getValue().getSqlSegment());
|
|
|
|
|
|
|
+ assertTrue(cap.getValue().getSqlSegment().contains("out_batch_no"),
|
|
|
|
|
+ "batchClose 查询必须按 out_batch_no: " + cap.getValue().getSqlSegment());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ==================== I1: 定时同步兜底(getPendingBatches) ====================
|
|
// ==================== I1: 定时同步兜底(getPendingBatches) ====================
|
|
@@ -461,7 +458,7 @@ class AlipayBatchPayServiceTest {
|
|
|
// 两个批次含相同 out_biz_no(out_biz_no 仅批内唯一)→ 不得抛 TooManyResultsException,且只回写本批次明细
|
|
// 两个批次含相同 out_biz_no(out_biz_no 仅批内唯一)→ 不得抛 TooManyResultsException,且只回写本批次明细
|
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
|
order.setId(1L);
|
|
order.setId(1L);
|
|
|
- order.setEnterpriseId("E100");
|
|
|
|
|
|
|
+ order.setServiceProviderId(1L);
|
|
|
order.setOutBatchNo("B1");
|
|
order.setOutBatchNo("B1");
|
|
|
order.setBatchTransId("BT1");
|
|
order.setBatchTransId("BT1");
|
|
|
order.setStatus("INIT");
|
|
order.setStatus("INIT");
|
|
@@ -485,7 +482,7 @@ class AlipayBatchPayServiceTest {
|
|
|
own.setStatus("INIT");
|
|
own.setStatus("INIT");
|
|
|
when(batchDetailMapper.selectList(any())).thenReturn(List.of(own));
|
|
when(batchDetailMapper.selectList(any())).thenReturn(List.of(own));
|
|
|
|
|
|
|
|
- Map<String, Object> result = service.batchQuery("E100", "B1");
|
|
|
|
|
|
|
+ Map<String, Object> result = service.batchQuery("B1");
|
|
|
|
|
|
|
|
assertEquals("SUCCESS", result.get("status"));
|
|
assertEquals("SUCCESS", result.get("status"));
|
|
|
assertEquals("SUCCESS", own.getStatus());
|
|
assertEquals("SUCCESS", own.getStatus());
|
|
@@ -549,7 +546,7 @@ class AlipayBatchPayServiceTest {
|
|
|
void batchList_pureDateRange_parsesToDayBoundaries() {
|
|
void batchList_pureDateRange_parsesToDayBoundaries() {
|
|
|
when(batchOrderMapper.selectPage(any(), any())).thenReturn(new Page<>());
|
|
when(batchOrderMapper.selectPage(any(), any())).thenReturn(new Page<>());
|
|
|
|
|
|
|
|
- PageResult<BatchOrderEntity> result = service.batchList("E100", null, "2026-08-01", "2026-08-02", 1, 20);
|
|
|
|
|
|
|
+ PageResult<BatchOrderEntity> result = service.batchList(null, null, "2026-08-01", "2026-08-02", 1, 20);
|
|
|
|
|
|
|
|
assertNotNull(result);
|
|
assertNotNull(result);
|
|
|
verify(batchOrderMapper).selectPage(any(), any());
|
|
verify(batchOrderMapper).selectPage(any(), any());
|
|
@@ -559,7 +556,7 @@ class AlipayBatchPayServiceTest {
|
|
|
void batchExport_pureDateRange_parses() {
|
|
void batchExport_pureDateRange_parses() {
|
|
|
when(batchOrderMapper.selectList(any())).thenReturn(List.of());
|
|
when(batchOrderMapper.selectList(any())).thenReturn(List.of());
|
|
|
|
|
|
|
|
- byte[] bytes = service.batchExport("E100", null, "2026-08-01", "2026-08-02");
|
|
|
|
|
|
|
+ byte[] bytes = service.batchExport(null, null, "2026-08-01", "2026-08-02");
|
|
|
|
|
|
|
|
assertNotNull(bytes);
|
|
assertNotNull(bytes);
|
|
|
assertTrue(bytes.length > 0);
|
|
assertTrue(bytes.length > 0);
|
|
@@ -570,7 +567,7 @@ class AlipayBatchPayServiceTest {
|
|
|
@Test
|
|
@Test
|
|
|
void renderPay_initializeCode_persistsAndReturns() throws AlipayApiException {
|
|
void renderPay_initializeCode_persistsAndReturns() throws AlipayApiException {
|
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
|
- order.setEnterpriseId("E100");
|
|
|
|
|
|
|
+ order.setServiceProviderId(1L);
|
|
|
order.setOutBatchNo("B1");
|
|
order.setOutBatchNo("B1");
|
|
|
order.setBatchTransId("BT1");
|
|
order.setBatchTransId("BT1");
|
|
|
order.setStatus("INIT");
|
|
order.setStatus("INIT");
|
|
@@ -582,25 +579,28 @@ class AlipayBatchPayServiceTest {
|
|
|
resp.setInitializeCode("https://p.tb.cn/_2PG4jfHMVvg9vqBUdtx1HZ");
|
|
resp.setInitializeCode("https://p.tb.cn/_2PG4jfHMVvg9vqBUdtx1HZ");
|
|
|
when(alipayClient.certificateExecute(any(AlipayFundTransRenderPayRequest.class))).thenReturn(resp);
|
|
when(alipayClient.certificateExecute(any(AlipayFundTransRenderPayRequest.class))).thenReturn(resp);
|
|
|
|
|
|
|
|
- Map<String, String> result = service.renderPay("E100", "B1");
|
|
|
|
|
|
|
+ Map<String, String> result = service.renderPay("B1");
|
|
|
|
|
|
|
|
assertEquals("https://p.tb.cn/_2PG4jfHMVvg9vqBUdtx1HZ", result.get("pay_url"));
|
|
assertEquals("https://p.tb.cn/_2PG4jfHMVvg9vqBUdtx1HZ", result.get("pay_url"));
|
|
|
verify(batchOrderMapper).updateById(order);
|
|
verify(batchOrderMapper).updateById(order);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
@Test
|
|
|
- void batchCreate_alwaysUsesEnterpriseAsPayer() throws AlipayApiException {
|
|
|
|
|
- // Ruling 19/22: 付款方恒为企业自身 UID(enterprise_id),DTO 已移除 payer_uid 不接受客户端指定
|
|
|
|
|
|
|
+ void batchCreate_alwaysUsesAuthorizedSubjectAsPayer() throws AlipayApiException {
|
|
|
|
|
+ // 账号级: 付款方恒为 DTO 选定的授权主体(participant_id),协议号由授权记录自动带出,不接受客户端指定
|
|
|
AlipayFundBatchCreateResponse resp = new AlipayFundBatchCreateResponse();
|
|
AlipayFundBatchCreateResponse resp = new AlipayFundBatchCreateResponse();
|
|
|
resp.setOutBatchNo("B1");
|
|
resp.setOutBatchNo("B1");
|
|
|
when(alipayClient.certificateExecute(any(AlipayFundBatchCreateRequest.class))).thenReturn(resp);
|
|
when(alipayClient.certificateExecute(any(AlipayFundBatchCreateRequest.class))).thenReturn(resp);
|
|
|
BatchAuthorizeEntity authed = new BatchAuthorizeEntity();
|
|
BatchAuthorizeEntity authed = new BatchAuthorizeEntity();
|
|
|
|
|
+ authed.setParticipantId("2088111122223333");
|
|
|
|
|
+ authed.setServiceProviderId(1L);
|
|
|
authed.setStatus("AUTHED");
|
|
authed.setStatus("AUTHED");
|
|
|
|
|
+ authed.setServiceProviderId(1L);
|
|
|
authed.setAgreementNo("AGMT001");
|
|
authed.setAgreementNo("AGMT001");
|
|
|
when(batchAuthorizeMapper.selectOne(any())).thenReturn(authed);
|
|
when(batchAuthorizeMapper.selectOne(any())).thenReturn(authed);
|
|
|
|
|
|
|
|
BatchCreateDTO dto = new BatchCreateDTO();
|
|
BatchCreateDTO dto = new BatchCreateDTO();
|
|
|
- dto.setEnterpriseId("E100");
|
|
|
|
|
|
|
+ dto.setParticipantId("2088111122223333");
|
|
|
dto.setOutBatchNo("B1");
|
|
dto.setOutBatchNo("B1");
|
|
|
dto.setOrderTitle("t");
|
|
dto.setOrderTitle("t");
|
|
|
BatchCreateDTO.BatchDetailDTO detail = new BatchCreateDTO.BatchDetailDTO();
|
|
BatchCreateDTO.BatchDetailDTO detail = new BatchCreateDTO.BatchDetailDTO();
|
|
@@ -617,11 +617,13 @@ class AlipayBatchPayServiceTest {
|
|
|
ArgumentCaptor<AlipayFundBatchCreateRequest> cap = ArgumentCaptor.forClass(AlipayFundBatchCreateRequest.class);
|
|
ArgumentCaptor<AlipayFundBatchCreateRequest> cap = ArgumentCaptor.forClass(AlipayFundBatchCreateRequest.class);
|
|
|
verify(alipayClient).certificateExecute(cap.capture());
|
|
verify(alipayClient).certificateExecute(cap.capture());
|
|
|
AlipayFundBatchCreateModel m = (AlipayFundBatchCreateModel) cap.getValue().getBizModel();
|
|
AlipayFundBatchCreateModel m = (AlipayFundBatchCreateModel) cap.getValue().getBizModel();
|
|
|
- assertEquals("E100", m.getPayerInfo().getIdentity());
|
|
|
|
|
- // DB 回写 payer_uid 恒为企业自身 UID
|
|
|
|
|
|
|
+ assertEquals("2088111122223333", m.getPayerInfo().getIdentity());
|
|
|
|
|
+ assertEquals("ALIPAY_USER_ID", m.getPayerInfo().getIdentityType());
|
|
|
|
|
+ // DB 回写 payer_uid 恒为授权主体 UID + 冗余服务商(client 解析依据)
|
|
|
ArgumentCaptor<BatchOrderEntity> order = ArgumentCaptor.forClass(BatchOrderEntity.class);
|
|
ArgumentCaptor<BatchOrderEntity> order = ArgumentCaptor.forClass(BatchOrderEntity.class);
|
|
|
verify(batchOrderMapper).insert(order.capture());
|
|
verify(batchOrderMapper).insert(order.capture());
|
|
|
- assertEquals("E100", order.getValue().getPayerUid());
|
|
|
|
|
|
|
+ assertEquals("2088111122223333", order.getValue().getPayerUid());
|
|
|
|
|
+ assertEquals(1L, order.getValue().getServiceProviderId());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
@Test
|
|
@@ -630,7 +632,7 @@ class AlipayBatchPayServiceTest {
|
|
|
when(batchAuthorizeMapper.selectOne(any())).thenReturn(null);
|
|
when(batchAuthorizeMapper.selectOne(any())).thenReturn(null);
|
|
|
|
|
|
|
|
BatchCreateDTO dto = new BatchCreateDTO();
|
|
BatchCreateDTO dto = new BatchCreateDTO();
|
|
|
- dto.setEnterpriseId("E100");
|
|
|
|
|
|
|
+ dto.setParticipantId("2088111122223333");
|
|
|
dto.setOutBatchNo("B1");
|
|
dto.setOutBatchNo("B1");
|
|
|
dto.setOrderTitle("t");
|
|
dto.setOrderTitle("t");
|
|
|
BatchCreateDTO.BatchDetailDTO detail = new BatchCreateDTO.BatchDetailDTO();
|
|
BatchCreateDTO.BatchDetailDTO detail = new BatchCreateDTO.BatchDetailDTO();
|
|
@@ -658,11 +660,12 @@ class AlipayBatchPayServiceTest {
|
|
|
when(alipayClient.certificateExecute(any(AlipayFundBatchCreateRequest.class))).thenReturn(resp);
|
|
when(alipayClient.certificateExecute(any(AlipayFundBatchCreateRequest.class))).thenReturn(resp);
|
|
|
BatchAuthorizeEntity authed = new BatchAuthorizeEntity();
|
|
BatchAuthorizeEntity authed = new BatchAuthorizeEntity();
|
|
|
authed.setStatus("NORMAL");
|
|
authed.setStatus("NORMAL");
|
|
|
|
|
+ authed.setServiceProviderId(1L);
|
|
|
authed.setAgreementNo("AGMT001");
|
|
authed.setAgreementNo("AGMT001");
|
|
|
when(batchAuthorizeMapper.selectOne(any())).thenReturn(authed);
|
|
when(batchAuthorizeMapper.selectOne(any())).thenReturn(authed);
|
|
|
|
|
|
|
|
BatchCreateDTO dto = new BatchCreateDTO();
|
|
BatchCreateDTO dto = new BatchCreateDTO();
|
|
|
- dto.setEnterpriseId("E100");
|
|
|
|
|
|
|
+ dto.setParticipantId("2088111122223333");
|
|
|
dto.setOutBatchNo("B1");
|
|
dto.setOutBatchNo("B1");
|
|
|
dto.setOrderTitle("t");
|
|
dto.setOrderTitle("t");
|
|
|
BatchCreateDTO.BatchDetailDTO detail = new BatchCreateDTO.BatchDetailDTO();
|
|
BatchCreateDTO.BatchDetailDTO detail = new BatchCreateDTO.BatchDetailDTO();
|
|
@@ -679,55 +682,17 @@ class AlipayBatchPayServiceTest {
|
|
|
verify(alipayClient).certificateExecute(any(AlipayFundBatchCreateRequest.class));
|
|
verify(alipayClient).certificateExecute(any(AlipayFundBatchCreateRequest.class));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- @Test
|
|
|
|
|
- void batchCreate_authorizedIdentity_proceedsWithIdentityAsPayer() throws AlipayApiException {
|
|
|
|
|
- // 反馈轮 4/5 协同: identity 有值时预检与付款方均用 identity(而非 enterprise_id)
|
|
|
|
|
- EnterpriseEntity ent = new EnterpriseEntity();
|
|
|
|
|
- ent.setEnterpriseId("E100");
|
|
|
|
|
- ent.setIdentity("2088IDENTITY");
|
|
|
|
|
- ent.setIdentityType("ALIPAY_OPEN_ID");
|
|
|
|
|
- when(enterpriseMapper.selectByEnterpriseIdIgnoreTenant("E100")).thenReturn(ent);
|
|
|
|
|
- AlipayFundBatchCreateResponse resp = new AlipayFundBatchCreateResponse();
|
|
|
|
|
- resp.setOutBatchNo("B1");
|
|
|
|
|
- when(alipayClient.certificateExecute(any(AlipayFundBatchCreateRequest.class))).thenReturn(resp);
|
|
|
|
|
- BatchAuthorizeEntity authed = new BatchAuthorizeEntity();
|
|
|
|
|
- authed.setStatus("AUTHED");
|
|
|
|
|
- authed.setAgreementNo("AGMT001");
|
|
|
|
|
- when(batchAuthorizeMapper.selectOne(any())).thenReturn(authed);
|
|
|
|
|
-
|
|
|
|
|
- BatchCreateDTO dto = new BatchCreateDTO();
|
|
|
|
|
- dto.setEnterpriseId("E100");
|
|
|
|
|
- dto.setOutBatchNo("B1");
|
|
|
|
|
- dto.setOrderTitle("t");
|
|
|
|
|
- BatchCreateDTO.BatchDetailDTO detail = new BatchCreateDTO.BatchDetailDTO();
|
|
|
|
|
- detail.setOutBizNo("D1");
|
|
|
|
|
- detail.setAmount(new BigDecimal("10"));
|
|
|
|
|
- detail.setPayeeIdentity("a@b.com");
|
|
|
|
|
- detail.setPayeeIdentityType("ALIPAY_LOGON_ID");
|
|
|
|
|
- detail.setPayeeName("张三");
|
|
|
|
|
- dto.setDetails(List.of(detail));
|
|
|
|
|
-
|
|
|
|
|
- Map<String, Object> result = service.batchCreate(dto);
|
|
|
|
|
-
|
|
|
|
|
- assertEquals("B1", result.get("out_batch_no"));
|
|
|
|
|
- ArgumentCaptor<AlipayFundBatchCreateRequest> cap = ArgumentCaptor.forClass(AlipayFundBatchCreateRequest.class);
|
|
|
|
|
- verify(alipayClient).certificateExecute(cap.capture());
|
|
|
|
|
- AlipayFundBatchCreateModel m = (AlipayFundBatchCreateModel) cap.getValue().getBizModel();
|
|
|
|
|
- assertEquals("2088IDENTITY", m.getPayerInfo().getIdentity());
|
|
|
|
|
- assertEquals("ALIPAY_OPEN_ID", m.getPayerInfo().getIdentityType());
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
// ==================== M3: batchClose INIT/WAIT_PAY 守卫 ====================
|
|
// ==================== M3: batchClose INIT/WAIT_PAY 守卫 ====================
|
|
|
|
|
|
|
|
@Test
|
|
@Test
|
|
|
void batchClose_nonInitStatus_throwsBusinessException() throws AlipayApiException {
|
|
void batchClose_nonInitStatus_throwsBusinessException() throws AlipayApiException {
|
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
|
- order.setEnterpriseId("E100");
|
|
|
|
|
|
|
+ order.setServiceProviderId(1L);
|
|
|
order.setOutBatchNo("B1");
|
|
order.setOutBatchNo("B1");
|
|
|
order.setStatus("SUCCESS");
|
|
order.setStatus("SUCCESS");
|
|
|
when(batchOrderMapper.selectOne(any())).thenReturn(order);
|
|
when(batchOrderMapper.selectOne(any())).thenReturn(order);
|
|
|
|
|
|
|
|
- BusinessException ex = assertThrows(BusinessException.class, () -> service.batchClose("E100", "B1"));
|
|
|
|
|
|
|
+ BusinessException ex = assertThrows(BusinessException.class, () -> service.batchClose("B1"));
|
|
|
|
|
|
|
|
assertEquals(400, ex.getCode());
|
|
assertEquals(400, ex.getCode());
|
|
|
assertTrue(ex.getMessage().contains("可关闭"), ex.getMessage());
|
|
assertTrue(ex.getMessage().contains("可关闭"), ex.getMessage());
|
|
@@ -738,7 +703,7 @@ class AlipayBatchPayServiceTest {
|
|
|
void batchClose_waitPayStatus_callsCloseApi() throws AlipayApiException {
|
|
void batchClose_waitPayStatus_callsCloseApi() throws AlipayApiException {
|
|
|
// WAIT_PAY=等待支付(render 过链接未支付)应可关闭(用户实测: 本地被同步成 WAIT_PAY 后关闭按钮消失)
|
|
// WAIT_PAY=等待支付(render 过链接未支付)应可关闭(用户实测: 本地被同步成 WAIT_PAY 后关闭按钮消失)
|
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
|
- order.setEnterpriseId("E100");
|
|
|
|
|
|
|
+ order.setServiceProviderId(1L);
|
|
|
order.setOutBatchNo("B1");
|
|
order.setOutBatchNo("B1");
|
|
|
order.setBatchTransId("BT1");
|
|
order.setBatchTransId("BT1");
|
|
|
order.setStatus("WAIT_PAY");
|
|
order.setStatus("WAIT_PAY");
|
|
@@ -746,7 +711,7 @@ class AlipayBatchPayServiceTest {
|
|
|
when(alipayClient.certificateExecute(any(AlipayFundBatchCloseRequest.class)))
|
|
when(alipayClient.certificateExecute(any(AlipayFundBatchCloseRequest.class)))
|
|
|
.thenReturn(new AlipayFundBatchCloseResponse());
|
|
.thenReturn(new AlipayFundBatchCloseResponse());
|
|
|
|
|
|
|
|
- Map<String, String> result = service.batchClose("E100", "B1");
|
|
|
|
|
|
|
+ Map<String, String> result = service.batchClose("B1");
|
|
|
|
|
|
|
|
assertEquals("DISUSE", result.get("status"));
|
|
assertEquals("DISUSE", result.get("status"));
|
|
|
verify(alipayClient).certificateExecute(any(AlipayFundBatchCloseRequest.class));
|
|
verify(alipayClient).certificateExecute(any(AlipayFundBatchCloseRequest.class));
|
|
@@ -757,7 +722,7 @@ class AlipayBatchPayServiceTest {
|
|
|
// 关闭失败(支付宝侧批次已不可关闭,用户实测 BATCH_ORDER_STATUS_INVALID)→
|
|
// 关闭失败(支付宝侧批次已不可关闭,用户实测 BATCH_ORDER_STATUS_INVALID)→
|
|
|
// detail.query 回写真实状态到本地,避免残留 INIT 让用户反复点关闭
|
|
// detail.query 回写真实状态到本地,避免残留 INIT 让用户反复点关闭
|
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
|
- order.setEnterpriseId("E100");
|
|
|
|
|
|
|
+ order.setServiceProviderId(1L);
|
|
|
order.setOutBatchNo("B1");
|
|
order.setOutBatchNo("B1");
|
|
|
order.setBatchTransId("BT1");
|
|
order.setBatchTransId("BT1");
|
|
|
order.setStatus("INIT");
|
|
order.setStatus("INIT");
|
|
@@ -772,7 +737,7 @@ class AlipayBatchPayServiceTest {
|
|
|
queryResp.setBatchStatus("INVALID");
|
|
queryResp.setBatchStatus("INVALID");
|
|
|
when(alipayClient.certificateExecute(any(AlipayFundBatchDetailQueryRequest.class))).thenReturn(queryResp);
|
|
when(alipayClient.certificateExecute(any(AlipayFundBatchDetailQueryRequest.class))).thenReturn(queryResp);
|
|
|
|
|
|
|
|
- BusinessException ex = assertThrows(BusinessException.class, () -> service.batchClose("E100", "B1"));
|
|
|
|
|
|
|
+ BusinessException ex = assertThrows(BusinessException.class, () -> service.batchClose("B1"));
|
|
|
|
|
|
|
|
assertEquals(400, ex.getCode());
|
|
assertEquals(400, ex.getCode());
|
|
|
assertTrue(ex.getMessage().contains("BATCH_ORDER_STATUS_INVALID"), ex.getMessage());
|
|
assertTrue(ex.getMessage().contains("BATCH_ORDER_STATUS_INVALID"), ex.getMessage());
|
|
@@ -785,7 +750,7 @@ class AlipayBatchPayServiceTest {
|
|
|
void renderPay_waitPayStatus_regeneratesPayUrl() throws AlipayApiException {
|
|
void renderPay_waitPayStatus_regeneratesPayUrl() throws AlipayApiException {
|
|
|
// WAIT_PAY=等待支付(render 过链接未支付)应可重新生成支付链接(用户实测: 不能二次发起支付)
|
|
// WAIT_PAY=等待支付(render 过链接未支付)应可重新生成支付链接(用户实测: 不能二次发起支付)
|
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
BatchOrderEntity order = new BatchOrderEntity();
|
|
|
- order.setEnterpriseId("E100");
|
|
|
|
|
|
|
+ order.setServiceProviderId(1L);
|
|
|
order.setOutBatchNo("B1");
|
|
order.setOutBatchNo("B1");
|
|
|
order.setBatchTransId("BT1");
|
|
order.setBatchTransId("BT1");
|
|
|
order.setStatus("WAIT_PAY");
|
|
order.setStatus("WAIT_PAY");
|
|
@@ -795,43 +760,12 @@ class AlipayBatchPayServiceTest {
|
|
|
resp.setInitializeCode("https://p.tb.cn/_2PG4jfHMVvg9vqBUdtx1HZ");
|
|
resp.setInitializeCode("https://p.tb.cn/_2PG4jfHMVvg9vqBUdtx1HZ");
|
|
|
when(alipayClient.certificateExecute(any(AlipayFundTransRenderPayRequest.class))).thenReturn(resp);
|
|
when(alipayClient.certificateExecute(any(AlipayFundTransRenderPayRequest.class))).thenReturn(resp);
|
|
|
|
|
|
|
|
- Map<String, String> result = service.renderPay("E100", "B1");
|
|
|
|
|
|
|
+ Map<String, String> result = service.renderPay("B1");
|
|
|
|
|
|
|
|
assertEquals("https://p.tb.cn/_2PG4jfHMVvg9vqBUdtx1HZ", result.get("pay_url"));
|
|
assertEquals("https://p.tb.cn/_2PG4jfHMVvg9vqBUdtx1HZ", result.get("pay_url"));
|
|
|
verify(batchOrderMapper).updateById(order);
|
|
verify(batchOrderMapper).updateById(order);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // ==================== 二轮复核修复: 空 enterpriseId 拒绝(条件式 eq 的空值漏洞) ====================
|
|
|
|
|
-
|
|
|
|
|
- @Test
|
|
|
|
|
- void renderPay_blankEnterpriseId_throws() {
|
|
|
|
|
- // enterprise_id 为空必须拒绝而非静默跳过租户过滤(防御 /pay body 零校验路径)
|
|
|
|
|
- BusinessException ex = assertThrows(BusinessException.class, () -> service.renderPay("", "B1"));
|
|
|
|
|
- assertEquals(400, ex.getCode());
|
|
|
|
|
- verify(batchOrderMapper, never()).selectOne(any());
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- @Test
|
|
|
|
|
- void batchQuery_nullEnterpriseId_throws() {
|
|
|
|
|
- BusinessException ex = assertThrows(BusinessException.class, () -> service.batchQuery(null, "B1"));
|
|
|
|
|
- assertEquals(400, ex.getCode());
|
|
|
|
|
- verify(batchOrderMapper, never()).selectOne(any());
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- @Test
|
|
|
|
|
- void batchClose_blankEnterpriseId_throws() {
|
|
|
|
|
- BusinessException ex = assertThrows(BusinessException.class, () -> service.batchClose(" ", "B1"));
|
|
|
|
|
- assertEquals(400, ex.getCode());
|
|
|
|
|
- verify(batchOrderMapper, never()).selectOne(any());
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- @Test
|
|
|
|
|
- void batchDetail_nullEnterpriseId_throws() {
|
|
|
|
|
- BusinessException ex = assertThrows(BusinessException.class, () -> service.batchDetail(null, "B1", 1, 20));
|
|
|
|
|
- assertEquals(400, ex.getCode());
|
|
|
|
|
- verify(batchOrderMapper, never()).selectOne(any());
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
// ==================== 二轮复核修复: parseTimeFilter 边界精确断言 ====================
|
|
// ==================== 二轮复核修复: parseTimeFilter 边界精确断言 ====================
|
|
|
|
|
|
|
|
@Test
|
|
@Test
|