feat(M09-D2): 完成商品订单与库存占用生命周期
This commit is contained in:
@@ -129,6 +129,15 @@ const productInventoryDownSql = read(
|
||||
const productInventoryVerifySql = read(
|
||||
'database/migrations/2026081107_m09d1_product_inventory_foundation.verify.sql'
|
||||
);
|
||||
const productOrderPaymentUpSql = read(
|
||||
'database/migrations/2026081108_m09d2_product_order_payment_inventory.up.sql'
|
||||
);
|
||||
const productOrderPaymentDownSql = read(
|
||||
'database/migrations/2026081108_m09d2_product_order_payment_inventory.down.sql'
|
||||
);
|
||||
const productOrderPaymentVerifySql = read(
|
||||
'database/migrations/2026081108_m09d2_product_order_payment_inventory.verify.sql'
|
||||
);
|
||||
|
||||
const coreTables = [
|
||||
'qipai_schema_migrations',
|
||||
@@ -611,4 +620,68 @@ 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.');
|
||||
for (const table of [
|
||||
'qipai_product_orders',
|
||||
'qipai_product_order_items',
|
||||
'qipai_product_order_events',
|
||||
'qipai_product_payments',
|
||||
'qipai_product_refunds',
|
||||
'qipai_product_payment_callbacks',
|
||||
'qipai_product_refund_events'
|
||||
]) {
|
||||
assert.match(productOrderPaymentUpSql, new RegExp(`CREATE TABLE IF NOT EXISTS ${table}\\b`));
|
||||
assert.match(productOrderPaymentDownSql, new RegExp(`DROP TABLE IF EXISTS ${table}\\b`));
|
||||
assert.match(productOrderPaymentVerifySql, new RegExp(`'${table}'`));
|
||||
}
|
||||
assert.doesNotMatch(productOrderPaymentUpSql, /\bDECIMAL\b/i);
|
||||
for (const state of [
|
||||
'PENDING_PAYMENT', 'PAID', 'ACCEPTED', 'DELIVERING',
|
||||
'READY_FOR_SELF_SERVICE', 'COMPLETED', 'CANCELLED',
|
||||
'REFUNDING', 'REFUNDED', 'REFUND_FAILED'
|
||||
]) assert.match(productOrderPaymentUpSql, new RegExp(`'${state}'`));
|
||||
assert.match(productOrderPaymentUpSql, /fulfillment_mode = 'DELIVERY' AND room_order_id IS NOT NULL/);
|
||||
assert.match(productOrderPaymentUpSql, /fulfillment_mode = 'SELF_SERVICE' AND room_order_id IS NULL/);
|
||||
assert.match(productOrderPaymentUpSql, /subtotal_cents = unit_price_cents \* quantity/);
|
||||
for (const snapshotColumn of [
|
||||
'product_code', 'product_name', 'sku_code', 'sku_name',
|
||||
'unit_name', 'attributes_snapshot', 'unit_price_cents', 'quantity', 'subtotal_cents'
|
||||
]) assert.match(productOrderPaymentUpSql, new RegExp(`\\b${snapshotColumn}\\b`));
|
||||
assert.match(productOrderPaymentUpSql, /order_no VARCHAR\(64\) CHARACTER SET ascii COLLATE ascii_bin/);
|
||||
assert.match(productOrderPaymentUpSql, /payment_no VARCHAR\(64\) CHARACTER SET ascii COLLATE ascii_bin/);
|
||||
assert.match(productOrderPaymentUpSql, /refund_no VARCHAR\(64\) CHARACTER SET ascii COLLATE ascii_bin/);
|
||||
assert.match(productOrderPaymentUpSql, /callback_id VARCHAR\(128\) CHARACTER SET ascii COLLATE ascii_bin/);
|
||||
assert.match(productOrderPaymentUpSql, /inventory_business_id VARCHAR\(128\) COLLATE utf8mb4_bin/);
|
||||
assert.match(productOrderPaymentUpSql, /request_fingerprint CHAR\(64\) CHARACTER SET ascii COLLATE ascii_bin/);
|
||||
assert.match(productOrderPaymentUpSql, /uq_qipai_product_order_client_request/);
|
||||
assert.match(productOrderPaymentUpSql, /uq_qipai_product_payment_client_request/);
|
||||
assert.match(productOrderPaymentUpSql, /uq_qipai_product_payment_provider_id/);
|
||||
assert.match(productOrderPaymentUpSql, /uq_qipai_product_payment_callback_provider/);
|
||||
assert.match(productOrderPaymentUpSql, /uq_qipai_product_refund_client_request/);
|
||||
assert.match(productOrderPaymentUpSql, /uq_qipai_product_refund_provider_id/);
|
||||
assert.match(productOrderPaymentUpSql, /uq_qipai_product_payment_active_order/);
|
||||
assert.match(productOrderPaymentUpSql, /status IN \('PENDING', 'PROCESSING'\) THEN order_id/);
|
||||
assert.match(productOrderPaymentUpSql, /uq_qipai_product_refund_active_payment/);
|
||||
assert.match(productOrderPaymentUpSql, /status IN \('PENDING', 'PROCESSING'\) THEN payment_id/);
|
||||
assert.match(productOrderPaymentUpSql, /fk_qipai_product_order_inventory_request/);
|
||||
assert.match(productOrderPaymentUpSql, /fk_qipai_product_refund_inventory_request/);
|
||||
assert.match(productOrderPaymentUpSql, /inventory_disposition = 'RESTOCK'/);
|
||||
assert.match(productOrderPaymentUpSql, /inventory_disposition = 'NO_RESTOCK'/);
|
||||
assert.match(productOrderPaymentUpSql, /inventory_status IN \('LOCKED', 'DEDUCTED', 'RELEASED', 'RETURNED'\)/);
|
||||
assert.match(productOrderPaymentUpSql, /'COMPENSATION_REQUIRED', 'REFUNDED'/);
|
||||
assert.match(productOrderPaymentUpSql, /qipai_product_order_items_no_update/);
|
||||
assert.match(productOrderPaymentUpSql, /qipai_product_order_items_no_delete/);
|
||||
assert.match(productOrderPaymentUpSql, /qipai_product_order_events_no_update/);
|
||||
assert.match(productOrderPaymentUpSql, /qipai_product_order_events_no_delete/);
|
||||
assert.match(productOrderPaymentUpSql, /qipai_product_refund_events_no_update/);
|
||||
assert.match(productOrderPaymentUpSql, /qipai_product_refund_events_no_delete/);
|
||||
for (const permission of ['goods.order.read', 'goods.order.manage']) {
|
||||
const pattern = new RegExp(permission.replace('.', '\\.'));
|
||||
assert.match(productOrderPaymentUpSql, pattern);
|
||||
assert.match(productOrderPaymentDownSql, pattern);
|
||||
assert.match(productOrderPaymentVerifySql, pattern);
|
||||
}
|
||||
assert.match(productOrderPaymentUpSql, /r\.code IN \('STAFF', 'STORE_ADMIN', 'TENANT_ADMIN', 'PLATFORM_ADMIN'\)/);
|
||||
assert.match(productOrderPaymentVerifySql, /fully_granted_goods_order_roles/);
|
||||
assert.match(productOrderPaymentVerifySql, /'2026081108'/);
|
||||
|
||||
console.log('PASS: M01-B through M09-D2 migration contracts are present.');
|
||||
|
||||
Reference in New Issue
Block a user