-- =====================================================================
-- CQHXDB / 到货核销数据持久化 schema
-- 设计：统一核心表 + JSONB raw 兜底（保留站点原始全列，一字段不丢）
-- 幂等：业务唯一键 UPSERT，重复下载天然合并、零冗余
-- 表：expected_record（运单级）/ actual_record（扫描件级）
--     / undelivered_record（百世站点直供未到明细，子单级）
-- =====================================================================

-- 隔离到专用 schema（不污染 public）；表名无需再加前缀。
CREATE SCHEMA IF NOT EXISTS inbound_verify;
SET search_path TO inbound_verify;

-- 应到货物（运单级：一运单一行；按运单号去重 keep-first 后入库）
CREATE TABLE IF NOT EXISTS expected_record (
    id              BIGSERIAL    PRIMARY KEY,
    site            TEXT         NOT NULL,   -- 站点：顺心 / 中通 / 韵达 / 安能
    waybill_no      TEXT         NOT NULL,   -- 运单基号（业务唯一键，去重键）
    handover_no     TEXT,                     -- 交接单号
    handover_pieces INTEGER,                  -- 交接件数（应到件数口径）
    order_pieces    INTEGER,                  -- 录单件数
    business_date   DATE,                     -- 业务日期（属性，非唯一键；读不到则 NULL）
    out_date        DATE,                     -- 出库日（批次归属日口径；从 raw.出库时间 解析）
    batch_out_date  DATE,                     -- 批次归属日（同交接单号出库日众数，并列取较早）
    raw             JSONB        NOT NULL,    -- 站点原始全列（key=原列名）
    ingested_at     TIMESTAMPTZ  NOT NULL DEFAULT now(),
    UNIQUE (site, waybill_no)
);
CREATE INDEX IF NOT EXISTS idx_expected_site_date ON expected_record (site, business_date);
CREATE INDEX IF NOT EXISTS idx_expected_handover ON expected_record (site, handover_no);
CREATE INDEX IF NOT EXISTS idx_expected_out_date ON expected_record (site, out_date);
CREATE INDEX IF NOT EXISTS idx_expected_batch_out_date ON expected_record (site, batch_out_date);

-- 实到货物（扫描件级：一扫描一行；每扫描一件系统生成一个单号）
CREATE TABLE IF NOT EXISTS actual_record (
    id           BIGSERIAL    PRIMARY KEY,
    site         TEXT         NOT NULL,
    waybill_no   TEXT         NOT NULL,   -- 运单基号（由扫描单号推导）
    piece_no     TEXT         NOT NULL,   -- 扫描单号 / 子单号（业务唯一键）
    scan_time    TIMESTAMPTZ,              -- 扫描时间（尽力解析，失败存 NULL，原始值在 raw）
    scan_site    TEXT,                     -- 扫描网点
    raw          JSONB        NOT NULL,
    ingested_at  TIMESTAMPTZ  NOT NULL DEFAULT now(),
    UNIQUE (site, piece_no)
);
CREATE INDEX IF NOT EXISTS idx_actual_waybill   ON actual_record (site, waybill_no);
CREATE INDEX IF NOT EXISTS idx_actual_scan_time ON actual_record (scan_time);

-- 应到未到（百世站点直供未到明细：子单级）
CREATE TABLE IF NOT EXISTS undelivered_record (
    id           BIGSERIAL    PRIMARY KEY,
    site         TEXT         NOT NULL,   -- 百世
    waybill_no   TEXT,                     -- 运单号
    piece_no     TEXT,                     -- 子单号（业务唯一键）
    biz_type     TEXT,                     -- 类型
    last_scan    TEXT,                     -- 最新扫描记录
    raw          JSONB        NOT NULL,
    ingested_at  TIMESTAMPTZ  NOT NULL DEFAULT now(),
    UNIQUE (site, piece_no)
);

-- 百世日聚合（应扫/已扫基数：站级日聚合，区别于运单级/件级/子单级表）
CREATE TABLE IF NOT EXISTS baishi_daily_stats (
    id                 BIGSERIAL    PRIMARY KEY,
    site               TEXT         NOT NULL,   -- 百世
    business_date      DATE         NOT NULL,   -- 业务日期（百世固定当天）
    expected_pieces    INTEGER,                  -- 应扫（应到基数）
    arrived_pieces     INTEGER,                  -- 已扫（实到基数）
    undelivered_pieces INTEGER,                  -- 未扫（=应扫-已扫，任一缺失则 NULL）
    raw                JSONB        NOT NULL,    -- 原始抓取值
    ingested_at        TIMESTAMPTZ  NOT NULL DEFAULT now(),
    UNIQUE (site, business_date)
);
