feat(firstleg): add private warehouse delivery fee
This commit is contained in:
@@ -7681,6 +7681,15 @@ SELECT 193000000001000111, 0, 'FBA_HEAD_FREIGHT', '头程运费', 'INTERNATIONAL
|
||||
0, 'system', '2026-08-14 00:00:00.000', 0, 'system', '2026-08-14 00:00:00.000'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM fl_fee_item WHERE fee_code = 'FBA_HEAD_FREIGHT');
|
||||
|
||||
INSERT INTO fl_fee_item (id, tenant_id, fee_code, category, trade_scope, fee_type_name,
|
||||
pickup_payable, pickup_receivable, warehouse_payable, warehouse_receivable,
|
||||
allocation_fee, description, status, created_by, created_by_name, created_at,
|
||||
updated_by, updated_by_name, updated_at, deleted, version)
|
||||
SELECT 193000000001000112, 0, 'PRIVATE_LAST_MILE_DELIVERY', '尾程派送费', 'INTERNATIONAL',
|
||||
'私人仓尾程派送费', 0, 0, 1, 1, 0, '仅用于destinationType=PRIVATE的入库单',
|
||||
'ACTIVE', 0, 'SYSTEM', CURRENT_TIMESTAMP(3), 0, 'SYSTEM', CURRENT_TIMESTAMP(3), 0, 0
|
||||
WHERE NOT EXISTS (SELECT 1 FROM fl_fee_item WHERE fee_code = 'PRIVATE_LAST_MILE_DELIVERY');
|
||||
|
||||
-- ============================================================================
|
||||
-- 2026-08-06:三期分柜、预装、拣货、装柜和派送当前基线
|
||||
-- ============================================================================
|
||||
@@ -15607,6 +15616,11 @@ BEGIN
|
||||
AND category = '头程运费' AND trade_scope = 'INTERNATIONAL' AND fee_type_name = 'FBA头程运费'
|
||||
AND pickup_payable = 0 AND pickup_receivable = 0 AND warehouse_payable = 0
|
||||
AND warehouse_receivable = 1 AND allocation_fee = 0 AND status = 'ACTIVE' AND deleted = 0) <> 1
|
||||
OR (SELECT COUNT(*) FROM baiyue_firstleg.fl_fee_item
|
||||
WHERE tenant_id = 0 AND fee_code = 'PRIVATE_LAST_MILE_DELIVERY'
|
||||
AND category = '尾程派送费' AND trade_scope = 'INTERNATIONAL'
|
||||
AND fee_type_name = '私人仓尾程派送费' AND warehouse_payable = 1
|
||||
AND warehouse_receivable = 1 AND status = 'ACTIVE' AND deleted = 0) <> 1
|
||||
OR EXISTS (
|
||||
SELECT 1
|
||||
FROM baiyue_firstleg.fl_inbound_fee_detail detail
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.List;
|
||||
@Service
|
||||
public class InboundFeeDetailService {
|
||||
private static final String FREIGHT_FEE_CODE = "FBA_HEAD_FREIGHT";
|
||||
private static final String PRIVATE_LAST_MILE_DELIVERY_FEE_CODE = "PRIVATE_LAST_MILE_DELIVERY";
|
||||
@Resource
|
||||
private FeeItemRepository repository;
|
||||
@Resource
|
||||
@@ -379,6 +380,7 @@ public class InboundFeeDetailService {
|
||||
|
||||
private void apply(InboundFeeDetailEntity value, InboundOrderEntity inbound,
|
||||
FeeItemEntity item, SaveRequest request, long operatorId) {
|
||||
ensureDestinationApplicable(item, inbound);
|
||||
ensureWarehouseApplicable(item, request.direction());
|
||||
value.setFeeItemId(item.getId());
|
||||
value.setInboundCode(inbound.getInboundCode());
|
||||
@@ -408,6 +410,13 @@ public class InboundFeeDetailService {
|
||||
value.setUpdatedBy(operatorId);
|
||||
}
|
||||
|
||||
private static void ensureDestinationApplicable(FeeItemEntity item, InboundOrderEntity inbound) {
|
||||
if (PRIVATE_LAST_MILE_DELIVERY_FEE_CODE.equals(item.getFeeCode())
|
||||
&& !"PRIVATE".equals(inbound.getDestinationType())) {
|
||||
throw conflict("私人仓尾程派送费只能绑定目的地类型为PRIVATE的入库单");
|
||||
}
|
||||
}
|
||||
|
||||
private void applySupplierSnapshot(InboundFeeDetailEntity value, FeeItemEntity item,
|
||||
String direction, Long supplierId) {
|
||||
if (!"PAYABLE".equals(direction)) {
|
||||
|
||||
@@ -471,6 +471,15 @@ SELECT 193000000001000111, 0, 'FBA_HEAD_FREIGHT', '头程运费', 'INTERNATIONAL
|
||||
0, 'system', '2026-08-14 00:00:00.000', 0, 'system', '2026-08-14 00:00:00.000'
|
||||
WHERE NOT EXISTS (SELECT 1 FROM fl_fee_item WHERE fee_code = 'FBA_HEAD_FREIGHT');
|
||||
|
||||
INSERT INTO fl_fee_item (id, tenant_id, fee_code, category, trade_scope, fee_type_name,
|
||||
pickup_payable, pickup_receivable, warehouse_payable, warehouse_receivable,
|
||||
allocation_fee, description, status, created_by, created_by_name, created_at,
|
||||
updated_by, updated_by_name, updated_at, deleted, version)
|
||||
SELECT 193000000001000112, 0, 'PRIVATE_LAST_MILE_DELIVERY', '尾程派送费', 'INTERNATIONAL',
|
||||
'私人仓尾程派送费', 0, 0, 1, 1, 0, '仅用于destinationType=PRIVATE的入库单',
|
||||
'ACTIVE', 0, 'SYSTEM', CURRENT_TIMESTAMP(3), 0, 'SYSTEM', CURRENT_TIMESTAMP(3), 0, 0
|
||||
WHERE NOT EXISTS (SELECT 1 FROM fl_fee_item WHERE fee_code = 'PRIVATE_LAST_MILE_DELIVERY');
|
||||
|
||||
DROP PROCEDURE IF EXISTS phase2_publish_assert_fee_schema;
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE phase2_publish_assert_fee_schema()
|
||||
@@ -491,11 +500,15 @@ BEGIN
|
||||
OR (SELECT COUNT(*) FROM fl_fee_item WHERE tenant_id = 0 AND status = 'ACTIVE' AND deleted = 0
|
||||
AND id BETWEEN 193000000001000001 AND 193000000001000110
|
||||
AND fee_code = CONCAT('FEE_TYPE_', LPAD(id - 193000000001000000, 3, '0'))) <> 110
|
||||
OR (SELECT COUNT(*) FROM fl_fee_item WHERE tenant_id = 0 AND fee_code = 'FBA_HEAD_FREIGHT'
|
||||
AND category = '头程运费' AND trade_scope = 'INTERNATIONAL' AND fee_type_name = 'FBA头程运费'
|
||||
AND pickup_payable = 0 AND pickup_receivable = 0 AND warehouse_payable = 0
|
||||
AND warehouse_receivable = 1 AND allocation_fee = 0 AND status = 'ACTIVE' AND deleted = 0) <> 1
|
||||
OR EXISTS (SELECT 1 FROM fl_inbound_fee_detail d JOIN fl_fee_item f ON f.id = d.fee_item_id
|
||||
OR (SELECT COUNT(*) FROM fl_fee_item WHERE tenant_id = 0 AND fee_code = 'FBA_HEAD_FREIGHT'
|
||||
AND category = '头程运费' AND trade_scope = 'INTERNATIONAL' AND fee_type_name = 'FBA头程运费'
|
||||
AND pickup_payable = 0 AND pickup_receivable = 0 AND warehouse_payable = 0
|
||||
AND warehouse_receivable = 1 AND allocation_fee = 0 AND status = 'ACTIVE' AND deleted = 0) <> 1
|
||||
OR (SELECT COUNT(*) FROM fl_fee_item WHERE tenant_id = 0 AND fee_code = 'PRIVATE_LAST_MILE_DELIVERY'
|
||||
AND category = '尾程派送费' AND trade_scope = 'INTERNATIONAL'
|
||||
AND fee_type_name = '私人仓尾程派送费' AND warehouse_payable = 1
|
||||
AND warehouse_receivable = 1 AND status = 'ACTIVE' AND deleted = 0) <> 1
|
||||
OR EXISTS (SELECT 1 FROM fl_inbound_fee_detail d JOIN fl_fee_item f ON f.id = d.fee_item_id
|
||||
WHERE d.tenant_id = 0 OR f.tenant_id <> 0) THEN
|
||||
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '二期迁移失败:费用项目未完成平台公共作用域或明细跨客户引用校验';
|
||||
END IF;
|
||||
|
||||
@@ -184,7 +184,7 @@ paths:
|
||||
responses: {'200': {description: 成功或业务失败, content: {application/json: {schema: {$ref: '#/components/schemas/InboundFeeDetailListApiResponse'}}}}, '403': {description: 无权限}}
|
||||
post:
|
||||
summary: 新增 MANUAL 其他费用
|
||||
description: 只允许创建 MANUAL 来源;FBA_PRICING 由系统从 fl_inbound_fee 派生。
|
||||
description: 只允许创建 MANUAL 来源;FBA_PRICING 由系统从 fl_inbound_fee 派生。费用项目 PRIVATE_LAST_MILE_DELIVERY 是独立的私人仓尾程派送费,仅 destinationType=PRIVATE 的入库单可创建;服务端按稳定 feeCode 校验,不按中文名称判断。
|
||||
parameters: [{$ref: '#/components/parameters/AccountId'}, {$ref: '#/components/parameters/InboundId'}]
|
||||
requestBody: {required: true, content: {application/json: {schema: {$ref: '#/components/schemas/InboundFeeDetailSaveRequest'}}}}
|
||||
responses: {'200': {description: 成功或业务失败, content: {application/json: {schema: {$ref: '#/components/schemas/InboundFeeDetailApiResponse'}}}}, '403': {description: 无权限}}
|
||||
|
||||
+2
@@ -24,6 +24,8 @@ class FeeItemMigrationSqlContractTest {
|
||||
.contains("matched_seed.trade_scope = f.trade_scope")
|
||||
.contains("193000000001000111, 0, 'FBA_HEAD_FREIGHT'")
|
||||
.contains("fee_code = 'FBA_HEAD_FREIGHT'")
|
||||
.contains("193000000001000112, 0, 'PRIVATE_LAST_MILE_DELIVERY'")
|
||||
.contains("fee_code = 'PRIVATE_LAST_MILE_DELIVERY'")
|
||||
.contains("warehouse_receivable = 1")
|
||||
.doesNotContain("LEFT JOIN tmp_fee_item_seed by_code")
|
||||
.doesNotContain("LEFT JOIN tmp_fee_item_seed by_semantic")
|
||||
|
||||
@@ -337,6 +337,29 @@ class FeeManagementServiceTest {
|
||||
.hasMessageContaining("仓储应收/应付");
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("私人仓尾程派送费只允许PRIVATE目的地")
|
||||
void restrictsPrivateLastMileDeliveryFeeByDestinationType() {
|
||||
InboundOrderEntity fbaInbound = inbound();
|
||||
fbaInbound.setDestinationType("FBA");
|
||||
FeeItemEntity privateDelivery = item(true, true);
|
||||
privateDelivery.setFeeCode("PRIVATE_LAST_MILE_DELIVERY");
|
||||
when(repository.findInbound(10001L, 21L)).thenReturn(fbaInbound);
|
||||
when(repository.findItem(11L)).thenReturn(privateDelivery);
|
||||
|
||||
assertThatThrownBy(() -> details.create(10001L, 21L, 9L,
|
||||
detailRequest("RECEIVABLE")))
|
||||
.isInstanceOf(BizException.class)
|
||||
.hasMessageContaining("目的地类型为PRIVATE");
|
||||
verify(repository, never()).insertDetail(any());
|
||||
|
||||
fbaInbound.setDestinationType("PRIVATE");
|
||||
doAnswer(invocation -> { ((InboundFeeDetailEntity) invocation.getArgument(0)).setId(32L); return null; })
|
||||
.when(repository).insertDetail(any());
|
||||
assertThat(details.create(10001L, 21L, 9L, detailRequest("RECEIVABLE")).getId())
|
||||
.isEqualTo(32L);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("审核只更新待审核明细")
|
||||
void approvesPendingDetail() {
|
||||
|
||||
Reference in New Issue
Block a user