Files
baiyue-firstleg/firstleg/src/test/java/com/baiyue/firstleg/service/ContainerFeeDetailServiceTest.java
T
2026-08-12 16:58:45 +08:00

148 lines
6.2 KiB
Java

package com.baiyue.firstleg.service;
import com.baiyue.common.core.exception.BizException;
import com.baiyue.firstleg.dto.ContainerFeeDetailDtos;
import com.baiyue.firstleg.entity.ContainerFeeDetailEntity;
import com.baiyue.firstleg.entity.FeeItemEntity;
import com.baiyue.firstleg.entity.LoadingPlanEntity;
import com.baiyue.firstleg.entity.LoadingPlanItemEntity;
import com.baiyue.firstleg.repository.ContainerFeeDetailRepository;
import com.baiyue.firstleg.repository.FeeItemRepository;
import com.baiyue.firstleg.repository.SmartLoadingRepository;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
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.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
class ContainerFeeDetailServiceTest {
private final ContainerFeeDetailRepository repository = mock(ContainerFeeDetailRepository.class);
private final SmartLoadingRepository loading = mock(SmartLoadingRepository.class);
private final FeeItemRepository feeItems = mock(FeeItemRepository.class);
private final FinanceFeeSourceOutboxService outbox = mock(FinanceFeeSourceOutboxService.class);
private final ContainerFeeDetailService service =
new ContainerFeeDetailService(repository, loading, feeItems, outbox);
@Test
void rejectsContainerThatDoesNotContainCustomerOrders() {
LoadingPlanEntity plan = new LoadingPlanEntity();
plan.setId(41L);
when(loading.plan(41L)).thenReturn(plan);
LoadingPlanItemEntity other = new LoadingPlanItemEntity();
other.setAccountId(20002L);
when(loading.items(41L)).thenReturn(List.of(other));
assertThatThrownBy(() -> service.create(10001L, 41L, 9L, request(true)))
.isInstanceOf(BizException.class).hasMessageContaining("不属于该客户");
verify(repository, never()).insert(any());
}
@Test
void approvedSettlementFeePublishesContainerSource() {
ownedPlan();
ContainerFeeDetailEntity approved = new ContainerFeeDetailEntity();
approved.setId(51L);
approved.setTenantId(10001L);
approved.setLoadingPlanId(41L);
approved.setSourceVersion(1);
approved.setSettlementIncluded(true);
when(repository.find(10001L, 41L, 51L)).thenReturn(approved);
when(repository.review(10001L, 41L, 51L, "APPROVED", 9L, "admin", null)).thenReturn(1);
service.approve(10001L, 41L, 51L, 9L, "admin");
verify(outbox).publishContainer(eq(FinanceFeeSourceOutboxService.PUBLISHED),
eq(10001L), eq(41L), eq(51L), eq(1), any(LocalDateTime.class));
}
@Test
void adjustmentIncrementsSourceVersionAndReturnsToReview() {
ownedPlan();
FeeItemEntity item = item();
when(feeItems.findItem(11L)).thenReturn(item);
ContainerFeeDetailEntity current = new ContainerFeeDetailEntity();
current.setId(51L);
current.setTenantId(10001L);
current.setLoadingPlanId(41L);
current.setSourceVersion(1);
when(repository.find(10001L, 41L, 51L)).thenReturn(current);
when(repository.adjust(any(), eq(1))).thenReturn(1);
service.adjust(10001L, 41L, 51L, 1, 9L, request(true));
ArgumentCaptor<ContainerFeeDetailEntity> captor = ArgumentCaptor.forClass(ContainerFeeDetailEntity.class);
verify(repository).adjust(captor.capture(), eq(1));
assertThat(captor.getValue().getSourceVersion()).isEqualTo(2);
assertThat(captor.getValue().getReviewStatus()).isEqualTo("PENDING");
assertThat(captor.getValue().getPartnerId()).isEqualTo(71L);
assertThat(captor.getValue().getPartnerName()).isEqualTo("现有往来单位");
}
@Test
void payableRequiresCounterpartySnapshot() {
ownedPlan();
when(feeItems.findItem(11L)).thenReturn(item());
var missingPartner = new ContainerFeeDetailDtos.SaveRequest(11L, "PAYABLE",
LocalDate.of(2026, 8, 11), new BigDecimal("300.00"), "CNY",
true, null, null, "整柜拖车费");
assertThatThrownBy(() -> service.create(10001L, 41L, 9L, missingPartner))
.isInstanceOf(BizException.class).hasMessageContaining("必须选择有效往来单位");
verify(repository, never()).insert(any());
}
@Test
void receivableClearsCounterpartyFields() {
ownedPlan();
when(feeItems.findItem(11L)).thenReturn(item());
var request = new ContainerFeeDetailDtos.SaveRequest(11L, "RECEIVABLE",
LocalDate.of(2026, 8, 11), new BigDecimal("300.00"), "CNY",
true, 71L, "不应保留", "整柜操作费");
service.create(10001L, 41L, 9L, request);
ArgumentCaptor<ContainerFeeDetailEntity> captor = ArgumentCaptor.forClass(ContainerFeeDetailEntity.class);
verify(repository).insert(captor.capture());
assertThat(captor.getValue().getPartnerId()).isNull();
assertThat(captor.getValue().getPartnerName()).isNull();
}
private void ownedPlan() {
LoadingPlanEntity plan = new LoadingPlanEntity();
plan.setId(41L);
when(loading.plan(41L)).thenReturn(plan);
LoadingPlanItemEntity item = new LoadingPlanItemEntity();
item.setAccountId(10001L);
when(loading.items(41L)).thenReturn(List.of(item));
}
private static FeeItemEntity item() {
FeeItemEntity value = new FeeItemEntity();
value.setId(11L);
value.setFeeCode("TRUCKING");
value.setFeeTypeName("拖车费");
value.setWarehouseReceivable(true);
value.setWarehousePayable(true);
value.setStatus("ACTIVE");
return value;
}
private static ContainerFeeDetailDtos.SaveRequest request(boolean settlementIncluded) {
return new ContainerFeeDetailDtos.SaveRequest(11L, "PAYABLE",
LocalDate.of(2026, 8, 11), new BigDecimal("300.00"), "CNY",
settlementIncluded, 71L, " 现有往来单位 ", "整柜拖车费");
}
}