﻿-- -*- coding: utf-8 -*-
-- Feiqiu-ETL schema (JSON-first alignment)

CREATE SCHEMA IF NOT EXISTS billiards;
CREATE SCHEMA IF NOT EXISTS billiards_ods;
CREATE SCHEMA IF NOT EXISTS etl_admin;

COMMENT ON SCHEMA billiards IS '门店业务数据 Schema，存放维度/事实层（与 JSON 字段对应）';
COMMENT ON SCHEMA etl_admin IS 'ETL 调度、游标与运行记录 Schema';

-- =========================
--  Billiards ODS tables
-- =========================

CREATE TABLE IF NOT EXISTS billiards_ods.ods_order_settle (
    store_id         bigint NOT NULL,
    order_settle_id  bigint NOT NULL,
    order_trade_no   bigint,
    page_no          integer,
    page_size        integer,
    source_file      varchar(255),
    fetched_at       timestamptz NOT NULL DEFAULT now(),
    payload          jsonb NOT NULL,
    PRIMARY KEY (store_id, order_settle_id)
);

COMMENT ON TABLE billiards_ods.ods_order_settle IS '订单/结算 ODS（/order/list、ticket 接口原始 JSON）';
COMMENT ON COLUMN billiards_ods.ods_order_settle.store_id IS '门店 ID';
COMMENT ON COLUMN billiards_ods.ods_order_settle.order_settle_id IS '结算单 ID (order_settle_id)';
COMMENT ON COLUMN billiards_ods.ods_order_settle.order_trade_no IS '订单交易号 (order_trade_no)';
COMMENT ON COLUMN billiards_ods.ods_order_settle.page_no IS '来源分页序号';
COMMENT ON COLUMN billiards_ods.ods_order_settle.page_size IS '来源分页大小';
COMMENT ON COLUMN billiards_ods.ods_order_settle.source_file IS '离线导出文件名/路径';
COMMENT ON COLUMN billiards_ods.ods_order_settle.fetched_at IS '入 ODS 时间';
COMMENT ON COLUMN billiards_ods.ods_order_settle.payload IS '原始 JSON 负载';

CREATE TABLE IF NOT EXISTS billiards_ods.ods_table_use_detail (
    store_id        bigint NOT NULL,
    ledger_id       bigint NOT NULL,
    order_trade_no  bigint,
    order_settle_id bigint,
    page_no         integer,
    source_file     varchar(255),
    fetched_at      timestamptz NOT NULL DEFAULT now(),
    payload         jsonb NOT NULL,
    PRIMARY KEY (store_id, ledger_id)
);

COMMENT ON TABLE billiards_ods.ods_table_use_detail IS '台费/开台流水 ODS（siteTableUseDetailsList 等接口）';

CREATE TABLE IF NOT EXISTS billiards_ods.ods_assistant_ledger (
    store_id        bigint NOT NULL,
    ledger_id       bigint NOT NULL,
    order_trade_no  bigint,
    order_settle_id bigint,
    page_no         integer,
    source_file     varchar(255),
    fetched_at      timestamptz NOT NULL DEFAULT now(),
    payload         jsonb NOT NULL,
    PRIMARY KEY (store_id, ledger_id)
);

COMMENT ON TABLE billiards_ods.ods_assistant_ledger IS '助教流水 ODS（orderAssistantDetails 等接口）';

CREATE TABLE IF NOT EXISTS billiards_ods.ods_assistant_abolish (
    store_id    bigint NOT NULL,
    abolish_id  bigint NOT NULL,
    page_no     integer,
    source_file varchar(255),
    fetched_at  timestamptz NOT NULL DEFAULT now(),
    payload     jsonb NOT NULL,
    PRIMARY KEY (store_id, abolish_id)
);

COMMENT ON TABLE billiards_ods.ods_assistant_abolish IS '助教作废记录 ODS';

CREATE TABLE IF NOT EXISTS billiards_ods.ods_goods_ledger (
    store_id        bigint NOT NULL,
    order_goods_id  bigint NOT NULL,
    order_trade_no  bigint,
    order_settle_id bigint,
    page_no         integer,
    source_file     varchar(255),
    fetched_at      timestamptz NOT NULL DEFAULT now(),
    payload         jsonb NOT NULL,
    PRIMARY KEY (store_id, order_goods_id)
);

COMMENT ON TABLE billiards_ods.ods_goods_ledger IS '商品销售流水 ODS（orderGoodsLedgers/orderGoodsList）';

CREATE TABLE IF NOT EXISTS billiards_ods.ods_payment (
    store_id        bigint NOT NULL,
    pay_id          bigint NOT NULL,
    relate_type     varchar(50),
    relate_id       bigint,
    page_no         integer,
    source_file     varchar(255),
    fetched_at      timestamptz NOT NULL DEFAULT now(),
    payload         jsonb NOT NULL,
    PRIMARY KEY (store_id, pay_id)
);

COMMENT ON TABLE billiards_ods.ods_payment IS '支付流水 ODS（payRecord/payList）';

CREATE TABLE IF NOT EXISTS billiards_ods.ods_refund (
    store_id    bigint NOT NULL,
    refund_id   bigint NOT NULL,
    page_no     integer,
    source_file varchar(255),
    fetched_at  timestamptz NOT NULL DEFAULT now(),
    payload     jsonb NOT NULL,
    PRIMARY KEY (store_id, refund_id)
);

COMMENT ON TABLE billiards_ods.ods_refund IS '退款流水 ODS';

CREATE TABLE IF NOT EXISTS billiards_ods.ods_coupon_verify (
    store_id    bigint NOT NULL,
    coupon_id   bigint NOT NULL,
    page_no     integer,
    source_file varchar(255),
    fetched_at  timestamptz NOT NULL DEFAULT now(),
    payload     jsonb NOT NULL,
    PRIMARY KEY (store_id, coupon_id)
);

COMMENT ON TABLE billiards_ods.ods_coupon_verify IS '团购/验券流水 ODS';

CREATE TABLE IF NOT EXISTS billiards_ods.ods_member (
    store_id    bigint NOT NULL,
    member_id   bigint NOT NULL,
    page_no     integer,
    source_file varchar(255),
    fetched_at  timestamptz NOT NULL DEFAULT now(),
    payload     jsonb NOT NULL,
    PRIMARY KEY (store_id, member_id)
);

COMMENT ON TABLE billiards_ods.ods_member IS '会员档案 ODS';

CREATE TABLE IF NOT EXISTS billiards_ods.ods_member_card (
    store_id     bigint NOT NULL,
    card_id      bigint NOT NULL,
    page_no      integer,
    source_file  varchar(255),
    fetched_at   timestamptz NOT NULL DEFAULT now(),
    payload      jsonb NOT NULL,
    PRIMARY KEY (store_id, card_id)
);

COMMENT ON TABLE billiards_ods.ods_member_card IS '储值卡/会员卡 ODS';

CREATE TABLE IF NOT EXISTS billiards_ods.ods_package_coupon (
    store_id    bigint NOT NULL,
    package_id  bigint NOT NULL,
    page_no     integer,
    source_file varchar(255),
    fetched_at  timestamptz NOT NULL DEFAULT now(),
    payload     jsonb NOT NULL,
    PRIMARY KEY (store_id, package_id)
);

COMMENT ON TABLE billiards_ods.ods_package_coupon IS '团购套餐定义 ODS';

CREATE TABLE IF NOT EXISTS billiards_ods.ods_inventory_stock (
    store_id      bigint NOT NULL,
    site_goods_id bigint NOT NULL,
    snapshot_key  varchar(100) NOT NULL DEFAULT 'default',
    page_no       integer,
    source_file   varchar(255),
    fetched_at    timestamptz NOT NULL DEFAULT now(),
    payload       jsonb NOT NULL,
    PRIMARY KEY (store_id, site_goods_id, snapshot_key)
);

COMMENT ON TABLE billiards_ods.ods_inventory_stock IS '库存汇总 ODS（inventorySummary 等接口）';

CREATE TABLE IF NOT EXISTS billiards_ods.ods_inventory_change (
    store_id    bigint NOT NULL,
    change_id   bigint NOT NULL,
    page_no     integer,
    source_file varchar(255),
    fetched_at  timestamptz NOT NULL DEFAULT now(),
    payload     jsonb NOT NULL,
    PRIMARY KEY (store_id, change_id)
);

COMMENT ON TABLE billiards_ods.ods_inventory_change IS '库存变动记录 ODS';

-- =========================
--  Billiards dimension tables
-- =========================

