修正外箱快照清空并提供当前计费量只读预览
This commit is contained in:
@@ -6,6 +6,7 @@ import com.baiyue.firstleg.domain.PriceModel;
|
||||
import com.baiyue.firstleg.domain.PricingTaxMode;
|
||||
import com.baiyue.firstleg.dto.FbaPricingDtos.FeeSnapshotResponse;
|
||||
import com.baiyue.firstleg.dto.FbaPricingDtos.ManualQuoteRequest;
|
||||
import com.baiyue.firstleg.dto.FbaPricingDtos.FeePreviewRequest;
|
||||
import com.baiyue.firstleg.entity.CarrierFbaRateEntity;
|
||||
import com.baiyue.firstleg.entity.InboundFeeEntity;
|
||||
import com.baiyue.firstleg.entity.InboundFeeItemEntity;
|
||||
@@ -70,6 +71,87 @@ class FbaPricingServiceTest {
|
||||
@MockBean private ContainerTierAmountAllocator containerTierAllocator;
|
||||
@Resource private FbaPricingService service;
|
||||
|
||||
@Test
|
||||
/** 预览只按当前选择值估价,不复用旧费用,也不产生任何计费写入。 */
|
||||
void previewsSelectedOuterVolumeWithoutWritingFeeState() {
|
||||
when(repository.findInbound(TENANT, INBOUND)).thenReturn(inbound("570.500", "3.6894"));
|
||||
InboundMeasurementEntity measurement = new InboundMeasurementEntity();
|
||||
measurement.setId(901L);
|
||||
InboundMeasurementItemEntity item = new InboundMeasurementItemEntity();
|
||||
item.setOuterLengthCm(new BigDecimal("63"));
|
||||
item.setOuterWidthCm(new BigDecimal("53"));
|
||||
item.setOuterHeightCm(new BigDecimal("53"));
|
||||
item.setCalculationRuleVersion("WAREHOUSE_OUTER_OVERRIDE_V1");
|
||||
when(measurementRepository.findLatestMeasurement(TENANT, INBOUND)).thenReturn(measurement);
|
||||
when(measurementRepository.listItems(TENANT, 901L)).thenReturn(List.of(item));
|
||||
when(priceBookEstimator.estimate(anyLong(), any())).thenReturn(
|
||||
estimate("KG", "650.298000", "13.6", "8844.05", "0"));
|
||||
|
||||
var preview = service.preview(TENANT, INBOUND, new FeePreviewRequest(NOW,
|
||||
new BigDecimal("570.500"), new BigDecimal("3.8940"), "ACTUAL", "OUTER", null));
|
||||
|
||||
assertThat(preview.actualVolumeCbm()).isEqualByComparingTo("3.8940");
|
||||
assertThat(preview.chargeableQuantity()).isEqualByComparingTo("650.298000");
|
||||
assertThat(preview.totalAmount()).isEqualByComparingTo("8844.05");
|
||||
assertThat(preview.priceMatched()).isTrue();
|
||||
verify(priceBookEstimator).estimate(eq(TENANT), argThat(request ->
|
||||
request.actualWeightKg().compareTo(new BigDecimal("570.5")) == 0
|
||||
&& request.actualVolumeCbm().compareTo(new BigDecimal("3.894")) == 0));
|
||||
verify(repository, never()).insertFee(any());
|
||||
verify(repository, never()).insertIdempotency(any());
|
||||
verify(repository, never()).nextFeeVersion(anyLong(), anyLong());
|
||||
verify(repository, never()).markInboundCalculated(anyLong(), anyLong(), any(), any(), any(), any(), any());
|
||||
org.mockito.Mockito.verifyNoInteractions(financeOutbox, feeDetails);
|
||||
}
|
||||
|
||||
@Test
|
||||
/** FBA 未命中价格时仍返回服务端计费量,供人工单价预览使用。 */
|
||||
void previewsManualQuantityWhenPriceIsMissing() {
|
||||
when(repository.findInbound(TENANT, INBOUND)).thenReturn(inbound("570.500", "3.6894"));
|
||||
when(priceBookEstimator.estimate(anyLong(), any()))
|
||||
.thenThrow(new BizException(ResultCode.NOT_FOUND, "价格未命中"));
|
||||
|
||||
var preview = service.preview(TENANT, INBOUND, new FeePreviewRequest(NOW,
|
||||
new BigDecimal("570.5"), new BigDecimal("3.894"), null, null, null));
|
||||
|
||||
assertThat(preview.priceMatched()).isFalse();
|
||||
assertThat(preview.unitPrice()).isNull();
|
||||
assertThat(preview.chargeableQuantity()).isEqualByComparingTo("650.298000");
|
||||
assertThat(preview.additionalAmount()).isZero();
|
||||
assertThat(preview.totalAmount()).isNull();
|
||||
verify(repository, never()).insertFee(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
/** 外箱快照缺失时拒绝预览,不把当前规则的前端推导结果视作已保存事实。 */
|
||||
void rejectsOuterPreviewWithoutSavedMeasurementSnapshot() {
|
||||
when(repository.findInbound(TENANT, INBOUND)).thenReturn(inbound("100", "1"));
|
||||
assertThatThrownBy(() -> service.preview(TENANT, INBOUND,
|
||||
new FeePreviewRequest(NOW, new BigDecimal("100"), BigDecimal.ONE, "ACTUAL", "OUTER", null)))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("测量数据不存在");
|
||||
org.mockito.Mockito.verifyNoInteractions(priceBookEstimator, financeOutbox, feeDetails);
|
||||
}
|
||||
|
||||
@Test
|
||||
/** 预览不能读取其他客户的入库单。 */
|
||||
void rejectsCrossCustomerPreview() {
|
||||
assertThatThrownBy(() -> service.preview(10002L, INBOUND, new FeePreviewRequest(NOW, null, null, null, null, null)))
|
||||
.isInstanceOf(BizException.class).hasMessageContaining("入库单不存在");
|
||||
org.mockito.Mockito.verifyNoInteractions(priceBookEstimator, financeOutbox, feeDetails);
|
||||
}
|
||||
|
||||
@Test
|
||||
/** 人工单价的金额也由服务端精确取整,不在页面重复实现舍入。 */
|
||||
void previewsManualUnitPriceUsingExactMoneyRounding() {
|
||||
when(repository.findInbound(TENANT, INBOUND)).thenReturn(inbound("1", "0.001"));
|
||||
when(priceBookEstimator.estimate(anyLong(), any())).thenReturn(estimate("KG", "1", "2", "2", "0"));
|
||||
var preview = service.preview(TENANT, INBOUND, new FeePreviewRequest(NOW,
|
||||
BigDecimal.ONE, new BigDecimal("0.001"), null, null, new BigDecimal("1.005")));
|
||||
assertThat(preview.unitPrice()).isEqualByComparingTo("2");
|
||||
assertThat(preview.totalAmount()).isEqualByComparingTo("1.01");
|
||||
verify(repository, never()).insertFee(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("客户B不能读取客户A的费用快照")
|
||||
void rejectsCrossCustomerFeeLookup() {
|
||||
|
||||
Reference in New Issue
Block a user