清理履约假草稿商品残留关联
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
-- 167_fulfillment_invalid_draft_product_cleanup.sql
|
||||
--
|
||||
-- 迁移 166 已停止生成并归档接单平台的 tpl:<内部SKU> 假草稿商品。
|
||||
-- 待判定履约记录仍可能保留这些商品的派生关联,需要在重试前清空,
|
||||
-- 避免页面继续展示旧商品或后续成本归集到错误商品。
|
||||
|
||||
WITH invalid_products AS (
|
||||
SELECT product.id
|
||||
FROM product_catalog product
|
||||
WHERE product.source_kind = 'work_order'
|
||||
AND product.canonical_sku LIKE 'tpl:%'
|
||||
AND COALESCE(product.attributes_json ->> 'draft', 'false') = 'true'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM work_product_rules rule
|
||||
WHERE rule.canonical_product_id = product.id
|
||||
)
|
||||
)
|
||||
UPDATE fulfillments fulfillment
|
||||
SET canonical_product_id = NULL,
|
||||
updated_at = NOW()
|
||||
FROM invalid_products invalid
|
||||
WHERE fulfillment.canonical_product_id = invalid.id;
|
||||
|
||||
CREATE OR REPLACE FUNCTION assert_fulfillment_product_not_invalid_draft()
|
||||
RETURNS trigger
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
IF NEW.canonical_product_id IS NULL THEN
|
||||
RETURN NEW;
|
||||
END IF;
|
||||
|
||||
IF EXISTS (
|
||||
SELECT 1
|
||||
FROM product_catalog product
|
||||
WHERE product.id = NEW.canonical_product_id
|
||||
AND product.source_kind = 'work_order'
|
||||
AND product.canonical_sku LIKE 'tpl:%'
|
||||
AND COALESCE(product.attributes_json ->> 'draft', 'false') = 'true'
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM work_product_rules rule
|
||||
WHERE rule.canonical_product_id = product.id
|
||||
)
|
||||
) THEN
|
||||
RAISE EXCEPTION
|
||||
'fulfillment % cannot reference invalid work-order draft product %',
|
||||
NEW.order_item_id,
|
||||
NEW.canonical_product_id
|
||||
USING ERRCODE = '23503',
|
||||
HINT = 'Attach the canonical product from the matched work_product_rule instead.';
|
||||
END IF;
|
||||
|
||||
RETURN NEW;
|
||||
END;
|
||||
$$;
|
||||
|
||||
DROP TRIGGER IF EXISTS trg_fulfillments_invalid_draft_product
|
||||
ON fulfillments;
|
||||
CREATE TRIGGER trg_fulfillments_invalid_draft_product
|
||||
BEFORE INSERT OR UPDATE OF canonical_product_id
|
||||
ON fulfillments
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION assert_fulfillment_product_not_invalid_draft();
|
||||
|
||||
COMMENT ON FUNCTION assert_fulfillment_product_not_invalid_draft() IS
|
||||
'履约商品不能指向接单平台历史伪造的 tpl 草稿商品;必须使用真实接单模板商品';
|
||||
@@ -281,6 +281,30 @@ test(
|
||||
finalFulfillments.rows.every((row) => row.issue_code === '' && row.pending_reason === null),
|
||||
)
|
||||
|
||||
const invalidDraftProduct = await query<{ id: number }>(
|
||||
`INSERT INTO product_catalog (
|
||||
canonical_sku, canonical_name, category, unit_name, source_kind, status,
|
||||
attributes_json, created_at, updated_at
|
||||
) VALUES (
|
||||
$1, '历史假草稿商品', '接单测试', '件', 'work_order', 'archived',
|
||||
'{"draft":true}'::jsonb, NOW(), NOW()
|
||||
) RETURNING id`,
|
||||
[`tpl:invalid-${suffix}`],
|
||||
)
|
||||
const invalidDraftProductId = Number(invalidDraftProduct.rows[0]!.id)
|
||||
productIds.push(invalidDraftProductId)
|
||||
await assert.rejects(
|
||||
() =>
|
||||
query(
|
||||
`UPDATE fulfillments
|
||||
SET canonical_product_id = $2,
|
||||
updated_at = NOW()
|
||||
WHERE order_item_id = $1`,
|
||||
[orderItemIds[0], invalidDraftProductId],
|
||||
),
|
||||
/invalid work-order draft product/,
|
||||
)
|
||||
|
||||
await assert.rejects(
|
||||
() =>
|
||||
query(
|
||||
|
||||
Reference in New Issue
Block a user