CREATE TABLE IF NOT EXISTS billiards.dim_store (
    store_id        bigint PRIMARY KEY,
    store_name      varchar(200),
    tenant_id       bigint,
    region_code     varchar(30),
    address         varchar(500),
    contact_name    varchar(100),
    contact_phone   varchar(30),
    created_time    timestamptz,
    updated_time    timestamptz,
    remark          text,
    raw_data        jsonb NOT NULL DEFAULT '{}'::jsonb
);

COMMENT ON TABLE billiards.dim_store IS '门店/场馆维度（siteProfile 信息快照）';
COMMENT ON COLUMN billiards.dim_store.store_id IS '门店 ID，主键（API storeId）';
COMMENT ON COLUMN billiards.dim_store.store_name IS '门店名称 (shop_name)';
COMMENT ON COLUMN billiards.dim_store.tenant_id IS '租户 ID (tenant_id)';
COMMENT ON COLUMN billiards.dim_store.region_code IS '区域编码/城市代码 (tenant_site_region_id)';
COMMENT ON COLUMN billiards.dim_store.address IS '完整地址 (full_address/address)';
COMMENT ON COLUMN billiards.dim_store.contact_name IS '联系人（可扩展）';
COMMENT ON COLUMN billiards.dim_store.contact_phone IS '联系电话 (business_tel)';
COMMENT ON COLUMN billiards.dim_store.created_time IS '创建时间';
COMMENT ON COLUMN billiards.dim_store.updated_time IS '更新时间';
COMMENT ON COLUMN billiards.dim_store.remark IS '备注';
COMMENT ON COLUMN billiards.dim_store.raw_data IS '原始 JSON 快照';

CREATE TABLE IF NOT EXISTS billiards.dim_assistant (
    store_id         bigint NOT NULL,
    assistant_id     bigint NOT NULL,
    assistant_no     varchar(64),
    nickname         varchar(100),
    real_name        varchar(100),
    gender           varchar(20),
    mobile           varchar(30),
    level            varchar(50),
    team_id          bigint,
    team_name        varchar(100),
    assistant_status varchar(30),
    work_status      varchar(30),
    entry_time       timestamptz,
    resign_time      timestamptz,
    start_time       timestamptz,
    end_time         timestamptz,
    create_time      timestamptz,
    update_time      timestamptz,
    system_role_id   bigint,
    online_status    varchar(30),
    allow_cx         integer,
    charge_way       varchar(30),
    pd_unit_price    numeric(14,2),
    cx_unit_price    numeric(14,2),
    is_guaranteed    integer,
    is_team_leader   integer,
    serial_number    varchar(64),
    show_sort        integer,
    is_delete        integer,
    raw_data         jsonb NOT NULL DEFAULT '{}'::jsonb,
    updated_at       timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (store_id, assistant_id)
);

COMMENT ON TABLE billiards.dim_assistant IS '助教/技师维度（Assistant/List）';
COMMENT ON COLUMN billiards.dim_assistant.store_id IS '门店 ID';
COMMENT ON COLUMN billiards.dim_assistant.assistant_id IS '助教 ID (id)';
COMMENT ON COLUMN billiards.dim_assistant.assistant_no IS '助教编号 (assistant_no)';
COMMENT ON COLUMN billiards.dim_assistant.nickname IS '昵称 (nickname)';
COMMENT ON COLUMN billiards.dim_assistant.real_name IS '真实姓名 (real_name)';
COMMENT ON COLUMN billiards.dim_assistant.gender IS '性别';
COMMENT ON COLUMN billiards.dim_assistant.mobile IS '手机号';
COMMENT ON COLUMN billiards.dim_assistant.level IS '等级/段位 (level)';
COMMENT ON COLUMN billiards.dim_assistant.team_id IS '团队 ID (team_id)';
COMMENT ON COLUMN billiards.dim_assistant.team_name IS '团队名称 (team_name)';
COMMENT ON COLUMN billiards.dim_assistant.assistant_status IS '账号状态 (assistant_status)';
COMMENT ON COLUMN billiards.dim_assistant.work_status IS '工作状态 (work_status)';
COMMENT ON COLUMN billiards.dim_assistant.entry_time IS '入职时间 (entry_time)';
COMMENT ON COLUMN billiards.dim_assistant.resign_time IS '离职时间 (resign_time)';
COMMENT ON COLUMN billiards.dim_assistant.start_time IS '可服务开始时间 (start_time)';
COMMENT ON COLUMN billiards.dim_assistant.end_time IS '可服务结束时间 (end_time)';
COMMENT ON COLUMN billiards.dim_assistant.create_time IS '创建时间 (create_time)';
COMMENT ON COLUMN billiards.dim_assistant.update_time IS '最近更新时间 (update_time)';
COMMENT ON COLUMN billiards.dim_assistant.system_role_id IS '系统角色 ID';
COMMENT ON COLUMN billiards.dim_assistant.online_status IS '在线/离线状态';
COMMENT ON COLUMN billiards.dim_assistant.allow_cx IS '是否允许撤销/重开';
COMMENT ON COLUMN billiards.dim_assistant.charge_way IS '计费方式 (charge_way)';
COMMENT ON COLUMN billiards.dim_assistant.pd_unit_price IS '陪打单价 (pd_unit_price)';
COMMENT ON COLUMN billiards.dim_assistant.cx_unit_price IS '拆洗/其它单价 (cx_unit_price)';
COMMENT ON COLUMN billiards.dim_assistant.is_guaranteed IS '是否保底';
COMMENT ON COLUMN billiards.dim_assistant.is_team_leader IS '是否队长';
COMMENT ON COLUMN billiards.dim_assistant.serial_number IS '序列号/展示码 (serial_number)';
COMMENT ON COLUMN billiards.dim_assistant.show_sort IS '展示排序 (show_sort)';
COMMENT ON COLUMN billiards.dim_assistant.is_delete IS '删除标记';
COMMENT ON COLUMN billiards.dim_assistant.raw_data IS '原始 JSON';
COMMENT ON COLUMN billiards.dim_assistant.updated_at IS 'ETL 更新时间';

CREATE TABLE IF NOT EXISTS billiards.dim_member (
    store_id      bigint NOT NULL,
    member_id     bigint NOT NULL,
    member_name   varchar(100),
    phone         varchar(30),
    balance       numeric(18,4),
    status        varchar(30),
    register_time timestamptz,
    raw_data      jsonb NOT NULL DEFAULT '{}'::jsonb,
    updated_at    timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (store_id, member_id)
);

COMMENT ON TABLE billiards.dim_member IS '会员维度（MemberProfile/GetTenantMemberList）';
COMMENT ON COLUMN billiards.dim_member.store_id IS '门店 ID';
COMMENT ON COLUMN billiards.dim_member.member_id IS '会员 ID (memberId)';
COMMENT ON COLUMN billiards.dim_member.member_name IS '会员名称 (memberName)';
COMMENT ON COLUMN billiards.dim_member.phone IS '手机号 (phone)';
COMMENT ON COLUMN billiards.dim_member.balance IS '储值余额 (balance)';
COMMENT ON COLUMN billiards.dim_member.status IS '会员状态 (status)';
COMMENT ON COLUMN billiards.dim_member.register_time IS '注册时间 (registerTime)';
COMMENT ON COLUMN billiards.dim_member.raw_data IS '原始 JSON';
COMMENT ON COLUMN billiards.dim_member.updated_at IS 'ETL 更新时间';

CREATE TABLE IF NOT EXISTS billiards.dim_package_coupon (
    store_id          bigint NOT NULL,
    package_id        bigint NOT NULL,
    package_code      varchar(100),
    package_name      varchar(200),
    table_area_id     bigint,
    table_area_name   varchar(100),
    selling_price     numeric(14,2),
    duration_seconds  integer,
    start_time        timestamptz,
    end_time          timestamptz,
    type              varchar(50),
    is_enabled        integer,
    is_delete         integer,
    usable_count      integer,
    creator_name      varchar(100),
    date_type         varchar(50),
    group_type        varchar(50),
    coupon_money      numeric(14,2),
    area_tag_type     varchar(50),
    system_group_type varchar(50),
    card_type_ids     text,
    raw_data          jsonb NOT NULL DEFAULT '{}'::jsonb,
    updated_at        timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (store_id, package_id)
);

