修改提交
This commit is contained in:
@@ -9,6 +9,8 @@ import com.baiyue.firstleg.entity.InboundFeeEntity;
|
||||
import com.baiyue.firstleg.entity.InboundFeeItemEntity;
|
||||
import com.baiyue.firstleg.entity.InboundPricingEntity;
|
||||
import com.baiyue.firstleg.entity.InboundPricingIdempotencyEntity;
|
||||
import com.baiyue.firstleg.entity.InboundMeasurementEntity;
|
||||
import com.baiyue.firstleg.entity.InboundMeasurementItemEntity;
|
||||
import com.baiyue.firstleg.pricing.ActivePriceBookEstimator;
|
||||
import com.baiyue.firstleg.repository.FbaPricingRepository;
|
||||
import com.baiyue.firstleg.pricebookquery.application.model.PriceBookQueryRows.RateRow;
|
||||
@@ -27,6 +29,7 @@ import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
@@ -49,6 +52,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 com.baiyue.firstleg.repository.InboundMeasurementRepository measurementRepository;
|
||||
@MockBean private InboundFeeDetailService feeDetails;
|
||||
@MockBean private ActivePriceBookEstimator priceBookEstimator;
|
||||
@Resource private FbaPricingService service;
|
||||
@@ -100,6 +104,35 @@ class FbaPricingServiceTest {
|
||||
assertThat(fee.getValue().getRoundingMode()).isEqualTo("HALF_UP");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("外箱规计费保存测量批次和尺寸来源快照")
|
||||
void bindsSavedOuterMeasurementWhenCalculatingCustomerFee() {
|
||||
readyRepository();
|
||||
InboundPricingEntity inbound = inbound("62.500", "1.0019");
|
||||
InboundMeasurementEntity measurement = new InboundMeasurementEntity();
|
||||
measurement.setId(301L);
|
||||
InboundMeasurementItemEntity item = new InboundMeasurementItemEntity();
|
||||
item.setOuterLengthCm(new BigDecimal("34"));
|
||||
item.setOuterWidthCm(new BigDecimal("24"));
|
||||
item.setOuterHeightCm(new BigDecimal("64"));
|
||||
item.setCalculationRuleVersion("CUSTOMER_DIMENSION_SMALL_V3");
|
||||
when(repository.findInbound(TENANT, INBOUND)).thenReturn(inbound);
|
||||
when(measurementRepository.findLatestMeasurement(TENANT, INBOUND)).thenReturn(measurement);
|
||||
when(measurementRepository.listItems(TENANT, 301L)).thenReturn(List.of(item));
|
||||
when(priceBookEstimator.estimate(any())).thenReturn(
|
||||
estimate("CBM", "1.0019", "100", "100.19", "0"));
|
||||
|
||||
service.calculate(TENANT, OPERATOR, INBOUND, NOW,
|
||||
new BigDecimal("62.500"), new BigDecimal("1.0019"),
|
||||
"OUTER", "OUTER", "calc-outer");
|
||||
|
||||
ArgumentCaptor<InboundFeeEntity> fee = ArgumentCaptor.forClass(InboundFeeEntity.class);
|
||||
verify(repository).insertFee(fee.capture());
|
||||
assertThat(fee.getValue().getMeasurementId()).isEqualTo(301L);
|
||||
assertThat(fee.getValue().getMeasurementSource()).isEqualTo("OUTER");
|
||||
assertThat(fee.getValue().getActualVolumeCbm()).isEqualByComparingTo("1.0019");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("缺少订单客户归属时拒绝生成对客费用")
|
||||
void rejectsMissingOrderCustomerOwnership() {
|
||||
@@ -182,44 +215,31 @@ class FbaPricingServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("装柜完成后的自动费用仍可确认")
|
||||
void confirmsCalculatedFeeAfterLoadingCompleted() {
|
||||
@DisplayName("装柜完成后禁止确认费用")
|
||||
void rejectsConfirmAfterLoadingCompleted() {
|
||||
InboundPricingEntity inbound = inbound("10.000", "1.0000");
|
||||
inbound.setProcessStatus("LOADED");
|
||||
inbound.setFeeStatus("CALCULATED");
|
||||
InboundFeeEntity fee = savedFee("CALCULATED");
|
||||
when(repository.findLatestFee(TENANT, INBOUND)).thenReturn(fee);
|
||||
when(repository.findIdempotency(TENANT, OPERATOR, "FEE_CONFIRM", "confirm-loaded"))
|
||||
.thenReturn(null);
|
||||
doAnswer(invocation -> {
|
||||
((InboundPricingIdempotencyEntity) invocation.getArgument(0)).setId(900L);
|
||||
return null;
|
||||
}).when(repository).insertIdempotency(any());
|
||||
when(repository.confirmFee(TENANT, 501L, OPERATOR, NOW)).thenReturn(1);
|
||||
when(repository.markInboundConfirmed(TENANT, INBOUND)).thenReturn(1);
|
||||
when(repository.completeIdempotency(any(), eq(501L), eq(NOW))).thenReturn(1);
|
||||
when(repository.findFee(TENANT, 501L)).thenReturn(fee);
|
||||
when(repository.findInbound(TENANT, INBOUND)).thenReturn(inbound);
|
||||
|
||||
FeeSnapshotResponse response = service.confirm(
|
||||
TENANT, OPERATOR, INBOUND, "confirm-loaded");
|
||||
|
||||
assertThat(response.nextProcessStatus()).isEqualTo("LOADED");
|
||||
verify(repository).markInboundConfirmed(TENANT, INBOUND);
|
||||
assertThatThrownBy(() -> service.confirm(TENANT, OPERATOR, INBOUND, "confirm-loaded"))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessageContaining("装柜流程");
|
||||
verify(repository, never()).markInboundConfirmed(TENANT, INBOUND);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("审核未通过的测量快照禁止计费")
|
||||
void rejectsUnapprovedMeasurementSnapshot() {
|
||||
@DisplayName("审核未通过的测量快照也允许计费")
|
||||
void allowsUnapprovedMeasurementSnapshot() {
|
||||
readyRepository();
|
||||
InboundPricingEntity inbound = inbound("10", "1");
|
||||
inbound.setMeasureReviewStatus("REJECTED");
|
||||
when(repository.findInbound(TENANT, INBOUND)).thenReturn(inbound);
|
||||
when(priceBookEstimator.estimate(any())).thenReturn(
|
||||
estimate("CBM", "1.0000", "10", "10", "0"));
|
||||
|
||||
assertThatThrownBy(() -> service.calculate(TENANT, OPERATOR, INBOUND, NOW, "calc-3"))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessageContaining("审核通过");
|
||||
verify(priceBookEstimator, never()).estimate(any());
|
||||
assertThat(service.calculate(TENANT, OPERATOR, INBOUND, NOW, "calc-3")).isNotNull();
|
||||
verify(priceBookEstimator).estimate(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -368,6 +388,55 @@ class FbaPricingServiceTest {
|
||||
eq(TENANT), eq(INBOUND), eq(502L), eq(2), eq(NOW));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("客户确认已发送费用后记录确认人并锁定版本")
|
||||
void customerConfirmsSentFeeAndLocksVersion() {
|
||||
InboundFeeEntity current = savedFee("SENT");
|
||||
when(repository.findLatestFee(TENANT, INBOUND)).thenReturn(current);
|
||||
when(repository.findIdempotency(TENANT, OPERATOR, "CUSTOMER_FEE_CONFIRM", "customer-confirm-1"))
|
||||
.thenReturn(null);
|
||||
doAnswer(invocation -> { ((InboundPricingIdempotencyEntity) invocation.getArgument(0)).setId(910L); return null; })
|
||||
.when(repository).insertIdempotency(any());
|
||||
when(repository.confirmFeeByCustomer(TENANT, 501L, 1, OPERATOR, "客户成员", NOW))
|
||||
.thenAnswer(invocation -> {
|
||||
current.setCustomerConfirmedBy(OPERATOR);
|
||||
current.setCustomerConfirmedByName("客户成员");
|
||||
current.setCustomerConfirmedAt(NOW);
|
||||
return 1;
|
||||
});
|
||||
when(repository.completeIdempotency(any(), eq(501L), eq(NOW))).thenReturn(1);
|
||||
when(repository.findFee(TENANT, 501L)).thenReturn(current);
|
||||
|
||||
FeeSnapshotResponse response = service.confirmByCustomer(
|
||||
TENANT, OPERATOR, "客户成员", INBOUND, 1, "customer-confirm-1");
|
||||
|
||||
assertThat(response.customerConfirmationStatus()).isEqualTo("CONFIRMED");
|
||||
assertThat(response.customerConfirmedBy()).isEqualTo(OPERATOR);
|
||||
assertThat(response.customerConfirmedByName()).isEqualTo("客户成员");
|
||||
assertThat(response.customerConfirmedAt()).isEqualTo(NOW);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("客户已确认费用时拒绝平台再次修改")
|
||||
void rejectsAdjustmentAfterCustomerConfirmation() {
|
||||
InboundPricingEntity inbound = inbound("10", "1");
|
||||
inbound.setProcessStatus("WAIT_SPLIT");
|
||||
InboundFeeEntity current = savedFee("SENT");
|
||||
current.setCustomerConfirmedAt(NOW);
|
||||
when(repository.findInbound(TENANT, INBOUND)).thenReturn(inbound);
|
||||
when(repository.findLatestFee(TENANT, INBOUND)).thenReturn(current);
|
||||
|
||||
assertThatThrownBy(() -> service.adjustPublished(TENANT, OPERATOR, INBOUND,
|
||||
new com.baiyue.firstleg.dto.FbaPricingDtos.AdjustFeeRequest(
|
||||
1, new BigDecimal("12.5"), new BigDecimal("8.00"),
|
||||
BigDecimal.ZERO, "客服修正"), "locked-adjust"))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessageContaining("客户已确认");
|
||||
|
||||
verify(repository, never()).insertIdempotency(any());
|
||||
verify(repository, never()).supersedeCurrent(anyLong(), anyLong(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("初算费用调整后保持初算状态且不发布财务来源")
|
||||
void adjustsCalculatedFeeWithoutPublishingIt() {
|
||||
|
||||
Reference in New Issue
Block a user