package queries import "database/sql" func EnsureProductSeriesAutoInfraTables(pg *sql.DB) error { stmts := []string{ ` CREATE TABLE IF NOT EXISTS mk_product_series_rule ( id BIGSERIAL PRIMARY KEY, series_id BIGINT NOT NULL REFERENCES dfgrp(id) ON DELETE CASCADE, size_group TEXT NOT NULL DEFAULT '', size_code TEXT NOT NULL, ratio_qty INTEGER NOT NULL DEFAULT 1, priority INTEGER NOT NULL DEFAULT 0, is_active BOOLEAN NOT NULL DEFAULT TRUE, source TEXT NOT NULL DEFAULT 'manual', notes TEXT NOT NULL DEFAULT '', created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), CONSTRAINT ck_mk_product_series_rule_ratio CHECK (ratio_qty > 0), CONSTRAINT uq_mk_product_series_rule UNIQUE (series_id, size_group, size_code) )`, `CREATE INDEX IF NOT EXISTS ix_mk_product_series_rule_series ON mk_product_series_rule (series_id, is_active)`, `CREATE INDEX IF NOT EXISTS ix_mk_product_series_rule_group ON mk_product_series_rule (size_group, size_code)`, ` CREATE TABLE IF NOT EXISTS mk_product_series_stock_state ( row_key TEXT PRIMARY KEY, product_code TEXT NOT NULL, color_code TEXT NOT NULL, dim3_code TEXT NOT NULL DEFAULT '', stock_hash TEXT NOT NULL DEFAULT '', total_qty NUMERIC(18,2) NOT NULL DEFAULT 0, last_seen_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now() )`, `CREATE INDEX IF NOT EXISTS ix_mk_product_series_stock_state_product ON mk_product_series_stock_state (product_code, updated_at DESC)`, ` CREATE TABLE IF NOT EXISTS mk_product_series_recalc_queue ( id BIGSERIAL PRIMARY KEY, row_key TEXT NOT NULL, product_code TEXT NOT NULL, color_code TEXT NOT NULL, dim3_code TEXT NOT NULL DEFAULT '', reason TEXT NOT NULL DEFAULT '', status TEXT NOT NULL DEFAULT 'pending', attempts SMALLINT NOT NULL DEFAULT 0, available_at TIMESTAMPTZ NOT NULL DEFAULT now(), queued_at TIMESTAMPTZ NOT NULL DEFAULT now(), processed_at TIMESTAMPTZ, last_error TEXT NOT NULL DEFAULT '', created_at TIMESTAMPTZ NOT NULL DEFAULT now(), updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), CONSTRAINT ck_mk_product_series_recalc_queue_status CHECK (status IN ('pending','processing','done','failed')) )`, `CREATE INDEX IF NOT EXISTS ix_mk_product_series_recalc_queue_status ON mk_product_series_recalc_queue (status, available_at, queued_at)`, `CREATE UNIQUE INDEX IF NOT EXISTS uq_mk_product_series_recalc_queue_pending ON mk_product_series_recalc_queue (row_key) WHERE status IN ('pending','processing')`, ` CREATE TABLE IF NOT EXISTS mk_product_series_job_log ( id BIGSERIAL PRIMARY KEY, job_name TEXT NOT NULL, reason TEXT NOT NULL DEFAULT '', started_at TIMESTAMPTZ NOT NULL DEFAULT now(), finished_at TIMESTAMPTZ, status TEXT NOT NULL DEFAULT 'running', scanned_rows INTEGER NOT NULL DEFAULT 0, changed_rows INTEGER NOT NULL DEFAULT 0, processed_rows INTEGER NOT NULL DEFAULT 0, written_rows INTEGER NOT NULL DEFAULT 0, skipped_rows INTEGER NOT NULL DEFAULT 0, error_text TEXT NOT NULL DEFAULT '' )`, `CREATE INDEX IF NOT EXISTS ix_mk_product_series_job_log_started ON mk_product_series_job_log (started_at DESC)`, } for _, stmt := range stmts { if _, err := pg.Exec(stmt); err != nil { return err } } _, err := pg.Exec(` INSERT INTO mk_product_series_rule (series_id, size_group, size_code, ratio_qty, priority, source, notes) SELECT d.id, '', BTRIM(x.size_code), 1, 0, 'dfgrp_title', 'auto-seeded from dfgrp.title' FROM dfgrp d CROSS JOIN LATERAL regexp_split_to_table(COALESCE(d.title, ''), '-') AS x(size_code) WHERE d.master='zbggseri' AND BTRIM(x.size_code) <> '' ON CONFLICT (series_id, size_group, size_code) DO NOTHING `) return err }