COMMENT ON TABLE billiards.dim_package_coupon IS '团购/套餐定义维度（Package/List）';
COMMENT ON COLUMN billiards.dim_package_coupon.store_id IS '门店 ID';
COMMENT ON COLUMN billiards.dim_package_coupon.package_id IS '套餐主键 (id)';
COMMENT ON COLUMN billiards.dim_package_coupon.package_code IS '套餐编码 (package_id 或自定义编码)';
COMMENT ON COLUMN billiards.dim_package_coupon.package_name IS '套餐名称 (package_name)';
COMMENT ON COLUMN billiards.dim_package_coupon.table_area_id IS '适用台桌区域 ID';
COMMENT ON COLUMN billiards.dim_package_coupon.table_area_name IS '适用台桌区域名称';
COMMENT ON COLUMN billiards.dim_package_coupon.selling_price IS '售卖价格 (selling_price)';
COMMENT ON COLUMN billiards.dim_package_coupon.duration_seconds IS '可用时长（秒）(duration)';
COMMENT ON COLUMN billiards.dim_package_coupon.start_time IS '可用时间起';
COMMENT ON COLUMN billiards.dim_package_coupon.end_time IS '可用时间止';
COMMENT ON COLUMN billiards.dim_package_coupon.type IS '套餐类型 (type/group_type)';
COMMENT ON COLUMN billiards.dim_package_coupon.is_enabled IS '是否启用 (is_enabled)';
COMMENT ON COLUMN billiards.dim_package_coupon.is_delete IS '删除标记 (is_delete)';
COMMENT ON COLUMN billiards.dim_package_coupon.usable_count IS '可使用次数 (usable_count)';
COMMENT ON COLUMN billiards.dim_package_coupon.creator_name IS '创建人 (creator_name)';
COMMENT ON COLUMN billiards.dim_package_coupon.date_type IS '日期限制 (date_type)';
COMMENT ON COLUMN billiards.dim_package_coupon.group_type IS '渠道/团购类型 (group_type)';
COMMENT ON COLUMN billiards.dim_package_coupon.coupon_money IS '券面额 (coupon_money)';
COMMENT ON COLUMN billiards.dim_package_coupon.area_tag_type IS '区域标签类型';
COMMENT ON COLUMN billiards.dim_package_coupon.system_group_type IS '系统套餐类型 (system_group_type)';
COMMENT ON COLUMN billiards.dim_package_coupon.card_type_ids IS '适用会员卡类型列表 (card_type_ids)';
COMMENT ON COLUMN billiards.dim_package_coupon.raw_data IS '原始 JSON';
COMMENT ON COLUMN billiards.dim_package_coupon.updated_at IS 'ETL 更新时间';

CREATE TABLE IF NOT EXISTS billiards.dim_product (
    store_id           bigint NOT NULL,
    product_id         bigint NOT NULL,
    site_product_id    bigint,
    product_name       varchar(200) NOT NULL,
    category_id        bigint,
    category_name      varchar(100),
    second_category_id bigint,
    unit               varchar(20),
    cost_price         numeric(14,4),
    sale_price         numeric(14,4),
    allow_discount     boolean,
    status             varchar(30),
    supplier_id        bigint,
    barcode            varchar(128),
    is_combo           boolean,
    created_time       timestamptz,
    updated_time       timestamptz,
    raw_data           jsonb NOT NULL DEFAULT '{}'::jsonb,
    updated_at         timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (store_id, product_id)
);

COMMENT ON TABLE billiards.dim_product IS '商品维度（TenantGoods/QueryTenantGoods）';
COMMENT ON COLUMN billiards.dim_product.store_id IS '门店 ID';
COMMENT ON COLUMN billiards.dim_product.product_id IS '商品 ID (siteGoodsId/tenantGoodsId)';
COMMENT ON COLUMN billiards.dim_product.site_product_id IS '站点/门店商品 ID (siteGoodsId)';
COMMENT ON COLUMN billiards.dim_product.product_name IS '商品名称 (goodsName/productName)';
COMMENT ON COLUMN billiards.dim_product.category_id IS '一级分类 ID (goodsCategoryId)';
COMMENT ON COLUMN billiards.dim_product.category_name IS '一级分类名称 (categoryName)';
COMMENT ON COLUMN billiards.dim_product.second_category_id IS '二级分类 ID (goodsSecondCategoryId)';
COMMENT ON COLUMN billiards.dim_product.unit IS '计量单位 (goodsUnit)';
COMMENT ON COLUMN billiards.dim_product.cost_price IS '成本价 (costPrice)';
COMMENT ON COLUMN billiards.dim_product.sale_price IS '销售价 (goodsPrice/salePrice)';
COMMENT ON COLUMN billiards.dim_product.allow_discount IS '是否允许折扣 (able_discount)';
COMMENT ON COLUMN billiards.dim_product.status IS '商品状态 (goodsState/status)';
COMMENT ON COLUMN billiards.dim_product.supplier_id IS '供应商 ID';
COMMENT ON COLUMN billiards.dim_product.barcode IS '条码 (barcode)';
COMMENT ON COLUMN billiards.dim_product.is_combo IS '是否组合/套餐商品 (isCombo)';
COMMENT ON COLUMN billiards.dim_product.created_time IS '创建时间 (createTime)';
COMMENT ON COLUMN billiards.dim_product.updated_time IS '更新时间 (updateTime)';
COMMENT ON COLUMN billiards.dim_product.raw_data IS '原始 JSON';
COMMENT ON COLUMN billiards.dim_product.updated_at IS 'ETL 更新时间';

CREATE TABLE IF NOT EXISTS billiards.dim_product_price_scd (
    product_scd_id     bigserial PRIMARY KEY,
    store_id           bigint NOT NULL,
    product_id         bigint NOT NULL,
    product_name       varchar(200),
    category_id        bigint,
    category_name      varchar(100),
    second_category_id bigint,
    cost_price         numeric(14,4),
    sale_price         numeric(14,4),
    allow_discount     boolean,
    status             varchar(30),
    valid_from         timestamptz NOT NULL DEFAULT now(),
    valid_to           timestamptz,
    is_current         boolean NOT NULL DEFAULT true,
    raw_data           jsonb NOT NULL DEFAULT '{}'::jsonb,
    CONSTRAINT fk_dpps_product FOREIGN KEY (store_id, product_id)
        REFERENCES billiards.dim_product(store_id, product_id) ON DELETE CASCADE,
    CONSTRAINT ck_dpps_range CHECK (
        valid_from < COALESCE(valid_to, '9999-12-31 00:00:00+00'::timestamptz)
    ),
    CONSTRAINT uq_dpps_current UNIQUE (store_id, product_id) WHERE (is_current)
);

COMMENT ON TABLE billiards.dim_product_price_scd IS '商品维度价格 SCD（记录价格/分类变动历史）';
COMMENT ON COLUMN billiards.dim_product_price_scd.product_scd_id IS '价格 SCD 主键';
COMMENT ON COLUMN billiards.dim_product_price_scd.store_id IS '门店 ID';
COMMENT ON COLUMN billiards.dim_product_price_scd.product_id IS '商品 ID';
COMMENT ON COLUMN billiards.dim_product_price_scd.product_name IS '商品名称（冗余，方便简单查询）';
COMMENT ON COLUMN billiards.dim_product_price_scd.category_id IS '一级分类 ID';
COMMENT ON COLUMN billiards.dim_product_price_scd.category_name IS '一级分类名称';
COMMENT ON COLUMN billiards.dim_product_price_scd.second_category_id IS '二级分类 ID';
COMMENT ON COLUMN billiards.dim_product_price_scd.cost_price IS '成本价';
COMMENT ON COLUMN billiards.dim_product_price_scd.sale_price IS '销售价';
COMMENT ON COLUMN billiards.dim_product_price_scd.allow_discount IS '是否允许折扣';
COMMENT ON COLUMN billiards.dim_product_price_scd.status IS '商品状态 (上/下架)';
COMMENT ON COLUMN billiards.dim_product_price_scd.valid_from IS '生效时间';
COMMENT ON COLUMN billiards.dim_product_price_scd.valid_to IS '失效时间，NULL 表示当前版本';
COMMENT ON COLUMN billiards.dim_product_price_scd.is_current IS '当前有效版本标记';
COMMENT ON COLUMN billiards.dim_product_price_scd.raw_data IS '原始 JSON 快照';

CREATE VIEW IF NOT EXISTS billiards.dim_product_price_current AS
SELECT product_scd_id,
       store_id,
       product_id,
       product_name,
       category_id,
       category_name,
       second_category_id,
       cost_price,
       sale_price,
       allow_discount,
       status,
       valid_from,
       valid_to,
       raw_data
  FROM billiards.dim_product_price_scd
 WHERE is_current;

