-- ============================================================================= -- 一次性迁移:盘点会话表(stocktake_session) -- -- 背景 -- 盘点原本只有 stocktake_draft(草稿行),没有任何「会话」实体,导致: -- 1. 盲盘/明盘、全盘/抽盘这类**会话级配置**无处存放; -- 2. 「空会话」无法表示 —— 会话开了但还没扫码时表里没有行, -- 旧实现只能靠 max(scan_time) 猜哪个会话活跃,于是新开的空会话 -- 会被其他 PDA 忽略、反而加入上一轮的旧会话; -- 3. 没有状态字段,「已结束」的会话仍会被当成活跃会话返回。 -- -- 本表把活跃会话判定变成 company_name + status='active' 的精确查询。 -- -- 唯一部分索引 -- 保证「一个公司同时只能有一个 status='active' 的会话」。 -- 多台 PDA 同时点「开启新盘点」时,后到的那条会在数据库层被挡住, -- 不会产生两个并行活跃会话导致进度分裂。 -- 因此 /draft/start-new 必须先把该公司原有的活跃会话置为 finished -- 再插入新记录(同一事务内完成)。 -- -- 存量数据 -- 不做回填。stocktake_draft 里的历史会话没有对应的会话行, -- 部署后会显示为「无进行中的盘点」,旧草稿仍留在原表不受影响。 -- -- 执行: docker exec -i inventory_db psql -U test -d inventory_system < 本文件 -- ============================================================================= BEGIN; CREATE TABLE IF NOT EXISTS stocktake_session ( session_id varchar(100) PRIMARY KEY, company_name varchar(255) NOT NULL, -- open=明盘(可看账面数) / blind=盲盘(隐藏账面数与差异) mode varchar(20) NOT NULL DEFAULT 'open', -- full=全仓盘点 / active=活跃库位抽盘 scope_type varchar(20) NOT NULL DEFAULT 'full', -- 范围明细,例: {"days":30,"top_n":50,"locations":[...],"uuids":[...]} scope_config jsonb NOT NULL DEFAULT '{}'::jsonb, status varchar(20) NOT NULL DEFAULT 'active', created_by varchar(100), created_at timestamp without time zone DEFAULT timezone('Asia/Shanghai', now()), finished_at timestamp without time zone, CONSTRAINT ck_stocktake_session_mode CHECK (mode IN ('open', 'blind')), CONSTRAINT ck_stocktake_session_scope CHECK (scope_type IN ('full', 'active')), CONSTRAINT ck_stocktake_session_status CHECK (status IN ('active', 'finished')) ); -- 活跃会话查询的主路径 CREATE INDEX IF NOT EXISTS ix_stocktake_session_company_status ON stocktake_session(company_name, status); -- ★ 一个公司同时只能有一个活跃会话 CREATE UNIQUE INDEX IF NOT EXISTS uq_stocktake_session_one_active ON stocktake_session(company_name) WHERE status = 'active'; COMMIT;