Test #1

Merged
admin merged 1726 commits from test into main 2026-09-17 11:52:45 +08:00
8 changed files with 186 additions and 75 deletions
Showing only changes of commit db80701534 - Show all commits
@@ -4,14 +4,12 @@ import com.baiyue.common.core.api.ResultCode;
import com.baiyue.common.core.exception.BizException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.baiyue.finance.client.FinanceFileClient;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
@@ -26,14 +24,12 @@ import java.util.Map;
public class FinanceService {
private final JdbcTemplate jdbc;
private final ObjectMapper objectMapper;
@Autowired(required = false)
private FinanceFileClient fileClient;
@org.springframework.beans.factory.annotation.Value("${baiyue.security.internal-service-token:}")
private String fileToken;
private final FinanceVoucherValidator voucherValidator;
public FinanceService(JdbcTemplate jdbc, ObjectMapper objectMapper) {
public FinanceService(JdbcTemplate jdbc, ObjectMapper objectMapper, FinanceVoucherValidator voucherValidator) {
this.jdbc = jdbc;
this.objectMapper = objectMapper;
this.voucherValidator = voucherValidator;
}
public Map<String, Object> customerTerms(long tenantId) {
@@ -203,20 +199,8 @@ public class FinanceService {
}
private void validateVoucherFiles(long tenantId, List<String> fileIds) {
if (fileIds == null || fileIds.isEmpty()) throw bad("财务凭证不能为空");
if (fileClient == null) throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "File服务校验能力不可用");
for (String raw : fileIds) {
long id; try { id = Long.parseLong(raw); } catch (Exception ex) { throw bad("凭证文件ID无效"); }
var response = fileClient.metadata(fileToken, tenantId, tenantId, id);
var metadata = response == null ? null : response.data();
if (metadata == null || metadata.fileId() == null || !tenantIdEquals(metadata.tenantId(), tenantId)
|| !"FINANCE_VOUCHER".equals(metadata.businessType()) || metadata.contentType() == null
|| !metadata.contentType().toLowerCase(java.util.Locale.ROOT).startsWith("image/")) {
throw bad("凭证文件不存在、归属不匹配或不是有效图片");
}
}
voucherValidator.validate(tenantId, fileIds, "财务凭证");
}
private static boolean tenantIdEquals(Long actual, long expected) { return actual != null && actual == expected; }
@Transactional
public Map<String, Object> createCost(long tenantId, long operatorId, CostRequest request, String idempotencyKey) {
@@ -1,6 +1,5 @@
package com.baiyue.finance.service;
import com.baiyue.finance.client.FinanceFileClient;
import com.baiyue.finance.dto.FinanceSettlementDtos.CreatePayableSettlementRequest;
import com.baiyue.finance.dto.FinanceSettlementDtos.CreateReceivableSettlementRequest;
import com.baiyue.finance.dto.FinanceSettlementDtos.CreateSettlementPaymentRequest;
@@ -14,7 +13,6 @@ import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
@@ -47,15 +45,12 @@ public class FinanceSettlementService {
private static final Set<String> PAYMENT_METHODS = Set.of("BANK_TRANSFER", "CASH", "OTHER");
private final JdbcTemplate jdbc;
private final ObjectMapper objectMapper;
private final FinanceFileClient fileClient;
private final FinanceVoucherValidator voucherValidator;
@Value("${baiyue.security.internal-service-token:}")
private String fileToken;
public FinanceSettlementService(JdbcTemplate jdbc, ObjectMapper objectMapper, FinanceFileClient fileClient) {
public FinanceSettlementService(JdbcTemplate jdbc, ObjectMapper objectMapper, FinanceVoucherValidator voucherValidator) {
this.jdbc = jdbc;
this.objectMapper = objectMapper;
this.fileClient = fileClient;
this.voucherValidator = voucherValidator;
}
@Transactional
@@ -355,26 +350,7 @@ public class FinanceSettlementService {
}
private void validateVoucherFiles(long customerId, List<String> fileIds) {
if (fileClient == null || !StringUtils.hasText(fileToken)) throw error("FIN_503", "File服务校验能力不可用");
for (String raw : fileIds) {
long fileId;
try { fileId = Long.parseLong(raw); } catch (RuntimeException invalid) { throw error("FIN_400", "付款凭证文件ID无效"); }
FinanceFileClient.Metadata metadata;
try {
var response = fileClient.metadata(fileToken, customerId, customerId, fileId);
metadata = response == null ? null : response.data();
} catch (RuntimeException unavailable) {
throw error("FIN_503", "File服务校验不可用");
}
if (metadata == null || metadata.fileId() == null || metadata.fileId() != fileId
|| metadata.tenantId() == null || metadata.tenantId() != customerId
|| !"FINANCE_VOUCHER".equals(metadata.businessType())
|| !String.valueOf(customerId).equals(metadata.businessId())
|| !StringUtils.hasText(metadata.contentType())
|| !metadata.contentType().toLowerCase(Locale.ROOT).startsWith("image/")) {
throw error("FIN_400", "付款凭证不存在、客户归属不匹配或文件类型无效");
}
}
voucherValidator.validate(customerId, fileIds, "付款凭证");
}
private Long reserve(long customerId, long operatorId, String operation, String key,
@@ -0,0 +1,56 @@
package com.baiyue.finance.service;
import com.baiyue.common.core.api.ResultCode;
import com.baiyue.common.core.exception.BizException;
import com.baiyue.finance.client.FinanceFileClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.util.List;
import java.util.Locale;
import java.util.HashSet;
@Component
public class FinanceVoucherValidator {
private final FinanceFileClient fileClient;
private final String fileToken;
@Autowired
public FinanceVoucherValidator(FinanceFileClient fileClient,
@Value("${baiyue.security.internal-service-token:}") String fileToken) {
this.fileClient = fileClient;
this.fileToken = fileToken;
}
public void validate(long customerId, List<String> fileIds, String message) {
if (fileIds == null || fileIds.isEmpty()) throw bad(message + "不能为空");
if (fileClient == null || !StringUtils.hasText(fileToken)) throw unavailable("File服务校验能力不可用");
if (new HashSet<>(fileIds).size() != fileIds.size()) throw bad(message + "文件ID不能重复");
for (String raw : fileIds) {
final long fileId;
try { fileId = Long.parseLong(raw); } catch (RuntimeException invalid) { throw bad(message + "文件ID无效"); }
FinanceFileClient.Metadata metadata;
try {
var response = fileClient.metadata(fileToken, customerId, customerId, fileId);
metadata = response == null ? null : response.data();
} catch (RuntimeException unavailable) {
throw unavailable("File服务校验不可用");
}
if (metadata == null || metadata.fileId() == null || metadata.fileId() != fileId
|| metadata.tenantId() == null || metadata.tenantId() != customerId
|| !String.valueOf(customerId).equals(metadata.businessId())
|| !"FINANCE_VOUCHER".equals(metadata.businessType())
|| !StringUtils.hasText(metadata.contentType())
|| !metadata.contentType().toLowerCase(Locale.ROOT).startsWith("image/")) {
throw bad(message + "不存在、归属不匹配或不是有效图片");
}
}
}
private static BizException bad(String message) { return new BizException(ResultCode.BAD_REQUEST, message); }
private static BizException unavailable(String message) {
return new BizException(ResultCode.SERVICE_UNAVAILABLE, message);
}
}
@@ -1,6 +1,7 @@
package com.baiyue.finance;
import com.baiyue.finance.service.FinanceService;
import com.baiyue.finance.service.FinanceVoucherValidator;
import com.baiyue.finance.client.FinanceFileClient;
import com.baiyue.common.core.api.ApiResponse;
import com.baiyue.common.core.api.ResultCode;
@@ -18,7 +19,6 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
import org.springframework.test.util.ReflectionTestUtils;
class FinanceServiceValidationTest {
@Test
@@ -49,7 +49,7 @@ class FinanceServiceValidationTest {
@Test
void rejectsUnsupportedCostTypeBeforeWrite() {
JdbcTemplate jdbc = mock(JdbcTemplate.class);
FinanceService service = new FinanceService(jdbc, new ObjectMapper());
FinanceService service = service(jdbc);
var request = new FinanceService.CostRequest("C-1", "TICKET", 1L, null, null, null, null, "MANUAL", "拖车", BigDecimal.ONE, List.of("f"), null);
assertThrows(RuntimeException.class, () -> service.createCost(1L, 2L, request, "k1"));
verify(jdbc, never()).update(startsWith("INSERT INTO fin_cost"), (Object[]) any());
@@ -58,7 +58,7 @@ class FinanceServiceValidationTest {
@Test
void rejectsNonPositiveAllocation() {
JdbcTemplate jdbc = mock(JdbcTemplate.class);
FinanceService service = new FinanceService(jdbc, new ObjectMapper());
FinanceService service = service(jdbc);
var request = new FinanceService.ReceiptRequest("R-1", 1L, null, "BANK_TRANSFER", null, List.of("f"), null,
List.of(new FinanceService.ReceiptAllocation(10L, BigDecimal.ZERO)));
assertThrows(RuntimeException.class, () -> service.createReceipt(1L, 2L, request, "k2"));
@@ -67,7 +67,7 @@ class FinanceServiceValidationTest {
@Test
void rejectsDuplicateBillAllocationInsteadOfMerging() {
JdbcTemplate jdbc = mock(JdbcTemplate.class);
FinanceService service = new FinanceService(jdbc, new ObjectMapper());
FinanceService service = service(jdbc);
var request = new FinanceService.ReceiptRequest("R-2", 1L, null, "BANK_TRANSFER", null, List.of("f"), null,
List.of(new FinanceService.ReceiptAllocation(10L, BigDecimal.ONE), new FinanceService.ReceiptAllocation(10L, BigDecimal.ONE)));
assertThrows(RuntimeException.class, () -> service.createReceipt(1L, 2L, request, "k3"));
@@ -76,7 +76,8 @@ class FinanceServiceValidationTest {
@Test
void receiptFailsClosedWhenFileValidationCapabilityIsUnavailable() {
JdbcTemplate jdbc = mock(JdbcTemplate.class);
FinanceService service = new FinanceService(jdbc, new ObjectMapper());
FinanceService service = new FinanceService(jdbc, new ObjectMapper(),
new FinanceVoucherValidator(null, ""));
var request = new FinanceService.ReceiptRequest("R-FILE", 1L, null, "BANK_TRANSFER", null, List.of("77"), null,
List.of(new FinanceService.ReceiptAllocation(10L, BigDecimal.ONE)));
@@ -92,8 +93,7 @@ class FinanceServiceValidationTest {
FinanceFileClient files = mock(FinanceFileClient.class);
when(files.metadata(anyString(), eq(9L), eq(9L), eq(77L))).thenReturn(ApiResponse.success(
new FinanceFileClient.Metadata(77L, 10L, "FINANCE_VOUCHER", "9", "v.jpg", "sha", "image/jpeg", 10L)));
FinanceService service = new FinanceService(jdbc, new ObjectMapper().findAndRegisterModules());
ReflectionTestUtils.setField(service, "fileClient", files);
FinanceService service = service(jdbc, files);
var request = new FinanceService.ReceiptRequest("R-3", 1L, null, "BANK_TRANSFER", null, List.of("77"), null,
List.of(new FinanceService.ReceiptAllocation(10L, BigDecimal.ONE)));
assertThrows(RuntimeException.class, () -> service.createReceipt(9L, 2L, request, "k4"));
@@ -117,9 +117,7 @@ class FinanceServiceValidationTest {
holder.getKeyList().add(java.util.Map.of("GENERATED_KEY", 701L));
return 1;
}).when(jdbc).update(any(org.springframework.jdbc.core.PreparedStatementCreator.class), any(org.springframework.jdbc.support.KeyHolder.class));
FinanceService service = new FinanceService(jdbc, new ObjectMapper().findAndRegisterModules());
ReflectionTestUtils.setField(service, "fileClient", files);
ReflectionTestUtils.setField(service, "fileToken", "internal-token");
FinanceService service = service(jdbc, files);
var request = new FinanceService.ReceiptRequest("R-4", 1L, java.time.LocalDateTime.of(2026, 8, 11, 10, 0),
"BANK_TRANSFER", null, List.of("77"), "首笔收款",
List.of(new FinanceService.ReceiptAllocation(50L, new BigDecimal("40.00"))));
@@ -154,9 +152,7 @@ class FinanceServiceValidationTest {
holder.getKeyList().add(java.util.Map.of("GENERATED_KEY", 701L));
return 1;
}).when(jdbc).update(any(org.springframework.jdbc.core.PreparedStatementCreator.class), any(org.springframework.jdbc.support.KeyHolder.class));
FinanceService service = new FinanceService(jdbc, new ObjectMapper().findAndRegisterModules());
ReflectionTestUtils.setField(service, "fileClient", files);
ReflectionTestUtils.setField(service, "fileToken", "internal-token");
FinanceService service = service(jdbc, files);
var request = new FinanceService.ReceiptRequest("R-300", 1L, java.time.LocalDateTime.of(2026, 8, 11, 10, 0),
"BANK_TRANSFER", "BANK-300", List.of("77"), "三单收款", List.of(
new FinanceService.ReceiptAllocation(50L, new BigDecimal("100.00")),
@@ -176,7 +172,7 @@ class FinanceServiceValidationTest {
void rejectsSingleOrderWhenOrderNotOwnedByCustomer() {
JdbcTemplate jdbc = mock(JdbcTemplate.class);
when(jdbc.queryForObject(startsWith("SELECT COUNT(*) FROM fin_fee_source"), eq(Number.class), any(), any())).thenReturn(0);
FinanceService service = new FinanceService(jdbc, new ObjectMapper());
FinanceService service = service(jdbc);
var request = new FinanceService.CostRequest("C-2", "SINGLE_ORDER", 99L, null, null, null, null, "MANUAL", "货拉拉", BigDecimal.ONE, List.of("1"), null);
assertThrows(RuntimeException.class, () -> service.createCost(9L, 2L, request, "k5"));
}
@@ -198,9 +194,7 @@ class FinanceServiceValidationTest {
holder.getKeyList().add(java.util.Map.of("GENERATED_KEY", 701L));
return 1;
}).when(jdbc).update(any(org.springframework.jdbc.core.PreparedStatementCreator.class), any(org.springframework.jdbc.support.KeyHolder.class));
FinanceService service = new FinanceService(jdbc, new ObjectMapper());
ReflectionTestUtils.setField(service, "fileClient", files);
ReflectionTestUtils.setField(service, "fileToken", "internal-token");
FinanceService service = service(jdbc, files);
var request = new FinanceService.CostRequest("C-3", "CONTAINER_SHARED", null, null, 88L,
null, null, "MANUAL", "整柜成本", new BigDecimal("300.00"), List.of("77"), null);
var snapshot = List.of(new FinanceService.ContainerOrderVolume(
@@ -221,7 +215,7 @@ class FinanceServiceValidationTest {
.thenReturn(1);
var rows = List.<java.util.Map<String, Object>>of(java.util.Map.of("version", 2));
when(jdbc.queryForList(startsWith("SELECT id,bill_id,version"), eq(9L), eq(50L))).thenReturn(rows);
FinanceService service = new FinanceService(jdbc, new ObjectMapper());
FinanceService service = service(jdbc);
assertEquals(rows, service.billRevisions(9L, 50L));
}
@@ -231,9 +225,19 @@ class FinanceServiceValidationTest {
JdbcTemplate jdbc = mock(JdbcTemplate.class);
when(jdbc.queryForObject(startsWith("SELECT COUNT(*) FROM fin_bill"), eq(Number.class), eq(50L), eq(9L)))
.thenReturn(0);
FinanceService service = new FinanceService(jdbc, new ObjectMapper());
FinanceService service = service(jdbc);
assertThrows(RuntimeException.class, () -> service.billRevisions(9L, 50L));
verify(jdbc, never()).queryForList(startsWith("SELECT id,bill_id,version"), (Object[]) any());
}
private static FinanceService service(JdbcTemplate jdbc, FinanceFileClient files) {
return new FinanceService(jdbc, new ObjectMapper().findAndRegisterModules(),
new FinanceVoucherValidator(files, "internal-token"));
}
private static FinanceService service(JdbcTemplate jdbc) {
return new FinanceService(jdbc, new ObjectMapper().findAndRegisterModules(),
mock(FinanceVoucherValidator.class));
}
}
@@ -1,6 +1,8 @@
package com.baiyue.finance;
import com.baiyue.common.core.api.ApiResponse;
import com.baiyue.common.core.api.ResultCode;
import com.baiyue.common.core.exception.BizException;
import com.baiyue.common.security.AuthenticatedUser;
import com.baiyue.finance.client.FinanceFileClient;
import com.baiyue.finance.controller.FinanceSettlementController;
@@ -12,6 +14,7 @@ import com.baiyue.finance.dto.FinanceSettlementDtos.SettlementSummary;
import com.baiyue.finance.dto.FinanceSettlementDtos.SettlementActionRequest;
import com.baiyue.finance.service.FinanceEventException;
import com.baiyue.finance.service.FinanceSettlementService;
import com.baiyue.finance.service.FinanceVoucherValidator;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -136,8 +139,11 @@ class FinanceSettlementBehaviorTest {
when(fileClient.metadata("internal-token", 10L, 10L, 91L)).thenThrow(new IllegalStateException("down"));
FinanceSettlementService service = service(jdbc, fileClient);
assertCode(() -> service.createSettlementPayment(88L, 7L, "pay-key",
payment(new BigDecimal("40.00"), 0)), "FIN_503");
assertThatThrownBy(() -> service.createSettlementPayment(88L, 7L, "pay-key",
payment(new BigDecimal("40.00"), 0)))
.isInstanceOf(BizException.class)
.extracting(error -> ((BizException) error).getResultCode())
.isEqualTo(ResultCode.SERVICE_UNAVAILABLE);
verify(jdbc, never()).update(startsWith("INSERT INTO fin_settlement_payment"), (Object[]) any());
verify(jdbc, never()).update(startsWith("UPDATE fin_settlement SET paid_amount"), (Object[]) any());
@@ -516,10 +522,8 @@ class FinanceSettlementBehaviorTest {
}
private static FinanceSettlementService service(JdbcTemplate jdbc, FinanceFileClient fileClient) {
FinanceSettlementService service = new FinanceSettlementService(
jdbc, new ObjectMapper().findAndRegisterModules(), fileClient);
ReflectionTestUtils.setField(service, "fileToken", "internal-token");
return service;
return new FinanceSettlementService(jdbc, new ObjectMapper().findAndRegisterModules(),
new FinanceVoucherValidator(fileClient, "internal-token"));
}
private static CreateSettlementPaymentRequest payment(BigDecimal amount, int version) {
@@ -0,0 +1,87 @@
package com.baiyue.finance;
import com.baiyue.common.core.api.ApiResponse;
import com.baiyue.finance.client.FinanceFileClient;
import com.baiyue.finance.service.FinanceVoucherValidator;
import com.baiyue.common.core.api.ResultCode;
import com.baiyue.common.core.exception.BizException;
import org.junit.jupiter.api.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class FinanceVoucherValidatorTest {
@Test
void acceptsCustomerOwnedFinanceImage() {
FinanceFileClient files = mock(FinanceFileClient.class);
when(files.metadata("token", 9L, 9L, 77L)).thenReturn(ApiResponse.success(
new FinanceFileClient.Metadata(77L, 9L, "FINANCE_VOUCHER", "9", "receipt.jpg", "sha", "image/jpeg", 10L)));
new FinanceVoucherValidator(files, "token").validate(9L, List.of("77"), "财务凭证");
verify(files).metadata("token", 9L, 9L, 77L);
}
@Test
void rejectsMismatchedFileIdentityOwnershipTypeAndMime() {
FinanceFileClient files = mock(FinanceFileClient.class);
List<FinanceFileClient.Metadata> invalid = List.of(
new FinanceFileClient.Metadata(78L, 9L, "FINANCE_VOUCHER", "9", "receipt.jpg", "sha", "image/jpeg", 10L),
new FinanceFileClient.Metadata(77L, 10L, "FINANCE_VOUCHER", "9", "receipt.jpg", "sha", "image/jpeg", 10L),
new FinanceFileClient.Metadata(77L, 9L, "FINANCE_VOUCHER", "10", "receipt.jpg", "sha", "image/jpeg", 10L),
new FinanceFileClient.Metadata(77L, 9L, "OTHER", "9", "receipt.jpg", "sha", "image/jpeg", 10L),
new FinanceFileClient.Metadata(77L, 9L, "FINANCE_VOUCHER", "9", "receipt.pdf", "sha", "application/pdf", 10L));
for (FinanceFileClient.Metadata metadata : invalid) {
when(files.metadata(eq("token"), eq(9L), eq(9L), eq(77L))).thenReturn(ApiResponse.success(metadata));
assertThatThrownBy(() -> new FinanceVoucherValidator(files, "token")
.validate(9L, List.of("77"), "付款凭证"))
.isInstanceOf(BizException.class)
.extracting(error -> ((BizException) error).getResultCode()).isEqualTo(ResultCode.BAD_REQUEST);
}
}
@Test
void failsClosedWhenFileDependencyUnavailable() {
FinanceFileClient files = mock(FinanceFileClient.class);
when(files.metadata("token", 9L, 9L, 77L)).thenThrow(new IllegalStateException("down"));
assertThatThrownBy(() -> new FinanceVoucherValidator(files, "token")
.validate(9L, List.of("77"), "付款凭证"))
.isInstanceOf(BizException.class)
.extracting(error -> ((BizException) error).getResultCode()).isEqualTo(ResultCode.SERVICE_UNAVAILABLE);
}
@Test
void rejectsMissingInvalidAndDuplicateFileIds() {
FinanceVoucherValidator validator = new FinanceVoucherValidator(mock(FinanceFileClient.class), "token");
assertResult(() -> validator.validate(9L, List.of(), "财务凭证"), ResultCode.BAD_REQUEST);
assertResult(() -> validator.validate(9L, List.of("invalid"), "财务凭证"), ResultCode.BAD_REQUEST);
assertResult(() -> validator.validate(9L, List.of("77", "77"), "付款凭证"), ResultCode.BAD_REQUEST);
}
@Test
void rejectsWrongFileIdAndCustomerOwnership() {
FinanceFileClient files = mock(FinanceFileClient.class);
when(files.metadata("token", 9L, 9L, 77L)).thenReturn(ApiResponse.success(
new FinanceFileClient.Metadata(78L, 10L, "FINANCE_VOUCHER", "9", "receipt.jpg", "sha", "image/jpeg", 10L)));
assertResult(() -> new FinanceVoucherValidator(files, "token")
.validate(9L, List.of("77"), "付款凭证"), ResultCode.BAD_REQUEST);
}
@Test
void rejectsMissingToken() {
assertResult(() -> new FinanceVoucherValidator(mock(FinanceFileClient.class), "")
.validate(9L, List.of("77"), "财务凭证"), ResultCode.SERVICE_UNAVAILABLE);
}
private static void assertResult(org.assertj.core.api.ThrowableAssert.ThrowingCallable call,
ResultCode resultCode) {
assertThatThrownBy(call).isInstanceOf(BizException.class)
.extracting(error -> ((BizException) error).getResultCode()).isEqualTo(resultCode);
}
}
@@ -27,7 +27,7 @@ test('覆盖模板生命周期、版本冲突、定时任务、幂等、查询
]) assert.match(moduleSource, new RegExp(token))
assert.match(moduleSource, /recipientType:\s*'PLATFORM_ROLE'/)
assert.match(moduleSource, /roleCode:\s*'PLATFORM_ADMIN'/)
assert.match(moduleSource, /Date\.now\(\) \+ 24 \* 60 \* 60 \* 1000/)
assert.match(moduleSource, /Date\.now\(\) \+ 365 \* 24 \* 60 \* 60 \* 1000/)
})
test('异常路径会取消定时任务并停用模板,不实际投递验收消息', () => {
@@ -94,7 +94,7 @@ export async function run(context) {
template?.status === 'ACTIVE' && Number(template?.version) === 3,
`status=${template?.status || 'missing'}, version=${template?.version ?? 'missing'}`, OPTIONS)
const scheduledAt = new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString().slice(0, 19)
const scheduledAt = new Date(Date.now() + 365 * 24 * 60 * 60 * 1000).toISOString().slice(0, 19)
const idempotencyKey = `${context.marker}-notification-scheduled`.slice(0, 128)
const taskCreate = {
tenantId: 0,