COMMENT ON VIEW billiards.dim_product_price_current IS '商品价格 SCD 当前有效版本视图';
COMMENT ON COLUMN billiards.dim_product_price_current.product_scd_id IS '价格 SCD 主键';
COMMENT ON COLUMN billiards.dim_product_price_current.store_id IS '门店 ID';
COMMENT ON COLUMN billiards.dim_product_price_current.product_id IS '商品 ID';
COMMENT ON COLUMN billiards.dim_product_price_current.product_name IS '商品名称';
COMMENT ON COLUMN billiards.dim_product_price_current.category_id IS '一级分类 ID';
COMMENT ON COLUMN billiards.dim_product_price_current.category_name IS '一级分类名称';
COMMENT ON COLUMN billiards.dim_product_price_current.second_category_id IS '二级分类 ID';
COMMENT ON COLUMN billiards.dim_product_price_current.cost_price IS '成本价';
COMMENT ON COLUMN billiards.dim_product_price_current.sale_price IS '销售价';
COMMENT ON COLUMN billiards.dim_product_price_current.allow_discount IS '是否允许折扣';
COMMENT ON COLUMN billiards.dim_product_price_current.status IS '商品状态';
COMMENT ON COLUMN billiards.dim_product_price_current.valid_from IS '生效时间';
COMMENT ON COLUMN billiards.dim_product_price_current.valid_to IS '失效时间';
COMMENT ON COLUMN billiards.dim_product_price_current.raw_data IS '原始 JSON';

CREATE TABLE IF NOT EXISTS billiards.dim_table (
    store_id             bigint NOT NULL,
    table_id             bigint NOT NULL,
    site_id              bigint,
    area_id              bigint,
    area_name            varchar(100),
    table_name           varchar(100) NOT NULL,
    table_price          numeric(14,4),
    table_status         varchar(30),
    table_status_name    varchar(50),
    light_status         integer,
    is_rest_area         integer,
    show_status          integer,
    virtual_table        integer,
    charge_free          integer,
    only_allow_groupon   integer,
    is_online_reservation integer,
    created_time         timestamptz,
    raw_data             jsonb NOT NULL DEFAULT '{}'::jsonb,
    updated_at           timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (store_id, table_id)
);

COMMENT ON TABLE billiards.dim_table IS '台桌档案维度（Table/GetSiteTables）';
COMMENT ON COLUMN billiards.dim_table.store_id IS '门店 ID';
COMMENT ON COLUMN billiards.dim_table.table_id IS '台桌 ID (id)';
COMMENT ON COLUMN billiards.dim_table.site_id IS '场馆/站点 ID (site_id)';
COMMENT ON COLUMN billiards.dim_table.area_id IS '区域 ID (site_table_area_id)';
COMMENT ON COLUMN billiards.dim_table.area_name IS '区域名称 (areaName)';
COMMENT ON COLUMN billiards.dim_table.table_name IS '台桌名称 (table_name)';
COMMENT ON COLUMN billiards.dim_table.table_price IS '台费单价 (table_price)';
COMMENT ON COLUMN billiards.dim_table.table_status IS '台桌状态代码 (table_status)';
COMMENT ON COLUMN billiards.dim_table.table_status_name IS '台桌状态名称 (tableStatusName)';
COMMENT ON COLUMN billiards.dim_table.light_status IS '灯光状态 (light_status)';
COMMENT ON COLUMN billiards.dim_table.is_rest_area IS '是否休息区 (is_rest_area)';
COMMENT ON COLUMN billiards.dim_table.show_status IS '是否展示 (show_status)';
COMMENT ON COLUMN billiards.dim_table.virtual_table IS '是否虚拟台 (virtual_table)';
COMMENT ON COLUMN billiards.dim_table.charge_free IS '是否免收费 (charge_free)';
COMMENT ON COLUMN billiards.dim_table.only_allow_groupon IS '是否仅限团购 (only_allow_groupon)';
COMMENT ON COLUMN billiards.dim_table.is_online_reservation IS '是否可线上预约 (is_online_reservation)';
COMMENT ON COLUMN billiards.dim_table.created_time IS '创建时间 (create_time)';
COMMENT ON COLUMN billiards.dim_table.raw_data IS '原始 JSON';
COMMENT ON COLUMN billiards.dim_table.updated_at IS 'ETL 更新时间';

-- =========================
--  Billiards fact tables
-- =========================

CREATE TABLE IF NOT EXISTS billiards.fact_assistant_abolish (
    store_id        bigint NOT NULL,
    abolish_id      bigint NOT NULL,
    table_id        bigint,
    table_name      varchar(100),
    table_area_id   bigint,
    table_area      varchar(100),
    assistant_no    varchar(64),
    assistant_name  varchar(100),
    charge_minutes  integer,
    abolish_amount  numeric(14,4),
    create_time     timestamptz,
    trash_reason    text,
    raw_data        jsonb NOT NULL DEFAULT '{}'::jsonb,
    updated_at      timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (store_id, abolish_id)
);

COMMENT ON TABLE billiards.fact_assistant_abolish IS '助教作废/撤单流水（Assistant/AbolishList）';
COMMENT ON COLUMN billiards.fact_assistant_abolish.store_id IS '门店 ID';
COMMENT ON COLUMN billiards.fact_assistant_abolish.abolish_id IS '作废记录 ID (id)';
COMMENT ON COLUMN billiards.fact_assistant_abolish.table_id IS '台桌 ID (tableId)';
COMMENT ON COLUMN billiards.fact_assistant_abolish.table_name IS '台桌名称';
COMMENT ON COLUMN billiards.fact_assistant_abolish.table_area_id IS '台桌区域 ID';
COMMENT ON COLUMN billiards.fact_assistant_abolish.table_area IS '台桌区域名称';
COMMENT ON COLUMN billiards.fact_assistant_abolish.assistant_no IS '助教编号 (assistantOn)';
COMMENT ON COLUMN billiards.fact_assistant_abolish.assistant_name IS '助教姓名';
COMMENT ON COLUMN billiards.fact_assistant_abolish.charge_minutes IS '计费分钟 (pdChargeMinutes)';
COMMENT ON COLUMN billiards.fact_assistant_abolish.abolish_amount IS '作废金额 (assistantAbolishAmount)';
COMMENT ON COLUMN billiards.fact_assistant_abolish.create_time IS '创建时间 (createTime)';
COMMENT ON COLUMN billiards.fact_assistant_abolish.trash_reason IS '作废原因 (trashReason)';
COMMENT ON COLUMN billiards.fact_assistant_abolish.raw_data IS '原始 JSON';
COMMENT ON COLUMN billiards.fact_assistant_abolish.updated_at IS 'ETL 更新时间';

CREATE TABLE IF NOT EXISTS billiards.fact_assistant_ledger (
    store_id                bigint NOT NULL,
    ledger_id               bigint NOT NULL,
    assistant_no            varchar(64),
    assistant_name          varchar(100),
    nickname                varchar(100),
    level_name              varchar(50),
    table_name              varchar(100),
    ledger_unit_price       numeric(14,4),
    ledger_count            numeric(14,4),
    ledger_amount           numeric(14,4),
    projected_income        numeric(14,4),
    service_money           numeric(14,4),
    member_discount_amount  numeric(14,4),
    manual_discount_amount  numeric(14,4),
    coupon_deduct_money     numeric(14,4),
    order_trade_no          bigint,
    order_settle_id         bigint,
    operator_id             bigint,
    operator_name           varchar(100),
    assistant_team_id       bigint,
    assistant_level         varchar(50),
    site_table_id           bigint,
    order_assistant_id      bigint,
    site_assistant_id       bigint,
    user_id                 bigint,
    ledger_start_time       timestamptz,
    ledger_end_time         timestamptz,
    start_use_time          timestamptz,
    last_use_time           timestamptz,
    income_seconds          integer,
    real_use_seconds        integer,
    is_trash                integer,
    trash_reason            text,
    is_confirm              integer,
    ledger_status           varchar(30),
    create_time             timestamptz,
    raw_data                jsonb NOT NULL DEFAULT '{}'::jsonb,
    updated_at              timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (store_id, ledger_id)
);

