优化
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
package com.baiyue.firstleg.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@TableName("fl_price_warehouse_mapping")
|
||||
public class PriceWarehouseMappingEntity {
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
private String sourceType;
|
||||
private String sourceValue;
|
||||
private Long warehouseId;
|
||||
private String warehouseCode;
|
||||
private String warehouseType;
|
||||
private String status;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package com.baiyue.firstleg.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baiyue.firstleg.entity.PriceWarehouseMappingEntity;
|
||||
|
||||
public interface PriceWarehouseMappingMapper extends BaseMapper<PriceWarehouseMappingEntity> {}
|
||||
@@ -7,11 +7,13 @@ import com.baiyue.firstleg.entity.PriceBookChannelEntity;
|
||||
import com.baiyue.firstleg.entity.PriceBookVersionEntity;
|
||||
import com.baiyue.firstleg.entity.PriceChannelCatalogEntity;
|
||||
import com.baiyue.firstleg.entity.PriceOriginAliasEntity;
|
||||
import com.baiyue.firstleg.entity.PriceWarehouseMappingEntity;
|
||||
import com.baiyue.firstleg.mapper.CarrierFbaRateMapper;
|
||||
import com.baiyue.firstleg.mapper.PriceBookChannelMapper;
|
||||
import com.baiyue.firstleg.mapper.PriceBookVersionMapper;
|
||||
import com.baiyue.firstleg.mapper.PriceChannelCatalogMapper;
|
||||
import com.baiyue.firstleg.mapper.PriceOriginAliasMapper;
|
||||
import com.baiyue.firstleg.mapper.PriceWarehouseMappingMapper;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@@ -25,6 +27,7 @@ public class PriceBookRepository {
|
||||
@Resource private CarrierFbaRateMapper rates;
|
||||
@Resource private PriceChannelCatalogMapper catalog;
|
||||
@Resource private PriceOriginAliasMapper aliases;
|
||||
@Resource private PriceWarehouseMappingMapper warehouseMappings;
|
||||
|
||||
public int insertVersion(PriceBookVersionEntity value) { return versions.insert(value); }
|
||||
public int updateVersion(PriceBookVersionEntity value) {
|
||||
@@ -109,6 +112,11 @@ public class PriceBookRepository {
|
||||
return aliases.selectList(new LambdaQueryWrapper<PriceOriginAliasEntity>()
|
||||
.eq(PriceOriginAliasEntity::getStatus, "ACTIVE"));
|
||||
}
|
||||
public List<PriceWarehouseMappingEntity> activeWarehouseMappings() {
|
||||
return warehouseMappings.selectList(new LambdaQueryWrapper<PriceWarehouseMappingEntity>()
|
||||
.eq(PriceWarehouseMappingEntity::getStatus, "ACTIVE")
|
||||
.orderByAsc(PriceWarehouseMappingEntity::getId));
|
||||
}
|
||||
public void supersede(PriceBookVersionEntity old, LocalDateTime at, long operatorId) {
|
||||
old.setStatus("SUPERSEDED"); old.setSupersededAt(at); old.setUpdatedBy(operatorId); old.setUpdatedAt(at);
|
||||
updateVersion(old);
|
||||
|
||||
@@ -16,6 +16,7 @@ import com.baiyue.firstleg.entity.CarrierFbaRateEntity;
|
||||
import com.baiyue.firstleg.entity.PriceBookChannelEntity;
|
||||
import com.baiyue.firstleg.entity.PriceBookVersionEntity;
|
||||
import com.baiyue.firstleg.entity.PriceChannelCatalogEntity;
|
||||
import com.baiyue.firstleg.entity.PriceWarehouseMappingEntity;
|
||||
import com.baiyue.firstleg.pricing.importer.PriceWorkbookParseResult;
|
||||
import com.baiyue.firstleg.pricing.importer.PriceWorkbookParser;
|
||||
import com.baiyue.firstleg.repository.PriceBookRepository;
|
||||
@@ -262,7 +263,37 @@ public class PlatformPriceBookService {
|
||||
List<PriceBookDtos.ParseIssue> issues = parsed.issues().stream().map(value -> issue(
|
||||
value.severity() == PriceWorkbookParseResult.Severity.ERROR ? "BLOCKING" : "WARNING",
|
||||
value.code(), value.message(), value.sheetName(), value.rowNumber(), null)).toList();
|
||||
return new ParsedPriceBook(channels, rates, issues);
|
||||
return new ParsedPriceBook(channels, applyInitializedWarehouseMappings(rates), issues);
|
||||
}
|
||||
|
||||
private List<PriceBookDtos.ParsedRate> applyInitializedWarehouseMappings(List<PriceBookDtos.ParsedRate> rates) {
|
||||
Map<String, PriceWarehouseMappingEntity> origins = new HashMap<>();
|
||||
Map<String, PriceWarehouseMappingEntity> overseas = new HashMap<>();
|
||||
for (PriceWarehouseMappingEntity mapping : repository.activeWarehouseMappings()) {
|
||||
if (mapping == null || mapping.getWarehouseId() == null || mapping.getWarehouseId() <= 0) continue;
|
||||
if ("ORIGIN_CODE".equals(mapping.getSourceType())
|
||||
&& "DOMESTIC".equals(mapping.getWarehouseType())
|
||||
&& mappingKey(mapping.getSourceValue()).equals(mappingKey(mapping.getWarehouseCode()))) {
|
||||
origins.putIfAbsent(mappingKey(mapping.getSourceValue()), mapping);
|
||||
} else if ("OVERSEAS_NAME".equals(mapping.getSourceType())
|
||||
&& "OVERSEAS".equals(mapping.getWarehouseType())
|
||||
&& StringUtils.hasText(mapping.getWarehouseCode())) {
|
||||
overseas.putIfAbsent(mappingKey(mapping.getSourceValue()), mapping);
|
||||
}
|
||||
}
|
||||
return rates.stream().map(rate -> {
|
||||
PriceWarehouseMappingEntity origin = origins.get(mappingKey(rate.originWarehouseCode()));
|
||||
PriceWarehouseMappingEntity destination = rate.destinationType() == PricingDestinationType.OVERSEAS
|
||||
? overseas.get(mappingKey(rate.destinationName())) : null;
|
||||
return new PriceBookDtos.ParsedRate(rate.id(), rate.channelCode(), rate.priceModel(),
|
||||
origin == null ? rate.originWarehouseId() : origin.getWarehouseId(),
|
||||
rate.originWarehouseCode(), rate.originWarehouseName(),
|
||||
destination == null ? rate.destinationCode() : mappingKey(destination.getWarehouseCode()), rate.destinationType(),
|
||||
destination == null ? rate.destinationWarehouseId() : destination.getWarehouseId(),
|
||||
rate.destinationName(), rate.regionCode(), rate.pricingTaxMode(), rate.chargeUnit(), rate.weightFromKg(),
|
||||
rate.unitPrice(), rate.currency(), rate.sourceSheetName(), rate.sourceRowNumber(),
|
||||
rate.sourceDestinationText(), rate.remark());
|
||||
}).toList();
|
||||
}
|
||||
|
||||
private PriceBookDtos.ParsedRate parsedRate(String channelCode, PriceModel model,
|
||||
|
||||
@@ -411,6 +411,21 @@ CREATE TABLE IF NOT EXISTS fl_price_origin_alias (
|
||||
KEY idx_price_origin_alias_name (alias_name, status)
|
||||
) ENGINE=InnoDB COMMENT='价格表起运仓名称别名映射';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fl_price_warehouse_mapping (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT '价格仓映射ID',
|
||||
source_type VARCHAR(24) NOT NULL COMMENT '来源维度:ORIGIN_CODE或OVERSEAS_NAME',
|
||||
source_value VARCHAR(128) NOT NULL COMMENT '解析后的来源仓编码或海外仓名称',
|
||||
warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '固定平台公共仓库ID',
|
||||
warehouse_code VARCHAR(64) NOT NULL COMMENT '平台仓库稳定编码快照',
|
||||
warehouse_type VARCHAR(16) NOT NULL COMMENT 'DOMESTIC或OVERSEAS',
|
||||
status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE',
|
||||
created_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
|
||||
updated_at DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_price_warehouse_mapping_source (source_type, source_value),
|
||||
KEY idx_price_warehouse_mapping_target (warehouse_id, status)
|
||||
) ENGINE=InnoDB COMMENT='价格表来源仓与固定平台公共仓映射';
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fl_price_book_version (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT '整表价格版本ID',
|
||||
tenant_id BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT '平台公共价格作用域固定为0',
|
||||
@@ -494,9 +509,21 @@ VALUES
|
||||
(3, 'CN-YIWU-01', '义乌', 'ACTIVE'),
|
||||
(4, 'CN-DONGGUAN-01', '华南仓(深圳)', 'ACTIVE'),
|
||||
(5, 'CN-DONGGUAN-01', '东莞仓', 'ACTIVE'),
|
||||
(6, 'CN-DONGGUAN-01', '深圳仓', 'ACTIVE')
|
||||
(6, 'CN-DONGGUAN-01', '深圳仓', 'ACTIVE'),
|
||||
(7, 'CN-DONGGUAN-01', '华南仓(深圳/东莞)', 'ACTIVE')
|
||||
ON DUPLICATE KEY UPDATE status = VALUES(status);
|
||||
|
||||
INSERT INTO fl_price_warehouse_mapping
|
||||
(id, source_type, source_value, warehouse_id, warehouse_code, warehouse_type, status)
|
||||
VALUES
|
||||
(1, 'ORIGIN_CODE', 'CN-YIWU-01', 193000000000200001, 'CN-YIWU-01', 'DOMESTIC', 'ACTIVE'),
|
||||
(2, 'ORIGIN_CODE', 'CN-DONGGUAN-01', 193000000000200002, 'CN-DONGGUAN-01', 'DOMESTIC', 'ACTIVE'),
|
||||
(3, 'OVERSEAS_NAME', '洛杉矶仓', 193000000000200003, 'US-LAX-01', 'OVERSEAS', 'ACTIVE'),
|
||||
(4, 'OVERSEAS_NAME', '纽约仓', 193000000000200004, 'US-NYC-01', 'OVERSEAS', 'ACTIVE')
|
||||
ON DUPLICATE KEY UPDATE
|
||||
warehouse_id = VALUES(warehouse_id), warehouse_code = VALUES(warehouse_code),
|
||||
warehouse_type = VALUES(warehouse_type), status = VALUES(status);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS fl_inbound_fee (
|
||||
id BIGINT UNSIGNED NOT NULL COMMENT '入库费用ID',
|
||||
tenant_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
|
||||
|
||||
@@ -28,6 +28,8 @@ class PriceBookSqlContractTest {
|
||||
assertThat(schema)
|
||||
.contains("CREATE TABLE IF NOT EXISTS fl_price_channel_catalog")
|
||||
.contains("CREATE TABLE IF NOT EXISTS fl_price_origin_alias")
|
||||
.contains("CREATE TABLE IF NOT EXISTS fl_price_warehouse_mapping")
|
||||
.contains("华南仓(深圳/东莞)")
|
||||
.contains("CREATE TABLE IF NOT EXISTS fl_price_book_version")
|
||||
.contains("CREATE TABLE IF NOT EXISTS fl_price_book_channel")
|
||||
.contains("price_book_version_id")
|
||||
@@ -40,6 +42,11 @@ class PriceBookSqlContractTest {
|
||||
.contains("destination_name VARCHAR(128)")
|
||||
.contains("parse_issues_json JSON NULL")
|
||||
.contains("DEFAULT 'PENDING_CONFIRMATION'");
|
||||
assertThat(schema)
|
||||
.contains("'ORIGIN_CODE', 'CN-YIWU-01', 193000000000200001")
|
||||
.contains("'ORIGIN_CODE', 'CN-DONGGUAN-01', 193000000000200002")
|
||||
.contains("'OVERSEAS_NAME', '洛杉矶仓', 193000000000200003")
|
||||
.contains("'OVERSEAS_NAME', '纽约仓', 193000000000200004");
|
||||
assertThat(channelTable)
|
||||
.contains("created_by BIGINT UNSIGNED NOT NULL COMMENT '创建人ID'")
|
||||
.contains("updated_by BIGINT UNSIGNED NOT NULL COMMENT '最后修改人ID'")
|
||||
|
||||
@@ -14,6 +14,7 @@ import com.baiyue.firstleg.entity.CarrierFbaRateEntity;
|
||||
import com.baiyue.firstleg.entity.PriceBookChannelEntity;
|
||||
import com.baiyue.firstleg.entity.PriceBookVersionEntity;
|
||||
import com.baiyue.firstleg.entity.PriceChannelCatalogEntity;
|
||||
import com.baiyue.firstleg.entity.PriceWarehouseMappingEntity;
|
||||
import com.baiyue.firstleg.repository.PriceBookRepository;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -230,6 +231,29 @@ class PlatformPriceBookServiceTest {
|
||||
.doesNotContain("DUPLICATE_RATE");
|
||||
}
|
||||
|
||||
@Test
|
||||
void initializedWarehouseMappingsBindFixedDomesticAndOverseasWarehouses() {
|
||||
CarrierFbaRateEntity overseasRate = rate(81L);
|
||||
overseasRate.setDestinationType(PricingDestinationType.OVERSEAS.name());
|
||||
overseasRate.setDestinationCode(null);
|
||||
overseasRate.setDestinationName("洛杉矶仓");
|
||||
PriceBookDtos.ParsedRate parsed = ReflectionTestUtils.invokeMethod(service, "rateDto", overseasRate);
|
||||
when(repository.activeWarehouseMappings()).thenReturn(List.of(
|
||||
warehouseMapping("ORIGIN_CODE", "CN-YIWU-01", 193000000000200001L, "CN-YIWU-01", "DOMESTIC"),
|
||||
warehouseMapping("OVERSEAS_NAME", "洛杉矶仓", 193000000000200003L, "US-LAX-01", "OVERSEAS")
|
||||
));
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<PriceBookDtos.ParsedRate> mapped = ReflectionTestUtils.invokeMethod(
|
||||
service, "applyInitializedWarehouseMappings", List.of(parsed));
|
||||
|
||||
assertThat(mapped).singleElement().satisfies(rate -> {
|
||||
assertThat(rate.originWarehouseId()).isEqualTo(193000000000200001L);
|
||||
assertThat(rate.destinationWarehouseId()).isEqualTo(193000000000200003L);
|
||||
assertThat(rate.destinationCode()).isEqualTo("US-LAX-01");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void duplicatePublishIsRejectedAfterPublishLock() {
|
||||
when(repository.findVersion(31L)).thenReturn(version(31L, PriceBookStatus.ACTIVE));
|
||||
@@ -300,6 +324,18 @@ class PlatformPriceBookServiceTest {
|
||||
List.of(new PriceBookConfirmationRequest.OriginMapping(code, id)), List.of());
|
||||
}
|
||||
|
||||
private static PriceWarehouseMappingEntity warehouseMapping(String sourceType, String sourceValue, long warehouseId,
|
||||
String warehouseCode, String warehouseType) {
|
||||
PriceWarehouseMappingEntity value = new PriceWarehouseMappingEntity();
|
||||
value.setSourceType(sourceType);
|
||||
value.setSourceValue(sourceValue);
|
||||
value.setWarehouseId(warehouseId);
|
||||
value.setWarehouseCode(warehouseCode);
|
||||
value.setWarehouseType(warehouseType);
|
||||
value.setStatus("ACTIVE");
|
||||
return value;
|
||||
}
|
||||
|
||||
private void executeTransactionsImmediately() {
|
||||
when(transactions.execute(any())).thenAnswer(invocation -> {
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
Reference in New Issue
Block a user