-- Data warehouse schema for the entertainment chain (ODS -> DWD -> DWS) -- ASCII only to keep cross-platform friendly. DROP SCHEMA IF EXISTS billiards_ods CASCADE; CREATE SCHEMA IF NOT EXISTS billiards_ods; CREATE SCHEMA IF NOT EXISTS billiards_dwd; CREATE SCHEMA IF NOT EXISTS billiards_dws; -- ---------- ODS (raw, lightly typed) ---------- -- Each ODS table keeps the source payload for replay/debug while exposing key fields. CREATE TABLE IF NOT EXISTS billiards_ods.member_profiles ( tenant_id BIGINT, site_id BIGINT NOT NULL, member_id BIGINT NOT NULL, system_member_id BIGINT, register_site_id BIGINT, site_name TEXT, member_name TEXT, nickname TEXT, mobile TEXT, gender TEXT, birthday DATE, register_time TIMESTAMPTZ, member_type_id BIGINT, member_type_name TEXT, member_card_grade_code TEXT, status TEXT, user_status TEXT, balance NUMERIC(18,2), points NUMERIC(18,2), growth_value NUMERIC(18,2), last_visit_time TIMESTAMPTZ, wechat_id TEXT, alipay_id TEXT, member_card_no TEXT, referrer_member_id BIGINT, remarks TEXT, source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, member_id) ); COMMENT ON TABLE billiards_ods.member_profiles IS '鏉ユ簮锛氫細鍛樻。妗?json -> data.tenantMemberInfos锛涗竴鏉¤褰曚唬琛ㄢ€滅鎴峰唴涓€寮犱細鍛樺崱璐︽埛鈥?; COMMENT ON COLUMN billiards_ods.member_profiles.tenant_id IS '婧愬瓧娈?tenant_id锛涚鎴?鍝佺墝ID'; COMMENT ON COLUMN billiards_ods.member_profiles.site_id IS '浠?register_site_id 琛ュ叆锛涙敞鍐岄棬搴桰D锛堟湰鎵逛负鍗曞簵锛?; COMMENT ON COLUMN billiards_ods.member_profiles.member_id IS '婧愬瓧娈?id锛涚鎴峰唴浼氬憳璐︽埛涓婚敭锛堝搴斿崱璐︽埛/妗fID锛?; COMMENT ON COLUMN billiards_ods.member_profiles.system_member_id IS '婧愬瓧娈?system_member_id锛涘叏骞冲彴浼氬憳ID锛屽彲璺ㄥ簵鑱氬悎鍚屼竴浜?; COMMENT ON COLUMN billiards_ods.member_profiles.register_site_id IS '婧愬瓧娈?register_site_id锛涘姙鍗?娉ㄥ唽闂ㄥ簵ID'; COMMENT ON COLUMN billiards_ods.member_profiles.site_name IS '婧愬瓧娈?site_name锛涘姙鍗¢棬搴楀悕绉板揩鐓?; COMMENT ON COLUMN billiards_ods.member_profiles.member_name IS '婧愭暟鎹湭鎻愪緵锛涢鐣欎細鍛樺疄鍚?; COMMENT ON COLUMN billiards_ods.member_profiles.nickname IS '婧愬瓧娈?nickname锛涗細鍛樻樉绀哄悕/鏄电О'; COMMENT ON COLUMN billiards_ods.member_profiles.mobile IS '婧愬瓧娈?mobile锛涗細鍛樻墜鏈哄彿'; COMMENT ON COLUMN billiards_ods.member_profiles.gender IS '婧愭暟鎹湭鎻愪緵锛涢鐣欐€у埆'; COMMENT ON COLUMN billiards_ods.member_profiles.birthday IS '婧愭暟鎹湭鎻愪緵锛涢鐣欑敓鏃?; COMMENT ON COLUMN billiards_ods.member_profiles.register_time IS '婧愬瓧娈?create_time锛涜处鎴峰垱寤烘椂闂?; COMMENT ON COLUMN billiards_ods.member_profiles.member_type_id IS '婧愭暟鎹湭鎻愪緵锛涢鐣欎細鍛樼被鍨?绛夌骇ID'; COMMENT ON COLUMN billiards_ods.member_profiles.member_type_name IS '婧愭暟鎹湭鎻愪緵锛涢鐣欎細鍛樼被鍨?绛夌骇鍚嶇О'; COMMENT ON COLUMN billiards_ods.member_profiles.member_card_grade_code IS '婧愬瓧娈?member_card_grade_code锛涘崱绉?绛夌骇缂栫爜锛堝偍鍊煎崱/鍙拌垂鍗?鏈堝崱/娲诲姩鍒哥瓑锛?; COMMENT ON COLUMN billiards_ods.member_profiles.status IS '婧愬瓧娈?status锛涘崱璐︽埛鐘舵€侊紙1姝e父锛屽叾浠栦负鍋滅敤/浣滃簾锛?; COMMENT ON COLUMN billiards_ods.member_profiles.user_status IS '婧愬瓧娈?user_status锛涚敤鎴峰眰鐘舵€侊紙1姝e父锛?绂佺敤绛夛級'; COMMENT ON COLUMN billiards_ods.member_profiles.balance IS '婧愭暟鎹湭鎻愪緵锛涢鐣欎綑棰濆揩鐓э紙瀹為檯浣欓鍦ㄥ崱琛級'; COMMENT ON COLUMN billiards_ods.member_profiles.points IS '婧愬瓧娈?point锛涘綋鍓嶇Н鍒嗕綑棰濓紙鏈壒涓?锛?; COMMENT ON COLUMN billiards_ods.member_profiles.growth_value IS '婧愬瓧娈?growth_value锛涙垚闀垮€?缁忛獙鍊硷紙鏈壒涓?锛?; COMMENT ON COLUMN billiards_ods.member_profiles.last_visit_time IS '婧愭暟鎹湭鎻愪緵锛涢鐣欐渶杩戝埌搴楁椂闂?; COMMENT ON COLUMN billiards_ods.member_profiles.wechat_id IS '婧愭暟鎹湭鎻愪緵锛涢鐣欏井淇D'; COMMENT ON COLUMN billiards_ods.member_profiles.alipay_id IS '婧愭暟鎹湭鎻愪緵锛涢鐣欐敮浠樺疂ID'; COMMENT ON COLUMN billiards_ods.member_profiles.member_card_no IS '婧愭暟鎹湭鎻愪緵锛涢鐣欏疄浣撳崱鍙?; COMMENT ON COLUMN billiards_ods.member_profiles.referrer_member_id IS '婧愬瓧娈?referrer_member_id锛涙帹鑽愪汉浼氬憳ID锛?琛ㄧず鏃狅級'; COMMENT ON COLUMN billiards_ods.member_profiles.remarks IS '婧愭暟鎹湭鎻愪緵锛涢鐣欏娉?; COMMENT ON COLUMN billiards_ods.member_profiles.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰?; COMMENT ON COLUMN billiards_ods.member_profiles.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣'; COMMENT ON COLUMN billiards_ods.member_profiles.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿'; COMMENT ON COLUMN billiards_ods.member_profiles.payload IS '鍘熷JSON鍏ㄩ噺瀛樻。锛屼究浜庨噸鏀?瀹¤'; CREATE TABLE IF NOT EXISTS billiards_ods.member_stored_value_cards ( tenant_id BIGINT, site_id BIGINT NOT NULL, card_id BIGINT NOT NULL, member_id BIGINT, tenant_member_id BIGINT, card_type_id BIGINT, card_type_name TEXT, card_no TEXT, card_physics_type TEXT, card_balance NUMERIC(18,2), denomination NUMERIC(18,2), discount_rate NUMERIC(8,4), table_discount NUMERIC(18,2), goods_discount NUMERIC(18,2), assistant_discount NUMERIC(18,2), assistant_reward_discount NUMERIC(18,2), valid_start_date DATE, valid_end_date DATE, disable_start_date DATE, disable_end_date DATE, last_consume_time TIMESTAMPTZ, status TEXT, is_delete BOOLEAN, activate_time TIMESTAMPTZ, deactivate_time TIMESTAMPTZ, register_site_id BIGINT, issuer_id BIGINT, issuer_name TEXT, source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, card_id) ); COMMENT ON TABLE billiards_ods.member_stored_value_cards IS '鏉ユ簮锛氬偍鍊煎崱鍒楄〃.json -> data.tenantMemberCards锛涘寘鍚偍鍊煎崱/鍙拌垂鍗?鏈堝崱/娲诲姩鍒哥瓑浼氬憳鍗″畾涔変笌浣欓'; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tenant_id IS '婧愬瓧娈?tenant_id锛涚鎴?鍝佺墝ID'; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.site_id IS '婧愬瓧娈?register_site_id锛涘紑鍗¢棬搴桰D'; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.card_id IS '婧愬瓧娈?id锛涗細鍛樺崱璐︽埛ID'; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.member_id IS '婧愬瓧娈?system_member_id锛涘钩鍙颁細鍛業D锛堟湭缁戝畾鏃朵负0锛?; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tenant_member_id IS '婧愬瓧娈?tenant_member_id锛涚鎴峰唴浼氬憳ID'; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.card_type_id IS '婧愬瓧娈?card_type_id锛涘崱绉岻D'; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.card_type_name IS '婧愬瓧娈?member_card_type_name锛涘崱绉嶅悕绉?; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.card_no IS '婧愬瓧娈?card_no锛涘疄浣?铏氭嫙鍗″彿锛堟湰鎵逛负绌猴級'; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.card_physics_type IS '婧愬瓧娈?card_physics_type锛涚墿鐞嗗崱绫诲瀷鏋氫妇锛堟湰鎵逛负1锛?; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.card_balance IS '婧愬瓧娈?balance锛涘綋鍓嶅崱鍐呬綑棰?; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.denomination IS '婧愬瓧娈?denomination锛涢潰棰?鍒濆鍌ㄥ€奸搴?; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.discount_rate IS '婧愭暟鎹湭鎷嗗嚭缁熶竴鎶樻墸锛涘悇鍦烘櫙鎶樻墸瑙?table/goods/assistant 瀛楁'; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.table_discount IS '婧愬瓧娈?table_discount锛涘彴璐规姌鎵o紝10琛ㄧず涓嶆墦鎶?; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_discount IS '婧愬瓧娈?goods_discount锛涘晢鍝佹姌鎵?; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_discount IS '婧愬瓧娈?assistant_discount锛涘姪鏁欐湇鍔℃姌鎵?; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_reward_discount IS '婧愬瓧娈?assistant_reward_discount锛涘姪鏁欏鍔遍噾鎶樻墸'; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.valid_start_date IS '婧愬瓧娈?start_time锛涘崱鏈夋晥鏈熻捣'; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.valid_end_date IS '婧愬瓧娈?end_time锛涘崱鏈夋晥鏈熸'; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.disable_start_date IS '婧愬瓧娈?disable_start_time锛涘仠鐢ㄥ紑濮嬫椂闂达紙鏈壒榛樿0001-01-01锛?; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.disable_end_date IS '婧愬瓧娈?disable_end_time锛涘仠鐢ㄧ粨鏉熸椂闂?; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.last_consume_time IS '婧愬瓧娈?last_consume_time锛涙渶杩戞秷璐规椂闂?; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.status IS '婧愬瓧娈?status锛涘崱鐘舵€侊紙1姝e父锛?杩囨湡/鍋滅敤绛夛級'; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.is_delete IS '婧愬瓧娈?is_delete锛涢€昏緫鍒犻櫎鏍囪'; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.activate_time IS '婧愬瓧娈?create_time锛涘紑鍗℃椂闂?; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.deactivate_time IS '婧愭暟鎹湭鎻愪緵锛涢鐣欐敞閿€/鍋滅敤鏃堕棿'; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.register_site_id IS '婧愬瓧娈?register_site_id锛涘紑鍗¢棬搴桰D'; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.issuer_id IS '婧愭暟鎹湭鎻愪緵锛涢鐣欏紑鍗℃搷浣滀汉ID'; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.issuer_name IS '婧愭暟鎹湭鎻愪緵锛涢鐣欏紑鍗℃搷浣滀汉鍚嶇О'; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰?; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣'; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿'; COMMENT ON COLUMN billiards_ods.member_stored_value_cards.payload IS '鍘熷JSON鍏ㄩ噺瀛樻。锛屼究浜庨噸鏀?瀹¤'; CREATE TABLE IF NOT EXISTS billiards_ods.member_balance_changes ( tenant_id BIGINT, site_id BIGINT NOT NULL, change_id BIGINT NOT NULL, member_id BIGINT, tenant_member_id BIGINT, tenant_member_card_id BIGINT, member_name TEXT, member_mobile TEXT, change_amount NUMERIC(18,2), balance_before NUMERIC(18,2), balance_after NUMERIC(18,2), change_type INT, payment_method INT, refund_amount NUMERIC(18,2), relate_id BIGINT, register_site_id BIGINT, register_site_name TEXT, pay_site_name TEXT, remark TEXT, operator_id BIGINT, operator_name TEXT, change_time TIMESTAMPTZ, is_deleted BOOLEAN DEFAULT FALSE, source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, change_id) ); COMMENT ON TABLE billiards_ods.goods_stock_movements IS 'Source: 搴撳瓨鍙樺寲璁板綍1.json -> data.queryDeliveryRecordsList'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.tenant_id IS 'source: queryDeliveryRecordsList.tenantId; tenant/brand id'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.site_id IS 'source: queryDeliveryRecordsList.siteId; store id'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.change_id IS 'source: queryDeliveryRecordsList.siteGoodsStockId; stock change record id'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.site_goods_id IS 'source: queryDeliveryRecordsList.siteGoodsId; site goods id'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.goods_id IS 'not present in export; reserved for tenant goods id'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.stock_type IS 'source: queryDeliveryRecordsList.stockType; stock change type'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.change_amount IS 'source: queryDeliveryRecordsList.changeNum; change amount (primary unit)'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.before_stock IS 'source: queryDeliveryRecordsList.startNum; stock before change'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.after_stock IS 'source: queryDeliveryRecordsList.endNum; stock after change'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.change_amount_alt IS 'source: queryDeliveryRecordsList.changeNumA; alt unit change amount'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.before_stock_alt IS 'source: queryDeliveryRecordsList.startNumA; alt unit stock before'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.after_stock_alt IS 'source: queryDeliveryRecordsList.endNumA; alt unit stock after'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.change_type IS 'source: queryDeliveryRecordsList.stockType; stock change type enum'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.relate_id IS 'not present in export; reserved for related business id'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.unit IS 'source: queryDeliveryRecordsList.unit; unit name'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.price IS 'source: queryDeliveryRecordsList.price; unit price'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.goods_category_id IS 'source: queryDeliveryRecordsList.goodsCategoryId; category id'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.goods_second_category_id IS 'source: queryDeliveryRecordsList.goodsSecondCategoryId; second category id'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.remark IS 'source: queryDeliveryRecordsList.remark; remark'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.operator_id IS 'not present in export; reserved for operator id'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.operator_name IS 'source: queryDeliveryRecordsList.operatorName; operator name'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.change_time IS 'source: queryDeliveryRecordsList.createTime; change time'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.source_file IS 'ingest metadata: source file path'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.source_endpoint IS 'ingest metadata: API or endpoint name'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.fetched_at IS 'ingest metadata: load timestamp'; COMMENT ON COLUMN billiards_ods.goods_stock_movements.payload IS 'raw JSON payload for replay/debug'; COMMENT ON TABLE billiards_ods.member_balance_changes IS '鏉ユ簮锛氫綑棰濆彉鏇磋褰?json -> data.tenantMemberCardLogs锛涜褰曟瘡娆″崱浣欓澧炲噺'; COMMENT ON COLUMN billiards_ods.member_balance_changes.tenant_id IS '婧愬瓧娈?tenant_id锛涚鎴?鍝佺墝ID'; COMMENT ON COLUMN billiards_ods.member_balance_changes.site_id IS '婧愬瓧娈?site_id锛涘彂鐢熷彉鍔ㄧ殑闂ㄥ簵ID锛?琛ㄧず骞冲彴/璺ㄥ簵璋冩暣锛?; COMMENT ON COLUMN billiards_ods.member_balance_changes.change_id IS '婧愬瓧娈?id锛涗綑棰濆彉鏇磋褰曚富閿?; COMMENT ON COLUMN billiards_ods.member_balance_changes.member_id IS '婧愬瓧娈?system_member_id锛涘钩鍙颁細鍛業D'; COMMENT ON COLUMN billiards_ods.member_balance_changes.tenant_member_id IS '婧愬瓧娈?tenant_member_id锛涚鎴峰唴浼氬憳ID'; COMMENT ON COLUMN billiards_ods.member_balance_changes.tenant_member_card_id IS '婧愬瓧娈?tenant_member_card_id锛涗細鍛樺崱璐︽埛ID'; COMMENT ON COLUMN billiards_ods.member_balance_changes.member_name IS '婧愬瓧娈?memberName锛涗細鍛樺鍚嶅揩鐓?; COMMENT ON COLUMN billiards_ods.member_balance_changes.member_mobile IS '婧愬瓧娈?memberMobile锛涗細鍛樻墜鏈哄彿蹇収'; COMMENT ON COLUMN billiards_ods.member_balance_changes.change_amount IS '婧愬瓧娈?account_data锛涙湰娆″彉鍔ㄩ噾棰濓紝姝e姞璐熷噺'; COMMENT ON COLUMN billiards_ods.member_balance_changes.balance_before IS '婧愬瓧娈?before锛涘彉鍔ㄥ墠浣欓'; COMMENT ON COLUMN billiards_ods.member_balance_changes.balance_after IS '婧愬瓧娈?after锛涘彉鍔ㄥ悗浣欓'; COMMENT ON COLUMN billiards_ods.member_balance_changes.change_type IS '婧愬瓧娈?from_type锛涘彉鍔ㄦ潵婧愮被鍨嬫灇涓?; COMMENT ON COLUMN billiards_ods.member_balance_changes.payment_method IS '婧愬瓧娈?payment_method锛涙敮浠樻柟寮忔灇涓?; COMMENT ON COLUMN billiards_ods.member_balance_changes.refund_amount IS '婧愬瓧娈?refund_amount锛涢€€娆鹃噾棰濓紙鏍锋湰涓?锛?; COMMENT ON COLUMN billiards_ods.member_balance_changes.relate_id IS '婧愬瓧娈?relate_id锛涘叧鑱斾笟鍔D锛堝厖鍊?缁撶畻/娲诲姩绛夛級'; COMMENT ON COLUMN billiards_ods.member_balance_changes.register_site_id IS '婧愬瓧娈?register_site_id锛涘姙鍗¢棬搴桰D'; COMMENT ON COLUMN billiards_ods.member_balance_changes.register_site_name IS '婧愬瓧娈?registerSiteName锛涘姙鍗¢棬搴楀悕绉?; COMMENT ON COLUMN billiards_ods.member_balance_changes.pay_site_name IS '婧愬瓧娈?paySiteName锛涙湰娆″彂鐢熼棬搴楀悕绉?; COMMENT ON COLUMN billiards_ods.member_balance_changes.remark IS '婧愬瓧娈?remark锛涘娉?; COMMENT ON COLUMN billiards_ods.member_balance_changes.operator_id IS '婧愬瓧娈?operator_id锛涙搷浣滃憳ID'; COMMENT ON COLUMN billiards_ods.member_balance_changes.operator_name IS '婧愬瓧娈?operator_name锛涙搷浣滃憳鍚嶇О'; COMMENT ON COLUMN billiards_ods.member_balance_changes.change_time IS '婧愬瓧娈?create_time锛涘彉鍔ㄦ椂闂?; COMMENT ON COLUMN billiards_ods.member_balance_changes.is_deleted IS '婧愬瓧娈?is_delete锛涢€昏緫鍒犻櫎鏍囪'; COMMENT ON COLUMN billiards_ods.member_balance_changes.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰?; COMMENT ON COLUMN billiards_ods.member_balance_changes.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣'; COMMENT ON COLUMN billiards_ods.member_balance_changes.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿'; COMMENT ON COLUMN billiards_ods.member_balance_changes.payload IS '鍘熷JSON鍏ㄩ噺瀛樻。锛屼究浜庨噸鏀?瀹¤'; CREATE TABLE IF NOT EXISTS billiards_ods.ods_recharge_record ( tenant_id BIGINT, site_id BIGINT NOT NULL, recharge_id BIGINT NOT NULL, member_id BIGINT, recharge_amount NUMERIC(18,2), gift_amount NUMERIC(18,2), pay_method INT, pay_trade_no TEXT, order_trade_no TEXT, recharge_time TIMESTAMPTZ, status TEXT, operator_id BIGINT, operator_name TEXT, source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, recharge_id) ); COMMENT ON TABLE billiards_ods.ods_recharge_record IS '鏉ユ簮锛氬厖鍊艰褰?json -> data.settleList[].settleList锛涙部鐢ㄧ粨绠楀崟妯″瀷鐨勫厖鍊兼祦姘?; COMMENT ON COLUMN billiards_ods.ods_recharge_record.tenant_id IS '婧愬瓧娈?tenantId锛涚鎴?鍝佺墝ID'; COMMENT ON COLUMN billiards_ods.ods_recharge_record.site_id IS '婧愬瓧娈?siteId锛涘厖鍊煎彂鐢熼棬搴?; COMMENT ON COLUMN billiards_ods.ods_recharge_record.recharge_id IS '婧愬瓧娈?id锛涘厖鍊艰褰旾D'; COMMENT ON COLUMN billiards_ods.ods_recharge_record.member_id IS '婧愬瓧娈?memberId锛涗細鍛業D锛堝彲涓?琛ㄧず鏈粦浼氬憳锛?; COMMENT ON COLUMN billiards_ods.ods_recharge_record.recharge_amount IS '婧愬瓧娈?payAmount锛涙湰娆″厖鍊兼敮浠橀噾棰?; COMMENT ON COLUMN billiards_ods.ods_recharge_record.gift_amount IS '婧愬瓧娈?giftCardAmount锛涜禒閫侀噾棰濓紙鏍锋湰涓?锛?; COMMENT ON COLUMN billiards_ods.ods_recharge_record.pay_method IS '婧愬瓧娈?paymentMethod锛涙敮浠樻柟寮忔灇涓?; COMMENT ON COLUMN billiards_ods.ods_recharge_record.pay_trade_no IS '婧愭暟鎹湭缁欙紱棰勭暀澶栭儴浜ゆ槗鍙?; COMMENT ON COLUMN billiards_ods.ods_recharge_record.order_trade_no IS '婧愬瓧娈?settleRelateId 鍙槧灏勶紱鍏宠仈涓氬姟鍗曞彿'; COMMENT ON COLUMN billiards_ods.ods_recharge_record.recharge_time IS '婧愬瓧娈?payTime锛涙敮浠樻椂闂?; COMMENT ON COLUMN billiards_ods.ods_recharge_record.status IS '婧愬瓧娈?settleStatus锛涘厖鍊肩姸鎬侊紙2鎴愬姛绛夛級'; COMMENT ON COLUMN billiards_ods.ods_recharge_record.operator_id IS '婧愬瓧娈?operatorId锛涙搷浣滃憳ID'; COMMENT ON COLUMN billiards_ods.ods_recharge_record.operator_name IS '婧愬瓧娈?operatorName锛涙搷浣滃憳鍚嶇О'; COMMENT ON COLUMN billiards_ods.ods_recharge_record.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰?; COMMENT ON COLUMN billiards_ods.ods_recharge_record.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣'; COMMENT ON COLUMN billiards_ods.ods_recharge_record.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿'; COMMENT ON COLUMN billiards_ods.ods_recharge_record.payload IS '鍘熷JSON鍏ㄩ噺瀛樻。锛屼究浜庨噸鏀?瀹¤'; CREATE TABLE IF NOT EXISTS billiards_ods.ods_product ( tenant_id BIGINT, site_id BIGINT NOT NULL, goods_id BIGINT NOT NULL, goods_name TEXT, goods_code TEXT, category_id BIGINT, category_name TEXT, goods_second_category_id BIGINT, unit TEXT, price NUMERIC(18,2), cost_price NUMERIC(18,2), market_price NUMERIC(18,2), goods_state TEXT, goods_cover TEXT, goods_bar_code TEXT, able_discount BOOLEAN, is_delete BOOLEAN, status TEXT, source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, goods_id) ); COMMENT ON TABLE billiards_ods.ods_product IS '鏉ユ簮锛氬晢鍝佹。妗?json -> data.tenantGoodsList锛涚鎴风骇鍟嗗搧鍩虹淇℃伅'; COMMENT ON COLUMN billiards_ods.ods_product.tenant_id IS '婧愬瓧娈?tenant_id锛涚鎴?鍝佺墝ID'; COMMENT ON COLUMN billiards_ods.ods_product.site_id IS '婧愭暟鎹湭缁欙紱鍟嗗搧涓虹鎴风骇锛屾寜閲囬泦涓婁笅鏂囪祴鍊?; COMMENT ON COLUMN billiards_ods.ods_product.goods_id IS '婧愬瓧娈?id锛涚鎴峰晢鍝両D'; COMMENT ON COLUMN billiards_ods.ods_product.goods_name IS '婧愬瓧娈?goods_name锛涘晢鍝佸悕绉?; COMMENT ON COLUMN billiards_ods.ods_product.goods_code IS '婧愬瓧娈?commodityCode/commodity_code锛涘唴閮ㄧ紪鐮?鏉$爜'; COMMENT ON COLUMN billiards_ods.ods_product.category_id IS '婧愬瓧娈?goods_category_id锛涗竴绾у垎绫籌D'; COMMENT ON COLUMN billiards_ods.ods_product.category_name IS '婧愬瓧娈?categoryName锛涗竴绾у垎绫诲悕绉?; COMMENT ON COLUMN billiards_ods.ods_product.goods_second_category_id IS '婧愬瓧娈?goods_second_category_id锛涗簩绾у垎绫籌D'; COMMENT ON COLUMN billiards_ods.ods_product.unit IS '婧愬瓧娈?unit锛涜閲忓崟浣?; COMMENT ON COLUMN billiards_ods.ods_product.price IS '婧愭暟鎹湭鐩存帴缁欙紱鍙寜 market_price/min_discount_price 琛ュ厖'; COMMENT ON COLUMN billiards_ods.ods_product.cost_price IS '婧愬瓧娈?cost_price锛涙垚鏈环'; COMMENT ON COLUMN billiards_ods.ods_product.market_price IS '婧愬瓧娈?market_price锛涘競鍦?鏍囦环'; COMMENT ON COLUMN billiards_ods.ods_product.goods_state IS '婧愬瓧娈?goods_state锛涗笂鏋剁姸鎬?; COMMENT ON COLUMN billiards_ods.ods_product.goods_cover IS '婧愬瓧娈?goods_cover锛涘晢鍝佸浘鐗嘦RL'; COMMENT ON COLUMN billiards_ods.ods_product.goods_bar_code IS '婧愬瓧娈?goods_bar_code锛涙潯鐮?; COMMENT ON COLUMN billiards_ods.ods_product.able_discount IS '婧愬瓧娈?able_discount锛涙槸鍚﹀彲鎵撴姌'; COMMENT ON COLUMN billiards_ods.ods_product.is_delete IS '婧愬瓧娈?is_delete锛涢€昏緫鍒犻櫎鏍囪'; COMMENT ON COLUMN billiards_ods.ods_product.status IS '涓?goods_state 瀵归綈鐨勯€氱敤鐘舵€?; COMMENT ON COLUMN billiards_ods.ods_product.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰?; COMMENT ON COLUMN billiards_ods.ods_product.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣'; COMMENT ON COLUMN billiards_ods.ods_product.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿'; COMMENT ON COLUMN billiards_ods.ods_product.payload IS '鍘熷JSON鍏ㄩ噺瀛樻。锛屼究浜庨噸鏀?瀹¤'; CREATE TABLE IF NOT EXISTS billiards_ods.ods_store_product ( tenant_id BIGINT, site_id BIGINT NOT NULL, site_goods_id BIGINT NOT NULL, goods_id BIGINT, goods_name TEXT, category_id BIGINT, category_name TEXT, unit TEXT, sale_price NUMERIC(18,2), cost_price NUMERIC(18,2), sale_num NUMERIC(18,2), stock_a NUMERIC(18,2), stock NUMERIC(18,2), provisional_total_cost NUMERIC(18,2), total_purchase_cost NUMERIC(18,2), batch_stock_quantity NUMERIC(18,2), goods_state TEXT, status TEXT, source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, site_goods_id) ); COMMENT ON TABLE billiards_ods.ods_store_product IS '鏉ユ簮锛氶棬搴楀晢鍝佹。妗?.json -> data.orderGoodsList锛涢棬搴楃淮搴﹀晢鍝佽鍥?; COMMENT ON COLUMN billiards_ods.ods_store_product.tenant_id IS '婧愬瓧娈?tenant_id锛涚鎴?鍝佺墝ID'; COMMENT ON COLUMN billiards_ods.ods_store_product.site_id IS '婧愬瓧娈?site_id锛涢棬搴桰D'; COMMENT ON COLUMN billiards_ods.ods_store_product.site_goods_id IS '婧愬瓧娈?id锛涢棬搴楀晢鍝両D'; COMMENT ON COLUMN billiards_ods.ods_store_product.goods_id IS '婧愬瓧娈?tenant_goods_id锛涚鎴风骇鍟嗗搧ID'; COMMENT ON COLUMN billiards_ods.ods_store_product.goods_name IS '婧愬瓧娈?goods_name锛涘晢鍝佸悕绉?; COMMENT ON COLUMN billiards_ods.ods_store_product.category_id IS '婧愬瓧娈?goods_category_id锛涘垎绫籌D'; COMMENT ON COLUMN billiards_ods.ods_store_product.category_name IS '婧愬瓧娈?twoCategoryName/oneCategoryName锛涘垎绫诲悕绉板揩鐓?; COMMENT ON COLUMN billiards_ods.ods_store_product.unit IS '婧愬瓧娈?unit锛涜閲忓崟浣?; COMMENT ON COLUMN billiards_ods.ods_store_product.sale_price IS '婧愬瓧娈?sale_price锛涢攢鍞环'; COMMENT ON COLUMN billiards_ods.ods_store_product.cost_price IS '婧愬瓧娈?cost_price锛涙垚鏈环'; COMMENT ON COLUMN billiards_ods.ods_store_product.sale_num IS '婧愬瓧娈?sale_num锛涚疮璁¢攢閲?; COMMENT ON COLUMN billiards_ods.ods_store_product.stock_a IS '婧愬瓧娈?stock_A锛涘鐢ㄥ簱瀛樻暟閲?; COMMENT ON COLUMN billiards_ods.ods_store_product.stock IS '婧愬瓧娈?stock锛涘綋鍓嶅簱瀛?; COMMENT ON COLUMN billiards_ods.ods_store_product.provisional_total_cost IS '婧愬瓧娈?provisional_total_cost锛涙殏浼板簱瀛樻垚鏈?; COMMENT ON COLUMN billiards_ods.ods_store_product.total_purchase_cost IS '婧愬瓧娈?total_purchase_cost锛涜繘璐ф€绘垚鏈?; COMMENT ON COLUMN billiards_ods.ods_store_product.batch_stock_quantity IS '婧愬瓧娈?batch_stock_quantity锛涙壒娆″簱瀛樻暟閲?; COMMENT ON COLUMN billiards_ods.ods_store_product.goods_state IS '婧愬瓧娈?goods_state锛涘晢鍝佺姸鎬?; COMMENT ON COLUMN billiards_ods.ods_store_product.status IS '婧愬瓧娈?enable_status锛涗笂涓嬫灦鐘舵€?; COMMENT ON COLUMN billiards_ods.ods_store_product.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰?; COMMENT ON COLUMN billiards_ods.ods_store_product.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣'; COMMENT ON COLUMN billiards_ods.ods_store_product.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿'; COMMENT ON COLUMN billiards_ods.ods_store_product.payload IS '鍘熷JSON鍏ㄩ噺瀛樻。锛屼究浜庨噸鏀?瀹¤'; CREATE TABLE IF NOT EXISTS billiards_ods.ods_store_sale_item ( tenant_id BIGINT, site_id BIGINT NOT NULL, sale_item_id BIGINT NOT NULL, order_goods_id BIGINT, order_trade_no TEXT, order_settle_id BIGINT, site_goods_id BIGINT, goods_id BIGINT, goods_name TEXT, category_id BIGINT, quantity NUMERIC(18,4), unit_price NUMERIC(18,2), original_amount NUMERIC(18,2), discount_amount NUMERIC(18,2), final_amount NUMERIC(18,2), is_gift BOOLEAN DEFAULT FALSE, sale_time TIMESTAMPTZ, member_id BIGINT, salesman_id BIGINT, operator_id BIGINT, is_refunded BOOLEAN DEFAULT FALSE, discount_price NUMERIC(18,2), cost_money NUMERIC(18,2), coupon_deduct_amount NUMERIC(18,2), member_discount_amount NUMERIC(18,2), point_discount_money NUMERIC(18,2), point_discount_cost NUMERIC(18,2), sales_type TEXT, goods_remark TEXT, source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, sale_item_id) ); COMMENT ON TABLE billiards_ods.ods_store_sale_item IS '鏉ユ簮锛氶棬搴楀晢鍝侀攢鍞褰?json -> data.orderGoodsLedgers锛涘晢鍝佹槑缁嗘祦姘?; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.tenant_id IS '婧愬瓧娈?tenant_id锛涚鎴?鍝佺墝ID'; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.site_id IS '婧愬瓧娈?site_id锛涢棬搴桰D'; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.sale_item_id IS '婧愬瓧娈?id锛涘晢鍝佹槑缁嗘祦姘碔D'; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.order_goods_id IS '婧愬瓧娈?order_goods_id锛涗笂娓歌鍗曞晢鍝両D'; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.order_trade_no IS '婧愬瓧娈?order_trade_no锛涗笟鍔¤鍗曞彿'; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.order_settle_id IS '婧愬瓧娈?order_settle_id锛涚粨绠楀崟ID'; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.site_goods_id IS '婧愬瓧娈?site_goods_id锛涢棬搴楀晢鍝両D'; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.goods_id IS '婧愬瓧娈?tenant_goods_id锛涚鎴风骇鍟嗗搧ID'; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.goods_name IS '婧愬瓧娈?ledger_name锛涘晢鍝佸悕绉板揩鐓?; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.category_id IS '婧愬瓧娈?tenant_goods_category_id锛涘晢鍝佸垎绫籌D'; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.quantity IS '婧愬瓧娈?ledger_count锛涢攢鍞暟閲?; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.unit_price IS '婧愬瓧娈?ledger_unit_price锛涚粨绠楀崟浠?; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.original_amount IS '婧愬瓧娈?ledger_amount锛涘師濮嬮噾棰濓紙鏈墸鍑忥級'; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.discount_amount IS '婧愬瓧娈?discount_money锛涙姌鎵i噾棰?; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.final_amount IS '婧愬瓧娈?real_goods_money锛涙姌鍚庡疄鏀堕噾棰?; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.is_gift IS '鐢?sales_type/ledger_status 鎺ㄥ锛涜禒閫?閫€璐у満鏅爣璁?; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.sale_time IS '婧愬瓧娈?create_time锛涢攢鍞椂闂?; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.member_id IS '婧愭暟鎹湭缁欙紱棰勭暀浼氬憳ID'; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.salesman_id IS '婧愬瓧娈?salesman_user_id锛涢攢鍞憳ID'; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.operator_id IS '婧愬瓧娈?operator_id锛涙敹閾?鎿嶄綔鍛業D'; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.is_refunded IS '鐢?returns_number>0 鎴?ledger_status 鍒ゆ柇锛涢€€璐ф爣璁?; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.discount_price IS '婧愬瓧娈?discount_price锛涙姌鍚庡崟浠凤紙濡傛湁锛?; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.cost_money IS '婧愬瓧娈?cost_money锛涙垚鏈噾棰?; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.coupon_deduct_amount IS '婧愬瓧娈?coupon_deduct_money + option_coupon_deduct_money锛涘埜鎶垫墸閲戦'; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.member_discount_amount IS '婧愬瓧娈?member_discount_amount锛涗細鍛樻姌鎵i噾棰?; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.point_discount_money IS '婧愬瓧娈?point_discount_money锛涚Н鍒嗘姷鎵i噾棰?; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.point_discount_cost IS '婧愬瓧娈?point_discount_money_cost锛涚Н鍒嗘姷鎵f垚鏈?; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.sales_type IS '婧愬瓧娈?sales_type锛涢攢鍞被鍨嬫灇涓?; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.goods_remark IS '婧愬瓧娈?goods_remark锛涘晢鍝佸娉?; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰?; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣'; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿'; COMMENT ON COLUMN billiards_ods.ods_store_sale_item.payload IS '鍘熷JSON鍏ㄩ噺瀛樻。锛屼究浜庨噸鏀?瀹¤'; CREATE TABLE IF NOT EXISTS billiards_ods.ods_table_info ( tenant_id BIGINT, site_id BIGINT NOT NULL, table_id BIGINT NOT NULL, table_code TEXT, table_name TEXT, table_type TEXT, area_name TEXT, site_table_area_id BIGINT, tenant_table_area_id BIGINT, table_price NUMERIC(18,2), table_status TEXT, audit_status INT, show_status INT, light_status INT, virtual_table BOOLEAN, is_rest_area BOOLEAN, charge_free BOOLEAN, table_cloth_use_time INT, table_cloth_use_cycle INT, status TEXT, created_time TIMESTAMPTZ, updated_time TIMESTAMPTZ, source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, table_id) ); COMMENT ON TABLE billiards_ods.ods_table_info IS '鏉ユ簮锛氬彴妗屽垪琛?json -> data.siteTables锛涢棬搴楃悆妗?鍖呭帰妗f'; COMMENT ON COLUMN billiards_ods.ods_table_info.tenant_id IS '婧愭暟鎹湭缁欙紱鎸夐噰闆嗕笂涓嬫枃璁剧疆'; COMMENT ON COLUMN billiards_ods.ods_table_info.site_id IS '婧愬瓧娈?site_id锛涢棬搴桰D'; COMMENT ON COLUMN billiards_ods.ods_table_info.table_id IS '婧愬瓧娈?id锛涚悆妗?鍖呭帰ID'; COMMENT ON COLUMN billiards_ods.ods_table_info.table_code IS '婧愭暟鎹湭缁欙紱棰勭暀鍐呴儴缂栧彿'; COMMENT ON COLUMN billiards_ods.ods_table_info.table_name IS '婧愬瓧娈?table_name锛涙鍙?鍚嶇О'; COMMENT ON COLUMN billiards_ods.ods_table_info.table_type IS '婧愭暟鎹湭缁欙紱棰勭暀妗屽瀷'; COMMENT ON COLUMN billiards_ods.ods_table_info.area_name IS '婧愬瓧娈?areaName锛涙墍灞炲尯鍩熷悕绉?; COMMENT ON COLUMN billiards_ods.ods_table_info.site_table_area_id IS '婧愬瓧娈?site_table_area_id锛涢棬搴楀尯鍩烮D'; COMMENT ON COLUMN billiards_ods.ods_table_info.tenant_table_area_id IS '婧愭暟鎹湭缁欙紱棰勭暀绉熸埛绾у尯鍩烮D'; COMMENT ON COLUMN billiards_ods.ods_table_info.table_price IS '婧愬瓧娈?table_price锛涘熀纭€鍙拌垂鍗曚环'; COMMENT ON COLUMN billiards_ods.ods_table_info.table_status IS '婧愬瓧娈?table_status锛涘綋鍓嶆鐘舵€?; COMMENT ON COLUMN billiards_ods.ods_table_info.audit_status IS '婧愬瓧娈?audit_status锛涘鏍哥姸鎬?; COMMENT ON COLUMN billiards_ods.ods_table_info.show_status IS '婧愬瓧娈?show_status锛涙樉绀虹姸鎬?; COMMENT ON COLUMN billiards_ods.ods_table_info.light_status IS '婧愬瓧娈?light_status锛涚伅鎺х姸鎬?; COMMENT ON COLUMN billiards_ods.ods_table_info.virtual_table IS '婧愬瓧娈?virtual_table锛涙槸鍚﹁櫄鎷熸'; COMMENT ON COLUMN billiards_ods.ods_table_info.is_rest_area IS '婧愬瓧娈?is_rest_area锛涙槸鍚︿紤鎭尯'; COMMENT ON COLUMN billiards_ods.ods_table_info.charge_free IS '婧愬瓧娈?charge_free锛涙槸鍚﹀厤璐?; COMMENT ON COLUMN billiards_ods.ods_table_info.table_cloth_use_time IS '婧愬瓧娈?table_cloth_use_time锛涘彴鍛㈠凡鐢ㄦ椂闀匡紙绉掞級'; COMMENT ON COLUMN billiards_ods.ods_table_info.table_cloth_use_cycle IS '婧愬瓧娈?table_cloth_use_Cycle锛涘彴鍛㈡洿鎹㈠懆鏈熼槇鍊硷紙绉掞級'; COMMENT ON COLUMN billiards_ods.ods_table_info.status IS '閫氱敤鐘舵€侊紱鍙粨鍚?table_status/show_status 浣跨敤'; COMMENT ON COLUMN billiards_ods.ods_table_info.created_time IS '婧愬瓧娈?create_time锛涘垱寤烘椂闂?; COMMENT ON COLUMN billiards_ods.ods_table_info.updated_time IS '婧愭暟鎹湭缁欙紱棰勭暀鏇存柊鏃堕棿'; COMMENT ON COLUMN billiards_ods.ods_table_info.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰?; COMMENT ON COLUMN billiards_ods.ods_table_info.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣'; COMMENT ON COLUMN billiards_ods.ods_table_info.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿'; COMMENT ON COLUMN billiards_ods.ods_table_info.payload IS '鍘熷JSON鍏ㄩ噺瀛樻。锛屼究浜庨噸鏀?瀹¤'; CREATE TABLE IF NOT EXISTS billiards_ods.table_fee_transactions_log ( tenant_id BIGINT, site_id BIGINT NOT NULL, ledger_id BIGINT NOT NULL, table_id BIGINT, table_name TEXT, order_trade_no TEXT, order_settle_id BIGINT, start_time TIMESTAMPTZ, end_time TIMESTAMPTZ, duration_seconds INT, billing_unit_price NUMERIC(18,4), billing_count NUMERIC(18,4), original_table_fee NUMERIC(18,2), member_discount_amount NUMERIC(18,2), coupon_discount_amount NUMERIC(18,2), manual_discount_amount NUMERIC(18,2), service_fee NUMERIC(18,2), final_table_fee NUMERIC(18,2), member_id BIGINT, operator_id BIGINT, salesman_id BIGINT, is_canceled BOOLEAN DEFAULT FALSE, cancel_time TIMESTAMPTZ, site_table_area_id BIGINT, tenant_table_area_id BIGINT, site_table_area_name TEXT, is_single_order BOOLEAN, used_card_amount NUMERIC(18,2), adjust_amount NUMERIC(18,2), coupon_promotion_amount NUMERIC(18,2), service_money NUMERIC(18,2), mgmt_fee NUMERIC(18,2), fee_total NUMERIC(18,2), real_table_use_seconds INT, last_use_time TIMESTAMPTZ, ledger_start_time TIMESTAMPTZ, ledger_end_time TIMESTAMPTZ, ledger_status INT, start_use_time TIMESTAMPTZ, add_clock_seconds INT, status TEXT, source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, ledger_id) ); COMMENT ON TABLE billiards_ods.ods_assistant_service_log IS 'Source: 鍔╂暀娴佹按.json -> data.orderAssistantDetails'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.tenant_id IS 'source: orderAssistantDetails.tenant_id; tenant/brand id'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.site_id IS 'source: orderAssistantDetails.site_id; store id'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.ledger_id IS 'source: orderAssistantDetails.id; assistant service ledger id'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.assistant_id IS 'source: orderAssistantDetails.site_assistant_id; assistant id'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.assistant_name IS 'source: orderAssistantDetails.assistantName; assistant name'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.service_type IS 'source: orderAssistantDetails.order_assistant_type; service type code'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.order_trade_no IS 'source: orderAssistantDetails.order_trade_no; business order number'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.order_settle_id IS 'source: orderAssistantDetails.order_settle_id; settlement id'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.start_time IS 'source: orderAssistantDetails.start_use_time; service start time'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.end_time IS 'source: orderAssistantDetails.ledger_end_time; service end time'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.duration_seconds IS 'source: orderAssistantDetails.real_use_seconds; actual service seconds'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.original_fee IS 'source: orderAssistantDetails.ledger_amount; amount before discounts'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.member_discount_amount IS 'source: orderAssistantDetails.member_discount_amount; member discount amount'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.manual_discount_amount IS 'source: orderAssistantDetails.manual_discount_amount; manual discount'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.coupon_discount_amount IS 'source: orderAssistantDetails.coupon_deduct_money; coupon deduction'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.final_fee IS 'source: orderAssistantDetails.service_money; final assistant fee'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.member_id IS 'source: orderAssistantDetails.system_member_id; member id'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.operator_id IS 'source: orderAssistantDetails.operator_id; operator id'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.salesman_id IS 'source: orderAssistantDetails.salesman_user_id; salesperson id'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.is_canceled IS 'derived; set when is_delete/is_trash indicates cancellation'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.cancel_time IS 'not present in export; reserved for cancel time'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.skill_grade IS 'source: orderAssistantDetails.skill_grade; skill grade score'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.service_grade IS 'source: orderAssistantDetails.service_grade; service grade score'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.composite_grade IS 'source: orderAssistantDetails.composite_grade; composite score'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.overall_score IS 'source: orderAssistantDetails.sum_grade; overall score sum'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.status IS 'source: orderAssistantDetails.ledger_status/grade_status; status flag'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.source_file IS 'ingest metadata: source file path'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.source_endpoint IS 'ingest metadata: API or endpoint name'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.fetched_at IS 'ingest metadata: load timestamp'; COMMENT ON COLUMN billiards_ods.ods_assistant_service_log.payload IS 'raw JSON payload for replay/debug'; COMMENT ON TABLE billiards_ods.table_fee_transactions_log IS '鏉ユ簮锛氬彴璐规祦姘?json -> data.siteTableUseDetailsList锛涘彴璐硅璐规祦姘?; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.tenant_id IS '婧愬瓧娈?tenant_id锛涚鎴?鍝佺墝ID'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.site_id IS '婧愬瓧娈?site_id锛涢棬搴桰D'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.ledger_id IS '婧愬瓧娈?id锛涘彴璐硅处鍗旾D'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.table_id IS '婧愬瓧娈?site_table_id锛涚悆妗孖D'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.table_name IS '婧愬瓧娈?ledger_name锛涙鍚嶅揩鐓?; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.order_trade_no IS '婧愬瓧娈?order_trade_no锛涗笟鍔¤鍗曞彿'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.order_settle_id IS '婧愬瓧娈?order_settle_id锛涚粨绠楀崟ID'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.start_time IS '婧愬瓧娈?ledger_start_time锛涜璐瑰紑濮嬫椂闂?; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.end_time IS '婧愬瓧娈?ledger_end_time锛涜璐圭粨鏉熸椂闂?; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.duration_seconds IS '婧愬瓧娈?ledger_count锛涜璐规椂闀?鏁伴噺锛堢锛?; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.billing_unit_price IS '婧愬瓧娈?ledger_unit_price锛涜璐瑰崟浠?; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.billing_count IS '婧愬瓧娈?ledger_count锛涜璐规暟閲?; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.original_table_fee IS '婧愬瓧娈?ledger_amount锛涙姌鎵e墠閲戦'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.member_discount_amount IS '婧愬瓧娈?member_discount_amount锛涗細鍛樻姌鎵?; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.coupon_discount_amount IS '婧愬瓧娈?coupon_promotion_amount锛涘埜鎶垫墸'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.manual_discount_amount IS '婧愬瓧娈?adjust_amount锛涙墜宸ヤ紭鎯?璋冩暣'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.service_fee IS '婧愬瓧娈?service_money锛涙湇鍔¤垂'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.final_table_fee IS '婧愬瓧娈?real_table_charge_money锛涙渶缁堝彴璐?; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.member_id IS '婧愬瓧娈?member_id锛涗細鍛業D'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.operator_id IS '婧愬瓧娈?operator_id锛涙搷浣滃憳ID'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.salesman_id IS '婧愬瓧娈?salesman_user_id锛涢攢鍞憳ID'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.is_canceled IS '鐢?ledger_status/is_delete 鎺ㄥ锛涙槸鍚﹀彇娑?; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.cancel_time IS '婧愭暟鎹湭缁欙紱棰勭暀鍙栨秷鏃堕棿'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.site_table_area_id IS '婧愬瓧娈?site_table_area_id锛涢棬搴楀尯鍩烮D'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.tenant_table_area_id IS '婧愬瓧娈?tenant_table_area_id锛涚鎴峰尯鍩烮D'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.site_table_area_name IS '婧愬瓧娈?site_table_area_name锛涘尯鍩熷悕绉?; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.is_single_order IS '婧愬瓧娈?is_single_order锛涘崟鍙?骞跺崟鏍囪'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.used_card_amount IS '婧愬瓧娈?used_card_amount锛涘崱鏀粯閲戦'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.adjust_amount IS '婧愬瓧娈?adjust_amount锛涜皟鏁撮噾棰?; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.coupon_promotion_amount IS '婧愬瓧娈?coupon_promotion_amount锛涗紭鎯犲埜淇冮攢閲戦'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.service_money IS '婧愬瓧娈?service_money锛涙湇鍔¤垂閲戦'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.mgmt_fee IS '婧愬瓧娈?mgmt_fee锛涚鐞嗚垂'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.fee_total IS '婧愬瓧娈?fee_total锛涙€昏垂鐢紙鍚績閿€鍚庯級'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.real_table_use_seconds IS '婧愬瓧娈?real_table_use_seconds锛涘疄闄呬娇鐢ㄧ鏁?; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.last_use_time IS '婧愬瓧娈?last_use_time锛涙渶杩戜娇鐢ㄧ粨鏉熸椂闂?; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.ledger_start_time IS '婧愬瓧娈?ledger_start_time锛涜璐瑰紑濮?; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.ledger_end_time IS '婧愬瓧娈?ledger_end_time锛涜璐圭粨鏉?; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.ledger_status IS '婧愬瓧娈?ledger_status锛涜处鍗曠姸鎬?; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.start_use_time IS '婧愬瓧娈?start_use_time锛涘疄闄呭紑濮嬬敤鍙版椂闂?; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.add_clock_seconds IS '婧愬瓧娈?add_clock_seconds锛涢澶栬鏃剁鏁?; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.status IS '閫氱敤鐘舵€侊紱缁撳悎 ledger_status/is_delete 鍒ゅ畾'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰?; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿'; COMMENT ON COLUMN billiards_ods.table_fee_transactions_log.payload IS '鍘熷JSON鍏ㄩ噺瀛樻。锛屼究浜庨噸鏀?瀹¤'; CREATE TABLE IF NOT EXISTS billiards_ods.ods_table_fee_adjust ( tenant_id BIGINT, site_id BIGINT NOT NULL, adjust_id BIGINT NOT NULL, ledger_id BIGINT, order_trade_no TEXT, discount_amount NUMERIC(18,2), reason TEXT, operator_id BIGINT, operator_name TEXT, created_at TIMESTAMPTZ, source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, adjust_id) ); COMMENT ON TABLE billiards_ods.ods_table_fee_adjust IS '鏉ユ簮锛氬彴璐规墦鎶?json -> data.taiFeeAdjustInfos锛涘彴璐规墜宸ユ姌鎵?璋冩暣璁板綍'; COMMENT ON COLUMN billiards_ods.ods_table_fee_adjust.tenant_id IS '婧愬瓧娈?tenant_id锛涚鎴?鍝佺墝ID'; COMMENT ON COLUMN billiards_ods.ods_table_fee_adjust.site_id IS '婧愬瓧娈?site_id锛涢棬搴桰D'; COMMENT ON COLUMN billiards_ods.ods_table_fee_adjust.adjust_id IS '婧愬瓧娈?id锛涘彴璐规姌鎵h褰旾D'; COMMENT ON COLUMN billiards_ods.ods_table_fee_adjust.ledger_id IS '婧愬瓧娈?order_settle_id锛涘叧鑱斿彴璐硅处鍗?缁撶畻ID'; COMMENT ON COLUMN billiards_ods.ods_table_fee_adjust.order_trade_no IS '婧愬瓧娈?order_trade_no锛涗笟鍔¤鍗曞彿'; COMMENT ON COLUMN billiards_ods.ods_table_fee_adjust.discount_amount IS '婧愬瓧娈?ledger_amount锛涙姌鎵i噾棰?; COMMENT ON COLUMN billiards_ods.ods_table_fee_adjust.reason IS '婧愬瓧娈?adjust_type/applicant_* 缁勫悎锛涜皟鏁村師鍥狅紙鏄庣粏闇€缁撳悎 payload锛?; COMMENT ON COLUMN billiards_ods.ods_table_fee_adjust.operator_id IS '婧愬瓧娈?operator_id锛涙搷浣滃憳ID'; COMMENT ON COLUMN billiards_ods.ods_table_fee_adjust.operator_name IS '婧愬瓧娈?operator_name锛涙搷浣滃憳鍚嶇О'; COMMENT ON COLUMN billiards_ods.ods_table_fee_adjust.created_at IS '婧愬瓧娈?create_time锛涘垱寤烘椂闂?; COMMENT ON COLUMN billiards_ods.ods_table_fee_adjust.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰?; COMMENT ON COLUMN billiards_ods.ods_table_fee_adjust.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣'; COMMENT ON COLUMN billiards_ods.ods_table_fee_adjust.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿'; COMMENT ON COLUMN billiards_ods.ods_table_fee_adjust.payload IS '鍘熷JSON鍏ㄩ噺瀛樻。锛屼究浜庨噸鏀?瀹¤'; CREATE TABLE IF NOT EXISTS billiards_ods.assistant_accounts_master ( tenant_id BIGINT, site_id BIGINT NOT NULL, assistant_id BIGINT NOT NULL, assistant_name TEXT, mobile TEXT, assistant_no INT, team_id BIGINT, team_name TEXT, group_id BIGINT, group_name TEXT, job_num TEXT, entry_type TEXT, leave_status TEXT, assistant_status TEXT, allow_cx BOOLEAN, status TEXT, hired_date DATE, left_date DATE, source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, assistant_id) ); COMMENT ON TABLE billiards_ods.assistant_accounts_master IS 'Source: 鍔╂暀璐﹀彿.json -> data.assistantInfos'; COMMENT ON COLUMN billiards_ods.assistant_accounts_master.tenant_id IS 'source: assistantInfos.tenant_id; tenant/brand id'; COMMENT ON COLUMN billiards_ods.assistant_accounts_master.site_id IS 'source: assistantInfos.site_id; store id'; COMMENT ON COLUMN billiards_ods.assistant_accounts_master.assistant_id IS 'source: assistantInfos.id; assistant account id'; COMMENT ON COLUMN billiards_ods.assistant_accounts_master.assistant_name IS 'source: assistantInfos.real_name; assistant real name'; COMMENT ON COLUMN billiards_ods.assistant_accounts_master.mobile IS 'source: assistantInfos.mobile; phone number'; COMMENT ON COLUMN billiards_ods.assistant_accounts_master.assistant_no IS 'source: assistantInfos.assistant_no; assistant code'; COMMENT ON COLUMN billiards_ods.assistant_accounts_master.team_id IS 'source: assistantInfos.team_id; team id'; COMMENT ON COLUMN billiards_ods.assistant_accounts_master.team_name IS 'source: assistantInfos.team_name; team name'; COMMENT ON COLUMN billiards_ods.assistant_accounts_master.group_id IS 'source: assistantInfos.group_id; group id'; COMMENT ON COLUMN billiards_ods.assistant_accounts_master.group_name IS 'source: assistantInfos.group_name; group name'; COMMENT ON COLUMN billiards_ods.assistant_accounts_master.job_num IS 'source: assistantInfos.job_num; job number'; COMMENT ON COLUMN billiards_ods.assistant_accounts_master.entry_type IS 'source: assistantInfos.entry_type; entry type enum'; COMMENT ON COLUMN billiards_ods.assistant_accounts_master.leave_status IS 'source: assistantInfos.leave_status; on-duty/off-duty status'; COMMENT ON COLUMN billiards_ods.assistant_accounts_master.assistant_status IS 'source: assistantInfos.assistant_status; account enable flag'; COMMENT ON COLUMN billiards_ods.assistant_accounts_master.allow_cx IS 'source: assistantInfos.allow_cx; allow promotion/discount flag'; COMMENT ON COLUMN billiards_ods.assistant_accounts_master.status IS 'source: assistantInfos.show_status/work_status; general status flag'; COMMENT ON COLUMN billiards_ods.assistant_accounts_master.hired_date IS 'source: assistantInfos.entry_time; hire date'; COMMENT ON COLUMN billiards_ods.assistant_accounts_master.left_date IS 'source: assistantInfos.resign_time; resign date'; COMMENT ON COLUMN billiards_ods.assistant_accounts_master.source_file IS 'ingest metadata: source file path'; COMMENT ON COLUMN billiards_ods.assistant_accounts_master.source_endpoint IS 'ingest metadata: API or endpoint name'; COMMENT ON COLUMN billiards_ods.assistant_accounts_master.fetched_at IS 'ingest metadata: load timestamp'; COMMENT ON COLUMN billiards_ods.assistant_accounts_master.payload IS 'raw JSON payload for replay/debug'; CREATE TABLE IF NOT EXISTS billiards_ods.ods_assistant_service_log ( tenant_id BIGINT, site_id BIGINT NOT NULL, ledger_id BIGINT NOT NULL, assistant_id BIGINT, assistant_name TEXT, service_type TEXT, order_trade_no TEXT, order_settle_id BIGINT, start_time TIMESTAMPTZ, end_time TIMESTAMPTZ, duration_seconds INT, original_fee NUMERIC(18,2), member_discount_amount NUMERIC(18,2), manual_discount_amount NUMERIC(18,2), coupon_discount_amount NUMERIC(18,2), final_fee NUMERIC(18,2), member_id BIGINT, operator_id BIGINT, salesman_id BIGINT, is_canceled BOOLEAN DEFAULT FALSE, cancel_time TIMESTAMPTZ, skill_grade NUMERIC(10,2), service_grade NUMERIC(10,2), composite_grade NUMERIC(10,2), overall_score NUMERIC(10,2), status TEXT, source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, ledger_id) ); CREATE TABLE IF NOT EXISTS billiards_ods.ods_assistant_cancel_log ( tenant_id BIGINT, site_id BIGINT NOT NULL, cancel_id BIGINT NOT NULL, ledger_id BIGINT, assistant_id BIGINT, order_trade_no TEXT, table_id BIGINT, table_area_id BIGINT, table_area_name TEXT, table_name TEXT, assistant_on INT, pd_charge_minutes INT, assistant_abolish_amount NUMERIC(18,2), reason TEXT, cancel_time TIMESTAMPTZ, operator_id BIGINT, operator_name TEXT, source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, cancel_id) ); COMMENT ON TABLE billiards_ods.ods_assistant_cancel_log IS 'Source: 鍔╂暀搴熼櫎.json -> data.abolitionAssistants'; COMMENT ON COLUMN billiards_ods.ods_assistant_cancel_log.tenant_id IS 'ingest context; tenant id not explicitly exported in abolitionAssistants'; COMMENT ON COLUMN billiards_ods.ods_assistant_cancel_log.site_id IS 'source: abolitionAssistants.siteId; store id'; COMMENT ON COLUMN billiards_ods.ods_assistant_cancel_log.cancel_id IS 'source: abolitionAssistants.id; abolish record id'; COMMENT ON COLUMN billiards_ods.ods_assistant_cancel_log.ledger_id IS 'not present; reserved for related ledger id'; COMMENT ON COLUMN billiards_ods.ods_assistant_cancel_log.assistant_id IS 'not present in export; assistant name only in payload'; COMMENT ON COLUMN billiards_ods.ods_assistant_cancel_log.order_trade_no IS 'not present in export; reserved for order number'; COMMENT ON COLUMN billiards_ods.ods_assistant_cancel_log.table_id IS 'source: abolitionAssistants.tableId; table id'; COMMENT ON COLUMN billiards_ods.ods_assistant_cancel_log.table_area_id IS 'source: abolitionAssistants.tableAreaId; table area id'; COMMENT ON COLUMN billiards_ods.ods_assistant_cancel_log.table_area_name IS 'source: abolitionAssistants.tableArea; table area name'; COMMENT ON COLUMN billiards_ods.ods_assistant_cancel_log.table_name IS 'source: abolitionAssistants.tableName; table name'; COMMENT ON COLUMN billiards_ods.ods_assistant_cancel_log.assistant_on IS 'source: abolitionAssistants.assistantOn; number of assistants on duty'; COMMENT ON COLUMN billiards_ods.ods_assistant_cancel_log.pd_charge_minutes IS 'source: abolitionAssistants.pdChargeMinutes; charged minutes'; COMMENT ON COLUMN billiards_ods.ods_assistant_cancel_log.assistant_abolish_amount IS 'source: abolitionAssistants.assistantAbolishAmount; abolish amount'; COMMENT ON COLUMN billiards_ods.ods_assistant_cancel_log.reason IS 'source: abolitionAssistants.trashReason; abolish reason'; COMMENT ON COLUMN billiards_ods.ods_assistant_cancel_log.cancel_time IS 'source: abolitionAssistants.createTime; abolish time'; COMMENT ON COLUMN billiards_ods.ods_assistant_cancel_log.operator_id IS 'not present in export; reserved for operator id'; COMMENT ON COLUMN billiards_ods.ods_assistant_cancel_log.operator_name IS 'not present in export; reserved for operator name'; COMMENT ON COLUMN billiards_ods.ods_assistant_cancel_log.source_file IS 'ingest metadata: source file path'; COMMENT ON COLUMN billiards_ods.ods_assistant_cancel_log.source_endpoint IS 'ingest metadata: API or endpoint name'; COMMENT ON COLUMN billiards_ods.ods_assistant_cancel_log.fetched_at IS 'ingest metadata: load timestamp'; COMMENT ON COLUMN billiards_ods.ods_assistant_cancel_log.payload IS 'raw JSON payload for replay/debug'; CREATE TABLE IF NOT EXISTS billiards_ods.group_buy_packages ( tenant_id BIGINT, site_id BIGINT NOT NULL, package_id BIGINT NOT NULL, package_name TEXT, table_area_id BIGINT, table_area_name TEXT, platform_code TEXT, status TEXT, face_price NUMERIC(18,2), settle_price NUMERIC(18,2), selling_price NUMERIC(18,2), duration INT, valid_from DATE, valid_to DATE, start_time TIMESTAMPTZ, end_time TIMESTAMPTZ, is_enabled BOOLEAN, is_delete BOOLEAN, package_type TEXT, usable_count INT, creator_name TEXT, tenant_table_area_id BIGINT, source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, package_id) ); COMMENT ON TABLE billiards_ods.group_buy_packages IS '鏉ユ簮锛氬洟璐椁?json -> data.packageCouponList锛涘洟璐?骞冲彴鍒稿畾涔?; COMMENT ON COLUMN billiards_ods.group_buy_packages.tenant_id IS '婧愬瓧娈?tenant_id锛涚鎴?鍝佺墝ID'; COMMENT ON COLUMN billiards_ods.group_buy_packages.site_id IS '婧愬瓧娈?site_id锛涢棬搴桰D'; COMMENT ON COLUMN billiards_ods.group_buy_packages.package_id IS '婧愬瓧娈?id/package_id锛涘椁愬畾涔塈D'; COMMENT ON COLUMN billiards_ods.group_buy_packages.package_name IS '婧愬瓧娈?package_name锛涘椁愬悕绉?; COMMENT ON COLUMN billiards_ods.group_buy_packages.table_area_id IS '婧愬瓧娈?table_area_id锛涢€傜敤鍖哄煙ID'; COMMENT ON COLUMN billiards_ods.group_buy_packages.table_area_name IS '婧愬瓧娈?table_area_name锛涢€傜敤鍖哄煙鍚嶇О'; COMMENT ON COLUMN billiards_ods.group_buy_packages.platform_code IS '婧愬瓧娈?groupon_type/system_group_type锛涘钩鍙?鍒告笭閬撶爜'; COMMENT ON COLUMN billiards_ods.group_buy_packages.status IS '婧愬瓧娈?effective_status锛涚敓鏁堢姸鎬?; COMMENT ON COLUMN billiards_ods.group_buy_packages.face_price IS '婧愬瓧娈?coupon_money锛涘埜闈㈤'; COMMENT ON COLUMN billiards_ods.group_buy_packages.settle_price IS '婧愭暟鎹湭鍗曞垪锛涢鐣欑粨绠椾环'; COMMENT ON COLUMN billiards_ods.group_buy_packages.selling_price IS '婧愬瓧娈?selling_price锛涘敭鍗栦环'; COMMENT ON COLUMN billiards_ods.group_buy_packages.duration IS '婧愬瓧娈?duration锛涙椂闀匡紙绉掞級'; COMMENT ON COLUMN billiards_ods.group_buy_packages.valid_from IS '婧愬瓧娈?start_time锛涙湁鏁堟湡寮€濮?; COMMENT ON COLUMN billiards_ods.group_buy_packages.valid_to IS '婧愬瓧娈?end_time锛涙湁鏁堟湡缁撴潫'; COMMENT ON COLUMN billiards_ods.group_buy_packages.start_time IS '婧愬瓧娈?start_clock/add_start_clock锛涙瘡鏃ョ敓鏁堣捣鐐?; COMMENT ON COLUMN billiards_ods.group_buy_packages.end_time IS '婧愬瓧娈?end_clock/add_end_clock锛涙瘡鏃ュけ鏁堢粓鐐?; COMMENT ON COLUMN billiards_ods.group_buy_packages.is_enabled IS '婧愬瓧娈?is_enabled锛涙槸鍚﹀惎鐢?; COMMENT ON COLUMN billiards_ods.group_buy_packages.is_delete IS '婧愬瓧娈?is_delete锛涢€昏緫鍒犻櫎鏍囪'; COMMENT ON COLUMN billiards_ods.group_buy_packages.package_type IS '婧愬瓧娈?type/system_group_type/group_type锛涘椁愮被鍨?; COMMENT ON COLUMN billiards_ods.group_buy_packages.usable_count IS '婧愬瓧娈?usable_count锛涘彲鐢ㄦ鏁?; COMMENT ON COLUMN billiards_ods.group_buy_packages.creator_name IS '婧愬瓧娈?creator_name锛涘垱寤轰汉'; COMMENT ON COLUMN billiards_ods.group_buy_packages.tenant_table_area_id IS '婧愬瓧娈?tenant_table_area_id锛涚鎴风骇鍖哄煙ID'; COMMENT ON COLUMN billiards_ods.group_buy_packages.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰?; COMMENT ON COLUMN billiards_ods.group_buy_packages.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣'; COMMENT ON COLUMN billiards_ods.group_buy_packages.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿'; COMMENT ON COLUMN billiards_ods.group_buy_packages.payload IS '鍘熷JSON鍏ㄩ噺瀛樻。锛屼究浜庨噸鏀?瀹¤'; CREATE TABLE IF NOT EXISTS billiards_ods.group_buy_packages_log ( tenant_id BIGINT, site_id BIGINT NOT NULL, usage_id BIGINT NOT NULL, package_id BIGINT, coupon_id BIGINT, order_trade_no TEXT, order_settle_id BIGINT, member_id BIGINT, status TEXT, used_time TIMESTAMPTZ, deduct_amount NUMERIC(18,2), settle_price NUMERIC(18,2), coupon_code TEXT, source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, usage_id) ); COMMENT ON TABLE billiards_ods.group_buy_packages_log IS '鏉ユ簮锛氬洟璐椁愭祦姘?json -> data.siteTableUseDetailsList锛涘洟璐埜鏍搁攢娴佹按'; COMMENT ON COLUMN billiards_ods.group_buy_packages_log.tenant_id IS '婧愬瓧娈?tenant_id锛涚鎴?鍝佺墝ID'; COMMENT ON COLUMN billiards_ods.group_buy_packages_log.site_id IS '婧愬瓧娈?site_id锛涢棬搴桰D'; COMMENT ON COLUMN billiards_ods.group_buy_packages_log.usage_id IS '婧愬瓧娈?id锛涙牳閿€娴佹按ID'; COMMENT ON COLUMN billiards_ods.group_buy_packages_log.package_id IS '婧愬瓧娈?promotion_coupon_id锛涘椁?鍒窱D'; COMMENT ON COLUMN billiards_ods.group_buy_packages_log.coupon_id IS '婧愬瓧娈?order_coupon_id/coupon_origin_id锛涘埜瀹炰緥ID'; COMMENT ON COLUMN billiards_ods.group_buy_packages_log.order_trade_no IS '婧愬瓧娈?order_trade_no锛涗笟鍔¤鍗曞彿'; COMMENT ON COLUMN billiards_ods.group_buy_packages_log.order_settle_id IS '婧愬瓧娈?order_settle_id锛涚粨绠楀崟ID'; COMMENT ON COLUMN billiards_ods.group_buy_packages_log.member_id IS '婧愭暟鎹湭缁欙紱棰勭暀浼氬憳ID'; COMMENT ON COLUMN billiards_ods.group_buy_packages_log.status IS '婧愬瓧娈?ledger_status锛涙祦姘寸姸鎬?; COMMENT ON COLUMN billiards_ods.group_buy_packages_log.used_time IS '婧愬瓧娈?create_time锛涙牳閿€鏃堕棿'; COMMENT ON COLUMN billiards_ods.group_buy_packages_log.deduct_amount IS '婧愬瓧娈?coupon_money锛涘埜鎶垫墸閲戦'; COMMENT ON COLUMN billiards_ods.group_buy_packages_log.settle_price IS '婧愬瓧娈?ledger_amount锛涙湰鏉℃槑缁嗙粨绠楅噾棰?; COMMENT ON COLUMN billiards_ods.group_buy_packages_log.coupon_code IS '婧愬瓧娈?coupon_code锛涘埜鐮?; COMMENT ON COLUMN billiards_ods.group_buy_packages_log.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰?; COMMENT ON COLUMN billiards_ods.group_buy_packages_log.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣'; COMMENT ON COLUMN billiards_ods.group_buy_packages_log.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿'; COMMENT ON COLUMN billiards_ods.group_buy_packages_log.payload IS '鍘熷JSON鍏ㄩ噺瀛樻。锛屼究浜庨噸鏀?瀹¤'; CREATE TABLE IF NOT EXISTS billiards_ods.ods_platform_coupon_log ( tenant_id BIGINT, site_id BIGINT NOT NULL, coupon_id BIGINT NOT NULL, platform_code TEXT, verify_code TEXT, coupon_code TEXT, coupon_channel TEXT, order_trade_no TEXT, order_settle_id BIGINT, member_id BIGINT, status TEXT, used_time TIMESTAMPTZ, deduct_amount NUMERIC(18,2), settle_price NUMERIC(18,2), coupon_money NUMERIC(18,2), source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, coupon_id) ); COMMENT ON TABLE billiards_ods.ods_platform_coupon_log IS '鏉ユ簮锛氬钩鍙伴獙鍒歌褰?json锛涘钩鍙板埜鏍搁攢璁板綍'; COMMENT ON COLUMN billiards_ods.ods_platform_coupon_log.tenant_id IS '婧愬瓧娈?tenant_id锛涚鎴?鍝佺墝ID'; COMMENT ON COLUMN billiards_ods.ods_platform_coupon_log.site_id IS '婧愬瓧娈?site_id锛涢棬搴桰D'; COMMENT ON COLUMN billiards_ods.ods_platform_coupon_log.coupon_id IS '婧愬瓧娈?id锛涙牳閿€璁板綍ID'; COMMENT ON COLUMN billiards_ods.ods_platform_coupon_log.platform_code IS '婧愬瓧娈?groupon_type锛涘埜骞冲彴/娓犻亾缂栫爜'; COMMENT ON COLUMN billiards_ods.ods_platform_coupon_log.verify_code IS '婧愬瓧娈?verify_id锛涙牳閿€娴佹按鍙?; COMMENT ON COLUMN billiards_ods.ods_platform_coupon_log.coupon_code IS '婧愬瓧娈?coupon_code锛涘埜鐮?; COMMENT ON COLUMN billiards_ods.ods_platform_coupon_log.coupon_channel IS '婧愬瓧娈?coupon_channel锛涢攢鍞笭閬?; COMMENT ON COLUMN billiards_ods.ods_platform_coupon_log.order_trade_no IS '婧愬瓧娈?site_order_id锛涘叧鑱旇鍗曞彿'; COMMENT ON COLUMN billiards_ods.ods_platform_coupon_log.order_settle_id IS '婧愭暟鎹湭缁欙紱棰勭暀缁撶畻ID'; COMMENT ON COLUMN billiards_ods.ods_platform_coupon_log.member_id IS '婧愭暟鎹湭缁欙紱棰勭暀浼氬憳ID'; COMMENT ON COLUMN billiards_ods.ods_platform_coupon_log.status IS '婧愬瓧娈?use_status锛涙牳閿€鐘舵€?; COMMENT ON COLUMN billiards_ods.ods_platform_coupon_log.used_time IS '婧愬瓧娈?consume_time锛涙牳閿€鏃堕棿'; COMMENT ON COLUMN billiards_ods.ods_platform_coupon_log.deduct_amount IS '婧愬瓧娈?coupon_money锛涙姷鎵i噾棰?; COMMENT ON COLUMN billiards_ods.ods_platform_coupon_log.settle_price IS '婧愬瓧娈?sale_price锛涚粨绠?閿€鍞环'; COMMENT ON COLUMN billiards_ods.ods_platform_coupon_log.coupon_money IS '婧愬瓧娈?coupon_money锛涘埜闈㈤'; COMMENT ON COLUMN billiards_ods.ods_platform_coupon_log.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰?; COMMENT ON COLUMN billiards_ods.ods_platform_coupon_log.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣'; COMMENT ON COLUMN billiards_ods.ods_platform_coupon_log.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿'; COMMENT ON COLUMN billiards_ods.ods_platform_coupon_log.payload IS '鍘熷JSON鍏ㄩ噺瀛樻。锛屼究浜庨噸鏀?瀹¤'; CREATE TABLE IF NOT EXISTS billiards_ods.goods_stock_movements ( tenant_id BIGINT, site_id BIGINT NOT NULL, change_id BIGINT NOT NULL, site_goods_id BIGINT, goods_id BIGINT, stock_type TEXT, change_amount NUMERIC(18,2), before_stock NUMERIC(18,2), after_stock NUMERIC(18,2), change_amount_alt NUMERIC(18,2), before_stock_alt NUMERIC(18,2), after_stock_alt NUMERIC(18,2), change_type TEXT, relate_id BIGINT, unit TEXT, price NUMERIC(18,2), goods_category_id BIGINT, goods_second_category_id BIGINT, remark TEXT, operator_id BIGINT, operator_name TEXT, change_time TIMESTAMPTZ, source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, change_id) ); CREATE TABLE IF NOT EXISTS billiards_ods.ods_inventory_stock ( tenant_id BIGINT, site_id BIGINT NOT NULL, site_goods_id BIGINT NOT NULL, goods_id BIGINT, goods_name TEXT, goods_unit TEXT, goods_category_id BIGINT, goods_second_category_id BIGINT, range_start_stock NUMERIC(18,2), range_end_stock NUMERIC(18,2), range_in NUMERIC(18,2), range_out NUMERIC(18,2), range_inventory NUMERIC(18,2), range_sale NUMERIC(18,2), range_sale_money NUMERIC(18,2), current_stock NUMERIC(18,2), cost_price NUMERIC(18,2), category_name TEXT, snapshot_key TEXT NOT NULL DEFAULT 'default', source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, site_goods_id, snapshot_key) ); COMMENT ON TABLE billiards_ods.ods_inventory_stock IS 'Source: 搴撳瓨姹囨€?json'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.tenant_id IS 'ingest context; tenant id not explicitly exported'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.site_id IS 'ingest context; site id not explicitly exported'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.site_goods_id IS 'source: 搴撳瓨姹囨€?siteGoodsId; site goods id'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.goods_id IS 'not present in export; reserved for tenant goods id'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.goods_name IS 'source: 搴撳瓨姹囨€?goodsName; goods name'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.goods_unit IS 'source: 搴撳瓨姹囨€?goodsUnit; unit'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.goods_category_id IS 'source: 搴撳瓨姹囨€?goodsCategoryId; category id'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.goods_second_category_id IS 'source: 搴撳瓨姹囨€?goodsCategorySecondId; second category id'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.range_start_stock IS 'source: 搴撳瓨姹囨€?rangeStartStock; period opening stock'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.range_end_stock IS 'source: 搴撳瓨姹囨€?rangeEndStock; period closing stock'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.range_in IS 'source: 搴撳瓨姹囨€?rangeIn; inbound qty during period'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.range_out IS 'source: 搴撳瓨姹囨€?rangeOut; outbound qty during period'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.range_inventory IS 'source: 搴撳瓨姹囨€?rangeInventory; inventory adjustments during period'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.range_sale IS 'source: 搴撳瓨姹囨€?rangeSale; sales qty during period'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.range_sale_money IS 'source: 搴撳瓨姹囨€?rangeSaleMoney; sales amount during period'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.current_stock IS 'source: 搴撳瓨姹囨€?currentStock; current stock'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.cost_price IS 'not present in export; reserved for cost price'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.category_name IS 'source: 搴撳瓨姹囨€?categoryName; category name'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.snapshot_key IS 'snapshot label (default ''default'') for periodic loads'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.source_file IS 'ingest metadata: source file path'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.source_endpoint IS 'ingest metadata: API or endpoint name'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.fetched_at IS 'ingest metadata: load timestamp'; COMMENT ON COLUMN billiards_ods.ods_inventory_stock.payload IS 'raw JSON payload for replay/debug'; CREATE TABLE IF NOT EXISTS billiards_ods.settlement_records ( tenant_id BIGINT, site_id BIGINT NOT NULL, order_settle_id BIGINT NOT NULL, settle_relate_id BIGINT, settle_name TEXT, settle_type INT, settle_status INT, member_id BIGINT, member_name TEXT, member_phone TEXT, table_id BIGINT, consume_money NUMERIC(18,2), table_charge_money NUMERIC(18,2), goods_money NUMERIC(18,2), service_money NUMERIC(18,2), assistant_pd_money NUMERIC(18,2), assistant_cx_money NUMERIC(18,2), pay_amount NUMERIC(18,2), cash_amount NUMERIC(18,2), online_amount NUMERIC(18,2), point_amount NUMERIC(18,2), coupon_amount NUMERIC(18,2), card_amount NUMERIC(18,2), balance_amount NUMERIC(18,2), refund_amount NUMERIC(18,2), prepay_money NUMERIC(18,2), adjust_amount NUMERIC(18,2), rounding_amount NUMERIC(18,2), member_discount_amount NUMERIC(18,2), coupon_sale_amount NUMERIC(18,2), goods_promotion_money NUMERIC(18,2), assistant_promotion_money NUMERIC(18,2), point_discount_price NUMERIC(18,2), point_discount_cost NUMERIC(18,2), real_goods_money NUMERIC(18,2), assistant_manual_discount NUMERIC(18,2), all_coupon_discount NUMERIC(18,2), is_use_coupon BOOLEAN, is_use_discount BOOLEAN, is_activity BOOLEAN, is_bind_member BOOLEAN, is_first BOOLEAN, recharge_card_amount NUMERIC(18,2), gift_card_amount NUMERIC(18,2), payment_method INT, create_time TIMESTAMPTZ, pay_time TIMESTAMPTZ, revoke_order_id BIGINT, revoke_order_name TEXT, revoke_time TIMESTAMPTZ, can_be_revoked BOOLEAN, serial_number TEXT, sales_man_name TEXT, sales_man_user_id BIGINT, order_remark TEXT, operator_id BIGINT, operator_name TEXT, source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, order_settle_id) ); COMMENT ON TABLE billiards_ods.settlement_records IS 'Source: 缁撹处璁板綍.json -> data.settleList[].settleList'; COMMENT ON COLUMN billiards_ods.settlement_records.tenant_id IS 'source: settleList.tenantId; tenant/brand id'; COMMENT ON COLUMN billiards_ods.settlement_records.site_id IS 'source: settleList.siteId; store id'; COMMENT ON COLUMN billiards_ods.settlement_records.order_settle_id IS 'source: settleList.id; settlement record id'; COMMENT ON COLUMN billiards_ods.settlement_records.settle_relate_id IS 'source: settleList.settleRelateId; related business/order id'; COMMENT ON COLUMN billiards_ods.settlement_records.settle_name IS 'source: settleList.settleName; settlement name'; COMMENT ON COLUMN billiards_ods.settlement_records.settle_type IS 'source: settleList.settleType; settlement type enum'; COMMENT ON COLUMN billiards_ods.settlement_records.settle_status IS 'source: settleList.settleStatus; settlement status'; COMMENT ON COLUMN billiards_ods.settlement_records.member_id IS 'source: settleList.memberId; member id'; COMMENT ON COLUMN billiards_ods.settlement_records.member_name IS 'source: settleList.memberName; member name'; COMMENT ON COLUMN billiards_ods.settlement_records.member_phone IS 'source: settleList.memberPhone; member phone'; COMMENT ON COLUMN billiards_ods.settlement_records.table_id IS 'source: settleList.tableId; table id'; COMMENT ON COLUMN billiards_ods.settlement_records.consume_money IS 'source: settleList.consumeMoney; total consumption amount'; COMMENT ON COLUMN billiards_ods.settlement_records.table_charge_money IS 'source: settleList.tableChargeMoney; table fee amount'; COMMENT ON COLUMN billiards_ods.settlement_records.goods_money IS 'source: settleList.goodsMoney; goods amount'; COMMENT ON COLUMN billiards_ods.settlement_records.service_money IS 'source: settleList.serviceMoney; service amount'; COMMENT ON COLUMN billiards_ods.settlement_records.assistant_pd_money IS 'source: settleList.assistantPdMoney; assistant accompany amount'; COMMENT ON COLUMN billiards_ods.settlement_records.assistant_cx_money IS 'source: settleList.assistantCxMoney; assistant promotion amount'; COMMENT ON COLUMN billiards_ods.settlement_records.pay_amount IS 'source: settleList.payAmount; payment amount (settled)'; COMMENT ON COLUMN billiards_ods.settlement_records.cash_amount IS 'source: settleList.cashAmount; cash payment amount'; COMMENT ON COLUMN billiards_ods.settlement_records.online_amount IS 'source: settleList.onlineAmount; online payment amount'; COMMENT ON COLUMN billiards_ods.settlement_records.point_amount IS 'source: settleList.pointAmount; amount credited to card/points'; COMMENT ON COLUMN billiards_ods.settlement_records.coupon_amount IS 'source: settleList.couponAmount; coupon deduction'; COMMENT ON COLUMN billiards_ods.settlement_records.card_amount IS 'source: settleList.cardAmount; member card amount'; COMMENT ON COLUMN billiards_ods.settlement_records.balance_amount IS 'source: settleList.balanceAmount; balance payment amount'; COMMENT ON COLUMN billiards_ods.settlement_records.refund_amount IS 'source: settleList.refundAmount; refund amount on this settlement'; COMMENT ON COLUMN billiards_ods.settlement_records.prepay_money IS 'source: settleList.prepayMoney; prepayment amount'; COMMENT ON COLUMN billiards_ods.settlement_records.adjust_amount IS 'source: settleList.adjustAmount; adjustment amount'; COMMENT ON COLUMN billiards_ods.settlement_records.rounding_amount IS 'source: settleList.roundingAmount; rounding write-off amount'; COMMENT ON COLUMN billiards_ods.settlement_records.member_discount_amount IS 'source: settleList.memberDiscountAmount; member discount amount'; COMMENT ON COLUMN billiards_ods.settlement_records.coupon_sale_amount IS 'source: settleList.couponSaleAmount; coupon sale amount'; COMMENT ON COLUMN billiards_ods.settlement_records.goods_promotion_money IS 'source: settleList.goodsPromotionMoney; goods promotion deduction'; COMMENT ON COLUMN billiards_ods.settlement_records.assistant_promotion_money IS 'source: settleList.assistantPromotionMoney; assistant promotion deduction'; COMMENT ON COLUMN billiards_ods.settlement_records.point_discount_price IS 'source: settleList.pointDiscountPrice; points discount amount'; COMMENT ON COLUMN billiards_ods.settlement_records.point_discount_cost IS 'source: settleList.pointDiscountCost; cost of points discount'; COMMENT ON COLUMN billiards_ods.settlement_records.real_goods_money IS 'source: settleList.realGoodsMoney; real goods amount after discount'; COMMENT ON COLUMN billiards_ods.settlement_records.assistant_manual_discount IS 'source: settleList.assistantManualDiscount; manual assistant discount'; COMMENT ON COLUMN billiards_ods.settlement_records.all_coupon_discount IS 'source: settleList.allCouponDiscount; total coupon discount'; COMMENT ON COLUMN billiards_ods.settlement_records.is_use_coupon IS 'source: settleList.isUseCoupon; whether coupon used'; COMMENT ON COLUMN billiards_ods.settlement_records.is_use_discount IS 'source: settleList.isUseDiscount; whether discount used'; COMMENT ON COLUMN billiards_ods.settlement_records.is_activity IS 'source: settleList.isActivity; whether activity applied'; COMMENT ON COLUMN billiards_ods.settlement_records.is_bind_member IS 'source: settleList.isBindMember; whether member bound'; COMMENT ON COLUMN billiards_ods.settlement_records.is_first IS 'source: settleList.isFirst; whether first order flag'; COMMENT ON COLUMN billiards_ods.settlement_records.recharge_card_amount IS 'source: settleList.rechargeCardAmount; recharge card amount'; COMMENT ON COLUMN billiards_ods.settlement_records.gift_card_amount IS 'source: settleList.giftCardAmount; gift card amount'; COMMENT ON COLUMN billiards_ods.settlement_records.payment_method IS 'source: settleList.paymentMethod; payment method code'; COMMENT ON COLUMN billiards_ods.settlement_records.create_time IS 'source: settleList.createTime; creation time'; COMMENT ON COLUMN billiards_ods.settlement_records.pay_time IS 'source: settleList.payTime; pay time'; COMMENT ON COLUMN billiards_ods.settlement_records.revoke_order_id IS 'source: settleList.revokeOrderId; revoke order id'; COMMENT ON COLUMN billiards_ods.settlement_records.revoke_order_name IS 'source: settleList.revokeOrderName; revoke order name'; COMMENT ON COLUMN billiards_ods.settlement_records.revoke_time IS 'source: settleList.revokeTime; revoke time'; COMMENT ON COLUMN billiards_ods.settlement_records.can_be_revoked IS 'source: settleList.canBeRevoked; flag whether revocable'; COMMENT ON COLUMN billiards_ods.settlement_records.serial_number IS 'source: settleList.serialNumber; receipt serial number'; COMMENT ON COLUMN billiards_ods.settlement_records.sales_man_name IS 'source: settleList.salesManName; sales person name'; COMMENT ON COLUMN billiards_ods.settlement_records.sales_man_user_id IS 'source: settleList.salesManUserId; sales person user id'; COMMENT ON COLUMN billiards_ods.settlement_records.order_remark IS 'source: settleList.orderRemark; order remark'; COMMENT ON COLUMN billiards_ods.settlement_records.operator_id IS 'source: settleList.operatorId; operator id'; COMMENT ON COLUMN billiards_ods.settlement_records.operator_name IS 'source: settleList.operatorName; operator name'; COMMENT ON COLUMN billiards_ods.settlement_records.source_file IS 'ingest metadata: source file path'; COMMENT ON COLUMN billiards_ods.settlement_records.source_endpoint IS 'ingest metadata: API or endpoint name'; COMMENT ON COLUMN billiards_ods.settlement_records.fetched_at IS 'ingest metadata: load timestamp'; COMMENT ON COLUMN billiards_ods.settlement_records.payload IS 'raw JSON payload for replay/debug'; CREATE TABLE IF NOT EXISTS billiards_ods.ods_goods_category ( tenant_id BIGINT, site_id BIGINT NOT NULL, category_id BIGINT NOT NULL, category_name TEXT, parent_id BIGINT, level_no INT, status TEXT, remark TEXT, source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, category_id) ); COMMENT ON TABLE billiards_ods.ods_goods_category IS 'Source: 搴撳瓨鍙樺寲璁板綍2.json -> data.goodsCategoryList'; COMMENT ON COLUMN billiards_ods.ods_goods_category.tenant_id IS 'source: goodsCategoryList.tenant_id; tenant/brand id'; COMMENT ON COLUMN billiards_ods.ods_goods_category.site_id IS 'ingest context; site id not explicitly exported'; COMMENT ON COLUMN billiards_ods.ods_goods_category.category_id IS 'source: goodsCategoryList.id; category id'; COMMENT ON COLUMN billiards_ods.ods_goods_category.category_name IS 'source: goodsCategoryList.category_name; category name'; COMMENT ON COLUMN billiards_ods.ods_goods_category.parent_id IS 'source: goodsCategoryList.pid; parent category id'; COMMENT ON COLUMN billiards_ods.ods_goods_category.level_no IS 'not present; reserved for category level'; COMMENT ON COLUMN billiards_ods.ods_goods_category.status IS 'source: goodsCategoryList.is_warehousing/open_salesman; category status flags'; COMMENT ON COLUMN billiards_ods.ods_goods_category.remark IS 'source: goodsCategoryList.alias_name/business_name; remark/alias'; COMMENT ON COLUMN billiards_ods.ods_goods_category.source_file IS 'ingest metadata: source file path'; COMMENT ON COLUMN billiards_ods.ods_goods_category.source_endpoint IS 'ingest metadata: API or endpoint name'; COMMENT ON COLUMN billiards_ods.ods_goods_category.fetched_at IS 'ingest metadata: load timestamp'; COMMENT ON COLUMN billiards_ods.ods_goods_category.payload IS 'raw JSON payload for replay/debug'; CREATE TABLE IF NOT EXISTS billiards_ods.payment_transactions ( tenant_id BIGINT, site_id BIGINT NOT NULL, pay_id BIGINT NOT NULL, order_trade_no TEXT, order_settle_id BIGINT, member_id BIGINT, pay_method_code TEXT, pay_method_name TEXT, pay_status INT, pay_amount NUMERIC(18,2), pay_time TIMESTAMPTZ, online_pay_channel TEXT, transaction_id TEXT, operator_id BIGINT, remark TEXT, relate_type TEXT, relate_id BIGINT, source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, pay_id) ); COMMENT ON TABLE billiards_ods.payment_transactions IS 'Source: 鏀粯璁板綍.json'; COMMENT ON COLUMN billiards_ods.payment_transactions.tenant_id IS 'ingest context; tenant id not explicitly exported'; COMMENT ON COLUMN billiards_ods.payment_transactions.site_id IS 'source: 鏀粯璁板綍.site_id; store id'; COMMENT ON COLUMN billiards_ods.payment_transactions.pay_id IS 'source: 鏀粯璁板綍.id; payment record id'; COMMENT ON COLUMN billiards_ods.payment_transactions.order_trade_no IS 'not present in export; reserved for business order number'; COMMENT ON COLUMN billiards_ods.payment_transactions.order_settle_id IS 'not present; reserved for settlement id'; COMMENT ON COLUMN billiards_ods.payment_transactions.member_id IS 'not present; reserved for member id'; COMMENT ON COLUMN billiards_ods.payment_transactions.pay_method_code IS 'source: 鏀粯璁板綍.payment_method; payment method enum'; COMMENT ON COLUMN billiards_ods.payment_transactions.pay_method_name IS 'not present; reserved for payment method name'; COMMENT ON COLUMN billiards_ods.payment_transactions.pay_status IS 'source: 鏀粯璁板綍.pay_status; payment status'; COMMENT ON COLUMN billiards_ods.payment_transactions.pay_amount IS 'source: 鏀粯璁板綍.pay_amount; paid amount'; COMMENT ON COLUMN billiards_ods.payment_transactions.pay_time IS 'source: 鏀粯璁板綍.pay_time; payment time'; COMMENT ON COLUMN billiards_ods.payment_transactions.online_pay_channel IS 'source: 鏀粯璁板綍.online_pay_channel; online channel code'; COMMENT ON COLUMN billiards_ods.payment_transactions.transaction_id IS 'not present in export; reserved for channel transaction id'; COMMENT ON COLUMN billiards_ods.payment_transactions.operator_id IS 'not present; reserved for operator id'; COMMENT ON COLUMN billiards_ods.payment_transactions.remark IS 'not present; reserved for remark'; COMMENT ON COLUMN billiards_ods.payment_transactions.relate_type IS 'source: 鏀粯璁板綍.relate_type; related business type'; COMMENT ON COLUMN billiards_ods.payment_transactions.relate_id IS 'source: 鏀粯璁板綍.relate_id; related business id'; COMMENT ON COLUMN billiards_ods.payment_transactions.source_file IS 'ingest metadata: source file path'; COMMENT ON COLUMN billiards_ods.payment_transactions.source_endpoint IS 'ingest metadata: API or endpoint name'; COMMENT ON COLUMN billiards_ods.payment_transactions.fetched_at IS 'ingest metadata: load timestamp'; COMMENT ON COLUMN billiards_ods.payment_transactions.payload IS 'raw JSON payload for replay/debug'; CREATE TABLE IF NOT EXISTS billiards_ods.refund_transactions ( tenant_id BIGINT, site_id BIGINT NOT NULL, refund_id BIGINT NOT NULL, order_trade_no TEXT, order_settle_id BIGINT, member_id BIGINT, pay_sn TEXT, pay_amount NUMERIC(18,2), pay_status INT, is_revoke BOOLEAN, is_delete BOOLEAN, online_pay_channel TEXT, pay_method_code TEXT, refund_amount NUMERIC(18,2), refund_time TIMESTAMPTZ, action_type INT, pay_terminal INT, pay_config_id BIGINT, cashier_point_id BIGINT, operator_id BIGINT, member_card_id BIGINT, balance_frozen_amount NUMERIC(18,2), card_frozen_amount NUMERIC(18,2), round_amount NUMERIC(18,2), online_pay_type INT, channel_payer_id TEXT, channel_pay_no TEXT, check_status INT, channel_fee NUMERIC(18,2), relate_type TEXT, relate_id BIGINT, status TEXT, reason TEXT, related_payment_id BIGINT, source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, refund_id) ); COMMENT ON TABLE billiards_ods.refund_transactions IS 'Source: 閫€娆捐褰?json'; COMMENT ON COLUMN billiards_ods.refund_transactions.tenant_id IS 'source: 閫€娆捐褰?tenant_id; tenant/brand id'; COMMENT ON COLUMN billiards_ods.refund_transactions.site_id IS 'source: 閫€娆捐褰?site_id; store id'; COMMENT ON COLUMN billiards_ods.refund_transactions.refund_id IS 'source: 閫€娆捐褰?id; refund record id'; COMMENT ON COLUMN billiards_ods.refund_transactions.order_trade_no IS 'not present in export; reserved for order number'; COMMENT ON COLUMN billiards_ods.refund_transactions.order_settle_id IS 'not present; reserved for settlement id'; COMMENT ON COLUMN billiards_ods.refund_transactions.member_id IS 'source: 閫€娆捐褰?member_id; member id'; COMMENT ON COLUMN billiards_ods.refund_transactions.pay_sn IS 'source: 閫€娆捐褰?pay_sn; payment serial number'; COMMENT ON COLUMN billiards_ods.refund_transactions.pay_amount IS 'source: 閫€娆捐褰?pay_amount; paid amount'; COMMENT ON COLUMN billiards_ods.refund_transactions.pay_status IS 'source: 閫€娆捐褰?pay_status; status code'; COMMENT ON COLUMN billiards_ods.refund_transactions.is_revoke IS 'source: 閫€娆捐褰?is_revoke; revoke flag'; COMMENT ON COLUMN billiards_ods.refund_transactions.is_delete IS 'source: 閫€娆捐褰?is_delete; logical delete flag'; COMMENT ON COLUMN billiards_ods.refund_transactions.online_pay_channel IS 'source: 閫€娆捐褰?online_pay_channel; online pay channel'; COMMENT ON COLUMN billiards_ods.refund_transactions.pay_method_code IS 'source: 閫€娆捐褰?payment_method; payment method enum'; COMMENT ON COLUMN billiards_ods.refund_transactions.refund_amount IS 'source: 閫€娆捐褰?refund_amount; refund amount'; COMMENT ON COLUMN billiards_ods.refund_transactions.refund_time IS 'source: 閫€娆捐褰?pay_time; refund time'; COMMENT ON COLUMN billiards_ods.refund_transactions.action_type IS 'source: 閫€娆捐褰?action_type; action type'; COMMENT ON COLUMN billiards_ods.refund_transactions.pay_terminal IS 'source: 閫€娆捐褰?pay_terminal; pay terminal'; COMMENT ON COLUMN billiards_ods.refund_transactions.pay_config_id IS 'source: 閫€娆捐褰?pay_config_id; pay config id'; COMMENT ON COLUMN billiards_ods.refund_transactions.cashier_point_id IS 'source: 閫€娆捐褰?cashier_point_id; cashier point id'; COMMENT ON COLUMN billiards_ods.refund_transactions.operator_id IS 'source: 閫€娆捐褰?operator_id; operator id'; COMMENT ON COLUMN billiards_ods.refund_transactions.member_card_id IS 'source: 閫€娆捐褰?member_card_id; member card id'; COMMENT ON COLUMN billiards_ods.refund_transactions.balance_frozen_amount IS 'source: 閫€娆捐褰?balance_frozen_amount; frozen balance amount'; COMMENT ON COLUMN billiards_ods.refund_transactions.card_frozen_amount IS 'source: 閫€娆捐褰?card_frozen_amount; frozen card amount'; COMMENT ON COLUMN billiards_ods.refund_transactions.round_amount IS 'source: 閫€娆捐褰?round_amount; rounding/write-off amount'; COMMENT ON COLUMN billiards_ods.refund_transactions.online_pay_type IS 'source: 閫€娆捐褰?online_pay_type; online refund type'; COMMENT ON COLUMN billiards_ods.refund_transactions.channel_payer_id IS 'source: 閫€娆捐褰?channel_payer_id; channel payer id'; COMMENT ON COLUMN billiards_ods.refund_transactions.channel_pay_no IS 'source: 閫€娆捐褰?channel_pay_no; channel transaction id'; COMMENT ON COLUMN billiards_ods.refund_transactions.check_status IS 'source: 閫€娆捐褰?check_status; audit status'; COMMENT ON COLUMN billiards_ods.refund_transactions.channel_fee IS 'source: 閫€娆捐褰?channel_fee; channel fee'; COMMENT ON COLUMN billiards_ods.refund_transactions.relate_type IS 'source: 閫€娆捐褰?relate_type; related business type'; COMMENT ON COLUMN billiards_ods.refund_transactions.relate_id IS 'source: 閫€娆捐褰?relate_id; related business id'; COMMENT ON COLUMN billiards_ods.refund_transactions.status IS 'alias for pay_status/is_delete to track row status'; COMMENT ON COLUMN billiards_ods.refund_transactions.reason IS 'not present in export; reserved for refund reason'; COMMENT ON COLUMN billiards_ods.refund_transactions.related_payment_id IS 'not present; reserved for linking to original payment'; COMMENT ON COLUMN billiards_ods.refund_transactions.source_file IS 'ingest metadata: source file path'; COMMENT ON COLUMN billiards_ods.refund_transactions.source_endpoint IS 'ingest metadata: API or endpoint name'; COMMENT ON COLUMN billiards_ods.refund_transactions.fetched_at IS 'ingest metadata: load timestamp'; COMMENT ON COLUMN billiards_ods.refund_transactions.payload IS 'raw JSON payload for replay/debug'; CREATE TABLE IF NOT EXISTS billiards_ods.ods_order_receipt_detail ( tenant_id BIGINT, site_id BIGINT NOT NULL, order_settle_id BIGINT NOT NULL, order_trade_no TEXT, order_settle_number TEXT, settle_type INT, receipt_no TEXT, receipt_time TIMESTAMPTZ, total_amount NUMERIC(18,2), discount_amount NUMERIC(18,2), final_amount NUMERIC(18,2), actual_payment NUMERIC(18,2), ledger_amount NUMERIC(18,2), member_offer_amount NUMERIC(18,2), delivery_fee NUMERIC(18,2), adjust_amount NUMERIC(18,2), payment_method INT, pay_time TIMESTAMPTZ, member_id BIGINT, order_remark TEXT, cashier_name TEXT, ticket_remark TEXT, ticket_custom_content TEXT, voucher_money NUMERIC(18,2), reward_name TEXT, consume_money NUMERIC(18,2), refund_amount NUMERIC(18,2), balance_amount NUMERIC(18,2), coupon_amount NUMERIC(18,2), member_deduct_amount NUMERIC(18,2), prepay_money NUMERIC(18,2), delivery_address TEXT, snapshot_raw JSONB, member_snapshot JSONB, source_file TEXT, source_endpoint TEXT, fetched_at TIMESTAMPTZ DEFAULT now(), payload JSONB NOT NULL, PRIMARY KEY (site_id, order_settle_id) ); COMMENT ON TABLE billiards_ods.ods_order_receipt_detail IS 'Source: 灏忕エ璇︽儏.json -> data.data (order detail)'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.order_settle_id IS 'source: orderSettleId; settlement id'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.order_trade_no IS 'not present in export; reserved for order number'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.order_settle_number IS 'source: orderSettleNumber; ticket/settlement number'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.settle_type IS 'source: settleType; settlement type enum'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.receipt_no IS 'not present in export; reserved for printed receipt number'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.receipt_time IS 'source: payTime; receipt/pay time'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.total_amount IS 'source: ledgerAmount; total amount before discounts'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.discount_amount IS 'derived from couponAmount/memberOfferAmount/pointDiscountPrice in payload; total discounts'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.final_amount IS 'source: consumeMoney; amount after discounts before payment'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.actual_payment IS 'source: actualPayment; amount actually paid'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.ledger_amount IS 'source: ledgerAmount; aggregated ledger amount'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.member_offer_amount IS 'source: memberOfferAmount; member discount amount'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.delivery_fee IS 'source: deliveryFee; delivery fee'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.adjust_amount IS 'source: adjustAmount; manual adjustment'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.payment_method IS 'source: paymentMethod; payment method code'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.pay_time IS 'source: payTime; payment time'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.member_id IS 'not present; memberProfile lacks id (only name/phone/point)'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.order_remark IS 'source: orderRemark; order remark'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.cashier_name IS 'source: cashierName; cashier name'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.ticket_remark IS 'source: ticketRemark; ticket remark'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.ticket_custom_content IS 'source: ticketCustomContent; custom print content'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.voucher_money IS 'source: voucherMoney; voucher amount'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.reward_name IS 'source: rewardName; reward description'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.consume_money IS 'source: consumeMoney; consumption amount'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.refund_amount IS 'source: refundAmount; refund amount'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.balance_amount IS 'source: balanceAmount or payMemberBalance; balance payment amount'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.coupon_amount IS 'source: couponAmount; coupon deduction amount'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.member_deduct_amount IS 'source: memberDeductAmount; member deduction amount'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.prepay_money IS 'source: prepayMoney; prepaid amount'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.delivery_address IS 'source: deliveryAddress; delivery address'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.snapshot_raw IS 'source: orderItem (table/goods/coupon ledgers); full nested detail JSON'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.member_snapshot IS 'source: memberProfile; member snapshot JSON'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.source_file IS 'ingest metadata: source file path'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.source_endpoint IS 'ingest metadata: API or endpoint name'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.fetched_at IS 'ingest metadata: load timestamp'; COMMENT ON COLUMN billiards_ods.ods_order_receipt_detail.payload IS 'raw JSON payload for replay/debug'; -- ---------- DWD Dimensions ---------- CREATE TABLE IF NOT EXISTS billiards_dwd.dim_tenant ( tenant_id BIGINT PRIMARY KEY, tenant_name TEXT, short_name TEXT, status TEXT, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); CREATE TABLE IF NOT EXISTS billiards_dwd.dim_site ( site_id BIGINT PRIMARY KEY, tenant_id BIGINT, site_code TEXT, site_name TEXT, city TEXT, region TEXT, status TEXT, open_date DATE, close_date DATE, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); CREATE TABLE IF NOT EXISTS billiards_dwd.dim_member_card_type ( card_type_id BIGINT PRIMARY KEY, card_type_name TEXT, discount_rate NUMERIC(8,4), description TEXT, remark TEXT ); CREATE TABLE IF NOT EXISTS billiards_dwd.dim_product_category ( category_id BIGINT PRIMARY KEY, category_name TEXT, parent_id BIGINT, level_no INT, status TEXT, remark TEXT ); CREATE TABLE IF NOT EXISTS billiards_dwd.dim_product ( goods_id BIGINT PRIMARY KEY, goods_name TEXT, goods_code TEXT, category_id BIGINT REFERENCES billiards_dwd.dim_product_category (category_id), category_name TEXT, unit TEXT, default_price NUMERIC(18,2), status TEXT, updated_at TIMESTAMPTZ DEFAULT now() ); CREATE TABLE IF NOT EXISTS billiards_dwd.dim_table ( table_id BIGINT PRIMARY KEY, site_id BIGINT, table_code TEXT, table_name TEXT, table_type TEXT, area_name TEXT, status TEXT, created_time TIMESTAMPTZ, updated_time TIMESTAMPTZ ); CREATE TABLE IF NOT EXISTS billiards_dwd.dim_assistant_team ( team_id BIGINT PRIMARY KEY, team_name TEXT, remark TEXT, updated_at TIMESTAMPTZ DEFAULT now() ); CREATE TABLE IF NOT EXISTS billiards_dwd.dim_assistant ( assistant_id BIGINT PRIMARY KEY, assistant_name TEXT, mobile TEXT, team_id BIGINT REFERENCES billiards_dwd.dim_assistant_team (team_id), status TEXT, hired_date DATE, left_date DATE, updated_at TIMESTAMPTZ DEFAULT now() ); CREATE TABLE IF NOT EXISTS billiards_dwd.dim_pay_method ( pay_method_code TEXT PRIMARY KEY, pay_method_name TEXT, is_stored_value BOOLEAN DEFAULT FALSE, status TEXT, updated_at TIMESTAMPTZ DEFAULT now() ); CREATE TABLE IF NOT EXISTS billiards_dwd.dim_order_assist_type ( assist_type_code TEXT PRIMARY KEY, assist_type_name TEXT, description TEXT ); CREATE TABLE IF NOT EXISTS billiards_dwd.dim_coupon_platform ( platform_code TEXT PRIMARY KEY, platform_name TEXT, description TEXT ); CREATE TABLE IF NOT EXISTS billiards_dwd.dim_date ( date_key DATE PRIMARY KEY, year_no INT, month_no INT, day_no INT, week_no INT, day_of_week INT, month_name TEXT ); CREATE TABLE IF NOT EXISTS billiards_dwd.dim_member ( site_id BIGINT, member_id BIGINT, tenant_id BIGINT, member_name TEXT, nickname TEXT, gender TEXT, birthday DATE, mobile TEXT, member_type_id BIGINT REFERENCES billiards_dwd.dim_member_card_type (card_type_id), member_type_name TEXT, status TEXT, register_time TIMESTAMPTZ, valid_from DATE, valid_to DATE, last_visit_time TIMESTAMPTZ, balance NUMERIC(18,2), total_recharge_amount NUMERIC(18,2), total_consumed_amount NUMERIC(18,2), wechat_id TEXT, alipay_id TEXT, remark TEXT, updated_at TIMESTAMPTZ DEFAULT now(), PRIMARY KEY (site_id, member_id) ); -- ---------- DWD Facts ---------- CREATE TABLE IF NOT EXISTS billiards_dwd.fact_sale_item ( site_id BIGINT NOT NULL, sale_item_id BIGINT NOT NULL, order_trade_no TEXT, order_settle_id BIGINT, member_id BIGINT, goods_id BIGINT REFERENCES billiards_dwd.dim_product (goods_id), category_id BIGINT REFERENCES billiards_dwd.dim_product_category (category_id), quantity NUMERIC(18,4), original_amount NUMERIC(18,2), discount_amount NUMERIC(18,2), final_amount NUMERIC(18,2), is_gift BOOLEAN DEFAULT FALSE, sale_time TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now(), PRIMARY KEY (site_id, sale_item_id) ); CREATE TABLE IF NOT EXISTS billiards_dwd.fact_table_usage ( site_id BIGINT NOT NULL, ledger_id BIGINT NOT NULL, order_trade_no TEXT, order_settle_id BIGINT, table_id BIGINT REFERENCES billiards_dwd.dim_table (table_id), member_id BIGINT, start_time TIMESTAMPTZ, end_time TIMESTAMPTZ, duration_minutes INT, original_table_fee NUMERIC(18,2), member_discount_amount NUMERIC(18,2), manual_discount_amount NUMERIC(18,2), final_table_fee NUMERIC(18,2), is_canceled BOOLEAN DEFAULT FALSE, cancel_time TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now(), PRIMARY KEY (site_id, ledger_id) ); CREATE TABLE IF NOT EXISTS billiards_dwd.fact_assistant_service ( site_id BIGINT NOT NULL, ledger_id BIGINT NOT NULL, order_trade_no TEXT, order_settle_id BIGINT, assistant_id BIGINT REFERENCES billiards_dwd.dim_assistant (assistant_id), assist_type_code TEXT REFERENCES billiards_dwd.dim_order_assist_type (assist_type_code), member_id BIGINT, start_time TIMESTAMPTZ, end_time TIMESTAMPTZ, duration_minutes INT, original_fee NUMERIC(18,2), member_discount_amount NUMERIC(18,2), manual_discount_amount NUMERIC(18,2), final_fee NUMERIC(18,2), is_canceled BOOLEAN DEFAULT FALSE, cancel_time TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now(), PRIMARY KEY (site_id, ledger_id) ); CREATE TABLE IF NOT EXISTS billiards_dwd.fact_coupon_usage ( site_id BIGINT NOT NULL, coupon_id BIGINT NOT NULL, package_id BIGINT, order_trade_no TEXT, order_settle_id BIGINT, member_id BIGINT, platform_code TEXT REFERENCES billiards_dwd.dim_coupon_platform (platform_code), status TEXT, deduct_amount NUMERIC(18,2), settle_price NUMERIC(18,2), used_time TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now(), PRIMARY KEY (site_id, coupon_id) ); CREATE TABLE IF NOT EXISTS billiards_dwd.fact_payment ( site_id BIGINT NOT NULL, pay_id BIGINT NOT NULL, order_trade_no TEXT, order_settle_id BIGINT, member_id BIGINT, pay_method_code TEXT REFERENCES billiards_dwd.dim_pay_method (pay_method_code), pay_amount NUMERIC(18,2), pay_time TIMESTAMPTZ, relate_type TEXT, relate_id BIGINT, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now(), PRIMARY KEY (site_id, pay_id) ); CREATE TABLE IF NOT EXISTS billiards_dwd.fact_refund ( site_id BIGINT NOT NULL, refund_id BIGINT NOT NULL, order_trade_no TEXT, order_settle_id BIGINT, member_id BIGINT, pay_method_code TEXT REFERENCES billiards_dwd.dim_pay_method (pay_method_code), refund_amount NUMERIC(18,2), refund_time TIMESTAMPTZ, status TEXT, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now(), PRIMARY KEY (site_id, refund_id) ); CREATE TABLE IF NOT EXISTS billiards_dwd.fact_balance_change ( site_id BIGINT NOT NULL, change_id BIGINT NOT NULL, member_id BIGINT, change_type INT, relate_type TEXT, relate_id BIGINT, pay_method_code TEXT REFERENCES billiards_dwd.dim_pay_method (pay_method_code), change_amount NUMERIC(18,2), balance_before NUMERIC(18,2), balance_after NUMERIC(18,2), change_time TIMESTAMPTZ, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now(), PRIMARY KEY (site_id, change_id) ); -- ---------- DWS (serving layers) ---------- CREATE TABLE IF NOT EXISTS billiards_dws.dws_order_summary ( site_id BIGINT NOT NULL, order_settle_id BIGINT NOT NULL, order_trade_no TEXT, order_date DATE, tenant_id BIGINT, member_id BIGINT, member_flag BOOLEAN DEFAULT FALSE, recharge_order_flag BOOLEAN DEFAULT FALSE, item_count INT, total_item_quantity NUMERIC(18,4), table_fee_amount NUMERIC(18,2), assistant_service_amount NUMERIC(18,2), goods_amount NUMERIC(18,2), group_amount NUMERIC(18,2), total_coupon_deduction NUMERIC(18,2), member_discount_amount NUMERIC(18,2), manual_discount_amount NUMERIC(18,2), order_original_amount NUMERIC(18,2), order_final_amount NUMERIC(18,2), stored_card_deduct NUMERIC(18,2), external_paid_amount NUMERIC(18,2), total_paid_amount NUMERIC(18,2), book_table_flow NUMERIC(18,2), book_assistant_flow NUMERIC(18,2), book_goods_flow NUMERIC(18,2), book_group_flow NUMERIC(18,2), book_order_flow NUMERIC(18,2), order_effective_consume_cash NUMERIC(18,2), order_effective_recharge_cash NUMERIC(18,2), order_effective_flow NUMERIC(18,2), refund_amount NUMERIC(18,2), net_income NUMERIC(18,2), created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now(), PRIMARY KEY (site_id, order_settle_id) ); -- ---------- etl_admin (scheduler, cursor, run tracking) ---------- CREATE SCHEMA IF NOT EXISTS etl_admin; CREATE TABLE IF NOT EXISTS etl_admin.etl_task ( task_id BIGSERIAL PRIMARY KEY, task_code TEXT NOT NULL, store_id BIGINT NOT NULL, enabled BOOLEAN DEFAULT TRUE, cursor_field TEXT, window_minutes_default INT DEFAULT 30, overlap_seconds INT DEFAULT 120, page_size INT DEFAULT 200, retry_max INT DEFAULT 3, params JSONB DEFAULT '{}'::jsonb, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now(), UNIQUE (task_code, store_id) ); 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, last_run_id BIGINT, extra JSONB DEFAULT '{}'::jsonb, created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now(), UNIQUE (task_id, store_id) ); CREATE TABLE IF NOT EXISTS etl_admin.etl_run ( run_id BIGSERIAL PRIMARY KEY, run_uuid TEXT NOT NULL, task_id BIGINT NOT NULL REFERENCES etl_admin.etl_task(task_id) ON DELETE CASCADE, store_id BIGINT NOT NULL, status TEXT NOT NULL, started_at TIMESTAMPTZ DEFAULT now(), ended_at TIMESTAMPTZ, window_start TIMESTAMPTZ, window_end TIMESTAMPTZ, window_minutes INT, overlap_seconds INT, fetched_count INT DEFAULT 0, loaded_count INT DEFAULT 0, updated_count INT DEFAULT 0, skipped_count INT DEFAULT 0, error_count INT DEFAULT 0, unknown_fields INT DEFAULT 0, export_dir TEXT, log_path TEXT, request_params JSONB DEFAULT '{}'::jsonb, manifest JSONB DEFAULT '{}'::jsonb, error_message TEXT, extra JSONB DEFAULT '{}'::jsonb ); -- Default task registry seed (idempotent) INSERT INTO etl_admin.etl_task (task_code, store_id, enabled) VALUES ('PRODUCTS', 2790685415443269, TRUE), ('TABLES', 2790685415443269, TRUE), ('MEMBERS', 2790685415443269, TRUE), ('ASSISTANTS', 2790685415443269, TRUE), ('PACKAGES_DEF', 2790685415443269, TRUE), ('ORDERS', 2790685415443269, TRUE), ('PAYMENTS', 2790685415443269, TRUE), ('REFUNDS', 2790685415443269, TRUE), ('COUPON_USAGE', 2790685415443269, TRUE), ('INVENTORY_CHANGE', 2790685415443269, TRUE), ('TOPUPS', 2790685415443269, TRUE), ('TABLE_DISCOUNT', 2790685415443269, TRUE), ('ASSISTANT_ABOLISH', 2790685415443269, TRUE), ('LEDGER', 2790685415443269, TRUE), ('TICKET_DWD', 2790685415443269, TRUE), ('PAYMENTS_DWD', 2790685415443269, TRUE), ('MEMBERS_DWD', 2790685415443269, TRUE), ('MANUAL_INGEST', 2790685415443269, TRUE), ('settlement_records', 2790685415443269, TRUE), ('table_fee_transactions', 2790685415443269, TRUE), ('assistant_service_records', 2790685415443269, TRUE), ('assistant_cancellation_records', 2790685415443269, TRUE), ('ODS_GOODS_LEDGER', 2790685415443269, TRUE), ('ODS_PAYMENT', 2790685415443269, TRUE), ('ODS_REFUND', 2790685415443269, TRUE), ('platform_coupon_redemption_records', 2790685415443269, TRUE), ('ODS_MEMBER', 2790685415443269, TRUE), ('member_stored_value_cards', 2790685415443269, TRUE), ('ODS_PACKAGE', 2790685415443269, TRUE), ('ODS_INVENTORY_STOCK', 2790685415443269, TRUE), ('goods_stock_movements', 2790685415443269, TRUE) ON CONFLICT (task_code, store_id) DO NOTHING;