COMMENT ON TABLE billiards.fact_assistant_ledger IS '助教陪打计费流水（Assistant/LedgerList）';
COMMENT ON COLUMN billiards.fact_assistant_ledger.store_id IS '门店 ID';
COMMENT ON COLUMN billiards.fact_assistant_ledger.ledger_id IS '流水 ID (id)';
COMMENT ON COLUMN billiards.fact_assistant_ledger.assistant_no IS '助教编号';
COMMENT ON COLUMN billiards.fact_assistant_ledger.assistant_name IS '助教姓名';
COMMENT ON COLUMN billiards.fact_assistant_ledger.nickname IS '昵称';
COMMENT ON COLUMN billiards.fact_assistant_ledger.level_name IS '等级名称';
COMMENT ON COLUMN billiards.fact_assistant_ledger.table_name IS '服务台桌名称';
COMMENT ON COLUMN billiards.fact_assistant_ledger.ledger_unit_price IS '计费单价 (ledger_unit_price)';
COMMENT ON COLUMN billiards.fact_assistant_ledger.ledger_count IS '计费数量 (ledger_count)';
COMMENT ON COLUMN billiards.fact_assistant_ledger.ledger_amount IS '计费金额 (ledger_amount)';
COMMENT ON COLUMN billiards.fact_assistant_ledger.projected_income IS '预计收益 (projected_income)';
COMMENT ON COLUMN billiards.fact_assistant_ledger.service_money IS '服务费 (service_money)';
COMMENT ON COLUMN billiards.fact_assistant_ledger.member_discount_amount IS '会员折扣金额';
COMMENT ON COLUMN billiards.fact_assistant_ledger.manual_discount_amount IS '手动折扣金额';
COMMENT ON COLUMN billiards.fact_assistant_ledger.coupon_deduct_money IS '券抵扣金额';
COMMENT ON COLUMN billiards.fact_assistant_ledger.order_trade_no IS '订单交易号 (order_trade_no)';
COMMENT ON COLUMN billiards.fact_assistant_ledger.order_settle_id IS '结算单 ID (order_settle_id)';
COMMENT ON COLUMN billiards.fact_assistant_ledger.operator_id IS '操作人 ID';
COMMENT ON COLUMN billiards.fact_assistant_ledger.operator_name IS '操作人姓名';
COMMENT ON COLUMN billiards.fact_assistant_ledger.assistant_team_id IS '助教团队 ID';
COMMENT ON COLUMN billiards.fact_assistant_ledger.assistant_level IS '助教等级';
COMMENT ON COLUMN billiards.fact_assistant_ledger.site_table_id IS '台桌 ID';
COMMENT ON COLUMN billiards.fact_assistant_ledger.order_assistant_id IS '订单内助教 ID';
COMMENT ON COLUMN billiards.fact_assistant_ledger.site_assistant_id IS '场馆助教 ID';
COMMENT ON COLUMN billiards.fact_assistant_ledger.user_id IS '会员/顾客 ID';
COMMENT ON COLUMN billiards.fact_assistant_ledger.ledger_start_time IS '计费开始时间';
COMMENT ON COLUMN billiards.fact_assistant_ledger.ledger_end_time IS '计费结束时间';
COMMENT ON COLUMN billiards.fact_assistant_ledger.start_use_time IS '开始使用时间';
COMMENT ON COLUMN billiards.fact_assistant_ledger.last_use_time IS '最后使用时间';
COMMENT ON COLUMN billiards.fact_assistant_ledger.income_seconds IS '计费秒数 (income_seconds)';
COMMENT ON COLUMN billiards.fact_assistant_ledger.real_use_seconds IS '实际使用秒数 (real_use_seconds)';
COMMENT ON COLUMN billiards.fact_assistant_ledger.is_trash IS '是否作废 (is_trash)';
COMMENT ON COLUMN billiards.fact_assistant_ledger.trash_reason IS '作废原因 (trash_reason)';
COMMENT ON COLUMN billiards.fact_assistant_ledger.is_confirm IS '是否确认 (is_confirm)';
COMMENT ON COLUMN billiards.fact_assistant_ledger.ledger_status IS '状态 (ledger_status)';
COMMENT ON COLUMN billiards.fact_assistant_ledger.create_time IS '创建时间';
COMMENT ON COLUMN billiards.fact_assistant_ledger.raw_data IS '原始 JSON';
COMMENT ON COLUMN billiards.fact_assistant_ledger.updated_at IS 'ETL 更新时间';

CREATE TABLE IF NOT EXISTS billiards.fact_inventory_change (
    store_id                bigint NOT NULL,
    change_id               bigint NOT NULL,
    site_goods_id           bigint,
    stock_type              varchar(50),
    goods_name              varchar(200),
    change_time             timestamptz,
    start_qty               numeric(18,4),
    end_qty                 numeric(18,4),
    change_qty              numeric(18,4),
    unit                    varchar(20),
    price                   numeric(14,4),
    operator_name           varchar(100),
    remark                  text,
    goods_category_id       bigint,
    goods_second_category_id bigint,
    raw_data                jsonb NOT NULL DEFAULT '{}'::jsonb,
    updated_at              timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (store_id, change_id)
);

COMMENT ON TABLE billiards.fact_inventory_change IS '库存变更流水（Inventory/ChangeList）';
COMMENT ON COLUMN billiards.fact_inventory_change.store_id IS '门店 ID';
COMMENT ON COLUMN billiards.fact_inventory_change.change_id IS '库存变动 ID (siteGoodsStockId)';
COMMENT ON COLUMN billiards.fact_inventory_change.site_goods_id IS '门店商品 ID (siteGoodsId)';
COMMENT ON COLUMN billiards.fact_inventory_change.stock_type IS '变动类型 (stockType)';
COMMENT ON COLUMN billiards.fact_inventory_change.goods_name IS '商品名称 (goodsName)';
COMMENT ON COLUMN billiards.fact_inventory_change.change_time IS '变动时间 (createTime)';
COMMENT ON COLUMN billiards.fact_inventory_change.start_qty IS '变动前数量 (startNum)';
COMMENT ON COLUMN billiards.fact_inventory_change.end_qty IS '变动后数量 (endNum)';
COMMENT ON COLUMN billiards.fact_inventory_change.change_qty IS '变化数量 (changeNum)';
COMMENT ON COLUMN billiards.fact_inventory_change.unit IS '单位 (unit)';
COMMENT ON COLUMN billiards.fact_inventory_change.price IS '单价 (price)';
COMMENT ON COLUMN billiards.fact_inventory_change.operator_name IS '操作人 (operatorName)';
COMMENT ON COLUMN billiards.fact_inventory_change.remark IS '备注 (remark)';
COMMENT ON COLUMN billiards.fact_inventory_change.goods_category_id IS '一级分类 ID';
COMMENT ON COLUMN billiards.fact_inventory_change.goods_second_category_id IS '二级分类 ID';
COMMENT ON COLUMN billiards.fact_inventory_change.raw_data IS '原始 JSON';
COMMENT ON COLUMN billiards.fact_inventory_change.updated_at IS 'ETL 更新时间';

CREATE TABLE IF NOT EXISTS billiards.fact_order (
    store_id        bigint NOT NULL,
    order_id        bigint NOT NULL,
    order_no        varchar(64),
    member_id       bigint,
    table_id        bigint,
    order_time      timestamptz,
    end_time        timestamptz,
    total_amount    numeric(14,4),
    discount_amount numeric(14,4),
    final_amount    numeric(14,4),
    pay_status      varchar(30),
    order_status    varchar(30),
    remark          text,
    raw_data        jsonb NOT NULL DEFAULT '{}'::jsonb,
    updated_at      timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (store_id, order_id)
);

COMMENT ON TABLE billiards.fact_order IS '订单事实表（/order/list 返回的结账记录）';
COMMENT ON COLUMN billiards.fact_order.store_id IS '门店 ID';
COMMENT ON COLUMN billiards.fact_order.order_id IS '订单 ID (orderId)';
COMMENT ON COLUMN billiards.fact_order.order_no IS '订单编号 (orderNo)';
COMMENT ON COLUMN billiards.fact_order.member_id IS '会员 ID (memberId)';
COMMENT ON COLUMN billiards.fact_order.table_id IS '台桌 ID (tableId)';
COMMENT ON COLUMN billiards.fact_order.order_time IS '开单时间/开始时间 (orderTime)';
COMMENT ON COLUMN billiards.fact_order.end_time IS '结账时间 (endTime)';
COMMENT ON COLUMN billiards.fact_order.total_amount IS '订单总金额 (totalAmount)';
COMMENT ON COLUMN billiards.fact_order.discount_amount IS '折扣金额 (discountAmount)';
COMMENT ON COLUMN billiards.fact_order.final_amount IS '应付金额 (finalAmount)';
COMMENT ON COLUMN billiards.fact_order.pay_status IS '支付状态 (payStatus)';
COMMENT ON COLUMN billiards.fact_order.order_status IS '订单状态 (orderStatus)';
COMMENT ON COLUMN billiards.fact_order.remark IS '备注 (remark)';
COMMENT ON COLUMN billiards.fact_order.raw_data IS '原始 JSON';
COMMENT ON COLUMN billiards.fact_order.updated_at IS 'ETL 更新时间';

