feat(barcode): 多条码管理(后端+迁移+GTIN校验)WIP
- 迁移 0007: 新增 product_barcode 表(一品多码),回填旧 product.gtin 为主码, 全局唯一索引保证「一码一品」,每品至多一个主码 - internal/gtin: GS1 GTIN-8/12/13/14 校验(校验位 + 拒收店内码/变量重量码/优惠券码) - 公开只读 API: 任一条码命中商品、详情返回 barcodes、搜索匹配条码 - adminstore: 商品详情含 barcodes;新增 AddBarcode/DeleteBarcode/SetPrimaryBarcode, 一码命中其他商品返回 ConflictError 供后台去重 待办(按用户要求暂停): 后台 handler 路由、投稿/审核多条码、前后端 UI Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1 @@
|
||||
DROP TABLE IF EXISTS product_barcode;
|
||||
@@ -0,0 +1,36 @@
|
||||
-- Multi-barcode support: one product can carry many GS1 barcodes
|
||||
-- (consumer unit EAN-13/UPC, case ITF-14, regional re-labels, etc.).
|
||||
-- product.gtin is kept as the denormalized "primary" barcode for
|
||||
-- backward compatibility and is mirrored from the is_primary row here.
|
||||
|
||||
CREATE TABLE product_barcode (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
product_id UUID NOT NULL REFERENCES product(id) ON DELETE CASCADE,
|
||||
gtin VARCHAR(14) NOT NULL,
|
||||
gtin_type VARCHAR(8) NOT NULL DEFAULT 'EAN13',
|
||||
pack_level VARCHAR(8) NOT NULL DEFAULT 'each',
|
||||
region VARCHAR(8),
|
||||
is_primary BOOLEAN NOT NULL DEFAULT false,
|
||||
source_id UUID REFERENCES source(id),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
CONSTRAINT product_barcode_type_chk CHECK (gtin_type IN ('EAN8','UPC','EAN13','ITF14','GTIN14')),
|
||||
CONSTRAINT product_barcode_pack_chk CHECK (pack_level IN ('each','case','pallet'))
|
||||
);
|
||||
|
||||
-- A barcode is globally unique: one code maps to exactly one product.
|
||||
CREATE UNIQUE INDEX idx_product_barcode_gtin ON product_barcode (gtin);
|
||||
CREATE INDEX idx_product_barcode_product ON product_barcode (product_id);
|
||||
-- At most one primary barcode per product.
|
||||
CREATE UNIQUE INDEX idx_product_barcode_primary ON product_barcode (product_id) WHERE is_primary;
|
||||
|
||||
-- Backfill: lift each product's existing gtin into the new table as primary.
|
||||
INSERT INTO product_barcode (product_id, gtin, gtin_type, pack_level, is_primary)
|
||||
SELECT id, gtin,
|
||||
CASE WHEN length(gtin) = 8 THEN 'EAN8'
|
||||
WHEN length(gtin) = 12 THEN 'UPC'
|
||||
WHEN length(gtin) = 14 THEN 'GTIN14'
|
||||
ELSE 'EAN13' END,
|
||||
'each', true
|
||||
FROM product
|
||||
WHERE gtin IS NOT NULL AND gtin <> ''
|
||||
ON CONFLICT (gtin) DO NOTHING;
|
||||
Reference in New Issue
Block a user