优化
This commit is contained in:
@@ -25,6 +25,7 @@ public final class ContainerDtos {
|
||||
@Size(max = 64) String cabinetNo,
|
||||
@Size(max = 128) String billOfLadingNo,
|
||||
@Size(max = 128) String keyword,
|
||||
@Positive Long customerId,
|
||||
@Positive Long warehouseId,
|
||||
@Size(max = 32) String containerType,
|
||||
@Positive Long shippingCompanyId,
|
||||
|
||||
@@ -18,6 +18,7 @@ public final class LoadingListDtos {
|
||||
public record PreloadQuery(
|
||||
@Size(max = 128) String keyword,
|
||||
String status,
|
||||
@Positive Long customerId,
|
||||
@Min(1) Long warehouseId,
|
||||
LocalDateTime createdFrom,
|
||||
LocalDateTime createdTo,
|
||||
@@ -32,6 +33,7 @@ public final class LoadingListDtos {
|
||||
|
||||
public record ConfirmedQuery(
|
||||
@Size(max = 128) String keyword,
|
||||
@Positive Long customerId,
|
||||
@Min(1) Long warehouseId,
|
||||
LocalDateTime createdFrom,
|
||||
LocalDateTime createdTo,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.baiyue.firstleg.dto;
|
||||
import jakarta.validation.constraints.*; import java.math.BigDecimal; import java.time.LocalDateTime;
|
||||
public final class TruckAppointmentDtos { private TruckAppointmentDtos(){}
|
||||
public record Query(@Size(max=64) String keyword, com.baiyue.firstleg.domain.TruckAppointmentStatus status, @Positive Long containerBookingId, @Min(1) long page, @Min(1) @Max(200) long size){ public Query{if(page==0)page=1;if(size==0)size=20;} }
|
||||
public record Query(@Size(max=64) String keyword, com.baiyue.firstleg.domain.TruckAppointmentStatus status, @Positive Long customerId, @Positive Long containerBookingId, @Min(1) long page, @Min(1) @Max(200) long size){ public Query{if(page==0)page=1;if(size==0)size=20;} }
|
||||
public record SaveRequest(@Positive Long outboundOrderId,@Positive Long oceanBookingId,@Positive Long containerBookingId,@Positive Long loadingPlanId,@Positive Long warehouseId,@Positive Long customerId,@Size(max=128) String customerName,@Positive Long carrierId,@Size(max=128) String carrierName,@Size(max=64) String fleetContact,@Size(max=32) String fleetPhone,@Size(max=64) String driverName,@Size(max=32) String driverPhone,@Size(max=32) String driverIdCard,@Size(max=32) String vehicleNo,@Size(max=128) String storeName,@Size(max=64) String storeContact,@Size(max=32) String storePhone,@Size(max=255) String storeAddress,@Size(max=64) String storeCity,@Size(max=16) String storeZipcode,@PositiveOrZero Integer packageCount,@DecimalMin("0") BigDecimal grossWeightKg,@DecimalMin("0") BigDecimal volumeCbm,@PositiveOrZero Integer palletCount,@Size(max=255) String poNo,@NotNull LocalDateTime plannedLoadingAt,@PositiveOrZero Integer transitMinutes,@DecimalMin("0") BigDecimal payableAmount,@DecimalMin("0") BigDecimal receivableAmount,@Size(max=8) String currency,@Size(max=1000) String remark,@NotNull @PositiveOrZero Integer expectedVersion){}
|
||||
public record ActionRequest(@NotNull @PositiveOrZero Integer expectedVersion,@Size(max=500) String reason){}
|
||||
public record AttachmentRequest(@NotNull @Positive Long fileId,@Size(max=64) String attachmentType,@Size(max=255) String fileName,@Size(max=128) String fileHash){ }
|
||||
|
||||
@@ -24,6 +24,12 @@ public interface ContainerBookingMapper extends BaseMapper<ContainerBookingEntit
|
||||
WHERE (#{query.containerNo} IS NULL OR b.container_no = #{query.containerNo})
|
||||
AND (#{query.cabinetNo} IS NULL OR b.cabinet_no = #{query.cabinetNo})
|
||||
AND (#{query.billOfLadingNo} IS NULL OR b.bill_of_lading_no = #{query.billOfLadingNo})
|
||||
AND (#{query.customerId} IS NULL OR EXISTS (
|
||||
SELECT 1 FROM fl_loading_plan_item customer_item
|
||||
WHERE customer_item.loading_plan_id = p.id
|
||||
AND customer_item.deleted = 0
|
||||
AND customer_item.account_id = #{query.customerId}
|
||||
))
|
||||
AND (#{query.warehouseId} IS NULL OR b.warehouse_id = #{query.warehouseId})
|
||||
AND (#{query.containerType} IS NULL OR b.container_type = #{query.containerType})
|
||||
AND (#{query.shippingCompanyId} IS NULL OR b.shipping_company_id = #{query.shippingCompanyId})
|
||||
|
||||
@@ -51,6 +51,7 @@ public interface LoadingListQueryMapper {
|
||||
AND EXISTS (SELECT 1 FROM fl_loading_plan_item active_item
|
||||
WHERE active_item.loading_plan_id = p.id AND active_item.deleted = 0)
|
||||
<if test="query.status != null and query.status != ''">AND p.plan_status = #{query.status}</if>
|
||||
<if test="query.customerId != null">AND EXISTS (SELECT 1 FROM fl_loading_plan_item customer_item WHERE customer_item.loading_plan_id = p.id AND customer_item.deleted = 0 AND customer_item.account_id = #{query.customerId})</if>
|
||||
<if test="query.keyword != null and query.keyword != ''">
|
||||
AND (p.plan_no LIKE CONCAT('%', #{query.keyword}, '%')
|
||||
OR b.container_no LIKE CONCAT('%', #{query.keyword}, '%')
|
||||
@@ -74,6 +75,7 @@ public interface LoadingListQueryMapper {
|
||||
JOIN fl_container_booking b ON b.id = p.container_booking_id
|
||||
LEFT JOIN fl_loading_plan_item i ON i.loading_plan_id = p.id AND i.deleted = 0
|
||||
WHERE p.plan_status = 'COMPLETED'
|
||||
<if test="query.customerId != null">AND EXISTS (SELECT 1 FROM fl_loading_plan_item customer_item WHERE customer_item.loading_plan_id = p.id AND customer_item.deleted = 0 AND customer_item.account_id = #{query.customerId})</if>
|
||||
<if test="query.keyword != null and query.keyword != ''">
|
||||
AND (p.plan_no LIKE CONCAT('%', #{query.keyword}, '%')
|
||||
OR b.container_no LIKE CONCAT('%', #{query.keyword}, '%')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package com.baiyue.firstleg.mapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baiyue.firstleg.dto.TruckAppointmentDtos.Query; import com.baiyue.firstleg.entity.TruckAppointmentEntity; import org.apache.ibatis.annotations.*;
|
||||
@Mapper public interface TruckAppointmentMapper extends BaseMapper<TruckAppointmentEntity>{
|
||||
@Select("<script>SELECT * FROM fl_truck_appointment WHERE (#{q.keyword} IS NULL OR appointment_no LIKE CONCAT('%',#{q.keyword},'%') OR vehicle_no LIKE CONCAT('%',#{q.keyword},'%') OR carrier_name LIKE CONCAT('%',#{q.keyword},'%')) AND (#{q.status} IS NULL OR status=#{q.status}) AND (#{q.containerBookingId} IS NULL OR container_booking_id=#{q.containerBookingId}) ORDER BY updated_at DESC,id DESC</script>") Page<TruckAppointmentEntity> page(Page<TruckAppointmentEntity> p,@Param("q") Query q);
|
||||
@Select("<script>SELECT * FROM fl_truck_appointment WHERE (#{q.keyword} IS NULL OR appointment_no LIKE CONCAT('%',#{q.keyword},'%') OR vehicle_no LIKE CONCAT('%',#{q.keyword},'%') OR carrier_name LIKE CONCAT('%',#{q.keyword},'%')) AND (#{q.status} IS NULL OR status=#{q.status}) AND (#{q.customerId} IS NULL OR customer_id=#{q.customerId}) AND (#{q.containerBookingId} IS NULL OR container_booking_id=#{q.containerBookingId}) ORDER BY updated_at DESC,id DESC</script>") Page<TruckAppointmentEntity> page(Page<TruckAppointmentEntity> p,@Param("q") Query q);
|
||||
@Update("UPDATE fl_truck_appointment SET status=#{toStatus}, actual_arrived_warehouse_at=CASE WHEN #{toStatus}='ARRIVED_WAREHOUSE' THEN CURRENT_TIMESTAMP(3) ELSE actual_arrived_warehouse_at END, actual_loading_at=CASE WHEN #{toStatus}='LOADING' THEN CURRENT_TIMESTAMP(3) ELSE actual_loading_at END, actual_departed_at=CASE WHEN #{toStatus}='DEPARTED' THEN CURRENT_TIMESTAMP(3) ELSE actual_departed_at END, revision=revision+1, version=version+1, updated_at=CURRENT_TIMESTAMP(3) WHERE id=#{id} AND status=#{fromStatus} AND version=#{version}") int transition(@Param("id") long id,@Param("fromStatus") String from,@Param("toStatus") String to,@Param("version") int version);
|
||||
@Update("UPDATE fl_truck_appointment SET planned_loading_at=#{at}, revision=revision+1, version=version+1, status='RESCHEDULED', remark=#{reason}, updated_at=CURRENT_TIMESTAMP(3) WHERE id=#{id} AND version=#{version}") int reschedule(@Param("id") long id,@Param("at") java.time.LocalDateTime at,@Param("reason") String reason,@Param("version") int version);
|
||||
@Update("UPDATE fl_truck_appointment SET vehicle_no=#{e.vehicleNo},driver_name=#{e.driverName},driver_phone=#{e.driverPhone},payable_amount=#{e.payableAmount},receivable_amount=#{e.receivableAmount},planned_loading_at=#{e.plannedLoadingAt},remark=#{e.remark},version=version+1,revision=revision+1,updated_at=CURRENT_TIMESTAMP(3) WHERE id=#{e.id} AND version=#{version}") int updateEdit(@Param("e") TruckAppointmentEntity e,@Param("version") int version);
|
||||
|
||||
@@ -73,8 +73,9 @@ public class ActivePriceBookEstimator {
|
||||
}
|
||||
|
||||
private Estimate estimateRegion(long versionId, String channelCode, EstimateRequest request) {
|
||||
if (request.destinationType() != PricingDestinationType.FBA) {
|
||||
throw validation("海派渠道仅支持FBA目的仓参考估价");
|
||||
if (request.destinationType() != PricingDestinationType.FBA
|
||||
&& request.destinationType() != PricingDestinationType.OVERSEAS) {
|
||||
throw validation("海派渠道仅支持平台FBA仓或海外中转仓参考估价");
|
||||
}
|
||||
if (request.pricingTaxMode() == null) {
|
||||
throw validation("请选择包税或不包税报价");
|
||||
@@ -95,7 +96,7 @@ public class ActivePriceBookEstimator {
|
||||
|
||||
private PriceRegion resolveWarehouseRegion(Long warehouseId) {
|
||||
if (warehouseId == null || warehouseId <= 0) {
|
||||
throw validation("请提供目的仓区域或平台FBA仓,以确定海派区域");
|
||||
throw validation("请提供目的仓区域、平台FBA仓或海外中转仓,以确定海派区域");
|
||||
}
|
||||
return warehouseRegionResolver.resolve(warehouseId);
|
||||
}
|
||||
|
||||
+6
-5
@@ -11,7 +11,7 @@ import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/** Resolves a platform FBA warehouse to the fixed sea-parcel price region. */
|
||||
/** Resolves a platform destination warehouse to the fixed sea-parcel price region. */
|
||||
@Component
|
||||
public class PriceBookWarehouseRegionResolver {
|
||||
@Resource private PriceBookWarehouseClient warehouses;
|
||||
@@ -20,7 +20,7 @@ public class PriceBookWarehouseRegionResolver {
|
||||
|
||||
public PriceRegion resolve(long warehouseId) {
|
||||
if (warehouseId <= 0) {
|
||||
throw validation("请提供目的仓区域或平台FBA仓,以确定海派区域");
|
||||
throw validation("请提供目的仓区域、平台FBA仓或海外中转仓,以确定海派区域");
|
||||
}
|
||||
try {
|
||||
ApiResponse<PriceBookWarehouseClient.Detail> response = warehouses.active(internalToken, 0L, warehouseId);
|
||||
@@ -28,12 +28,13 @@ public class PriceBookWarehouseRegionResolver {
|
||||
throw new BizException(ResultCode.SERVICE_UNAVAILABLE, "目的仓服务暂时不可用");
|
||||
}
|
||||
if (!response.successful() || response.data() == null || response.data().warehouse() == null) {
|
||||
throw validation("目的仓不是可用的平台FBA仓");
|
||||
throw validation("目的仓不是可用的平台目的仓");
|
||||
}
|
||||
var warehouse = response.data().warehouse();
|
||||
if (!Long.valueOf(warehouseId).equals(warehouse.id()) || !Long.valueOf(0L).equals(warehouse.tenantId())
|
||||
|| !"FBA".equals(warehouse.warehouseType()) || !"ACTIVE".equals(warehouse.status())) {
|
||||
throw validation("目的仓不是可用的平台FBA仓");
|
||||
|| !("FBA".equals(warehouse.warehouseType()) || "OVERSEAS".equals(warehouse.warehouseType()))
|
||||
|| !"ACTIVE".equals(warehouse.status())) {
|
||||
throw validation("目的仓不是可用的平台FBA仓或海外中转仓");
|
||||
}
|
||||
String postalCode = response.data().addresses() == null ? null : response.data().addresses().stream()
|
||||
.filter(address -> address != null && StringUtils.hasText(address.postalCode()))
|
||||
|
||||
@@ -191,7 +191,7 @@ public class ContainerService {
|
||||
}
|
||||
private static Query normalize(Query q) {
|
||||
return new Query(trim(q.containerNo()), trim(q.cabinetNo()), trim(q.billOfLadingNo()), trim(q.keyword()),
|
||||
q.warehouseId(), trim(q.containerType()), q.shippingCompanyId(), trim(q.departurePortCode()),
|
||||
q.customerId(), q.warehouseId(), trim(q.containerType()), q.shippingCompanyId(), trim(q.departurePortCode()),
|
||||
trim(q.destinationPortCode()), trim(q.destinationWarehouseCode()), q.status(), q.estimatedSailingFrom(),
|
||||
q.estimatedSailingTo(), q.page(), q.size());
|
||||
}
|
||||
|
||||
@@ -227,9 +227,8 @@ public class FbaPricingService {
|
||||
|| inbound.getActualVolumeCbm() == null || inbound.getActualVolumeCbm().signum() <= 0) {
|
||||
throw conflict("审核通过的测量快照必须包含大于零的实重和体积");
|
||||
}
|
||||
if (inbound.getCustomerId() == null || inbound.getWarehouseId() == null
|
||||
|| !StringUtils.hasText(inbound.getChannelCode())) {
|
||||
throw conflict("入库单缺少客户、起运仓或渠道匹配维度");
|
||||
if (inbound.getWarehouseId() == null || !StringUtils.hasText(inbound.getChannelCode())) {
|
||||
throw conflict("入库单缺少起运仓或渠道匹配维度");
|
||||
}
|
||||
return inbound;
|
||||
}
|
||||
|
||||
@@ -71,13 +71,13 @@ public class LoadingListService {
|
||||
if (StringUtils.hasText(status) && !PRELOAD_STATUSES.contains(status)) {
|
||||
throw badRequest("预装清单状态只能是 EDITING 或 LOADING");
|
||||
}
|
||||
return repository.preloadPage(new PreloadQuery(trim(query.keyword()), status,
|
||||
return repository.preloadPage(new PreloadQuery(trim(query.keyword()), status, query.customerId(),
|
||||
query.warehouseId(), query.createdFrom(), query.createdTo(), query.page(), query.size()));
|
||||
}
|
||||
|
||||
public PageResult<ConfirmedSummary> confirmedPage(ConfirmedQuery query) {
|
||||
validateRange(query.createdFrom(), query.createdTo());
|
||||
return repository.confirmedPage(new ConfirmedQuery(trim(query.keyword()), query.warehouseId(),
|
||||
return repository.confirmedPage(new ConfirmedQuery(trim(query.keyword()), query.customerId(), query.warehouseId(),
|
||||
query.createdFrom(), query.createdTo(), query.page(), query.size()));
|
||||
}
|
||||
|
||||
|
||||
@@ -566,7 +566,7 @@ CREATE TABLE IF NOT EXISTS fl_inbound_fee (
|
||||
carrier_rate_version INT UNSIGNED NOT NULL COMMENT '船司价格版本快照',
|
||||
price_book_version_id BIGINT UNSIGNED NULL COMMENT '整表价格版本ID快照',
|
||||
rule_code VARCHAR(50) NULL COMMENT '历史客户规则编码快照',
|
||||
customer_id BIGINT UNSIGNED NOT NULL COMMENT '客户ID快照',
|
||||
customer_id BIGINT UNSIGNED NULL COMMENT '可选业务客户快照;平台公共渠道计费不依赖该字段',
|
||||
customer_name VARCHAR(128) NOT NULL COMMENT '客户名称快照',
|
||||
business_type VARCHAR(32) NOT NULL COMMENT '业务类型快照',
|
||||
tax_mode VARCHAR(24) NULL COMMENT '订单买单或退税模式快照',
|
||||
|
||||
@@ -130,7 +130,7 @@ paths:
|
||||
/api/platform/v1/inbounds/{inboundId}/fees/calculate:
|
||||
post:
|
||||
summary: 按审核通过测量快照试算 FBA 费用
|
||||
description: 仅匹配当前唯一 ACTIVE 船期价格表中的 ACTIVE 价格行,按起运仓、渠道、目的仓、pricingTaxMode 和计费单位估价;不再以 carrierId 或客户计费规则作为前置。海派还需按FBA区域和重量阶梯匹配;测量审核后即使主流程已到 WAIT_SPLIT,也可独立试算且不回退主流程状态;需要 firstleg:fba-pricing:calculate 权限。
|
||||
description: 仅匹配当前唯一 ACTIVE 船期价格表中的 ACTIVE 价格行,按起运仓、渠道、目的仓、pricingTaxMode 和计费单位估价;不再以 carrierId、业务 customerId 或客户计费规则作为前置。区域阶梯渠道可按平台 FBA 仓或海外中转仓的邮编区域和重量阶梯匹配;测量审核后即使主流程已到 WAIT_SPLIT,也可独立试算且不回退主流程状态;需要 firstleg:fba-pricing:calculate 权限。
|
||||
parameters: [{$ref: '#/components/parameters/TenantId'}, {$ref: '#/components/parameters/InboundId'}, {$ref: '#/components/parameters/IdempotencyKey'}]
|
||||
requestBody: {content: {application/json: {schema: {$ref: '#/components/schemas/CalculateRequest'}}}}
|
||||
responses: {'200': {description: 成功或业务失败}, '403': {description: 无权限}}
|
||||
|
||||
@@ -205,6 +205,7 @@ paths:
|
||||
- {$ref: '#/components/parameters/Page'}
|
||||
- {$ref: '#/components/parameters/Size'}
|
||||
- {name: keyword, in: query, schema: {type: string, maxLength: 128}}
|
||||
- {name: customerId, in: query, description: 仅返回包含该客户货物的柜次, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
- {name: containerNo, in: query, schema: {type: string, maxLength: 64}}
|
||||
- {name: cabinetNo, in: query, schema: {type: string, maxLength: 64}}
|
||||
- {name: warehouseId, in: query, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
|
||||
@@ -7,12 +7,13 @@ paths:
|
||||
/api/platform/v1/first-leg/loading-plans:
|
||||
get:
|
||||
summary: 分页查询预装清单
|
||||
description: 默认返回全部仓库的装柜计划;可按仓库筛选,客户账号仅用于展示货物归属。
|
||||
description: 默认返回全部仓库的装柜计划;可按客户和仓库筛选。
|
||||
x-permission: platform:firstleg:preload:list
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/Page'}
|
||||
- {$ref: '#/components/parameters/Size'}
|
||||
- {$ref: '#/components/parameters/Keyword'}
|
||||
- {$ref: '#/components/parameters/CustomerId'}
|
||||
- name: status
|
||||
in: query
|
||||
description: 预装状态
|
||||
@@ -49,12 +50,13 @@ paths:
|
||||
/api/platform/v1/first-leg/loading-lists:
|
||||
get:
|
||||
summary: 分页查询装柜清单
|
||||
description: 默认返回全部仓库的 COMPLETED 装柜计划;可按仓库筛选,包含全部客户单据。
|
||||
description: 默认返回全部仓库的 COMPLETED 装柜计划;可按客户和仓库筛选。
|
||||
x-permission: platform:firstleg:loading-list:list
|
||||
parameters:
|
||||
- {$ref: '#/components/parameters/Page'}
|
||||
- {$ref: '#/components/parameters/Size'}
|
||||
- {$ref: '#/components/parameters/Keyword'}
|
||||
- {$ref: '#/components/parameters/CustomerId'}
|
||||
- {$ref: '#/components/parameters/OptionalWarehouseId'}
|
||||
- {$ref: '#/components/parameters/CreatedFrom'}
|
||||
- {$ref: '#/components/parameters/CreatedTo'}
|
||||
@@ -138,6 +140,12 @@ components:
|
||||
in: query
|
||||
description: 按预装单号、集装箱号或柜号模糊查询
|
||||
schema: {type: string, maxLength: 128}
|
||||
CustomerId:
|
||||
name: customerId
|
||||
in: query
|
||||
required: false
|
||||
description: 仅返回包含该客户货物的清单
|
||||
schema: {$ref: '#/components/schemas/LongId'}
|
||||
WarehouseId:
|
||||
name: warehouseId
|
||||
in: query
|
||||
|
||||
@@ -6,6 +6,8 @@ paths:
|
||||
/api/platform/v1/truck-appointments:
|
||||
get:
|
||||
summary: Query truck appointments
|
||||
parameters:
|
||||
- {name: customerId, in: query, description: Filter by customer, schema: {type: string, pattern: '^[1-9][0-9]*$'}}
|
||||
responses:
|
||||
'200': {description: Paged truck appointments}
|
||||
post:
|
||||
|
||||
@@ -49,6 +49,8 @@ class FbaPricingContractTest {
|
||||
.contains("/api/platform/v1/inbounds/{inboundId}/fees/published:")
|
||||
.contains("Idempotency-Key")
|
||||
.contains("主流程已到 WAIT_SPLIT,也可独立试算且不回退主流程状态")
|
||||
.contains("区域阶梯渠道可按平台 FBA 仓或海外中转仓的邮编区域")
|
||||
.contains("不再以 carrierId、业务 customerId 或客户计费规则作为前置")
|
||||
.contains("该动作涉及后续仓储流程,本轮二期验收不调用")
|
||||
.contains("不回退 WAIT_SPLIT 状态")
|
||||
.doesNotContain("应收")
|
||||
|
||||
+2
-2
@@ -51,9 +51,9 @@ class LoadingListRepositoryTest {
|
||||
confirmedPage.setTotal(1);
|
||||
when(mapper.selectConfirmedPage(any(), any())).thenReturn(confirmedPage);
|
||||
|
||||
var preload = repository.preloadPage(new PreloadQuery(null, null, null, null, null, 1, 20))
|
||||
var preload = repository.preloadPage(new PreloadQuery(null, null, null, null, null, null, 1, 20))
|
||||
.records().get(0);
|
||||
var confirmed = repository.confirmedPage(new ConfirmedQuery(null, null, null, null, 1, 20))
|
||||
var confirmed = repository.confirmedPage(new ConfirmedQuery(null, null, null, null, null, 1, 20))
|
||||
.records().get(0);
|
||||
|
||||
assertThat(preload.planId()).isEqualTo(41L);
|
||||
|
||||
@@ -42,6 +42,8 @@ class PriceBookSqlContractTest {
|
||||
.contains("destination_name VARCHAR(128)")
|
||||
.contains("parse_issues_json JSON NULL")
|
||||
.contains("DEFAULT 'PENDING_CONFIRMATION'");
|
||||
assertThat(schema)
|
||||
.contains("customer_id BIGINT UNSIGNED NULL COMMENT '可选业务客户快照;平台公共渠道计费不依赖该字段'");
|
||||
assertThat(schema)
|
||||
.contains("'ORIGIN_CODE', 'CN-YIWU-01', 193000000000200001")
|
||||
.contains("'ORIGIN_CODE', 'CN-DONGGUAN-01', 193000000000200002")
|
||||
|
||||
@@ -92,6 +92,24 @@ class FbaPricingServiceTest {
|
||||
assertThat(fee.getValue().getCarrierId()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("平台公共渠道计费允许业务客户快照为空")
|
||||
void calculatesWithoutOptionalBusinessCustomerSnapshot() {
|
||||
readyRepository();
|
||||
InboundPricingEntity inbound = inbound("200.000", "0.2000");
|
||||
inbound.setCustomerId(null);
|
||||
when(repository.findInbound(TENANT, INBOUND)).thenReturn(inbound);
|
||||
when(priceBookEstimator.estimate(any())).thenReturn(
|
||||
estimate("KG", "200.000", "14.300000", "2860.00", "0.00"));
|
||||
|
||||
FeeSnapshotResponse response = service.calculate(TENANT, OPERATOR, INBOUND, NOW, "calc-no-customer");
|
||||
|
||||
assertThat(response.totalAmount()).isEqualByComparingTo("2860.00");
|
||||
ArgumentCaptor<InboundFeeEntity> fee = ArgumentCaptor.forClass(InboundFeeEntity.class);
|
||||
verify(repository).insertFee(fee.capture());
|
||||
assertThat(fee.getValue().getCustomerId()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("不包税CBM使用生效价格表返回的计费量")
|
||||
void calculatesTaxExcludedCbmFromActivePriceBook() {
|
||||
|
||||
@@ -61,7 +61,7 @@ class LoadingListServiceTest {
|
||||
|
||||
@Test
|
||||
void shouldAcceptEditingStatusFromPreloadList() {
|
||||
PreloadQuery query = new PreloadQuery(null, "EDITING", 100L, null, null, 1, 20);
|
||||
PreloadQuery query = new PreloadQuery(null, "EDITING", null, 100L, null, null, 1, 20);
|
||||
|
||||
service.preloadPage(query);
|
||||
|
||||
@@ -184,7 +184,7 @@ class LoadingListServiceTest {
|
||||
|
||||
@Test
|
||||
void confirmedPageAlwaysUsesRepositoryConfirmedProjection() {
|
||||
ConfirmedQuery query = new ConfirmedQuery(" plan ", 100L, null, null, 1, 20);
|
||||
ConfirmedQuery query = new ConfirmedQuery(" plan ", null, 100L, null, null, 1, 20);
|
||||
when(repository.confirmedPage(org.mockito.ArgumentMatchers.any())).thenReturn(
|
||||
new PageResult<>(List.of(), 1, 20, 0, 0));
|
||||
|
||||
@@ -201,8 +201,8 @@ class LoadingListServiceTest {
|
||||
when(repository.confirmedPage(org.mockito.ArgumentMatchers.any())).thenReturn(
|
||||
new PageResult<>(List.of(), 1, 20, 0, 0));
|
||||
|
||||
service.preloadPage(new PreloadQuery(null, "LOADING", null, null, null, 1, 20));
|
||||
service.confirmedPage(new ConfirmedQuery(null, null, null, null, 1, 20));
|
||||
service.preloadPage(new PreloadQuery(null, "LOADING", null, null, null, null, 1, 20));
|
||||
service.confirmedPage(new ConfirmedQuery(null, null, null, null, null, 1, 20));
|
||||
|
||||
verify(repository).preloadPage(org.mockito.ArgumentMatchers.argThat(value -> value.warehouseId() == null));
|
||||
verify(repository).confirmedPage(org.mockito.ArgumentMatchers.argThat(value -> value.warehouseId() == null));
|
||||
|
||||
+21
-1
@@ -187,6 +187,26 @@ class MerchantPriceBookServiceTest {
|
||||
verify(repository).regionTiers(8L, 10L, "MATSON_PARCEL", "EAST", "TAX_INCLUDED");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolveTierRegionFromPlatformOverseasWarehousePostalCode() {
|
||||
stubChannel(8L, "MATSON_MAX_PARCEL", PriceModel.REGION_WEIGHT_TIER);
|
||||
when(repository.regionTiers(8L, 10L, "MATSON_MAX_PARCEL", "WEST", "TAX_INCLUDED"))
|
||||
.thenReturn(tiers());
|
||||
var warehouse = new PriceBookWarehouseClient.Warehouse(901L, 0L, "US-LAX-01", "洛杉矶仓",
|
||||
"OVERSEAS", "US", "ACTIVE");
|
||||
var address = new PriceBookWarehouseClient.Address("US", "CA", "Los Angeles", null,
|
||||
"90001", "address", null);
|
||||
when(warehouses.active("internal-token", 0L, 901L))
|
||||
.thenReturn(ApiResponse.success(new PriceBookWarehouseClient.Detail(warehouse, List.of(address))));
|
||||
|
||||
var result = service.estimate(10001L,
|
||||
request("MATSON_MAX_PARCEL", PricingDestinationType.OVERSEAS, null, 901L, null,
|
||||
PricingTaxMode.TAX_INCLUDED, "51", null));
|
||||
|
||||
assertThat(result.unitPrice()).isEqualByComparingTo("13");
|
||||
verify(repository).regionTiers(8L, 10L, "MATSON_MAX_PARCEL", "WEST", "TAX_INCLUDED");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectMissingRequiredEstimateFields() {
|
||||
stubChannel(7L, "MATSON_TRUCK", PriceModel.FBA_WAREHOUSE_RATE);
|
||||
@@ -206,7 +226,7 @@ class MerchantPriceBookServiceTest {
|
||||
request("MATSON_PARCEL", PricingDestinationType.FBA, "ONT8", null, null,
|
||||
PricingTaxMode.TAX_INCLUDED, "51", null)))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessageContaining("目的仓区域或平台FBA仓");
|
||||
.hasMessageContaining("目的仓区域");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user