CREATE TABLE IF NOT EXISTS billiards.fact_payment (
    store_id          bigint NOT NULL,
    pay_id            bigint NOT NULL,
    order_id          bigint,
    order_settle_id   bigint,
    relate_type       varchar(50),
    relate_id         bigint,
    site_id           bigint,
    tenant_id         bigint,
    pay_time          timestamptz,
    create_time       timestamptz,
    pay_amount        numeric(14,4),
    pay_type          varchar(50),
    payment_method    varchar(50),
    online_pay_channel varchar(50),
    pay_status        varchar(30),
    pay_terminal      varchar(50),
    remark            text,
    raw_data          jsonb NOT NULL DEFAULT '{}'::jsonb,
    updated_at        timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (store_id, pay_id)
);

COMMENT ON TABLE billiards.fact_payment IS '支付流水（pay/records）';
COMMENT ON COLUMN billiards.fact_payment.store_id IS '门店 ID';
COMMENT ON COLUMN billiards.fact_payment.pay_id IS '支付记录 ID (payId)';
COMMENT ON COLUMN billiards.fact_payment.order_id IS '旧版订单 ID (orderId)，保留兼容';
COMMENT ON COLUMN billiards.fact_payment.order_settle_id IS '结算单 ID (relate_id 当 relate_type=2)';
COMMENT ON COLUMN billiards.fact_payment.relate_type IS '关联类型 (relate_type)';
COMMENT ON COLUMN billiards.fact_payment.relate_id IS '关联 ID (relate_id)';
COMMENT ON COLUMN billiards.fact_payment.site_id IS '门店 ID（冗余自 payload）';
COMMENT ON COLUMN billiards.fact_payment.tenant_id IS '租户 ID';
COMMENT ON COLUMN billiards.fact_payment.pay_time IS '支付时间 (payTime)';
COMMENT ON COLUMN billiards.fact_payment.create_time IS '创建时间 (create_time)';
COMMENT ON COLUMN billiards.fact_payment.pay_amount IS '支付金额 (payAmount)';
COMMENT ON COLUMN billiards.fact_payment.pay_type IS '支付渠道 (payType)';
COMMENT ON COLUMN billiards.fact_payment.payment_method IS '支付方式 (payment_method)';
COMMENT ON COLUMN billiards.fact_payment.online_pay_channel IS '线上支付渠道 (online_pay_channel)';
COMMENT ON COLUMN billiards.fact_payment.pay_status IS '支付状态 (payStatus)';
COMMENT ON COLUMN billiards.fact_payment.pay_terminal IS '支付终端 (pay_terminal)';
COMMENT ON COLUMN billiards.fact_payment.remark IS '备注';
COMMENT ON COLUMN billiards.fact_payment.raw_data IS '原始 JSON';
COMMENT ON COLUMN billiards.fact_payment.updated_at IS 'ETL 更新时间';

CREATE TABLE IF NOT EXISTS billiards.fact_refund (
    store_id       bigint NOT NULL,
    refund_id      bigint NOT NULL,
    site_id        bigint,
    tenant_id      bigint,
    pay_amount     numeric(14,4),
    pay_status     varchar(30),
    pay_time       timestamptz,
    create_time    timestamptz,
    relate_type    varchar(50),
    relate_id      bigint,
    payment_method varchar(50),
    refund_amount  numeric(14,4),
    action_type    varchar(30),
    pay_terminal   varchar(50),
    operator_id    bigint,
    channel_pay_no varchar(100),
    channel_fee    numeric(14,4),
    is_delete      integer,
    member_id      bigint,
    member_card_id bigint,
    raw_data       jsonb NOT NULL DEFAULT '{}'::jsonb,
    updated_at     timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (store_id, refund_id)
);

COMMENT ON TABLE billiards.fact_refund IS '退款流水（Pay/RefundList）';
COMMENT ON COLUMN billiards.fact_refund.store_id IS '门店 ID';
COMMENT ON COLUMN billiards.fact_refund.refund_id IS '退款记录 ID (id)';
COMMENT ON COLUMN billiards.fact_refund.site_id IS '场地 ID (site_id)';
COMMENT ON COLUMN billiards.fact_refund.tenant_id IS '租户 ID (tenant_id)';
COMMENT ON COLUMN billiards.fact_refund.pay_amount IS '原支付金额 (pay_amount)';
COMMENT ON COLUMN billiards.fact_refund.pay_status IS '支付状态 (pay_status)';
COMMENT ON COLUMN billiards.fact_refund.pay_time IS '支付时间 (pay_time)';
COMMENT ON COLUMN billiards.fact_refund.create_time IS '创建时间 (create_time)';
COMMENT ON COLUMN billiards.fact_refund.relate_type IS '关联对象类型 (relate_type)';
COMMENT ON COLUMN billiards.fact_refund.relate_id IS '关联对象 ID (relate_id)';
COMMENT ON COLUMN billiards.fact_refund.payment_method IS '支付方式 (payment_method)';
COMMENT ON COLUMN billiards.fact_refund.refund_amount IS '退款金额 (refund_amount)';
COMMENT ON COLUMN billiards.fact_refund.action_type IS '操作类型 (action_type)';
COMMENT ON COLUMN billiards.fact_refund.pay_terminal IS '终端类型 (pay_terminal)';
COMMENT ON COLUMN billiards.fact_refund.operator_id IS '操作人 ID (operator_id)';
COMMENT ON COLUMN billiards.fact_refund.channel_pay_no IS '渠道支付单号 (channel_pay_no)';
COMMENT ON COLUMN billiards.fact_refund.channel_fee IS '渠道手续费 (channel_fee)';
COMMENT ON COLUMN billiards.fact_refund.is_delete IS '删除标记 (is_delete)';
COMMENT ON COLUMN billiards.fact_refund.member_id IS '会员 ID (member_id)';
COMMENT ON COLUMN billiards.fact_refund.member_card_id IS '会员卡 ID (member_card_id)';
COMMENT ON COLUMN billiards.fact_refund.raw_data IS '原始 JSON';
COMMENT ON COLUMN billiards.fact_refund.updated_at IS 'ETL 更新时间';

CREATE TABLE IF NOT EXISTS billiards.fact_table_discount (
    store_id        bigint NOT NULL,
    discount_id     bigint NOT NULL,
    adjust_type     varchar(50),
    applicant_id    bigint,
    applicant_name  varchar(100),
    operator_id     bigint,
    operator_name   varchar(100),
    ledger_amount   numeric(14,4),
    ledger_count    numeric(14,4),
    ledger_name     varchar(100),
    ledger_status   varchar(30),
    order_settle_id bigint,
    order_trade_no  bigint,
    site_table_id   bigint,
    table_area_id   bigint,
    table_area_name varchar(100),
    create_time     timestamptz,
    is_delete       integer,
    raw_data        jsonb NOT NULL DEFAULT '{}'::jsonb,
    updated_at      timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (store_id, discount_id)
);

COMMENT ON TABLE billiards.fact_table_discount IS '台费调价/折扣记录（Table/AdjustList）';
COMMENT ON COLUMN billiards.fact_table_discount.store_id IS '门店 ID';
COMMENT ON COLUMN billiards.fact_table_discount.discount_id IS '调价记录 ID (id)';
COMMENT ON COLUMN billiards.fact_table_discount.adjust_type IS '调价类型 (adjust_type/adjustType)';
COMMENT ON COLUMN billiards.fact_table_discount.applicant_id IS '申请人 ID (applicant_id)';
COMMENT ON COLUMN billiards.fact_table_discount.applicant_name IS '申请人姓名 (applicant_name)';
COMMENT ON COLUMN billiards.fact_table_discount.operator_id IS '操作人 ID (operator_id)';
COMMENT ON COLUMN billiards.fact_table_discount.operator_name IS '操作人姓名 (operator_name)';
COMMENT ON COLUMN billiards.fact_table_discount.ledger_amount IS '台费金额调整 (ledger_amount)';
COMMENT ON COLUMN billiards.fact_table_discount.ledger_count IS '台费数量调整 (ledger_count)';
COMMENT ON COLUMN billiards.fact_table_discount.ledger_name IS '科目名称 (ledger_name)';
COMMENT ON COLUMN billiards.fact_table_discount.ledger_status IS '记录状态 (ledger_status)';
COMMENT ON COLUMN billiards.fact_table_discount.order_settle_id IS '结算单 ID (order_settle_id)';
COMMENT ON COLUMN billiards.fact_table_discount.order_trade_no IS '订单号 (order_trade_no)';
COMMENT ON COLUMN billiards.fact_table_discount.site_table_id IS '台桌 ID (site_table_id)';
COMMENT ON COLUMN billiards.fact_table_discount.table_area_id IS '台桌区域 ID';
COMMENT ON COLUMN billiards.fact_table_discount.table_area_name IS '台桌区域名称';
COMMENT ON COLUMN billiards.fact_table_discount.create_time IS '创建时间 (create_time)';
COMMENT ON COLUMN billiards.fact_table_discount.is_delete IS '删除标记 (is_delete)';
COMMENT ON COLUMN billiards.fact_table_discount.raw_data IS '原始 JSON';
COMMENT ON COLUMN billiards.fact_table_discount.updated_at IS 'ETL 更新时间';

