日志记录提交
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
package com.baiyue.firstleg.controller;
|
||||
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@DisplayName("费用管理接口权限契约")
|
||||
class FeeManagementContractTest {
|
||||
@Test
|
||||
@DisplayName("通过和驳回共用审核按钮权限")
|
||||
void protectsReviewActions() {
|
||||
for (String methodName : new String[] {"approve", "reject"}) {
|
||||
Method method = Arrays.stream(PlatformInboundFeeDetailController.class.getDeclaredMethods())
|
||||
.filter(candidate -> candidate.getName().equals(methodName))
|
||||
.findFirst().orElseThrow();
|
||||
assertThat(method.getAnnotation(PreAuthorize.class).value())
|
||||
.isEqualTo("hasAuthority('firstleg:inbound:fee-detail:review')");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("费用项目增删改查权限彼此独立")
|
||||
void separatesCrudPermissions() {
|
||||
assertPermission("list", "firstleg:fee-item:view");
|
||||
assertPermission("detail", "firstleg:fee-item:view");
|
||||
assertPermission("create", "firstleg:fee-item:create");
|
||||
assertPermission("update", "firstleg:fee-item:edit");
|
||||
assertPermission("changeStatus", "firstleg:fee-item:edit");
|
||||
assertPermission("delete", "firstleg:fee-item:delete");
|
||||
}
|
||||
|
||||
private static void assertPermission(String methodName, String permission) {
|
||||
Method method = Arrays.stream(PlatformFeeItemController.class.getDeclaredMethods())
|
||||
.filter(candidate -> candidate.getName().equals(methodName))
|
||||
.findFirst().orElseThrow();
|
||||
assertThat(method.getAnnotation(PreAuthorize.class).value())
|
||||
.isEqualTo("hasAuthority('" + permission + "')");
|
||||
}
|
||||
}
|
||||
+13
@@ -1,8 +1,10 @@
|
||||
package com.baiyue.firstleg.controller;
|
||||
|
||||
import com.baiyue.common.audit.BusinessAudit;
|
||||
import com.baiyue.common.security.AuthenticatedUser;
|
||||
import com.baiyue.firstleg.dto.ExceptionReleaseRequest;
|
||||
import com.baiyue.firstleg.dto.MeasurementReviewRequest;
|
||||
import com.baiyue.firstleg.service.AutomaticInboundCompletionService;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
@@ -43,6 +45,17 @@ class InboundMeasurementReviewContractTest {
|
||||
.doesNotContain("待客户确认");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAuditAutomaticInboundCompletion() throws Exception {
|
||||
Method method = AutomaticInboundCompletionService.class.getDeclaredMethod("completeApproved",
|
||||
long.class, long.class, long.class, String.class, long.class, int.class);
|
||||
BusinessAudit audit = method.getAnnotation(BusinessAudit.class);
|
||||
assertThat(audit.event()).isEqualTo("INBOUND_AUTO_COMPLETE");
|
||||
assertThat(audit.resourceType()).isEqualTo("INBOUND");
|
||||
assertThat(audit.resourceId()).isEqualTo("#inboundId");
|
||||
assertThat(audit.captureBefore()).isFalse();
|
||||
}
|
||||
|
||||
private void assertAuthority(String name, String expression, Class<?>... types) throws Exception {
|
||||
Method method = PlatformInboundMeasurementReviewController.class.getDeclaredMethod(name, types);
|
||||
assertThat(method.getAnnotation(PreAuthorize.class).value()).isEqualTo(expression);
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
package com.baiyue.firstleg.service;
|
||||
|
||||
import com.baiyue.common.core.api.PageResult;
|
||||
import com.baiyue.common.core.exception.BizException;
|
||||
import com.baiyue.firstleg.dto.FeeItemDtos;
|
||||
import com.baiyue.firstleg.dto.InboundFeeDetailDtos;
|
||||
import com.baiyue.firstleg.entity.FeeItemEntity;
|
||||
import com.baiyue.firstleg.entity.InboundFeeDetailEntity;
|
||||
import com.baiyue.firstleg.entity.InboundOrderEntity;
|
||||
import com.baiyue.firstleg.repository.FeeItemRepository;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@DisplayName("费用项目和入库费用明细")
|
||||
@SpringJUnitConfig({FeeItemService.class, InboundFeeDetailService.class})
|
||||
class FeeManagementServiceTest {
|
||||
@MockBean
|
||||
private FeeItemRepository repository;
|
||||
@Resource
|
||||
private FeeItemService feeItems;
|
||||
@Resource
|
||||
private InboundFeeDetailService details;
|
||||
|
||||
@Test
|
||||
@DisplayName("费用项目列表返回分页结果")
|
||||
void pagesItems() {
|
||||
PageResult<FeeItemEntity> expected = new PageResult<>(List.of(), 2, 20, 21, 2);
|
||||
when(repository.listItems(10001L, "仓储成本", "INTERNATIONAL", "人工", "ACTIVE", 2, 20))
|
||||
.thenReturn(expected);
|
||||
|
||||
assertThat(feeItems.list(10001L, "仓储成本", "INTERNATIONAL", "人工", "ACTIVE", 2, 20))
|
||||
.isSameAs(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("新增费用项目保存原型字段")
|
||||
void createsItem() {
|
||||
doAnswer(invocation -> {
|
||||
((FeeItemEntity) invocation.getArgument(0)).setId(11L);
|
||||
return null;
|
||||
}).when(repository).insertItem(any());
|
||||
|
||||
FeeItemEntity created = feeItems.create(10001L, 9L, "admin", itemRequest());
|
||||
|
||||
assertThat(created.getId()).isEqualTo(11L);
|
||||
assertThat(created.getAllocationFee()).isTrue();
|
||||
assertThat(created.getWarehouseReceivable()).isTrue();
|
||||
assertThat(created.getCreatedByName()).isEqualTo("admin");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("入库费用绑定项目并生成订单快照")
|
||||
void bindsInboundFee() {
|
||||
InboundOrderEntity inbound = inbound();
|
||||
FeeItemEntity item = item(true, true);
|
||||
when(repository.findInbound(10001L, 21L)).thenReturn(inbound);
|
||||
when(repository.findItem(10001L, 11L)).thenReturn(item);
|
||||
doAnswer(invocation -> {
|
||||
((InboundFeeDetailEntity) invocation.getArgument(0)).setId(31L);
|
||||
return null;
|
||||
}).when(repository).insertDetail(any());
|
||||
|
||||
InboundFeeDetailEntity created = details.create(10001L, 21L, 9L,
|
||||
detailRequest("RECEIVABLE"));
|
||||
|
||||
assertThat(created.getId()).isEqualTo(31L);
|
||||
assertThat(created.getInboundCode()).isEqualTo("RK-20260805-001");
|
||||
assertThat(created.getFeeTypeNameSnapshot()).isEqualTo("仓库租赁费");
|
||||
assertThat(created.getActualGrossWeightKg()).isEqualByComparingTo("10.5000");
|
||||
assertThat(created.getReviewStatus()).isEqualTo("PENDING");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("拒绝绑定未启用仓储应收的项目")
|
||||
void rejectsInapplicableItem() {
|
||||
when(repository.findInbound(10001L, 21L)).thenReturn(inbound());
|
||||
when(repository.findItem(10001L, 11L)).thenReturn(item(false, true));
|
||||
|
||||
assertThatThrownBy(() -> details.create(10001L, 21L, 9L,
|
||||
detailRequest("RECEIVABLE")))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessageContaining("仓储应收/应付");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("审核只更新待审核明细")
|
||||
void approvesPendingDetail() {
|
||||
when(repository.findDetail(10001L, 21L, 31L)).thenReturn(new InboundFeeDetailEntity());
|
||||
when(repository.review(10001L, 21L, 31L, "APPROVED", 9L, "admin", null)).thenReturn(1);
|
||||
|
||||
details.approve(10001L, 21L, 31L, 9L, "admin");
|
||||
|
||||
verify(repository).review(10001L, 21L, 31L, "APPROVED", 9L, "admin", null);
|
||||
}
|
||||
|
||||
private static FeeItemDtos.SaveRequest itemRequest() {
|
||||
return new FeeItemDtos.SaveRequest("仓储成本", "INTERNATIONAL", "仓库租赁费",
|
||||
false, false, true, true, true, "应付仓库租赁费");
|
||||
}
|
||||
|
||||
private static InboundFeeDetailDtos.SaveRequest detailRequest(String direction) {
|
||||
return new InboundFeeDetailDtos.SaveRequest(11L, direction, LocalDate.of(2026, 8, 5),
|
||||
new BigDecimal("12.3456"), "CNY", new BigDecimal("123.46"), "联调费用");
|
||||
}
|
||||
|
||||
private static FeeItemEntity item(boolean receivable, boolean payable) {
|
||||
FeeItemEntity item = new FeeItemEntity();
|
||||
item.setId(11L);
|
||||
item.setCategory("仓储成本");
|
||||
item.setTradeScope("INTERNATIONAL");
|
||||
item.setFeeTypeName("仓库租赁费");
|
||||
item.setWarehouseReceivable(receivable);
|
||||
item.setWarehousePayable(payable);
|
||||
item.setStatus("ACTIVE");
|
||||
return item;
|
||||
}
|
||||
|
||||
private static InboundOrderEntity inbound() {
|
||||
InboundOrderEntity inbound = new InboundOrderEntity();
|
||||
inbound.setId(21L);
|
||||
inbound.setInboundCode("RK-20260805-001");
|
||||
inbound.setChannelCode("SEA");
|
||||
inbound.setChannelName("海运");
|
||||
inbound.setDestinationCode("ONT8");
|
||||
inbound.setDestinationName("ONT8");
|
||||
inbound.setTotalPackageCount(10);
|
||||
inbound.setActualGrossWeightKg(new BigDecimal("10.5000"));
|
||||
inbound.setActualVolumeCbm(new BigDecimal("1.250000"));
|
||||
inbound.setVolumeWeightKg(new BigDecimal("208.3333"));
|
||||
inbound.setChargeableWeightKg(new BigDecimal("208.3333"));
|
||||
inbound.setChargeableVolumeCbm(new BigDecimal("1.250000"));
|
||||
return inbound;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user