feat(M09-D1): 完成商品目录与库存流水底座
This commit is contained in:
@@ -120,6 +120,15 @@ const cleaningSettlementIntegrityDownSql = read(
|
||||
const cleaningSettlementIntegrityVerifySql = read(
|
||||
'database/migrations/2026081006_m09c_cleaning_settlement_integrity.verify.sql'
|
||||
);
|
||||
const productInventoryUpSql = read(
|
||||
'database/migrations/2026081107_m09d1_product_inventory_foundation.up.sql'
|
||||
);
|
||||
const productInventoryDownSql = read(
|
||||
'database/migrations/2026081107_m09d1_product_inventory_foundation.down.sql'
|
||||
);
|
||||
const productInventoryVerifySql = read(
|
||||
'database/migrations/2026081107_m09d1_product_inventory_foundation.verify.sql'
|
||||
);
|
||||
|
||||
const coreTables = [
|
||||
'qipai_schema_migrations',
|
||||
@@ -536,4 +545,70 @@ assert.match(cleaningSettlementIntegrityVerifySql, /'2026081006'/);
|
||||
assert.match(franchiseDownSql, /DROP TABLE IF EXISTS qipai_franchise_follow_ups/);
|
||||
assert.match(franchiseVerifySql, /idx_qipai_franchise_follow_up_history/);
|
||||
|
||||
console.log('PASS: M01-B through M09-C migration contracts are present.');
|
||||
for (const table of [
|
||||
'qipai_product_categories',
|
||||
'qipai_products',
|
||||
'qipai_product_skus',
|
||||
'qipai_product_store_listings',
|
||||
'qipai_product_store_settings',
|
||||
'qipai_product_store_hours',
|
||||
'qipai_product_inventory',
|
||||
'qipai_product_inventory_requests',
|
||||
'qipai_product_inventory_ledger'
|
||||
]) {
|
||||
assert.match(productInventoryUpSql, new RegExp(`CREATE TABLE IF NOT EXISTS ${table}`));
|
||||
assert.match(productInventoryDownSql, new RegExp(`DROP TABLE IF EXISTS ${table}`));
|
||||
assert.match(productInventoryVerifySql, new RegExp(`'${table}'`));
|
||||
}
|
||||
assert.match(productInventoryUpSql, /ADD UNIQUE KEY uq_qipai_stores_tenant_id/);
|
||||
assert.match(productInventoryUpSql, /ADD UNIQUE KEY uq_qipai_users_tenant_id/);
|
||||
assert.match(productInventoryUpSql, /ADD COLUMN checksum CHAR\(64\)/);
|
||||
assert.match(productInventoryUpSql, /store_id BIGINT UNSIGNED NOT NULL/);
|
||||
assert.match(productInventoryUpSql, /uq_qipai_product_category_scope_id/);
|
||||
assert.match(
|
||||
productInventoryUpSql,
|
||||
/FOREIGN KEY \(tenant_id, store_id, category_id\)[\s\S]*qipai_product_categories/
|
||||
);
|
||||
assert.match(productInventoryUpSql, /delivery_enabled TINYINT\(1\) NOT NULL DEFAULT 1/);
|
||||
assert.match(productInventoryUpSql, /storage_enabled TINYINT\(1\) NOT NULL DEFAULT 0/);
|
||||
assert.match(productInventoryUpSql, /default_inventory_policy VARCHAR\(16\)/);
|
||||
assert.match(productInventoryUpSql, /default_inventory_policy IN \('TRACKED', 'UNLIMITED'\)/);
|
||||
assert.match(productInventoryUpSql, /manual_paused_at DATETIME\(3\) NULL/);
|
||||
assert.match(productInventoryUpSql, /manual_paused_until DATETIME\(3\) NULL/);
|
||||
assert.match(productInventoryUpSql, /manual_pause_reason VARCHAR\(512\)/);
|
||||
assert.match(productInventoryUpSql, /crosses_midnight TINYINT\(1\) NOT NULL DEFAULT 0/);
|
||||
assert.match(productInventoryUpSql, /crosses_midnight = 1 AND close_minute <= open_minute/);
|
||||
assert.match(productInventoryUpSql, /loss_quantity BIGINT UNSIGNED NOT NULL DEFAULT 0/);
|
||||
assert.match(productInventoryUpSql, /loss_delta BIGINT NOT NULL DEFAULT 0/);
|
||||
assert.match(productInventoryUpSql, /loss_after BIGINT UNSIGNED NOT NULL/);
|
||||
for (const operation of [
|
||||
'CONFIGURE', 'INBOUND', 'ADJUST', 'LOCK', 'RELEASE',
|
||||
'DEDUCT', 'STOCKTAKE', 'LOSS', 'RETURN'
|
||||
]) assert.match(productInventoryUpSql, new RegExp(`'${operation}'`));
|
||||
assert.match(productInventoryUpSql, /uq_qipai_product_inventory_ledger_request/);
|
||||
assert.match(productInventoryUpSql, /uq_qipai_product_inventory_request/);
|
||||
assert.match(productInventoryUpSql, /fk_qipai_product_inventory_ledger_request/);
|
||||
assert.match(productInventoryUpSql, /uq_qipai_product_inventory_ledger_version/);
|
||||
assert.match(productInventoryUpSql, /qipai_product_inventory_ledger_no_update/);
|
||||
assert.match(productInventoryUpSql, /qipai_product_inventory_ledger_no_delete/);
|
||||
for (const permission of [
|
||||
'product.catalog.read', 'product.catalog.write', 'inventory.read', 'inventory.adjust'
|
||||
]) {
|
||||
assert.match(productInventoryUpSql, new RegExp(permission.replace('.', '\\.')));
|
||||
assert.match(productInventoryDownSql, new RegExp(permission.replace('.', '\\.')));
|
||||
assert.match(productInventoryVerifySql, new RegExp(permission.replace('.', '\\.')));
|
||||
}
|
||||
assert.match(productInventoryUpSql, /r\.code = 'STAFF'/);
|
||||
assert.match(productInventoryUpSql, /r\.code IN \('STORE_ADMIN', 'TENANT_ADMIN', 'PLATFORM_ADMIN'\)/);
|
||||
assert.match(productInventoryDownSql, /DROP INDEX uq_qipai_stores_tenant_id/);
|
||||
assert.match(productInventoryDownSql, /DROP INDEX uq_qipai_users_tenant_id/);
|
||||
assert.match(productInventoryDownSql, /DROP COLUMN checksum/);
|
||||
assert.match(
|
||||
productInventoryUpSql,
|
||||
/FOREIGN KEY \(tenant_id, operator_id\) REFERENCES qipai_users\(tenant_id, id\)/
|
||||
);
|
||||
assert.match(productInventoryVerifySql, /fully_granted_product_roles/);
|
||||
assert.match(productInventoryVerifySql, /'uq_qipai_product_inventory_ledger_version'/);
|
||||
assert.match(productInventoryVerifySql, /'2026081107'/);
|
||||
|
||||
console.log('PASS: M01-B through M09-D1 migration contracts are present.');
|
||||
|
||||
Reference in New Issue
Block a user