CREATE TABLE IF NOT EXISTS billiards.fact_topup (
    store_id          bigint NOT NULL,
    topup_id          bigint NOT NULL,
    member_id         bigint,
    member_name       varchar(100),
    member_phone      varchar(30),
    card_id           bigint,
    card_type_name    varchar(100),
    pay_amount        numeric(14,4),
    consume_money     numeric(14,4),
    settle_status     varchar(30),
    settle_type       varchar(30),
    settle_name       varchar(100),
    settle_relate_id  bigint,
    pay_time          timestamptz,
    create_time       timestamptz,
    operator_id       bigint,
    operator_name     varchar(100),
    payment_method    varchar(50),
    refund_amount     numeric(14,4),
    cash_amount       numeric(14,4),
    card_amount       numeric(14,4),
    balance_amount    numeric(14,4),
    online_amount     numeric(14,4),
    rounding_amount   numeric(14,4),
    adjust_amount     numeric(14,4),
    goods_money       numeric(14,4),
    table_charge_money numeric(14,4),
    service_money     numeric(14,4),
    coupon_amount     numeric(14,4),
    order_remark      text,
    raw_data          jsonb NOT NULL DEFAULT '{}'::jsonb,
    updated_at        timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (store_id, topup_id)
);

COMMENT ON TABLE billiards.fact_topup IS '储值充值结算流水（Topup/SettleList）';
COMMENT ON COLUMN billiards.fact_topup.store_id IS '门店 ID';
COMMENT ON COLUMN billiards.fact_topup.topup_id IS '充值记录 ID (id)';
COMMENT ON COLUMN billiards.fact_topup.member_id IS '会员 ID (memberId)';
COMMENT ON COLUMN billiards.fact_topup.member_name IS '会员姓名 (memberName)';
COMMENT ON COLUMN billiards.fact_topup.member_phone IS '会员手机号 (memberPhone)';
COMMENT ON COLUMN billiards.fact_topup.card_id IS '会员卡 ID (tenantMemberCardId)';
COMMENT ON COLUMN billiards.fact_topup.card_type_name IS '会员卡类型名称 (memberCardTypeName)';
COMMENT ON COLUMN billiards.fact_topup.pay_amount IS '支付金额 (payAmount)';
COMMENT ON COLUMN billiards.fact_topup.consume_money IS '可消费金额/储值 (consumeMoney)';
COMMENT ON COLUMN billiards.fact_topup.settle_status IS '结算状态 (settleStatus)';
COMMENT ON COLUMN billiards.fact_topup.settle_type IS '结算方式 (settleType)';
COMMENT ON COLUMN billiards.fact_topup.settle_name IS '结算名称 (settleName)';
COMMENT ON COLUMN billiards.fact_topup.settle_relate_id IS '结算关联 ID (settleRelateId)';
COMMENT ON COLUMN billiards.fact_topup.pay_time IS '支付时间 (payTime)';
COMMENT ON COLUMN billiards.fact_topup.create_time IS '创建时间 (createTime)';
COMMENT ON COLUMN billiards.fact_topup.operator_id IS '操作人 ID (operatorId)';
COMMENT ON COLUMN billiards.fact_topup.operator_name IS '操作人姓名 (operatorName)';
COMMENT ON COLUMN billiards.fact_topup.payment_method IS '支付方式 (paymentMethod)';
COMMENT ON COLUMN billiards.fact_topup.refund_amount IS '退款金额 (refundAmount)';
COMMENT ON COLUMN billiards.fact_topup.cash_amount IS '现金金额 (cashAmount)';
COMMENT ON COLUMN billiards.fact_topup.card_amount IS '银行卡金额 (cardAmount)';
COMMENT ON COLUMN billiards.fact_topup.balance_amount IS '余额抵扣金额 (balanceAmount)';
COMMENT ON COLUMN billiards.fact_topup.online_amount IS '在线支付金额 (onlineAmount)';
COMMENT ON COLUMN billiards.fact_topup.rounding_amount IS '抹零金额 (roundingAmount)';
COMMENT ON COLUMN billiards.fact_topup.adjust_amount IS '调整金额 (adjustAmount)';
COMMENT ON COLUMN billiards.fact_topup.goods_money IS '商品金额 (goodsMoney)';
COMMENT ON COLUMN billiards.fact_topup.table_charge_money IS '台费金额 (tableChargeMoney)';
COMMENT ON COLUMN billiards.fact_topup.service_money IS '服务费 (serviceMoney)';
COMMENT ON COLUMN billiards.fact_topup.coupon_amount IS '券抵扣金额 (couponAmount)';
COMMENT ON COLUMN billiards.fact_topup.order_remark IS '备注 (orderRemark)';
COMMENT ON COLUMN billiards.fact_topup.raw_data IS '原始 JSON';
COMMENT ON COLUMN billiards.fact_topup.updated_at IS 'ETL 更新时间';

CREATE TABLE IF NOT EXISTS billiards.fact_coupon_usage (
    store_id        bigint NOT NULL,
    usage_id        bigint NOT NULL,
    coupon_code     varchar(100),
    coupon_channel  varchar(50),
    coupon_name     varchar(200),
    sale_price      numeric(14,4),
    coupon_money    numeric(14,4),
    coupon_free_time integer,
    use_status      varchar(30),
    create_time     timestamptz,
    consume_time    timestamptz,
    operator_id     bigint,
    operator_name   varchar(100),
    table_id        bigint,
    site_order_id   bigint,
    group_package_id bigint,
    coupon_remark   text,
    deal_id         varchar(100),
    certificate_id  varchar(100),
    verify_id       varchar(100),
    is_delete       integer,
    raw_data        jsonb NOT NULL DEFAULT '{}'::jsonb,
    updated_at      timestamptz NOT NULL DEFAULT now(),
    PRIMARY KEY (store_id, usage_id)
);

COMMENT ON TABLE billiards.fact_coupon_usage IS '平台券验券/核销流水（Coupon/UsageList）';
COMMENT ON COLUMN billiards.fact_coupon_usage.store_id IS '门店 ID';
COMMENT ON COLUMN billiards.fact_coupon_usage.usage_id IS '核销记录 ID (id)';
COMMENT ON COLUMN billiards.fact_coupon_usage.coupon_code IS '券码 (coupon_code)';
COMMENT ON COLUMN billiards.fact_coupon_usage.coupon_channel IS '券渠道 (coupon_channel)';
COMMENT ON COLUMN billiards.fact_coupon_usage.coupon_name IS '券名称 (coupon_name)';
COMMENT ON COLUMN billiards.fact_coupon_usage.sale_price IS '售卖价 (sale_price)';
COMMENT ON COLUMN billiards.fact_coupon_usage.coupon_money IS '券面额 (coupon_money)';
COMMENT ON COLUMN billiards.fact_coupon_usage.coupon_free_time IS '赠送/免单时长 (coupon_free_time)';
COMMENT ON COLUMN billiards.fact_coupon_usage.use_status IS '核销状态 (use_status)';
COMMENT ON COLUMN billiards.fact_coupon_usage.create_time IS '创建时间 (create_time)';
COMMENT ON COLUMN billiards.fact_coupon_usage.consume_time IS '核销时间 (consume_time)';
COMMENT ON COLUMN billiards.fact_coupon_usage.operator_id IS '操作人 ID (operator_id)';
COMMENT ON COLUMN billiards.fact_coupon_usage.operator_name IS '操作人姓名 (operator_name)';
COMMENT ON COLUMN billiards.fact_coupon_usage.table_id IS '台桌 ID (table_id)';
COMMENT ON COLUMN billiards.fact_coupon_usage.site_order_id IS '场馆订单 ID (site_order_id)';
COMMENT ON COLUMN billiards.fact_coupon_usage.group_package_id IS '套餐 ID (group_package_id)';
COMMENT ON COLUMN billiards.fact_coupon_usage.coupon_remark IS '备注 (coupon_remark)';
COMMENT ON COLUMN billiards.fact_coupon_usage.deal_id IS '团购/渠道 deal_id';
COMMENT ON COLUMN billiards.fact_coupon_usage.certificate_id IS '凭证号 (certificate_id)';
COMMENT ON COLUMN billiards.fact_coupon_usage.verify_id IS '核销流水号 (verify_id)';
COMMENT ON COLUMN billiards.fact_coupon_usage.is_delete IS '删除标记 (is_delete)';
COMMENT ON COLUMN billiards.fact_coupon_usage.raw_data IS '原始 JSON';
COMMENT ON COLUMN billiards.fact_coupon_usage.updated_at IS 'ETL 更新时间';

