This commit is contained in:
2026-09-24 08:54:26 +08:00
parent 66c2651be7
commit 49e63eca9f
10 changed files with 23 additions and 20 deletions
@@ -2917,7 +2917,6 @@ CREATE TABLE wh_location (
id bigint unsigned NOT NULL COMMENT '库位ID(雪花ID)', id bigint unsigned NOT NULL COMMENT '库位ID(雪花ID)',
customer_id bigint unsigned NOT NULL COMMENT '数据所属租户ID', customer_id bigint unsigned NOT NULL COMMENT '数据所属租户ID',
warehouse_id bigint unsigned NOT NULL COMMENT '所属仓库ID', warehouse_id bigint unsigned NOT NULL COMMENT '所属仓库ID',
zone_code varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '仓库分区编码',
location_code varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '仓库内唯一库位编码', location_code varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '仓库内唯一库位编码',
location_type varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '库位类型', location_type varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '库位类型',
shared_overflow tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否系统共享溢出库位(A0)', shared_overflow tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否系统共享溢出库位(A0)',
@@ -2932,9 +2931,15 @@ CREATE TABLE wh_location (
version int NOT NULL DEFAULT '0' COMMENT '乐观锁版本号', version int NOT NULL DEFAULT '0' COMMENT '乐观锁版本号',
PRIMARY KEY (id), PRIMARY KEY (id),
UNIQUE KEY uk_location_code (customer_id,warehouse_id,location_code,deleted), UNIQUE KEY uk_location_code (customer_id,warehouse_id,location_code,deleted),
KEY idx_location_query (customer_id,warehouse_id,zone_code,status,deleted) KEY idx_location_query (customer_id,warehouse_id,status,deleted)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='仓库库位表:按租户和仓库维护库位及承重信息'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='仓库库位表:按租户和仓库维护库位及承重信息';
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='wh_location' AND index_name='idx_location_query'), 'ALTER TABLE wh_location DROP INDEX idx_location_query', 'SELECT 1'));
PREPARE location_zone_index_stmt FROM @ddl; EXECUTE location_zone_index_stmt; DEALLOCATE PREPARE location_zone_index_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='wh_location' AND column_name='zone_code'), 'ALTER TABLE wh_location DROP COLUMN zone_code', 'SELECT 1'));
PREPARE location_zone_column_stmt FROM @ddl; EXECUTE location_zone_column_stmt; DEALLOCATE PREPARE location_zone_column_stmt;
CREATE TABLE wh_pallet ( CREATE TABLE wh_pallet (
id bigint unsigned NOT NULL COMMENT '托盘ID(雪花ID)', id bigint unsigned NOT NULL COMMENT '托盘ID(雪花ID)',
customer_id bigint unsigned NOT NULL COMMENT '数据所属租户ID', customer_id bigint unsigned NOT NULL COMMENT '数据所属租户ID',
@@ -45,7 +45,7 @@ function contextFixture({ tenants = [{ id: '10001', status: 'ACTIVE' }], warehou
if (requestPath.includes('/inventory/balances?')) return response(page([{ id: '60001', customerId: '10001', skuCode: 'SKU-1', totalPackages: 10, availablePackages: 10, updatedAt: '2026-08-21T10:00:00' }])) if (requestPath.includes('/inventory/balances?')) return response(page([{ id: '60001', customerId: '10001', skuCode: 'SKU-1', totalPackages: 10, availablePackages: 10, updatedAt: '2026-08-21T10:00:00' }]))
if (requestPath.includes('/inventory/balances/60001/positions?')) return response([{ id: '61001', balanceId: '60001', totalPackages: 10 }]) if (requestPath.includes('/inventory/balances/60001/positions?')) return response([{ id: '61001', balanceId: '60001', totalPackages: 10 }])
if (requestPath.includes('/inventory/ledger?')) return response(page([{ id: '62001', customerId: '10001', businessType: 'STOCK_IN', beforePackages: 0, deltaPackages: 10, afterPackages: 10, occurredAt: '2026-08-21T10:00:00' }])) if (requestPath.includes('/inventory/ledger?')) return response(page([{ id: '62001', customerId: '10001', businessType: 'STOCK_IN', beforePackages: 0, deltaPackages: 10, afterPackages: 10, occurredAt: '2026-08-21T10:00:00' }]))
if (requestPath.endsWith('/warehouse-admin/20001/locations?page=1&size=20')) return response(page([{ id: '72001', customerId: '0', warehouseId: '20001', zoneCode: 'A', locationCode: 'A-01', locationType: 'STORAGE', maxLoadKg: 1000, status: 'ACTIVE' }])) if (requestPath.endsWith('/warehouse-admin/20001/locations?page=1&size=20')) return response(page([{ id: '72001', customerId: '0', warehouseId: '20001', locationCode: 'A-01', locationType: 'STORAGE', maxLoadKg: 1000, status: 'ACTIVE' }]))
if (requestPath.endsWith('/warehouse-admin/20001/locations/72001')) return response({ id: '72001', customerId: '0', warehouseId: '20001', locationCode: 'A-01', status: 'ACTIVE' }) if (requestPath.endsWith('/warehouse-admin/20001/locations/72001')) return response({ id: '72001', customerId: '0', warehouseId: '20001', locationCode: 'A-01', status: 'ACTIVE' })
if (requestPath.endsWith('/warehouse-admin/20001/locations/72002')) return createdLocation == null if (requestPath.endsWith('/warehouse-admin/20001/locations/72002')) return createdLocation == null
? response(undefined, 'A0404') : response(createdLocation) ? response(undefined, 'A0404') : response(createdLocation)
@@ -210,7 +210,7 @@ async function verifyLocationLifecycle(context, warehouseId) {
try { try {
const created = await overseasMutation(context, 'POST', '创建本轮公共库位', const created = await overseasMutation(context, 'POST', '创建本轮公共库位',
`/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}/locations`, { `/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}/locations`, {
zoneCode: 'ACC', locationCode, locationType: 'STORAGE', maxLoadKg: 1000, locationCode, locationType: 'STORAGE', maxLoadKg: 1000,
status: 'ACTIVE', remark: context.marker, status: 'ACTIVE', remark: context.marker,
}) })
locationId = id(created.data) locationId = id(created.data)
@@ -225,7 +225,7 @@ async function verifyLocationLifecycle(context, warehouseId) {
&& detail.data?.locationCode === locationCode && detail.data?.remark === context.marker, && detail.data?.locationCode === locationCode && detail.data?.remark === context.marker,
`locationId=${id(detail.data?.id) || 'missing'}, code=${detail.data?.locationCode || 'missing'}; ${trace(detail.response)}`, OPTIONS) `locationId=${id(detail.data?.id) || 'missing'}, code=${detail.data?.locationCode || 'missing'}; ${trace(detail.response)}`, OPTIONS)
const updated = await overseasMutation(context, 'PUT', '编辑本轮公共库位', detailPath, { const updated = await overseasMutation(context, 'PUT', '编辑本轮公共库位', detailPath, {
zoneCode: 'ACC', locationCode, locationType: 'STORAGE', maxLoadKg: 1200, locationCode, locationType: 'STORAGE', maxLoadKg: 1200,
status: 'ACTIVE', remark: `${context.marker}-edited`, status: 'ACTIVE', remark: `${context.marker}-edited`,
}) })
context.assert(MODULE, '公共库位编辑成功', updated.response, voidMutationSucceeded(updated), context.assert(MODULE, '公共库位编辑成功', updated.response, voidMutationSucceeded(updated),
@@ -14,7 +14,6 @@ public final class LocationRequests {
} }
public record SaveRequest( public record SaveRequest(
@NotBlank @Size(max = 50) String zoneCode,
@NotBlank @Size(max = 64) String locationCode, @NotBlank @Size(max = 64) String locationCode,
@NotBlank @Size(max = 32) String locationType, @NotBlank @Size(max = 32) String locationType,
@NotNull @DecimalMin(value = "0.000", inclusive = false) BigDecimal maxLoadKg, @NotNull @DecimalMin(value = "0.000", inclusive = false) BigDecimal maxLoadKg,
@@ -26,7 +25,6 @@ public final class LocationRequests {
public record QueryRequest( public record QueryRequest(
@Min(1) long page, @Min(1) long page,
@Min(1) @Max(200) long size, @Min(1) @Max(200) long size,
String zoneCode,
String locationType, String locationType,
String status, String status,
String keyword String keyword
@@ -17,7 +17,6 @@ public class WarehouseLocationEntity extends BaseEntity {
private Long id; private Long id;
private Long customerId; private Long customerId;
private Long warehouseId; private Long warehouseId;
private String zoneCode;
private String locationCode; private String locationCode;
private String locationType; private String locationType;
/** A0 is a system-managed shared overflow location; normal locations are exclusive. */ /** A0 is a system-managed shared overflow location; normal locations are exclusive. */
@@ -14,10 +14,10 @@ public interface WarehouseLocationMapper extends BaseMapper<WarehouseLocationEnt
*/ */
@Insert(""" @Insert("""
INSERT IGNORE INTO wh_location INSERT IGNORE INTO wh_location
(id, customer_id, warehouse_id, zone_code, location_code, location_type, (id, customer_id, warehouse_id, location_code, location_type,
max_load_kg, status, remark, deleted, version) max_load_kg, status, remark, deleted, version)
VALUES VALUES
(#{location.id}, #{location.customerId}, #{location.warehouseId}, #{location.zoneCode}, (#{location.id}, #{location.customerId}, #{location.warehouseId},
#{location.locationCode}, #{location.locationType}, #{location.maxLoadKg}, #{location.locationCode}, #{location.locationType}, #{location.maxLoadKg},
#{location.status}, #{location.remark}, 0, 0) #{location.status}, #{location.remark}, 0, 0)
""") """)
@@ -94,13 +94,11 @@ public class WarehouseResourceRepository {
var wrapper = new LambdaQueryWrapper<WarehouseLocationEntity>() var wrapper = new LambdaQueryWrapper<WarehouseLocationEntity>()
.eq(WarehouseLocationEntity::getCustomerId, customerId) .eq(WarehouseLocationEntity::getCustomerId, customerId)
.eq(WarehouseLocationEntity::getWarehouseId, warehouseId) .eq(WarehouseLocationEntity::getWarehouseId, warehouseId)
.eq(StringUtils.hasText(query.zoneCode()), WarehouseLocationEntity::getZoneCode, query.zoneCode())
.eq(StringUtils.hasText(query.locationType()), WarehouseLocationEntity::getLocationType, query.locationType()) .eq(StringUtils.hasText(query.locationType()), WarehouseLocationEntity::getLocationType, query.locationType())
.eq(StringUtils.hasText(query.status()), WarehouseLocationEntity::getStatus, query.status()) .eq(StringUtils.hasText(query.status()), WarehouseLocationEntity::getStatus, query.status())
.and(StringUtils.hasText(query.keyword()), q -> q .and(StringUtils.hasText(query.keyword()), q -> q
.like(WarehouseLocationEntity::getLocationCode, query.keyword()) .like(WarehouseLocationEntity::getLocationCode, query.keyword())
.or().like(WarehouseLocationEntity::getZoneCode, query.keyword())) )
.orderByAsc(WarehouseLocationEntity::getZoneCode)
.orderByAsc(WarehouseLocationEntity::getLocationCode); .orderByAsc(WarehouseLocationEntity::getLocationCode);
return PageResult.from(locations.selectPage(new Page<>(query.page(), query.size()), wrapper)); return PageResult.from(locations.selectPage(new Page<>(query.page(), query.size()), wrapper));
} }
@@ -185,7 +185,6 @@ public class WarehouseResourceService {
location.setId(IdWorker.getId()); location.setId(IdWorker.getId());
location.setCustomerId(customerId); location.setCustomerId(customerId);
location.setWarehouseId(warehouseId); location.setWarehouseId(warehouseId);
location.setZoneCode("DEFAULT");
location.setLocationCode(locationCode); location.setLocationCode(locationCode);
location.setLocationType("VIRTUAL"); location.setLocationType("VIRTUAL");
location.setMaxLoadKg(new java.math.BigDecimal("999999999.000")); location.setMaxLoadKg(new java.math.BigDecimal("999999999.000"));
@@ -214,7 +213,6 @@ public class WarehouseResourceService {
location.setId(IdWorker.getId()); location.setId(IdWorker.getId());
location.setCustomerId(PUBLIC_RESOURCE_SCOPE); location.setCustomerId(PUBLIC_RESOURCE_SCOPE);
location.setWarehouseId(warehouseId); location.setWarehouseId(warehouseId);
location.setZoneCode("OVERFLOW");
location.setLocationCode(SHARED_OVERFLOW_LOCATION_CODE); location.setLocationCode(SHARED_OVERFLOW_LOCATION_CODE);
location.setLocationType("SHARED_OVERFLOW"); location.setLocationType("SHARED_OVERFLOW");
location.setSharedOverflow(true); location.setSharedOverflow(true);
@@ -424,7 +422,6 @@ public class WarehouseResourceService {
WarehouseLocationEntity entity = new WarehouseLocationEntity(); WarehouseLocationEntity entity = new WarehouseLocationEntity();
entity.setCustomerId(customerId); entity.setCustomerId(customerId);
entity.setWarehouseId(warehouseId); entity.setWarehouseId(warehouseId);
entity.setZoneCode(request.zoneCode());
entity.setLocationCode(request.locationCode()); entity.setLocationCode(request.locationCode());
entity.setLocationType(request.locationType()); entity.setLocationType(request.locationType());
entity.setMaxLoadKg(request.maxLoadKg()); entity.setMaxLoadKg(request.maxLoadKg());
@@ -9,7 +9,6 @@ CREATE TABLE IF NOT EXISTS wh_location (
id BIGINT UNSIGNED NOT NULL COMMENT '库位ID(雪花ID)', id BIGINT UNSIGNED NOT NULL COMMENT '库位ID(雪花ID)',
customer_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID', customer_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '所属仓库ID', warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '所属仓库ID',
zone_code VARCHAR(50) NOT NULL COMMENT '仓库分区编码',
location_code VARCHAR(64) NOT NULL COMMENT '仓库内唯一库位编码', location_code VARCHAR(64) NOT NULL COMMENT '仓库内唯一库位编码',
location_type VARCHAR(32) NOT NULL COMMENT '库位类型', location_type VARCHAR(32) NOT NULL COMMENT '库位类型',
shared_overflow TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否系统共享溢出库位(A0)', shared_overflow TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否系统共享溢出库位(A0)',
@@ -24,9 +23,17 @@ CREATE TABLE IF NOT EXISTS wh_location (
version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号', version INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
PRIMARY KEY (id), PRIMARY KEY (id),
UNIQUE KEY uk_location_code (customer_id, warehouse_id, location_code, deleted), UNIQUE KEY uk_location_code (customer_id, warehouse_id, location_code, deleted),
KEY idx_location_query (customer_id, warehouse_id, zone_code, status, deleted) KEY idx_location_query (customer_id, warehouse_id, status, deleted)
) ENGINE=InnoDB COMMENT='仓库库位表:按租户和仓库维护库位及承重信息'; ) ENGINE=InnoDB COMMENT='仓库库位表:按租户和仓库维护库位及承重信息';
-- Remove the retired zone concept from installations created by the previous schema.
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.statistics WHERE table_schema=DATABASE() AND table_name='wh_location' AND index_name='idx_location_query'), 'ALTER TABLE wh_location DROP INDEX idx_location_query', 'SELECT 1'));
PREPARE location_zone_index_stmt FROM @ddl; EXECUTE location_zone_index_stmt; DEALLOCATE PREPARE location_zone_index_stmt;
SET @ddl = (SELECT IF(EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema=DATABASE() AND table_name='wh_location' AND column_name='zone_code'), 'ALTER TABLE wh_location DROP COLUMN zone_code', 'SELECT 1'));
PREPARE location_zone_column_stmt FROM @ddl; EXECUTE location_zone_column_stmt; DEALLOCATE PREPARE location_zone_column_stmt;
CREATE TABLE IF NOT EXISTS wh_pallet ( CREATE TABLE IF NOT EXISTS wh_pallet (
id BIGINT UNSIGNED NOT NULL COMMENT '托盘ID(雪花ID)', id BIGINT UNSIGNED NOT NULL COMMENT '托盘ID(雪花ID)',
customer_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID', customer_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
@@ -97,7 +104,6 @@ ALTER TABLE wh_location
MODIFY COLUMN id BIGINT UNSIGNED NOT NULL COMMENT '库位ID(雪花ID)', MODIFY COLUMN id BIGINT UNSIGNED NOT NULL COMMENT '库位ID(雪花ID)',
MODIFY COLUMN customer_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID', MODIFY COLUMN customer_id BIGINT UNSIGNED NOT NULL COMMENT '数据所属租户ID',
MODIFY COLUMN warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '所属仓库ID', MODIFY COLUMN warehouse_id BIGINT UNSIGNED NOT NULL COMMENT '所属仓库ID',
MODIFY COLUMN zone_code VARCHAR(50) NOT NULL COMMENT '仓库分区编码',
MODIFY COLUMN location_code VARCHAR(64) NOT NULL COMMENT '仓库内唯一库位编码', MODIFY COLUMN location_code VARCHAR(64) NOT NULL COMMENT '仓库内唯一库位编码',
MODIFY COLUMN location_type VARCHAR(32) NOT NULL COMMENT '库位类型', MODIFY COLUMN location_type VARCHAR(32) NOT NULL COMMENT '库位类型',
MODIFY COLUMN shared_overflow TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否系统共享溢出库位(A0)', MODIFY COLUMN shared_overflow TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否系统共享溢出库位(A0)',
@@ -243,7 +243,7 @@ class WarehouseResourceServiceTest {
} }
private static LocationRequests.SaveRequest locationRequest(String code) { private static LocationRequests.SaveRequest locationRequest(String code) {
return new LocationRequests.SaveRequest("A", code, "STORAGE", return new LocationRequests.SaveRequest(code, "STORAGE",
new BigDecimal("1000.000"), "ACTIVE", null); new BigDecimal("1000.000"), "ACTIVE", null);
} }