客户运费计费
This commit is contained in:
@@ -47,6 +47,7 @@ class FbaPricingServiceTest {
|
||||
private static final long INBOUND = 30001L;
|
||||
private static final LocalDateTime NOW = LocalDateTime.of(2026, 8, 3, 10, 0);
|
||||
@MockBean private FbaPricingRepository repository;
|
||||
@MockBean private InboundFeeDetailService feeDetails;
|
||||
@Resource private FbaPricingService service;
|
||||
|
||||
@Test
|
||||
@@ -172,6 +173,7 @@ class FbaPricingServiceTest {
|
||||
|
||||
verify(repository, times(1)).insertOutbox(any());
|
||||
verify(repository, times(1)).sendFee(TENANT, 501L, OPERATOR, NOW);
|
||||
verify(feeDetails, times(2)).publishFreight(TENANT, INBOUND, 501L, OPERATOR, null, NOW);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -6,22 +6,29 @@ 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.InboundFeeEntity;
|
||||
import com.baiyue.firstleg.entity.InboundFeeItemEntity;
|
||||
import com.baiyue.firstleg.entity.InboundOrderEntity;
|
||||
import com.baiyue.firstleg.repository.FeeItemRepository;
|
||||
import com.baiyue.firstleg.repository.FbaPricingRepository;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
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.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.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
@@ -31,6 +38,8 @@ import static org.mockito.Mockito.when;
|
||||
class FeeManagementServiceTest {
|
||||
@MockBean
|
||||
private FeeItemRepository repository;
|
||||
@MockBean
|
||||
private FbaPricingRepository pricingRepository;
|
||||
@Resource
|
||||
private FeeItemService feeItems;
|
||||
@Resource
|
||||
@@ -96,6 +105,92 @@ class FeeManagementServiceTest {
|
||||
assertThat(created.getReviewStatus()).isEqualTo("PENDING");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("发布计费快照生成客户与后台共用的入库运费明细")
|
||||
void publishesSharedFreightDetail() {
|
||||
InboundOrderEntity inbound = inbound();
|
||||
inbound.setCustomerId(101L);
|
||||
inbound.setCustomerName("客户A");
|
||||
inbound.setCompanyName("客户A有限公司");
|
||||
when(repository.findInbound(10001L, 21L)).thenReturn(inbound);
|
||||
when(repository.findBySourceFee(10001L, "FBA_PRICING", 501L)).thenReturn(null);
|
||||
when(repository.findItemByCode(10001L, "FBA_HEAD_FREIGHT")).thenReturn(null);
|
||||
doAnswer(invocation -> {
|
||||
FeeItemEntity value = invocation.getArgument(0);
|
||||
value.setId(11L);
|
||||
return null;
|
||||
}).when(repository).insertItem(any());
|
||||
|
||||
InboundFeeEntity fee = new InboundFeeEntity();
|
||||
fee.setId(501L);
|
||||
fee.setInboundId(21L);
|
||||
fee.setFeeNo("FBAF-21-1");
|
||||
fee.setFeeVersion(1);
|
||||
fee.setFeeStatus("SENT");
|
||||
fee.setActualWeightKg(new BigDecimal("100.0000"));
|
||||
fee.setActualVolumeCbm(new BigDecimal("1.000000"));
|
||||
fee.setChargeableQuantity(new BigDecimal("167.0000"));
|
||||
fee.setChargeUnit("KG");
|
||||
fee.setCurrency("USD");
|
||||
fee.setTotalAmount(new BigDecimal("354.00"));
|
||||
when(pricingRepository.findFee(10001L, 501L)).thenReturn(fee);
|
||||
InboundFeeItemEntity base = new InboundFeeItemEntity();
|
||||
base.setUnitPrice(new BigDecimal("2.0000"));
|
||||
when(pricingRepository.findBaseItem(10001L, 501L)).thenReturn(base);
|
||||
|
||||
LocalDateTime publishedAt = LocalDateTime.of(2026, 8, 5, 12, 0);
|
||||
InboundFeeDetailEntity result = details.publishFreight(
|
||||
10001L, 21L, 501L, 9L, "admin", publishedAt);
|
||||
|
||||
ArgumentCaptor<InboundFeeDetailEntity> captor = ArgumentCaptor.forClass(InboundFeeDetailEntity.class);
|
||||
verify(repository).insertDetail(captor.capture());
|
||||
InboundFeeDetailEntity saved = captor.getValue();
|
||||
assertThat(result).isSameAs(saved);
|
||||
assertThat(saved.getFeeItemId()).isEqualTo(11L);
|
||||
assertThat(saved.getSourceFeeId()).isEqualTo(501L);
|
||||
assertThat(saved.getDirection()).isEqualTo("RECEIVABLE");
|
||||
assertThat(saved.getAmount()).isEqualByComparingTo("354.00");
|
||||
assertThat(saved.getUnitPrice()).isEqualByComparingTo("2.1198");
|
||||
assertThat(saved.getReviewStatus()).isEqualTo("APPROVED");
|
||||
assertThat(saved.getPublicationStatus()).isEqualTo("PUBLISHED");
|
||||
assertThat(saved.getSettlementIncluded()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("并发发布同一计费快照时返回已生成的运费明细")
|
||||
void reusesConcurrentFreightDetail() {
|
||||
InboundFeeDetailEntity concurrent = new InboundFeeDetailEntity();
|
||||
concurrent.setId(99L);
|
||||
when(repository.findBySourceFee(10001L, "FBA_PRICING", 501L))
|
||||
.thenReturn(null, concurrent);
|
||||
when(repository.findInbound(10001L, 21L)).thenReturn(inbound());
|
||||
|
||||
FeeItemEntity freightItem = item(true, false);
|
||||
freightItem.setFeeCode("FBA_HEAD_FREIGHT");
|
||||
when(repository.findItemByCode(10001L, "FBA_HEAD_FREIGHT")).thenReturn(freightItem);
|
||||
|
||||
InboundFeeEntity fee = new InboundFeeEntity();
|
||||
fee.setId(501L);
|
||||
fee.setInboundId(21L);
|
||||
fee.setFeeNo("FBAF-21-1");
|
||||
fee.setFeeVersion(1);
|
||||
fee.setFeeStatus("SENT");
|
||||
fee.setActualWeightKg(new BigDecimal("100.0000"));
|
||||
fee.setActualVolumeCbm(new BigDecimal("1.000000"));
|
||||
fee.setChargeableQuantity(new BigDecimal("1.0000"));
|
||||
fee.setChargeUnit("CBM");
|
||||
fee.setCurrency("USD");
|
||||
fee.setTotalAmount(new BigDecimal("200.00"));
|
||||
when(pricingRepository.findFee(10001L, 501L)).thenReturn(fee);
|
||||
doThrow(new DuplicateKeyException("duplicate source fee"))
|
||||
.when(repository).insertDetail(any());
|
||||
|
||||
InboundFeeDetailEntity result = details.publishFreight(
|
||||
10001L, 21L, 501L, 9L, "admin", LocalDateTime.of(2026, 8, 5, 12, 0));
|
||||
|
||||
assertThat(result).isSameAs(concurrent);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("拒绝绑定未启用仓储应收的项目")
|
||||
void rejectsInapplicableItem() {
|
||||
|
||||
+5
@@ -16,6 +16,7 @@ import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
@@ -28,6 +29,8 @@ class InboundCompletionOrchestratorTest {
|
||||
private InboundWorkflowRepository repository;
|
||||
@MockBean
|
||||
private InboundIdempotencyService idempotency;
|
||||
@MockBean
|
||||
private InboundFeeDetailService feeDetails;
|
||||
@Resource
|
||||
private InboundCompletionOrchestrator service;
|
||||
@Test
|
||||
@@ -81,6 +84,8 @@ class InboundCompletionOrchestratorTest {
|
||||
|
||||
verify(fixture.repository).completeInbound(10001L, 10L, 9L, 5);
|
||||
verify(fixture.repository).markFeeSent(10001L, 10L, 30L, 9L);
|
||||
verify(feeDetails).publishFreight(eq(10001L), eq(10L), eq(30L), eq(9L), eq("操作员"),
|
||||
org.mockito.ArgumentMatchers.any(java.time.LocalDateTime.class));
|
||||
verify(fixture.repository).insertOutbox(any());
|
||||
}
|
||||
|
||||
|
||||
+13
@@ -6,6 +6,7 @@ import com.baiyue.firstleg.dto.InboundOrderDetail;
|
||||
import com.baiyue.firstleg.dto.InboundMeasurementResponses;
|
||||
import com.baiyue.firstleg.client.MeasurementImageClient;
|
||||
import com.baiyue.firstleg.entity.InboundOrderEntity;
|
||||
import com.baiyue.firstleg.entity.InboundFeeDetailEntity;
|
||||
import com.baiyue.firstleg.repository.InboundOrderRepository;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -30,6 +31,7 @@ class MerchantInboundBillingServiceTest {
|
||||
@MockBean private FbaPricingService pricing;
|
||||
@MockBean private InboundMeasurementService measurements;
|
||||
@MockBean private MeasurementImageClient imageClient;
|
||||
@MockBean private InboundFeeDetailService feeDetails;
|
||||
@Resource private MerchantInboundBillingService service;
|
||||
|
||||
@Test
|
||||
@@ -50,6 +52,15 @@ class MerchantInboundBillingServiceTest {
|
||||
when(measurement.items()).thenReturn(List.of());
|
||||
when(measurement.weightResults()).thenReturn(List.of());
|
||||
when(pricing.latest(10001L, 88L)).thenReturn(fee);
|
||||
InboundFeeDetailEntity published = new InboundFeeDetailEntity();
|
||||
published.setId(601L);
|
||||
published.setInboundId(88L);
|
||||
published.setSourceFeeId(501L);
|
||||
published.setSourceFeeVersion(1);
|
||||
published.setFeeTypeNameSnapshot("FBA头程运费");
|
||||
published.setAmount(new BigDecimal("334.00"));
|
||||
published.setPublicationStatus("PUBLISHED");
|
||||
when(feeDetails.publishedFreight(10001L, 88L)).thenReturn(published);
|
||||
when(fee.chargeMode()).thenReturn("KG");
|
||||
when(fee.chargeUnit()).thenReturn("KG");
|
||||
when(fee.actualWeightKg()).thenReturn(new BigDecimal("20"));
|
||||
@@ -65,6 +76,8 @@ class MerchantInboundBillingServiceTest {
|
||||
assertThat(result.inbound().statusHistory()).isEmpty();
|
||||
assertThat(result.billingBasis().chargeableBasis()).isEqualTo("VOLUME_WEIGHT");
|
||||
assertThat(result.latestFee()).isSameAs(fee);
|
||||
assertThat(result.publishedFeeDetail().id()).isEqualTo(601L);
|
||||
assertThat(result.publishedFeeDetail().amount()).isEqualByComparingTo("334.00");
|
||||
verify(orders).findByOrderId(10001L, 77L);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user