-- =========================
--  ETL admin tables
-- =========================

CREATE TYPE IF NOT EXISTS etl_admin.run_status_enum AS ENUM ('SUCC', 'FAIL', 'PARTIAL');

COMMENT ON TYPE etl_admin.run_status_enum IS 'ETL 运行状态枚举（成功/失败/部分成功）';

CREATE TABLE IF NOT EXISTS etl_admin.etl_task (
    task_id                 bigserial PRIMARY KEY,
    store_id                bigint NOT NULL,
    task_code               varchar(50) NOT NULL,
    description             text,
    enabled                 boolean NOT NULL DEFAULT true,
    cursor_field            varchar(100),
    window_minutes_default  integer DEFAULT 60,
    overlap_seconds         integer DEFAULT 120,
    page_size               integer DEFAULT 200,
    retry_max               integer DEFAULT 3,
    params                  jsonb NOT NULL DEFAULT '{}'::jsonb,
    created_at              timestamptz NOT NULL DEFAULT now(),
    updated_at              timestamptz NOT NULL DEFAULT now(),
    UNIQUE (store_id, task_code)
);

COMMENT ON TABLE etl_admin.etl_task IS 'ETL 任务配置（启停、窗口、分页参数等）';
COMMENT ON COLUMN etl_admin.etl_task.task_id IS '任务 ID（自增主键）';
COMMENT ON COLUMN etl_admin.etl_task.store_id IS '门店 ID（任务所属门店）';
COMMENT ON COLUMN etl_admin.etl_task.task_code IS '任务代码（如 PRODUCTS、ORDERS）';
COMMENT ON COLUMN etl_admin.etl_task.description IS '任务描述';
COMMENT ON COLUMN etl_admin.etl_task.enabled IS '是否启用';
COMMENT ON COLUMN etl_admin.etl_task.cursor_field IS '游标使用的字段（如时间或 ID）';
COMMENT ON COLUMN etl_admin.etl_task.window_minutes_default IS '默认抓取窗口（分钟）';
COMMENT ON COLUMN etl_admin.etl_task.overlap_seconds IS '窗口重叠秒数，用于防重';
COMMENT ON COLUMN etl_admin.etl_task.page_size IS 'API 分页大小';
COMMENT ON COLUMN etl_admin.etl_task.retry_max IS 'API 最大重试次数';
COMMENT ON COLUMN etl_admin.etl_task.params IS '额外参数 (JSON)';
COMMENT ON COLUMN etl_admin.etl_task.created_at IS '创建时间';
COMMENT ON COLUMN etl_admin.etl_task.updated_at IS '更新时间';

CREATE TABLE IF NOT EXISTS etl_admin.etl_cursor (
    cursor_id   bigserial PRIMARY KEY,
    task_id     bigint NOT NULL REFERENCES etl_admin.etl_task(task_id) ON DELETE CASCADE,
    store_id    bigint NOT NULL,
    last_start  timestamptz,
    last_end    timestamptz,
    last_id     bigint,
    extra       jsonb NOT NULL DEFAULT '{}'::jsonb,
    last_run_id bigint,
    updated_at  timestamptz NOT NULL DEFAULT now(),
    UNIQUE (task_id, store_id)
);

COMMENT ON TABLE etl_admin.etl_cursor IS 'ETL 游标存储（记录每个任务的上次窗口与 ID）';
COMMENT ON COLUMN etl_admin.etl_cursor.cursor_id IS '游标主键';
COMMENT ON COLUMN etl_admin.etl_cursor.task_id IS '关联任务 ID';
COMMENT ON COLUMN etl_admin.etl_cursor.store_id IS '门店 ID';
COMMENT ON COLUMN etl_admin.etl_cursor.last_start IS '上次窗口起始时间';
COMMENT ON COLUMN etl_admin.etl_cursor.last_end IS '上次窗口结束时间';
COMMENT ON COLUMN etl_admin.etl_cursor.last_id IS '上次处理的 ID（适用于基于 ID 的翻页）';
COMMENT ON COLUMN etl_admin.etl_cursor.extra IS '额外游标信息 (JSON)';
COMMENT ON COLUMN etl_admin.etl_cursor.last_run_id IS '最后一次运行 run_id';
COMMENT ON COLUMN etl_admin.etl_cursor.updated_at IS '更新时间';

CREATE TABLE IF NOT EXISTS etl_admin.etl_run (
    run_id          bigserial PRIMARY KEY,
    run_uuid        varchar(64) NOT NULL,
    task_id         bigint NOT NULL REFERENCES etl_admin.etl_task(task_id) ON DELETE CASCADE,
    store_id        bigint NOT NULL,
    status          etl_admin.run_status_enum NOT NULL DEFAULT 'SUCC',
    started_at      timestamptz NOT NULL DEFAULT now(),
    ended_at        timestamptz,
    window_start    timestamptz,
    window_end      timestamptz,
    window_minutes  integer,
    overlap_seconds integer,
    fetched_count   integer DEFAULT 0,
    loaded_count    integer DEFAULT 0,
    updated_count   integer DEFAULT 0,
    skipped_count   integer DEFAULT 0,
    error_count     integer DEFAULT 0,
    unknown_fields  integer DEFAULT 0,
    export_dir      text,
    log_path        text,
    request_params  jsonb NOT NULL DEFAULT '{}'::jsonb,
    manifest        jsonb NOT NULL DEFAULT '{}'::jsonb,
    error_message   text,
    extra           jsonb NOT NULL DEFAULT '{}'::jsonb
);

CREATE INDEX IF NOT EXISTS idx_etl_run_task ON etl_admin.etl_run(task_id, started_at DESC);
CREATE INDEX IF NOT EXISTS idx_etl_run_status ON etl_admin.etl_run(status);

COMMENT ON TABLE etl_admin.etl_run IS 'ETL 运行记录（针对每次任务执行）';
COMMENT ON COLUMN etl_admin.etl_run.run_id IS '运行记录 ID';
COMMENT ON COLUMN etl_admin.etl_run.run_uuid IS '运行批次 UUID';
COMMENT ON COLUMN etl_admin.etl_run.task_id IS '任务 ID';
COMMENT ON COLUMN etl_admin.etl_run.store_id IS '门店 ID';
COMMENT ON COLUMN etl_admin.etl_run.status IS '运行状态 (SUCC/FAIL/PARTIAL)';
COMMENT ON COLUMN etl_admin.etl_run.started_at IS '开始时间';
COMMENT ON COLUMN etl_admin.etl_run.ended_at IS '结束时间';
COMMENT ON COLUMN etl_admin.etl_run.window_start IS '窗口起始时间';
COMMENT ON COLUMN etl_admin.etl_run.window_end IS '窗口结束时间';
COMMENT ON COLUMN etl_admin.etl_run.window_minutes IS '窗口长度（分钟）';
COMMENT ON COLUMN etl_admin.etl_run.overlap_seconds IS '重叠秒数';
COMMENT ON COLUMN etl_admin.etl_run.fetched_count IS '抓取条数';
COMMENT ON COLUMN etl_admin.etl_run.loaded_count IS '插入条数';
COMMENT ON COLUMN etl_admin.etl_run.updated_count IS '更新条数';
COMMENT ON COLUMN etl_admin.etl_run.skipped_count IS '跳过条数';
COMMENT ON COLUMN etl_admin.etl_run.error_count IS '错误条数';
COMMENT ON COLUMN etl_admin.etl_run.unknown_fields IS '未知字段次数';
COMMENT ON COLUMN etl_admin.etl_run.export_dir IS '导出目录';
COMMENT ON COLUMN etl_admin.etl_run.log_path IS '日志文件路径';
COMMENT ON COLUMN etl_admin.etl_run.request_params IS '本次请求参数 (JSON)';
COMMENT ON COLUMN etl_admin.etl_run.manifest IS '导出 manifest (JSON)';
COMMENT ON COLUMN etl_admin.etl_run.error_message IS '错误信息';
COMMENT ON COLUMN etl_admin.etl_run.extra IS '额外信息 (JSON)';


