diff --git a/20251121-task.txt b/20251121-task.txt
index bc47be0..5b3cb2d 100644
--- a/20251121-task.txt
+++ b/20251121-task.txt
@@ -1,1360 +1,1361 @@
-2. 数仓分层结构总览
+2. 鏁颁粨鍒嗗眰缁撴瀯鎬昏
-本项目采用典型的三层数仓分层体系:
+鏈」鐩噰鐢ㄥ吀鍨嬬殑涓夊眰鏁颁粨鍒嗗眰浣撶郴锛?
-- **ODS(Operational Data Store,操作数据层)**:
- 以“贴源”方式承接上游 JSON 数据,一条记录尽量对应上游一条业务记录,仅做最轻度的数据类型规范与字段补充,不做业务口径改造。
-- **DWD(Data Warehouse Detail,明细数据层)**:
- 在 ODS 基础上进行清洗、标准化与轻度汇总,形成标准的「事实表 + 维度表」模型,作为后续 DWS 和报表的统一明细数据源。
-- **DWS(Data Warehouse Service,汇总服务层)**:
- 面向具体经营分析场景的汇总宽表或主题汇总表,本期重点为「订单粒度」的汇总(每笔结账一行),后续可扩展日粒度、助教绩效粒度等宽表。
+- **ODS锛圤perational Data Store锛屾搷浣滄暟鎹眰锛?*锛?
+ 浠モ€滆创婧愨€濇柟寮忔壙鎺ヤ笂娓?JSON 鏁版嵁锛屼竴鏉¤褰曞敖閲忓搴斾笂娓镐竴鏉′笟鍔¤褰曪紝浠呭仛鏈€杞诲害鐨勬暟鎹被鍨嬭鑼冧笌瀛楁琛ュ厖锛屼笉鍋氫笟鍔″彛寰勬敼閫犮€?
+- **DWD锛圖ata Warehouse Detail锛屾槑缁嗘暟鎹眰锛?*锛?
+ 鍦?ODS 鍩虹涓婅繘琛屾竻娲椼€佹爣鍑嗗寲涓庤交搴︽眹鎬伙紝褰㈡垚鏍囧噯鐨勩€屼簨瀹炶〃 + 缁村害琛ㄣ€嶆ā鍨嬶紝浣滀负鍚庣画 DWS 鍜屾姤琛ㄧ殑缁熶竴鏄庣粏鏁版嵁婧愩€?
+- **DWS锛圖ata Warehouse Service锛屾眹鎬绘湇鍔″眰锛?*锛?
+ 闈㈠悜鍏蜂綋缁忚惀鍒嗘瀽鍦烘櫙鐨勬眹鎬诲琛ㄦ垨涓婚姹囨€昏〃锛屾湰鏈熼噸鐐逛负銆岃鍗曠矑搴︺€嶇殑姹囨€伙紙姣忕瑪缁撹处涓€琛岋級锛屽悗缁彲鎵╁睍鏃ョ矑搴︺€佸姪鏁欑哗鏁堢矑搴︾瓑瀹借〃銆?
-### 2.1 各层表清单
+### 2.1 鍚勫眰琛ㄦ竻鍗?
-#### 2.1.1 ODS 层表(源数据镜像)
+#### 2.1.1 ODS 灞傝〃锛堟簮鏁版嵁闀滃儚锛?
-ODS 层按上游 JSON 文件一一映射,保留源系统字段,字段命名尽量对齐源字段。
+ODS 灞傛寜涓婃父 JSON 鏂囦欢涓€涓€鏄犲皠锛屼繚鐣欐簮绯荤粺瀛楁锛屽瓧娈靛懡鍚嶅敖閲忓榻愭簮瀛楁銆?
-| 表名 | 粒度描述 | 主要来源 JSON / 说明 |
+| 琛ㄥ悕 | 绮掑害鎻忚堪 | 涓昏鏉ユ簮 JSON / 璇存槑 |
|------------------------------|------------------------------------|------------------------------------|
-| `ods_member_profile` | 会员档案,1 行 = 1 个会员账号 | 会员档案.JSON |
-| `ods_member_card` | 会员卡记录,1 行 = 1 张卡 | 储值卡列表.JSON |
-| `ods_balance_change` | 余额变更记录,1 行 = 1 次余额变动 | 余额变动.JSON |
-| `ods_recharge_record` | 充值记录,1 行 = 1 笔充值交易 | 充值记录.JSON |
-| `ods_product` | 租户级商品档案 | 商品档案.JSON |
-| `ods_store_product` | 门店商品档案,门店维度的商品配置 | 门店商品档案.JSON |
-| `ods_store_sale_item` | 商品销售明细,1 行 = 1 个销售行 | 门店销售记录.JSON |
-| `ods_table_info` | 台桌档案,1 行 = 1 张台/包厢 | 台桌列表.JSON |
-| `ods_table_use_log` | 台费流水,1 行 = 1 笔台桌使用记录 | 台费流水.JSON |
-| `ods_table_fee_adjust` | 台费打折记录,1 行 = 1 次人工折扣 | 台费打折.JSON |
-| `ods_assistant_account` | 助教账号档案,1 行 = 1 个助教账号 | 助教账号.JSON |
-| `ods_assistant_service_log` | 助教服务流水,1 行 = 1 条助教服务 | 助教流水.JSON |
-| `ods_assistant_cancel_log` | 助教废除记录,1 行 = 1 次服务取消 | 助教废除.JSON |
-| `ods_group_package` | 团购套餐定义 | 团购套餐定义.JSON |
-| `ods_group_package_log` | 团购套餐使用流水 | 团购套餐使用.JSON |
-| `ods_platform_coupon_log` | 平台验券记录 | 平台验券.JSON |
-| `ods_payment_record` | 支付记录,1 行 = 1 个支付渠道流水 | 支付记录.JSON |
-| `ods_refund_record` | 退款记录,1 行 = 1 个退款流水 | 退款记录.JSON |
-| `ods_order_receipt_detail` | 结账小票详情,1 行 = 1 张结算小票 | 小票详情 JSON(含 siteProfile 快照) |
+| `member_profiles` | 浼氬憳妗f锛? 琛?= 1 涓細鍛樿处鍙? | 浼氬憳妗f.JSON |
+| `member_stored_value_cards` | 浼氬憳鍗¤褰曪紝1 琛?= 1 寮犲崱 | 鍌ㄥ€煎崱鍒楄〃.JSON |
+| `member_balance_changes` | 浣欓鍙樻洿璁板綍锛? 琛?= 1 娆′綑棰濆彉鍔? | 浣欓鍙樺姩.JSON |
+| `ods_recharge_record` | 鍏呭€艰褰曪紝1 琛?= 1 绗斿厖鍊间氦鏄? | 鍏呭€艰褰?JSON |
+| `ods_product` | 绉熸埛绾у晢鍝佹。妗? | 鍟嗗搧妗f.JSON |
+| `ods_store_product` | 闂ㄥ簵鍟嗗搧妗f锛岄棬搴楃淮搴︾殑鍟嗗搧閰嶇疆 | 闂ㄥ簵鍟嗗搧妗f.JSON |
+| `ods_store_sale_item` | 鍟嗗搧閿€鍞槑缁嗭紝1 琛?= 1 涓攢鍞 | 闂ㄥ簵閿€鍞褰?JSON |
+| `ods_table_info` | 鍙版妗f锛? 琛?= 1 寮犲彴/鍖呭帰 | 鍙版鍒楄〃.JSON |
+| `table_fee_transactions_log` | 鍙拌垂娴佹按锛? 琛?= 1 绗斿彴妗屼娇鐢ㄨ褰? | 鍙拌垂娴佹按.JSON |
+| `ods_table_fee_adjust` | 鍙拌垂鎵撴姌璁板綍锛? 琛?= 1 娆′汉宸ユ姌鎵? | 鍙拌垂鎵撴姌.JSON |
+| `assistant_accounts_master` | 鍔╂暀璐﹀彿妗f锛? 琛?= 1 涓姪鏁欒处鍙? | 鍔╂暀璐﹀彿.JSON |
+| `ods_assistant_service_log` | 鍔╂暀鏈嶅姟娴佹按锛? 琛?= 1 鏉″姪鏁欐湇鍔? | 鍔╂暀娴佹按.JSON |
+| `ods_assistant_cancel_log` | 鍔╂暀搴熼櫎璁板綍锛? 琛?= 1 娆℃湇鍔″彇娑? | 鍔╂暀搴熼櫎.JSON |
+| `group_buy_packages` | 鍥㈣喘濂楅瀹氫箟 | 鍥㈣喘濂楅瀹氫箟.JSON |
+| `group_buy_packages_log` | 鍥㈣喘濂楅浣跨敤娴佹按 | 鍥㈣喘濂楅浣跨敤.JSON |
+| `ods_platform_coupon_log` | 骞冲彴楠屽埜璁板綍 | 骞冲彴楠屽埜.JSON |
+| `payment_transactions` | 鏀粯璁板綍锛? 琛?= 1 涓敮浠樻笭閬撴祦姘? | 鏀粯璁板綍.JSON |
+| `refund_transactions` | 閫€娆捐褰曪紝1 琛?= 1 涓€€娆炬祦姘? | 閫€娆捐褰?JSON |
+| `ods_order_receipt_detail` | 缁撹处灏忕エ璇︽儏锛? 琛?= 1 寮犵粨绠楀皬绁? | 灏忕エ璇︽儏 JSON锛堝惈 siteProfile 蹇収锛?|
-> 说明:未来如果上游新增 JSON 类型(如库存明细、套餐定义等),按上述命名规范扩展对应 ODS 表即可。
+> 璇存槑锛氭湭鏉ュ鏋滀笂娓告柊澧?JSON 绫诲瀷锛堝搴撳瓨鏄庣粏銆佸椁愬畾涔夌瓑锛夛紝鎸変笂杩板懡鍚嶈鑼冩墿灞曞搴?ODS 琛ㄥ嵆鍙€?
-#### 2.1.2 DWD 层表(维度 + 明细事实)
+#### 2.1.2 DWD 灞傝〃锛堢淮搴?+ 鏄庣粏浜嬪疄锛?
-DWD 层在 ODS 基础上做清洗、归一化命名与业务规则整理,形成本期的核心事实与维度。
+DWD 灞傚湪 ODS 鍩虹涓婂仛娓呮礂銆佸綊涓€鍖栧懡鍚嶄笌涓氬姟瑙勫垯鏁寸悊锛屽舰鎴愭湰鏈熺殑鏍稿績浜嬪疄涓庣淮搴︺€?
-**维度表(Dim):**
+**缁村害琛紙Dim锛夛細**
-| 表名 | 描述 | 说明 |
+| 琛ㄥ悕 | 鎻忚堪 | 璇存槑 |
|------------------------|------------------------------|-------------------------------|
-| `dim_tenant` | 租户/品牌维度 | 品牌级主数据(如朗朗桌球) |
-| `dim_site` | 门店维度 | 统一承载门店主数据(新增) |
-| `dim_member` | 会员维度 | 由会员档案 + 卡信息归并而来 |
-| `dim_member_card_type` | 会员卡类型维度 | 卡种/等级等枚举维 |
-| `dim_product` | 商品维度 | 商品主数据(品牌级) |
-| `dim_product_category` | 商品分类维度 | 从商品分类配置 JSON 构建 |
-| `dim_table` | 台桌维度 | 台号、区域、台型等 |
-| `dim_assistant` | 助教维度 | 助教/陪练账号主数据 |
-| `dim_assistant_team` | 助教团队维度(如使用) | 班组/团队信息 |
-| `dim_pay_method` | 支付方式维度 | 支付渠道枚举(现金/微信等) |
-| `dim_order_assist_type`| 助教服务类型维度 | 基础课/附加课等类型 |
-| `dim_coupon_platform` | 券平台维度(美团/点评等) | 团购券来源渠道 |
-| `dim_date` 等 | 时间维度 | 自然日粒度,不做营业日切分 |
+| `dim_tenant` | 绉熸埛/鍝佺墝缁村害 | 鍝佺墝绾т富鏁版嵁锛堝鏈楁湕妗岀悆锛? |
+| `dim_site` | 闂ㄥ簵缁村害 | 缁熶竴鎵胯浇闂ㄥ簵涓绘暟鎹紙鏂板锛? |
+| `dim_member` | 浼氬憳缁村害 | 鐢变細鍛樻。妗?+ 鍗′俊鎭綊骞惰€屾潵 |
+| `dim_member_card_type` | 浼氬憳鍗$被鍨嬬淮搴? | 鍗$/绛夌骇绛夋灇涓剧淮 |
+| `dim_product` | 鍟嗗搧缁村害 | 鍟嗗搧涓绘暟鎹紙鍝佺墝绾э級 |
+| `dim_product_category` | 鍟嗗搧鍒嗙被缁村害 | 浠庡晢鍝佸垎绫婚厤缃?JSON 鏋勫缓 |
+| `dim_table` | 鍙版缁村害 | 鍙板彿銆佸尯鍩熴€佸彴鍨嬬瓑 |
+| `dim_assistant` | 鍔╂暀缁村害 | 鍔╂暀/闄粌璐﹀彿涓绘暟鎹? |
+| `dim_assistant_team` | 鍔╂暀鍥㈤槦缁村害锛堝浣跨敤锛? | 鐝粍/鍥㈤槦淇℃伅 |
+| `dim_pay_method` | 鏀粯鏂瑰紡缁村害 | 鏀粯娓犻亾鏋氫妇锛堢幇閲?寰俊绛夛級 |
+| `dim_order_assist_type`| 鍔╂暀鏈嶅姟绫诲瀷缁村害 | 鍩虹璇?闄勫姞璇剧瓑绫诲瀷 |
+| `dim_coupon_platform` | 鍒稿钩鍙扮淮搴︼紙缇庡洟/鐐硅瘎绛夛級 | 鍥㈣喘鍒告潵婧愭笭閬? |
+| `dim_date` 绛? | 鏃堕棿缁村害 | 鑷劧鏃ョ矑搴︼紝涓嶅仛钀ヤ笟鏃ュ垏鍒? |
-**事实表(Fact):**
+**浜嬪疄琛紙Fact锛夛細**
-| 表名 | 粒度描述 |
+| 琛ㄥ悕 | 绮掑害鎻忚堪 |
|----------------------------|-------------------------------------------|
-| `fact_sale_item` | 商品销售明细:1 行 = 1 个商品销售行 |
-| `fact_table_usage` | 台费使用明细:1 行 = 1 笔台桌使用记录 |
-| `fact_assistant_service` | 助教服务明细:1 行 = 1 条助教服务记录 |
-| `fact_coupon_usage` | 团购券使用明细:1 行 = 1 次券核销 |
-| `fact_payment` | 支付明细:1 行 = 1 笔支付流水 |
-| `fact_refund` | 退款明细:1 行 = 1 笔退款流水 |
-| `fact_balance_change` | 余额变动明细:1 行 = 1 次余额增减事件 |
+| `fact_sale_item` | 鍟嗗搧閿€鍞槑缁嗭細1 琛?= 1 涓晢鍝侀攢鍞 |
+| `fact_table_usage` | 鍙拌垂浣跨敤鏄庣粏锛? 琛?= 1 绗斿彴妗屼娇鐢ㄨ褰? |
+| `fact_assistant_service` | 鍔╂暀鏈嶅姟鏄庣粏锛? 琛?= 1 鏉″姪鏁欐湇鍔¤褰? |
+| `fact_coupon_usage` | 鍥㈣喘鍒镐娇鐢ㄦ槑缁嗭細1 琛?= 1 娆″埜鏍搁攢 |
+| `fact_payment` | 鏀粯鏄庣粏锛? 琛?= 1 绗旀敮浠樻祦姘? |
+| `fact_refund` | 閫€娆炬槑缁嗭細1 琛?= 1 绗旈€€娆炬祦姘? |
+| `fact_balance_change` | 浣欓鍙樺姩鏄庣粏锛? 琛?= 1 娆′綑棰濆鍑忎簨浠? |
-> 说明:本期 DWD 不再保留“siteProfile”等门店快照字段,而是统一沉淀到 `dim_site`,所有事实表通过 `site_id` 关联门店。
+> 璇存槑锛氭湰鏈?DWD 涓嶅啀淇濈暀鈥渟iteProfile鈥濈瓑闂ㄥ簵蹇収瀛楁锛岃€屾槸缁熶竴娌夋穩鍒?`dim_site`锛屾墍鏈変簨瀹炶〃閫氳繃 `site_id` 鍏宠仈闂ㄥ簵銆?
-#### 2.1.3 DWS 层表(汇总宽表)
+#### 2.1.3 DWS 灞傝〃锛堟眹鎬诲琛級
-DWS 层面向经营分析场景输出汇总结果,本期重点如下:
+DWS 灞傞潰鍚戠粡钀ュ垎鏋愬満鏅緭鍑烘眹鎬荤粨鏋滐紝鏈湡閲嶇偣濡備笅锛?
-| 表名 | 粒度描述 |
+| 琛ㄥ悕 | 绮掑害鎻忚堪 |
|-------------------------|----------------------------------------------------|
-| `dws_order_summary` | 订单汇总宽表:1 行 = 1 次结账 / 单笔消费 |
-| (后续可扩展) | (按日/按助教/按门店的各类经营日报、绩效宽表等) |
+| `dws_order_summary` | 璁㈠崟姹囨€诲琛細1 琛?= 1 娆$粨璐?/ 鍗曠瑪娑堣垂 |
+| 锛堝悗缁彲鎵╁睍锛? | 锛堟寜鏃?鎸夊姪鏁?鎸夐棬搴楃殑鍚勭被缁忚惀鏃ユ姤銆佺哗鏁堝琛ㄧ瓑锛? |
-> 说明:
-> - `dws_order_summary` 是本期最核心的 DWS 表,所有“订单有效流水、记账流水、台费/商品/助教收入拆解”等指标均在此表定义。
-> - 本期暂不输出按日/按助教等 DWS 宽表,如后续有需求,可基于 DWD 和 `dws_order_summary` 再行建设。
-2. ODS层表定义(源数据表)
-ODS层直接存储业务系统各数据源的明细记录,结构与源 JSON 基本对应。一条ODS记录通常对应源系统中的一条业务记录(或业务对象快照)。字段命名以来源字段英文为准,数据类型贴近源数据类型。每个字段均标注来源JSON路径,便于ETL开发准确取数。以下按照业务主题逐一列出ODS表设计:
-ODS_MEMBER_PROFILE(会员档案表)
-描述: 存储会员账户基本信息,每条记录对应一个租户内的会员账户(通常也对应一张会员卡)。该表是会员维度的基础数据,提供会员的身份标识及联系信息等。
-字段定义:
-• id (BIGINT) - 会员账户ID,唯一标识会员(租户范围内)。来源JSON路径: $.id
-• tenant_id (BIGINT) - 租户ID(品牌ID)。当前数据中固定为单一值,但设计保留此字段以支持多品牌。来源: $.tenant_id
-• member_name (STRING) - 会员姓名。如会员未实名,可能为空或为默认值。来源: $.name(若JSON无明确name字段,则使用真实姓名字段)
-• nickname (STRING) - 会员昵称。若无单独昵称则可能与姓名相同或留空。来源: $.nickname
-• mobile (STRING) - 会员手机号。11位手机号码字符串,唯一标识会员联系方式。【重复的手机号应为数据异常,同一号码重复出现需在ETL时考虑合并或清洗】来源: $.mobile
-• gender (STRING) - 会员性别。来源: $.sex(例如 "M"/"F" 或其他标记,如JSON为数字需转换为描述,可在DWD阶段关联性别维表)
-• birthday (DATE) - 会员生日。来源: $.birthday(如源为字符串需转换为日期)
-• register_time (DATETIME) - 会员入会时间/开户时间。来源: $.register_time
-• member_type_id (BIGINT) - 会员卡类型ID。表示会员所持卡的类型/级别,与卡种定义相关联。来源: $.cardTypeId(如JSON中以具体字段提供)
-• member_type_name (STRING) - 会员卡类型名称。如“黄金卡”、“白银卡”等,描述会员级别或卡种权益。来源: $.cardTypeName(如果JSON中提供;如未提供则需在DWD从卡列表或配置推导)
-• status (STRING) - 会员账户状态。例如“正常”、“停用”等。来源: $.status 或 $.state(按JSON实际字段)
-• balance (DECIMAL(10,2)) - 当前储值余额。单位:元。来源: $.balance(如果会员档案JSON提供当前余额)
-• points (DECIMAL(10,2)) - 当前积分或点数。单位:分。来源: $.point 或 $.points(如有)
-• last_visit_time (DATETIME) - 最近一次到店/消费时间。来源: $.lastVisitTime(如有)
-• wechat_id (STRING) - 微信ID或绑定的微信识别码。来源: $.wechatId(如有)
-• alipay_id (STRING) - 支付宝ID或绑定账号。来源: $.alipayId(如有)
-• member_card_no (STRING) - 会员卡号。用于实体卡场景下的卡片编号。来源: $.cardNo(如有)
-• remarks (STRING) - 会员备注。来源: $.remark(如有备注字段)
-(说明: 原始“会员档案.json”中出现了一例重复记录(相同id的记录重复),ETL需过滤此类重复,以id唯一为准。上述字段可能分散于会员档案和储值卡列表两个源,在ODS阶段暂以会员档案JSON为准,如某些字段缺失可在DWD阶段结合“储值卡列表”补充。)
-ODS_MEMBER_CARD(会员卡列表表)
-描述: 存储会员卡开卡记录及卡状态信息。每条记录对应一张已开通的会员卡,包含卡的定义属性和当前状态。即便当前系统仅有储值卡,也统一按卡片视角记录。
-字段定义:
-• card_id (BIGINT) - 会员卡实例ID,唯一标识一张具体会员卡。来源JSON路径: $.id(储值卡列表JSON中的卡片主键)
-• member_id (BIGINT) - 持卡会员ID。对应ODS_MEMBER_PROFILE表的id,用于关联会员基本信息。来源: $.member_id 或 $.memberCardId(根据实际字段,如出现member_card_id应对应会员档案id)
-• card_type_id (BIGINT) - 卡种ID。标识此卡对应的卡种定义,例如储值卡、次卡等类别。来源: $.cardTypeId
-• card_type_name (STRING) - 卡种名称。来源: $.cardTypeName(例如“储值卡”“次卡”等)
-• card_balance (DECIMAL(10,2)) - 卡当前余额。单位:元。来源: $.balance
-• discount_rate (DECIMAL(5,2)) - 折扣率。如持此卡消费可享受的折扣,90%则存0.90。来源: $.discount(字段含义需确认,可能JSON中提供折扣规则)
-• valid_start_date (DATE) - 卡有效期起始日期。来源: $.validStart 或类似字段
-• valid_end_date (DATE) - 卡有效期截止日期。来源: $.validEnd
-• last_consume_time (DATETIME) - 最近一次使用该卡的消费时间。来源: $.lastConsumeTime
-• status (STRING) - 卡状态。如“正常”、“已过期”、“已挂失”等。来源: $.status(若为数字代码将在DWD关联维表)
-• activate_time (DATETIME) - 开卡时间/激活时间。来源: $.activateTime
-• deactivate_time (DATETIME) - 注销时间(如适用)。来源: $.cancelTime(如有)
-• issuer_name (STRING) - 开卡操作员姓名。来源: $.issuerName(如有)
-• issuer_id (BIGINT) - 开卡操作员ID。来源: $.issuerId
-(说明: 如果每个会员只有一张卡,ODS_MEMBER_PROFILE与ODS_MEMBER_CARD记录将一一对应;但模型设计仍区分两表,以支持一人多卡场景。例如未来可能推出不同类型的会员卡、或旧卡更换新卡等。ETL从“储值卡列表.json”提取上述字段。)
-ODS_BALANCE_CHANGE(余额变更记录表)
-描述: 存储会员账户余额每次变动的流水记录。包括会员充值、消费扣款、后台调整等导致储值余额增减的事件。
-字段定义:
-• id (BIGINT) - 余额变更记录ID,唯一标识一次余额变动事件。来源JSON路径: $.id
-• member_id (BIGINT) - 会员账户ID。本次余额变动关联的会员,引用ODS_MEMBER_PROFILE.id。来源: $.memberId 或 $.member_card_id(根据JSON字段,如出现member_card_id则对应会员档案id)
-• change_amount (DECIMAL(10,2)) - 变动金额。正数表示账户充值/增加,负数表示消费扣减。单位:元。来源: $.change_amount(若JSON将充值与扣款统一正负表示)
-• balance_before (DECIMAL(10,2)) - 变动前余额。来源: $.before_balance(如有)
-• balance_after (DECIMAL(10,2)) - 变动后余额。来源: $.after_balance(如有)
-• change_type (INT) - 变动类型代码。用于区分余额变动原因/来源,例如1=充值、2=消费、3=调整等。【在DWD将关联维表获取类型描述】来源: $.from_type 或 $.type
-• relate_id (BIGINT) - 相关业务单据ID。用于关联产生此次余额变动的业务记录,例如充值记录ID、订单结算ID、券核销ID等。若为0或空表示无对应单(如纯后台调整)。来源: $.relate_id
-• pay_method (INT) - 支付方式代码。仅在充值或消费通过某支付渠道时有意义,表示此次变动涉及的付款渠道(如现金、微信等)。来源: $.pay_type(如果余额变动记录中包含支付方式信息)
-• remark (STRING) - 备注信息。对此次余额变更的说明文字。来源: $.remark(如有)
-• operator_id (BIGINT) - 操作员ID。执行此次余额变动操作的员工账号。来源: $.operatorId
-• operator_name (STRING) - 操作员姓名。来源: $.operatorName
-• change_time (DATETIME) - 变动时间。记录余额实际变更发生的时间。来源: $.create_time 或 $.changeTime
-• tenant_id (BIGINT) - 租户ID(品牌ID),来源: $.tenant_id(通常固定值)
-• site_id (BIGINT) - 门店ID,指明发生此变动的门店。来源: $.site_id(通常固定值,但预留多门店)
-• is_deleted (TINYINT) - 记录是否被删除标志。0=正常,1=已删除(可能用于软删)。来源: $.is_delete 或 $.is_deleted(如有)
-(说明: 通过 change_type 和 relate_id,可以在DWD层进一步将余额变动与具体业务事实(充值、消费结算等)关联起来。例如 change_type=充值时,relate_id对应 ODS_RECHARGE.id;change_type=消费扣款时,relate_id对应 ODS_ORDER_SETTLEMENT.id 等。)
-ODS_RECHARGE_RECORD(充值记录表)
-描述: 存储会员储值卡充值的记录。每条记录表示一笔会员充值(增值)交易,通常对应会员支付一定金额并增加账户余额。
-字段定义:
-• id (BIGINT) - 充值记录ID,唯一标识一笔充值交易。来源JSON路径: $.id
-• member_id (BIGINT) - 会员账户ID,指明充值到账的会员。来源: $.memberId 或 $.member_card_id
-• recharge_amount (DECIMAL(10,2)) - 充值金额。会员实际支付的金额。单位:元。来源: $.amount
-• bonus_amount (DECIMAL(10,2)) - 赠送金额。若有充值优惠活动赠送的额外金额。来源: $.gift_amount 或 $.bonus(如有)
-• total_amount (DECIMAL(10,2)) - 充值总额。即充值金额 + 赠送金额,账户实际增加的余额。单位:元。来源: 无(可ETL计算得到)
-• pay_method (INT) - 支付方式代码。会员通过何种渠道支付了此次充值金额,如1=现金、2=微信等。来源: $.pay_type(如JSON提供)
-• pay_status (INT) - 支付状态代码。如0=未支付,1=已支付,2=支付完成/成功。来源: $.pay_status(样本中充值一般直接成功)
-• transaction_id (STRING) - 第三方支付流水号。如通过微信/支付宝充值对应的支付交易号。来源: $.transactionId(如有)
-• recharge_time (DATETIME) - 充值时间。来源: $.create_time 或 $.rechargeTime
-• operator_id (BIGINT) - 操作员ID。执行或登记此次充值的工作人员账号。来源: $.operatorId
-• operator_name (STRING) - 操作员姓名。来源: $.operatorName
-• tenant_id (BIGINT) - 租户ID。来源: $.tenant_id
-• site_id (BIGINT) - 门店ID。来源: $.site_id
-(说明: 充值成功后会员账户余额增加,对应的余额变更记录也会有一条与之关联。通过 pay_method 可以分析会员喜欢的充值渠道分布。)
-ODS_PRODUCT(商品档案表)
-描述: 存储品牌级商品档案信息。每条记录唯一标识一个由总部/品牌定义的商品(商品基本信息),不区分具体门店。商品可以是酒水、小吃等卖品,也可能包括服务类项目(如按次收费的服务)。
-字段定义:
-• goods_id (BIGINT) - 商品ID,商品档案主键,唯一标识一个商品定义。来源JSON路径: $.id
-• tenant_id (BIGINT) - 租户ID(品牌ID)。同一品牌的商品在各门店共享此tenant_id。来源: $.tenant_id
-• goods_name (STRING) - 商品名称。来源: $.name 或 $.goodsName
-• goods_code (STRING) - 商品编码。用于内部管理的编码,如条码或自定义码。来源: $.code(如有)
-• goods_type_id (BIGINT) - 商品类别ID。引用商品分类维度,例如酒水、小吃、服务等类别。来源: $.category_id(如“库存变化记录2”中定义的分类ID)
-• goods_type_name (STRING) - 商品类别名称。来源: $.category_name(如有提供)
-• unit (STRING) - 计量单位。如“瓶”、“份”、“小时”等。来源: $.unit
-• price (DECIMAL(10,2)) - 标准售价。品牌建议零售价。来源: $.price
-• cost_price (DECIMAL(10,2)) - 成本价。来源: $.cost_price(如有)
-• is_service (TINYINT) - 是否服务类项目标识。1表示服务(如计时收费项目),0表示商品。来源: $.is_service(如商品档案区分了实物与服务)
-• status (STRING) - 商品状态。如“上架”、“下架”。来源: $.status(若为枚举码将在维表映射)
-• created_time (DATETIME) - 商品档案创建时间。来源: $.create_time
-• updated_time (DATETIME) - 最近修改时间。来源: $.update_time
-(说明: 部分字段如商品分类可能需要与另一个JSON(库存变化记录2.json)的商品分类树对应,ODS_PRODUCT中可直接存分类ID,分类名称可在维度表中维护以避免重复。商品档案主要用于提供商品的标准信息。)
-ODS_STORE_PRODUCT(门店商品档案表)
-描述: 存储门店级商品配置,每条记录表示某门店中的一种商品及其设定(例如售价、上下架状态等)。多个门店可各自有不同的商品列表或配置。本次数据由于仅一店,ODS_STORE_PRODUCT记录即为该店商品明细。
-字段定义:
-• site_goods_id (BIGINT) - 门店商品ID,唯一标识某门店的一条商品记录。来源JSON路径: $.id(门店商品档案JSON中的主键)
-• goods_id (BIGINT) - 商品ID(品牌商品ID)。关联ODS_PRODUCT.goods_id,表示此门店商品所属的商品档案定义。来源: $.tenant_goods_id(字段含义:租户级商品ID)
-• tenant_id (BIGINT) - 租户ID。来源: $.tenant_id(应与ODS_PRODUCT保持一致)
-• site_id (BIGINT) - 门店ID。来源: $.site_id
-• goods_name (STRING) - 商品名称。在门店中的展示名称(通常与品牌商品名一致,可有细微差异)。来源: $.goodsName
-• category_id (BIGINT) - 商品分类ID。来源: $.goodsCategoryId
-• category_name (STRING) - 商品分类名称。来源: $.goodsCategoryName(如有)
-• selling_price (DECIMAL(10,2)) - 门店售卖价。此店实际销售此商品的单价。来源: $.sellingPrice
-• member_price (DECIMAL(10,2)) - 会员价。如对会员有优惠价则记录,否则可能与售卖价相同。来源: $.memberPrice(如有字段)
-• stock_quantity (DECIMAL(10,2)) - 当前库存数量。来源: $.stock(如有库存字段)
-• min_stock_alert (DECIMAL) - 库存警戒值。低于此数可能需要补货。来源: $.minStock(如有)
-• unit (STRING) - 计量单位。来源: $.unit(如未提供则继承ODS_PRODUCT.unit)
-• is_weighable (TINYINT) - 是否称重商品。1是称重商品(如水果按斤卖),0非称重。来源: $.isWeigh(如有)
-• status (STRING) - 上架状态。例:“on”上架、“off”下架。来源: $.status
-• created_time (DATETIME) - 记录创建时间。来源: $.create_time
-• updated_time (DATETIME) - 记录最近修改时间。来源: $.update_time
-(说明: 门店商品档案在当前数据中 tenant_id、site_id 固定各一值,但在模型中保留,以支持多店场景下同一商品在不同店有不同site_goods_id。库存相关字段如stock_quantity可用于库存分析,但销售主题中可能不重点使用。若数据不足,此类字段可以保留但在ETL时为空。)
-ODS_STORE_SALE_ITEM(门店商品销售记录表)
-描述: 存储商品销售明细流水,每条记录代表订单中售出的某种商品行项目。也称为销售行项目表。例如一笔订单买了3瓶饮料,则有3条对应记录(或一条记录含数量3)。这是销售事实的细粒度数据。
-字段定义:
-• id (BIGINT) - 销售流水ID,唯一标识一条销售明细记录。来源JSON路径: $.id
-• order_trade_no (BIGINT) - 订单交易号。表示此销售所属的订单号,用于将多个明细归属同一订单。【不同模块间订单交易号相同,用于串联台费、商品、助教、套餐等消费明细】来源: $.order_trade_no
-• order_settle_id (BIGINT) - 订单结算ID。对应结账单号的内部主键。如果订单已结算,可用于关联结账记录或小票详情。来源: $.order_settle_id
-• site_id (BIGINT) - 门店ID。来源: $.site_id
-• site_goods_id (BIGINT) - 门店商品ID。标识卖出的商品,关联ODS_STORE_PRODUCT.site_goods_id获取商品信息。来源: $.site_goods_id
-• goods_id (BIGINT) - 商品ID(品牌商品ID)。方便直接关联商品维度。来源: $.tenant_goods_id(通常与site_goods_id对应的品牌商品ID)
-• goods_name (STRING) - 商品名称。销售记录中的冗余商品名。来源: $.goodsName
-• quantity (DECIMAL(10,2)) - 销售数量。卖出商品的数量(或重量)。来源: $.quantity
-• unit_price (DECIMAL(10,2)) - 单价。商品原本单价,可能为标准售价。来源: $.price 或 $.unit_price
-• discount_amount (DECIMAL(10,2)) - 折扣金额。该明细获得的总折扣减免额(会员折扣或手工优惠)。正值表示优惠金额,0表示无折扣。来源: $.discount_money(JSON中如有)
-• actual_amount (DECIMAL(10,2)) - 实收金额。即此商品行实际收取金额 = 单价*数量 - 折扣金额。来源: 无(ETL计算,或JSON中已有如$.total_fee)
-• is_gift (TINYINT) - 是否赠送品标识。1表示该商品作为赠品未计价,0表示正常销售。来源: $.is_gift(如有)
-• operator_id (BIGINT) - 操作员ID。登记/录入此销售的员工。来源: $.operator_id
-• operator_name (STRING) - 操作员姓名。来源: $.operator_name
-• sales_time (DATETIME) - 销售时间。一般取订单创建时间,对于商品明细等同于订单开单时间。来源: $.create_time
-• salesman_user_id (BIGINT) - 推销员用户ID。指如有业务员提成,此字段记录关联的销售人员账号ID。来源: $.salesman_user_id(如有)
-• salesman_name (STRING) - 推销员姓名。来源: $.salesman_name(如有)
-• is_refunded (TINYINT) - 是否已退款标志。1表示该销售后续有退款撤销,0表示正常。来源: $.is_refund 或根据退款记录在DWD衍生。
-• remark (STRING) - 备注。对该销售明细的额外说明。来源: $.remark(如有)
-(说明: 商品销售记录在订单级汇总时会汇入订单总额。若有退款,可能需要在DWD层与退款事实关联以标识已退款项。discount_amount字段综合了会员折扣和手工折让,若需分别分析可在DWD阶段依据规则拆分。当前ODS数据中 salesm相关字段样本为0或空,如无推销员则留空即可。)
-ODS_TABLE_INFO(台桌列表表)
-描述: 存储台桌信息维度,每条记录代表门店中的一个台桌/包厢。比如台球桌、KTV包房、麻将房等。此为典型维表,为各类流水(台费、助教等)提供台号、区域等静态属性。
-字段定义:
-• site_table_id (BIGINT) - 台桌ID,主键,唯一标识一个台桌。来源JSON路径: $.id
-• tenant_id (BIGINT) - 租户ID(品牌ID)。来源: $.tenant_id
-• site_id (BIGINT) - 门店ID。来源: $.site_id
-• table_name (STRING) - 台桌名称/编号。供业务展示的名称,如“A1”、“B3”、“VIP1”、“斯1”(斯诺克1号桌)等。来源: $.tableName 或合成自区域+编号
-• table_no (STRING) - 台桌编号(纯数字部分)。如果有单独编号字段则记录,没有则可与table_name相同。来源: $.tableNo(如有)
-• area_id (BIGINT) - 台桌区域ID。用于区分台桌所属的区域/厅,例如A区、VIP区等。来源: $.tenant_site_region_id 或 $.areaId(如有)
-• area_name (STRING) - 台桌区域名称。如“A区”“VIP厅”。来源: $.area_name 或通过区域ID关联获得。
-• table_type (STRING) - 台桌类型。标识此台用于何种项目,如“美式台球”、“斯诺克”、“KTV包房”、“麻将房”等。【不写死枚举,DWD设计维表】来源: $.type 或从名称/配置推断(例如名称中“斯”开头表示斯诺克)
-• is_vip (TINYINT) - VIP专属标志。1表示该台为VIP专用,0表示普通。来源: 由名称或配置(如名称包含VIP)确定(若源数据有字段更好)
-• status (STRING) - 台桌状态。如“启用”、“停用”。来源: $.status(如有枚举,在维度表映射)
-• rate (DECIMAL(10,2)) - 台费费率。若每台桌可能有不同计费单价(每小时价格),则记录该基础费率。来源: $.rate(如有)
-• description (STRING) - 备注描述。对台桌的额外说明,如包厢大小、球台规格等。来源: $.description(如有)
-(说明: 台桌列表通常相对静态,ODS层保存现有台桌配置。表中示例值如“董事办”、“666”表明部分台号可使用自定义命名。area和type等若未在JSON中明确提供,DWD层可通过维护维表或规则补全。)
-ODS_TABLE_USE_LOG(台费流水表)
-描述: 记录台桌使用(计费)流水,每条记录对应一笔台桌使用明细(通常与一个订单绑定)。这相当于客人使用一张台从开始到结束所产生的台费账单。包含计费开始结束时间、时长、应收费用以及折扣减免等信息。
-字段定义:
-• id (BIGINT) - 台费流水ID,唯一标识一条台桌使用记录。来源JSON路径: $.id
-• order_trade_no (BIGINT) - 订单交易号。此台费所属订单的编号。来源: $.order_trade_no
-• order_settle_id (BIGINT) - 订单结算ID。订单结账单主键,用于关联结账/小票详情。来源: $.order_settle_id
-• site_id (BIGINT) - 门店ID。来源: $.site_id
-• site_table_id (BIGINT) - 台桌ID。关联ODS_TABLE_INFO.site_table_id,标识哪张台产生此费用。来源: $.site_table_id
-• table_name (STRING) - 台桌名称。冗余存储便于直接查看。来源: $.tableName
-• start_use_time (DATETIME) - 开台时间。顾客开始使用该台桌的时间。来源: $.start_use_time
-• last_use_time (DATETIME) - 结束时间。顾客结束使用/结账时间。来源: $.last_use_time
-• use_duration (INT) - 使用时长,单位秒或分钟。可由开始结束时间计算得到,或源数据直接提供。来源: 计算(last_use_time - start_use_time),如JSON中有 real_table_use_seconds 则直接用。
-• billing_unit_price (DECIMAL(10,2)) - 计费单价。使用时的收费标准(每小时/每半小时金额)。来源: $.ledger_unit_price(ledger单价)
-• billing_count (DECIMAL(10,2)) - 计费数量。按计费单位累计的数量。例如按小时计费的总小时数。来源: $.ledger_count
-• ledger_amount (DECIMAL(10,2)) - 原始台费金额。根据时长和单价计算的未折扣费用。来源: $.ledger_amount
-• member_discount_amount (DECIMAL(10,2)) - 会员折扣金额。因会员卡折扣减免的金额。来源: $.member_discount_amount
-• coupon_discount_amount (DECIMAL(10,2)) - 券抵扣金额。使用团购券等促销抵扣的金额。来源: $.coupon_promotion_amount
-• manual_adjust_amount (DECIMAL(10,2)) - 手工调整金额。通过台费打折流水记录的人工减免金额(正值表示减免了多少钱)。来源: $.adjust_amount
-• service_fee (DECIMAL(10,2)) - 附加服务费。若有额外服务费(例如夜场服务费)计入台费。来源: $.mgmt_fee(字段意义推测,样本中如有非0值则表示附加费)
-• final_table_fee (DECIMAL(10,2)) - 台费实收金额。即顾客最终为该台支付的费用 = ledger_amount - 所有折扣减免 + 附加费。来源: $.real_table_charge_money(如JSON提供;否则ETL计算)
-• member_id (BIGINT) - 会员ID。若该次开台绑定了会员,则记录会员账户ID,否则为空。来源: $.member_id
-• operator_id (BIGINT) - 操作员ID。办理开台/结账的员工账号。来源: $.operator_id
-• operator_name (STRING) - 操作员姓名。来源: $.operator_name
-• salesman_user_id (BIGINT) - 销售员ID。比如球台服务过程中的跟单员/营销员。来源: $.salesman_user_id
-• salesman_name (STRING) - 销售员姓名。来源: $.salesman_name
-• is_single_order (TINYINT) - 是否单独订单标志。1表示此台仅该订单使用,0表示可能有订单拆分(极少情况)。来源: $.is_single_order
-• is_deleted (TINYINT) - 记录删除标志。1表示该记录被作废(例如订单取消),0正常。来源: $.is_delete
-(说明: 台费流水表详细记录每笔台桌使用账目,包含各种折扣拆分,ETL时应尽量保留这些字段。在DWD汇总订单时,final_table_fee汇总进入订单总金额;各类折扣额也可汇总统计。manual_adjust_amount字段对应台费打折记录中的操作,如果为0表示未做人工减免。)
-ODS_TABLE_FEE_ADJUST(台费打折记录表)
-描述: 记录针对台费账单的人工调整(打折或减免费用)行为。每条记录表示一次对某订单台费的手工减免操作,并非台的使用记录本身,而是附加的一条调整流水。通常用于记录收银员给予顾客的台费折扣。
-字段定义:
-• id (BIGINT) - 台费调整记录ID,唯一标识一次台费打折操作。来源JSON路径: $.id
-• order_trade_no (BIGINT) - 订单交易号。本调整所属的订单。来源: $.order_trade_no
-• order_settle_id (BIGINT) - 订单结算ID。本调整所属订单的结算单ID。来源: $.order_settle_id
-• site_id (BIGINT) - 门店ID。来源: $.site_id(可能通过siteProfile获取)
-• site_table_id (BIGINT) - 台桌ID。指明此次调整针对哪张台桌的费用。来源: $.site_table_id(如JSON提供)
-• table_name (STRING) - 台桌名称。来源: $.tableName
-• adjust_amount (DECIMAL(10,2)) - 减免金额。正值表示减免了多少钱(即台费降低额)。来源: $.adjust_fee 或 $.reduce_amount(按实际字段)
-• reason (STRING) - 打折原因。对本次人工调整的说明,如“会员投诉补偿”或“店长特批”。来源: $.reason(如有)
-• operator_id (BIGINT) - 操作员ID。执行此打折操作的员工账号。来源: $.operator_id
-• operator_name (STRING) - 操作员姓名。来源: $.operator_name
-• adjust_time (DATETIME) - 调整时间。来源: $.create_time
-(说明: 台费打折记录在ODS_TABLE_USE_LOG中已反映为manual_adjust_amount,但为了保留操作原因、经办人等细节,ODS仍存此表。DWD建模时,可将adjust_amount合并计入台费最终金额计算。reason字段若为有限枚举,可建立维表维护各种折扣原因。)
-ODS_ASSISTANT_ACCOUNT(助教账号表)
-描述: 存储门店下所有助教(教练/服务人员,包括管理账号)的基础配置和档案信息。每条记录对应一名助教账号,属于人事维度表。字段涵盖助教的个人信息、账号状态、计费策略等。
-字段定义:
-• id (BIGINT) - 助教账号ID,主键。唯一标识一个助教/员工账号。在助教服务流水等事实表中以site_assistant_id引用该ID关联。来源JSON路径: $.id
-• user_id (BIGINT) - 系统用户ID。助教账号对应的系统登录账号ID,用于在不同模块下统一识别人员。区别于岗位级的id。来源: $.user_id
-• assistant_no (STRING) - 助教工号/编号。用于业务识别的编号,可能不唯一(不同助教可能编号相同但id不同)。来源: $.assistantNo
-• job_num (STRING) - 助教工作证编号。备用工号字段,当前门店可能未使用。来源: $.job_num
-• serial_number (INT) - 序号。系统内部生成的排序号或迁移用的序列值。来源: $.serial_number
-• real_name (STRING) - 助教真实姓名。来源: $.real_name
-• nickname (STRING) - 助教昵称。前台展示用的绰号,例如“佳怡”、“周周”。来源: $.nickname
-• gender (STRING) - 性别。来源: $.sex(例如“M”/“F”或“男”/“女”)
-• birthday (DATE) - 出生日期。来源: $.birthday
-• mobile (STRING) - 手机号。助教联系手机。来源: $.mobile
-• id_card (STRING) - 身份证号。来源: $.id_card(如有)
-• hire_date (DATE) - 入职日期。来源: $.hire_date(如有字段)
-• resign_date (DATE) - 离职日期。如账号已废除则记录离职时间。来源: $.resign_date(如有)
-• status (STRING) - 在职状态。示例:“在职”、“离职”、“停用”等。来源: $.status(若源为数字,在维表映射)
-• visible (TINYINT) - 前台可见性。0表示不在前台展示,1表示可被顾客看到选择。来源: $.visible(如有)
-• billing_mode (STRING) - 计费策略。助教服务计费方式,如“按小时计费”或固定场次。来源: $.billing_mode(推测字段,如无明确则可能通过关联配置决定)
-• skill_name (STRING) - 服务技能名称。例如“基础课”“附加课”等,表示该助教提供服务的类别。来源: $.skillName
-• skill_level (STRING) - 技能级别/等级。如“初级”“高级”。来源: $.levelName 或 $.assistant_level
-• team_id (BIGINT) - 助教团队ID。将助教分组的团队/班组标识。来源: $.assistant_team_id
-• team_name (STRING) - 助教团队名称。来源: $.ledger_group_name(猜测对应团队名称字段)
-• service_rate (DECIMAL(10,2)) - 服务费标准。助教服务的费率或提成标准。来源: $.service_rate(如有)
-• comment (STRING) - 备注。其他补充说明。来源: $.remark(如有)
-• tenant_id (BIGINT) - 租户ID。来源: $.tenant_id
-• site_id (BIGINT) - 门店ID。来源: $.site_id
-(说明: 助教账号作为维表,将通过id或user_id关联到助教服务流水、助教排班等事实。在当前数据中包含管理类账号,visible字段用于控制其是否提供给顾客选择服务。billing_mode/skill等决定其服务计费类别,例如区分基础课和附加课,在助教流水中也有对应枚举值。)
-ODS_ASSISTANT_SERVICE_LOG(助教流水表)
-描述: 记录助教服务/陪练的明细流水,每条记录代表一次助教为顾客提供服务的过程,通常对应订单中的一项助教服务消费。可能包含开始结束时间、服务费用、助教评价等。若一次订单中更换或多次聘请助教,会产生多条记录。
-字段定义:
-• id (BIGINT) - 助教流水ID,唯一标识一条助教服务记录。来源JSON路径: $.id
-• order_trade_no (BIGINT) - 订单交易号。标识此助教服务所属的订单。来源: $.order_trade_no
-• order_settle_id (BIGINT) - 订单结算ID。关联结账单,用于与小票详情等对应。【当前导出结账记录为空,此字段依然保留用于关联】来源: $.order_settle_id
-• order_assistant_id (BIGINT) - 订单助教项ID。用于区分同一订单中多条助教服务项的内部ID。来源: $.order_assistant_id
-• order_assistant_type (INT) - 助教服务类型编码。枚举值,示例:1=常规助教服务(基础课),2=附加助教服务(加课)。对应的含义可从系统配置获取。【模型中通过维表解析】来源: $.order_assistant_type
-• site_id (BIGINT) - 门店ID。来源: $.site_id
-• site_table_id (BIGINT) - 台桌ID。助教服务所在的台桌,如教练在哪张球台服务。来源: $.site_table_id
-• table_name (STRING) - 台桌名称。来源: $.tableName
-• site_assistant_id (BIGINT) - 助教ID。提供服务的助教账号ID,关联ODS_ASSISTANT_ACCOUNT.id。来源: $.site_assistant_id
-• assistant_name (STRING) - 助教姓名。冗余字段,来源: $.assistantName
-• assistant_no (STRING) - 助教工号。来源: $.assistantNo
-• skill_name (STRING) - 服务技能名称。例:“基础课”或“附加课”,与order_assistant_type相对应。来源: $.skillName
-• assistant_level (STRING) - 助教等级/级别。如“初级”“中级”。来源: $.assistant_level 或 $.levelName
-• start_time (DATETIME) - 服务开始时间。来源: $.start_use_time
-• end_time (DATETIME) - 服务结束时间。来源: $.last_use_time
-• service_duration (INT) - 服务时长(秒)。来源: $.income_seconds 或 $.real_use_seconds(如有)
-• ledger_unit_price (DECIMAL(10,2)) - 计费单价。助教服务费率(每单位时间费用)。来源: $.ledger_unit_price
-• ledger_amount (DECIMAL(10,2)) - 原始服务金额。按时长和单价计算的费用。来源: $.ledger_amount
-• member_discount_amount (DECIMAL(10,2)) - 会员折扣金额。会员价优惠的金额。来源: $.member_discount_amount
-• coupon_deduct_amount (DECIMAL(10,2)) - 券抵扣金额。使用促销券抵扣的金额。来源: $.coupon_deduct_money
-• manual_discount_amount (DECIMAL(10,2)) - 手工减免金额。人工给予的减免费用。来源: $.manual_discount_amount
-• final_service_fee (DECIMAL(10,2)) - 助教服务实收金额。= ledger_amount - 折扣 - 券抵扣 - 手工减免。来源: $.service_money(或ETL计算)
-• member_id (BIGINT) - 会员ID。若顾客为会员,此服务绑定的会员账号。来源: $.tenant_member_id 或 $.member_id(根据字段,样本中可能存在system_member_id/tenant_member_id用于区别品牌会员)
-• is_confirm (TINYINT) - 顾客确认标志。1表示顾客已确认服务(可能有签字确认流程),0未确认。来源: $.is_confirm
-• grade_status (TINYINT) - 评分状态。标识顾客是否已对本次服务评分/评价。来源: $.grade_status
-• service_grade (INT) - 服务态度评分。可能范围1-5。来源: $.service_grade(如有评分功能)
-• skill_grade (INT) - 技能专业度评分。来源: $.skill_grade
-• sum_grade (INT) - 综合评分。可能是平均或总分。来源: $.composite_grade
-• grade_time (DATETIME) - 评价时间。来源: $.composite_grade_time
-• get_grade_times (INT) - 获评次数。也许表示该助教被评价的总次数(字段意义存疑)。来源: $.get_grade_times
-• is_not_responding (TINYINT) - 助教未响应标志。1表示助教未及时应答服务请求。来源: $.is_not_responding
-• is_trash (TINYINT) - 作废标志。1表示该服务记录被废弃(可能由于助教更换/取消),0正常。来源: $.is_trash
-• trash_reason (STRING) - 废除原因。若is_trash=1,记录取消服务的原因说明。来源: $.trash_reason
-• trash_applicant_id (BIGINT) - 废除申请人ID。谁发起了取消(顾客或员工)。来源: $.trash_applicant_id
-• trash_applicant_name (STRING) - 废除申请人姓名。来源: $.trash_applicant_name
-• operator_id (BIGINT) - 操作员ID。登记此服务的操作员账号。来源: $.operator_id
-• operator_name (STRING) - 操作员姓名。来源: $.operator_name
-• salesman_user_id (BIGINT) - 销售员/推介人ID。如有业务员推荐此服务,则记录。来源: $.salesman_user_id
-• salesman_name (STRING) - 销售员姓名。来源: $.salesman_name
-• remark (STRING) - 备注。额外说明。来源: $.remark(如有)
-(说明: 助教服务流水包含一些服务质量相关字段(评分等),这是超出纯消费计费的内容,可供人员绩效分析。is_trash=1表示该记录对应一次助教服务被取消或废除,与助教废除表的数据相关。trash_reason等提供取消原因。在DWD层可结合助教废除记录进一步分析。)
+> 璇存槑锛?
+> - `dws_order_summary` 鏄湰鏈熸渶鏍稿績鐨?DWS 琛紝鎵€鏈夆€滆鍗曟湁鏁堟祦姘淬€佽璐︽祦姘淬€佸彴璐?鍟嗗搧/鍔╂暀鏀跺叆鎷嗚В鈥濈瓑鎸囨爣鍧囧湪姝よ〃瀹氫箟銆?
+> - 鏈湡鏆備笉杈撳嚭鎸夋棩/鎸夊姪鏁欑瓑 DWS 瀹借〃锛屽鍚庣画鏈夐渶姹傦紝鍙熀浜?DWD 鍜?`dws_order_summary` 鍐嶈寤鸿銆?
+2. ODS灞傝〃瀹氫箟锛堟簮鏁版嵁琛級
+ODS灞傜洿鎺ュ瓨鍌ㄤ笟鍔$郴缁熷悇鏁版嵁婧愮殑鏄庣粏璁板綍锛岀粨鏋勪笌婧?JSON 鍩烘湰瀵瑰簲銆備竴鏉DS璁板綍閫氬父瀵瑰簲婧愮郴缁熶腑鐨勪竴鏉′笟鍔¤褰曪紙鎴栦笟鍔″璞″揩鐓э級銆傚瓧娈靛懡鍚嶄互鏉ユ簮瀛楁鑻辨枃涓哄噯锛屾暟鎹被鍨嬭创杩戞簮鏁版嵁绫诲瀷銆傛瘡涓瓧娈靛潎鏍囨敞鏉ユ簮JSON璺緞锛屼究浜嶦TL寮€鍙戝噯纭彇鏁般€備互涓嬫寜鐓т笟鍔′富棰橀€愪竴鍒楀嚭ODS琛ㄨ璁★細
+member_profiles锛堜細鍛樻。妗堣〃锛?
+鎻忚堪锛?瀛樺偍浼氬憳璐︽埛鍩烘湰淇℃伅锛屾瘡鏉¤褰曞搴斾竴涓鎴峰唴鐨勪細鍛樿处鎴凤紙閫氬父涔熷搴斾竴寮犱細鍛樺崱锛夈€傝琛ㄦ槸浼氬憳缁村害鐨勫熀纭€鏁版嵁锛屾彁渚涗細鍛樼殑韬唤鏍囪瘑鍙婅仈绯讳俊鎭瓑銆?
+瀛楁瀹氫箟锛?
+鈥?id (BIGINT) - 浼氬憳璐︽埛ID锛屽敮涓€鏍囪瘑浼氬憳锛堢鎴疯寖鍥村唴锛夈€傛潵婧怞SON璺緞: $.id
+鈥?tenant_id (BIGINT) - 绉熸埛ID锛堝搧鐗孖D锛夈€傚綋鍓嶆暟鎹腑鍥哄畾涓哄崟涓€鍊硷紝浣嗚璁′繚鐣欐瀛楁浠ユ敮鎸佸鍝佺墝銆傛潵婧? $.tenant_id
+鈥?member_name (STRING) - 浼氬憳濮撳悕銆傚浼氬憳鏈疄鍚嶏紝鍙兘涓虹┖鎴栦负榛樿鍊笺€傛潵婧? $.name锛堣嫢JSON鏃犳槑纭畁ame瀛楁锛屽垯浣跨敤鐪熷疄濮撳悕瀛楁锛?
+鈥?nickname (STRING) - 浼氬憳鏄电О銆傝嫢鏃犲崟鐙樀绉板垯鍙兘涓庡鍚嶇浉鍚屾垨鐣欑┖銆傛潵婧? $.nickname
+鈥?mobile (STRING) - 浼氬憳鎵嬫満鍙枫€?1浣嶆墜鏈哄彿鐮佸瓧绗︿覆锛屽敮涓€鏍囪瘑浼氬憳鑱旂郴鏂瑰紡銆傘€愰噸澶嶇殑鎵嬫満鍙峰簲涓烘暟鎹紓甯革紝鍚屼竴鍙风爜閲嶅鍑虹幇闇€鍦‥TL鏃惰€冭檻鍚堝苟鎴栨竻娲椼€戞潵婧? $.mobile
+鈥?gender (STRING) - 浼氬憳鎬у埆銆傛潵婧? $.sex锛堜緥濡?"M"/"F" 鎴栧叾浠栨爣璁帮紝濡侸SON涓烘暟瀛楅渶杞崲涓烘弿杩帮紝鍙湪DWD闃舵鍏宠仈鎬у埆缁磋〃锛?
+鈥?birthday (DATE) - 浼氬憳鐢熸棩銆傛潵婧? $.birthday锛堝婧愪负瀛楃涓查渶杞崲涓烘棩鏈燂級
+鈥?register_time (DATETIME) - 浼氬憳鍏ヤ細鏃堕棿/寮€鎴锋椂闂淬€傛潵婧? $.register_time
+鈥?member_type_id (BIGINT) - 浼氬憳鍗$被鍨婭D銆傝〃绀轰細鍛樻墍鎸佸崱鐨勭被鍨?绾у埆锛屼笌鍗$瀹氫箟鐩稿叧鑱斻€傛潵婧? $.cardTypeId锛堝JSON涓互鍏蜂綋瀛楁鎻愪緵锛?
+鈥?member_type_name (STRING) - 浼氬憳鍗$被鍨嬪悕绉般€傚鈥滈粍閲戝崱鈥濄€佲€滅櫧閾跺崱鈥濈瓑锛屾弿杩颁細鍛樼骇鍒垨鍗$鏉冪泭銆傛潵婧? $.cardTypeName锛堝鏋淛SON涓彁渚涳紱濡傛湭鎻愪緵鍒欓渶鍦―WD浠庡崱鍒楄〃鎴栭厤缃帹瀵硷級
+鈥?status (STRING) - 浼氬憳璐︽埛鐘舵€併€備緥濡傗€滄甯糕€濄€佲€滃仠鐢ㄢ€濈瓑銆傛潵婧? $.status 鎴?$.state锛堟寜JSON瀹為檯瀛楁锛?
+鈥?balance (DECIMAL(10,2)) - 褰撳墠鍌ㄥ€间綑棰濄€傚崟浣嶏細鍏冦€傛潵婧? $.balance锛堝鏋滀細鍛樻。妗圝SON鎻愪緵褰撳墠浣欓锛?
+鈥?points (DECIMAL(10,2)) - 褰撳墠绉垎鎴栫偣鏁般€傚崟浣嶏細鍒嗐€傛潵婧? $.point 鎴?$.points锛堝鏈夛級
+鈥?last_visit_time (DATETIME) - 鏈€杩戜竴娆″埌搴?娑堣垂鏃堕棿銆傛潵婧? $.lastVisitTime锛堝鏈夛級
+鈥?wechat_id (STRING) - 寰俊ID鎴栫粦瀹氱殑寰俊璇嗗埆鐮併€傛潵婧? $.wechatId锛堝鏈夛級
+鈥?alipay_id (STRING) - 鏀粯瀹滻D鎴栫粦瀹氳处鍙枫€傛潵婧? $.alipayId锛堝鏈夛級
+鈥?member_card_no (STRING) - 浼氬憳鍗″彿銆傜敤浜庡疄浣撳崱鍦烘櫙涓嬬殑鍗$墖缂栧彿銆傛潵婧? $.cardNo锛堝鏈夛級
+鈥?remarks (STRING) - 浼氬憳澶囨敞銆傛潵婧? $.remark锛堝鏈夊娉ㄥ瓧娈碉級
+(璇存槑: 鍘熷鈥滀細鍛樻。妗?json鈥濅腑鍑虹幇浜嗕竴渚嬮噸澶嶈褰曪紙鐩稿悓id鐨勮褰曢噸澶嶏級锛孍TL闇€杩囨护姝ょ被閲嶅锛屼互id鍞竴涓哄噯銆備笂杩板瓧娈靛彲鑳藉垎鏁d簬浼氬憳妗f鍜屽偍鍊煎崱鍒楄〃涓や釜婧愶紝鍦∣DS闃舵鏆備互浼氬憳妗fJSON涓哄噯锛屽鏌愪簺瀛楁缂哄け鍙湪DWD闃舵缁撳悎鈥滃偍鍊煎崱鍒楄〃鈥濊ˉ鍏呫€?
+member_stored_value_cards锛堜細鍛樺崱鍒楄〃琛級
+鎻忚堪锛?瀛樺偍浼氬憳鍗″紑鍗¤褰曞強鍗$姸鎬佷俊鎭€傛瘡鏉¤褰曞搴斾竴寮犲凡寮€閫氱殑浼氬憳鍗★紝鍖呭惈鍗$殑瀹氫箟灞炴€у拰褰撳墠鐘舵€併€傚嵆渚垮綋鍓嶇郴缁熶粎鏈夊偍鍊煎崱锛屼篃缁熶竴鎸夊崱鐗囪瑙掕褰曘€?
+瀛楁瀹氫箟锛?
+鈥?card_id (BIGINT) - 浼氬憳鍗″疄渚婭D锛屽敮涓€鏍囪瘑涓€寮犲叿浣撲細鍛樺崱銆傛潵婧怞SON璺緞: $.id锛堝偍鍊煎崱鍒楄〃JSON涓殑鍗$墖涓婚敭锛?
+鈥?member_id (BIGINT) - 鎸佸崱浼氬憳ID銆傚搴擮DS_MEMBER_PROFILE琛ㄧ殑id锛岀敤浜庡叧鑱斾細鍛樺熀鏈俊鎭€傛潵婧? $.member_id 鎴?$.memberCardId锛堟牴鎹疄闄呭瓧娈碉紝濡傚嚭鐜癿ember_card_id搴斿搴斾細鍛樻。妗坕d锛?
+鈥?card_type_id (BIGINT) - 鍗$ID銆傛爣璇嗘鍗″搴旂殑鍗$瀹氫箟锛屼緥濡傚偍鍊煎崱銆佹鍗$瓑绫诲埆銆傛潵婧? $.cardTypeId
+鈥?card_type_name (STRING) - 鍗$鍚嶇О銆傛潵婧? $.cardTypeName锛堜緥濡傗€滃偍鍊煎崱鈥濃€滄鍗♀€濈瓑锛?
+鈥?card_balance (DECIMAL(10,2)) - 鍗″綋鍓嶄綑棰濄€傚崟浣嶏細鍏冦€傛潵婧? $.balance
+鈥?discount_rate (DECIMAL(5,2)) - 鎶樻墸鐜囥€傚鎸佹鍗℃秷璐瑰彲浜彈鐨勬姌鎵o紝90%鍒欏瓨0.90銆傛潵婧? $.discount锛堝瓧娈靛惈涔夐渶纭锛屽彲鑳絁SON涓彁渚涙姌鎵h鍒欙級
+鈥?valid_start_date (DATE) - 鍗℃湁鏁堟湡璧峰鏃ユ湡銆傛潵婧? $.validStart 鎴栫被浼煎瓧娈?
+鈥?valid_end_date (DATE) - 鍗℃湁鏁堟湡鎴鏃ユ湡銆傛潵婧? $.validEnd
+鈥?last_consume_time (DATETIME) - 鏈€杩戜竴娆′娇鐢ㄨ鍗$殑娑堣垂鏃堕棿銆傛潵婧? $.lastConsumeTime
+鈥?status (STRING) - 鍗$姸鎬併€傚鈥滄甯糕€濄€佲€滃凡杩囨湡鈥濄€佲€滃凡鎸傚け鈥濈瓑銆傛潵婧? $.status锛堣嫢涓烘暟瀛椾唬鐮佸皢鍦―WD鍏宠仈缁磋〃锛?
+鈥?activate_time (DATETIME) - 寮€鍗℃椂闂?婵€娲绘椂闂淬€傛潵婧? $.activateTime
+鈥?deactivate_time (DATETIME) - 娉ㄩ攢鏃堕棿锛堝閫傜敤锛夈€傛潵婧? $.cancelTime锛堝鏈夛級
+鈥?issuer_name (STRING) - 寮€鍗℃搷浣滃憳濮撳悕銆傛潵婧? $.issuerName锛堝鏈夛級
+鈥?issuer_id (BIGINT) - 寮€鍗℃搷浣滃憳ID銆傛潵婧? $.issuerId
+(璇存槑: 濡傛灉姣忎釜浼氬憳鍙湁涓€寮犲崱锛孫DS_MEMBER_PROFILE涓嶰DS_MEMBER_CARD璁板綍灏嗕竴涓€瀵瑰簲锛涗絾妯″瀷璁捐浠嶅尯鍒嗕袱琛紝浠ユ敮鎸佷竴浜哄鍗″満鏅€備緥濡傛湭鏉ュ彲鑳芥帹鍑轰笉鍚岀被鍨嬬殑浼氬憳鍗°€佹垨鏃у崱鏇存崲鏂板崱绛夈€侲TL浠庘€滃偍鍊煎崱鍒楄〃.json鈥濇彁鍙栦笂杩板瓧娈点€?
+member_balance_changes锛堜綑棰濆彉鏇磋褰曡〃锛?
+鎻忚堪: 瀛樺偍浼氬憳璐︽埛浣欓姣忔鍙樺姩鐨勬祦姘磋褰曘€傚寘鎷細鍛樺厖鍊笺€佹秷璐规墸娆俱€佸悗鍙拌皟鏁寸瓑瀵艰嚧鍌ㄥ€间綑棰濆鍑忕殑浜嬩欢銆?
+瀛楁瀹氫箟锛?
+鈥?id (BIGINT) - 浣欓鍙樻洿璁板綍ID锛屽敮涓€鏍囪瘑涓€娆′綑棰濆彉鍔ㄤ簨浠躲€傛潵婧怞SON璺緞: $.id
+鈥?member_id (BIGINT) - 浼氬憳璐︽埛ID銆傛湰娆′綑棰濆彉鍔ㄥ叧鑱旂殑浼氬憳锛屽紩鐢∣DS_MEMBER_PROFILE.id銆傛潵婧? $.memberId 鎴?$.member_card_id锛堟牴鎹甁SON瀛楁锛屽鍑虹幇member_card_id鍒欏搴斾細鍛樻。妗坕d锛?
+鈥?change_amount (DECIMAL(10,2)) - 鍙樺姩閲戦銆傛鏁拌〃绀鸿处鎴峰厖鍊?澧炲姞锛岃礋鏁拌〃绀烘秷璐规墸鍑忋€傚崟浣嶏細鍏冦€傛潵婧? $.change_amount锛堣嫢JSON灏嗗厖鍊间笌鎵f缁熶竴姝h礋琛ㄧず锛?
+鈥?balance_before (DECIMAL(10,2)) - 鍙樺姩鍓嶄綑棰濄€傛潵婧? $.before_balance锛堝鏈夛級
+鈥?balance_after (DECIMAL(10,2)) - 鍙樺姩鍚庝綑棰濄€傛潵婧? $.after_balance锛堝鏈夛級
+鈥?change_type (INT) - 鍙樺姩绫诲瀷浠g爜銆傜敤浜庡尯鍒嗕綑棰濆彉鍔ㄥ師鍥?鏉ユ簮锛屼緥濡?=鍏呭€笺€?=娑堣垂銆?=璋冩暣绛夈€傘€愬湪DWD灏嗗叧鑱旂淮琛ㄨ幏鍙栫被鍨嬫弿杩般€戞潵婧? $.from_type 鎴?$.type
+鈥?relate_id (BIGINT) - 鐩稿叧涓氬姟鍗曟嵁ID銆傜敤浜庡叧鑱斾骇鐢熸娆′綑棰濆彉鍔ㄧ殑涓氬姟璁板綍锛屼緥濡傚厖鍊艰褰旾D銆佽鍗曠粨绠桰D銆佸埜鏍搁攢ID绛夈€傝嫢涓?鎴栫┖琛ㄧず鏃犲搴斿崟锛堝绾悗鍙拌皟鏁达級銆傛潵婧? $.relate_id
+鈥?pay_method (INT) - 鏀粯鏂瑰紡浠g爜銆備粎鍦ㄥ厖鍊兼垨娑堣垂閫氳繃鏌愭敮浠樻笭閬撴椂鏈夋剰涔夛紝琛ㄧず姝ゆ鍙樺姩娑夊強鐨勪粯娆炬笭閬擄紙濡傜幇閲戙€佸井淇$瓑锛夈€傛潵婧? $.pay_type锛堝鏋滀綑棰濆彉鍔ㄨ褰曚腑鍖呭惈鏀粯鏂瑰紡淇℃伅锛?
+鈥?remark (STRING) - 澶囨敞淇℃伅銆傚姝ゆ浣欓鍙樻洿鐨勮鏄庢枃瀛椼€傛潵婧? $.remark锛堝鏈夛級
+鈥?operator_id (BIGINT) - 鎿嶄綔鍛業D銆傛墽琛屾娆′綑棰濆彉鍔ㄦ搷浣滅殑鍛樺伐璐﹀彿銆傛潵婧? $.operatorId
+鈥?operator_name (STRING) - 鎿嶄綔鍛樺鍚嶃€傛潵婧? $.operatorName
+鈥?change_time (DATETIME) - 鍙樺姩鏃堕棿銆傝褰曚綑棰濆疄闄呭彉鏇村彂鐢熺殑鏃堕棿銆傛潵婧? $.create_time 鎴?$.changeTime
+鈥?tenant_id (BIGINT) - 绉熸埛ID锛堝搧鐗孖D锛夛紝鏉ユ簮: $.tenant_id锛堥€氬父鍥哄畾鍊硷級
+鈥?site_id (BIGINT) - 闂ㄥ簵ID锛屾寚鏄庡彂鐢熸鍙樺姩鐨勯棬搴椼€傛潵婧? $.site_id锛堥€氬父鍥哄畾鍊硷紝浣嗛鐣欏闂ㄥ簵锛?
+鈥?is_deleted (TINYINT) - 璁板綍鏄惁琚垹闄ゆ爣蹇椼€?=姝e父锛?=宸插垹闄わ紙鍙兘鐢ㄤ簬杞垹锛夈€傛潵婧? $.is_delete 鎴?$.is_deleted锛堝鏈夛級
+(璇存槑: 閫氳繃 change_type 鍜?relate_id锛屽彲浠ュ湪DWD灞傝繘涓€姝ュ皢浣欓鍙樺姩涓庡叿浣撲笟鍔′簨瀹烇紙鍏呭€笺€佹秷璐圭粨绠楃瓑锛夊叧鑱旇捣鏉ャ€備緥濡?change_type=鍏呭€兼椂锛宺elate_id瀵瑰簲 ODS_RECHARGE.id锛沜hange_type=娑堣垂鎵f鏃讹紝relate_id瀵瑰簲 settlement_recordsMENT.id 绛夈€?
+ODS_RECHARGE_RECORD锛堝厖鍊艰褰曡〃锛?
+鎻忚堪: 瀛樺偍浼氬憳鍌ㄥ€煎崱鍏呭€肩殑璁板綍銆傛瘡鏉¤褰曡〃绀轰竴绗斾細鍛樺厖鍊硷紙澧炲€硷級浜ゆ槗锛岄€氬父瀵瑰簲浼氬憳鏀粯涓€瀹氶噾棰濆苟澧炲姞璐︽埛浣欓銆?
+瀛楁瀹氫箟锛?
+鈥?id (BIGINT) - 鍏呭€艰褰旾D锛屽敮涓€鏍囪瘑涓€绗斿厖鍊间氦鏄撱€傛潵婧怞SON璺緞: $.id
+鈥?member_id (BIGINT) - 浼氬憳璐︽埛ID锛屾寚鏄庡厖鍊煎埌璐︾殑浼氬憳銆傛潵婧? $.memberId 鎴?$.member_card_id
+鈥?recharge_amount (DECIMAL(10,2)) - 鍏呭€奸噾棰濄€備細鍛樺疄闄呮敮浠樼殑閲戦銆傚崟浣嶏細鍏冦€傛潵婧? $.amount
+鈥?bonus_amount (DECIMAL(10,2)) - 璧犻€侀噾棰濄€傝嫢鏈夊厖鍊间紭鎯犳椿鍔ㄨ禒閫佺殑棰濆閲戦銆傛潵婧? $.gift_amount 鎴?$.bonus锛堝鏈夛級
+鈥?total_amount (DECIMAL(10,2)) - 鍏呭€兼€婚銆傚嵆鍏呭€奸噾棰?+ 璧犻€侀噾棰濓紝璐︽埛瀹為檯澧炲姞鐨勪綑棰濄€傚崟浣嶏細鍏冦€傛潵婧? 鏃狅紙鍙疎TL璁$畻寰楀埌锛?
+鈥?pay_method (INT) - 鏀粯鏂瑰紡浠g爜銆備細鍛橀€氳繃浣曠娓犻亾鏀粯浜嗘娆″厖鍊奸噾棰濓紝濡?=鐜伴噾銆?=寰俊绛夈€傛潵婧? $.pay_type锛堝JSON鎻愪緵锛?
+鈥?pay_status (INT) - 鏀粯鐘舵€佷唬鐮併€傚0=鏈敮浠橈紝1=宸叉敮浠橈紝2=鏀粯瀹屾垚/鎴愬姛銆傛潵婧? $.pay_status锛堟牱鏈腑鍏呭€间竴鑸洿鎺ユ垚鍔燂級
+鈥?transaction_id (STRING) - 绗笁鏂规敮浠樻祦姘村彿銆傚閫氳繃寰俊/鏀粯瀹濆厖鍊煎搴旂殑鏀粯浜ゆ槗鍙枫€傛潵婧? $.transactionId锛堝鏈夛級
+鈥?recharge_time (DATETIME) - 鍏呭€兼椂闂淬€傛潵婧? $.create_time 鎴?$.rechargeTime
+鈥?operator_id (BIGINT) - 鎿嶄綔鍛業D銆傛墽琛屾垨鐧昏姝ゆ鍏呭€肩殑宸ヤ綔浜哄憳璐﹀彿銆傛潵婧? $.operatorId
+鈥?operator_name (STRING) - 鎿嶄綔鍛樺鍚嶃€傛潵婧? $.operatorName
+鈥?tenant_id (BIGINT) - 绉熸埛ID銆傛潵婧? $.tenant_id
+鈥?site_id (BIGINT) - 闂ㄥ簵ID銆傛潵婧? $.site_id
+(璇存槑: 鍏呭€兼垚鍔熷悗浼氬憳璐︽埛浣欓澧炲姞锛屽搴旂殑浣欓鍙樻洿璁板綍涔熶細鏈変竴鏉′笌涔嬪叧鑱斻€傞€氳繃 pay_method 鍙互鍒嗘瀽浼氬憳鍠滄鐨勫厖鍊兼笭閬撳垎甯冦€?
+ODS_PRODUCT锛堝晢鍝佹。妗堣〃锛?
+鎻忚堪: 瀛樺偍鍝佺墝绾у晢鍝佹。妗堜俊鎭€傛瘡鏉¤褰曞敮涓€鏍囪瘑涓€涓敱鎬婚儴/鍝佺墝瀹氫箟鐨勫晢鍝侊紙鍟嗗搧鍩烘湰淇℃伅锛夛紝涓嶅尯鍒嗗叿浣撻棬搴椼€傚晢鍝佸彲浠ユ槸閰掓按銆佸皬鍚冪瓑鍗栧搧锛屼篃鍙兘鍖呮嫭鏈嶅姟绫婚」鐩紙濡傛寜娆℃敹璐圭殑鏈嶅姟锛夈€?
+瀛楁瀹氫箟锛?
+鈥?goods_id (BIGINT) - 鍟嗗搧ID锛屽晢鍝佹。妗堜富閿紝鍞竴鏍囪瘑涓€涓晢鍝佸畾涔夈€傛潵婧怞SON璺緞: $.id
+鈥?tenant_id (BIGINT) - 绉熸埛ID锛堝搧鐗孖D锛夈€傚悓涓€鍝佺墝鐨勫晢鍝佸湪鍚勯棬搴楀叡浜tenant_id銆傛潵婧? $.tenant_id
+鈥?goods_name (STRING) - 鍟嗗搧鍚嶇О銆傛潵婧? $.name 鎴?$.goodsName
+鈥?goods_code (STRING) - 鍟嗗搧缂栫爜銆傜敤浜庡唴閮ㄧ鐞嗙殑缂栫爜锛屽鏉$爜鎴栬嚜瀹氫箟鐮併€傛潵婧? $.code锛堝鏈夛級
+鈥?goods_type_id (BIGINT) - 鍟嗗搧绫诲埆ID銆傚紩鐢ㄥ晢鍝佸垎绫荤淮搴︼紝渚嬪閰掓按銆佸皬鍚冦€佹湇鍔$瓑绫诲埆銆傛潵婧? $.category_id锛堝鈥滃簱瀛樺彉鍖栬褰?鈥濅腑瀹氫箟鐨勫垎绫籌D锛?
+鈥?goods_type_name (STRING) - 鍟嗗搧绫诲埆鍚嶇О銆傛潵婧? $.category_name锛堝鏈夋彁渚涳級
+鈥?unit (STRING) - 璁¢噺鍗曚綅銆傚鈥滅摱鈥濄€佲€滀唤鈥濄€佲€滃皬鏃垛€濈瓑銆傛潵婧? $.unit
+鈥?price (DECIMAL(10,2)) - 鏍囧噯鍞环銆傚搧鐗屽缓璁浂鍞环銆傛潵婧? $.price
+鈥?cost_price (DECIMAL(10,2)) - 鎴愭湰浠枫€傛潵婧? $.cost_price锛堝鏈夛級
+鈥?is_service (TINYINT) - 鏄惁鏈嶅姟绫婚」鐩爣璇嗐€?琛ㄧず鏈嶅姟锛堝璁℃椂鏀惰垂椤圭洰锛夛紝0琛ㄧず鍟嗗搧銆傛潵婧? $.is_service锛堝鍟嗗搧妗f鍖哄垎浜嗗疄鐗╀笌鏈嶅姟锛?
+鈥?status (STRING) - 鍟嗗搧鐘舵€併€傚鈥滀笂鏋垛€濄€佲€滀笅鏋垛€濄€傛潵婧? $.status锛堣嫢涓烘灇涓剧爜灏嗗湪缁磋〃鏄犲皠锛?
+鈥?created_time (DATETIME) - 鍟嗗搧妗f鍒涘缓鏃堕棿銆傛潵婧? $.create_time
+鈥?updated_time (DATETIME) - 鏈€杩戜慨鏀规椂闂淬€傛潵婧? $.update_time
+(璇存槑: 閮ㄥ垎瀛楁濡傚晢鍝佸垎绫诲彲鑳介渶瑕佷笌鍙︿竴涓狫SON锛堝簱瀛樺彉鍖栬褰?.json锛夌殑鍟嗗搧鍒嗙被鏍戝搴旓紝ODS_PRODUCT涓彲鐩存帴瀛樺垎绫籌D锛屽垎绫诲悕绉板彲鍦ㄧ淮搴﹁〃涓淮鎶や互閬垮厤閲嶅銆傚晢鍝佹。妗堜富瑕佺敤浜庢彁渚涘晢鍝佺殑鏍囧噯淇℃伅銆?
+ODS_STORE_PRODUCT锛堥棬搴楀晢鍝佹。妗堣〃锛?
+鎻忚堪: 瀛樺偍闂ㄥ簵绾у晢鍝侀厤缃紝姣忔潯璁板綍琛ㄧず鏌愰棬搴椾腑鐨勪竴绉嶅晢鍝佸強鍏惰瀹氾紙渚嬪鍞环銆佷笂涓嬫灦鐘舵€佺瓑锛夈€傚涓棬搴楀彲鍚勮嚜鏈変笉鍚岀殑鍟嗗搧鍒楄〃鎴栭厤缃€傛湰娆℃暟鎹敱浜庝粎涓€搴楋紝ODS_STORE_PRODUCT璁板綍鍗充负璇ュ簵鍟嗗搧鏄庣粏銆?
+瀛楁瀹氫箟锛?
+鈥?site_goods_id (BIGINT) - 闂ㄥ簵鍟嗗搧ID锛屽敮涓€鏍囪瘑鏌愰棬搴楃殑涓€鏉″晢鍝佽褰曘€傛潵婧怞SON璺緞: $.id锛堥棬搴楀晢鍝佹。妗圝SON涓殑涓婚敭锛?
+鈥?goods_id (BIGINT) - 鍟嗗搧ID锛堝搧鐗屽晢鍝両D锛夈€傚叧鑱擮DS_PRODUCT.goods_id锛岃〃绀烘闂ㄥ簵鍟嗗搧鎵€灞炵殑鍟嗗搧妗f瀹氫箟銆傛潵婧? $.tenant_goods_id锛堝瓧娈靛惈涔夛細绉熸埛绾у晢鍝両D锛?
+鈥?tenant_id (BIGINT) - 绉熸埛ID銆傛潵婧? $.tenant_id锛堝簲涓嶰DS_PRODUCT淇濇寔涓€鑷达級
+鈥?site_id (BIGINT) - 闂ㄥ簵ID銆傛潵婧? $.site_id
+鈥?goods_name (STRING) - 鍟嗗搧鍚嶇О銆傚湪闂ㄥ簵涓殑灞曠ず鍚嶇О锛堥€氬父涓庡搧鐗屽晢鍝佸悕涓€鑷达紝鍙湁缁嗗井宸紓锛夈€傛潵婧? $.goodsName
+鈥?category_id (BIGINT) - 鍟嗗搧鍒嗙被ID銆傛潵婧? $.goodsCategoryId
+鈥?category_name (STRING) - 鍟嗗搧鍒嗙被鍚嶇О銆傛潵婧? $.goodsCategoryName锛堝鏈夛級
+鈥?selling_price (DECIMAL(10,2)) - 闂ㄥ簵鍞崠浠枫€傛搴楀疄闄呴攢鍞鍟嗗搧鐨勫崟浠枫€傛潵婧? $.sellingPrice
+鈥?member_price (DECIMAL(10,2)) - 浼氬憳浠枫€傚瀵逛細鍛樻湁浼樻儬浠峰垯璁板綍锛屽惁鍒欏彲鑳戒笌鍞崠浠风浉鍚屻€傛潵婧? $.memberPrice锛堝鏈夊瓧娈碉級
+鈥?stock_quantity (DECIMAL(10,2)) - 褰撳墠搴撳瓨鏁伴噺銆傛潵婧? $.stock锛堝鏈夊簱瀛樺瓧娈碉級
+鈥?min_stock_alert (DECIMAL) - 搴撳瓨璀︽垝鍊笺€備綆浜庢鏁板彲鑳介渶瑕佽ˉ璐с€傛潵婧? $.minStock锛堝鏈夛級
+鈥?unit (STRING) - 璁¢噺鍗曚綅銆傛潵婧? $.unit锛堝鏈彁渚涘垯缁ф壙ODS_PRODUCT.unit锛?
+鈥?is_weighable (TINYINT) - 鏄惁绉伴噸鍟嗗搧銆?鏄О閲嶅晢鍝侊紙濡傛按鏋滄寜鏂ゅ崠锛夛紝0闈炵О閲嶃€傛潵婧? $.isWeigh锛堝鏈夛級
+鈥?status (STRING) - 涓婃灦鐘舵€併€備緥锛氣€渙n鈥濅笂鏋躲€佲€渙ff鈥濅笅鏋躲€傛潵婧? $.status
+鈥?created_time (DATETIME) - 璁板綍鍒涘缓鏃堕棿銆傛潵婧? $.create_time
+鈥?updated_time (DATETIME) - 璁板綍鏈€杩戜慨鏀规椂闂淬€傛潵婧? $.update_time
+(璇存槑: 闂ㄥ簵鍟嗗搧妗f鍦ㄥ綋鍓嶆暟鎹腑 tenant_id銆乻ite_id 鍥哄畾鍚勪竴鍊硷紝浣嗗湪妯″瀷涓繚鐣欙紝浠ユ敮鎸佸搴楀満鏅笅鍚屼竴鍟嗗搧鍦ㄤ笉鍚屽簵鏈変笉鍚宻ite_goods_id銆傚簱瀛樼浉鍏冲瓧娈靛stock_quantity鍙敤浜庡簱瀛樺垎鏋愶紝浣嗛攢鍞富棰樹腑鍙兘涓嶉噸鐐逛娇鐢ㄣ€傝嫢鏁版嵁涓嶈冻锛屾绫诲瓧娈靛彲浠ヤ繚鐣欎絾鍦‥TL鏃朵负绌恒€?
+ODS_STORE_SALE_ITEM锛堥棬搴楀晢鍝侀攢鍞褰曡〃锛?
+鎻忚堪: 瀛樺偍鍟嗗搧閿€鍞槑缁嗘祦姘达紝姣忔潯璁板綍浠h〃璁㈠崟涓敭鍑虹殑鏌愮鍟嗗搧琛岄」鐩€備篃绉颁负閿€鍞椤圭洰琛ㄣ€備緥濡備竴绗旇鍗曚拱浜?鐡堕ギ鏂欙紝鍒欐湁3鏉″搴旇褰曪紙鎴栦竴鏉¤褰曞惈鏁伴噺3锛夈€傝繖鏄攢鍞簨瀹炵殑缁嗙矑搴︽暟鎹€?
+瀛楁瀹氫箟锛?
+鈥?id (BIGINT) - 閿€鍞祦姘碔D锛屽敮涓€鏍囪瘑涓€鏉¢攢鍞槑缁嗚褰曘€傛潵婧怞SON璺緞: $.id
+鈥?order_trade_no (BIGINT) - 璁㈠崟浜ゆ槗鍙枫€傝〃绀烘閿€鍞墍灞炵殑璁㈠崟鍙凤紝鐢ㄤ簬灏嗗涓槑缁嗗綊灞炲悓涓€璁㈠崟銆傘€愪笉鍚屾ā鍧楅棿璁㈠崟浜ゆ槗鍙风浉鍚岋紝鐢ㄤ簬涓茶仈鍙拌垂銆佸晢鍝併€佸姪鏁欍€佸椁愮瓑娑堣垂鏄庣粏銆戞潵婧? $.order_trade_no
+鈥?order_settle_id (BIGINT) - 璁㈠崟缁撶畻ID銆傚搴旂粨璐﹀崟鍙风殑鍐呴儴涓婚敭銆傚鏋滆鍗曞凡缁撶畻锛屽彲鐢ㄤ簬鍏宠仈缁撹处璁板綍鎴栧皬绁ㄨ鎯呫€傛潵婧? $.order_settle_id
+鈥?site_id (BIGINT) - 闂ㄥ簵ID銆傛潵婧? $.site_id
+鈥?site_goods_id (BIGINT) - 闂ㄥ簵鍟嗗搧ID銆傛爣璇嗗崠鍑虹殑鍟嗗搧锛屽叧鑱擮DS_STORE_PRODUCT.site_goods_id鑾峰彇鍟嗗搧淇℃伅銆傛潵婧? $.site_goods_id
+鈥?goods_id (BIGINT) - 鍟嗗搧ID锛堝搧鐗屽晢鍝両D锛夈€傛柟渚跨洿鎺ュ叧鑱斿晢鍝佺淮搴︺€傛潵婧? $.tenant_goods_id锛堥€氬父涓巗ite_goods_id瀵瑰簲鐨勫搧鐗屽晢鍝両D锛?
+鈥?goods_name (STRING) - 鍟嗗搧鍚嶇О銆傞攢鍞褰曚腑鐨勫啑浣欏晢鍝佸悕銆傛潵婧? $.goodsName
+鈥?quantity (DECIMAL(10,2)) - 閿€鍞暟閲忋€傚崠鍑哄晢鍝佺殑鏁伴噺锛堟垨閲嶉噺锛夈€傛潵婧? $.quantity
+鈥?unit_price (DECIMAL(10,2)) - 鍗曚环銆傚晢鍝佸師鏈崟浠凤紝鍙兘涓烘爣鍑嗗敭浠枫€傛潵婧? $.price 鎴?$.unit_price
+鈥?discount_amount (DECIMAL(10,2)) - 鎶樻墸閲戦銆傝鏄庣粏鑾峰緱鐨勬€绘姌鎵e噺鍏嶉锛堜細鍛樻姌鎵f垨鎵嬪伐浼樻儬锛夈€傛鍊艰〃绀轰紭鎯犻噾棰濓紝0琛ㄧず鏃犳姌鎵c€傛潵婧? $.discount_money锛圝SON涓鏈夛級
+鈥?actual_amount (DECIMAL(10,2)) - 瀹炴敹閲戦銆傚嵆姝ゅ晢鍝佽瀹為檯鏀跺彇閲戦 = 鍗曚环*鏁伴噺 - 鎶樻墸閲戦銆傛潵婧? 鏃狅紙ETL璁$畻锛屾垨JSON涓凡鏈夊$.total_fee锛?
+鈥?is_gift (TINYINT) - 鏄惁璧犻€佸搧鏍囪瘑銆?琛ㄧず璇ュ晢鍝佷綔涓鸿禒鍝佹湭璁′环锛?琛ㄧず姝e父閿€鍞€傛潵婧? $.is_gift锛堝鏈夛級
+鈥?operator_id (BIGINT) - 鎿嶄綔鍛業D銆傜櫥璁?褰曞叆姝ら攢鍞殑鍛樺伐銆傛潵婧? $.operator_id
+鈥?operator_name (STRING) - 鎿嶄綔鍛樺鍚嶃€傛潵婧? $.operator_name
+鈥?sales_time (DATETIME) - 閿€鍞椂闂淬€備竴鑸彇璁㈠崟鍒涘缓鏃堕棿锛屽浜庡晢鍝佹槑缁嗙瓑鍚屼簬璁㈠崟寮€鍗曟椂闂淬€傛潵婧? $.create_time
+鈥?salesman_user_id (BIGINT) - 鎺ㄩ攢鍛樼敤鎴稩D銆傛寚濡傛湁涓氬姟鍛樻彁鎴愶紝姝ゅ瓧娈佃褰曞叧鑱旂殑閿€鍞汉鍛樿处鍙稩D銆傛潵婧? $.salesman_user_id锛堝鏈夛級
+鈥?salesman_name (STRING) - 鎺ㄩ攢鍛樺鍚嶃€傛潵婧? $.salesman_name锛堝鏈夛級
+鈥?is_refunded (TINYINT) - 鏄惁宸查€€娆炬爣蹇椼€?琛ㄧず璇ラ攢鍞悗缁湁閫€娆炬挙閿€锛?琛ㄧず姝e父銆傛潵婧? $.is_refund 鎴栨牴鎹€€娆捐褰曞湪DWD琛嶇敓銆?
+鈥?remark (STRING) - 澶囨敞銆傚璇ラ攢鍞槑缁嗙殑棰濆璇存槑銆傛潵婧? $.remark锛堝鏈夛級
+(璇存槑: 鍟嗗搧閿€鍞褰曞湪璁㈠崟绾ф眹鎬绘椂浼氭眹鍏ヨ鍗曟€婚銆傝嫢鏈夐€€娆撅紝鍙兘闇€瑕佸湪DWD灞備笌閫€娆句簨瀹炲叧鑱斾互鏍囪瘑宸查€€娆鹃」銆俤iscount_amount瀛楁缁煎悎浜嗕細鍛樻姌鎵e拰鎵嬪伐鎶樿锛岃嫢闇€鍒嗗埆鍒嗘瀽鍙湪DWD闃舵渚濇嵁瑙勫垯鎷嗗垎銆傚綋鍓峅DS鏁版嵁涓?salesm鐩稿叧瀛楁鏍锋湰涓?鎴栫┖锛屽鏃犳帹閿€鍛樺垯鐣欑┖鍗冲彲銆?
+ODS_TABLE_INFO锛堝彴妗屽垪琛ㄨ〃锛?
+鎻忚堪: 瀛樺偍鍙版淇℃伅缁村害锛屾瘡鏉¤褰曚唬琛ㄩ棬搴椾腑鐨勪竴涓彴妗?鍖呭帰銆傛瘮濡傚彴鐞冩銆並TV鍖呮埧銆侀夯灏嗘埧绛夈€傛涓哄吀鍨嬬淮琛紝涓哄悇绫绘祦姘达紙鍙拌垂銆佸姪鏁欑瓑锛夋彁渚涘彴鍙枫€佸尯鍩熺瓑闈欐€佸睘鎬с€?
+瀛楁瀹氫箟锛?
+鈥?site_table_id (BIGINT) - 鍙版ID锛屼富閿紝鍞竴鏍囪瘑涓€涓彴妗屻€傛潵婧怞SON璺緞: $.id
+鈥?tenant_id (BIGINT) - 绉熸埛ID锛堝搧鐗孖D锛夈€傛潵婧? $.tenant_id
+鈥?site_id (BIGINT) - 闂ㄥ簵ID銆傛潵婧? $.site_id
+鈥?table_name (STRING) - 鍙版鍚嶇О/缂栧彿銆備緵涓氬姟灞曠ず鐨勫悕绉帮紝濡傗€淎1鈥濄€佲€淏3鈥濄€佲€淰IP1鈥濄€佲€滄柉1鈥濓紙鏂鍏?鍙锋锛夌瓑銆傛潵婧? $.tableName 鎴栧悎鎴愯嚜鍖哄煙+缂栧彿
+鈥?table_no (STRING) - 鍙版缂栧彿锛堢函鏁板瓧閮ㄥ垎锛夈€傚鏋滄湁鍗曠嫭缂栧彿瀛楁鍒欒褰曪紝娌℃湁鍒欏彲涓巘able_name鐩稿悓銆傛潵婧? $.tableNo锛堝鏈夛級
+鈥?area_id (BIGINT) - 鍙版鍖哄煙ID銆傜敤浜庡尯鍒嗗彴妗屾墍灞炵殑鍖哄煙/鍘咃紝渚嬪A鍖恒€乂IP鍖虹瓑銆傛潵婧? $.tenant_site_region_id 鎴?$.areaId锛堝鏈夛級
+鈥?area_name (STRING) - 鍙版鍖哄煙鍚嶇О銆傚鈥淎鍖衡€濃€淰IP鍘呪€濄€傛潵婧? $.area_name 鎴栭€氳繃鍖哄煙ID鍏宠仈鑾峰緱銆?
+鈥?table_type (STRING) - 鍙版绫诲瀷銆傛爣璇嗘鍙扮敤浜庝綍绉嶉」鐩紝濡傗€滅編寮忓彴鐞冣€濄€佲€滄柉璇哄厠鈥濄€佲€淜TV鍖呮埧鈥濄€佲€滈夯灏嗘埧鈥濈瓑銆傘€愪笉鍐欐鏋氫妇锛孌WD璁捐缁磋〃銆戞潵婧? $.type 鎴栦粠鍚嶇О/閰嶇疆鎺ㄦ柇锛堜緥濡傚悕绉颁腑鈥滄柉鈥濆紑澶磋〃绀烘柉璇哄厠锛?
+鈥?is_vip (TINYINT) - VIP涓撳睘鏍囧織銆?琛ㄧず璇ュ彴涓篤IP涓撶敤锛?琛ㄧず鏅€氥€傛潵婧? 鐢卞悕绉版垨閰嶇疆锛堝鍚嶇О鍖呭惈VIP锛夌‘瀹氾紙鑻ユ簮鏁版嵁鏈夊瓧娈垫洿濂斤級
+鈥?status (STRING) - 鍙版鐘舵€併€傚鈥滃惎鐢ㄢ€濄€佲€滃仠鐢ㄢ€濄€傛潵婧? $.status锛堝鏈夋灇涓撅紝鍦ㄧ淮搴﹁〃鏄犲皠锛?
+鈥?rate (DECIMAL(10,2)) - 鍙拌垂璐圭巼銆傝嫢姣忓彴妗屽彲鑳芥湁涓嶅悓璁¤垂鍗曚环锛堟瘡灏忔椂浠锋牸锛夛紝鍒欒褰曡鍩虹璐圭巼銆傛潵婧? $.rate锛堝鏈夛級
+鈥?description (STRING) - 澶囨敞鎻忚堪銆傚鍙版鐨勯澶栬鏄庯紝濡傚寘鍘㈠ぇ灏忋€佺悆鍙拌鏍肩瓑銆傛潵婧? $.description锛堝鏈夛級
+(璇存槑: 鍙版鍒楄〃閫氬父鐩稿闈欐€侊紝ODS灞備繚瀛樼幇鏈夊彴妗岄厤缃€傝〃涓ず渚嬪€煎鈥滆懀浜嬪姙鈥濄€佲€?66鈥濊〃鏄庨儴鍒嗗彴鍙峰彲浣跨敤鑷畾涔夊懡鍚嶃€俛rea鍜宼ype绛夎嫢鏈湪JSON涓槑纭彁渚涳紝DWD灞傚彲閫氳繃缁存姢缁磋〃鎴栬鍒欒ˉ鍏ㄣ€?
+table_fee_transactions_LOG锛堝彴璐规祦姘磋〃锛?
+鎻忚堪: 璁板綍鍙版浣跨敤锛堣璐癸級娴佹按锛屾瘡鏉¤褰曞搴斾竴绗斿彴妗屼娇鐢ㄦ槑缁嗭紙閫氬父涓庝竴涓鍗曠粦瀹氾級銆傝繖鐩稿綋浜庡浜轰娇鐢ㄤ竴寮犲彴浠庡紑濮嬪埌缁撴潫鎵€浜х敓鐨勫彴璐硅处鍗曘€傚寘鍚璐瑰紑濮嬬粨鏉熸椂闂淬€佹椂闀裤€佸簲鏀惰垂鐢ㄤ互鍙婃姌鎵e噺鍏嶇瓑淇℃伅銆?
+瀛楁瀹氫箟锛?
+鈥?id (BIGINT) - 鍙拌垂娴佹按ID锛屽敮涓€鏍囪瘑涓€鏉″彴妗屼娇鐢ㄨ褰曘€傛潵婧怞SON璺緞: $.id
+鈥?order_trade_no (BIGINT) - 璁㈠崟浜ゆ槗鍙枫€傛鍙拌垂鎵€灞炶鍗曠殑缂栧彿銆傛潵婧? $.order_trade_no
+鈥?order_settle_id (BIGINT) - 璁㈠崟缁撶畻ID銆傝鍗曠粨璐﹀崟涓婚敭锛岀敤浜庡叧鑱旂粨璐?灏忕エ璇︽儏銆傛潵婧? $.order_settle_id
+鈥?site_id (BIGINT) - 闂ㄥ簵ID銆傛潵婧? $.site_id
+鈥?site_table_id (BIGINT) - 鍙版ID銆傚叧鑱擮DS_TABLE_INFO.site_table_id锛屾爣璇嗗摢寮犲彴浜х敓姝よ垂鐢ㄣ€傛潵婧? $.site_table_id
+鈥?table_name (STRING) - 鍙版鍚嶇О銆傚啑浣欏瓨鍌ㄤ究浜庣洿鎺ユ煡鐪嬨€傛潵婧? $.tableName
+鈥?start_use_time (DATETIME) - 寮€鍙版椂闂淬€傞【瀹㈠紑濮嬩娇鐢ㄨ鍙版鐨勬椂闂淬€傛潵婧? $.start_use_time
+鈥?last_use_time (DATETIME) - 缁撴潫鏃堕棿銆傞【瀹㈢粨鏉熶娇鐢?缁撹处鏃堕棿銆傛潵婧? $.last_use_time
+鈥?use_duration (INT) - 浣跨敤鏃堕暱锛屽崟浣嶇鎴栧垎閽熴€傚彲鐢卞紑濮嬬粨鏉熸椂闂磋绠楀緱鍒帮紝鎴栨簮鏁版嵁鐩存帴鎻愪緵銆傛潵婧? 璁$畻(last_use_time - start_use_time)锛屽JSON涓湁 real_table_use_seconds 鍒欑洿鎺ョ敤銆?
+鈥?billing_unit_price (DECIMAL(10,2)) - 璁¤垂鍗曚环銆備娇鐢ㄦ椂鐨勬敹璐规爣鍑嗭紙姣忓皬鏃?姣忓崐灏忔椂閲戦锛夈€傛潵婧? $.ledger_unit_price锛坙edger鍗曚环锛?
+鈥?billing_count (DECIMAL(10,2)) - 璁¤垂鏁伴噺銆傛寜璁¤垂鍗曚綅绱鐨勬暟閲忋€備緥濡傛寜灏忔椂璁¤垂鐨勬€诲皬鏃舵暟銆傛潵婧? $.ledger_count
+鈥?ledger_amount (DECIMAL(10,2)) - 鍘熷鍙拌垂閲戦銆傛牴鎹椂闀垮拰鍗曚环璁$畻鐨勬湭鎶樻墸璐圭敤銆傛潵婧? $.ledger_amount
+鈥?member_discount_amount (DECIMAL(10,2)) - 浼氬憳鎶樻墸閲戦銆傚洜浼氬憳鍗℃姌鎵e噺鍏嶇殑閲戦銆傛潵婧? $.member_discount_amount
+鈥?coupon_discount_amount (DECIMAL(10,2)) - 鍒告姷鎵i噾棰濄€備娇鐢ㄥ洟璐埜绛変績閿€鎶垫墸鐨勯噾棰濄€傛潵婧? $.coupon_promotion_amount
+鈥?manual_adjust_amount (DECIMAL(10,2)) - 鎵嬪伐璋冩暣閲戦銆傞€氳繃鍙拌垂鎵撴姌娴佹按璁板綍鐨勪汉宸ュ噺鍏嶉噾棰濓紙姝e€艰〃绀哄噺鍏嶄簡澶氬皯閽憋級銆傛潵婧? $.adjust_amount
+鈥?service_fee (DECIMAL(10,2)) - 闄勫姞鏈嶅姟璐广€傝嫢鏈夐澶栨湇鍔¤垂锛堜緥濡傚鍦烘湇鍔¤垂锛夎鍏ュ彴璐广€傛潵婧? $.mgmt_fee锛堝瓧娈垫剰涔夋帹娴嬶紝鏍锋湰涓鏈夐潪0鍊煎垯琛ㄧず闄勫姞璐癸級
+鈥?final_table_fee (DECIMAL(10,2)) - 鍙拌垂瀹炴敹閲戦銆傚嵆椤惧鏈€缁堜负璇ュ彴鏀粯鐨勮垂鐢?= ledger_amount - 鎵€鏈夋姌鎵e噺鍏?+ 闄勫姞璐广€傛潵婧? $.real_table_charge_money锛堝JSON鎻愪緵锛涘惁鍒橢TL璁$畻锛?
+鈥?member_id (BIGINT) - 浼氬憳ID銆傝嫢璇ユ寮€鍙扮粦瀹氫簡浼氬憳锛屽垯璁板綍浼氬憳璐︽埛ID锛屽惁鍒欎负绌恒€傛潵婧? $.member_id
+鈥?operator_id (BIGINT) - 鎿嶄綔鍛業D銆傚姙鐞嗗紑鍙?缁撹处鐨勫憳宸ヨ处鍙枫€傛潵婧? $.operator_id
+鈥?operator_name (STRING) - 鎿嶄綔鍛樺鍚嶃€傛潵婧? $.operator_name
+鈥?salesman_user_id (BIGINT) - 閿€鍞憳ID銆傛瘮濡傜悆鍙版湇鍔¤繃绋嬩腑鐨勮窡鍗曞憳/钀ラ攢鍛樸€傛潵婧? $.salesman_user_id
+鈥?salesman_name (STRING) - 閿€鍞憳濮撳悕銆傛潵婧? $.salesman_name
+鈥?is_single_order (TINYINT) - 鏄惁鍗曠嫭璁㈠崟鏍囧織銆?琛ㄧず姝ゅ彴浠呰璁㈠崟浣跨敤锛?琛ㄧず鍙兘鏈夎鍗曟媶鍒嗭紙鏋佸皯鎯呭喌锛夈€傛潵婧? $.is_single_order
+鈥?is_deleted (TINYINT) - 璁板綍鍒犻櫎鏍囧織銆?琛ㄧず璇ヨ褰曡浣滃簾锛堜緥濡傝鍗曞彇娑堬級锛?姝e父銆傛潵婧? $.is_delete
+(璇存槑: 鍙拌垂娴佹按琛ㄨ缁嗚褰曟瘡绗斿彴妗屼娇鐢ㄨ处鐩紝鍖呭惈鍚勭鎶樻墸鎷嗗垎锛孍TL鏃跺簲灏介噺淇濈暀杩欎簺瀛楁銆傚湪DWD姹囨€昏鍗曟椂锛宖inal_table_fee姹囨€昏繘鍏ヨ鍗曟€婚噾棰濓紱鍚勭被鎶樻墸棰濅篃鍙眹鎬荤粺璁°€俶anual_adjust_amount瀛楁瀵瑰簲鍙拌垂鎵撴姌璁板綍涓殑鎿嶄綔锛屽鏋滀负0琛ㄧず鏈仛浜哄伐鍑忓厤銆?
+ODS_TABLE_FEE_ADJUST锛堝彴璐规墦鎶樿褰曡〃锛?
+鎻忚堪: 璁板綍閽堝鍙拌垂璐﹀崟鐨勪汉宸ヨ皟鏁达紙鎵撴姌鎴栧噺鍏嶈垂鐢級琛屼负銆傛瘡鏉¤褰曡〃绀轰竴娆″鏌愯鍗曞彴璐圭殑鎵嬪伐鍑忓厤鎿嶄綔锛屽苟闈炲彴鐨勪娇鐢ㄨ褰曟湰韬紝鑰屾槸闄勫姞鐨勪竴鏉¤皟鏁存祦姘淬€傞€氬父鐢ㄤ簬璁板綍鏀堕摱鍛樼粰浜堥【瀹㈢殑鍙拌垂鎶樻墸銆?
+瀛楁瀹氫箟锛?
+鈥?id (BIGINT) - 鍙拌垂璋冩暣璁板綍ID锛屽敮涓€鏍囪瘑涓€娆″彴璐规墦鎶樻搷浣溿€傛潵婧怞SON璺緞: $.id
+鈥?order_trade_no (BIGINT) - 璁㈠崟浜ゆ槗鍙枫€傛湰璋冩暣鎵€灞炵殑璁㈠崟銆傛潵婧? $.order_trade_no
+鈥?order_settle_id (BIGINT) - 璁㈠崟缁撶畻ID銆傛湰璋冩暣鎵€灞炶鍗曠殑缁撶畻鍗旾D銆傛潵婧? $.order_settle_id
+鈥?site_id (BIGINT) - 闂ㄥ簵ID銆傛潵婧? $.site_id锛堝彲鑳介€氳繃siteProfile鑾峰彇锛?
+鈥?site_table_id (BIGINT) - 鍙版ID銆傛寚鏄庢娆¤皟鏁撮拡瀵瑰摢寮犲彴妗岀殑璐圭敤銆傛潵婧? $.site_table_id锛堝JSON鎻愪緵锛?
+鈥?table_name (STRING) - 鍙版鍚嶇О銆傛潵婧? $.tableName
+鈥?adjust_amount (DECIMAL(10,2)) - 鍑忓厤閲戦銆傛鍊艰〃绀哄噺鍏嶄簡澶氬皯閽憋紙鍗冲彴璐归檷浣庨锛夈€傛潵婧? $.adjust_fee 鎴?$.reduce_amount锛堟寜瀹為檯瀛楁锛?
+鈥?reason (STRING) - 鎵撴姌鍘熷洜銆傚鏈浜哄伐璋冩暣鐨勮鏄庯紝濡傗€滀細鍛樻姇璇夎ˉ鍋库€濇垨鈥滃簵闀跨壒鎵光€濄€傛潵婧? $.reason锛堝鏈夛級
+鈥?operator_id (BIGINT) - 鎿嶄綔鍛業D銆傛墽琛屾鎵撴姌鎿嶄綔鐨勫憳宸ヨ处鍙枫€傛潵婧? $.operator_id
+鈥?operator_name (STRING) - 鎿嶄綔鍛樺鍚嶃€傛潵婧? $.operator_name
+鈥?adjust_time (DATETIME) - 璋冩暣鏃堕棿銆傛潵婧? $.create_time
+(璇存槑: 鍙拌垂鎵撴姌璁板綍鍦∣DS_TABLE_USE_LOG涓凡鍙嶆槧涓簃anual_adjust_amount锛屼絾涓轰簡淇濈暀鎿嶄綔鍘熷洜銆佺粡鍔炰汉绛夌粏鑺傦紝ODS浠嶅瓨姝よ〃銆侱WD寤烘ā鏃讹紝鍙皢adjust_amount鍚堝苟璁″叆鍙拌垂鏈€缁堥噾棰濊绠椼€俽eason瀛楁鑻ヤ负鏈夐檺鏋氫妇锛屽彲寤虹珛缁磋〃缁存姢鍚勭鎶樻墸鍘熷洜銆?
+assistant_accounts_master锛堝姪鏁欒处鍙疯〃锛?
+鎻忚堪: 瀛樺偍闂ㄥ簵涓嬫墍鏈夊姪鏁欙紙鏁欑粌/鏈嶅姟浜哄憳锛屽寘鎷鐞嗚处鍙凤級鐨勫熀纭€閰嶇疆鍜屾。妗堜俊鎭€傛瘡鏉¤褰曞搴斾竴鍚嶅姪鏁欒处鍙凤紝灞炰簬浜轰簨缁村害琛ㄣ€傚瓧娈垫兜鐩栧姪鏁欑殑涓汉淇℃伅銆佽处鍙风姸鎬併€佽璐圭瓥鐣ョ瓑銆?
+瀛楁瀹氫箟锛?
+鈥?id (BIGINT) - 鍔╂暀璐﹀彿ID锛屼富閿€傚敮涓€鏍囪瘑涓€涓姪鏁?鍛樺伐璐﹀彿銆傚湪鍔╂暀鏈嶅姟娴佹按绛変簨瀹炶〃涓互site_assistant_id寮曠敤璇D鍏宠仈銆傛潵婧怞SON璺緞: $.id
+鈥?user_id (BIGINT) - 绯荤粺鐢ㄦ埛ID銆傚姪鏁欒处鍙峰搴旂殑绯荤粺鐧诲綍璐﹀彿ID锛岀敤浜庡湪涓嶅悓妯″潡涓嬬粺涓€璇嗗埆浜哄憳銆傚尯鍒簬宀椾綅绾х殑id銆傛潵婧? $.user_id
+鈥?assistant_no (STRING) - 鍔╂暀宸ュ彿/缂栧彿銆傜敤浜庝笟鍔¤瘑鍒殑缂栧彿锛屽彲鑳戒笉鍞竴锛堜笉鍚屽姪鏁欏彲鑳界紪鍙风浉鍚屼絾id涓嶅悓锛夈€傛潵婧? $.assistantNo
+鈥?job_num (STRING) - 鍔╂暀宸ヤ綔璇佺紪鍙枫€傚鐢ㄥ伐鍙峰瓧娈碉紝褰撳墠闂ㄥ簵鍙兘鏈娇鐢ㄣ€傛潵婧? $.job_num
+鈥?serial_number (INT) - 搴忓彿銆傜郴缁熷唴閮ㄧ敓鎴愮殑鎺掑簭鍙锋垨杩佺Щ鐢ㄧ殑搴忓垪鍊笺€傛潵婧? $.serial_number
+鈥?real_name (STRING) - 鍔╂暀鐪熷疄濮撳悕銆傛潵婧? $.real_name
+鈥?nickname (STRING) - 鍔╂暀鏄电О銆傚墠鍙板睍绀虹敤鐨勭话鍙凤紝渚嬪鈥滀匠鎬♀€濄€佲€滃懆鍛ㄢ€濄€傛潵婧? $.nickname
+鈥?gender (STRING) - 鎬у埆銆傛潵婧? $.sex锛堜緥濡傗€淢鈥?鈥淔鈥濇垨鈥滅敺鈥?鈥滃コ鈥濓級
+鈥?birthday (DATE) - 鍑虹敓鏃ユ湡銆傛潵婧? $.birthday
+鈥?mobile (STRING) - 鎵嬫満鍙枫€傚姪鏁欒仈绯绘墜鏈恒€傛潵婧? $.mobile
+鈥?id_card (STRING) - 韬唤璇佸彿銆傛潵婧? $.id_card锛堝鏈夛級
+鈥?hire_date (DATE) - 鍏ヨ亴鏃ユ湡銆傛潵婧? $.hire_date锛堝鏈夊瓧娈碉級
+鈥?resign_date (DATE) - 绂昏亴鏃ユ湡銆傚璐﹀彿宸插簾闄ゅ垯璁板綍绂昏亴鏃堕棿銆傛潵婧? $.resign_date锛堝鏈夛級
+鈥?status (STRING) - 鍦ㄨ亴鐘舵€併€傜ず渚嬶細鈥滃湪鑱屸€濄€佲€滅鑱屸€濄€佲€滃仠鐢ㄢ€濈瓑銆傛潵婧? $.status锛堣嫢婧愪负鏁板瓧锛屽湪缁磋〃鏄犲皠锛?
+鈥?visible (TINYINT) - 鍓嶅彴鍙鎬с€?琛ㄧず涓嶅湪鍓嶅彴灞曠ず锛?琛ㄧず鍙椤惧鐪嬪埌閫夋嫨銆傛潵婧? $.visible锛堝鏈夛級
+鈥?billing_mode (STRING) - 璁¤垂绛栫暐銆傚姪鏁欐湇鍔¤璐规柟寮忥紝濡傗€滄寜灏忔椂璁¤垂鈥濇垨鍥哄畾鍦烘銆傛潵婧? $.billing_mode锛堟帹娴嬪瓧娈碉紝濡傛棤鏄庣‘鍒欏彲鑳介€氳繃鍏宠仈閰嶇疆鍐冲畾锛?
+鈥?skill_name (STRING) - 鏈嶅姟鎶€鑳藉悕绉般€備緥濡傗€滃熀纭€璇锯€濃€滈檮鍔犺鈥濈瓑锛岃〃绀鸿鍔╂暀鎻愪緵鏈嶅姟鐨勭被鍒€傛潵婧? $.skillName
+鈥?skill_level (STRING) - 鎶€鑳界骇鍒?绛夌骇銆傚鈥滃垵绾р€濃€滈珮绾р€濄€傛潵婧? $.levelName 鎴?$.assistant_level
+鈥?team_id (BIGINT) - 鍔╂暀鍥㈤槦ID銆傚皢鍔╂暀鍒嗙粍鐨勫洟闃?鐝粍鏍囪瘑銆傛潵婧? $.assistant_team_id
+鈥?team_name (STRING) - 鍔╂暀鍥㈤槦鍚嶇О銆傛潵婧? $.ledger_group_name锛堢寽娴嬪搴斿洟闃熷悕绉板瓧娈碉級
+鈥?service_rate (DECIMAL(10,2)) - 鏈嶅姟璐规爣鍑嗐€傚姪鏁欐湇鍔$殑璐圭巼鎴栨彁鎴愭爣鍑嗐€傛潵婧? $.service_rate锛堝鏈夛級
+鈥?comment (STRING) - 澶囨敞銆傚叾浠栬ˉ鍏呰鏄庛€傛潵婧? $.remark锛堝鏈夛級
+鈥?tenant_id (BIGINT) - 绉熸埛ID銆傛潵婧? $.tenant_id
+鈥?site_id (BIGINT) - 闂ㄥ簵ID銆傛潵婧? $.site_id
+(璇存槑: 鍔╂暀璐﹀彿浣滀负缁磋〃锛屽皢閫氳繃id鎴杣ser_id鍏宠仈鍒板姪鏁欐湇鍔℃祦姘淬€佸姪鏁欐帓鐝瓑浜嬪疄銆傚湪褰撳墠鏁版嵁涓寘鍚鐞嗙被璐﹀彿锛寁isible瀛楁鐢ㄤ簬鎺у埗鍏舵槸鍚︽彁渚涚粰椤惧閫夋嫨鏈嶅姟銆俠illing_mode/skill绛夊喅瀹氬叾鏈嶅姟璁¤垂绫诲埆锛屼緥濡傚尯鍒嗗熀纭€璇惧拰闄勫姞璇撅紝鍦ㄥ姪鏁欐祦姘翠腑涔熸湁瀵瑰簲鏋氫妇鍊笺€?
+ODS_ASSISTANT_SERVICE_LOG锛堝姪鏁欐祦姘磋〃锛?
+鎻忚堪: 璁板綍鍔╂暀鏈嶅姟/闄粌鐨勬槑缁嗘祦姘达紝姣忔潯璁板綍浠h〃涓€娆″姪鏁欎负椤惧鎻愪緵鏈嶅姟鐨勮繃绋嬶紝閫氬父瀵瑰簲璁㈠崟涓殑涓€椤瑰姪鏁欐湇鍔℃秷璐广€傚彲鑳藉寘鍚紑濮嬬粨鏉熸椂闂淬€佹湇鍔¤垂鐢ㄣ€佸姪鏁欒瘎浠风瓑銆傝嫢涓€娆¤鍗曚腑鏇存崲鎴栧娆¤仒璇峰姪鏁欙紝浼氫骇鐢熷鏉¤褰曘€?
+瀛楁瀹氫箟锛?
+鈥?id (BIGINT) - 鍔╂暀娴佹按ID锛屽敮涓€鏍囪瘑涓€鏉″姪鏁欐湇鍔¤褰曘€傛潵婧怞SON璺緞: $.id
+鈥?order_trade_no (BIGINT) - 璁㈠崟浜ゆ槗鍙枫€傛爣璇嗘鍔╂暀鏈嶅姟鎵€灞炵殑璁㈠崟銆傛潵婧? $.order_trade_no
+鈥?order_settle_id (BIGINT) - 璁㈠崟缁撶畻ID銆傚叧鑱旂粨璐﹀崟锛岀敤浜庝笌灏忕エ璇︽儏绛夊搴斻€傘€愬綋鍓嶅鍑虹粨璐﹁褰曚负绌猴紝姝ゅ瓧娈典緷鐒朵繚鐣欑敤浜庡叧鑱斻€戞潵婧? $.order_settle_id
+鈥?order_assistant_id (BIGINT) - 璁㈠崟鍔╂暀椤笽D銆傜敤浜庡尯鍒嗗悓涓€璁㈠崟涓鏉″姪鏁欐湇鍔¢」鐨勫唴閮↖D銆傛潵婧? $.order_assistant_id
+鈥?order_assistant_type (INT) - 鍔╂暀鏈嶅姟绫诲瀷缂栫爜銆傛灇涓惧€硷紝绀轰緥锛?=甯歌鍔╂暀鏈嶅姟锛堝熀纭€璇撅級锛?=闄勫姞鍔╂暀鏈嶅姟锛堝姞璇撅級銆傚搴旂殑鍚箟鍙粠绯荤粺閰嶇疆鑾峰彇銆傘€愭ā鍨嬩腑閫氳繃缁磋〃瑙f瀽銆戞潵婧? $.order_assistant_type
+鈥?site_id (BIGINT) - 闂ㄥ簵ID銆傛潵婧? $.site_id
+鈥?site_table_id (BIGINT) - 鍙版ID銆傚姪鏁欐湇鍔℃墍鍦ㄧ殑鍙版锛屽鏁欑粌鍦ㄥ摢寮犵悆鍙版湇鍔°€傛潵婧? $.site_table_id
+鈥?table_name (STRING) - 鍙版鍚嶇О銆傛潵婧? $.tableName
+鈥?site_assistant_id (BIGINT) - 鍔╂暀ID銆傛彁渚涙湇鍔$殑鍔╂暀璐﹀彿ID锛屽叧鑱擮DS_ASSISTANT_ACCOUNT.id銆傛潵婧? $.site_assistant_id
+鈥?assistant_name (STRING) - 鍔╂暀濮撳悕銆傚啑浣欏瓧娈碉紝鏉ユ簮: $.assistantName
+鈥?assistant_no (STRING) - 鍔╂暀宸ュ彿銆傛潵婧? $.assistantNo
+鈥?skill_name (STRING) - 鏈嶅姟鎶€鑳藉悕绉般€備緥锛氣€滃熀纭€璇锯€濇垨鈥滈檮鍔犺鈥濓紝涓巓rder_assistant_type鐩稿搴斻€傛潵婧? $.skillName
+鈥?assistant_level (STRING) - 鍔╂暀绛夌骇/绾у埆銆傚鈥滃垵绾р€濃€滀腑绾р€濄€傛潵婧? $.assistant_level 鎴?$.levelName
+鈥?start_time (DATETIME) - 鏈嶅姟寮€濮嬫椂闂淬€傛潵婧? $.start_use_time
+鈥?end_time (DATETIME) - 鏈嶅姟缁撴潫鏃堕棿銆傛潵婧? $.last_use_time
+鈥?service_duration (INT) - 鏈嶅姟鏃堕暱锛堢锛夈€傛潵婧? $.income_seconds 鎴?$.real_use_seconds锛堝鏈夛級
+鈥?ledger_unit_price (DECIMAL(10,2)) - 璁¤垂鍗曚环銆傚姪鏁欐湇鍔¤垂鐜囷紙姣忓崟浣嶆椂闂磋垂鐢級銆傛潵婧? $.ledger_unit_price
+鈥?ledger_amount (DECIMAL(10,2)) - 鍘熷鏈嶅姟閲戦銆傛寜鏃堕暱鍜屽崟浠疯绠楃殑璐圭敤銆傛潵婧? $.ledger_amount
+鈥?member_discount_amount (DECIMAL(10,2)) - 浼氬憳鎶樻墸閲戦銆備細鍛樹环浼樻儬鐨勯噾棰濄€傛潵婧? $.member_discount_amount
+鈥?coupon_deduct_amount (DECIMAL(10,2)) - 鍒告姷鎵i噾棰濄€備娇鐢ㄤ績閿€鍒告姷鎵g殑閲戦銆傛潵婧? $.coupon_deduct_money
+鈥?manual_discount_amount (DECIMAL(10,2)) - 鎵嬪伐鍑忓厤閲戦銆備汉宸ョ粰浜堢殑鍑忓厤璐圭敤銆傛潵婧? $.manual_discount_amount
+鈥?final_service_fee (DECIMAL(10,2)) - 鍔╂暀鏈嶅姟瀹炴敹閲戦銆? ledger_amount - 鎶樻墸 - 鍒告姷鎵?- 鎵嬪伐鍑忓厤銆傛潵婧? $.service_money锛堟垨ETL璁$畻锛?
+鈥?member_id (BIGINT) - 浼氬憳ID銆傝嫢椤惧涓轰細鍛橈紝姝ゆ湇鍔$粦瀹氱殑浼氬憳璐﹀彿銆傛潵婧? $.tenant_member_id 鎴?$.member_id锛堟牴鎹瓧娈碉紝鏍锋湰涓彲鑳藉瓨鍦╯ystem_member_id/tenant_member_id鐢ㄤ簬鍖哄埆鍝佺墝浼氬憳锛?
+鈥?is_confirm (TINYINT) - 椤惧纭鏍囧織銆?琛ㄧず椤惧宸茬‘璁ゆ湇鍔★紙鍙兘鏈夌瀛楃‘璁ゆ祦绋嬶級锛?鏈‘璁ゃ€傛潵婧? $.is_confirm
+鈥?grade_status (TINYINT) - 璇勫垎鐘舵€併€傛爣璇嗛【瀹㈡槸鍚﹀凡瀵规湰娆℃湇鍔¤瘎鍒?璇勪环銆傛潵婧? $.grade_status
+鈥?service_grade (INT) - 鏈嶅姟鎬佸害璇勫垎銆傚彲鑳借寖鍥?-5銆傛潵婧? $.service_grade锛堝鏈夎瘎鍒嗗姛鑳斤級
+鈥?skill_grade (INT) - 鎶€鑳戒笓涓氬害璇勫垎銆傛潵婧? $.skill_grade
+鈥?sum_grade (INT) - 缁煎悎璇勫垎銆傚彲鑳芥槸骞冲潎鎴栨€诲垎銆傛潵婧? $.composite_grade
+鈥?grade_time (DATETIME) - 璇勪环鏃堕棿銆傛潵婧? $.composite_grade_time
+鈥?get_grade_times (INT) - 鑾疯瘎娆℃暟銆備篃璁歌〃绀鸿鍔╂暀琚瘎浠风殑鎬绘鏁帮紙瀛楁鎰忎箟瀛樼枒锛夈€傛潵婧? $.get_grade_times
+鈥?is_not_responding (TINYINT) - 鍔╂暀鏈搷搴旀爣蹇椼€?琛ㄧず鍔╂暀鏈強鏃跺簲绛旀湇鍔¤姹傘€傛潵婧? $.is_not_responding
+鈥?is_trash (TINYINT) - 浣滃簾鏍囧織銆?琛ㄧず璇ユ湇鍔¤褰曡搴熷純锛堝彲鑳界敱浜庡姪鏁欐洿鎹?鍙栨秷锛夛紝0姝e父銆傛潵婧? $.is_trash
+鈥?trash_reason (STRING) - 搴熼櫎鍘熷洜銆傝嫢is_trash=1锛岃褰曞彇娑堟湇鍔$殑鍘熷洜璇存槑銆傛潵婧? $.trash_reason
+鈥?trash_applicant_id (BIGINT) - 搴熼櫎鐢宠浜篒D銆傝皝鍙戣捣浜嗗彇娑堬紙椤惧鎴栧憳宸ワ級銆傛潵婧? $.trash_applicant_id
+鈥?trash_applicant_name (STRING) - 搴熼櫎鐢宠浜哄鍚嶃€傛潵婧? $.trash_applicant_name
+鈥?operator_id (BIGINT) - 鎿嶄綔鍛業D銆傜櫥璁版鏈嶅姟鐨勬搷浣滃憳璐﹀彿銆傛潵婧? $.operator_id
+鈥?operator_name (STRING) - 鎿嶄綔鍛樺鍚嶃€傛潵婧? $.operator_name
+鈥?salesman_user_id (BIGINT) - 閿€鍞憳/鎺ㄤ粙浜篒D銆傚鏈変笟鍔″憳鎺ㄨ崘姝ゆ湇鍔★紝鍒欒褰曘€傛潵婧? $.salesman_user_id
+鈥?salesman_name (STRING) - 閿€鍞憳濮撳悕銆傛潵婧? $.salesman_name
+鈥?remark (STRING) - 澶囨敞銆傞澶栬鏄庛€傛潵婧? $.remark锛堝鏈夛級
+(璇存槑: 鍔╂暀鏈嶅姟娴佹按鍖呭惈涓€浜涙湇鍔¤川閲忕浉鍏冲瓧娈碉紙璇勫垎绛夛級锛岃繖鏄秴鍑虹函娑堣垂璁¤垂鐨勫唴瀹癸紝鍙緵浜哄憳缁╂晥鍒嗘瀽銆俰s_trash=1琛ㄧず璇ヨ褰曞搴斾竴娆″姪鏁欐湇鍔¤鍙栨秷鎴栧簾闄わ紝涓庡姪鏁欏簾闄よ〃鐨勬暟鎹浉鍏炽€倀rash_reason绛夋彁渚涘彇娑堝師鍥犮€傚湪DWD灞傚彲缁撳悎鍔╂暀搴熼櫎璁板綍杩涗竴姝ュ垎鏋愩€?
-计费与废除语义说明(新增)
-助教流水记录中涉及以下与计费和废除相关的时间与金额字段(字段名以 JSON / ODS 实际字段为准):
-• real_use_seconds:本次助教服务实际发生的服务时长,单位秒。
-• income_seconds:本次助教服务中,可计入收入的服务时长,单位秒。
-o 当服务正常完成时,通常 income_seconds = real_use_seconds。
-o 当服务中途被废除时,可能只对其中一部分时间计费,此时 income_seconds <= real_use_seconds。
-• ledger_amount(或类似字段):按计划服务时长与费率计算得到的原始应收金额(不考虑废除)。
-• projected_income(或 service_money 等):本条助教服务最终计入营收的金额,已考虑会员折扣、手工减免以及废除逻辑。
-• is_trash:助教流水是否被废除的标记。
-o is_trash = 0 表示正常完成的服务。
-o is_trash = 1 表示该条助教服务被废除(可能是未开始就废除,或者中途废除)。
-废除逻辑在 ODS 层的语义约定如下:
-1. 未实际发生服务的废除:
-o 情况:顾客点了助教,但助教尚未真正服务(例如马上撤回)。
-o 表征:real_use_seconds = 0,income_seconds = 0,projected_income = 0,is_trash = 1。
-o 口径:该条记录不产生任何收入,仅作为业务流程记录存在。
-2. 已部分服务后废除:
-o 情况:助教服务了一段时间后被顾客或门店废除,例如服务 100 分钟,只按 60 分钟计费。
-o 表征:real_use_seconds > income_seconds >= 0,is_trash = 1。
-o 口径:
- 已计费部分:income_seconds 对应的金额计入 projected_income,视为有效营收。
- 未计费部分:real_use_seconds - income_seconds 对应的时间不计入营收,仅作为服务过程信息。
-3. 正常完成的服务:
-o 情况:助教服务按计划正常完成。
-o 表征:is_trash = 0,通常 income_seconds = real_use_seconds。
-o 口径:按 projected_income 全额计入营收。
-后续在 DWD / DWS 层关于“助教收入”相关指标,统一以 projected_income(或相应的实收金额字段)为准,并结合 is_trash、income_seconds 与 real_use_seconds 做口径控制,避免把未计费部分误算入营业收入。
+璁¤垂涓庡簾闄よ涔夎鏄庯紙鏂板锛?
+鍔╂暀娴佹按璁板綍涓秹鍙婁互涓嬩笌璁¤垂鍜屽簾闄ょ浉鍏崇殑鏃堕棿涓庨噾棰濆瓧娈碉紙瀛楁鍚嶄互 JSON / ODS 瀹為檯瀛楁涓哄噯锛夛細
+鈥?real_use_seconds锛氭湰娆″姪鏁欐湇鍔″疄闄呭彂鐢熺殑鏈嶅姟鏃堕暱锛屽崟浣嶇銆?
+鈥?income_seconds锛氭湰娆″姪鏁欐湇鍔′腑锛屽彲璁″叆鏀跺叆鐨勬湇鍔℃椂闀匡紝鍗曚綅绉掋€?
+o 褰撴湇鍔℃甯稿畬鎴愭椂锛岄€氬父 income_seconds = real_use_seconds銆?
+o 褰撴湇鍔′腑閫旇搴熼櫎鏃讹紝鍙兘鍙鍏朵腑涓€閮ㄥ垎鏃堕棿璁¤垂锛屾鏃?income_seconds <= real_use_seconds銆?
+鈥?ledger_amount锛堟垨绫讳技瀛楁锛夛細鎸夎鍒掓湇鍔℃椂闀夸笌璐圭巼璁$畻寰楀埌鐨勫師濮嬪簲鏀堕噾棰濓紙涓嶈€冭檻搴熼櫎锛夈€?
+鈥?projected_income锛堟垨 service_money 绛夛級锛氭湰鏉″姪鏁欐湇鍔℃渶缁堣鍏ヨ惀鏀剁殑閲戦锛屽凡鑰冭檻浼氬憳鎶樻墸銆佹墜宸ュ噺鍏嶄互鍙婂簾闄ら€昏緫銆?
+鈥?is_trash锛氬姪鏁欐祦姘存槸鍚﹁搴熼櫎鐨勬爣璁般€?
+o is_trash = 0 琛ㄧず姝e父瀹屾垚鐨勬湇鍔°€?
+o is_trash = 1 琛ㄧず璇ユ潯鍔╂暀鏈嶅姟琚簾闄わ紙鍙兘鏄湭寮€濮嬪氨搴熼櫎锛屾垨鑰呬腑閫斿簾闄わ級銆?
+搴熼櫎閫昏緫鍦?ODS 灞傜殑璇箟绾﹀畾濡備笅锛?
+1. 鏈疄闄呭彂鐢熸湇鍔$殑搴熼櫎锛?
+o 鎯呭喌锛氶【瀹㈢偣浜嗗姪鏁欙紝浣嗗姪鏁欏皻鏈湡姝f湇鍔★紙渚嬪椹笂鎾ゅ洖锛夈€?
+o 琛ㄥ緛锛歳eal_use_seconds = 0锛宨ncome_seconds = 0锛宲rojected_income = 0锛宨s_trash = 1銆?
+o 鍙e緞锛氳鏉¤褰曚笉浜х敓浠讳綍鏀跺叆锛屼粎浣滀负涓氬姟娴佺▼璁板綍瀛樺湪銆?
+2. 宸查儴鍒嗘湇鍔″悗搴熼櫎锛?
+o 鎯呭喌锛氬姪鏁欐湇鍔′簡涓€娈垫椂闂村悗琚【瀹㈡垨闂ㄥ簵搴熼櫎锛屼緥濡傛湇鍔?100 鍒嗛挓锛屽彧鎸?60 鍒嗛挓璁¤垂銆?
+o 琛ㄥ緛锛歳eal_use_seconds > income_seconds >= 0锛宨s_trash = 1銆?
+o 鍙e緞锛?
+飩?宸茶璐归儴鍒嗭細income_seconds 瀵瑰簲鐨勯噾棰濊鍏?projected_income锛岃涓烘湁鏁堣惀鏀躲€?
+飩?鏈璐归儴鍒嗭細real_use_seconds - income_seconds 瀵瑰簲鐨勬椂闂翠笉璁″叆钀ユ敹锛屼粎浣滀负鏈嶅姟杩囩▼淇℃伅銆?
+3. 姝e父瀹屾垚鐨勬湇鍔★細
+o 鎯呭喌锛氬姪鏁欐湇鍔℃寜璁″垝姝e父瀹屾垚銆?
+o 琛ㄥ緛锛歩s_trash = 0锛岄€氬父 income_seconds = real_use_seconds銆?
+o 鍙e緞锛氭寜 projected_income 鍏ㄩ璁″叆钀ユ敹銆?
+鍚庣画鍦?DWD / DWS 灞傚叧浜庘€滃姪鏁欐敹鍏モ€濈浉鍏虫寚鏍囷紝缁熶竴浠?projected_income锛堟垨鐩稿簲鐨勫疄鏀堕噾棰濆瓧娈碉級涓哄噯锛屽苟缁撳悎 is_trash銆乮ncome_seconds 涓?real_use_seconds 鍋氬彛寰勬帶鍒讹紝閬垮厤鎶婃湭璁¤垂閮ㄥ垎璇畻鍏ヨ惀涓氭敹鍏ャ€?
-ODS_ASSISTANT_CANCEL_LOG(助教废除记录表)
-描述: 记录助教服务被取消/废除的事件。每条记录对应一次助教服务未完成的情况(例如顾客要求更换助教或提前结束服务)。这些记录通常与助教服务流水的is_trash标志对应,用于详细描述废除原因和过程。
-字段定义:
-• id (BIGINT) - 助教废除记录ID,唯一标识一次助教服务取消事件。来源JSON路径: $.id
-• order_trade_no (BIGINT) - 订单交易号。被取消服务所在订单的编号。来源: $.order_trade_no
-• order_settle_id (BIGINT) - 订单结算ID。来源: $.order_settle_id
-• site_id (BIGINT) - 门店ID。来源: $.siteProfile.id(通过siteProfile对象获取)
-• site_table_id (BIGINT) - 台桌ID。此次涉及的台桌。来源: $.site_table_id
-• table_name (STRING) - 台桌名称。来源: $.tableName
-• site_assistant_id (BIGINT) - 助教ID。被取消的助教账号。来源: $.site_assistant_id
-• assistant_name (STRING) - 助教姓名。来源: $.assistantName
-• assistant_no (STRING) - 助教工号。来源: $.assistantNo
-• cancel_time (DATETIME) - 废除时间。记录服务被取消的时间。来源: $.create_time(推测为记录创建时间)
-• cancel_reason (STRING) - 废除原因描述。如“顾客不满意”、“超时未响应”等。来源: $.reason 或组装自 $.trash_reason
-• applicant_type (STRING) - 申请方类型。标识由谁发起取消,例如“customer”或“staff”。来源: 无直接字段,可能依据 $.trash_applicant_id 是否为顾客ID推断,在DWD处理。
-• applicant_name (STRING) - 取消发起人姓名。来源: $.trash_applicant_name
-• operator_id (BIGINT) - 操作员ID。处理取消的工作人员账号。来源: $.operator_id(如有)
-• operator_name (STRING) - 操作员姓名。来源: $.operator_name(如有)
-(说明: 助教废除记录与助教服务流水存在对应关系:当某助教服务被废除时,助教流水标记is_trash=1,同时产生一条废除记录说明详情。在ETL中,可利用order_trade_no和site_assistant_id将两者关联,确保不会重复计算费用(废除的服务通常不计费)。该表为业务监控服务取消情况提供数据支持。)
+ODS_ASSISTANT_CANCEL_LOG锛堝姪鏁欏簾闄よ褰曡〃锛?
+鎻忚堪: 璁板綍鍔╂暀鏈嶅姟琚彇娑?搴熼櫎鐨勪簨浠躲€傛瘡鏉¤褰曞搴斾竴娆″姪鏁欐湇鍔℃湭瀹屾垚鐨勬儏鍐碉紙渚嬪椤惧瑕佹眰鏇存崲鍔╂暀鎴栨彁鍓嶇粨鏉熸湇鍔★級銆傝繖浜涜褰曢€氬父涓庡姪鏁欐湇鍔℃祦姘寸殑is_trash鏍囧織瀵瑰簲锛岀敤浜庤缁嗘弿杩板簾闄ゅ師鍥犲拰杩囩▼銆?
+瀛楁瀹氫箟锛?
+鈥?id (BIGINT) - 鍔╂暀搴熼櫎璁板綍ID锛屽敮涓€鏍囪瘑涓€娆″姪鏁欐湇鍔″彇娑堜簨浠躲€傛潵婧怞SON璺緞: $.id
+鈥?order_trade_no (BIGINT) - 璁㈠崟浜ゆ槗鍙枫€傝鍙栨秷鏈嶅姟鎵€鍦ㄨ鍗曠殑缂栧彿銆傛潵婧? $.order_trade_no
+鈥?order_settle_id (BIGINT) - 璁㈠崟缁撶畻ID銆傛潵婧? $.order_settle_id
+鈥?site_id (BIGINT) - 闂ㄥ簵ID銆傛潵婧? $.siteProfile.id锛堥€氳繃siteProfile瀵硅薄鑾峰彇锛?
+鈥?site_table_id (BIGINT) - 鍙版ID銆傛娆℃秹鍙婄殑鍙版銆傛潵婧? $.site_table_id
+鈥?table_name (STRING) - 鍙版鍚嶇О銆傛潵婧? $.tableName
+鈥?site_assistant_id (BIGINT) - 鍔╂暀ID銆傝鍙栨秷鐨勫姪鏁欒处鍙枫€傛潵婧? $.site_assistant_id
+鈥?assistant_name (STRING) - 鍔╂暀濮撳悕銆傛潵婧? $.assistantName
+鈥?assistant_no (STRING) - 鍔╂暀宸ュ彿銆傛潵婧? $.assistantNo
+鈥?cancel_time (DATETIME) - 搴熼櫎鏃堕棿銆傝褰曟湇鍔¤鍙栨秷鐨勬椂闂淬€傛潵婧? $.create_time锛堟帹娴嬩负璁板綍鍒涘缓鏃堕棿锛?
+鈥?cancel_reason (STRING) - 搴熼櫎鍘熷洜鎻忚堪銆傚鈥滈【瀹笉婊℃剰鈥濄€佲€滆秴鏃舵湭鍝嶅簲鈥濈瓑銆傛潵婧? $.reason 鎴栫粍瑁呰嚜 $.trash_reason
+鈥?applicant_type (STRING) - 鐢宠鏂圭被鍨嬨€傛爣璇嗙敱璋佸彂璧峰彇娑堬紝渚嬪鈥渃ustomer鈥濇垨鈥渟taff鈥濄€傛潵婧? 鏃犵洿鎺ュ瓧娈碉紝鍙兘渚濇嵁 $.trash_applicant_id 鏄惁涓洪【瀹D鎺ㄦ柇锛屽湪DWD澶勭悊銆?
+鈥?applicant_name (STRING) - 鍙栨秷鍙戣捣浜哄鍚嶃€傛潵婧? $.trash_applicant_name
+鈥?operator_id (BIGINT) - 鎿嶄綔鍛業D銆傚鐞嗗彇娑堢殑宸ヤ綔浜哄憳璐﹀彿銆傛潵婧? $.operator_id锛堝鏈夛級
+鈥?operator_name (STRING) - 鎿嶄綔鍛樺鍚嶃€傛潵婧? $.operator_name锛堝鏈夛級
+(璇存槑: 鍔╂暀搴熼櫎璁板綍涓庡姪鏁欐湇鍔℃祦姘村瓨鍦ㄥ搴斿叧绯伙細褰撴煇鍔╂暀鏈嶅姟琚簾闄ゆ椂锛屽姪鏁欐祦姘存爣璁癷s_trash=1锛屽悓鏃朵骇鐢熶竴鏉″簾闄よ褰曡鏄庤鎯呫€傚湪ETL涓紝鍙埄鐢╫rder_trade_no鍜宻ite_assistant_id灏嗕袱鑰呭叧鑱旓紝纭繚涓嶄細閲嶅璁$畻璐圭敤锛堝簾闄ょ殑鏈嶅姟閫氬父涓嶈璐癸級銆傝琛ㄤ负涓氬姟鐩戞帶鏈嶅姟鍙栨秷鎯呭喌鎻愪緵鏁版嵁鏀寔銆?
-与助教流水的关联及废除口径(新增)
-助教废除记录表与助教流水表之间的关系:
-• 一条助教服务流水(助教流水表中的一条记录),在被废除时,会在助教废除表中产生一条对应记录。
-• 关联键通常包括:
-o order_trade_no(订单交易号);
-o site_assistant_id(助教ID);
-o 必要时还可结合台桌ID、时间窗口进行匹配。
-废除记录主要承担原因说明和责任归属的作用,例如:
-• trash_reason / cancel_reason:废除原因,例如“顾客更换助教”、“顾客临时离场”、“服务不满意”等。
-• trash_applicant_id / trash_applicant_name:发起废除的一方(顾客、值班经理等)。
-在计费口径上:
-• 是否计费、计多少,以助教流水中的 projected_income、income_seconds、real_use_seconds 字段为准。
-• 助教废除表本身不直接存金额,只是补充说明“为何部分原始应收未计入营业收入”。
-后续在 DWD / DWS 层进行收入分析时,出现“原始应收高于实际入账”的差异,可通过关联助教废除表查看原因分布(例如:顾客原因 vs 助教原因)。
+涓庡姪鏁欐祦姘寸殑鍏宠仈鍙婂簾闄ゅ彛寰勶紙鏂板锛?
+鍔╂暀搴熼櫎璁板綍琛ㄤ笌鍔╂暀娴佹按琛ㄤ箣闂寸殑鍏崇郴锛?
+鈥?涓€鏉″姪鏁欐湇鍔℃祦姘达紙鍔╂暀娴佹按琛ㄤ腑鐨勪竴鏉¤褰曪級锛屽湪琚簾闄ゆ椂锛屼細鍦ㄥ姪鏁欏簾闄よ〃涓骇鐢熶竴鏉″搴旇褰曘€?
+鈥?鍏宠仈閿€氬父鍖呮嫭锛?
+o order_trade_no锛堣鍗曚氦鏄撳彿锛夛紱
+o site_assistant_id锛堝姪鏁橧D锛夛紱
+o 蹇呰鏃惰繕鍙粨鍚堝彴妗孖D銆佹椂闂寸獥鍙h繘琛屽尮閰嶃€?
+搴熼櫎璁板綍涓昏鎵挎媴鍘熷洜璇存槑鍜岃矗浠诲綊灞炵殑浣滅敤锛屼緥濡傦細
+鈥?trash_reason / cancel_reason锛氬簾闄ゅ師鍥狅紝渚嬪鈥滈【瀹㈡洿鎹㈠姪鏁欌€濄€佲€滈【瀹复鏃剁鍦衡€濄€佲€滄湇鍔′笉婊℃剰鈥濈瓑銆?
+鈥?trash_applicant_id / trash_applicant_name锛氬彂璧峰簾闄ょ殑涓€鏂癸紙椤惧銆佸€肩彮缁忕悊绛夛級銆?
+鍦ㄨ璐瑰彛寰勪笂锛?
+鈥?鏄惁璁¤垂銆佽澶氬皯锛屼互鍔╂暀娴佹按涓殑 projected_income銆乮ncome_seconds銆乺eal_use_seconds 瀛楁涓哄噯銆?
+鈥?鍔╂暀搴熼櫎琛ㄦ湰韬笉鐩存帴瀛橀噾棰濓紝鍙槸琛ュ厖璇存槑鈥滀负浣曢儴鍒嗗師濮嬪簲鏀舵湭璁″叆钀ヤ笟鏀跺叆鈥濄€?
+鍚庣画鍦?DWD / DWS 灞傝繘琛屾敹鍏ュ垎鏋愭椂锛屽嚭鐜扳€滃師濮嬪簲鏀堕珮浜庡疄闄呭叆璐︹€濈殑宸紓锛屽彲閫氳繃鍏宠仈鍔╂暀搴熼櫎琛ㄦ煡鐪嬪師鍥犲垎甯冿紙渚嬪锛氶【瀹㈠師鍥?vs 鍔╂暀鍘熷洜锛夈€?
-ODS_GROUP_PACKAGE(团购套餐定义表)
-描述: 存储门店可用的团购套餐列表,即以团购形式售卖的优惠套餐的配置。每条记录定义一种团购套餐的规则,包括名称、面值、有效期、适用时段、限定台桌类型、上架状态等。
-字段定义:
-• package_id (BIGINT) - 团购套餐ID,主键。唯一标识一种套餐。来源JSON路径: $.id
-• tenant_id (BIGINT) - 租户ID。来源: $.tenant_id
-• site_id (BIGINT) - 门店ID。来源: $.site_id
-• package_name (STRING) - 套餐名称。例:“早场1小时”“斯诺克两小时”“KTV四小时”。来源: $.name
-• coupon_value (DECIMAL(10,2)) - 套餐面值。该套餐可抵扣的金额或服务时长对应的价值(通常为原价)。来源: $.coupon_money
-• selling_price (DECIMAL(10,2)) - 销售价。消费者购买此套餐所付金额(通常低于面值)。来源: $.sell_price(如有)
-• valid_from (DATE) - 套餐有效期起始日期。来源: $.start_date
-• valid_to (DATE) - 套餐有效期结束日期。来源: $.end_date
-• valid_time_period (STRING) - 每日可用时段描述。如“每日09:00-18:00可用”。来源: $.daily_time(JSON可能提供起止时间字段,此处可存文本描述或拆分字段)
-• limit_table_type (STRING) - 限定台桌类型。说明此券可用的台桌范围,例如“仅限斯诺克区”,“KTV包厢适用”。来源: $.limit_table_type(可能需要根据JSON字段组合,如限定的区域/台类型)
-• limit_table_count (INT) - 每次可用台数限制。如一个订单一次只能用一张券对应一张台。来源: $.limit_table_count(如有)
-• status (STRING) - 上架状态。示例:“active”在售,“inactive”下架,“expired”已过期。来源: $.status(若为布尔或代码,DWD将维表映射)
-• is_expired (TINYINT) - 是否已过期标志。1表示套餐已过期(当前日期超过valid_to),0尚在有效期。来源: 依据valid_to由ETL判断得到(源数据如有直接字段则使用)
-• platform (STRING) - 销售平台。指该套餐发布的平台,如“美团”、“大众点评”,如果仅门店自有则为“SELF”。来源: 如果JSON提供 platform 字段或通过dealId前缀推断,在DWD处理。
-• deal_id (STRING) - 外部平台Deal编号。对应第三方平台上的套餐ID。来源: $.dealId(如有)
-• created_time (DATETIME) - 套餐定义创建时间。来源: $.create_time
-• updated_time (DATETIME) - 最后修改时间。来源: $.update_time
-(说明: 团购套餐定义用于分析各套餐的使用和销售情况。limit_table_type等可以在DWD阶段细化为关联台桌类型维度。platform若有多个渠道,可在维表中枚举。)
-ODS_GROUP_PACKAGE_LOG(团购套餐使用流水表)
-描述: 记录团购套餐券被使用(核销)的流水。每条记录表示一张团购券在门店的一次使用,通常对应一个订单的一部分(例如使用券抵扣了特定台费时长)。包含订单信息、所用券的ID/名称、抵扣金额、以及操作员等信息。
-字段定义:
-• id (BIGINT) - 团购券使用记录ID,唯一标识一次券使用流水。来源JSON路径: $.id
-• order_trade_no (BIGINT) - 订单交易号。使用该券的订单编号。来源: $.order_trade_no
-• order_settle_id (BIGINT) - 订单结算ID。来源: $.order_settle_id
-• site_id (BIGINT) - 门店ID。来源: $.site_id
-• site_table_id (BIGINT) - 台桌ID。本券使用关联的台桌(通常券对应某张台的费用)。来源: $.site_table_id
-• table_name (STRING) - 台桌名称。来源: $.tableName
-• package_id (BIGINT) - 团购套餐ID。标识所使用券属于哪种套餐定义,关联ODS_GROUP_PACKAGE.package_id。来源: $.deal_id 或 $.package_id(根据字段含义,可能deal_id需匹配套餐定义)
-• package_name (STRING) - 套餐名称。冗余记录券名称,来源: $.deal_name 或 $.package_name(如有)
-• coupon_code (STRING) - 券码。消费者购买后收到的券编号。来源: $.coupon_code(如有)
-• deduct_amount (DECIMAL(10,2)) - 券抵扣金额。使用该券抵扣的金额价值。来源: $.deduct_money 或 $.coupon_deduct_money
-• remaining_amount (DECIMAL(10,2)) - 券剩余金额/价值。若券可部分使用,多次核销则记录剩余可用价值。来源: $.remain_money(如有)
-• status (STRING) - 券使用状态。可能统一为“used”(已核销),如有异常则标记。如源数据提供,用于确认券成功使用。来源: $.status(如全部已用可不细分)
-• used_time (DATETIME) - 券使用时间。来源: $.create_time
-• salesman_user_id (BIGINT) - 销售员ID。引导售券或核销的员工。来源: $.salesman_user_id
-• salesman_name (STRING) - 销售员姓名。来源: $.salesman_name
-• operator_id (BIGINT) - 核销操作员ID。实际在系统中操作验券的员工账号。来源: $.operator_id
-• operator_name (STRING) - 核销操作员姓名。来源: $.operator_name
-(说明: 团购套餐使用记录可以帮助分析团购券对收入的贡献。deduct_amount在订单汇总中会体现为一种折扣/预付部分。coupon_code通常对应第三方平台发放的券码,但由于还有平台验券记录表,内部记录可能未展示具体券码。package_id/名称确保可关联到套餐定义维度。)
-ODS_PLATFORM_COUPON_LOG(平台验券记录表)
-描述: 记录来自第三方平台的团购券在本门店被核销的事件。每条记录对应一次第三方券码的验证使用,携带平台相关信息和门店内部关联信息。通常与团购套餐流水存在一一对应关系。
-字段定义:
-• id (BIGINT) - 平台验券记录ID,唯一标识一次第三方券核销事件。来源JSON路径: $.id
-• platform (STRING) - 券来源平台名称。如“美团”、“大众点评”。来源: 通过$.dealId前缀或配置推断平台,在DWD映射到维表。
-• deal_id (STRING) - 平台Deal ID。对应第三方平台团购项目标识。来源: $.dealId
-• certificate_id (STRING) - 券码ID。第三方券的唯一编码。来源: $.certificateId
-• order_id (BIGINT) - 门店内部订单ID。此券关联的店内订单ID(非交易号,可能对应siteOrderId)。来源: $.orderId 或 $.order_id
-• order_trade_no (BIGINT) - 订单交易号。来源: 若JSON未直接给出,可通过内部订单ID在DWD阶段关联得到;如有字段直接提供则填入。
-• site_id (BIGINT) - 门店ID。来源: $.siteId
-• site_table_id (BIGINT) - 台桌ID。此券使用所对应的台桌。来源: $.site_table_id(如有)
-• table_name (STRING) - 台桌名称。来源: $.tableName(如有)
-• assistant_id (BIGINT) - 助教ID。如券涉及助教服务,可记录相关助教账号。来源: $.assistant_id(猜测可能没有此字段,若有则填)
-• used_time (DATETIME) - 券核销时间。来源: $.create_time
-• operator_id (BIGINT) - 核销操作员ID。来源: $.operator_id
-• operator_name (STRING) - 核销操作员姓名。来源: $.operator_name
-(说明: 平台验券记录重点在外部券信息(platform, certificate_id等)。它与内部团购套餐使用记录通过订单或券码关联,实际分析时可结合两表数据。模型中保留该表以完整记录第三方平台券的使用明细。platform字段可能不直接给出,在ETL时可依据deal_id或certificate_id编码规则判断,或通过配置表(如只有美团一种则固定为美团)。)
-ODS_PAYMENT_RECORD(支付记录表)
-描述: 存储订单支付流水,每条记录对应订单的一种付款渠道的收款情况。一笔订单可能拆分多种支付方式(如部分用会员卡余额,部分微信),则会有多条支付记录。该表反映收银端每笔实际收款。
-字段定义:
-• id (BIGINT) - 支付记录ID,唯一标识一条支付流水。来源JSON路径: $.id
-• order_trade_no (BIGINT) - 订单交易号。此支付对应的订单编号。来源: $.order_trade_no
-• order_settle_id (BIGINT) - 订单结算ID。来源: $.order_settle_id
-• pay_amount (DECIMAL(10,2)) - 支付金额。此支付流水涉及的金额。正值表示店内收款,负值(在退款记录中出现)表示店内支出。来源: $.pay_amount
-• pay_method (INT) - 支付方式代码。表示付款渠道类型,例如1=现金、2=微信、3=支付宝、4=储值卡等。【需通过维表映射具体名称】来源: $.paymentMethod 或 $.pay_type
-• pay_method_name (STRING) - 支付方式名称。可以在ODS中直接存储文字,如“微信”、“现金”(如果源直接给出了),否则在维度表中维护映射。来源: $.payTypeName(如有)
-• pay_status (INT) - 支付状态码。2表示完成,可能0/1表示处理中/失败等(本数据集中均为2完成)。来源: $.pay_status
-• transaction_id (STRING) - 外部支付流水号。第三方支付平台交易ID。来源: $.transaction_id(如有)
-• pay_time (DATETIME) - 支付时间。来源: $.pay_time 或 $.create_time
-• site_id (BIGINT) - 门店ID。来源: $.siteProfile.id(支付记录JSON带有siteProfile快照)
-• operator_id (BIGINT) - 收银操作员ID。来源: $.operator_id(如有)
-• operator_name (STRING) - 收银操作员姓名。来源: $.operator_name
-(说明: 支付记录表中的每条记录通常应对应于订单的某个支付方式实际到账金额。对账和分析各支付渠道收入时,用此表的数据。对于储值卡支付,pay_method可能对应会员卡扣款;其金额在店内不形成新资金流入,而是内部结转,但仍作为支付方式之一记录。pay_status基本都会是“完成”,额外状态可忽略或用于异常监控。)
-ODS_REFUND_RECORD(退款记录表)
-描述: 存储发生的退款流水,每条记录代表一笔退款操作(将钱退还给顾客的交易)。通常与支付记录对应,用于财务核对退款支出。
-字段定义:
-• id (BIGINT) - 退款记录ID,唯一标识一次退款交易。来源JSON路径: $.id
-• order_trade_no (BIGINT) - 订单交易号。此退款所属的原订单编号。来源: $.order_trade_no
-• order_settle_id (BIGINT) - 订单结算ID。来源: $.order_settle_id
-• refund_amount (DECIMAL(10,2)) - 退款金额。该笔退款支付给顾客的金额,通常为负值表示流出。来源: $.pay_amount(样本中均为负数)
-• pay_method (INT) - 退款渠道代码。对应原支付的渠道。来源: $.paymentMethod 或 $.pay_type(应与支付记录的code一致)
-• pay_method_name (STRING) - 退款渠道名称。来源: $.payTypeName(如有)
-• pay_status (INT) - 退款状态码。值为2表示退款完成(样本全为2),0/1可能表示未处理/处理中。来源: $.pay_status
-• original_pay_id (BIGINT) - 原支付流水ID。指明本次退款对应哪笔支付记录。来源: $.relate_pay_id 或类似字段(如有)
-• refund_time (DATETIME) - 退款时间。来源: $.create_time
-• site_id (BIGINT) - 门店ID。来源: $.site_id(通过siteProfile等)
-• operator_id (BIGINT) - 操作员ID。执行退款的员工账号。来源: $.operator_id
-• operator_name (STRING) - 操作员姓名。来源: $.operator_name
-(说明: 退款记录可用于与支付记录核对应收支平衡。在订单汇总分析时,退款通常不计入当日收入,而是冲减历史订单,因此DWS层会根据需要处理退款影响。模型中仍将退款事实表独立存储,方便查询退款总额、退款率等指标。)
-ODS_ORDER_RECEIPT_DETAIL(结账小票详情表)
-描述: 存储结算小票的完整快照,每条记录对应一张结账单(一次订单结算)。其中包含门店信息、订单整单金额汇总、会员使用情况、以及订单内各分项明细(台费、商品、券、支付)等结构化子对象。可视为对结账记录的扩展详细版。
-字段定义:
-• order_settle_id (BIGINT) - 订单结算ID,主键。唯一标识一张结算单。来源JSON路径: $.orderSettleId
-• site_id (BIGINT) - 门店ID。来源: $.data.data.siteId(通过嵌套data获取)
-• tenant_id (BIGINT) - 租户ID。来源: $.data.data.tenantId
-• site_name (STRING) - 门店名称。来源: $.data.data.shop_name
-• site_address (STRING) - 门店地址。来源: $.data.data.full_address
-• site_tel (STRING) - 门店电话。来源: $.data.data.business_tel
-• cashier_name (STRING) - 收银员姓名。小票上打印的收银员,如“收银员:张三”。来源: $.data.data.cashierName
-• member_name (STRING) - 会员姓名快照。若结账时绑定了会员,则记录会员名称,未绑定则可能显示“匿名用户”。来源: $.data.data.memberName
-• member_phone (STRING) - 会员手机号快照。来源: $.data.data.memberPhone
-• member_point (DECIMAL(10,2)) - 会员积分快照。结账时会员积分余额。来源: $.data.data.memberPoint
-• total_amount (DECIMAL(10,2)) - 订单总金额(原价总计)。即所有消费项未折扣前合计金额。来源: $.data.data.orderItem[*].price等汇总(如无直接字段则ETL计算)
-• total_discount (DECIMAL(10,2)) - 整单折扣总额。包含会员折扣和人工优惠的总和。来源: 各明细折扣之和(如无直接字段,ETL汇总计算)
-• coupon_deduct_total (DECIMAL(10,2)) - 券抵扣总额。使用团购券等抵扣的总金额。来源: $.data.data.couponItem[*].couponMoney等汇总
-• prepaid_deduct (DECIMAL(10,2)) - 会员卡储值抵扣金额。本单使用会员储值卡支付的金额。来源: $.data.data.memberDeductAmount
-• amount_receivable (DECIMAL(10,2)) - 应收金额。即扣除所有折扣券后顾客需支付的金额。来源: 计算得到(total_amount - total_discount - coupon_deduct_total)或 $.data.data.ledgerAmount
-• amount_paid (DECIMAL(10,2)) - 实收金额。顾客实际支付的金额总计(包括储值卡支付和其他支付)。来源: $.data.data.actualPayment
-• pay_method_count (INT) - 支付方式种类数。该订单使用的支付渠道数量(如用两种方式支付则为2)。来源: 支付明细count
-• pay_details (STRING) - 支付详情摘要。将各支付方式及金额拼接描述,如“微信10元+会员卡20元”。来源: 来自支付明细列表拼接(ETL组装)
-• refund_amount (DECIMAL(10,2)) - 退款金额。若该订单发生退款,则记录退款总额(一般负值)。来源: 关联退款记录计算
-• settle_time (DATETIME) - 结账时间。订单完成结算的时间。来源: $.data.data.createTime 或 $.data.data.payTime(需确认JSON字段)
-• order_items_json (JSON) - 订单商品明细JSON。嵌入原始商品列表结构,以JSON保存(包含每个商品名称、数量、价格等)。来源: $.data.data.orderItem 对象
-• table_fee_json (JSON) - 台费明细JSON。嵌入原始台费使用明细。来源: $.data.data.taiFeeItem
-• coupon_json (JSON) - 券使用明细JSON。嵌入原始券项列表。来源: $.data.data.couponItem
-• payment_json (JSON) - 支付明细JSON。嵌入原始支付列表。来源: $.data.data.paymentItem 或 $.data.data.payList
-(说明: 结账小票详情ODS表由于结构复杂,部分字段以嵌入JSON形式保存以防信息丢失,但在DWD层会拆解整合同步到相应事实表。该表主要用于核对和补充订单汇总信息。例如支付详情可以解析但此处也保留文本方便查询。total_amount、total_discount等可以ETL阶段从各子项汇总得到,以确保准确。refund_amount需结合退款表计算,因为小票详情可能不直接体现退款。此ODS表在ETL中也用于生成DWS订单汇总宽表。)
+group_buy_packages锛堝洟璐椁愬畾涔夎〃锛?
+鎻忚堪: 瀛樺偍闂ㄥ簵鍙敤鐨勫洟璐椁愬垪琛紝鍗充互鍥㈣喘褰㈠紡鍞崠鐨勪紭鎯犲椁愮殑閰嶇疆銆傛瘡鏉¤褰曞畾涔変竴绉嶅洟璐椁愮殑瑙勫垯锛屽寘鎷悕绉般€侀潰鍊笺€佹湁鏁堟湡銆侀€傜敤鏃舵銆侀檺瀹氬彴妗岀被鍨嬨€佷笂鏋剁姸鎬佺瓑銆?
+瀛楁瀹氫箟锛?
+鈥?package_id (BIGINT) - 鍥㈣喘濂楅ID锛屼富閿€傚敮涓€鏍囪瘑涓€绉嶅椁愩€傛潵婧怞SON璺緞: $.id
+鈥?tenant_id (BIGINT) - 绉熸埛ID銆傛潵婧? $.tenant_id
+鈥?site_id (BIGINT) - 闂ㄥ簵ID銆傛潵婧? $.site_id
+鈥?package_name (STRING) - 濂楅鍚嶇О銆備緥锛氣€滄棭鍦?灏忔椂鈥濃€滄柉璇哄厠涓ゅ皬鏃垛€濃€淜TV鍥涘皬鏃垛€濄€傛潵婧? $.name
+鈥?coupon_value (DECIMAL(10,2)) - 濂楅闈㈠€笺€傝濂楅鍙姷鎵g殑閲戦鎴栨湇鍔℃椂闀垮搴旂殑浠峰€硷紙閫氬父涓哄師浠凤級銆傛潵婧? $.coupon_money
+鈥?selling_price (DECIMAL(10,2)) - 閿€鍞环銆傛秷璐硅€呰喘涔版濂楅鎵€浠橀噾棰濓紙閫氬父浣庝簬闈㈠€硷級銆傛潵婧? $.sell_price锛堝鏈夛級
+鈥?valid_from (DATE) - 濂楅鏈夋晥鏈熻捣濮嬫棩鏈熴€傛潵婧? $.start_date
+鈥?valid_to (DATE) - 濂楅鏈夋晥鏈熺粨鏉熸棩鏈熴€傛潵婧? $.end_date
+鈥?valid_time_period (STRING) - 姣忔棩鍙敤鏃舵鎻忚堪銆傚鈥滄瘡鏃?9:00-18:00鍙敤鈥濄€傛潵婧? $.daily_time锛圝SON鍙兘鎻愪緵璧锋鏃堕棿瀛楁锛屾澶勫彲瀛樻枃鏈弿杩版垨鎷嗗垎瀛楁锛?
+鈥?limit_table_type (STRING) - 闄愬畾鍙版绫诲瀷銆傝鏄庢鍒稿彲鐢ㄧ殑鍙版鑼冨洿锛屼緥濡傗€滀粎闄愭柉璇哄厠鍖衡€濓紝鈥淜TV鍖呭帰閫傜敤鈥濄€傛潵婧? $.limit_table_type锛堝彲鑳介渶瑕佹牴鎹甁SON瀛楁缁勫悎锛屽闄愬畾鐨勫尯鍩?鍙扮被鍨嬶級
+鈥?limit_table_count (INT) - 姣忔鍙敤鍙版暟闄愬埗銆傚涓€涓鍗曚竴娆″彧鑳界敤涓€寮犲埜瀵瑰簲涓€寮犲彴銆傛潵婧? $.limit_table_count锛堝鏈夛級
+鈥?status (STRING) - 涓婃灦鐘舵€併€傜ず渚嬶細鈥渁ctive鈥濆湪鍞紝鈥渋nactive鈥濅笅鏋讹紝鈥渆xpired鈥濆凡杩囨湡銆傛潵婧? $.status锛堣嫢涓哄竷灏旀垨浠g爜锛孌WD灏嗙淮琛ㄦ槧灏勶級
+鈥?is_expired (TINYINT) - 鏄惁宸茶繃鏈熸爣蹇椼€?琛ㄧず濂楅宸茶繃鏈燂紙褰撳墠鏃ユ湡瓒呰繃valid_to锛夛紝0灏氬湪鏈夋晥鏈熴€傛潵婧? 渚濇嵁valid_to鐢盓TL鍒ゆ柇寰楀埌锛堟簮鏁版嵁濡傛湁鐩存帴瀛楁鍒欎娇鐢級
+鈥?platform (STRING) - 閿€鍞钩鍙般€傛寚璇ュ椁愬彂甯冪殑骞冲彴锛屽鈥滅編鍥⑩€濄€佲€滃ぇ浼楃偣璇勨€濓紝濡傛灉浠呴棬搴楄嚜鏈夊垯涓衡€淪ELF鈥濄€傛潵婧? 濡傛灉JSON鎻愪緵 platform 瀛楁鎴栭€氳繃dealId鍓嶇紑鎺ㄦ柇锛屽湪DWD澶勭悊銆?
+鈥?deal_id (STRING) - 澶栭儴骞冲彴Deal缂栧彿銆傚搴旂涓夋柟骞冲彴涓婄殑濂楅ID銆傛潵婧? $.dealId锛堝鏈夛級
+鈥?created_time (DATETIME) - 濂楅瀹氫箟鍒涘缓鏃堕棿銆傛潵婧? $.create_time
+鈥?updated_time (DATETIME) - 鏈€鍚庝慨鏀规椂闂淬€傛潵婧? $.update_time
+(璇存槑: 鍥㈣喘濂楅瀹氫箟鐢ㄤ簬鍒嗘瀽鍚勫椁愮殑浣跨敤鍜岄攢鍞儏鍐点€俵imit_table_type绛夊彲浠ュ湪DWD闃舵缁嗗寲涓哄叧鑱斿彴妗岀被鍨嬬淮搴︺€俻latform鑻ユ湁澶氫釜娓犻亾锛屽彲鍦ㄧ淮琛ㄤ腑鏋氫妇銆?
+group_buy_packages_LOG锛堝洟璐椁愪娇鐢ㄦ祦姘磋〃锛?
+鎻忚堪: 璁板綍鍥㈣喘濂楅鍒歌浣跨敤锛堟牳閿€锛夌殑娴佹按銆傛瘡鏉¤褰曡〃绀轰竴寮犲洟璐埜鍦ㄩ棬搴楃殑涓€娆′娇鐢紝閫氬父瀵瑰簲涓€涓鍗曠殑涓€閮ㄥ垎锛堜緥濡備娇鐢ㄥ埜鎶垫墸浜嗙壒瀹氬彴璐规椂闀匡級銆傚寘鍚鍗曚俊鎭€佹墍鐢ㄥ埜鐨処D/鍚嶇О銆佹姷鎵i噾棰濄€佷互鍙婃搷浣滃憳绛変俊鎭€?
+瀛楁瀹氫箟锛?
+鈥?id (BIGINT) - 鍥㈣喘鍒镐娇鐢ㄨ褰旾D锛屽敮涓€鏍囪瘑涓€娆″埜浣跨敤娴佹按銆傛潵婧怞SON璺緞: $.id
+鈥?order_trade_no (BIGINT) - 璁㈠崟浜ゆ槗鍙枫€備娇鐢ㄨ鍒哥殑璁㈠崟缂栧彿銆傛潵婧? $.order_trade_no
+鈥?order_settle_id (BIGINT) - 璁㈠崟缁撶畻ID銆傛潵婧? $.order_settle_id
+鈥?site_id (BIGINT) - 闂ㄥ簵ID銆傛潵婧? $.site_id
+鈥?site_table_id (BIGINT) - 鍙版ID銆傛湰鍒镐娇鐢ㄥ叧鑱旂殑鍙版锛堥€氬父鍒稿搴旀煇寮犲彴鐨勮垂鐢級銆傛潵婧? $.site_table_id
+鈥?table_name (STRING) - 鍙版鍚嶇О銆傛潵婧? $.tableName
+鈥?package_id (BIGINT) - 鍥㈣喘濂楅ID銆傛爣璇嗘墍浣跨敤鍒稿睘浜庡摢绉嶅椁愬畾涔夛紝鍏宠仈group_buy_packages.package_id銆傛潵婧? $.deal_id 鎴?$.package_id锛堟牴鎹瓧娈靛惈涔夛紝鍙兘deal_id闇€鍖归厤濂楅瀹氫箟锛?
+鈥?package_name (STRING) - 濂楅鍚嶇О銆傚啑浣欒褰曞埜鍚嶇О锛屾潵婧? $.deal_name 鎴?$.package_name锛堝鏈夛級
+鈥?coupon_code (STRING) - 鍒哥爜銆傛秷璐硅€呰喘涔板悗鏀跺埌鐨勫埜缂栧彿銆傛潵婧? $.coupon_code锛堝鏈夛級
+鈥?deduct_amount (DECIMAL(10,2)) - 鍒告姷鎵i噾棰濄€備娇鐢ㄨ鍒告姷鎵g殑閲戦浠峰€笺€傛潵婧? $.deduct_money 鎴?$.coupon_deduct_money
+鈥?remaining_amount (DECIMAL(10,2)) - 鍒稿墿浣欓噾棰?浠峰€笺€傝嫢鍒稿彲閮ㄥ垎浣跨敤锛屽娆℃牳閿€鍒欒褰曞墿浣欏彲鐢ㄤ环鍊笺€傛潵婧? $.remain_money锛堝鏈夛級
+鈥?status (STRING) - 鍒镐娇鐢ㄧ姸鎬併€傚彲鑳界粺涓€涓衡€渦sed鈥濓紙宸叉牳閿€锛夛紝濡傛湁寮傚父鍒欐爣璁般€傚婧愭暟鎹彁渚涳紝鐢ㄤ簬纭鍒告垚鍔熶娇鐢ㄣ€傛潵婧? $.status锛堝鍏ㄩ儴宸茬敤鍙笉缁嗗垎锛?
+鈥?used_time (DATETIME) - 鍒镐娇鐢ㄦ椂闂淬€傛潵婧? $.create_time
+鈥?salesman_user_id (BIGINT) - 閿€鍞憳ID銆傚紩瀵煎敭鍒告垨鏍搁攢鐨勫憳宸ャ€傛潵婧? $.salesman_user_id
+鈥?salesman_name (STRING) - 閿€鍞憳濮撳悕銆傛潵婧? $.salesman_name
+鈥?operator_id (BIGINT) - 鏍搁攢鎿嶄綔鍛業D銆傚疄闄呭湪绯荤粺涓搷浣滈獙鍒哥殑鍛樺伐璐﹀彿銆傛潵婧? $.operator_id
+鈥?operator_name (STRING) - 鏍搁攢鎿嶄綔鍛樺鍚嶃€傛潵婧? $.operator_name
+(璇存槑: 鍥㈣喘濂楅浣跨敤璁板綍鍙互甯姪鍒嗘瀽鍥㈣喘鍒稿鏀跺叆鐨勮础鐚€俤educt_amount鍦ㄨ鍗曟眹鎬讳腑浼氫綋鐜颁负涓€绉嶆姌鎵?棰勪粯閮ㄥ垎銆俢oupon_code閫氬父瀵瑰簲绗笁鏂瑰钩鍙板彂鏀剧殑鍒哥爜锛屼絾鐢变簬杩樻湁骞冲彴楠屽埜璁板綍琛紝鍐呴儴璁板綍鍙兘鏈睍绀哄叿浣撳埜鐮併€俻ackage_id/鍚嶇О纭繚鍙叧鑱斿埌濂楅瀹氫箟缁村害銆?
+ODS_PLATFORM_COUPON_LOG锛堝钩鍙伴獙鍒歌褰曡〃锛?
+鎻忚堪: 璁板綍鏉ヨ嚜绗笁鏂瑰钩鍙扮殑鍥㈣喘鍒稿湪鏈棬搴楄鏍搁攢鐨勪簨浠躲€傛瘡鏉¤褰曞搴斾竴娆$涓夋柟鍒哥爜鐨勯獙璇佷娇鐢紝鎼哄甫骞冲彴鐩稿叧淇℃伅鍜岄棬搴楀唴閮ㄥ叧鑱斾俊鎭€傞€氬父涓庡洟璐椁愭祦姘村瓨鍦ㄤ竴涓€瀵瑰簲鍏崇郴銆?
+瀛楁瀹氫箟锛?
+鈥?id (BIGINT) - 骞冲彴楠屽埜璁板綍ID锛屽敮涓€鏍囪瘑涓€娆$涓夋柟鍒告牳閿€浜嬩欢銆傛潵婧怞SON璺緞: $.id
+鈥?platform (STRING) - 鍒告潵婧愬钩鍙板悕绉般€傚鈥滅編鍥⑩€濄€佲€滃ぇ浼楃偣璇勨€濄€傛潵婧? 閫氳繃$.dealId鍓嶇紑鎴栭厤缃帹鏂钩鍙帮紝鍦―WD鏄犲皠鍒扮淮琛ㄣ€?
+鈥?deal_id (STRING) - 骞冲彴Deal ID銆傚搴旂涓夋柟骞冲彴鍥㈣喘椤圭洰鏍囪瘑銆傛潵婧? $.dealId
+鈥?certificate_id (STRING) - 鍒哥爜ID銆傜涓夋柟鍒哥殑鍞竴缂栫爜銆傛潵婧? $.certificateId
+鈥?order_id (BIGINT) - 闂ㄥ簵鍐呴儴璁㈠崟ID銆傛鍒稿叧鑱旂殑搴楀唴璁㈠崟ID锛堥潪浜ゆ槗鍙凤紝鍙兘瀵瑰簲siteOrderId锛夈€傛潵婧? $.orderId 鎴?$.order_id
+鈥?order_trade_no (BIGINT) - 璁㈠崟浜ゆ槗鍙枫€傛潵婧? 鑻SON鏈洿鎺ョ粰鍑猴紝鍙€氳繃鍐呴儴璁㈠崟ID鍦―WD闃舵鍏宠仈寰楀埌锛涘鏈夊瓧娈电洿鎺ユ彁渚涘垯濉叆銆?
+鈥?site_id (BIGINT) - 闂ㄥ簵ID銆傛潵婧? $.siteId
+鈥?site_table_id (BIGINT) - 鍙版ID銆傛鍒镐娇鐢ㄦ墍瀵瑰簲鐨勫彴妗屻€傛潵婧? $.site_table_id锛堝鏈夛級
+鈥?table_name (STRING) - 鍙版鍚嶇О銆傛潵婧? $.tableName锛堝鏈夛級
+鈥?assistant_id (BIGINT) - 鍔╂暀ID銆傚鍒告秹鍙婂姪鏁欐湇鍔★紝鍙褰曠浉鍏冲姪鏁欒处鍙枫€傛潵婧? $.assistant_id锛堢寽娴嬪彲鑳芥病鏈夋瀛楁锛岃嫢鏈夊垯濉級
+鈥?used_time (DATETIME) - 鍒告牳閿€鏃堕棿銆傛潵婧? $.create_time
+鈥?operator_id (BIGINT) - 鏍搁攢鎿嶄綔鍛業D銆傛潵婧? $.operator_id
+鈥?operator_name (STRING) - 鏍搁攢鎿嶄綔鍛樺鍚嶃€傛潵婧? $.operator_name
+(璇存槑: 骞冲彴楠屽埜璁板綍閲嶇偣鍦ㄥ閮ㄥ埜淇℃伅锛坧latform, certificate_id绛夛級銆傚畠涓庡唴閮ㄥ洟璐椁愪娇鐢ㄨ褰曢€氳繃璁㈠崟鎴栧埜鐮佸叧鑱旓紝瀹為檯鍒嗘瀽鏃跺彲缁撳悎涓よ〃鏁版嵁銆傛ā鍨嬩腑淇濈暀璇ヨ〃浠ュ畬鏁磋褰曠涓夋柟骞冲彴鍒哥殑浣跨敤鏄庣粏銆俻latform瀛楁鍙兘涓嶇洿鎺ョ粰鍑猴紝鍦‥TL鏃跺彲渚濇嵁deal_id鎴朿ertificate_id缂栫爜瑙勫垯鍒ゆ柇锛屾垨閫氳繃閰嶇疆琛紙濡傚彧鏈夌編鍥竴绉嶅垯鍥哄畾涓虹編鍥級銆?
+payment_transactions锛堟敮浠樿褰曡〃锛?
+鎻忚堪: 瀛樺偍璁㈠崟鏀粯娴佹按锛屾瘡鏉¤褰曞搴旇鍗曠殑涓€绉嶄粯娆炬笭閬撶殑鏀舵鎯呭喌銆備竴绗旇鍗曞彲鑳芥媶鍒嗗绉嶆敮浠樻柟寮忥紙濡傞儴鍒嗙敤浼氬憳鍗′綑棰濓紝閮ㄥ垎寰俊锛夛紝鍒欎細鏈夊鏉℃敮浠樿褰曘€傝琛ㄥ弽鏄犳敹閾剁姣忕瑪瀹為檯鏀舵銆?
+瀛楁瀹氫箟锛?
+鈥?id (BIGINT) - 鏀粯璁板綍ID锛屽敮涓€鏍囪瘑涓€鏉℃敮浠樻祦姘淬€傛潵婧怞SON璺緞: $.id
+鈥?order_trade_no (BIGINT) - 璁㈠崟浜ゆ槗鍙枫€傛鏀粯瀵瑰簲鐨勮鍗曠紪鍙枫€傛潵婧? $.order_trade_no
+鈥?order_settle_id (BIGINT) - 璁㈠崟缁撶畻ID銆傛潵婧? $.order_settle_id
+鈥?pay_amount (DECIMAL(10,2)) - 鏀粯閲戦銆傛鏀粯娴佹按娑夊強鐨勯噾棰濄€傛鍊艰〃绀哄簵鍐呮敹娆撅紝璐熷€硷紙鍦ㄩ€€娆捐褰曚腑鍑虹幇锛夎〃绀哄簵鍐呮敮鍑恒€傛潵婧? $.pay_amount
+鈥?pay_method (INT) - 鏀粯鏂瑰紡浠g爜銆傝〃绀轰粯娆炬笭閬撶被鍨嬶紝渚嬪1=鐜伴噾銆?=寰俊銆?=鏀粯瀹濄€?=鍌ㄥ€煎崱绛夈€傘€愰渶閫氳繃缁磋〃鏄犲皠鍏蜂綋鍚嶇О銆戞潵婧? $.paymentMethod 鎴?$.pay_type
+鈥?pay_method_name (STRING) - 鏀粯鏂瑰紡鍚嶇О銆傚彲浠ュ湪ODS涓洿鎺ュ瓨鍌ㄦ枃瀛楋紝濡傗€滃井淇♀€濄€佲€滅幇閲戔€濓紙濡傛灉婧愮洿鎺ョ粰鍑轰簡锛夛紝鍚﹀垯鍦ㄧ淮搴﹁〃涓淮鎶ゆ槧灏勩€傛潵婧? $.payTypeName锛堝鏈夛級
+鈥?pay_status (INT) - 鏀粯鐘舵€佺爜銆?琛ㄧず瀹屾垚锛屽彲鑳?/1琛ㄧず澶勭悊涓?澶辫触绛夛紙鏈暟鎹泦涓潎涓?瀹屾垚锛夈€傛潵婧? $.pay_status
+鈥?transaction_id (STRING) - 澶栭儴鏀粯娴佹按鍙枫€傜涓夋柟鏀粯骞冲彴浜ゆ槗ID銆傛潵婧? $.transaction_id锛堝鏈夛級
+鈥?pay_time (DATETIME) - 鏀粯鏃堕棿銆傛潵婧? $.pay_time 鎴?$.create_time
+鈥?site_id (BIGINT) - 闂ㄥ簵ID銆傛潵婧? $.siteProfile.id锛堟敮浠樿褰旿SON甯︽湁siteProfile蹇収锛?
+鈥?operator_id (BIGINT) - 鏀堕摱鎿嶄綔鍛業D銆傛潵婧? $.operator_id锛堝鏈夛級
+鈥?operator_name (STRING) - 鏀堕摱鎿嶄綔鍛樺鍚嶃€傛潵婧? $.operator_name
+(璇存槑: 鏀粯璁板綍琛ㄤ腑鐨勬瘡鏉¤褰曢€氬父搴斿搴斾簬璁㈠崟鐨勬煇涓敮浠樻柟寮忓疄闄呭埌璐﹂噾棰濄€傚璐﹀拰鍒嗘瀽鍚勬敮浠樻笭閬撴敹鍏ユ椂锛岀敤姝よ〃鐨勬暟鎹€傚浜庡偍鍊煎崱鏀粯锛宲ay_method鍙兘瀵瑰簲浼氬憳鍗℃墸娆撅紱鍏堕噾棰濆湪搴楀唴涓嶅舰鎴愭柊璧勯噾娴佸叆锛岃€屾槸鍐呴儴缁撹浆锛屼絾浠嶄綔涓烘敮浠樻柟寮忎箣涓€璁板綍銆俻ay_status鍩烘湰閮戒細鏄€滃畬鎴愨€濓紝棰濆鐘舵€佸彲蹇界暐鎴栫敤浜庡紓甯哥洃鎺с€?
+refund_transactions锛堥€€娆捐褰曡〃锛?
+鎻忚堪: 瀛樺偍鍙戠敓鐨勯€€娆炬祦姘达紝姣忔潯璁板綍浠h〃涓€绗旈€€娆炬搷浣滐紙灏嗛挶閫€杩樼粰椤惧鐨勪氦鏄擄級銆傞€氬父涓庢敮浠樿褰曞搴旓紝鐢ㄤ簬璐㈠姟鏍稿閫€娆炬敮鍑恒€?
+瀛楁瀹氫箟锛?
+鈥?id (BIGINT) - 閫€娆捐褰旾D锛屽敮涓€鏍囪瘑涓€娆¢€€娆句氦鏄撱€傛潵婧怞SON璺緞: $.id
+鈥?order_trade_no (BIGINT) - 璁㈠崟浜ゆ槗鍙枫€傛閫€娆炬墍灞炵殑鍘熻鍗曠紪鍙枫€傛潵婧? $.order_trade_no
+鈥?order_settle_id (BIGINT) - 璁㈠崟缁撶畻ID銆傛潵婧? $.order_settle_id
+鈥?refund_amount (DECIMAL(10,2)) - 閫€娆鹃噾棰濄€傝绗旈€€娆炬敮浠樼粰椤惧鐨勯噾棰濓紝閫氬父涓鸿礋鍊艰〃绀烘祦鍑恒€傛潵婧? $.pay_amount锛堟牱鏈腑鍧囦负璐熸暟锛?
+鈥?pay_method (INT) - 閫€娆炬笭閬撲唬鐮併€傚搴斿師鏀粯鐨勬笭閬撱€傛潵婧? $.paymentMethod 鎴?$.pay_type锛堝簲涓庢敮浠樿褰曠殑code涓€鑷达級
+鈥?pay_method_name (STRING) - 閫€娆炬笭閬撳悕绉般€傛潵婧? $.payTypeName锛堝鏈夛級
+鈥?pay_status (INT) - 閫€娆剧姸鎬佺爜銆傚€间负2琛ㄧず閫€娆惧畬鎴愶紙鏍锋湰鍏ㄤ负2锛夛紝0/1鍙兘琛ㄧず鏈鐞?澶勭悊涓€傛潵婧? $.pay_status
+鈥?original_pay_id (BIGINT) - 鍘熸敮浠樻祦姘碔D銆傛寚鏄庢湰娆¢€€娆惧搴斿摢绗旀敮浠樿褰曘€傛潵婧? $.relate_pay_id 鎴栫被浼煎瓧娈碉紙濡傛湁锛?
+鈥?refund_time (DATETIME) - 閫€娆炬椂闂淬€傛潵婧? $.create_time
+鈥?site_id (BIGINT) - 闂ㄥ簵ID銆傛潵婧? $.site_id锛堥€氳繃siteProfile绛夛級
+鈥?operator_id (BIGINT) - 鎿嶄綔鍛業D銆傛墽琛岄€€娆剧殑鍛樺伐璐﹀彿銆傛潵婧? $.operator_id
+鈥?operator_name (STRING) - 鎿嶄綔鍛樺鍚嶃€傛潵婧? $.operator_name
+(璇存槑: 閫€娆捐褰曞彲鐢ㄤ簬涓庢敮浠樿褰曟牳瀵瑰簲鏀舵敮骞宠 銆傚湪璁㈠崟姹囨€诲垎鏋愭椂锛岄€€娆鹃€氬父涓嶈鍏ュ綋鏃ユ敹鍏ワ紝鑰屾槸鍐插噺鍘嗗彶璁㈠崟锛屽洜姝WS灞備細鏍规嵁闇€瑕佸鐞嗛€€娆惧奖鍝嶃€傛ā鍨嬩腑浠嶅皢閫€娆句簨瀹炶〃鐙珛瀛樺偍锛屾柟渚挎煡璇㈤€€娆炬€婚銆侀€€娆剧巼绛夋寚鏍囥€?
+ODS_ORDER_RECEIPT_DETAIL锛堢粨璐﹀皬绁ㄨ鎯呰〃锛?
+鎻忚堪: 瀛樺偍缁撶畻灏忕エ鐨勫畬鏁村揩鐓э紝姣忔潯璁板綍瀵瑰簲涓€寮犵粨璐﹀崟锛堜竴娆¤鍗曠粨绠楋級銆傚叾涓寘鍚棬搴椾俊鎭€佽鍗曟暣鍗曢噾棰濇眹鎬汇€佷細鍛樹娇鐢ㄦ儏鍐点€佷互鍙婅鍗曞唴鍚勫垎椤规槑缁嗭紙鍙拌垂銆佸晢鍝併€佸埜銆佹敮浠橈級绛夌粨鏋勫寲瀛愬璞°€傚彲瑙嗕负瀵圭粨璐﹁褰曠殑鎵╁睍璇︾粏鐗堛€?
+瀛楁瀹氫箟锛?
+鈥?order_settle_id (BIGINT) - 璁㈠崟缁撶畻ID锛屼富閿€傚敮涓€鏍囪瘑涓€寮犵粨绠楀崟銆傛潵婧怞SON璺緞: $.orderSettleId
+鈥?site_id (BIGINT) - 闂ㄥ簵ID銆傛潵婧? $.data.data.siteId锛堥€氳繃宓屽data鑾峰彇锛?
+鈥?tenant_id (BIGINT) - 绉熸埛ID銆傛潵婧? $.data.data.tenantId
+鈥?site_name (STRING) - 闂ㄥ簵鍚嶇О銆傛潵婧? $.data.data.shop_name
+鈥?site_address (STRING) - 闂ㄥ簵鍦板潃銆傛潵婧? $.data.data.full_address
+鈥?site_tel (STRING) - 闂ㄥ簵鐢佃瘽銆傛潵婧? $.data.data.business_tel
+鈥?cashier_name (STRING) - 鏀堕摱鍛樺鍚嶃€傚皬绁ㄤ笂鎵撳嵃鐨勬敹閾跺憳锛屽鈥滄敹閾跺憳:寮犱笁鈥濄€傛潵婧? $.data.data.cashierName
+鈥?member_name (STRING) - 浼氬憳濮撳悕蹇収銆傝嫢缁撹处鏃剁粦瀹氫簡浼氬憳锛屽垯璁板綍浼氬憳鍚嶇О锛屾湭缁戝畾鍒欏彲鑳芥樉绀衡€滃尶鍚嶇敤鎴封€濄€傛潵婧? $.data.data.memberName
+鈥?member_phone (STRING) - 浼氬憳鎵嬫満鍙峰揩鐓с€傛潵婧? $.data.data.memberPhone
+鈥?member_point (DECIMAL(10,2)) - 浼氬憳绉垎蹇収銆傜粨璐︽椂浼氬憳绉垎浣欓銆傛潵婧? $.data.data.memberPoint
+鈥?total_amount (DECIMAL(10,2)) - 璁㈠崟鎬婚噾棰濓紙鍘熶环鎬昏锛夈€傚嵆鎵€鏈夋秷璐归」鏈姌鎵e墠鍚堣閲戦銆傛潵婧? $.data.data.orderItem[*].price绛夋眹鎬伙紙濡傛棤鐩存帴瀛楁鍒橢TL璁$畻锛?
+鈥?total_discount (DECIMAL(10,2)) - 鏁村崟鎶樻墸鎬婚銆傚寘鍚細鍛樻姌鎵e拰浜哄伐浼樻儬鐨勬€诲拰銆傛潵婧? 鍚勬槑缁嗘姌鎵d箣鍜岋紙濡傛棤鐩存帴瀛楁锛孍TL姹囨€昏绠楋級
+鈥?coupon_deduct_total (DECIMAL(10,2)) - 鍒告姷鎵f€婚銆備娇鐢ㄥ洟璐埜绛夋姷鎵g殑鎬婚噾棰濄€傛潵婧? $.data.data.couponItem[*].couponMoney绛夋眹鎬?
+鈥?prepaid_deduct (DECIMAL(10,2)) - 浼氬憳鍗″偍鍊兼姷鎵i噾棰濄€傛湰鍗曚娇鐢ㄤ細鍛樺偍鍊煎崱鏀粯鐨勯噾棰濄€傛潵婧? $.data.data.memberDeductAmount
+鈥?amount_receivable (DECIMAL(10,2)) - 搴旀敹閲戦銆傚嵆鎵i櫎鎵€鏈夋姌鎵e埜鍚庨【瀹㈤渶鏀粯鐨勯噾棰濄€傛潵婧? 璁$畻寰楀埌锛坱otal_amount - total_discount - coupon_deduct_total锛夋垨 $.data.data.ledgerAmount
+鈥?amount_paid (DECIMAL(10,2)) - 瀹炴敹閲戦銆傞【瀹㈠疄闄呮敮浠樼殑閲戦鎬昏锛堝寘鎷偍鍊煎崱鏀粯鍜屽叾浠栨敮浠橈級銆傛潵婧? $.data.data.actualPayment
+鈥?pay_method_count (INT) - 鏀粯鏂瑰紡绉嶇被鏁般€傝璁㈠崟浣跨敤鐨勬敮浠樻笭閬撴暟閲忥紙濡傜敤涓ょ鏂瑰紡鏀粯鍒欎负2锛夈€傛潵婧? 鏀粯鏄庣粏count
+鈥?pay_details (STRING) - 鏀粯璇︽儏鎽樿銆傚皢鍚勬敮浠樻柟寮忓強閲戦鎷兼帴鎻忚堪锛屽鈥滃井淇?0鍏?浼氬憳鍗?0鍏冣€濄€傛潵婧? 鏉ヨ嚜鏀粯鏄庣粏鍒楄〃鎷兼帴锛圗TL缁勮锛?
+鈥?refund_amount (DECIMAL(10,2)) - 閫€娆鹃噾棰濄€傝嫢璇ヨ鍗曞彂鐢熼€€娆撅紝鍒欒褰曢€€娆炬€婚锛堜竴鑸礋鍊硷級銆傛潵婧? 鍏宠仈閫€娆捐褰曡绠?
+鈥?settle_time (DATETIME) - 缁撹处鏃堕棿銆傝鍗曞畬鎴愮粨绠楃殑鏃堕棿銆傛潵婧? $.data.data.createTime 鎴?$.data.data.payTime锛堥渶纭JSON瀛楁锛?
+鈥?order_items_json (JSON) - 璁㈠崟鍟嗗搧鏄庣粏JSON銆傚祵鍏ュ師濮嬪晢鍝佸垪琛ㄧ粨鏋勶紝浠SON淇濆瓨锛堝寘鍚瘡涓晢鍝佸悕绉般€佹暟閲忋€佷环鏍肩瓑锛夈€傛潵婧? $.data.data.orderItem 瀵硅薄
+鈥?table_fee_json (JSON) - 鍙拌垂鏄庣粏JSON銆傚祵鍏ュ師濮嬪彴璐逛娇鐢ㄦ槑缁嗐€傛潵婧? $.data.data.taiFeeItem
+鈥?coupon_json (JSON) - 鍒镐娇鐢ㄦ槑缁咼SON銆傚祵鍏ュ師濮嬪埜椤瑰垪琛ㄣ€傛潵婧? $.data.data.couponItem
+鈥?payment_json (JSON) - 鏀粯鏄庣粏JSON銆傚祵鍏ュ師濮嬫敮浠樺垪琛ㄣ€傛潵婧? $.data.data.paymentItem 鎴?$.data.data.payList
+(璇存槑: 缁撹处灏忕エ璇︽儏ODS琛ㄧ敱浜庣粨鏋勫鏉傦紝閮ㄥ垎瀛楁浠ュ祵鍏SON褰㈠紡淇濆瓨浠ラ槻淇℃伅涓㈠け锛屼絾鍦―WD灞備細鎷嗚В鏁村悎鍚屾鍒扮浉搴斾簨瀹炶〃銆傝琛ㄤ富瑕佺敤浜庢牳瀵瑰拰琛ュ厖璁㈠崟姹囨€讳俊鎭€備緥濡傛敮浠樿鎯呭彲浠ヨВ鏋愪絾姝ゅ涔熶繚鐣欐枃鏈柟渚挎煡璇€倀otal_amount銆乼otal_discount绛夊彲浠TL闃舵浠庡悇瀛愰」姹囨€诲緱鍒帮紝浠ョ‘淇濆噯纭€俽efund_amount闇€缁撳悎閫€娆捐〃璁$畻锛屽洜涓哄皬绁ㄨ鎯呭彲鑳戒笉鐩存帴浣撶幇閫€娆俱€傛ODS琛ㄥ湪ETL涓篃鐢ㄤ簬鐢熸垚DWS璁㈠崟姹囨€诲琛ㄣ€?
________________________________________
-以上列出了主要ODS层表及字段。如有源数据新增模块,ODS层可按类似方式扩展。
-3. DWD层表定义(明细层,维度表与事实表)
-DWD层在ODS的基础上进行清洗加工,得到企业业务分析的维度表和事实表。维度表(DIM)整理主数据,如门店、会员、商品、助教等,事实表(FACT)保存业务事务明细,如销售、台费、助教服务、收款等。DWD层字段命名规范统一、含义清晰,并已剔除无效数据、关联到相应维度ID。所有枚举类字段在此层通过维表翻译或以维表ID替代,避免直接存储代码。以下分别列出维度表和明细事实表设计:
-维度表字段来源总体遵循:
-• 若维表是 ODS 同步的“主数据”(如 dim_member, dim_product, dim_table, dim_assistant),则 DWD 字段与 ODS 字段基本同名一一对应,字段级 JSON 路径以 ODS 章节为准;
-• DWD 只在以下情况增加/重命名字段:统一门店/租户主键(tenant_id, site_id)、抽取分类/团队等枚举到专门维表、增加状态描述字段等。
-可以在 PRD 中统一加一句约定,例如:
-除本章节特别注明的“衍生/重命名字段”外,所有 DWD 维度表字段均与对应 ODS 表字段同名一一映射;字段的 JSON 来源路径以 ODS 表章节定义为准,不在 DWD 重复。
+浠ヤ笂鍒楀嚭浜嗕富瑕丱DS灞傝〃鍙婂瓧娈点€傚鏈夋簮鏁版嵁鏂板妯″潡锛孫DS灞傚彲鎸夌被浼兼柟寮忔墿灞曘€?
+3. DWD灞傝〃瀹氫箟锛堟槑缁嗗眰锛岀淮搴﹁〃涓庝簨瀹炶〃锛?
+DWD灞傚湪ODS鐨勫熀纭€涓婅繘琛屾竻娲楀姞宸ワ紝寰楀埌浼佷笟涓氬姟鍒嗘瀽鐨勭淮搴﹁〃鍜屼簨瀹炶〃銆傜淮搴﹁〃锛圖IM锛夋暣鐞嗕富鏁版嵁锛屽闂ㄥ簵銆佷細鍛樸€佸晢鍝併€佸姪鏁欑瓑锛屼簨瀹炶〃锛團ACT锛変繚瀛樹笟鍔′簨鍔℃槑缁嗭紝濡傞攢鍞€佸彴璐广€佸姪鏁欐湇鍔°€佹敹娆剧瓑銆侱WD灞傚瓧娈靛懡鍚嶈鑼冪粺涓€銆佸惈涔夋竻鏅帮紝骞跺凡鍓旈櫎鏃犳晥鏁版嵁銆佸叧鑱斿埌鐩稿簲缁村害ID銆傛墍鏈夋灇涓剧被瀛楁鍦ㄦ灞傞€氳繃缁磋〃缈昏瘧鎴栦互缁磋〃ID鏇夸唬锛岄伩鍏嶇洿鎺ュ瓨鍌ㄤ唬鐮併€備互涓嬪垎鍒垪鍑虹淮搴﹁〃鍜屾槑缁嗕簨瀹炶〃璁捐锛?
+缁村害琛ㄥ瓧娈垫潵婧愭€讳綋閬靛惊锛?
+鈥?鑻ョ淮琛ㄦ槸 ODS 鍚屾鐨勨€滀富鏁版嵁鈥濓紙濡?dim_member, dim_product, dim_table, dim_assistant锛夛紝鍒?DWD 瀛楁涓?ODS 瀛楁鍩烘湰鍚屽悕涓€涓€瀵瑰簲锛屽瓧娈电骇 JSON 璺緞浠?ODS 绔犺妭涓哄噯锛?
+鈥?DWD 鍙湪浠ヤ笅鎯呭喌澧炲姞/閲嶅懡鍚嶅瓧娈碉細缁熶竴闂ㄥ簵/绉熸埛涓婚敭锛坱enant_id, site_id锛夈€佹娊鍙栧垎绫?鍥㈤槦绛夋灇涓惧埌涓撻棬缁磋〃銆佸鍔犵姸鎬佹弿杩板瓧娈电瓑銆?
+鍙互鍦?PRD 涓粺涓€鍔犱竴鍙ョ害瀹氾紝渚嬪锛?
+闄ゆ湰绔犺妭鐗瑰埆娉ㄦ槑鐨勨€滆鐢?閲嶅懡鍚嶅瓧娈碘€濆锛屾墍鏈?DWD 缁村害琛ㄥ瓧娈靛潎涓庡搴?ODS 琛ㄥ瓧娈靛悓鍚嶄竴涓€鏄犲皠锛涘瓧娈电殑 JSON 鏉ユ簮璺緞浠?ODS 琛ㄧ珷鑺傚畾涔変负鍑嗭紝涓嶅湪 DWD 閲嶅銆?
-3.1 维度表定义
-DIM_SITE(门店维度表)
- 业务定义
+3.1 缁村害琛ㄥ畾涔?
+DIM_SITE锛堥棬搴楃淮搴﹁〃锛?
+ 涓氬姟瀹氫箟
-`dim_site` 统一承载门店主数据,是所有事实表和 DWS 宽表的门店归属维度。
+`dim_site` 缁熶竴鎵胯浇闂ㄥ簵涓绘暟鎹紝鏄墍鏈変簨瀹炶〃鍜?DWS 瀹借〃鐨勯棬搴楀綊灞炵淮搴︺€?
-- 业务层面的**核心实体是门店(site)**;
-- **所有事实表、汇总表均通过 `site_id` 关联到 dim_site**;
-- 租户/品牌(tenant)信息**不再单独建维表**,仅作为 `dim_site` 的属性存在(如 `tenant_name`)。
+- 涓氬姟灞傞潰鐨?*鏍稿績瀹炰綋鏄棬搴楋紙site锛?*锛?
+- **鎵€鏈変簨瀹炶〃銆佹眹鎬昏〃鍧囬€氳繃 `site_id` 鍏宠仈鍒?dim_site**锛?
+- 绉熸埛/鍝佺墝锛坱enant锛変俊鎭?*涓嶅啀鍗曠嫭寤虹淮琛?*锛屼粎浣滀负 `dim_site` 鐨勫睘鎬у瓨鍦紙濡?`tenant_name`锛夈€?
-上游各类 JSON 中出现的 `site_id`、`siteProfile` 等门店信息,在 ODS 层以原始快照保留,在 DWD 层统一抽取到 `dim_site`,避免在事实层重复嵌入 `siteProfile` 结构。
+涓婃父鍚勭被 JSON 涓嚭鐜扮殑 `site_id`銆乣siteProfile` 绛夐棬搴椾俊鎭紝鍦?ODS 灞備互鍘熷蹇収淇濈暀锛屽湪 DWD 灞傜粺涓€鎶藉彇鍒?`dim_site`锛岄伩鍏嶅湪浜嬪疄灞傞噸澶嶅祵鍏?`siteProfile` 缁撴瀯銆?
-字段设计与 JSON 映射
+瀛楁璁捐涓?JSON 鏄犲皠
-| 字段名 | 类型 | 说明 | 典型 JSON 来源示例 |
+| 瀛楁鍚? | 绫诲瀷 | 璇存槑 | 鍏稿瀷 JSON 鏉ユ簮绀轰緥 |
|----------------|--------------------|------------------------------------------------------------|---------------------------------------------------------|
-| `site_id` | BIGINT | 门店 ID,主键 | 小票详情:`$.data.data.siteId`;
其它含 siteProfile 的 JSON 中的 `siteProfile.id` |
-| `tenant_name` | VARCHAR(200) | 品牌/租户名称,仅作为描述属性,不作为事实层关联键 | 可由配置或首个门店快照人工指定,如“朗朗桌球”等 |
-| `site_code` | VARCHAR(50) | 门店编码(如上游有单独编码,可为空) | 小票详情:`$.data.data.shop_code` 或 siteProfile 中同义字段 |
-| `site_name` | VARCHAR(200) | 门店名称 | 小票详情:`$.data.data.shop_name`;siteProfile.name |
-| `full_address` | VARCHAR(500) | 门店完整地址 | 小票详情:`$.data.data.full_address` |
-| `city_name` | VARCHAR(100) | 城市名称(可由地址或区域 ID 解析,解析不到则为空) | 由 `full_address` 或 `tenant_site_region_id` 解析 |
-| `district_name`| VARCHAR(100) | 区/县名称(可选) | 同上 |
-| `longitude` | DECIMAL(10,6) | 经度 | siteProfile:`$.longitude`(如有) |
-| `latitude` | DECIMAL(10,6) | 纬度 | siteProfile:`$.latitude`(如有) |
-| `business_tel` | VARCHAR(50) | 门店电话 | 小票详情:`$.data.data.business_tel` |
-| `open_date` | DATE | 开店日期(如无则为空,后续可人工维护) | 无直接字段时由业务侧补录 |
-| `status` | VARCHAR(50) | 门店状态:营业中 / 停业 / 筹备等 | 如上游有门店状态配置则映射;当前可默认“营业中” |
-| `org_id` | BIGINT | 组织/区域 ID(如有,如租户侧的区域树) | siteProfile:`$.tenant_site_region_id` 或 `$.org_id` |
-| `remark` | VARCHAR(500) | 备注 | 数仓侧维护 |
-| `created_at` | TIMESTAMP | 记录创建时间(数仓) | 数仓 ETL 生成 |
-| `updated_at` | TIMESTAMP | 记录最后更新时间(数仓) | 数仓 ETL 生成 |
+| `site_id` | BIGINT | 闂ㄥ簵 ID锛屼富閿? | 灏忕エ璇︽儏锛歚$.data.data.siteId`锛?br>鍏跺畠鍚?siteProfile 鐨?JSON 涓殑 `siteProfile.id` |
+| `tenant_name` | VARCHAR(200) | 鍝佺墝/绉熸埛鍚嶇О锛屼粎浣滀负鎻忚堪灞炴€э紝涓嶄綔涓轰簨瀹炲眰鍏宠仈閿? | 鍙敱閰嶇疆鎴栭涓棬搴楀揩鐓т汉宸ユ寚瀹氾紝濡傗€滄湕鏈楁鐞冣€濈瓑 |
+| `site_code` | VARCHAR(50) | 闂ㄥ簵缂栫爜锛堝涓婃父鏈夊崟鐙紪鐮侊紝鍙负绌猴級 | 灏忕エ璇︽儏锛歚$.data.data.shop_code` 鎴?siteProfile 涓悓涔夊瓧娈?|
+| `site_name` | VARCHAR(200) | 闂ㄥ簵鍚嶇О | 灏忕エ璇︽儏锛歚$.data.data.shop_name`锛泂iteProfile.name |
+| `full_address` | VARCHAR(500) | 闂ㄥ簵瀹屾暣鍦板潃 | 灏忕エ璇︽儏锛歚$.data.data.full_address` |
+| `city_name` | VARCHAR(100) | 鍩庡競鍚嶇О锛堝彲鐢卞湴鍧€鎴栧尯鍩?ID 瑙f瀽锛岃В鏋愪笉鍒板垯涓虹┖锛? | 鐢?`full_address` 鎴?`tenant_site_region_id` 瑙f瀽 |
+| `district_name`| VARCHAR(100) | 鍖?鍘垮悕绉帮紙鍙€夛級 | 鍚屼笂 |
+| `longitude` | DECIMAL(10,6) | 缁忓害 | siteProfile锛歚$.longitude`锛堝鏈夛級 |
+| `latitude` | DECIMAL(10,6) | 绾害 | siteProfile锛歚$.latitude`锛堝鏈夛級 |
+| `business_tel` | VARCHAR(50) | 闂ㄥ簵鐢佃瘽 | 灏忕エ璇︽儏锛歚$.data.data.business_tel` |
+| `open_date` | DATE | 寮€搴楁棩鏈燂紙濡傛棤鍒欎负绌猴紝鍚庣画鍙汉宸ョ淮鎶わ級 | 鏃犵洿鎺ュ瓧娈垫椂鐢变笟鍔′晶琛ュ綍 |
+| `status` | VARCHAR(50) | 闂ㄥ簵鐘舵€侊細钀ヤ笟涓?/ 鍋滀笟 / 绛瑰绛? | 濡備笂娓告湁闂ㄥ簵鐘舵€侀厤缃垯鏄犲皠锛涘綋鍓嶅彲榛樿鈥滆惀涓氫腑鈥? |
+| `org_id` | BIGINT | 缁勭粐/鍖哄煙 ID锛堝鏈夛紝濡傜鎴蜂晶鐨勫尯鍩熸爲锛? | siteProfile锛歚$.tenant_site_region_id` 鎴?`$.org_id` |
+| `remark` | VARCHAR(500) | 澶囨敞 | 鏁颁粨渚х淮鎶? |
+| `created_at` | TIMESTAMP | 璁板綍鍒涘缓鏃堕棿锛堟暟浠擄級 | 鏁颁粨 ETL 鐢熸垚 |
+| `updated_at` | TIMESTAMP | 璁板綍鏈€鍚庢洿鏂版椂闂达紙鏁颁粨锛? | 鏁颁粨 ETL 鐢熸垚 |
-> 说明:
-> - 上游 JSON 中的 `tenant_id` 在 DWD 层**不再用于建模关联**,如有需要可在 DIM_SITE 增加一个 `tenant_code` 字段作为纯描述/对照用;
-> - 任何品牌/租户维度分析,统一通过:`site_id -> dim_site.tenant_name` 实现。
+> 璇存槑锛?
+> - 涓婃父 JSON 涓殑 `tenant_id` 鍦?DWD 灞?*涓嶅啀鐢ㄤ簬寤烘ā鍏宠仈**锛屽鏈夐渶瑕佸彲鍦?DIM_SITE 澧炲姞涓€涓?`tenant_code` 瀛楁浣滀负绾弿杩?瀵圭収鐢紱
+> - 浠讳綍鍝佺墝/绉熸埛缁村害鍒嗘瀽锛岀粺涓€閫氳繃锛歚site_id -> dim_site.tenant_name` 瀹炵幇銆?
-#### 建表 SQL 草案(PostgreSQL)
+#### 寤鸿〃 SQL 鑽夋锛圥ostgreSQL锛?
```sql
CREATE TABLE dim_site (
- site_id BIGINT PRIMARY KEY, -- 门店ID,对应各业务表中的 site_id
- tenant_name VARCHAR(200) NOT NULL, -- 品牌/租户名称,仅作为属性
- site_code VARCHAR(50), -- 门店编码(选填)
- site_name VARCHAR(200) NOT NULL, -- 门店名称
- full_address VARCHAR(500), -- 完整地址
- city_name VARCHAR(100), -- 城市
- district_name VARCHAR(100), -- 区/县
- longitude DECIMAL(10,6), -- 经度
- latitude DECIMAL(10,6), -- 纬度
- business_tel VARCHAR(50), -- 门店电话
- open_date DATE, -- 开店日期(可为空)
- status VARCHAR(50) DEFAULT '营业中', -- 门店状态(默认营业中)
- org_id BIGINT, -- 组织/区域ID(如有)
- remark VARCHAR(500), -- 备注
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- 记录创建时间(数仓)
- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- 记录更新时间(数仓)
+ site_id BIGINT PRIMARY KEY, -- 闂ㄥ簵ID锛屽搴斿悇涓氬姟琛ㄤ腑鐨?site_id
+ tenant_name VARCHAR(200) NOT NULL, -- 鍝佺墝/绉熸埛鍚嶇О锛屼粎浣滀负灞炴€?
+ site_code VARCHAR(50), -- 闂ㄥ簵缂栫爜锛堥€夊~锛?
+ site_name VARCHAR(200) NOT NULL, -- 闂ㄥ簵鍚嶇О
+ full_address VARCHAR(500), -- 瀹屾暣鍦板潃
+ city_name VARCHAR(100), -- 鍩庡競
+ district_name VARCHAR(100), -- 鍖?鍘?
+ longitude DECIMAL(10,6), -- 缁忓害
+ latitude DECIMAL(10,6), -- 绾害
+ business_tel VARCHAR(50), -- 闂ㄥ簵鐢佃瘽
+ open_date DATE, -- 寮€搴楁棩鏈燂紙鍙负绌猴級
+ status VARCHAR(50) DEFAULT '钀ヤ笟涓?, -- 闂ㄥ簵鐘舵€侊紙榛樿钀ヤ笟涓級
+ org_id BIGINT, -- 缁勭粐/鍖哄煙ID锛堝鏈夛級
+ remark VARCHAR(500), -- 澶囨敞
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- 璁板綍鍒涘缓鏃堕棿锛堟暟浠擄級
+ updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP -- 璁板綍鏇存柊鏃堕棿锛堟暟浠擄級
);
-COMMENT ON TABLE dim_site IS '门店维度表,统一存放门店主数据,支持多门店扩展;租户/品牌信息仅作为属性存在';
+COMMENT ON TABLE dim_site IS '闂ㄥ簵缁村害琛紝缁熶竴瀛樻斁闂ㄥ簵涓绘暟鎹紝鏀寔澶氶棬搴楁墿灞曪紱绉熸埛/鍝佺墝淇℃伅浠呬綔涓哄睘鎬у瓨鍦?;
-COMMENT ON COLUMN dim_site.site_id IS '门店ID,上游各JSON中的site_id统一映射到此';
-COMMENT ON COLUMN dim_site.tenant_name IS '品牌/租户名称,仅作为描述属性,事实表不直接关联租户维';
-COMMENT ON COLUMN dim_site.site_code IS '门店编码(如上游有单独编码,可为空)';
-COMMENT ON COLUMN dim_site.site_name IS '门店名称';
-COMMENT ON COLUMN dim_site.full_address IS '门店完整地址';
-COMMENT ON COLUMN dim_site.city_name IS '城市名称';
-COMMENT ON COLUMN dim_site.district_name IS '区/县名称';
-COMMENT ON COLUMN dim_site.longitude IS '经度';
-COMMENT ON COLUMN dim_site.latitude IS '纬度';
-COMMENT ON COLUMN dim_site.business_tel IS '门店电话';
-COMMENT ON COLUMN dim_site.open_date IS '开店日期';
-COMMENT ON COLUMN dim_site.status IS '门店状态:营业中/停业/筹备等';
-COMMENT ON COLUMN dim_site.org_id IS '门店所属组织/区域ID(如上游有tenant_site_region_id)';
-COMMENT ON COLUMN dim_site.remark IS '备注';
-COMMENT ON COLUMN dim_site.created_at IS '记录创建时间(数仓侧)';
-COMMENT ON COLUMN dim_site.updated_at IS '记录最后更新时间(数仓侧)';
-DIM_MEMBER(会员维度表)
-描述: 会员维度,记录会员个人及账户属性。将ODS会员档案和会员卡信息合并,提供完整会员画像。
-主键: member_id(会员账户ID)
-字段:
-• member_id (BIGINT) - 会员ID,主键。对应ODS_MEMBER_PROFILE.id。
-• member_name (STRING) - 会员姓名。来自ODS_MEMBER_PROFILE.real_name,如为空则用昵称代替。
-• nickname (STRING) - 会员昵称。
-• gender (STRING) - 性别(“男”/“女”)。由ODS_MEMBER_PROFILE.gender代码翻译得到。
-• birthday (DATE) - 出生日期。
-• mobile (STRING) - 手机号码。
-• member_type_id (BIGINT) - 会员卡类型ID,外键参照DIM_MEMBER_CARD_TYPE.card_type_id。
-• member_type_name (STRING) - 会员卡类型名称。如“储值卡”、“银卡”、“金卡”等。
-• status (STRING) - 会员状态。翻译ODS_MEMBER_PROFILE.status枚举,如“正常”、“停用”。
-• register_time (DATETIME) - 注册时间/开卡时间。
-• valid_from (DATE) - 会员卡有效期开始。
-• valid_to (DATE) - 会员卡有效期截止。
-• last_visit_time (DATETIME) - 最近消费时间。
-• balance (DECIMAL(10,2)) - 当前储值余额(元)。
-• total_recharge_amount (DECIMAL(10,2)) - 历史充值总额(元)。(可以在ETL初始化时计算或后续累计)
-• total_consumed_amount (DECIMAL(10,2)) - 历史消费总额(储值部分,元)。
-• wechat_id (STRING) - 绑定微信号ID。
-• alipay_id (STRING) - 绑定支付宝号ID。
-• remark (STRING) - 备注。
-(来源: 主要来自ODS_MEMBER_PROFILE字段,member_type相关则结合ODS_MEMBER_CARD或配置表确定。如卡类型和有效期从ODS_MEMBER_CARD提取。余额取ODS_MEMBER_PROFILE.balance,但在分析中更可靠的是通过余额变更流水计算,这里保留一个快照值。充值/消费总额可在ETL或BI层通过事实表汇总得到,不一定在维表存储。初始可不填或通过历史计算更新。DIM_MEMBER与事实表关联时,通过member_id连接。)
-DIM_MEMBER_CARD_TYPE(会员卡类型维度表)
-描述: 会员卡种类维度。描述各种会员卡级别或类型的定义属性,例如名称、折扣、权益。避免在模型中硬编码会员卡枚举。
-主键: card_type_id
-字段:
-• card_type_id (BIGINT) - 卡种ID,主键。
-• card_type_name (STRING) - 卡种名称。
-• discount_rate (DECIMAL(5,2)) - 默认折扣率。如0.90表示打九折。
-• description (STRING) - 卡种描述/权益说明。
-• remark (STRING) - 备注。
-(来源: 结合业务配置。当前可从ODS_MEMBER_CARD中汇总不同card_type_id及名称,填充进此维表,例如储值卡一类,次卡另一类等,并记录其折扣规则。如无更多信息可暂存空描述,由业务补充。)
-DIM_PRODUCT(商品维度表)
-描述: 商品维度,描述品牌商品的属性。由ODS_PRODUCT清洗而来,并关联商品类别等信息。
-主键: goods_id
-字段:
-• goods_id (BIGINT) - 商品ID,主键。
-• goods_name (STRING) - 商品名称。
-• goods_code (STRING) - 商品编码。
-• category_id (BIGINT) - 商品类别ID,外键参照DIM_PRODUCT_CATEGORY.category_id。
-• category_name (STRING) - 商品类别名称。
-• unit (STRING) - 计量单位。
-• is_service (TINYINT) - 是否服务类商品(1服务/0商品)。
-• status (STRING) - 商品状态(“上架”/“下架”)。
-• site_id (BIGINT) – 门店ID。
-(来源: ODS_PRODUCT,去除不需要分析的字段,仅保留核心属性。category_id对应DIM_PRODUCT_CATEGORY以获得类别名称。status由代码转成文本。site_id为了链路完整也存储。)
-DIM_PRODUCT_CATEGORY(商品类别维度表)
-描述: 商品分类维度。存储商品的类别层次信息,如大类、子类名称,用于按品类分析销售。
-主键: category_id
-字段:
-• category_id (BIGINT) - 分类ID,主键。
-• category_name (STRING) - 分类名称。
-• parent_category_id (BIGINT) - 父类别ID(如有上下级)。
-• parent_category_name (STRING) - 父类别名称。
-• is_active (TINYINT) - 是否在用(1是/0否)。
-(来源: 库存变化记录2.json 中解析 goodsCategoryList 获取。由于库存变化记录2实际是一份商品分类配置树,其每条记录为一个分类节点。ETL需遍历提取category_id、name和parent_id构建维表。分类层级关系可用于按大类/小类汇总销售。当前数据所有分类 is_warehousing=1 表示参与库存管理,均可视为有效分类。)
-DIM_TABLE(台桌维度表)
-描述: 台桌维度,描述门店内各台桌/包厢的属性,如编号、区域、类型等。由ODS_TABLE_INFO加工得到。
-主键: site_table_id
-字段:
-• site_table_id (BIGINT) - 台桌ID,主键。
-• table_name (STRING) - 台桌名称。
-• table_no (STRING) - 台桌编号(纯数字序号,如有的话)。
-• area_name (STRING) - 区域名称。
-• table_type (STRING) - 台桌类型(例如“美式桌”、“斯诺克桌”、“KTV包间”、“麻将房”)。
-• is_vip (TINYINT) - 是否VIP专属台。
-• status (STRING) - 台桌状态(“启用”/“停用”)。
-• site_id (BIGINT) - 门店ID。
-(来源: 主要字段来自ODS_TABLE_INFO,area_name和table_type可能需要结合配置或名称规则填充。例如 area_name 通过ODS_TABLE_INFO.area_id关联门店区域配置表(如果有)获取名称,没有则从table_name解析。table_type可基于table_name中关键字映射,如含“斯”字的为斯诺克桌,在维表中统一管理映射关系避免硬编码。)
-DIM_ASSISTANT(助教维度表)
-描述: 助教(服务人员)维度,记录员工/助教的属性。由ODS_ASSISTANT_ACCOUNT清洗得到,包括其个人信息和状态等。
-主键: assistant_id
-字段:
-• assistant_id (BIGINT) - 助教ID(账号ID),主键。
-• user_id (BIGINT) - 系统用户ID(登录账号ID)。
-• assistant_no (STRING) - 助教工号。
-• real_name (STRING) - 助教姓名。
-• nickname (STRING) - 助教昵称。
-• gender (STRING) - 性别。
-• mobile (STRING) - 手机号。
-• status (STRING) - 在职状态(“在职”/“离职”等)。
-• visible_flag (TINYINT) - 前台可见标志(1展示/0隐藏)。
-• skill_category (STRING) - 服务技能类别。比如“基础课教练”、“高级课教练”等,对应其主要服务类型。
-• level (STRING) - 助教等级。
-• team_name (STRING) - 所属团队/班组名称。
-• billing_mode (STRING) - 计费模式(按小时/按场次等)。
-• site_id (BIGINT) - 门店ID。
-(来源: ODS_ASSISTANT_ACCOUNT字段整理,剔除不必要字段如serial_number等。status由码表转换为文本。skill_category可基于助教具备的技能类型确定,例如若助教有基础课技能则标为“基础课教练”;如一个助教账号有多种服务类型,可以填写主要类型或“多技能”。团队名称team_name若ODS没有可通过assistant_team_id关联TEAM维表获取。)
-DIM_ASSISTANT_TEAM(助教团队维度表)
-描述: 助教团队/组织维度。如果有将助教划分团队或部门的需求,则建立此维表。当前数据有assistant_team_id但未给名称,可后续补充。
-主键: team_id
-字段:
-• team_id (BIGINT) - 团队ID,主键。
-• team_name (STRING) - 团队名称。
-• site_id (BIGINT) - 门店ID/组织归属ID。
-• remark (STRING) - 备注。
-(来源: 如业务配置有定义团队,则填入。当前可从assistant_team_id不同值枚举填默认名称,例如都属于“教练组”暂时。此维度在数据中信息缺乏,可不强制使用。)
-DIM_PAY_METHOD(支付方式维度表)
-描述: 支付方式维度。维护支付渠道编码与名称的对应关系。用于翻译支付记录中的pay_method。
-主键: pay_method_code
-字段:
-• pay_method_code (INT) - 支付方式代码,主键。
-• pay_method_name (STRING) - 支付方式名称。例如“现金”、“微信”、“支付宝”、“储值卡”。
-• method_type (STRING) - 支付类型大类。例如“现金类”、“第三方支付”、“会员账户”等分类。
-• remark (STRING) - 备注。
-(来源: 业务系统支付方式配置。由于导出数据中仅出现2种pay_method代码且未给文字,需与业务确认编码。例如常见映射:1=现金,2=微信,3=支付宝,4=银联,5=储值卡 等。ETL初始化时可根据已知支付方式填充,后续若有新方式通过配置增补。此维表确保分析报表显示支付方式时用名称而非代码。)
-DIM_ORDER_ASSISTANT_TYPE(助教服务类型维度表)
-描述: 助教服务类型维度。描述订单中助教服务的类型编码含义。
-主键: type_code
-字段:
-• type_code (INT) - 助教服务类型码,主键。
-• type_name (STRING) - 类型名称。如“基础课服务”、“附加课服务”。
-• description (STRING) - 描述说明。
-(来源: 由业务配置或数据推断。本案例根据助教流水中出现的1和2推定:1=基础服务,2=附加服务。维表需由业务确认实际含义后维护。)
-DIM_COUPON_PLATFORM(券平台维度表)
-描述: 券所属平台维度。标识团购券来源的平台,例如美团、大众点评等。用于分析各渠道券使用情况。
-主键: platform_code
-字段:
-• platform_code (STRING) - 平台代码,主键。如“MT”代表美团。
-• platform_name (STRING) - 平台名称。如“美团”。
-• company (STRING) - 平台公司/所属集团。
-• remark (STRING) - 备注。
-(来源: 业务维护。可预设常见团购平台。ETL可根据券dealId或certificateId格式判断平台,如以 “MT”开头的券码归类美团。为稳妥起见应人工建立维表,platform_code可用拼音缩写或英文。)
-其他维度说明:
-除上述主要维度外,数据模型还包括时间维度(DIM_DATE 等)用于日期的属性分析,每日可维护一条自然日期记录,包括年、月、日、星期、节假日标识等,用于按日统计(本次未详列字段)。由于要求按自然日汇总,不考虑营业时段划分,因此时间维度只需按日历日粒度设计,无需闲时/忙时等属性。
-3.2 明细事实表定义
-FACT_SALE_ITEM(商品销售明细事实表)
-描述: 记录商品销售的最细粒度明细,每条记录代表订单中售出的一个商品项(SKU行)。粒度:一件商品销售记录。
-主键: (order_trade_no, site_goods_id, sequence_no) 复合键,或系统内部生成的流水ID。
-外键关联: 关联维度表 DIM_SITE、DIM_PRODUCT、DIM_TABLE(若需要知道在哪张台消费,可通过订单关联台费表获取,不直接关联table)、DIM_MEMBER(如果订单有关联会员,通过订单汇总可拿到,不直接在行关联)。
-字段:
-DWD 字段名 业务含义 来源 ODS 字段 / 计算公式
-sale_item_id 商品销售明细ID,主键 ods_store_sale_item.id
-order_trade_no 订单交易号 ods_store_sale_item.order_trade_no
-order_settle_id 订单结算ID ods_store_sale_item.order_settle_id
-site_id 门店ID ods_store_sale_item.site_id
-site_goods_id 门店商品ID ods_store_sale_item.site_goods_id
-goods_id 品牌商品ID ods_store_sale_item.goods_id(tenant_goods_id)
-goods_name 商品名称(销售时冗余) ods_store_sale_item.goods_name
-category_id 商品分类ID ods_store_sale_item.category_id 或通过 site_goods_id 关联 ods_store_product 取 category_id
-quantity 销售数量 ods_store_sale_item.quantity
-unit_price 销售单价 ods_store_sale_item.unit_price
-discount_amount 折扣金额(会员折扣+手工优惠混合) ods_store_sale_item.discount_amount(discount_money)
-final_amount 实收金额 优先用 ods_store_sale_item.actual_amount;如无,则 unit_price * quantity - discount_amount
-is_gift 是否赠品 ods_store_sale_item.is_gift
-sale_time 销售时间 默认:ods_store_sale_item.sales_time;如需统一以结账时间,可通过 order_settle_id 关联 ods_order_receipt_detail.settle_time 覆盖
-member_id 会员ID(统一从订单维度获取) ods_order_receipt_detail.member_id(按 order_settle_id 关联)
-salesman_id 推销员ID ods_store_sale_item.salesman_user_id
-operator_id 操作员ID ods_store_sale_item.operator_id
-is_refunded 是否已退款(标记为后续被退款的销售) 若 ods_store_sale_item.is_refunded 字段有效则直接映射,否则依据 fact_refund 中关联的 sale_item_id 衍生
+COMMENT ON COLUMN dim_site.site_id IS '闂ㄥ簵ID锛屼笂娓稿悇JSON涓殑site_id缁熶竴鏄犲皠鍒版';
+COMMENT ON COLUMN dim_site.tenant_name IS '鍝佺墝/绉熸埛鍚嶇О锛屼粎浣滀负鎻忚堪灞炴€э紝浜嬪疄琛ㄤ笉鐩存帴鍏宠仈绉熸埛缁?;
+COMMENT ON COLUMN dim_site.site_code IS '闂ㄥ簵缂栫爜锛堝涓婃父鏈夊崟鐙紪鐮侊紝鍙负绌猴級';
+COMMENT ON COLUMN dim_site.site_name IS '闂ㄥ簵鍚嶇О';
+COMMENT ON COLUMN dim_site.full_address IS '闂ㄥ簵瀹屾暣鍦板潃';
+COMMENT ON COLUMN dim_site.city_name IS '鍩庡競鍚嶇О';
+COMMENT ON COLUMN dim_site.district_name IS '鍖?鍘垮悕绉?;
+COMMENT ON COLUMN dim_site.longitude IS '缁忓害';
+COMMENT ON COLUMN dim_site.latitude IS '绾害';
+COMMENT ON COLUMN dim_site.business_tel IS '闂ㄥ簵鐢佃瘽';
+COMMENT ON COLUMN dim_site.open_date IS '寮€搴楁棩鏈?;
+COMMENT ON COLUMN dim_site.status IS '闂ㄥ簵鐘舵€侊細钀ヤ笟涓?鍋滀笟/绛瑰绛?;
+COMMENT ON COLUMN dim_site.org_id IS '闂ㄥ簵鎵€灞炵粍缁?鍖哄煙ID锛堝涓婃父鏈塼enant_site_region_id锛?;
+COMMENT ON COLUMN dim_site.remark IS '澶囨敞';
+COMMENT ON COLUMN dim_site.created_at IS '璁板綍鍒涘缓鏃堕棿锛堟暟浠撲晶锛?;
+COMMENT ON COLUMN dim_site.updated_at IS '璁板綍鏈€鍚庢洿鏂版椂闂达紙鏁颁粨渚э級';
+DIM_MEMBER锛堜細鍛樼淮搴﹁〃锛?
+鎻忚堪锛?浼氬憳缁村害锛岃褰曚細鍛樹釜浜哄強璐︽埛灞炴€с€傚皢ODS浼氬憳妗f鍜屼細鍛樺崱淇℃伅鍚堝苟锛屾彁渚涘畬鏁翠細鍛樼敾鍍忋€?
+涓婚敭: member_id锛堜細鍛樿处鎴稩D锛?
+瀛楁:
+鈥?member_id (BIGINT) - 浼氬憳ID锛屼富閿€傚搴擮DS_MEMBER_PROFILE.id銆?
+鈥?member_name (STRING) - 浼氬憳濮撳悕銆傛潵鑷狾DS_MEMBER_PROFILE.real_name锛屽涓虹┖鍒欑敤鏄电О浠f浛銆?
+鈥?nickname (STRING) - 浼氬憳鏄电О銆?
+鈥?gender (STRING) - 鎬у埆锛堚€滅敺鈥?鈥滃コ鈥濓級銆傜敱member_profiles.gender浠g爜缈昏瘧寰楀埌銆?
+鈥?birthday (DATE) - 鍑虹敓鏃ユ湡銆?
+鈥?mobile (STRING) - 鎵嬫満鍙风爜銆?
+鈥?member_type_id (BIGINT) - 浼氬憳鍗$被鍨婭D锛屽閿弬鐓IM_MEMBER_CARD_TYPE.card_type_id銆?
+鈥?member_type_name (STRING) - 浼氬憳鍗$被鍨嬪悕绉般€傚鈥滃偍鍊煎崱鈥濄€佲€滈摱鍗♀€濄€佲€滈噾鍗♀€濈瓑銆?
+鈥?status (STRING) - 浼氬憳鐘舵€併€傜炕璇慜DS_MEMBER_PROFILE.status鏋氫妇锛屽鈥滄甯糕€濄€佲€滃仠鐢ㄢ€濄€?
+鈥?register_time (DATETIME) - 娉ㄥ唽鏃堕棿/寮€鍗℃椂闂淬€?
+鈥?valid_from (DATE) - 浼氬憳鍗℃湁鏁堟湡寮€濮嬨€?
+鈥?valid_to (DATE) - 浼氬憳鍗℃湁鏁堟湡鎴銆?
+鈥?last_visit_time (DATETIME) - 鏈€杩戞秷璐规椂闂淬€?
+鈥?balance (DECIMAL(10,2)) - 褰撳墠鍌ㄥ€间綑棰濓紙鍏冿級銆?
+鈥?total_recharge_amount (DECIMAL(10,2)) - 鍘嗗彶鍏呭€兼€婚锛堝厓锛夈€?鍙互鍦‥TL鍒濆鍖栨椂璁$畻鎴栧悗缁疮璁?
+鈥?total_consumed_amount (DECIMAL(10,2)) - 鍘嗗彶娑堣垂鎬婚锛堝偍鍊奸儴鍒嗭紝鍏冿級銆?
+鈥?wechat_id (STRING) - 缁戝畾寰俊鍙稩D銆?
+鈥?alipay_id (STRING) - 缁戝畾鏀粯瀹濆彿ID銆?
+鈥?remark (STRING) - 澶囨敞銆?
+(鏉ユ簮: 涓昏鏉ヨ嚜member_profiles瀛楁锛宮ember_type鐩稿叧鍒欑粨鍚圤DS_MEMBER_CARD鎴栭厤缃〃纭畾銆傚鍗$被鍨嬪拰鏈夋晥鏈熶粠member_stored_value_cards鎻愬彇銆備綑棰濆彇member_profiles.balance锛屼絾鍦ㄥ垎鏋愪腑鏇村彲闈犵殑鏄€氳繃浣欓鍙樻洿娴佹按璁$畻锛岃繖閲屼繚鐣欎竴涓揩鐓у€笺€傚厖鍊?娑堣垂鎬婚鍙湪ETL鎴朆I灞傞€氳繃浜嬪疄琛ㄦ眹鎬诲緱鍒帮紝涓嶄竴瀹氬湪缁磋〃瀛樺偍銆傚垵濮嬪彲涓嶅~鎴栭€氳繃鍘嗗彶璁$畻鏇存柊銆侱IM_MEMBER涓庝簨瀹炶〃鍏宠仈鏃讹紝閫氳繃member_id杩炴帴銆?
+DIM_MEMBER_CARD_TYPE锛堜細鍛樺崱绫诲瀷缁村害琛級
+鎻忚堪锛?浼氬憳鍗$绫荤淮搴︺€傛弿杩板悇绉嶄細鍛樺崱绾у埆鎴栫被鍨嬬殑瀹氫箟灞炴€э紝渚嬪鍚嶇О銆佹姌鎵c€佹潈鐩娿€傞伩鍏嶅湪妯″瀷涓‖缂栫爜浼氬憳鍗℃灇涓俱€?
+涓婚敭: card_type_id
+瀛楁:
+鈥?card_type_id (BIGINT) - 鍗$ID锛屼富閿€?
+鈥?card_type_name (STRING) - 鍗$鍚嶇О銆?
+鈥?discount_rate (DECIMAL(5,2)) - 榛樿鎶樻墸鐜囥€傚0.90琛ㄧず鎵撲節鎶樸€?
+鈥?description (STRING) - 鍗$鎻忚堪/鏉冪泭璇存槑銆?
+鈥?remark (STRING) - 澶囨敞銆?
+(鏉ユ簮: 缁撳悎涓氬姟閰嶇疆銆傚綋鍓嶅彲浠嶰DS_MEMBER_CARD涓眹鎬讳笉鍚宑ard_type_id鍙婂悕绉帮紝濉厖杩涙缁磋〃锛屼緥濡傚偍鍊煎崱涓€绫伙紝娆″崱鍙︿竴绫荤瓑锛屽苟璁板綍鍏舵姌鎵h鍒欍€傚鏃犳洿澶氫俊鎭彲鏆傚瓨绌烘弿杩帮紝鐢变笟鍔¤ˉ鍏呫€?
+DIM_PRODUCT锛堝晢鍝佺淮搴﹁〃锛?
+鎻忚堪锛?鍟嗗搧缁村害锛屾弿杩板搧鐗屽晢鍝佺殑灞炴€с€傜敱ODS_PRODUCT娓呮礂鑰屾潵锛屽苟鍏宠仈鍟嗗搧绫诲埆绛変俊鎭€?
+涓婚敭: goods_id
+瀛楁:
+鈥?goods_id (BIGINT) - 鍟嗗搧ID锛屼富閿€?
+鈥?goods_name (STRING) - 鍟嗗搧鍚嶇О銆?
+鈥?goods_code (STRING) - 鍟嗗搧缂栫爜銆?
+鈥?category_id (BIGINT) - 鍟嗗搧绫诲埆ID锛屽閿弬鐓IM_PRODUCT_CATEGORY.category_id銆?
+鈥?category_name (STRING) - 鍟嗗搧绫诲埆鍚嶇О銆?
+鈥?unit (STRING) - 璁¢噺鍗曚綅銆?
+鈥?is_service (TINYINT) - 鏄惁鏈嶅姟绫诲晢鍝侊紙1鏈嶅姟/0鍟嗗搧锛夈€?
+鈥?status (STRING) - 鍟嗗搧鐘舵€侊紙鈥滀笂鏋垛€?鈥滀笅鏋垛€濓級銆?
+鈥?site_id (BIGINT) 鈥?闂ㄥ簵ID銆?
+(鏉ユ簮: ODS_PRODUCT锛屽幓闄や笉闇€瑕佸垎鏋愮殑瀛楁锛屼粎淇濈暀鏍稿績灞炴€с€俢ategory_id瀵瑰簲DIM_PRODUCT_CATEGORY浠ヨ幏寰楃被鍒悕绉般€俿tatus鐢变唬鐮佽浆鎴愭枃鏈€俿ite_id涓轰簡閾捐矾瀹屾暣涔熷瓨鍌ㄣ€?
+DIM_PRODUCT_CATEGORY锛堝晢鍝佺被鍒淮搴﹁〃锛?
+鎻忚堪锛?鍟嗗搧鍒嗙被缁村害銆傚瓨鍌ㄥ晢鍝佺殑绫诲埆灞傛淇℃伅锛屽澶х被銆佸瓙绫诲悕绉帮紝鐢ㄤ簬鎸夊搧绫诲垎鏋愰攢鍞€?
+涓婚敭: category_id
+瀛楁:
+鈥?category_id (BIGINT) - 鍒嗙被ID锛屼富閿€?
+鈥?category_name (STRING) - 鍒嗙被鍚嶇О銆?
+鈥?parent_category_id (BIGINT) - 鐖剁被鍒獻D锛堝鏈変笂涓嬬骇锛夈€?
+鈥?parent_category_name (STRING) - 鐖剁被鍒悕绉般€?
+鈥?is_active (TINYINT) - 鏄惁鍦ㄧ敤锛?鏄?0鍚︼級銆?
+(鏉ユ簮: 搴撳瓨鍙樺寲璁板綍2.json 涓В鏋?goodsCategoryList 鑾峰彇銆傜敱浜庡簱瀛樺彉鍖栬褰?瀹為檯鏄竴浠藉晢鍝佸垎绫婚厤缃爲锛屽叾姣忔潯璁板綍涓轰竴涓垎绫昏妭鐐广€侲TL闇€閬嶅巻鎻愬彇category_id銆乶ame鍜宲arent_id鏋勫缓缁磋〃銆傚垎绫诲眰绾у叧绯诲彲鐢ㄤ簬鎸夊ぇ绫?灏忕被姹囨€婚攢鍞€傚綋鍓嶆暟鎹墍鏈夊垎绫?is_warehousing=1 琛ㄧず鍙備笌搴撳瓨绠$悊锛屽潎鍙涓烘湁鏁堝垎绫汇€?
+DIM_TABLE锛堝彴妗岀淮搴﹁〃锛?
+鎻忚堪锛?鍙版缁村害锛屾弿杩伴棬搴楀唴鍚勫彴妗?鍖呭帰鐨勫睘鎬э紝濡傜紪鍙枫€佸尯鍩熴€佺被鍨嬬瓑銆傜敱ODS_TABLE_INFO鍔犲伐寰楀埌銆?
+涓婚敭: site_table_id
+瀛楁:
+鈥?site_table_id (BIGINT) - 鍙版ID锛屼富閿€?
+鈥?table_name (STRING) - 鍙版鍚嶇О銆?
+鈥?table_no (STRING) - 鍙版缂栧彿锛堢函鏁板瓧搴忓彿锛屽鏈夌殑璇濓級銆?
+鈥?area_name (STRING) - 鍖哄煙鍚嶇О銆?
+鈥?table_type (STRING) - 鍙版绫诲瀷锛堜緥濡傗€滅編寮忔鈥濄€佲€滄柉璇哄厠妗屸€濄€佲€淜TV鍖呴棿鈥濄€佲€滈夯灏嗘埧鈥濓級銆?
+鈥?is_vip (TINYINT) - 鏄惁VIP涓撳睘鍙般€?
+鈥?status (STRING) - 鍙版鐘舵€侊紙鈥滃惎鐢ㄢ€?鈥滃仠鐢ㄢ€濓級銆?
+鈥?site_id (BIGINT) - 闂ㄥ簵ID銆?
+(鏉ユ簮: 涓昏瀛楁鏉ヨ嚜ODS_TABLE_INFO锛宎rea_name鍜宼able_type鍙兘闇€瑕佺粨鍚堥厤缃垨鍚嶇О瑙勫垯濉厖銆備緥濡?area_name 閫氳繃ODS_TABLE_INFO.area_id鍏宠仈闂ㄥ簵鍖哄煙閰嶇疆琛?濡傛灉鏈?鑾峰彇鍚嶇О锛屾病鏈夊垯浠巘able_name瑙f瀽銆倀able_type鍙熀浜巘able_name涓叧閿瓧鏄犲皠锛屽鍚€滄柉鈥濆瓧鐨勪负鏂鍏嬫锛屽湪缁磋〃涓粺涓€绠$悊鏄犲皠鍏崇郴閬垮厤纭紪鐮併€?
+DIM_ASSISTANT锛堝姪鏁欑淮搴﹁〃锛?
+鎻忚堪锛?鍔╂暀锛堟湇鍔′汉鍛橈級缁村害锛岃褰曞憳宸?鍔╂暀鐨勫睘鎬с€傜敱assistant_accounts_master娓呮礂寰楀埌锛屽寘鎷叾涓汉淇℃伅鍜岀姸鎬佺瓑銆?
+涓婚敭: assistant_id
+瀛楁:
+鈥?assistant_id (BIGINT) - 鍔╂暀ID锛堣处鍙稩D锛夛紝涓婚敭銆?
+鈥?user_id (BIGINT) - 绯荤粺鐢ㄦ埛ID锛堢櫥褰曡处鍙稩D锛夈€?
+鈥?assistant_no (STRING) - 鍔╂暀宸ュ彿銆?
+鈥?real_name (STRING) - 鍔╂暀濮撳悕銆?
+鈥?nickname (STRING) - 鍔╂暀鏄电О銆?
+鈥?gender (STRING) - 鎬у埆銆?
+鈥?mobile (STRING) - 鎵嬫満鍙枫€?
+鈥?status (STRING) - 鍦ㄨ亴鐘舵€侊紙鈥滃湪鑱屸€?鈥滅鑱屸€濈瓑锛夈€?
+鈥?visible_flag (TINYINT) - 鍓嶅彴鍙鏍囧織锛?灞曠ず/0闅愯棌锛夈€?
+鈥?skill_category (STRING) - 鏈嶅姟鎶€鑳界被鍒€傛瘮濡傗€滃熀纭€璇炬暀缁冣€濄€佲€滈珮绾ц鏁欑粌鈥濈瓑锛屽搴斿叾涓昏鏈嶅姟绫诲瀷銆?
+鈥?level (STRING) - 鍔╂暀绛夌骇銆?
+鈥?team_name (STRING) - 鎵€灞炲洟闃?鐝粍鍚嶇О銆?
+鈥?billing_mode (STRING) - 璁¤垂妯″紡锛堟寜灏忔椂/鎸夊満娆$瓑锛夈€?
+鈥?site_id (BIGINT) - 闂ㄥ簵ID銆?
+(鏉ユ簮: assistant_accounts_master瀛楁鏁寸悊锛屽墧闄や笉蹇呰瀛楁濡俿erial_number绛夈€俿tatus鐢辩爜琛ㄨ浆鎹负鏂囨湰銆俿kill_category鍙熀浜庡姪鏁欏叿澶囩殑鎶€鑳界被鍨嬬‘瀹氾紝渚嬪鑻ュ姪鏁欐湁鍩虹璇炬妧鑳藉垯鏍囦负鈥滃熀纭€璇炬暀缁冣€濓紱濡備竴涓姪鏁欒处鍙锋湁澶氱鏈嶅姟绫诲瀷锛屽彲浠ュ~鍐欎富瑕佺被鍨嬫垨鈥滃鎶€鑳解€濄€傚洟闃熷悕绉皌eam_name鑻DS娌℃湁鍙€氳繃assistant_team_id鍏宠仈TEAM缁磋〃鑾峰彇銆?
+DIM_ASSISTANT_TEAM锛堝姪鏁欏洟闃熺淮搴﹁〃锛?
+鎻忚堪锛?鍔╂暀鍥㈤槦/缁勭粐缁村害銆傚鏋滄湁灏嗗姪鏁欏垝鍒嗗洟闃熸垨閮ㄩ棬鐨勯渶姹傦紝鍒欏缓绔嬫缁磋〃銆傚綋鍓嶆暟鎹湁assistant_team_id浣嗘湭缁欏悕绉帮紝鍙悗缁ˉ鍏呫€?
+涓婚敭: team_id
+瀛楁:
+鈥?team_id (BIGINT) - 鍥㈤槦ID锛屼富閿€?
+鈥?team_name (STRING) - 鍥㈤槦鍚嶇О銆?
+鈥?site_id (BIGINT) - 闂ㄥ簵ID/缁勭粐褰掑睘ID銆?
+鈥?remark (STRING) - 澶囨敞銆?
+(鏉ユ簮: 濡備笟鍔¢厤缃湁瀹氫箟鍥㈤槦锛屽垯濉叆銆傚綋鍓嶅彲浠巃ssistant_team_id涓嶅悓鍊兼灇涓惧~榛樿鍚嶇О锛屼緥濡傞兘灞炰簬鈥滄暀缁冪粍鈥濇殏鏃躲€傛缁村害鍦ㄦ暟鎹腑淇℃伅缂轰箯锛屽彲涓嶅己鍒朵娇鐢ㄣ€?
+DIM_PAY_METHOD锛堟敮浠樻柟寮忕淮搴﹁〃锛?
+鎻忚堪锛?鏀粯鏂瑰紡缁村害銆傜淮鎶ゆ敮浠樻笭閬撶紪鐮佷笌鍚嶇О鐨勫搴斿叧绯汇€傜敤浜庣炕璇戞敮浠樿褰曚腑鐨刾ay_method銆?
+涓婚敭: pay_method_code
+瀛楁:
+鈥?pay_method_code (INT) - 鏀粯鏂瑰紡浠g爜锛屼富閿€?
+鈥?pay_method_name (STRING) - 鏀粯鏂瑰紡鍚嶇О銆備緥濡傗€滅幇閲戔€濄€佲€滃井淇♀€濄€佲€滄敮浠樺疂鈥濄€佲€滃偍鍊煎崱鈥濄€?
+鈥?method_type (STRING) - 鏀粯绫诲瀷澶х被銆備緥濡傗€滅幇閲戠被鈥濄€佲€滅涓夋柟鏀粯鈥濄€佲€滀細鍛樿处鎴封€濈瓑鍒嗙被銆?
+鈥?remark (STRING) - 澶囨敞銆?
+(鏉ユ簮: 涓氬姟绯荤粺鏀粯鏂瑰紡閰嶇疆銆傜敱浜庡鍑烘暟鎹腑浠呭嚭鐜?绉峱ay_method浠g爜涓旀湭缁欐枃瀛楋紝闇€涓庝笟鍔$‘璁ょ紪鐮併€備緥濡傚父瑙佹槧灏勶細1=鐜伴噾,2=寰俊,3=鏀粯瀹?4=閾惰仈,5=鍌ㄥ€煎崱 绛夈€侲TL鍒濆鍖栨椂鍙牴鎹凡鐭ユ敮浠樻柟寮忓~鍏咃紝鍚庣画鑻ユ湁鏂版柟寮忛€氳繃閰嶇疆澧炶ˉ銆傛缁磋〃纭繚鍒嗘瀽鎶ヨ〃鏄剧ず鏀粯鏂瑰紡鏃剁敤鍚嶇О鑰岄潪浠g爜銆?
+DIM_ORDER_ASSISTANT_TYPE锛堝姪鏁欐湇鍔$被鍨嬬淮搴﹁〃锛?
+鎻忚堪锛?鍔╂暀鏈嶅姟绫诲瀷缁村害銆傛弿杩拌鍗曚腑鍔╂暀鏈嶅姟鐨勭被鍨嬬紪鐮佸惈涔夈€?
+涓婚敭: type_code
+瀛楁:
+鈥?type_code (INT) - 鍔╂暀鏈嶅姟绫诲瀷鐮侊紝涓婚敭銆?
+鈥?type_name (STRING) - 绫诲瀷鍚嶇О銆傚鈥滃熀纭€璇炬湇鍔♀€濄€佲€滈檮鍔犺鏈嶅姟鈥濄€?
+鈥?description (STRING) - 鎻忚堪璇存槑銆?
+(鏉ユ簮: 鐢变笟鍔¢厤缃垨鏁版嵁鎺ㄦ柇銆傛湰妗堜緥鏍规嵁鍔╂暀娴佹按涓嚭鐜扮殑1鍜?鎺ㄥ畾锛?=鍩虹鏈嶅姟锛?=闄勫姞鏈嶅姟銆傜淮琛ㄩ渶鐢变笟鍔$‘璁ゅ疄闄呭惈涔夊悗缁存姢銆?
+DIM_COUPON_PLATFORM锛堝埜骞冲彴缁村害琛級
+鎻忚堪锛?鍒告墍灞炲钩鍙扮淮搴︺€傛爣璇嗗洟璐埜鏉ユ簮鐨勫钩鍙帮紝渚嬪缇庡洟銆佸ぇ浼楃偣璇勭瓑銆傜敤浜庡垎鏋愬悇娓犻亾鍒镐娇鐢ㄦ儏鍐点€?
+涓婚敭: platform_code
+瀛楁:
+鈥?platform_code (STRING) - 骞冲彴浠g爜锛屼富閿€傚鈥淢T鈥濅唬琛ㄧ編鍥€?
+鈥?platform_name (STRING) - 骞冲彴鍚嶇О銆傚鈥滅編鍥⑩€濄€?
+鈥?company (STRING) - 骞冲彴鍏徃/鎵€灞為泦鍥€?
+鈥?remark (STRING) - 澶囨敞銆?
+(鏉ユ簮: 涓氬姟缁存姢銆傚彲棰勮甯歌鍥㈣喘骞冲彴銆侲TL鍙牴鎹埜dealId鎴朿ertificateId鏍煎紡鍒ゆ柇骞冲彴锛屽浠?鈥淢T鈥濆紑澶寸殑鍒哥爜褰掔被缇庡洟銆備负绋冲Ε璧疯搴斾汉宸ュ缓绔嬬淮琛紝platform_code鍙敤鎷奸煶缂╁啓鎴栬嫳鏂囥€?
+鍏朵粬缁村害璇存槑锛?
+闄や笂杩颁富瑕佺淮搴﹀锛屾暟鎹ā鍨嬭繕鍖呮嫭鏃堕棿缁村害锛圖IM_DATE 绛夛級鐢ㄤ簬鏃ユ湡鐨勫睘鎬у垎鏋愶紝姣忔棩鍙淮鎶や竴鏉¤嚜鐒舵棩鏈熻褰曪紝鍖呮嫭骞淬€佹湀銆佹棩銆佹槦鏈熴€佽妭鍋囨棩鏍囪瘑绛夛紝鐢ㄤ簬鎸夋棩缁熻锛堟湰娆℃湭璇﹀垪瀛楁锛夈€傜敱浜庤姹傛寜鑷劧鏃ユ眹鎬伙紝涓嶈€冭檻钀ヤ笟鏃舵鍒掑垎锛屽洜姝ゆ椂闂寸淮搴﹀彧闇€鎸夋棩鍘嗘棩绮掑害璁捐锛屾棤闇€闂叉椂/蹇欐椂绛夊睘鎬с€?
+3.2 鏄庣粏浜嬪疄琛ㄥ畾涔?
+FACT_SALE_ITEM锛堝晢鍝侀攢鍞槑缁嗕簨瀹炶〃锛?
+鎻忚堪锛?璁板綍鍟嗗搧閿€鍞殑鏈€缁嗙矑搴︽槑缁嗭紝姣忔潯璁板綍浠h〃璁㈠崟涓敭鍑虹殑涓€涓晢鍝侀」锛圫KU琛岋級銆傜矑搴︼細涓€浠跺晢鍝侀攢鍞褰曘€?
+涓婚敭: (order_trade_no, site_goods_id, sequence_no) 澶嶅悎閿紝鎴栫郴缁熷唴閮ㄧ敓鎴愮殑娴佹按ID銆?
+澶栭敭鍏宠仈: 鍏宠仈缁村害琛?DIM_SITE銆丏IM_PRODUCT銆丏IM_TABLE锛堣嫢闇€瑕佺煡閬撳湪鍝紶鍙版秷璐癸紝鍙€氳繃璁㈠崟鍏宠仈鍙拌垂琛ㄨ幏鍙栵紝涓嶇洿鎺ュ叧鑱攖able锛夈€丏IM_MEMBER锛堝鏋滆鍗曟湁鍏宠仈浼氬憳锛岄€氳繃璁㈠崟姹囨€诲彲鎷垮埌锛屼笉鐩存帴鍦ㄨ鍏宠仈锛夈€?
+瀛楁:
+DWD 瀛楁鍚?涓氬姟鍚箟 鏉ユ簮 ODS 瀛楁 / 璁$畻鍏紡
+sale_item_id 鍟嗗搧閿€鍞槑缁咺D锛屼富閿?ods_store_sale_item.id
+order_trade_no 璁㈠崟浜ゆ槗鍙?ods_store_sale_item.order_trade_no
+order_settle_id 璁㈠崟缁撶畻ID ods_store_sale_item.order_settle_id
+site_id 闂ㄥ簵ID ods_store_sale_item.site_id
+site_goods_id 闂ㄥ簵鍟嗗搧ID ods_store_sale_item.site_goods_id
+goods_id 鍝佺墝鍟嗗搧ID ods_store_sale_item.goods_id锛坱enant_goods_id锛?
+goods_name 鍟嗗搧鍚嶇О锛堥攢鍞椂鍐椾綑锛?ods_store_sale_item.goods_name
+category_id 鍟嗗搧鍒嗙被ID ods_store_sale_item.category_id 鎴栭€氳繃 site_goods_id 鍏宠仈 ods_store_product 鍙?category_id
+quantity 閿€鍞暟閲?ods_store_sale_item.quantity
+unit_price 閿€鍞崟浠?ods_store_sale_item.unit_price
+discount_amount 鎶樻墸閲戦锛堜細鍛樻姌鎵?鎵嬪伐浼樻儬娣峰悎锛?ods_store_sale_item.discount_amount锛坉iscount_money锛?
+final_amount 瀹炴敹閲戦 浼樺厛鐢?ods_store_sale_item.actual_amount锛涘鏃狅紝鍒?unit_price * quantity - discount_amount
+is_gift 鏄惁璧犲搧 ods_store_sale_item.is_gift
+sale_time 閿€鍞椂闂?榛樿锛歰ds_store_sale_item.sales_time锛涘闇€缁熶竴浠ョ粨璐︽椂闂达紝鍙€氳繃 order_settle_id 鍏宠仈 ods_order_receipt_detail.settle_time 瑕嗙洊
+member_id 浼氬憳ID锛堢粺涓€浠庤鍗曠淮搴﹁幏鍙栵級 ods_order_receipt_detail.member_id锛堟寜 order_settle_id 鍏宠仈锛?
+salesman_id 鎺ㄩ攢鍛業D ods_store_sale_item.salesman_user_id
+operator_id 鎿嶄綔鍛業D ods_store_sale_item.operator_id
+is_refunded 鏄惁宸查€€娆撅紙鏍囪涓哄悗缁閫€娆剧殑閿€鍞級 鑻?ods_store_sale_item.is_refunded 瀛楁鏈夋晥鍒欑洿鎺ユ槧灏勶紝鍚﹀垯渚濇嵁 fact_refund 涓叧鑱旂殑 sale_item_id 琛嶇敓
-• order_trade_no (BIGINT) - 订单交易号,标识属于哪个订单。
-• order_settle_id (BIGINT) - 订单结算ID,便于与结算/支付关联。
-• site_id (BIGINT) - 门店ID,关联DIM_SITE。
-• goods_id (BIGINT) - 品牌商品ID,关联DIM_PRODUCT.goods_id。
-• site_goods_id (BIGINT) - 门店商品ID,关联DIM_PRODUCT(可通过该ID找到商品,也可不重复存储site_goods_id,因已能通过goods_id+site_id定位,这里保留方便直接连接ODS参考)。
-• goods_name (STRING) - 商品名称冗余。
-• category_id (BIGINT) - 商品类别ID,关联DIM_PRODUCT_CATEGORY,用于方便按类别统计。
-• quantity (DECIMAL(10,2)) - 销售数量。
-• unit_price (DECIMAL(10,2)) - 原单价。该商品原价(未折扣时的单价)。
-• discount_amount (DECIMAL(10,2)) - 折扣金额。该行商品享受的折扣总额。
-• final_amount (DECIMAL(10,2)) - 实收金额。= unit_price*quantity - discount_amount。
-• is_gift (TINYINT) - 是否赠品标志。1=赠送,0=正常销售。赠品的final_amount通常为0。
-• sale_time (DATETIME) - 销售时间/订单时间。取订单的结账时间或商品加入订单时间。用于日粒度分析。
-• member_id (BIGINT) - 会员ID。若订单有会员,则此项归属该会员,否则为空。
-• salesman_id (BIGINT) - 推销员ID。如有指定的销售人员。
-• operator_id (BIGINT) - 操作员ID。录入此销售的收银员。
-来源及逻辑: 由ODS_STORE_SALE_ITEM清洗得到。直接映射大部分字段:quantity, unit_price, discount_amount 来自ODS对应字段;final_amount在ODS中可计算或已提供。member_id并未直接在ODS销售行中出现,但若该订单绑定会员,则通过订单汇总关联到所有行,ETL可以在加载时填入同一order_trade_no下的member_id(这要求ETL在处理订单时有会员映射)。sale_time可取订单结账时间,以便所有行使用同一结算时间便于对齐日期。若有退款发生,fact_sale_item不删除原销售记录,而是在FACT_REFUND中记录退款,或可增加一个标记is_refunded。这里保留is_refund标志以供过滤退货项,但金额不调整,净销售额的计算将在汇总层考虑退款。
-FACT_TABLE_USAGE(台费使用明细事实表)
-描述: 记录台桌使用产生的台费明细。每条记录代表顾客使用一张台桌一次的收费情况。粒度:一笔台费账单(通常对应一个订单的台费部分)。
-主键: id(台费流水ID)。
-外键关联: site_id→DIM_SITE,site_table_id→DIM_TABLE,member_id→DIM_MEMBER(如适用),assistant_id无直接关联这里,因为助教收费独立记录。
-字段:
-DWD 字段名 业务含义 来源 ODS 字段 / 计算公式
-table_usage_id 台费流水ID,主键 ods_table_use_log.id
-order_trade_no 订单交易号 ods_table_use_log.order_trade_no
-order_settle_id 订单结算ID ods_table_use_log.order_settle_id
-site_id 门店ID ods_table_use_log.site_id
-site_table_id 台桌ID ods_table_use_log.site_table_id
-table_name 台桌名称 ods_table_use_log.table_name
-start_time 开台时间 ods_table_use_log.start_use_time
-end_time 离台时间 ods_table_use_log.last_use_time
-duration_minutes 使用时长(分钟) 若 real_table_use_seconds 有值:real_table_use_seconds / 60;否则:EXTRACT(EPOCH FROM (last_use_time - start_use_time))/60
-billing_unit_price 计费单价(可选保留) ods_table_use_log.billing_unit_price(即 ledger_unit_price)
-数据仓库建模与 ETL 对接 PRD
-billing_count 计费数量(可选保留) ods_table_use_log.billing_count(即 ledger_count)
-base_fee 台费原价小计(未折扣) ods_table_use_log.ledger_amount
-member_discount 会员折扣金额 ods_table_use_log.member_discount_amount
-coupon_deduction 券抵扣金额 ods_table_use_log.coupon_discount_amount(coupon_promotion_amount)
-manual_discount 人工减免金额 优先:ods_table_use_log.manual_adjust_amount;如无,则 Σ ods_table_fee_adjust.adjust_amount(按 order_settle_id+site_table_id 汇总)
-数据仓库建模与 ETL 对接 PRD
-service_fee 附加服务费/管理费 ods_table_use_log.service_fee(mgmt_fee)
-final_table_fee 台费实收金额 优先用 ods_table_use_log.final_table_fee(real_table_charge_money);如无,则 base_fee - member_discount - coupon_deduction - manual_discount + service_fee
-member_id 关联会员ID(可空) ods_table_use_log.member_id
-operator_id 操作员ID ods_table_use_log.operator_id
-salesman_id 推销员ID(如有) ods_table_use_log.salesman_user_id
-is_adjusted 是否做过人工调整(0/1) CASE WHEN manual_discount > 0 THEN 1 ELSE 0 END
-is_canceled 台费记录是否作废/删除(0/1) CASE WHEN ods_table_use_log.is_deleted = 1 THEN 1 ELSE 0 END
+鈥?order_trade_no (BIGINT) - 璁㈠崟浜ゆ槗鍙凤紝鏍囪瘑灞炰簬鍝釜璁㈠崟銆?
+鈥?order_settle_id (BIGINT) - 璁㈠崟缁撶畻ID锛屼究浜庝笌缁撶畻/鏀粯鍏宠仈銆?
+鈥?site_id (BIGINT) - 闂ㄥ簵ID锛屽叧鑱擠IM_SITE銆?
+鈥?goods_id (BIGINT) - 鍝佺墝鍟嗗搧ID锛屽叧鑱擠IM_PRODUCT.goods_id銆?
+鈥?site_goods_id (BIGINT) - 闂ㄥ簵鍟嗗搧ID锛屽叧鑱擠IM_PRODUCT锛堝彲閫氳繃璇D鎵惧埌鍟嗗搧锛屼篃鍙笉閲嶅瀛樺偍site_goods_id锛屽洜宸茶兘閫氳繃goods_id+site_id瀹氫綅锛岃繖閲屼繚鐣欐柟渚跨洿鎺ヨ繛鎺DS鍙傝€冿級銆?
+鈥?goods_name (STRING) - 鍟嗗搧鍚嶇О鍐椾綑銆?
+鈥?category_id (BIGINT) - 鍟嗗搧绫诲埆ID锛屽叧鑱擠IM_PRODUCT_CATEGORY锛岀敤浜庢柟渚挎寜绫诲埆缁熻銆?
+鈥?quantity (DECIMAL(10,2)) - 閿€鍞暟閲忋€?
+鈥?unit_price (DECIMAL(10,2)) - 鍘熷崟浠枫€傝鍟嗗搧鍘熶环锛堟湭鎶樻墸鏃剁殑鍗曚环锛夈€?
+鈥?discount_amount (DECIMAL(10,2)) - 鎶樻墸閲戦銆傝琛屽晢鍝佷韩鍙楃殑鎶樻墸鎬婚銆?
+鈥?final_amount (DECIMAL(10,2)) - 瀹炴敹閲戦銆? unit_price*quantity - discount_amount銆?
+鈥?is_gift (TINYINT) - 鏄惁璧犲搧鏍囧織銆?=璧犻€侊紝0=姝e父閿€鍞€傝禒鍝佺殑final_amount閫氬父涓?銆?
+鈥?sale_time (DATETIME) - 閿€鍞椂闂?璁㈠崟鏃堕棿銆傚彇璁㈠崟鐨勭粨璐︽椂闂存垨鍟嗗搧鍔犲叆璁㈠崟鏃堕棿銆傜敤浜庢棩绮掑害鍒嗘瀽銆?
+鈥?member_id (BIGINT) - 浼氬憳ID銆傝嫢璁㈠崟鏈変細鍛橈紝鍒欐椤瑰綊灞炶浼氬憳锛屽惁鍒欎负绌恒€?
+鈥?salesman_id (BIGINT) - 鎺ㄩ攢鍛業D銆傚鏈夋寚瀹氱殑閿€鍞汉鍛樸€?
+鈥?operator_id (BIGINT) - 鎿嶄綔鍛業D銆傚綍鍏ユ閿€鍞殑鏀堕摱鍛樸€?
+鏉ユ簮鍙婇€昏緫锛?鐢監DS_STORE_SALE_ITEM娓呮礂寰楀埌銆傜洿鎺ユ槧灏勫ぇ閮ㄥ垎瀛楁锛歲uantity, unit_price, discount_amount 鏉ヨ嚜ODS瀵瑰簲瀛楁锛沠inal_amount鍦∣DS涓彲璁$畻鎴栧凡鎻愪緵銆俶ember_id骞舵湭鐩存帴鍦∣DS閿€鍞涓嚭鐜帮紝浣嗚嫢璇ヨ鍗曠粦瀹氫細鍛橈紝鍒欓€氳繃璁㈠崟姹囨€诲叧鑱斿埌鎵€鏈夎锛孍TL鍙互鍦ㄥ姞杞芥椂濉叆鍚屼竴order_trade_no涓嬬殑member_id锛堣繖瑕佹眰ETL鍦ㄥ鐞嗚鍗曟椂鏈変細鍛樻槧灏勶級銆俿ale_time鍙彇璁㈠崟缁撹处鏃堕棿锛屼互渚挎墍鏈夎浣跨敤鍚屼竴缁撶畻鏃堕棿渚夸簬瀵归綈鏃ユ湡銆傝嫢鏈夐€€娆惧彂鐢燂紝fact_sale_item涓嶅垹闄ゅ師閿€鍞褰曪紝鑰屾槸鍦‵ACT_REFUND涓褰曢€€娆撅紝鎴栧彲澧炲姞涓€涓爣璁癷s_refunded銆傝繖閲屼繚鐣檌s_refund鏍囧織浠ヤ緵杩囨护閫€璐ч」锛屼絾閲戦涓嶈皟鏁达紝鍑€閿€鍞鐨勮绠楀皢鍦ㄦ眹鎬诲眰鑰冭檻閫€娆俱€?
+FACT_TABLE_USAGE锛堝彴璐逛娇鐢ㄦ槑缁嗕簨瀹炶〃锛?
+鎻忚堪: 璁板綍鍙版浣跨敤浜х敓鐨勫彴璐规槑缁嗐€傛瘡鏉¤褰曚唬琛ㄩ【瀹娇鐢ㄤ竴寮犲彴妗屼竴娆$殑鏀惰垂鎯呭喌銆傜矑搴︼細涓€绗斿彴璐硅处鍗曪紙閫氬父瀵瑰簲涓€涓鍗曠殑鍙拌垂閮ㄥ垎锛夈€?
+涓婚敭: id锛堝彴璐规祦姘碔D锛夈€?
+澶栭敭鍏宠仈: site_id鈫扗IM_SITE锛宻ite_table_id鈫扗IM_TABLE锛宮ember_id鈫扗IM_MEMBER锛堝閫傜敤锛夛紝assistant_id鏃犵洿鎺ュ叧鑱旇繖閲岋紝鍥犱负鍔╂暀鏀惰垂鐙珛璁板綍銆?
+瀛楁:
+DWD 瀛楁鍚?涓氬姟鍚箟 鏉ユ簮 ODS 瀛楁 / 璁$畻鍏紡
+table_usage_id 鍙拌垂娴佹按ID锛屼富閿?table_fee_transactions_log.id
+order_trade_no 璁㈠崟浜ゆ槗鍙?table_fee_transactions_log.order_trade_no
+order_settle_id 璁㈠崟缁撶畻ID table_fee_transactions_log.order_settle_id
+site_id 闂ㄥ簵ID table_fee_transactions_log.site_id
+site_table_id 鍙版ID table_fee_transactions_log.site_table_id
+table_name 鍙版鍚嶇О table_fee_transactions_log.table_name
+start_time 寮€鍙版椂闂?table_fee_transactions_log.start_use_time
+end_time 绂诲彴鏃堕棿 table_fee_transactions_log.last_use_time
+duration_minutes 浣跨敤鏃堕暱锛堝垎閽燂級 鑻?real_table_use_seconds 鏈夊€硷細real_table_use_seconds / 60锛涘惁鍒欙細EXTRACT(EPOCH FROM (last_use_time - start_use_time))/60
+billing_unit_price 璁¤垂鍗曚环锛堝彲閫変繚鐣欙級 table_fee_transactions_log.billing_unit_price锛堝嵆 ledger_unit_price锛?
+鏁版嵁浠撳簱寤烘ā涓?ETL 瀵规帴 PRD
+billing_count 璁¤垂鏁伴噺锛堝彲閫変繚鐣欙級 table_fee_transactions_log.billing_count锛堝嵆 ledger_count锛?
+base_fee 鍙拌垂鍘熶环灏忚锛堟湭鎶樻墸锛?table_fee_transactions_log.ledger_amount
+member_discount 浼氬憳鎶樻墸閲戦 table_fee_transactions_log.member_discount_amount
+coupon_deduction 鍒告姷鎵i噾棰?table_fee_transactions_log.coupon_discount_amount锛坈oupon_promotion_amount锛?
+manual_discount 浜哄伐鍑忓厤閲戦 浼樺厛锛歰ds_table_use_log.manual_adjust_amount锛涘鏃狅紝鍒?危 ods_table_fee_adjust.adjust_amount锛堟寜 order_settle_id+site_table_id 姹囨€伙級
+鏁版嵁浠撳簱寤烘ā涓?ETL 瀵规帴 PRD
+service_fee 闄勫姞鏈嶅姟璐?绠$悊璐?table_fee_transactions_log.service_fee锛坢gmt_fee锛?
+final_table_fee 鍙拌垂瀹炴敹閲戦 浼樺厛鐢?table_fee_transactions_log.final_table_fee锛坮eal_table_charge_money锛夛紱濡傛棤锛屽垯 base_fee - member_discount - coupon_deduction - manual_discount + service_fee
+member_id 鍏宠仈浼氬憳ID锛堝彲绌猴級 table_fee_transactions_log.member_id
+operator_id 鎿嶄綔鍛業D table_fee_transactions_log.operator_id
+salesman_id 鎺ㄩ攢鍛業D锛堝鏈夛級 table_fee_transactions_log.salesman_user_id
+is_adjusted 鏄惁鍋氳繃浜哄伐璋冩暣锛?/1锛?CASE WHEN manual_discount > 0 THEN 1 ELSE 0 END
+is_canceled 鍙拌垂璁板綍鏄惁浣滃簾/鍒犻櫎锛?/1锛?CASE WHEN table_fee_transactions_log.is_deleted = 1 THEN 1 ELSE 0 END
-• table_usage_id (BIGINT) - 台费流水ID(FACT主键,对应ODS_TABLE_USE_LOG.id)。
-• order_trade_no (BIGINT) - 订单交易号。
-• order_settle_id (BIGINT) - 订单结算ID。
-• site_id (BIGINT) - 门店ID。
-• site_table_id (BIGINT) - 台桌ID,关联DIM_TABLE。
-• table_name (STRING) - 台桌名称。冗余方便查阅。
-• start_time (DATETIME) - 开台时间。
-• end_time (DATETIME) - 离台时间。
-• duration_minutes (INT) - 使用时长(分钟)。可由start/end计算或直接取ODS real_table_use_seconds换算。
-• base_fee (DECIMAL(10,2)) - 原台费金额(未扣减前费用)。
-• member_discount (DECIMAL(10,2)) - 会员折扣减免金额。
-• coupon_deduction (DECIMAL(10,2)) - 券抵扣金额。
-• manual_discount (DECIMAL(10,2)) - 手工减免费用。
-• service_fee (DECIMAL(10,2)) - 附加服务费。
-• final_table_fee (DECIMAL(10,2)) - 实收台费金额。= base_fee + service_fee - member_discount - coupon_deduction - manual_discount。
-• member_id (BIGINT) - 会员ID(如果该开台绑定会员)。
-• operator_id (BIGINT) - 操作员ID(开台/结账经办人)。
-• salesman_id (BIGINT) - 营销员ID(如果有在场服务员)。
-• is_adjusted (TINYINT) - 是否有人工调整。1表示有手工打折(manual_discount>0),0无。
-• is_canceled (TINYINT) - 是否作废。1表示此台费记录被取消未收费(由于订单取消等),0正常。
+鈥?table_usage_id (BIGINT) - 鍙拌垂娴佹按ID锛團ACT涓婚敭锛屽搴擮DS_TABLE_USE_LOG.id锛夈€?
+鈥?order_trade_no (BIGINT) - 璁㈠崟浜ゆ槗鍙枫€?
+鈥?order_settle_id (BIGINT) - 璁㈠崟缁撶畻ID銆?
+鈥?site_id (BIGINT) - 闂ㄥ簵ID銆?
+鈥?site_table_id (BIGINT) - 鍙版ID锛屽叧鑱擠IM_TABLE銆?
+鈥?table_name (STRING) - 鍙版鍚嶇О銆傚啑浣欐柟渚挎煡闃呫€?
+鈥?start_time (DATETIME) - 寮€鍙版椂闂淬€?
+鈥?end_time (DATETIME) - 绂诲彴鏃堕棿銆?
+鈥?duration_minutes (INT) - 浣跨敤鏃堕暱锛堝垎閽燂級銆傚彲鐢眘tart/end璁$畻鎴栫洿鎺ュ彇ODS real_table_use_seconds鎹㈢畻銆?
+鈥?base_fee (DECIMAL(10,2)) - 鍘熷彴璐归噾棰濓紙鏈墸鍑忓墠璐圭敤锛夈€?
+鈥?member_discount (DECIMAL(10,2)) - 浼氬憳鎶樻墸鍑忓厤閲戦銆?
+鈥?coupon_deduction (DECIMAL(10,2)) - 鍒告姷鎵i噾棰濄€?
+鈥?manual_discount (DECIMAL(10,2)) - 鎵嬪伐鍑忓厤璐圭敤銆?
+鈥?service_fee (DECIMAL(10,2)) - 闄勫姞鏈嶅姟璐广€?
+鈥?final_table_fee (DECIMAL(10,2)) - 瀹炴敹鍙拌垂閲戦銆? base_fee + service_fee - member_discount - coupon_deduction - manual_discount銆?
+鈥?member_id (BIGINT) - 浼氬憳ID锛堝鏋滆寮€鍙扮粦瀹氫細鍛橈級銆?
+鈥?operator_id (BIGINT) - 鎿嶄綔鍛業D锛堝紑鍙?缁撹处缁忓姙浜猴級銆?
+鈥?salesman_id (BIGINT) - 钀ラ攢鍛業D锛堝鏋滄湁鍦ㄥ満鏈嶅姟鍛橈級銆?
+鈥?is_adjusted (TINYINT) - 鏄惁鏈変汉宸ヨ皟鏁淬€?琛ㄧず鏈夋墜宸ユ墦鎶橈紙manual_discount>0锛夛紝0鏃犮€?
+鈥?is_canceled (TINYINT) - 鏄惁浣滃簾銆?琛ㄧず姝ゅ彴璐硅褰曡鍙栨秷鏈敹璐癸紙鐢变簬璁㈠崟鍙栨秷绛夛級锛?姝e父銆?
-来源及逻辑: 由ODS_TABLE_USE_LOG直接整理。base_fee对应ODS的ledger_amount,member_discount, coupon_deduction, manual_discount, service_fee直接来自同名字段,final_table_fee取ODS.real_table_charge_money校验计算。is_adjusted标志=1当manual_discount>0或adjust_amount有值。is_canceled可根据ODS.is_delete或订单取消情况设定(若订单未结算导致此记录无效)。注意: manual_discount来自单独的ODS_TABLE_FEE_ADJUST记录,如果ODS_USE_LOG里已有adjust_amount字段,则ETL需要与调整表核对确保一致。所有金额字段单位均为元。FACT_TABLE_USAGE为订单汇总时台费总额的来源。
-FACT_ASSISTANT_SERVICE(助教服务明细事实表)
-描述: 记录助教服务/教练陪练的明细。每条记录对应顾客享受的一次助教服务。粒度:一条助教服务记录。
-主键: id(助教流水ID)。
-外键关联: site_id→DIM_SITE,assistant_id→DIM_ASSISTANT,member_id→DIM_MEMBER,site_table_id→DIM_TABLE(如分析需要,可保留字段但不一定强关联),service_type→DIM_ORDER_ASSISTANT_TYPE。
-字段:
-DWD 字段名 业务含义 来源 ODS 字段 / 计算公式
-assistant_service_id 助教服务流水ID,主键 ods_assistant_service_log.id
-order_trade_no 订单交易号 ods_assistant_service_log.order_trade_no
-order_settle_id 订单结算ID ods_assistant_service_log.order_settle_id
-site_id 门店ID ods_assistant_service_log.site_id
-site_assistant_id 门店助教账号ID ods_assistant_service_log.site_assistant_id
-assistant_name 助教名称冗余 ods_assistant_service_log.assistant_name 或关联 ods_assistant_account.real_name/nickname
-member_id 会员ID ods_assistant_service_log.member_id
-service_start_time 服务开始时间 ods_assistant_service_log.start_time
-service_end_time 服务结束时间 ods_assistant_service_log.end_time
-service_duration_minutes 服务时长(分钟) 若 ODS 有总秒数字段:seconds/60;否则 EXTRACT(EPOCH FROM (end_time - start_time))/60
-service_type_id 助教服务类型(基础课/附加课等) ods_assistant_service_log.service_type(在 DWD 关联 dim_order_assist_type 转义)
-base_fee 助教基础课/单价计费金额(原价) ods_assistant_service_log.base_fee,或按单价×时长计算(见样本字段)
-member_discount 助教服务会员折扣金额 ods_assistant_service_log.member_discount_amount
-manual_discount 助教服务人工折扣金额 ods_assistant_service_log.manual_discount_amount
-coupon_deduction 券抵扣金额(如团购券分摊到助教) 若 ODS 有对应字段则直接映射;若无则默认 0,由 fact_coupon_usage 不再分摊到助教
-final_service_fee 助教服务实收金额 优先:ods_assistant_service_log.final_service_fee;否则 base_fee - member_discount - manual_discount - coupon_deduction
-operator_id 操作员ID ods_assistant_service_log.operator_id
-salesman_id 推销员ID ods_assistant_service_log.salesman_user_id(如有)
-is_canceled 该条助教服务是否被“废除” CASE WHEN (ods_assistant_service_log.is_trash = 1 OR 在 ods_assistant_cancel_log 有匹配记录) THEN 1 ELSE 0 END
-数据仓库建模与 ETL 对接 PRD
-cancel_reason 废除原因 若存在 ods_assistant_cancel_log 记录,则取其 reason;否则为空
-service_score 服务评分 ods_assistant_service_log.service_grade
-skill_score 技能评分 ods_assistant_service_log.skill_grade
-overall_score 综合评分 ods_assistant_service_log.sum_grade
+鏉ユ簮鍙婇€昏緫锛?鐢監DS_TABLE_USE_LOG鐩存帴鏁寸悊銆俠ase_fee瀵瑰簲ODS鐨刲edger_amount锛宮ember_discount, coupon_deduction, manual_discount, service_fee鐩存帴鏉ヨ嚜鍚屽悕瀛楁锛宖inal_table_fee鍙朞DS.real_table_charge_money鏍¢獙璁$畻銆俰s_adjusted鏍囧織=1褰搈anual_discount>0鎴朼djust_amount鏈夊€笺€俰s_canceled鍙牴鎹甇DS.is_delete鎴栬鍗曞彇娑堟儏鍐佃瀹氾紙鑻ヨ鍗曟湭缁撶畻瀵艰嚧姝よ褰曟棤鏁堬級銆傛敞鎰忥細 manual_discount鏉ヨ嚜鍗曠嫭鐨凮DS_TABLE_FEE_ADJUST璁板綍锛屽鏋淥DS_USE_LOG閲屽凡鏈塧djust_amount瀛楁锛屽垯ETL闇€瑕佷笌璋冩暣琛ㄦ牳瀵圭‘淇濅竴鑷淬€傛墍鏈夐噾棰濆瓧娈靛崟浣嶅潎涓哄厓銆侳ACT_TABLE_USAGE涓鸿鍗曟眹鎬绘椂鍙拌垂鎬婚鐨勬潵婧愩€?
+FACT_ASSISTANT_SERVICE锛堝姪鏁欐湇鍔℃槑缁嗕簨瀹炶〃锛?
+鎻忚堪: 璁板綍鍔╂暀鏈嶅姟/鏁欑粌闄粌鐨勬槑缁嗐€傛瘡鏉¤褰曞搴旈【瀹韩鍙楃殑涓€娆″姪鏁欐湇鍔°€傜矑搴︼細涓€鏉″姪鏁欐湇鍔¤褰曘€?
+涓婚敭: id锛堝姪鏁欐祦姘碔D锛夈€?
+澶栭敭鍏宠仈: site_id鈫扗IM_SITE锛宎ssistant_id鈫扗IM_ASSISTANT锛宮ember_id鈫扗IM_MEMBER锛宻ite_table_id鈫扗IM_TABLE锛堝鍒嗘瀽闇€瑕侊紝鍙繚鐣欏瓧娈典絾涓嶄竴瀹氬己鍏宠仈锛夛紝service_type鈫扗IM_ORDER_ASSISTANT_TYPE銆?
+瀛楁:
+DWD 瀛楁鍚?涓氬姟鍚箟 鏉ユ簮 ODS 瀛楁 / 璁$畻鍏紡
+assistant_service_id 鍔╂暀鏈嶅姟娴佹按ID锛屼富閿?ods_assistant_service_log.id
+order_trade_no 璁㈠崟浜ゆ槗鍙?ods_assistant_service_log.order_trade_no
+order_settle_id 璁㈠崟缁撶畻ID ods_assistant_service_log.order_settle_id
+site_id 闂ㄥ簵ID ods_assistant_service_log.site_id
+site_assistant_id 闂ㄥ簵鍔╂暀璐﹀彿ID ods_assistant_service_log.site_assistant_id
+assistant_name 鍔╂暀鍚嶇О鍐椾綑 ods_assistant_service_log.assistant_name 鎴栧叧鑱?assistant_accounts_master.real_name/nickname
+member_id 浼氬憳ID ods_assistant_service_log.member_id
+service_start_time 鏈嶅姟寮€濮嬫椂闂?ods_assistant_service_log.start_time
+service_end_time 鏈嶅姟缁撴潫鏃堕棿 ods_assistant_service_log.end_time
+service_duration_minutes 鏈嶅姟鏃堕暱锛堝垎閽燂級 鑻?ODS 鏈夋€荤鏁板瓧娈碉細seconds/60锛涘惁鍒?EXTRACT(EPOCH FROM (end_time - start_time))/60
+service_type_id 鍔╂暀鏈嶅姟绫诲瀷锛堝熀纭€璇?闄勫姞璇剧瓑锛?ods_assistant_service_log.service_type锛堝湪 DWD 鍏宠仈 dim_order_assist_type 杞箟锛?
+base_fee 鍔╂暀鍩虹璇?鍗曚环璁¤垂閲戦锛堝師浠凤級 ods_assistant_service_log.base_fee锛屾垨鎸夊崟浠访楁椂闀胯绠楋紙瑙佹牱鏈瓧娈碉級
+member_discount 鍔╂暀鏈嶅姟浼氬憳鎶樻墸閲戦 ods_assistant_service_log.member_discount_amount
+manual_discount 鍔╂暀鏈嶅姟浜哄伐鎶樻墸閲戦 ods_assistant_service_log.manual_discount_amount
+coupon_deduction 鍒告姷鎵i噾棰濓紙濡傚洟璐埜鍒嗘憡鍒板姪鏁欙級 鑻?ODS 鏈夊搴斿瓧娈靛垯鐩存帴鏄犲皠锛涜嫢鏃犲垯榛樿 0锛岀敱 fact_coupon_usage 涓嶅啀鍒嗘憡鍒板姪鏁?
+final_service_fee 鍔╂暀鏈嶅姟瀹炴敹閲戦 浼樺厛锛歰ds_assistant_service_log.final_service_fee锛涘惁鍒?base_fee - member_discount - manual_discount - coupon_deduction
+operator_id 鎿嶄綔鍛業D ods_assistant_service_log.operator_id
+salesman_id 鎺ㄩ攢鍛業D ods_assistant_service_log.salesman_user_id锛堝鏈夛級
+is_canceled 璇ユ潯鍔╂暀鏈嶅姟鏄惁琚€滃簾闄も€?CASE WHEN (ods_assistant_service_log.is_trash = 1 OR 鍦?ods_assistant_cancel_log 鏈夊尮閰嶈褰? THEN 1 ELSE 0 END
+鏁版嵁浠撳簱寤烘ā涓?ETL 瀵规帴 PRD
+cancel_reason 搴熼櫎鍘熷洜 鑻ュ瓨鍦?ods_assistant_cancel_log 璁板綍锛屽垯鍙栧叾 reason锛涘惁鍒欎负绌?
+service_score 鏈嶅姟璇勫垎 ods_assistant_service_log.service_grade
+skill_score 鎶€鑳借瘎鍒?ods_assistant_service_log.skill_grade
+overall_score 缁煎悎璇勫垎 ods_assistant_service_log.sum_grade
-• assistant_service_id (BIGINT) - 助教服务流水ID(主键)。
-• order_trade_no (BIGINT) - 订单交易号。
-• order_settle_id (BIGINT) - 订单结算ID。
-• site_id (BIGINT) - 门店ID。
-• site_table_id (BIGINT) - 台桌ID(助教服务发生的台桌)。
-• assistant_id (BIGINT) - 助教ID,关联DIM_ASSISTANT。
-• assistant_name (STRING) - 助教姓名冗余。
-• service_type (INT) - 助教服务类型代码,关联DIM_ORDER_ASSISTANT_TYPE获取类型名称。
-• start_time (DATETIME) - 服务开始时间。
-• end_time (DATETIME) - 服务结束时间。
-• duration_minutes (INT) - 服务时长(分钟)。
-• base_fee (DECIMAL(10,2)) - 原服务金额。
-• member_discount (DECIMAL(10,2)) - 会员折扣金额。
-• coupon_deduction (DECIMAL(10,2)) - 券抵扣金额。
-• manual_discount (DECIMAL(10,2)) - 手工减免金额。
-• final_fee (DECIMAL(10,2)) - 实收服务费金额。= base_fee - 各类折扣减免。
-• member_id (BIGINT) - 会员ID(享受服务的顾客,如有会员绑定)。
-• is_canceled (TINYINT) - 是否被取消。1表示该服务实际未完成(被废除),0正常完成。
-• cancel_reason (STRING) - 取消原因描述(如有)。
-• operator_id (BIGINT) - 操作员ID(录入/确认此服务的员工)。
-• salesman_id (BIGINT) - 推销员ID(如有营销人员促成此服务)。
-• service_score (INT) - 服务评分(顾客对服务态度的评分)。
-• skill_score (INT) - 技能评分。
-• overall_score (INT) - 综合评分。
-• score_time (DATETIME) - 评价时间。
-来源及逻辑: 由ODS_ASSISTANT_SERVICE_LOG整理。大部分字段直接映射:base_fee=ledger_amount, member_discount/manual_discount/coupon_deduction来源对应字段,final_fee=service_money。duration计算秒数转换分钟。service_type以ODS.order_assistant_type填充。is_canceled基于ODS.is_trash判断,如为1则本记录在业务上被取消,不计入最终收费(final_fee应该为0或忽略)。对于取消记录,可进一步参考ODS_ASSISTANT_CANCEL_LOG以获取cancel_reason等,在ETL中通过order_trade_no和assistant_id匹配将原因填入。评分字段直接取ODS中的service_grade/skill_grade/sum_grade,如有的话。注意: 已取消的助教服务不应计入订单实际支出,因此在汇总时应排除或final_fee=0。FACT_ASSISTANT_SERVICE为订单汇总层助教费部分来源,也用于人力绩效统计(如单个助教服务次数、评分)。
+鈥?assistant_service_id (BIGINT) - 鍔╂暀鏈嶅姟娴佹按ID锛堜富閿級銆?
+鈥?order_trade_no (BIGINT) - 璁㈠崟浜ゆ槗鍙枫€?
+鈥?order_settle_id (BIGINT) - 璁㈠崟缁撶畻ID銆?
+鈥?site_id (BIGINT) - 闂ㄥ簵ID銆?
+鈥?site_table_id (BIGINT) - 鍙版ID锛堝姪鏁欐湇鍔″彂鐢熺殑鍙版锛夈€?
+鈥?assistant_id (BIGINT) - 鍔╂暀ID锛屽叧鑱擠IM_ASSISTANT銆?
+鈥?assistant_name (STRING) - 鍔╂暀濮撳悕鍐椾綑銆?
+鈥?service_type (INT) - 鍔╂暀鏈嶅姟绫诲瀷浠g爜锛屽叧鑱擠IM_ORDER_ASSISTANT_TYPE鑾峰彇绫诲瀷鍚嶇О銆?
+鈥?start_time (DATETIME) - 鏈嶅姟寮€濮嬫椂闂淬€?
+鈥?end_time (DATETIME) - 鏈嶅姟缁撴潫鏃堕棿銆?
+鈥?duration_minutes (INT) - 鏈嶅姟鏃堕暱锛堝垎閽燂級銆?
+鈥?base_fee (DECIMAL(10,2)) - 鍘熸湇鍔¢噾棰濄€?
+鈥?member_discount (DECIMAL(10,2)) - 浼氬憳鎶樻墸閲戦銆?
+鈥?coupon_deduction (DECIMAL(10,2)) - 鍒告姷鎵i噾棰濄€?
+鈥?manual_discount (DECIMAL(10,2)) - 鎵嬪伐鍑忓厤閲戦銆?
+鈥?final_fee (DECIMAL(10,2)) - 瀹炴敹鏈嶅姟璐归噾棰濄€? base_fee - 鍚勭被鎶樻墸鍑忓厤銆?
+鈥?member_id (BIGINT) - 浼氬憳ID锛堜韩鍙楁湇鍔$殑椤惧锛屽鏈変細鍛樼粦瀹氾級銆?
+鈥?is_canceled (TINYINT) - 鏄惁琚彇娑堛€?琛ㄧず璇ユ湇鍔″疄闄呮湭瀹屾垚锛堣搴熼櫎锛夛紝0姝e父瀹屾垚銆?
+鈥?cancel_reason (STRING) - 鍙栨秷鍘熷洜鎻忚堪锛堝鏈夛級銆?
+鈥?operator_id (BIGINT) - 鎿嶄綔鍛業D锛堝綍鍏?纭姝ゆ湇鍔$殑鍛樺伐锛夈€?
+鈥?salesman_id (BIGINT) - 鎺ㄩ攢鍛業D锛堝鏈夎惀閿€浜哄憳淇冩垚姝ゆ湇鍔★級銆?
+鈥?service_score (INT) - 鏈嶅姟璇勫垎锛堥【瀹㈠鏈嶅姟鎬佸害鐨勮瘎鍒嗭級銆?
+鈥?skill_score (INT) - 鎶€鑳借瘎鍒嗐€?
+鈥?overall_score (INT) - 缁煎悎璇勫垎銆?
+鈥?score_time (DATETIME) - 璇勪环鏃堕棿銆?
+鏉ユ簮鍙婇€昏緫锛?鐢監DS_ASSISTANT_SERVICE_LOG鏁寸悊銆傚ぇ閮ㄥ垎瀛楁鐩存帴鏄犲皠锛歜ase_fee=ledger_amount, member_discount/manual_discount/coupon_deduction鏉ユ簮瀵瑰簲瀛楁锛宖inal_fee=service_money銆俤uration璁$畻绉掓暟杞崲鍒嗛挓銆俿ervice_type浠DS.order_assistant_type濉厖銆俰s_canceled鍩轰簬ODS.is_trash鍒ゆ柇锛屽涓?鍒欐湰璁板綍鍦ㄤ笟鍔′笂琚彇娑堬紝涓嶈鍏ユ渶缁堟敹璐癸紙final_fee搴旇涓?鎴栧拷鐣ワ級銆傚浜庡彇娑堣褰曪紝鍙繘涓€姝ュ弬鑰僌DS_ASSISTANT_CANCEL_LOG浠ヨ幏鍙朿ancel_reason绛夛紝鍦‥TL涓€氳繃order_trade_no鍜宎ssistant_id鍖归厤灏嗗師鍥犲~鍏ャ€傝瘎鍒嗗瓧娈电洿鎺ュ彇ODS涓殑service_grade/skill_grade/sum_grade锛屽鏈夌殑璇濄€傛敞鎰忥細 宸插彇娑堢殑鍔╂暀鏈嶅姟涓嶅簲璁″叆璁㈠崟瀹為檯鏀嚭锛屽洜姝ゅ湪姹囨€绘椂搴旀帓闄ゆ垨final_fee=0銆侳ACT_ASSISTANT_SERVICE涓鸿鍗曟眹鎬诲眰鍔╂暀璐归儴鍒嗘潵婧愶紝涔熺敤浜庝汉鍔涚哗鏁堢粺璁★紙濡傚崟涓姪鏁欐湇鍔℃鏁般€佽瘎鍒嗭級銆?
-废除计费逻辑与派生字段(新增)
-在 DWD 层,我们将 ODS 助教流水中的时间与金额字段标准化为以下核心指标(字段名以本事实表实际命名为准):
-• service_duration_sec:服务实际发生时长(秒),来源于 ODS real_use_seconds。
-• charge_duration_sec:计费时长(秒),来源于 ODS income_seconds。
-• base_fee:原始应收金额,来源于 ODS ledger_amount。
-• final_fee:本条服务最终计入营收的金额,来源于 ODS projected_income / service_money。
-• is_canceled:是否废除标志,来源于 ODS is_trash。
-DWD 层统一约定:
-1. 收入统计口径:
-o 所有“助教收入”类指标,统一使用 final_fee 作为计收入口径。
-o 不再直接使用 base_fee 汇总,以避免将废除的未计费部分算入收入。
-2. 废除服务的处理:
-o is_canceled = 1 的记录仍保留在事实表中,用于分析“被废除的服务数量 / 时长 / 原始金额”。
-o 在“营收类报表”中,若不特别说明,统一按 final_fee 汇总,因此废除服务中未计费部分不会进入营业收入。
-o 如需统计“废除导致的收入损失”,则可使用:lost_fee = base_fee - final_fee(仅对 is_canceled = 1 的记录统计)。
-3. 服务时长相关分析:
-o 实际服务投入人力时长使用 service_duration_sec;
-o 可计费时长使用 charge_duration_sec;
-o 两者差值 service_duration_sec - charge_duration_sec 可用于衡量“非计费投入”(例如免费服务、投诉补偿等)。
+搴熼櫎璁¤垂閫昏緫涓庢淳鐢熷瓧娈碉紙鏂板锛?
+鍦?DWD 灞傦紝鎴戜滑灏?ODS 鍔╂暀娴佹按涓殑鏃堕棿涓庨噾棰濆瓧娈垫爣鍑嗗寲涓轰互涓嬫牳蹇冩寚鏍囷紙瀛楁鍚嶄互鏈簨瀹炶〃瀹為檯鍛藉悕涓哄噯锛夛細
+鈥?service_duration_sec锛氭湇鍔″疄闄呭彂鐢熸椂闀匡紙绉掞級锛屾潵婧愪簬 ODS real_use_seconds銆?
+鈥?charge_duration_sec锛氳璐规椂闀匡紙绉掞級锛屾潵婧愪簬 ODS income_seconds銆?
+鈥?base_fee锛氬師濮嬪簲鏀堕噾棰濓紝鏉ユ簮浜?ODS ledger_amount銆?
+鈥?final_fee锛氭湰鏉℃湇鍔℃渶缁堣鍏ヨ惀鏀剁殑閲戦锛屾潵婧愪簬 ODS projected_income / service_money銆?
+鈥?is_canceled锛氭槸鍚﹀簾闄ゆ爣蹇楋紝鏉ユ簮浜?ODS is_trash銆?
+DWD 灞傜粺涓€绾﹀畾锛?
+1. 鏀跺叆缁熻鍙e緞锛?
+o 鎵€鏈夆€滃姪鏁欐敹鍏モ€濈被鎸囨爣锛岀粺涓€浣跨敤 final_fee 浣滀负璁℃敹鍏ュ彛寰勩€?
+o 涓嶅啀鐩存帴浣跨敤 base_fee 姹囨€伙紝浠ラ伩鍏嶅皢搴熼櫎鐨勬湭璁¤垂閮ㄥ垎绠楀叆鏀跺叆銆?
+2. 搴熼櫎鏈嶅姟鐨勫鐞嗭細
+o is_canceled = 1 鐨勮褰曚粛淇濈暀鍦ㄤ簨瀹炶〃涓紝鐢ㄤ簬鍒嗘瀽鈥滆搴熼櫎鐨勬湇鍔℃暟閲?/ 鏃堕暱 / 鍘熷閲戦鈥濄€?
+o 鍦ㄢ€滆惀鏀剁被鎶ヨ〃鈥濅腑锛岃嫢涓嶇壒鍒鏄庯紝缁熶竴鎸?final_fee 姹囨€伙紝鍥犳搴熼櫎鏈嶅姟涓湭璁¤垂閮ㄥ垎涓嶄細杩涘叆钀ヤ笟鏀跺叆銆?
+o 濡傞渶缁熻鈥滃簾闄ゅ鑷寸殑鏀跺叆鎹熷け鈥濓紝鍒欏彲浣跨敤锛歭ost_fee = base_fee - final_fee锛堜粎瀵?is_canceled = 1 鐨勮褰曠粺璁★級銆?
+3. 鏈嶅姟鏃堕暱鐩稿叧鍒嗘瀽锛?
+o 瀹為檯鏈嶅姟鎶曞叆浜哄姏鏃堕暱浣跨敤 service_duration_sec锛?
+o 鍙璐规椂闀夸娇鐢?charge_duration_sec锛?
+o 涓よ€呭樊鍊?service_duration_sec - charge_duration_sec 鍙敤浜庤 閲忊€滈潪璁¤垂鎶曞叆鈥濓紙渚嬪鍏嶈垂鏈嶅姟銆佹姇璇夎ˉ鍋跨瓑锛夈€?
-FACT_COUPON_USAGE(团购券使用明细事实表)
-描述: 记录团购优惠券(团购套餐券)的使用情况。每条记录代表一张券被使用一次(核销)。粒度:一次团购券核销事件。
-主键: id(券使用流水ID)。
-外键关联: site_id→DIM_SITE,package_id→DIM_GROUP_PACKAGE(需在DWD建立团购套餐维度),platform_code→DIM_COUPON_PLATFORM。
-字段:
+FACT_COUPON_USAGE锛堝洟璐埜浣跨敤鏄庣粏浜嬪疄琛級
+鎻忚堪: 璁板綍鍥㈣喘浼樻儬鍒革紙鍥㈣喘濂楅鍒革級鐨勪娇鐢ㄦ儏鍐点€傛瘡鏉¤褰曚唬琛ㄤ竴寮犲埜琚娇鐢ㄤ竴娆★紙鏍搁攢锛夈€傜矑搴︼細涓€娆″洟璐埜鏍搁攢浜嬩欢銆?
+涓婚敭: id锛堝埜浣跨敤娴佹按ID锛夈€?
+澶栭敭鍏宠仈: site_id鈫扗IM_SITE锛宲ackage_id鈫扗IM_GROUP_PACKAGE锛堥渶鍦―WD寤虹珛鍥㈣喘濂楅缁村害锛夛紝platform_code鈫扗IM_COUPON_PLATFORM銆?
+瀛楁:
-DWD 字段名 业务含义 来源 ODS 字段 / 计算公式
-coupon_usage_id 团购券使用流水ID ods_group_package_log.id
-order_trade_no 订单交易号 ods_group_package_log.order_trade_no
-order_settle_id 订单结算ID ods_group_package_log.order_settle_id
-site_id 门店ID ods_group_package_log.site_id
-coupon_code 券码/核销码 ods_platform_coupon_log.coupon_code 或 verify_code(按实际字段)
-coupon_platform_id 券平台ID(美团/点评等) ods_platform_coupon_log.platform_id(在 DWD 关联 dim_coupon_platform)
-group_package_id 团购套餐定义ID ods_group_package_log.group_package_id
-group_package_name 团购套餐名称 ods_group_package.group_package_name(通过 ID 关联)
-coupon_face_value 券标称原价(市场价) ods_group_package.face_value 或平台记录中的 original_price
-coupon_settle_price 券结算价(门店实际从平台收到的金额) ods_platform_coupon_log.settle_price
-deduct_amount 本次核销抵扣到订单的金额(用于订单记账流水) 一般等于 coupon_settle_price;如有差额(例如多券叠加)可取 ods_group_package_log.deduct_amount
-verify_time 核销时间 ods_platform_coupon_log.verify_time
-member_id 绑定会员ID(如有) 若券核销与会员绑定,则取 ods_group_package_log.member_id;无则为空
+DWD 瀛楁鍚?涓氬姟鍚箟 鏉ユ簮 ODS 瀛楁 / 璁$畻鍏紡
+coupon_usage_id 鍥㈣喘鍒镐娇鐢ㄦ祦姘碔D group_buy_packages_log.id
+order_trade_no 璁㈠崟浜ゆ槗鍙?group_buy_packages_log.order_trade_no
+order_settle_id 璁㈠崟缁撶畻ID group_buy_packages_log.order_settle_id
+site_id 闂ㄥ簵ID group_buy_packages_log.site_id
+coupon_code 鍒哥爜/鏍搁攢鐮?ods_platform_coupon_log.coupon_code 鎴?verify_code锛堟寜瀹為檯瀛楁锛?
+coupon_platform_id 鍒稿钩鍙癐D锛堢編鍥?鐐硅瘎绛夛級 ods_platform_coupon_log.platform_id锛堝湪 DWD 鍏宠仈 dim_coupon_platform锛?
+group_package_id 鍥㈣喘濂楅瀹氫箟ID group_buy_packages_log.group_package_id
+group_package_name 鍥㈣喘濂楅鍚嶇О group_buy_packages.group_package_name锛堥€氳繃 ID 鍏宠仈锛?
+coupon_face_value 鍒告爣绉板師浠凤紙甯傚満浠凤級 group_buy_packages.face_value 鎴栧钩鍙拌褰曚腑鐨?original_price
+coupon_settle_price 鍒哥粨绠椾环锛堥棬搴楀疄闄呬粠骞冲彴鏀跺埌鐨勯噾棰濓級 ods_platform_coupon_log.settle_price
+deduct_amount 鏈鏍搁攢鎶垫墸鍒拌鍗曠殑閲戦锛堢敤浜庤鍗曡璐︽祦姘达級 涓€鑸瓑浜?coupon_settle_price锛涘鏈夊樊棰濓紙渚嬪澶氬埜鍙犲姞锛夊彲鍙?group_buy_packages_log.deduct_amount
+verify_time 鏍搁攢鏃堕棿 ods_platform_coupon_log.verify_time
+member_id 缁戝畾浼氬憳ID锛堝鏈夛級 鑻ュ埜鏍搁攢涓庝細鍛樼粦瀹氾紝鍒欏彇 group_buy_packages_log.member_id锛涙棤鍒欎负绌?
-• coupon_usage_id (BIGINT) - 券使用记录ID(主键)。
-• order_trade_no (BIGINT) - 订单交易号。
-• order_settle_id (BIGINT) - 订单结算ID。
-• site_id (BIGINT) - 门店ID。
-• site_table_id (BIGINT) - 台桌ID(券对应的台桌消费)。
-• assistant_id (BIGINT) - 助教ID(如券包含助教服务,可记录关联,否则为空)。
-• package_id (BIGINT) - 套餐ID,关联DIM_GROUP_PACKAGE。
-• package_name (STRING) - 套餐名称冗余。
-• platform_code (STRING) - 券来源平台代码,关联DIM_COUPON_PLATFORM获得名称。
-• coupon_code (STRING) - 券码编号。
-• deduct_amount (DECIMAL(10,2)) - 抵扣金额。该券核销抵扣的金额价值。
-• used_time (DATETIME) - 券使用时间。
-• operator_id (BIGINT) - 核销操作员ID。
-• salesman_id (BIGINT) - 销售员ID(如果有)。
-• status (STRING) - 券使用状态(通常为“已使用”,如有需要可标识异常)。
-来源及逻辑: 综合ODS_GROUP_PACKAGE_LOG和ODS_PLATFORM_COUPON_LOG的数据。考虑到一张券使用会在两张表各有一条记录,DWD层可将两者合并:以ODS_GROUP_PACKAGE_LOG为主,因为它包含抵扣金额等门店内部信息,补充平台信息(platform_code, coupon_code等从ODS_PLATFORM_COUPON_LOG获取)。合并逻辑:匹配条件可以是订单号+券ID或券码。由于coupon_code在ODS_GROUP_PACKAGE_LOG未必有,而在平台表有certificateId,需要通过deal_id或order关联核对。如果匹配困难,也可不合并,两张事实表分别建;但为方便分析,合并成一张FACT_COUPON_USAGE包含主要字段。deduct_amount直接取套餐流水的deduct_money;platform_code通过平台表或deal_id映射;coupon_code取platform表的certificateId(券码)。如果有未匹配的平台券记录,也可独立分析,此处以业务成功使用为主。FACT_COUPON_USAGE的deduct_amount会参与订单汇总的优惠总额计算,也可用于统计团购贡献收入。
-FACT_PAYMENT(支付事实表)
-描述: 记录订单的收款明细,每条记录代表店内收到一笔款项。与ODS_PAYMENT_RECORD一致,但在DWD层将支付方式代码转译,关联订单等。粒度:一笔支付流水。
-主键: id(支付流水ID)。
-外键关联: site_id→DIM_SITE,pay_method_code→DIM_PAY_METHOD,member_id→DIM_MEMBER(如支付方式为储值卡扣款,可关联对应会员)。
-字段:
+鈥?coupon_usage_id (BIGINT) - 鍒镐娇鐢ㄨ褰旾D锛堜富閿級銆?
+鈥?order_trade_no (BIGINT) - 璁㈠崟浜ゆ槗鍙枫€?
+鈥?order_settle_id (BIGINT) - 璁㈠崟缁撶畻ID銆?
+鈥?site_id (BIGINT) - 闂ㄥ簵ID銆?
+鈥?site_table_id (BIGINT) - 鍙版ID锛堝埜瀵瑰簲鐨勫彴妗屾秷璐癸級銆?
+鈥?assistant_id (BIGINT) - 鍔╂暀ID锛堝鍒稿寘鍚姪鏁欐湇鍔★紝鍙褰曞叧鑱旓紝鍚﹀垯涓虹┖锛夈€?
+鈥?package_id (BIGINT) - 濂楅ID锛屽叧鑱擠IM_GROUP_PACKAGE銆?
+鈥?package_name (STRING) - 濂楅鍚嶇О鍐椾綑銆?
+鈥?platform_code (STRING) - 鍒告潵婧愬钩鍙颁唬鐮侊紝鍏宠仈DIM_COUPON_PLATFORM鑾峰緱鍚嶇О銆?
+鈥?coupon_code (STRING) - 鍒哥爜缂栧彿銆?
+鈥?deduct_amount (DECIMAL(10,2)) - 鎶垫墸閲戦銆傝鍒告牳閿€鎶垫墸鐨勯噾棰濅环鍊笺€?
+鈥?used_time (DATETIME) - 鍒镐娇鐢ㄦ椂闂淬€?
+鈥?operator_id (BIGINT) - 鏍搁攢鎿嶄綔鍛業D銆?
+鈥?salesman_id (BIGINT) - 閿€鍞憳ID锛堝鏋滄湁锛夈€?
+鈥?status (STRING) - 鍒镐娇鐢ㄧ姸鎬侊紙閫氬父涓衡€滃凡浣跨敤鈥濓紝濡傛湁闇€瑕佸彲鏍囪瘑寮傚父锛夈€?
+鏉ユ簮鍙婇€昏緫锛?缁煎悎group_buy_packages_LOG鍜孫DS_PLATFORM_COUPON_LOG鐨勬暟鎹€傝€冭檻鍒颁竴寮犲埜浣跨敤浼氬湪涓ゅ紶琛ㄥ悇鏈変竴鏉¤褰曪紝DWD灞傚彲灏嗕袱鑰呭悎骞讹細浠DS_GROUP_PACKAGE_LOG涓轰富锛屽洜涓哄畠鍖呭惈鎶垫墸閲戦绛夐棬搴楀唴閮ㄤ俊鎭紝琛ュ厖骞冲彴淇℃伅锛坧latform_code, coupon_code绛変粠ODS_PLATFORM_COUPON_LOG鑾峰彇锛夈€傚悎骞堕€昏緫锛氬尮閰嶆潯浠跺彲浠ユ槸璁㈠崟鍙?鍒窱D鎴栧埜鐮併€傜敱浜巆oupon_code鍦∣DS_GROUP_PACKAGE_LOG鏈繀鏈夛紝鑰屽湪骞冲彴琛ㄦ湁certificateId锛岄渶瑕侀€氳繃deal_id鎴杘rder鍏宠仈鏍稿銆傚鏋滃尮閰嶅洶闅撅紝涔熷彲涓嶅悎骞讹紝涓ゅ紶浜嬪疄琛ㄥ垎鍒缓锛涗絾涓烘柟渚垮垎鏋愶紝鍚堝苟鎴愪竴寮燜ACT_COUPON_USAGE鍖呭惈涓昏瀛楁銆俤educt_amount鐩存帴鍙栧椁愭祦姘寸殑deduct_money锛沺latform_code閫氳繃骞冲彴琛ㄦ垨deal_id鏄犲皠锛沜oupon_code鍙杙latform琛ㄧ殑certificateId锛堝埜鐮侊級銆傚鏋滄湁鏈尮閰嶇殑骞冲彴鍒歌褰曪紝涔熷彲鐙珛鍒嗘瀽锛屾澶勪互涓氬姟鎴愬姛浣跨敤涓轰富銆侳ACT_COUPON_USAGE鐨刣educt_amount浼氬弬涓庤鍗曟眹鎬荤殑浼樻儬鎬婚璁$畻锛屼篃鍙敤浜庣粺璁″洟璐础鐚敹鍏ャ€?
+FACT_PAYMENT锛堟敮浠樹簨瀹炶〃锛?
+鎻忚堪: 璁板綍璁㈠崟鐨勬敹娆炬槑缁嗭紝姣忔潯璁板綍浠h〃搴楀唴鏀跺埌涓€绗旀椤广€備笌payment_transactions涓€鑷达紝浣嗗湪DWD灞傚皢鏀粯鏂瑰紡浠g爜杞瘧锛屽叧鑱旇鍗曠瓑銆傜矑搴︼細涓€绗旀敮浠樻祦姘淬€?
+涓婚敭: id锛堟敮浠樻祦姘碔D锛夈€?
+澶栭敭鍏宠仈: site_id鈫扗IM_SITE锛宲ay_method_code鈫扗IM_PAY_METHOD锛宮ember_id鈫扗IM_MEMBER锛堝鏀粯鏂瑰紡涓哄偍鍊煎崱鎵f锛屽彲鍏宠仈瀵瑰簲浼氬憳锛夈€?
+瀛楁:
-DWD 字段名 业务含义 来源 ODS 字段 / 计算公式
-payment_id 支付流水ID,主键 ods_payment_record.id
-order_trade_no 订单交易号 ods_payment_record.order_trade_no
-order_settle_id 订单结算ID ods_payment_record.order_settle_id
-site_id 门店ID ods_payment_record.site_id
-member_id 会员ID(如支付与会员绑定) ods_payment_record.member_id
-pay_method_code 支付方式编码(现金/微信/储值卡等) ods_payment_record.pay_type(在 DWD 关联 dim_pay_method)
-pay_amount 支付金额 ods_payment_record.amount
-pay_time 支付时间 ods_payment_record.pay_time
-transaction_id 第三方交易流水号 ods_payment_record.third_transaction_id(按实际字段)
-operator_id 操作员ID ods_payment_record.operator_id
-remark 备注 ods_payment_record.remark
+DWD 瀛楁鍚?涓氬姟鍚箟 鏉ユ簮 ODS 瀛楁 / 璁$畻鍏紡
+payment_id 鏀粯娴佹按ID锛屼富閿?payment_transactions.id
+order_trade_no 璁㈠崟浜ゆ槗鍙?payment_transactions.order_trade_no
+order_settle_id 璁㈠崟缁撶畻ID payment_transactions.order_settle_id
+site_id 闂ㄥ簵ID payment_transactions.site_id
+member_id 浼氬憳ID锛堝鏀粯涓庝細鍛樼粦瀹氾級 payment_transactions.member_id
+pay_method_code 鏀粯鏂瑰紡缂栫爜锛堢幇閲?寰俊/鍌ㄥ€煎崱绛夛級 payment_transactions.pay_type锛堝湪 DWD 鍏宠仈 dim_pay_method锛?
+pay_amount 鏀粯閲戦 payment_transactions.amount
+pay_time 鏀粯鏃堕棿 payment_transactions.pay_time
+transaction_id 绗笁鏂逛氦鏄撴祦姘村彿 payment_transactions.third_transaction_id锛堟寜瀹為檯瀛楁锛?
+operator_id 鎿嶄綔鍛業D payment_transactions.operator_id
+remark 澶囨敞 payment_transactions.remark
-• payment_id (BIGINT) - 支付流水ID(主键)。
-• order_trade_no (BIGINT) - 订单交易号。
-• order_settle_id (BIGINT) - 订单结算ID。
-• site_id (BIGINT) - 门店ID。
-• pay_method_code (INT) - 支付方式代码,关联DIM_PAY_METHOD获取名称。
-• pay_method_name (STRING) - 支付方式名称冗余。
-• pay_amount (DECIMAL(10,2)) - 支付金额(正值,元)。
-• pay_time (DATETIME) - 支付完成时间。
-• transaction_id (STRING) - 第三方支付流水号。
-• member_id (BIGINT) - 会员ID(如果是储值卡支付,此处记录会员账号,否则为空)。
-• operator_id (BIGINT) - 操作员ID(收款收银员)。
-来源及逻辑: 直接来源ODS_PAYMENT_RECORD清洗。pay_method_code替换原有支付方式字段,pay_method_name可通过维表填入或直接保留ODS中的文本。member_id一般不在支付记录出现,但当支付方式是“储值卡”时,可以推导对应哪个会员:支付记录本身或订单有会员关联。ETL可以在遇到储值卡支付(例如pay_method_code=5储值卡)时,将该订单的member_id填充此字段,表示这笔支付从该会员账户扣款。其他支付方式则member_id留空。FACT_PAYMENT数据用于分析付款方式占比,也用于订单汇总计算实收金额校验。
-FACT_REFUND(退款事实表)
-描述: 记录退款交易明细,每条记录代表店里退出一笔款给顾客。与ODS_REFUND_RECORD对应。粒度:一笔退款流水。
-主键: id(退款流水ID)。
-外键关联: site_id→DIM_SITE,pay_method_code→DIM_PAY_METHOD。
-字段:
+鈥?payment_id (BIGINT) - 鏀粯娴佹按ID锛堜富閿級銆?
+鈥?order_trade_no (BIGINT) - 璁㈠崟浜ゆ槗鍙枫€?
+鈥?order_settle_id (BIGINT) - 璁㈠崟缁撶畻ID銆?
+鈥?site_id (BIGINT) - 闂ㄥ簵ID銆?
+鈥?pay_method_code (INT) - 鏀粯鏂瑰紡浠g爜锛屽叧鑱擠IM_PAY_METHOD鑾峰彇鍚嶇О銆?
+鈥?pay_method_name (STRING) - 鏀粯鏂瑰紡鍚嶇О鍐椾綑銆?
+鈥?pay_amount (DECIMAL(10,2)) - 鏀粯閲戦锛堟鍊硷紝鍏冿級銆?
+鈥?pay_time (DATETIME) - 鏀粯瀹屾垚鏃堕棿銆?
+鈥?transaction_id (STRING) - 绗笁鏂规敮浠樻祦姘村彿銆?
+鈥?member_id (BIGINT) - 浼氬憳ID锛堝鏋滄槸鍌ㄥ€煎崱鏀粯锛屾澶勮褰曚細鍛樿处鍙凤紝鍚﹀垯涓虹┖锛夈€?
+鈥?operator_id (BIGINT) - 鎿嶄綔鍛業D锛堟敹娆炬敹閾跺憳锛夈€?
+鏉ユ簮鍙婇€昏緫锛?鐩存帴鏉ユ簮payment_transactions娓呮礂銆俻ay_method_code鏇挎崲鍘熸湁鏀粯鏂瑰紡瀛楁锛宲ay_method_name鍙€氳繃缁磋〃濉叆鎴栫洿鎺ヤ繚鐣橭DS涓殑鏂囨湰銆俶ember_id涓€鑸笉鍦ㄦ敮浠樿褰曞嚭鐜帮紝浣嗗綋鏀粯鏂瑰紡鏄€滃偍鍊煎崱鈥濇椂锛屽彲浠ユ帹瀵煎搴斿摢涓細鍛橈細鏀粯璁板綍鏈韩鎴栬鍗曟湁浼氬憳鍏宠仈銆侲TL鍙互鍦ㄩ亣鍒板偍鍊煎崱鏀粯锛堜緥濡俻ay_method_code=5鍌ㄥ€煎崱锛夋椂锛屽皢璇ヨ鍗曠殑member_id濉厖姝ゅ瓧娈碉紝琛ㄧず杩欑瑪鏀粯浠庤浼氬憳璐︽埛鎵f銆傚叾浠栨敮浠樻柟寮忓垯member_id鐣欑┖銆侳ACT_PAYMENT鏁版嵁鐢ㄤ簬鍒嗘瀽浠樻鏂瑰紡鍗犳瘮锛屼篃鐢ㄤ簬璁㈠崟姹囨€昏绠楀疄鏀堕噾棰濇牎楠屻€?
+FACT_REFUND锛堥€€娆句簨瀹炶〃锛?
+鎻忚堪: 璁板綍閫€娆句氦鏄撴槑缁嗭紝姣忔潯璁板綍浠h〃搴楅噷閫€鍑轰竴绗旀缁欓【瀹€備笌refund_transactions瀵瑰簲銆傜矑搴︼細涓€绗旈€€娆炬祦姘淬€?
+涓婚敭: id锛堥€€娆炬祦姘碔D锛夈€?
+澶栭敭鍏宠仈: site_id鈫扗IM_SITE锛宲ay_method_code鈫扗IM_PAY_METHOD銆?
+瀛楁:
-DWD 字段名 业务含义 来源 ODS 字段 / 计算公式
-refund_id 退款流水ID,主键 ods_refund_record.id
-order_trade_no 原订单交易号 ods_refund_record.order_trade_no
-order_settle_id 原订单结算ID ods_refund_record.order_settle_id
-site_id 门店ID ods_refund_record.site_id
-member_id 会员ID ods_refund_record.member_id
-refund_amount 退款金额 ods_refund_record.amount
-pay_method_code 原支付方式编码 ods_refund_record.pay_type
-refund_time 退款时间 ods_refund_record.refund_time
-operator_id 操作员ID ods_refund_record.operator_id
-reason 退款原因 ods_refund_record.reason
-related_payment_id 关联支付流水ID(如有) ods_refund_record.payment_id 或通过第三方流水号匹配
+DWD 瀛楁鍚?涓氬姟鍚箟 鏉ユ簮 ODS 瀛楁 / 璁$畻鍏紡
+refund_id 閫€娆炬祦姘碔D锛屼富閿?refund_transactions.id
+order_trade_no 鍘熻鍗曚氦鏄撳彿 refund_transactions.order_trade_no
+order_settle_id 鍘熻鍗曠粨绠桰D refund_transactions.order_settle_id
+site_id 闂ㄥ簵ID refund_transactions.site_id
+member_id 浼氬憳ID refund_transactions.member_id
+refund_amount 閫€娆鹃噾棰?refund_transactions.amount
+pay_method_code 鍘熸敮浠樻柟寮忕紪鐮?refund_transactions.pay_type
+refund_time 閫€娆炬椂闂?refund_transactions.refund_time
+operator_id 鎿嶄綔鍛業D refund_transactions.operator_id
+reason 閫€娆惧師鍥?refund_transactions.reason
+related_payment_id 鍏宠仈鏀粯娴佹按ID锛堝鏈夛級 refund_transactions.payment_id 鎴栭€氳繃绗笁鏂规祦姘村彿鍖归厤
-• refund_id (BIGINT) - 退款流水ID(主键)。
-• order_trade_no (BIGINT) - 原订单交易号。
-• order_settle_id (BIGINT) - 原订单结算ID。
-• site_id (BIGINT) - 门店ID。
-• pay_method_code (INT) - 退款渠道代码,关联DIM_PAY_METHOD。
-• pay_method_name (STRING) - 退款渠道名称冗余。
-• refund_amount (DECIMAL(10,2)) - 退款金额(正值表示退还给顾客的钱,元)。
-• refund_time (DATETIME) - 退款时间。
-• original_payment_id (BIGINT) - 原支付流水ID。
-• operator_id (BIGINT) - 操作员ID(执行退款的员工)。
-来源及逻辑: 由ODS_REFUND_RECORD清洗。refund_amount取绝对值(因为ODS可能存为负值,我们在fact中用正值字段表示退还金额,但在汇总计算时会作为减项)。pay_method_code译码,同支付方式维表。original_payment_id可用于关联找出是哪笔支付被退(但分析用处不大,可选保留)。FACT_REFUND主要用于财务核对和计算净收入=收款-退款。对订单汇总的影响在于如果某订单当场退款,DWS订单汇总可减去退款额;如果退款发生在不同日则视分析口径决定如何处理。
-FACT_BALANCE_CHANGE(余额变动事实表)
-描述: 记录会员储值余额的每次变动明细。每条记录对应余额增减事件。与ODS_BALANCE_CHANGE类似,但进行清洗和关联。粒度:一次余额变动。
-主键: id(余额变动ID)。
-外键关联: member_id→DIM_MEMBER,site_id→DIM_SITE,change_type→DIM_BALANCE_CHANGE_TYPE(如果需要,对类型进行描述映射)。
-字段:
+鈥?refund_id (BIGINT) - 閫€娆炬祦姘碔D锛堜富閿級銆?
+鈥?order_trade_no (BIGINT) - 鍘熻鍗曚氦鏄撳彿銆?
+鈥?order_settle_id (BIGINT) - 鍘熻鍗曠粨绠桰D銆?
+鈥?site_id (BIGINT) - 闂ㄥ簵ID銆?
+鈥?pay_method_code (INT) - 閫€娆炬笭閬撲唬鐮侊紝鍏宠仈DIM_PAY_METHOD銆?
+鈥?pay_method_name (STRING) - 閫€娆炬笭閬撳悕绉板啑浣欍€?
+鈥?refund_amount (DECIMAL(10,2)) - 閫€娆鹃噾棰濓紙姝e€艰〃绀洪€€杩樼粰椤惧鐨勯挶锛屽厓锛夈€?
+鈥?refund_time (DATETIME) - 閫€娆炬椂闂淬€?
+鈥?original_payment_id (BIGINT) - 鍘熸敮浠樻祦姘碔D銆?
+鈥?operator_id (BIGINT) - 鎿嶄綔鍛業D锛堟墽琛岄€€娆剧殑鍛樺伐锛夈€?
+鏉ユ簮鍙婇€昏緫锛?鐢監DS_REFUND_RECORD娓呮礂銆俽efund_amount鍙栫粷瀵瑰€硷紙鍥犱负ODS鍙兘瀛樹负璐熷€硷紝鎴戜滑鍦╢act涓敤姝e€煎瓧娈佃〃绀洪€€杩橀噾棰濓紝浣嗗湪姹囨€昏绠楁椂浼氫綔涓哄噺椤癸級銆俻ay_method_code璇戠爜锛屽悓鏀粯鏂瑰紡缁磋〃銆俹riginal_payment_id鍙敤浜庡叧鑱旀壘鍑烘槸鍝瑪鏀粯琚€€锛堜絾鍒嗘瀽鐢ㄥ涓嶅ぇ锛屽彲閫変繚鐣欙級銆侳ACT_REFUND涓昏鐢ㄤ簬璐㈠姟鏍稿鍜岃绠楀噣鏀跺叆=鏀舵-閫€娆俱€傚璁㈠崟姹囨€荤殑褰卞搷鍦ㄤ簬濡傛灉鏌愯鍗曞綋鍦洪€€娆撅紝DWS璁㈠崟姹囨€诲彲鍑忓幓閫€娆鹃锛涘鏋滈€€娆惧彂鐢熷湪涓嶅悓鏃ュ垯瑙嗗垎鏋愬彛寰勫喅瀹氬浣曞鐞嗐€?
+FACT_BALANCE_CHANGE锛堜綑棰濆彉鍔ㄤ簨瀹炶〃锛?
+鎻忚堪: 璁板綍浼氬憳鍌ㄥ€间綑棰濈殑姣忔鍙樺姩鏄庣粏銆傛瘡鏉¤褰曞搴斾綑棰濆鍑忎簨浠躲€備笌member_balance_changes绫讳技锛屼絾杩涜娓呮礂鍜屽叧鑱斻€傜矑搴︼細涓€娆′綑棰濆彉鍔ㄣ€?
+涓婚敭: id锛堜綑棰濆彉鍔↖D锛夈€?
+澶栭敭鍏宠仈: member_id鈫扗IM_MEMBER锛宻ite_id鈫扗IM_SITE锛宑hange_type鈫扗IM_BALANCE_CHANGE_TYPE锛堝鏋滈渶瑕侊紝瀵圭被鍨嬭繘琛屾弿杩版槧灏勶級銆?
+瀛楁:
-DWD 字段名 业务含义 来源 ODS 字段 / 计算公式
-balance_change_id 余额变动记录ID,主键 ods_balance_change.id
-member_id 会员ID ods_balance_change.member_id
-site_id 门店ID ods_balance_change.site_id
-change_amount 变动金额(正=增加,负=减少) ods_balance_change.change_amount
-balance_before 变动前余额 ods_balance_change.balance_before
-balance_after 变动后余额 ods_balance_change.balance_after
-change_type_code 变动类型编码(充值/消费/调整…) ods_balance_change.change_type,DWD 关联 dim_balance_change_type
-relate_id 关联业务记录ID ods_balance_change.relate_id
-pay_method_code 涉及支付方式(仅对充值类有意义) ods_balance_change.pay_method 或由 ods_recharge_record.pay_method 回填
-change_time 变动时间 ods_balance_change.change_time
-operator_id 操作员ID ods_balance_change.operator_id
-remark 备注 ods_balance_change.remark
+DWD 瀛楁鍚?涓氬姟鍚箟 鏉ユ簮 ODS 瀛楁 / 璁$畻鍏紡
+balance_change_id 浣欓鍙樺姩璁板綍ID锛屼富閿?member_balance_changes.id
+member_id 浼氬憳ID member_balance_changes.member_id
+site_id 闂ㄥ簵ID member_balance_changes.site_id
+change_amount 鍙樺姩閲戦锛堟=澧炲姞锛岃礋=鍑忓皯锛?member_balance_changes.change_amount
+balance_before 鍙樺姩鍓嶄綑棰?member_balance_changes.balance_before
+balance_after 鍙樺姩鍚庝綑棰?member_balance_changes.balance_after
+change_type_code 鍙樺姩绫诲瀷缂栫爜锛堝厖鍊?娑堣垂/璋冩暣鈥︼級 member_balance_changes.change_type锛孌WD 鍏宠仈 dim_balance_change_type
+relate_id 鍏宠仈涓氬姟璁板綍ID member_balance_changes.relate_id
+pay_method_code 娑夊強鏀粯鏂瑰紡锛堜粎瀵瑰厖鍊肩被鏈夋剰涔夛級 member_balance_changes.pay_method 鎴栫敱 ods_recharge_record.pay_method 鍥炲~
+change_time 鍙樺姩鏃堕棿 member_balance_changes.change_time
+operator_id 鎿嶄綔鍛業D member_balance_changes.operator_id
+remark 澶囨敞 member_balance_changes.remark
-• change_id (BIGINT) - 余额变动ID(主键)。
-• member_id (BIGINT) - 会员ID,关联DIM_MEMBER。
-• change_type_code (INT) - 变动类型编码,关联DIM_BALANCE_CHANGE_TYPE维表。
-• change_type_name (STRING) - 变动类型名称(如“充值到账”、“消费扣款”、“后台调整”)。
-• related_id (BIGINT) - 关联业务ID(充值记录ID或订单结算ID等)。
-• change_amount (DECIMAL(10,2)) - 变动金额(+增加/-减少)。
-• balance_after (DECIMAL(10,2)) - 变动后余额。
-• change_time (DATETIME) - 变动时间。
-• pay_method_code (INT) - 支付方式编码(仅当change_type为充值时有意义)。
-• pay_method_name (STRING) - 支付方式名称。
-• operator_id (BIGINT) - 操作员ID。
-来源及逻辑: 由ODS_BALANCE_CHANGE清洗。由于余额变动本身不是核心分析指标(大部分可以从充值和消费推导),此fact可选。如果保留:change_type_code统一编码,需建立DIM_BALANCE_CHANGE_TYPE,如1=充值、2=消费、3=调整等。变动类型名称通过维表给出或直接写明。related_id用于灵活关联对应事实,如充值对应FACT_RECHARGE.id,消费对应FACT_PAYMENT/FACT_ORDER_SUMMARY.id(可能比较复杂映射,可在ETL中部分实现,对应不上则留存ID备用)。支付方式仅对充值型的有意义,直接从ODS取。FACT_BALANCE_CHANGE有助于核对会员资金流,但其数据基本可以由其他事实推算,因此在数据量不大时保留以备检查。*
+鈥?change_id (BIGINT) - 浣欓鍙樺姩ID锛堜富閿級銆?
+鈥?member_id (BIGINT) - 浼氬憳ID锛屽叧鑱擠IM_MEMBER銆?
+鈥?change_type_code (INT) - 鍙樺姩绫诲瀷缂栫爜锛屽叧鑱擠IM_BALANCE_CHANGE_TYPE缁磋〃銆?
+鈥?change_type_name (STRING) - 鍙樺姩绫诲瀷鍚嶇О锛堝鈥滃厖鍊煎埌璐︹€濄€佲€滄秷璐规墸娆锯€濄€佲€滃悗鍙拌皟鏁粹€濓級銆?
+鈥?related_id (BIGINT) - 鍏宠仈涓氬姟ID锛堝厖鍊艰褰旾D鎴栬鍗曠粨绠桰D绛夛級銆?
+鈥?change_amount (DECIMAL(10,2)) - 鍙樺姩閲戦锛?澧炲姞/-鍑忓皯锛夈€?
+鈥?balance_after (DECIMAL(10,2)) - 鍙樺姩鍚庝綑棰濄€?
+鈥?change_time (DATETIME) - 鍙樺姩鏃堕棿銆?
+鈥?pay_method_code (INT) - 鏀粯鏂瑰紡缂栫爜锛堜粎褰揷hange_type涓哄厖鍊兼椂鏈夋剰涔夛級銆?
+鈥?pay_method_name (STRING) - 鏀粯鏂瑰紡鍚嶇О銆?
+鈥?operator_id (BIGINT) - 鎿嶄綔鍛業D銆?
+鏉ユ簮鍙婇€昏緫锛?鐢監DS_BALANCE_CHANGE娓呮礂銆傜敱浜庝綑棰濆彉鍔ㄦ湰韬笉鏄牳蹇冨垎鏋愭寚鏍囷紙澶ч儴鍒嗗彲浠ヤ粠鍏呭€煎拰娑堣垂鎺ㄥ锛夛紝姝act鍙€夈€傚鏋滀繚鐣欙細change_type_code缁熶竴缂栫爜锛岄渶寤虹珛DIM_BALANCE_CHANGE_TYPE锛屽1=鍏呭€笺€?=娑堣垂銆?=璋冩暣绛夈€傚彉鍔ㄧ被鍨嬪悕绉伴€氳繃缁磋〃缁欏嚭鎴栫洿鎺ュ啓鏄庛€俽elated_id鐢ㄤ簬鐏垫椿鍏宠仈瀵瑰簲浜嬪疄锛屽鍏呭€煎搴擣ACT_RECHARGE.id锛屾秷璐瑰搴擣ACT_PAYMENT/FACT_ORDER_SUMMARY.id锛堝彲鑳芥瘮杈冨鏉傛槧灏勶紝鍙湪ETL涓儴鍒嗗疄鐜帮紝瀵瑰簲涓嶄笂鍒欑暀瀛業D澶囩敤锛夈€傛敮浠樻柟寮忎粎瀵瑰厖鍊煎瀷鐨勬湁鎰忎箟锛岀洿鎺ヤ粠ODS鍙栥€侳ACT_BALANCE_CHANGE鏈夊姪浜庢牳瀵逛細鍛樿祫閲戞祦锛屼絾鍏舵暟鎹熀鏈彲浠ョ敱鍏朵粬浜嬪疄鎺ㄧ畻锛屽洜姝ゅ湪鏁版嵁閲忎笉澶ф椂淇濈暀浠ュ妫€鏌ャ€?
________________________________________
-以上事实表涵盖会员消费的主要明细。所有事实表均包含site_id以支持多店分开统计,以及包含相应的维度ID来连接维度表,从而获得丰富维度属性。
-在事实数据清洗过程中,需要确保:
-- 所有关联键有效(如销售记录里商品ID、订单号能找到对应维表或事实)。
-- 金额字段单位统一为元,类型统一使用DECIMAL(10,2)。
-- 时间字段标准化为Timestamp或DATETIME,且对应本地时区(日切按自然日00:00)。
-4. DWS层表定义(汇总层)
-DWS 层主要面向分析需求,对明细事实(DWD)进行汇总和重构,形成便于直接取用的订单级宽表和主题汇总表。本方案重点设计订单结算汇总宽表 DWS_ORDER_SUMMARY,以「每笔结账记录一行」为粒度,整合一张订单/结算单的主要指标,用于从订单视角分析:
-• 客单价与消费结构(台费/商品/助教/团购)
-• 优惠构成(会员折扣、手工折扣、团购券)
-• 支付与资金口径(含储值 / 非储值、退款、有效流水)
-• 会员贡献与行为(会员标识、会员快照等)
-如需日报等其他汇总,可在本表基础上按日期、门店等维度进行二次汇总(本次不展开)。
+浠ヤ笂浜嬪疄琛ㄦ兜鐩栦細鍛樻秷璐圭殑涓昏鏄庣粏銆傛墍鏈変簨瀹炶〃鍧囧寘鍚玸ite_id浠ユ敮鎸佸搴楀垎寮€缁熻锛屼互鍙婂寘鍚浉搴旂殑缁村害ID鏉ヨ繛鎺ョ淮搴﹁〃锛屼粠鑰岃幏寰椾赴瀵岀淮搴﹀睘鎬с€?
+鍦ㄤ簨瀹炴暟鎹竻娲楄繃绋嬩腑锛岄渶瑕佺‘淇濓細
+- 鎵€鏈夊叧鑱旈敭鏈夋晥锛堝閿€鍞褰曢噷鍟嗗搧ID銆佽鍗曞彿鑳芥壘鍒板搴旂淮琛ㄦ垨浜嬪疄锛夈€?
+- 閲戦瀛楁鍗曚綅缁熶竴涓哄厓锛岀被鍨嬬粺涓€浣跨敤DECIMAL(10,2)銆?
+- 鏃堕棿瀛楁鏍囧噯鍖栦负Timestamp鎴朌ATETIME锛屼笖瀵瑰簲鏈湴鏃跺尯锛堟棩鍒囨寜鑷劧鏃?0:00锛夈€?
+4. DWS灞傝〃瀹氫箟锛堟眹鎬诲眰锛?
+DWS 灞備富瑕侀潰鍚戝垎鏋愰渶姹傦紝瀵规槑缁嗕簨瀹烇紙DWD锛夎繘琛屾眹鎬诲拰閲嶆瀯锛屽舰鎴愪究浜庣洿鎺ュ彇鐢ㄧ殑璁㈠崟绾у琛ㄥ拰涓婚姹囨€昏〃銆傛湰鏂规閲嶇偣璁捐璁㈠崟缁撶畻姹囨€诲琛?DWS_ORDER_SUMMARY锛屼互銆屾瘡绗旂粨璐﹁褰曚竴琛屻€嶄负绮掑害锛屾暣鍚堜竴寮犺鍗?缁撶畻鍗曠殑涓昏鎸囨爣锛岀敤浜庝粠璁㈠崟瑙嗚鍒嗘瀽锛?
+鈥?瀹㈠崟浠蜂笌娑堣垂缁撴瀯锛堝彴璐?鍟嗗搧/鍔╂暀/鍥㈣喘锛?
+鈥?浼樻儬鏋勬垚锛堜細鍛樻姌鎵c€佹墜宸ユ姌鎵c€佸洟璐埜锛?
+鈥?鏀粯涓庤祫閲戝彛寰勶紙鍚偍鍊?/ 闈炲偍鍊笺€侀€€娆俱€佹湁鏁堟祦姘达級
+鈥?浼氬憳璐$尞涓庤涓猴紙浼氬憳鏍囪瘑銆佷細鍛樺揩鐓х瓑锛?
+濡傞渶鏃ユ姤绛夊叾浠栨眹鎬伙紝鍙湪鏈〃鍩虹涓婃寜鏃ユ湡銆侀棬搴楃瓑缁村害杩涜浜屾姹囨€伙紙鏈涓嶅睍寮€锛夈€?
________________________________________
-4.1 DWS_ORDER_SUMMARY(订单结算汇总表)概述
-• 表名:DWS_ORDER_SUMMARY(订单结算汇总表)
-• 粒度:一笔订单结算 / 结账单(order_settle_id)
-• 主键:order_settle_id(订单结算 ID)
-• 聚合键:site_id + order_settle_id(门店维度下唯一)
-• 主要用途:
-o 订单级经营分析:客单价、消费结构、折扣结构、支付结构、会员贡献
-o 资金视角分析:有效流水(含充值)、净收入
-o 配合 DWD 事实和维表,支撑多维 OLAP 与报表
-时间与金额口径约定
-• 订单日期:order_date = DATE(settle_time),按自然日划分,不再做 4 点切日。
-• 支付统计:所有“支付金额”统计基于 FACT_PAYMENT,仅包含支付明细,不含退款;
-退款单独通过 refund_amount 字段和退款事实表体现。
-• 金额字段:除特别说明外,均为“订单级汇总值”,即同一订单下相关明细金额的汇总结果。
-• 优惠拆分:台费、商品、助教明细中涉及会员折扣、手工折扣、团购券抵扣等,均在订单级进行归并。
-来源优先级约定
-• 若某订单级指标可同时从小票 ODS 表与 DWD fact 汇总得到:
-o 推荐以 DWD fact 为主(建模统一口径);
-o ODS 小票金额用于对账与校验;
-o 对账不一致时,以实际业务约定为准并在 ETL 规则中固化。
+4.1 DWS_ORDER_SUMMARY锛堣鍗曠粨绠楁眹鎬昏〃锛夋杩?
+鈥?琛ㄥ悕锛欴WS_ORDER_SUMMARY锛堣鍗曠粨绠楁眹鎬昏〃锛?
+鈥?绮掑害锛氫竴绗旇鍗曠粨绠?/ 缁撹处鍗曪紙order_settle_id锛?
+鈥?涓婚敭锛歰rder_settle_id锛堣鍗曠粨绠?ID锛?
+鈥?鑱氬悎閿細site_id + order_settle_id锛堥棬搴楃淮搴︿笅鍞竴锛?
+鈥?涓昏鐢ㄩ€旓細
+o 璁㈠崟绾х粡钀ュ垎鏋愶細瀹㈠崟浠枫€佹秷璐圭粨鏋勩€佹姌鎵g粨鏋勩€佹敮浠樼粨鏋勩€佷細鍛樿础鐚?
+o 璧勯噾瑙嗚鍒嗘瀽锛氭湁鏁堟祦姘达紙鍚厖鍊硷級銆佸噣鏀跺叆
+o 閰嶅悎 DWD 浜嬪疄鍜岀淮琛紝鏀拺澶氱淮 OLAP 涓庢姤琛?
+鏃堕棿涓庨噾棰濆彛寰勭害瀹?
+鈥?璁㈠崟鏃ユ湡锛歰rder_date = DATE(settle_time)锛屾寜鑷劧鏃ュ垝鍒嗭紝涓嶅啀鍋?4 鐐瑰垏鏃ャ€?
+鈥?鏀粯缁熻锛氭墍鏈夆€滄敮浠橀噾棰濃€濈粺璁″熀浜?FACT_PAYMENT锛屼粎鍖呭惈鏀粯鏄庣粏锛屼笉鍚€€娆撅紱
+閫€娆惧崟鐙€氳繃 refund_amount 瀛楁鍜岄€€娆句簨瀹炶〃浣撶幇銆?
+鈥?閲戦瀛楁锛氶櫎鐗瑰埆璇存槑澶栵紝鍧囦负鈥滆鍗曠骇姹囨€诲€尖€濓紝鍗冲悓涓€璁㈠崟涓嬬浉鍏虫槑缁嗛噾棰濈殑姹囨€荤粨鏋溿€?
+鈥?浼樻儬鎷嗗垎锛氬彴璐广€佸晢鍝併€佸姪鏁欐槑缁嗕腑娑夊強浼氬憳鎶樻墸銆佹墜宸ユ姌鎵c€佸洟璐埜鎶垫墸绛夛紝鍧囧湪璁㈠崟绾ц繘琛屽綊骞躲€?
+鏉ユ簮浼樺厛绾х害瀹?
+鈥?鑻ユ煇璁㈠崟绾ф寚鏍囧彲鍚屾椂浠庡皬绁?ODS 琛ㄤ笌 DWD fact 姹囨€诲緱鍒帮細
+o 鎺ㄨ崘浠?DWD fact 涓轰富锛堝缓妯$粺涓€鍙e緞锛夛紱
+o ODS 灏忕エ閲戦鐢ㄤ簬瀵硅处涓庢牎楠岋紱
+o 瀵硅处涓嶄竴鑷存椂锛屼互瀹為檯涓氬姟绾﹀畾涓哄噯骞跺湪 ETL 瑙勫垯涓浐鍖栥€?
________________________________________
-4.2 字段设计
-以下按功能分组列出字段。字段类型可根据目标数仓实现微调,默认金额类为 DECIMAL(18,2),数量类为 INT 或 DECIMAL(18,2),标志类为 TINYINT。
-4.2.1 基础维度与主键信息
-• order_settle_id (BIGINT)
-订单结算 ID,主键。一笔订单结算的唯一标识。
-• order_trade_no (BIGINT)
-订单交易号。与 order_settle_id 一一对应(当前假定一单一结,如后续存在多次结算需再明确规则)。
-• order_type (STRING)
-订单类型标识。'消费单' = 存在台费的消费 ;'助教单' =仅助教服务;’充值单’=仅充值无消费。用于在 ETL 中决定有效流水的分摊方式。
-• site_id (BIGINT)
-门店 ID,关联 DIM_SITE 获取门店名称、区域等信息。
-• order_date (DATE)
-订单日期(自然日)。从 settle_time 提取日期部分,用于按日汇总。
-• settle_time (DATETIME)
-结账完成时间,即订单实际关闭时间。
-• member_id (BIGINT, 可空)
-订单绑定的会员 ID,无会员则为空。
-• member_flag (TINYINT)
-会员标识;1 表示会员单(member_id 非空),0 表示非会员单,便于筛选统计。
-4.2.2 订单级金额字段(消费与优惠拆分)
-• total_table_fee (DECIMAL(18,2))
-台费实收总额。该订单所有台费实际收取金额之和(已扣除折扣与券抵扣)。
-• total_product_amount (DECIMAL(18,2))
-商品实收总额。订单中所有商品实收金额之和(不含退款/作废行)。
-• total_assistant_fee (DECIMAL(18,2))
-助教服务实收总额。订单中所有未作废助教服务实际收费总额。
-• total_coupon_deduction (DECIMAL(18,2))
-团购券抵扣总额。按券“抵扣金额”(记账侧的用券抵扣)汇总。
-• manual_discount_amount (DECIMAL(18,2))
-手工优惠总额。包含台费、助教(以及如有可识别的商品手工折扣)的人工减免金额。
-• member_discount_amount (DECIMAL(18,2))
-会员折扣总额。因会员身份享受的优惠总和(可含台费、助教、商品的会员折扣)。
-• order_original_amount (DECIMAL(18,2))
-订单原价总额(未扣减任何优惠/券的应付金额),定义为:
-order_original_amount = total_table_fee + total_product_amount + total_assistant_fee + member_discount_amount + manual_discount_amount + total_coupon_deduction。
-• order_final_amount (DECIMAL(18,2))
-订单应收金额。扣除所有优惠与券抵扣后的实收金额,理论上应满足:
-order_final_amount = total_table_fee + total_product_amount + total_assistant_fee,
-并与小票 ODS 中的订单应收金额字段保持对齐,如存在差异,以小票实际口径为准并在 ETL 层进行调整。
-4.2.3 支付拆分与退款、净收入字段
-• total_paid_amount (DECIMAL(18,2))
-实付金额总计。顾客实际支付的总金额(包括现金/电子支付 + 储值卡支付)。
-• stored_card_deduct (DECIMAL(18,2))
-储值卡支付金额。该订单由会员储值余额支付的金额。
-• external_paid_amount (DECIMAL(18,2))
-外部支付金额(非储值类支付) = total_paid_amount - stored_card_deduct。
-• pay_cash (DECIMAL(18,2), 可选)
-现金支付金额。
-• pay_wechat (DECIMAL(18,2), 可选)
-微信支付金额。
-• pay_alipay (DECIMAL(18,2), 可选)
-支付宝支付金额。
-• pay_other (DECIMAL(18,2), 可选)
-其他支付渠道金额(如银联卡、其他第三方支付等),可作为除现金/微信/支付宝/储值卡之外的汇总。
-说明:出于“避免写死支付方式枚举”的原则,具体支付渠道列(pay_xxx)可按实际需要选择是否在宽表固化,如支付方式变化频繁,可仅保留关键区分(如储值/非储值),其余在报表层通过关联支付维表透视。
-• pay_method_count (INT)
-本单使用的支付方式种类数(DISTINCT 支付方式编码)。
-• refund_amount (DECIMAL(18,2))
-退款金额。本订单相关退款总额(按正数存储),包含全额或部分退款。
-• net_income (DECIMAL(18,2))
-净收款金额。标准口径为:
-net_income = total_paid_amount - refund_amount。
-表示该订单在收款视角上的净入账金额。
-4.2.4 数量类与辅助分析字段
-• item_count (INT)
-商品行数。订单中不同商品行的数量(去重后的行数)。
-• total_item_quantity (DECIMAL(18,2))
-商品总数量。按件数/重量等单位汇总的总数。
-• assistant_count (INT)
-助教服务总次数。订单中发生的未作废助教服务记录数。
-• table_count (INT)
-使用的台桌数量。订单涉及的不同台桌数(换台场景可能大于 1)。
-• duration_total (INT)
-台桌使用总时长(分钟)。如有多台桌,会进行累加。
-• avg_item_price (DECIMAL(18,2))
-商品平均单价(实收 / 数量),定义为:
-CASE WHEN total_item_quantity > 0 THEN total_product_amount / total_item_quantity ELSE NULL END。
-4.2.5 订单级快照维度字段
-• member_name_snapshot (STRING)
-结账时会员姓名快照。来自小票 ODS;用于反映当时会员信息(会员资料后续可能变更)。
-• member_mobile_snapshot (STRING)
-结账时会员手机号快照。
-• cashier_name (STRING)
-收银员姓名。处理此订单结账的操作员,可由 ODS 收银员字段清洗得到。
-• remark (STRING)
-订单备注。如小票或订单中的附加说明。
-4.2.6 记账流水字段(Book Flow)
-用于从“经营结构 / 记账科目”视角,分析台费、助教、商品、团购在营业额中的构成,不关注支付方式。
-• book_table_flow (DECIMAL(18,2))
-台费记账流水。该订单在“台费”科目下的营业收入(含储值支付,不含作废/取消)。
-• book_assistant_flow (DECIMAL(18,2))
-助教记账流水。该订单在“助教服务”科目下的营业收入(仅统计未作废且实际计费的助教服务)。
-• book_goods_flow (DECIMAL(18,2))
-商品记账流水。该订单在“商品销售”科目下的营业收入(不含赠品)。
-• book_group_flow (DECIMAL(18,2))
-团购记账流水。该订单使用团购券形成的收入,按团购“平台结算价”入账。
-• book_order_flow (DECIMAL(18,2))
-订单记账总流水,用于经营结构分析。定义为:
-book_order_flow = book_table_flow + book_assistant_flow + book_goods_flow + book_group_flow。
-4.2.7 订单有效流水字段(Effective Order Flow)
-从“资金视角 + 含充值”的财务口径定义订单对门店实际资金流入的贡献。
-• order_effective_consume_cash (DECIMAL(18,2))
-非储值类支付中,用于消费(台费 + 助教 + 商品 + 团购)的金额。
-• order_effective_recharge_cash (DECIMAL(18,2))
-非储值类支付中,用于充值的金额(纯充值单)。
-• order_effective_flow (DECIMAL(18,2))
-订单有效流水。定义为:
-order_effective_flow = order_effective_consume_cash + order_effective_recharge_cash + book_group_flow。
-说明:
-• 按约定,“现金支付”理解为“非储值类支付”(现金 / 微信 / 支付宝 / 银行卡等);
-储值卡扣款仅视为内部结转,不视为新增资金流入。
-• 团购使用按“平台结算价”计入有效流水(通过 book_group_flow 体现),不按券面值。
+4.2 瀛楁璁捐
+浠ヤ笅鎸夊姛鑳藉垎缁勫垪鍑哄瓧娈点€傚瓧娈电被鍨嬪彲鏍规嵁鐩爣鏁颁粨瀹炵幇寰皟锛岄粯璁ら噾棰濈被涓?DECIMAL(18,2)锛屾暟閲忕被涓?INT 鎴?DECIMAL(18,2)锛屾爣蹇楃被涓?TINYINT銆?
+4.2.1 鍩虹缁村害涓庝富閿俊鎭?
+鈥?order_settle_id (BIGINT)
+璁㈠崟缁撶畻 ID锛屼富閿€備竴绗旇鍗曠粨绠楃殑鍞竴鏍囪瘑銆?
+鈥?order_trade_no (BIGINT)
+璁㈠崟浜ゆ槗鍙枫€備笌 order_settle_id 涓€涓€瀵瑰簲锛堝綋鍓嶅亣瀹氫竴鍗曚竴缁擄紝濡傚悗缁瓨鍦ㄥ娆$粨绠楅渶鍐嶆槑纭鍒欙級銆?
+鈥?order_type (STRING)
+璁㈠崟绫诲瀷鏍囪瘑銆?娑堣垂鍗? = 瀛樺湪鍙拌垂鐨勬秷璐?锛?鍔╂暀鍗? =浠呭姪鏁欐湇鍔★紱鈥欏厖鍊煎崟鈥?浠呭厖鍊兼棤娑堣垂銆傜敤浜庡湪 ETL 涓喅瀹氭湁鏁堟祦姘寸殑鍒嗘憡鏂瑰紡銆?
+鈥?site_id (BIGINT)
+闂ㄥ簵 ID锛屽叧鑱?DIM_SITE 鑾峰彇闂ㄥ簵鍚嶇О銆佸尯鍩熺瓑淇℃伅銆?
+鈥?order_date (DATE)
+璁㈠崟鏃ユ湡锛堣嚜鐒舵棩锛夈€備粠 settle_time 鎻愬彇鏃ユ湡閮ㄥ垎锛岀敤浜庢寜鏃ユ眹鎬汇€?
+鈥?settle_time (DATETIME)
+缁撹处瀹屾垚鏃堕棿锛屽嵆璁㈠崟瀹為檯鍏抽棴鏃堕棿銆?
+鈥?member_id (BIGINT, 鍙┖)
+璁㈠崟缁戝畾鐨勪細鍛?ID锛屾棤浼氬憳鍒欎负绌恒€?
+鈥?member_flag (TINYINT)
+浼氬憳鏍囪瘑锛? 琛ㄧず浼氬憳鍗曪紙member_id 闈炵┖锛夛紝0 琛ㄧず闈炰細鍛樺崟锛屼究浜庣瓫閫夌粺璁°€?
+4.2.2 璁㈠崟绾ч噾棰濆瓧娈碉紙娑堣垂涓庝紭鎯犳媶鍒嗭級
+鈥?total_table_fee (DECIMAL(18,2))
+鍙拌垂瀹炴敹鎬婚銆傝璁㈠崟鎵€鏈夊彴璐瑰疄闄呮敹鍙栭噾棰濅箣鍜岋紙宸叉墸闄ゆ姌鎵d笌鍒告姷鎵o級銆?
+鈥?total_product_amount (DECIMAL(18,2))
+鍟嗗搧瀹炴敹鎬婚銆傝鍗曚腑鎵€鏈夊晢鍝佸疄鏀堕噾棰濅箣鍜岋紙涓嶅惈閫€娆?浣滃簾琛岋級銆?
+鈥?total_assistant_fee (DECIMAL(18,2))
+鍔╂暀鏈嶅姟瀹炴敹鎬婚銆傝鍗曚腑鎵€鏈夋湭浣滃簾鍔╂暀鏈嶅姟瀹為檯鏀惰垂鎬婚銆?
+鈥?total_coupon_deduction (DECIMAL(18,2))
+鍥㈣喘鍒告姷鎵f€婚銆傛寜鍒糕€滄姷鎵i噾棰濃€濓紙璁拌处渚х殑鐢ㄥ埜鎶垫墸锛夋眹鎬汇€?
+鈥?manual_discount_amount (DECIMAL(18,2))
+鎵嬪伐浼樻儬鎬婚銆傚寘鍚彴璐广€佸姪鏁欙紙浠ュ強濡傛湁鍙瘑鍒殑鍟嗗搧鎵嬪伐鎶樻墸锛夌殑浜哄伐鍑忓厤閲戦銆?
+鈥?member_discount_amount (DECIMAL(18,2))
+浼氬憳鎶樻墸鎬婚銆傚洜浼氬憳韬唤浜彈鐨勪紭鎯犳€诲拰锛堝彲鍚彴璐广€佸姪鏁欍€佸晢鍝佺殑浼氬憳鎶樻墸锛夈€?
+鈥?order_original_amount (DECIMAL(18,2))
+璁㈠崟鍘熶环鎬婚锛堟湭鎵e噺浠讳綍浼樻儬/鍒哥殑搴斾粯閲戦锛夛紝瀹氫箟涓猴細
+order_original_amount = total_table_fee + total_product_amount + total_assistant_fee + member_discount_amount + manual_discount_amount + total_coupon_deduction銆?
+鈥?order_final_amount (DECIMAL(18,2))
+璁㈠崟搴旀敹閲戦銆傛墸闄ゆ墍鏈変紭鎯犱笌鍒告姷鎵e悗鐨勫疄鏀堕噾棰濓紝鐞嗚涓婂簲婊¤冻锛?
+order_final_amount = total_table_fee + total_product_amount + total_assistant_fee锛?
+骞朵笌灏忕エ ODS 涓殑璁㈠崟搴旀敹閲戦瀛楁淇濇寔瀵归綈锛屽瀛樺湪宸紓锛屼互灏忕エ瀹為檯鍙e緞涓哄噯骞跺湪 ETL 灞傝繘琛岃皟鏁淬€?
+4.2.3 鏀粯鎷嗗垎涓庨€€娆俱€佸噣鏀跺叆瀛楁
+鈥?total_paid_amount (DECIMAL(18,2))
+瀹炰粯閲戦鎬昏銆傞【瀹㈠疄闄呮敮浠樼殑鎬婚噾棰濓紙鍖呮嫭鐜伴噾/鐢靛瓙鏀粯 + 鍌ㄥ€煎崱鏀粯锛夈€?
+鈥?stored_card_deduct (DECIMAL(18,2))
+鍌ㄥ€煎崱鏀粯閲戦銆傝璁㈠崟鐢变細鍛樺偍鍊间綑棰濇敮浠樼殑閲戦銆?
+鈥?external_paid_amount (DECIMAL(18,2))
+澶栭儴鏀粯閲戦锛堥潪鍌ㄥ€肩被鏀粯锛?= total_paid_amount - stored_card_deduct銆?
+鈥?pay_cash (DECIMAL(18,2), 鍙€?
+鐜伴噾鏀粯閲戦銆?
+鈥?pay_wechat (DECIMAL(18,2), 鍙€?
+寰俊鏀粯閲戦銆?
+鈥?pay_alipay (DECIMAL(18,2), 鍙€?
+鏀粯瀹濇敮浠橀噾棰濄€?
+鈥?pay_other (DECIMAL(18,2), 鍙€?
+鍏朵粬鏀粯娓犻亾閲戦锛堝閾惰仈鍗°€佸叾浠栫涓夋柟鏀粯绛夛級锛屽彲浣滀负闄ょ幇閲?寰俊/鏀粯瀹?鍌ㄥ€煎崱涔嬪鐨勬眹鎬汇€?
+璇存槑锛氬嚭浜庘€滈伩鍏嶅啓姝绘敮浠樻柟寮忔灇涓锯€濈殑鍘熷垯锛屽叿浣撴敮浠樻笭閬撳垪锛坧ay_xxx锛夊彲鎸夊疄闄呴渶瑕侀€夋嫨鏄惁鍦ㄥ琛ㄥ浐鍖栵紝濡傛敮浠樻柟寮忓彉鍖栭绻侊紝鍙粎淇濈暀鍏抽敭鍖哄垎锛堝鍌ㄥ€?闈炲偍鍊硷級锛屽叾浣欏湪鎶ヨ〃灞傞€氳繃鍏宠仈鏀粯缁磋〃閫忚銆?
+鈥?pay_method_count (INT)
+鏈崟浣跨敤鐨勬敮浠樻柟寮忕绫绘暟锛圖ISTINCT 鏀粯鏂瑰紡缂栫爜锛夈€?
+鈥?refund_amount (DECIMAL(18,2))
+閫€娆鹃噾棰濄€傛湰璁㈠崟鐩稿叧閫€娆炬€婚锛堟寜姝f暟瀛樺偍锛夛紝鍖呭惈鍏ㄩ鎴栭儴鍒嗛€€娆俱€?
+鈥?net_income (DECIMAL(18,2))
+鍑€鏀舵閲戦銆傛爣鍑嗗彛寰勪负锛?
+net_income = total_paid_amount - refund_amount銆?
+琛ㄧず璇ヨ鍗曞湪鏀舵瑙嗚涓婄殑鍑€鍏ヨ处閲戦銆?
+4.2.4 鏁伴噺绫讳笌杈呭姪鍒嗘瀽瀛楁
+鈥?item_count (INT)
+鍟嗗搧琛屾暟銆傝鍗曚腑涓嶅悓鍟嗗搧琛岀殑鏁伴噺锛堝幓閲嶅悗鐨勮鏁帮級銆?
+鈥?total_item_quantity (DECIMAL(18,2))
+鍟嗗搧鎬绘暟閲忋€傛寜浠舵暟/閲嶉噺绛夊崟浣嶆眹鎬荤殑鎬绘暟銆?
+鈥?assistant_count (INT)
+鍔╂暀鏈嶅姟鎬绘鏁般€傝鍗曚腑鍙戠敓鐨勬湭浣滃簾鍔╂暀鏈嶅姟璁板綍鏁般€?
+鈥?table_count (INT)
+浣跨敤鐨勫彴妗屾暟閲忋€傝鍗曟秹鍙婄殑涓嶅悓鍙版鏁帮紙鎹㈠彴鍦烘櫙鍙兘澶т簬 1锛夈€?
+鈥?duration_total (INT)
+鍙版浣跨敤鎬绘椂闀匡紙鍒嗛挓锛夈€傚鏈夊鍙版锛屼細杩涜绱姞銆?
+鈥?avg_item_price (DECIMAL(18,2))
+鍟嗗搧骞冲潎鍗曚环锛堝疄鏀?/ 鏁伴噺锛夛紝瀹氫箟涓猴細
+CASE WHEN total_item_quantity > 0 THEN total_product_amount / total_item_quantity ELSE NULL END銆?
+4.2.5 璁㈠崟绾у揩鐓х淮搴﹀瓧娈?
+鈥?member_name_snapshot (STRING)
+缁撹处鏃朵細鍛樺鍚嶅揩鐓с€傛潵鑷皬绁?ODS锛涚敤浜庡弽鏄犲綋鏃朵細鍛樹俊鎭紙浼氬憳璧勬枡鍚庣画鍙兘鍙樻洿锛夈€?
+鈥?member_mobile_snapshot (STRING)
+缁撹处鏃朵細鍛樻墜鏈哄彿蹇収銆?
+鈥?cashier_name (STRING)
+鏀堕摱鍛樺鍚嶃€傚鐞嗘璁㈠崟缁撹处鐨勬搷浣滃憳锛屽彲鐢?ODS 鏀堕摱鍛樺瓧娈垫竻娲楀緱鍒般€?
+鈥?remark (STRING)
+璁㈠崟澶囨敞銆傚灏忕エ鎴栬鍗曚腑鐨勯檮鍔犺鏄庛€?
+4.2.6 璁拌处娴佹按瀛楁锛圔ook Flow锛?
+鐢ㄤ簬浠庘€滅粡钀ョ粨鏋?/ 璁拌处绉戠洰鈥濊瑙掞紝鍒嗘瀽鍙拌垂銆佸姪鏁欍€佸晢鍝併€佸洟璐湪钀ヤ笟棰濅腑鐨勬瀯鎴愶紝涓嶅叧娉ㄦ敮浠樻柟寮忋€?
+鈥?book_table_flow (DECIMAL(18,2))
+鍙拌垂璁拌处娴佹按銆傝璁㈠崟鍦ㄢ€滃彴璐光€濈鐩笅鐨勮惀涓氭敹鍏ワ紙鍚偍鍊兼敮浠橈紝涓嶅惈浣滃簾/鍙栨秷锛夈€?
+鈥?book_assistant_flow (DECIMAL(18,2))
+鍔╂暀璁拌处娴佹按銆傝璁㈠崟鍦ㄢ€滃姪鏁欐湇鍔♀€濈鐩笅鐨勮惀涓氭敹鍏ワ紙浠呯粺璁℃湭浣滃簾涓斿疄闄呰璐圭殑鍔╂暀鏈嶅姟锛夈€?
+鈥?book_goods_flow (DECIMAL(18,2))
+鍟嗗搧璁拌处娴佹按銆傝璁㈠崟鍦ㄢ€滃晢鍝侀攢鍞€濈鐩笅鐨勮惀涓氭敹鍏ワ紙涓嶅惈璧犲搧锛夈€?
+鈥?book_group_flow (DECIMAL(18,2))
+鍥㈣喘璁拌处娴佹按銆傝璁㈠崟浣跨敤鍥㈣喘鍒稿舰鎴愮殑鏀跺叆锛屾寜鍥㈣喘鈥滃钩鍙扮粨绠椾环鈥濆叆璐︺€?
+鈥?book_order_flow (DECIMAL(18,2))
+璁㈠崟璁拌处鎬绘祦姘达紝鐢ㄤ簬缁忚惀缁撴瀯鍒嗘瀽銆傚畾涔変负锛?
+book_order_flow = book_table_flow + book_assistant_flow + book_goods_flow + book_group_flow銆?
+4.2.7 璁㈠崟鏈夋晥娴佹按瀛楁锛圗ffective Order Flow锛?
+浠庘€滆祫閲戣瑙?+ 鍚厖鍊尖€濈殑璐㈠姟鍙e緞瀹氫箟璁㈠崟瀵归棬搴楀疄闄呰祫閲戞祦鍏ョ殑璐$尞銆?
+鈥?order_effective_consume_cash (DECIMAL(18,2))
+闈炲偍鍊肩被鏀粯涓紝鐢ㄤ簬娑堣垂锛堝彴璐?+ 鍔╂暀 + 鍟嗗搧 + 鍥㈣喘锛夌殑閲戦銆?
+鈥?order_effective_recharge_cash (DECIMAL(18,2))
+闈炲偍鍊肩被鏀粯涓紝鐢ㄤ簬鍏呭€肩殑閲戦锛堢函鍏呭€煎崟锛夈€?
+鈥?order_effective_flow (DECIMAL(18,2))
+璁㈠崟鏈夋晥娴佹按銆傚畾涔変负锛?
+order_effective_flow = order_effective_consume_cash + order_effective_recharge_cash + book_group_flow銆?
+璇存槑锛?
+鈥?鎸夌害瀹氾紝鈥滅幇閲戞敮浠樷€濈悊瑙d负鈥滈潪鍌ㄥ€肩被鏀粯鈥濓紙鐜伴噾 / 寰俊 / 鏀粯瀹?/ 閾惰鍗$瓑锛夛紱
+鍌ㄥ€煎崱鎵f浠呰涓哄唴閮ㄧ粨杞紝涓嶈涓烘柊澧炶祫閲戞祦鍏ャ€?
+鈥?鍥㈣喘浣跨敤鎸夆€滃钩鍙扮粨绠椾环鈥濊鍏ユ湁鏁堟祦姘达紙閫氳繃 book_group_flow 浣撶幇锛夛紝涓嶆寜鍒搁潰鍊笺€?
________________________________________
-4.3 来源及汇总逻辑说明
-本表主要通过订单 ID / 交易号在各 DWD 事实表间关联,并按订单聚合得到。以下为关键字段的来源与口径。
-4.3.1 消费与优惠类金额字段
-1. total_table_fee(台费实收合计)
-o 来源:FACT_TABLE_USAGE.final_table_fee
-o 过滤:is_canceled = 0(未作废台费记录)
-o 聚合:按 site_id, order_settle_id 或 order_trade_no 分组求和。
-o 如 ODS 小票中有台费汇总字段,可用于对账。
-2. total_product_amount(商品实收合计)
-o 来源:FACT_SALE_ITEM.final_amount
-o 建议过滤:is_refunded = 0 或按实际业务标识排除已退款/作废行。
-o 聚合:按订单维度求和。
-3. total_assistant_fee(助教服务实收合计)
-o 来源:FACT_ASSISTANT_SERVICE.final_service_fee / final_fee
-o 过滤:is_canceled = 0(排除助教废除记录)
-o 聚合:按订单维度求和。
-助教相关金额口径说明(新增)
-DWS 层所有“助教相关金额”字段,统一遵循以下口径:
-• 订单维度的助教金额(如“助教基础课本笔订单总额”、“助教附加课本笔订单总额”)均由 DWD 助教服务事实表中 final_fee 汇总而来:
-o 基础课金额:汇总 service_type = 基础课 且 final_fee 的金额;
-o 附加课金额:汇总 service_type = 附加课 且 final_fee 的金额。
-• is_canceled = 1 的废除记录:
-o 其 final_fee 可能为 0(完全未计费)或为部分计费金额(已服务部分计费,未服务部分不计费);
-o DWS 订单层仅按 final_fee 汇总,因此废除未计费部分不会计入订单有效流水。
-如需分析“助教服务原本应收与实际入账”的差额,可在专题报表中使用 DWD 助教事实表的 base_fee 与 final_fee 差值,并结合助教废除表中的原因字段进行拆解。
+4.3 鏉ユ簮鍙婃眹鎬婚€昏緫璇存槑
+鏈〃涓昏閫氳繃璁㈠崟 ID / 浜ゆ槗鍙峰湪鍚?DWD 浜嬪疄琛ㄩ棿鍏宠仈锛屽苟鎸夎鍗曡仛鍚堝緱鍒般€備互涓嬩负鍏抽敭瀛楁鐨勬潵婧愪笌鍙e緞銆?
+4.3.1 娑堣垂涓庝紭鎯犵被閲戦瀛楁
+1. total_table_fee锛堝彴璐瑰疄鏀跺悎璁★級
+o 鏉ユ簮锛欶ACT_TABLE_USAGE.final_table_fee
+o 杩囨护锛歩s_canceled = 0锛堟湭浣滃簾鍙拌垂璁板綍锛?
+o 鑱氬悎锛氭寜 site_id, order_settle_id 鎴?order_trade_no 鍒嗙粍姹傚拰銆?
+o 濡?ODS 灏忕エ涓湁鍙拌垂姹囨€诲瓧娈碉紝鍙敤浜庡璐︺€?
+2. total_product_amount锛堝晢鍝佸疄鏀跺悎璁★級
+o 鏉ユ簮锛欶ACT_SALE_ITEM.final_amount
+o 寤鸿杩囨护锛歩s_refunded = 0 鎴栨寜瀹為檯涓氬姟鏍囪瘑鎺掗櫎宸查€€娆?浣滃簾琛屻€?
+o 鑱氬悎锛氭寜璁㈠崟缁村害姹傚拰銆?
+3. total_assistant_fee锛堝姪鏁欐湇鍔″疄鏀跺悎璁★級
+o 鏉ユ簮锛欶ACT_ASSISTANT_SERVICE.final_service_fee / final_fee
+o 杩囨护锛歩s_canceled = 0锛堟帓闄ゅ姪鏁欏簾闄よ褰曪級
+o 鑱氬悎锛氭寜璁㈠崟缁村害姹傚拰銆?
+鍔╂暀鐩稿叧閲戦鍙e緞璇存槑锛堟柊澧烇級
+DWS 灞傛墍鏈夆€滃姪鏁欑浉鍏抽噾棰濃€濆瓧娈碉紝缁熶竴閬靛惊浠ヤ笅鍙e緞锛?
+鈥?璁㈠崟缁村害鐨勫姪鏁欓噾棰濓紙濡傗€滃姪鏁欏熀纭€璇炬湰绗旇鍗曟€婚鈥濄€佲€滃姪鏁欓檮鍔犺鏈瑪璁㈠崟鎬婚鈥濓級鍧囩敱 DWD 鍔╂暀鏈嶅姟浜嬪疄琛ㄤ腑 final_fee 姹囨€昏€屾潵锛?
+o 鍩虹璇鹃噾棰濓細姹囨€?service_type = 鍩虹璇?涓?final_fee 鐨勯噾棰濓紱
+o 闄勫姞璇鹃噾棰濓細姹囨€?service_type = 闄勫姞璇?涓?final_fee 鐨勯噾棰濄€?
+鈥?is_canceled = 1 鐨勫簾闄よ褰曪細
+o 鍏?final_fee 鍙兘涓?0锛堝畬鍏ㄦ湭璁¤垂锛夋垨涓洪儴鍒嗚璐归噾棰濓紙宸叉湇鍔¢儴鍒嗚璐癸紝鏈湇鍔¢儴鍒嗕笉璁¤垂锛夛紱
+o DWS 璁㈠崟灞備粎鎸?final_fee 姹囨€伙紝鍥犳搴熼櫎鏈璐归儴鍒嗕笉浼氳鍏ヨ鍗曟湁鏁堟祦姘淬€?
+濡傞渶鍒嗘瀽鈥滃姪鏁欐湇鍔″師鏈簲鏀朵笌瀹為檯鍏ヨ处鈥濈殑宸锛屽彲鍦ㄤ笓棰樻姤琛ㄤ腑浣跨敤 DWD 鍔╂暀浜嬪疄琛ㄧ殑 base_fee 涓?final_fee 宸€硷紝骞剁粨鍚堝姪鏁欏簾闄よ〃涓殑鍘熷洜瀛楁杩涜鎷嗚В銆?
-4. total_coupon_deduction(团购券抵扣金额)
-o 来源:FACT_COUPON_USAGE.deduct_amount
-o 过滤:状态为正常核销(如存在 status 字段需排除异常状态)
-o 聚合:按订单维度求和。
-5. member_discount_amount 与 manual_discount_amount
-o 台费、助教层面通常存在明确的会员折扣字段和手工折扣字段;
-o 商品层面若无法区分折扣类型,可采用保守规则:
- 将商品 discount_amount 统一计入 member_discount_amount(或由业务口径统一归类);
- manual_discount_amount 至少包括台费与助教的手工折扣;
-o 若未来商品折扣可拆分为“会员折扣 vs 手工折扣”,对应字段可再调整拆分逻辑。
-6. order_original_amount、order_final_amount
-o 按公式计算,确保与明细和小票金额一致;
-o 优先以 DWD 汇总为主,小票 ODS 用于对账和异常检查。
-4.3.2 记账流水口径(Book Flow)
-记账流水只关注“消费结构科目”,不关心支付方式与资金来源,不包含充值,也不直接回滚退款。
-1. book_table_flow(台费记账流水)
-o 来源表:FACT_TABLE_USAGE
-o 过滤:order_trade_no = 当前订单,is_canceled = 0
-o 聚合:book_table_flow = SUM(final_table_fee)
-o 含义:已经扣除所有优惠和券抵扣后记入“台费”科目的营业收入。
-2. book_assistant_flow(助教记账流水)
-o 来源表:FACT_ASSISTANT_SERVICE
-o 过滤:order_trade_no = 当前订单,is_canceled = 0
-o 聚合:book_assistant_flow = SUM(final_fee)
-o 含义:仅统计实际完成并计费的助教服务。
-3. book_goods_flow(商品记账流水)
-o 来源表:FACT_SALE_ITEM
-o 过滤:order_trade_no = 当前订单,is_gift = 0(排除赠品)
-o 聚合:book_goods_flow = SUM(final_amount)
-o 含义:不计入赠送商品的金额,赠品不构成营业收入。
-4. book_group_flow(团购记账流水)
-o 来源表:FACT_COUPON_USAGE
-o 过滤:order_trade_no = 当前订单,状态为正常核销
-o 聚合:book_group_flow = SUM(settle_price)
-o 含义:按团购“平台结算价”入账,而非券面值。多张券累加。
-5. book_order_flow(订单记账总流水)
-o 定义:
+4. total_coupon_deduction锛堝洟璐埜鎶垫墸閲戦锛?
+o 鏉ユ簮锛欶ACT_COUPON_USAGE.deduct_amount
+o 杩囨护锛氱姸鎬佷负姝e父鏍搁攢锛堝瀛樺湪 status 瀛楁闇€鎺掗櫎寮傚父鐘舵€侊級
+o 鑱氬悎锛氭寜璁㈠崟缁村害姹傚拰銆?
+5. member_discount_amount 涓?manual_discount_amount
+o 鍙拌垂銆佸姪鏁欏眰闈㈤€氬父瀛樺湪鏄庣‘鐨勪細鍛樻姌鎵e瓧娈靛拰鎵嬪伐鎶樻墸瀛楁锛?
+o 鍟嗗搧灞傞潰鑻ユ棤娉曞尯鍒嗘姌鎵g被鍨嬶紝鍙噰鐢ㄤ繚瀹堣鍒欙細
+飩?灏嗗晢鍝?discount_amount 缁熶竴璁″叆 member_discount_amount锛堟垨鐢变笟鍔″彛寰勭粺涓€褰掔被锛夛紱
+飩?manual_discount_amount 鑷冲皯鍖呮嫭鍙拌垂涓庡姪鏁欑殑鎵嬪伐鎶樻墸锛?
+o 鑻ユ湭鏉ュ晢鍝佹姌鎵e彲鎷嗗垎涓衡€滀細鍛樻姌鎵?vs 鎵嬪伐鎶樻墸鈥濓紝瀵瑰簲瀛楁鍙啀璋冩暣鎷嗗垎閫昏緫銆?
+6. order_original_amount銆乷rder_final_amount
+o 鎸夊叕寮忚绠楋紝纭繚涓庢槑缁嗗拰灏忕エ閲戦涓€鑷达紱
+o 浼樺厛浠?DWD 姹囨€讳负涓伙紝灏忕エ ODS 鐢ㄤ簬瀵硅处鍜屽紓甯告鏌ャ€?
+4.3.2 璁拌处娴佹按鍙e緞锛圔ook Flow锛?
+璁拌处娴佹按鍙叧娉ㄢ€滄秷璐圭粨鏋勭鐩€濓紝涓嶅叧蹇冩敮浠樻柟寮忎笌璧勯噾鏉ユ簮锛屼笉鍖呭惈鍏呭€硷紝涔熶笉鐩存帴鍥炴粴閫€娆俱€?
+1. book_table_flow锛堝彴璐硅璐︽祦姘达級
+o 鏉ユ簮琛細FACT_TABLE_USAGE
+o 杩囨护锛歰rder_trade_no = 褰撳墠璁㈠崟锛宨s_canceled = 0
+o 鑱氬悎锛歜ook_table_flow = SUM(final_table_fee)
+o 鍚箟锛氬凡缁忔墸闄ゆ墍鏈変紭鎯犲拰鍒告姷鎵e悗璁板叆鈥滃彴璐光€濈鐩殑钀ヤ笟鏀跺叆銆?
+2. book_assistant_flow锛堝姪鏁欒璐︽祦姘达級
+o 鏉ユ簮琛細FACT_ASSISTANT_SERVICE
+o 杩囨护锛歰rder_trade_no = 褰撳墠璁㈠崟锛宨s_canceled = 0
+o 鑱氬悎锛歜ook_assistant_flow = SUM(final_fee)
+o 鍚箟锛氫粎缁熻瀹為檯瀹屾垚骞惰璐圭殑鍔╂暀鏈嶅姟銆?
+3. book_goods_flow锛堝晢鍝佽璐︽祦姘达級
+o 鏉ユ簮琛細FACT_SALE_ITEM
+o 杩囨护锛歰rder_trade_no = 褰撳墠璁㈠崟锛宨s_gift = 0锛堟帓闄よ禒鍝侊級
+o 鑱氬悎锛歜ook_goods_flow = SUM(final_amount)
+o 鍚箟锛氫笉璁″叆璧犻€佸晢鍝佺殑閲戦锛岃禒鍝佷笉鏋勬垚钀ヤ笟鏀跺叆銆?
+4. book_group_flow锛堝洟璐璐︽祦姘达級
+o 鏉ユ簮琛細FACT_COUPON_USAGE
+o 杩囨护锛歰rder_trade_no = 褰撳墠璁㈠崟锛岀姸鎬佷负姝e父鏍搁攢
+o 鑱氬悎锛歜ook_group_flow = SUM(settle_price)
+o 鍚箟锛氭寜鍥㈣喘鈥滃钩鍙扮粨绠椾环鈥濆叆璐︼紝鑰岄潪鍒搁潰鍊笺€傚寮犲埜绱姞銆?
+5. book_order_flow锛堣鍗曡璐︽€绘祦姘达級
+o 瀹氫箟锛?
book_order_flow = book_table_flow + book_assistant_flow + book_goods_flow + book_group_flow
-o 用途:
- 回答“这笔订单在台费 / 助教 / 商品 / 团购各记入了多少营业收入”;
- 为各科目营业结构占比分析提供基础。
-o 退款:记账流水不直接冲减退款;退款在 FACT_REFUND 和 refund_amount 中单独体现。如需“记账净流水”口径,可在报表层:
-记账净流水 = SUM(book_order_flow) - 对应退款折返金额。
-4.3.3 订单有效流水口径(Effective Order Flow)
-订单有效流水从资金实际流入视角定义,关注“新增外部资金 + 团购结算收入”。
-基本原则
-• 储值卡支付:视为内部资金在储值账户与消费之间转移,不计入“新增资金流入”,但其对应的消费仍计入各 book_* 流水。
-• 非储值类支付(现金、微信、支付宝、银行卡等):视为门店真实流入资金。
-• 充值:
-o 充值发生时(非储值支付充值到储值账户)计入有效流水;
-o 之后使用储值卡消费时不再重复计入有效流水。
-• 团购:按平台结算价计入有效流水(通过 book_group_flow 反映)。
-1)非储值消费款 order_effective_consume_cash
-• 来源:FACT_PAYMENT + 当前订单类型判断。
-• 支付过滤:
-o 仅统计本订单中支付方式为“非储值类”的支付记录(如 pay_method_code ∈【现金、微信、支付宝、银行卡…】),排除储值卡。
-• 业务前提:
-o 当前项目约定单笔订单不会同时包含“消费 + 充值”,即订单要么是消费单,要么是充值单;
-o 在此前提下可采用简单口径:
- 若订单为消费单(存在台费/商品/助教等消费,且无充值行):
- order_effective_consume_cash = 该订单所有非储值支付总额
- order_effective_recharge_cash = 0
- 如未来出现同单既消费又充值的复杂场景,则需在 ETL 中按明细拆分非储值金额并按消费与充值比例分摊。
-2)非储值充值款 order_effective_recharge_cash
-• 来源:FACT_PAYMENT + 充值类事实(如 FACT_RECHARGE 或 FACT_BALANCE_CHANGE 中的充值记录)。
-• 对于标记为“充值业务”的订单(无消费,仅充值):
-o order_effective_recharge_cash = 本订单所有非储值类支付总额
+o 鐢ㄩ€旓細
+飩?鍥炵瓟鈥滆繖绗旇鍗曞湪鍙拌垂 / 鍔╂暀 / 鍟嗗搧 / 鍥㈣喘鍚勮鍏ヤ簡澶氬皯钀ヤ笟鏀跺叆鈥濓紱
+飩?涓哄悇绉戠洰钀ヤ笟缁撴瀯鍗犳瘮鍒嗘瀽鎻愪緵鍩虹銆?
+o 閫€娆撅細璁拌处娴佹按涓嶇洿鎺ュ啿鍑忛€€娆撅紱閫€娆惧湪 FACT_REFUND 鍜?refund_amount 涓崟鐙綋鐜般€傚闇€鈥滆璐﹀噣娴佹按鈥濆彛寰勶紝鍙湪鎶ヨ〃灞傦細
+璁拌处鍑€娴佹按 = SUM(book_order_flow) - 瀵瑰簲閫€娆炬姌杩旈噾棰濄€?
+4.3.3 璁㈠崟鏈夋晥娴佹按鍙e緞锛圗ffective Order Flow锛?
+璁㈠崟鏈夋晥娴佹按浠庤祫閲戝疄闄呮祦鍏ヨ瑙掑畾涔夛紝鍏虫敞鈥滄柊澧炲閮ㄨ祫閲?+ 鍥㈣喘缁撶畻鏀跺叆鈥濄€?
+鍩烘湰鍘熷垯
+鈥?鍌ㄥ€煎崱鏀粯锛氳涓哄唴閮ㄨ祫閲戝湪鍌ㄥ€艰处鎴蜂笌娑堣垂涔嬮棿杞Щ锛屼笉璁″叆鈥滄柊澧炶祫閲戞祦鍏モ€濓紝浣嗗叾瀵瑰簲鐨勬秷璐逛粛璁″叆鍚?book_* 娴佹按銆?
+鈥?闈炲偍鍊肩被鏀粯锛堢幇閲戙€佸井淇°€佹敮浠樺疂銆侀摱琛屽崱绛夛級锛氳涓洪棬搴楃湡瀹炴祦鍏ヨ祫閲戙€?
+鈥?鍏呭€硷細
+o 鍏呭€煎彂鐢熸椂锛堥潪鍌ㄥ€兼敮浠樺厖鍊煎埌鍌ㄥ€艰处鎴凤級璁″叆鏈夋晥娴佹按锛?
+o 涔嬪悗浣跨敤鍌ㄥ€煎崱娑堣垂鏃朵笉鍐嶉噸澶嶈鍏ユ湁鏁堟祦姘淬€?
+鈥?鍥㈣喘锛氭寜骞冲彴缁撶畻浠疯鍏ユ湁鏁堟祦姘达紙閫氳繃 book_group_flow 鍙嶆槧锛夈€?
+1锛夐潪鍌ㄥ€兼秷璐规 order_effective_consume_cash
+鈥?鏉ユ簮锛欶ACT_PAYMENT + 褰撳墠璁㈠崟绫诲瀷鍒ゆ柇銆?
+鈥?鏀粯杩囨护锛?
+o 浠呯粺璁℃湰璁㈠崟涓敮浠樻柟寮忎负鈥滈潪鍌ㄥ€肩被鈥濈殑鏀粯璁板綍锛堝 pay_method_code 鈭堛€愮幇閲戙€佸井淇°€佹敮浠樺疂銆侀摱琛屽崱鈥︺€戯級锛屾帓闄ゅ偍鍊煎崱銆?
+鈥?涓氬姟鍓嶆彁锛?
+o 褰撳墠椤圭洰绾﹀畾鍗曠瑪璁㈠崟涓嶄細鍚屾椂鍖呭惈鈥滄秷璐?+ 鍏呭€尖€濓紝鍗宠鍗曡涔堟槸娑堣垂鍗曪紝瑕佷箞鏄厖鍊煎崟锛?
+o 鍦ㄦ鍓嶆彁涓嬪彲閲囩敤绠€鍗曞彛寰勶細
+飩?鑻ヨ鍗曚负娑堣垂鍗曪紙瀛樺湪鍙拌垂/鍟嗗搧/鍔╂暀绛夋秷璐癸紝涓旀棤鍏呭€艰锛夛細
+飩?order_effective_consume_cash = 璇ヨ鍗曟墍鏈夐潪鍌ㄥ€兼敮浠樻€婚
+飩?order_effective_recharge_cash = 0
+飩?濡傛湭鏉ュ嚭鐜板悓鍗曟棦娑堣垂鍙堝厖鍊肩殑澶嶆潅鍦烘櫙锛屽垯闇€鍦?ETL 涓寜鏄庣粏鎷嗗垎闈炲偍鍊奸噾棰濆苟鎸夋秷璐逛笌鍏呭€兼瘮渚嬪垎鎽娿€?
+2锛夐潪鍌ㄥ€煎厖鍊兼 order_effective_recharge_cash
+鈥?鏉ユ簮锛欶ACT_PAYMENT + 鍏呭€肩被浜嬪疄锛堝 FACT_RECHARGE 鎴?FACT_BALANCE_CHANGE 涓殑鍏呭€艰褰曪級銆?
+鈥?瀵逛簬鏍囪涓衡€滃厖鍊间笟鍔♀€濈殑璁㈠崟锛堟棤娑堣垂锛屼粎鍏呭€硷級锛?
+o order_effective_recharge_cash = 鏈鍗曟墍鏈夐潪鍌ㄥ€肩被鏀粯鎬婚
o order_effective_consume_cash = 0
-• 含义:表示门店通过本订单向会员账户“存入”的真实资金,在充值时计入有效流水,后续消费只在消费端反映 book_* 流水。
-3)订单有效流水 order_effective_flow
-• 定义:
+鈥?鍚箟锛氳〃绀洪棬搴楅€氳繃鏈鍗曞悜浼氬憳璐︽埛鈥滃瓨鍏モ€濈殑鐪熷疄璧勯噾锛屽湪鍏呭€兼椂璁″叆鏈夋晥娴佹按锛屽悗缁秷璐瑰彧鍦ㄦ秷璐圭鍙嶆槧 book_* 娴佹按銆?
+3锛夎鍗曟湁鏁堟祦姘?order_effective_flow
+鈥?瀹氫箟锛?
order_effective_flow = order_effective_consume_cash + order_effective_recharge_cash + book_group_flow
-• 解释:
-o order_effective_consume_cash:非储值支付直接形成的消费收入;
-o order_effective_recharge_cash:非储值支付形成的充值收入;
-o book_group_flow:团购平台以结算价方式为门店带来的收入(本质上是平台代收后结算)。
-• 含义:
-o 从财务角度,可简单理解为“本订单为门店带来的对外现金收入”,包含消费类收入与充值类收入,并将团购结算价纳入视为一类外部资金流入。
-• 聚合使用:
-o 某一周期(自然日 / 自然月等)的有效流水:
- SUM(order_effective_flow)
-o 若需净有效流水口径,可在报表层按:
- 净有效流水 = SUM(order_effective_flow) - SUM(refund_amount)
- 是否将退款冲减有效流水取决于财务要求,可在指标定义中进一步固化。
-4) 充值单识别:
-若某 order_settle_id 在 FACT_TABLE_USAGE / FACT_SALE_ITEM / FACT_ASSISTANT_SERVICE 中均无记录,
-但在 FACT_RECHARGE 或 BALANCE_CHANGE(type=充值)中存在记录,则将该订单标记为 '充值订单';
-其对应的非储值支付金额归入 order_effective_recharge_cash。
+鈥?瑙i噴锛?
+o order_effective_consume_cash锛氶潪鍌ㄥ€兼敮浠樼洿鎺ュ舰鎴愮殑娑堣垂鏀跺叆锛?
+o order_effective_recharge_cash锛氶潪鍌ㄥ€兼敮浠樺舰鎴愮殑鍏呭€兼敹鍏ワ紱
+o book_group_flow锛氬洟璐钩鍙颁互缁撶畻浠锋柟寮忎负闂ㄥ簵甯︽潵鐨勬敹鍏ワ紙鏈川涓婃槸骞冲彴浠f敹鍚庣粨绠楋級銆?
+鈥?鍚箟锛?
+o 浠庤储鍔¤搴︼紝鍙畝鍗曠悊瑙d负鈥滄湰璁㈠崟涓洪棬搴楀甫鏉ョ殑瀵瑰鐜伴噾鏀跺叆鈥濓紝鍖呭惈娑堣垂绫绘敹鍏ヤ笌鍏呭€肩被鏀跺叆锛屽苟灏嗗洟璐粨绠椾环绾冲叆瑙嗕负涓€绫诲閮ㄨ祫閲戞祦鍏ャ€?
+鈥?鑱氬悎浣跨敤锛?
+o 鏌愪竴鍛ㄦ湡锛堣嚜鐒舵棩 / 鑷劧鏈堢瓑锛夌殑鏈夋晥娴佹按锛?
+飩?SUM(order_effective_flow)
+o 鑻ラ渶鍑€鏈夋晥娴佹按鍙e緞锛屽彲鍦ㄦ姤琛ㄥ眰鎸夛細
+飩?鍑€鏈夋晥娴佹按 = SUM(order_effective_flow) - SUM(refund_amount)
+飩?鏄惁灏嗛€€娆惧啿鍑忔湁鏁堟祦姘村彇鍐充簬璐㈠姟瑕佹眰锛屽彲鍦ㄦ寚鏍囧畾涔変腑杩涗竴姝ュ浐鍖栥€?
+4) 鍏呭€煎崟璇嗗埆锛?
+鑻ユ煇 order_settle_id 鍦?FACT_TABLE_USAGE / FACT_SALE_ITEM / FACT_ASSISTANT_SERVICE 涓潎鏃犺褰曪紝
+浣嗗湪 FACT_RECHARGE 鎴?BALANCE_CHANGE锛坱ype=鍏呭€硷級涓瓨鍦ㄨ褰曪紝鍒欏皢璇ヨ鍗曟爣璁颁负 '鍏呭€艰鍗?锛?
+鍏跺搴旂殑闈炲偍鍊兼敮浠橀噾棰濆綊鍏?order_effective_recharge_cash銆?
________________________________________
-4.4 指标示例与分析口径
-基于 DWS_ORDER_SUMMARY,可直接或衍生出常用分析指标,包括但不限于:
-• 客单价:
-o 可用 order_final_amount 或 total_paid_amount 做为客单消费额;
-o 周期客单价 = 周期内消费总额 / 订单数。
-• 会员贡献率:
-o 会员订单占比:member_flag = 1 的订单数 / 总订单数;
-o 会员金额贡献:SUM(order_final_amount WHERE member_flag = 1) / SUM(order_final_amount)。
-• 折扣率:
-o 订单折扣率:
-(member_discount_amount + manual_discount_amount + total_coupon_deduction) / order_original_amount。
-• 商品丰富度与平均件数:
-o 每单商品数:AVG(total_item_quantity);
-o 商品行数与平均行数:AVG(item_count)。
-• 支付结构:
-o 非储值 vs 储值:external_paid_amount 与 stored_card_deduct 的占比;
-o 若保留 pay_xxx 字段,可直接分析各支付渠道结构。
-• 经营结构(记账流水视角):
-o 台费 / 商品 / 助教 / 团购占比:
-各 book_*_flow / book_order_flow。
-• 有效流水与净收入:
-o 有效流水:SUM(order_effective_flow);
-o 净收入(资金口径):SUM(order_effective_flow) - SUM(refund_amount) 或直接使用 SUM(net_income),两者口径需在报表层统一。
+4.4 鎸囨爣绀轰緥涓庡垎鏋愬彛寰?
+鍩轰簬 DWS_ORDER_SUMMARY锛屽彲鐩存帴鎴栬鐢熷嚭甯哥敤鍒嗘瀽鎸囨爣锛屽寘鎷絾涓嶉檺浜庯細
+鈥?瀹㈠崟浠凤細
+o 鍙敤 order_final_amount 鎴?total_paid_amount 鍋氫负瀹㈠崟娑堣垂棰濓紱
+o 鍛ㄦ湡瀹㈠崟浠?= 鍛ㄦ湡鍐呮秷璐规€婚 / 璁㈠崟鏁般€?
+鈥?浼氬憳璐$尞鐜囷細
+o 浼氬憳璁㈠崟鍗犳瘮锛歮ember_flag = 1 鐨勮鍗曟暟 / 鎬昏鍗曟暟锛?
+o 浼氬憳閲戦璐$尞锛歋UM(order_final_amount WHERE member_flag = 1) / SUM(order_final_amount)銆?
+鈥?鎶樻墸鐜囷細
+o 璁㈠崟鎶樻墸鐜囷細
+(member_discount_amount + manual_discount_amount + total_coupon_deduction) / order_original_amount銆?
+鈥?鍟嗗搧涓板瘜搴︿笌骞冲潎浠舵暟锛?
+o 姣忓崟鍟嗗搧鏁帮細AVG(total_item_quantity)锛?
+o 鍟嗗搧琛屾暟涓庡钩鍧囪鏁帮細AVG(item_count)銆?
+鈥?鏀粯缁撴瀯锛?
+o 闈炲偍鍊?vs 鍌ㄥ€硷細external_paid_amount 涓?stored_card_deduct 鐨勫崰姣旓紱
+o 鑻ヤ繚鐣?pay_xxx 瀛楁锛屽彲鐩存帴鍒嗘瀽鍚勬敮浠樻笭閬撶粨鏋勩€?
+鈥?缁忚惀缁撴瀯锛堣璐︽祦姘磋瑙掞級锛?
+o 鍙拌垂 / 鍟嗗搧 / 鍔╂暀 / 鍥㈣喘鍗犳瘮锛?
+鍚?book_*_flow / book_order_flow銆?
+鈥?鏈夋晥娴佹按涓庡噣鏀跺叆锛?
+o 鏈夋晥娴佹按锛歋UM(order_effective_flow)锛?
+o 鍑€鏀跺叆锛堣祫閲戝彛寰勶級锛歋UM(order_effective_flow) - SUM(refund_amount) 鎴栫洿鎺ヤ娇鐢?SUM(net_income)锛屼袱鑰呭彛寰勯渶鍦ㄦ姤琛ㄥ眰缁熶竴銆?
________________________________________
-4.5 注意事项
-• 时间口径统一按自然日(order_date)进行日粒度汇总,暂不区分时段(闲时/忙时)类别。
-• 支付方式、订单状态等枚举值应通过维表转义,DWS 层只保留必要的代码与少量关键标签,避免在宽表中写死业务枚举。
-• 多门店扩展:site_id 是主键和分组维度的一部分,可直接按门店、城市、区域等维度进行汇总分析。
-• 退款:
-o 不直接回滚记账流水字段(book_*)和有效流水字段;
-o 通过 refund_amount 在报表层定义“净收入 / 净有效流水”等指标实现冲减。
+4.5 娉ㄦ剰浜嬮」
+鈥?鏃堕棿鍙e緞缁熶竴鎸夎嚜鐒舵棩锛坥rder_date锛夎繘琛屾棩绮掑害姹囨€伙紝鏆備笉鍖哄垎鏃舵锛堥棽鏃?蹇欐椂锛夌被鍒€?
+鈥?鏀粯鏂瑰紡銆佽鍗曠姸鎬佺瓑鏋氫妇鍊煎簲閫氳繃缁磋〃杞箟锛孌WS 灞傚彧淇濈暀蹇呰鐨勪唬鐮佷笌灏戦噺鍏抽敭鏍囩锛岄伩鍏嶅湪瀹借〃涓啓姝讳笟鍔℃灇涓俱€?
+鈥?澶氶棬搴楁墿灞曪細site_id 鏄富閿拰鍒嗙粍缁村害鐨勪竴閮ㄥ垎锛屽彲鐩存帴鎸夐棬搴椼€佸煄甯傘€佸尯鍩熺瓑缁村害杩涜姹囨€诲垎鏋愩€?
+鈥?閫€娆撅細
+o 涓嶇洿鎺ュ洖婊氳璐︽祦姘村瓧娈碉紙book_*锛夊拰鏈夋晥娴佹按瀛楁锛?
+o 閫氳繃 refund_amount 鍦ㄦ姤琛ㄥ眰瀹氫箟鈥滃噣鏀跺叆 / 鍑€鏈夋晥娴佹按鈥濈瓑鎸囨爣瀹炵幇鍐插噺銆?
+
diff --git a/README.md b/README.md
index 1e19776..54e9f85 100644
--- a/README.md
+++ b/README.md
@@ -1,79 +1,88 @@
-# 台球场 ETL 系统
+# 飞球 ETL 系统
-用于台球门店业务的数据采集与入湖:从上游 API 拉取订单、支付、会员、库存等数据,先落地 ODS,再清洗写入事实/维度表,并提供运行追踪、增量游标、数据质量检查与测试脚手架。
+面向门店业务的 ETL 流水线:从上游 API 拉取订单/支付/会员/库存等 JSON,先落地 ODS,随后清洗装载 DWD(含 SCD2 维度、事实增量),并提供质量校验与回归验证工具。
-## 核心特性
-- **两阶段链路**:ODS 原始留痕 + DWD/事实表清洗,支持回放与重跑。
-- **任务注册与调度**:`TaskRegistry` 统一管理任务代码,`ETLScheduler` 负责游标、运行记录和失败隔离。
-- **统一底座**:配置(默认值 + `.env` + CLI 覆盖)、分页/重试的 API 客户端、批量 Upsert 的数据库封装、SCD2 维度处理、质量检查。
-- **测试与回放**:ONLINE/OFFLINE 模式切换,`run_tests.py`/`test_presets.py` 支持参数化测试;`MANUAL_INGEST` 可将归档 JSON 重灌入 ODS。
-- **可安装**:`setup.py` / `entry_point` 提供 `etl-billiards` 命令,或直接 `python -m cli.main` 运行。
+## 功能要点
+- 双层形态:ODS 原始保留 + DWD 清洗标准化,支持回放与重载。
+- 任务调度:ETLScheduler 统一管理任务、日志、失败隔离,CLI 友好。
+- 配置体系:默认值 + .env + CLI 覆盖,便于多环境运行。
+- 批量入库:通用 ODS Loader / SCD2 维度合并 / 事实增量写入。
+- 回归校验:示例 JSON、行数对照、质量报告,便于快速验证。
-## 仓库结构(摘录)
-- `etl_billiards/config`:默认配置、环境变量解析、配置加载。
-- `etl_billiards/api`:HTTP 客户端,内置重试/分页。
-- `etl_billiards/database`:连接管理、批量 Upsert。
-- `etl_billiards/tasks`:业务任务(ORDERS、PAYMENTS…)、ODS 任务、DWD 任务、人工回放;`base_task.py`/`base_dwd_task.py` 提供模板。
-- `etl_billiards/loaders`:事实/维度/ODS Loader;`scd/` 为 SCD2。
-- `etl_billiards/orchestration`:调度器、任务注册表、游标与运行追踪。
-- `etl_billiards/scripts`:测试执行器、数据库连通性检测、预置测试指令。
-- `etl_billiards/tests`:单元/集成测试与离线 JSON 归档。
-- `C:\dev\LLTQ\export\temp\source-data-doc`:测试示例数据 JSON
+## 仓库结构
+- etl_billiards/config:默认配置、环境变量解析、CLI 覆盖。
+- etl_billiards/api:HTTP 客户端与重试、分页封装。
+- etl_billiards/database:连接管理、批量 upsert 封装、DDL。
+- etl_billiards/tasks:业务任务(ODS/DWD/初始化/手工灌入等)。
+- etl_billiards/loaders:ODS/DWD/SCD Loader 实现。
+- etl_billiards/orchestration:调度器与任务注册。
+- etl_billiards/scripts:测试、重建、探活脚本。
+- etl_billiards/reports:质量报告输出。
+- etl_billiards/docs:ODS->DWD 映射说明、样例 JSON 说明。
-## 支持的任务代码
-- **事实/维度**:`ORDERS`、`PAYMENTS`、`REFUNDS`、`INVENTORY_CHANGE`、`COUPON_USAGE`、`MEMBERS`、`ASSISTANTS`、`PRODUCTS`、`TABLES`、`PACKAGES_DEF`、`TOPUPS`、`TABLE_DISCOUNT`、`ASSISTANT_ABOLISH`、`LEDGER`、`TICKET_DWD`、`PAYMENTS_DWD`、`MEMBERS_DWD`。
-- **ODS 原始采集**:`ODS_ORDER_SETTLE`、`ODS_TABLE_USE`、`ODS_ASSISTANT_LEDGER`、`ODS_ASSISTANT_ABOLISH`、`ODS_GOODS_LEDGER`、`ODS_PAYMENT`、`ODS_REFUND`、`ODS_COUPON_VERIFY`、`ODS_MEMBER`、`ODS_MEMBER_CARD`、`ODS_PACKAGE`、`ODS_INVENTORY_STOCK`、`ODS_INVENTORY_CHANGE`。
-- **辅助**:`MANUAL_INGEST`(将归档 JSON 回放到 ODS)。
+## 支持的主要任务
+- ODS:订单结算、台费流水、助教流水/废除、库存、支付、退款、会员、充值结算等。
+- DWD:维度表(门店/台桌/会员/助教/商品等)与事实表(结算、支付、退款、充值、台费、商品销售等)。
+- 初始化与手工灌入:INIT_ODS_SCHEMA、MANUAL_INGEST。
## 快速开始
-1. **环境要求**:Python 3.10+、PostgreSQL。推荐在 `etl_billiards/` 目录下执行命令。
-2. **安装依赖**
+1) 环境:Python 3.10+,PostgreSQL 可用;在 etl_billiards/ 下运行命令。
+2) 安装依赖:
```bash
cd etl_billiards
pip install -r requirements.txt
# 开发模式:pip install -e .
```
-3. **配置 `.env`**
+3) 配置 .env(示例关键项):
```bash
- cp .env.example .env
- # 核心项
- PG_DSN=postgresql://user:pwd@host:5432/LLZQ
+ PG_DSN=postgresql://user:pwd@host:5432/LLZQ-test
API_BASE=https://api.example.com
API_TOKEN=your_token
STORE_ID=2790685415443269
- EXPORT_ROOT=/path/to/export
- LOG_ROOT=/path/to/logs
+ EXPORT_ROOT=C:\dev\LLTQ\export\JSON
+ LOG_ROOT=C:\dev\LLTQ\export\LOG
+ INGEST_SOURCE_DIR=C:\dev\LLTQ\export\test-json-doc
```
- 配置的生效顺序为 “默认值” < “环境变量/.env” < “CLI 参数”。
-4. **运行任务**
+4) 初始化库表:
```bash
- # 运行默认任务集
- python -m cli.main
-
- # 按需选择任务(逗号分隔)
- python -m cli.main --tasks ODS_ORDER_SETTLE,ORDERS,PAYMENTS
-
- # Dry-run 示例(不提交事务)
- python -m cli.main --tasks ORDERS --dry-run
-
- # Windows 批处理
- ..\\run_etl.bat --tasks PAYMENTS
+ python -m cli.main --tasks INIT_ODS_SCHEMA --pipeline-flow INGEST_ONLY --ingest-source "C:\dev\LLTQ\export\test-json-doc"
+ # 或直接用 psql 执行 schema_*.sql
+ ```
+5) 运行任务(示例):
+ ```bash
+ # 默认任务列表(见 config/defaults.py)
+ python -m cli.main
+ # 指定任务
+ python -m cli.main --tasks settlement_records,recharge_settlements
+ # 仅手工灌入示例 JSON
+ python -m cli.main --tasks MANUAL_INGEST --pipeline-flow INGEST_ONLY --ingest-source "C:\dev\LLTQ\export\test-json-doc"
```
-5. **查看输出**:日志目录与导出目录分别由 `LOG_ROOT`、`EXPORT_ROOT` 控制;运行追踪与游标记录写入数据库 `etl_admin.*` 表。
-## 数据与运行流转
-- CLI 解析参数 → `AppConfig.load()` 组装配置 → `ETLScheduler` 创建 DB/API/游标/运行追踪器。
-- 调度器按任务代码实例化任务,读取/推进游标,落盘运行记录。
-- 任务模板:确定时间窗口 → 调用 API/ODS 数据 → 解析校验 → Loader 批量 Upsert/SCD2 → 质量检查 → 提交事务并回写游标。
+## 运行与数据流
+- CLI 解析参数 -> AppConfig.load 合并配置 -> ETLScheduler 创建 DB/API/日志上下文 -> 实例化任务 -> 拉取/清洗/写入。
+- ODS 任务:调用 API,分页提取,字段解析后批量 upsert;payload 保留原始 JSON。
+- DWD 任务:维度表做 SCD2,事实表按时间水位增量写入。
-## 测试与回放
-- 单元/集成测试:`pytest` 或 `python scripts/run_tests.py --suite online`。
-- 预置组合:`python scripts/run_tests.py --preset offline_realdb`(见 `scripts/test_presets.py`)。
-- 离线模式:`TEST_MODE=OFFLINE TEST_JSON_ARCHIVE_DIR=... pytest tests/unit/test_etl_tasks_offline.py`。
-- 数据库连通性:`python scripts/test_db_connection.py --dsn postgresql://... --query "SELECT 1"`。
+## 测试与回归
+- 单测/集成:pytest 或 python scripts/run_tests.py --suite online。
+- 离线模式:TEST_MODE=OFFLINE TEST_JSON_ARCHIVE_DIR=... pytest tests/unit/test_etl_tasks_offline.py。
+- 数据库连通:python scripts/test_db_connection.py --dsn --query "SELECT 1"。
## 其他提示
-- `.env.example` 列出了所有常用配置;`config/defaults.py` 记录默认值与任务窗口配置。
-- `loaders/ods/generic.py` 支持定义主键/列名即可落 ODS;`tasks/manual_ingest_task.py` 可将归档 JSON 快速灌入对应 ODS 表。
-- 需要新增任务时,在 `tasks/` 中实现并在 `orchestration/task_registry.py` 注册即可复用调度能力。
+- .env.example 罗列全部配置;config/defaults.py 给出默认值与任务窗口。
+- loaders/ods/generic.py 支持自定义主键/冲突列; asks/manual_ingest_task.py 可将示例 JSON 快速灌入对应 ODS 表。
+- 添加新任务:在 asks/ 中实现并在 orchestration/task_registry.py 注册。
+
+## ODS 任务与调度使用
+- 注册:etl_admin.etl_task 已启用 INIT_ODS_SCHEMA、MANUAL_INGEST(store_id=2790685415443269,可按需追加其他任务)。
+- 示例数据目录:默认 C:\dev\LLTQ\export\test-json-doc(可在 .env 的 INGEST_SOURCE_DIR 覆盖)。
+- 一键重建+灌入:
+ `bash
+ python -m cli.main --tasks INIT_ODS_SCHEMA,MANUAL_INGEST --pipeline-flow INGEST_ONLY --ingest-source "C:\dev\LLTQ\export\test-json-doc"
+ `
+- 行数对照:etl_billiards/ods_row_report.json 存示例 JSON 行数与 ODS 行数,可用于回归校验。
+- 备份:etl_billiards/backups/ 保存当前 schema_ODS_doc.sql、 asks/manual_ingest_task.py 版本。
+- 充值结算 ODS:recharge_settlements 已按 settleList 扁平化主字段(
+echarge_order_id 主键,金额/状态/快照等列),site_profile 与 payload 保留原始 JSON;任务 recharge_settlements 直接写入该表,手工灌入会自动展开
+echarge_settlements.json。
diff --git a/etl_billiards/.env b/etl_billiards/.env
index 06bca67..9d42149 100644
--- a/etl_billiards/.env
+++ b/etl_billiards/.env
@@ -1,53 +1,49 @@
-# 数据库配置(真实库)
+# -*- coding: utf-8 -*-
+# 文件说明:ETL 环境变量(config/env_parser.py 读取),用于数据库连接、目录与运行参数。
+
+# 数据库连接字符串,config/env_parser.py -> db.dsn,所有任务必需
PG_DSN=postgresql://local-Python:Neo-local-1991125@100.64.0.4:5432/LLZQ-test
+# 数据库连接超时秒,config/env_parser.py -> db.connect_timeout_sec
PG_CONNECT_TIMEOUT=10
-# 如需拆分配置:PG_HOST=... PG_PORT=... PG_NAME=... PG_USER=... PG_PASSWORD=...
-# API配置(如需走真实接口再填写)
-API_BASE=https://api.example.com
-API_TOKEN=your_token_here
-# API_TIMEOUT=20
-# API_PAGE_SIZE=200
-# API_RETRY_MAX=3
-
-# 应用配置
+# 门店/租户ID,config/env_parser.py -> app.store_id,任务调度记录使用
STORE_ID=2790685415443269
-# TIMEZONE=Asia/Taipei
-# SCHEMA_OLTP=billiards
-# SCHEMA_ETL=etl_admin
+# 时区标识,config/env_parser.py -> app.timezone
+TIMEZONE=Asia/Taipei
-# 路径配置
-EXPORT_ROOT=C:\dev\LLTQ\export\JSON
+# API 基础地址,config/env_parser.py -> api.base_url,FETCH 类任务调用
+API_BASE=https://api.example.com
+# API 鉴权 Token,config/env_parser.py -> api.token,FETCH 类任务调用
+API_TOKEN=your_token_here
+# API 请求超时秒,config/env_parser.py -> api.timeout_sec
+API_TIMEOUT=20
+# API 分页大小,config/env_parser.py -> api.page_size
+API_PAGE_SIZE=200
+# API 最大重试次数,config/env_parser.py -> api.retries.max_attempts
+API_RETRY_MAX=3
+
+# 日志根目录,config/env_parser.py -> io.log_root,Init/任务运行写日志
LOG_ROOT=C:\dev\LLTQ\export\LOG
-FETCH_ROOT=
-INGEST_SOURCE_DIR=
-WRITE_PRETTY_JSON=false
-PGCLIENTENCODING=utf8
+# JSON 导出根目录,config/env_parser.py -> io.export_root,FETCH 产出及 INIT 准备
+EXPORT_ROOT=C:\dev\LLTQ\export\JSON
-# ETL配置
+# FETCH 模式本地输出目录,config/env_parser.py -> pipeline.fetch_root
+FETCH_ROOT=C:\dev\LLTQ\export\JSON
+# 本地入库 JSON 目录,config/env_parser.py -> pipeline.ingest_source_dir,MANUAL_INGEST/INGEST_ONLY 使用
+INGEST_SOURCE_DIR=C:\dev\LLTQ\export\test-json-doc
+
+# JSON 漂亮格式输出开关,config/env_parser.py -> io.write_pretty_json
+WRITE_PRETTY_JSON=false
+
+# 运行流程:FULL / FETCH_ONLY / INGEST_ONLY,config/env_parser.py -> pipeline.flow
+PIPELINE_FLOW=FULL
+# 指定任务列表(逗号分隔,覆盖默认),config/env_parser.py -> run.tasks
+# RUN_TASKS=INIT_ODS_SCHEMA,MANUAL_INGEST
+
+# 窗口/补偿参数,config/env_parser.py -> run.*
OVERLAP_SECONDS=120
WINDOW_BUSY_MIN=30
WINDOW_IDLE_MIN=180
IDLE_START=04:00
IDLE_END=16:00
ALLOW_EMPTY_RESULT_ADVANCE=true
-
-# 清洗配置
-LOG_UNKNOWN_FIELDS=true
-HASH_ALGO=sha1
-STRICT_NUMERIC=true
-ROUND_MONEY_SCALE=2
-
-# 测试/离线模式(真实库联调建议 ONLINE)
-TEST_MODE=ONLINE
-TEST_JSON_ARCHIVE_DIR=tests/source-data-doc
-TEST_JSON_TEMP_DIR=/tmp/etl_billiards_json_tmp
-
-# 测试数据库
-TEST_DB_DSN=postgresql://local-Python:Neo-local-1991125@100.64.0.4:5432/LLZQ-test
-
-# ODS ؽűãã
-JSON_DOC_DIR=C:\dev\LLTQ\export\test-json-doc
-ODS_INCLUDE_FILES=
-ODS_DROP_SCHEMA_FIRST=true
-
diff --git a/etl_billiards/backups/manual_ingest_task.py b/etl_billiards/backups/manual_ingest_task.py
new file mode 100644
index 0000000..dca6230
--- /dev/null
+++ b/etl_billiards/backups/manual_ingest_task.py
@@ -0,0 +1,321 @@
+# -*- coding: utf-8 -*-
+"""鎵嬪伐绀轰緥鏁版嵁鐏屽叆锛氭寜 schema_ODS_doc.sql 涓婚敭/鍞竴閿壒閲忓啓鍏?ODS銆?""
+from __future__ import annotations
+
+import json
+import os
+from datetime import datetime
+from typing import Any, Iterable
+
+from psycopg2.extras import Json
+
+from .base_task import BaseTask
+
+
+class ManualIngestTask(BaseTask):
+ """鏈湴绀轰緥 JSON 鐏屽叆 ODS锛岀‘淇濊〃鍚嶃€佷富閿€佹彃鍏ュ垪涓?schema_ODS_doc.sql 瀵归綈銆?""
+
+ def __init__(self, config, db_connection, api_client, logger):
+ """鍒濆鍖栫紦瀛橈紝閬垮厤閲嶅鏌ヨ琛ㄧ粨鏋勩€?""
+ super().__init__(config, db_connection, api_client, logger)
+ self._table_columns_cache: dict[str, list[str]] = {}
+
+ # 鏂囦欢鍏抽敭璇?-> 鐩爣琛紙鍖归厤 C:\dev\LLTQ\export\temp\source-data-doc 涓嬬ず鑼?JSON 鍚嶇О锛? FILE_MAPPING: list[tuple[tuple[str, ...], str]] = [
+ (("浼氬憳妗f", "member_profiles"), "billiards_ods.member_profiles"),
+ (("浣欓鍙樻洿璁板綍", "member_balance_changes"), "billiards_ods.member_balance_changes"),
+ (("鍌ㄥ€煎崱鍒楄〃", "member_stored_value_cards"), "billiards_ods.member_stored_value_cards"),
+ (("鍏呭€艰褰?, "recharge_settlements"), "billiards_ods.recharge_settlements"),
+ (("缁撹处璁板綍", "settlement_records"), "billiards_ods.settlement_records"),
+ (("鍔╂暀搴熼櫎", "assistant_cancellation_records"), "billiards_ods.assistant_cancellation_records"),
+ (("鍔╂暀璐﹀彿", "assistant_accounts_master"), "billiards_ods.assistant_accounts_master"),
+ (("鍔╂暀娴佹按", "assistant_service_records"), "billiards_ods.assistant_service_records"),
+ (("鍙版鍒楄〃", "site_tables_master"), "billiards_ods.site_tables_master"),
+ (("鍙拌垂鎵撴姌", "table_fee_discount_records"), "billiards_ods.table_fee_discount_records"),
+ (("鍙拌垂娴佹按", "table_fee_transactions"), "billiards_ods.table_fee_transactions"),
+ (("搴撳瓨鍙樺寲璁板綍1", "goods_stock_movements"), "billiards_ods.goods_stock_movements"),
+ (("搴撳瓨鍙樺寲璁板綍2", "stock_goods_category_tree"), "billiards_ods.stock_goods_category_tree"),
+ (("搴撳瓨姹囨€?, "goods_stock_summary"), "billiards_ods.goods_stock_summary"),
+ (("鏀粯璁板綍", "payment_transactions"), "billiards_ods.payment_transactions"),
+ (("閫€娆捐褰?, "refund_transactions"), "billiards_ods.refund_transactions"),
+ (("骞冲彴楠屽埜璁板綍", "platform_coupon_redemption_records"), "billiards_ods.platform_coupon_redemption_records"),
+ (("鍥㈣喘濂楅娴佹按", "group_buy_redemption_records"), "billiards_ods.group_buy_packages_ledger"),
+ (("鍥㈣喘濂楅", "group_buy_packages"), "billiards_ods.group_buy_packages"),
+ (("灏忕エ璇︽儏", "settlement_ticket_details"), "billiards_ods.settlement_ticket_details"),
+ (("闂ㄥ簵鍟嗗搧妗f", "store_goods_master"), "billiards_ods.store_goods_master"),
+ (("鍟嗗搧妗f", "tenant_goods_master"), "billiards_ods.tenant_goods_master"),
+ (("闂ㄥ簵鍟嗗搧閿€鍞褰?, "store_goods_sales_records"), "billiards_ods.store_goods_sales_records"),
+ ]
+
+ # 琛ㄧ粨鏋勮鏄庯細pk=涓婚敭鍒?None 琛ㄧず鏃犲啿绐佹洿鏂?锛宩son_cols=闇€瑕佸崟鍒楀瓨 JSONB 鐨勫瓧娈? TABLE_SPECS: dict[str, dict[str, Any]] = {
+ "billiards_ods.member_profiles": {"pk": "id"},
+ "billiards_ods.member_balance_changes": {"pk": "id"},
+ "billiards_ods.member_stored_value_cards": {"pk": "id"},
+ "billiards_ods.recharge_settlements": {"pk": None, "json_cols": ["settleList", "siteProfile"]},
+ "billiards_ods.settlement_records": {"pk": None, "json_cols": ["settleList", "siteProfile"]},
+ "billiards_ods.assistant_cancellation_records": {"pk": "id", "json_cols": ["siteProfile"]},
+ "billiards_ods.assistant_accounts_master": {"pk": "id"},
+ "billiards_ods.assistant_service_records": {"pk": "id", "json_cols": ["siteProfile"]},
+ "billiards_ods.site_tables_master": {"pk": "id"},
+ "billiards_ods.table_fee_discount_records": {"pk": "id", "json_cols": ["siteProfile", "tableProfile"]},
+ "billiards_ods.table_fee_transactions": {"pk": "id", "json_cols": ["siteProfile"]},
+ "billiards_ods.goods_stock_movements": {"pk": "siteGoodsStockId"},
+ "billiards_ods.stock_goods_category_tree": {"pk": "id", "json_cols": ["categoryBoxes"]},
+ "billiards_ods.goods_stock_summary": {"pk": "siteGoodsId"},
+ "billiards_ods.payment_transactions": {"pk": "id", "json_cols": ["siteProfile"]},
+ "billiards_ods.refund_transactions": {"pk": "id", "json_cols": ["siteProfile"]},
+ "billiards_ods.platform_coupon_redemption_records": {"pk": "id"},
+ "billiards_ods.tenant_goods_master": {"pk": "id"},
+ "billiards_ods.group_buy_packages": {"pk": "id"},
+ "billiards_ods.group_buy_packages_ledger": {"pk": "id"},
+ "billiards_ods.settlement_ticket_details": {
+ "pk": "orderSettleId",
+ "json_cols": ["memberProfile", "orderItem", "tenantMemberCardLogs"],
+ },
+ "billiards_ods.store_goods_master": {"pk": "id"},
+ "billiards_ods.store_goods_sales_records": {"pk": "id"},
+ }
+
+ def get_task_code(self) -> str:
+ """杩斿洖浠诲姟缂栫爜銆?""
+ return "MANUAL_INGEST"
+
+ def execute(self, cursor_data: dict | None = None) -> dict:
+ """浠庣ず鑼冪洰褰曡鍙?JSON锛屾寜琛?涓婚敭鎵归噺鍏ュ簱銆?""
+ data_dir = (
+ self.config.get("manual.data_dir")
+ or self.config.get("pipeline.ingest_source_dir")
+ or r"c:\dev\LLTQ\ETL\feiqiu-ETL\etl_billiards\tests\testdata_json"
+ )
+ if not os.path.exists(data_dir):
+ self.logger.error("Data directory not found: %s", data_dir)
+ return {"status": "error", "message": "Directory not found"}
+
+ counts = {"fetched": 0, "inserted": 0, "updated": 0, "skipped": 0, "errors": 0}
+
+ for filename in sorted(os.listdir(data_dir)):
+ if not filename.endswith(".json"):
+ continue
+ filepath = os.path.join(data_dir, filename)
+ try:
+ with open(filepath, "r", encoding="utf-8") as fh:
+ raw_entries = json.load(fh)
+ except Exception:
+ counts["errors"] += 1
+ self.logger.exception("Failed to read %s", filename)
+ continue
+
+ if not isinstance(raw_entries, list):
+ raw_entries = [raw_entries]
+
+ records = self._extract_records(raw_entries)
+ if not records:
+ counts["skipped"] += 1
+ continue
+
+ target_table = self._match_by_filename(filename)
+ if not target_table:
+ self.logger.warning("No mapping found for file: %s", filename)
+ counts["skipped"] += 1
+ continue
+
+ self.logger.info("Ingesting %s into %s", filename, target_table)
+ try:
+ inserted, updated = self._ingest_table(target_table, records, filename)
+ counts["inserted"] += inserted
+ counts["updated"] += updated
+ counts["fetched"] += len(records)
+ except Exception:
+ counts["errors"] += 1
+ self.logger.exception("Error processing %s", filename)
+ self.db.rollback()
+ continue
+
+ try:
+ self.db.commit()
+ except Exception:
+ self.db.rollback()
+ raise
+
+ return {"status": "SUCCESS", "counts": counts}
+
+ # ------------------------------------------------------------------ helpers
+ def _match_by_filename(self, filename: str) -> str | None:
+ """鏍规嵁鏂囦欢鍚嶅叧閿瘝鎵惧埌鐩爣琛ㄣ€?""
+ for keywords, table in self.FILE_MAPPING:
+ if any(keyword and keyword in filename for keyword in keywords):
+ return table
+ return None
+
+ def _extract_records(self, raw_entries: Iterable[Any]) -> list[dict]:
+ """鍏煎澶氱 JSON 缁撴瀯锛屾彁鍙栨垚璁板綍鍒楄〃銆?""
+ records: list[dict] = []
+ for entry in raw_entries:
+ if isinstance(entry, dict):
+ # 濡傛灉鍚?data 涓旇繕鍖呭惈鍏朵粬閿紙濡?orderSettleId锛夛紝浼樺厛淇濈暀澶栧眰浠ュ厤涓㈠け涓婚敭
+ preferred = entry
+ if "data" in entry and not any(k not in {"data", "code"} for k in entry.keys()):
+ preferred = entry["data"]
+ data = preferred
+ if isinstance(data, dict):
+ list_used = False
+ for v in data.values():
+ if isinstance(v, list) and v and isinstance(v[0], dict):
+ records.extend(v)
+ list_used = True
+ break
+ if list_used:
+ continue
+ if isinstance(data, list) and data and isinstance(data[0], dict):
+ records.extend(data)
+ elif isinstance(data, dict):
+ records.append(data)
+ elif isinstance(entry, list):
+ records.extend([item for item in entry if isinstance(item, dict)])
+ return records
+
+ def _get_table_columns(self, table: str) -> list[str]:
+ """鏌ヨ淇℃伅_schema锛岃幏鍙栫洰鏍囪〃鐨勫叏閮ㄥ垪鍚嶏紙鎸夐『搴忥級銆?""
+ if table in self._table_columns_cache:
+ return self._table_columns_cache[table]
+ if "." in table:
+ schema, name = table.split(".", 1)
+ else:
+ schema, name = "public", table
+ sql = """
+ SELECT column_name, data_type, udt_name
+ FROM information_schema.columns
+ WHERE table_schema = %s AND table_name = %s
+ ORDER BY ordinal_position
+ """
+ with self.db.conn.cursor() as cur:
+ cur.execute(sql, (schema, name))
+ cols = [(r[0], (r[1] or "").lower(), (r[2] or "").lower()) for r in cur.fetchall()]
+ self._table_columns_cache[table] = cols
+ return cols
+
+ def _ingest_table(self, table: str, records: list[dict], source_file: str) -> tuple[int, int]:
+ """鏋勯€?INSERT/ON CONFLICT 璇彞骞舵壒閲忔墽琛屻€?""
+ spec = self.TABLE_SPECS.get(table)
+ if not spec:
+ raise ValueError(f"No table spec for {table}")
+
+ pk_col = spec.get("pk")
+ json_cols = set(spec.get("json_cols", []))
+ json_cols_lower = {c.lower() for c in json_cols}
+
+ columns_info = self._get_table_columns(table)
+ columns = [c[0] for c in columns_info]
+ db_json_cols_lower = {
+ c[0].lower() for c in columns_info if c[1] in ("json", "jsonb") or c[2] in ("json", "jsonb")
+ }
+ pk_col_db = None
+ if pk_col:
+ pk_col_db = next((c for c in columns if c.lower() == pk_col.lower()), pk_col)
+
+ placeholders = ", ".join(["%s"] * len(columns))
+ col_list = ", ".join(f'"{c}"' for c in columns)
+ sql = f'INSERT INTO {table} ({col_list}) VALUES ({placeholders})'
+ if pk_col_db:
+ update_cols = [c for c in columns if c != pk_col_db]
+ set_clause = ", ".join(f'"{c}"=EXCLUDED."{c}"' for c in update_cols)
+ sql += f' ON CONFLICT ("{pk_col_db}") DO UPDATE SET {set_clause}'
+ sql += " RETURNING (xmax = 0) AS inserted"
+
+ params = []
+ now = datetime.now()
+ json_dump = lambda v: json.dumps(v, ensure_ascii=False) # noqa: E731
+ for rec in records:
+ merged_rec = rec if isinstance(rec, dict) else {}
+ # 閫愬眰灞曞紑 data -> data.data 缁撴瀯锛屽~鍏呯己澶卞瓧娈? data_part = merged_rec.get("data")
+ while isinstance(data_part, dict):
+ merged_rec = {**data_part, **merged_rec}
+ data_part = data_part.get("data")
+
+ pk_val = self._get_value_case_insensitive(merged_rec, pk_col) if pk_col else None
+ if pk_col and (pk_val is None or pk_val == ""):
+ continue
+
+ row_vals = []
+ for col_name, data_type, udt in columns_info:
+ col_lower = col_name.lower()
+ if col_lower == "payload":
+ row_vals.append(Json(rec, dumps=json_dump))
+ continue
+ if col_lower == "source_file":
+ row_vals.append(source_file)
+ continue
+ if col_lower == "fetched_at":
+ row_vals.append(merged_rec.get(col_name, now))
+ continue
+
+ value = self._normalize_scalar(self._get_value_case_insensitive(merged_rec, col_name))
+
+ if col_lower in json_cols_lower or col_lower in db_json_cols_lower:
+ row_vals.append(Json(value, dumps=json_dump) if value is not None else None)
+ continue
+
+ casted = self._cast_value(value, data_type)
+ row_vals.append(casted)
+ params.append(tuple(row_vals))
+
+ if not params:
+ return 0, 0
+
+ inserted = 0
+ updated = 0
+ with self.db.conn.cursor() as cur:
+ for row in params:
+ cur.execute(sql, row)
+ try:
+ flag = cur.fetchone()[0]
+ except Exception:
+ flag = None
+ if flag:
+ inserted += 1
+ else:
+ updated += 1
+ return inserted, updated
+
+ def _get_value_case_insensitive(self, record: dict, col: str):
+ """蹇界暐澶у皬鍐欒幏鍙栧€硷紝鍏煎 information_schema 灏忓啓鍒楀悕涓?JSON 鍘熷澶у皬鍐欍€?""
+ if record is None:
+ return None
+ if col is None:
+ return None
+ if col in record:
+ return record.get(col)
+ col_lower = col.lower()
+ for k, v in record.items():
+ if isinstance(k, str) and k.lower() == col_lower:
+ return v
+ return None
+
+ def _normalize_scalar(self, value):
+ """灏嗙┖瀛楃涓叉爣鍑嗗寲涓?None锛岄伩鍏嶆暟鍊?鏃堕棿瀛楁绫诲瀷閿欒銆?""
+ if value == "" or value == "{}" or value == "[]":
+ return None
+ return value
+
+ def _cast_value(self, value, data_type: str):
+ """鏍规嵁鍒楃被鍨嬪仛杞婚噺杞崲锛岄伩鍏嶇被鍨嬩笉鍖归厤銆?""
+ if value is None:
+ return None
+ dt = (data_type or "").lower()
+ if dt in ("integer", "bigint", "smallint"):
+ if isinstance(value, bool):
+ return int(value)
+ try:
+ return int(value)
+ except Exception:
+ return None
+ if dt in ("numeric", "double precision", "real", "decimal"):
+ if isinstance(value, bool):
+ return int(value)
+ try:
+ return float(value)
+ except Exception:
+ return None
+ if dt.startswith("timestamp") or dt in ("date", "time", "interval"):
+ # 浠呮帴鍙楀瓧绗︿覆/鏃ユ湡锛屾暟鍊肩瓑涓€寰嬬疆绌? return value if isinstance(value, str) else None
+ return value
+
diff --git a/etl_billiards/backups/manual_ingest_task.py.bak_20251209 b/etl_billiards/backups/manual_ingest_task.py.bak_20251209
new file mode 100644
index 0000000..14ed8ae
--- /dev/null
+++ b/etl_billiards/backups/manual_ingest_task.py.bak_20251209
@@ -0,0 +1,347 @@
+# -*- coding: utf-8 -*-
+"""手工示例数据灌入:按 schema_ODS_doc.sql 的表结构写入 ODS。"""
+from __future__ import annotations
+
+import json
+import os
+from datetime import datetime
+from typing import Any, Iterable
+
+from psycopg2.extras import Json
+
+from .base_task import BaseTask
+
+
+class ManualIngestTask(BaseTask):
+ """本地示例 JSON 灌入 ODS,确保表名/主键/插入列与 schema_ODS_doc.sql 对齐。"""
+
+ FILE_MAPPING: list[tuple[tuple[str, ...], str]] = [
+ (("member_profiles",), "billiards_ods.member_profiles"),
+ (("member_balance_changes",), "billiards_ods.member_balance_changes"),
+ (("member_stored_value_cards",), "billiards_ods.member_stored_value_cards"),
+ (("recharge_settlements",), "billiards_ods.recharge_settlements"),
+ (("settlement_records",), "billiards_ods.settlement_records"),
+ (("assistant_cancellation_records",), "billiards_ods.assistant_cancellation_records"),
+ (("assistant_accounts_master",), "billiards_ods.assistant_accounts_master"),
+ (("assistant_service_records",), "billiards_ods.assistant_service_records"),
+ (("site_tables_master",), "billiards_ods.site_tables_master"),
+ (("table_fee_discount_records",), "billiards_ods.table_fee_discount_records"),
+ (("table_fee_transactions",), "billiards_ods.table_fee_transactions"),
+ (("goods_stock_movements",), "billiards_ods.goods_stock_movements"),
+ (("stock_goods_category_tree",), "billiards_ods.stock_goods_category_tree"),
+ (("goods_stock_summary",), "billiards_ods.goods_stock_summary"),
+ (("payment_transactions",), "billiards_ods.payment_transactions"),
+ (("refund_transactions",), "billiards_ods.refund_transactions"),
+ (("platform_coupon_redemption_records",), "billiards_ods.platform_coupon_redemption_records"),
+ (("group_buy_redemption_records",), "billiards_ods.group_buy_redemption_records"),
+ (("group_buy_packages",), "billiards_ods.group_buy_packages"),
+ (("settlement_ticket_details",), "billiards_ods.settlement_ticket_details"),
+ (("store_goods_master",), "billiards_ods.store_goods_master"),
+ (("tenant_goods_master",), "billiards_ods.tenant_goods_master"),
+ (("store_goods_sales_records",), "billiards_ods.store_goods_sales_records"),
+ ]
+
+ TABLE_SPECS: dict[str, dict[str, Any]] = {
+ "billiards_ods.member_profiles": {"pk": "id"},
+ "billiards_ods.member_balance_changes": {"pk": "id"},
+ "billiards_ods.member_stored_value_cards": {"pk": "id"},
+ "billiards_ods.recharge_settlements": {"pk": "id"},
+ "billiards_ods.settlement_records": {"pk": "id"},
+ "billiards_ods.assistant_cancellation_records": {"pk": "id", "json_cols": ["siteProfile"]},
+ "billiards_ods.assistant_accounts_master": {"pk": "id"},
+ "billiards_ods.assistant_service_records": {"pk": "id", "json_cols": ["siteProfile"]},
+ "billiards_ods.site_tables_master": {"pk": "id"},
+ "billiards_ods.table_fee_discount_records": {"pk": "id", "json_cols": ["siteProfile", "tableProfile"]},
+ "billiards_ods.table_fee_transactions": {"pk": "id", "json_cols": ["siteProfile"]},
+ "billiards_ods.goods_stock_movements": {"pk": "siteGoodsStockId"},
+ "billiards_ods.stock_goods_category_tree": {"pk": "id", "json_cols": ["categoryBoxes"]},
+ "billiards_ods.goods_stock_summary": {"pk": "siteGoodsId"},
+ "billiards_ods.payment_transactions": {"pk": "id", "json_cols": ["siteProfile"]},
+ "billiards_ods.refund_transactions": {"pk": "id", "json_cols": ["siteProfile"]},
+ "billiards_ods.platform_coupon_redemption_records": {"pk": "id"},
+ "billiards_ods.tenant_goods_master": {"pk": "id"},
+ "billiards_ods.group_buy_packages": {"pk": "id"},
+ "billiards_ods.group_buy_redemption_records": {"pk": "id"},
+ "billiards_ods.settlement_ticket_details": {
+ "pk": "orderSettleId",
+ "json_cols": ["memberProfile", "orderItem", "tenantMemberCardLogs"],
+ },
+ "billiards_ods.store_goods_master": {"pk": "id"},
+ "billiards_ods.store_goods_sales_records": {"pk": "id"},
+ }
+
+ def get_task_code(self) -> str:
+ """返回任务编码。"""
+ return "MANUAL_INGEST"
+
+ def execute(self, cursor_data: dict | None = None) -> dict:
+ """从目录读取 JSON,按表定义批量入库。"""
+ data_dir = (
+ self.config.get("manual.data_dir")
+ or self.config.get("pipeline.ingest_source_dir")
+ or r"c:\dev\LLTQ\ETL\feiqiu-ETL\etl_billiards\tests\testdata_json"
+ )
+ if not os.path.exists(data_dir):
+ self.logger.error("Data directory not found: %s", data_dir)
+ return {"status": "error", "message": "Directory not found"}
+
+ counts = {"fetched": 0, "inserted": 0, "updated": 0, "skipped": 0, "errors": 0}
+
+ for filename in sorted(os.listdir(data_dir)):
+ if not filename.endswith(".json"):
+ continue
+ filepath = os.path.join(data_dir, filename)
+ try:
+ with open(filepath, "r", encoding="utf-8") as fh:
+ raw_entries = json.load(fh)
+ except Exception:
+ counts["errors"] += 1
+ self.logger.exception("Failed to read %s", filename)
+ continue
+
+ entries = raw_entries if isinstance(raw_entries, list) else [raw_entries]
+ records = self._extract_records(entries)
+ if not records:
+ counts["skipped"] += 1
+ continue
+
+ target_table = self._match_by_filename(filename)
+ if not target_table:
+ self.logger.warning("No mapping found for file: %s", filename)
+ counts["skipped"] += 1
+ continue
+
+ self.logger.info("Ingesting %s into %s", filename, target_table)
+ try:
+ inserted, updated = self._ingest_table(target_table, records, filename)
+ counts["inserted"] += inserted
+ counts["updated"] += updated
+ counts["fetched"] += len(records)
+ except Exception:
+ counts["errors"] += 1
+ self.logger.exception("Error processing %s", filename)
+ self.db.rollback()
+ continue
+
+ try:
+ self.db.commit()
+ except Exception:
+ self.db.rollback()
+ raise
+
+ return {"status": "SUCCESS", "counts": counts}
+
+ def _match_by_filename(self, filename: str) -> str | None:
+ """根据文件名关键字匹配目标表。"""
+ for keywords, table in self.FILE_MAPPING:
+ if any(keyword and keyword in filename for keyword in keywords):
+ return table
+ return None
+
+ def _extract_records(self, raw_entries: Iterable[Any]) -> list[dict]:
+ """兼容多层 data/list 包装,抽取记录列表。"""
+ records: list[dict] = []
+ for entry in raw_entries:
+ if isinstance(entry, dict):
+ preferred = entry
+ if "data" in entry and not any(k not in {"data", "code"} for k in entry.keys()):
+ preferred = entry["data"]
+ data = preferred
+ if isinstance(data, dict):
+ # 特殊处理 settleList(充值、结算记录):展开 data.settleList 下的 settleList,抛弃上层 siteProfile
+ if "settleList" in data:
+ settle_list_val = data.get("settleList")
+ if isinstance(settle_list_val, dict):
+ settle_list_iter = [settle_list_val]
+ elif isinstance(settle_list_val, list):
+ settle_list_iter = settle_list_val
+ else:
+ settle_list_iter = []
+
+ handled = False
+ for item in settle_list_iter or []:
+ if not isinstance(item, dict):
+ continue
+ inner = item.get("settleList")
+ merged = dict(inner) if isinstance(inner, dict) else dict(item)
+ # 保留 siteProfile 供后续字段补充,但不落库
+ site_profile = data.get("siteProfile")
+ if isinstance(site_profile, dict):
+ merged.setdefault("siteProfile", site_profile)
+ records.append(merged)
+ handled = True
+ if handled:
+ continue
+
+ list_used = False
+ for v in data.values():
+ if isinstance(v, list) and v and isinstance(v[0], dict):
+ records.extend(v)
+ list_used = True
+ break
+ if list_used:
+ continue
+ if isinstance(data, list) and data and isinstance(data[0], dict):
+ records.extend(data)
+ elif isinstance(data, dict):
+ records.append(data)
+ elif isinstance(entry, list):
+ records.extend([item for item in entry if isinstance(item, dict)])
+ return records
+
+ def _get_table_columns(self, table: str) -> list[tuple[str, str, str]]:
+ """查询 information_schema,获取目标表列信息。"""
+ cache = getattr(self, "_table_columns_cache", {})
+ if table in cache:
+ return cache[table]
+ if "." in table:
+ schema, name = table.split(".", 1)
+ else:
+ schema, name = "public", table
+ sql = """
+ SELECT column_name, data_type, udt_name
+ FROM information_schema.columns
+ WHERE table_schema = %s AND table_name = %s
+ ORDER BY ordinal_position
+ """
+ with self.db.conn.cursor() as cur:
+ cur.execute(sql, (schema, name))
+ cols = [(r[0], (r[1] or "").lower(), (r[2] or "").lower()) for r in cur.fetchall()]
+ cache[table] = cols
+ self._table_columns_cache = cache
+ return cols
+
+ def _ingest_table(self, table: str, records: list[dict], source_file: str) -> tuple[int, int]:
+ """构建 INSERT/ON CONFLICT 语句并批量执行。"""
+ spec = self.TABLE_SPECS.get(table)
+ if not spec:
+ raise ValueError(f"No table spec for {table}")
+
+ pk_col = spec.get("pk")
+ json_cols = set(spec.get("json_cols", []))
+ json_cols_lower = {c.lower() for c in json_cols}
+
+ columns_info = self._get_table_columns(table)
+ columns = [c[0] for c in columns_info]
+ db_json_cols_lower = {
+ c[0].lower() for c in columns_info if c[1] in ("json", "jsonb") or c[2] in ("json", "jsonb")
+ }
+ pk_col_db = None
+ if pk_col:
+ pk_col_db = next((c for c in columns if c.lower() == pk_col.lower()), pk_col)
+
+ placeholders = ", ".join(["%s"] * len(columns))
+ col_list = ", ".join(f'"{c}"' for c in columns)
+ sql = f'INSERT INTO {table} ({col_list}) VALUES ({placeholders})'
+ if pk_col_db:
+ update_cols = [c for c in columns if c != pk_col_db]
+ set_clause = ", ".join(f'"{c}"=EXCLUDED."{c}"' for c in update_cols)
+ sql += f' ON CONFLICT ("{pk_col_db}") DO UPDATE SET {set_clause}'
+ sql += " RETURNING (xmax = 0) AS inserted"
+
+ params = []
+ now = datetime.now()
+ json_dump = lambda v: json.dumps(v, ensure_ascii=False) # noqa: E731
+ for rec in records:
+ merged_rec = rec if isinstance(rec, dict) else {}
+ data_part = merged_rec.get("data")
+ while isinstance(data_part, dict):
+ merged_rec = {**data_part, **merged_rec}
+ data_part = data_part.get("data")
+
+ # 针对充值/结算,补齐 siteProfile 中的店铺信息
+ if table in {
+ "billiards_ods.recharge_settlements",
+ "billiards_ods.settlement_records",
+ }:
+ site_profile = merged_rec.get("siteProfile") or merged_rec.get("site_profile")
+ if isinstance(site_profile, dict):
+ merged_rec.setdefault("tenantid", site_profile.get("tenant_id") or site_profile.get("tenantId"))
+ merged_rec.setdefault("siteid", site_profile.get("id") or site_profile.get("siteId"))
+ merged_rec.setdefault("sitename", site_profile.get("shop_name") or site_profile.get("siteName"))
+
+ pk_val = self._get_value_case_insensitive(merged_rec, pk_col) if pk_col else None
+ if pk_col and (pk_val is None or pk_val == ""):
+ continue
+
+ row_vals = []
+ for col_name, data_type, udt in columns_info:
+ col_lower = col_name.lower()
+ if col_lower == "payload":
+ row_vals.append(Json(rec, dumps=json_dump))
+ continue
+ if col_lower == "source_file":
+ row_vals.append(source_file)
+ continue
+ if col_lower == "fetched_at":
+ row_vals.append(merged_rec.get(col_name, now))
+ continue
+
+ value = self._normalize_scalar(self._get_value_case_insensitive(merged_rec, col_name))
+
+ if col_lower in json_cols_lower or col_lower in db_json_cols_lower:
+ row_vals.append(Json(value, dumps=json_dump) if value is not None else None)
+ continue
+
+ casted = self._cast_value(value, data_type)
+ row_vals.append(casted)
+ params.append(tuple(row_vals))
+
+ if not params:
+ return 0, 0
+
+ inserted = 0
+ updated = 0
+ with self.db.conn.cursor() as cur:
+ for row in params:
+ cur.execute(sql, row)
+ flag = cur.fetchone()[0]
+ if flag:
+ inserted += 1
+ else:
+ updated += 1
+ return inserted, updated
+
+ @staticmethod
+ def _get_value_case_insensitive(record: dict, col: str | None):
+ """忽略大小写获取值,兼容 information_schema 与 JSON 原始字段。"""
+ if record is None or col is None:
+ return None
+ if col in record:
+ return record.get(col)
+ col_lower = col.lower()
+ for k, v in record.items():
+ if isinstance(k, str) and k.lower() == col_lower:
+ return v
+ return None
+
+ @staticmethod
+ def _normalize_scalar(value):
+ """将空字符串/空 JSON 规范为 None,避免类型转换错误。"""
+ if value == "" or value == "{}" or value == "[]":
+ return None
+ return value
+
+ @staticmethod
+ def _cast_value(value, data_type: str):
+ """根据列类型做简单转换,保证批量插入兼容。"""
+ if value is None:
+ return None
+ dt = (data_type or "").lower()
+ if dt in ("integer", "bigint", "smallint"):
+ if isinstance(value, bool):
+ return int(value)
+ try:
+ return int(value)
+ except Exception:
+ return None
+ if dt in ("numeric", "double precision", "real", "decimal"):
+ if isinstance(value, bool):
+ return int(value)
+ try:
+ return float(value)
+ except Exception:
+ return None
+ if dt.startswith("timestamp") or dt in ("date", "time", "interval"):
+ return value if isinstance(value, str) else None
+ return value
diff --git a/etl_billiards/backups/schema_ODS_doc.sql b/etl_billiards/backups/schema_ODS_doc.sql
new file mode 100644
index 0000000..73d3307
--- /dev/null
+++ b/etl_billiards/backups/schema_ODS_doc.sql
@@ -0,0 +1,1714 @@
+-- 鏂囦欢璇存槑锛歄DS 灞?DDL锛屾寜绀鸿寖 JSON锛圕:\dev\LLTQ\export\temp\source-data-doc锛夌敓鎴愶紝瀛楁鍚嶄笌婧?JSON 涓€鑷翠究浜庤拷婧€?
+-- 澶囨敞鍧囦娇鐢ㄤ腑鏂囷紝鏍囨敞鏉ユ簮瀛楁璺緞鍙婂惈涔夛紱鏈睍寮€鐨勫祵濂楀瓧娈典互 JSONB 鍏ㄩ噺淇濈暀銆?
+-- 鎵€鏈夊瓧娈靛娉ㄥ潎鏍囨敞鏉ユ簮JSON璺緞涓庝腑鏂囧惈涔夛紙鍚箟鍙傝€冨搴旂殑鈥滃瓧娈典笌鍏崇郴鍒嗘瀽鈥滿D锛夈€?
+
+DROP SCHEMA IF EXISTS billiards_ods CASCADE;
+CREATE SCHEMA IF NOT EXISTS billiards_ods;
+
+-- ========== 浼氬憳妗f锛堜細鍛樻。妗?json -> data.tenantMemberInfos锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.member_profiles (
+ tenant_id BIGINT,
+ register_site_id BIGINT,
+ site_name TEXT,
+ id BIGINT PRIMARY KEY,
+ system_member_id BIGINT,
+ member_card_grade_code BIGINT,
+ member_card_grade_name TEXT,
+ mobile TEXT,
+ nickname TEXT,
+ point NUMERIC(18,2),
+ growth_value NUMERIC(18,2),
+ referrer_member_id BIGINT,
+ status INT,
+ user_status INT,
+ create_time TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+COMMENT ON TABLE billiards_ods.member_profiles IS '鏉ユ簮锛氫細鍛樻。妗?json -> data.tenantMemberInfos锛涙瘡鏉¤褰曟槸浼氬憳鍦ㄧ鎴蜂笅鐨勫崱妗f锛堜細鍛樏楀崱绉嶏級銆?;
+COMMENT ON COLUMN billiards_ods.member_profiles.tenant_id IS '鏉ユ簮:data.tenantMemberInfos.tenant_id锛涚鎴?鍝佺墝ID銆?;
+COMMENT ON COLUMN billiards_ods.member_profiles.register_site_id IS '鏉ユ簮:data.tenantMemberInfos.register_site_id锛涗細鍛樻敞鍐岄棬搴桰D銆?;
+COMMENT ON COLUMN billiards_ods.member_profiles.site_name IS '鏉ユ簮:data.tenantMemberInfos.site_name锛涙敞鍐岄棬搴楀悕绉板揩鐓с€?;
+COMMENT ON COLUMN billiards_ods.member_profiles.id IS '鏉ユ簮:data.tenantMemberInfos.id锛涗細鍛樿处鎴蜂富閿紙绉熸埛鍐呬竴寮犲崱/涓€涓处鎴凤級銆?;
+COMMENT ON COLUMN billiards_ods.member_profiles.system_member_id IS '鏉ユ簮:data.tenantMemberInfos.system_member_id锛涘钩鍙扮骇浼氬憳ID锛岀敤浜庤法搴?璺ㄥ崱鑱氬悎鍚屼竴浼氬憳銆?;
+COMMENT ON COLUMN billiards_ods.member_profiles.member_card_grade_code IS '鏉ユ簮:data.tenantMemberInfos.member_card_grade_code锛涗細鍛樺崱绉?绛夌骇缂栫爜锛堝鍌ㄥ€煎崱/鍙拌垂鍗$瓑锛夈€?;
+COMMENT ON COLUMN billiards_ods.member_profiles.member_card_grade_name IS '鏉ユ簮:data.tenantMemberInfos.member_card_grade_name锛涗細鍛樺崱绉?绛夌骇鍚嶇О銆?;
+COMMENT ON COLUMN billiards_ods.member_profiles.mobile IS '鏉ユ簮:data.tenantMemberInfos.mobile锛涗細鍛樻墜鏈哄彿銆?;
+COMMENT ON COLUMN billiards_ods.member_profiles.nickname IS '鏉ユ簮:data.tenantMemberInfos.nickname锛涗細鍛樻樀绉?灞曠ず鍚嶃€?;
+COMMENT ON COLUMN billiards_ods.member_profiles.point IS '鏉ユ簮:data.tenantMemberInfos.point锛涘綋鍓嶇Н鍒嗕綑棰濄€?;
+COMMENT ON COLUMN billiards_ods.member_profiles.growth_value IS '鏉ユ簮:data.tenantMemberInfos.growth_value锛涙垚闀垮€?缁忛獙鍊笺€?;
+COMMENT ON COLUMN billiards_ods.member_profiles.referrer_member_id IS '鏉ユ簮:data.tenantMemberInfos.referrer_member_id锛涙帹鑽愪汉浼氬憳ID锛? 琛ㄧず鏃狅級銆?;
+COMMENT ON COLUMN billiards_ods.member_profiles.status IS '鏉ユ簮:data.tenantMemberInfos.status锛涘崱璐︽埛鐘舵€佹灇涓俱€?;
+COMMENT ON COLUMN billiards_ods.member_profiles.user_status IS '鏉ユ簮:data.tenantMemberInfos.user_status锛涚敤鎴风姸鎬佹灇涓俱€?;
+COMMENT ON COLUMN billiards_ods.member_profiles.create_time IS '鏉ユ簮:data.tenantMemberInfos.create_time锛涜处鎴峰垱寤烘椂闂淬€?;
+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鏁存潯璁板綍锛屼繚鐣欐湭灞曞紑瀛楁銆?;
+
+-- ========== 浣欓鍙樻洿璁板綍锛堜綑棰濆彉鏇磋褰?json -> data.tenantMemberCardLogs锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.member_balance_changes (
+ tenant_id BIGINT,
+ site_id BIGINT,
+ register_site_id BIGINT,
+ registerSiteName TEXT,
+ paySiteName TEXT,
+ id BIGINT PRIMARY KEY,
+ tenant_member_id BIGINT,
+ tenant_member_card_id BIGINT,
+ system_member_id BIGINT,
+ memberName TEXT,
+ memberMobile TEXT,
+ card_type_id BIGINT,
+ memberCardTypeName TEXT,
+ account_data NUMERIC(18,2),
+ before NUMERIC(18,2),
+ after NUMERIC(18,2),
+ refund_amount NUMERIC(18,2),
+ from_type INT,
+ payment_method INT,
+ relate_id BIGINT,
+ remark TEXT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ is_delete INT,
+ create_time TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+COMMENT ON TABLE billiards_ods.member_balance_changes IS '鏉ユ簮锛氫綑棰濆彉鏇磋褰?json -> data.tenantMemberCardLogs锛涜褰曚細鍛樺崱浣欓姣忔鍙樻洿銆?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.tenant_id IS '鏉ユ簮:data.tenantMemberCardLogs.tenant_id锛涚鎴稩D銆?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.site_id IS '鏉ユ簮:data.tenantMemberCardLogs.site_id锛涘彂鐢熷彉鏇寸殑闂ㄥ簵ID銆?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.register_site_id IS '鏉ユ簮:data.tenantMemberCardLogs.register_site_id锛涘紑鍗?娉ㄥ唽闂ㄥ簵ID銆?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.registerSiteName IS '鏉ユ簮:data.tenantMemberCardLogs.registerSiteName锛涙敞鍐岄棬搴楀悕绉般€?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.paySiteName IS '鏉ユ簮:data.tenantMemberCardLogs.paySiteName锛涙敮浠樺彂鐢熼棬搴楀悕绉般€?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.id IS '鏉ユ簮:data.tenantMemberCardLogs.id锛涗綑棰濆彉鏇磋褰曚富閿€?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.tenant_member_id IS '鏉ユ簮:data.tenantMemberCardLogs.tenant_member_id锛涚鎴峰唴浼氬憳ID銆?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.tenant_member_card_id IS '鏉ユ簮:data.tenantMemberCardLogs.tenant_member_card_id锛涗細鍛樺崱璐︽埛ID銆?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.system_member_id IS '鏉ユ簮:data.tenantMemberCardLogs.system_member_id锛涘钩鍙颁細鍛業D銆?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.memberName IS '鏉ユ簮:data.tenantMemberCardLogs.memberName锛涗細鍛樺鍚?鏄电О蹇収銆?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.memberMobile IS '鏉ユ簮:data.tenantMemberCardLogs.memberMobile锛涗細鍛樻墜鏈哄彿蹇収銆?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.card_type_id IS '鏉ユ簮:data.tenantMemberCardLogs.card_type_id锛涘崱绉岻D銆?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.memberCardTypeName IS '鏉ユ簮:data.tenantMemberCardLogs.memberCardTypeName锛涘崱绉嶅悕绉般€?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.account_data IS '鏉ユ簮:data.tenantMemberCardLogs.account_data锛涙湰娆″彉鍔ㄩ噾棰濓紝姝d负澧炲姞銆佽礋涓哄噺灏戙€?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.before IS '鏉ユ簮:data.tenantMemberCardLogs.before锛涘彉鏇村墠浣欓銆?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.after IS '鏉ユ簮:data.tenantMemberCardLogs.after锛涘彉鏇村悗浣欓銆?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.refund_amount IS '鏉ユ簮:data.tenantMemberCardLogs.refund_amount锛涙湰娆℃秹鍙婇€€娆鹃噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.from_type IS '鏉ユ簮:data.tenantMemberCardLogs.from_type锛涘彉鏇存潵婧愮被鍨嬫灇涓俱€?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.payment_method IS '鏉ユ簮:data.tenantMemberCardLogs.payment_method锛涙敮浠樻柟寮忔灇涓俱€?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.relate_id IS '鏉ユ簮:data.tenantMemberCardLogs.relate_id锛涗笟鍔″叧鑱擨D锛堝璁㈠崟/缁撶畻鍗曪級銆?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.remark IS '鏉ユ簮:data.tenantMemberCardLogs.remark锛涘娉ㄣ€?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.operator_id IS '鏉ユ簮:data.tenantMemberCardLogs.operator_id锛涙搷浣滀汉ID銆?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.operator_name IS '鏉ユ簮:data.tenantMemberCardLogs.operator_name锛涙搷浣滀汉鍚嶇О銆?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.is_delete IS '鏉ユ簮:data.tenantMemberCardLogs.is_delete锛涢€昏緫鍒犻櫎鏍囪瘑銆?;
+COMMENT ON COLUMN billiards_ods.member_balance_changes.create_time IS '鏉ユ簮:data.tenantMemberCardLogs.create_time锛涜褰曞垱寤烘椂闂淬€?;
+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鏁存潯璁板綍锛屼繚鐣欐湭灞曞紑瀛楁銆?;
+
+-- ========== 鍌ㄥ€煎崱鍒楄〃锛堝偍鍊煎崱鍒楄〃.json -> data.tenantMemberCards锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.member_stored_value_cards (
+ tenant_id BIGINT,
+ tenant_member_id BIGINT,
+ system_member_id BIGINT,
+ register_site_id BIGINT,
+ site_name TEXT,
+ id BIGINT PRIMARY KEY,
+ member_card_grade_code BIGINT,
+ member_card_grade_code_name TEXT,
+ member_card_type_name TEXT,
+ member_name TEXT,
+ member_mobile TEXT,
+ card_type_id BIGINT,
+ card_no TEXT,
+ card_physics_type TEXT,
+ balance NUMERIC(18,2),
+ denomination NUMERIC(18,2),
+ table_discount NUMERIC(10,4),
+ goods_discount NUMERIC(10,4),
+ assistant_discount NUMERIC(10,4),
+ assistant_reward_discount NUMERIC(10,4),
+ table_service_discount NUMERIC(10,4),
+ assistant_service_discount NUMERIC(10,4),
+ coupon_discount NUMERIC(10,4),
+ goods_service_discount NUMERIC(10,4),
+ assistant_discount_sub_switch INT,
+ table_discount_sub_switch INT,
+ goods_discount_sub_switch INT,
+ assistant_reward_discount_sub_switch INT,
+ table_service_deduct_radio NUMERIC(10,4),
+ assistant_service_deduct_radio NUMERIC(10,4),
+ goods_service_deduct_radio NUMERIC(10,4),
+ assistant_deduct_radio NUMERIC(10,4),
+ table_deduct_radio NUMERIC(10,4),
+ goods_deduct_radio NUMERIC(10,4),
+ coupon_deduct_radio NUMERIC(10,4),
+ assistant_reward_deduct_radio NUMERIC(10,4),
+ tableCardDeduct NUMERIC(18,2),
+ tableServiceCardDeduct NUMERIC(18,2),
+ goodsCarDeduct NUMERIC(18,2),
+ goodsServiceCardDeduct NUMERIC(18,2),
+ assistantCardDeduct NUMERIC(18,2),
+ assistantServiceCardDeduct NUMERIC(18,2),
+ assistantRewardCardDeduct NUMERIC(18,2),
+ cardSettleDeduct NUMERIC(18,2),
+ couponCardDeduct NUMERIC(18,2),
+ deliveryFeeDeduct NUMERIC(18,2),
+ use_scene INT,
+ able_cross_site INT,
+ able_site_transfer INT,
+ is_allow_give INT,
+ is_allow_order_deduct INT,
+ is_delete INT,
+ bind_password TEXT,
+ goods_discount_range_type INT,
+ goodsCategoryId BIGINT,
+ tableAreaId BIGINT,
+ effect_site_id BIGINT,
+ start_time TIMESTAMP,
+ end_time TIMESTAMP,
+ disable_start_time TIMESTAMP,
+ disable_end_time TIMESTAMP,
+ last_consume_time TIMESTAMP,
+ create_time TIMESTAMP,
+ status INT,
+ sort INT,
+ tenantAvatar TEXT,
+ tenantName TEXT,
+ pdAssisnatLevel TEXT,
+ cxAssisnatLevel TEXT,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+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 '鏉ユ簮:data.tenantMemberCards.tenant_id锛涚鎴稩D銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tenant_member_id IS '鏉ユ簮:data.tenantMemberCards.tenant_member_id锛涚鎴峰唴浼氬憳ID銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.system_member_id IS '鏉ユ簮:data.tenantMemberCards.system_member_id锛涘钩鍙颁細鍛業D銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.register_site_id IS '鏉ユ簮:data.tenantMemberCards.register_site_id锛涘紑鍗¢棬搴桰D銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.site_name IS '鏉ユ簮:data.tenantMemberCards.site_name锛涘紑鍗¢棬搴楀悕绉般€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.id IS '鏉ユ簮:data.tenantMemberCards.id锛涗細鍛樺崱璐︽埛ID銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.member_card_grade_code IS '鏉ユ簮:data.tenantMemberCards.member_card_grade_code锛涘崱绉?绛夌骇缂栫爜銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.member_card_grade_code_name IS '鏉ユ簮:data.tenantMemberCards.member_card_grade_code_name锛涘崱绉?绛夌骇鍚嶇О銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.member_card_type_name IS '鏉ユ簮:data.tenantMemberCards.member_card_type_name锛涘崱绫诲瀷鍚嶇О銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.member_name IS '鏉ユ簮:data.tenantMemberCards.member_name锛涗細鍛樺鍚嶅揩鐓с€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.member_mobile IS '鏉ユ簮:data.tenantMemberCards.member_mobile锛涗細鍛樻墜鏈哄彿蹇収銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.card_type_id IS '鏉ユ簮:data.tenantMemberCards.card_type_id锛涘崱绫诲瀷ID銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.card_no IS '鏉ユ簮:data.tenantMemberCards.card_no锛涘疄浣?铏氭嫙鍗″彿銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.card_physics_type IS '鏉ユ簮:data.tenantMemberCards.card_physics_type锛涚墿鐞嗗崱绫诲瀷鏍囪瘑銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.balance IS '鏉ユ簮:data.tenantMemberCards.balance锛涘崱鍐呭綋鍓嶄綑棰濄€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.denomination IS '鏉ユ簮:data.tenantMemberCards.denomination锛涘崱闈㈤/鍒濆鍌ㄥ€奸噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.table_discount IS '鏉ユ簮:data.tenantMemberCards.table_discount锛涘彴璐规姌鎵o紝10琛ㄧず涓嶆墦鎶樸€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_discount IS '鏉ユ簮:data.tenantMemberCards.goods_discount锛涘晢鍝佹姌鎵c€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_discount IS '鏉ユ簮:data.tenantMemberCards.assistant_discount锛涘姪鏁欐湇鍔℃姌鎵c€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_reward_discount IS '鏉ユ簮:data.tenantMemberCards.assistant_reward_discount锛涘姪鏁欏鍔遍噾鎶樻墸銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.table_service_discount IS '鏉ユ簮:data.tenantMemberCards.table_service_discount锛涘彴鐞冩湇鍔℃姌鎵c€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_service_discount IS '鏉ユ簮:data.tenantMemberCards.assistant_service_discount锛涘姪鏁欐湇鍔℃姌鎵o紙鍙︿竴鍙e緞锛夈€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.coupon_discount IS '鏉ユ簮:data.tenantMemberCards.coupon_discount锛涘埜绫绘姌鎵c€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_service_discount IS '鏉ユ簮:data.tenantMemberCards.goods_service_discount锛涘晢鍝佹湇鍔℃姌鎵c€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_discount_sub_switch IS '鏉ユ簮:data.tenantMemberCards.assistant_discount_sub_switch锛涘姪鏁欐姌鎵e紑鍏炽€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.table_discount_sub_switch IS '鏉ユ簮:data.tenantMemberCards.table_discount_sub_switch锛涘彴璐规姌鎵e紑鍏炽€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_discount_sub_switch IS '鏉ユ簮:data.tenantMemberCards.goods_discount_sub_switch锛涘晢鍝佹姌鎵e紑鍏炽€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_reward_discount_sub_switch IS '鏉ユ簮:data.tenantMemberCards.assistant_reward_discount_sub_switch锛涘姪鏁欏鍔辨姌鎵e紑鍏炽€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.table_service_deduct_radio IS '鏉ユ簮:data.tenantMemberCards.table_service_deduct_radio锛涘彴璐规姷鎵f瘮渚嬨€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_service_deduct_radio IS '鏉ユ簮:data.tenantMemberCards.assistant_service_deduct_radio锛涘姪鏁欐湇鍔℃姷鎵f瘮渚嬨€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_service_deduct_radio IS '鏉ユ簮:data.tenantMemberCards.goods_service_deduct_radio锛涘晢鍝佹湇鍔℃姷鎵f瘮渚嬨€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_deduct_radio IS '鏉ユ簮:data.tenantMemberCards.assistant_deduct_radio锛涘姪鏁欐姷鎵f瘮渚嬨€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.table_deduct_radio IS '鏉ユ簮:data.tenantMemberCards.table_deduct_radio锛涘彴璐规姷鎵f瘮渚嬨€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_deduct_radio IS '鏉ユ簮:data.tenantMemberCards.goods_deduct_radio锛涘晢鍝佹姷鎵f瘮渚嬨€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.coupon_deduct_radio IS '鏉ユ簮:data.tenantMemberCards.coupon_deduct_radio锛涘埜鎶垫墸姣斾緥銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_reward_deduct_radio IS '鏉ユ簮:data.tenantMemberCards.assistant_reward_deduct_radio锛涘姪鏁欏鍔辨姷鎵f瘮渚嬨€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tableCardDeduct IS '鏉ユ簮:data.tenantMemberCards.tableCardDeduct锛涘彴璐规姷鎵i噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tableServiceCardDeduct IS '鏉ユ簮:data.tenantMemberCards.tableServiceCardDeduct锛涘彴鐞冩湇鍔℃姷鎵i噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goodsCarDeduct IS '鏉ユ簮:data.tenantMemberCards.goodsCarDeduct锛涘晢鍝佹姷鎵i噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goodsServiceCardDeduct IS '鏉ユ簮:data.tenantMemberCards.goodsServiceCardDeduct锛涘晢鍝佹湇鍔℃姷鎵i噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistantCardDeduct IS '鏉ユ簮:data.tenantMemberCards.assistantCardDeduct锛涘姪鏁欐姷鎵i噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistantServiceCardDeduct IS '鏉ユ簮:data.tenantMemberCards.assistantServiceCardDeduct锛涘姪鏁欐湇鍔℃姷鎵i噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistantRewardCardDeduct IS '鏉ユ簮:data.tenantMemberCards.assistantRewardCardDeduct锛涘姪鏁欏鍔辨姷鎵i噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.cardSettleDeduct IS '鏉ユ簮:data.tenantMemberCards.cardSettleDeduct锛涚粨绠楁姷鎵i噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.couponCardDeduct IS '鏉ユ簮:data.tenantMemberCards.couponCardDeduct锛涘埜鎶垫墸閲戦銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.deliveryFeeDeduct IS '鏉ユ簮:data.tenantMemberCards.deliveryFeeDeduct锛涢厤閫佽垂鐢ㄦ姷鎵i噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.use_scene IS '鏉ユ簮:data.tenantMemberCards.use_scene锛涗娇鐢ㄥ満鏅灇涓俱€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.able_cross_site IS '鏉ユ簮:data.tenantMemberCards.able_cross_site锛涙槸鍚﹁法搴楅€氱敤銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.able_site_transfer IS '鏉ユ簮:data.tenantMemberCards.able_site_transfer锛涙槸鍚﹀彲闂ㄥ簵杞Щ銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.is_allow_give IS '鏉ユ簮:data.tenantMemberCards.is_allow_give锛涙槸鍚﹀厑璁歌浆璧犮€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.is_allow_order_deduct IS '鏉ユ簮:data.tenantMemberCards.is_allow_order_deduct锛涙槸鍚﹀厑璁歌鍗曟姷鎵c€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.is_delete IS '鏉ユ簮:data.tenantMemberCards.is_delete锛涢€昏緫鍒犻櫎鏍囪瘑銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.bind_password IS '鏉ユ簮:data.tenantMemberCards.bind_password锛涙槸鍚︾粦瀹氬瘑鐮?缁戝畾瀵嗙爜鍐呭銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_discount_range_type IS '鏉ユ簮:data.tenantMemberCards.goods_discount_range_type锛涘晢鍝佹姌鎵i€傜敤鑼冨洿绫诲瀷銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_discount_sub_switch IS '鏉ユ簮:data.tenantMemberCards.goods_discount_sub_switch锛涘晢鍝佹姌鎵e紑鍏炽€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goodsCategoryId IS '鏉ユ簮:data.tenantMemberCards.goodsCategoryId锛涘晢鍝佸垎绫籌D銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tableAreaId IS '鏉ユ簮:data.tenantMemberCards.tableAreaId锛涘彴鐞冨尯鍩烮D銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.effect_site_id IS '鏉ユ簮:data.tenantMemberCards.effect_site_id锛涚敓鏁堥棬搴桰D銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.start_time IS '鏉ユ簮:data.tenantMemberCards.start_time锛涙湁鏁堟湡寮€濮嬫椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.end_time IS '鏉ユ簮:data.tenantMemberCards.end_time锛涙湁鏁堟湡缁撴潫鏃堕棿銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.disable_start_time IS '鏉ユ簮:data.tenantMemberCards.disable_start_time锛涘仠鐢ㄥ紑濮嬫椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.disable_end_time IS '鏉ユ簮:data.tenantMemberCards.disable_end_time锛涘仠鐢ㄧ粨鏉熸椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.last_consume_time IS '鏉ユ簮:data.tenantMemberCards.last_consume_time锛涙渶杩戞秷璐规椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.create_time IS '鏉ユ簮:data.tenantMemberCards.create_time锛涘崱鍒涘缓鏃堕棿銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.status IS '鏉ユ簮:data.tenantMemberCards.status锛涘崱鐘舵€併€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.sort IS '鏉ユ簮:data.tenantMemberCards.sort锛涙帓搴忓瓧娈点€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tenantAvatar IS '鏉ユ簮:data.tenantMemberCards.tenantAvatar锛涚鎴峰ご鍍廢RL銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tenantName IS '鏉ユ簮:data.tenantMemberCards.tenantName锛涚鎴峰悕绉般€?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.pdAssisnatLevel IS '鏉ユ簮:data.tenantMemberCards.pdAssisnatLevel锛涘姪鏁欑瓑绾э紙鍏呭€艰禒閫侀厤缃級銆?;
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.cxAssisnatLevel IS '鏉ユ簮:data.tenantMemberCards.cxAssisnatLevel锛涘姪鏁欑瓑绾э紙鎸佺画娑堣垂閰嶇疆锛夈€?;
+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鏁存潯璁板綍锛屼繚鐣欐湭灞曞紑瀛楁銆?;
+
+-- ========== 鍏呭€艰褰曪紙鍏呭€艰褰?json -> data.settleList[] = {settleList, siteProfile}锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.recharge_settlements (
+ recharge_order_id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ site_name_snapshot TEXT,
+ member_id BIGINT,
+ member_name_snapshot TEXT,
+ member_phone_snapshot TEXT,
+ tenant_member_card_id BIGINT,
+ member_card_type_name TEXT,
+ settle_relate_id BIGINT,
+ settle_type INT,
+ settle_name TEXT,
+ is_first INT,
+ settle_status INT,
+ pay_amount NUMERIC(18,2),
+ refund_amount NUMERIC(18,2),
+ point_amount NUMERIC(18,2),
+ cash_amount NUMERIC(18,2),
+ online_amount NUMERIC(18,2),
+ balance_amount NUMERIC(18,2),
+ card_amount NUMERIC(18,2),
+ coupon_amount NUMERIC(18,2),
+ recharge_card_amount NUMERIC(18,2),
+ gift_card_amount NUMERIC(18,2),
+ prepay_money NUMERIC(18,2),
+ consume_money NUMERIC(18,2),
+ goods_money NUMERIC(18,2),
+ real_goods_money NUMERIC(18,2),
+ table_charge_money NUMERIC(18,2),
+ service_money NUMERIC(18,2),
+ activity_discount NUMERIC(18,2),
+ all_coupon_discount NUMERIC(18,2),
+ goods_promotion_money NUMERIC(18,2),
+ assistant_promotion_money NUMERIC(18,2),
+ assistant_pd_money NUMERIC(18,2),
+ assistant_cx_money NUMERIC(18,2),
+ assistant_manual_discount NUMERIC(18,2),
+ coupon_sale_amount NUMERIC(18,2),
+ member_discount_amount NUMERIC(18,2),
+ point_discount_price NUMERIC(18,2),
+ point_discount_cost NUMERIC(18,2),
+ adjust_amount NUMERIC(18,2),
+ rounding_amount NUMERIC(18,2),
+ payment_method INT,
+ can_be_revoked BOOLEAN,
+ is_bind_member BOOLEAN,
+ is_activity BOOLEAN,
+ is_use_coupon BOOLEAN,
+ is_use_discount BOOLEAN,
+ operator_id BIGINT,
+ operator_name_snapshot TEXT,
+ salesman_user_id BIGINT,
+ salesman_name TEXT,
+ order_remark TEXT,
+ table_id BIGINT,
+ serial_number BIGINT,
+ revoke_order_id BIGINT,
+ revoke_order_name TEXT,
+ revoke_time TIMESTAMPTZ,
+ create_time TIMESTAMPTZ,
+ pay_time TIMESTAMPTZ,
+ site_profile JSONB,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+COMMENT ON TABLE billiards_ods.recharge_settlements IS '???????.json -> data.settleList[]?? settleList ???????site_profile ???????payload ???????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.recharge_order_id IS '??:settleList.id???/????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.tenant_id IS '??:settleList.tenantId???ID?';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.site_id IS '??:settleList.siteId???ID????? siteProfile.id??';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.site_name_snapshot IS '??:siteProfile.shop_name ????? settleList.siteName?';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.member_id IS '??:settleList.memberId?????ID?';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.member_name_snapshot IS '??:settleList.memberName????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.member_phone_snapshot IS '??:settleList.memberPhone?????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.tenant_member_card_id IS '??:settleList.tenantMemberCardId??????ID?';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.member_card_type_name IS '??:settleList.memberCardTypeName?????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.settle_relate_id IS '??:settleList.settleRelateId?????ID?';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.settle_type IS '??:settleList.settleType?5=?????7=?????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.settle_name IS '??:settleList.settleName????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.is_first IS '??:settleList.isFirst????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.settle_status IS '??:settleList.settleStatus??????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.pay_amount IS '??:settleList.payAmount????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.refund_amount IS '??:settleList.refundAmount??????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.point_amount IS '??:settleList.pointAmount????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.cash_amount IS '??:settleList.cashAmount????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.online_amount IS '??:settleList.onlineAmount????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.balance_amount IS '??:settleList.balanceAmount????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.card_amount IS '??:settleList.cardAmount?????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.coupon_amount IS '??:settleList.couponAmount???????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.recharge_card_amount IS '??:settleList.rechargeCardAmount???????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.gift_card_amount IS '??:settleList.giftCardAmount???????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.prepay_money IS '??:settleList.prepayMoney????/?????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.consume_money IS '??:settleList.consumeMoney??????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.goods_money IS '??:settleList.goodsMoney????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.real_goods_money IS '??:settleList.realGoodsMoney????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.table_charge_money IS '??:settleList.tableChargeMoney??????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.service_money IS '??:settleList.serviceMoney??????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.activity_discount IS '??:settleList.activityDiscount????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.all_coupon_discount IS '??:settleList.allCouponDiscount????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.goods_promotion_money IS '??:settleList.goodsPromotionMoney????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.assistant_promotion_money IS '??:settleList.assistantPromotionMoney????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.assistant_pd_money IS '??:settleList.assistantPdMoney????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.assistant_cx_money IS '??:settleList.assistantCxMoney????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.assistant_manual_discount IS '??:settleList.assistantManualDiscount????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.coupon_sale_amount IS '??:settleList.couponSaleAmount??/???????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.member_discount_amount IS '??:settleList.memberDiscountAmount????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.point_discount_price IS '??:settleList.pointDiscountPrice????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.point_discount_cost IS '??:settleList.pointDiscountCost????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.adjust_amount IS '??:settleList.adjustAmount????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.rounding_amount IS '??:settleList.roundingAmount??????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.payment_method IS '??:settleList.paymentMethod????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.can_be_revoked IS '??:settleList.canBeRevoked???????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.is_bind_member IS '??:settleList.isBindMember??????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.is_activity IS '??:settleList.isActivity????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.is_use_coupon IS '??:settleList.isUseCoupon?????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.is_use_discount IS '??:settleList.isUseDiscount????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.operator_id IS '??:settleList.operatorId????/???ID?';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.operator_name_snapshot IS '??:settleList.operatorName?????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.salesman_user_id IS '??:settleList.salesManUserId??????ID?';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.salesman_name IS '??:settleList.salesManName???????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.order_remark IS '??:settleList.orderRemark??????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.table_id IS '??:settleList.tableId????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.serial_number IS '??:settleList.serialNumber???/?????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.revoke_order_id IS '??:settleList.revokeOrderId???????ID?';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.revoke_order_name IS '??:settleList.revokeOrderName???????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.revoke_time IS '??:settleList.revokeTime??????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.create_time IS '??:settleList.createTime????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.pay_time IS '??:settleList.payTime??????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.site_profile IS '??:siteProfile????????JSON??';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.source_file IS '????????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.source_endpoint IS '??????????/???';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.fetched_at IS '???????????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.payload IS '??JSON?????? settleList ? siteProfile??';
+
+
+-- ========== 缁撹处璁板綍锛堢粨璐﹁褰?json -> data.settleList[] = {settleList, siteProfile}锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.settlement_records (
+ settleList JSONB,
+ siteProfile JSONB,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+COMMENT ON TABLE billiards_ods.settlement_records IS '鏉ユ簮锛氱粨璐﹁褰?json -> data.settleList锛涢棬搴楁秷璐圭粨绠楄褰曪紝settleList鍚噾棰濇槑缁嗐€乻ettleType銆佹敮浠樻柟寮忕瓑锛宻iteProfile涓洪棬搴楀揩鐓с€?;
+COMMENT ON COLUMN billiards_ods.settlement_records.settleList IS '鏉ユ簮:data.settleList[].settleList锛涚粨绠椾富瀵硅薄鍘熸牱瀛樺偍銆?;
+COMMENT ON COLUMN billiards_ods.settlement_records.siteProfile IS '鏉ユ簮:data.settleList[].siteProfile锛涢棬搴椾俊鎭揩鐓с€?;
+COMMENT ON COLUMN billiards_ods.settlement_records.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰勩€?;
+COMMENT ON COLUMN billiards_ods.settlement_records.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣锛堢粨璐﹁褰曪級銆?;
+COMMENT ON COLUMN billiards_ods.settlement_records.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿銆?;
+COMMENT ON COLUMN billiards_ods.settlement_records.payload IS '鍘熷JSON鏁存潯璁板綍锛堝惈settleList涓巗iteProfile锛夛紝渚夸簬澶嶅師銆?;
+
+-- ========== 鍔╂暀搴熼櫎锛堝姪鏁欏簾闄?json -> data.abolitionAssistants锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.assistant_cancellation_records (
+ id BIGINT PRIMARY KEY,
+ siteId BIGINT,
+ siteProfile JSONB,
+ assistantName TEXT,
+ assistantAbolishAmount NUMERIC(18,2),
+ assistantOn INT,
+ pdChargeMinutes INT,
+ tableAreaId BIGINT,
+ tableArea TEXT,
+ tableId BIGINT,
+ tableName TEXT,
+ trashReason TEXT,
+ createTime TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+COMMENT ON TABLE billiards_ods.assistant_cancellation_records IS '鏉ユ簮锛氬姪鏁欏簾闄?json -> data.abolitionAssistants锛涜褰曞姪鏁欒搴熼櫎/鍙栨秷鐨勫彴娆′笌閲戦銆?;
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.id IS '鏉ユ簮:data.abolitionAssistants.id锛涘簾闄よ褰曚富閿€?;
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.siteId IS '鏉ユ簮:data.abolitionAssistants.siteId锛涢棬搴桰D銆?;
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.siteProfile IS '鏉ユ簮:data.abolitionAssistants.siteProfile锛涢棬搴椾俊鎭揩鐓с€?;
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.assistantName IS '鏉ユ簮:data.abolitionAssistants.assistantName锛涘姪鏁欏鍚?鏄电О銆?;
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.assistantAbolishAmount IS '鏉ユ簮:data.abolitionAssistants.assistantAbolishAmount锛涜搴熼櫎鐨勮垂鐢ㄩ噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.assistantOn IS '鏉ユ簮:data.abolitionAssistants.assistantOn锛涘姪鏁欎笂閽熸爣璇嗐€?;
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.pdChargeMinutes IS '鏉ユ簮:data.abolitionAssistants.pdChargeMinutes锛涜璐瑰垎閽熸暟銆?;
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.tableAreaId IS '鏉ユ簮:data.abolitionAssistants.tableAreaId锛涘彴鐞冨尯鍩烮D銆?;
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.tableArea IS '鏉ユ簮:data.abolitionAssistants.tableArea锛涘彴鐞冨尯鍩熷悕绉般€?;
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.tableId IS '鏉ユ簮:data.abolitionAssistants.tableId锛涘彴妗孖D銆?;
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.tableName IS '鏉ユ簮:data.abolitionAssistants.tableName锛涘彴妗屽悕绉般€?;
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.trashReason IS '鏉ユ簮:data.abolitionAssistants.trashReason锛涘簾闄ゅ師鍥犮€?;
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.createTime IS '鏉ユ簮:data.abolitionAssistants.createTime锛涜褰曟椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰勩€?;
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣銆?;
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿銆?;
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.payload IS '鍘熷JSON鏁存潯璁板綍锛屼繚鐣欏叾浠栧瓧娈点€?;
+
+-- ========== 鍔╂暀璐﹀彿锛堝姪鏁欒处鍙?json -> data.assistantInfos锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.assistant_accounts_master (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ assistant_no TEXT,
+ nickname TEXT,
+ real_name TEXT,
+ mobile TEXT,
+ team_id BIGINT,
+ team_name TEXT,
+ level TEXT,
+ assistant_status INT,
+ work_status INT,
+ leave_status INT,
+ entry_time TIMESTAMP,
+ resign_time TIMESTAMP,
+ start_time TIMESTAMP,
+ end_time TIMESTAMP,
+ create_time TIMESTAMP,
+ update_time TIMESTAMP,
+ order_trade_no TEXT,
+ staff_id BIGINT,
+ staff_profile_id BIGINT,
+ system_role_id BIGINT,
+ avatar TEXT,
+ gender INT,
+ show_status INT,
+ show_sort INT,
+ sum_grade NUMERIC(18,2),
+ get_grade_times INT,
+ video_introduction_url TEXT,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+COMMENT ON TABLE billiards_ods.assistant_accounts_master IS '鏉ユ簮锛氬姪鏁欒处鍙?json -> data.assistantInfos锛涘姪鏁欎汉鍛樻。妗堬紝鍏抽敭瀛楁灞曞紑锛屽叾浣欎繚鎸佸湪payload銆?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.id IS '鏉ユ簮:data.assistantInfos.id锛涘姪鏁欎富閿€?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.tenant_id IS '鏉ユ簮:data.assistantInfos.tenant_id锛涚鎴稩D銆?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.site_id IS '鏉ユ簮:data.assistantInfos.site_id锛涢棬搴桰D銆?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.assistant_no IS '鏉ユ簮:data.assistantInfos.assistant_no锛涘姪鏁欑紪鍙枫€?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.nickname IS '鏉ユ簮:data.assistantInfos.nickname锛涘姪鏁欐樀绉般€?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.real_name IS '鏉ユ簮:data.assistantInfos.real_name锛涚湡瀹炲鍚嶃€?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.mobile IS '鏉ユ簮:data.assistantInfos.mobile锛涙墜鏈哄彿銆?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.team_id IS '鏉ユ簮:data.assistantInfos.team_id锛涙墍灞炲洟闃烮D銆?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.team_name IS '鏉ユ簮:data.assistantInfos.team_name锛涙墍灞炲洟闃熷悕绉般€?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.level IS '鏉ユ簮:data.assistantInfos.level锛涘姪鏁欑骇鍒€?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.assistant_status IS '鏉ユ簮:data.assistantInfos.assistant_status锛涜处鍙风姸鎬?鍦ㄨ亴鐘舵€併€?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.work_status IS '鏉ユ簮:data.assistantInfos.work_status锛涘伐浣滅姸鎬侊紙鍦ㄧ嚎/蹇欑绛夛級銆?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.leave_status IS '鏉ユ簮:data.assistantInfos.leave_status锛涜鍋?绂诲矖鐘舵€併€?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.entry_time IS '鏉ユ簮:data.assistantInfos.entry_time锛涘叆鑱屾椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.resign_time IS '鏉ユ簮:data.assistantInfos.resign_time锛涚鑱?鎾ゅ矖鏃堕棿銆?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.start_time IS '鏉ユ簮:data.assistantInfos.start_time锛涜处鍙峰惎鐢ㄦ椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.end_time IS '鏉ユ簮:data.assistantInfos.end_time锛涜处鍙风粨鏉熸椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.create_time IS '鏉ユ簮:data.assistantInfos.create_time锛涘垱寤烘椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.update_time IS '鏉ユ簮:data.assistantInfos.update_time锛涙洿鏂版椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.order_trade_no IS '鏉ユ簮:data.assistantInfos.order_trade_no锛涘叧鑱旇鍗曞彿锛堣嫢鏈夛級銆?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.staff_id IS '鏉ユ簮:data.assistantInfos.staff_id锛涘憳宸D銆?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.staff_profile_id IS '鏉ユ簮:data.assistantInfos.staff_profile_id锛涘憳宸ユ。妗圛D銆?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.system_role_id IS '鏉ユ簮:data.assistantInfos.system_role_id锛涚郴缁熻鑹睮D銆?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.avatar IS '鏉ユ簮:data.assistantInfos.avatar锛涘ご鍍忋€?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.gender IS '鏉ユ簮:data.assistantInfos.gender锛涙€у埆銆?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.show_status IS '鏉ユ簮:data.assistantInfos.show_status锛涙槸鍚﹀睍绀恒€?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.show_sort IS '鏉ユ簮:data.assistantInfos.show_sort锛涘睍绀烘帓搴忋€?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.sum_grade IS '鏉ユ簮:data.assistantInfos.sum_grade锛涚患鍚堣瘎鍒嗙疮璁°€?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.get_grade_times IS '鏉ユ簮:data.assistantInfos.get_grade_times锛涜璇勫垎娆℃暟銆?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.video_introduction_url IS '鏉ユ簮:data.assistantInfos.video_introduction_url锛涗粙缁嶈棰慤RL銆?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰勩€?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣銆?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿銆?;
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.payload IS '鍘熷JSON鏁存潯璁板綍锛屽寘鍚湭灞曞紑鐨勫叾瀹冨瓧娈碉紙allow_cx銆乧harge_way绛夛級銆?;
+
+-- ========== 鍔╂暀娴佹按锛堝姪鏁欐祦姘?json -> data.orderAssistantDetails锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.assistant_service_records (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ siteProfile JSONB,
+ site_table_id BIGINT,
+ order_settle_id BIGINT,
+ order_trade_no TEXT,
+ order_pay_id BIGINT,
+ order_assistant_id BIGINT,
+ order_assistant_type INT,
+ assistantName TEXT,
+ assistantNo TEXT,
+ assistant_level TEXT,
+ assistant_team_id BIGINT,
+ nickname TEXT,
+ ledger_name TEXT,
+ ledger_group_name TEXT,
+ ledger_amount NUMERIC(18,2),
+ ledger_count NUMERIC(18,4),
+ ledger_unit_price NUMERIC(18,4),
+ ledger_status INT,
+ ledger_start_time TIMESTAMP,
+ ledger_end_time TIMESTAMP,
+ manual_discount_amount NUMERIC(18,2),
+ member_discount_amount NUMERIC(18,2),
+ coupon_deduct_money NUMERIC(18,2),
+ service_money NUMERIC(18,2),
+ projected_income NUMERIC(18,2),
+ real_use_seconds INT,
+ income_seconds INT,
+ start_use_time TIMESTAMP,
+ last_use_time TIMESTAMP,
+ create_time TIMESTAMP,
+ is_single_order INT,
+ is_delete INT,
+ is_trash INT,
+ trash_reason TEXT,
+ trash_applicant_id BIGINT,
+ trash_applicant_name TEXT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ salesman_name TEXT,
+ salesman_org_id BIGINT,
+ salesman_user_id BIGINT,
+ person_org_id BIGINT,
+ assistant_team_id_dup BIGINT,
+ add_clock INT,
+ returns_clock INT,
+ composite_grade NUMERIC(10,2),
+ composite_grade_time TIMESTAMP,
+ skill_grade NUMERIC(10,2),
+ service_grade NUMERIC(10,2),
+ sum_grade NUMERIC(10,2),
+ grade_status INT,
+ get_grade_times INT,
+ is_not_responding INT,
+ is_confirm INT,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+COMMENT ON TABLE billiards_ods.assistant_service_records IS '鏉ユ簮锛氬姪鏁欐祦姘?json -> data.orderAssistantDetails锛涘姪鏁欐湇鍔¤璐规槑缁嗭紝涓昏瀛楁灞曞紑锛屽叾浣欎繚鐣欏湪payload銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.id IS '鏉ユ簮:data.orderAssistantDetails.id锛涘姪鏁欐祦姘翠富閿€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.tenant_id IS '鏉ユ簮:data.orderAssistantDetails.tenant_id锛涚鎴稩D銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.site_id IS '鏉ユ簮:data.orderAssistantDetails.site_id锛涢棬搴桰D銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.siteProfile IS '鏉ユ簮:data.orderAssistantDetails.siteProfile锛涢棬搴楀揩鐓с€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.site_table_id IS '鏉ユ簮:data.orderAssistantDetails.site_table_id锛涘彴妗孖D銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.order_settle_id IS '鏉ユ簮:data.orderAssistantDetails.order_settle_id锛涚粨绠楀崟ID銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.order_trade_no IS '鏉ユ簮:data.orderAssistantDetails.order_trade_no锛涜鍗曞彿銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.order_pay_id IS '鏉ユ簮:data.orderAssistantDetails.order_pay_id锛涙敮浠樿褰旾D銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.order_assistant_id IS '鏉ユ簮:data.orderAssistantDetails.order_assistant_id锛涘姪鏁欒鍗曞叧鑱擨D銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.order_assistant_type IS '鏉ユ簮:data.orderAssistantDetails.order_assistant_type锛涘姪鏁欑被鍨嬫灇涓俱€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.assistantName IS '鏉ユ簮:data.orderAssistantDetails.assistantName锛涘姪鏁欏悕绉般€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.assistantNo IS '鏉ユ簮:data.orderAssistantDetails.assistantNo锛涘姪鏁欑紪鍙枫€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.assistant_level IS '鏉ユ簮:data.orderAssistantDetails.assistant_level锛涘姪鏁欑瓑绾с€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.assistant_team_id IS '鏉ユ簮:data.orderAssistantDetails.assistant_team_id锛涘姪鏁欏洟闃烮D銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.nickname IS '鏉ユ簮:data.orderAssistantDetails.nickname锛涘姪鏁欐樀绉般€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_name IS '鏉ユ簮:data.orderAssistantDetails.ledger_name锛涜璐归」鍚嶇О銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_group_name IS '鏉ユ簮:data.orderAssistantDetails.ledger_group_name锛涜璐瑰垎缁勩€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_amount IS '鏉ユ簮:data.orderAssistantDetails.ledger_amount锛涜璐归噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_count IS '鏉ユ簮:data.orderAssistantDetails.ledger_count锛涜璐规暟閲?鏃堕暱銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_unit_price IS '鏉ユ簮:data.orderAssistantDetails.ledger_unit_price锛涜璐瑰崟浠枫€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_status IS '鏉ユ簮:data.orderAssistantDetails.ledger_status锛涜璐圭姸鎬併€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_start_time IS '鏉ユ簮:data.orderAssistantDetails.ledger_start_time锛涜璐瑰紑濮嬫椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_end_time IS '鏉ユ簮:data.orderAssistantDetails.ledger_end_time锛涜璐圭粨鏉熸椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.manual_discount_amount IS '鏉ユ簮:data.orderAssistantDetails.manual_discount_amount锛涗汉宸ヤ紭鎯犻噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.member_discount_amount IS '鏉ユ簮:data.orderAssistantDetails.member_discount_amount锛涗細鍛樻姌鎵i噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.coupon_deduct_money IS '鏉ユ簮:data.orderAssistantDetails.coupon_deduct_money锛涘埜鎶垫墸閲戦銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.service_money IS '鏉ユ簮:data.orderAssistantDetails.service_money锛涙湇鍔¤垂閲戦銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.projected_income IS '鏉ユ簮:data.orderAssistantDetails.projected_income锛涢璁℃敹鍏ャ€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.real_use_seconds IS '鏉ユ簮:data.orderAssistantDetails.real_use_seconds锛涘疄闄呬娇鐢ㄧ鏁般€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.income_seconds IS '鏉ユ簮:data.orderAssistantDetails.income_seconds锛涜璐圭鏁般€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.start_use_time IS '鏉ユ簮:data.orderAssistantDetails.start_use_time锛涘紑濮嬩娇鐢ㄦ椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.last_use_time IS '鏉ユ簮:data.orderAssistantDetails.last_use_time锛涙渶鍚庝娇鐢ㄦ椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.create_time IS '鏉ユ簮:data.orderAssistantDetails.create_time锛涙祦姘村垱寤烘椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.is_single_order IS '鏉ユ簮:data.orderAssistantDetails.is_single_order锛涙槸鍚﹀崟鐐硅鍗曟爣璇嗐€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.is_delete IS '鏉ユ簮:data.orderAssistantDetails.is_delete锛涢€昏緫鍒犻櫎鏍囪瘑銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.is_trash IS '鏉ユ簮:data.orderAssistantDetails.is_trash锛涘簾闄ゆ爣璇嗐€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.trash_reason IS '鏉ユ簮:data.orderAssistantDetails.trash_reason锛涘簾闄ゅ師鍥犮€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.trash_applicant_id IS '鏉ユ簮:data.orderAssistantDetails.trash_applicant_id锛涘簾闄ょ敵璇蜂汉ID銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.trash_applicant_name IS '鏉ユ簮:data.orderAssistantDetails.trash_applicant_name锛涘簾闄ょ敵璇蜂汉鍚嶇О銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.operator_id IS '鏉ユ簮:data.orderAssistantDetails.operator_id锛涙搷浣滀汉ID銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.operator_name IS '鏉ユ簮:data.orderAssistantDetails.operator_name锛涙搷浣滀汉鍚嶇О銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.salesman_name IS '鏉ユ簮:data.orderAssistantDetails.salesman_name锛涢攢鍞?鎺ュ緟濮撳悕銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.salesman_org_id IS '鏉ユ簮:data.orderAssistantDetails.salesman_org_id锛涢攢鍞粍缁嘔D銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.salesman_user_id IS '鏉ユ簮:data.orderAssistantDetails.salesman_user_id锛涢攢鍞敤鎴稩D銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.person_org_id IS '鏉ユ簮:data.orderAssistantDetails.person_org_id锛涘憳宸ョ粍缁嘔D銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.assistant_team_id_dup IS '鏉ユ簮:data.orderAssistantDetails.assistant_team_id锛涘洟闃烮D鍐椾綑灞曞紑銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.add_clock IS '鏉ユ簮:data.orderAssistantDetails.add_clock锛涘姞閽熸椂闀挎爣璇嗐€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.returns_clock IS '鏉ユ簮:data.orderAssistantDetails.returns_clock锛涢€€閽熸椂闀挎爣璇嗐€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.composite_grade IS '鏉ユ簮:data.orderAssistantDetails.composite_grade锛涚患鍚堣瘎鍒嗐€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.composite_grade_time IS '鏉ユ簮:data.orderAssistantDetails.composite_grade_time锛涜瘎鍒嗘椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.skill_grade IS '鏉ユ簮:data.orderAssistantDetails.skill_grade锛涙妧鑳借瘎鍒嗐€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.service_grade IS '鏉ユ簮:data.orderAssistantDetails.service_grade锛涙湇鍔¤瘎鍒嗐€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.sum_grade IS '鏉ユ簮:data.orderAssistantDetails.sum_grade锛涜瘎鍒嗙疮璁°€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.grade_status IS '鏉ユ簮:data.orderAssistantDetails.grade_status锛涜瘎鍒嗙姸鎬併€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.get_grade_times IS '鏉ユ簮:data.orderAssistantDetails.get_grade_times锛涜璇勫垎娆℃暟銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.is_not_responding IS '鏉ユ簮:data.orderAssistantDetails.is_not_responding锛涙槸鍚︽棤鍝嶅簲銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.is_confirm IS '鏉ユ簮:data.orderAssistantDetails.is_confirm锛涙槸鍚﹀凡纭銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.payload IS '鍘熷JSON鏁存潯璁板綍锛屽叾浣欏瓧娈碉紙濡俵evelName銆乻killName绛夛級淇濈暀銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰勩€?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣銆?;
+COMMENT ON COLUMN billiards_ods.assistant_service_records.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿銆?;
+
+-- ========== 鍙版鍒楄〃锛堝彴妗屽垪琛?json -> data.siteTables锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.site_tables_master (
+ id BIGINT PRIMARY KEY,
+ site_id BIGINT,
+ siteName TEXT,
+ "appletQrCodeUrl" TEXT,
+ areaName TEXT,
+ audit_status INT,
+ charge_free INT,
+ create_time TIMESTAMP,
+ delay_lights_time INT,
+ is_online_reservation INT,
+ is_rest_area INT,
+ light_status INT,
+ only_allow_groupon INT,
+ order_delay_time INT,
+ self_table INT,
+ show_status INT,
+ site_table_area_id BIGINT,
+ tableStatusName TEXT,
+ table_cloth_use_Cycle INT,
+ table_cloth_use_time TIMESTAMP,
+ table_name TEXT,
+ table_price NUMERIC(18,2),
+ table_status INT,
+ temporary_light_second INT,
+ virtual_table INT,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+COMMENT ON TABLE billiards_ods.site_tables_master IS '鏉ユ簮锛氬彴妗屽垪琛?json -> data.siteTables锛涢棬搴楀彴妗屽熀纭€淇℃伅銆?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.id IS '鏉ユ簮:data.siteTables.id锛涘彴妗屼富閿€?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.site_id IS '鏉ユ簮:data.siteTables.site_id锛涢棬搴桰D銆?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.siteName IS '鏉ユ簮:data.siteTables.siteName锛涢棬搴楀悕绉般€?;
+COMMENT ON COLUMN billiards_ods.site_tables_master."appletQrCodeUrl" IS '鏉ユ簮:data.siteTables.appletQrCodeUrl锛涘皬绋嬪簭浜岀淮鐮乁RL銆?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.areaName IS '鏉ユ簮:data.siteTables.areaName锛涘尯鍩熷悕绉般€?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.audit_status IS '鏉ユ簮:data.siteTables.audit_status锛涘鏍哥姸鎬併€?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.charge_free IS '鏉ユ簮:data.siteTables.charge_free锛涙槸鍚﹀厤璐瑰彴銆?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.create_time IS '鏉ユ簮:data.siteTables.create_time锛涘垱寤烘椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.delay_lights_time IS '鏉ユ簮:data.siteTables.delay_lights_time锛涘欢鏃跺叧鐏鏁般€?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.is_online_reservation IS '鏉ユ簮:data.siteTables.is_online_reservation锛涙槸鍚︽敮鎸佺嚎涓婇绾︺€?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.is_rest_area IS '鏉ユ簮:data.siteTables.is_rest_area锛涙槸鍚︿紤鎭尯銆?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.light_status IS '鏉ユ簮:data.siteTables.light_status锛涚伅鍏夌姸鎬併€?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.only_allow_groupon IS '鏉ユ簮:data.siteTables.only_allow_groupon锛涙槸鍚︿粎鍏佽鍥㈣喘銆?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.order_delay_time IS '鏉ユ簮:data.siteTables.order_delay_time锛涘紑鍗曞欢鏃剁銆?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.self_table IS '鏉ユ簮:data.siteTables.self_table锛涙槸鍚﹁嚜鍔╁彴銆?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.show_status IS '鏉ユ簮:data.siteTables.show_status锛涘睍绀虹姸鎬併€?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.site_table_area_id IS '鏉ユ簮:data.siteTables.site_table_area_id锛涘彴妗屽尯鍩烮D銆?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.tableStatusName IS '鏉ユ簮:data.siteTables.tableStatusName锛涘彴妗岀姸鎬佸悕绉般€?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.table_cloth_use_Cycle IS '鏉ユ簮:data.siteTables.table_cloth_use_Cycle锛涚悆鍙板竷浣跨敤鍛ㄦ湡銆?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.table_cloth_use_time IS '鏉ユ簮:data.siteTables.table_cloth_use_time锛涚悆鍙板竷鏈€杩戞洿鎹㈡椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.table_name IS '鏉ユ簮:data.siteTables.table_name锛涘彴妗屽悕绉般€?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.table_price IS '鏉ユ簮:data.siteTables.table_price锛涘彴璐瑰崟浠枫€?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.table_status IS '鏉ユ簮:data.siteTables.table_status锛涘彴妗岀姸鎬併€?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.temporary_light_second IS '鏉ユ簮:data.siteTables.temporary_light_second锛涗复鏃跺紑鐏鏁般€?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.virtual_table IS '鏉ユ簮:data.siteTables.virtual_table锛涙槸鍚﹁櫄鎷熷彴銆?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰勩€?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣銆?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿銆?;
+COMMENT ON COLUMN billiards_ods.site_tables_master.payload IS '鍘熷JSON鏁存潯璁板綍锛屼繚鐣欓澶栧瓧娈点€?;
+
+-- ========== 鍙拌垂鎵撴姌锛堝彴璐规墦鎶?json -> data.taiFeeAdjustInfos锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.table_fee_discount_records (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ siteProfile JSONB,
+ site_table_id BIGINT,
+ tableProfile JSONB,
+ tenant_table_area_id BIGINT,
+ adjust_type INT,
+ ledger_amount NUMERIC(18,2),
+ ledger_count NUMERIC(18,4),
+ ledger_name TEXT,
+ ledger_status INT,
+ applicant_id BIGINT,
+ applicant_name TEXT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ order_settle_id BIGINT,
+ order_trade_no TEXT,
+ is_delete INT,
+ create_time TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+COMMENT ON TABLE billiards_ods.table_fee_discount_records IS '鏉ユ簮锛氬彴璐规墦鎶?json -> data.taiFeeAdjustInfos锛涘彴璐规姌鎵?璋冧环璁板綍銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.id IS '鏉ユ簮:data.taiFeeAdjustInfos.id锛涙姌鎵h褰曚富閿€?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.tenant_id IS '鏉ユ簮:data.taiFeeAdjustInfos.tenant_id锛涚鎴稩D銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.site_id IS '鏉ユ簮:data.taiFeeAdjustInfos.site_id锛涢棬搴桰D銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.siteProfile IS '鏉ユ簮:data.taiFeeAdjustInfos.siteProfile锛涢棬搴楀揩鐓с€?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.site_table_id IS '鏉ユ簮:data.taiFeeAdjustInfos.site_table_id锛涘彴妗孖D銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.tableProfile IS '鏉ユ簮:data.taiFeeAdjustInfos.tableProfile锛涘彴妗屼俊鎭揩鐓с€?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.tenant_table_area_id IS '鏉ユ簮:data.taiFeeAdjustInfos.tenant_table_area_id锛涘彴妗屽尯鍩烮D銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.adjust_type IS '鏉ユ簮:data.taiFeeAdjustInfos.adjust_type锛涜皟浠风被鍨嬨€?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.ledger_amount IS '鏉ユ簮:data.taiFeeAdjustInfos.ledger_amount锛涜皟浠峰悗閲戦銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.ledger_count IS '鏉ユ簮:data.taiFeeAdjustInfos.ledger_count锛涜皟浠锋暟閲?鏃堕暱銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.ledger_name IS '鏉ユ簮:data.taiFeeAdjustInfos.ledger_name锛涜璐归」鍚嶇О銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.ledger_status IS '鏉ユ簮:data.taiFeeAdjustInfos.ledger_status锛涜璐圭姸鎬併€?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.applicant_id IS '鏉ユ簮:data.taiFeeAdjustInfos.applicant_id锛涚敵璇蜂汉ID銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.applicant_name IS '鏉ユ簮:data.taiFeeAdjustInfos.applicant_name锛涚敵璇蜂汉鍚嶇О銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.operator_id IS '鏉ユ簮:data.taiFeeAdjustInfos.operator_id锛涙搷浣滀汉ID銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.operator_name IS '鏉ユ簮:data.taiFeeAdjustInfos.operator_name锛涙搷浣滀汉鍚嶇О銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.order_settle_id IS '鏉ユ簮:data.taiFeeAdjustInfos.order_settle_id锛涘叧鑱旂粨绠楀崟ID銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.order_trade_no IS '鏉ユ簮:data.taiFeeAdjustInfos.order_trade_no锛涜鍗曞彿銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.is_delete IS '鏉ユ簮:data.taiFeeAdjustInfos.is_delete锛涢€昏緫鍒犻櫎鏍囪瘑銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.create_time IS '鏉ユ簮:data.taiFeeAdjustInfos.create_time锛涜褰曞垱寤烘椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰勩€?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.payload IS '鍘熷JSON鏁存潯璁板綍锛屼繚鐣欏叾浠栧瓧娈点€?;
+
+-- ========== 鍙拌垂娴佹按锛堝彴璐规祦姘?json -> data.siteTableUseDetailsList锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.table_fee_transactions (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ siteProfile JSONB,
+ site_table_id BIGINT,
+ site_table_area_id BIGINT,
+ site_table_area_name TEXT,
+ tenant_table_area_id BIGINT,
+ order_trade_no TEXT,
+ order_pay_id BIGINT,
+ order_settle_id BIGINT,
+ ledger_name TEXT,
+ ledger_amount NUMERIC(18,2),
+ ledger_count NUMERIC(18,4),
+ ledger_unit_price NUMERIC(18,4),
+ ledger_status INT,
+ ledger_start_time TIMESTAMP,
+ ledger_end_time TIMESTAMP,
+ start_use_time TIMESTAMP,
+ last_use_time TIMESTAMP,
+ real_table_use_seconds INT,
+ real_table_charge_money NUMERIC(18,2),
+ add_clock_seconds INT,
+ adjust_amount NUMERIC(18,2),
+ coupon_promotion_amount NUMERIC(18,2),
+ member_discount_amount NUMERIC(18,2),
+ used_card_amount NUMERIC(18,2),
+ mgmt_fee NUMERIC(18,2),
+ service_money NUMERIC(18,2),
+ fee_total NUMERIC(18,2),
+ is_single_order INT,
+ is_delete INT,
+ member_id BIGINT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ salesman_name TEXT,
+ salesman_org_id BIGINT,
+ salesman_user_id BIGINT,
+ create_time TIMESTAMP,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+COMMENT ON TABLE billiards_ods.table_fee_transactions IS '鏉ユ簮锛氬彴璐规祦姘?json -> data.siteTableUseDetailsList锛涘彴妗屼娇鐢ㄨ璐规祦姘淬€?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.id IS '鏉ユ簮:data.siteTableUseDetailsList.id锛涘彴璐规祦姘翠富閿€?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.tenant_id IS '鏉ユ簮:data.siteTableUseDetailsList.tenant_id锛涚鎴稩D銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.site_id IS '鏉ユ簮:data.siteTableUseDetailsList.site_id锛涢棬搴桰D銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.siteProfile IS '鏉ユ簮:data.siteTableUseDetailsList.siteProfile锛涢棬搴楀揩鐓с€?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.site_table_id IS '鏉ユ簮:data.siteTableUseDetailsList.site_table_id锛涘彴妗孖D銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.site_table_area_id IS '鏉ユ簮:data.siteTableUseDetailsList.site_table_area_id锛涘彴妗屽尯鍩烮D銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.site_table_area_name IS '鏉ユ簮:data.siteTableUseDetailsList.site_table_area_name锛涘彴妗屽尯鍩熷悕绉般€?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.tenant_table_area_id IS '鏉ユ簮:data.siteTableUseDetailsList.tenant_table_area_id锛涚鎴蜂晶鍙版鍖哄煙ID銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.order_trade_no IS '鏉ユ簮:data.siteTableUseDetailsList.order_trade_no锛涜鍗曞彿銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.order_pay_id IS '鏉ユ簮:data.siteTableUseDetailsList.order_pay_id锛涙敮浠樿褰旾D銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.order_settle_id IS '鏉ユ簮:data.siteTableUseDetailsList.order_settle_id锛涚粨绠楀崟ID銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_name IS '鏉ユ簮:data.siteTableUseDetailsList.ledger_name锛涜璐归」鍚嶇О銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_amount IS '鏉ユ簮:data.siteTableUseDetailsList.ledger_amount锛涜璐归噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_count IS '鏉ユ簮:data.siteTableUseDetailsList.ledger_count锛涜璐规暟閲?鏃堕暱銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_unit_price IS '鏉ユ簮:data.siteTableUseDetailsList.ledger_unit_price锛涜璐瑰崟浠枫€?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_status IS '鏉ユ簮:data.siteTableUseDetailsList.ledger_status锛涜璐圭姸鎬併€?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_start_time IS '鏉ユ簮:data.siteTableUseDetailsList.ledger_start_time锛涜璐瑰紑濮嬫椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_end_time IS '鏉ユ簮:data.siteTableUseDetailsList.ledger_end_time锛涜璐圭粨鏉熸椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.start_use_time IS '鏉ユ簮:data.siteTableUseDetailsList.start_use_time锛涘紑濮嬩娇鐢ㄦ椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.last_use_time IS '鏉ユ簮:data.siteTableUseDetailsList.last_use_time锛涙渶鍚庝娇鐢ㄦ椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.real_table_use_seconds IS '鏉ユ簮:data.siteTableUseDetailsList.real_table_use_seconds锛涘疄闄呬娇鐢ㄧ銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.real_table_charge_money IS '鏉ユ簮:data.siteTableUseDetailsList.real_table_charge_money锛涘疄闄呭彴璐归噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.add_clock_seconds IS '鏉ユ簮:data.siteTableUseDetailsList.add_clock_seconds锛涘姞閽熺鏁般€?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.adjust_amount IS '鏉ユ簮:data.siteTableUseDetailsList.adjust_amount锛涜皟鏁撮噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.coupon_promotion_amount IS '鏉ユ簮:data.siteTableUseDetailsList.coupon_promotion_amount锛涗紭鎯犲埜浼樻儬閲戦銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.member_discount_amount IS '鏉ユ簮:data.siteTableUseDetailsList.member_discount_amount锛涗細鍛樻姌鎵i噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.used_card_amount IS '鏉ユ簮:data.siteTableUseDetailsList.used_card_amount锛涘崱鎶垫墸閲戦銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.mgmt_fee IS '鏉ユ簮:data.siteTableUseDetailsList.mgmt_fee锛涚鐞嗚垂銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.service_money IS '鏉ユ簮:data.siteTableUseDetailsList.service_money锛涙湇鍔¤垂銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.fee_total IS '鏉ユ簮:data.siteTableUseDetailsList.fee_total锛涘悎璁″彴璐广€?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.is_single_order IS '鏉ユ簮:data.siteTableUseDetailsList.is_single_order锛涙槸鍚﹀崟鐐硅鍗曘€?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.is_delete IS '鏉ユ簮:data.siteTableUseDetailsList.is_delete锛涢€昏緫鍒犻櫎鏍囪瘑銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.member_id IS '鏉ユ簮:data.siteTableUseDetailsList.member_id锛涗細鍛業D锛堣嫢缁戝畾锛夈€?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.operator_id IS '鏉ユ簮:data.siteTableUseDetailsList.operator_id锛涙搷浣滀汉ID銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.operator_name IS '鏉ユ簮:data.siteTableUseDetailsList.operator_name锛涙搷浣滀汉鍚嶇О銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.salesman_name IS '鏉ユ簮:data.siteTableUseDetailsList.salesman_name锛涢攢鍞?鎺ュ緟濮撳悕銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.salesman_org_id IS '鏉ユ簮:data.siteTableUseDetailsList.salesman_org_id锛涢攢鍞粍缁嘔D銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.salesman_user_id IS '鏉ユ簮:data.siteTableUseDetailsList.salesman_user_id锛涢攢鍞敤鎴稩D銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.create_time IS '鏉ユ簮:data.siteTableUseDetailsList.create_time锛涜褰曞垱寤烘椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.payload IS '鍘熷JSON鏁存潯璁板綍銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰勩€?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣銆?;
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿銆?;
+
+-- ========== 搴撳瓨鍙樺寲璁板綍1锛堝簱瀛樺彉鍖栬褰?.json -> data.queryDeliveryRecordsList锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.goods_stock_movements (
+ siteGoodsStockId BIGINT PRIMARY KEY,
+ tenantId BIGINT,
+ siteId BIGINT,
+ siteGoodsId BIGINT,
+ goodsName TEXT,
+ goodsCategoryId BIGINT,
+ goodsSecondCategoryId BIGINT,
+ unit TEXT,
+ price NUMERIC(18,4),
+ stockType INT,
+ changeNum NUMERIC(18,4),
+ startNum NUMERIC(18,4),
+ endNum NUMERIC(18,4),
+ changeNumA NUMERIC(18,4),
+ startNumA NUMERIC(18,4),
+ endNumA NUMERIC(18,4),
+ remark TEXT,
+ operatorName TEXT,
+ createTime TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+COMMENT ON TABLE billiards_ods.goods_stock_movements IS '鏉ユ簮锛氬簱瀛樺彉鍖栬褰?.json -> data.queryDeliveryRecordsList锛涘簱瀛樺彉鍔ㄦ祦姘达紙鍚富鍓崟浣嶏級銆?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.siteGoodsStockId IS '鏉ユ簮:data.queryDeliveryRecordsList.siteGoodsStockId锛涘簱瀛樺彉鍔ㄨ褰旾D銆?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.tenantId IS '鏉ユ簮:data.queryDeliveryRecordsList.tenantId锛涚鎴稩D銆?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.siteId IS '鏉ユ簮:data.queryDeliveryRecordsList.siteId锛涢棬搴桰D銆?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.siteGoodsId IS '鏉ユ簮:data.queryDeliveryRecordsList.siteGoodsId锛涢棬搴楀晢鍝両D銆?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.goodsName IS '鏉ユ簮:data.queryDeliveryRecordsList.goodsName锛涘晢鍝佸悕绉般€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.goodsCategoryId IS '鏉ユ簮:data.queryDeliveryRecordsList.goodsCategoryId锛涗竴绾у垎绫籌D銆?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.goodsSecondCategoryId IS '鏉ユ簮:data.queryDeliveryRecordsList.goodsSecondCategoryId锛涗簩绾у垎绫籌D銆?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.unit IS '鏉ユ簮:data.queryDeliveryRecordsList.unit锛涜閲忓崟浣嶃€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.price IS '鏉ユ簮:data.queryDeliveryRecordsList.price锛涘崟浠枫€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.stockType IS '鏉ユ簮:data.queryDeliveryRecordsList.stockType锛涘彉鍔ㄧ被鍨嬨€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.changeNum IS '鏉ユ簮:data.queryDeliveryRecordsList.changeNum锛涗富鍗曚綅鍙樺姩鏁伴噺銆?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.startNum IS '鏉ユ簮:data.queryDeliveryRecordsList.startNum锛涘彉鍔ㄥ墠搴撳瓨锛堜富鍗曚綅锛夈€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.endNum IS '鏉ユ簮:data.queryDeliveryRecordsList.endNum锛涘彉鍔ㄥ悗搴撳瓨锛堜富鍗曚綅锛夈€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.changeNumA IS '鏉ユ簮:data.queryDeliveryRecordsList.changeNumA锛涘壇鍗曚綅鍙樺姩鏁伴噺銆?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.startNumA IS '鏉ユ簮:data.queryDeliveryRecordsList.startNumA锛涘彉鍔ㄥ墠搴撳瓨锛堝壇鍗曚綅锛夈€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.endNumA IS '鏉ユ簮:data.queryDeliveryRecordsList.endNumA锛涘彉鍔ㄥ悗搴撳瓨锛堝壇鍗曚綅锛夈€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.remark IS '鏉ユ簮:data.queryDeliveryRecordsList.remark锛涘娉ㄣ€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.operatorName IS '鏉ユ簮:data.queryDeliveryRecordsList.operatorName锛涙搷浣滀汉銆?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.createTime IS '鏉ユ簮:data.queryDeliveryRecordsList.createTime锛涘彉鍔ㄦ椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰勩€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣銆?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿銆?;
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.payload IS '鍘熷JSON鏁存潯璁板綍銆?;
+
+-- ========== 搴撳瓨鍙樺寲璁板綍2锛堝簱瀛樺彉鍖栬褰?.json -> data.goodsCategoryList锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.stock_goods_category_tree (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ category_name TEXT,
+ alias_name TEXT,
+ pid BIGINT,
+ business_name TEXT,
+ tenant_goods_business_id BIGINT,
+ open_salesman INT,
+ categoryBoxes JSONB,
+ sort INT,
+ is_warehousing INT,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+COMMENT ON TABLE billiards_ods.stock_goods_category_tree IS '鏉ユ簮锛氬簱瀛樺彉鍖栬褰?.json -> data.goodsCategoryList锛涢棬搴楀晢鍝佸垎绫伙紙鍚瓙绫籧ategoryBoxes锛夈€?;
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.id IS '鏉ユ簮:data.goodsCategoryList.id锛涘垎绫籌D銆?;
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.tenant_id IS '鏉ユ簮:data.goodsCategoryList.tenant_id锛涚鎴稩D銆?;
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.category_name IS '鏉ユ簮:data.goodsCategoryList.category_name锛涘垎绫诲悕绉般€?;
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.alias_name IS '鏉ユ簮:data.goodsCategoryList.alias_name锛涘埆鍚嶃€?;
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.pid IS '鏉ユ簮:data.goodsCategoryList.pid锛涚埗绾у垎绫籌D銆?;
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.business_name IS '鏉ユ簮:data.goodsCategoryList.business_name锛涗笟鍔$嚎鍚嶇О銆?;
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.tenant_goods_business_id IS '鏉ユ簮:data.goodsCategoryList.tenant_goods_business_id锛涗笟鍔$嚎ID銆?;
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.open_salesman IS '鏉ユ簮:data.goodsCategoryList.open_salesman锛涢攢鍞紑鍏?鏉冮檺銆?;
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.categoryBoxes IS '鏉ユ簮:data.goodsCategoryList.categoryBoxes锛涘瓙鍒嗙被鍒楄〃JSON銆?;
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.sort IS '鏉ユ簮:data.goodsCategoryList.sort锛涙帓搴忓彿銆?;
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.is_warehousing IS '鏉ユ簮:data.goodsCategoryList.is_warehousing锛涙槸鍚﹀叆搴撶鐞嗐€?;
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰勩€?;
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣銆?;
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿銆?;
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.payload IS '鍘熷JSON鏁存潯璁板綍銆?;
+
+-- ========== 搴撳瓨姹囨€伙紙搴撳瓨姹囨€?json锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.goods_stock_summary (
+ siteGoodsId BIGINT PRIMARY KEY,
+ goodsName TEXT,
+ goodsUnit TEXT,
+ goodsCategoryId BIGINT,
+ goodsCategorySecondId BIGINT,
+ categoryName TEXT,
+ rangeStartStock NUMERIC(18,4),
+ rangeEndStock NUMERIC(18,4),
+ rangeIn NUMERIC(18,4),
+ rangeOut NUMERIC(18,4),
+ rangeSale NUMERIC(18,4),
+ rangeSaleMoney NUMERIC(18,2),
+ rangeInventory NUMERIC(18,4),
+ currentStock NUMERIC(18,4),
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+COMMENT ON TABLE billiards_ods.goods_stock_summary IS '鏉ユ簮锛氬簱瀛樻眹鎬?json锛涢棬搴楀晢鍝佸湪缁熻鍖洪棿鍐呯殑搴撳瓨姹囨€汇€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.siteGoodsId IS '鏉ユ簮:siteGoodsId锛涢棬搴楀晢鍝両D銆?;
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.goodsName IS '鏉ユ簮:goodsName锛涘晢鍝佸悕绉般€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.goodsUnit IS '鏉ユ簮:goodsUnit锛涜閲忓崟浣嶃€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.goodsCategoryId IS '鏉ユ簮:goodsCategoryId锛涗竴绾у垎绫籌D銆?;
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.goodsCategorySecondId IS '鏉ユ簮:goodsCategorySecondId锛涗簩绾у垎绫籌D銆?;
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.categoryName IS '鏉ユ簮:categoryName锛涘垎绫诲悕绉般€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeStartStock IS '鏉ユ簮:rangeStartStock锛涘尯闂存湡鍒濆簱瀛樸€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeEndStock IS '鏉ユ簮:rangeEndStock锛涘尯闂存湡鏈簱瀛樸€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeIn IS '鏉ユ簮:rangeIn锛涘尯闂村叆搴撴暟閲忋€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeOut IS '鏉ユ簮:rangeOut锛涘尯闂村嚭搴撴暟閲忋€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeSale IS '鏉ユ簮:rangeSale锛涘尯闂撮攢鍞暟閲忋€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeSaleMoney IS '鏉ユ簮:rangeSaleMoney锛涘尯闂撮攢鍞噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeInventory IS '鏉ユ簮:rangeInventory锛涚洏鐐瑰樊寮傛暟閲忋€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.currentStock IS '鏉ユ簮:currentStock锛涘綋鍓嶅簱瀛樸€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰勩€?;
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣銆?;
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿銆?;
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.payload IS '鍘熷JSON鏁存潯璁板綍銆?;
+
+-- ========== 鏀粯璁板綍锛堟敮浠樿褰?json锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.payment_transactions (
+ id BIGINT PRIMARY KEY,
+ site_id BIGINT,
+ siteProfile JSONB,
+ relate_type INT,
+ relate_id BIGINT,
+ pay_amount NUMERIC(18,2),
+ pay_status INT,
+ pay_time TIMESTAMP,
+ create_time TIMESTAMP,
+ payment_method INT,
+ online_pay_channel INT,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+COMMENT ON TABLE billiards_ods.payment_transactions IS '鏉ユ簮锛氭敮浠樿褰?json锛涙敮浠樻祦姘达紝鍚嚎涓?绾夸笅娓犻亾銆?;
+COMMENT ON COLUMN billiards_ods.payment_transactions.id IS '鏉ユ簮:id锛涙敮浠樿褰曚富閿€?;
+COMMENT ON COLUMN billiards_ods.payment_transactions.site_id IS '鏉ユ簮:site_id锛涢棬搴桰D銆?;
+COMMENT ON COLUMN billiards_ods.payment_transactions.siteProfile IS '鏉ユ簮:siteProfile锛涢棬搴椾俊鎭揩鐓с€?;
+COMMENT ON COLUMN billiards_ods.payment_transactions.relate_type IS '鏉ユ簮:relate_type锛涘叧鑱斾笟鍔$被鍨嬨€?;
+COMMENT ON COLUMN billiards_ods.payment_transactions.relate_id IS '鏉ユ簮:relate_id锛涘叧鑱斾笟鍔D銆?;
+COMMENT ON COLUMN billiards_ods.payment_transactions.pay_amount IS '鏉ユ簮:pay_amount锛涙敮浠橀噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.payment_transactions.pay_status IS '鏉ユ簮:pay_status锛涙敮浠樼姸鎬併€?;
+COMMENT ON COLUMN billiards_ods.payment_transactions.pay_time IS '鏉ユ簮:pay_time锛涙敮浠樻椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.payment_transactions.create_time IS '鏉ユ簮:create_time锛涘垱寤烘椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.payment_transactions.payment_method IS '鏉ユ簮:payment_method锛涙敮浠樻柟寮忔灇涓俱€?;
+COMMENT ON COLUMN billiards_ods.payment_transactions.online_pay_channel IS '鏉ユ簮:online_pay_channel锛涚嚎涓婃笭閬撲唬鐮併€?;
+COMMENT ON COLUMN billiards_ods.payment_transactions.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰勩€?;
+COMMENT ON COLUMN billiards_ods.payment_transactions.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣銆?;
+COMMENT ON COLUMN billiards_ods.payment_transactions.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿銆?;
+COMMENT ON COLUMN billiards_ods.payment_transactions.payload IS '鍘熷JSON鏁存潯璁板綍銆?;
+
+-- ========== 閫€娆捐褰曪紙閫€娆捐褰?json锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.refund_transactions (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ tenantName TEXT,
+ site_id BIGINT,
+ siteProfile JSONB,
+ relate_type INT,
+ relate_id BIGINT,
+ pay_sn TEXT,
+ pay_amount NUMERIC(18,2),
+ refund_amount NUMERIC(18,2),
+ round_amount NUMERIC(18,2),
+ pay_status INT,
+ pay_time TIMESTAMP,
+ create_time TIMESTAMP,
+ payment_method INT,
+ pay_terminal INT,
+ pay_config_id BIGINT,
+ online_pay_channel INT,
+ online_pay_type INT,
+ channel_fee NUMERIC(18,2),
+ channel_payer_id TEXT,
+ channel_pay_no TEXT,
+ member_id BIGINT,
+ member_card_id BIGINT,
+ cashier_point_id BIGINT,
+ operator_id BIGINT,
+ action_type INT,
+ check_status INT,
+ is_revoke INT,
+ is_delete INT,
+ balance_frozen_amount NUMERIC(18,2),
+ card_frozen_amount NUMERIC(18,2),
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+COMMENT ON TABLE billiards_ods.refund_transactions IS '鏉ユ簮锛氶€€娆捐褰?json锛涢€€娆惧強鍐荤粨璧勯噾鏄庣粏銆?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.id IS '鏉ユ簮:id锛涢€€娆捐褰曚富閿€?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.tenant_id IS '鏉ユ簮:tenant_id锛涚鎴稩D銆?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.tenantName IS '鏉ユ簮:tenantName锛涚鎴峰悕绉般€?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.site_id IS '鏉ユ簮:site_id锛涢棬搴桰D銆?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.siteProfile IS '鏉ユ簮:siteProfile锛涢棬搴楀揩鐓с€?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.relate_type IS '鏉ユ簮:relate_type锛涘叧鑱斾笟鍔$被鍨嬨€?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.relate_id IS '鏉ユ簮:relate_id锛涘叧鑱斾笟鍔D銆?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_sn IS '鏉ユ簮:pay_sn锛涙敮浠樻祦姘村彿銆?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_amount IS '鏉ユ簮:pay_amount锛涘師鏀粯閲戦銆?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.refund_amount IS '鏉ユ簮:refund_amount锛涢€€娆鹃噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.round_amount IS '鏉ユ簮:round_amount锛涙姽闆堕噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_status IS '鏉ユ簮:pay_status锛涚姸鎬併€?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_time IS '鏉ユ簮:pay_time锛涙敮浠?閫€娆炬椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.create_time IS '鏉ユ簮:create_time锛涘垱寤烘椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.payment_method IS '鏉ユ簮:payment_method锛涙敮浠樻柟寮忋€?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_terminal IS '鏉ユ簮:pay_terminal锛涙敮浠樼粓绔被鍨嬨€?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_config_id IS '鏉ユ簮:pay_config_id锛涙敮浠橀厤缃甀D銆?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.online_pay_channel IS '鏉ユ簮:online_pay_channel锛涚嚎涓婃笭閬撱€?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.online_pay_type IS '鏉ユ簮:online_pay_type锛涚嚎涓婃敮浠樼被鍨嬨€?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.channel_fee IS '鏉ユ簮:channel_fee锛涙笭閬撴墜缁垂銆?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.channel_payer_id IS '鏉ユ簮:channel_payer_id锛涙笭閬撲粯娆句汉鏍囪瘑銆?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.channel_pay_no IS '鏉ユ簮:channel_pay_no锛涙笭閬撴敮浠樺崟鍙枫€?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.member_id IS '鏉ユ簮:member_id锛涗細鍛業D銆?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.member_card_id IS '鏉ユ簮:member_card_id锛涗細鍛樺崱ID銆?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.cashier_point_id IS '鏉ユ簮:cashier_point_id锛涙敹閾剁偣ID銆?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.operator_id IS '鏉ユ簮:operator_id锛涙搷浣滀汉ID銆?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.action_type IS '鏉ユ簮:action_type锛涘姩浣滅被鍨嬨€?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.check_status IS '鏉ユ簮:check_status锛涘鏍哥姸鎬併€?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.is_revoke IS '鏉ユ簮:is_revoke锛涙槸鍚︽挙閿€銆?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.is_delete IS '鏉ユ簮:is_delete锛涢€昏緫鍒犻櫎鏍囪瘑銆?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.balance_frozen_amount IS '鏉ユ簮:balance_frozen_amount锛涗綑棰濆喕缁撻噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.card_frozen_amount IS '鏉ユ簮:card_frozen_amount锛涘崱鍐荤粨閲戦銆?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰勩€?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣銆?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿銆?;
+COMMENT ON COLUMN billiards_ods.refund_transactions.payload IS '鍘熷JSON鏁存潯璁板綍銆?;
+
+-- ========== 骞冲彴楠屽埜璁板綍锛堝钩鍙伴獙鍒歌褰?json锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.platform_coupon_redemption_records (
+ id BIGINT PRIMARY KEY,
+ verify_id BIGINT,
+ certificate_id TEXT,
+ coupon_code TEXT,
+ coupon_name TEXT,
+ coupon_channel INT,
+ groupon_type INT,
+ group_package_id BIGINT,
+ sale_price NUMERIC(18,2),
+ coupon_money NUMERIC(18,2),
+ coupon_free_time NUMERIC(18,2),
+ coupon_cover TEXT,
+ coupon_remark TEXT,
+ use_status INT,
+ consume_time TIMESTAMP,
+ create_time TIMESTAMP,
+ deal_id TEXT,
+ channel_deal_id TEXT,
+ site_id BIGINT,
+ site_order_id BIGINT,
+ table_id BIGINT,
+ tenant_id BIGINT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ is_delete INT,
+ siteProfile JSONB,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+COMMENT ON TABLE billiards_ods.platform_coupon_redemption_records IS '鏉ユ簮锛氬钩鍙伴獙鍒歌褰?json锛涚涓夋柟/骞冲彴鍒告牳閿€娴佹按銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.id IS '鏉ユ簮:id锛涙祦姘翠富閿€?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.verify_id IS '鏉ユ簮:verify_id锛涢獙鍒窱D銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.certificate_id IS '鏉ユ簮:certificate_id锛涘埜鍑瘉ID銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_code IS '鏉ユ簮:coupon_code锛涘埜鐮併€?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_name IS '鏉ユ簮:coupon_name锛涘埜鍚嶇О銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_channel IS '鏉ユ簮:coupon_channel锛涘埜娓犻亾銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.groupon_type IS '鏉ユ簮:groupon_type锛涘洟璐被鍨嬨€?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.group_package_id IS '鏉ユ簮:group_package_id锛涘洟璐椁怚D銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.sale_price IS '鏉ユ簮:sale_price锛涘敭鍗栦环銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_money IS '鏉ユ簮:coupon_money锛涘埜闈㈤/鎶垫墸閲戦銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_free_time IS '鏉ユ簮:coupon_free_time锛涜禒閫佹椂闀?鍏嶈垂鏃堕暱銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_cover IS '鏉ユ簮:coupon_cover锛涘埜灏侀潰URL銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_remark IS '鏉ユ簮:coupon_remark锛涘埜澶囨敞銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.use_status IS '鏉ユ簮:use_status锛涙牳閿€鐘舵€併€?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.consume_time IS '鏉ユ簮:consume_time锛涙牳閿€鏃堕棿銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.create_time IS '鏉ユ簮:create_time锛涘垱寤烘椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.deal_id IS '鏉ユ簮:deal_id锛涗氦鏄揑D銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.channel_deal_id IS '鏉ユ簮:channel_deal_id锛涙笭閬撲氦鏄揑D銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.site_id IS '鏉ユ簮:site_id锛涢棬搴桰D銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.site_order_id IS '鏉ユ簮:site_order_id锛涢棬搴楄鍗旾D銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.table_id IS '鏉ユ簮:table_id锛涘彴妗孖D銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.tenant_id IS '鏉ユ簮:tenant_id锛涚鎴稩D銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.operator_id IS '鏉ユ簮:operator_id锛涙搷浣滀汉ID銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.operator_name IS '鏉ユ簮:operator_name锛涙搷浣滀汉鍚嶇О銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.is_delete IS '鏉ユ簮:is_delete锛涢€昏緫鍒犻櫎鏍囪瘑銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.siteProfile IS '鏉ユ簮:siteProfile锛涢棬搴楀揩鐓с€?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰勩€?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿銆?;
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.payload IS '鍘熷JSON鏁存潯璁板綍銆?;
+
+-- ========== 鍟嗗搧妗f锛堝晢鍝佹。妗?json -> data.tenantGoodsList锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.tenant_goods_master (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ goods_name TEXT,
+ goods_bar_code TEXT,
+ goods_category_id BIGINT,
+ goods_second_category_id BIGINT,
+ categoryName TEXT,
+ unit TEXT,
+ goods_number TEXT,
+ goods_state INT,
+ sale_channel INT,
+ able_discount INT,
+ able_site_transfer INT,
+ is_delete INT,
+ is_warehousing INT,
+ isInSite INT,
+ cost_price NUMERIC(18,4),
+ cost_price_type INT,
+ market_price NUMERIC(18,4),
+ min_discount_price NUMERIC(18,4),
+ common_sale_royalty NUMERIC(18,4),
+ point_sale_royalty NUMERIC(18,4),
+ pinyin_initial TEXT,
+ commodityCode TEXT,
+ commodity_code TEXT,
+ goods_cover TEXT,
+ supplier_id BIGINT,
+ remark_name TEXT,
+ create_time TIMESTAMP,
+ update_time TIMESTAMP,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+COMMENT ON TABLE billiards_ods.tenant_goods_master IS '鏉ユ簮锛氬晢鍝佹。妗?json -> data.tenantGoodsList锛涚鎴峰晢鍝佷富鏁版嵁銆?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.id IS '鏉ユ簮:id锛涘晢鍝両D銆?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.tenant_id IS '鏉ユ簮:tenant_id锛涚鎴稩D銆?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_name IS '鏉ユ簮:goods_name锛涘晢鍝佸悕绉般€?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_bar_code IS '鏉ユ簮:goods_bar_code锛涙潯鐮併€?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_category_id IS '鏉ユ簮:goods_category_id锛涗竴绾у垎绫籌D銆?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_second_category_id IS '鏉ユ簮:goods_second_category_id锛涗簩绾у垎绫籌D銆?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.categoryName IS '鏉ユ簮:categoryName锛涘垎绫诲悕绉般€?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.unit IS '鏉ユ簮:unit锛涜閲忓崟浣嶃€?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_number IS '鏉ユ簮:goods_number锛涘晢鍝佺紪鐮併€?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_state IS '鏉ユ簮:goods_state锛涘晢鍝佺姸鎬併€?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.sale_channel IS '鏉ユ簮:sale_channel锛涢攢鍞笭閬撱€?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.able_discount IS '鏉ユ簮:able_discount锛涙槸鍚﹀彲鎶樻墸銆?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.able_site_transfer IS '鏉ユ簮:able_site_transfer锛涙槸鍚﹀彲璺ㄥ簵銆?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.is_delete IS '鏉ユ簮:is_delete锛涢€昏緫鍒犻櫎鏍囪瘑銆?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.is_warehousing IS '鏉ユ簮:is_warehousing锛涙槸鍚︾撼鍏ュ簱瀛樼鐞嗐€?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.isInSite IS '鏉ユ簮:isInSite锛涙槸鍚﹂棬搴楀晢鍝佹爣璇嗐€?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.cost_price IS '鏉ユ簮:cost_price锛涙垚鏈环銆?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.cost_price_type IS '鏉ユ簮:cost_price_type锛涙垚鏈环绫诲瀷銆?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.market_price IS '鏉ユ簮:market_price锛涘競鍦轰环銆?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.min_discount_price IS '鏉ユ簮:min_discount_price锛涙渶浣庢姌鍚庝环銆?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.common_sale_royalty IS '鏉ユ簮:common_sale_royalty锛涙櫘閫氶攢鍞彁鎴愩€?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.point_sale_royalty IS '鏉ユ簮:point_sale_royalty锛涚Н鍒嗛攢鍞彁鎴愩€?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.pinyin_initial IS '鏉ユ簮:pinyin_initial锛涙嫾闊抽瀛楁瘝銆?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.commodityCode IS '鏉ユ簮:commodityCode锛涘晢鍝佺紪鐮侊紙瀛楁鍒悕锛夈€?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.commodity_code IS '鏉ユ簮:commodity_code锛涘晢鍝佺紪鐮侊紙鍙︿竴瀛楁锛夈€?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_cover IS '鏉ユ簮:goods_cover锛涘晢鍝佸浘鐗囥€?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.supplier_id IS '鏉ユ簮:supplier_id锛涗緵搴斿晢ID銆?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.remark_name IS '鏉ユ簮:remark_name锛涘娉ㄥ悕銆?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.create_time IS '鏉ユ簮:create_time锛涘垱寤烘椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.update_time IS '鏉ユ簮:update_time锛涙洿鏂版椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.payload IS '鍘熷JSON鏁存潯璁板綍锛屼繚鐣欐湭灞曞紑瀛楁銆?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰勩€?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣銆?;
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿銆?;
+
+-- ========== 鍥㈣喘濂楅锛堝洟璐椁?json -> data.packageCouponList锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.group_buy_packages (
+ id BIGINT PRIMARY KEY,
+ package_id BIGINT,
+ package_name TEXT,
+ selling_price NUMERIC(18,2),
+ coupon_money NUMERIC(18,2),
+ date_type INT,
+ date_info TEXT,
+ start_time TIMESTAMP,
+ end_time TIMESTAMP,
+ start_clock TEXT,
+ end_clock TEXT,
+ add_start_clock TEXT,
+ add_end_clock TEXT,
+ duration INT,
+ usable_count INT,
+ usable_range INT,
+ table_area_id BIGINT,
+ table_area_name TEXT,
+ table_area_id_list JSONB,
+ tenant_table_area_id BIGINT,
+ tenant_table_area_id_list JSONB,
+ site_id BIGINT,
+ site_name TEXT,
+ tenant_id BIGINT,
+ card_type_ids JSONB,
+ group_type INT,
+ system_group_type INT,
+ type INT,
+ effective_status INT,
+ is_enabled INT,
+ is_delete INT,
+ max_selectable_categories INT,
+ area_tag_type INT,
+ creator_name TEXT,
+ create_time TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+COMMENT ON TABLE billiards_ods.group_buy_packages IS '鏉ユ簮锛氬洟璐椁?json -> data.packageCouponList锛涘洟璐?濂楅瀹氫箟銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.id IS '鏉ユ簮:id锛涘椁愯褰曚富閿€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.package_id IS '鏉ユ簮:package_id锛涘椁怚D銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.package_name IS '鏉ユ簮:package_name锛涘椁愬悕绉般€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.selling_price IS '鏉ユ簮:selling_price锛涘敭鍗栦环銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.coupon_money IS '鏉ユ簮:coupon_money锛涘埜闈㈤/浠峰€笺€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.date_type IS '鏉ユ簮:date_type锛涙棩鏈熺被鍨嬨€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.date_info IS '鏉ユ簮:date_info锛涙棩鏈熼檺鍒舵弿杩般€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.start_time IS '鏉ユ簮:start_time锛涙湁鏁堟湡寮€濮嬨€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.end_time IS '鏉ユ簮:end_time锛涙湁鏁堟湡缁撴潫銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.start_clock IS '鏉ユ簮:start_clock锛涙瘡鏃ュ彲鐢ㄥ紑濮嬫椂娈点€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.end_clock IS '鏉ユ簮:end_clock锛涙瘡鏃ュ彲鐢ㄧ粨鏉熸椂娈点€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.add_start_clock IS '鏉ユ簮:add_start_clock锛涢檮鍔犲紑濮嬫椂娈点€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.add_end_clock IS '鏉ユ簮:add_end_clock锛涢檮鍔犵粨鏉熸椂娈点€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.duration IS '鏉ユ簮:duration锛涘彲鐢ㄦ椂闀?鍒嗛挓銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.usable_count IS '鏉ユ簮:usable_count锛涘彲鐢ㄦ鏁般€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.usable_range IS '鏉ユ簮:usable_range锛涘彲鐢ㄨ寖鍥寸被鍨嬨€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.table_area_id IS '鏉ユ簮:table_area_id锛涘彴妗屽尯鍩烮D銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.table_area_name IS '鏉ユ簮:table_area_name锛涘彴妗屽尯鍩熷悕绉般€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.table_area_id_list IS '鏉ユ簮:table_area_id_list锛涘彲鐢ㄥ彴妗屽尯鍩熷垪琛↗SON銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.tenant_table_area_id IS '鏉ユ簮:tenant_table_area_id锛涚鎴峰彴妗屽尯鍩烮D銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.tenant_table_area_id_list IS '鏉ユ簮:tenant_table_area_id_list锛涚鎴峰彴妗屽尯鍩熷垪琛↗SON銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.site_id IS '鏉ユ簮:site_id锛涢棬搴桰D銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.site_name IS '鏉ユ簮:site_name锛涢棬搴楀悕绉般€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.tenant_id IS '鏉ユ簮:tenant_id锛涚鎴稩D銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.card_type_ids IS '鏉ユ簮:card_type_ids锛涘厑璁镐娇鐢ㄧ殑鍗$被鍨婭D鍒楄〃JSON銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.group_type IS '鏉ユ簮:group_type锛涘洟璐被鍨嬨€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.system_group_type IS '鏉ユ簮:system_group_type锛涚郴缁熷洟璐被鍨嬨€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.type IS '鏉ユ簮:type锛涘椁愮被鍨嬨€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.effective_status IS '鏉ユ簮:effective_status锛涚敓鏁堢姸鎬併€?;
+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.max_selectable_categories IS '鏉ユ簮:max_selectable_categories锛涘彲閫夊垎绫讳笂闄愩€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.area_tag_type IS '鏉ユ簮:area_tag_type锛涘尯鍩熸爣绛剧被鍨嬨€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.creator_name IS '鏉ユ簮:creator_name锛涘垱寤轰汉鍚嶇О銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages.create_time IS '鏉ユ簮:create_time锛涘垱寤烘椂闂淬€?;
+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鏁存潯璁板綍銆?;
+
+-- ========== 鍥㈣喘濂楅娴佹按锛堝洟璐椁愭祦姘?json -> data.siteTableUseDetailsList锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.group_buy_packages_ledger (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ siteName TEXT,
+ table_id BIGINT,
+ tableName TEXT,
+ tableAreaName TEXT,
+ tenant_table_area_id BIGINT,
+ order_trade_no TEXT,
+ order_settle_id BIGINT,
+ order_pay_id BIGINT,
+ order_coupon_id BIGINT,
+ order_coupon_channel INT,
+ coupon_code TEXT,
+ coupon_money NUMERIC(18,2),
+ coupon_origin_id BIGINT,
+ ledger_name TEXT,
+ ledger_group_name TEXT,
+ ledger_amount NUMERIC(18,2),
+ ledger_count NUMERIC(18,4),
+ ledger_unit_price NUMERIC(18,4),
+ ledger_status INT,
+ table_charge_seconds INT,
+ promotion_activity_id BIGINT,
+ promotion_coupon_id BIGINT,
+ promotion_seconds INT,
+ offer_type INT,
+ assistant_promotion_money NUMERIC(18,2),
+ assistant_service_promotion_money NUMERIC(18,2),
+ table_service_promotion_money NUMERIC(18,2),
+ goods_promotion_money NUMERIC(18,2),
+ recharge_promotion_money NUMERIC(18,2),
+ reward_promotion_money NUMERIC(18,2),
+ goodsOptionPrice NUMERIC(18,2),
+ salesman_name TEXT,
+ sales_man_org_id BIGINT,
+ salesman_role_id BIGINT,
+ salesman_user_id BIGINT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ is_single_order INT,
+ is_delete INT,
+ create_time TIMESTAMP,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+COMMENT ON TABLE billiards_ods.group_buy_packages_ledger IS '鏉ユ簮锛氬洟璐椁愭祦姘?json -> data.siteTableUseDetailsList锛涘洟璐埜浣跨敤/鏍搁攢娴佹按銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.id IS '鏉ユ簮:id锛涙祦姘翠富閿€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.tenant_id IS '鏉ユ簮:tenant_id锛涚鎴稩D銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.site_id IS '鏉ユ簮:site_id锛涢棬搴桰D銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.siteName IS '鏉ユ簮:siteName锛涢棬搴楀悕绉般€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.table_id IS '鏉ユ簮:table_id锛涘彴妗孖D銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.tableName IS '鏉ユ簮:tableName锛涘彴妗屽悕绉般€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.tableAreaName IS '鏉ユ簮:tableAreaName锛涘彴妗屽尯鍩熷悕绉般€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.tenant_table_area_id IS '鏉ユ簮:tenant_table_area_id锛涚鎴峰彴妗屽尯鍩烮D銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.order_trade_no IS '鏉ユ簮:order_trade_no锛涜鍗曞彿銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.order_settle_id IS '鏉ユ簮:order_settle_id锛涚粨绠楀崟ID銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.order_pay_id IS '鏉ユ簮:order_pay_id锛涙敮浠樿褰旾D銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.order_coupon_id IS '鏉ユ簮:order_coupon_id锛涜鍗曞埜ID銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.order_coupon_channel IS '鏉ユ簮:order_coupon_channel锛涘埜娓犻亾銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.coupon_code IS '鏉ユ簮:coupon_code锛涘埜鐮併€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.coupon_money IS '鏉ユ簮:coupon_money锛涘埜閲戦銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.coupon_origin_id IS '鏉ユ簮:coupon_origin_id锛涘埜鏉ユ簮ID銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.ledger_name IS '鏉ユ簮:ledger_name锛涜璐归」鍚嶇О銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.ledger_group_name IS '鏉ユ簮:ledger_group_name锛涜璐瑰垎缁勩€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.ledger_amount IS '鏉ユ簮:ledger_amount锛涢噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.ledger_count IS '鏉ユ簮:ledger_count锛涙暟閲?鏃堕暱銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.ledger_unit_price IS '鏉ユ簮:ledger_unit_price锛涘崟浠枫€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.ledger_status IS '鏉ユ簮:ledger_status锛涚姸鎬併€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.table_charge_seconds IS '鏉ユ簮:table_charge_seconds锛涘彴璐硅璐圭鏁般€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.promotion_activity_id IS '鏉ユ簮:promotion_activity_id锛涗績閿€娲诲姩ID銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.promotion_coupon_id IS '鏉ユ簮:promotion_coupon_id锛涗績閿€鍒窱D銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.promotion_seconds IS '鏉ユ簮:promotion_seconds锛涗績閿€璧犻€佹椂闀裤€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.offer_type IS '鏉ユ簮:offer_type锛涗紭鎯犵被鍨嬨€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.assistant_promotion_money IS '鏉ユ簮:assistant_promotion_money锛涘姪鏁欎紭鎯犻噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.assistant_service_promotion_money IS '鏉ユ簮:assistant_service_promotion_money锛涘姪鏁欐湇鍔′紭鎯犻噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.table_service_promotion_money IS '鏉ユ簮:table_service_promotion_money锛涘彴璐逛紭鎯犻噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.goods_promotion_money IS '鏉ユ簮:goods_promotion_money锛涘晢鍝佷紭鎯犻噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.recharge_promotion_money IS '鏉ユ簮:recharge_promotion_money锛涘厖鍊间紭鎯犻噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.reward_promotion_money IS '鏉ユ簮:reward_promotion_money锛涘鍔变紭鎯犻噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.goodsOptionPrice IS '鏉ユ簮:goodsOptionPrice锛涘晢鍝佽鏍间环銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.salesman_name IS '鏉ユ簮:salesman_name锛涢攢鍞鍚嶃€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.sales_man_org_id IS '鏉ユ簮:sales_man_org_id锛涢攢鍞粍缁嘔D銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.salesman_role_id IS '鏉ユ簮:salesman_role_id锛涢攢鍞鑹睮D銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.salesman_user_id IS '鏉ユ簮:salesman_user_id锛涢攢鍞敤鎴稩D銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.operator_id IS '鏉ユ簮:operator_id锛涙搷浣滀汉ID銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.operator_name IS '鏉ユ簮:operator_name锛涙搷浣滀汉鍚嶇О銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.is_single_order IS '鏉ユ簮:is_single_order锛涙槸鍚﹀崟鐐硅鍗曘€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.is_delete IS '鏉ユ簮:is_delete锛涢€昏緫鍒犻櫎鏍囪瘑銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.create_time IS '鏉ユ簮:create_time锛涘垱寤烘椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.payload IS '鍘熷JSON鏁存潯璁板綍銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰勩€?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣銆?;
+COMMENT ON COLUMN billiards_ods.group_buy_packages_ledger.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿銆?;
+
+-- ========== 灏忕エ璇︽儏锛堝皬绁ㄨ鎯?json -> data.data锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.settlement_ticket_details (
+ orderSettleId BIGINT PRIMARY KEY,
+ actualPayment NUMERIC(18,2),
+ adjustAmount NUMERIC(18,2),
+ assistantManualDiscount NUMERIC(18,2),
+ balanceAmount NUMERIC(18,2),
+ cashierName TEXT,
+ consumeMoney NUMERIC(18,2),
+ couponAmount NUMERIC(18,2),
+ deliveryAddress TEXT,
+ deliveryFee NUMERIC(18,2),
+ ledgerAmount NUMERIC(18,2),
+ memberDeductAmount NUMERIC(18,2),
+ memberOfferAmount NUMERIC(18,2),
+ onlineReturnAmount NUMERIC(18,2),
+ orderRemark TEXT,
+ orderSettleNumber BIGINT,
+ payMemberBalance NUMERIC(18,2),
+ payTime TIMESTAMP,
+ paymentMethod INT,
+ pointDiscountCost NUMERIC(18,2),
+ pointDiscountPrice NUMERIC(18,2),
+ prepayMoney NUMERIC(18,2),
+ refundAmount NUMERIC(18,2),
+ returnGoodsAmount NUMERIC(18,2),
+ rewardName TEXT,
+ settleType TEXT,
+ siteAddress TEXT,
+ siteBusinessTel TEXT,
+ siteId BIGINT,
+ siteName TEXT,
+ tenantId BIGINT,
+ tenantName TEXT,
+ ticketCustomContent TEXT,
+ ticketRemark TEXT,
+ voucherMoney NUMERIC(18,2),
+ memberProfile JSONB,
+ orderItem JSONB,
+ tenantMemberCardLogs JSONB,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+COMMENT ON TABLE billiards_ods.settlement_ticket_details IS '鏉ユ簮锛氬皬绁ㄨ鎯?json -> data.data锛涘皬绁?缁撶畻璇﹀崟锛屾槑缁嗕笌浼氬憳蹇収瀛楯SON銆?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.orderSettleId IS '鏉ユ簮:orderSettleId锛涚粨绠楀崟ID銆?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.actualPayment IS '鏉ユ簮:actualPayment锛涘疄鏀堕噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.adjustAmount IS '鏉ユ簮:adjustAmount锛涙姽闆?璋冩暣閲戦銆?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.assistantManualDiscount IS '鏉ユ簮:assistantManualDiscount锛涘姪鏁欎汉宸ヤ紭鎯犮€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.balanceAmount IS '鏉ユ簮:balanceAmount锛涗綑棰濇敮浠橀噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.cashierName IS '鏉ユ簮:cashierName锛涙敹閾跺憳銆?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.consumeMoney IS '鏉ユ簮:consumeMoney锛涙秷璐归噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.couponAmount IS '鏉ユ簮:couponAmount锛涘埜鎶垫墸閲戦銆?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.deliveryAddress IS '鏉ユ簮:deliveryAddress锛涢厤閫佸湴鍧€銆?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.deliveryFee IS '鏉ユ簮:deliveryFee锛涢厤閫佽垂銆?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.ledgerAmount IS '鏉ユ簮:ledgerAmount锛涜处鍗曢噾棰濇眹鎬汇€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.memberDeductAmount IS '鏉ユ簮:memberDeductAmount锛涗細鍛樻姷鎵i噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.memberOfferAmount IS '鏉ユ簮:memberOfferAmount锛涗細鍛樹紭鎯犻噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.onlineReturnAmount IS '鏉ユ簮:onlineReturnAmount锛涚嚎涓婇€€杩橀噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.orderRemark IS '鏉ユ簮:orderRemark锛涜鍗曞娉ㄣ€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.orderSettleNumber IS '鏉ユ簮:orderSettleNumber锛涚粨绠楀崟鍙枫€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.payMemberBalance IS '鏉ユ簮:payMemberBalance锛涗細鍛樹綑棰濇敮浠橀噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.payTime IS '鏉ユ簮:payTime锛涙敮浠樻椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.paymentMethod IS '鏉ユ簮:paymentMethod锛涙敮浠樻柟寮忋€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.pointDiscountCost IS '鏉ユ簮:pointDiscountCost锛涚Н鍒嗘姷鎵f垚鏈€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.pointDiscountPrice IS '鏉ユ簮:pointDiscountPrice锛涚Н鍒嗘姷鎵i噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.prepayMoney IS '鏉ユ簮:prepayMoney锛涢浠橀噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.refundAmount IS '鏉ユ簮:refundAmount锛涢€€娆鹃噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.returnGoodsAmount IS '鏉ユ簮:returnGoodsAmount锛涢€€璐ч噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.rewardName IS '鏉ユ簮:rewardName锛涘鍔辫鏄庛€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.settleType IS '鏉ユ簮:settleType锛涚粨绠楃被鍨嬨€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.siteAddress IS '鏉ユ簮:siteAddress锛涢棬搴楀湴鍧€銆?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.siteBusinessTel IS '鏉ユ簮:siteBusinessTel锛涢棬搴楃數璇濄€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.siteId IS '鏉ユ簮:siteId锛涢棬搴桰D銆?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.siteName IS '鏉ユ簮:siteName锛涢棬搴楀悕绉般€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.tenantId IS '鏉ユ簮:tenantId锛涚鎴稩D銆?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.tenantName IS '鏉ユ簮:tenantName锛涚鎴峰悕绉般€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.ticketCustomContent IS '鏉ユ簮:ticketCustomContent锛涜嚜瀹氫箟绁ㄩ潰鍐呭銆?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.ticketRemark IS '鏉ユ簮:ticketRemark锛涘皬绁ㄥ娉ㄣ€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.voucherMoney IS '鏉ユ簮:voucherMoney锛涗唬閲戝埜閲戦銆?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.memberProfile IS '鏉ユ簮:memberProfile锛涗細鍛樺揩鐓SON銆?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.orderItem IS '鏉ユ簮:orderItem锛涘晢鍝?鍙版/鍒稿垎椤规槑缁咼SON銆?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.tenantMemberCardLogs IS '鏉ユ簮:tenantMemberCardLogs锛涘叧鑱斾綑棰濆彉鏇存祦姘碕SON銆?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.payload IS '鍘熷JSON鏁存潯璁板綍銆?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰勩€?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣銆?;
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿銆?;
+
+-- ========== 闂ㄥ簵鍟嗗搧妗f锛堥棬搴楀晢鍝佹。妗?.json -> data.orderGoodsList锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.store_goods_master (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ siteName TEXT,
+ tenant_goods_id BIGINT,
+ goods_name TEXT,
+ goods_bar_code TEXT,
+ goods_category_id BIGINT,
+ goods_second_category_id BIGINT,
+ oneCategoryName TEXT,
+ twoCategoryName TEXT,
+ unit TEXT,
+ sale_price NUMERIC(18,4),
+ cost_price NUMERIC(18,4),
+ cost_price_type INT,
+ min_discount_price NUMERIC(18,4),
+ safe_stock NUMERIC(18,4),
+ stock NUMERIC(18,4),
+ stock_A NUMERIC(18,4),
+ sale_num NUMERIC(18,4),
+ total_purchase_cost NUMERIC(18,4),
+ total_sales NUMERIC(18,4),
+ average_monthly_sales NUMERIC(18,4),
+ enable_status INT,
+ audit_status INT,
+ goods_state INT,
+ is_delete INT,
+ is_warehousing INT,
+ able_discount INT,
+ able_site_transfer INT,
+ forbid_sell_status INT,
+ "freeze" INT,
+ send_state INT,
+ custom_label_type INT,
+ option_required INT,
+ sale_channel INT,
+ remark TEXT,
+ pinyin_initial TEXT,
+ goods_cover TEXT,
+ create_time TIMESTAMP,
+ update_time TIMESTAMP,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+COMMENT ON TABLE billiards_ods.store_goods_master IS '鏉ユ簮锛氶棬搴楀晢鍝佹。妗?.json -> data.orderGoodsList锛涢棬搴楀眰鍟嗗搧妗f锛屽叧閿簱瀛?浠锋牸瀛楁灞曞紑銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.id IS '鏉ユ簮:id锛涢棬搴楀晢鍝佽褰旾D銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.tenant_id IS '鏉ユ簮:tenant_id锛涚鎴稩D銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.site_id IS '鏉ユ簮:site_id锛涢棬搴桰D銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.siteName IS '鏉ユ簮:siteName锛涢棬搴楀悕绉般€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.tenant_goods_id IS '鏉ユ簮:tenant_goods_id锛涚鎴峰晢鍝両D銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_name IS '鏉ユ簮:goods_name锛涘晢鍝佸悕绉般€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_bar_code IS '鏉ユ簮:goods_bar_code锛涙潯鐮併€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_category_id IS '鏉ユ簮:goods_category_id锛涗竴绾у垎绫籌D銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_second_category_id IS '鏉ユ簮:goods_second_category_id锛涗簩绾у垎绫籌D銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.oneCategoryName IS '鏉ユ簮:oneCategoryName锛涗竴绾у垎绫诲悕绉般€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.twoCategoryName IS '鏉ユ簮:twoCategoryName锛涗簩绾у垎绫诲悕绉般€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.unit IS '鏉ユ簮:unit锛涜閲忓崟浣嶃€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.sale_price IS '鏉ユ簮:sale_price锛涢攢鍞环銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.cost_price IS '鏉ユ簮:cost_price锛涙垚鏈环銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.cost_price_type IS '鏉ユ簮:cost_price_type锛涙垚鏈环绫诲瀷銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.min_discount_price IS '鏉ユ簮:min_discount_price锛涙渶浣庢姌鎵d环銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.safe_stock IS '鏉ユ簮:safe_stock锛涘畨鍏ㄥ簱瀛樸€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.stock IS '鏉ユ簮:stock锛涘綋鍓嶅簱瀛樸€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.stock_A IS '鏉ユ簮:stock_A锛涜緟鍗曚綅搴撳瓨銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.sale_num IS '鏉ユ簮:sale_num锛涚疮璁¢攢閲忋€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.total_purchase_cost IS '鏉ユ簮:total_purchase_cost锛涚疮璁¢噰璐垚鏈€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.total_sales IS '鏉ユ簮:total_sales锛涚疮璁¢攢鍞銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.average_monthly_sales IS '鏉ユ簮:average_monthly_sales锛涙湀鍧囬攢閲忋€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.enable_status IS '鏉ユ簮:enable_status锛涘惎鐢ㄧ姸鎬併€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.audit_status IS '鏉ユ簮:audit_status锛涘鏍哥姸鎬併€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_state IS '鏉ユ簮:goods_state锛涘晢鍝佺姸鎬併€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.is_delete IS '鏉ユ簮:is_delete锛涢€昏緫鍒犻櫎銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.is_warehousing IS '鏉ユ簮:is_warehousing锛涙槸鍚︾撼鍏ュ簱瀛樸€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.able_discount IS '鏉ユ簮:able_discount锛涘彲鍚︽姌鎵c€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.able_site_transfer IS '鏉ユ簮:able_site_transfer锛涘彲鍚﹁法搴楄皟鎷ㄣ€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.forbid_sell_status IS '鏉ユ簮:forbid_sell_status锛涚鍞姸鎬併€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master."freeze" IS '鏉ユ簮:freeze锛涘喕缁撴爣璁般€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.send_state IS '鏉ユ簮:send_state锛涢厤閫佺姸鎬併€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.custom_label_type IS '鏉ユ簮:custom_label_type锛涜嚜瀹氫箟鏍囩绫诲瀷銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.option_required IS '鏉ユ簮:option_required锛涜鏍煎繀閫夋爣璇嗐€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.sale_channel IS '鏉ユ簮:sale_channel锛涢攢鍞笭閬撱€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.remark IS '鏉ユ簮:remark锛涘娉ㄣ€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.pinyin_initial IS '鏉ユ簮:pinyin_initial锛涙嫾闊抽瀛楁瘝銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_cover IS '鏉ユ簮:goods_cover锛涘晢鍝佸浘鐗囥€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.create_time IS '鏉ユ簮:create_time锛涘垱寤烘椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.update_time IS '鏉ユ簮:update_time锛涙洿鏂版椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.payload IS '鍘熷JSON鏁存潯璁板綍銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰勩€?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_master.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿銆?;
+
+-- ========== 闂ㄥ簵鍟嗗搧閿€鍞褰曪紙闂ㄥ簵鍟嗗搧閿€鍞褰?json -> data.orderGoodsLedgers锛?==========
+CREATE TABLE IF NOT EXISTS billiards_ods.store_goods_sales_records (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ site_goods_id BIGINT,
+ tenant_goods_id BIGINT,
+ order_settle_id BIGINT,
+ order_trade_no TEXT,
+ order_goods_id BIGINT,
+ order_pay_id BIGINT,
+ order_coupon_id BIGINT,
+ ledger_name TEXT,
+ ledger_group_name TEXT,
+ ledger_amount NUMERIC(18,2),
+ ledger_count NUMERIC(18,4),
+ ledger_unit_price NUMERIC(18,4),
+ ledger_status INT,
+ discount_money NUMERIC(18,2),
+ coupon_deduct_money NUMERIC(18,2),
+ member_discount_amount NUMERIC(18,2),
+ option_coupon_deduct_money NUMERIC(18,2),
+ option_member_discount_money NUMERIC(18,2),
+ point_discount_money NUMERIC(18,2),
+ point_discount_money_cost NUMERIC(18,2),
+ real_goods_money NUMERIC(18,2),
+ cost_money NUMERIC(18,2),
+ push_money NUMERIC(18,2),
+ sales_type INT,
+ is_single_order INT,
+ is_delete INT,
+ goods_remark TEXT,
+ option_price NUMERIC(18,2),
+ option_value_name TEXT,
+ option_name TEXT,
+ member_coupon_id BIGINT,
+ package_coupon_id BIGINT,
+ sales_man_org_id BIGINT,
+ salesman_name TEXT,
+ salesman_role_id BIGINT,
+ salesman_user_id BIGINT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ openSalesman TEXT,
+ site_table_id BIGINT,
+ tenant_goods_business_id BIGINT,
+ tenant_goods_category_id BIGINT,
+ create_time TIMESTAMP,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+COMMENT ON TABLE billiards_ods.store_goods_sales_records IS '鏉ユ簮锛氶棬搴楀晢鍝侀攢鍞褰?json -> data.orderGoodsLedgers锛涘晢鍝侀攢鍞槑缁嗐€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.id IS '鏉ユ簮:id锛涢攢鍞槑缁咺D銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.tenant_id IS '鏉ユ簮:tenant_id锛涚鎴稩D銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.site_id IS '鏉ユ簮:site_id锛涢棬搴桰D銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.site_goods_id IS '鏉ユ簮:site_goods_id锛涢棬搴楀晢鍝両D銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.tenant_goods_id IS '鏉ユ簮:tenant_goods_id锛涚鎴峰晢鍝両D銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.order_settle_id IS '鏉ユ簮:order_settle_id锛涚粨绠楀崟ID銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.order_trade_no IS '鏉ユ簮:order_trade_no锛涜鍗曞彿銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.order_goods_id IS '鏉ユ簮:order_goods_id锛涜鍗曞晢鍝両D銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.order_pay_id IS '鏉ユ簮:order_pay_id锛涙敮浠樿褰旾D銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.order_coupon_id IS '鏉ユ簮:order_coupon_id锛涜鍗曞埜ID銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_name IS '鏉ユ簮:ledger_name锛涜璐归」鍚嶇О銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_group_name IS '鏉ユ簮:ledger_group_name锛涜璐瑰垎缁勩€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_amount IS '鏉ユ簮:ledger_amount锛涢噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_count IS '鏉ユ簮:ledger_count锛涙暟閲忋€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_unit_price IS '鏉ユ簮:ledger_unit_price锛涘崟浠枫€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_status IS '鏉ユ簮:ledger_status锛涚姸鎬併€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.discount_money IS '鏉ユ簮:discount_money锛涙姌鎵i噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.coupon_deduct_money IS '鏉ユ簮:coupon_deduct_money锛涘埜鎶垫墸閲戦銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.member_discount_amount IS '鏉ユ簮:member_discount_amount锛涗細鍛樹紭鎯犻噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.option_coupon_deduct_money IS '鏉ユ簮:option_coupon_deduct_money锛涜鏍煎眰绾у埜鎶垫墸銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.option_member_discount_money IS '鏉ユ簮:option_member_discount_money锛涜鏍煎眰绾т細鍛樹紭鎯犮€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.point_discount_money IS '鏉ユ簮:point_discount_money锛涚Н鍒嗘姷鎵i噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.point_discount_money_cost IS '鏉ユ簮:point_discount_money_cost锛涚Н鍒嗘姷鎵f垚鏈€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.real_goods_money IS '鏉ユ簮:real_goods_money锛涘疄浠樺晢鍝侀噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.cost_money IS '鏉ユ簮:cost_money锛涙垚鏈噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.push_money IS '鏉ユ簮:push_money锛涙彁鎴愰噾棰濄€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.sales_type IS '鏉ユ簮:sales_type锛涢攢鍞被鍨嬨€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.is_single_order IS '鏉ユ簮:is_single_order锛涙槸鍚﹀崟鐐硅鍗曘€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.is_delete IS '鏉ユ簮:is_delete锛涢€昏緫鍒犻櫎銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.goods_remark IS '鏉ユ簮:goods_remark锛涘晢鍝佸娉ㄣ€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.option_price IS '鏉ユ簮:option_price锛涜鏍煎姞浠枫€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.option_value_name IS '鏉ユ簮:option_value_name锛涜鏍煎€煎悕绉般€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.option_name IS '鏉ユ簮:option_name锛涜鏍煎悕绉般€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.member_coupon_id IS '鏉ユ簮:member_coupon_id锛涗細鍛樺埜ID銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.package_coupon_id IS '鏉ユ簮:package_coupon_id锛涘椁愬埜ID銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.sales_man_org_id IS '鏉ユ簮:sales_man_org_id锛涢攢鍞粍缁嘔D銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.salesman_name IS '鏉ユ簮:salesman_name锛涢攢鍞鍚嶃€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.salesman_role_id IS '鏉ユ簮:salesman_role_id锛涢攢鍞鑹睮D銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.salesman_user_id IS '鏉ユ簮:salesman_user_id锛涢攢鍞敤鎴稩D銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.operator_id IS '鏉ユ簮:operator_id锛涙搷浣滀汉ID銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.operator_name IS '鏉ユ簮:operator_name锛涙搷浣滀汉鍚嶇О銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.openSalesman IS '鏉ユ簮:openSalesman锛涘紑鍗曞憳鍚嶇О銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.site_table_id IS '鏉ユ簮:site_table_id锛涘彴妗孖D銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.tenant_goods_business_id IS '鏉ユ簮:tenant_goods_business_id锛涗笟鍔$嚎ID銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.tenant_goods_category_id IS '鏉ユ簮:tenant_goods_category_id锛涚鎴峰垎绫籌D銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.create_time IS '鏉ユ簮:create_time锛涘垱寤烘椂闂淬€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.payload IS '鍘熷JSON鏁存潯璁板綍銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.source_file IS '閲囬泦鍏冩暟鎹細婧愭枃浠惰矾寰勩€?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.source_endpoint IS '閲囬泦鍏冩暟鎹細鏉ユ簮鎺ュ彛/绔偣銆?;
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.fetched_at IS '閲囬泦鍏冩暟鎹細鍏ユ箹鏃堕棿銆?;
+
diff --git a/etl_billiards/backups/schema_ODS_doc.sql.bak_20251209 b/etl_billiards/backups/schema_ODS_doc.sql.bak_20251209
new file mode 100644
index 0000000..d8a0408
--- /dev/null
+++ b/etl_billiards/backups/schema_ODS_doc.sql.bak_20251209
@@ -0,0 +1,1886 @@
+-- 文件:schema_ODS_doc.sql
+-- 说明:ODS 层 DDL,表名与示例 JSON 前缀对应,用于本地回放/调试。
+-- 编码:UTF-8
+SET client_encoding TO "UTF8";
+
+DROP SCHEMA IF EXISTS billiards_ods CASCADE;
+CREATE SCHEMA IF NOT EXISTS billiards_ods;
+
+CREATE TABLE IF NOT EXISTS billiards_ods.member_profiles (
+ tenant_id BIGINT,
+ register_site_id BIGINT,
+ site_name TEXT,
+ id BIGINT PRIMARY KEY,
+ system_member_id BIGINT,
+ member_card_grade_code BIGINT,
+ member_card_grade_name TEXT,
+ mobile TEXT,
+ nickname TEXT,
+ point NUMERIC(18,2),
+ growth_value NUMERIC(18,2),
+ referrer_member_id BIGINT,
+ status INT,
+ user_status INT,
+ create_time TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.member_profiles IS '对应JSON字段:member_profiles.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 member_profiles-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_profiles.tenant_id IS '对应JSON字段:tenant_id,说明::,示例值及对应分析:租户/品牌 ID。';
+COMMENT ON COLUMN billiards_ods.member_profiles.register_site_id IS '对应JSON字段:register_site_id,说明::,示例值及对应分析:会员的注册门店 ID。';
+COMMENT ON COLUMN billiards_ods.member_profiles.site_name IS '对应JSON字段:site_name,说明::,示例值及对应分析:注册门店名称,属于冗余字段,用于直接展示。';
+COMMENT ON COLUMN billiards_ods.member_profiles.id IS '对应JSON字段:id,说明::,示例值及对应分析:这是“租户内会员账户”的主键 ID。';
+COMMENT ON COLUMN billiards_ods.member_profiles.system_member_id IS '对应JSON字段:system_member_id,说明:(结合其它文件):,示例值及对应分析:这是“系统级会员 ID”,在全平台唯一,用来把一个会员在不同门店/不同卡类型下的账户统一到一个“人”的维度上。';
+COMMENT ON COLUMN billiards_ods.member_profiles.member_card_grade_code IS '对应JSON字段:member_card_grade_code,说明:类型:int,示例值及对应分析:唯一值个数:4';
+COMMENT ON COLUMN billiards_ods.member_profiles.member_card_grade_name IS '对应JSON字段:member_card_grade_name,说明::,示例值及对应分析:这是“会员卡种类/等级”的定义字段。';
+COMMENT ON COLUMN billiards_ods.member_profiles.mobile IS '对应JSON字段:mobile,说明::,示例值及对应分析:会员绑定的手机号码。';
+COMMENT ON COLUMN billiards_ods.member_profiles.nickname IS '对应JSON字段:nickname,说明::,示例值及对应分析:会员在当前租户下的显示名称(可以是姓名,也可以是昵称)。';
+COMMENT ON COLUMN billiards_ods.member_profiles.point IS '对应JSON字段:point,说明::,示例值及对应分析:当前积分余额(这条会员账户的积分值)。';
+COMMENT ON COLUMN billiards_ods.member_profiles.growth_value IS '对应JSON字段:growth_value,说明:(按常见会员体系设计):,示例值及对应分析:成长值 / 经验值,用于会员等级晋升的累计指标。';
+COMMENT ON COLUMN billiards_ods.member_profiles.referrer_member_id IS '对应JSON字段:referrer_member_id,说明:(按命名推断):,示例值及对应分析:推荐人会员 ID,用于记录该会员是由哪位老会员推荐。';
+COMMENT ON COLUMN billiards_ods.member_profiles.status IS '对应JSON字段:status,说明:(按命名推断):,示例值及对应分析:帐户状态(偏“卡状态/档案状态”)。';
+COMMENT ON COLUMN billiards_ods.member_profiles.user_status IS '对应JSON字段:user_status,说明:(结合行业惯例):,示例值及对应分析:用户账号状态(偏“用户逻辑”层面的状态)。';
+COMMENT ON COLUMN billiards_ods.member_profiles.create_time IS '对应JSON字段:create_time,说明::,示例值及对应分析:会员账户的创建时间(即这条档案/这张卡在系统中被创建的时间)。';
+COMMENT ON COLUMN billiards_ods.member_profiles.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_profiles.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_profiles.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_profiles.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.member_balance_changes (
+ tenant_id BIGINT,
+ site_id BIGINT,
+ register_site_id BIGINT,
+ registerSiteName TEXT,
+ paySiteName TEXT,
+ id BIGINT PRIMARY KEY,
+ tenant_member_id BIGINT,
+ tenant_member_card_id BIGINT,
+ system_member_id BIGINT,
+ memberName TEXT,
+ memberMobile TEXT,
+ card_type_id BIGINT,
+ memberCardTypeName TEXT,
+ account_data NUMERIC(18,2),
+ before NUMERIC(18,2),
+ after NUMERIC(18,2),
+ refund_amount NUMERIC(18,2),
+ from_type INT,
+ payment_method INT,
+ relate_id BIGINT,
+ remark TEXT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ is_delete INT,
+ create_time TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.member_balance_changes IS '对应JSON字段:member_balance_changes.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.tenant_id IS '对应JSON字段:tenant_id,说明::租户/商户 ID,本数据中是固定值(同一品牌/商户)。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.site_id IS '对应JSON字段:site_id,说明:表示本次余额变动的发生门店,绝大多数也在“朗朗桌球”,少数特殊业务(活动抵用券结算)显示为 site_id=0、paySiteName 为空。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.register_site_id IS '对应JSON字段:register_site_id,说明:已在前文说明:办卡门店的 ID 与名称,所有记录一致,说明所有卡均在“朗朗桌球”注册。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.registerSiteName IS '对应JSON字段:registerSiteName,说明:已在前文说明:办卡门店的 ID 与名称,所有记录一致,说明所有卡均在“朗朗桌球”注册。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.paySiteName IS '对应JSON字段:paySiteName,说明:表示本次余额变动的发生门店,绝大多数也在“朗朗桌球”,少数特殊业务(活动抵用券结算)显示为 site_id=0、paySiteName 为空。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.id IS '对应JSON字段:id,说明::余额变更记录的主键 ID,唯一标识这一条“账户余额变化事件”。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.tenant_member_id IS '对应JSON字段:tenant_member_id,说明::商户维度的会员 ID(租户内会员主键)。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.tenant_member_card_id IS '对应JSON字段:tenant_member_card_id,说明::会员卡账户 ID,在租户内唯一标识某张卡。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.system_member_id IS '对应JSON字段:system_member_id,说明::系统级(全局)会员 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.memberName IS '对应JSON字段:memberName,说明::会员姓名或称呼(非昵称字段)。,示例值及对应分析:说明:例如“陈腾鑫”“胡先生”“江先生”等,多为中文姓名或带“先生”称呼。';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.memberMobile IS '对应JSON字段:memberMobile,说明::会员手机号。,示例值及对应分析:说明:字符型存储,完整手机号,用来识别会员与联系客户。';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.card_type_id IS '对应JSON字段:card_type_id,说明::卡种类型 ID,用于区分不同卡种。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.memberCardTypeName IS '对应JSON字段:memberCardTypeName,说明::卡种名称,与 card_type_id 一一对应,是一个 卡种枚举名称。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.account_data IS '对应JSON字段:account_data,说明::本次变动的金额(元),正数表示增加,负数表示减少。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.before IS '对应JSON字段:before,说明::本次变动前,该卡账户的余额(元)。,示例值及对应分析:说明:';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.after IS '对应JSON字段:after,说明::本次变动后,该卡账户的余额(元)。,示例值及对应分析:重要关系:';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.refund_amount IS '对应JSON字段:refund_amount,说明:(推测):与退款业务相关的金额字段,但在当前这份导出中实际未使用:,示例值及对应分析:可能用于标记“其中有多少金额是以‘退款’形式回流的”,或区分“退回余额”和“原路退回”两种模式。';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.from_type IS '对应JSON字段:from_type,说明:(根据金额符号与 remark 综合推断):,示例值及对应分析:1:日常消费扣款';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.payment_method IS '对应JSON字段:payment_method,说明:类型:int,枚举,示例值及对应分析:值分布:';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.relate_id IS '对应JSON字段:relate_id,说明:(推测):关联业务记录的 ID:,示例值及对应分析:例如某次充值记录的 ID、某张订单/结算单 ID、某次活动抵用券核销记录 ID 等。';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.remark IS '对应JSON字段:remark,说明::,示例值及对应分析:当为空时,说明这条变动没有额外备注说明。';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.operator_id IS '对应JSON字段:operator_id,说明::执行此次余额变更操作的员工 ID。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.operator_name IS '对应JSON字段:operator_name,说明::操作员姓名(带职位前缀),是对 operator_id 的可读冗余字段。,示例值及对应分析:9. 状态字段与标志';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标记:,示例值及对应分析:0:正常;';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.create_time IS '对应JSON字段:create_time,说明::本条余额变更记录的创建时间,通常接近交易发生时间。,示例值及对应分析:说明:可与订单、支付记录的时间做对齐,构造时序链路(但你现在不要求做时序分析,这里只说明结构)。';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.member_stored_value_cards (
+ tenant_id BIGINT,
+ tenant_member_id BIGINT,
+ system_member_id BIGINT,
+ register_site_id BIGINT,
+ site_name TEXT,
+ id BIGINT PRIMARY KEY,
+ member_card_grade_code BIGINT,
+ member_card_grade_code_name TEXT,
+ member_card_type_name TEXT,
+ member_name TEXT,
+ member_mobile TEXT,
+ card_type_id BIGINT,
+ card_no TEXT,
+ card_physics_type TEXT,
+ balance NUMERIC(18,2),
+ denomination NUMERIC(18,2),
+ table_discount NUMERIC(10,4),
+ goods_discount NUMERIC(10,4),
+ assistant_discount NUMERIC(10,4),
+ assistant_reward_discount NUMERIC(10,4),
+ table_service_discount NUMERIC(10,4),
+ assistant_service_discount NUMERIC(10,4),
+ coupon_discount NUMERIC(10,4),
+ goods_service_discount NUMERIC(10,4),
+ assistant_discount_sub_switch INT,
+ table_discount_sub_switch INT,
+ goods_discount_sub_switch INT,
+ assistant_reward_discount_sub_switch INT,
+ table_service_deduct_radio NUMERIC(10,4),
+ assistant_service_deduct_radio NUMERIC(10,4),
+ goods_service_deduct_radio NUMERIC(10,4),
+ assistant_deduct_radio NUMERIC(10,4),
+ table_deduct_radio NUMERIC(10,4),
+ goods_deduct_radio NUMERIC(10,4),
+ coupon_deduct_radio NUMERIC(10,4),
+ assistant_reward_deduct_radio NUMERIC(10,4),
+ tableCardDeduct NUMERIC(18,2),
+ tableServiceCardDeduct NUMERIC(18,2),
+ goodsCarDeduct NUMERIC(18,2),
+ goodsServiceCardDeduct NUMERIC(18,2),
+ assistantCardDeduct NUMERIC(18,2),
+ assistantServiceCardDeduct NUMERIC(18,2),
+ assistantRewardCardDeduct NUMERIC(18,2),
+ cardSettleDeduct NUMERIC(18,2),
+ couponCardDeduct NUMERIC(18,2),
+ deliveryFeeDeduct NUMERIC(18,2),
+ use_scene INT,
+ able_cross_site INT,
+ able_site_transfer INT,
+ is_allow_give INT,
+ is_allow_order_deduct INT,
+ is_delete INT,
+ bind_password TEXT,
+ goods_discount_range_type INT,
+ goodsCategoryId BIGINT,
+ tableAreaId BIGINT,
+ effect_site_id BIGINT,
+ start_time TIMESTAMP,
+ end_time TIMESTAMP,
+ disable_start_time TIMESTAMP,
+ disable_end_time TIMESTAMP,
+ last_consume_time TIMESTAMP,
+ create_time TIMESTAMP,
+ status INT,
+ sort INT,
+ tenantAvatar TEXT,
+ tenantName TEXT,
+ pdAssisnatLevel TEXT,
+ cxAssisnatLevel TEXT,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.member_stored_value_cards IS '对应JSON字段:member_stored_value_cards.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID,与其他 JSON 中 tenant_id 一致。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tenant_member_id IS '对应JSON字段:tenant_member_id,说明::当前商户(品牌/租户)中会员的主键 ID。,示例值及对应分析:枚举特征:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.system_member_id IS '对应JSON字段:system_member_id,说明::系统级会员 ID(跨门店统一主键)。,示例值及对应分析:枚举特征:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.register_site_id IS '对应JSON字段:register_site_id,说明::卡首次办理的门店 ID。,示例值及对应分析:对应门店的 site_id;本数据中所有卡都是在同一家门店开卡。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.site_name IS '对应JSON字段:site_name,说明::卡归属门店名称(视图中的展示字段)。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.id IS '对应JSON字段:id,说明:?????? member_stored_value_cards-Analysis.md,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.member_card_grade_code IS '对应JSON字段:member_card_grade_code,说明::卡等级/卡类代码,和下面两个名称字段一一对应。,示例值及对应分析:枚举:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.member_card_grade_code_name IS '对应JSON字段:member_card_grade_code_name,说明::卡等级/卡类名称。,示例值及对应分析:枚举值(与上面 code 一一对应):';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.member_card_type_name IS '对应JSON字段:member_card_type_name,说明::卡类型名称,实际与 member_card_grade_code_name 一致。,示例值及对应分析:枚举值同上。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.member_name IS '对应JSON字段:member_name,说明::持卡会员姓名快照。,示例值及对应分析:特点:存在 null(20 张卡没有绑定会员名字)。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.member_mobile IS '对应JSON字段:member_mobile,说明::持卡会员手机号快照。,示例值及对应分析:特点:与 member_name 对应,多数有值,少量为 null。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.card_type_id IS '对应JSON字段:card_type_id,说明::卡种 ID(定义“这是哪一种卡”)。,示例值及对应分析:枚举(按数据分布):';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.card_no IS '对应JSON字段:card_no,说明:(推测):实体卡物理卡号/条码号。当前这批卡看起来全部为“无物理卡号”(可能是全部虚拟卡或卡号隐藏不导出)。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.card_physics_type IS '对应JSON字段:card_physics_type,说明::物理卡类型。,示例值及对应分析:当前数据:全部为 1。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.balance IS '对应JSON字段:balance,说明::当前卡内余额(主要针对储值卡、部分券卡)。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.denomination IS '对应JSON字段:denomination,说明:(推测):面额/初始储值额度。,示例值及对应分析:本页数据未填充此字段;可能在分类型卡(如次卡/券)中才有意义,或者另有配置表。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.table_discount IS '对应JSON字段:table_discount,说明::,示例值及对应分析:采用“几折”的记法:10=不打折,9=九折,8=八折。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_discount IS '对应JSON字段:goods_discount,说明::,示例值及对应分析:采用“几折”的记法:10=不打折,9=九折,8=八折。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_discount IS '对应JSON字段:assistant_discount,说明::,示例值及对应分析:采用“几折”的记法:10=不打折,9=九折,8=八折。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_reward_discount IS '对应JSON字段:assistant_reward_discount,说明::,示例值及对应分析:采用“几折”的记法:10=不打折,9=九折,8=八折。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.table_service_discount IS '对应JSON字段:table_service_discount,说明::,示例值及对应分析:采用“几折”的记法:10=不打折,9=九折,8=八折。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_service_discount IS '对应JSON字段:assistant_service_discount,说明::,示例值及对应分析:采用“几折”的记法:10=不打折,9=九折,8=八折。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.coupon_discount IS '对应JSON字段:coupon_discount,说明:?????? member_stored_value_cards-Analysis.md,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_service_discount IS '对应JSON字段:goods_service_discount,说明::,示例值及对应分析:采用“几折”的记法:10=不打折,9=九折,8=八折。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_discount_sub_switch IS '对应JSON字段:assistant_discount_sub_switch,说明:(推测):“折扣是否叠加/替换其他折扣”的开关。,示例值及对应分析:可能枚举:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.table_discount_sub_switch IS '对应JSON字段:table_discount_sub_switch,说明:(推测):“折扣是否叠加/替换其他折扣”的开关。,示例值及对应分析:可能枚举:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_discount_sub_switch IS '对应JSON字段:goods_discount_sub_switch,说明:(推测):“折扣是否叠加/替换其他折扣”的开关。,示例值及对应分析:可能枚举:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_reward_discount_sub_switch IS '对应JSON字段:assistant_reward_discount_sub_switch,说明:(推测):“折扣是否叠加/替换其他折扣”的开关。,示例值及对应分析:可能枚举:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.table_service_deduct_radio IS '对应JSON字段:table_service_deduct_radio,说明::允许从该卡余额中抵扣的比例(百分比)。,示例值及对应分析:100.0 表示允许 100% 用卡余额支付该类消费;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_service_deduct_radio IS '对应JSON字段:assistant_service_deduct_radio,说明::允许从该卡余额中抵扣的比例(百分比)。,示例值及对应分析:100.0 表示允许 100% 用卡余额支付该类消费;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_service_deduct_radio IS '对应JSON字段:goods_service_deduct_radio,说明::允许从该卡余额中抵扣的比例(百分比)。,示例值及对应分析:100.0 表示允许 100% 用卡余额支付该类消费;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_deduct_radio IS '对应JSON字段:assistant_deduct_radio,说明::允许从该卡余额中抵扣的比例(百分比)。,示例值及对应分析:100.0 表示允许 100% 用卡余额支付该类消费;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.table_deduct_radio IS '对应JSON字段:table_deduct_radio,说明::允许从该卡余额中抵扣的比例(百分比)。,示例值及对应分析:100.0 表示允许 100% 用卡余额支付该类消费;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_deduct_radio IS '对应JSON字段:goods_deduct_radio,说明::允许从该卡余额中抵扣的比例(百分比)。,示例值及对应分析:100.0 表示允许 100% 用卡余额支付该类消费;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.coupon_deduct_radio IS '对应JSON字段:coupon_deduct_radio,说明::允许从该卡余额中抵扣的比例(百分比)。,示例值及对应分析:100.0 表示允许 100% 用卡余额支付该类消费;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_reward_deduct_radio IS '对应JSON字段:assistant_reward_deduct_radio,说明:?????? member_stored_value_cards-Analysis.md,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tableCardDeduct IS '对应JSON字段:tableCardDeduct,说明::针对台费/商品/助教三类消费的扣卡金额配置(类似“每小时从卡里扣 xx 元”或“每次抵扣 xx 元”的规则)。,示例值及对应分析:当前:所有为 0,说明在卡定义层面并没有指定固定扣卡金额,而是按照一般储值逻辑消费。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tableServiceCardDeduct IS '对应JSON字段:tableServiceCardDeduct,说明::如果系统中区分“储值金、服务金、奖励金”等子账户,这三个字段对应“服务金”子账户的扣款配置。,示例值及对应分析:当前未启用。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goodsCarDeduct IS '对应JSON字段:goodsCarDeduct,说明::针对台费/商品/助教三类消费的扣卡金额配置(类似“每小时从卡里扣 xx 元”或“每次抵扣 xx 元”的规则)。,示例值及对应分析:当前:所有为 0,说明在卡定义层面并没有指定固定扣卡金额,而是按照一般储值逻辑消费。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goodsServiceCardDeduct IS '对应JSON字段:goodsServiceCardDeduct,说明::如果系统中区分“储值金、服务金、奖励金”等子账户,这三个字段对应“服务金”子账户的扣款配置。,示例值及对应分析:当前未启用。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistantCardDeduct IS '对应JSON字段:assistantCardDeduct,说明::针对台费/商品/助教三类消费的扣卡金额配置(类似“每小时从卡里扣 xx 元”或“每次抵扣 xx 元”的规则)。,示例值及对应分析:当前:所有为 0,说明在卡定义层面并没有指定固定扣卡金额,而是按照一般储值逻辑消费。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistantServiceCardDeduct IS '对应JSON字段:assistantServiceCardDeduct,说明::如果系统中区分“储值金、服务金、奖励金”等子账户,这三个字段对应“服务金”子账户的扣款配置。,示例值及对应分析:当前未启用。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistantRewardCardDeduct IS '对应JSON字段:assistantRewardCardDeduct,说明::助教奖励金方向扣款的配置。,示例值及对应分析:当前未启用。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.cardSettleDeduct IS '对应JSON字段:cardSettleDeduct,说明:已在扣卡规则部分说明,当前为 0。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.couponCardDeduct IS '对应JSON字段:couponCardDeduct,说明::与卡绑定的“券额度扣除配置”。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.deliveryFeeDeduct IS '对应JSON字段:deliveryFeeDeduct,说明::配送费可否/多少从卡中抵扣,目前无业务发生。,示例值及对应分析:综合来看:本门店的卡片在“规则配置层”预留了大量细粒度控制字段,但目前实际使用只体现在“balance”和“可用范围”,折扣和具体扣卡规则基本都未启用(全部保持默认值 10 折、100%比例、0 扣款),真正扣款逻辑在交易流水中体现。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.use_scene IS '对应JSON字段:use_scene,说明::卡使用场景说明(比如“仅店内使用”“仅团建”等),本门店尚未使用此字段。,示例值及对应分析:2. 会员信息与关联字段';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.able_cross_site IS '对应JSON字段:able_cross_site,说明::是否允许跨店使用。,示例值及对应分析:1:可以跨门店使用;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.able_site_transfer IS '对应JSON字段:able_site_transfer,说明:?????? member_stored_value_cards-Analysis.md,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.is_allow_give IS '对应JSON字段:is_allow_give,说明::是否允许转赠/转让给其他会员。,示例值及对应分析:0:不允许;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.is_allow_order_deduct IS '对应JSON字段:is_allow_order_deduct,说明::是否允许在“订单层面统一扣款”。,示例值及对应分析:0:不允许(仅按项目扣卡);';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志。,示例值及对应分析:0:未删除;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.bind_password IS '对应JSON字段:bind_password,说明::卡绑定密码,用于消费或查询验证(目前未启用)。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_discount_range_type IS '对应JSON字段:goods_discount_range_type,说明:?????? member_stored_value_cards-Analysis.md,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goodsCategoryId IS '对应JSON字段:goodsCategoryId,说明:已上文说明:均为扩展限定维度,当前全部为空列表。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tableAreaId IS '对应JSON字段:tableAreaId,说明:已上文说明:均为扩展限定维度,当前全部为空列表。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.effect_site_id IS '对应JSON字段:effect_site_id,说明:(推测):卡片限定生效门店 ID。,示例值及对应分析:为 0 时,配合 able_cross_site=1,可解释为“所有门店可用”。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.start_time IS '对应JSON字段:start_time,说明::卡片生效开始时间(有效期起始)。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.end_time IS '对应JSON字段:end_time,说明::卡片有效期结束时间。,示例值及对应分析:start_time / end_time 组合就是卡的有效期。不同卡种有效期配置不同,如储值卡长效、月卡固定一个月等。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.disable_start_time IS '对应JSON字段:disable_start_time,说明::停用时间段(比如临时冻结卡的起止时间)。,示例值及对应分析:当前未启用,所有卡都是“未进入停用窗口”。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.disable_end_time IS '对应JSON字段:disable_end_time,说明::停用时间段(比如临时冻结卡的起止时间)。,示例值及对应分析:当前未启用,所有卡都是“未进入停用窗口”。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.last_consume_time IS '对应JSON字段:last_consume_time,说明::最近一次消费时间。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.create_time IS '对应JSON字段:create_time,说明::卡片创建时间(开卡时间)。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.status IS '对应JSON字段:status,说明:(推测):,示例值及对应分析:1:正常可用;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.sort IS '对应JSON字段:sort,说明::在前端展示或某些列表中的排序权重。,示例值及对应分析:具体取值分布不重要,主要反映展示优先级。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tenantAvatar IS '对应JSON字段:tenantAvatar,说明::品牌头像 URL(未配置)。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tenantName IS '对应JSON字段:tenantName,说明::租户/品牌名称(当前导出为空)。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.pdAssisnatLevel IS '对应JSON字段:pdAssisnatLevel,说明:已上文说明:均为扩展限定维度,当前全部为空列表。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.cxAssisnatLevel IS '对应JSON字段:cxAssisnatLevel,说明:已上文说明:均为扩展限定维度,当前全部为空列表。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.recharge_settlements (
+ id BIGINT PRIMARY KEY,
+ tenantid BIGINT,
+ siteid BIGINT,
+ sitename TEXT,
+ balanceamount NUMERIC(18,2),
+ cardamount NUMERIC(18,2),
+ cashamount NUMERIC(18,2),
+ couponamount NUMERIC(18,2),
+ createtime TIMESTAMPTZ,
+ memberid BIGINT,
+ membername TEXT,
+ tenantmembercardid BIGINT,
+ membercardtypename TEXT,
+ memberphone TEXT,
+ tableid BIGINT,
+ consumemoney NUMERIC(18,2),
+ onlineamount NUMERIC(18,2),
+ operatorid BIGINT,
+ operatorname TEXT,
+ revokeorderid BIGINT,
+ revokeordername TEXT,
+ revoketime TIMESTAMPTZ,
+ payamount NUMERIC(18,2),
+ pointamount NUMERIC(18,2),
+ refundamount NUMERIC(18,2),
+ settlename TEXT,
+ settlerelateid BIGINT,
+ settlestatus INT,
+ settletype INT,
+ paytime TIMESTAMPTZ,
+ roundingamount NUMERIC(18,2),
+ paymentmethod INT,
+ adjustamount NUMERIC(18,2),
+ assistantcxmoney NUMERIC(18,2),
+ assistantpdmoney NUMERIC(18,2),
+ couponsaleamount NUMERIC(18,2),
+ memberdiscountamount NUMERIC(18,2),
+ tablechargemoney NUMERIC(18,2),
+ goodsmoney NUMERIC(18,2),
+ realgoodsmoney NUMERIC(18,2),
+ servicemoney NUMERIC(18,2),
+ prepaymoney NUMERIC(18,2),
+ salesmanname TEXT,
+ orderremark TEXT,
+ salesmanuserid BIGINT,
+ canberevoked BOOLEAN,
+ pointdiscountprice NUMERIC(18,2),
+ pointdiscountcost NUMERIC(18,2),
+ activitydiscount NUMERIC(18,2),
+ serialnumber BIGINT,
+ assistantmanualdiscount NUMERIC(18,2),
+ allcoupondiscount NUMERIC(18,2),
+ goodspromotionmoney NUMERIC(18,2),
+ assistantpromotionmoney NUMERIC(18,2),
+ isusecoupon BOOLEAN,
+ isusediscount BOOLEAN,
+ isactivity BOOLEAN,
+ isbindmember BOOLEAN,
+ isfirst INT,
+ rechargecardamount NUMERIC(18,2),
+ giftcardamount NUMERIC(18,2),
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.recharge_settlements IS '对应JSON字段:recharge_settlements.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.id IS '对应JSON字段:id,说明::本条充值结算记录的主键 ID(唯一标识一条充值/撤销记录)。,示例值及对应分析:唯一性:74 条记录全部不同。';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.tenantid IS '对应JSON字段:tenantid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.siteid IS '对应JSON字段:siteid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.sitename IS '对应JSON字段:sitename,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.balanceamount IS '对应JSON字段:balanceamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.cardamount IS '对应JSON字段:cardamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.cashamount IS '对应JSON字段:cashamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.couponamount IS '对应JSON字段:couponamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.createtime IS '对应JSON字段:createtime,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.memberid IS '对应JSON字段:memberid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.membername IS '对应JSON字段:membername,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.tenantmembercardid IS '对应JSON字段:tenantmembercardid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.membercardtypename IS '对应JSON字段:membercardtypename,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.memberphone IS '对应JSON字段:memberphone,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.tableid IS '对应JSON字段:tableid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.consumemoney IS '对应JSON字段:consumemoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.onlineamount IS '对应JSON字段:onlineamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.operatorid IS '对应JSON字段:operatorid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.operatorname IS '对应JSON字段:operatorname,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.revokeorderid IS '对应JSON字段:revokeorderid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.revokeordername IS '对应JSON字段:revokeordername,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.revoketime IS '对应JSON字段:revoketime,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.payamount IS '对应JSON字段:payamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.pointamount IS '对应JSON字段:pointamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.refundamount IS '对应JSON字段:refundamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.settlename IS '对应JSON字段:settlename,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.settlerelateid IS '对应JSON字段:settlerelateid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.settlestatus IS '对应JSON字段:settlestatus,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.settletype IS '对应JSON字段:settletype,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.paytime IS '对应JSON字段:paytime,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.roundingamount IS '对应JSON字段:roundingamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.paymentmethod IS '对应JSON字段:paymentmethod,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.adjustamount IS '对应JSON字段:adjustamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.assistantcxmoney IS '对应JSON字段:assistantcxmoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.assistantpdmoney IS '对应JSON字段:assistantpdmoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.couponsaleamount IS '对应JSON字段:couponsaleamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.memberdiscountamount IS '对应JSON字段:memberdiscountamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.tablechargemoney IS '对应JSON字段:tablechargemoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.goodsmoney IS '对应JSON字段:goodsmoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.realgoodsmoney IS '对应JSON字段:realgoodsmoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.servicemoney IS '对应JSON字段:servicemoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.prepaymoney IS '对应JSON字段:prepaymoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.salesmanname IS '对应JSON字段:salesmanname,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.orderremark IS '对应JSON字段:orderremark,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.salesmanuserid IS '对应JSON字段:salesmanuserid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.canberevoked IS '对应JSON字段:canberevoked,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.pointdiscountprice IS '对应JSON字段:pointdiscountprice,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.pointdiscountcost IS '对应JSON字段:pointdiscountcost,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.activitydiscount IS '对应JSON字段:activitydiscount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.serialnumber IS '对应JSON字段:serialnumber,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.assistantmanualdiscount IS '对应JSON字段:assistantmanualdiscount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.allcoupondiscount IS '对应JSON字段:allcoupondiscount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.goodspromotionmoney IS '对应JSON字段:goodspromotionmoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.assistantpromotionmoney IS '对应JSON字段:assistantpromotionmoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.isusecoupon IS '对应JSON字段:isusecoupon,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.isusediscount IS '对应JSON字段:isusediscount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.isactivity IS '对应JSON字段:isactivity,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.isbindmember IS '对应JSON字段:isbindmember,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.isfirst IS '对应JSON字段:isfirst,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.rechargecardamount IS '对应JSON字段:rechargecardamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.giftcardamount IS '对应JSON字段:giftcardamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.settlement_records (
+ id BIGINT PRIMARY KEY,
+ tenantid BIGINT,
+ siteid BIGINT,
+ sitename TEXT,
+ balanceamount NUMERIC(18,2),
+ cardamount NUMERIC(18,2),
+ cashamount NUMERIC(18,2),
+ couponamount NUMERIC(18,2),
+ createtime TIMESTAMPTZ,
+ memberid BIGINT,
+ membername TEXT,
+ tenantmembercardid BIGINT,
+ membercardtypename TEXT,
+ memberphone TEXT,
+ tableid BIGINT,
+ consumemoney NUMERIC(18,2),
+ onlineamount NUMERIC(18,2),
+ operatorid BIGINT,
+ operatorname TEXT,
+ revokeorderid BIGINT,
+ revokeordername TEXT,
+ revoketime TIMESTAMPTZ,
+ payamount NUMERIC(18,2),
+ pointamount NUMERIC(18,2),
+ refundamount NUMERIC(18,2),
+ settlename TEXT,
+ settlerelateid BIGINT,
+ settlestatus INT,
+ settletype INT,
+ paytime TIMESTAMPTZ,
+ roundingamount NUMERIC(18,2),
+ paymentmethod INT,
+ adjustamount NUMERIC(18,2),
+ assistantcxmoney NUMERIC(18,2),
+ assistantpdmoney NUMERIC(18,2),
+ couponsaleamount NUMERIC(18,2),
+ memberdiscountamount NUMERIC(18,2),
+ tablechargemoney NUMERIC(18,2),
+ goodsmoney NUMERIC(18,2),
+ realgoodsmoney NUMERIC(18,2),
+ servicemoney NUMERIC(18,2),
+ prepaymoney NUMERIC(18,2),
+ salesmanname TEXT,
+ orderremark TEXT,
+ salesmanuserid BIGINT,
+ canberevoked BOOLEAN,
+ pointdiscountprice NUMERIC(18,2),
+ pointdiscountcost NUMERIC(18,2),
+ activitydiscount NUMERIC(18,2),
+ serialnumber BIGINT,
+ assistantmanualdiscount NUMERIC(18,2),
+ allcoupondiscount NUMERIC(18,2),
+ goodspromotionmoney NUMERIC(18,2),
+ assistantpromotionmoney NUMERIC(18,2),
+ isusecoupon BOOLEAN,
+ isusediscount BOOLEAN,
+ isactivity BOOLEAN,
+ isbindmember BOOLEAN,
+ isfirst INT,
+ rechargecardamount NUMERIC(18,2),
+ giftcardamount NUMERIC(18,2),
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.settlement_records IS '对应JSON字段:settlement_records.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.id IS '对应JSON字段:id,说明::结账记录主键 ID(订单结算 ID)。,示例值及对应分析:结构关联:';
+COMMENT ON COLUMN billiards_ods.settlement_records.tenantid IS '对应JSON字段:tenantid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.siteid IS '对应JSON字段:siteid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.sitename IS '对应JSON字段:sitename,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.balanceamount IS '对应JSON字段:balanceamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.cardamount IS '对应JSON字段:cardamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.cashamount IS '对应JSON字段:cashamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.couponamount IS '对应JSON字段:couponamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.createtime IS '对应JSON字段:createtime,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.memberid IS '对应JSON字段:memberid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.membername IS '对应JSON字段:membername,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.tenantmembercardid IS '对应JSON字段:tenantmembercardid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.membercardtypename IS '对应JSON字段:membercardtypename,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.memberphone IS '对应JSON字段:memberphone,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.tableid IS '对应JSON字段:tableid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.consumemoney IS '对应JSON字段:consumemoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.onlineamount IS '对应JSON字段:onlineamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.operatorid IS '对应JSON字段:operatorid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.operatorname IS '对应JSON字段:operatorname,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.revokeorderid IS '对应JSON字段:revokeorderid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.revokeordername IS '对应JSON字段:revokeordername,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.revoketime IS '对应JSON字段:revoketime,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.payamount IS '对应JSON字段:payamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.pointamount IS '对应JSON字段:pointamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.refundamount IS '对应JSON字段:refundamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.settlename IS '对应JSON字段:settlename,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.settlerelateid IS '对应JSON字段:settlerelateid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.settlestatus IS '对应JSON字段:settlestatus,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.settletype IS '对应JSON字段:settletype,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.paytime IS '对应JSON字段:paytime,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.roundingamount IS '对应JSON字段:roundingamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.paymentmethod IS '对应JSON字段:paymentmethod,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.adjustamount IS '对应JSON字段:adjustamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.assistantcxmoney IS '对应JSON字段:assistantcxmoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.assistantpdmoney IS '对应JSON字段:assistantpdmoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.couponsaleamount IS '对应JSON字段:couponsaleamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.memberdiscountamount IS '对应JSON字段:memberdiscountamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.tablechargemoney IS '对应JSON字段:tablechargemoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.goodsmoney IS '对应JSON字段:goodsmoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.realgoodsmoney IS '对应JSON字段:realgoodsmoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.servicemoney IS '对应JSON字段:servicemoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.prepaymoney IS '对应JSON字段:prepaymoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.salesmanname IS '对应JSON字段:salesmanname,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.orderremark IS '对应JSON字段:orderremark,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.salesmanuserid IS '对应JSON字段:salesmanuserid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.canberevoked IS '对应JSON字段:canberevoked,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.pointdiscountprice IS '对应JSON字段:pointdiscountprice,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.pointdiscountcost IS '对应JSON字段:pointdiscountcost,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.activitydiscount IS '对应JSON字段:activitydiscount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.serialnumber IS '对应JSON字段:serialnumber,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.assistantmanualdiscount IS '对应JSON字段:assistantmanualdiscount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.allcoupondiscount IS '对应JSON字段:allcoupondiscount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.goodspromotionmoney IS '对应JSON字段:goodspromotionmoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.assistantpromotionmoney IS '对应JSON字段:assistantpromotionmoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.isusecoupon IS '对应JSON字段:isusecoupon,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.isusediscount IS '对应JSON字段:isusediscount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.isactivity IS '对应JSON字段:isactivity,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.isbindmember IS '对应JSON字段:isbindmember,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.isfirst IS '对应JSON字段:isfirst,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.rechargecardamount IS '对应JSON字段:rechargecardamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.giftcardamount IS '对应JSON字段:giftcardamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.settlement_records.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.settlement_records.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.settlement_records.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.assistant_cancellation_records (
+ id BIGINT PRIMARY KEY,
+ siteId BIGINT,
+ siteProfile JSONB,
+ assistantName TEXT,
+ assistantAbolishAmount NUMERIC(18,2),
+ assistantOn INT,
+ pdChargeMinutes INT,
+ tableAreaId BIGINT,
+ tableArea TEXT,
+ tableId BIGINT,
+ tableName TEXT,
+ trashReason TEXT,
+ createTime TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.assistant_cancellation_records IS '对应JSON字段:assistant_cancellation_records.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.id IS '对应JSON字段:id,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.siteId IS '对应JSON字段:siteId,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.siteProfile IS '对应JSON字段:siteProfile,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.assistantName IS '对应JSON字段:assistantName,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.assistantAbolishAmount IS '对应JSON字段:assistantAbolishAmount,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.assistantOn IS '对应JSON字段:assistantOn,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.pdChargeMinutes IS '对应JSON字段:pdChargeMinutes,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.tableAreaId IS '对应JSON字段:tableAreaId,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.tableArea IS '对应JSON字段:tableArea,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.tableId IS '对应JSON字段:tableId,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.tableName IS '对应JSON字段:tableName,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.trashReason IS '对应JSON字段:trashReason,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.createTime IS '对应JSON字段:createTime,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.assistant_accounts_master (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ assistant_no TEXT,
+ nickname TEXT,
+ real_name TEXT,
+ mobile TEXT,
+ team_id BIGINT,
+ team_name TEXT,
+ user_id BIGINT,
+ level TEXT,
+ assistant_status INT,
+ work_status INT,
+ leave_status INT,
+ entry_time TIMESTAMP,
+ resign_time TIMESTAMP,
+ start_time TIMESTAMP,
+ end_time TIMESTAMP,
+ create_time TIMESTAMP,
+ update_time TIMESTAMP,
+ order_trade_no TEXT,
+ staff_id BIGINT,
+ staff_profile_id BIGINT,
+ system_role_id BIGINT,
+ avatar TEXT,
+ gender INT,
+ height NUMERIC(18,2),
+ weight NUMERIC(18,2),
+ job_num TEXT,
+ show_status INT,
+ show_sort INT,
+ sum_grade NUMERIC(18,2),
+ assistant_grade NUMERIC(18,2),
+ get_grade_times INT,
+ introduce TEXT,
+ video_introduction_url TEXT,
+ group_id BIGINT,
+ group_name TEXT,
+ shop_name TEXT,
+ charge_way INT,
+ entry_type INT,
+ allow_cx INT,
+ is_guaranteed INT,
+ salary_grant_enabled INT,
+ light_status INT,
+ online_status INT,
+ is_delete INT,
+ cx_unit_price NUMERIC(18,2),
+ pd_unit_price NUMERIC(18,2),
+ last_table_id BIGINT,
+ last_table_name TEXT,
+ person_org_id BIGINT,
+ serial_number BIGINT,
+ is_team_leader INT,
+ criticism_status INT,
+ ding_talk_synced INT,
+ site_light_cfg_id BIGINT,
+ light_equipment_id TEXT,
+ entry_sign_status INT,
+ resign_sign_status INT,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.assistant_accounts_master IS '对应JSON字段:assistant_accounts_master.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.id IS '对应JSON字段:id,说明::助教账号主键 ID,在“助教流水.json”中对应 site_assistant_id。,示例值及对应分析:作用:所有与助教相关的事实表(助教流水、助教排班等)都会通过这个 ID 关联到该维表。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.tenant_id IS '对应JSON字段:tenant_id,说明::品牌/租户 ID,对应“非球科技”系统中该商户的唯一标识。,示例值及对应分析:用途:多门店时用来区分不同商户。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.site_id IS '对应JSON字段:site_id,说明::门店 ID,对应本次数据的这家球房(朗朗桌球)。,示例值及对应分析:关联:与其它 JSON(台费流水、库存、销售等)中的 site_id 一致。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.assistant_no IS '对应JSON字段:assistant_no,说明:(结合字段名推测):助教工号 / 编号,便于业务侧识别。,示例值及对应分析:关联:在“助教流水.json”中有 assistantNo,与此字段对应。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.nickname IS '对应JSON字段:nickname,说明::助教在前台展示的昵称,如“佳怡”“周周”“球球”等。,示例值及对应分析:用途:与真实姓名区分,用于顾客侧展示。如在助教流水中 nickname 就是这个值。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.real_name IS '对应JSON字段:real_name,说明::助教真实姓名,如“何海婷”“梁婷婷”等。,示例值及对应分析:关联:在“助教流水.json”的 assistantName 与此一致。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.mobile IS '对应JSON字段:mobile,说明::助教手机号,用于登录绑定、通知、钉钉同步等。,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.team_id IS '对应JSON字段:team_id,说明::助教所属团队 ID。,示例值及对应分析:关联:在“助教流水.json”中 assistant_team_id 与此一致。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.team_name IS '对应JSON字段:team_name,说明::团队名称,展示用,和 team_id 一一对应。,示例值及对应分析:group_id';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.level IS '对应JSON字段:level,说明:(结合“助教流水中的 assistant_level / levelName 推测”):,示例值及对应分析:8:助教管理/管理员(和流水里的 "助教管理" 对应)';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.assistant_status IS '对应JSON字段:assistant_status,说明:(推测):账号启用状态:,示例值及对应分析:1:启用';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.work_status IS '对应JSON字段:work_status,说明::,示例值及对应分析:1:在岗/可排班';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.leave_status IS '对应JSON字段:leave_status,说明:类型:int,枚举。,示例值及对应分析:观测:';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.entry_time IS '对应JSON字段:entry_time,说明::入职时间。,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.resign_time IS '对应JSON字段:resign_time,说明::离职日期;使用“远未来日期”作为“未离职”的占位。,示例值及对应分析:entry_type';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.start_time IS '对应JSON字段:start_time,说明:(推测):当前配置生效的开始日期。,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.end_time IS '对应JSON字段:end_time,说明::当前配置生效的结束日期(例如一个周期性的排班/合同周期)。,示例值及对应分析:last_table_id';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.create_time IS '对应JSON字段:create_time,说明::账号创建时间。,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.update_time IS '对应JSON字段:update_time,说明::账号最近一次被修改的时间(例如修改等级、昵称等)。,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.order_trade_no IS '对应JSON字段:order_trade_no,说明:(推测):该助教最近一次关联的订单号,用于快速跳转或回溯最近服务行为。,示例值及对应分析:9. 灯控、钉钉等系统集成相关字段';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.staff_id IS '对应JSON字段:staff_id,说明:(推测):预留给“人事系统员工 ID”的字段,目前未接入或未启用。,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.staff_profile_id IS '对应JSON字段:staff_profile_id,说明:(推测):人事档案 ID,与第三方 HR 系统或内部员工档案集成使用,当前未启用。,示例值及对应分析:4. 等级、计费与薪资配置字段';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.system_role_id IS '对应JSON字段:system_role_id,说明:?????? assistant_accounts_master-Analysis.md,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.avatar IS '对应JSON字段:avatar,说明::助教头像地址。,示例值及对应分析:introduce';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.gender IS '对应JSON字段:gender,说明:(结合常见约定与值分布推测):,示例值及对应分析:0:未填/保密';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.show_status IS '对应JSON字段:show_status,说明:(推测):前台展示状态:,示例值及对应分析:1:在助教选择界面展示。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.show_sort IS '对应JSON字段:show_sort,说明::前台展示排序权重,值越小/越大对应不同的排序策略(当前看起来与 assistant_no 有一定对应关系)。,示例值及对应分析:online_status';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.sum_grade IS '对应JSON字段:sum_grade,说明::评分总和,用于计算平均分(assistant_grade = sum_grade / get_grade_times),当前为 0。,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.get_grade_times IS '对应JSON字段:get_grade_times,说明::累计被评分次数。,示例值及对应分析:charge_way';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.video_introduction_url IS '对应JSON字段:video_introduction_url,说明::助教个人视频介绍地址。,示例值及对应分析:height';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.user_id IS '对应JSON字段:user_id,说明:账号对应的用户 ID/员工 ID,用于跨表关联。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.height IS '对应JSON字段:height,说明:身高(数值),可空。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.weight IS '对应JSON字段:weight,说明:体重(数值),可空。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.job_num IS '对应JSON字段:job_num,说明:工号/岗位编号,保留原始取值。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.assistant_grade IS '对应JSON字段:assistant_grade,说明:平均评分,通常 = sum_grade/get_grade_times。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.introduce IS '对应JSON字段:introduce,说明:个人简介/自我介绍,可空。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.group_id IS '对应JSON字段:group_id,说明:分组/自定义分组 ID。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.group_name IS '对应JSON字段:group_name,说明:分组名称。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.shop_name IS '对应JSON字段:shop_name,说明:门店名称冗余。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.charge_way IS '对应JSON字段:charge_way,说明:收费方式枚举,保留原值。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.entry_type IS '对应JSON字段:entry_type,说明:入职类型枚举,保留原值。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.allow_cx IS '对应JSON字段:allow_cx,说明:是否允许超休/冲销(0/1)。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.is_guaranteed IS '对应JSON字段:is_guaranteed,说明:是否保底(0/1)。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.salary_grant_enabled IS '对应JSON字段:salary_grant_enabled,说明:薪资发放/补贴开关,枚举。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.light_status IS '对应JSON字段:light_status,说明:灯控状态/模式,保留原值。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.online_status IS '对应JSON字段:online_status,说明:在线状态标记(0/1等)。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.is_delete IS '对应JSON字段:is_delete,说明:逻辑删除标记(0=有效,1=删除)。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.cx_unit_price IS '对应JSON字段:cx_unit_price,说明:超休单价/冲销单价,金额类。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.pd_unit_price IS '对应JSON字段:pd_unit_price,说明:排钟/点钟单价,金额类。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.last_table_id IS '对应JSON字段:last_table_id,说明:最近服务桌台 ID。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.last_table_name IS '对应JSON字段:last_table_name,说明:最近服务桌台名称。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.person_org_id IS '对应JSON字段:person_org_id,说明:人员组织 ID/部门 ID。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.serial_number IS '对应JSON字段:serial_number,说明:序列号/排序号,保留原值。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.is_team_leader IS '对应JSON字段:is_team_leader,说明:是否组长(0/1)。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.criticism_status IS '对应JSON字段:criticism_status,说明:处罚/警告状态标记,枚举。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.ding_talk_synced IS '对应JSON字段:ding_talk_synced,说明:是否已同步钉钉(0/1)。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.site_light_cfg_id IS '对应JSON字段:site_light_cfg_id,说明:门店灯控配置 ID。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.light_equipment_id IS '对应JSON字段:light_equipment_id,说明:灯控设备 ID/硬件编号。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.entry_sign_status IS '对应JSON字段:entry_sign_status,说明:入职签署状态,枚举。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.resign_sign_status IS '对应JSON字段:resign_sign_status,说明:离职签署状态,枚举。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.assistant_service_records (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ siteProfile JSONB,
+ site_table_id BIGINT,
+ order_settle_id BIGINT,
+ order_trade_no TEXT,
+ order_pay_id BIGINT,
+ order_assistant_id BIGINT,
+ order_assistant_type INT,
+ assistantName TEXT,
+ assistantNo TEXT,
+ assistant_level TEXT,
+ assistant_team_id BIGINT,
+ nickname TEXT,
+ ledger_name TEXT,
+ ledger_group_name TEXT,
+ ledger_amount NUMERIC(18,2),
+ ledger_count NUMERIC(18,4),
+ ledger_unit_price NUMERIC(18,4),
+ ledger_status INT,
+ ledger_start_time TIMESTAMP,
+ ledger_end_time TIMESTAMP,
+ manual_discount_amount NUMERIC(18,2),
+ member_discount_amount NUMERIC(18,2),
+ coupon_deduct_money NUMERIC(18,2),
+ service_money NUMERIC(18,2),
+ projected_income NUMERIC(18,2),
+ real_use_seconds INT,
+ income_seconds INT,
+ start_use_time TIMESTAMP,
+ last_use_time TIMESTAMP,
+ create_time TIMESTAMP,
+ is_single_order INT,
+ is_delete INT,
+ is_trash INT,
+ trash_reason TEXT,
+ trash_applicant_id BIGINT,
+ trash_applicant_name TEXT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ salesman_name TEXT,
+ salesman_org_id BIGINT,
+ salesman_user_id BIGINT,
+ person_org_id BIGINT,
+ add_clock INT,
+ returns_clock INT,
+ composite_grade NUMERIC(10,2),
+ composite_grade_time TIMESTAMP,
+ skill_grade NUMERIC(10,2),
+ service_grade NUMERIC(10,2),
+ sum_grade NUMERIC(10,2),
+ grade_status INT,
+ get_grade_times INT,
+ is_not_responding INT,
+ is_confirm INT,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+
+COMMENT ON TABLE billiards_ods.assistant_service_records IS '对应JSON字段:assistant_service_records.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.id IS '对应JSON字段:id,说明::本条助教流水记录的主键 ID(流水唯一标识)。,示例值及对应分析:作用:在系统内部唯一定位这一条助教服务记录。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID;你这份数据中是固定值(同一个商户)。,示例值及对应分析:关联:全库所有表都有,作为“商户维度”的过滤键。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.site_id IS '对应JSON字段:site_id,说明::门店 ID,本数据中指“朗朗桌球”这一家门店。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.siteProfile IS '对应JSON字段:siteProfile,说明::门店信息快照,包括 id、shop_name、address 等,和其他 JSON 里的 siteProfile 一致。,示例值及对应分析:作用:冗余门店信息,方便查看(而不是每次都联表看门店档案)。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.site_table_id IS '对应JSON字段:site_table_id,说明::球台 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.order_settle_id IS '对应JSON字段:order_settle_id,说明::订单结算 ID,相当于“结账单号”的内部主键。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.order_trade_no IS '对应JSON字段:order_trade_no,说明::订单交易号,整个订单层面的编号。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.order_pay_id IS '对应JSON字段:order_pay_id,说明::关联到“支付记录”的主键 ID。,示例值及对应分析:作用:可以和支付记录中的 id / relate_id 等字段对应,找到这条助教服务对应的支付流水。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.order_assistant_id IS '对应JSON字段:order_assistant_id,说明::订单中“助教项目明细”的内部 ID。,示例值及对应分析:作用:如果订单里有多条助教项目(比如换助教、多个时间段),此字段唯一标识这一条助教明细。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.order_assistant_type IS '对应JSON字段:order_assistant_type,说明:(推测):,示例值及对应分析:1:常规助教服务(主课/基础课)。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.assistantName IS '对应JSON字段:assistantName,说明::助教姓名,如“何海婷”“胡敏”等。,示例值及对应分析:备注:和助教账号档案里的 real_name 一致。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.assistantNo IS '对应JSON字段:assistantNo,说明::助教编号,例如 "27"。,示例值及对应分析:关联:在助教账号表里也有 assistant_no 字段,对应工号/编号。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.assistant_level IS '对应JSON字段:assistant_level,说明::助教等级名称,与 assistant_level 一一对应(初级/中级/高级/助教管理)。,示例值及对应分析:备注:属于展示用的冗余字段。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.assistant_team_id IS '对应JSON字段:assistant_team_id,说明::当前这条助教服务所对应的“课程/技能名称”。,示例值及对应分析:当 order_assistant_type = 1 时,多为“基础课”。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.nickname IS '对应JSON字段:nickname,说明::助教对外昵称,如“佳怡”“周周”“球球”等。,示例值及对应分析:说明:从数据看,这个 nickname 是“助教昵称”,不是顾客昵称(容易混淆)。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_name IS '对应JSON字段:ledger_name,说明:?????? assistant_service_records-Analysis.md,示例值及对应分析:?? assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_group_name IS '对应JSON字段:ledger_group_name,说明:(推测):助教项目所属的“计费分组/套餐分组名称”,例如某种助教套餐或业务组名称。,示例值及对应分析:目前未被实际使用。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_amount IS '对应JSON字段:ledger_amount,说明::按标准单价计算出来的应收金额(近似 = ledger_unit_price × income_seconds / 3600)。,示例值及对应分析:说明:从数据看,这个金额对应“按原价计费”的金额,未扣除各种优惠。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_count IS '对应JSON字段:ledger_count,说明::台账记录的计时总秒数。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_unit_price IS '对应JSON字段:ledger_unit_price,说明::助教服务 标准单价(通常是标价:每小时、每节课的单价)。,示例值及对应分析:特点:如 98.0、108.0、190.0 等。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_status IS '对应JSON字段:ledger_status,说明:(推测):助教流水记录状态:,示例值及对应分析:1:正常有效。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_start_time IS '对应JSON字段:ledger_start_time,说明::台账层面记录的开始时间。,示例值及对应分析:说明:与 start_use_time 在当前数据中完全一致,可以视为“计费起始时间”。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_end_time IS '对应JSON字段:ledger_end_time,说明::台账层面的结束时间。,示例值及对应分析:说明:与 last_use_time 一致,可以视为“计费结束时间”。对于 real_use_seconds = 0 的记录,开始和结束时间相同,说明只是预约/录入,并未实际服务。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.manual_discount_amount IS '对应JSON字段:manual_discount_amount,说明::收银员手动给予的减免金额(人工改价)。,示例值及对应分析:当前导出时间段内暂未出现手动打折的情况。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.member_discount_amount IS '对应JSON字段:member_discount_amount,说明::由会员卡折扣产生的优惠金额。,示例值及对应分析:说明:尽管字段里是 0,但实际折扣可能已经体现在 projected_income 与 ledger_amount 的差额中,这里只是未单独拆出。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.coupon_deduct_money IS '对应JSON字段:coupon_deduct_money,说明::由“优惠券/代金券/团购券”等 直接抵扣到这条助教服务上的金额。,示例值及对应分析:说明:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.service_money IS '对应JSON字段:service_money,说明:(推测):用于记录与助教结算的金额(平台预留的“成本/分成”字段)。,示例值及对应分析:当前数据中未启用这个机制,所以全为 0。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.projected_income IS '对应JSON字段:projected_income,说明::实际结算计入门店的金额(已经考虑折扣、卡权益、券等后的结果)。,示例值及对应分析:从数据:projected_income 明显低于 ledger_amount,说明中间有折扣,但折扣的明细并不全由下面几个字段体现(很多是卡权益内生折扣)。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.real_use_seconds IS '对应JSON字段:real_use_seconds,说明::实际使用时长(秒)。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.income_seconds IS '对应JSON字段:income_seconds,说明::计费秒数 / 应计收入对应的时间。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.start_use_time IS '对应JSON字段:start_use_time,说明::助教实际开始服务时间。,示例值及对应分析:特点:正常情况下与 ledger_start_time 相同。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.last_use_time IS '对应JSON字段:last_use_time,说明::最后一次使用(实际服务)时间。,示例值及对应分析:特点:正常结束时与 ledger_end_time 相同;如果服务还未真正开始或立即结束,开始/结束时间可能相同。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.create_time IS '对应JSON字段:create_time,说明::这条助教流水记录创建时间(一般接近结算/下单时间)。,示例值及对应分析:?? assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.is_single_order IS '对应JSON字段:is_single_order,说明:(推测):是否单独订单:,示例值及对应分析:1:本助教服务作为单独订单结算(或单独拆项)。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志。,示例值及对应分析:0:未删除;';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.is_trash IS '对应JSON字段:is_trash,说明::是否已废除/作废:,示例值及对应分析:0:正常有效;';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.trash_reason IS '对应JSON字段:trash_reason,说明::废除原因(文本说明),例如“顾客取消”“录入错误”等。,示例值及对应分析:当前数据为空字符串,说明当前导出时间段没有被废除的助教流水记录。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.trash_applicant_id IS '对应JSON字段:trash_applicant_id,说明::提出废除申请的员工 ID(通常是操作员/管理员)。,示例值及对应分析:当前数据全为 0,因此短期内没有发生废除操作。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.trash_applicant_name IS '对应JSON字段:trash_applicant_name,说明::废除申请人姓名。,示例值及对应分析:?? assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.operator_id IS '对应JSON字段:operator_id,说明::操作员 ID(录入/结算这条助教服务的员工)。,示例值及对应分析:关联:可与员工/账号表对应(本次导出未单独给员工表,但其他 JSON 里多处出现该 ID)。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.operator_name IS '对应JSON字段:operator_name,说明::操作员姓名,与 operator_id 一起使用,便于直接阅读。,示例值及对应分析:user_id';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.salesman_name IS '对应JSON字段:salesman_name,说明::关联的“营业员/销售员姓名”,用于提成归属。,示例值及对应分析:观测:本数据中多数为空字符串,说明助教流水没有配置单独的营业员。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.salesman_org_id IS '对应JSON字段:salesman_org_id,说明::营业员所属组织/部门 ID。,示例值及对应分析:观测:多为 0。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.salesman_user_id IS '对应JSON字段:salesman_user_id,说明::营业员用户 ID。,示例值及对应分析:观测:多为 0,代表未指定。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.person_org_id IS '对应JSON字段:person_org_id,说明:同样在上文说明:助教所属人事组织 ID。,示例值及对应分析:9. 作废 / 废除相关字段';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.add_clock IS '对应JSON字段:add_clock,说明:(推测):加钟秒数,即在原有预约/服务基础上临时追加的时长。,示例值及对应分析:说明:值均为 60 的倍数(分钟级加钟),如 600 秒=10 分钟。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.returns_clock IS '对应JSON字段:returns_clock,说明:(推测):退钟秒数(取消加钟或提前结束退回的时间)。,示例值及对应分析:当前数据里没有退钟场景,所以全为 0,但字段设计已经预留。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.composite_grade IS '对应JSON字段:composite_grade,说明::综合评分(例如技能+服务加权后的平均分),当前数据没有实际评分。,示例值及对应分析:?? assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.composite_grade_time IS '对应JSON字段:composite_grade_time,说明:(推测):最近一次评价时间/综合评分更新时间。现在都是默认“无效时间”。,示例值及对应分析:3. 桌台 / 门店维度字段';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.skill_grade IS '对应JSON字段:skill_grade,说明:(推测):顾客对“技能表现”的评分(整数或打分等级)。,示例值及对应分析:当前数据中还未产生评分记录,所以都是默认值 0。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.service_grade IS '对应JSON字段:service_grade,说明:(推测):顾客对“服务态度”的评分。,示例值及对应分析:?? assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.sum_grade IS '对应JSON字段:sum_grade,说明::累计评分总和(可能用于计算平均分),当前为 0。,示例值及对应分析:?? assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.grade_status IS '对应JSON字段:grade_status,说明:(推测):评价状态,比如:,示例值及对应分析:1 = 未评价/正常;';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.get_grade_times IS '对应JSON字段:get_grade_times,说明::该条记录对应的评价次数(或该助教被评价次数快照)。,示例值及对应分析:?? assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.is_not_responding IS '对应JSON字段:is_not_responding,说明:(推测):是否存在“爽约/未响应”情况:,示例值及对应分析:0:正常;';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.is_confirm IS '对应JSON字段:is_confirm,说明:(推测):确认状态,例如:,示例值及对应分析:1:待确认;';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.site_tables_master (
+ id BIGINT PRIMARY KEY,
+ site_id BIGINT,
+ siteName TEXT,
+ "appletQrCodeUrl" TEXT,
+ areaName TEXT,
+ audit_status INT,
+ charge_free INT,
+ create_time TIMESTAMP,
+ delay_lights_time INT,
+ is_online_reservation INT,
+ is_rest_area INT,
+ light_status INT,
+ only_allow_groupon INT,
+ order_delay_time INT,
+ self_table INT,
+ show_status INT,
+ site_table_area_id BIGINT,
+ tableStatusName TEXT,
+ table_cloth_use_Cycle INT,
+ table_cloth_use_time TIMESTAMP,
+ table_name TEXT,
+ table_price NUMERIC(18,2),
+ table_status INT,
+ temporary_light_second INT,
+ virtual_table INT,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.site_tables_master IS '对应JSON字段:site_tables_master.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 site_tables_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.site_tables_master.id IS '对应JSON字段:id,说明::台桌主键 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.site_tables_master.site_id IS '对应JSON字段:site_id,说明::门店 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.site_tables_master.siteName IS '对应JSON字段:siteName,说明::门店名称快照,冗余字段,配合 site_id 使用。,示例值及对应分析:?? site_tables_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.site_tables_master."appletQrCodeUrl" IS '对应JSON字段:appletQrCodeUrl,说明::小程序二维码 URL。 一般用于:,示例值及对应分析:打印二维码贴在台上,顾客扫码可呼叫服务、查看账单或发起线上预约;';
+COMMENT ON COLUMN billiards_ods.site_tables_master.areaName IS '对应JSON字段:areaName,说明::区域名称,用于前台展示和区域维度管理。,示例值及对应分析:结构特征:';
+COMMENT ON COLUMN billiards_ods.site_tables_master.audit_status IS '对应JSON字段:audit_status,说明:(结合命名惯例):,示例值及对应分析:2:已审核/已启用;';
+COMMENT ON COLUMN billiards_ods.site_tables_master.charge_free IS '对应JSON字段:charge_free,说明:(推测):,示例值及对应分析:0:正常计费;';
+COMMENT ON COLUMN billiards_ods.site_tables_master.create_time IS '对应JSON字段:create_time,说明::台桌配置的创建时间或最近一次创建/复制时间。,示例值及对应分析:三、与其它 JSON 的字段级关联关系(结构视角)';
+COMMENT ON COLUMN billiards_ods.site_tables_master.delay_lights_time IS '对应JSON字段:delay_lights_time,说明:(推测):台灯熄灭延迟时间(单位多半是秒或分钟),用于结账后延时关灯。,示例值及对应分析:本门店未启用延迟关灯功能(全部为 0)。';
+COMMENT ON COLUMN billiards_ods.site_tables_master.is_online_reservation IS '对应JSON字段:is_online_reservation,说明:(结合值分布推断):,示例值及对应分析:1:允许线上预约(可在小程序/线上平台预约这张台);';
+COMMENT ON COLUMN billiards_ods.site_tables_master.is_rest_area IS '对应JSON字段:is_rest_area,说明:(推测):,示例值及对应分析:0:正常计费区域;';
+COMMENT ON COLUMN billiards_ods.site_tables_master.light_status IS '对应JSON字段:light_status,说明:(结合命名推断):,示例值及对应分析:该字段是台灯/灯光状态开关位:';
+COMMENT ON COLUMN billiards_ods.site_tables_master.only_allow_groupon IS '对应JSON字段:only_allow_groupon,说明:(结合命名推断):,示例值及对应分析:1:仅允许团购/券预约使用(团购专用台);';
+COMMENT ON COLUMN billiards_ods.site_tables_master.order_delay_time IS '对应JSON字段:order_delay_time,说明:(推测):订单层面允许的“自动延时时长”(例如到点后自动延长多少时间继续计费)。,示例值及对应分析:本门店未使用此功能。';
+COMMENT ON COLUMN billiards_ods.site_tables_master.self_table IS '对应JSON字段:self_table,说明:(推测):,示例值及对应分析:1:“本门店自有台”,非共享或外部配置;';
+COMMENT ON COLUMN billiards_ods.site_tables_master.show_status IS '对应JSON字段:show_status,说明:(推测):,示例值及对应分析:1:正常在前台“开台列表”中展示;';
+COMMENT ON COLUMN billiards_ods.site_tables_master.site_table_area_id IS '对应JSON字段:site_table_area_id,说明::门店维度的“台桌区域 ID”。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.site_tables_master.tableStatusName IS '对应JSON字段:tableStatusName,说明::table_status 的中文名称,仅为展示用途。,示例值及对应分析:?? site_tables_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.site_tables_master.table_cloth_use_Cycle IS '对应JSON字段:table_cloth_use_Cycle,说明:(推测):,示例值及对应分析:台呢使用周期阈值,例如达到某个秒数后提醒更换;';
+COMMENT ON COLUMN billiards_ods.site_tables_master.table_cloth_use_time IS '对应JSON字段:table_cloth_use_time,说明:(结合命名和数值特征):,示例值及对应分析:台呢使用累计时长,单位极大概率为“秒”:';
+COMMENT ON COLUMN billiards_ods.site_tables_master.table_name IS '对应JSON字段:table_name,说明::台号/台名称,用于前台操作界面展示,也出现在小票和各种流水中的 ledger_name 或 tableName 字段。,示例值及对应分析:?? site_tables_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.site_tables_master.table_price IS '对应JSON字段:table_price,说明:(结构角度):,示例值及对应分析:设计上应为“台的基础单价”字段(例如按小时或按局单价);';
+COMMENT ON COLUMN billiards_ods.site_tables_master.table_status IS '对应JSON字段:table_status,说明::台当前运行状态,真实反映某一时刻台的占用/暂停情况。,示例值及对应分析:?? site_tables_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.site_tables_master.temporary_light_second IS '对应JSON字段:temporary_light_second,说明:(推测):临时点灯时长(秒),例如手动临时开灯一段时间。,示例值及对应分析:本门店未使用。';
+COMMENT ON COLUMN billiards_ods.site_tables_master.virtual_table IS '对应JSON字段:virtual_table,说明:(推测):,示例值及对应分析:0:物理台(实体存在的桌);';
+COMMENT ON COLUMN billiards_ods.site_tables_master.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.site_tables_master.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.site_tables_master.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.site_tables_master.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.table_fee_discount_records (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ siteProfile JSONB,
+ site_table_id BIGINT,
+ tableProfile JSONB,
+ tenant_table_area_id BIGINT,
+ adjust_type INT,
+ ledger_amount NUMERIC(18,2),
+ ledger_count NUMERIC(18,4),
+ ledger_name TEXT,
+ ledger_status INT,
+ applicant_id BIGINT,
+ applicant_name TEXT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ order_settle_id BIGINT,
+ order_trade_no TEXT,
+ is_delete INT,
+ create_time TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.table_fee_discount_records IS '对应JSON字段:table_fee_discount_records.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 table_fee_discount_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.id IS '对应JSON字段:id,说明::台费打折 / 调整流水主键 ID。,示例值及对应分析:作用:在“台费调账表”中唯一标识一条折扣/调账操作。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID。,示例值及对应分析:作用:标识记录属于哪一个商户(同一个“非球科技”租户)。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.site_id IS '对应JSON字段:site_id,说明::门店 ID,本批数据全部为同一家门店(朗朗桌球)。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.siteProfile IS '对应JSON字段:siteProfile,说明::门店信息快照,用于报表时直接读取,无需再联门店档案。,示例值及对应分析:?? table_fee_discount_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.site_table_id IS '对应JSON字段:site_table_id,说明::台桌 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.tableProfile IS '对应JSON字段:tableProfile,说明::折扣发生时,对应台桌的配置信息快照。,示例值及对应分析:?? table_fee_discount_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.tenant_table_area_id IS '对应JSON字段:tenant_table_area_id,说明::租户维度的“台桌区域 ID”。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.adjust_type IS '对应JSON字段:adjust_type,说明:(根据文件含义 + 命名 + 数据):,示例值及对应分析:文件名是“台费打折”,字段名为“调整类型”,当前所有记录都是 1,即“台费打折/台费减免”这一种调整类型。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.ledger_amount IS '对应JSON字段:ledger_amount,说明:(关键点):,示例值及对应分析:通过与 台费流水.json 做对比,可以明确:';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.ledger_count IS '对应JSON字段:ledger_count,说明::,示例值及对应分析:这里不是“秒数”,而是“调整次数/条数”的量化,目前固定为 1,表示“一次调账事件”。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.ledger_name IS '对应JSON字段:ledger_name,说明:(推测):,示例值及对应分析:设计上应该用于记录“调账项目名称”或“打折原因描述”(例如某种优惠规则名称),但当前门店并未使用该字段。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.ledger_status IS '对应JSON字段:ledger_status,说明::,示例值及对应分析:1:生效调整(当前有效的台费打折 / 调账记录);';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.applicant_id IS '对应JSON字段:applicant_id,说明::打折/调账申请人 ID。,示例值及对应分析:作用:记录谁发起了这次台费调整。 本时段内所有调整均由同一位员工发起。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.applicant_name IS '对应JSON字段:applicant_name,说明::申请人姓名(带角色描述),为 applicant_id 的冗余显示字段。,示例值及对应分析:?? table_fee_discount_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.operator_id IS '对应JSON字段:operator_id,说明::实际执行调账操作的操作员 ID。,示例值及对应分析:说明:这段时间内,“申请人”和“操作员”是同一个人。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.operator_name IS '对应JSON字段:operator_name,说明::操作员姓名。,示例值及对应分析:?? table_fee_discount_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.order_settle_id IS '对应JSON字段:order_settle_id,说明::结算单/小票 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.order_trade_no IS '对应JSON字段:order_trade_no,说明::订单交易号。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志:,示例值及对应分析:0:未删除(有效记录);';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.create_time IS '对应JSON字段:create_time,说明::台费调整记录的创建时间,即打折操作被执行的时间戳。,示例值及对应分析:说明:与台费流水中的 create_time(结算时间)相互配合,可以还原调整发生于结账之前还是之后。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.table_fee_transactions (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ siteProfile JSONB,
+ site_table_id BIGINT,
+ site_table_area_id BIGINT,
+ site_table_area_name TEXT,
+ tenant_table_area_id BIGINT,
+ order_trade_no TEXT,
+ order_pay_id BIGINT,
+ order_settle_id BIGINT,
+ ledger_name TEXT,
+ ledger_amount NUMERIC(18,2),
+ ledger_count NUMERIC(18,4),
+ ledger_unit_price NUMERIC(18,4),
+ ledger_status INT,
+ ledger_start_time TIMESTAMP,
+ ledger_end_time TIMESTAMP,
+ start_use_time TIMESTAMP,
+ last_use_time TIMESTAMP,
+ real_table_use_seconds INT,
+ real_table_charge_money NUMERIC(18,2),
+ add_clock_seconds INT,
+ adjust_amount NUMERIC(18,2),
+ coupon_promotion_amount NUMERIC(18,2),
+ member_discount_amount NUMERIC(18,2),
+ used_card_amount NUMERIC(18,2),
+ mgmt_fee NUMERIC(18,2),
+ service_money NUMERIC(18,2),
+ fee_total NUMERIC(18,2),
+ is_single_order INT,
+ is_delete INT,
+ member_id BIGINT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ salesman_name TEXT,
+ salesman_org_id BIGINT,
+ salesman_user_id BIGINT,
+ create_time TIMESTAMP,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+
+COMMENT ON TABLE billiards_ods.table_fee_transactions IS '对应JSON字段:table_fee_transactions.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 table_fee_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.id IS '对应JSON字段:id,说明::台费流水记录主键(事实表主键)。,示例值及对应分析:?? table_fee_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID。本文件所有记录都属于同一租户。,示例值及对应分析:关联:与所有其它 JSON 中的 tenant_id 一致,用于跨表做“商户维度”的过滤。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.site_id IS '对应JSON字段:site_id,说明::门店 ID,本次数据全部来自同一门店(朗朗桌球)。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.siteProfile IS '对应JSON字段:siteProfile,说明::当前门店的完整档案快照,冗余到流水表中,便于报表直接读取而无需再联表门店档案。,示例值及对应分析:三、与其它 JSON 的结构关联关系(从字段层面)';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.site_table_id IS '对应JSON字段:site_table_id,说明::球台 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.site_table_area_id IS '对应JSON字段:site_table_area_id,说明::门店内“台桌区域” ID(站在门店物理布局的角度)。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.site_table_area_name IS '对应JSON字段:site_table_area_name,说明::台桌区域的名称,用于门店表现和区域统计。,示例值及对应分析:4. 会员维度与相关字段';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.tenant_table_area_id IS '对应JSON字段:tenant_table_area_id,说明::租户维度的台桌区域 ID(品牌层面的同一类区域)。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.order_trade_no IS '对应JSON字段:order_trade_no,说明::订单交易号,是整笔订单的主编号。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.order_pay_id IS '对应JSON字段:order_pay_id,说明::订单支付记录 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.order_settle_id IS '对应JSON字段:order_settle_id,说明::结算单号/结账 ID,对应一次结账操作。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_name IS '对应JSON字段:ledger_name,说明::台号名称,实际展示给员工/顾客看的桌台编号。,示例值及对应分析:备注:与 site_table_id 一一对应,是桌台维表中的名称字段冗余到流水里的快照。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_amount IS '对应JSON字段:ledger_amount,说明::按单价与计费时长计算出的原始应收台费金额。,示例值及对应分析:近似关系:ledger_amount ≈ ledger_unit_price × ledger_count / 3600,考虑到四舍五入会有小数差。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_count IS '对应JSON字段:ledger_count,说明::台账记录的计费秒数,计费用秒数(应收时长)。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_unit_price IS '对应JSON字段:ledger_unit_price,说明::台费结算时设置的 每小时单价/计费单价。,示例值及对应分析:用途:与 ledger_count 共同决定原始应收额。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_status IS '对应JSON字段:ledger_status,说明:(推测):,示例值及对应分析:1:正常已结算台费;';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_start_time IS '对应JSON字段:ledger_start_time,说明::台账上的计费起始时间。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_end_time IS '对应JSON字段:ledger_end_time,说明::台账上的计费结束时间。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.start_use_time IS '对应JSON字段:start_use_time,说明::台开始使用的时间(实际开台时间)。,示例值及对应分析:特点:在数据中,与 ledger_start_time 完全相同(见下)。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.last_use_time IS '对应JSON字段:last_use_time,说明::最后使用/操作时间。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.real_table_use_seconds IS '对应JSON字段:real_table_use_seconds,说明::实际使用的总秒数(系统真实统计的使用时长)。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.real_table_charge_money IS '对应JSON字段:real_table_charge_money,说明::台费中实际向顾客收取的金额(现金/实付维度,未含券方承担或内部调账的那一部分)。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.add_clock_seconds IS '对应JSON字段:add_clock_seconds,说明::加钟秒数,在原有使用基础上追加的时长。,示例值及对应分析:观测:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.adjust_amount IS '对应JSON字段:adjust_amount,说明::调整金额/调账金额,用于将台费金额转移或冲减到其它项目,或手工调整。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.coupon_promotion_amount IS '对应JSON字段:coupon_promotion_amount,说明::由优惠券/活动/团购(平台/门店促销)承担的优惠金额,直接抵扣在台费上。,示例值及对应分析:特点:当 real_table_charge_money = 0 且该字段为 ledger_amount 时,说明整笔台费是由券促销全额承担。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.member_discount_amount IS '对应JSON字段:member_discount_amount,说明:上文已说明,这里补充与金额的结构关系:,示例值及对应分析:功能:表示由会员折扣或会员权益承担的那部分金额。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.used_card_amount IS '对应JSON字段:used_card_amount,说明::由储值卡、次卡等“卡内余额”抵扣的金额。,示例值及对应分析:说明:字段设计已预留,但本段时间内台费没有通过储值卡扣款,或者卡扣款在其他表体现。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.mgmt_fee IS '对应JSON字段:mgmt_fee,说明:(推测):管理费字段,用于未来支持“台费附加管理费/服务费”的功能。,示例值及对应分析:当前未启用。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.service_money IS '对应JSON字段:service_money,说明:(推测):门店用于记录“服务费/成本/分成金额”的字段,类似助教流水里的 service_money。,示例值及对应分析:说明:当前门店未启用此字段结算台费。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.fee_total IS '对应JSON字段:fee_total,说明::各种附加费用(如管理费、服务费)合计值。,示例值及对应分析:说明:和 mgmt_fee 一样,目前作为预留字段,没有实际使用。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.is_single_order IS '对应JSON字段:is_single_order,说明:(推测):,示例值及对应分析:1:该台费记录对应的是一个独立计费单元(单独结算的桌费);';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志:,示例值及对应分析:0:未删除(有效记录);';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.member_id IS '对应JSON字段:member_id,说明::门店/租户内的会员 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.operator_id IS '对应JSON字段:operator_id,说明::操作员 ID,负责开台/结账的员工账号 ID。,示例值及对应分析:关联:与员工/账号体系中的用户 ID 对应(与助教账号的 user_id 属于同一种 ID 体系)。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.operator_name IS '对应JSON字段:operator_name,说明::操作员姓名(冗余字段),便于直接阅读,不必再联表员工档案。,示例值及对应分析:?? table_fee_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.salesman_name IS '对应JSON字段:salesman_name,说明::业务员/营业员姓名,如果台费有单独提成员工,这里记录归属人。,示例值及对应分析:当前门店未启用该字段做提成归属。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.salesman_org_id IS '对应JSON字段:salesman_org_id,说明::营业员所属机构/部门 ID。,示例值及对应分析:8. 状态 / 标记类字段';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.salesman_user_id IS '对应JSON字段:salesman_user_id,说明::营业员的用户 ID(与 salesman_name 搭配)。,示例值及对应分析:?? table_fee_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.create_time IS '对应JSON字段:create_time,说明::这条台费流水记录的创建时间,通常接近结账时间。,示例值及对应分析:?? table_fee_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.goods_stock_movements (
+ siteGoodsStockId BIGINT PRIMARY KEY,
+ tenantId BIGINT,
+ siteId BIGINT,
+ siteGoodsId BIGINT,
+ goodsName TEXT,
+ goodsCategoryId BIGINT,
+ goodsSecondCategoryId BIGINT,
+ unit TEXT,
+ price NUMERIC(18,4),
+ stockType INT,
+ changeNum NUMERIC(18,4),
+ startNum NUMERIC(18,4),
+ endNum NUMERIC(18,4),
+ changeNumA NUMERIC(18,4),
+ startNumA NUMERIC(18,4),
+ endNumA NUMERIC(18,4),
+ remark TEXT,
+ operatorName TEXT,
+ createTime TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.goods_stock_movements IS '对应JSON字段:goods_stock_movements.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 goods_stock_movements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.siteGoodsStockId IS '对应JSON字段:siteGoodsStockId,说明::门店某个“商品库存记录”的主键 ID。,示例值及对应分析:特点:每条库存变动记录对应一个 siteGoodsStockId,同一个商品可能在不同库存记录中出现(例如不同仓位或不同批次)。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.tenantId IS '对应JSON字段:tenantId,说明::租户/品牌 ID。,示例值及对应分析:观测:全部记录相同值,说明属于同一商户。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.siteId IS '对应JSON字段:siteId,说明::门店 ID。,示例值及对应分析:观测:本文件中所有记录的 siteId 都相同,对应“朗朗桌球”这家门店。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.siteGoodsId IS '对应JSON字段:siteGoodsId,说明::门店维度的商品 ID。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.goodsName IS '对应JSON字段:goodsName,说明::商品名称。,示例值及对应分析:示例值:';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.goodsCategoryId IS '对应JSON字段:goodsCategoryId,说明::商品一级分类 ID。,示例值及对应分析:观测:当前 100 条样本中约有 5 个不同 ID,对应如“酒水类”“食品小吃类”“香烟类”等大类(仅从命名与商品名推断)。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.goodsSecondCategoryId IS '对应JSON字段:goodsSecondCategoryId,说明::商品二级分类 ID。,示例值及对应分析:观测:样本中约有 7 个不同 ID,如饮料中的“矿泉水/功能饮料/碳酸饮料”等。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.unit IS '对应JSON字段:unit,说明::库存计量单位。,示例值及对应分析:说明:库存数量(startNum、endNum、changeNum)均以这里的单位计数。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.price IS '对应JSON字段:price,说明::商品单价(单位金额)。,示例值及对应分析:观测特征:';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.stockType IS '对应JSON字段:stockType,说明:(基于数据行为推断):,示例值及对应分析:1:出库类变动 典型情况是销售出库,库存减少 1 或 2;例如顾客点了一瓶饮料,对应一条 stockType=1, changeNum=-1 的记录。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.changeNum IS '对应JSON字段:changeNum,说明::本次库存数量变化值。,示例值及对应分析:特点及取值:';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.startNum IS '对应JSON字段:startNum,说明::变动前(这次出入库之前)的库存数量。,示例值及对应分析:示例: 如记录:startNum = 28, changeNum = -1, endNum = 27。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.endNum IS '对应JSON字段:endNum,说明::变动后(出入库之后)的库存数量。,示例值及对应分析:结构关系:';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.changeNumA IS '对应JSON字段:changeNumA,说明::辅助单位的变化量(与 changeNum 对应的第二计量单位变化),当前未使用。,示例值及对应分析:结论: startNumA / endNumA / changeNumA 是为“一个商品有两种计量单位(如箱与瓶)”而设计的预留字段。 目前门店只在单一单位层面管理库存,故全部为 0。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.startNumA IS '对应JSON字段:startNumA,说明:(推测):辅助计量单位的起始库存(例如件/箱等第二单位)。,示例值及对应分析:当前门店在样本时间段内没有启用多单位库存管理,因此全部为 0。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.endNumA IS '对应JSON字段:endNumA,说明::辅助单位的变动后库存,同样未启用。,示例值及对应分析:?? goods_stock_movements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.remark IS '对应JSON字段:remark,说明::备注信息,用于手工记录本次变更的特殊原因说明(例如“盘点差异调整”“报损”)。,示例值及对应分析:当前样本中没有填入任何备注,但字段已预留,适用于盘点或手工调整场景。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.operatorName IS '对应JSON字段:operatorName,说明::执行此次库存变动的操作人。,示例值及对应分析:观测值:';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.createTime IS '对应JSON字段:createTime,说明::这条库存变动记录的创建时间,即发生库存变更的时间点。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.stock_goods_category_tree (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ category_name TEXT,
+ alias_name TEXT,
+ pid BIGINT,
+ business_name TEXT,
+ tenant_goods_business_id BIGINT,
+ open_salesman INT,
+ categoryBoxes JSONB,
+ sort INT,
+ is_warehousing INT,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.stock_goods_category_tree IS '对应JSON字段:stock_goods_category_tree.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.id IS '对应JSON字段:id,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.tenant_id IS '对应JSON字段:tenant_id,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.category_name IS '对应JSON字段:category_name,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.alias_name IS '对应JSON字段:alias_name,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.pid IS '对应JSON字段:pid,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.business_name IS '对应JSON字段:business_name,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.tenant_goods_business_id IS '对应JSON字段:tenant_goods_business_id,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.open_salesman IS '对应JSON字段:open_salesman,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.categoryBoxes IS '对应JSON字段:categoryBoxes,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.sort IS '对应JSON字段:sort,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.is_warehousing IS '对应JSON字段:is_warehousing,说明::分类节点主键 ID(在商品分类维度中的唯一标识)。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.goods_stock_summary (
+ siteGoodsId BIGINT PRIMARY KEY,
+ goodsName TEXT,
+ goodsUnit TEXT,
+ goodsCategoryId BIGINT,
+ goodsCategorySecondId BIGINT,
+ categoryName TEXT,
+ rangeStartStock NUMERIC(18,4),
+ rangeEndStock NUMERIC(18,4),
+ rangeIn NUMERIC(18,4),
+ rangeOut NUMERIC(18,4),
+ rangeSale NUMERIC(18,4),
+ rangeSaleMoney NUMERIC(18,2),
+ rangeInventory NUMERIC(18,4),
+ currentStock NUMERIC(18,4),
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.goods_stock_summary IS '对应JSON字段:goods_stock_summary.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.siteGoodsId IS '对应JSON字段:siteGoodsId,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.goodsName IS '对应JSON字段:goodsName,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.goodsUnit IS '对应JSON字段:goodsUnit,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.goodsCategoryId IS '对应JSON字段:goodsCategoryId,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.goodsCategorySecondId IS '对应JSON字段:goodsCategorySecondId,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.categoryName IS '对应JSON字段:categoryName,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeStartStock IS '对应JSON字段:rangeStartStock,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeEndStock IS '对应JSON字段:rangeEndStock,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeIn IS '对应JSON字段:rangeIn,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeOut IS '对应JSON字段:rangeOut,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeSale IS '对应JSON字段:rangeSale,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeSaleMoney IS '对应JSON字段:rangeSaleMoney,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeInventory IS '对应JSON字段:rangeInventory,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.currentStock IS '对应JSON字段:currentStock,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.payment_transactions (
+ id BIGINT PRIMARY KEY,
+ site_id BIGINT,
+ siteProfile JSONB,
+ relate_type INT,
+ relate_id BIGINT,
+ pay_amount NUMERIC(18,2),
+ pay_status INT,
+ pay_time TIMESTAMP,
+ create_time TIMESTAMP,
+ payment_method INT,
+ online_pay_channel INT,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.payment_transactions IS '对应JSON字段:payment_transactions.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.id IS '对应JSON字段:id,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.site_id IS '对应JSON字段:site_id,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.siteProfile IS '对应JSON字段:siteProfile,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.relate_type IS '对应JSON字段:relate_type,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.relate_id IS '对应JSON字段:relate_id,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.pay_amount IS '对应JSON字段:pay_amount,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.pay_status IS '对应JSON字段:pay_status,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.pay_time IS '对应JSON字段:pay_time,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.create_time IS '对应JSON字段:create_time,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.payment_method IS '对应JSON字段:payment_method,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.online_pay_channel IS '对应JSON字段:online_pay_channel,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.payment_transactions.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.payment_transactions.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.payment_transactions.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.refund_transactions (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ tenantName TEXT,
+ site_id BIGINT,
+ siteProfile JSONB,
+ relate_type INT,
+ relate_id BIGINT,
+ pay_sn TEXT,
+ pay_amount NUMERIC(18,2),
+ refund_amount NUMERIC(18,2),
+ round_amount NUMERIC(18,2),
+ pay_status INT,
+ pay_time TIMESTAMP,
+ create_time TIMESTAMP,
+ payment_method INT,
+ pay_terminal INT,
+ pay_config_id BIGINT,
+ online_pay_channel INT,
+ online_pay_type INT,
+ channel_fee NUMERIC(18,2),
+ channel_payer_id TEXT,
+ channel_pay_no TEXT,
+ member_id BIGINT,
+ member_card_id BIGINT,
+ cashier_point_id BIGINT,
+ operator_id BIGINT,
+ action_type INT,
+ check_status INT,
+ is_revoke INT,
+ is_delete INT,
+ balance_frozen_amount NUMERIC(18,2),
+ card_frozen_amount NUMERIC(18,2),
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.refund_transactions IS '对应JSON字段:refund_transactions.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 refund_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.refund_transactions.id IS '对应JSON字段:id,说明::本条 退款流水 的唯一 ID。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID,全系统维度标识该商户。,示例值及对应分析:特点:本文件中所有记录相同。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.tenantName IS '对应JSON字段:tenantName,说明::租户(商户)名称。,示例值及对应分析:特点:本文件中固定为“朗朗桌球”,完全冗余于 siteProfile.shop_name。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.site_id IS '对应JSON字段:site_id,说明::门店 ID。,示例值及对应分析:特点:本文件中所有记录相同(单门店)。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.siteProfile IS '对应JSON字段:siteProfile,说明::门店信息快照,结构与其他 JSON 中的 siteProfile 完全一致。包含字段包括但不限于:,示例值及对应分析:id:门店 ID(= site_id);';
+COMMENT ON COLUMN billiards_ods.refund_transactions.relate_type IS '对应JSON字段:relate_type,说明::本退款对应的“业务类型”。,示例值及对应分析:结合支付记录的 relate_type 推测:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.relate_id IS '对应JSON字段:relate_id,说明::本次退款关联的业务 ID。,示例值及对应分析:对于 relate_type = 2:应该对应某个订单/结算的主键;';
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_sn IS '对应JSON字段:pay_sn,说明:?????? refund_transactions-Analysis.md,示例值及对应分析:?? refund_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_amount IS '对应JSON字段:pay_amount,说明::本次退款的 资金变动金额。,示例值及对应分析:特征很重要:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.refund_amount IS '对应JSON字段:refund_amount,说明:(推测):,示例值及对应分析:设计上本应显示“实际退款金额”(正数),与 pay_amount 配合使用;';
+COMMENT ON COLUMN billiards_ods.refund_transactions.round_amount IS '对应JSON字段:round_amount,说明:(推测):,示例值及对应分析:舍入金额/抹零金额;';
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_status IS '对应JSON字段:pay_status,说明:(推测):,示例值及对应分析:支付/退款状态枚举:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_time IS '对应JSON字段:pay_time,说明::退款在支付渠道层面实际发生的时间。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.create_time IS '对应JSON字段:create_time,说明::本条退款流水在系统内创建时间。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.payment_method IS '对应JSON字段:payment_method,说明:(推测):,示例值及对应分析:支付/退款的 方式类型:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_terminal IS '对应JSON字段:pay_terminal,说明:(推测):,示例值及对应分析:退款所使用的 终端类型:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_config_id IS '对应JSON字段:pay_config_id,说明:(推测):,示例值及对应分析:支付配置 ID,例如商户在“非球科技”内配置的某一条支付通道(某个微信商户号、银联通道)的主键。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.online_pay_channel IS '对应JSON字段:online_pay_channel,说明:(推测):,示例值及对应分析:线上支付的 渠道编号,例如:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.online_pay_type IS '对应JSON字段:online_pay_type,说明:(推测):,示例值及对应分析:在线退款的类型:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.channel_fee IS '对应JSON字段:channel_fee,说明:(推测):,示例值及对应分析:第三方支付渠道对本次退款收取的手续费;';
+COMMENT ON COLUMN billiards_ods.refund_transactions.channel_payer_id IS '对应JSON字段:channel_payer_id,说明:(推测):,示例值及对应分析:支付渠道侧的 payer ID,例如微信 openid、银行卡号掩码等。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.channel_pay_no IS '对应JSON字段:channel_pay_no,说明:(推测):,示例值及对应分析:第三方支付平台的交易号(如微信支付单号、支付宝交易号等)。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.member_id IS '对应JSON字段:member_id,说明::,示例值及对应分析:租户内部的会员 ID(对应会员档案中的某个主键)。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.member_card_id IS '对应JSON字段:member_card_id,说明::,示例值及对应分析:关联的会员卡账户 ID(对应“储值卡列表”或“会员档案”中的某一张卡)。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.cashier_point_id IS '对应JSON字段:cashier_point_id,说明:(推测):,示例值及对应分析:收银点 ID,例如前台 1、前台 2、自助机等。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.operator_id IS '对应JSON字段:operator_id,说明::,示例值及对应分析:执行该退款操作的操作员 ID。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.action_type IS '对应JSON字段:action_type,说明:(推测):,示例值及对应分析:行为类型:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.check_status IS '对应JSON字段:check_status,说明:(推测):,示例值及对应分析:审核状态:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.is_revoke IS '对应JSON字段:is_revoke,说明:(推测):,示例值及对应分析:是否撤销型退款/撤销原支付:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志。,示例值及对应分析:0:未删除;';
+COMMENT ON COLUMN billiards_ods.refund_transactions.balance_frozen_amount IS '对应JSON字段:balance_frozen_amount,说明:(推测):,示例值及对应分析:涉及会员储值卡退款时,暂时冻结的余额金额;';
+COMMENT ON COLUMN billiards_ods.refund_transactions.card_frozen_amount IS '对应JSON字段:card_frozen_amount,说明::与上一个类似,偏向“某张卡的被冻结金额”,也与会员卡/储值账户相关。,示例值及对应分析:状态同上:本数据中未发生“卡冻结退款”。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.refund_transactions.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.refund_transactions.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.refund_transactions.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.platform_coupon_redemption_records (
+ id BIGINT PRIMARY KEY,
+ verify_id BIGINT,
+ certificate_id TEXT,
+ coupon_code TEXT,
+ coupon_name TEXT,
+ coupon_channel INT,
+ groupon_type INT,
+ group_package_id BIGINT,
+ sale_price NUMERIC(18,2),
+ coupon_money NUMERIC(18,2),
+ coupon_free_time NUMERIC(18,2),
+ coupon_cover TEXT,
+ coupon_remark TEXT,
+ use_status INT,
+ consume_time TIMESTAMP,
+ create_time TIMESTAMP,
+ deal_id TEXT,
+ channel_deal_id TEXT,
+ site_id BIGINT,
+ site_order_id BIGINT,
+ table_id BIGINT,
+ tenant_id BIGINT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ is_delete INT,
+ siteProfile JSONB,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.platform_coupon_redemption_records IS '对应JSON字段:platform_coupon_redemption_records.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.id IS '对应JSON字段:id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.verify_id IS '对应JSON字段:verify_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.certificate_id IS '对应JSON字段:certificate_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_code IS '对应JSON字段:coupon_code,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_name IS '对应JSON字段:coupon_name,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_channel IS '对应JSON字段:coupon_channel,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.groupon_type IS '对应JSON字段:groupon_type,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.group_package_id IS '对应JSON字段:group_package_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.sale_price IS '对应JSON字段:sale_price,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_money IS '对应JSON字段:coupon_money,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_free_time IS '对应JSON字段:coupon_free_time,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_cover IS '对应JSON字段:coupon_cover,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_remark IS '对应JSON字段:coupon_remark,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.use_status IS '对应JSON字段:use_status,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.consume_time IS '对应JSON字段:consume_time,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.create_time IS '对应JSON字段:create_time,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.deal_id IS '对应JSON字段:deal_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.channel_deal_id IS '对应JSON字段:channel_deal_id,说明:任意一个 ID 字段缺失时(如部分记录 deal_id=0),仍然可以通过其他字段(coupon_name + sale_price + coupon_money + channel_deal_id)唯一识别该产品。,示例值及对应分析:这种多字段冗余,结构上提升了抗“配置缺失”的能力。';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.site_id IS '对应JSON字段:site_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.site_order_id IS '对应JSON字段:site_order_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.table_id IS '对应JSON字段:table_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.tenant_id IS '对应JSON字段:tenant_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.operator_id IS '对应JSON字段:operator_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.operator_name IS '对应JSON字段:operator_name,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.is_delete IS '对应JSON字段:is_delete,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.siteProfile IS '对应JSON字段:siteProfile,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.tenant_goods_master (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ goods_name TEXT,
+ goods_bar_code TEXT,
+ goods_category_id BIGINT,
+ goods_second_category_id BIGINT,
+ categoryName TEXT,
+ unit TEXT,
+ goods_number TEXT,
+ goods_state INT,
+ sale_channel INT,
+ able_discount INT,
+ able_site_transfer INT,
+ is_delete INT,
+ is_warehousing INT,
+ isInSite INT,
+ cost_price NUMERIC(18,4),
+ cost_price_type INT,
+ market_price NUMERIC(18,4),
+ min_discount_price NUMERIC(18,4),
+ common_sale_royalty NUMERIC(18,4),
+ point_sale_royalty NUMERIC(18,4),
+ pinyin_initial TEXT,
+ commodityCode TEXT,
+ commodity_code TEXT,
+ goods_cover TEXT,
+ supplier_id BIGINT,
+ remark_name TEXT,
+ create_time TIMESTAMP,
+ update_time TIMESTAMP,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+
+COMMENT ON TABLE billiards_ods.tenant_goods_master IS '对应JSON字段:tenant_goods_master.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 tenant_goods_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.id IS '对应JSON字段:id,说明::商品档案主键 ID,唯一标识一条商品。,示例值及对应分析:作用:作为其他业务表(销售明细、库存流水、门店商品表等)的外键,通常以 tenant_goods_id 或类似字段出现。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID。,示例值及对应分析:作用:和其它 JSON 中的 tenant_id / tenantId 一致,用于区分不同商户(本次数据只包含同一租户)。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_name IS '对应JSON字段:goods_name,说明::商品名称(前台展示名称)。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_bar_code IS '对应JSON字段:goods_bar_code,说明::商品条码(EAN 等),目前未维护。,示例值及对应分析:说明:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_category_id IS '对应JSON字段:goods_category_id,说明::商品一级分类 ID。,示例值及对应分析:取值情况:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_second_category_id IS '对应JSON字段:goods_second_category_id,说明::商品二级分类 ID。,示例值及对应分析:取值情况:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.categoryName IS '对应JSON字段:categoryName,说明::商品一级分类名称(业务可读)。,示例值及对应分析:取值情况:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.unit IS '对应JSON字段:unit,说明::计量单位。,示例值及对应分析:取值(共 12 种左右):';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_number IS '对应JSON字段:goods_number,说明::商品内部编码(自定义货号/系统货号)。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_state IS '对应JSON字段:goods_state,说明:(推测):商品状态(上架/下架等)。,示例值及对应分析:1:正常/上架;';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.sale_channel IS '对应JSON字段:sale_channel,说明:(推测):销售渠道类型,如“门店堂食/线下零售/线上小程序”等的一种编码。,示例值及对应分析:现有数据只有一个值,说明本门店目前仅通过一种渠道销售这些商品。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.able_discount IS '对应JSON字段:able_discount,说明:(推测):是否允许参与折扣/打折。,示例值及对应分析:1:允许折扣;';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.able_site_transfer IS '对应JSON字段:able_site_transfer,说明:(推测):,示例值及对应分析:字面意思是“是否允许门店间调拨/门店级操作”:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志。,示例值及对应分析:0:未删除(有效商品);';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.is_warehousing IS '对应JSON字段:is_warehousing,说明:(推测):是否启用库存管理。,示例值及对应分析:1:该商品纳入库存管理;';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.isInSite IS '对应JSON字段:isInSite,说明:(从命名推测):是否在当前门店启用/上架。,示例值及对应分析:现象:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.cost_price IS '对应JSON字段:cost_price,说明::成本价格。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.cost_price_type IS '对应JSON字段:cost_price_type,说明:(推测):,示例值及对应分析:不同的成本价格来源或计算方式,如:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.market_price IS '对应JSON字段:market_price,说明::商品标价 / 售价(标准销售单价)。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.min_discount_price IS '对应JSON字段:min_discount_price,说明::该商品允许售卖的最低价格(底价)。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.common_sale_royalty IS '对应JSON字段:common_sale_royalty,说明:(推测):普通销售提成比例或提成金额的配置字段。,示例值及对应分析:当前门店未在商品档案上配置员工提成规则,全部为 0。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.point_sale_royalty IS '对应JSON字段:point_sale_royalty,说明:(推测):积分销售提成/积分赠送规则相关配置。,示例值及对应分析:当前同样未启用。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.pinyin_initial IS '对应JSON字段:pinyin_initial,说明::拼音首字母/助记码。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.commodityCode IS '对应JSON字段:commodityCode,说明::,示例值及对应分析:与 commodity_code 是同一信息的数组形式(冗余存储),便于支持一个商品对应多个编码的场景。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.commodity_code IS '对应JSON字段:commodity_code,说明::商品编码(通常为对外商品编码或条码)。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_cover IS '对应JSON字段:goods_cover,说明::商品封面图片 URL 地址。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.supplier_id IS '对应JSON字段:supplier_id,说明::供应商 ID,用于关联到供应商档案。,示例值及对应分析:当前所有商品都未挂接具体供应商(或门店未使用供应链管理模块)。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.remark_name IS '对应JSON字段:remark_name,说明:(从命名推断):商品备注名/别名,通常用来配置简写或特殊显示名称。,示例值及对应分析:当前门店尚未使用该字段,字段设计为将来扩展预留。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.create_time IS '对应JSON字段:create_time,说明::商品档案创建时间。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.update_time IS '对应JSON字段:update_time,说明::商品档案最近一次修改时间。,示例值及对应分析:分布:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.group_buy_packages (
+ id BIGINT PRIMARY KEY,
+ package_id BIGINT,
+ package_name TEXT,
+ selling_price NUMERIC(18,2),
+ coupon_money NUMERIC(18,2),
+ date_type INT,
+ date_info TEXT,
+ start_time TIMESTAMP,
+ end_time TIMESTAMP,
+ start_clock TEXT,
+ end_clock TEXT,
+ add_start_clock TEXT,
+ add_end_clock TEXT,
+ duration INT,
+ usable_count INT,
+ usable_range INT,
+ table_area_id BIGINT,
+ table_area_name TEXT,
+ table_area_id_list JSONB,
+ tenant_table_area_id BIGINT,
+ tenant_table_area_id_list JSONB,
+ site_id BIGINT,
+ site_name TEXT,
+ tenant_id BIGINT,
+ card_type_ids JSONB,
+ group_type INT,
+ system_group_type INT,
+ type INT,
+ effective_status INT,
+ is_enabled INT,
+ is_delete INT,
+ max_selectable_categories INT,
+ area_tag_type INT,
+ creator_name TEXT,
+ create_time TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.group_buy_packages IS '对应JSON字段:group_buy_packages.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 group_buy_packages-Analysis.md';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.id IS '对应JSON字段:id,说明::门店侧套餐 ID,本文件内部的主键。,示例值及对应分析:特点:17 条记录中均为不同的大整数 ID。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.package_id IS '对应JSON字段:package_id,说明::“上层套餐 ID” 或“总部/系统级套餐 ID”。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.package_name IS '对应JSON字段:package_name,说明::团购套餐名称,用于前台展示和核销界面。,示例值及对应分析:示例:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.selling_price IS '对应JSON字段:selling_price,说明:(结合字段命名):,示例值及对应分析:语义上应该是“团购售卖价”(顾客在平台购买券时的成交价格)。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.coupon_money IS '对应JSON字段:coupon_money,说明::券面值或内部结算面值,表示该套餐在门店侧对应的金额额度。,示例值及对应分析:示例(对应套餐名称):';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.date_type IS '对应JSON字段:date_type,说明:(推测):,示例值及对应分析:典型用法:区分“全部日期可用 / 工作日 / 周末 / 指定日期”等。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.date_info IS '对应JSON字段:date_info,说明:(推测):,示例值及对应分析:预留字段,通常用来存储更细粒度的日期信息,如具体日期列表、节假日特殊规则(可能是 JSON 字符串或编码)。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.start_time IS '对应JSON字段:start_time,说明::套餐开始生效的日期时间。,示例值及对应分析:示例:"2025-07-20 00:00:00" 等。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.end_time IS '对应JSON字段:end_time,说明::套餐失效的日期时间(到这个时间点后不可使用)。,示例值及对应分析:示例:形如 "2025-11-30 23:59:59",部分记录使用 9999-12-31 23:59:59 风格的极大日期表示长期有效(本数据中如有这种值,可解读为“长期有效”)。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.start_clock IS '对应JSON字段:start_clock,说明::每日可用起始时间点(第一段)。,示例值及对应分析:说明:配合 end_clock 使用,定义一个日内时段。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.end_clock IS '对应JSON字段:end_clock,说明::每日可用的结束时间点(第一段)。,示例值及对应分析:结构说明:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.add_start_clock IS '对应JSON字段:add_start_clock,说明:(推测):附加可用时间段的起始时间(第二段)。,示例值及对应分析:例如有的套餐可以在两个不连续的时段使用:早场 + 夜场,则可用第一段 start_clock / end_clock 和第二段 add_start_clock / add_end_clock 组合。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.add_end_clock IS '对应JSON字段:add_end_clock,说明::附加时段结束时间,多数情况配合 "00:00:00" 或 "10:00:00" 使用。,示例值及对应分析:整体理解:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.duration IS '对应JSON字段:duration,说明::套餐内包含的时长(秒)。,示例值及对应分析:与名称一致:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.usable_count IS '对应JSON字段:usable_count,说明::可使用次数上限。,示例值及对应分析:数据特征说明:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.usable_range IS '对应JSON字段:usable_range,说明:吻合(A区中八/B区中八/斯诺克/KTV/包厢等)。,示例值及对应分析:通过该关联,系统在核销时可以校验:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.table_area_id IS '对应JSON字段:table_area_id,说明:(推测):,示例值及对应分析:原始设计应为“单一台区 ID”,当套餐只限一个区域可以用这个字段存储。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.table_area_name IS '对应JSON字段:table_area_name,说明::套餐适用的“门店台区名称”,用于显示和筛选。,示例值及对应分析:说明:这个字段是对区域 ID 维度的文字描述,便于直观理解。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.table_area_id_list IS '对应JSON字段:table_area_id_list,说明:(推测):,示例值及对应分析:用来存放具体台区 ID 列表(例如 "1,2,3"),实现更细粒度的台桌限制。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.tenant_table_area_id IS '对应JSON字段:tenant_table_area_id,说明:(推测):,示例值及对应分析:与 table_area_id 类似,是租户层级的台区 ID,原本用于单区选择。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.tenant_table_area_id_list IS '对应JSON字段:tenant_table_area_id_list,说明:(推测):,示例值及对应分析:实际代表“台区集合 ID”或“租户台区配置 ID”,用来限制套餐可用的台区范围。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.site_id IS '对应JSON字段:site_id,说明::门店 ID。,示例值及对应分析:特点:全表值相同,且与其他 JSON 文件中的 site_id 一致,对应“朗朗桌球”这家门店。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.site_name IS '对应JSON字段:site_name,说明::门店名称。,示例值及对应分析:观测值:全部为 "朗朗桌球"。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.tenant_id IS '对应JSON字段:tenant_id,说明::租户 ID(品牌/商户 ID)。,示例值及对应分析:特点:全表值相同,说明所有套餐定义属于同一商户(同一品牌)。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.card_type_ids IS '对应JSON字段:card_type_ids,说明:(推测):,示例值及对应分析:原意是“适用会员卡类型 ID 列表”,例如某套餐只允许某几种会员卡使用,可以在此配置。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.group_type IS '对应JSON字段:group_type,说明:(推测):,示例值及对应分析:团购类型,例如:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.system_group_type IS '对应JSON字段:system_group_type,说明:(推测):,示例值及对应分析:系统内对团购类型更底层的划分,比如:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.type IS '对应JSON字段:type,说明:(推测):,示例值及对应分析:内部业务子类型,具体含义需要结合系统文档;仅从数据无法确定是“台费类 vs 包厢类”还是“平台套餐 vs 自定义套餐”。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.effective_status IS '对应JSON字段:effective_status,说明:(结合命名和数据特征推断):,示例值及对应分析:1:有效(在当前时间区间内、配置正常,可核销使用)。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.is_enabled IS '对应JSON字段:is_enabled,说明::启用状态。,示例值及对应分析:从其他表的统一风格来看,1 一般表示“启用 / 上架”,2 表示“停用 / 下架”。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志。,示例值及对应分析:0:正常;';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.max_selectable_categories IS '对应JSON字段:max_selectable_categories,说明:?????? group_buy_packages-Analysis.md,示例值及对应分析:?? group_buy_packages-Analysis.md';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.area_tag_type IS '对应JSON字段:area_tag_type,说明:(推测):区域标记类型:,示例值及对应分析:1 很可能代表“按台区标签限制”,例如 A区、中八区、包厢、KTV 等。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.creator_name IS '对应JSON字段:creator_name,说明::创建人信息,一般包含“角色:姓名”。,示例值及对应分析:示例:"管理员:郑丽珊"';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.create_time IS '对应JSON字段:create_time,说明::该套餐在系统中创建的时间。,示例值及对应分析:特点:每条记录各不相同,覆盖了 2025-07 至 2025-10 的创建时间。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.group_buy_redemption_records (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ siteName TEXT,
+ table_id BIGINT,
+ tableName TEXT,
+ tableAreaName TEXT,
+ tenant_table_area_id BIGINT,
+ order_trade_no TEXT,
+ order_settle_id BIGINT,
+ order_pay_id BIGINT,
+ order_coupon_id BIGINT,
+ order_coupon_channel INT,
+ coupon_code TEXT,
+ coupon_money NUMERIC(18,2),
+ coupon_origin_id BIGINT,
+ ledger_name TEXT,
+ ledger_group_name TEXT,
+ ledger_amount NUMERIC(18,2),
+ ledger_count NUMERIC(18,4),
+ ledger_unit_price NUMERIC(18,4),
+ ledger_status INT,
+ table_charge_seconds INT,
+ promotion_activity_id BIGINT,
+ promotion_coupon_id BIGINT,
+ promotion_seconds INT,
+ offer_type INT,
+ assistant_promotion_money NUMERIC(18,2),
+ assistant_service_promotion_money NUMERIC(18,2),
+ table_service_promotion_money NUMERIC(18,2),
+ goods_promotion_money NUMERIC(18,2),
+ recharge_promotion_money NUMERIC(18,2),
+ reward_promotion_money NUMERIC(18,2),
+ goodsOptionPrice NUMERIC(18,2),
+ salesman_name TEXT,
+ sales_man_org_id BIGINT,
+ salesman_role_id BIGINT,
+ salesman_user_id BIGINT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ is_single_order INT,
+ is_delete INT,
+ create_time TIMESTAMP,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+
+COMMENT ON TABLE billiards_ods.group_buy_redemption_records IS '对应JSON字段:group_buy_redemption_records.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 group_buy_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.id IS '对应JSON字段:id,说明::本条“团购套餐流水”记录的 主键 ID。,示例值及对应分析:作用:唯一标识一条券使用到台费上的记录。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID。,示例值及对应分析:特点:全表值相同,说明所有记录属于同一租户。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.site_id IS '对应JSON字段:site_id,说明::门店 ID,与其它 JSON 中一致。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.siteName IS '对应JSON字段:siteName,说明::门店名称,冗余展示用。,示例值及对应分析:?? group_buy_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.table_id IS '对应JSON字段:table_id,说明::球台 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.tableName IS '对应JSON字段:tableName,说明::本次使用券所关联的 球台名称/台号。,示例值及对应分析:关联:对应台桌列表中的 table_name / table_no,通过 table_id 进一步关联。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.tableAreaName IS '对应JSON字段:tableAreaName,说明::该球台所属的 台区名称。,示例值及对应分析:关联:与台区配置中的 area_name 含义一致,与团购套餐定义中的 table_area_name 一致。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.tenant_table_area_id IS '对应JSON字段:tenant_table_area_id,说明::租户级台区分组 ID,表示当前使用券的台桌所属的区域组合。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.order_trade_no IS '对应JSON字段:order_trade_no,说明::订单交易号,和其它消费明细(台费、商品、助教、团购)共用的订单主键。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.order_settle_id IS '对应JSON字段:order_settle_id,说明::结算单 ID(小票结账主键)。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.order_pay_id IS '对应JSON字段:order_pay_id,说明:(推测):,示例值及对应分析:指向支付记录表中的支付流水 ID。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.order_coupon_id IS '对应JSON字段:order_coupon_id,说明::订单中“券使用记录”的 ID。,示例值及对应分析:结构特点:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.order_coupon_channel IS '对应JSON字段:order_coupon_channel,说明:(推测):,示例值及对应分析:券渠道类型,例如:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.coupon_code IS '对应JSON字段:coupon_code,说明::团购券券码,核销时扫描/录入的字符串。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.coupon_money IS '对应JSON字段:coupon_money,说明::本次核销时,这张券在门店侧对应的金额额度(“可抵扣金额”)。,示例值及对应分析:结构关系:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.coupon_origin_id IS '对应JSON字段:coupon_origin_id,说明:(推测):,示例值及对应分析:平台/上游系统中的券记录主键 ID,“券来源 ID”。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.ledger_name IS '对应JSON字段:ledger_name,说明::台费侧关联的“团购项目名称”(记账名)。,示例值及对应分析:结构上通常来源于团购套餐定义的 package_name,或由系统在创建活动时生成。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.ledger_group_name IS '对应JSON字段:ledger_group_name,说明:(推测):团购项目所属的“记账分组名称”(例如“团购台费”“团购包厢”等)。,示例值及对应分析:当前门店未对团购项目做进一步分组。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.ledger_amount IS '对应JSON字段:ledger_amount,说明::本次券实际冲抵台费的金额。,示例值及对应分析:结构关系:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.ledger_count IS '对应JSON字段:ledger_count,说明::按此次优惠实际计算的“核销秒数”。,示例值及对应分析:结构观察:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.ledger_unit_price IS '对应JSON字段:ledger_unit_price,说明::对应台费的标准单价,单位元/小时(从数值来看是类似29.9/小时这种定价)。,示例值及对应分析:作用:配合 ledger_count 用于计算这一条券在台费层面对应的金额(理论上应接近 = 单价 × 秒数/3600)。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.ledger_status IS '对应JSON字段:ledger_status,说明:(推测):流水状态。,示例值及对应分析:1:正常有效;';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.table_charge_seconds IS '对应JSON字段:table_charge_seconds,说明::本次结算中该球台总计计费的秒数(整台的台费计费时间)。,示例值及对应分析:结构特点:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.promotion_activity_id IS '对应JSON字段:promotion_activity_id,说明:(推测):团购/促销活动 ID。,示例值及对应分析:对应平台或内部促销活动的主键,每个活动通常绑定一个或多个具体套餐(promotion_coupon_id)。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.promotion_coupon_id IS '对应JSON字段:promotion_coupon_id,说明::团购套餐定义 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.promotion_seconds IS '对应JSON字段:promotion_seconds,说明::团购套餐定义的“标准时长”(券本身标称的可用时长)。,示例值及对应分析:结构关系:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.offer_type IS '对应JSON字段:offer_type,说明:(推测):优惠类型。,示例值及对应分析:在券适用多个优惠方式的系统中,一般用来区分“满减/折扣/代金券/套餐券”等。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.assistant_promotion_money IS '对应JSON字段:assistant_promotion_money,说明::分摊到“助教服务”的促销金额。,示例值及对应分析:当前场景下,团购券只与台费相关,未涉及助教的金额抵扣。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.assistant_service_promotion_money IS '对应JSON字段:assistant_service_promotion_money,说明::进一步细分助教服务的促销金额。,示例值及对应分析:当前未使用。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.table_service_promotion_money IS '对应JSON字段:table_service_promotion_money,说明::本次券使用中,分摊到“台费服务费”部分的促销金额。,示例值及对应分析:当前样本中,促销金额都在 ledger_amount 中体现,该字段未单独拆出。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.goods_promotion_money IS '对应JSON字段:goods_promotion_money,说明::本次券使用中,分摊到“商品”部分的促销金额。,示例值及对应分析:当前数据中,所有团购券都只用于抵扣台费,没有用来抵扣商品,因此该字段为 0。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.recharge_promotion_money IS '对应JSON字段:recharge_promotion_money,说明::来自“充值类优惠”的分摊金额(例如储值赠送部分)。,示例值及对应分析:当前所有数据为 0,但结构上已经预留了“多来源促销金额分摊”的能力。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.reward_promotion_money IS '对应JSON字段:reward_promotion_money,说明::本次促销中,属于“奖励金/积分抵扣”的金额。,示例值及对应分析:当前没有使用此维度的促销。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.goodsOptionPrice IS '对应JSON字段:goodsOptionPrice,说明:(按命名推测):商品规格价格,用于商品类促销分摊时使用。,示例值及对应分析:当前在“团购套餐流水”中未被实际使用。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.salesman_name IS '对应JSON字段:salesman_name,说明::营业员姓名。,示例值及对应分析:?? group_buy_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.sales_man_org_id IS '对应JSON字段:sales_man_org_id,说明::营业员所属组织 ID。,示例值及对应分析:以上 4 个销售相关字段在当前门店的团购套餐使用中都未启用,仅作为结构预留。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.salesman_role_id IS '对应JSON字段:salesman_role_id,说明::营业员角色 ID。,示例值及对应分析:?? group_buy_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.salesman_user_id IS '对应JSON字段:salesman_user_id,说明::营业员/业务员用户 ID。,示例值及对应分析:当前所有团购套餐流水都未指定独立的营业员。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.operator_id IS '对应JSON字段:operator_id,说明::执行本次核销/结算操作的 操作员 ID。,示例值及对应分析:关联:可以与员工档案表中的 id 对应(当前导出中员工表未单独给出,但风格和其它表一致)。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.operator_name IS '对应JSON字段:operator_name,说明::操作员名称(包含角色说明),与 operator_id 对应的冗余展示字段。,示例值及对应分析:?? group_buy_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.is_single_order IS '对应JSON字段:is_single_order,说明:(推测):是否单独作为一条订单行。,示例值及对应分析:1:以独立条目方式进行结算(绝大部分记录如此)。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志:,示例值及对应分析:0:正常;';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.create_time IS '对应JSON字段:create_time,说明::本条团购套餐使用流水创建时间(即券核销时间,或与结账时间接近)。,示例值及对应分析:用法:可用于按时间范围过滤团购使用记录。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.settlement_ticket_details (
+ orderSettleId BIGINT PRIMARY KEY,
+ actualPayment NUMERIC(18,2),
+ adjustAmount NUMERIC(18,2),
+ assistantManualDiscount NUMERIC(18,2),
+ balanceAmount NUMERIC(18,2),
+ cashierName TEXT,
+ consumeMoney NUMERIC(18,2),
+ couponAmount NUMERIC(18,2),
+ deliveryAddress TEXT,
+ deliveryFee NUMERIC(18,2),
+ ledgerAmount NUMERIC(18,2),
+ memberDeductAmount NUMERIC(18,2),
+ memberOfferAmount NUMERIC(18,2),
+ onlineReturnAmount NUMERIC(18,2),
+ orderRemark TEXT,
+ orderSettleNumber BIGINT,
+ payMemberBalance NUMERIC(18,2),
+ payTime TIMESTAMP,
+ paymentMethod INT,
+ pointDiscountCost NUMERIC(18,2),
+ pointDiscountPrice NUMERIC(18,2),
+ prepayMoney NUMERIC(18,2),
+ refundAmount NUMERIC(18,2),
+ returnGoodsAmount NUMERIC(18,2),
+ rewardName TEXT,
+ settleType TEXT,
+ siteAddress TEXT,
+ siteBusinessTel TEXT,
+ siteId BIGINT,
+ siteName TEXT,
+ tenantId BIGINT,
+ tenantName TEXT,
+ ticketCustomContent TEXT,
+ ticketRemark TEXT,
+ voucherMoney NUMERIC(18,2),
+ memberProfile JSONB,
+ orderItem JSONB,
+ tenantMemberCardLogs JSONB,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+
+COMMENT ON TABLE billiards_ods.settlement_ticket_details IS '对应JSON字段:settlement_ticket_details.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.orderSettleId IS '对应JSON字段:orderSettleId,说明::同 data.data.orderSettleId,为结算单 ID 的冗余。,示例值及对应分析:orderType';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.actualPayment IS '对应JSON字段:actualPayment,说明::本单实际支付金额总和(顾客本次实际付出:现金 + 线上 + 会员余额等)。,示例值及对应分析:一般应与支付记录中各支付流水金额汇总相匹配。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.adjustAmount IS '对应JSON字段:adjustAmount,说明::台费层面的人工调价金额(仅台费部分)。,示例值及对应分析:memberDiscountAmount';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.assistantManualDiscount IS '对应JSON字段:assistantManualDiscount,说明::针对“助教项目”的人工减免金额汇总(整单维度)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.balanceAmount IS '对应JSON字段:balanceAmount,说明::本单通过“会员余额/储值卡”支付的金额(从余额中扣除的总额)。,示例值及对应分析:对应 结账记录.json 的同名字段。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.cashierName IS '对应JSON字段:cashierName,说明::本单结算操作员名称(带角色前缀文字)。,示例值及对应分析:对应员工维表中的某个账号,便于小票上展示“收银员:XXX”。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.consumeMoney IS '对应JSON字段:consumeMoney,说明::本单“消费金额总计”(原价层面),即台费 + 商品 + 助教 + 服务等消费项目的金额总和(未扣除各类优惠)。,示例值及对应分析:对应 结账记录.json 的 consumeMoney 字段。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.couponAmount IS '对应JSON字段:couponAmount,说明::本单由优惠券抵扣的金额汇总。,示例值及对应分析:结构上:应与 orderCouponLedgers.discountAmount 的合计存在关系,但当前导出未填充。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.deliveryAddress IS '对应JSON字段:deliveryAddress,说明::配送地址(若存在外送业务时使用)。,示例值及对应分析:对于球房场景,当前时间范围内未使用。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.deliveryFee IS '对应JSON字段:deliveryFee,说明::配送费金额(如果支持外送业务)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.ledgerAmount IS '对应JSON字段:ledgerAmount,说明::按台账口径对应的金额,一般与 discountAmount 一致或有固定关系。,示例值及对应分析:rewardPromotionMoney';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.memberDeductAmount IS '对应JSON字段:memberDeductAmount,说明:(结构上):会员抵扣的某种数量或金额(例如积分抵现金额、次卡次数抵扣等),当前数据未启用。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.memberOfferAmount IS '对应JSON字段:memberOfferAmount,说明::由“会员权益/折扣”产生的优惠金额总计(整单维度)。,示例值及对应分析:与 memberProfile 以及台费/商品明细中的 memberDiscountAmount 有对应关系。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.onlineReturnAmount IS '对应JSON字段:onlineReturnAmount,说明::本单通过线上支付渠道退回的金额(如微信/支付宝退款)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.orderRemark IS '对应JSON字段:orderRemark,说明::订单备注,由收银员录入,用于记录与本单相关的特殊说明。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.orderSettleNumber IS '对应JSON字段:orderSettleNumber,说明:(推测):结算单编号(与 ID 独立的一套编号体系,如流水号)。当前导出时间段内未启用。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.payMemberBalance IS '对应JSON字段:payMemberBalance,说明:(结构上):使用会员余额支付的金额,用于区分与 balanceAmount 的不同维度(如“本次支付使用余额部分”与“余额本身变化”等),当前未实际使用。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.payTime IS '对应JSON字段:payTime,说明::本单最终支付成功时间。,示例值及对应分析:和 结账记录.json 中的 payTime 对应,一般与 支付记录.create_time/pay_time 在同一时间段。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.paymentMethod IS '对应JSON字段:paymentMethod,说明::结算主支付方式编码(汇总视角)。,示例值及对应分析:对应 结账记录.json 中的 paymentMethod 字段;';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.pointDiscountCost IS '对应JSON字段:pointDiscountCost,说明::积分抵扣对应的成本金额(成本侧)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.pointDiscountPrice IS '对应JSON字段:pointDiscountPrice,说明::积分抵扣对应的金额(售价侧)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.prepayMoney IS '对应JSON字段:prepayMoney,说明::预付金/定金在本单中使用的金额。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.refundAmount IS '对应JSON字段:refundAmount,说明::本单涉及的退款金额(汇总)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.returnGoodsAmount IS '对应JSON字段:returnGoodsAmount,说明::本单涉及的退货金额汇总。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.rewardName IS '对应JSON字段:rewardName,说明:(结构上):用于标识本单适用的激励方案名称,可能用于内部绩效或活动名称展示。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.settleType IS '对应JSON字段:settleType,说明::结算类型字符串标识。,示例值及对应分析:"SiteOrder":店内消费订单结算。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.siteAddress IS '对应JSON字段:siteAddress,说明::门店地址(详细地址)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.siteBusinessTel IS '对应JSON字段:siteBusinessTel,说明::门店电话。,示例值及对应分析:用途:用于小票打印上的客服电话。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.siteId IS '对应JSON字段:siteId,说明::门店 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.siteName IS '对应JSON字段:siteName,说明::门店名称,如“朗朗桌球”。,示例值及对应分析:用途:小票上展示门店名。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.tenantId IS '对应JSON字段:tenantId,说明::租户 / 商户 ID(品牌维度)。,示例值及对应分析:当前数据:恒定为同一值,表示所有记录都来自同一商户。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.tenantName IS '对应JSON字段:tenantName,说明::租户名称,如“朗朗桌球”。,示例值及对应分析:当前数据:全表统一一个值。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.ticketCustomContent IS '对应JSON字段:ticketCustomContent,说明::自定义小票内容,如商家自定义宣传语、条款等。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.ticketRemark IS '对应JSON字段:ticketRemark,说明::小票备注内容,可用于打印在小票底部或顶部(例如活动说明、特别提示)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.voucherMoney IS '对应JSON字段:voucherMoney,说明::代金券类金额字段(可能用于某类“代金券余额”或“券面值”记录)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.memberProfile IS '对应JSON字段:memberProfile,说明::,示例值及对应分析:不是会员卡主键,而是本次结账时的会员信息快照;';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.orderItem IS '对应JSON字段:orderItem,说明::本次结算对应的“订单明细列表”,这部分是连接“台费流水 / 商品出库 / 券使用”等多个子领域的关键结构。,示例值及对应分析:下面专门展开 orderItem 及其子结构。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.tenantMemberCardLogs IS '对应JSON字段:tenantMemberCardLogs,说明:?????? settlement_ticket_details-Analysis.md,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.store_goods_master (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ siteName TEXT,
+ tenant_goods_id BIGINT,
+ goods_name TEXT,
+ goods_bar_code TEXT,
+ goods_category_id BIGINT,
+ goods_second_category_id BIGINT,
+ oneCategoryName TEXT,
+ twoCategoryName TEXT,
+ unit TEXT,
+ sale_price NUMERIC(18,4),
+ cost_price NUMERIC(18,4),
+ cost_price_type INT,
+ min_discount_price NUMERIC(18,4),
+ safe_stock NUMERIC(18,4),
+ stock NUMERIC(18,4),
+ stock_A NUMERIC(18,4),
+ sale_num NUMERIC(18,4),
+ total_purchase_cost NUMERIC(18,4),
+ total_sales NUMERIC(18,4),
+ average_monthly_sales NUMERIC(18,4),
+ enable_status INT,
+ audit_status INT,
+ goods_state INT,
+ is_delete INT,
+ is_warehousing INT,
+ able_discount INT,
+ able_site_transfer INT,
+ forbid_sell_status INT,
+ "freeze" INT,
+ send_state INT,
+ custom_label_type INT,
+ option_required INT,
+ sale_channel INT,
+ remark TEXT,
+ pinyin_initial TEXT,
+ goods_cover TEXT,
+ create_time TIMESTAMP,
+ update_time TIMESTAMP,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+
+COMMENT ON TABLE billiards_ods.store_goods_master IS '对应JSON字段:store_goods_master.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 store_goods_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_master.id IS '对应JSON字段:id,说明::门店商品 ID,门店维度的商品主键。,示例值及对应分析:用途:在其它文件中经常以 site_goods_id 的名字出现,与这里的 id 一致,用来关联库存记录、销售记录等。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID。同一品牌下多个门店共享一个 tenant_id。,示例值及对应分析:枚举情况:本文件中为单一固定值(同一品牌)。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.site_id IS '对应JSON字段:site_id,说明::门店 ID。,示例值及对应分析:枚举情况:本文件中为单一固定值(同一家门店“朗朗桌球”),和其它 JSON 中的 site_id 一致。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.siteName IS '对应JSON字段:siteName,说明::门店名称,是对 site_id 的冗余展示,方便直接阅读,无需再去关联门店档案。,示例值及对应分析:2. 商品标识和分类维度';
+COMMENT ON COLUMN billiards_ods.store_goods_master.tenant_goods_id IS '对应JSON字段:tenant_goods_id,说明::租户/品牌维度的商品 ID,相当于“全局商品 ID”。,示例值及对应分析:用途:用于跨门店或与“商品档案(商品档案.json)”对齐时使用。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_name IS '对应JSON字段:goods_name,说明::商品名称,例如“合味道泡面”“地道肠”“麻将房茶位费”等。,示例值及对应分析:用途:业务展示字段,历史流水里也会冗余存一份商品名。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_bar_code IS '对应JSON字段:goods_bar_code,说明::商品条形码(如 EAN-13 编码),用于扫码销售。此字段设计为可填,但此店目前未配置。,示例值及对应分析:?? store_goods_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_category_id IS '对应JSON字段:goods_category_id,说明::商品一级分类 ID。,示例值及对应分析:用途:';
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_second_category_id IS '对应JSON字段:goods_second_category_id,说明::商品二级分类 ID。,示例值及对应分析:用途:';
+COMMENT ON COLUMN billiards_ods.store_goods_master.oneCategoryName IS '对应JSON字段:oneCategoryName,说明::一级分类名称,如“零食”“酒水”“服务费”等。,示例值及对应分析:说明:与 goods_category_id 一一对应,是易读文本字段。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.twoCategoryName IS '对应JSON字段:twoCategoryName,说明::二级分类名称,如“面”“洋酒”“纸巾”等。,示例值及对应分析:说明:与 goods_second_category_id 对应。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.unit IS '对应JSON字段:unit,说明::商品计量单位(销售单位)。,示例值及对应分析:?? store_goods_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_master.sale_price IS '对应JSON字段:sale_price,说明::商品标准销售价(挂牌价),单位为元。,示例值及对应分析:说明:实际结算时可能会打折或用券抵扣,但这个字段表示“定价”。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.cost_price IS '对应JSON字段:cost_price,说明::商品成本价(单件成本)。,示例值及对应分析:观察:';
+COMMENT ON COLUMN billiards_ods.store_goods_master.cost_price_type IS '对应JSON字段:cost_price_type,说明:(结合成本字段推测):,示例值及对应分析:1 代表使用“固定成本价”(手工维护的 cost_price),provisional_total_cost 按“数量 × cost_price”算。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.min_discount_price IS '对应JSON字段:min_discount_price,说明::最低允许成交价(限价)。,示例值及对应分析:用法逻辑(推测):';
+COMMENT ON COLUMN billiards_ods.store_goods_master.safe_stock IS '对应JSON字段:safe_stock,说明::安全库存量(阈值),低于该值时系统可以提示补货。,示例值及对应分析:当前门店尚未设置安全库存,所以全部为 0,仅起到结构占位作用。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.stock IS '对应JSON字段:stock,说明::当前可用库存数量(以 unit 为单位)。,示例值及对应分析:特征:可以是 0(库存卖完),也可以非常大(例如纸巾、茶位费这种按“份”计的虚拟库存设定)。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.stock_A IS '对应JSON字段:stock_A,说明:(系统设计):副单位库存数量。如果商品存在双单位(例如箱/瓶),stock_A 通常用于记录副单位库存。当前门店没有启用副单位库存管理,因此为 0。,示例值及对应分析:batch_stock_quantity';
+COMMENT ON COLUMN billiards_ods.store_goods_master.sale_num IS '对应JSON字段:sale_num,说明::在当前统计口径下的销售数量(总销量,单位同 unit)。,示例值及对应分析:特征:和 total_sales 完全一致(当前导出时的统计口径下),说明两者是同一统计周期。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.total_purchase_cost IS '对应JSON字段:total_purchase_cost,说明::总采购成本,单位为元。,示例值及对应分析:当前数据:与 provisional_total_cost 完全相等。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.total_sales IS '对应JSON字段:total_sales,说明:(从命名看):累计销售数量。,示例值及对应分析:实际:当前数据中 total_sales == sale_num,说明此接口的统计区间 = “截至当前的全部历史”,因此数量一致。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.average_monthly_sales IS '对应JSON字段:average_monthly_sales,说明::平均月销量(件/月),根据某个统计周期内的销售数据折算而来。,示例值及对应分析:结构特征:';
+COMMENT ON COLUMN billiards_ods.store_goods_master.enable_status IS '对应JSON字段:enable_status,说明:(结合名称与常见编码):,示例值及对应分析:1:启用。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.audit_status IS '对应JSON字段:audit_status,说明:(典型业务语义):,示例值及对应分析:2:审核通过。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_state IS '对应JSON字段:goods_state,说明:类型:int,枚举,示例值及对应分析:观察值:';
+COMMENT ON COLUMN billiards_ods.store_goods_master.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志。,示例值及对应分析:0:未删除(有效档案);';
+COMMENT ON COLUMN billiards_ods.store_goods_master.is_warehousing IS '对应JSON字段:is_warehousing,说明::是否纳入库存管理。,示例值及对应分析:1:启用库存管理(会有出入库流水)。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.able_discount IS '对应JSON字段:able_discount,说明:(结合命名):,示例值及对应分析:是否允许参与折扣。当前全部为 1,说明所有商品都允许打折。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.able_site_transfer IS '对应JSON字段:able_site_transfer,说明:(结合命名与值分布):,示例值及对应分析:表示是否允许跨门店调拨或跨站点共享库存。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.forbid_sell_status IS '对应JSON字段:forbid_sell_status,说明:类型:int,枚举,示例值及对应分析:观察值:全部为 1。';
+COMMENT ON COLUMN billiards_ods.store_goods_master."freeze" IS '对应JSON字段:freeze,说明::冻结状态。,示例值及对应分析:0:未冻结;';
+COMMENT ON COLUMN billiards_ods.store_goods_master.send_state IS '对应JSON字段:send_state,说明:(命名趋近“上架状态/可售状态”):,示例值及对应分析:1:可销售/可下单。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.custom_label_type IS '对应JSON字段:custom_label_type,说明:(推测):自定义标签类型。,示例值及对应分析:1:使用系统默认标签(未出现);';
+COMMENT ON COLUMN billiards_ods.store_goods_master.option_required IS '对应JSON字段:option_required,说明:(推测):是否需要在销售时选择规格/选项。,示例值及对应分析:1:不要求额外选项(单规格商品);';
+COMMENT ON COLUMN billiards_ods.store_goods_master.sale_channel IS '对应JSON字段:sale_channel,说明::销售渠道类型。,示例值及对应分析:常见模式:';
+COMMENT ON COLUMN billiards_ods.store_goods_master.remark IS '对应JSON字段:remark,说明::商品备注(可以写口味说明、供应商、注意事项等)。当前尚未使用。,示例值及对应分析:sort';
+COMMENT ON COLUMN billiards_ods.store_goods_master.pinyin_initial IS '对应JSON字段:pinyin_initial,说明::商品名称的拼音首字母缩写,有时多个别名用逗号分隔。,示例值及对应分析:作用:';
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_cover IS '对应JSON字段:goods_cover,说明::商品图片 URL(如 OSS 对象存储地址),用于前端展示商品图片。,示例值及对应分析:?? store_goods_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_master.create_time IS '对应JSON字段:create_time,说明::门店商品档案创建时间(商品在门店建立档案的时间点)。,示例值及对应分析:?? store_goods_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_master.update_time IS '对应JSON字段:update_time,说明::最后一次修改该商品档案的时间(包括价格调整、状态变更等)。,示例值及对应分析:days_available';
+COMMENT ON COLUMN billiards_ods.store_goods_master.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.store_goods_master.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.store_goods_master.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.store_goods_master.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.store_goods_sales_records (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ site_goods_id BIGINT,
+ tenant_goods_id BIGINT,
+ order_settle_id BIGINT,
+ order_trade_no TEXT,
+ order_goods_id BIGINT,
+ order_pay_id BIGINT,
+ order_coupon_id BIGINT,
+ ledger_name TEXT,
+ ledger_group_name TEXT,
+ ledger_amount NUMERIC(18,2),
+ ledger_count NUMERIC(18,4),
+ ledger_unit_price NUMERIC(18,4),
+ ledger_status INT,
+ discount_money NUMERIC(18,2),
+ coupon_deduct_money NUMERIC(18,2),
+ member_discount_amount NUMERIC(18,2),
+ option_coupon_deduct_money NUMERIC(18,2),
+ option_member_discount_money NUMERIC(18,2),
+ point_discount_money NUMERIC(18,2),
+ point_discount_money_cost NUMERIC(18,2),
+ real_goods_money NUMERIC(18,2),
+ cost_money NUMERIC(18,2),
+ push_money NUMERIC(18,2),
+ sales_type INT,
+ is_single_order INT,
+ is_delete INT,
+ goods_remark TEXT,
+ option_price NUMERIC(18,2),
+ option_value_name TEXT,
+ option_name TEXT,
+ member_coupon_id BIGINT,
+ package_coupon_id BIGINT,
+ sales_man_org_id BIGINT,
+ salesman_name TEXT,
+ salesman_role_id BIGINT,
+ salesman_user_id BIGINT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ openSalesman TEXT,
+ site_table_id BIGINT,
+ tenant_goods_business_id BIGINT,
+ tenant_goods_category_id BIGINT,
+ create_time TIMESTAMP,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+
+COMMENT ON TABLE billiards_ods.store_goods_sales_records IS '对应JSON字段:store_goods_sales_records.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.id IS '对应JSON字段:id,说明::本条「门店销售流水」记录的主键 ID。,示例值及对应分析:用途:在系统内部唯一标识这一条销售明细。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID。,示例值及对应分析:特征:所有记录为同一个值,对应「非球科技系统中你的商户」。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.site_id IS '对应JSON字段:site_id,说明::门店 ID(系统主键)。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.site_goods_id IS '对应JSON字段:site_goods_id,说明::门店商品 ID。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.tenant_goods_id IS '对应JSON字段:tenant_goods_id,说明::租户(品牌)级商品 ID(全局商品 ID)。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.order_settle_id IS '对应JSON字段:order_settle_id,说明:与台费、助教、团购套餐流水等表共享,形成「订单主表(结算)– 多种明细表」的结构。,示例值及对应分析:如果结账记录表有数据,order_settle_id 对应那里的主键,create_time 与订单结束时间基本一致。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.order_trade_no IS '对应JSON字段:order_trade_no,说明:与台费、助教、团购套餐流水等表共享,形成「订单主表(结算)– 多种明细表」的结构。,示例值及对应分析:如果结账记录表有数据,order_settle_id 对应那里的主键,create_time 与订单结束时间基本一致。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.order_goods_id IS '对应JSON字段:order_goods_id,说明::订单商品明细 ID(订单内部的商品行主键)。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.order_pay_id IS '对应JSON字段:order_pay_id,说明:连接到「支付记录」中的一条支付流水,再通过支付的 relate_type/relate_id 把支付和订单、充值等业务区分开。,示例值及对应分析:对于退款,则通过退款记录里的 relate_type/relate_id 反向关联到原来的订单或支付。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.order_coupon_id IS '对应JSON字段:order_coupon_id,说明::订单级优惠券 ID。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_name IS '对应JSON字段:ledger_name,说明::销售项目名称(商品名称),例如 “哇哈哈矿泉水”“地道肠”“东方树叶”等。,示例值及对应分析:说明:业务展示用字段,历史流水即使商品改名,这里会保留当时的名字。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_group_name IS '对应JSON字段:ledger_group_name,说明::销售项目所属的「门店内部分组名称」,类似前台菜单分组或大类标签。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_amount IS '对应JSON字段:ledger_amount,说明::原始应收金额,公式上接近 ledger_unit_price × ledger_count。,示例值及对应分析:说明:这是未考虑优惠前的金额基础,用于后续计算折扣和抵扣。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_count IS '对应JSON字段:ledger_count,说明::销售数量(以 unit 为单位,unit 字段在门店商品档案中)。,示例值及对应分析:观测值:如 1, 2, 3, 6, 36 等。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_unit_price IS '对应JSON字段:ledger_unit_price,说明::商品在该次销售中的「结算单价」(元/单位)。,示例值及对应分析:观测值示例:5.0, 8.0, 2.0, 10.0, 72.0 等。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_status IS '对应JSON字段:ledger_status,说明::销售流水状态。,示例值及对应分析:1:正常有效。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.discount_money IS '对应JSON字段:discount_money,说明::本条销售明细的「价格优惠金额」,即原价部分被减免掉的金额。,示例值及对应分析:典型关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.coupon_deduct_money IS '对应JSON字段:coupon_deduct_money,说明::被优惠券 / 团购券直接抵扣到这条商品明细上的金额。,示例值及对应分析:说明:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.member_discount_amount IS '对应JSON字段:member_discount_amount,说明::由会员身份(会员折扣)针对这一行商品产生的优惠金额。,示例值及对应分析:说明:尽管字段存在,但当前实际折扣可能合并反映在 discount_money 中,这个字段没有拆开体现。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.option_coupon_deduct_money IS '对应JSON字段:option_coupon_deduct_money,说明::由优惠券抵扣“选项价格”的金额。,示例值及对应分析:上面这三个 option_* 字段,是为“主商品 + 选项”的更复杂计价方式预留的,本店当前所有记录都是单规格,选项体系未启用。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.option_member_discount_money IS '对应JSON字段:option_member_discount_money,说明::由会员折扣作用在“选项价格”上的优惠金额。,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.point_discount_money IS '对应JSON字段:point_discount_money,说明::由积分抵扣的金额(顾客兑换积分抵现金额)。,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.point_discount_money_cost IS '对应JSON字段:point_discount_money_cost,说明::积分抵扣对应的“成本金额”(后台核算用),例如按积分成本来计提费用。,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.real_goods_money IS '对应JSON字段:real_goods_money,说明::商品实际入账金额(考虑折扣、可能还会考虑其它抵扣后的实际销售金额)。,示例值及对应分析:观测值:5.0, 10.0, 8.0, 6.0, 4.0 等。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.cost_money IS '对应JSON字段:cost_money,说明::本条销售对应的成本金额(以元计)。,示例值及对应分析:观测示例:0.01, 0.00, 3.58, 1.79, 0.64 等。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.push_money IS '对应JSON字段:push_money,说明::本条销售对应的提成金额(给营业员/促销员的提成)。,示例值及对应分析:在启用营业员体系时,这里才会出现正数。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.sales_type IS '对应JSON字段:sales_type,说明::销售类型。,示例值及对应分析:1:正常销售;';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.is_single_order IS '对应JSON字段:is_single_order,说明::是否单独订单标识。,示例值及对应分析:1:作为独立明细参与某个订单结算;';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志。,示例值及对应分析:0:正常有效;';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.goods_remark IS '对应JSON字段:goods_remark,说明::商品备注/口味说明/特殊说明。,示例值及对应分析:用途:点单时如果需要额外说明,可以写在这里。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.option_price IS '对应JSON字段:option_price,说明::商品选项(规格/加料)的附加价格。,示例值及对应分析:说明:如加冰、加料、升级大杯等产生附加费用时,理论上应该体现到这里。当前门店未使用此功能。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.option_value_name IS '对应JSON字段:option_value_name,说明::商品选项名称(如规格、口味:大杯/小杯,不加冰等)。,示例值及对应分析:结构用途:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.option_name IS '对应JSON字段:option_name,说明:?????? store_goods_sales_records-Analysis.md,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.member_coupon_id IS '对应JSON字段:member_coupon_id,说明::会员券 ID(比如会员专享优惠券)。,示例值及对应分析:当前数据未使用,属于为会员权益预留的字段。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.package_coupon_id IS '对应JSON字段:package_coupon_id,说明::套餐券 ID。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.sales_man_org_id IS '对应JSON字段:sales_man_org_id,说明::营业员所属组织/部门 ID。,示例值及对应分析:当前门店全部为 0,说明未启用这套销售员分组织的体系。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.salesman_name IS '对应JSON字段:salesman_name,说明::营业员姓名(如果有为具体销售员记业绩,则在此填姓名)。,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.salesman_role_id IS '对应JSON字段:salesman_role_id,说明::营业员的系统角色 ID(例如某个角色代码表示“销售员”)。,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.salesman_user_id IS '对应JSON字段:salesman_user_id,说明::营业员用户 ID(系统账号 ID)。,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.operator_id IS '对应JSON字段:operator_id,说明::操作员 ID(录入这笔销售的员工)。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.operator_name IS '对应JSON字段:operator_name,说明::操作员姓名,文字冗余。,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.openSalesman IS '对应JSON字段:openSalesman,说明:(结合系统其它文件推断):,示例值及对应分析:1:启用“营业员/销售员”机制(要指定 salesman);';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.site_table_id IS '对应JSON字段:site_table_id,说明::球台 ID。,示例值及对应分析:非 0:销售记录关联到具体某张桌台(例如顾客在台上点饮料)。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.tenant_goods_business_id IS '对应JSON字段:tenant_goods_business_id,说明::租户级商品「业务大类」ID(例如“零食类”“酒水类”等更高维度)。,示例值及对应分析:2.2 门店 / 球台维度字段';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.tenant_goods_category_id IS '对应JSON字段:tenant_goods_category_id,说明::租户级商品一级分类 ID。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.create_time IS '对应JSON字段:create_time,说明::销售记录创建时间,通常就是结账时间或录入时间。,示例值及对应分析:用途:用于按时间维度查询销售流水,与订单层的时间字段对齐。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
diff --git a/etl_billiards/database/schema_ODS_doc copy.sql b/etl_billiards/database/schema_ODS_doc copy.sql
new file mode 100644
index 0000000..d8a0408
--- /dev/null
+++ b/etl_billiards/database/schema_ODS_doc copy.sql
@@ -0,0 +1,1886 @@
+-- 文件:schema_ODS_doc.sql
+-- 说明:ODS 层 DDL,表名与示例 JSON 前缀对应,用于本地回放/调试。
+-- 编码:UTF-8
+SET client_encoding TO "UTF8";
+
+DROP SCHEMA IF EXISTS billiards_ods CASCADE;
+CREATE SCHEMA IF NOT EXISTS billiards_ods;
+
+CREATE TABLE IF NOT EXISTS billiards_ods.member_profiles (
+ tenant_id BIGINT,
+ register_site_id BIGINT,
+ site_name TEXT,
+ id BIGINT PRIMARY KEY,
+ system_member_id BIGINT,
+ member_card_grade_code BIGINT,
+ member_card_grade_name TEXT,
+ mobile TEXT,
+ nickname TEXT,
+ point NUMERIC(18,2),
+ growth_value NUMERIC(18,2),
+ referrer_member_id BIGINT,
+ status INT,
+ user_status INT,
+ create_time TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.member_profiles IS '对应JSON字段:member_profiles.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 member_profiles-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_profiles.tenant_id IS '对应JSON字段:tenant_id,说明::,示例值及对应分析:租户/品牌 ID。';
+COMMENT ON COLUMN billiards_ods.member_profiles.register_site_id IS '对应JSON字段:register_site_id,说明::,示例值及对应分析:会员的注册门店 ID。';
+COMMENT ON COLUMN billiards_ods.member_profiles.site_name IS '对应JSON字段:site_name,说明::,示例值及对应分析:注册门店名称,属于冗余字段,用于直接展示。';
+COMMENT ON COLUMN billiards_ods.member_profiles.id IS '对应JSON字段:id,说明::,示例值及对应分析:这是“租户内会员账户”的主键 ID。';
+COMMENT ON COLUMN billiards_ods.member_profiles.system_member_id IS '对应JSON字段:system_member_id,说明:(结合其它文件):,示例值及对应分析:这是“系统级会员 ID”,在全平台唯一,用来把一个会员在不同门店/不同卡类型下的账户统一到一个“人”的维度上。';
+COMMENT ON COLUMN billiards_ods.member_profiles.member_card_grade_code IS '对应JSON字段:member_card_grade_code,说明:类型:int,示例值及对应分析:唯一值个数:4';
+COMMENT ON COLUMN billiards_ods.member_profiles.member_card_grade_name IS '对应JSON字段:member_card_grade_name,说明::,示例值及对应分析:这是“会员卡种类/等级”的定义字段。';
+COMMENT ON COLUMN billiards_ods.member_profiles.mobile IS '对应JSON字段:mobile,说明::,示例值及对应分析:会员绑定的手机号码。';
+COMMENT ON COLUMN billiards_ods.member_profiles.nickname IS '对应JSON字段:nickname,说明::,示例值及对应分析:会员在当前租户下的显示名称(可以是姓名,也可以是昵称)。';
+COMMENT ON COLUMN billiards_ods.member_profiles.point IS '对应JSON字段:point,说明::,示例值及对应分析:当前积分余额(这条会员账户的积分值)。';
+COMMENT ON COLUMN billiards_ods.member_profiles.growth_value IS '对应JSON字段:growth_value,说明:(按常见会员体系设计):,示例值及对应分析:成长值 / 经验值,用于会员等级晋升的累计指标。';
+COMMENT ON COLUMN billiards_ods.member_profiles.referrer_member_id IS '对应JSON字段:referrer_member_id,说明:(按命名推断):,示例值及对应分析:推荐人会员 ID,用于记录该会员是由哪位老会员推荐。';
+COMMENT ON COLUMN billiards_ods.member_profiles.status IS '对应JSON字段:status,说明:(按命名推断):,示例值及对应分析:帐户状态(偏“卡状态/档案状态”)。';
+COMMENT ON COLUMN billiards_ods.member_profiles.user_status IS '对应JSON字段:user_status,说明:(结合行业惯例):,示例值及对应分析:用户账号状态(偏“用户逻辑”层面的状态)。';
+COMMENT ON COLUMN billiards_ods.member_profiles.create_time IS '对应JSON字段:create_time,说明::,示例值及对应分析:会员账户的创建时间(即这条档案/这张卡在系统中被创建的时间)。';
+COMMENT ON COLUMN billiards_ods.member_profiles.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_profiles.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_profiles.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_profiles.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.member_balance_changes (
+ tenant_id BIGINT,
+ site_id BIGINT,
+ register_site_id BIGINT,
+ registerSiteName TEXT,
+ paySiteName TEXT,
+ id BIGINT PRIMARY KEY,
+ tenant_member_id BIGINT,
+ tenant_member_card_id BIGINT,
+ system_member_id BIGINT,
+ memberName TEXT,
+ memberMobile TEXT,
+ card_type_id BIGINT,
+ memberCardTypeName TEXT,
+ account_data NUMERIC(18,2),
+ before NUMERIC(18,2),
+ after NUMERIC(18,2),
+ refund_amount NUMERIC(18,2),
+ from_type INT,
+ payment_method INT,
+ relate_id BIGINT,
+ remark TEXT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ is_delete INT,
+ create_time TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.member_balance_changes IS '对应JSON字段:member_balance_changes.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.tenant_id IS '对应JSON字段:tenant_id,说明::租户/商户 ID,本数据中是固定值(同一品牌/商户)。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.site_id IS '对应JSON字段:site_id,说明:表示本次余额变动的发生门店,绝大多数也在“朗朗桌球”,少数特殊业务(活动抵用券结算)显示为 site_id=0、paySiteName 为空。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.register_site_id IS '对应JSON字段:register_site_id,说明:已在前文说明:办卡门店的 ID 与名称,所有记录一致,说明所有卡均在“朗朗桌球”注册。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.registerSiteName IS '对应JSON字段:registerSiteName,说明:已在前文说明:办卡门店的 ID 与名称,所有记录一致,说明所有卡均在“朗朗桌球”注册。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.paySiteName IS '对应JSON字段:paySiteName,说明:表示本次余额变动的发生门店,绝大多数也在“朗朗桌球”,少数特殊业务(活动抵用券结算)显示为 site_id=0、paySiteName 为空。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.id IS '对应JSON字段:id,说明::余额变更记录的主键 ID,唯一标识这一条“账户余额变化事件”。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.tenant_member_id IS '对应JSON字段:tenant_member_id,说明::商户维度的会员 ID(租户内会员主键)。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.tenant_member_card_id IS '对应JSON字段:tenant_member_card_id,说明::会员卡账户 ID,在租户内唯一标识某张卡。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.system_member_id IS '对应JSON字段:system_member_id,说明::系统级(全局)会员 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.memberName IS '对应JSON字段:memberName,说明::会员姓名或称呼(非昵称字段)。,示例值及对应分析:说明:例如“陈腾鑫”“胡先生”“江先生”等,多为中文姓名或带“先生”称呼。';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.memberMobile IS '对应JSON字段:memberMobile,说明::会员手机号。,示例值及对应分析:说明:字符型存储,完整手机号,用来识别会员与联系客户。';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.card_type_id IS '对应JSON字段:card_type_id,说明::卡种类型 ID,用于区分不同卡种。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.memberCardTypeName IS '对应JSON字段:memberCardTypeName,说明::卡种名称,与 card_type_id 一一对应,是一个 卡种枚举名称。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.account_data IS '对应JSON字段:account_data,说明::本次变动的金额(元),正数表示增加,负数表示减少。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.before IS '对应JSON字段:before,说明::本次变动前,该卡账户的余额(元)。,示例值及对应分析:说明:';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.after IS '对应JSON字段:after,说明::本次变动后,该卡账户的余额(元)。,示例值及对应分析:重要关系:';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.refund_amount IS '对应JSON字段:refund_amount,说明:(推测):与退款业务相关的金额字段,但在当前这份导出中实际未使用:,示例值及对应分析:可能用于标记“其中有多少金额是以‘退款’形式回流的”,或区分“退回余额”和“原路退回”两种模式。';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.from_type IS '对应JSON字段:from_type,说明:(根据金额符号与 remark 综合推断):,示例值及对应分析:1:日常消费扣款';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.payment_method IS '对应JSON字段:payment_method,说明:类型:int,枚举,示例值及对应分析:值分布:';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.relate_id IS '对应JSON字段:relate_id,说明:(推测):关联业务记录的 ID:,示例值及对应分析:例如某次充值记录的 ID、某张订单/结算单 ID、某次活动抵用券核销记录 ID 等。';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.remark IS '对应JSON字段:remark,说明::,示例值及对应分析:当为空时,说明这条变动没有额外备注说明。';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.operator_id IS '对应JSON字段:operator_id,说明::执行此次余额变更操作的员工 ID。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.operator_name IS '对应JSON字段:operator_name,说明::操作员姓名(带职位前缀),是对 operator_id 的可读冗余字段。,示例值及对应分析:9. 状态字段与标志';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标记:,示例值及对应分析:0:正常;';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.create_time IS '对应JSON字段:create_time,说明::本条余额变更记录的创建时间,通常接近交易发生时间。,示例值及对应分析:说明:可与订单、支付记录的时间做对齐,构造时序链路(但你现在不要求做时序分析,这里只说明结构)。';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.member_stored_value_cards (
+ tenant_id BIGINT,
+ tenant_member_id BIGINT,
+ system_member_id BIGINT,
+ register_site_id BIGINT,
+ site_name TEXT,
+ id BIGINT PRIMARY KEY,
+ member_card_grade_code BIGINT,
+ member_card_grade_code_name TEXT,
+ member_card_type_name TEXT,
+ member_name TEXT,
+ member_mobile TEXT,
+ card_type_id BIGINT,
+ card_no TEXT,
+ card_physics_type TEXT,
+ balance NUMERIC(18,2),
+ denomination NUMERIC(18,2),
+ table_discount NUMERIC(10,4),
+ goods_discount NUMERIC(10,4),
+ assistant_discount NUMERIC(10,4),
+ assistant_reward_discount NUMERIC(10,4),
+ table_service_discount NUMERIC(10,4),
+ assistant_service_discount NUMERIC(10,4),
+ coupon_discount NUMERIC(10,4),
+ goods_service_discount NUMERIC(10,4),
+ assistant_discount_sub_switch INT,
+ table_discount_sub_switch INT,
+ goods_discount_sub_switch INT,
+ assistant_reward_discount_sub_switch INT,
+ table_service_deduct_radio NUMERIC(10,4),
+ assistant_service_deduct_radio NUMERIC(10,4),
+ goods_service_deduct_radio NUMERIC(10,4),
+ assistant_deduct_radio NUMERIC(10,4),
+ table_deduct_radio NUMERIC(10,4),
+ goods_deduct_radio NUMERIC(10,4),
+ coupon_deduct_radio NUMERIC(10,4),
+ assistant_reward_deduct_radio NUMERIC(10,4),
+ tableCardDeduct NUMERIC(18,2),
+ tableServiceCardDeduct NUMERIC(18,2),
+ goodsCarDeduct NUMERIC(18,2),
+ goodsServiceCardDeduct NUMERIC(18,2),
+ assistantCardDeduct NUMERIC(18,2),
+ assistantServiceCardDeduct NUMERIC(18,2),
+ assistantRewardCardDeduct NUMERIC(18,2),
+ cardSettleDeduct NUMERIC(18,2),
+ couponCardDeduct NUMERIC(18,2),
+ deliveryFeeDeduct NUMERIC(18,2),
+ use_scene INT,
+ able_cross_site INT,
+ able_site_transfer INT,
+ is_allow_give INT,
+ is_allow_order_deduct INT,
+ is_delete INT,
+ bind_password TEXT,
+ goods_discount_range_type INT,
+ goodsCategoryId BIGINT,
+ tableAreaId BIGINT,
+ effect_site_id BIGINT,
+ start_time TIMESTAMP,
+ end_time TIMESTAMP,
+ disable_start_time TIMESTAMP,
+ disable_end_time TIMESTAMP,
+ last_consume_time TIMESTAMP,
+ create_time TIMESTAMP,
+ status INT,
+ sort INT,
+ tenantAvatar TEXT,
+ tenantName TEXT,
+ pdAssisnatLevel TEXT,
+ cxAssisnatLevel TEXT,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.member_stored_value_cards IS '对应JSON字段:member_stored_value_cards.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID,与其他 JSON 中 tenant_id 一致。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tenant_member_id IS '对应JSON字段:tenant_member_id,说明::当前商户(品牌/租户)中会员的主键 ID。,示例值及对应分析:枚举特征:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.system_member_id IS '对应JSON字段:system_member_id,说明::系统级会员 ID(跨门店统一主键)。,示例值及对应分析:枚举特征:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.register_site_id IS '对应JSON字段:register_site_id,说明::卡首次办理的门店 ID。,示例值及对应分析:对应门店的 site_id;本数据中所有卡都是在同一家门店开卡。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.site_name IS '对应JSON字段:site_name,说明::卡归属门店名称(视图中的展示字段)。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.id IS '对应JSON字段:id,说明:?????? member_stored_value_cards-Analysis.md,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.member_card_grade_code IS '对应JSON字段:member_card_grade_code,说明::卡等级/卡类代码,和下面两个名称字段一一对应。,示例值及对应分析:枚举:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.member_card_grade_code_name IS '对应JSON字段:member_card_grade_code_name,说明::卡等级/卡类名称。,示例值及对应分析:枚举值(与上面 code 一一对应):';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.member_card_type_name IS '对应JSON字段:member_card_type_name,说明::卡类型名称,实际与 member_card_grade_code_name 一致。,示例值及对应分析:枚举值同上。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.member_name IS '对应JSON字段:member_name,说明::持卡会员姓名快照。,示例值及对应分析:特点:存在 null(20 张卡没有绑定会员名字)。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.member_mobile IS '对应JSON字段:member_mobile,说明::持卡会员手机号快照。,示例值及对应分析:特点:与 member_name 对应,多数有值,少量为 null。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.card_type_id IS '对应JSON字段:card_type_id,说明::卡种 ID(定义“这是哪一种卡”)。,示例值及对应分析:枚举(按数据分布):';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.card_no IS '对应JSON字段:card_no,说明:(推测):实体卡物理卡号/条码号。当前这批卡看起来全部为“无物理卡号”(可能是全部虚拟卡或卡号隐藏不导出)。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.card_physics_type IS '对应JSON字段:card_physics_type,说明::物理卡类型。,示例值及对应分析:当前数据:全部为 1。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.balance IS '对应JSON字段:balance,说明::当前卡内余额(主要针对储值卡、部分券卡)。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.denomination IS '对应JSON字段:denomination,说明:(推测):面额/初始储值额度。,示例值及对应分析:本页数据未填充此字段;可能在分类型卡(如次卡/券)中才有意义,或者另有配置表。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.table_discount IS '对应JSON字段:table_discount,说明::,示例值及对应分析:采用“几折”的记法:10=不打折,9=九折,8=八折。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_discount IS '对应JSON字段:goods_discount,说明::,示例值及对应分析:采用“几折”的记法:10=不打折,9=九折,8=八折。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_discount IS '对应JSON字段:assistant_discount,说明::,示例值及对应分析:采用“几折”的记法:10=不打折,9=九折,8=八折。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_reward_discount IS '对应JSON字段:assistant_reward_discount,说明::,示例值及对应分析:采用“几折”的记法:10=不打折,9=九折,8=八折。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.table_service_discount IS '对应JSON字段:table_service_discount,说明::,示例值及对应分析:采用“几折”的记法:10=不打折,9=九折,8=八折。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_service_discount IS '对应JSON字段:assistant_service_discount,说明::,示例值及对应分析:采用“几折”的记法:10=不打折,9=九折,8=八折。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.coupon_discount IS '对应JSON字段:coupon_discount,说明:?????? member_stored_value_cards-Analysis.md,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_service_discount IS '对应JSON字段:goods_service_discount,说明::,示例值及对应分析:采用“几折”的记法:10=不打折,9=九折,8=八折。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_discount_sub_switch IS '对应JSON字段:assistant_discount_sub_switch,说明:(推测):“折扣是否叠加/替换其他折扣”的开关。,示例值及对应分析:可能枚举:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.table_discount_sub_switch IS '对应JSON字段:table_discount_sub_switch,说明:(推测):“折扣是否叠加/替换其他折扣”的开关。,示例值及对应分析:可能枚举:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_discount_sub_switch IS '对应JSON字段:goods_discount_sub_switch,说明:(推测):“折扣是否叠加/替换其他折扣”的开关。,示例值及对应分析:可能枚举:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_reward_discount_sub_switch IS '对应JSON字段:assistant_reward_discount_sub_switch,说明:(推测):“折扣是否叠加/替换其他折扣”的开关。,示例值及对应分析:可能枚举:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.table_service_deduct_radio IS '对应JSON字段:table_service_deduct_radio,说明::允许从该卡余额中抵扣的比例(百分比)。,示例值及对应分析:100.0 表示允许 100% 用卡余额支付该类消费;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_service_deduct_radio IS '对应JSON字段:assistant_service_deduct_radio,说明::允许从该卡余额中抵扣的比例(百分比)。,示例值及对应分析:100.0 表示允许 100% 用卡余额支付该类消费;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_service_deduct_radio IS '对应JSON字段:goods_service_deduct_radio,说明::允许从该卡余额中抵扣的比例(百分比)。,示例值及对应分析:100.0 表示允许 100% 用卡余额支付该类消费;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_deduct_radio IS '对应JSON字段:assistant_deduct_radio,说明::允许从该卡余额中抵扣的比例(百分比)。,示例值及对应分析:100.0 表示允许 100% 用卡余额支付该类消费;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.table_deduct_radio IS '对应JSON字段:table_deduct_radio,说明::允许从该卡余额中抵扣的比例(百分比)。,示例值及对应分析:100.0 表示允许 100% 用卡余额支付该类消费;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_deduct_radio IS '对应JSON字段:goods_deduct_radio,说明::允许从该卡余额中抵扣的比例(百分比)。,示例值及对应分析:100.0 表示允许 100% 用卡余额支付该类消费;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.coupon_deduct_radio IS '对应JSON字段:coupon_deduct_radio,说明::允许从该卡余额中抵扣的比例(百分比)。,示例值及对应分析:100.0 表示允许 100% 用卡余额支付该类消费;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_reward_deduct_radio IS '对应JSON字段:assistant_reward_deduct_radio,说明:?????? member_stored_value_cards-Analysis.md,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tableCardDeduct IS '对应JSON字段:tableCardDeduct,说明::针对台费/商品/助教三类消费的扣卡金额配置(类似“每小时从卡里扣 xx 元”或“每次抵扣 xx 元”的规则)。,示例值及对应分析:当前:所有为 0,说明在卡定义层面并没有指定固定扣卡金额,而是按照一般储值逻辑消费。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tableServiceCardDeduct IS '对应JSON字段:tableServiceCardDeduct,说明::如果系统中区分“储值金、服务金、奖励金”等子账户,这三个字段对应“服务金”子账户的扣款配置。,示例值及对应分析:当前未启用。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goodsCarDeduct IS '对应JSON字段:goodsCarDeduct,说明::针对台费/商品/助教三类消费的扣卡金额配置(类似“每小时从卡里扣 xx 元”或“每次抵扣 xx 元”的规则)。,示例值及对应分析:当前:所有为 0,说明在卡定义层面并没有指定固定扣卡金额,而是按照一般储值逻辑消费。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goodsServiceCardDeduct IS '对应JSON字段:goodsServiceCardDeduct,说明::如果系统中区分“储值金、服务金、奖励金”等子账户,这三个字段对应“服务金”子账户的扣款配置。,示例值及对应分析:当前未启用。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistantCardDeduct IS '对应JSON字段:assistantCardDeduct,说明::针对台费/商品/助教三类消费的扣卡金额配置(类似“每小时从卡里扣 xx 元”或“每次抵扣 xx 元”的规则)。,示例值及对应分析:当前:所有为 0,说明在卡定义层面并没有指定固定扣卡金额,而是按照一般储值逻辑消费。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistantServiceCardDeduct IS '对应JSON字段:assistantServiceCardDeduct,说明::如果系统中区分“储值金、服务金、奖励金”等子账户,这三个字段对应“服务金”子账户的扣款配置。,示例值及对应分析:当前未启用。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistantRewardCardDeduct IS '对应JSON字段:assistantRewardCardDeduct,说明::助教奖励金方向扣款的配置。,示例值及对应分析:当前未启用。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.cardSettleDeduct IS '对应JSON字段:cardSettleDeduct,说明:已在扣卡规则部分说明,当前为 0。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.couponCardDeduct IS '对应JSON字段:couponCardDeduct,说明::与卡绑定的“券额度扣除配置”。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.deliveryFeeDeduct IS '对应JSON字段:deliveryFeeDeduct,说明::配送费可否/多少从卡中抵扣,目前无业务发生。,示例值及对应分析:综合来看:本门店的卡片在“规则配置层”预留了大量细粒度控制字段,但目前实际使用只体现在“balance”和“可用范围”,折扣和具体扣卡规则基本都未启用(全部保持默认值 10 折、100%比例、0 扣款),真正扣款逻辑在交易流水中体现。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.use_scene IS '对应JSON字段:use_scene,说明::卡使用场景说明(比如“仅店内使用”“仅团建”等),本门店尚未使用此字段。,示例值及对应分析:2. 会员信息与关联字段';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.able_cross_site IS '对应JSON字段:able_cross_site,说明::是否允许跨店使用。,示例值及对应分析:1:可以跨门店使用;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.able_site_transfer IS '对应JSON字段:able_site_transfer,说明:?????? member_stored_value_cards-Analysis.md,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.is_allow_give IS '对应JSON字段:is_allow_give,说明::是否允许转赠/转让给其他会员。,示例值及对应分析:0:不允许;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.is_allow_order_deduct IS '对应JSON字段:is_allow_order_deduct,说明::是否允许在“订单层面统一扣款”。,示例值及对应分析:0:不允许(仅按项目扣卡);';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志。,示例值及对应分析:0:未删除;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.bind_password IS '对应JSON字段:bind_password,说明::卡绑定密码,用于消费或查询验证(目前未启用)。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_discount_range_type IS '对应JSON字段:goods_discount_range_type,说明:?????? member_stored_value_cards-Analysis.md,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goodsCategoryId IS '对应JSON字段:goodsCategoryId,说明:已上文说明:均为扩展限定维度,当前全部为空列表。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tableAreaId IS '对应JSON字段:tableAreaId,说明:已上文说明:均为扩展限定维度,当前全部为空列表。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.effect_site_id IS '对应JSON字段:effect_site_id,说明:(推测):卡片限定生效门店 ID。,示例值及对应分析:为 0 时,配合 able_cross_site=1,可解释为“所有门店可用”。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.start_time IS '对应JSON字段:start_time,说明::卡片生效开始时间(有效期起始)。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.end_time IS '对应JSON字段:end_time,说明::卡片有效期结束时间。,示例值及对应分析:start_time / end_time 组合就是卡的有效期。不同卡种有效期配置不同,如储值卡长效、月卡固定一个月等。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.disable_start_time IS '对应JSON字段:disable_start_time,说明::停用时间段(比如临时冻结卡的起止时间)。,示例值及对应分析:当前未启用,所有卡都是“未进入停用窗口”。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.disable_end_time IS '对应JSON字段:disable_end_time,说明::停用时间段(比如临时冻结卡的起止时间)。,示例值及对应分析:当前未启用,所有卡都是“未进入停用窗口”。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.last_consume_time IS '对应JSON字段:last_consume_time,说明::最近一次消费时间。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.create_time IS '对应JSON字段:create_time,说明::卡片创建时间(开卡时间)。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.status IS '对应JSON字段:status,说明:(推测):,示例值及对应分析:1:正常可用;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.sort IS '对应JSON字段:sort,说明::在前端展示或某些列表中的排序权重。,示例值及对应分析:具体取值分布不重要,主要反映展示优先级。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tenantAvatar IS '对应JSON字段:tenantAvatar,说明::品牌头像 URL(未配置)。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tenantName IS '对应JSON字段:tenantName,说明::租户/品牌名称(当前导出为空)。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.pdAssisnatLevel IS '对应JSON字段:pdAssisnatLevel,说明:已上文说明:均为扩展限定维度,当前全部为空列表。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.cxAssisnatLevel IS '对应JSON字段:cxAssisnatLevel,说明:已上文说明:均为扩展限定维度,当前全部为空列表。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.recharge_settlements (
+ id BIGINT PRIMARY KEY,
+ tenantid BIGINT,
+ siteid BIGINT,
+ sitename TEXT,
+ balanceamount NUMERIC(18,2),
+ cardamount NUMERIC(18,2),
+ cashamount NUMERIC(18,2),
+ couponamount NUMERIC(18,2),
+ createtime TIMESTAMPTZ,
+ memberid BIGINT,
+ membername TEXT,
+ tenantmembercardid BIGINT,
+ membercardtypename TEXT,
+ memberphone TEXT,
+ tableid BIGINT,
+ consumemoney NUMERIC(18,2),
+ onlineamount NUMERIC(18,2),
+ operatorid BIGINT,
+ operatorname TEXT,
+ revokeorderid BIGINT,
+ revokeordername TEXT,
+ revoketime TIMESTAMPTZ,
+ payamount NUMERIC(18,2),
+ pointamount NUMERIC(18,2),
+ refundamount NUMERIC(18,2),
+ settlename TEXT,
+ settlerelateid BIGINT,
+ settlestatus INT,
+ settletype INT,
+ paytime TIMESTAMPTZ,
+ roundingamount NUMERIC(18,2),
+ paymentmethod INT,
+ adjustamount NUMERIC(18,2),
+ assistantcxmoney NUMERIC(18,2),
+ assistantpdmoney NUMERIC(18,2),
+ couponsaleamount NUMERIC(18,2),
+ memberdiscountamount NUMERIC(18,2),
+ tablechargemoney NUMERIC(18,2),
+ goodsmoney NUMERIC(18,2),
+ realgoodsmoney NUMERIC(18,2),
+ servicemoney NUMERIC(18,2),
+ prepaymoney NUMERIC(18,2),
+ salesmanname TEXT,
+ orderremark TEXT,
+ salesmanuserid BIGINT,
+ canberevoked BOOLEAN,
+ pointdiscountprice NUMERIC(18,2),
+ pointdiscountcost NUMERIC(18,2),
+ activitydiscount NUMERIC(18,2),
+ serialnumber BIGINT,
+ assistantmanualdiscount NUMERIC(18,2),
+ allcoupondiscount NUMERIC(18,2),
+ goodspromotionmoney NUMERIC(18,2),
+ assistantpromotionmoney NUMERIC(18,2),
+ isusecoupon BOOLEAN,
+ isusediscount BOOLEAN,
+ isactivity BOOLEAN,
+ isbindmember BOOLEAN,
+ isfirst INT,
+ rechargecardamount NUMERIC(18,2),
+ giftcardamount NUMERIC(18,2),
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.recharge_settlements IS '对应JSON字段:recharge_settlements.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.id IS '对应JSON字段:id,说明::本条充值结算记录的主键 ID(唯一标识一条充值/撤销记录)。,示例值及对应分析:唯一性:74 条记录全部不同。';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.tenantid IS '对应JSON字段:tenantid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.siteid IS '对应JSON字段:siteid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.sitename IS '对应JSON字段:sitename,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.balanceamount IS '对应JSON字段:balanceamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.cardamount IS '对应JSON字段:cardamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.cashamount IS '对应JSON字段:cashamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.couponamount IS '对应JSON字段:couponamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.createtime IS '对应JSON字段:createtime,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.memberid IS '对应JSON字段:memberid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.membername IS '对应JSON字段:membername,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.tenantmembercardid IS '对应JSON字段:tenantmembercardid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.membercardtypename IS '对应JSON字段:membercardtypename,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.memberphone IS '对应JSON字段:memberphone,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.tableid IS '对应JSON字段:tableid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.consumemoney IS '对应JSON字段:consumemoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.onlineamount IS '对应JSON字段:onlineamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.operatorid IS '对应JSON字段:operatorid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.operatorname IS '对应JSON字段:operatorname,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.revokeorderid IS '对应JSON字段:revokeorderid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.revokeordername IS '对应JSON字段:revokeordername,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.revoketime IS '对应JSON字段:revoketime,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.payamount IS '对应JSON字段:payamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.pointamount IS '对应JSON字段:pointamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.refundamount IS '对应JSON字段:refundamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.settlename IS '对应JSON字段:settlename,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.settlerelateid IS '对应JSON字段:settlerelateid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.settlestatus IS '对应JSON字段:settlestatus,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.settletype IS '对应JSON字段:settletype,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.paytime IS '对应JSON字段:paytime,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.roundingamount IS '对应JSON字段:roundingamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.paymentmethod IS '对应JSON字段:paymentmethod,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.adjustamount IS '对应JSON字段:adjustamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.assistantcxmoney IS '对应JSON字段:assistantcxmoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.assistantpdmoney IS '对应JSON字段:assistantpdmoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.couponsaleamount IS '对应JSON字段:couponsaleamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.memberdiscountamount IS '对应JSON字段:memberdiscountamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.tablechargemoney IS '对应JSON字段:tablechargemoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.goodsmoney IS '对应JSON字段:goodsmoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.realgoodsmoney IS '对应JSON字段:realgoodsmoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.servicemoney IS '对应JSON字段:servicemoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.prepaymoney IS '对应JSON字段:prepaymoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.salesmanname IS '对应JSON字段:salesmanname,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.orderremark IS '对应JSON字段:orderremark,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.salesmanuserid IS '对应JSON字段:salesmanuserid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.canberevoked IS '对应JSON字段:canberevoked,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.pointdiscountprice IS '对应JSON字段:pointdiscountprice,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.pointdiscountcost IS '对应JSON字段:pointdiscountcost,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.activitydiscount IS '对应JSON字段:activitydiscount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.serialnumber IS '对应JSON字段:serialnumber,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.assistantmanualdiscount IS '对应JSON字段:assistantmanualdiscount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.allcoupondiscount IS '对应JSON字段:allcoupondiscount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.goodspromotionmoney IS '对应JSON字段:goodspromotionmoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.assistantpromotionmoney IS '对应JSON字段:assistantpromotionmoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.isusecoupon IS '对应JSON字段:isusecoupon,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.isusediscount IS '对应JSON字段:isusediscount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.isactivity IS '对应JSON字段:isactivity,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.isbindmember IS '对应JSON字段:isbindmember,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.isfirst IS '对应JSON字段:isfirst,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.rechargecardamount IS '对应JSON字段:rechargecardamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.giftcardamount IS '对应JSON字段:giftcardamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.settlement_records (
+ id BIGINT PRIMARY KEY,
+ tenantid BIGINT,
+ siteid BIGINT,
+ sitename TEXT,
+ balanceamount NUMERIC(18,2),
+ cardamount NUMERIC(18,2),
+ cashamount NUMERIC(18,2),
+ couponamount NUMERIC(18,2),
+ createtime TIMESTAMPTZ,
+ memberid BIGINT,
+ membername TEXT,
+ tenantmembercardid BIGINT,
+ membercardtypename TEXT,
+ memberphone TEXT,
+ tableid BIGINT,
+ consumemoney NUMERIC(18,2),
+ onlineamount NUMERIC(18,2),
+ operatorid BIGINT,
+ operatorname TEXT,
+ revokeorderid BIGINT,
+ revokeordername TEXT,
+ revoketime TIMESTAMPTZ,
+ payamount NUMERIC(18,2),
+ pointamount NUMERIC(18,2),
+ refundamount NUMERIC(18,2),
+ settlename TEXT,
+ settlerelateid BIGINT,
+ settlestatus INT,
+ settletype INT,
+ paytime TIMESTAMPTZ,
+ roundingamount NUMERIC(18,2),
+ paymentmethod INT,
+ adjustamount NUMERIC(18,2),
+ assistantcxmoney NUMERIC(18,2),
+ assistantpdmoney NUMERIC(18,2),
+ couponsaleamount NUMERIC(18,2),
+ memberdiscountamount NUMERIC(18,2),
+ tablechargemoney NUMERIC(18,2),
+ goodsmoney NUMERIC(18,2),
+ realgoodsmoney NUMERIC(18,2),
+ servicemoney NUMERIC(18,2),
+ prepaymoney NUMERIC(18,2),
+ salesmanname TEXT,
+ orderremark TEXT,
+ salesmanuserid BIGINT,
+ canberevoked BOOLEAN,
+ pointdiscountprice NUMERIC(18,2),
+ pointdiscountcost NUMERIC(18,2),
+ activitydiscount NUMERIC(18,2),
+ serialnumber BIGINT,
+ assistantmanualdiscount NUMERIC(18,2),
+ allcoupondiscount NUMERIC(18,2),
+ goodspromotionmoney NUMERIC(18,2),
+ assistantpromotionmoney NUMERIC(18,2),
+ isusecoupon BOOLEAN,
+ isusediscount BOOLEAN,
+ isactivity BOOLEAN,
+ isbindmember BOOLEAN,
+ isfirst INT,
+ rechargecardamount NUMERIC(18,2),
+ giftcardamount NUMERIC(18,2),
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.settlement_records IS '对应JSON字段:settlement_records.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.id IS '对应JSON字段:id,说明::结账记录主键 ID(订单结算 ID)。,示例值及对应分析:结构关联:';
+COMMENT ON COLUMN billiards_ods.settlement_records.tenantid IS '对应JSON字段:tenantid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.siteid IS '对应JSON字段:siteid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.sitename IS '对应JSON字段:sitename,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.balanceamount IS '对应JSON字段:balanceamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.cardamount IS '对应JSON字段:cardamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.cashamount IS '对应JSON字段:cashamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.couponamount IS '对应JSON字段:couponamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.createtime IS '对应JSON字段:createtime,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.memberid IS '对应JSON字段:memberid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.membername IS '对应JSON字段:membername,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.tenantmembercardid IS '对应JSON字段:tenantmembercardid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.membercardtypename IS '对应JSON字段:membercardtypename,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.memberphone IS '对应JSON字段:memberphone,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.tableid IS '对应JSON字段:tableid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.consumemoney IS '对应JSON字段:consumemoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.onlineamount IS '对应JSON字段:onlineamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.operatorid IS '对应JSON字段:operatorid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.operatorname IS '对应JSON字段:operatorname,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.revokeorderid IS '对应JSON字段:revokeorderid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.revokeordername IS '对应JSON字段:revokeordername,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.revoketime IS '对应JSON字段:revoketime,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.payamount IS '对应JSON字段:payamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.pointamount IS '对应JSON字段:pointamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.refundamount IS '对应JSON字段:refundamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.settlename IS '对应JSON字段:settlename,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.settlerelateid IS '对应JSON字段:settlerelateid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.settlestatus IS '对应JSON字段:settlestatus,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.settletype IS '对应JSON字段:settletype,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.paytime IS '对应JSON字段:paytime,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.roundingamount IS '对应JSON字段:roundingamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.paymentmethod IS '对应JSON字段:paymentmethod,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.adjustamount IS '对应JSON字段:adjustamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.assistantcxmoney IS '对应JSON字段:assistantcxmoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.assistantpdmoney IS '对应JSON字段:assistantpdmoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.couponsaleamount IS '对应JSON字段:couponsaleamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.memberdiscountamount IS '对应JSON字段:memberdiscountamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.tablechargemoney IS '对应JSON字段:tablechargemoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.goodsmoney IS '对应JSON字段:goodsmoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.realgoodsmoney IS '对应JSON字段:realgoodsmoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.servicemoney IS '对应JSON字段:servicemoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.prepaymoney IS '对应JSON字段:prepaymoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.salesmanname IS '对应JSON字段:salesmanname,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.orderremark IS '对应JSON字段:orderremark,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.salesmanuserid IS '对应JSON字段:salesmanuserid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.canberevoked IS '对应JSON字段:canberevoked,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.pointdiscountprice IS '对应JSON字段:pointdiscountprice,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.pointdiscountcost IS '对应JSON字段:pointdiscountcost,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.activitydiscount IS '对应JSON字段:activitydiscount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.serialnumber IS '对应JSON字段:serialnumber,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.assistantmanualdiscount IS '对应JSON字段:assistantmanualdiscount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.allcoupondiscount IS '对应JSON字段:allcoupondiscount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.goodspromotionmoney IS '对应JSON字段:goodspromotionmoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.assistantpromotionmoney IS '对应JSON字段:assistantpromotionmoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.isusecoupon IS '对应JSON字段:isusecoupon,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.isusediscount IS '对应JSON字段:isusediscount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.isactivity IS '对应JSON字段:isactivity,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.isbindmember IS '对应JSON字段:isbindmember,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.isfirst IS '对应JSON字段:isfirst,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.rechargecardamount IS '对应JSON字段:rechargecardamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.giftcardamount IS '对应JSON字段:giftcardamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.settlement_records.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.settlement_records.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.settlement_records.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.assistant_cancellation_records (
+ id BIGINT PRIMARY KEY,
+ siteId BIGINT,
+ siteProfile JSONB,
+ assistantName TEXT,
+ assistantAbolishAmount NUMERIC(18,2),
+ assistantOn INT,
+ pdChargeMinutes INT,
+ tableAreaId BIGINT,
+ tableArea TEXT,
+ tableId BIGINT,
+ tableName TEXT,
+ trashReason TEXT,
+ createTime TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.assistant_cancellation_records IS '对应JSON字段:assistant_cancellation_records.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.id IS '对应JSON字段:id,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.siteId IS '对应JSON字段:siteId,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.siteProfile IS '对应JSON字段:siteProfile,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.assistantName IS '对应JSON字段:assistantName,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.assistantAbolishAmount IS '对应JSON字段:assistantAbolishAmount,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.assistantOn IS '对应JSON字段:assistantOn,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.pdChargeMinutes IS '对应JSON字段:pdChargeMinutes,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.tableAreaId IS '对应JSON字段:tableAreaId,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.tableArea IS '对应JSON字段:tableArea,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.tableId IS '对应JSON字段:tableId,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.tableName IS '对应JSON字段:tableName,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.trashReason IS '对应JSON字段:trashReason,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.createTime IS '对应JSON字段:createTime,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.assistant_accounts_master (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ assistant_no TEXT,
+ nickname TEXT,
+ real_name TEXT,
+ mobile TEXT,
+ team_id BIGINT,
+ team_name TEXT,
+ user_id BIGINT,
+ level TEXT,
+ assistant_status INT,
+ work_status INT,
+ leave_status INT,
+ entry_time TIMESTAMP,
+ resign_time TIMESTAMP,
+ start_time TIMESTAMP,
+ end_time TIMESTAMP,
+ create_time TIMESTAMP,
+ update_time TIMESTAMP,
+ order_trade_no TEXT,
+ staff_id BIGINT,
+ staff_profile_id BIGINT,
+ system_role_id BIGINT,
+ avatar TEXT,
+ gender INT,
+ height NUMERIC(18,2),
+ weight NUMERIC(18,2),
+ job_num TEXT,
+ show_status INT,
+ show_sort INT,
+ sum_grade NUMERIC(18,2),
+ assistant_grade NUMERIC(18,2),
+ get_grade_times INT,
+ introduce TEXT,
+ video_introduction_url TEXT,
+ group_id BIGINT,
+ group_name TEXT,
+ shop_name TEXT,
+ charge_way INT,
+ entry_type INT,
+ allow_cx INT,
+ is_guaranteed INT,
+ salary_grant_enabled INT,
+ light_status INT,
+ online_status INT,
+ is_delete INT,
+ cx_unit_price NUMERIC(18,2),
+ pd_unit_price NUMERIC(18,2),
+ last_table_id BIGINT,
+ last_table_name TEXT,
+ person_org_id BIGINT,
+ serial_number BIGINT,
+ is_team_leader INT,
+ criticism_status INT,
+ ding_talk_synced INT,
+ site_light_cfg_id BIGINT,
+ light_equipment_id TEXT,
+ entry_sign_status INT,
+ resign_sign_status INT,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.assistant_accounts_master IS '对应JSON字段:assistant_accounts_master.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.id IS '对应JSON字段:id,说明::助教账号主键 ID,在“助教流水.json”中对应 site_assistant_id。,示例值及对应分析:作用:所有与助教相关的事实表(助教流水、助教排班等)都会通过这个 ID 关联到该维表。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.tenant_id IS '对应JSON字段:tenant_id,说明::品牌/租户 ID,对应“非球科技”系统中该商户的唯一标识。,示例值及对应分析:用途:多门店时用来区分不同商户。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.site_id IS '对应JSON字段:site_id,说明::门店 ID,对应本次数据的这家球房(朗朗桌球)。,示例值及对应分析:关联:与其它 JSON(台费流水、库存、销售等)中的 site_id 一致。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.assistant_no IS '对应JSON字段:assistant_no,说明:(结合字段名推测):助教工号 / 编号,便于业务侧识别。,示例值及对应分析:关联:在“助教流水.json”中有 assistantNo,与此字段对应。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.nickname IS '对应JSON字段:nickname,说明::助教在前台展示的昵称,如“佳怡”“周周”“球球”等。,示例值及对应分析:用途:与真实姓名区分,用于顾客侧展示。如在助教流水中 nickname 就是这个值。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.real_name IS '对应JSON字段:real_name,说明::助教真实姓名,如“何海婷”“梁婷婷”等。,示例值及对应分析:关联:在“助教流水.json”的 assistantName 与此一致。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.mobile IS '对应JSON字段:mobile,说明::助教手机号,用于登录绑定、通知、钉钉同步等。,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.team_id IS '对应JSON字段:team_id,说明::助教所属团队 ID。,示例值及对应分析:关联:在“助教流水.json”中 assistant_team_id 与此一致。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.team_name IS '对应JSON字段:team_name,说明::团队名称,展示用,和 team_id 一一对应。,示例值及对应分析:group_id';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.level IS '对应JSON字段:level,说明:(结合“助教流水中的 assistant_level / levelName 推测”):,示例值及对应分析:8:助教管理/管理员(和流水里的 "助教管理" 对应)';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.assistant_status IS '对应JSON字段:assistant_status,说明:(推测):账号启用状态:,示例值及对应分析:1:启用';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.work_status IS '对应JSON字段:work_status,说明::,示例值及对应分析:1:在岗/可排班';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.leave_status IS '对应JSON字段:leave_status,说明:类型:int,枚举。,示例值及对应分析:观测:';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.entry_time IS '对应JSON字段:entry_time,说明::入职时间。,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.resign_time IS '对应JSON字段:resign_time,说明::离职日期;使用“远未来日期”作为“未离职”的占位。,示例值及对应分析:entry_type';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.start_time IS '对应JSON字段:start_time,说明:(推测):当前配置生效的开始日期。,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.end_time IS '对应JSON字段:end_time,说明::当前配置生效的结束日期(例如一个周期性的排班/合同周期)。,示例值及对应分析:last_table_id';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.create_time IS '对应JSON字段:create_time,说明::账号创建时间。,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.update_time IS '对应JSON字段:update_time,说明::账号最近一次被修改的时间(例如修改等级、昵称等)。,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.order_trade_no IS '对应JSON字段:order_trade_no,说明:(推测):该助教最近一次关联的订单号,用于快速跳转或回溯最近服务行为。,示例值及对应分析:9. 灯控、钉钉等系统集成相关字段';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.staff_id IS '对应JSON字段:staff_id,说明:(推测):预留给“人事系统员工 ID”的字段,目前未接入或未启用。,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.staff_profile_id IS '对应JSON字段:staff_profile_id,说明:(推测):人事档案 ID,与第三方 HR 系统或内部员工档案集成使用,当前未启用。,示例值及对应分析:4. 等级、计费与薪资配置字段';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.system_role_id IS '对应JSON字段:system_role_id,说明:?????? assistant_accounts_master-Analysis.md,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.avatar IS '对应JSON字段:avatar,说明::助教头像地址。,示例值及对应分析:introduce';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.gender IS '对应JSON字段:gender,说明:(结合常见约定与值分布推测):,示例值及对应分析:0:未填/保密';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.show_status IS '对应JSON字段:show_status,说明:(推测):前台展示状态:,示例值及对应分析:1:在助教选择界面展示。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.show_sort IS '对应JSON字段:show_sort,说明::前台展示排序权重,值越小/越大对应不同的排序策略(当前看起来与 assistant_no 有一定对应关系)。,示例值及对应分析:online_status';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.sum_grade IS '对应JSON字段:sum_grade,说明::评分总和,用于计算平均分(assistant_grade = sum_grade / get_grade_times),当前为 0。,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.get_grade_times IS '对应JSON字段:get_grade_times,说明::累计被评分次数。,示例值及对应分析:charge_way';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.video_introduction_url IS '对应JSON字段:video_introduction_url,说明::助教个人视频介绍地址。,示例值及对应分析:height';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.user_id IS '对应JSON字段:user_id,说明:账号对应的用户 ID/员工 ID,用于跨表关联。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.height IS '对应JSON字段:height,说明:身高(数值),可空。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.weight IS '对应JSON字段:weight,说明:体重(数值),可空。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.job_num IS '对应JSON字段:job_num,说明:工号/岗位编号,保留原始取值。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.assistant_grade IS '对应JSON字段:assistant_grade,说明:平均评分,通常 = sum_grade/get_grade_times。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.introduce IS '对应JSON字段:introduce,说明:个人简介/自我介绍,可空。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.group_id IS '对应JSON字段:group_id,说明:分组/自定义分组 ID。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.group_name IS '对应JSON字段:group_name,说明:分组名称。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.shop_name IS '对应JSON字段:shop_name,说明:门店名称冗余。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.charge_way IS '对应JSON字段:charge_way,说明:收费方式枚举,保留原值。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.entry_type IS '对应JSON字段:entry_type,说明:入职类型枚举,保留原值。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.allow_cx IS '对应JSON字段:allow_cx,说明:是否允许超休/冲销(0/1)。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.is_guaranteed IS '对应JSON字段:is_guaranteed,说明:是否保底(0/1)。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.salary_grant_enabled IS '对应JSON字段:salary_grant_enabled,说明:薪资发放/补贴开关,枚举。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.light_status IS '对应JSON字段:light_status,说明:灯控状态/模式,保留原值。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.online_status IS '对应JSON字段:online_status,说明:在线状态标记(0/1等)。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.is_delete IS '对应JSON字段:is_delete,说明:逻辑删除标记(0=有效,1=删除)。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.cx_unit_price IS '对应JSON字段:cx_unit_price,说明:超休单价/冲销单价,金额类。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.pd_unit_price IS '对应JSON字段:pd_unit_price,说明:排钟/点钟单价,金额类。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.last_table_id IS '对应JSON字段:last_table_id,说明:最近服务桌台 ID。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.last_table_name IS '对应JSON字段:last_table_name,说明:最近服务桌台名称。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.person_org_id IS '对应JSON字段:person_org_id,说明:人员组织 ID/部门 ID。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.serial_number IS '对应JSON字段:serial_number,说明:序列号/排序号,保留原值。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.is_team_leader IS '对应JSON字段:is_team_leader,说明:是否组长(0/1)。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.criticism_status IS '对应JSON字段:criticism_status,说明:处罚/警告状态标记,枚举。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.ding_talk_synced IS '对应JSON字段:ding_talk_synced,说明:是否已同步钉钉(0/1)。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.site_light_cfg_id IS '对应JSON字段:site_light_cfg_id,说明:门店灯控配置 ID。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.light_equipment_id IS '对应JSON字段:light_equipment_id,说明:灯控设备 ID/硬件编号。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.entry_sign_status IS '对应JSON字段:entry_sign_status,说明:入职签署状态,枚举。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.resign_sign_status IS '对应JSON字段:resign_sign_status,说明:离职签署状态,枚举。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.assistant_service_records (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ siteProfile JSONB,
+ site_table_id BIGINT,
+ order_settle_id BIGINT,
+ order_trade_no TEXT,
+ order_pay_id BIGINT,
+ order_assistant_id BIGINT,
+ order_assistant_type INT,
+ assistantName TEXT,
+ assistantNo TEXT,
+ assistant_level TEXT,
+ assistant_team_id BIGINT,
+ nickname TEXT,
+ ledger_name TEXT,
+ ledger_group_name TEXT,
+ ledger_amount NUMERIC(18,2),
+ ledger_count NUMERIC(18,4),
+ ledger_unit_price NUMERIC(18,4),
+ ledger_status INT,
+ ledger_start_time TIMESTAMP,
+ ledger_end_time TIMESTAMP,
+ manual_discount_amount NUMERIC(18,2),
+ member_discount_amount NUMERIC(18,2),
+ coupon_deduct_money NUMERIC(18,2),
+ service_money NUMERIC(18,2),
+ projected_income NUMERIC(18,2),
+ real_use_seconds INT,
+ income_seconds INT,
+ start_use_time TIMESTAMP,
+ last_use_time TIMESTAMP,
+ create_time TIMESTAMP,
+ is_single_order INT,
+ is_delete INT,
+ is_trash INT,
+ trash_reason TEXT,
+ trash_applicant_id BIGINT,
+ trash_applicant_name TEXT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ salesman_name TEXT,
+ salesman_org_id BIGINT,
+ salesman_user_id BIGINT,
+ person_org_id BIGINT,
+ add_clock INT,
+ returns_clock INT,
+ composite_grade NUMERIC(10,2),
+ composite_grade_time TIMESTAMP,
+ skill_grade NUMERIC(10,2),
+ service_grade NUMERIC(10,2),
+ sum_grade NUMERIC(10,2),
+ grade_status INT,
+ get_grade_times INT,
+ is_not_responding INT,
+ is_confirm INT,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+
+COMMENT ON TABLE billiards_ods.assistant_service_records IS '对应JSON字段:assistant_service_records.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.id IS '对应JSON字段:id,说明::本条助教流水记录的主键 ID(流水唯一标识)。,示例值及对应分析:作用:在系统内部唯一定位这一条助教服务记录。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID;你这份数据中是固定值(同一个商户)。,示例值及对应分析:关联:全库所有表都有,作为“商户维度”的过滤键。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.site_id IS '对应JSON字段:site_id,说明::门店 ID,本数据中指“朗朗桌球”这一家门店。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.siteProfile IS '对应JSON字段:siteProfile,说明::门店信息快照,包括 id、shop_name、address 等,和其他 JSON 里的 siteProfile 一致。,示例值及对应分析:作用:冗余门店信息,方便查看(而不是每次都联表看门店档案)。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.site_table_id IS '对应JSON字段:site_table_id,说明::球台 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.order_settle_id IS '对应JSON字段:order_settle_id,说明::订单结算 ID,相当于“结账单号”的内部主键。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.order_trade_no IS '对应JSON字段:order_trade_no,说明::订单交易号,整个订单层面的编号。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.order_pay_id IS '对应JSON字段:order_pay_id,说明::关联到“支付记录”的主键 ID。,示例值及对应分析:作用:可以和支付记录中的 id / relate_id 等字段对应,找到这条助教服务对应的支付流水。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.order_assistant_id IS '对应JSON字段:order_assistant_id,说明::订单中“助教项目明细”的内部 ID。,示例值及对应分析:作用:如果订单里有多条助教项目(比如换助教、多个时间段),此字段唯一标识这一条助教明细。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.order_assistant_type IS '对应JSON字段:order_assistant_type,说明:(推测):,示例值及对应分析:1:常规助教服务(主课/基础课)。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.assistantName IS '对应JSON字段:assistantName,说明::助教姓名,如“何海婷”“胡敏”等。,示例值及对应分析:备注:和助教账号档案里的 real_name 一致。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.assistantNo IS '对应JSON字段:assistantNo,说明::助教编号,例如 "27"。,示例值及对应分析:关联:在助教账号表里也有 assistant_no 字段,对应工号/编号。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.assistant_level IS '对应JSON字段:assistant_level,说明::助教等级名称,与 assistant_level 一一对应(初级/中级/高级/助教管理)。,示例值及对应分析:备注:属于展示用的冗余字段。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.assistant_team_id IS '对应JSON字段:assistant_team_id,说明::当前这条助教服务所对应的“课程/技能名称”。,示例值及对应分析:当 order_assistant_type = 1 时,多为“基础课”。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.nickname IS '对应JSON字段:nickname,说明::助教对外昵称,如“佳怡”“周周”“球球”等。,示例值及对应分析:说明:从数据看,这个 nickname 是“助教昵称”,不是顾客昵称(容易混淆)。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_name IS '对应JSON字段:ledger_name,说明:?????? assistant_service_records-Analysis.md,示例值及对应分析:?? assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_group_name IS '对应JSON字段:ledger_group_name,说明:(推测):助教项目所属的“计费分组/套餐分组名称”,例如某种助教套餐或业务组名称。,示例值及对应分析:目前未被实际使用。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_amount IS '对应JSON字段:ledger_amount,说明::按标准单价计算出来的应收金额(近似 = ledger_unit_price × income_seconds / 3600)。,示例值及对应分析:说明:从数据看,这个金额对应“按原价计费”的金额,未扣除各种优惠。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_count IS '对应JSON字段:ledger_count,说明::台账记录的计时总秒数。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_unit_price IS '对应JSON字段:ledger_unit_price,说明::助教服务 标准单价(通常是标价:每小时、每节课的单价)。,示例值及对应分析:特点:如 98.0、108.0、190.0 等。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_status IS '对应JSON字段:ledger_status,说明:(推测):助教流水记录状态:,示例值及对应分析:1:正常有效。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_start_time IS '对应JSON字段:ledger_start_time,说明::台账层面记录的开始时间。,示例值及对应分析:说明:与 start_use_time 在当前数据中完全一致,可以视为“计费起始时间”。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_end_time IS '对应JSON字段:ledger_end_time,说明::台账层面的结束时间。,示例值及对应分析:说明:与 last_use_time 一致,可以视为“计费结束时间”。对于 real_use_seconds = 0 的记录,开始和结束时间相同,说明只是预约/录入,并未实际服务。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.manual_discount_amount IS '对应JSON字段:manual_discount_amount,说明::收银员手动给予的减免金额(人工改价)。,示例值及对应分析:当前导出时间段内暂未出现手动打折的情况。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.member_discount_amount IS '对应JSON字段:member_discount_amount,说明::由会员卡折扣产生的优惠金额。,示例值及对应分析:说明:尽管字段里是 0,但实际折扣可能已经体现在 projected_income 与 ledger_amount 的差额中,这里只是未单独拆出。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.coupon_deduct_money IS '对应JSON字段:coupon_deduct_money,说明::由“优惠券/代金券/团购券”等 直接抵扣到这条助教服务上的金额。,示例值及对应分析:说明:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.service_money IS '对应JSON字段:service_money,说明:(推测):用于记录与助教结算的金额(平台预留的“成本/分成”字段)。,示例值及对应分析:当前数据中未启用这个机制,所以全为 0。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.projected_income IS '对应JSON字段:projected_income,说明::实际结算计入门店的金额(已经考虑折扣、卡权益、券等后的结果)。,示例值及对应分析:从数据:projected_income 明显低于 ledger_amount,说明中间有折扣,但折扣的明细并不全由下面几个字段体现(很多是卡权益内生折扣)。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.real_use_seconds IS '对应JSON字段:real_use_seconds,说明::实际使用时长(秒)。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.income_seconds IS '对应JSON字段:income_seconds,说明::计费秒数 / 应计收入对应的时间。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.start_use_time IS '对应JSON字段:start_use_time,说明::助教实际开始服务时间。,示例值及对应分析:特点:正常情况下与 ledger_start_time 相同。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.last_use_time IS '对应JSON字段:last_use_time,说明::最后一次使用(实际服务)时间。,示例值及对应分析:特点:正常结束时与 ledger_end_time 相同;如果服务还未真正开始或立即结束,开始/结束时间可能相同。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.create_time IS '对应JSON字段:create_time,说明::这条助教流水记录创建时间(一般接近结算/下单时间)。,示例值及对应分析:?? assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.is_single_order IS '对应JSON字段:is_single_order,说明:(推测):是否单独订单:,示例值及对应分析:1:本助教服务作为单独订单结算(或单独拆项)。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志。,示例值及对应分析:0:未删除;';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.is_trash IS '对应JSON字段:is_trash,说明::是否已废除/作废:,示例值及对应分析:0:正常有效;';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.trash_reason IS '对应JSON字段:trash_reason,说明::废除原因(文本说明),例如“顾客取消”“录入错误”等。,示例值及对应分析:当前数据为空字符串,说明当前导出时间段没有被废除的助教流水记录。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.trash_applicant_id IS '对应JSON字段:trash_applicant_id,说明::提出废除申请的员工 ID(通常是操作员/管理员)。,示例值及对应分析:当前数据全为 0,因此短期内没有发生废除操作。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.trash_applicant_name IS '对应JSON字段:trash_applicant_name,说明::废除申请人姓名。,示例值及对应分析:?? assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.operator_id IS '对应JSON字段:operator_id,说明::操作员 ID(录入/结算这条助教服务的员工)。,示例值及对应分析:关联:可与员工/账号表对应(本次导出未单独给员工表,但其他 JSON 里多处出现该 ID)。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.operator_name IS '对应JSON字段:operator_name,说明::操作员姓名,与 operator_id 一起使用,便于直接阅读。,示例值及对应分析:user_id';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.salesman_name IS '对应JSON字段:salesman_name,说明::关联的“营业员/销售员姓名”,用于提成归属。,示例值及对应分析:观测:本数据中多数为空字符串,说明助教流水没有配置单独的营业员。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.salesman_org_id IS '对应JSON字段:salesman_org_id,说明::营业员所属组织/部门 ID。,示例值及对应分析:观测:多为 0。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.salesman_user_id IS '对应JSON字段:salesman_user_id,说明::营业员用户 ID。,示例值及对应分析:观测:多为 0,代表未指定。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.person_org_id IS '对应JSON字段:person_org_id,说明:同样在上文说明:助教所属人事组织 ID。,示例值及对应分析:9. 作废 / 废除相关字段';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.add_clock IS '对应JSON字段:add_clock,说明:(推测):加钟秒数,即在原有预约/服务基础上临时追加的时长。,示例值及对应分析:说明:值均为 60 的倍数(分钟级加钟),如 600 秒=10 分钟。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.returns_clock IS '对应JSON字段:returns_clock,说明:(推测):退钟秒数(取消加钟或提前结束退回的时间)。,示例值及对应分析:当前数据里没有退钟场景,所以全为 0,但字段设计已经预留。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.composite_grade IS '对应JSON字段:composite_grade,说明::综合评分(例如技能+服务加权后的平均分),当前数据没有实际评分。,示例值及对应分析:?? assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.composite_grade_time IS '对应JSON字段:composite_grade_time,说明:(推测):最近一次评价时间/综合评分更新时间。现在都是默认“无效时间”。,示例值及对应分析:3. 桌台 / 门店维度字段';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.skill_grade IS '对应JSON字段:skill_grade,说明:(推测):顾客对“技能表现”的评分(整数或打分等级)。,示例值及对应分析:当前数据中还未产生评分记录,所以都是默认值 0。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.service_grade IS '对应JSON字段:service_grade,说明:(推测):顾客对“服务态度”的评分。,示例值及对应分析:?? assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.sum_grade IS '对应JSON字段:sum_grade,说明::累计评分总和(可能用于计算平均分),当前为 0。,示例值及对应分析:?? assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.grade_status IS '对应JSON字段:grade_status,说明:(推测):评价状态,比如:,示例值及对应分析:1 = 未评价/正常;';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.get_grade_times IS '对应JSON字段:get_grade_times,说明::该条记录对应的评价次数(或该助教被评价次数快照)。,示例值及对应分析:?? assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.is_not_responding IS '对应JSON字段:is_not_responding,说明:(推测):是否存在“爽约/未响应”情况:,示例值及对应分析:0:正常;';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.is_confirm IS '对应JSON字段:is_confirm,说明:(推测):确认状态,例如:,示例值及对应分析:1:待确认;';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.site_tables_master (
+ id BIGINT PRIMARY KEY,
+ site_id BIGINT,
+ siteName TEXT,
+ "appletQrCodeUrl" TEXT,
+ areaName TEXT,
+ audit_status INT,
+ charge_free INT,
+ create_time TIMESTAMP,
+ delay_lights_time INT,
+ is_online_reservation INT,
+ is_rest_area INT,
+ light_status INT,
+ only_allow_groupon INT,
+ order_delay_time INT,
+ self_table INT,
+ show_status INT,
+ site_table_area_id BIGINT,
+ tableStatusName TEXT,
+ table_cloth_use_Cycle INT,
+ table_cloth_use_time TIMESTAMP,
+ table_name TEXT,
+ table_price NUMERIC(18,2),
+ table_status INT,
+ temporary_light_second INT,
+ virtual_table INT,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.site_tables_master IS '对应JSON字段:site_tables_master.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 site_tables_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.site_tables_master.id IS '对应JSON字段:id,说明::台桌主键 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.site_tables_master.site_id IS '对应JSON字段:site_id,说明::门店 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.site_tables_master.siteName IS '对应JSON字段:siteName,说明::门店名称快照,冗余字段,配合 site_id 使用。,示例值及对应分析:?? site_tables_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.site_tables_master."appletQrCodeUrl" IS '对应JSON字段:appletQrCodeUrl,说明::小程序二维码 URL。 一般用于:,示例值及对应分析:打印二维码贴在台上,顾客扫码可呼叫服务、查看账单或发起线上预约;';
+COMMENT ON COLUMN billiards_ods.site_tables_master.areaName IS '对应JSON字段:areaName,说明::区域名称,用于前台展示和区域维度管理。,示例值及对应分析:结构特征:';
+COMMENT ON COLUMN billiards_ods.site_tables_master.audit_status IS '对应JSON字段:audit_status,说明:(结合命名惯例):,示例值及对应分析:2:已审核/已启用;';
+COMMENT ON COLUMN billiards_ods.site_tables_master.charge_free IS '对应JSON字段:charge_free,说明:(推测):,示例值及对应分析:0:正常计费;';
+COMMENT ON COLUMN billiards_ods.site_tables_master.create_time IS '对应JSON字段:create_time,说明::台桌配置的创建时间或最近一次创建/复制时间。,示例值及对应分析:三、与其它 JSON 的字段级关联关系(结构视角)';
+COMMENT ON COLUMN billiards_ods.site_tables_master.delay_lights_time IS '对应JSON字段:delay_lights_time,说明:(推测):台灯熄灭延迟时间(单位多半是秒或分钟),用于结账后延时关灯。,示例值及对应分析:本门店未启用延迟关灯功能(全部为 0)。';
+COMMENT ON COLUMN billiards_ods.site_tables_master.is_online_reservation IS '对应JSON字段:is_online_reservation,说明:(结合值分布推断):,示例值及对应分析:1:允许线上预约(可在小程序/线上平台预约这张台);';
+COMMENT ON COLUMN billiards_ods.site_tables_master.is_rest_area IS '对应JSON字段:is_rest_area,说明:(推测):,示例值及对应分析:0:正常计费区域;';
+COMMENT ON COLUMN billiards_ods.site_tables_master.light_status IS '对应JSON字段:light_status,说明:(结合命名推断):,示例值及对应分析:该字段是台灯/灯光状态开关位:';
+COMMENT ON COLUMN billiards_ods.site_tables_master.only_allow_groupon IS '对应JSON字段:only_allow_groupon,说明:(结合命名推断):,示例值及对应分析:1:仅允许团购/券预约使用(团购专用台);';
+COMMENT ON COLUMN billiards_ods.site_tables_master.order_delay_time IS '对应JSON字段:order_delay_time,说明:(推测):订单层面允许的“自动延时时长”(例如到点后自动延长多少时间继续计费)。,示例值及对应分析:本门店未使用此功能。';
+COMMENT ON COLUMN billiards_ods.site_tables_master.self_table IS '对应JSON字段:self_table,说明:(推测):,示例值及对应分析:1:“本门店自有台”,非共享或外部配置;';
+COMMENT ON COLUMN billiards_ods.site_tables_master.show_status IS '对应JSON字段:show_status,说明:(推测):,示例值及对应分析:1:正常在前台“开台列表”中展示;';
+COMMENT ON COLUMN billiards_ods.site_tables_master.site_table_area_id IS '对应JSON字段:site_table_area_id,说明::门店维度的“台桌区域 ID”。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.site_tables_master.tableStatusName IS '对应JSON字段:tableStatusName,说明::table_status 的中文名称,仅为展示用途。,示例值及对应分析:?? site_tables_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.site_tables_master.table_cloth_use_Cycle IS '对应JSON字段:table_cloth_use_Cycle,说明:(推测):,示例值及对应分析:台呢使用周期阈值,例如达到某个秒数后提醒更换;';
+COMMENT ON COLUMN billiards_ods.site_tables_master.table_cloth_use_time IS '对应JSON字段:table_cloth_use_time,说明:(结合命名和数值特征):,示例值及对应分析:台呢使用累计时长,单位极大概率为“秒”:';
+COMMENT ON COLUMN billiards_ods.site_tables_master.table_name IS '对应JSON字段:table_name,说明::台号/台名称,用于前台操作界面展示,也出现在小票和各种流水中的 ledger_name 或 tableName 字段。,示例值及对应分析:?? site_tables_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.site_tables_master.table_price IS '对应JSON字段:table_price,说明:(结构角度):,示例值及对应分析:设计上应为“台的基础单价”字段(例如按小时或按局单价);';
+COMMENT ON COLUMN billiards_ods.site_tables_master.table_status IS '对应JSON字段:table_status,说明::台当前运行状态,真实反映某一时刻台的占用/暂停情况。,示例值及对应分析:?? site_tables_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.site_tables_master.temporary_light_second IS '对应JSON字段:temporary_light_second,说明:(推测):临时点灯时长(秒),例如手动临时开灯一段时间。,示例值及对应分析:本门店未使用。';
+COMMENT ON COLUMN billiards_ods.site_tables_master.virtual_table IS '对应JSON字段:virtual_table,说明:(推测):,示例值及对应分析:0:物理台(实体存在的桌);';
+COMMENT ON COLUMN billiards_ods.site_tables_master.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.site_tables_master.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.site_tables_master.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.site_tables_master.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.table_fee_discount_records (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ siteProfile JSONB,
+ site_table_id BIGINT,
+ tableProfile JSONB,
+ tenant_table_area_id BIGINT,
+ adjust_type INT,
+ ledger_amount NUMERIC(18,2),
+ ledger_count NUMERIC(18,4),
+ ledger_name TEXT,
+ ledger_status INT,
+ applicant_id BIGINT,
+ applicant_name TEXT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ order_settle_id BIGINT,
+ order_trade_no TEXT,
+ is_delete INT,
+ create_time TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.table_fee_discount_records IS '对应JSON字段:table_fee_discount_records.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 table_fee_discount_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.id IS '对应JSON字段:id,说明::台费打折 / 调整流水主键 ID。,示例值及对应分析:作用:在“台费调账表”中唯一标识一条折扣/调账操作。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID。,示例值及对应分析:作用:标识记录属于哪一个商户(同一个“非球科技”租户)。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.site_id IS '对应JSON字段:site_id,说明::门店 ID,本批数据全部为同一家门店(朗朗桌球)。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.siteProfile IS '对应JSON字段:siteProfile,说明::门店信息快照,用于报表时直接读取,无需再联门店档案。,示例值及对应分析:?? table_fee_discount_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.site_table_id IS '对应JSON字段:site_table_id,说明::台桌 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.tableProfile IS '对应JSON字段:tableProfile,说明::折扣发生时,对应台桌的配置信息快照。,示例值及对应分析:?? table_fee_discount_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.tenant_table_area_id IS '对应JSON字段:tenant_table_area_id,说明::租户维度的“台桌区域 ID”。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.adjust_type IS '对应JSON字段:adjust_type,说明:(根据文件含义 + 命名 + 数据):,示例值及对应分析:文件名是“台费打折”,字段名为“调整类型”,当前所有记录都是 1,即“台费打折/台费减免”这一种调整类型。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.ledger_amount IS '对应JSON字段:ledger_amount,说明:(关键点):,示例值及对应分析:通过与 台费流水.json 做对比,可以明确:';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.ledger_count IS '对应JSON字段:ledger_count,说明::,示例值及对应分析:这里不是“秒数”,而是“调整次数/条数”的量化,目前固定为 1,表示“一次调账事件”。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.ledger_name IS '对应JSON字段:ledger_name,说明:(推测):,示例值及对应分析:设计上应该用于记录“调账项目名称”或“打折原因描述”(例如某种优惠规则名称),但当前门店并未使用该字段。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.ledger_status IS '对应JSON字段:ledger_status,说明::,示例值及对应分析:1:生效调整(当前有效的台费打折 / 调账记录);';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.applicant_id IS '对应JSON字段:applicant_id,说明::打折/调账申请人 ID。,示例值及对应分析:作用:记录谁发起了这次台费调整。 本时段内所有调整均由同一位员工发起。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.applicant_name IS '对应JSON字段:applicant_name,说明::申请人姓名(带角色描述),为 applicant_id 的冗余显示字段。,示例值及对应分析:?? table_fee_discount_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.operator_id IS '对应JSON字段:operator_id,说明::实际执行调账操作的操作员 ID。,示例值及对应分析:说明:这段时间内,“申请人”和“操作员”是同一个人。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.operator_name IS '对应JSON字段:operator_name,说明::操作员姓名。,示例值及对应分析:?? table_fee_discount_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.order_settle_id IS '对应JSON字段:order_settle_id,说明::结算单/小票 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.order_trade_no IS '对应JSON字段:order_trade_no,说明::订单交易号。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志:,示例值及对应分析:0:未删除(有效记录);';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.create_time IS '对应JSON字段:create_time,说明::台费调整记录的创建时间,即打折操作被执行的时间戳。,示例值及对应分析:说明:与台费流水中的 create_time(结算时间)相互配合,可以还原调整发生于结账之前还是之后。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.table_fee_transactions (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ siteProfile JSONB,
+ site_table_id BIGINT,
+ site_table_area_id BIGINT,
+ site_table_area_name TEXT,
+ tenant_table_area_id BIGINT,
+ order_trade_no TEXT,
+ order_pay_id BIGINT,
+ order_settle_id BIGINT,
+ ledger_name TEXT,
+ ledger_amount NUMERIC(18,2),
+ ledger_count NUMERIC(18,4),
+ ledger_unit_price NUMERIC(18,4),
+ ledger_status INT,
+ ledger_start_time TIMESTAMP,
+ ledger_end_time TIMESTAMP,
+ start_use_time TIMESTAMP,
+ last_use_time TIMESTAMP,
+ real_table_use_seconds INT,
+ real_table_charge_money NUMERIC(18,2),
+ add_clock_seconds INT,
+ adjust_amount NUMERIC(18,2),
+ coupon_promotion_amount NUMERIC(18,2),
+ member_discount_amount NUMERIC(18,2),
+ used_card_amount NUMERIC(18,2),
+ mgmt_fee NUMERIC(18,2),
+ service_money NUMERIC(18,2),
+ fee_total NUMERIC(18,2),
+ is_single_order INT,
+ is_delete INT,
+ member_id BIGINT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ salesman_name TEXT,
+ salesman_org_id BIGINT,
+ salesman_user_id BIGINT,
+ create_time TIMESTAMP,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+
+COMMENT ON TABLE billiards_ods.table_fee_transactions IS '对应JSON字段:table_fee_transactions.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 table_fee_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.id IS '对应JSON字段:id,说明::台费流水记录主键(事实表主键)。,示例值及对应分析:?? table_fee_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID。本文件所有记录都属于同一租户。,示例值及对应分析:关联:与所有其它 JSON 中的 tenant_id 一致,用于跨表做“商户维度”的过滤。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.site_id IS '对应JSON字段:site_id,说明::门店 ID,本次数据全部来自同一门店(朗朗桌球)。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.siteProfile IS '对应JSON字段:siteProfile,说明::当前门店的完整档案快照,冗余到流水表中,便于报表直接读取而无需再联表门店档案。,示例值及对应分析:三、与其它 JSON 的结构关联关系(从字段层面)';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.site_table_id IS '对应JSON字段:site_table_id,说明::球台 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.site_table_area_id IS '对应JSON字段:site_table_area_id,说明::门店内“台桌区域” ID(站在门店物理布局的角度)。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.site_table_area_name IS '对应JSON字段:site_table_area_name,说明::台桌区域的名称,用于门店表现和区域统计。,示例值及对应分析:4. 会员维度与相关字段';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.tenant_table_area_id IS '对应JSON字段:tenant_table_area_id,说明::租户维度的台桌区域 ID(品牌层面的同一类区域)。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.order_trade_no IS '对应JSON字段:order_trade_no,说明::订单交易号,是整笔订单的主编号。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.order_pay_id IS '对应JSON字段:order_pay_id,说明::订单支付记录 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.order_settle_id IS '对应JSON字段:order_settle_id,说明::结算单号/结账 ID,对应一次结账操作。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_name IS '对应JSON字段:ledger_name,说明::台号名称,实际展示给员工/顾客看的桌台编号。,示例值及对应分析:备注:与 site_table_id 一一对应,是桌台维表中的名称字段冗余到流水里的快照。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_amount IS '对应JSON字段:ledger_amount,说明::按单价与计费时长计算出的原始应收台费金额。,示例值及对应分析:近似关系:ledger_amount ≈ ledger_unit_price × ledger_count / 3600,考虑到四舍五入会有小数差。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_count IS '对应JSON字段:ledger_count,说明::台账记录的计费秒数,计费用秒数(应收时长)。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_unit_price IS '对应JSON字段:ledger_unit_price,说明::台费结算时设置的 每小时单价/计费单价。,示例值及对应分析:用途:与 ledger_count 共同决定原始应收额。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_status IS '对应JSON字段:ledger_status,说明:(推测):,示例值及对应分析:1:正常已结算台费;';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_start_time IS '对应JSON字段:ledger_start_time,说明::台账上的计费起始时间。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_end_time IS '对应JSON字段:ledger_end_time,说明::台账上的计费结束时间。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.start_use_time IS '对应JSON字段:start_use_time,说明::台开始使用的时间(实际开台时间)。,示例值及对应分析:特点:在数据中,与 ledger_start_time 完全相同(见下)。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.last_use_time IS '对应JSON字段:last_use_time,说明::最后使用/操作时间。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.real_table_use_seconds IS '对应JSON字段:real_table_use_seconds,说明::实际使用的总秒数(系统真实统计的使用时长)。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.real_table_charge_money IS '对应JSON字段:real_table_charge_money,说明::台费中实际向顾客收取的金额(现金/实付维度,未含券方承担或内部调账的那一部分)。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.add_clock_seconds IS '对应JSON字段:add_clock_seconds,说明::加钟秒数,在原有使用基础上追加的时长。,示例值及对应分析:观测:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.adjust_amount IS '对应JSON字段:adjust_amount,说明::调整金额/调账金额,用于将台费金额转移或冲减到其它项目,或手工调整。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.coupon_promotion_amount IS '对应JSON字段:coupon_promotion_amount,说明::由优惠券/活动/团购(平台/门店促销)承担的优惠金额,直接抵扣在台费上。,示例值及对应分析:特点:当 real_table_charge_money = 0 且该字段为 ledger_amount 时,说明整笔台费是由券促销全额承担。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.member_discount_amount IS '对应JSON字段:member_discount_amount,说明:上文已说明,这里补充与金额的结构关系:,示例值及对应分析:功能:表示由会员折扣或会员权益承担的那部分金额。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.used_card_amount IS '对应JSON字段:used_card_amount,说明::由储值卡、次卡等“卡内余额”抵扣的金额。,示例值及对应分析:说明:字段设计已预留,但本段时间内台费没有通过储值卡扣款,或者卡扣款在其他表体现。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.mgmt_fee IS '对应JSON字段:mgmt_fee,说明:(推测):管理费字段,用于未来支持“台费附加管理费/服务费”的功能。,示例值及对应分析:当前未启用。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.service_money IS '对应JSON字段:service_money,说明:(推测):门店用于记录“服务费/成本/分成金额”的字段,类似助教流水里的 service_money。,示例值及对应分析:说明:当前门店未启用此字段结算台费。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.fee_total IS '对应JSON字段:fee_total,说明::各种附加费用(如管理费、服务费)合计值。,示例值及对应分析:说明:和 mgmt_fee 一样,目前作为预留字段,没有实际使用。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.is_single_order IS '对应JSON字段:is_single_order,说明:(推测):,示例值及对应分析:1:该台费记录对应的是一个独立计费单元(单独结算的桌费);';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志:,示例值及对应分析:0:未删除(有效记录);';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.member_id IS '对应JSON字段:member_id,说明::门店/租户内的会员 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.operator_id IS '对应JSON字段:operator_id,说明::操作员 ID,负责开台/结账的员工账号 ID。,示例值及对应分析:关联:与员工/账号体系中的用户 ID 对应(与助教账号的 user_id 属于同一种 ID 体系)。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.operator_name IS '对应JSON字段:operator_name,说明::操作员姓名(冗余字段),便于直接阅读,不必再联表员工档案。,示例值及对应分析:?? table_fee_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.salesman_name IS '对应JSON字段:salesman_name,说明::业务员/营业员姓名,如果台费有单独提成员工,这里记录归属人。,示例值及对应分析:当前门店未启用该字段做提成归属。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.salesman_org_id IS '对应JSON字段:salesman_org_id,说明::营业员所属机构/部门 ID。,示例值及对应分析:8. 状态 / 标记类字段';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.salesman_user_id IS '对应JSON字段:salesman_user_id,说明::营业员的用户 ID(与 salesman_name 搭配)。,示例值及对应分析:?? table_fee_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.create_time IS '对应JSON字段:create_time,说明::这条台费流水记录的创建时间,通常接近结账时间。,示例值及对应分析:?? table_fee_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.goods_stock_movements (
+ siteGoodsStockId BIGINT PRIMARY KEY,
+ tenantId BIGINT,
+ siteId BIGINT,
+ siteGoodsId BIGINT,
+ goodsName TEXT,
+ goodsCategoryId BIGINT,
+ goodsSecondCategoryId BIGINT,
+ unit TEXT,
+ price NUMERIC(18,4),
+ stockType INT,
+ changeNum NUMERIC(18,4),
+ startNum NUMERIC(18,4),
+ endNum NUMERIC(18,4),
+ changeNumA NUMERIC(18,4),
+ startNumA NUMERIC(18,4),
+ endNumA NUMERIC(18,4),
+ remark TEXT,
+ operatorName TEXT,
+ createTime TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.goods_stock_movements IS '对应JSON字段:goods_stock_movements.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 goods_stock_movements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.siteGoodsStockId IS '对应JSON字段:siteGoodsStockId,说明::门店某个“商品库存记录”的主键 ID。,示例值及对应分析:特点:每条库存变动记录对应一个 siteGoodsStockId,同一个商品可能在不同库存记录中出现(例如不同仓位或不同批次)。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.tenantId IS '对应JSON字段:tenantId,说明::租户/品牌 ID。,示例值及对应分析:观测:全部记录相同值,说明属于同一商户。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.siteId IS '对应JSON字段:siteId,说明::门店 ID。,示例值及对应分析:观测:本文件中所有记录的 siteId 都相同,对应“朗朗桌球”这家门店。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.siteGoodsId IS '对应JSON字段:siteGoodsId,说明::门店维度的商品 ID。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.goodsName IS '对应JSON字段:goodsName,说明::商品名称。,示例值及对应分析:示例值:';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.goodsCategoryId IS '对应JSON字段:goodsCategoryId,说明::商品一级分类 ID。,示例值及对应分析:观测:当前 100 条样本中约有 5 个不同 ID,对应如“酒水类”“食品小吃类”“香烟类”等大类(仅从命名与商品名推断)。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.goodsSecondCategoryId IS '对应JSON字段:goodsSecondCategoryId,说明::商品二级分类 ID。,示例值及对应分析:观测:样本中约有 7 个不同 ID,如饮料中的“矿泉水/功能饮料/碳酸饮料”等。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.unit IS '对应JSON字段:unit,说明::库存计量单位。,示例值及对应分析:说明:库存数量(startNum、endNum、changeNum)均以这里的单位计数。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.price IS '对应JSON字段:price,说明::商品单价(单位金额)。,示例值及对应分析:观测特征:';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.stockType IS '对应JSON字段:stockType,说明:(基于数据行为推断):,示例值及对应分析:1:出库类变动 典型情况是销售出库,库存减少 1 或 2;例如顾客点了一瓶饮料,对应一条 stockType=1, changeNum=-1 的记录。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.changeNum IS '对应JSON字段:changeNum,说明::本次库存数量变化值。,示例值及对应分析:特点及取值:';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.startNum IS '对应JSON字段:startNum,说明::变动前(这次出入库之前)的库存数量。,示例值及对应分析:示例: 如记录:startNum = 28, changeNum = -1, endNum = 27。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.endNum IS '对应JSON字段:endNum,说明::变动后(出入库之后)的库存数量。,示例值及对应分析:结构关系:';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.changeNumA IS '对应JSON字段:changeNumA,说明::辅助单位的变化量(与 changeNum 对应的第二计量单位变化),当前未使用。,示例值及对应分析:结论: startNumA / endNumA / changeNumA 是为“一个商品有两种计量单位(如箱与瓶)”而设计的预留字段。 目前门店只在单一单位层面管理库存,故全部为 0。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.startNumA IS '对应JSON字段:startNumA,说明:(推测):辅助计量单位的起始库存(例如件/箱等第二单位)。,示例值及对应分析:当前门店在样本时间段内没有启用多单位库存管理,因此全部为 0。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.endNumA IS '对应JSON字段:endNumA,说明::辅助单位的变动后库存,同样未启用。,示例值及对应分析:?? goods_stock_movements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.remark IS '对应JSON字段:remark,说明::备注信息,用于手工记录本次变更的特殊原因说明(例如“盘点差异调整”“报损”)。,示例值及对应分析:当前样本中没有填入任何备注,但字段已预留,适用于盘点或手工调整场景。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.operatorName IS '对应JSON字段:operatorName,说明::执行此次库存变动的操作人。,示例值及对应分析:观测值:';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.createTime IS '对应JSON字段:createTime,说明::这条库存变动记录的创建时间,即发生库存变更的时间点。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.stock_goods_category_tree (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ category_name TEXT,
+ alias_name TEXT,
+ pid BIGINT,
+ business_name TEXT,
+ tenant_goods_business_id BIGINT,
+ open_salesman INT,
+ categoryBoxes JSONB,
+ sort INT,
+ is_warehousing INT,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.stock_goods_category_tree IS '对应JSON字段:stock_goods_category_tree.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.id IS '对应JSON字段:id,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.tenant_id IS '对应JSON字段:tenant_id,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.category_name IS '对应JSON字段:category_name,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.alias_name IS '对应JSON字段:alias_name,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.pid IS '对应JSON字段:pid,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.business_name IS '对应JSON字段:business_name,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.tenant_goods_business_id IS '对应JSON字段:tenant_goods_business_id,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.open_salesman IS '对应JSON字段:open_salesman,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.categoryBoxes IS '对应JSON字段:categoryBoxes,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.sort IS '对应JSON字段:sort,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.is_warehousing IS '对应JSON字段:is_warehousing,说明::分类节点主键 ID(在商品分类维度中的唯一标识)。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.goods_stock_summary (
+ siteGoodsId BIGINT PRIMARY KEY,
+ goodsName TEXT,
+ goodsUnit TEXT,
+ goodsCategoryId BIGINT,
+ goodsCategorySecondId BIGINT,
+ categoryName TEXT,
+ rangeStartStock NUMERIC(18,4),
+ rangeEndStock NUMERIC(18,4),
+ rangeIn NUMERIC(18,4),
+ rangeOut NUMERIC(18,4),
+ rangeSale NUMERIC(18,4),
+ rangeSaleMoney NUMERIC(18,2),
+ rangeInventory NUMERIC(18,4),
+ currentStock NUMERIC(18,4),
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.goods_stock_summary IS '对应JSON字段:goods_stock_summary.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.siteGoodsId IS '对应JSON字段:siteGoodsId,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.goodsName IS '对应JSON字段:goodsName,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.goodsUnit IS '对应JSON字段:goodsUnit,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.goodsCategoryId IS '对应JSON字段:goodsCategoryId,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.goodsCategorySecondId IS '对应JSON字段:goodsCategorySecondId,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.categoryName IS '对应JSON字段:categoryName,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeStartStock IS '对应JSON字段:rangeStartStock,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeEndStock IS '对应JSON字段:rangeEndStock,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeIn IS '对应JSON字段:rangeIn,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeOut IS '对应JSON字段:rangeOut,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeSale IS '对应JSON字段:rangeSale,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeSaleMoney IS '对应JSON字段:rangeSaleMoney,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeInventory IS '对应JSON字段:rangeInventory,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.currentStock IS '对应JSON字段:currentStock,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.payment_transactions (
+ id BIGINT PRIMARY KEY,
+ site_id BIGINT,
+ siteProfile JSONB,
+ relate_type INT,
+ relate_id BIGINT,
+ pay_amount NUMERIC(18,2),
+ pay_status INT,
+ pay_time TIMESTAMP,
+ create_time TIMESTAMP,
+ payment_method INT,
+ online_pay_channel INT,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.payment_transactions IS '对应JSON字段:payment_transactions.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.id IS '对应JSON字段:id,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.site_id IS '对应JSON字段:site_id,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.siteProfile IS '对应JSON字段:siteProfile,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.relate_type IS '对应JSON字段:relate_type,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.relate_id IS '对应JSON字段:relate_id,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.pay_amount IS '对应JSON字段:pay_amount,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.pay_status IS '对应JSON字段:pay_status,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.pay_time IS '对应JSON字段:pay_time,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.create_time IS '对应JSON字段:create_time,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.payment_method IS '对应JSON字段:payment_method,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.online_pay_channel IS '对应JSON字段:online_pay_channel,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.payment_transactions.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.payment_transactions.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.payment_transactions.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.refund_transactions (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ tenantName TEXT,
+ site_id BIGINT,
+ siteProfile JSONB,
+ relate_type INT,
+ relate_id BIGINT,
+ pay_sn TEXT,
+ pay_amount NUMERIC(18,2),
+ refund_amount NUMERIC(18,2),
+ round_amount NUMERIC(18,2),
+ pay_status INT,
+ pay_time TIMESTAMP,
+ create_time TIMESTAMP,
+ payment_method INT,
+ pay_terminal INT,
+ pay_config_id BIGINT,
+ online_pay_channel INT,
+ online_pay_type INT,
+ channel_fee NUMERIC(18,2),
+ channel_payer_id TEXT,
+ channel_pay_no TEXT,
+ member_id BIGINT,
+ member_card_id BIGINT,
+ cashier_point_id BIGINT,
+ operator_id BIGINT,
+ action_type INT,
+ check_status INT,
+ is_revoke INT,
+ is_delete INT,
+ balance_frozen_amount NUMERIC(18,2),
+ card_frozen_amount NUMERIC(18,2),
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.refund_transactions IS '对应JSON字段:refund_transactions.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 refund_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.refund_transactions.id IS '对应JSON字段:id,说明::本条 退款流水 的唯一 ID。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID,全系统维度标识该商户。,示例值及对应分析:特点:本文件中所有记录相同。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.tenantName IS '对应JSON字段:tenantName,说明::租户(商户)名称。,示例值及对应分析:特点:本文件中固定为“朗朗桌球”,完全冗余于 siteProfile.shop_name。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.site_id IS '对应JSON字段:site_id,说明::门店 ID。,示例值及对应分析:特点:本文件中所有记录相同(单门店)。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.siteProfile IS '对应JSON字段:siteProfile,说明::门店信息快照,结构与其他 JSON 中的 siteProfile 完全一致。包含字段包括但不限于:,示例值及对应分析:id:门店 ID(= site_id);';
+COMMENT ON COLUMN billiards_ods.refund_transactions.relate_type IS '对应JSON字段:relate_type,说明::本退款对应的“业务类型”。,示例值及对应分析:结合支付记录的 relate_type 推测:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.relate_id IS '对应JSON字段:relate_id,说明::本次退款关联的业务 ID。,示例值及对应分析:对于 relate_type = 2:应该对应某个订单/结算的主键;';
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_sn IS '对应JSON字段:pay_sn,说明:?????? refund_transactions-Analysis.md,示例值及对应分析:?? refund_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_amount IS '对应JSON字段:pay_amount,说明::本次退款的 资金变动金额。,示例值及对应分析:特征很重要:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.refund_amount IS '对应JSON字段:refund_amount,说明:(推测):,示例值及对应分析:设计上本应显示“实际退款金额”(正数),与 pay_amount 配合使用;';
+COMMENT ON COLUMN billiards_ods.refund_transactions.round_amount IS '对应JSON字段:round_amount,说明:(推测):,示例值及对应分析:舍入金额/抹零金额;';
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_status IS '对应JSON字段:pay_status,说明:(推测):,示例值及对应分析:支付/退款状态枚举:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_time IS '对应JSON字段:pay_time,说明::退款在支付渠道层面实际发生的时间。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.create_time IS '对应JSON字段:create_time,说明::本条退款流水在系统内创建时间。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.payment_method IS '对应JSON字段:payment_method,说明:(推测):,示例值及对应分析:支付/退款的 方式类型:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_terminal IS '对应JSON字段:pay_terminal,说明:(推测):,示例值及对应分析:退款所使用的 终端类型:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_config_id IS '对应JSON字段:pay_config_id,说明:(推测):,示例值及对应分析:支付配置 ID,例如商户在“非球科技”内配置的某一条支付通道(某个微信商户号、银联通道)的主键。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.online_pay_channel IS '对应JSON字段:online_pay_channel,说明:(推测):,示例值及对应分析:线上支付的 渠道编号,例如:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.online_pay_type IS '对应JSON字段:online_pay_type,说明:(推测):,示例值及对应分析:在线退款的类型:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.channel_fee IS '对应JSON字段:channel_fee,说明:(推测):,示例值及对应分析:第三方支付渠道对本次退款收取的手续费;';
+COMMENT ON COLUMN billiards_ods.refund_transactions.channel_payer_id IS '对应JSON字段:channel_payer_id,说明:(推测):,示例值及对应分析:支付渠道侧的 payer ID,例如微信 openid、银行卡号掩码等。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.channel_pay_no IS '对应JSON字段:channel_pay_no,说明:(推测):,示例值及对应分析:第三方支付平台的交易号(如微信支付单号、支付宝交易号等)。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.member_id IS '对应JSON字段:member_id,说明::,示例值及对应分析:租户内部的会员 ID(对应会员档案中的某个主键)。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.member_card_id IS '对应JSON字段:member_card_id,说明::,示例值及对应分析:关联的会员卡账户 ID(对应“储值卡列表”或“会员档案”中的某一张卡)。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.cashier_point_id IS '对应JSON字段:cashier_point_id,说明:(推测):,示例值及对应分析:收银点 ID,例如前台 1、前台 2、自助机等。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.operator_id IS '对应JSON字段:operator_id,说明::,示例值及对应分析:执行该退款操作的操作员 ID。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.action_type IS '对应JSON字段:action_type,说明:(推测):,示例值及对应分析:行为类型:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.check_status IS '对应JSON字段:check_status,说明:(推测):,示例值及对应分析:审核状态:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.is_revoke IS '对应JSON字段:is_revoke,说明:(推测):,示例值及对应分析:是否撤销型退款/撤销原支付:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志。,示例值及对应分析:0:未删除;';
+COMMENT ON COLUMN billiards_ods.refund_transactions.balance_frozen_amount IS '对应JSON字段:balance_frozen_amount,说明:(推测):,示例值及对应分析:涉及会员储值卡退款时,暂时冻结的余额金额;';
+COMMENT ON COLUMN billiards_ods.refund_transactions.card_frozen_amount IS '对应JSON字段:card_frozen_amount,说明::与上一个类似,偏向“某张卡的被冻结金额”,也与会员卡/储值账户相关。,示例值及对应分析:状态同上:本数据中未发生“卡冻结退款”。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.refund_transactions.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.refund_transactions.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.refund_transactions.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.platform_coupon_redemption_records (
+ id BIGINT PRIMARY KEY,
+ verify_id BIGINT,
+ certificate_id TEXT,
+ coupon_code TEXT,
+ coupon_name TEXT,
+ coupon_channel INT,
+ groupon_type INT,
+ group_package_id BIGINT,
+ sale_price NUMERIC(18,2),
+ coupon_money NUMERIC(18,2),
+ coupon_free_time NUMERIC(18,2),
+ coupon_cover TEXT,
+ coupon_remark TEXT,
+ use_status INT,
+ consume_time TIMESTAMP,
+ create_time TIMESTAMP,
+ deal_id TEXT,
+ channel_deal_id TEXT,
+ site_id BIGINT,
+ site_order_id BIGINT,
+ table_id BIGINT,
+ tenant_id BIGINT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ is_delete INT,
+ siteProfile JSONB,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.platform_coupon_redemption_records IS '对应JSON字段:platform_coupon_redemption_records.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.id IS '对应JSON字段:id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.verify_id IS '对应JSON字段:verify_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.certificate_id IS '对应JSON字段:certificate_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_code IS '对应JSON字段:coupon_code,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_name IS '对应JSON字段:coupon_name,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_channel IS '对应JSON字段:coupon_channel,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.groupon_type IS '对应JSON字段:groupon_type,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.group_package_id IS '对应JSON字段:group_package_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.sale_price IS '对应JSON字段:sale_price,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_money IS '对应JSON字段:coupon_money,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_free_time IS '对应JSON字段:coupon_free_time,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_cover IS '对应JSON字段:coupon_cover,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_remark IS '对应JSON字段:coupon_remark,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.use_status IS '对应JSON字段:use_status,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.consume_time IS '对应JSON字段:consume_time,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.create_time IS '对应JSON字段:create_time,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.deal_id IS '对应JSON字段:deal_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.channel_deal_id IS '对应JSON字段:channel_deal_id,说明:任意一个 ID 字段缺失时(如部分记录 deal_id=0),仍然可以通过其他字段(coupon_name + sale_price + coupon_money + channel_deal_id)唯一识别该产品。,示例值及对应分析:这种多字段冗余,结构上提升了抗“配置缺失”的能力。';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.site_id IS '对应JSON字段:site_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.site_order_id IS '对应JSON字段:site_order_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.table_id IS '对应JSON字段:table_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.tenant_id IS '对应JSON字段:tenant_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.operator_id IS '对应JSON字段:operator_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.operator_name IS '对应JSON字段:operator_name,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.is_delete IS '对应JSON字段:is_delete,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.siteProfile IS '对应JSON字段:siteProfile,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.tenant_goods_master (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ goods_name TEXT,
+ goods_bar_code TEXT,
+ goods_category_id BIGINT,
+ goods_second_category_id BIGINT,
+ categoryName TEXT,
+ unit TEXT,
+ goods_number TEXT,
+ goods_state INT,
+ sale_channel INT,
+ able_discount INT,
+ able_site_transfer INT,
+ is_delete INT,
+ is_warehousing INT,
+ isInSite INT,
+ cost_price NUMERIC(18,4),
+ cost_price_type INT,
+ market_price NUMERIC(18,4),
+ min_discount_price NUMERIC(18,4),
+ common_sale_royalty NUMERIC(18,4),
+ point_sale_royalty NUMERIC(18,4),
+ pinyin_initial TEXT,
+ commodityCode TEXT,
+ commodity_code TEXT,
+ goods_cover TEXT,
+ supplier_id BIGINT,
+ remark_name TEXT,
+ create_time TIMESTAMP,
+ update_time TIMESTAMP,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+
+COMMENT ON TABLE billiards_ods.tenant_goods_master IS '对应JSON字段:tenant_goods_master.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 tenant_goods_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.id IS '对应JSON字段:id,说明::商品档案主键 ID,唯一标识一条商品。,示例值及对应分析:作用:作为其他业务表(销售明细、库存流水、门店商品表等)的外键,通常以 tenant_goods_id 或类似字段出现。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID。,示例值及对应分析:作用:和其它 JSON 中的 tenant_id / tenantId 一致,用于区分不同商户(本次数据只包含同一租户)。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_name IS '对应JSON字段:goods_name,说明::商品名称(前台展示名称)。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_bar_code IS '对应JSON字段:goods_bar_code,说明::商品条码(EAN 等),目前未维护。,示例值及对应分析:说明:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_category_id IS '对应JSON字段:goods_category_id,说明::商品一级分类 ID。,示例值及对应分析:取值情况:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_second_category_id IS '对应JSON字段:goods_second_category_id,说明::商品二级分类 ID。,示例值及对应分析:取值情况:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.categoryName IS '对应JSON字段:categoryName,说明::商品一级分类名称(业务可读)。,示例值及对应分析:取值情况:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.unit IS '对应JSON字段:unit,说明::计量单位。,示例值及对应分析:取值(共 12 种左右):';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_number IS '对应JSON字段:goods_number,说明::商品内部编码(自定义货号/系统货号)。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_state IS '对应JSON字段:goods_state,说明:(推测):商品状态(上架/下架等)。,示例值及对应分析:1:正常/上架;';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.sale_channel IS '对应JSON字段:sale_channel,说明:(推测):销售渠道类型,如“门店堂食/线下零售/线上小程序”等的一种编码。,示例值及对应分析:现有数据只有一个值,说明本门店目前仅通过一种渠道销售这些商品。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.able_discount IS '对应JSON字段:able_discount,说明:(推测):是否允许参与折扣/打折。,示例值及对应分析:1:允许折扣;';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.able_site_transfer IS '对应JSON字段:able_site_transfer,说明:(推测):,示例值及对应分析:字面意思是“是否允许门店间调拨/门店级操作”:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志。,示例值及对应分析:0:未删除(有效商品);';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.is_warehousing IS '对应JSON字段:is_warehousing,说明:(推测):是否启用库存管理。,示例值及对应分析:1:该商品纳入库存管理;';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.isInSite IS '对应JSON字段:isInSite,说明:(从命名推测):是否在当前门店启用/上架。,示例值及对应分析:现象:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.cost_price IS '对应JSON字段:cost_price,说明::成本价格。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.cost_price_type IS '对应JSON字段:cost_price_type,说明:(推测):,示例值及对应分析:不同的成本价格来源或计算方式,如:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.market_price IS '对应JSON字段:market_price,说明::商品标价 / 售价(标准销售单价)。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.min_discount_price IS '对应JSON字段:min_discount_price,说明::该商品允许售卖的最低价格(底价)。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.common_sale_royalty IS '对应JSON字段:common_sale_royalty,说明:(推测):普通销售提成比例或提成金额的配置字段。,示例值及对应分析:当前门店未在商品档案上配置员工提成规则,全部为 0。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.point_sale_royalty IS '对应JSON字段:point_sale_royalty,说明:(推测):积分销售提成/积分赠送规则相关配置。,示例值及对应分析:当前同样未启用。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.pinyin_initial IS '对应JSON字段:pinyin_initial,说明::拼音首字母/助记码。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.commodityCode IS '对应JSON字段:commodityCode,说明::,示例值及对应分析:与 commodity_code 是同一信息的数组形式(冗余存储),便于支持一个商品对应多个编码的场景。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.commodity_code IS '对应JSON字段:commodity_code,说明::商品编码(通常为对外商品编码或条码)。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_cover IS '对应JSON字段:goods_cover,说明::商品封面图片 URL 地址。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.supplier_id IS '对应JSON字段:supplier_id,说明::供应商 ID,用于关联到供应商档案。,示例值及对应分析:当前所有商品都未挂接具体供应商(或门店未使用供应链管理模块)。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.remark_name IS '对应JSON字段:remark_name,说明:(从命名推断):商品备注名/别名,通常用来配置简写或特殊显示名称。,示例值及对应分析:当前门店尚未使用该字段,字段设计为将来扩展预留。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.create_time IS '对应JSON字段:create_time,说明::商品档案创建时间。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.update_time IS '对应JSON字段:update_time,说明::商品档案最近一次修改时间。,示例值及对应分析:分布:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.group_buy_packages (
+ id BIGINT PRIMARY KEY,
+ package_id BIGINT,
+ package_name TEXT,
+ selling_price NUMERIC(18,2),
+ coupon_money NUMERIC(18,2),
+ date_type INT,
+ date_info TEXT,
+ start_time TIMESTAMP,
+ end_time TIMESTAMP,
+ start_clock TEXT,
+ end_clock TEXT,
+ add_start_clock TEXT,
+ add_end_clock TEXT,
+ duration INT,
+ usable_count INT,
+ usable_range INT,
+ table_area_id BIGINT,
+ table_area_name TEXT,
+ table_area_id_list JSONB,
+ tenant_table_area_id BIGINT,
+ tenant_table_area_id_list JSONB,
+ site_id BIGINT,
+ site_name TEXT,
+ tenant_id BIGINT,
+ card_type_ids JSONB,
+ group_type INT,
+ system_group_type INT,
+ type INT,
+ effective_status INT,
+ is_enabled INT,
+ is_delete INT,
+ max_selectable_categories INT,
+ area_tag_type INT,
+ creator_name TEXT,
+ create_time TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.group_buy_packages IS '对应JSON字段:group_buy_packages.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 group_buy_packages-Analysis.md';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.id IS '对应JSON字段:id,说明::门店侧套餐 ID,本文件内部的主键。,示例值及对应分析:特点:17 条记录中均为不同的大整数 ID。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.package_id IS '对应JSON字段:package_id,说明::“上层套餐 ID” 或“总部/系统级套餐 ID”。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.package_name IS '对应JSON字段:package_name,说明::团购套餐名称,用于前台展示和核销界面。,示例值及对应分析:示例:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.selling_price IS '对应JSON字段:selling_price,说明:(结合字段命名):,示例值及对应分析:语义上应该是“团购售卖价”(顾客在平台购买券时的成交价格)。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.coupon_money IS '对应JSON字段:coupon_money,说明::券面值或内部结算面值,表示该套餐在门店侧对应的金额额度。,示例值及对应分析:示例(对应套餐名称):';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.date_type IS '对应JSON字段:date_type,说明:(推测):,示例值及对应分析:典型用法:区分“全部日期可用 / 工作日 / 周末 / 指定日期”等。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.date_info IS '对应JSON字段:date_info,说明:(推测):,示例值及对应分析:预留字段,通常用来存储更细粒度的日期信息,如具体日期列表、节假日特殊规则(可能是 JSON 字符串或编码)。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.start_time IS '对应JSON字段:start_time,说明::套餐开始生效的日期时间。,示例值及对应分析:示例:"2025-07-20 00:00:00" 等。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.end_time IS '对应JSON字段:end_time,说明::套餐失效的日期时间(到这个时间点后不可使用)。,示例值及对应分析:示例:形如 "2025-11-30 23:59:59",部分记录使用 9999-12-31 23:59:59 风格的极大日期表示长期有效(本数据中如有这种值,可解读为“长期有效”)。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.start_clock IS '对应JSON字段:start_clock,说明::每日可用起始时间点(第一段)。,示例值及对应分析:说明:配合 end_clock 使用,定义一个日内时段。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.end_clock IS '对应JSON字段:end_clock,说明::每日可用的结束时间点(第一段)。,示例值及对应分析:结构说明:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.add_start_clock IS '对应JSON字段:add_start_clock,说明:(推测):附加可用时间段的起始时间(第二段)。,示例值及对应分析:例如有的套餐可以在两个不连续的时段使用:早场 + 夜场,则可用第一段 start_clock / end_clock 和第二段 add_start_clock / add_end_clock 组合。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.add_end_clock IS '对应JSON字段:add_end_clock,说明::附加时段结束时间,多数情况配合 "00:00:00" 或 "10:00:00" 使用。,示例值及对应分析:整体理解:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.duration IS '对应JSON字段:duration,说明::套餐内包含的时长(秒)。,示例值及对应分析:与名称一致:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.usable_count IS '对应JSON字段:usable_count,说明::可使用次数上限。,示例值及对应分析:数据特征说明:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.usable_range IS '对应JSON字段:usable_range,说明:吻合(A区中八/B区中八/斯诺克/KTV/包厢等)。,示例值及对应分析:通过该关联,系统在核销时可以校验:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.table_area_id IS '对应JSON字段:table_area_id,说明:(推测):,示例值及对应分析:原始设计应为“单一台区 ID”,当套餐只限一个区域可以用这个字段存储。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.table_area_name IS '对应JSON字段:table_area_name,说明::套餐适用的“门店台区名称”,用于显示和筛选。,示例值及对应分析:说明:这个字段是对区域 ID 维度的文字描述,便于直观理解。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.table_area_id_list IS '对应JSON字段:table_area_id_list,说明:(推测):,示例值及对应分析:用来存放具体台区 ID 列表(例如 "1,2,3"),实现更细粒度的台桌限制。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.tenant_table_area_id IS '对应JSON字段:tenant_table_area_id,说明:(推测):,示例值及对应分析:与 table_area_id 类似,是租户层级的台区 ID,原本用于单区选择。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.tenant_table_area_id_list IS '对应JSON字段:tenant_table_area_id_list,说明:(推测):,示例值及对应分析:实际代表“台区集合 ID”或“租户台区配置 ID”,用来限制套餐可用的台区范围。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.site_id IS '对应JSON字段:site_id,说明::门店 ID。,示例值及对应分析:特点:全表值相同,且与其他 JSON 文件中的 site_id 一致,对应“朗朗桌球”这家门店。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.site_name IS '对应JSON字段:site_name,说明::门店名称。,示例值及对应分析:观测值:全部为 "朗朗桌球"。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.tenant_id IS '对应JSON字段:tenant_id,说明::租户 ID(品牌/商户 ID)。,示例值及对应分析:特点:全表值相同,说明所有套餐定义属于同一商户(同一品牌)。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.card_type_ids IS '对应JSON字段:card_type_ids,说明:(推测):,示例值及对应分析:原意是“适用会员卡类型 ID 列表”,例如某套餐只允许某几种会员卡使用,可以在此配置。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.group_type IS '对应JSON字段:group_type,说明:(推测):,示例值及对应分析:团购类型,例如:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.system_group_type IS '对应JSON字段:system_group_type,说明:(推测):,示例值及对应分析:系统内对团购类型更底层的划分,比如:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.type IS '对应JSON字段:type,说明:(推测):,示例值及对应分析:内部业务子类型,具体含义需要结合系统文档;仅从数据无法确定是“台费类 vs 包厢类”还是“平台套餐 vs 自定义套餐”。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.effective_status IS '对应JSON字段:effective_status,说明:(结合命名和数据特征推断):,示例值及对应分析:1:有效(在当前时间区间内、配置正常,可核销使用)。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.is_enabled IS '对应JSON字段:is_enabled,说明::启用状态。,示例值及对应分析:从其他表的统一风格来看,1 一般表示“启用 / 上架”,2 表示“停用 / 下架”。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志。,示例值及对应分析:0:正常;';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.max_selectable_categories IS '对应JSON字段:max_selectable_categories,说明:?????? group_buy_packages-Analysis.md,示例值及对应分析:?? group_buy_packages-Analysis.md';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.area_tag_type IS '对应JSON字段:area_tag_type,说明:(推测):区域标记类型:,示例值及对应分析:1 很可能代表“按台区标签限制”,例如 A区、中八区、包厢、KTV 等。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.creator_name IS '对应JSON字段:creator_name,说明::创建人信息,一般包含“角色:姓名”。,示例值及对应分析:示例:"管理员:郑丽珊"';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.create_time IS '对应JSON字段:create_time,说明::该套餐在系统中创建的时间。,示例值及对应分析:特点:每条记录各不相同,覆盖了 2025-07 至 2025-10 的创建时间。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.group_buy_redemption_records (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ siteName TEXT,
+ table_id BIGINT,
+ tableName TEXT,
+ tableAreaName TEXT,
+ tenant_table_area_id BIGINT,
+ order_trade_no TEXT,
+ order_settle_id BIGINT,
+ order_pay_id BIGINT,
+ order_coupon_id BIGINT,
+ order_coupon_channel INT,
+ coupon_code TEXT,
+ coupon_money NUMERIC(18,2),
+ coupon_origin_id BIGINT,
+ ledger_name TEXT,
+ ledger_group_name TEXT,
+ ledger_amount NUMERIC(18,2),
+ ledger_count NUMERIC(18,4),
+ ledger_unit_price NUMERIC(18,4),
+ ledger_status INT,
+ table_charge_seconds INT,
+ promotion_activity_id BIGINT,
+ promotion_coupon_id BIGINT,
+ promotion_seconds INT,
+ offer_type INT,
+ assistant_promotion_money NUMERIC(18,2),
+ assistant_service_promotion_money NUMERIC(18,2),
+ table_service_promotion_money NUMERIC(18,2),
+ goods_promotion_money NUMERIC(18,2),
+ recharge_promotion_money NUMERIC(18,2),
+ reward_promotion_money NUMERIC(18,2),
+ goodsOptionPrice NUMERIC(18,2),
+ salesman_name TEXT,
+ sales_man_org_id BIGINT,
+ salesman_role_id BIGINT,
+ salesman_user_id BIGINT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ is_single_order INT,
+ is_delete INT,
+ create_time TIMESTAMP,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+
+COMMENT ON TABLE billiards_ods.group_buy_redemption_records IS '对应JSON字段:group_buy_redemption_records.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 group_buy_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.id IS '对应JSON字段:id,说明::本条“团购套餐流水”记录的 主键 ID。,示例值及对应分析:作用:唯一标识一条券使用到台费上的记录。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID。,示例值及对应分析:特点:全表值相同,说明所有记录属于同一租户。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.site_id IS '对应JSON字段:site_id,说明::门店 ID,与其它 JSON 中一致。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.siteName IS '对应JSON字段:siteName,说明::门店名称,冗余展示用。,示例值及对应分析:?? group_buy_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.table_id IS '对应JSON字段:table_id,说明::球台 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.tableName IS '对应JSON字段:tableName,说明::本次使用券所关联的 球台名称/台号。,示例值及对应分析:关联:对应台桌列表中的 table_name / table_no,通过 table_id 进一步关联。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.tableAreaName IS '对应JSON字段:tableAreaName,说明::该球台所属的 台区名称。,示例值及对应分析:关联:与台区配置中的 area_name 含义一致,与团购套餐定义中的 table_area_name 一致。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.tenant_table_area_id IS '对应JSON字段:tenant_table_area_id,说明::租户级台区分组 ID,表示当前使用券的台桌所属的区域组合。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.order_trade_no IS '对应JSON字段:order_trade_no,说明::订单交易号,和其它消费明细(台费、商品、助教、团购)共用的订单主键。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.order_settle_id IS '对应JSON字段:order_settle_id,说明::结算单 ID(小票结账主键)。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.order_pay_id IS '对应JSON字段:order_pay_id,说明:(推测):,示例值及对应分析:指向支付记录表中的支付流水 ID。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.order_coupon_id IS '对应JSON字段:order_coupon_id,说明::订单中“券使用记录”的 ID。,示例值及对应分析:结构特点:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.order_coupon_channel IS '对应JSON字段:order_coupon_channel,说明:(推测):,示例值及对应分析:券渠道类型,例如:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.coupon_code IS '对应JSON字段:coupon_code,说明::团购券券码,核销时扫描/录入的字符串。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.coupon_money IS '对应JSON字段:coupon_money,说明::本次核销时,这张券在门店侧对应的金额额度(“可抵扣金额”)。,示例值及对应分析:结构关系:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.coupon_origin_id IS '对应JSON字段:coupon_origin_id,说明:(推测):,示例值及对应分析:平台/上游系统中的券记录主键 ID,“券来源 ID”。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.ledger_name IS '对应JSON字段:ledger_name,说明::台费侧关联的“团购项目名称”(记账名)。,示例值及对应分析:结构上通常来源于团购套餐定义的 package_name,或由系统在创建活动时生成。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.ledger_group_name IS '对应JSON字段:ledger_group_name,说明:(推测):团购项目所属的“记账分组名称”(例如“团购台费”“团购包厢”等)。,示例值及对应分析:当前门店未对团购项目做进一步分组。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.ledger_amount IS '对应JSON字段:ledger_amount,说明::本次券实际冲抵台费的金额。,示例值及对应分析:结构关系:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.ledger_count IS '对应JSON字段:ledger_count,说明::按此次优惠实际计算的“核销秒数”。,示例值及对应分析:结构观察:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.ledger_unit_price IS '对应JSON字段:ledger_unit_price,说明::对应台费的标准单价,单位元/小时(从数值来看是类似29.9/小时这种定价)。,示例值及对应分析:作用:配合 ledger_count 用于计算这一条券在台费层面对应的金额(理论上应接近 = 单价 × 秒数/3600)。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.ledger_status IS '对应JSON字段:ledger_status,说明:(推测):流水状态。,示例值及对应分析:1:正常有效;';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.table_charge_seconds IS '对应JSON字段:table_charge_seconds,说明::本次结算中该球台总计计费的秒数(整台的台费计费时间)。,示例值及对应分析:结构特点:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.promotion_activity_id IS '对应JSON字段:promotion_activity_id,说明:(推测):团购/促销活动 ID。,示例值及对应分析:对应平台或内部促销活动的主键,每个活动通常绑定一个或多个具体套餐(promotion_coupon_id)。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.promotion_coupon_id IS '对应JSON字段:promotion_coupon_id,说明::团购套餐定义 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.promotion_seconds IS '对应JSON字段:promotion_seconds,说明::团购套餐定义的“标准时长”(券本身标称的可用时长)。,示例值及对应分析:结构关系:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.offer_type IS '对应JSON字段:offer_type,说明:(推测):优惠类型。,示例值及对应分析:在券适用多个优惠方式的系统中,一般用来区分“满减/折扣/代金券/套餐券”等。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.assistant_promotion_money IS '对应JSON字段:assistant_promotion_money,说明::分摊到“助教服务”的促销金额。,示例值及对应分析:当前场景下,团购券只与台费相关,未涉及助教的金额抵扣。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.assistant_service_promotion_money IS '对应JSON字段:assistant_service_promotion_money,说明::进一步细分助教服务的促销金额。,示例值及对应分析:当前未使用。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.table_service_promotion_money IS '对应JSON字段:table_service_promotion_money,说明::本次券使用中,分摊到“台费服务费”部分的促销金额。,示例值及对应分析:当前样本中,促销金额都在 ledger_amount 中体现,该字段未单独拆出。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.goods_promotion_money IS '对应JSON字段:goods_promotion_money,说明::本次券使用中,分摊到“商品”部分的促销金额。,示例值及对应分析:当前数据中,所有团购券都只用于抵扣台费,没有用来抵扣商品,因此该字段为 0。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.recharge_promotion_money IS '对应JSON字段:recharge_promotion_money,说明::来自“充值类优惠”的分摊金额(例如储值赠送部分)。,示例值及对应分析:当前所有数据为 0,但结构上已经预留了“多来源促销金额分摊”的能力。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.reward_promotion_money IS '对应JSON字段:reward_promotion_money,说明::本次促销中,属于“奖励金/积分抵扣”的金额。,示例值及对应分析:当前没有使用此维度的促销。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.goodsOptionPrice IS '对应JSON字段:goodsOptionPrice,说明:(按命名推测):商品规格价格,用于商品类促销分摊时使用。,示例值及对应分析:当前在“团购套餐流水”中未被实际使用。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.salesman_name IS '对应JSON字段:salesman_name,说明::营业员姓名。,示例值及对应分析:?? group_buy_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.sales_man_org_id IS '对应JSON字段:sales_man_org_id,说明::营业员所属组织 ID。,示例值及对应分析:以上 4 个销售相关字段在当前门店的团购套餐使用中都未启用,仅作为结构预留。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.salesman_role_id IS '对应JSON字段:salesman_role_id,说明::营业员角色 ID。,示例值及对应分析:?? group_buy_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.salesman_user_id IS '对应JSON字段:salesman_user_id,说明::营业员/业务员用户 ID。,示例值及对应分析:当前所有团购套餐流水都未指定独立的营业员。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.operator_id IS '对应JSON字段:operator_id,说明::执行本次核销/结算操作的 操作员 ID。,示例值及对应分析:关联:可以与员工档案表中的 id 对应(当前导出中员工表未单独给出,但风格和其它表一致)。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.operator_name IS '对应JSON字段:operator_name,说明::操作员名称(包含角色说明),与 operator_id 对应的冗余展示字段。,示例值及对应分析:?? group_buy_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.is_single_order IS '对应JSON字段:is_single_order,说明:(推测):是否单独作为一条订单行。,示例值及对应分析:1:以独立条目方式进行结算(绝大部分记录如此)。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志:,示例值及对应分析:0:正常;';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.create_time IS '对应JSON字段:create_time,说明::本条团购套餐使用流水创建时间(即券核销时间,或与结账时间接近)。,示例值及对应分析:用法:可用于按时间范围过滤团购使用记录。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.settlement_ticket_details (
+ orderSettleId BIGINT PRIMARY KEY,
+ actualPayment NUMERIC(18,2),
+ adjustAmount NUMERIC(18,2),
+ assistantManualDiscount NUMERIC(18,2),
+ balanceAmount NUMERIC(18,2),
+ cashierName TEXT,
+ consumeMoney NUMERIC(18,2),
+ couponAmount NUMERIC(18,2),
+ deliveryAddress TEXT,
+ deliveryFee NUMERIC(18,2),
+ ledgerAmount NUMERIC(18,2),
+ memberDeductAmount NUMERIC(18,2),
+ memberOfferAmount NUMERIC(18,2),
+ onlineReturnAmount NUMERIC(18,2),
+ orderRemark TEXT,
+ orderSettleNumber BIGINT,
+ payMemberBalance NUMERIC(18,2),
+ payTime TIMESTAMP,
+ paymentMethod INT,
+ pointDiscountCost NUMERIC(18,2),
+ pointDiscountPrice NUMERIC(18,2),
+ prepayMoney NUMERIC(18,2),
+ refundAmount NUMERIC(18,2),
+ returnGoodsAmount NUMERIC(18,2),
+ rewardName TEXT,
+ settleType TEXT,
+ siteAddress TEXT,
+ siteBusinessTel TEXT,
+ siteId BIGINT,
+ siteName TEXT,
+ tenantId BIGINT,
+ tenantName TEXT,
+ ticketCustomContent TEXT,
+ ticketRemark TEXT,
+ voucherMoney NUMERIC(18,2),
+ memberProfile JSONB,
+ orderItem JSONB,
+ tenantMemberCardLogs JSONB,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+
+COMMENT ON TABLE billiards_ods.settlement_ticket_details IS '对应JSON字段:settlement_ticket_details.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.orderSettleId IS '对应JSON字段:orderSettleId,说明::同 data.data.orderSettleId,为结算单 ID 的冗余。,示例值及对应分析:orderType';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.actualPayment IS '对应JSON字段:actualPayment,说明::本单实际支付金额总和(顾客本次实际付出:现金 + 线上 + 会员余额等)。,示例值及对应分析:一般应与支付记录中各支付流水金额汇总相匹配。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.adjustAmount IS '对应JSON字段:adjustAmount,说明::台费层面的人工调价金额(仅台费部分)。,示例值及对应分析:memberDiscountAmount';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.assistantManualDiscount IS '对应JSON字段:assistantManualDiscount,说明::针对“助教项目”的人工减免金额汇总(整单维度)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.balanceAmount IS '对应JSON字段:balanceAmount,说明::本单通过“会员余额/储值卡”支付的金额(从余额中扣除的总额)。,示例值及对应分析:对应 结账记录.json 的同名字段。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.cashierName IS '对应JSON字段:cashierName,说明::本单结算操作员名称(带角色前缀文字)。,示例值及对应分析:对应员工维表中的某个账号,便于小票上展示“收银员:XXX”。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.consumeMoney IS '对应JSON字段:consumeMoney,说明::本单“消费金额总计”(原价层面),即台费 + 商品 + 助教 + 服务等消费项目的金额总和(未扣除各类优惠)。,示例值及对应分析:对应 结账记录.json 的 consumeMoney 字段。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.couponAmount IS '对应JSON字段:couponAmount,说明::本单由优惠券抵扣的金额汇总。,示例值及对应分析:结构上:应与 orderCouponLedgers.discountAmount 的合计存在关系,但当前导出未填充。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.deliveryAddress IS '对应JSON字段:deliveryAddress,说明::配送地址(若存在外送业务时使用)。,示例值及对应分析:对于球房场景,当前时间范围内未使用。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.deliveryFee IS '对应JSON字段:deliveryFee,说明::配送费金额(如果支持外送业务)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.ledgerAmount IS '对应JSON字段:ledgerAmount,说明::按台账口径对应的金额,一般与 discountAmount 一致或有固定关系。,示例值及对应分析:rewardPromotionMoney';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.memberDeductAmount IS '对应JSON字段:memberDeductAmount,说明:(结构上):会员抵扣的某种数量或金额(例如积分抵现金额、次卡次数抵扣等),当前数据未启用。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.memberOfferAmount IS '对应JSON字段:memberOfferAmount,说明::由“会员权益/折扣”产生的优惠金额总计(整单维度)。,示例值及对应分析:与 memberProfile 以及台费/商品明细中的 memberDiscountAmount 有对应关系。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.onlineReturnAmount IS '对应JSON字段:onlineReturnAmount,说明::本单通过线上支付渠道退回的金额(如微信/支付宝退款)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.orderRemark IS '对应JSON字段:orderRemark,说明::订单备注,由收银员录入,用于记录与本单相关的特殊说明。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.orderSettleNumber IS '对应JSON字段:orderSettleNumber,说明:(推测):结算单编号(与 ID 独立的一套编号体系,如流水号)。当前导出时间段内未启用。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.payMemberBalance IS '对应JSON字段:payMemberBalance,说明:(结构上):使用会员余额支付的金额,用于区分与 balanceAmount 的不同维度(如“本次支付使用余额部分”与“余额本身变化”等),当前未实际使用。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.payTime IS '对应JSON字段:payTime,说明::本单最终支付成功时间。,示例值及对应分析:和 结账记录.json 中的 payTime 对应,一般与 支付记录.create_time/pay_time 在同一时间段。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.paymentMethod IS '对应JSON字段:paymentMethod,说明::结算主支付方式编码(汇总视角)。,示例值及对应分析:对应 结账记录.json 中的 paymentMethod 字段;';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.pointDiscountCost IS '对应JSON字段:pointDiscountCost,说明::积分抵扣对应的成本金额(成本侧)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.pointDiscountPrice IS '对应JSON字段:pointDiscountPrice,说明::积分抵扣对应的金额(售价侧)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.prepayMoney IS '对应JSON字段:prepayMoney,说明::预付金/定金在本单中使用的金额。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.refundAmount IS '对应JSON字段:refundAmount,说明::本单涉及的退款金额(汇总)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.returnGoodsAmount IS '对应JSON字段:returnGoodsAmount,说明::本单涉及的退货金额汇总。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.rewardName IS '对应JSON字段:rewardName,说明:(结构上):用于标识本单适用的激励方案名称,可能用于内部绩效或活动名称展示。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.settleType IS '对应JSON字段:settleType,说明::结算类型字符串标识。,示例值及对应分析:"SiteOrder":店内消费订单结算。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.siteAddress IS '对应JSON字段:siteAddress,说明::门店地址(详细地址)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.siteBusinessTel IS '对应JSON字段:siteBusinessTel,说明::门店电话。,示例值及对应分析:用途:用于小票打印上的客服电话。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.siteId IS '对应JSON字段:siteId,说明::门店 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.siteName IS '对应JSON字段:siteName,说明::门店名称,如“朗朗桌球”。,示例值及对应分析:用途:小票上展示门店名。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.tenantId IS '对应JSON字段:tenantId,说明::租户 / 商户 ID(品牌维度)。,示例值及对应分析:当前数据:恒定为同一值,表示所有记录都来自同一商户。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.tenantName IS '对应JSON字段:tenantName,说明::租户名称,如“朗朗桌球”。,示例值及对应分析:当前数据:全表统一一个值。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.ticketCustomContent IS '对应JSON字段:ticketCustomContent,说明::自定义小票内容,如商家自定义宣传语、条款等。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.ticketRemark IS '对应JSON字段:ticketRemark,说明::小票备注内容,可用于打印在小票底部或顶部(例如活动说明、特别提示)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.voucherMoney IS '对应JSON字段:voucherMoney,说明::代金券类金额字段(可能用于某类“代金券余额”或“券面值”记录)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.memberProfile IS '对应JSON字段:memberProfile,说明::,示例值及对应分析:不是会员卡主键,而是本次结账时的会员信息快照;';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.orderItem IS '对应JSON字段:orderItem,说明::本次结算对应的“订单明细列表”,这部分是连接“台费流水 / 商品出库 / 券使用”等多个子领域的关键结构。,示例值及对应分析:下面专门展开 orderItem 及其子结构。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.tenantMemberCardLogs IS '对应JSON字段:tenantMemberCardLogs,说明:?????? settlement_ticket_details-Analysis.md,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.store_goods_master (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ siteName TEXT,
+ tenant_goods_id BIGINT,
+ goods_name TEXT,
+ goods_bar_code TEXT,
+ goods_category_id BIGINT,
+ goods_second_category_id BIGINT,
+ oneCategoryName TEXT,
+ twoCategoryName TEXT,
+ unit TEXT,
+ sale_price NUMERIC(18,4),
+ cost_price NUMERIC(18,4),
+ cost_price_type INT,
+ min_discount_price NUMERIC(18,4),
+ safe_stock NUMERIC(18,4),
+ stock NUMERIC(18,4),
+ stock_A NUMERIC(18,4),
+ sale_num NUMERIC(18,4),
+ total_purchase_cost NUMERIC(18,4),
+ total_sales NUMERIC(18,4),
+ average_monthly_sales NUMERIC(18,4),
+ enable_status INT,
+ audit_status INT,
+ goods_state INT,
+ is_delete INT,
+ is_warehousing INT,
+ able_discount INT,
+ able_site_transfer INT,
+ forbid_sell_status INT,
+ "freeze" INT,
+ send_state INT,
+ custom_label_type INT,
+ option_required INT,
+ sale_channel INT,
+ remark TEXT,
+ pinyin_initial TEXT,
+ goods_cover TEXT,
+ create_time TIMESTAMP,
+ update_time TIMESTAMP,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+
+COMMENT ON TABLE billiards_ods.store_goods_master IS '对应JSON字段:store_goods_master.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 store_goods_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_master.id IS '对应JSON字段:id,说明::门店商品 ID,门店维度的商品主键。,示例值及对应分析:用途:在其它文件中经常以 site_goods_id 的名字出现,与这里的 id 一致,用来关联库存记录、销售记录等。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID。同一品牌下多个门店共享一个 tenant_id。,示例值及对应分析:枚举情况:本文件中为单一固定值(同一品牌)。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.site_id IS '对应JSON字段:site_id,说明::门店 ID。,示例值及对应分析:枚举情况:本文件中为单一固定值(同一家门店“朗朗桌球”),和其它 JSON 中的 site_id 一致。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.siteName IS '对应JSON字段:siteName,说明::门店名称,是对 site_id 的冗余展示,方便直接阅读,无需再去关联门店档案。,示例值及对应分析:2. 商品标识和分类维度';
+COMMENT ON COLUMN billiards_ods.store_goods_master.tenant_goods_id IS '对应JSON字段:tenant_goods_id,说明::租户/品牌维度的商品 ID,相当于“全局商品 ID”。,示例值及对应分析:用途:用于跨门店或与“商品档案(商品档案.json)”对齐时使用。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_name IS '对应JSON字段:goods_name,说明::商品名称,例如“合味道泡面”“地道肠”“麻将房茶位费”等。,示例值及对应分析:用途:业务展示字段,历史流水里也会冗余存一份商品名。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_bar_code IS '对应JSON字段:goods_bar_code,说明::商品条形码(如 EAN-13 编码),用于扫码销售。此字段设计为可填,但此店目前未配置。,示例值及对应分析:?? store_goods_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_category_id IS '对应JSON字段:goods_category_id,说明::商品一级分类 ID。,示例值及对应分析:用途:';
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_second_category_id IS '对应JSON字段:goods_second_category_id,说明::商品二级分类 ID。,示例值及对应分析:用途:';
+COMMENT ON COLUMN billiards_ods.store_goods_master.oneCategoryName IS '对应JSON字段:oneCategoryName,说明::一级分类名称,如“零食”“酒水”“服务费”等。,示例值及对应分析:说明:与 goods_category_id 一一对应,是易读文本字段。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.twoCategoryName IS '对应JSON字段:twoCategoryName,说明::二级分类名称,如“面”“洋酒”“纸巾”等。,示例值及对应分析:说明:与 goods_second_category_id 对应。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.unit IS '对应JSON字段:unit,说明::商品计量单位(销售单位)。,示例值及对应分析:?? store_goods_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_master.sale_price IS '对应JSON字段:sale_price,说明::商品标准销售价(挂牌价),单位为元。,示例值及对应分析:说明:实际结算时可能会打折或用券抵扣,但这个字段表示“定价”。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.cost_price IS '对应JSON字段:cost_price,说明::商品成本价(单件成本)。,示例值及对应分析:观察:';
+COMMENT ON COLUMN billiards_ods.store_goods_master.cost_price_type IS '对应JSON字段:cost_price_type,说明:(结合成本字段推测):,示例值及对应分析:1 代表使用“固定成本价”(手工维护的 cost_price),provisional_total_cost 按“数量 × cost_price”算。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.min_discount_price IS '对应JSON字段:min_discount_price,说明::最低允许成交价(限价)。,示例值及对应分析:用法逻辑(推测):';
+COMMENT ON COLUMN billiards_ods.store_goods_master.safe_stock IS '对应JSON字段:safe_stock,说明::安全库存量(阈值),低于该值时系统可以提示补货。,示例值及对应分析:当前门店尚未设置安全库存,所以全部为 0,仅起到结构占位作用。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.stock IS '对应JSON字段:stock,说明::当前可用库存数量(以 unit 为单位)。,示例值及对应分析:特征:可以是 0(库存卖完),也可以非常大(例如纸巾、茶位费这种按“份”计的虚拟库存设定)。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.stock_A IS '对应JSON字段:stock_A,说明:(系统设计):副单位库存数量。如果商品存在双单位(例如箱/瓶),stock_A 通常用于记录副单位库存。当前门店没有启用副单位库存管理,因此为 0。,示例值及对应分析:batch_stock_quantity';
+COMMENT ON COLUMN billiards_ods.store_goods_master.sale_num IS '对应JSON字段:sale_num,说明::在当前统计口径下的销售数量(总销量,单位同 unit)。,示例值及对应分析:特征:和 total_sales 完全一致(当前导出时的统计口径下),说明两者是同一统计周期。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.total_purchase_cost IS '对应JSON字段:total_purchase_cost,说明::总采购成本,单位为元。,示例值及对应分析:当前数据:与 provisional_total_cost 完全相等。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.total_sales IS '对应JSON字段:total_sales,说明:(从命名看):累计销售数量。,示例值及对应分析:实际:当前数据中 total_sales == sale_num,说明此接口的统计区间 = “截至当前的全部历史”,因此数量一致。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.average_monthly_sales IS '对应JSON字段:average_monthly_sales,说明::平均月销量(件/月),根据某个统计周期内的销售数据折算而来。,示例值及对应分析:结构特征:';
+COMMENT ON COLUMN billiards_ods.store_goods_master.enable_status IS '对应JSON字段:enable_status,说明:(结合名称与常见编码):,示例值及对应分析:1:启用。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.audit_status IS '对应JSON字段:audit_status,说明:(典型业务语义):,示例值及对应分析:2:审核通过。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_state IS '对应JSON字段:goods_state,说明:类型:int,枚举,示例值及对应分析:观察值:';
+COMMENT ON COLUMN billiards_ods.store_goods_master.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志。,示例值及对应分析:0:未删除(有效档案);';
+COMMENT ON COLUMN billiards_ods.store_goods_master.is_warehousing IS '对应JSON字段:is_warehousing,说明::是否纳入库存管理。,示例值及对应分析:1:启用库存管理(会有出入库流水)。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.able_discount IS '对应JSON字段:able_discount,说明:(结合命名):,示例值及对应分析:是否允许参与折扣。当前全部为 1,说明所有商品都允许打折。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.able_site_transfer IS '对应JSON字段:able_site_transfer,说明:(结合命名与值分布):,示例值及对应分析:表示是否允许跨门店调拨或跨站点共享库存。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.forbid_sell_status IS '对应JSON字段:forbid_sell_status,说明:类型:int,枚举,示例值及对应分析:观察值:全部为 1。';
+COMMENT ON COLUMN billiards_ods.store_goods_master."freeze" IS '对应JSON字段:freeze,说明::冻结状态。,示例值及对应分析:0:未冻结;';
+COMMENT ON COLUMN billiards_ods.store_goods_master.send_state IS '对应JSON字段:send_state,说明:(命名趋近“上架状态/可售状态”):,示例值及对应分析:1:可销售/可下单。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.custom_label_type IS '对应JSON字段:custom_label_type,说明:(推测):自定义标签类型。,示例值及对应分析:1:使用系统默认标签(未出现);';
+COMMENT ON COLUMN billiards_ods.store_goods_master.option_required IS '对应JSON字段:option_required,说明:(推测):是否需要在销售时选择规格/选项。,示例值及对应分析:1:不要求额外选项(单规格商品);';
+COMMENT ON COLUMN billiards_ods.store_goods_master.sale_channel IS '对应JSON字段:sale_channel,说明::销售渠道类型。,示例值及对应分析:常见模式:';
+COMMENT ON COLUMN billiards_ods.store_goods_master.remark IS '对应JSON字段:remark,说明::商品备注(可以写口味说明、供应商、注意事项等)。当前尚未使用。,示例值及对应分析:sort';
+COMMENT ON COLUMN billiards_ods.store_goods_master.pinyin_initial IS '对应JSON字段:pinyin_initial,说明::商品名称的拼音首字母缩写,有时多个别名用逗号分隔。,示例值及对应分析:作用:';
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_cover IS '对应JSON字段:goods_cover,说明::商品图片 URL(如 OSS 对象存储地址),用于前端展示商品图片。,示例值及对应分析:?? store_goods_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_master.create_time IS '对应JSON字段:create_time,说明::门店商品档案创建时间(商品在门店建立档案的时间点)。,示例值及对应分析:?? store_goods_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_master.update_time IS '对应JSON字段:update_time,说明::最后一次修改该商品档案的时间(包括价格调整、状态变更等)。,示例值及对应分析:days_available';
+COMMENT ON COLUMN billiards_ods.store_goods_master.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.store_goods_master.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.store_goods_master.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.store_goods_master.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.store_goods_sales_records (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ site_goods_id BIGINT,
+ tenant_goods_id BIGINT,
+ order_settle_id BIGINT,
+ order_trade_no TEXT,
+ order_goods_id BIGINT,
+ order_pay_id BIGINT,
+ order_coupon_id BIGINT,
+ ledger_name TEXT,
+ ledger_group_name TEXT,
+ ledger_amount NUMERIC(18,2),
+ ledger_count NUMERIC(18,4),
+ ledger_unit_price NUMERIC(18,4),
+ ledger_status INT,
+ discount_money NUMERIC(18,2),
+ coupon_deduct_money NUMERIC(18,2),
+ member_discount_amount NUMERIC(18,2),
+ option_coupon_deduct_money NUMERIC(18,2),
+ option_member_discount_money NUMERIC(18,2),
+ point_discount_money NUMERIC(18,2),
+ point_discount_money_cost NUMERIC(18,2),
+ real_goods_money NUMERIC(18,2),
+ cost_money NUMERIC(18,2),
+ push_money NUMERIC(18,2),
+ sales_type INT,
+ is_single_order INT,
+ is_delete INT,
+ goods_remark TEXT,
+ option_price NUMERIC(18,2),
+ option_value_name TEXT,
+ option_name TEXT,
+ member_coupon_id BIGINT,
+ package_coupon_id BIGINT,
+ sales_man_org_id BIGINT,
+ salesman_name TEXT,
+ salesman_role_id BIGINT,
+ salesman_user_id BIGINT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ openSalesman TEXT,
+ site_table_id BIGINT,
+ tenant_goods_business_id BIGINT,
+ tenant_goods_category_id BIGINT,
+ create_time TIMESTAMP,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+
+COMMENT ON TABLE billiards_ods.store_goods_sales_records IS '对应JSON字段:store_goods_sales_records.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.id IS '对应JSON字段:id,说明::本条「门店销售流水」记录的主键 ID。,示例值及对应分析:用途:在系统内部唯一标识这一条销售明细。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID。,示例值及对应分析:特征:所有记录为同一个值,对应「非球科技系统中你的商户」。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.site_id IS '对应JSON字段:site_id,说明::门店 ID(系统主键)。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.site_goods_id IS '对应JSON字段:site_goods_id,说明::门店商品 ID。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.tenant_goods_id IS '对应JSON字段:tenant_goods_id,说明::租户(品牌)级商品 ID(全局商品 ID)。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.order_settle_id IS '对应JSON字段:order_settle_id,说明:与台费、助教、团购套餐流水等表共享,形成「订单主表(结算)– 多种明细表」的结构。,示例值及对应分析:如果结账记录表有数据,order_settle_id 对应那里的主键,create_time 与订单结束时间基本一致。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.order_trade_no IS '对应JSON字段:order_trade_no,说明:与台费、助教、团购套餐流水等表共享,形成「订单主表(结算)– 多种明细表」的结构。,示例值及对应分析:如果结账记录表有数据,order_settle_id 对应那里的主键,create_time 与订单结束时间基本一致。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.order_goods_id IS '对应JSON字段:order_goods_id,说明::订单商品明细 ID(订单内部的商品行主键)。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.order_pay_id IS '对应JSON字段:order_pay_id,说明:连接到「支付记录」中的一条支付流水,再通过支付的 relate_type/relate_id 把支付和订单、充值等业务区分开。,示例值及对应分析:对于退款,则通过退款记录里的 relate_type/relate_id 反向关联到原来的订单或支付。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.order_coupon_id IS '对应JSON字段:order_coupon_id,说明::订单级优惠券 ID。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_name IS '对应JSON字段:ledger_name,说明::销售项目名称(商品名称),例如 “哇哈哈矿泉水”“地道肠”“东方树叶”等。,示例值及对应分析:说明:业务展示用字段,历史流水即使商品改名,这里会保留当时的名字。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_group_name IS '对应JSON字段:ledger_group_name,说明::销售项目所属的「门店内部分组名称」,类似前台菜单分组或大类标签。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_amount IS '对应JSON字段:ledger_amount,说明::原始应收金额,公式上接近 ledger_unit_price × ledger_count。,示例值及对应分析:说明:这是未考虑优惠前的金额基础,用于后续计算折扣和抵扣。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_count IS '对应JSON字段:ledger_count,说明::销售数量(以 unit 为单位,unit 字段在门店商品档案中)。,示例值及对应分析:观测值:如 1, 2, 3, 6, 36 等。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_unit_price IS '对应JSON字段:ledger_unit_price,说明::商品在该次销售中的「结算单价」(元/单位)。,示例值及对应分析:观测值示例:5.0, 8.0, 2.0, 10.0, 72.0 等。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_status IS '对应JSON字段:ledger_status,说明::销售流水状态。,示例值及对应分析:1:正常有效。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.discount_money IS '对应JSON字段:discount_money,说明::本条销售明细的「价格优惠金额」,即原价部分被减免掉的金额。,示例值及对应分析:典型关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.coupon_deduct_money IS '对应JSON字段:coupon_deduct_money,说明::被优惠券 / 团购券直接抵扣到这条商品明细上的金额。,示例值及对应分析:说明:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.member_discount_amount IS '对应JSON字段:member_discount_amount,说明::由会员身份(会员折扣)针对这一行商品产生的优惠金额。,示例值及对应分析:说明:尽管字段存在,但当前实际折扣可能合并反映在 discount_money 中,这个字段没有拆开体现。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.option_coupon_deduct_money IS '对应JSON字段:option_coupon_deduct_money,说明::由优惠券抵扣“选项价格”的金额。,示例值及对应分析:上面这三个 option_* 字段,是为“主商品 + 选项”的更复杂计价方式预留的,本店当前所有记录都是单规格,选项体系未启用。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.option_member_discount_money IS '对应JSON字段:option_member_discount_money,说明::由会员折扣作用在“选项价格”上的优惠金额。,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.point_discount_money IS '对应JSON字段:point_discount_money,说明::由积分抵扣的金额(顾客兑换积分抵现金额)。,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.point_discount_money_cost IS '对应JSON字段:point_discount_money_cost,说明::积分抵扣对应的“成本金额”(后台核算用),例如按积分成本来计提费用。,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.real_goods_money IS '对应JSON字段:real_goods_money,说明::商品实际入账金额(考虑折扣、可能还会考虑其它抵扣后的实际销售金额)。,示例值及对应分析:观测值:5.0, 10.0, 8.0, 6.0, 4.0 等。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.cost_money IS '对应JSON字段:cost_money,说明::本条销售对应的成本金额(以元计)。,示例值及对应分析:观测示例:0.01, 0.00, 3.58, 1.79, 0.64 等。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.push_money IS '对应JSON字段:push_money,说明::本条销售对应的提成金额(给营业员/促销员的提成)。,示例值及对应分析:在启用营业员体系时,这里才会出现正数。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.sales_type IS '对应JSON字段:sales_type,说明::销售类型。,示例值及对应分析:1:正常销售;';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.is_single_order IS '对应JSON字段:is_single_order,说明::是否单独订单标识。,示例值及对应分析:1:作为独立明细参与某个订单结算;';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志。,示例值及对应分析:0:正常有效;';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.goods_remark IS '对应JSON字段:goods_remark,说明::商品备注/口味说明/特殊说明。,示例值及对应分析:用途:点单时如果需要额外说明,可以写在这里。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.option_price IS '对应JSON字段:option_price,说明::商品选项(规格/加料)的附加价格。,示例值及对应分析:说明:如加冰、加料、升级大杯等产生附加费用时,理论上应该体现到这里。当前门店未使用此功能。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.option_value_name IS '对应JSON字段:option_value_name,说明::商品选项名称(如规格、口味:大杯/小杯,不加冰等)。,示例值及对应分析:结构用途:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.option_name IS '对应JSON字段:option_name,说明:?????? store_goods_sales_records-Analysis.md,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.member_coupon_id IS '对应JSON字段:member_coupon_id,说明::会员券 ID(比如会员专享优惠券)。,示例值及对应分析:当前数据未使用,属于为会员权益预留的字段。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.package_coupon_id IS '对应JSON字段:package_coupon_id,说明::套餐券 ID。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.sales_man_org_id IS '对应JSON字段:sales_man_org_id,说明::营业员所属组织/部门 ID。,示例值及对应分析:当前门店全部为 0,说明未启用这套销售员分组织的体系。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.salesman_name IS '对应JSON字段:salesman_name,说明::营业员姓名(如果有为具体销售员记业绩,则在此填姓名)。,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.salesman_role_id IS '对应JSON字段:salesman_role_id,说明::营业员的系统角色 ID(例如某个角色代码表示“销售员”)。,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.salesman_user_id IS '对应JSON字段:salesman_user_id,说明::营业员用户 ID(系统账号 ID)。,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.operator_id IS '对应JSON字段:operator_id,说明::操作员 ID(录入这笔销售的员工)。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.operator_name IS '对应JSON字段:operator_name,说明::操作员姓名,文字冗余。,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.openSalesman IS '对应JSON字段:openSalesman,说明:(结合系统其它文件推断):,示例值及对应分析:1:启用“营业员/销售员”机制(要指定 salesman);';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.site_table_id IS '对应JSON字段:site_table_id,说明::球台 ID。,示例值及对应分析:非 0:销售记录关联到具体某张桌台(例如顾客在台上点饮料)。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.tenant_goods_business_id IS '对应JSON字段:tenant_goods_business_id,说明::租户级商品「业务大类」ID(例如“零食类”“酒水类”等更高维度)。,示例值及对应分析:2.2 门店 / 球台维度字段';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.tenant_goods_category_id IS '对应JSON字段:tenant_goods_category_id,说明::租户级商品一级分类 ID。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.create_time IS '对应JSON字段:create_time,说明::销售记录创建时间,通常就是结账时间或录入时间。,示例值及对应分析:用途:用于按时间维度查询销售流水,与订单层的时间字段对齐。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
diff --git a/etl_billiards/database/schema_ODS_doc.sql b/etl_billiards/database/schema_ODS_doc.sql
new file mode 100644
index 0000000..514f931
--- /dev/null
+++ b/etl_billiards/database/schema_ODS_doc.sql
@@ -0,0 +1,1907 @@
+-- 文件:schema_ODS_doc.sql
+-- 说明:ODS 层 DDL,表名与示例 JSON 前缀对应,用于本地回放/调试。
+-- 编码:UTF-8
+SET client_encoding TO "UTF8";
+
+DROP SCHEMA IF EXISTS billiards_ods CASCADE;
+CREATE SCHEMA IF NOT EXISTS billiards_ods;
+
+CREATE TABLE IF NOT EXISTS billiards_ods.member_profiles (
+ tenant_id BIGINT,
+ register_site_id BIGINT,
+ site_name TEXT,
+ id BIGINT PRIMARY KEY,
+ system_member_id BIGINT,
+ member_card_grade_code BIGINT,
+ member_card_grade_name TEXT,
+ mobile TEXT,
+ nickname TEXT,
+ point NUMERIC(18,2),
+ growth_value NUMERIC(18,2),
+ referrer_member_id BIGINT,
+ status INT,
+ user_status INT,
+ create_time TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.member_profiles IS '对应JSON字段:member_profiles.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 member_profiles-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_profiles.tenant_id IS '对应JSON字段:tenant_id,说明::,示例值及对应分析:租户/品牌 ID。';
+COMMENT ON COLUMN billiards_ods.member_profiles.register_site_id IS '对应JSON字段:register_site_id,说明::,示例值及对应分析:会员的注册门店 ID。';
+COMMENT ON COLUMN billiards_ods.member_profiles.site_name IS '对应JSON字段:site_name,说明::,示例值及对应分析:注册门店名称,属于冗余字段,用于直接展示。';
+COMMENT ON COLUMN billiards_ods.member_profiles.id IS '对应JSON字段:id,说明::,示例值及对应分析:这是“租户内会员账户”的主键 ID。';
+COMMENT ON COLUMN billiards_ods.member_profiles.system_member_id IS '对应JSON字段:system_member_id,说明:(结合其它文件):,示例值及对应分析:这是“系统级会员 ID”,在全平台唯一,用来把一个会员在不同门店/不同卡类型下的账户统一到一个“人”的维度上。';
+COMMENT ON COLUMN billiards_ods.member_profiles.member_card_grade_code IS '对应JSON字段:member_card_grade_code,说明:类型:int,示例值及对应分析:唯一值个数:4';
+COMMENT ON COLUMN billiards_ods.member_profiles.member_card_grade_name IS '对应JSON字段:member_card_grade_name,说明::,示例值及对应分析:这是“会员卡种类/等级”的定义字段。';
+COMMENT ON COLUMN billiards_ods.member_profiles.mobile IS '对应JSON字段:mobile,说明::,示例值及对应分析:会员绑定的手机号码。';
+COMMENT ON COLUMN billiards_ods.member_profiles.nickname IS '对应JSON字段:nickname,说明::,示例值及对应分析:会员在当前租户下的显示名称(可以是姓名,也可以是昵称)。';
+COMMENT ON COLUMN billiards_ods.member_profiles.point IS '对应JSON字段:point,说明::,示例值及对应分析:当前积分余额(这条会员账户的积分值)。';
+COMMENT ON COLUMN billiards_ods.member_profiles.growth_value IS '对应JSON字段:growth_value,说明:(按常见会员体系设计):,示例值及对应分析:成长值 / 经验值,用于会员等级晋升的累计指标。';
+COMMENT ON COLUMN billiards_ods.member_profiles.referrer_member_id IS '对应JSON字段:referrer_member_id,说明:(按命名推断):,示例值及对应分析:推荐人会员 ID,用于记录该会员是由哪位老会员推荐。';
+COMMENT ON COLUMN billiards_ods.member_profiles.status IS '对应JSON字段:status,说明:(按命名推断):,示例值及对应分析:帐户状态(偏“卡状态/档案状态”)。';
+COMMENT ON COLUMN billiards_ods.member_profiles.user_status IS '对应JSON字段:user_status,说明:(结合行业惯例):,示例值及对应分析:用户账号状态(偏“用户逻辑”层面的状态)。';
+COMMENT ON COLUMN billiards_ods.member_profiles.create_time IS '对应JSON字段:create_time,说明::,示例值及对应分析:会员账户的创建时间(即这条档案/这张卡在系统中被创建的时间)。';
+COMMENT ON COLUMN billiards_ods.member_profiles.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_profiles.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_profiles.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_profiles.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.member_balance_changes (
+ tenant_id BIGINT,
+ site_id BIGINT,
+ register_site_id BIGINT,
+ registerSiteName TEXT,
+ paySiteName TEXT,
+ id BIGINT PRIMARY KEY,
+ tenant_member_id BIGINT,
+ tenant_member_card_id BIGINT,
+ system_member_id BIGINT,
+ memberName TEXT,
+ memberMobile TEXT,
+ card_type_id BIGINT,
+ memberCardTypeName TEXT,
+ account_data NUMERIC(18,2),
+ before NUMERIC(18,2),
+ after NUMERIC(18,2),
+ refund_amount NUMERIC(18,2),
+ from_type INT,
+ payment_method INT,
+ relate_id BIGINT,
+ remark TEXT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ is_delete INT,
+ create_time TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.member_balance_changes IS '对应JSON字段:member_balance_changes.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.tenant_id IS '对应JSON字段:tenant_id,说明::租户/商户 ID,本数据中是固定值(同一品牌/商户)。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.site_id IS '对应JSON字段:site_id,说明:表示本次余额变动的发生门店,绝大多数也在“朗朗桌球”,少数特殊业务(活动抵用券结算)显示为 site_id=0、paySiteName 为空。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.register_site_id IS '对应JSON字段:register_site_id,说明:已在前文说明:办卡门店的 ID 与名称,所有记录一致,说明所有卡均在“朗朗桌球”注册。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.registerSiteName IS '对应JSON字段:registerSiteName,说明:已在前文说明:办卡门店的 ID 与名称,所有记录一致,说明所有卡均在“朗朗桌球”注册。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.paySiteName IS '对应JSON字段:paySiteName,说明:表示本次余额变动的发生门店,绝大多数也在“朗朗桌球”,少数特殊业务(活动抵用券结算)显示为 site_id=0、paySiteName 为空。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.id IS '对应JSON字段:id,说明::余额变更记录的主键 ID,唯一标识这一条“账户余额变化事件”。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.tenant_member_id IS '对应JSON字段:tenant_member_id,说明::商户维度的会员 ID(租户内会员主键)。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.tenant_member_card_id IS '对应JSON字段:tenant_member_card_id,说明::会员卡账户 ID,在租户内唯一标识某张卡。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.system_member_id IS '对应JSON字段:system_member_id,说明::系统级(全局)会员 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.memberName IS '对应JSON字段:memberName,说明::会员姓名或称呼(非昵称字段)。,示例值及对应分析:说明:例如“陈腾鑫”“胡先生”“江先生”等,多为中文姓名或带“先生”称呼。';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.memberMobile IS '对应JSON字段:memberMobile,说明::会员手机号。,示例值及对应分析:说明:字符型存储,完整手机号,用来识别会员与联系客户。';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.card_type_id IS '对应JSON字段:card_type_id,说明::卡种类型 ID,用于区分不同卡种。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.memberCardTypeName IS '对应JSON字段:memberCardTypeName,说明::卡种名称,与 card_type_id 一一对应,是一个 卡种枚举名称。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.account_data IS '对应JSON字段:account_data,说明::本次变动的金额(元),正数表示增加,负数表示减少。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.before IS '对应JSON字段:before,说明::本次变动前,该卡账户的余额(元)。,示例值及对应分析:说明:';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.after IS '对应JSON字段:after,说明::本次变动后,该卡账户的余额(元)。,示例值及对应分析:重要关系:';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.refund_amount IS '对应JSON字段:refund_amount,说明:(推测):与退款业务相关的金额字段,但在当前这份导出中实际未使用:,示例值及对应分析:可能用于标记“其中有多少金额是以‘退款’形式回流的”,或区分“退回余额”和“原路退回”两种模式。';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.from_type IS '对应JSON字段:from_type,说明:(根据金额符号与 remark 综合推断):,示例值及对应分析:1:日常消费扣款';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.payment_method IS '对应JSON字段:payment_method,说明:类型:int,枚举,示例值及对应分析:值分布:';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.relate_id IS '对应JSON字段:relate_id,说明:(推测):关联业务记录的 ID:,示例值及对应分析:例如某次充值记录的 ID、某张订单/结算单 ID、某次活动抵用券核销记录 ID 等。';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.remark IS '对应JSON字段:remark,说明::,示例值及对应分析:当为空时,说明这条变动没有额外备注说明。';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.operator_id IS '对应JSON字段:operator_id,说明::执行此次余额变更操作的员工 ID。,示例值及对应分析:?? member_balance_changes-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.operator_name IS '对应JSON字段:operator_name,说明::操作员姓名(带职位前缀),是对 operator_id 的可读冗余字段。,示例值及对应分析:9. 状态字段与标志';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标记:,示例值及对应分析:0:正常;';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.create_time IS '对应JSON字段:create_time,说明::本条余额变更记录的创建时间,通常接近交易发生时间。,示例值及对应分析:说明:可与订单、支付记录的时间做对齐,构造时序链路(但你现在不要求做时序分析,这里只说明结构)。';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_balance_changes.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.member_stored_value_cards (
+ tenant_id BIGINT,
+ tenant_member_id BIGINT,
+ system_member_id BIGINT,
+ register_site_id BIGINT,
+ site_name TEXT,
+ id BIGINT PRIMARY KEY,
+ member_card_grade_code BIGINT,
+ member_card_grade_code_name TEXT,
+ member_card_type_name TEXT,
+ member_name TEXT,
+ member_mobile TEXT,
+ card_type_id BIGINT,
+ card_no TEXT,
+ card_physics_type TEXT,
+ balance NUMERIC(18,2),
+ denomination NUMERIC(18,2),
+ table_discount NUMERIC(10,4),
+ goods_discount NUMERIC(10,4),
+ assistant_discount NUMERIC(10,4),
+ assistant_reward_discount NUMERIC(10,4),
+ table_service_discount NUMERIC(10,4),
+ assistant_service_discount NUMERIC(10,4),
+ coupon_discount NUMERIC(10,4),
+ goods_service_discount NUMERIC(10,4),
+ assistant_discount_sub_switch INT,
+ table_discount_sub_switch INT,
+ goods_discount_sub_switch INT,
+ assistant_reward_discount_sub_switch INT,
+ table_service_deduct_radio NUMERIC(10,4),
+ assistant_service_deduct_radio NUMERIC(10,4),
+ goods_service_deduct_radio NUMERIC(10,4),
+ assistant_deduct_radio NUMERIC(10,4),
+ table_deduct_radio NUMERIC(10,4),
+ goods_deduct_radio NUMERIC(10,4),
+ coupon_deduct_radio NUMERIC(10,4),
+ assistant_reward_deduct_radio NUMERIC(10,4),
+ tableCardDeduct NUMERIC(18,2),
+ tableServiceCardDeduct NUMERIC(18,2),
+ goodsCarDeduct NUMERIC(18,2),
+ goodsServiceCardDeduct NUMERIC(18,2),
+ assistantCardDeduct NUMERIC(18,2),
+ assistantServiceCardDeduct NUMERIC(18,2),
+ assistantRewardCardDeduct NUMERIC(18,2),
+ cardSettleDeduct NUMERIC(18,2),
+ couponCardDeduct NUMERIC(18,2),
+ deliveryFeeDeduct NUMERIC(18,2),
+ use_scene INT,
+ able_cross_site INT,
+ able_site_transfer INT,
+ is_allow_give INT,
+ is_allow_order_deduct INT,
+ is_delete INT,
+ bind_password TEXT,
+ goods_discount_range_type INT,
+ goodsCategoryId BIGINT,
+ tableAreaId BIGINT,
+ effect_site_id BIGINT,
+ start_time TIMESTAMP,
+ end_time TIMESTAMP,
+ disable_start_time TIMESTAMP,
+ disable_end_time TIMESTAMP,
+ last_consume_time TIMESTAMP,
+ create_time TIMESTAMP,
+ status INT,
+ sort INT,
+ tenantAvatar TEXT,
+ tenantName TEXT,
+ pdAssisnatLevel TEXT,
+ cxAssisnatLevel TEXT,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.member_stored_value_cards IS '对应JSON字段:member_stored_value_cards.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID,与其他 JSON 中 tenant_id 一致。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tenant_member_id IS '对应JSON字段:tenant_member_id,说明::当前商户(品牌/租户)中会员的主键 ID。,示例值及对应分析:枚举特征:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.system_member_id IS '对应JSON字段:system_member_id,说明::系统级会员 ID(跨门店统一主键)。,示例值及对应分析:枚举特征:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.register_site_id IS '对应JSON字段:register_site_id,说明::卡首次办理的门店 ID。,示例值及对应分析:对应门店的 site_id;本数据中所有卡都是在同一家门店开卡。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.site_name IS '对应JSON字段:site_name,说明::卡归属门店名称(视图中的展示字段)。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.id IS '对应JSON字段:id,说明:?????? member_stored_value_cards-Analysis.md,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.member_card_grade_code IS '对应JSON字段:member_card_grade_code,说明::卡等级/卡类代码,和下面两个名称字段一一对应。,示例值及对应分析:枚举:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.member_card_grade_code_name IS '对应JSON字段:member_card_grade_code_name,说明::卡等级/卡类名称。,示例值及对应分析:枚举值(与上面 code 一一对应):';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.member_card_type_name IS '对应JSON字段:member_card_type_name,说明::卡类型名称,实际与 member_card_grade_code_name 一致。,示例值及对应分析:枚举值同上。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.member_name IS '对应JSON字段:member_name,说明::持卡会员姓名快照。,示例值及对应分析:特点:存在 null(20 张卡没有绑定会员名字)。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.member_mobile IS '对应JSON字段:member_mobile,说明::持卡会员手机号快照。,示例值及对应分析:特点:与 member_name 对应,多数有值,少量为 null。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.card_type_id IS '对应JSON字段:card_type_id,说明::卡种 ID(定义“这是哪一种卡”)。,示例值及对应分析:枚举(按数据分布):';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.card_no IS '对应JSON字段:card_no,说明:(推测):实体卡物理卡号/条码号。当前这批卡看起来全部为“无物理卡号”(可能是全部虚拟卡或卡号隐藏不导出)。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.card_physics_type IS '对应JSON字段:card_physics_type,说明::物理卡类型。,示例值及对应分析:当前数据:全部为 1。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.balance IS '对应JSON字段:balance,说明::当前卡内余额(主要针对储值卡、部分券卡)。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.denomination IS '对应JSON字段:denomination,说明:(推测):面额/初始储值额度。,示例值及对应分析:本页数据未填充此字段;可能在分类型卡(如次卡/券)中才有意义,或者另有配置表。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.table_discount IS '对应JSON字段:table_discount,说明::,示例值及对应分析:采用“几折”的记法:10=不打折,9=九折,8=八折。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_discount IS '对应JSON字段:goods_discount,说明::,示例值及对应分析:采用“几折”的记法:10=不打折,9=九折,8=八折。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_discount IS '对应JSON字段:assistant_discount,说明::,示例值及对应分析:采用“几折”的记法:10=不打折,9=九折,8=八折。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_reward_discount IS '对应JSON字段:assistant_reward_discount,说明::,示例值及对应分析:采用“几折”的记法:10=不打折,9=九折,8=八折。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.table_service_discount IS '对应JSON字段:table_service_discount,说明::,示例值及对应分析:采用“几折”的记法:10=不打折,9=九折,8=八折。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_service_discount IS '对应JSON字段:assistant_service_discount,说明::,示例值及对应分析:采用“几折”的记法:10=不打折,9=九折,8=八折。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.coupon_discount IS '对应JSON字段:coupon_discount,说明:?????? member_stored_value_cards-Analysis.md,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_service_discount IS '对应JSON字段:goods_service_discount,说明::,示例值及对应分析:采用“几折”的记法:10=不打折,9=九折,8=八折。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_discount_sub_switch IS '对应JSON字段:assistant_discount_sub_switch,说明:(推测):“折扣是否叠加/替换其他折扣”的开关。,示例值及对应分析:可能枚举:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.table_discount_sub_switch IS '对应JSON字段:table_discount_sub_switch,说明:(推测):“折扣是否叠加/替换其他折扣”的开关。,示例值及对应分析:可能枚举:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_discount_sub_switch IS '对应JSON字段:goods_discount_sub_switch,说明:(推测):“折扣是否叠加/替换其他折扣”的开关。,示例值及对应分析:可能枚举:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_reward_discount_sub_switch IS '对应JSON字段:assistant_reward_discount_sub_switch,说明:(推测):“折扣是否叠加/替换其他折扣”的开关。,示例值及对应分析:可能枚举:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.table_service_deduct_radio IS '对应JSON字段:table_service_deduct_radio,说明::允许从该卡余额中抵扣的比例(百分比)。,示例值及对应分析:100.0 表示允许 100% 用卡余额支付该类消费;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_service_deduct_radio IS '对应JSON字段:assistant_service_deduct_radio,说明::允许从该卡余额中抵扣的比例(百分比)。,示例值及对应分析:100.0 表示允许 100% 用卡余额支付该类消费;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_service_deduct_radio IS '对应JSON字段:goods_service_deduct_radio,说明::允许从该卡余额中抵扣的比例(百分比)。,示例值及对应分析:100.0 表示允许 100% 用卡余额支付该类消费;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_deduct_radio IS '对应JSON字段:assistant_deduct_radio,说明::允许从该卡余额中抵扣的比例(百分比)。,示例值及对应分析:100.0 表示允许 100% 用卡余额支付该类消费;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.table_deduct_radio IS '对应JSON字段:table_deduct_radio,说明::允许从该卡余额中抵扣的比例(百分比)。,示例值及对应分析:100.0 表示允许 100% 用卡余额支付该类消费;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_deduct_radio IS '对应JSON字段:goods_deduct_radio,说明::允许从该卡余额中抵扣的比例(百分比)。,示例值及对应分析:100.0 表示允许 100% 用卡余额支付该类消费;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.coupon_deduct_radio IS '对应JSON字段:coupon_deduct_radio,说明::允许从该卡余额中抵扣的比例(百分比)。,示例值及对应分析:100.0 表示允许 100% 用卡余额支付该类消费;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistant_reward_deduct_radio IS '对应JSON字段:assistant_reward_deduct_radio,说明:?????? member_stored_value_cards-Analysis.md,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tableCardDeduct IS '对应JSON字段:tableCardDeduct,说明::针对台费/商品/助教三类消费的扣卡金额配置(类似“每小时从卡里扣 xx 元”或“每次抵扣 xx 元”的规则)。,示例值及对应分析:当前:所有为 0,说明在卡定义层面并没有指定固定扣卡金额,而是按照一般储值逻辑消费。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tableServiceCardDeduct IS '对应JSON字段:tableServiceCardDeduct,说明::如果系统中区分“储值金、服务金、奖励金”等子账户,这三个字段对应“服务金”子账户的扣款配置。,示例值及对应分析:当前未启用。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goodsCarDeduct IS '对应JSON字段:goodsCarDeduct,说明::针对台费/商品/助教三类消费的扣卡金额配置(类似“每小时从卡里扣 xx 元”或“每次抵扣 xx 元”的规则)。,示例值及对应分析:当前:所有为 0,说明在卡定义层面并没有指定固定扣卡金额,而是按照一般储值逻辑消费。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goodsServiceCardDeduct IS '对应JSON字段:goodsServiceCardDeduct,说明::如果系统中区分“储值金、服务金、奖励金”等子账户,这三个字段对应“服务金”子账户的扣款配置。,示例值及对应分析:当前未启用。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistantCardDeduct IS '对应JSON字段:assistantCardDeduct,说明::针对台费/商品/助教三类消费的扣卡金额配置(类似“每小时从卡里扣 xx 元”或“每次抵扣 xx 元”的规则)。,示例值及对应分析:当前:所有为 0,说明在卡定义层面并没有指定固定扣卡金额,而是按照一般储值逻辑消费。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistantServiceCardDeduct IS '对应JSON字段:assistantServiceCardDeduct,说明::如果系统中区分“储值金、服务金、奖励金”等子账户,这三个字段对应“服务金”子账户的扣款配置。,示例值及对应分析:当前未启用。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.assistantRewardCardDeduct IS '对应JSON字段:assistantRewardCardDeduct,说明::助教奖励金方向扣款的配置。,示例值及对应分析:当前未启用。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.cardSettleDeduct IS '对应JSON字段:cardSettleDeduct,说明:已在扣卡规则部分说明,当前为 0。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.couponCardDeduct IS '对应JSON字段:couponCardDeduct,说明::与卡绑定的“券额度扣除配置”。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.deliveryFeeDeduct IS '对应JSON字段:deliveryFeeDeduct,说明::配送费可否/多少从卡中抵扣,目前无业务发生。,示例值及对应分析:综合来看:本门店的卡片在“规则配置层”预留了大量细粒度控制字段,但目前实际使用只体现在“balance”和“可用范围”,折扣和具体扣卡规则基本都未启用(全部保持默认值 10 折、100%比例、0 扣款),真正扣款逻辑在交易流水中体现。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.use_scene IS '对应JSON字段:use_scene,说明::卡使用场景说明(比如“仅店内使用”“仅团建”等),本门店尚未使用此字段。,示例值及对应分析:2. 会员信息与关联字段';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.able_cross_site IS '对应JSON字段:able_cross_site,说明::是否允许跨店使用。,示例值及对应分析:1:可以跨门店使用;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.able_site_transfer IS '对应JSON字段:able_site_transfer,说明:?????? member_stored_value_cards-Analysis.md,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.is_allow_give IS '对应JSON字段:is_allow_give,说明::是否允许转赠/转让给其他会员。,示例值及对应分析:0:不允许;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.is_allow_order_deduct IS '对应JSON字段:is_allow_order_deduct,说明::是否允许在“订单层面统一扣款”。,示例值及对应分析:0:不允许(仅按项目扣卡);';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志。,示例值及对应分析:0:未删除;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.bind_password IS '对应JSON字段:bind_password,说明::卡绑定密码,用于消费或查询验证(目前未启用)。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goods_discount_range_type IS '对应JSON字段:goods_discount_range_type,说明:?????? member_stored_value_cards-Analysis.md,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.goodsCategoryId IS '对应JSON字段:goodsCategoryId,说明:已上文说明:均为扩展限定维度,当前全部为空列表。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tableAreaId IS '对应JSON字段:tableAreaId,说明:已上文说明:均为扩展限定维度,当前全部为空列表。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.effect_site_id IS '对应JSON字段:effect_site_id,说明:(推测):卡片限定生效门店 ID。,示例值及对应分析:为 0 时,配合 able_cross_site=1,可解释为“所有门店可用”。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.start_time IS '对应JSON字段:start_time,说明::卡片生效开始时间(有效期起始)。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.end_time IS '对应JSON字段:end_time,说明::卡片有效期结束时间。,示例值及对应分析:start_time / end_time 组合就是卡的有效期。不同卡种有效期配置不同,如储值卡长效、月卡固定一个月等。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.disable_start_time IS '对应JSON字段:disable_start_time,说明::停用时间段(比如临时冻结卡的起止时间)。,示例值及对应分析:当前未启用,所有卡都是“未进入停用窗口”。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.disable_end_time IS '对应JSON字段:disable_end_time,说明::停用时间段(比如临时冻结卡的起止时间)。,示例值及对应分析:当前未启用,所有卡都是“未进入停用窗口”。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.last_consume_time IS '对应JSON字段:last_consume_time,说明::最近一次消费时间。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.create_time IS '对应JSON字段:create_time,说明::卡片创建时间(开卡时间)。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.status IS '对应JSON字段:status,说明:(推测):,示例值及对应分析:1:正常可用;';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.sort IS '对应JSON字段:sort,说明::在前端展示或某些列表中的排序权重。,示例值及对应分析:具体取值分布不重要,主要反映展示优先级。';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tenantAvatar IS '对应JSON字段:tenantAvatar,说明::品牌头像 URL(未配置)。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.tenantName IS '对应JSON字段:tenantName,说明::租户/品牌名称(当前导出为空)。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.pdAssisnatLevel IS '对应JSON字段:pdAssisnatLevel,说明:已上文说明:均为扩展限定维度,当前全部为空列表。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.cxAssisnatLevel IS '对应JSON字段:cxAssisnatLevel,说明:已上文说明:均为扩展限定维度,当前全部为空列表。,示例值及对应分析:?? member_stored_value_cards-Analysis.md';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.member_stored_value_cards.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.recharge_settlements (
+ id BIGINT PRIMARY KEY,
+ tenantid BIGINT,
+ siteid BIGINT,
+ sitename TEXT,
+ balanceamount NUMERIC(18,2),
+ cardamount NUMERIC(18,2),
+ cashamount NUMERIC(18,2),
+ couponamount NUMERIC(18,2),
+ createtime TIMESTAMPTZ,
+ memberid BIGINT,
+ membername TEXT,
+ tenantmembercardid BIGINT,
+ membercardtypename TEXT,
+ memberphone TEXT,
+ tableid BIGINT,
+ consumemoney NUMERIC(18,2),
+ onlineamount NUMERIC(18,2),
+ operatorid BIGINT,
+ operatorname TEXT,
+ revokeorderid BIGINT,
+ revokeordername TEXT,
+ revoketime TIMESTAMPTZ,
+ payamount NUMERIC(18,2),
+ pointamount NUMERIC(18,2),
+ refundamount NUMERIC(18,2),
+ settlename TEXT,
+ settlerelateid BIGINT,
+ settlestatus INT,
+ settletype INT,
+ paytime TIMESTAMPTZ,
+ roundingamount NUMERIC(18,2),
+ paymentmethod INT,
+ adjustamount NUMERIC(18,2),
+ assistantcxmoney NUMERIC(18,2),
+ assistantpdmoney NUMERIC(18,2),
+ couponsaleamount NUMERIC(18,2),
+ memberdiscountamount NUMERIC(18,2),
+ tablechargemoney NUMERIC(18,2),
+ goodsmoney NUMERIC(18,2),
+ realgoodsmoney NUMERIC(18,2),
+ servicemoney NUMERIC(18,2),
+ prepaymoney NUMERIC(18,2),
+ salesmanname TEXT,
+ orderremark TEXT,
+ salesmanuserid BIGINT,
+ canberevoked BOOLEAN,
+ pointdiscountprice NUMERIC(18,2),
+ pointdiscountcost NUMERIC(18,2),
+ activitydiscount NUMERIC(18,2),
+ serialnumber BIGINT,
+ assistantmanualdiscount NUMERIC(18,2),
+ allcoupondiscount NUMERIC(18,2),
+ goodspromotionmoney NUMERIC(18,2),
+ assistantpromotionmoney NUMERIC(18,2),
+ isusecoupon BOOLEAN,
+ isusediscount BOOLEAN,
+ isactivity BOOLEAN,
+ isbindmember BOOLEAN,
+ isfirst INT,
+ rechargecardamount NUMERIC(18,2),
+ giftcardamount NUMERIC(18,2),
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.recharge_settlements IS '对应JSON字段:recharge_settlements.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.id IS '对应JSON字段:id,说明::本条充值结算记录的主键 ID(唯一标识一条充值/撤销记录)。,示例值及对应分析:唯一性:74 条记录全部不同。';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.tenantid IS '对应JSON字段:tenantid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.siteid IS '对应JSON字段:siteid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.sitename IS '对应JSON字段:sitename,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.balanceamount IS '对应JSON字段:balanceamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.cardamount IS '对应JSON字段:cardamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.cashamount IS '对应JSON字段:cashamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.couponamount IS '对应JSON字段:couponamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.createtime IS '对应JSON字段:createtime,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.memberid IS '对应JSON字段:memberid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.membername IS '对应JSON字段:membername,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.tenantmembercardid IS '对应JSON字段:tenantmembercardid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.membercardtypename IS '对应JSON字段:membercardtypename,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.memberphone IS '对应JSON字段:memberphone,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.tableid IS '对应JSON字段:tableid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.consumemoney IS '对应JSON字段:consumemoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.onlineamount IS '对应JSON字段:onlineamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.operatorid IS '对应JSON字段:operatorid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.operatorname IS '对应JSON字段:operatorname,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.revokeorderid IS '对应JSON字段:revokeorderid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.revokeordername IS '对应JSON字段:revokeordername,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.revoketime IS '对应JSON字段:revoketime,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.payamount IS '对应JSON字段:payamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.pointamount IS '对应JSON字段:pointamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.refundamount IS '对应JSON字段:refundamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.settlename IS '对应JSON字段:settlename,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.settlerelateid IS '对应JSON字段:settlerelateid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.settlestatus IS '对应JSON字段:settlestatus,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.settletype IS '对应JSON字段:settletype,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.paytime IS '对应JSON字段:paytime,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.roundingamount IS '对应JSON字段:roundingamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.paymentmethod IS '对应JSON字段:paymentmethod,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.adjustamount IS '对应JSON字段:adjustamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.assistantcxmoney IS '对应JSON字段:assistantcxmoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.assistantpdmoney IS '对应JSON字段:assistantpdmoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.couponsaleamount IS '对应JSON字段:couponsaleamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.memberdiscountamount IS '对应JSON字段:memberdiscountamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.tablechargemoney IS '对应JSON字段:tablechargemoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.goodsmoney IS '对应JSON字段:goodsmoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.realgoodsmoney IS '对应JSON字段:realgoodsmoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.servicemoney IS '对应JSON字段:servicemoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.prepaymoney IS '对应JSON字段:prepaymoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.salesmanname IS '对应JSON字段:salesmanname,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.orderremark IS '对应JSON字段:orderremark,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.salesmanuserid IS '对应JSON字段:salesmanuserid,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.canberevoked IS '对应JSON字段:canberevoked,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.pointdiscountprice IS '对应JSON字段:pointdiscountprice,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.pointdiscountcost IS '对应JSON字段:pointdiscountcost,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.activitydiscount IS '对应JSON字段:activitydiscount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.serialnumber IS '对应JSON字段:serialnumber,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.assistantmanualdiscount IS '对应JSON字段:assistantmanualdiscount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.allcoupondiscount IS '对应JSON字段:allcoupondiscount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.goodspromotionmoney IS '对应JSON字段:goodspromotionmoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.assistantpromotionmoney IS '对应JSON字段:assistantpromotionmoney,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.isusecoupon IS '对应JSON字段:isusecoupon,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.isusediscount IS '对应JSON字段:isusediscount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.isactivity IS '对应JSON字段:isactivity,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.isbindmember IS '对应JSON字段:isbindmember,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.isfirst IS '对应JSON字段:isfirst,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.rechargecardamount IS '对应JSON字段:rechargecardamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.giftcardamount IS '对应JSON字段:giftcardamount,说明:?????? recharge_settlements-Analysis.md,示例值及对应分析:?? recharge_settlements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.recharge_settlements.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.settlement_records (
+ id BIGINT PRIMARY KEY,
+ tenantid BIGINT,
+ siteid BIGINT,
+ sitename TEXT,
+ balanceamount NUMERIC(18,2),
+ cardamount NUMERIC(18,2),
+ cashamount NUMERIC(18,2),
+ couponamount NUMERIC(18,2),
+ createtime TIMESTAMPTZ,
+ memberid BIGINT,
+ membername TEXT,
+ tenantmembercardid BIGINT,
+ membercardtypename TEXT,
+ memberphone TEXT,
+ tableid BIGINT,
+ consumemoney NUMERIC(18,2),
+ onlineamount NUMERIC(18,2),
+ operatorid BIGINT,
+ operatorname TEXT,
+ revokeorderid BIGINT,
+ revokeordername TEXT,
+ revoketime TIMESTAMPTZ,
+ payamount NUMERIC(18,2),
+ pointamount NUMERIC(18,2),
+ refundamount NUMERIC(18,2),
+ settlename TEXT,
+ settlerelateid BIGINT,
+ settlestatus INT,
+ settletype INT,
+ paytime TIMESTAMPTZ,
+ roundingamount NUMERIC(18,2),
+ paymentmethod INT,
+ adjustamount NUMERIC(18,2),
+ assistantcxmoney NUMERIC(18,2),
+ assistantpdmoney NUMERIC(18,2),
+ couponsaleamount NUMERIC(18,2),
+ memberdiscountamount NUMERIC(18,2),
+ tablechargemoney NUMERIC(18,2),
+ goodsmoney NUMERIC(18,2),
+ realgoodsmoney NUMERIC(18,2),
+ servicemoney NUMERIC(18,2),
+ prepaymoney NUMERIC(18,2),
+ salesmanname TEXT,
+ orderremark TEXT,
+ salesmanuserid BIGINT,
+ canberevoked BOOLEAN,
+ pointdiscountprice NUMERIC(18,2),
+ pointdiscountcost NUMERIC(18,2),
+ activitydiscount NUMERIC(18,2),
+ serialnumber BIGINT,
+ assistantmanualdiscount NUMERIC(18,2),
+ allcoupondiscount NUMERIC(18,2),
+ goodspromotionmoney NUMERIC(18,2),
+ assistantpromotionmoney NUMERIC(18,2),
+ isusecoupon BOOLEAN,
+ isusediscount BOOLEAN,
+ isactivity BOOLEAN,
+ isbindmember BOOLEAN,
+ isfirst INT,
+ rechargecardamount NUMERIC(18,2),
+ giftcardamount NUMERIC(18,2),
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.settlement_records IS '对应JSON字段:settlement_records.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.id IS '对应JSON字段:id,说明::结账记录主键 ID(订单结算 ID)。,示例值及对应分析:结构关联:';
+COMMENT ON COLUMN billiards_ods.settlement_records.tenantid IS '对应JSON字段:tenantid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.siteid IS '对应JSON字段:siteid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.sitename IS '对应JSON字段:sitename,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.balanceamount IS '对应JSON字段:balanceamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.cardamount IS '对应JSON字段:cardamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.cashamount IS '对应JSON字段:cashamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.couponamount IS '对应JSON字段:couponamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.createtime IS '对应JSON字段:createtime,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.memberid IS '对应JSON字段:memberid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.membername IS '对应JSON字段:membername,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.tenantmembercardid IS '对应JSON字段:tenantmembercardid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.membercardtypename IS '对应JSON字段:membercardtypename,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.memberphone IS '对应JSON字段:memberphone,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.tableid IS '对应JSON字段:tableid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.consumemoney IS '对应JSON字段:consumemoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.onlineamount IS '对应JSON字段:onlineamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.operatorid IS '对应JSON字段:operatorid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.operatorname IS '对应JSON字段:operatorname,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.revokeorderid IS '对应JSON字段:revokeorderid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.revokeordername IS '对应JSON字段:revokeordername,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.revoketime IS '对应JSON字段:revoketime,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.payamount IS '对应JSON字段:payamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.pointamount IS '对应JSON字段:pointamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.refundamount IS '对应JSON字段:refundamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.settlename IS '对应JSON字段:settlename,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.settlerelateid IS '对应JSON字段:settlerelateid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.settlestatus IS '对应JSON字段:settlestatus,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.settletype IS '对应JSON字段:settletype,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.paytime IS '对应JSON字段:paytime,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.roundingamount IS '对应JSON字段:roundingamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.paymentmethod IS '对应JSON字段:paymentmethod,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.adjustamount IS '对应JSON字段:adjustamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.assistantcxmoney IS '对应JSON字段:assistantcxmoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.assistantpdmoney IS '对应JSON字段:assistantpdmoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.couponsaleamount IS '对应JSON字段:couponsaleamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.memberdiscountamount IS '对应JSON字段:memberdiscountamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.tablechargemoney IS '对应JSON字段:tablechargemoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.goodsmoney IS '对应JSON字段:goodsmoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.realgoodsmoney IS '对应JSON字段:realgoodsmoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.servicemoney IS '对应JSON字段:servicemoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.prepaymoney IS '对应JSON字段:prepaymoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.salesmanname IS '对应JSON字段:salesmanname,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.orderremark IS '对应JSON字段:orderremark,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.salesmanuserid IS '对应JSON字段:salesmanuserid,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.canberevoked IS '对应JSON字段:canberevoked,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.pointdiscountprice IS '对应JSON字段:pointdiscountprice,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.pointdiscountcost IS '对应JSON字段:pointdiscountcost,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.activitydiscount IS '对应JSON字段:activitydiscount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.serialnumber IS '对应JSON字段:serialnumber,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.assistantmanualdiscount IS '对应JSON字段:assistantmanualdiscount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.allcoupondiscount IS '对应JSON字段:allcoupondiscount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.goodspromotionmoney IS '对应JSON字段:goodspromotionmoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.assistantpromotionmoney IS '对应JSON字段:assistantpromotionmoney,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.isusecoupon IS '对应JSON字段:isusecoupon,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.isusediscount IS '对应JSON字段:isusediscount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.isactivity IS '对应JSON字段:isactivity,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.isbindmember IS '对应JSON字段:isbindmember,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.isfirst IS '对应JSON字段:isfirst,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.rechargecardamount IS '对应JSON字段:rechargecardamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.giftcardamount IS '对应JSON字段:giftcardamount,说明:?????? settlement_records-Analysis.md,示例值及对应分析:?? settlement_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_records.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.settlement_records.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.settlement_records.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.settlement_records.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.assistant_cancellation_records (
+ id BIGINT PRIMARY KEY,
+ siteId BIGINT,
+ siteProfile JSONB,
+ assistantName TEXT,
+ assistantAbolishAmount NUMERIC(18,2),
+ assistantOn INT,
+ pdChargeMinutes INT,
+ tableAreaId BIGINT,
+ tableArea TEXT,
+ tableId BIGINT,
+ tableName TEXT,
+ trashReason TEXT,
+ createTime TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.assistant_cancellation_records IS '对应JSON字段:assistant_cancellation_records.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.id IS '对应JSON字段:id,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.siteId IS '对应JSON字段:siteId,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.siteProfile IS '对应JSON字段:siteProfile,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.assistantName IS '对应JSON字段:assistantName,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.assistantAbolishAmount IS '对应JSON字段:assistantAbolishAmount,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.assistantOn IS '对应JSON字段:assistantOn,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.pdChargeMinutes IS '对应JSON字段:pdChargeMinutes,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.tableAreaId IS '对应JSON字段:tableAreaId,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.tableArea IS '对应JSON字段:tableArea,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.tableId IS '对应JSON字段:tableId,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.tableName IS '对应JSON字段:tableName,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.trashReason IS '对应JSON字段:trashReason,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.createTime IS '对应JSON字段:createTime,说明:?????? assistant_cancellation_records-Analysis.md,示例值及对应分析:?? assistant_cancellation_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_cancellation_records.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.assistant_accounts_master (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ assistant_no TEXT,
+ nickname TEXT,
+ real_name TEXT,
+ mobile TEXT,
+ team_id BIGINT,
+ team_name TEXT,
+ user_id BIGINT,
+ level TEXT,
+ assistant_status INT,
+ work_status INT,
+ leave_status INT,
+ entry_time TIMESTAMP,
+ resign_time TIMESTAMP,
+ start_time TIMESTAMP,
+ end_time TIMESTAMP,
+ create_time TIMESTAMP,
+ update_time TIMESTAMP,
+ order_trade_no TEXT,
+ staff_id BIGINT,
+ staff_profile_id BIGINT,
+ system_role_id BIGINT,
+ avatar TEXT,
+ birth_date TIMESTAMP,
+ gender INT,
+ height NUMERIC(18,2),
+ weight NUMERIC(18,2),
+ job_num TEXT,
+ show_status INT,
+ show_sort INT,
+ sum_grade NUMERIC(18,2),
+ assistant_grade NUMERIC(18,2),
+ get_grade_times INT,
+ introduce TEXT,
+ video_introduction_url TEXT,
+ group_id BIGINT,
+ group_name TEXT,
+ shop_name TEXT,
+ charge_way INT,
+ entry_type INT,
+ allow_cx INT,
+ is_guaranteed INT,
+ salary_grant_enabled INT,
+ light_status INT,
+ online_status INT,
+ is_delete INT,
+ cx_unit_price NUMERIC(18,2),
+ pd_unit_price NUMERIC(18,2),
+ last_table_id BIGINT,
+ last_table_name TEXT,
+ person_org_id BIGINT,
+ serial_number BIGINT,
+ is_team_leader INT,
+ criticism_status INT,
+ last_update_name TEXT,
+ ding_talk_synced INT,
+ site_light_cfg_id BIGINT,
+ light_equipment_id TEXT,
+ entry_sign_status INT,
+ resign_sign_status INT,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.assistant_accounts_master IS '对应JSON字段:assistant_accounts_master.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.id IS '对应JSON字段:id,说明::助教账号主键 ID,在“助教流水.json”中对应 site_assistant_id。,示例值及对应分析:作用:所有与助教相关的事实表(助教流水、助教排班等)都会通过这个 ID 关联到该维表。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.tenant_id IS '对应JSON字段:tenant_id,说明::品牌/租户 ID,对应“非球科技”系统中该商户的唯一标识。,示例值及对应分析:用途:多门店时用来区分不同商户。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.site_id IS '对应JSON字段:site_id,说明::门店 ID,对应本次数据的这家球房(朗朗桌球)。,示例值及对应分析:关联:与其它 JSON(台费流水、库存、销售等)中的 site_id 一致。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.assistant_no IS '对应JSON字段:assistant_no,说明:(结合字段名推测):助教工号 / 编号,便于业务侧识别。,示例值及对应分析:关联:在“助教流水.json”中有 assistantNo,与此字段对应。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.nickname IS '对应JSON字段:nickname,说明::助教在前台展示的昵称,如“佳怡”“周周”“球球”等。,示例值及对应分析:用途:与真实姓名区分,用于顾客侧展示。如在助教流水中 nickname 就是这个值。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.real_name IS '对应JSON字段:real_name,说明::助教真实姓名,如“何海婷”“梁婷婷”等。,示例值及对应分析:关联:在“助教流水.json”的 assistantName 与此一致。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.mobile IS '对应JSON字段:mobile,说明::助教手机号,用于登录绑定、通知、钉钉同步等。,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.team_id IS '对应JSON字段:team_id,说明::助教所属团队 ID。,示例值及对应分析:关联:在“助教流水.json”中 assistant_team_id 与此一致。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.team_name IS '对应JSON字段:team_name,说明::团队名称,展示用,和 team_id 一一对应。,示例值及对应分析:group_id';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.level IS '对应JSON字段:level,说明:(结合“助教流水中的 assistant_level / levelName 推测”):,示例值及对应分析:8:助教管理/管理员(和流水里的 "助教管理" 对应)';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.assistant_status IS '对应JSON字段:assistant_status,说明:(推测):账号启用状态:,示例值及对应分析:1:启用';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.work_status IS '对应JSON字段:work_status,说明::,示例值及对应分析:1:在岗/可排班';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.leave_status IS '对应JSON字段:leave_status,说明:类型:int,枚举。,示例值及对应分析:观测:';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.entry_time IS '对应JSON字段:entry_time,说明::入职时间。,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.resign_time IS '对应JSON字段:resign_time,说明::离职日期;使用“远未来日期”作为“未离职”的占位。,示例值及对应分析:entry_type';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.start_time IS '对应JSON字段:start_time,说明:(推测):当前配置生效的开始日期。,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.end_time IS '对应JSON字段:end_time,说明::当前配置生效的结束日期(例如一个周期性的排班/合同周期)。,示例值及对应分析:last_table_id';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.create_time IS '对应JSON字段:create_time,说明::账号创建时间。,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.update_time IS '对应JSON字段:update_time,说明::账号最近一次被修改的时间(例如修改等级、昵称等)。,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.order_trade_no IS '对应JSON字段:order_trade_no,说明:(推测):该助教最近一次关联的订单号,用于快速跳转或回溯最近服务行为。,示例值及对应分析:9. 灯控、钉钉等系统集成相关字段';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.staff_id IS '对应JSON字段:staff_id,说明:(推测):预留给“人事系统员工 ID”的字段,目前未接入或未启用。,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.staff_profile_id IS '对应JSON字段:staff_profile_id,说明:(推测):人事档案 ID,与第三方 HR 系统或内部员工档案集成使用,当前未启用。,示例值及对应分析:4. 等级、计费与薪资配置字段';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.system_role_id IS '对应JSON字段:system_role_id,说明:?????? assistant_accounts_master-Analysis.md,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.avatar IS '对应JSON字段:avatar,说明::助教头像地址。,示例值及对应分析:introduce';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.gender IS '对应JSON字段:gender,说明:(结合常见约定与值分布推测):,示例值及对应分析:0:未填/保密';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.show_status IS '对应JSON字段:show_status,说明:(推测):前台展示状态:,示例值及对应分析:1:在助教选择界面展示。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.show_sort IS '对应JSON字段:show_sort,说明::前台展示排序权重,值越小/越大对应不同的排序策略(当前看起来与 assistant_no 有一定对应关系)。,示例值及对应分析:online_status';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.sum_grade IS '对应JSON字段:sum_grade,说明::评分总和,用于计算平均分(assistant_grade = sum_grade / get_grade_times),当前为 0。,示例值及对应分析:?? assistant_accounts_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.get_grade_times IS '对应JSON字段:get_grade_times,说明::累计被评分次数。,示例值及对应分析:charge_way';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.video_introduction_url IS '对应JSON字段:video_introduction_url,说明::助教个人视频介绍地址。,示例值及对应分析:height';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.user_id IS '对应JSON字段:user_id,说明:账号对应的用户 ID/员工 ID,用于跨表关联。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.height IS '对应JSON字段:height,说明:身高(数值),可空。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.weight IS '对应JSON字段:weight,说明:体重(数值),可空。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.job_num IS '对应JSON字段:job_num,说明:工号/岗位编号,保留原始取值。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.assistant_grade IS '对应JSON字段:assistant_grade,说明:平均评分,通常 = sum_grade/get_grade_times。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.introduce IS '对应JSON字段:introduce,说明:个人简介/自我介绍,可空。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.group_id IS '对应JSON字段:group_id,说明:分组/自定义分组 ID。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.group_name IS '对应JSON字段:group_name,说明:分组名称。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.shop_name IS '对应JSON字段:shop_name,说明:门店名称冗余。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.charge_way IS '对应JSON字段:charge_way,说明:收费方式枚举,保留原值。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.entry_type IS '对应JSON字段:entry_type,说明:入职类型枚举,保留原值。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.allow_cx IS '对应JSON字段:allow_cx,说明:是否允许超休/冲销(0/1)。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.is_guaranteed IS '对应JSON字段:is_guaranteed,说明:是否保底(0/1)。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.salary_grant_enabled IS '对应JSON字段:salary_grant_enabled,说明:薪资发放/补贴开关,枚举。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.light_status IS '对应JSON字段:light_status,说明:灯控状态/模式,保留原值。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.online_status IS '对应JSON字段:online_status,说明:在线状态标记(0/1等)。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.is_delete IS '对应JSON字段:is_delete,说明:逻辑删除标记(0=有效,1=删除)。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.cx_unit_price IS '对应JSON字段:cx_unit_price,说明:超休单价/冲销单价,金额类。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.pd_unit_price IS '对应JSON字段:pd_unit_price,说明:排钟/点钟单价,金额类。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.last_table_id IS '对应JSON字段:last_table_id,说明:最近服务桌台 ID。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.last_table_name IS '对应JSON字段:last_table_name,说明:最近服务桌台名称。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.person_org_id IS '对应JSON字段:person_org_id,说明:人员组织 ID/部门 ID。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.serial_number IS '对应JSON字段:serial_number,说明:序列号/排序号,保留原值。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.is_team_leader IS '对应JSON字段:is_team_leader,说明:是否组长(0/1)。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.criticism_status IS '对应JSON字段:criticism_status,说明:处罚/警告状态标记,枚举。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.ding_talk_synced IS '对应JSON字段:ding_talk_synced,说明:是否已同步钉钉(0/1)。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.site_light_cfg_id IS '对应JSON字段:site_light_cfg_id,说明:门店灯控配置 ID。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.light_equipment_id IS '对应JSON字段:light_equipment_id,说明:灯控设备 ID/硬件编号。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.entry_sign_status IS '对应JSON字段:entry_sign_status,说明:入职签署状态,枚举。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.resign_sign_status IS '对应JSON字段:resign_sign_status,说明:离职签署状态,枚举。';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_accounts_master.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.assistant_service_records (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ siteProfile JSONB,
+ site_table_id BIGINT,
+ order_settle_id BIGINT,
+ order_trade_no TEXT,
+ order_pay_id BIGINT,
+ order_assistant_id BIGINT,
+ order_assistant_type INT,
+ assistantName TEXT,
+ assistantNo TEXT,
+ assistant_level TEXT,
+ levelname TEXT,
+ site_assistant_id BIGINT,
+ skill_id BIGINT,
+ skillname TEXT,
+ system_member_id BIGINT,
+ tablename TEXT,
+ tenant_member_id BIGINT,
+ user_id BIGINT,
+ assistant_team_id BIGINT,
+ nickname TEXT,
+ ledger_name TEXT,
+ ledger_group_name TEXT,
+ ledger_amount NUMERIC(18,2),
+ ledger_count NUMERIC(18,4),
+ ledger_unit_price NUMERIC(18,4),
+ ledger_status INT,
+ ledger_start_time TIMESTAMP,
+ ledger_end_time TIMESTAMP,
+ manual_discount_amount NUMERIC(18,2),
+ member_discount_amount NUMERIC(18,2),
+ coupon_deduct_money NUMERIC(18,2),
+ service_money NUMERIC(18,2),
+ projected_income NUMERIC(18,2),
+ real_use_seconds INT,
+ income_seconds INT,
+ start_use_time TIMESTAMP,
+ last_use_time TIMESTAMP,
+ create_time TIMESTAMP,
+ is_single_order INT,
+ is_delete INT,
+ is_trash INT,
+ trash_reason TEXT,
+ trash_applicant_id BIGINT,
+ trash_applicant_name TEXT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ salesman_name TEXT,
+ salesman_org_id BIGINT,
+ salesman_user_id BIGINT,
+ person_org_id BIGINT,
+ add_clock INT,
+ returns_clock INT,
+ composite_grade NUMERIC(10,2),
+ composite_grade_time TIMESTAMP,
+ skill_grade NUMERIC(10,2),
+ service_grade NUMERIC(10,2),
+ sum_grade NUMERIC(10,2),
+ grade_status INT,
+ get_grade_times INT,
+ is_not_responding INT,
+ is_confirm INT,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+
+COMMENT ON TABLE billiards_ods.assistant_service_records IS '对应JSON字段:assistant_service_records.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.id IS '对应JSON字段:id,说明::本条助教流水记录的主键 ID(流水唯一标识)。,示例值及对应分析:作用:在系统内部唯一定位这一条助教服务记录。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID;你这份数据中是固定值(同一个商户)。,示例值及对应分析:关联:全库所有表都有,作为“商户维度”的过滤键。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.site_id IS '对应JSON字段:site_id,说明::门店 ID,本数据中指“朗朗桌球”这一家门店。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.siteProfile IS '对应JSON字段:siteProfile,说明::门店信息快照,包括 id、shop_name、address 等,和其他 JSON 里的 siteProfile 一致。,示例值及对应分析:作用:冗余门店信息,方便查看(而不是每次都联表看门店档案)。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.site_table_id IS '对应JSON字段:site_table_id,说明::球台 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.order_settle_id IS '对应JSON字段:order_settle_id,说明::订单结算 ID,相当于“结账单号”的内部主键。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.order_trade_no IS '对应JSON字段:order_trade_no,说明::订单交易号,整个订单层面的编号。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.order_pay_id IS '对应JSON字段:order_pay_id,说明::关联到“支付记录”的主键 ID。,示例值及对应分析:作用:可以和支付记录中的 id / relate_id 等字段对应,找到这条助教服务对应的支付流水。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.order_assistant_id IS '对应JSON字段:order_assistant_id,说明::订单中“助教项目明细”的内部 ID。,示例值及对应分析:作用:如果订单里有多条助教项目(比如换助教、多个时间段),此字段唯一标识这一条助教明细。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.order_assistant_type IS '对应JSON字段:order_assistant_type,说明:(推测):,示例值及对应分析:1:常规助教服务(主课/基础课)。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.assistantName IS '对应JSON字段:assistantName,说明::助教姓名,如“何海婷”“胡敏”等。,示例值及对应分析:备注:和助教账号档案里的 real_name 一致。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.assistantNo IS '对应JSON字段:assistantNo,说明::助教编号,例如 "27"。,示例值及对应分析:关联:在助教账号表里也有 assistant_no 字段,对应工号/编号。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.assistant_level IS '对应JSON字段:assistant_level,说明::助教等级名称,与 assistant_level 一一对应(初级/中级/高级/助教管理)。,示例值及对应分析:备注:属于展示用的冗余字段。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.assistant_team_id IS '对应JSON字段:assistant_team_id,说明::当前这条助教服务所对应的“课程/技能名称”。,示例值及对应分析:当 order_assistant_type = 1 时,多为“基础课”。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.nickname IS '对应JSON字段:nickname,说明::助教对外昵称,如“佳怡”“周周”“球球”等。,示例值及对应分析:说明:从数据看,这个 nickname 是“助教昵称”,不是顾客昵称(容易混淆)。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_name IS '对应JSON字段:ledger_name,说明:?????? assistant_service_records-Analysis.md,示例值及对应分析:?? assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_group_name IS '对应JSON字段:ledger_group_name,说明:(推测):助教项目所属的“计费分组/套餐分组名称”,例如某种助教套餐或业务组名称。,示例值及对应分析:目前未被实际使用。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_amount IS '对应JSON字段:ledger_amount,说明::按标准单价计算出来的应收金额(近似 = ledger_unit_price × income_seconds / 3600)。,示例值及对应分析:说明:从数据看,这个金额对应“按原价计费”的金额,未扣除各种优惠。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_count IS '对应JSON字段:ledger_count,说明::台账记录的计时总秒数。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_unit_price IS '对应JSON字段:ledger_unit_price,说明::助教服务 标准单价(通常是标价:每小时、每节课的单价)。,示例值及对应分析:特点:如 98.0、108.0、190.0 等。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_status IS '对应JSON字段:ledger_status,说明:(推测):助教流水记录状态:,示例值及对应分析:1:正常有效。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_start_time IS '对应JSON字段:ledger_start_time,说明::台账层面记录的开始时间。,示例值及对应分析:说明:与 start_use_time 在当前数据中完全一致,可以视为“计费起始时间”。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.ledger_end_time IS '对应JSON字段:ledger_end_time,说明::台账层面的结束时间。,示例值及对应分析:说明:与 last_use_time 一致,可以视为“计费结束时间”。对于 real_use_seconds = 0 的记录,开始和结束时间相同,说明只是预约/录入,并未实际服务。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.manual_discount_amount IS '对应JSON字段:manual_discount_amount,说明::收银员手动给予的减免金额(人工改价)。,示例值及对应分析:当前导出时间段内暂未出现手动打折的情况。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.member_discount_amount IS '对应JSON字段:member_discount_amount,说明::由会员卡折扣产生的优惠金额。,示例值及对应分析:说明:尽管字段里是 0,但实际折扣可能已经体现在 projected_income 与 ledger_amount 的差额中,这里只是未单独拆出。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.coupon_deduct_money IS '对应JSON字段:coupon_deduct_money,说明::由“优惠券/代金券/团购券”等 直接抵扣到这条助教服务上的金额。,示例值及对应分析:说明:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.service_money IS '对应JSON字段:service_money,说明:(推测):用于记录与助教结算的金额(平台预留的“成本/分成”字段)。,示例值及对应分析:当前数据中未启用这个机制,所以全为 0。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.projected_income IS '对应JSON字段:projected_income,说明::实际结算计入门店的金额(已经考虑折扣、卡权益、券等后的结果)。,示例值及对应分析:从数据:projected_income 明显低于 ledger_amount,说明中间有折扣,但折扣的明细并不全由下面几个字段体现(很多是卡权益内生折扣)。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.real_use_seconds IS '对应JSON字段:real_use_seconds,说明::实际使用时长(秒)。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.income_seconds IS '对应JSON字段:income_seconds,说明::计费秒数 / 应计收入对应的时间。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.start_use_time IS '对应JSON字段:start_use_time,说明::助教实际开始服务时间。,示例值及对应分析:特点:正常情况下与 ledger_start_time 相同。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.last_use_time IS '对应JSON字段:last_use_time,说明::最后一次使用(实际服务)时间。,示例值及对应分析:特点:正常结束时与 ledger_end_time 相同;如果服务还未真正开始或立即结束,开始/结束时间可能相同。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.create_time IS '对应JSON字段:create_time,说明::这条助教流水记录创建时间(一般接近结算/下单时间)。,示例值及对应分析:?? assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.is_single_order IS '对应JSON字段:is_single_order,说明:(推测):是否单独订单:,示例值及对应分析:1:本助教服务作为单独订单结算(或单独拆项)。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志。,示例值及对应分析:0:未删除;';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.is_trash IS '对应JSON字段:is_trash,说明::是否已废除/作废:,示例值及对应分析:0:正常有效;';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.trash_reason IS '对应JSON字段:trash_reason,说明::废除原因(文本说明),例如“顾客取消”“录入错误”等。,示例值及对应分析:当前数据为空字符串,说明当前导出时间段没有被废除的助教流水记录。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.trash_applicant_id IS '对应JSON字段:trash_applicant_id,说明::提出废除申请的员工 ID(通常是操作员/管理员)。,示例值及对应分析:当前数据全为 0,因此短期内没有发生废除操作。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.trash_applicant_name IS '对应JSON字段:trash_applicant_name,说明::废除申请人姓名。,示例值及对应分析:?? assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.operator_id IS '对应JSON字段:operator_id,说明::操作员 ID(录入/结算这条助教服务的员工)。,示例值及对应分析:关联:可与员工/账号表对应(本次导出未单独给员工表,但其他 JSON 里多处出现该 ID)。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.operator_name IS '对应JSON字段:operator_name,说明::操作员姓名,与 operator_id 一起使用,便于直接阅读。,示例值及对应分析:user_id';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.salesman_name IS '对应JSON字段:salesman_name,说明::关联的“营业员/销售员姓名”,用于提成归属。,示例值及对应分析:观测:本数据中多数为空字符串,说明助教流水没有配置单独的营业员。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.salesman_org_id IS '对应JSON字段:salesman_org_id,说明::营业员所属组织/部门 ID。,示例值及对应分析:观测:多为 0。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.salesman_user_id IS '对应JSON字段:salesman_user_id,说明::营业员用户 ID。,示例值及对应分析:观测:多为 0,代表未指定。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.person_org_id IS '对应JSON字段:person_org_id,说明:同样在上文说明:助教所属人事组织 ID。,示例值及对应分析:9. 作废 / 废除相关字段';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.add_clock IS '对应JSON字段:add_clock,说明:(推测):加钟秒数,即在原有预约/服务基础上临时追加的时长。,示例值及对应分析:说明:值均为 60 的倍数(分钟级加钟),如 600 秒=10 分钟。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.returns_clock IS '对应JSON字段:returns_clock,说明:(推测):退钟秒数(取消加钟或提前结束退回的时间)。,示例值及对应分析:当前数据里没有退钟场景,所以全为 0,但字段设计已经预留。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.composite_grade IS '对应JSON字段:composite_grade,说明::综合评分(例如技能+服务加权后的平均分),当前数据没有实际评分。,示例值及对应分析:?? assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.composite_grade_time IS '对应JSON字段:composite_grade_time,说明:(推测):最近一次评价时间/综合评分更新时间。现在都是默认“无效时间”。,示例值及对应分析:3. 桌台 / 门店维度字段';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.skill_grade IS '对应JSON字段:skill_grade,说明:(推测):顾客对“技能表现”的评分(整数或打分等级)。,示例值及对应分析:当前数据中还未产生评分记录,所以都是默认值 0。';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.service_grade IS '对应JSON字段:service_grade,说明:(推测):顾客对“服务态度”的评分。,示例值及对应分析:?? assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.sum_grade IS '对应JSON字段:sum_grade,说明::累计评分总和(可能用于计算平均分),当前为 0。,示例值及对应分析:?? assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.grade_status IS '对应JSON字段:grade_status,说明:(推测):评价状态,比如:,示例值及对应分析:1 = 未评价/正常;';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.get_grade_times IS '对应JSON字段:get_grade_times,说明::该条记录对应的评价次数(或该助教被评价次数快照)。,示例值及对应分析:?? assistant_service_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.is_not_responding IS '对应JSON字段:is_not_responding,说明:(推测):是否存在“爽约/未响应”情况:,示例值及对应分析:0:正常;';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.is_confirm IS '对应JSON字段:is_confirm,说明:(推测):确认状态,例如:,示例值及对应分析:1:待确认;';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.assistant_service_records.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.site_tables_master (
+ id BIGINT PRIMARY KEY,
+ site_id BIGINT,
+ siteName TEXT,
+ "appletQrCodeUrl" TEXT,
+ areaName TEXT,
+ audit_status INT,
+ charge_free INT,
+ create_time TIMESTAMP,
+ delay_lights_time INT,
+ is_online_reservation INT,
+ is_rest_area INT,
+ light_status INT,
+ only_allow_groupon INT,
+ order_delay_time INT,
+ self_table INT,
+ show_status INT,
+ site_table_area_id BIGINT,
+ tableStatusName TEXT,
+ table_cloth_use_Cycle INT,
+ table_cloth_use_time TIMESTAMP,
+ table_name TEXT,
+ table_price NUMERIC(18,2),
+ table_status INT,
+ temporary_light_second INT,
+ virtual_table INT,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.site_tables_master IS '对应JSON字段:site_tables_master.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 site_tables_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.site_tables_master.id IS '对应JSON字段:id,说明::台桌主键 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.site_tables_master.site_id IS '对应JSON字段:site_id,说明::门店 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.site_tables_master.siteName IS '对应JSON字段:siteName,说明::门店名称快照,冗余字段,配合 site_id 使用。,示例值及对应分析:?? site_tables_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.site_tables_master."appletQrCodeUrl" IS '对应JSON字段:appletQrCodeUrl,说明::小程序二维码 URL。 一般用于:,示例值及对应分析:打印二维码贴在台上,顾客扫码可呼叫服务、查看账单或发起线上预约;';
+COMMENT ON COLUMN billiards_ods.site_tables_master.areaName IS '对应JSON字段:areaName,说明::区域名称,用于前台展示和区域维度管理。,示例值及对应分析:结构特征:';
+COMMENT ON COLUMN billiards_ods.site_tables_master.audit_status IS '对应JSON字段:audit_status,说明:(结合命名惯例):,示例值及对应分析:2:已审核/已启用;';
+COMMENT ON COLUMN billiards_ods.site_tables_master.charge_free IS '对应JSON字段:charge_free,说明:(推测):,示例值及对应分析:0:正常计费;';
+COMMENT ON COLUMN billiards_ods.site_tables_master.create_time IS '对应JSON字段:create_time,说明::台桌配置的创建时间或最近一次创建/复制时间。,示例值及对应分析:三、与其它 JSON 的字段级关联关系(结构视角)';
+COMMENT ON COLUMN billiards_ods.site_tables_master.delay_lights_time IS '对应JSON字段:delay_lights_time,说明:(推测):台灯熄灭延迟时间(单位多半是秒或分钟),用于结账后延时关灯。,示例值及对应分析:本门店未启用延迟关灯功能(全部为 0)。';
+COMMENT ON COLUMN billiards_ods.site_tables_master.is_online_reservation IS '对应JSON字段:is_online_reservation,说明:(结合值分布推断):,示例值及对应分析:1:允许线上预约(可在小程序/线上平台预约这张台);';
+COMMENT ON COLUMN billiards_ods.site_tables_master.is_rest_area IS '对应JSON字段:is_rest_area,说明:(推测):,示例值及对应分析:0:正常计费区域;';
+COMMENT ON COLUMN billiards_ods.site_tables_master.light_status IS '对应JSON字段:light_status,说明:(结合命名推断):,示例值及对应分析:该字段是台灯/灯光状态开关位:';
+COMMENT ON COLUMN billiards_ods.site_tables_master.only_allow_groupon IS '对应JSON字段:only_allow_groupon,说明:(结合命名推断):,示例值及对应分析:1:仅允许团购/券预约使用(团购专用台);';
+COMMENT ON COLUMN billiards_ods.site_tables_master.order_delay_time IS '对应JSON字段:order_delay_time,说明:(推测):订单层面允许的“自动延时时长”(例如到点后自动延长多少时间继续计费)。,示例值及对应分析:本门店未使用此功能。';
+COMMENT ON COLUMN billiards_ods.site_tables_master.self_table IS '对应JSON字段:self_table,说明:(推测):,示例值及对应分析:1:“本门店自有台”,非共享或外部配置;';
+COMMENT ON COLUMN billiards_ods.site_tables_master.show_status IS '对应JSON字段:show_status,说明:(推测):,示例值及对应分析:1:正常在前台“开台列表”中展示;';
+COMMENT ON COLUMN billiards_ods.site_tables_master.site_table_area_id IS '对应JSON字段:site_table_area_id,说明::门店维度的“台桌区域 ID”。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.site_tables_master.tableStatusName IS '对应JSON字段:tableStatusName,说明::table_status 的中文名称,仅为展示用途。,示例值及对应分析:?? site_tables_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.site_tables_master.table_cloth_use_Cycle IS '对应JSON字段:table_cloth_use_Cycle,说明:(推测):,示例值及对应分析:台呢使用周期阈值,例如达到某个秒数后提醒更换;';
+COMMENT ON COLUMN billiards_ods.site_tables_master.table_cloth_use_time IS '对应JSON字段:table_cloth_use_time,说明:(结合命名和数值特征):,示例值及对应分析:台呢使用累计时长,单位极大概率为“秒”:';
+COMMENT ON COLUMN billiards_ods.site_tables_master.table_name IS '对应JSON字段:table_name,说明::台号/台名称,用于前台操作界面展示,也出现在小票和各种流水中的 ledger_name 或 tableName 字段。,示例值及对应分析:?? site_tables_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.site_tables_master.table_price IS '对应JSON字段:table_price,说明:(结构角度):,示例值及对应分析:设计上应为“台的基础单价”字段(例如按小时或按局单价);';
+COMMENT ON COLUMN billiards_ods.site_tables_master.table_status IS '对应JSON字段:table_status,说明::台当前运行状态,真实反映某一时刻台的占用/暂停情况。,示例值及对应分析:?? site_tables_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.site_tables_master.temporary_light_second IS '对应JSON字段:temporary_light_second,说明:(推测):临时点灯时长(秒),例如手动临时开灯一段时间。,示例值及对应分析:本门店未使用。';
+COMMENT ON COLUMN billiards_ods.site_tables_master.virtual_table IS '对应JSON字段:virtual_table,说明:(推测):,示例值及对应分析:0:物理台(实体存在的桌);';
+COMMENT ON COLUMN billiards_ods.site_tables_master.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.site_tables_master.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.site_tables_master.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.site_tables_master.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.table_fee_discount_records (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ siteProfile JSONB,
+ site_table_id BIGINT,
+ tableProfile JSONB,
+ tenant_table_area_id BIGINT,
+ adjust_type INT,
+ ledger_amount NUMERIC(18,2),
+ ledger_count NUMERIC(18,4),
+ ledger_name TEXT,
+ ledger_status INT,
+ applicant_id BIGINT,
+ applicant_name TEXT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ order_settle_id BIGINT,
+ order_trade_no TEXT,
+ is_delete INT,
+ create_time TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.table_fee_discount_records IS '对应JSON字段:table_fee_discount_records.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 table_fee_discount_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.id IS '对应JSON字段:id,说明::台费打折 / 调整流水主键 ID。,示例值及对应分析:作用:在“台费调账表”中唯一标识一条折扣/调账操作。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID。,示例值及对应分析:作用:标识记录属于哪一个商户(同一个“非球科技”租户)。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.site_id IS '对应JSON字段:site_id,说明::门店 ID,本批数据全部为同一家门店(朗朗桌球)。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.siteProfile IS '对应JSON字段:siteProfile,说明::门店信息快照,用于报表时直接读取,无需再联门店档案。,示例值及对应分析:?? table_fee_discount_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.site_table_id IS '对应JSON字段:site_table_id,说明::台桌 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.tableProfile IS '对应JSON字段:tableProfile,说明::折扣发生时,对应台桌的配置信息快照。,示例值及对应分析:?? table_fee_discount_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.tenant_table_area_id IS '对应JSON字段:tenant_table_area_id,说明::租户维度的“台桌区域 ID”。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.adjust_type IS '对应JSON字段:adjust_type,说明:(根据文件含义 + 命名 + 数据):,示例值及对应分析:文件名是“台费打折”,字段名为“调整类型”,当前所有记录都是 1,即“台费打折/台费减免”这一种调整类型。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.ledger_amount IS '对应JSON字段:ledger_amount,说明:(关键点):,示例值及对应分析:通过与 台费流水.json 做对比,可以明确:';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.ledger_count IS '对应JSON字段:ledger_count,说明::,示例值及对应分析:这里不是“秒数”,而是“调整次数/条数”的量化,目前固定为 1,表示“一次调账事件”。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.ledger_name IS '对应JSON字段:ledger_name,说明:(推测):,示例值及对应分析:设计上应该用于记录“调账项目名称”或“打折原因描述”(例如某种优惠规则名称),但当前门店并未使用该字段。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.ledger_status IS '对应JSON字段:ledger_status,说明::,示例值及对应分析:1:生效调整(当前有效的台费打折 / 调账记录);';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.applicant_id IS '对应JSON字段:applicant_id,说明::打折/调账申请人 ID。,示例值及对应分析:作用:记录谁发起了这次台费调整。 本时段内所有调整均由同一位员工发起。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.applicant_name IS '对应JSON字段:applicant_name,说明::申请人姓名(带角色描述),为 applicant_id 的冗余显示字段。,示例值及对应分析:?? table_fee_discount_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.operator_id IS '对应JSON字段:operator_id,说明::实际执行调账操作的操作员 ID。,示例值及对应分析:说明:这段时间内,“申请人”和“操作员”是同一个人。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.operator_name IS '对应JSON字段:operator_name,说明::操作员姓名。,示例值及对应分析:?? table_fee_discount_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.order_settle_id IS '对应JSON字段:order_settle_id,说明::结算单/小票 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.order_trade_no IS '对应JSON字段:order_trade_no,说明::订单交易号。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志:,示例值及对应分析:0:未删除(有效记录);';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.create_time IS '对应JSON字段:create_time,说明::台费调整记录的创建时间,即打折操作被执行的时间戳。,示例值及对应分析:说明:与台费流水中的 create_time(结算时间)相互配合,可以还原调整发生于结账之前还是之后。';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.table_fee_discount_records.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.table_fee_transactions (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ siteProfile JSONB,
+ site_table_id BIGINT,
+ site_table_area_id BIGINT,
+ site_table_area_name TEXT,
+ tenant_table_area_id BIGINT,
+ order_trade_no TEXT,
+ order_pay_id BIGINT,
+ order_settle_id BIGINT,
+ ledger_name TEXT,
+ ledger_amount NUMERIC(18,2),
+ ledger_count NUMERIC(18,4),
+ ledger_unit_price NUMERIC(18,4),
+ ledger_status INT,
+ ledger_start_time TIMESTAMP,
+ ledger_end_time TIMESTAMP,
+ start_use_time TIMESTAMP,
+ last_use_time TIMESTAMP,
+ real_table_use_seconds INT,
+ real_table_charge_money NUMERIC(18,2),
+ add_clock_seconds INT,
+ adjust_amount NUMERIC(18,2),
+ coupon_promotion_amount NUMERIC(18,2),
+ member_discount_amount NUMERIC(18,2),
+ used_card_amount NUMERIC(18,2),
+ mgmt_fee NUMERIC(18,2),
+ service_money NUMERIC(18,2),
+ fee_total NUMERIC(18,2),
+ is_single_order INT,
+ is_delete INT,
+ member_id BIGINT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ salesman_name TEXT,
+ salesman_org_id BIGINT,
+ salesman_user_id BIGINT,
+ create_time TIMESTAMP,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+
+COMMENT ON TABLE billiards_ods.table_fee_transactions IS '对应JSON字段:table_fee_transactions.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 table_fee_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.id IS '对应JSON字段:id,说明::台费流水记录主键(事实表主键)。,示例值及对应分析:?? table_fee_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID。本文件所有记录都属于同一租户。,示例值及对应分析:关联:与所有其它 JSON 中的 tenant_id 一致,用于跨表做“商户维度”的过滤。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.site_id IS '对应JSON字段:site_id,说明::门店 ID,本次数据全部来自同一门店(朗朗桌球)。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.siteProfile IS '对应JSON字段:siteProfile,说明::当前门店的完整档案快照,冗余到流水表中,便于报表直接读取而无需再联表门店档案。,示例值及对应分析:三、与其它 JSON 的结构关联关系(从字段层面)';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.site_table_id IS '对应JSON字段:site_table_id,说明::球台 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.site_table_area_id IS '对应JSON字段:site_table_area_id,说明::门店内“台桌区域” ID(站在门店物理布局的角度)。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.site_table_area_name IS '对应JSON字段:site_table_area_name,说明::台桌区域的名称,用于门店表现和区域统计。,示例值及对应分析:4. 会员维度与相关字段';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.tenant_table_area_id IS '对应JSON字段:tenant_table_area_id,说明::租户维度的台桌区域 ID(品牌层面的同一类区域)。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.order_trade_no IS '对应JSON字段:order_trade_no,说明::订单交易号,是整笔订单的主编号。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.order_pay_id IS '对应JSON字段:order_pay_id,说明::订单支付记录 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.order_settle_id IS '对应JSON字段:order_settle_id,说明::结算单号/结账 ID,对应一次结账操作。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_name IS '对应JSON字段:ledger_name,说明::台号名称,实际展示给员工/顾客看的桌台编号。,示例值及对应分析:备注:与 site_table_id 一一对应,是桌台维表中的名称字段冗余到流水里的快照。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_amount IS '对应JSON字段:ledger_amount,说明::按单价与计费时长计算出的原始应收台费金额。,示例值及对应分析:近似关系:ledger_amount ≈ ledger_unit_price × ledger_count / 3600,考虑到四舍五入会有小数差。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_count IS '对应JSON字段:ledger_count,说明::台账记录的计费秒数,计费用秒数(应收时长)。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_unit_price IS '对应JSON字段:ledger_unit_price,说明::台费结算时设置的 每小时单价/计费单价。,示例值及对应分析:用途:与 ledger_count 共同决定原始应收额。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_status IS '对应JSON字段:ledger_status,说明:(推测):,示例值及对应分析:1:正常已结算台费;';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_start_time IS '对应JSON字段:ledger_start_time,说明::台账上的计费起始时间。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.ledger_end_time IS '对应JSON字段:ledger_end_time,说明::台账上的计费结束时间。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.start_use_time IS '对应JSON字段:start_use_time,说明::台开始使用的时间(实际开台时间)。,示例值及对应分析:特点:在数据中,与 ledger_start_time 完全相同(见下)。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.last_use_time IS '对应JSON字段:last_use_time,说明::最后使用/操作时间。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.real_table_use_seconds IS '对应JSON字段:real_table_use_seconds,说明::实际使用的总秒数(系统真实统计的使用时长)。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.real_table_charge_money IS '对应JSON字段:real_table_charge_money,说明::台费中实际向顾客收取的金额(现金/实付维度,未含券方承担或内部调账的那一部分)。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.add_clock_seconds IS '对应JSON字段:add_clock_seconds,说明::加钟秒数,在原有使用基础上追加的时长。,示例值及对应分析:观测:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.adjust_amount IS '对应JSON字段:adjust_amount,说明::调整金额/调账金额,用于将台费金额转移或冲减到其它项目,或手工调整。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.coupon_promotion_amount IS '对应JSON字段:coupon_promotion_amount,说明::由优惠券/活动/团购(平台/门店促销)承担的优惠金额,直接抵扣在台费上。,示例值及对应分析:特点:当 real_table_charge_money = 0 且该字段为 ledger_amount 时,说明整笔台费是由券促销全额承担。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.member_discount_amount IS '对应JSON字段:member_discount_amount,说明:上文已说明,这里补充与金额的结构关系:,示例值及对应分析:功能:表示由会员折扣或会员权益承担的那部分金额。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.used_card_amount IS '对应JSON字段:used_card_amount,说明::由储值卡、次卡等“卡内余额”抵扣的金额。,示例值及对应分析:说明:字段设计已预留,但本段时间内台费没有通过储值卡扣款,或者卡扣款在其他表体现。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.mgmt_fee IS '对应JSON字段:mgmt_fee,说明:(推测):管理费字段,用于未来支持“台费附加管理费/服务费”的功能。,示例值及对应分析:当前未启用。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.service_money IS '对应JSON字段:service_money,说明:(推测):门店用于记录“服务费/成本/分成金额”的字段,类似助教流水里的 service_money。,示例值及对应分析:说明:当前门店未启用此字段结算台费。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.fee_total IS '对应JSON字段:fee_total,说明::各种附加费用(如管理费、服务费)合计值。,示例值及对应分析:说明:和 mgmt_fee 一样,目前作为预留字段,没有实际使用。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.is_single_order IS '对应JSON字段:is_single_order,说明:(推测):,示例值及对应分析:1:该台费记录对应的是一个独立计费单元(单独结算的桌费);';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志:,示例值及对应分析:0:未删除(有效记录);';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.member_id IS '对应JSON字段:member_id,说明::门店/租户内的会员 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.operator_id IS '对应JSON字段:operator_id,说明::操作员 ID,负责开台/结账的员工账号 ID。,示例值及对应分析:关联:与员工/账号体系中的用户 ID 对应(与助教账号的 user_id 属于同一种 ID 体系)。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.operator_name IS '对应JSON字段:operator_name,说明::操作员姓名(冗余字段),便于直接阅读,不必再联表员工档案。,示例值及对应分析:?? table_fee_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.salesman_name IS '对应JSON字段:salesman_name,说明::业务员/营业员姓名,如果台费有单独提成员工,这里记录归属人。,示例值及对应分析:当前门店未启用该字段做提成归属。';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.salesman_org_id IS '对应JSON字段:salesman_org_id,说明::营业员所属机构/部门 ID。,示例值及对应分析:8. 状态 / 标记类字段';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.salesman_user_id IS '对应JSON字段:salesman_user_id,说明::营业员的用户 ID(与 salesman_name 搭配)。,示例值及对应分析:?? table_fee_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.create_time IS '对应JSON字段:create_time,说明::这条台费流水记录的创建时间,通常接近结账时间。,示例值及对应分析:?? table_fee_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.table_fee_transactions.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.goods_stock_movements (
+ siteGoodsStockId BIGINT PRIMARY KEY,
+ tenantId BIGINT,
+ siteId BIGINT,
+ siteGoodsId BIGINT,
+ goodsName TEXT,
+ goodsCategoryId BIGINT,
+ goodsSecondCategoryId BIGINT,
+ unit TEXT,
+ price NUMERIC(18,4),
+ stockType INT,
+ changeNum NUMERIC(18,4),
+ startNum NUMERIC(18,4),
+ endNum NUMERIC(18,4),
+ changeNumA NUMERIC(18,4),
+ startNumA NUMERIC(18,4),
+ endNumA NUMERIC(18,4),
+ remark TEXT,
+ operatorName TEXT,
+ createTime TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.goods_stock_movements IS '对应JSON字段:goods_stock_movements.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 goods_stock_movements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.siteGoodsStockId IS '对应JSON字段:siteGoodsStockId,说明::门店某个“商品库存记录”的主键 ID。,示例值及对应分析:特点:每条库存变动记录对应一个 siteGoodsStockId,同一个商品可能在不同库存记录中出现(例如不同仓位或不同批次)。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.tenantId IS '对应JSON字段:tenantId,说明::租户/品牌 ID。,示例值及对应分析:观测:全部记录相同值,说明属于同一商户。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.siteId IS '对应JSON字段:siteId,说明::门店 ID。,示例值及对应分析:观测:本文件中所有记录的 siteId 都相同,对应“朗朗桌球”这家门店。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.siteGoodsId IS '对应JSON字段:siteGoodsId,说明::门店维度的商品 ID。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.goodsName IS '对应JSON字段:goodsName,说明::商品名称。,示例值及对应分析:示例值:';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.goodsCategoryId IS '对应JSON字段:goodsCategoryId,说明::商品一级分类 ID。,示例值及对应分析:观测:当前 100 条样本中约有 5 个不同 ID,对应如“酒水类”“食品小吃类”“香烟类”等大类(仅从命名与商品名推断)。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.goodsSecondCategoryId IS '对应JSON字段:goodsSecondCategoryId,说明::商品二级分类 ID。,示例值及对应分析:观测:样本中约有 7 个不同 ID,如饮料中的“矿泉水/功能饮料/碳酸饮料”等。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.unit IS '对应JSON字段:unit,说明::库存计量单位。,示例值及对应分析:说明:库存数量(startNum、endNum、changeNum)均以这里的单位计数。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.price IS '对应JSON字段:price,说明::商品单价(单位金额)。,示例值及对应分析:观测特征:';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.stockType IS '对应JSON字段:stockType,说明:(基于数据行为推断):,示例值及对应分析:1:出库类变动 典型情况是销售出库,库存减少 1 或 2;例如顾客点了一瓶饮料,对应一条 stockType=1, changeNum=-1 的记录。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.changeNum IS '对应JSON字段:changeNum,说明::本次库存数量变化值。,示例值及对应分析:特点及取值:';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.startNum IS '对应JSON字段:startNum,说明::变动前(这次出入库之前)的库存数量。,示例值及对应分析:示例: 如记录:startNum = 28, changeNum = -1, endNum = 27。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.endNum IS '对应JSON字段:endNum,说明::变动后(出入库之后)的库存数量。,示例值及对应分析:结构关系:';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.changeNumA IS '对应JSON字段:changeNumA,说明::辅助单位的变化量(与 changeNum 对应的第二计量单位变化),当前未使用。,示例值及对应分析:结论: startNumA / endNumA / changeNumA 是为“一个商品有两种计量单位(如箱与瓶)”而设计的预留字段。 目前门店只在单一单位层面管理库存,故全部为 0。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.startNumA IS '对应JSON字段:startNumA,说明:(推测):辅助计量单位的起始库存(例如件/箱等第二单位)。,示例值及对应分析:当前门店在样本时间段内没有启用多单位库存管理,因此全部为 0。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.endNumA IS '对应JSON字段:endNumA,说明::辅助单位的变动后库存,同样未启用。,示例值及对应分析:?? goods_stock_movements-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.remark IS '对应JSON字段:remark,说明::备注信息,用于手工记录本次变更的特殊原因说明(例如“盘点差异调整”“报损”)。,示例值及对应分析:当前样本中没有填入任何备注,但字段已预留,适用于盘点或手工调整场景。';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.operatorName IS '对应JSON字段:operatorName,说明::执行此次库存变动的操作人。,示例值及对应分析:观测值:';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.createTime IS '对应JSON字段:createTime,说明::这条库存变动记录的创建时间,即发生库存变更的时间点。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.goods_stock_movements.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.stock_goods_category_tree (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ category_name TEXT,
+ alias_name TEXT,
+ pid BIGINT,
+ business_name TEXT,
+ tenant_goods_business_id BIGINT,
+ open_salesman INT,
+ categoryBoxes JSONB,
+ sort INT,
+ is_warehousing INT,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.stock_goods_category_tree IS '对应JSON字段:stock_goods_category_tree.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.id IS '对应JSON字段:id,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.tenant_id IS '对应JSON字段:tenant_id,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.category_name IS '对应JSON字段:category_name,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.alias_name IS '对应JSON字段:alias_name,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.pid IS '对应JSON字段:pid,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.business_name IS '对应JSON字段:business_name,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.tenant_goods_business_id IS '对应JSON字段:tenant_goods_business_id,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.open_salesman IS '对应JSON字段:open_salesman,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.categoryBoxes IS '对应JSON字段:categoryBoxes,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.sort IS '对应JSON字段:sort,说明:?????? stock_goods_category_tree-Analysis.md,示例值及对应分析:?? stock_goods_category_tree-Analysis.md';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.is_warehousing IS '对应JSON字段:is_warehousing,说明::分类节点主键 ID(在商品分类维度中的唯一标识)。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.stock_goods_category_tree.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.goods_stock_summary (
+ siteGoodsId BIGINT PRIMARY KEY,
+ goodsName TEXT,
+ goodsUnit TEXT,
+ goodsCategoryId BIGINT,
+ goodsCategorySecondId BIGINT,
+ categoryName TEXT,
+ rangeStartStock NUMERIC(18,4),
+ rangeEndStock NUMERIC(18,4),
+ rangeIn NUMERIC(18,4),
+ rangeOut NUMERIC(18,4),
+ rangeSale NUMERIC(18,4),
+ rangeSaleMoney NUMERIC(18,2),
+ rangeInventory NUMERIC(18,4),
+ currentStock NUMERIC(18,4),
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.goods_stock_summary IS '对应JSON字段:goods_stock_summary.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.siteGoodsId IS '对应JSON字段:siteGoodsId,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.goodsName IS '对应JSON字段:goodsName,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.goodsUnit IS '对应JSON字段:goodsUnit,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.goodsCategoryId IS '对应JSON字段:goodsCategoryId,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.goodsCategorySecondId IS '对应JSON字段:goodsCategorySecondId,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.categoryName IS '对应JSON字段:categoryName,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeStartStock IS '对应JSON字段:rangeStartStock,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeEndStock IS '对应JSON字段:rangeEndStock,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeIn IS '对应JSON字段:rangeIn,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeOut IS '对应JSON字段:rangeOut,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeSale IS '对应JSON字段:rangeSale,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeSaleMoney IS '对应JSON字段:rangeSaleMoney,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.rangeInventory IS '对应JSON字段:rangeInventory,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.currentStock IS '对应JSON字段:currentStock,说明:?????? goods_stock_summary-Analysis.md,示例值及对应分析:?? goods_stock_summary-Analysis.md';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.goods_stock_summary.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.payment_transactions (
+ id BIGINT PRIMARY KEY,
+ site_id BIGINT,
+ siteProfile JSONB,
+ relate_type INT,
+ relate_id BIGINT,
+ pay_amount NUMERIC(18,2),
+ pay_status INT,
+ pay_time TIMESTAMP,
+ create_time TIMESTAMP,
+ payment_method INT,
+ online_pay_channel INT,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.payment_transactions IS '对应JSON字段:payment_transactions.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.id IS '对应JSON字段:id,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.site_id IS '对应JSON字段:site_id,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.siteProfile IS '对应JSON字段:siteProfile,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.relate_type IS '对应JSON字段:relate_type,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.relate_id IS '对应JSON字段:relate_id,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.pay_amount IS '对应JSON字段:pay_amount,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.pay_status IS '对应JSON字段:pay_status,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.pay_time IS '对应JSON字段:pay_time,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.create_time IS '对应JSON字段:create_time,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.payment_method IS '对应JSON字段:payment_method,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.online_pay_channel IS '对应JSON字段:online_pay_channel,说明:?????? payment_transactions-Analysis.md,示例值及对应分析:?? payment_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.payment_transactions.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.payment_transactions.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.payment_transactions.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.payment_transactions.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.refund_transactions (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ tenantName TEXT,
+ site_id BIGINT,
+ siteProfile JSONB,
+ relate_type INT,
+ relate_id BIGINT,
+ pay_sn TEXT,
+ pay_amount NUMERIC(18,2),
+ refund_amount NUMERIC(18,2),
+ round_amount NUMERIC(18,2),
+ pay_status INT,
+ pay_time TIMESTAMP,
+ create_time TIMESTAMP,
+ payment_method INT,
+ pay_terminal INT,
+ pay_config_id BIGINT,
+ online_pay_channel INT,
+ online_pay_type INT,
+ channel_fee NUMERIC(18,2),
+ channel_payer_id TEXT,
+ channel_pay_no TEXT,
+ member_id BIGINT,
+ member_card_id BIGINT,
+ cashier_point_id BIGINT,
+ operator_id BIGINT,
+ action_type INT,
+ check_status INT,
+ is_revoke INT,
+ is_delete INT,
+ balance_frozen_amount NUMERIC(18,2),
+ card_frozen_amount NUMERIC(18,2),
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.refund_transactions IS '对应JSON字段:refund_transactions.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 refund_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.refund_transactions.id IS '对应JSON字段:id,说明::本条 退款流水 的唯一 ID。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID,全系统维度标识该商户。,示例值及对应分析:特点:本文件中所有记录相同。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.tenantName IS '对应JSON字段:tenantName,说明::租户(商户)名称。,示例值及对应分析:特点:本文件中固定为“朗朗桌球”,完全冗余于 siteProfile.shop_name。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.site_id IS '对应JSON字段:site_id,说明::门店 ID。,示例值及对应分析:特点:本文件中所有记录相同(单门店)。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.siteProfile IS '对应JSON字段:siteProfile,说明::门店信息快照,结构与其他 JSON 中的 siteProfile 完全一致。包含字段包括但不限于:,示例值及对应分析:id:门店 ID(= site_id);';
+COMMENT ON COLUMN billiards_ods.refund_transactions.relate_type IS '对应JSON字段:relate_type,说明::本退款对应的“业务类型”。,示例值及对应分析:结合支付记录的 relate_type 推测:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.relate_id IS '对应JSON字段:relate_id,说明::本次退款关联的业务 ID。,示例值及对应分析:对于 relate_type = 2:应该对应某个订单/结算的主键;';
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_sn IS '对应JSON字段:pay_sn,说明:?????? refund_transactions-Analysis.md,示例值及对应分析:?? refund_transactions-Analysis.md';
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_amount IS '对应JSON字段:pay_amount,说明::本次退款的 资金变动金额。,示例值及对应分析:特征很重要:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.refund_amount IS '对应JSON字段:refund_amount,说明:(推测):,示例值及对应分析:设计上本应显示“实际退款金额”(正数),与 pay_amount 配合使用;';
+COMMENT ON COLUMN billiards_ods.refund_transactions.round_amount IS '对应JSON字段:round_amount,说明:(推测):,示例值及对应分析:舍入金额/抹零金额;';
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_status IS '对应JSON字段:pay_status,说明:(推测):,示例值及对应分析:支付/退款状态枚举:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_time IS '对应JSON字段:pay_time,说明::退款在支付渠道层面实际发生的时间。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.create_time IS '对应JSON字段:create_time,说明::本条退款流水在系统内创建时间。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.payment_method IS '对应JSON字段:payment_method,说明:(推测):,示例值及对应分析:支付/退款的 方式类型:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_terminal IS '对应JSON字段:pay_terminal,说明:(推测):,示例值及对应分析:退款所使用的 终端类型:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.pay_config_id IS '对应JSON字段:pay_config_id,说明:(推测):,示例值及对应分析:支付配置 ID,例如商户在“非球科技”内配置的某一条支付通道(某个微信商户号、银联通道)的主键。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.online_pay_channel IS '对应JSON字段:online_pay_channel,说明:(推测):,示例值及对应分析:线上支付的 渠道编号,例如:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.online_pay_type IS '对应JSON字段:online_pay_type,说明:(推测):,示例值及对应分析:在线退款的类型:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.channel_fee IS '对应JSON字段:channel_fee,说明:(推测):,示例值及对应分析:第三方支付渠道对本次退款收取的手续费;';
+COMMENT ON COLUMN billiards_ods.refund_transactions.channel_payer_id IS '对应JSON字段:channel_payer_id,说明:(推测):,示例值及对应分析:支付渠道侧的 payer ID,例如微信 openid、银行卡号掩码等。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.channel_pay_no IS '对应JSON字段:channel_pay_no,说明:(推测):,示例值及对应分析:第三方支付平台的交易号(如微信支付单号、支付宝交易号等)。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.member_id IS '对应JSON字段:member_id,说明::,示例值及对应分析:租户内部的会员 ID(对应会员档案中的某个主键)。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.member_card_id IS '对应JSON字段:member_card_id,说明::,示例值及对应分析:关联的会员卡账户 ID(对应“储值卡列表”或“会员档案”中的某一张卡)。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.cashier_point_id IS '对应JSON字段:cashier_point_id,说明:(推测):,示例值及对应分析:收银点 ID,例如前台 1、前台 2、自助机等。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.operator_id IS '对应JSON字段:operator_id,说明::,示例值及对应分析:执行该退款操作的操作员 ID。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.action_type IS '对应JSON字段:action_type,说明:(推测):,示例值及对应分析:行为类型:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.check_status IS '对应JSON字段:check_status,说明:(推测):,示例值及对应分析:审核状态:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.is_revoke IS '对应JSON字段:is_revoke,说明:(推测):,示例值及对应分析:是否撤销型退款/撤销原支付:';
+COMMENT ON COLUMN billiards_ods.refund_transactions.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志。,示例值及对应分析:0:未删除;';
+COMMENT ON COLUMN billiards_ods.refund_transactions.balance_frozen_amount IS '对应JSON字段:balance_frozen_amount,说明:(推测):,示例值及对应分析:涉及会员储值卡退款时,暂时冻结的余额金额;';
+COMMENT ON COLUMN billiards_ods.refund_transactions.card_frozen_amount IS '对应JSON字段:card_frozen_amount,说明::与上一个类似,偏向“某张卡的被冻结金额”,也与会员卡/储值账户相关。,示例值及对应分析:状态同上:本数据中未发生“卡冻结退款”。';
+COMMENT ON COLUMN billiards_ods.refund_transactions.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.refund_transactions.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.refund_transactions.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.refund_transactions.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.platform_coupon_redemption_records (
+ id BIGINT PRIMARY KEY,
+ verify_id BIGINT,
+ certificate_id TEXT,
+ coupon_code TEXT,
+ coupon_name TEXT,
+ coupon_channel INT,
+ groupon_type INT,
+ group_package_id BIGINT,
+ sale_price NUMERIC(18,2),
+ coupon_money NUMERIC(18,2),
+ coupon_free_time NUMERIC(18,2),
+ coupon_cover TEXT,
+ coupon_remark TEXT,
+ use_status INT,
+ consume_time TIMESTAMP,
+ create_time TIMESTAMP,
+ deal_id TEXT,
+ channel_deal_id TEXT,
+ site_id BIGINT,
+ site_order_id BIGINT,
+ table_id BIGINT,
+ tenant_id BIGINT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ is_delete INT,
+ siteProfile JSONB,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.platform_coupon_redemption_records IS '对应JSON字段:platform_coupon_redemption_records.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.id IS '对应JSON字段:id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.verify_id IS '对应JSON字段:verify_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.certificate_id IS '对应JSON字段:certificate_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_code IS '对应JSON字段:coupon_code,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_name IS '对应JSON字段:coupon_name,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_channel IS '对应JSON字段:coupon_channel,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.groupon_type IS '对应JSON字段:groupon_type,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.group_package_id IS '对应JSON字段:group_package_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.sale_price IS '对应JSON字段:sale_price,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_money IS '对应JSON字段:coupon_money,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_free_time IS '对应JSON字段:coupon_free_time,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_cover IS '对应JSON字段:coupon_cover,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.coupon_remark IS '对应JSON字段:coupon_remark,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.use_status IS '对应JSON字段:use_status,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.consume_time IS '对应JSON字段:consume_time,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.create_time IS '对应JSON字段:create_time,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.deal_id IS '对应JSON字段:deal_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.channel_deal_id IS '对应JSON字段:channel_deal_id,说明:任意一个 ID 字段缺失时(如部分记录 deal_id=0),仍然可以通过其他字段(coupon_name + sale_price + coupon_money + channel_deal_id)唯一识别该产品。,示例值及对应分析:这种多字段冗余,结构上提升了抗“配置缺失”的能力。';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.site_id IS '对应JSON字段:site_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.site_order_id IS '对应JSON字段:site_order_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.table_id IS '对应JSON字段:table_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.tenant_id IS '对应JSON字段:tenant_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.operator_id IS '对应JSON字段:operator_id,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.operator_name IS '对应JSON字段:operator_name,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.is_delete IS '对应JSON字段:is_delete,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.siteProfile IS '对应JSON字段:siteProfile,说明:?????? platform_coupon_redemption_records-Analysis.md,示例值及对应分析:?? platform_coupon_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.platform_coupon_redemption_records.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.tenant_goods_master (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ goods_name TEXT,
+ goods_bar_code TEXT,
+ goods_category_id BIGINT,
+ goods_second_category_id BIGINT,
+ categoryName TEXT,
+ unit TEXT,
+ goods_number TEXT,
+ out_goods_id TEXT,
+ goods_state INT,
+ sale_channel INT,
+ able_discount INT,
+ able_site_transfer INT,
+ is_delete INT,
+ is_warehousing INT,
+ isInSite INT,
+ cost_price NUMERIC(18,4),
+ cost_price_type INT,
+ market_price NUMERIC(18,4),
+ min_discount_price NUMERIC(18,4),
+ common_sale_royalty NUMERIC(18,4),
+ point_sale_royalty NUMERIC(18,4),
+ pinyin_initial TEXT,
+ commodityCode TEXT,
+ commodity_code TEXT,
+ goods_cover TEXT,
+ supplier_id BIGINT,
+ remark_name TEXT,
+ create_time TIMESTAMP,
+ update_time TIMESTAMP,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+
+COMMENT ON TABLE billiards_ods.tenant_goods_master IS '对应JSON字段:tenant_goods_master.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 tenant_goods_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.id IS '对应JSON字段:id,说明::商品档案主键 ID,唯一标识一条商品。,示例值及对应分析:作用:作为其他业务表(销售明细、库存流水、门店商品表等)的外键,通常以 tenant_goods_id 或类似字段出现。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID。,示例值及对应分析:作用:和其它 JSON 中的 tenant_id / tenantId 一致,用于区分不同商户(本次数据只包含同一租户)。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_name IS '对应JSON字段:goods_name,说明::商品名称(前台展示名称)。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_bar_code IS '对应JSON字段:goods_bar_code,说明::商品条码(EAN 等),目前未维护。,示例值及对应分析:说明:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_category_id IS '对应JSON字段:goods_category_id,说明::商品一级分类 ID。,示例值及对应分析:取值情况:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_second_category_id IS '对应JSON字段:goods_second_category_id,说明::商品二级分类 ID。,示例值及对应分析:取值情况:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.categoryName IS '对应JSON字段:categoryName,说明::商品一级分类名称(业务可读)。,示例值及对应分析:取值情况:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.unit IS '对应JSON字段:unit,说明::计量单位。,示例值及对应分析:取值(共 12 种左右):';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_number IS '对应JSON字段:goods_number,说明::商品内部编码(自定义货号/系统货号)。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_state IS '对应JSON字段:goods_state,说明:(推测):商品状态(上架/下架等)。,示例值及对应分析:1:正常/上架;';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.sale_channel IS '对应JSON字段:sale_channel,说明:(推测):销售渠道类型,如“门店堂食/线下零售/线上小程序”等的一种编码。,示例值及对应分析:现有数据只有一个值,说明本门店目前仅通过一种渠道销售这些商品。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.able_discount IS '对应JSON字段:able_discount,说明:(推测):是否允许参与折扣/打折。,示例值及对应分析:1:允许折扣;';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.able_site_transfer IS '对应JSON字段:able_site_transfer,说明:(推测):,示例值及对应分析:字面意思是“是否允许门店间调拨/门店级操作”:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志。,示例值及对应分析:0:未删除(有效商品);';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.is_warehousing IS '对应JSON字段:is_warehousing,说明:(推测):是否启用库存管理。,示例值及对应分析:1:该商品纳入库存管理;';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.isInSite IS '对应JSON字段:isInSite,说明:(从命名推测):是否在当前门店启用/上架。,示例值及对应分析:现象:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.cost_price IS '对应JSON字段:cost_price,说明::成本价格。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.cost_price_type IS '对应JSON字段:cost_price_type,说明:(推测):,示例值及对应分析:不同的成本价格来源或计算方式,如:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.market_price IS '对应JSON字段:market_price,说明::商品标价 / 售价(标准销售单价)。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.min_discount_price IS '对应JSON字段:min_discount_price,说明::该商品允许售卖的最低价格(底价)。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.common_sale_royalty IS '对应JSON字段:common_sale_royalty,说明:(推测):普通销售提成比例或提成金额的配置字段。,示例值及对应分析:当前门店未在商品档案上配置员工提成规则,全部为 0。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.point_sale_royalty IS '对应JSON字段:point_sale_royalty,说明:(推测):积分销售提成/积分赠送规则相关配置。,示例值及对应分析:当前同样未启用。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.pinyin_initial IS '对应JSON字段:pinyin_initial,说明::拼音首字母/助记码。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.commodityCode IS '对应JSON字段:commodityCode,说明::,示例值及对应分析:与 commodity_code 是同一信息的数组形式(冗余存储),便于支持一个商品对应多个编码的场景。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.commodity_code IS '对应JSON字段:commodity_code,说明::商品编码(通常为对外商品编码或条码)。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.goods_cover IS '对应JSON字段:goods_cover,说明::商品封面图片 URL 地址。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.supplier_id IS '对应JSON字段:supplier_id,说明::供应商 ID,用于关联到供应商档案。,示例值及对应分析:当前所有商品都未挂接具体供应商(或门店未使用供应链管理模块)。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.remark_name IS '对应JSON字段:remark_name,说明:(从命名推断):商品备注名/别名,通常用来配置简写或特殊显示名称。,示例值及对应分析:当前门店尚未使用该字段,字段设计为将来扩展预留。';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.create_time IS '对应JSON字段:create_time,说明::商品档案创建时间。,示例值及对应分析:特征:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.update_time IS '对应JSON字段:update_time,说明::商品档案最近一次修改时间。,示例值及对应分析:分布:';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.tenant_goods_master.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.group_buy_packages (
+ id BIGINT PRIMARY KEY,
+ package_id BIGINT,
+ package_name TEXT,
+ selling_price NUMERIC(18,2),
+ coupon_money NUMERIC(18,2),
+ date_type INT,
+ date_info TEXT,
+ start_time TIMESTAMP,
+ end_time TIMESTAMP,
+ start_clock TEXT,
+ end_clock TEXT,
+ add_start_clock TEXT,
+ add_end_clock TEXT,
+ duration INT,
+ usable_count INT,
+ usable_range INT,
+ table_area_id BIGINT,
+ table_area_name TEXT,
+ table_area_id_list JSONB,
+ tenant_table_area_id BIGINT,
+ tenant_table_area_id_list JSONB,
+ site_id BIGINT,
+ site_name TEXT,
+ tenant_id BIGINT,
+ card_type_ids JSONB,
+ group_type INT,
+ system_group_type INT,
+ type INT,
+ effective_status INT,
+ is_enabled INT,
+ is_delete INT,
+ max_selectable_categories INT,
+ area_tag_type INT,
+ creator_name TEXT,
+ create_time TIMESTAMP,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now(),
+ payload JSONB NOT NULL
+);
+
+COMMENT ON TABLE billiards_ods.group_buy_packages IS '对应JSON字段:group_buy_packages.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 group_buy_packages-Analysis.md';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.id IS '对应JSON字段:id,说明::门店侧套餐 ID,本文件内部的主键。,示例值及对应分析:特点:17 条记录中均为不同的大整数 ID。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.package_id IS '对应JSON字段:package_id,说明::“上层套餐 ID” 或“总部/系统级套餐 ID”。,示例值及对应分析:特点:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.package_name IS '对应JSON字段:package_name,说明::团购套餐名称,用于前台展示和核销界面。,示例值及对应分析:示例:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.selling_price IS '对应JSON字段:selling_price,说明:(结合字段命名):,示例值及对应分析:语义上应该是“团购售卖价”(顾客在平台购买券时的成交价格)。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.coupon_money IS '对应JSON字段:coupon_money,说明::券面值或内部结算面值,表示该套餐在门店侧对应的金额额度。,示例值及对应分析:示例(对应套餐名称):';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.date_type IS '对应JSON字段:date_type,说明:(推测):,示例值及对应分析:典型用法:区分“全部日期可用 / 工作日 / 周末 / 指定日期”等。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.date_info IS '对应JSON字段:date_info,说明:(推测):,示例值及对应分析:预留字段,通常用来存储更细粒度的日期信息,如具体日期列表、节假日特殊规则(可能是 JSON 字符串或编码)。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.start_time IS '对应JSON字段:start_time,说明::套餐开始生效的日期时间。,示例值及对应分析:示例:"2025-07-20 00:00:00" 等。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.end_time IS '对应JSON字段:end_time,说明::套餐失效的日期时间(到这个时间点后不可使用)。,示例值及对应分析:示例:形如 "2025-11-30 23:59:59",部分记录使用 9999-12-31 23:59:59 风格的极大日期表示长期有效(本数据中如有这种值,可解读为“长期有效”)。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.start_clock IS '对应JSON字段:start_clock,说明::每日可用起始时间点(第一段)。,示例值及对应分析:说明:配合 end_clock 使用,定义一个日内时段。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.end_clock IS '对应JSON字段:end_clock,说明::每日可用的结束时间点(第一段)。,示例值及对应分析:结构说明:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.add_start_clock IS '对应JSON字段:add_start_clock,说明:(推测):附加可用时间段的起始时间(第二段)。,示例值及对应分析:例如有的套餐可以在两个不连续的时段使用:早场 + 夜场,则可用第一段 start_clock / end_clock 和第二段 add_start_clock / add_end_clock 组合。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.add_end_clock IS '对应JSON字段:add_end_clock,说明::附加时段结束时间,多数情况配合 "00:00:00" 或 "10:00:00" 使用。,示例值及对应分析:整体理解:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.duration IS '对应JSON字段:duration,说明::套餐内包含的时长(秒)。,示例值及对应分析:与名称一致:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.usable_count IS '对应JSON字段:usable_count,说明::可使用次数上限。,示例值及对应分析:数据特征说明:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.usable_range IS '对应JSON字段:usable_range,说明:吻合(A区中八/B区中八/斯诺克/KTV/包厢等)。,示例值及对应分析:通过该关联,系统在核销时可以校验:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.table_area_id IS '对应JSON字段:table_area_id,说明:(推测):,示例值及对应分析:原始设计应为“单一台区 ID”,当套餐只限一个区域可以用这个字段存储。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.table_area_name IS '对应JSON字段:table_area_name,说明::套餐适用的“门店台区名称”,用于显示和筛选。,示例值及对应分析:说明:这个字段是对区域 ID 维度的文字描述,便于直观理解。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.table_area_id_list IS '对应JSON字段:table_area_id_list,说明:(推测):,示例值及对应分析:用来存放具体台区 ID 列表(例如 "1,2,3"),实现更细粒度的台桌限制。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.tenant_table_area_id IS '对应JSON字段:tenant_table_area_id,说明:(推测):,示例值及对应分析:与 table_area_id 类似,是租户层级的台区 ID,原本用于单区选择。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.tenant_table_area_id_list IS '对应JSON字段:tenant_table_area_id_list,说明:(推测):,示例值及对应分析:实际代表“台区集合 ID”或“租户台区配置 ID”,用来限制套餐可用的台区范围。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.site_id IS '对应JSON字段:site_id,说明::门店 ID。,示例值及对应分析:特点:全表值相同,且与其他 JSON 文件中的 site_id 一致,对应“朗朗桌球”这家门店。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.site_name IS '对应JSON字段:site_name,说明::门店名称。,示例值及对应分析:观测值:全部为 "朗朗桌球"。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.tenant_id IS '对应JSON字段:tenant_id,说明::租户 ID(品牌/商户 ID)。,示例值及对应分析:特点:全表值相同,说明所有套餐定义属于同一商户(同一品牌)。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.card_type_ids IS '对应JSON字段:card_type_ids,说明:(推测):,示例值及对应分析:原意是“适用会员卡类型 ID 列表”,例如某套餐只允许某几种会员卡使用,可以在此配置。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.group_type IS '对应JSON字段:group_type,说明:(推测):,示例值及对应分析:团购类型,例如:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.system_group_type IS '对应JSON字段:system_group_type,说明:(推测):,示例值及对应分析:系统内对团购类型更底层的划分,比如:';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.type IS '对应JSON字段:type,说明:(推测):,示例值及对应分析:内部业务子类型,具体含义需要结合系统文档;仅从数据无法确定是“台费类 vs 包厢类”还是“平台套餐 vs 自定义套餐”。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.effective_status IS '对应JSON字段:effective_status,说明:(结合命名和数据特征推断):,示例值及对应分析:1:有效(在当前时间区间内、配置正常,可核销使用)。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.is_enabled IS '对应JSON字段:is_enabled,说明::启用状态。,示例值及对应分析:从其他表的统一风格来看,1 一般表示“启用 / 上架”,2 表示“停用 / 下架”。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志。,示例值及对应分析:0:正常;';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.max_selectable_categories IS '对应JSON字段:max_selectable_categories,说明:?????? group_buy_packages-Analysis.md,示例值及对应分析:?? group_buy_packages-Analysis.md';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.area_tag_type IS '对应JSON字段:area_tag_type,说明:(推测):区域标记类型:,示例值及对应分析:1 很可能代表“按台区标签限制”,例如 A区、中八区、包厢、KTV 等。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.creator_name IS '对应JSON字段:creator_name,说明::创建人信息,一般包含“角色:姓名”。,示例值及对应分析:示例:"管理员:郑丽珊"';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.create_time IS '对应JSON字段:create_time,说明::该套餐在系统中创建的时间。,示例值及对应分析:特点:每条记录各不相同,覆盖了 2025-07 至 2025-10 的创建时间。';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.group_buy_packages.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.group_buy_redemption_records (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ siteName TEXT,
+ table_id BIGINT,
+ tableName TEXT,
+ tableAreaName TEXT,
+ tenant_table_area_id BIGINT,
+ order_trade_no TEXT,
+ order_settle_id BIGINT,
+ order_pay_id BIGINT,
+ order_coupon_id BIGINT,
+ order_coupon_channel INT,
+ coupon_code TEXT,
+ coupon_money NUMERIC(18,2),
+ coupon_origin_id BIGINT,
+ ledger_name TEXT,
+ ledger_group_name TEXT,
+ ledger_amount NUMERIC(18,2),
+ ledger_count NUMERIC(18,4),
+ ledger_unit_price NUMERIC(18,4),
+ ledger_status INT,
+ table_charge_seconds INT,
+ promotion_activity_id BIGINT,
+ promotion_coupon_id BIGINT,
+ promotion_seconds INT,
+ offer_type INT,
+ assistant_promotion_money NUMERIC(18,2),
+ assistant_service_promotion_money NUMERIC(18,2),
+ table_service_promotion_money NUMERIC(18,2),
+ goods_promotion_money NUMERIC(18,2),
+ recharge_promotion_money NUMERIC(18,2),
+ reward_promotion_money NUMERIC(18,2),
+ goodsOptionPrice NUMERIC(18,2),
+ salesman_name TEXT,
+ sales_man_org_id BIGINT,
+ salesman_role_id BIGINT,
+ salesman_user_id BIGINT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ is_single_order INT,
+ is_delete INT,
+ create_time TIMESTAMP,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+
+COMMENT ON TABLE billiards_ods.group_buy_redemption_records IS '对应JSON字段:group_buy_redemption_records.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 group_buy_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.id IS '对应JSON字段:id,说明::本条“团购套餐流水”记录的 主键 ID。,示例值及对应分析:作用:唯一标识一条券使用到台费上的记录。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID。,示例值及对应分析:特点:全表值相同,说明所有记录属于同一租户。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.site_id IS '对应JSON字段:site_id,说明::门店 ID,与其它 JSON 中一致。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.siteName IS '对应JSON字段:siteName,说明::门店名称,冗余展示用。,示例值及对应分析:?? group_buy_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.table_id IS '对应JSON字段:table_id,说明::球台 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.tableName IS '对应JSON字段:tableName,说明::本次使用券所关联的 球台名称/台号。,示例值及对应分析:关联:对应台桌列表中的 table_name / table_no,通过 table_id 进一步关联。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.tableAreaName IS '对应JSON字段:tableAreaName,说明::该球台所属的 台区名称。,示例值及对应分析:关联:与台区配置中的 area_name 含义一致,与团购套餐定义中的 table_area_name 一致。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.tenant_table_area_id IS '对应JSON字段:tenant_table_area_id,说明::租户级台区分组 ID,表示当前使用券的台桌所属的区域组合。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.order_trade_no IS '对应JSON字段:order_trade_no,说明::订单交易号,和其它消费明细(台费、商品、助教、团购)共用的订单主键。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.order_settle_id IS '对应JSON字段:order_settle_id,说明::结算单 ID(小票结账主键)。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.order_pay_id IS '对应JSON字段:order_pay_id,说明:(推测):,示例值及对应分析:指向支付记录表中的支付流水 ID。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.order_coupon_id IS '对应JSON字段:order_coupon_id,说明::订单中“券使用记录”的 ID。,示例值及对应分析:结构特点:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.order_coupon_channel IS '对应JSON字段:order_coupon_channel,说明:(推测):,示例值及对应分析:券渠道类型,例如:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.coupon_code IS '对应JSON字段:coupon_code,说明::团购券券码,核销时扫描/录入的字符串。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.coupon_money IS '对应JSON字段:coupon_money,说明::本次核销时,这张券在门店侧对应的金额额度(“可抵扣金额”)。,示例值及对应分析:结构关系:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.coupon_origin_id IS '对应JSON字段:coupon_origin_id,说明:(推测):,示例值及对应分析:平台/上游系统中的券记录主键 ID,“券来源 ID”。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.ledger_name IS '对应JSON字段:ledger_name,说明::台费侧关联的“团购项目名称”(记账名)。,示例值及对应分析:结构上通常来源于团购套餐定义的 package_name,或由系统在创建活动时生成。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.ledger_group_name IS '对应JSON字段:ledger_group_name,说明:(推测):团购项目所属的“记账分组名称”(例如“团购台费”“团购包厢”等)。,示例值及对应分析:当前门店未对团购项目做进一步分组。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.ledger_amount IS '对应JSON字段:ledger_amount,说明::本次券实际冲抵台费的金额。,示例值及对应分析:结构关系:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.ledger_count IS '对应JSON字段:ledger_count,说明::按此次优惠实际计算的“核销秒数”。,示例值及对应分析:结构观察:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.ledger_unit_price IS '对应JSON字段:ledger_unit_price,说明::对应台费的标准单价,单位元/小时(从数值来看是类似29.9/小时这种定价)。,示例值及对应分析:作用:配合 ledger_count 用于计算这一条券在台费层面对应的金额(理论上应接近 = 单价 × 秒数/3600)。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.ledger_status IS '对应JSON字段:ledger_status,说明:(推测):流水状态。,示例值及对应分析:1:正常有效;';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.table_charge_seconds IS '对应JSON字段:table_charge_seconds,说明::本次结算中该球台总计计费的秒数(整台的台费计费时间)。,示例值及对应分析:结构特点:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.promotion_activity_id IS '对应JSON字段:promotion_activity_id,说明:(推测):团购/促销活动 ID。,示例值及对应分析:对应平台或内部促销活动的主键,每个活动通常绑定一个或多个具体套餐(promotion_coupon_id)。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.promotion_coupon_id IS '对应JSON字段:promotion_coupon_id,说明::团购套餐定义 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.promotion_seconds IS '对应JSON字段:promotion_seconds,说明::团购套餐定义的“标准时长”(券本身标称的可用时长)。,示例值及对应分析:结构关系:';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.offer_type IS '对应JSON字段:offer_type,说明:(推测):优惠类型。,示例值及对应分析:在券适用多个优惠方式的系统中,一般用来区分“满减/折扣/代金券/套餐券”等。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.assistant_promotion_money IS '对应JSON字段:assistant_promotion_money,说明::分摊到“助教服务”的促销金额。,示例值及对应分析:当前场景下,团购券只与台费相关,未涉及助教的金额抵扣。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.assistant_service_promotion_money IS '对应JSON字段:assistant_service_promotion_money,说明::进一步细分助教服务的促销金额。,示例值及对应分析:当前未使用。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.table_service_promotion_money IS '对应JSON字段:table_service_promotion_money,说明::本次券使用中,分摊到“台费服务费”部分的促销金额。,示例值及对应分析:当前样本中,促销金额都在 ledger_amount 中体现,该字段未单独拆出。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.goods_promotion_money IS '对应JSON字段:goods_promotion_money,说明::本次券使用中,分摊到“商品”部分的促销金额。,示例值及对应分析:当前数据中,所有团购券都只用于抵扣台费,没有用来抵扣商品,因此该字段为 0。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.recharge_promotion_money IS '对应JSON字段:recharge_promotion_money,说明::来自“充值类优惠”的分摊金额(例如储值赠送部分)。,示例值及对应分析:当前所有数据为 0,但结构上已经预留了“多来源促销金额分摊”的能力。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.reward_promotion_money IS '对应JSON字段:reward_promotion_money,说明::本次促销中,属于“奖励金/积分抵扣”的金额。,示例值及对应分析:当前没有使用此维度的促销。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.goodsOptionPrice IS '对应JSON字段:goodsOptionPrice,说明:(按命名推测):商品规格价格,用于商品类促销分摊时使用。,示例值及对应分析:当前在“团购套餐流水”中未被实际使用。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.salesman_name IS '对应JSON字段:salesman_name,说明::营业员姓名。,示例值及对应分析:?? group_buy_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.sales_man_org_id IS '对应JSON字段:sales_man_org_id,说明::营业员所属组织 ID。,示例值及对应分析:以上 4 个销售相关字段在当前门店的团购套餐使用中都未启用,仅作为结构预留。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.salesman_role_id IS '对应JSON字段:salesman_role_id,说明::营业员角色 ID。,示例值及对应分析:?? group_buy_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.salesman_user_id IS '对应JSON字段:salesman_user_id,说明::营业员/业务员用户 ID。,示例值及对应分析:当前所有团购套餐流水都未指定独立的营业员。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.operator_id IS '对应JSON字段:operator_id,说明::执行本次核销/结算操作的 操作员 ID。,示例值及对应分析:关联:可以与员工档案表中的 id 对应(当前导出中员工表未单独给出,但风格和其它表一致)。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.operator_name IS '对应JSON字段:operator_name,说明::操作员名称(包含角色说明),与 operator_id 对应的冗余展示字段。,示例值及对应分析:?? group_buy_redemption_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.is_single_order IS '对应JSON字段:is_single_order,说明:(推测):是否单独作为一条订单行。,示例值及对应分析:1:以独立条目方式进行结算(绝大部分记录如此)。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志:,示例值及对应分析:0:正常;';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.create_time IS '对应JSON字段:create_time,说明::本条团购套餐使用流水创建时间(即券核销时间,或与结账时间接近)。,示例值及对应分析:用法:可用于按时间范围过滤团购使用记录。';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.group_buy_redemption_records.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.settlement_ticket_details (
+ orderSettleId BIGINT PRIMARY KEY,
+ actualPayment NUMERIC(18,2),
+ adjustAmount NUMERIC(18,2),
+ assistantManualDiscount NUMERIC(18,2),
+ balanceAmount NUMERIC(18,2),
+ cashierName TEXT,
+ consumeMoney NUMERIC(18,2),
+ couponAmount NUMERIC(18,2),
+ deliveryAddress TEXT,
+ deliveryFee NUMERIC(18,2),
+ ledgerAmount NUMERIC(18,2),
+ memberDeductAmount NUMERIC(18,2),
+ memberOfferAmount NUMERIC(18,2),
+ onlineReturnAmount NUMERIC(18,2),
+ orderRemark TEXT,
+ orderSettleNumber BIGINT,
+ payMemberBalance NUMERIC(18,2),
+ payTime TIMESTAMP,
+ paymentMethod INT,
+ pointDiscountCost NUMERIC(18,2),
+ pointDiscountPrice NUMERIC(18,2),
+ prepayMoney NUMERIC(18,2),
+ refundAmount NUMERIC(18,2),
+ returnGoodsAmount NUMERIC(18,2),
+ rewardName TEXT,
+ settleType TEXT,
+ siteAddress TEXT,
+ siteBusinessTel TEXT,
+ siteId BIGINT,
+ siteName TEXT,
+ tenantId BIGINT,
+ tenantName TEXT,
+ ticketCustomContent TEXT,
+ ticketRemark TEXT,
+ voucherMoney NUMERIC(18,2),
+ memberProfile JSONB,
+ orderItem JSONB,
+ tenantMemberCardLogs JSONB,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+
+COMMENT ON TABLE billiards_ods.settlement_ticket_details IS '对应JSON字段:settlement_ticket_details.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.orderSettleId IS '对应JSON字段:orderSettleId,说明::同 data.data.orderSettleId,为结算单 ID 的冗余。,示例值及对应分析:orderType';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.actualPayment IS '对应JSON字段:actualPayment,说明::本单实际支付金额总和(顾客本次实际付出:现金 + 线上 + 会员余额等)。,示例值及对应分析:一般应与支付记录中各支付流水金额汇总相匹配。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.adjustAmount IS '对应JSON字段:adjustAmount,说明::台费层面的人工调价金额(仅台费部分)。,示例值及对应分析:memberDiscountAmount';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.assistantManualDiscount IS '对应JSON字段:assistantManualDiscount,说明::针对“助教项目”的人工减免金额汇总(整单维度)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.balanceAmount IS '对应JSON字段:balanceAmount,说明::本单通过“会员余额/储值卡”支付的金额(从余额中扣除的总额)。,示例值及对应分析:对应 结账记录.json 的同名字段。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.cashierName IS '对应JSON字段:cashierName,说明::本单结算操作员名称(带角色前缀文字)。,示例值及对应分析:对应员工维表中的某个账号,便于小票上展示“收银员:XXX”。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.consumeMoney IS '对应JSON字段:consumeMoney,说明::本单“消费金额总计”(原价层面),即台费 + 商品 + 助教 + 服务等消费项目的金额总和(未扣除各类优惠)。,示例值及对应分析:对应 结账记录.json 的 consumeMoney 字段。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.couponAmount IS '对应JSON字段:couponAmount,说明::本单由优惠券抵扣的金额汇总。,示例值及对应分析:结构上:应与 orderCouponLedgers.discountAmount 的合计存在关系,但当前导出未填充。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.deliveryAddress IS '对应JSON字段:deliveryAddress,说明::配送地址(若存在外送业务时使用)。,示例值及对应分析:对于球房场景,当前时间范围内未使用。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.deliveryFee IS '对应JSON字段:deliveryFee,说明::配送费金额(如果支持外送业务)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.ledgerAmount IS '对应JSON字段:ledgerAmount,说明::按台账口径对应的金额,一般与 discountAmount 一致或有固定关系。,示例值及对应分析:rewardPromotionMoney';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.memberDeductAmount IS '对应JSON字段:memberDeductAmount,说明:(结构上):会员抵扣的某种数量或金额(例如积分抵现金额、次卡次数抵扣等),当前数据未启用。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.memberOfferAmount IS '对应JSON字段:memberOfferAmount,说明::由“会员权益/折扣”产生的优惠金额总计(整单维度)。,示例值及对应分析:与 memberProfile 以及台费/商品明细中的 memberDiscountAmount 有对应关系。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.onlineReturnAmount IS '对应JSON字段:onlineReturnAmount,说明::本单通过线上支付渠道退回的金额(如微信/支付宝退款)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.orderRemark IS '对应JSON字段:orderRemark,说明::订单备注,由收银员录入,用于记录与本单相关的特殊说明。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.orderSettleNumber IS '对应JSON字段:orderSettleNumber,说明:(推测):结算单编号(与 ID 独立的一套编号体系,如流水号)。当前导出时间段内未启用。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.payMemberBalance IS '对应JSON字段:payMemberBalance,说明:(结构上):使用会员余额支付的金额,用于区分与 balanceAmount 的不同维度(如“本次支付使用余额部分”与“余额本身变化”等),当前未实际使用。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.payTime IS '对应JSON字段:payTime,说明::本单最终支付成功时间。,示例值及对应分析:和 结账记录.json 中的 payTime 对应,一般与 支付记录.create_time/pay_time 在同一时间段。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.paymentMethod IS '对应JSON字段:paymentMethod,说明::结算主支付方式编码(汇总视角)。,示例值及对应分析:对应 结账记录.json 中的 paymentMethod 字段;';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.pointDiscountCost IS '对应JSON字段:pointDiscountCost,说明::积分抵扣对应的成本金额(成本侧)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.pointDiscountPrice IS '对应JSON字段:pointDiscountPrice,说明::积分抵扣对应的金额(售价侧)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.prepayMoney IS '对应JSON字段:prepayMoney,说明::预付金/定金在本单中使用的金额。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.refundAmount IS '对应JSON字段:refundAmount,说明::本单涉及的退款金额(汇总)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.returnGoodsAmount IS '对应JSON字段:returnGoodsAmount,说明::本单涉及的退货金额汇总。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.rewardName IS '对应JSON字段:rewardName,说明:(结构上):用于标识本单适用的激励方案名称,可能用于内部绩效或活动名称展示。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.settleType IS '对应JSON字段:settleType,说明::结算类型字符串标识。,示例值及对应分析:"SiteOrder":店内消费订单结算。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.siteAddress IS '对应JSON字段:siteAddress,说明::门店地址(详细地址)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.siteBusinessTel IS '对应JSON字段:siteBusinessTel,说明::门店电话。,示例值及对应分析:用途:用于小票打印上的客服电话。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.siteId IS '对应JSON字段:siteId,说明::门店 ID。,示例值及对应分析:关联:';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.siteName IS '对应JSON字段:siteName,说明::门店名称,如“朗朗桌球”。,示例值及对应分析:用途:小票上展示门店名。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.tenantId IS '对应JSON字段:tenantId,说明::租户 / 商户 ID(品牌维度)。,示例值及对应分析:当前数据:恒定为同一值,表示所有记录都来自同一商户。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.tenantName IS '对应JSON字段:tenantName,说明::租户名称,如“朗朗桌球”。,示例值及对应分析:当前数据:全表统一一个值。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.ticketCustomContent IS '对应JSON字段:ticketCustomContent,说明::自定义小票内容,如商家自定义宣传语、条款等。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.ticketRemark IS '对应JSON字段:ticketRemark,说明::小票备注内容,可用于打印在小票底部或顶部(例如活动说明、特别提示)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.voucherMoney IS '对应JSON字段:voucherMoney,说明::代金券类金额字段(可能用于某类“代金券余额”或“券面值”记录)。,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.memberProfile IS '对应JSON字段:memberProfile,说明::,示例值及对应分析:不是会员卡主键,而是本次结账时的会员信息快照;';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.orderItem IS '对应JSON字段:orderItem,说明::本次结算对应的“订单明细列表”,这部分是连接“台费流水 / 商品出库 / 券使用”等多个子领域的关键结构。,示例值及对应分析:下面专门展开 orderItem 及其子结构。';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.tenantMemberCardLogs IS '对应JSON字段:tenantMemberCardLogs,说明:?????? settlement_ticket_details-Analysis.md,示例值及对应分析:?? settlement_ticket_details-Analysis.md';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.settlement_ticket_details.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.store_goods_master (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ siteName TEXT,
+ tenant_goods_id BIGINT,
+ goods_name TEXT,
+ goods_bar_code TEXT,
+ goods_category_id BIGINT,
+ goods_second_category_id BIGINT,
+ oneCategoryName TEXT,
+ twoCategoryName TEXT,
+ unit TEXT,
+ sale_price NUMERIC(18,4),
+ cost_price NUMERIC(18,4),
+ cost_price_type INT,
+ min_discount_price NUMERIC(18,4),
+ safe_stock NUMERIC(18,4),
+ stock NUMERIC(18,4),
+ stock_A NUMERIC(18,4),
+ sale_num NUMERIC(18,4),
+ total_purchase_cost NUMERIC(18,4),
+ total_sales NUMERIC(18,4),
+ average_monthly_sales NUMERIC(18,4),
+ batch_stock_quantity NUMERIC(18,2),
+ days_available INT,
+ provisional_total_cost NUMERIC(18,2),
+ enable_status INT,
+ audit_status INT,
+ goods_state INT,
+ is_delete INT,
+ is_warehousing INT,
+ able_discount INT,
+ able_site_transfer INT,
+ forbid_sell_status INT,
+ "freeze" INT,
+ send_state INT,
+ custom_label_type INT,
+ option_required INT,
+ sale_channel INT,
+ sort INT,
+ remark TEXT,
+ pinyin_initial TEXT,
+ goods_cover TEXT,
+ create_time TIMESTAMP,
+ update_time TIMESTAMP,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+
+COMMENT ON TABLE billiards_ods.store_goods_master IS '对应JSON字段:store_goods_master.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 store_goods_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_master.id IS '对应JSON字段:id,说明::门店商品 ID,门店维度的商品主键。,示例值及对应分析:用途:在其它文件中经常以 site_goods_id 的名字出现,与这里的 id 一致,用来关联库存记录、销售记录等。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID。同一品牌下多个门店共享一个 tenant_id。,示例值及对应分析:枚举情况:本文件中为单一固定值(同一品牌)。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.site_id IS '对应JSON字段:site_id,说明::门店 ID。,示例值及对应分析:枚举情况:本文件中为单一固定值(同一家门店“朗朗桌球”),和其它 JSON 中的 site_id 一致。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.siteName IS '对应JSON字段:siteName,说明::门店名称,是对 site_id 的冗余展示,方便直接阅读,无需再去关联门店档案。,示例值及对应分析:2. 商品标识和分类维度';
+COMMENT ON COLUMN billiards_ods.store_goods_master.tenant_goods_id IS '对应JSON字段:tenant_goods_id,说明::租户/品牌维度的商品 ID,相当于“全局商品 ID”。,示例值及对应分析:用途:用于跨门店或与“商品档案(商品档案.json)”对齐时使用。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_name IS '对应JSON字段:goods_name,说明::商品名称,例如“合味道泡面”“地道肠”“麻将房茶位费”等。,示例值及对应分析:用途:业务展示字段,历史流水里也会冗余存一份商品名。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_bar_code IS '对应JSON字段:goods_bar_code,说明::商品条形码(如 EAN-13 编码),用于扫码销售。此字段设计为可填,但此店目前未配置。,示例值及对应分析:?? store_goods_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_category_id IS '对应JSON字段:goods_category_id,说明::商品一级分类 ID。,示例值及对应分析:用途:';
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_second_category_id IS '对应JSON字段:goods_second_category_id,说明::商品二级分类 ID。,示例值及对应分析:用途:';
+COMMENT ON COLUMN billiards_ods.store_goods_master.oneCategoryName IS '对应JSON字段:oneCategoryName,说明::一级分类名称,如“零食”“酒水”“服务费”等。,示例值及对应分析:说明:与 goods_category_id 一一对应,是易读文本字段。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.twoCategoryName IS '对应JSON字段:twoCategoryName,说明::二级分类名称,如“面”“洋酒”“纸巾”等。,示例值及对应分析:说明:与 goods_second_category_id 对应。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.unit IS '对应JSON字段:unit,说明::商品计量单位(销售单位)。,示例值及对应分析:?? store_goods_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_master.sale_price IS '对应JSON字段:sale_price,说明::商品标准销售价(挂牌价),单位为元。,示例值及对应分析:说明:实际结算时可能会打折或用券抵扣,但这个字段表示“定价”。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.cost_price IS '对应JSON字段:cost_price,说明::商品成本价(单件成本)。,示例值及对应分析:观察:';
+COMMENT ON COLUMN billiards_ods.store_goods_master.cost_price_type IS '对应JSON字段:cost_price_type,说明:(结合成本字段推测):,示例值及对应分析:1 代表使用“固定成本价”(手工维护的 cost_price),provisional_total_cost 按“数量 × cost_price”算。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.min_discount_price IS '对应JSON字段:min_discount_price,说明::最低允许成交价(限价)。,示例值及对应分析:用法逻辑(推测):';
+COMMENT ON COLUMN billiards_ods.store_goods_master.safe_stock IS '对应JSON字段:safe_stock,说明::安全库存量(阈值),低于该值时系统可以提示补货。,示例值及对应分析:当前门店尚未设置安全库存,所以全部为 0,仅起到结构占位作用。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.stock IS '对应JSON字段:stock,说明::当前可用库存数量(以 unit 为单位)。,示例值及对应分析:特征:可以是 0(库存卖完),也可以非常大(例如纸巾、茶位费这种按“份”计的虚拟库存设定)。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.stock_A IS '对应JSON字段:stock_A,说明:(系统设计):副单位库存数量。如果商品存在双单位(例如箱/瓶),stock_A 通常用于记录副单位库存。当前门店没有启用副单位库存管理,因此为 0。,示例值及对应分析:batch_stock_quantity';
+COMMENT ON COLUMN billiards_ods.store_goods_master.sale_num IS '对应JSON字段:sale_num,说明::在当前统计口径下的销售数量(总销量,单位同 unit)。,示例值及对应分析:特征:和 total_sales 完全一致(当前导出时的统计口径下),说明两者是同一统计周期。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.total_purchase_cost IS '对应JSON字段:total_purchase_cost,说明::总采购成本,单位为元。,示例值及对应分析:当前数据:与 provisional_total_cost 完全相等。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.total_sales IS '对应JSON字段:total_sales,说明:(从命名看):累计销售数量。,示例值及对应分析:实际:当前数据中 total_sales == sale_num,说明此接口的统计区间 = “截至当前的全部历史”,因此数量一致。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.average_monthly_sales IS '对应JSON字段:average_monthly_sales,说明::平均月销量(件/月),根据某个统计周期内的销售数据折算而来。,示例值及对应分析:结构特征:';
+COMMENT ON COLUMN billiards_ods.store_goods_master.enable_status IS '对应JSON字段:enable_status,说明:(结合名称与常见编码):,示例值及对应分析:1:启用。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.audit_status IS '对应JSON字段:audit_status,说明:(典型业务语义):,示例值及对应分析:2:审核通过。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_state IS '对应JSON字段:goods_state,说明:类型:int,枚举,示例值及对应分析:观察值:';
+COMMENT ON COLUMN billiards_ods.store_goods_master.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志。,示例值及对应分析:0:未删除(有效档案);';
+COMMENT ON COLUMN billiards_ods.store_goods_master.is_warehousing IS '对应JSON字段:is_warehousing,说明::是否纳入库存管理。,示例值及对应分析:1:启用库存管理(会有出入库流水)。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.able_discount IS '对应JSON字段:able_discount,说明:(结合命名):,示例值及对应分析:是否允许参与折扣。当前全部为 1,说明所有商品都允许打折。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.able_site_transfer IS '对应JSON字段:able_site_transfer,说明:(结合命名与值分布):,示例值及对应分析:表示是否允许跨门店调拨或跨站点共享库存。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.forbid_sell_status IS '对应JSON字段:forbid_sell_status,说明:类型:int,枚举,示例值及对应分析:观察值:全部为 1。';
+COMMENT ON COLUMN billiards_ods.store_goods_master."freeze" IS '对应JSON字段:freeze,说明::冻结状态。,示例值及对应分析:0:未冻结;';
+COMMENT ON COLUMN billiards_ods.store_goods_master.send_state IS '对应JSON字段:send_state,说明:(命名趋近“上架状态/可售状态”):,示例值及对应分析:1:可销售/可下单。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.custom_label_type IS '对应JSON字段:custom_label_type,说明:(推测):自定义标签类型。,示例值及对应分析:1:使用系统默认标签(未出现);';
+COMMENT ON COLUMN billiards_ods.store_goods_master.option_required IS '对应JSON字段:option_required,说明:(推测):是否需要在销售时选择规格/选项。,示例值及对应分析:1:不要求额外选项(单规格商品);';
+COMMENT ON COLUMN billiards_ods.store_goods_master.sale_channel IS '对应JSON字段:sale_channel,说明::销售渠道类型。,示例值及对应分析:常见模式:';
+COMMENT ON COLUMN billiards_ods.store_goods_master.sort IS '对应JSON字段:sort,说明::前端展示或内部配置的排序号,数值越小/越大排前取决于业务约定。';
+COMMENT ON COLUMN billiards_ods.store_goods_master.remark IS '对应JSON字段:remark,说明::商品备注(可以写口味说明、供应商、注意事项等)。当前尚未使用。,示例值及对应分析:sort';
+COMMENT ON COLUMN billiards_ods.store_goods_master.pinyin_initial IS '对应JSON字段:pinyin_initial,说明::商品名称的拼音首字母缩写,有时多个别名用逗号分隔。,示例值及对应分析:作用:';
+COMMENT ON COLUMN billiards_ods.store_goods_master.goods_cover IS '对应JSON字段:goods_cover,说明::商品图片 URL(如 OSS 对象存储地址),用于前端展示商品图片。,示例值及对应分析:?? store_goods_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_master.create_time IS '对应JSON字段:create_time,说明::门店商品档案创建时间(商品在门店建立档案的时间点)。,示例值及对应分析:?? store_goods_master-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_master.update_time IS '对应JSON字段:update_time,说明::最后一次修改该商品档案的时间(包括价格调整、状态变更等)。,示例值及对应分析:days_available';
+COMMENT ON COLUMN billiards_ods.store_goods_master.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.store_goods_master.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.store_goods_master.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.store_goods_master.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
+
+CREATE TABLE IF NOT EXISTS billiards_ods.store_goods_sales_records (
+ id BIGINT PRIMARY KEY,
+ tenant_id BIGINT,
+ site_id BIGINT,
+ siteid BIGINT,
+ sitename TEXT,
+ site_goods_id BIGINT,
+ tenant_goods_id BIGINT,
+ order_settle_id BIGINT,
+ order_trade_no TEXT,
+ order_goods_id BIGINT,
+ ordergoodsid BIGINT,
+ order_pay_id BIGINT,
+ order_coupon_id BIGINT,
+ ledger_name TEXT,
+ ledger_group_name TEXT,
+ ledger_amount NUMERIC(18,2),
+ ledger_count NUMERIC(18,4),
+ ledger_unit_price NUMERIC(18,4),
+ ledger_status INT,
+ discount_money NUMERIC(18,2),
+ discount_price NUMERIC(18,2),
+ coupon_deduct_money NUMERIC(18,2),
+ member_discount_amount NUMERIC(18,2),
+ option_coupon_deduct_money NUMERIC(18,2),
+ option_member_discount_money NUMERIC(18,2),
+ point_discount_money NUMERIC(18,2),
+ point_discount_money_cost NUMERIC(18,2),
+ real_goods_money NUMERIC(18,2),
+ cost_money NUMERIC(18,2),
+ push_money NUMERIC(18,2),
+ sales_type INT,
+ is_single_order INT,
+ is_delete INT,
+ goods_remark TEXT,
+ option_price NUMERIC(18,2),
+ option_value_name TEXT,
+ option_name TEXT,
+ member_coupon_id BIGINT,
+ package_coupon_id BIGINT,
+ sales_man_org_id BIGINT,
+ salesman_name TEXT,
+ salesman_role_id BIGINT,
+ salesman_user_id BIGINT,
+ operator_id BIGINT,
+ operator_name TEXT,
+ openSalesman TEXT,
+ returns_number INT,
+ site_table_id BIGINT,
+ tenant_goods_business_id BIGINT,
+ tenant_goods_category_id BIGINT,
+ create_time TIMESTAMP,
+ payload JSONB NOT NULL,
+ source_file TEXT,
+ source_endpoint TEXT,
+ fetched_at TIMESTAMPTZ DEFAULT now()
+);
+
+COMMENT ON TABLE billiards_ods.store_goods_sales_records IS '对应JSON字段:store_goods_sales_records.json,说明:ODS 原始明细表(保留payload),示例值及对应分析:详见 store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.id IS '对应JSON字段:id,说明::本条「门店销售流水」记录的主键 ID。,示例值及对应分析:用途:在系统内部唯一标识这一条销售明细。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.tenant_id IS '对应JSON字段:tenant_id,说明::租户/品牌 ID。,示例值及对应分析:特征:所有记录为同一个值,对应「非球科技系统中你的商户」。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.site_id IS '对应JSON字段:site_id,说明::门店 ID(系统主键)。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.site_goods_id IS '对应JSON字段:site_goods_id,说明::门店商品 ID。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.tenant_goods_id IS '对应JSON字段:tenant_goods_id,说明::租户(品牌)级商品 ID(全局商品 ID)。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.order_settle_id IS '对应JSON字段:order_settle_id,说明:与台费、助教、团购套餐流水等表共享,形成「订单主表(结算)– 多种明细表」的结构。,示例值及对应分析:如果结账记录表有数据,order_settle_id 对应那里的主键,create_time 与订单结束时间基本一致。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.order_trade_no IS '对应JSON字段:order_trade_no,说明:与台费、助教、团购套餐流水等表共享,形成「订单主表(结算)– 多种明细表」的结构。,示例值及对应分析:如果结账记录表有数据,order_settle_id 对应那里的主键,create_time 与订单结束时间基本一致。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.order_goods_id IS '对应JSON字段:order_goods_id,说明::订单商品明细 ID(订单内部的商品行主键)。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.order_pay_id IS '对应JSON字段:order_pay_id,说明:连接到「支付记录」中的一条支付流水,再通过支付的 relate_type/relate_id 把支付和订单、充值等业务区分开。,示例值及对应分析:对于退款,则通过退款记录里的 relate_type/relate_id 反向关联到原来的订单或支付。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.order_coupon_id IS '对应JSON字段:order_coupon_id,说明::订单级优惠券 ID。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_name IS '对应JSON字段:ledger_name,说明::销售项目名称(商品名称),例如 “哇哈哈矿泉水”“地道肠”“东方树叶”等。,示例值及对应分析:说明:业务展示用字段,历史流水即使商品改名,这里会保留当时的名字。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_group_name IS '对应JSON字段:ledger_group_name,说明::销售项目所属的「门店内部分组名称」,类似前台菜单分组或大类标签。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_amount IS '对应JSON字段:ledger_amount,说明::原始应收金额,公式上接近 ledger_unit_price × ledger_count。,示例值及对应分析:说明:这是未考虑优惠前的金额基础,用于后续计算折扣和抵扣。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_count IS '对应JSON字段:ledger_count,说明::销售数量(以 unit 为单位,unit 字段在门店商品档案中)。,示例值及对应分析:观测值:如 1, 2, 3, 6, 36 等。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_unit_price IS '对应JSON字段:ledger_unit_price,说明::商品在该次销售中的「结算单价」(元/单位)。,示例值及对应分析:观测值示例:5.0, 8.0, 2.0, 10.0, 72.0 等。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.ledger_status IS '对应JSON字段:ledger_status,说明::销售流水状态。,示例值及对应分析:1:正常有效。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.discount_money IS '对应JSON字段:discount_money,说明::本条销售明细的「价格优惠金额」,即原价部分被减免掉的金额。,示例值及对应分析:典型关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.coupon_deduct_money IS '对应JSON字段:coupon_deduct_money,说明::被优惠券 / 团购券直接抵扣到这条商品明细上的金额。,示例值及对应分析:说明:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.member_discount_amount IS '对应JSON字段:member_discount_amount,说明::由会员身份(会员折扣)针对这一行商品产生的优惠金额。,示例值及对应分析:说明:尽管字段存在,但当前实际折扣可能合并反映在 discount_money 中,这个字段没有拆开体现。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.option_coupon_deduct_money IS '对应JSON字段:option_coupon_deduct_money,说明::由优惠券抵扣“选项价格”的金额。,示例值及对应分析:上面这三个 option_* 字段,是为“主商品 + 选项”的更复杂计价方式预留的,本店当前所有记录都是单规格,选项体系未启用。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.option_member_discount_money IS '对应JSON字段:option_member_discount_money,说明::由会员折扣作用在“选项价格”上的优惠金额。,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.point_discount_money IS '对应JSON字段:point_discount_money,说明::由积分抵扣的金额(顾客兑换积分抵现金额)。,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.point_discount_money_cost IS '对应JSON字段:point_discount_money_cost,说明::积分抵扣对应的“成本金额”(后台核算用),例如按积分成本来计提费用。,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.real_goods_money IS '对应JSON字段:real_goods_money,说明::商品实际入账金额(考虑折扣、可能还会考虑其它抵扣后的实际销售金额)。,示例值及对应分析:观测值:5.0, 10.0, 8.0, 6.0, 4.0 等。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.cost_money IS '对应JSON字段:cost_money,说明::本条销售对应的成本金额(以元计)。,示例值及对应分析:观测示例:0.01, 0.00, 3.58, 1.79, 0.64 等。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.push_money IS '对应JSON字段:push_money,说明::本条销售对应的提成金额(给营业员/促销员的提成)。,示例值及对应分析:在启用营业员体系时,这里才会出现正数。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.sales_type IS '对应JSON字段:sales_type,说明::销售类型。,示例值及对应分析:1:正常销售;';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.is_single_order IS '对应JSON字段:is_single_order,说明::是否单独订单标识。,示例值及对应分析:1:作为独立明细参与某个订单结算;';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.is_delete IS '对应JSON字段:is_delete,说明::逻辑删除标志。,示例值及对应分析:0:正常有效;';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.goods_remark IS '对应JSON字段:goods_remark,说明::商品备注/口味说明/特殊说明。,示例值及对应分析:用途:点单时如果需要额外说明,可以写在这里。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.option_price IS '对应JSON字段:option_price,说明::商品选项(规格/加料)的附加价格。,示例值及对应分析:说明:如加冰、加料、升级大杯等产生附加费用时,理论上应该体现到这里。当前门店未使用此功能。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.option_value_name IS '对应JSON字段:option_value_name,说明::商品选项名称(如规格、口味:大杯/小杯,不加冰等)。,示例值及对应分析:结构用途:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.option_name IS '对应JSON字段:option_name,说明:?????? store_goods_sales_records-Analysis.md,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.member_coupon_id IS '对应JSON字段:member_coupon_id,说明::会员券 ID(比如会员专享优惠券)。,示例值及对应分析:当前数据未使用,属于为会员权益预留的字段。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.package_coupon_id IS '对应JSON字段:package_coupon_id,说明::套餐券 ID。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.sales_man_org_id IS '对应JSON字段:sales_man_org_id,说明::营业员所属组织/部门 ID。,示例值及对应分析:当前门店全部为 0,说明未启用这套销售员分组织的体系。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.salesman_name IS '对应JSON字段:salesman_name,说明::营业员姓名(如果有为具体销售员记业绩,则在此填姓名)。,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.salesman_role_id IS '对应JSON字段:salesman_role_id,说明::营业员的系统角色 ID(例如某个角色代码表示“销售员”)。,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.salesman_user_id IS '对应JSON字段:salesman_user_id,说明::营业员用户 ID(系统账号 ID)。,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.operator_id IS '对应JSON字段:operator_id,说明::操作员 ID(录入这笔销售的员工)。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.operator_name IS '对应JSON字段:operator_name,说明::操作员姓名,文字冗余。,示例值及对应分析:?? store_goods_sales_records-Analysis.md';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.openSalesman IS '对应JSON字段:openSalesman,说明:(结合系统其它文件推断):,示例值及对应分析:1:启用“营业员/销售员”机制(要指定 salesman);';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.site_table_id IS '对应JSON字段:site_table_id,说明::球台 ID。,示例值及对应分析:非 0:销售记录关联到具体某张桌台(例如顾客在台上点饮料)。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.tenant_goods_business_id IS '对应JSON字段:tenant_goods_business_id,说明::租户级商品「业务大类」ID(例如“零食类”“酒水类”等更高维度)。,示例值及对应分析:2.2 门店 / 球台维度字段';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.tenant_goods_category_id IS '对应JSON字段:tenant_goods_category_id,说明::租户级商品一级分类 ID。,示例值及对应分析:关系:';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.create_time IS '对应JSON字段:create_time,说明::销售记录创建时间,通常就是结账时间或录入时间。,示例值及对应分析:用途:用于按时间维度查询销售流水,与订单层的时间字段对齐。';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.payload IS '对应JSON字段:payload,说明:完整原始 JSON 内容,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.source_file IS '对应JSON字段:source_file,说明:原始文件名(含时间戳后缀),示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.source_endpoint IS '对应JSON字段:source_endpoint,说明:抓取来源接口/URL 标识,示例值及对应分析:???????';
+COMMENT ON COLUMN billiards_ods.store_goods_sales_records.fetched_at IS '对应JSON字段:fetched_at,说明:入库时间(ETL 拉取时间),示例值及对应分析:???????';
diff --git a/etl_billiards/database/schema_dwd_doc.sql b/etl_billiards/database/schema_dwd_doc.sql
index 90f4c82..b4d2d3d 100644
--- a/etl_billiards/database/schema_dwd_doc.sql
+++ b/etl_billiards/database/schema_dwd_doc.sql
@@ -2,22 +2,117 @@
CREATE SCHEMA IF NOT EXISTS billiards_dwd;
SET search_path TO billiards_dwd;
+-- SCD2 字段统一默认值、中文注释、唯一性(业务键 + 时间段不重叠)控制
+CREATE EXTENSION IF NOT EXISTS btree_gist;
+
+DO $$
+DECLARE
+ rec RECORD;
+BEGIN
+ -- 统一 SCD2 默认值与注释,避免后续手工遗漏
+ FOR rec IN
+ SELECT table_name
+ FROM information_schema.columns
+ WHERE table_schema = 'billiards_dwd'
+ AND column_name = 'scd2_start_time'
+ LOOP
+ EXECUTE format('ALTER TABLE billiards_dwd.%I ALTER COLUMN scd2_start_time SET DEFAULT now()', rec.table_name);
+ EXECUTE format('ALTER TABLE billiards_dwd.%I ALTER COLUMN scd2_end_time SET DEFAULT ''9999-12-31''', rec.table_name);
+ EXECUTE format('ALTER TABLE billiards_dwd.%I ALTER COLUMN scd2_is_current SET DEFAULT 1', rec.table_name);
+ EXECUTE format('ALTER TABLE billiards_dwd.%I ALTER COLUMN scd2_version SET DEFAULT 1', rec.table_name);
+
+ EXECUTE format('COMMENT ON COLUMN billiards_dwd.%I.scd2_start_time IS ''SCD2 开始时间(版本生效起点)''', rec.table_name);
+ EXECUTE format('COMMENT ON COLUMN billiards_dwd.%I.scd2_end_time IS ''SCD2 结束时间(默认 9999-12-31,表示当前版本仍有效)''', rec.table_name);
+ EXECUTE format('COMMENT ON COLUMN billiards_dwd.%I.scd2_is_current IS ''SCD2 当前版本标记:1=当前版本,0=历史版本''', rec.table_name);
+ EXECUTE format('COMMENT ON COLUMN billiards_dwd.%I.scd2_version IS ''SCD2 版本号,自增,配合时间段避免重叠''', rec.table_name);
+ END LOOP;
+
+ -- 约束:同一业务键时间段不重叠,且仅有一条当前版本
+ FOR rec IN (
+ SELECT tc.table_name,
+ string_agg(format('%I WITH =', kcu.column_name), ', ' ORDER BY kcu.ordinal_position) AS pk_eq_expr,
+ string_agg(format('%I', kcu.column_name), ', ' ORDER BY kcu.ordinal_position) AS pk_cols
+ FROM information_schema.table_constraints tc
+ JOIN information_schema.key_column_usage kcu
+ ON tc.table_schema = kcu.table_schema
+ AND tc.table_name = kcu.table_name
+ AND tc.constraint_name = kcu.constraint_name
+ WHERE tc.table_schema = 'billiards_dwd'
+ AND tc.constraint_type = 'PRIMARY KEY'
+ AND EXISTS (
+ SELECT 1 FROM information_schema.columns c
+ WHERE c.table_schema = 'billiards_dwd'
+ AND c.table_name = tc.table_name
+ AND c.column_name = 'scd2_start_time'
+ )
+ GROUP BY tc.table_name
+ )
+ LOOP
+ IF NOT EXISTS (
+ SELECT 1 FROM pg_constraint
+ WHERE conname = format('%s_scd2_no_overlap', rec.table_name)
+ AND conrelid = format('billiards_dwd.%s', rec.table_name)::regclass
+ ) THEN
+ EXECUTE format(
+ 'ALTER TABLE billiards_dwd.%I ADD CONSTRAINT %I EXCLUDE USING gist (%s, tstzrange(scd2_start_time, scd2_end_time) WITH &&) WHERE (scd2_is_current = 1);',
+ rec.table_name,
+ rec.table_name || '_scd2_no_overlap',
+ rec.pk_eq_expr
+ );
+ END IF;
+
+ IF to_regclass(format('billiards_dwd.%s_scd2_current_unique_idx', rec.table_name)) IS NULL THEN
+ EXECUTE format(
+ 'CREATE UNIQUE INDEX %I ON billiards_dwd.%I (%s) WHERE (scd2_is_current = 1);',
+ rec.table_name || '_scd2_current_unique_idx',
+ rec.table_name,
+ rec.pk_cols
+ );
+ END IF;
+ END LOOP;
+END
+$$;
+
+-- SCD2 统一约定(DIM 表使用):
+-- SCD2_start_time TIMESTAMPTZ DEFAULT now() -- 版本开始时间
+-- SCD2_end_time TIMESTAMPTZ DEFAULT '9999-12-31' -- 版本结束时间
+-- SCD2_is_current INT DEFAULT 1 -- 当前版本标记(1当前/0历史)
+-- SCD2_version INT DEFAULT 1 -- 版本号,自增
+
-- dim_site
CREATE TABLE IF NOT EXISTS dim_site (
site_id BIGINT,
org_id BIGINT,
- shop_name TEXT,
- business_tel TEXT,
- full_address TEXT,
tenant_id BIGINT,
+ shop_name TEXT,
+ site_label TEXT,
+ full_address TEXT,
+ address TEXT,
+ longitude NUMERIC(10,6),
+ latitude NUMERIC(10,6),
+ tenant_site_region_id BIGINT,
+ business_tel TEXT,
+ site_type INTEGER,
+ shop_status INTEGER,
+ SCD2_start_time TIMESTAMPTZ DEFAULT now(),
+ SCD2_end_time TIMESTAMPTZ DEFAULT '9999-12-31',
+ SCD2_is_current INT DEFAULT 1,
+ SCD2_version INT DEFAULT 1,
PRIMARY KEY (site_id)
);
-COMMENT ON COLUMN dim_site.site_id IS '门店主键 ID,唯一标识一家门店。与所有事实表中的 site_id 对应。 | 来源: siteProfile.id | 角色: 主键';
-COMMENT ON COLUMN dim_site.org_id IS '上级组织 ID,用于区域组织划分。 | 来源: siteProfile.org_id | 角色: 外键';
-COMMENT ON COLUMN dim_site.shop_name IS '门店名称,展示用。 | 来源: siteProfile.shop_name';
-COMMENT ON COLUMN dim_site.business_tel IS '门店电话。 | 来源: siteProfile.business_tel';
-COMMENT ON COLUMN dim_site.full_address IS '门店完整地址。 | 来源: siteProfile.full_address';
-COMMENT ON COLUMN dim_site.tenant_id IS '租户 ID。与其它表 tenant_id 对应。 | 来源: siteProfile.tenant_id | 角色: 外键';
+COMMENT ON COLUMN dim_site.site_id IS '???? ID?????????????????? site_id ??? | ??: siteProfile.id | ??: ??';
+COMMENT ON COLUMN dim_site.org_id IS '???? ID?????????? | ??: siteProfile.org_id | ??: ??';
+COMMENT ON COLUMN dim_site.tenant_id IS '?? ID????? tenant_id ??? | ??: siteProfile.tenant_id | ??: ??';
+COMMENT ON COLUMN dim_site.shop_name IS '????????? | ??: siteProfile.shop_name';
+COMMENT ON COLUMN dim_site.site_label IS '???????????????? | ??: siteProfile.site_label';
+COMMENT ON COLUMN dim_site.full_address IS '??????? | ??: siteProfile.full_address';
+COMMENT ON COLUMN dim_site.address IS '???????????? | ??: siteProfile.address';
+COMMENT ON COLUMN dim_site.longitude IS '???????? | ??: siteProfile.longitude';
+COMMENT ON COLUMN dim_site.latitude IS '???????? | ??: siteProfile.latitude';
+COMMENT ON COLUMN dim_site.tenant_site_region_id IS '????/?????????? | ??: siteProfile.tenant_site_region_id';
+COMMENT ON COLUMN dim_site.business_tel IS '????? | ??: siteProfile.business_tel';
+COMMENT ON COLUMN dim_site.site_type IS '??????????????????? | ??: siteProfile.site_type';
+COMMENT ON COLUMN dim_site.shop_status IS '??????????????????? | ??: siteProfile.shop_status';
-- dim_site_Ex
CREATE TABLE IF NOT EXISTS dim_site_Ex (
@@ -42,6 +137,10 @@ CREATE TABLE IF NOT EXISTS dim_site_Ex (
shop_status INTEGER,
create_time TIMESTAMPTZ,
update_time TIMESTAMPTZ,
+ SCD2_start_time TIMESTAMPTZ DEFAULT now(),
+ SCD2_end_time TIMESTAMPTZ DEFAULT '9999-12-31',
+ SCD2_is_current INT DEFAULT 1,
+ SCD2_version INT DEFAULT 1,
PRIMARY KEY (site_id)
);
COMMENT ON COLUMN dim_site_Ex.site_id IS '门店主键 ID,唯一标识一家门店。与所有事实表中的 site_id 对应。 | 来源: siteProfile.id | 角色: 主键';
@@ -69,17 +168,19 @@ COMMENT ON COLUMN dim_site_Ex.update_time IS '门店最近更新时间。 | 来
-- dim_table
CREATE TABLE IF NOT EXISTS dim_table (
table_id BIGINT,
- tenant_id BIGINT,
site_id BIGINT,
table_name TEXT,
site_table_area_id BIGINT,
site_table_area_name TEXT,
tenant_table_area_id BIGINT,
table_price NUMERIC(18,2),
+ SCD2_start_time TIMESTAMPTZ DEFAULT now(),
+ SCD2_end_time TIMESTAMPTZ DEFAULT '9999-12-31',
+ SCD2_is_current INT DEFAULT 1,
+ SCD2_version INT DEFAULT 1,
PRIMARY KEY (table_id)
);
COMMENT ON COLUMN dim_table.table_id IS '台桌主键,唯一标识一张台或包厢。 | 来源: id | 角色: 主键';
-COMMENT ON COLUMN dim_table.tenant_id IS '租户 ID。 | 来源: tenantId | 角色: 外键';
COMMENT ON COLUMN dim_table.site_id IS '门店 ID。 | 来源: siteId | 角色: 外键';
COMMENT ON COLUMN dim_table.table_name IS '台桌名称/编号,如 A17、888。 | 来源: tableName';
COMMENT ON COLUMN dim_table.site_table_area_id IS '门店区 ID,用于区分 A区/B区/补时区等。 | 来源: siteTableAreaId | 角色: 外键';
@@ -95,8 +196,10 @@ CREATE TABLE IF NOT EXISTS dim_table_Ex (
table_cloth_use_time INTEGER,
table_cloth_use_cycle INTEGER,
table_status INTEGER,
- last_maintenance_time TIMESTAMPTZ,
- remark TEXT,
+ SCD2_start_time TIMESTAMPTZ DEFAULT now(),
+ SCD2_end_time TIMESTAMPTZ DEFAULT '9999-12-31',
+ SCD2_is_current INT DEFAULT 1,
+ SCD2_version INT DEFAULT 1,
PRIMARY KEY (table_id)
);
COMMENT ON COLUMN dim_table_Ex.table_id IS '台桌主键,唯一标识一张台或包厢。 | 来源: id | 角色: 主键';
@@ -105,8 +208,6 @@ COMMENT ON COLUMN dim_table_Ex.is_online_reservation IS '是否可线上预约
COMMENT ON COLUMN dim_table_Ex.table_cloth_use_time IS '已使用台呢时长(秒)。 | 来源: tableClothUseTime';
COMMENT ON COLUMN dim_table_Ex.table_cloth_use_cycle IS '台呢更换周期阈值(秒)。 | 来源: tableClothUseCycle';
COMMENT ON COLUMN dim_table_Ex.table_status IS '当前台桌状态:1=空闲,2=使用中,3=暂停中,4=锁定。 | 来源: tableStatus';
-COMMENT ON COLUMN dim_table_Ex.last_maintenance_time IS '最近保养时间(未在 JSON 中出现)。 | 来源: lastMaintenanceTime';
-COMMENT ON COLUMN dim_table_Ex.remark IS '备注信息。 | 来源: remark';
-- dim_assistant
CREATE TABLE IF NOT EXISTS dim_assistant (
@@ -125,6 +226,10 @@ CREATE TABLE IF NOT EXISTS dim_assistant (
resign_time TIMESTAMPTZ,
leave_status INTEGER,
assistant_status INTEGER,
+ SCD2_start_time TIMESTAMPTZ,
+ SCD2_end_time TIMESTAMPTZ,
+ SCD2_is_current INT,
+ SCD2_version INT,
PRIMARY KEY (assistant_id)
);
COMMENT ON COLUMN dim_assistant.assistant_id IS '助教账号 ID,关联助教服务流水表。 | 来源: id | 角色: 主键';
@@ -189,6 +294,10 @@ CREATE TABLE IF NOT EXISTS dim_assistant_Ex (
light_status INTEGER,
is_team_leader INTEGER,
serial_number BIGINT,
+ SCD2_start_time TIMESTAMPTZ,
+ SCD2_end_time TIMESTAMPTZ,
+ SCD2_is_current INT,
+ SCD2_version INT,
PRIMARY KEY (assistant_id)
);
COMMENT ON COLUMN dim_assistant_Ex.assistant_id IS '助教账号 ID,关联助教服务流水表。 | 来源: id | 角色: 主键';
@@ -248,6 +357,10 @@ CREATE TABLE IF NOT EXISTS dim_member (
member_card_grade_name TEXT,
create_time TIMESTAMPTZ,
update_time TIMESTAMPTZ,
+ SCD2_start_time TIMESTAMPTZ,
+ SCD2_end_time TIMESTAMPTZ,
+ SCD2_is_current INT,
+ SCD2_version INT,
PRIMARY KEY (member_id)
);
COMMENT ON COLUMN dim_member.member_id IS '租户内会员主键。 | 来源: id | 角色: 主键';
@@ -259,7 +372,6 @@ COMMENT ON COLUMN dim_member.nickname IS '昵称(未必是真实姓名)。 |
COMMENT ON COLUMN dim_member.member_card_grade_code IS '会员等级代码:1=金卡?2=银卡?3=钻石卡?4=黑卡?(按照 MD 文档枚举)。 | 来源: member_card_grade_code';
COMMENT ON COLUMN dim_member.member_card_grade_name IS '等级名称,中文描述。 | 来源: member_card_grade_name';
COMMENT ON COLUMN dim_member.create_time IS '会员档案创建时间。 | 来源: create_time';
-COMMENT ON COLUMN dim_member.update_time IS '最近更新时间。 | 来源: update_time';
-- dim_member_Ex
CREATE TABLE IF NOT EXISTS dim_member_Ex (
@@ -270,6 +382,10 @@ CREATE TABLE IF NOT EXISTS dim_member_Ex (
growth_value NUMERIC(18,2),
user_status INTEGER,
status INTEGER,
+ SCD2_start_time TIMESTAMPTZ,
+ SCD2_end_time TIMESTAMPTZ,
+ SCD2_is_current INT,
+ SCD2_version INT,
PRIMARY KEY (member_id)
);
COMMENT ON COLUMN dim_member_Ex.member_id IS '租户内会员主键。 | 来源: id | 角色: 主键';
@@ -299,6 +415,10 @@ CREATE TABLE IF NOT EXISTS dim_member_card_account (
last_consume_time TIMESTAMPTZ,
status INTEGER,
is_delete INTEGER,
+ SCD2_start_time TIMESTAMPTZ,
+ SCD2_end_time TIMESTAMPTZ,
+ SCD2_is_current INT,
+ SCD2_version INT,
PRIMARY KEY (member_card_id)
);
COMMENT ON COLUMN dim_member_card_account.member_card_id IS '会员卡账户主键,唯一标识一张具体卡。 | 来源: id | 角色: 主键';
@@ -373,6 +493,10 @@ CREATE TABLE IF NOT EXISTS dim_member_card_account_Ex (
goodsCategoryId TEXT,
pdAssisnatLevel TEXT,
cxAssisnatLevel TEXT,
+ SCD2_start_time TIMESTAMPTZ,
+ SCD2_end_time TIMESTAMPTZ,
+ SCD2_is_current INT,
+ SCD2_version INT,
PRIMARY KEY (member_card_id)
);
COMMENT ON COLUMN dim_member_card_account_Ex.member_card_id IS '会员卡账户主键,唯一标识一张具体卡。 | 来源: id | 角色: 主键';
@@ -444,6 +568,10 @@ CREATE TABLE IF NOT EXISTS dim_tenant_goods (
create_time TIMESTAMPTZ,
update_time TIMESTAMPTZ,
is_delete INTEGER,
+ SCD2_start_time TIMESTAMPTZ,
+ SCD2_end_time TIMESTAMPTZ,
+ SCD2_is_current INT,
+ SCD2_version INT,
PRIMARY KEY (tenant_goods_id)
);
COMMENT ON COLUMN dim_tenant_goods.tenant_goods_id IS '租户级商品档案主键 ID,唯一标识一条商品档案。所有业务事实表(销售、库存等)中引用租户级商品时应指向此字段。 | 来源: id | 角色: 主键';
@@ -481,6 +609,10 @@ CREATE TABLE IF NOT EXISTS dim_tenant_goods_Ex (
common_sale_royalty INTEGER,
point_sale_royalty INTEGER,
out_goods_id BIGINT,
+ SCD2_start_time TIMESTAMPTZ,
+ SCD2_end_time TIMESTAMPTZ,
+ SCD2_is_current INT,
+ SCD2_version INT,
PRIMARY KEY (tenant_goods_id)
);
COMMENT ON COLUMN dim_tenant_goods_Ex.tenant_goods_id IS '租户级商品档案主键 ID,唯一标识一条商品档案。所有业务事实表(销售、库存等)中引用租户级商品时应指向此字段。 | 来源: id | 角色: 主键';
@@ -524,6 +656,10 @@ CREATE TABLE IF NOT EXISTS dim_store_goods (
enable_status INTEGER,
send_state INTEGER,
is_delete INTEGER,
+ SCD2_start_time TIMESTAMPTZ,
+ SCD2_end_time TIMESTAMPTZ,
+ SCD2_is_current INT,
+ SCD2_version INT,
PRIMARY KEY (site_goods_id)
);
COMMENT ON COLUMN dim_store_goods.site_goods_id IS '门店级商品 ID,本表主键;其它业务表中的 site_goods_id 与此对应,用于库存、销售等关联。 | 来源: id | 角色: 主键';
@@ -575,6 +711,10 @@ CREATE TABLE IF NOT EXISTS dim_store_goods_Ex (
option_required INTEGER,
remark TEXT,
sort_order INTEGER,
+ SCD2_start_time TIMESTAMPTZ,
+ SCD2_end_time TIMESTAMPTZ,
+ SCD2_is_current INT,
+ SCD2_version INT,
PRIMARY KEY (site_goods_id)
);
COMMENT ON COLUMN dim_store_goods_Ex.site_goods_id IS '门店级商品 ID,本表主键;其它业务表中的 site_goods_id 与此对应,用于库存、销售等关联。 | 来源: id | 角色: 主键';
@@ -618,6 +758,10 @@ CREATE TABLE IF NOT EXISTS dim_goods_category (
open_salesman INTEGER,
sort_order INTEGER,
is_warehousing INTEGER,
+ SCD2_start_time TIMESTAMPTZ,
+ SCD2_end_time TIMESTAMPTZ,
+ SCD2_is_current INT,
+ SCD2_version INT,
PRIMARY KEY (category_id)
);
COMMENT ON COLUMN dim_goods_category.category_id IS '分类节点主键。来自分类树节点的 id,在整个商品分类维度内唯一。用于在事实表中作为商品分类外键引用。 | 来源: id | 角色: 主键';
@@ -651,6 +795,10 @@ CREATE TABLE IF NOT EXISTS dim_groupbuy_package (
create_time TIMESTAMPTZ,
tenant_table_area_id_list VARCHAR(512),
card_type_ids VARCHAR(255),
+ SCD2_start_time TIMESTAMPTZ,
+ SCD2_end_time TIMESTAMPTZ,
+ SCD2_is_current INT,
+ SCD2_version INT,
PRIMARY KEY (groupbuy_package_id)
);
COMMENT ON COLUMN dim_groupbuy_package.groupbuy_package_id IS '门店侧团购套餐主键。每条记录一个套餐定义,供团购券核销记录指向。平台验券记录中的 group_package_id 通常指向这里。 | 来源: id | 角色: 主键';
@@ -692,6 +840,10 @@ CREATE TABLE IF NOT EXISTS dim_groupbuy_package_Ex (
effective_status INTEGER,
max_selectable_categories INTEGER,
creator_name VARCHAR(100),
+ SCD2_start_time TIMESTAMPTZ,
+ SCD2_end_time TIMESTAMPTZ,
+ SCD2_is_current INT,
+ SCD2_version INT,
PRIMARY KEY (groupbuy_package_id)
);
COMMENT ON COLUMN dim_groupbuy_package_Ex.groupbuy_package_id IS '门店侧团购套餐主键。每条记录一个套餐定义,供团购券核销记录指向。平台验券记录中的 group_package_id 通常指向这里。 | 来源: id | 角色: 主键';
diff --git a/etl_billiards/database/schema_etl_admin.sql b/etl_billiards/database/schema_etl_admin.sql
new file mode 100644
index 0000000..de98d86
--- /dev/null
+++ b/etl_billiards/database/schema_etl_admin.sql
@@ -0,0 +1,105 @@
+-- 文件说明:etl_admin 调度元数据 DDL(独立文件,便于初始化任务单独执行)。
+-- 包含任务注册表、游标表、运行记录表;字段注释使用中文。
+
+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)
+);
+COMMENT ON TABLE etl_admin.etl_task IS '任务注册表:调度依据的任务清单(与 task_registry 中的任务码对应)。';
+COMMENT ON COLUMN etl_admin.etl_task.task_code IS '任务编码,需与代码中的任务码一致。';
+COMMENT ON COLUMN etl_admin.etl_task.store_id IS '门店/租户粒度,区分多门店执行。';
+COMMENT ON COLUMN etl_admin.etl_task.enabled IS '是否启用此任务。';
+COMMENT ON COLUMN etl_admin.etl_task.cursor_field IS '增量游标字段名(可选)。';
+COMMENT ON COLUMN etl_admin.etl_task.window_minutes_default IS '默认时间窗口(分钟)。';
+COMMENT ON COLUMN etl_admin.etl_task.overlap_seconds IS '窗口重叠秒数,用于防止遗漏。';
+COMMENT ON COLUMN etl_admin.etl_task.page_size IS '默认分页大小。';
+COMMENT ON COLUMN etl_admin.etl_task.retry_max IS 'API重试次数上限。';
+COMMENT ON COLUMN etl_admin.etl_task.params IS '任务级自定义参数 JSON。';
+COMMENT ON COLUMN etl_admin.etl_task.created_at IS '创建时间。';
+COMMENT ON COLUMN etl_admin.etl_task.updated_at IS '更新时间。';
+
+CREATE TABLE IF NOT EXISTS etl_admin.etl_cursor (
+ cursor_id BIGSERIAL PRIMARY KEY,
+ task_id BIGINT NOT NULL REFERENCES etl_admin.etl_task(task_id) ON DELETE CASCADE,
+ store_id BIGINT NOT NULL,
+ last_start TIMESTAMPTZ,
+ last_end TIMESTAMPTZ,
+ last_id BIGINT,
+ last_run_id BIGINT,
+ extra JSONB DEFAULT '{}'::jsonb,
+ created_at TIMESTAMPTZ DEFAULT now(),
+ updated_at TIMESTAMPTZ DEFAULT now(),
+ UNIQUE (task_id, store_id)
+);
+COMMENT ON TABLE etl_admin.etl_cursor IS '任务游标表:记录每个任务/门店的增量窗口及最后 run。';
+COMMENT ON COLUMN etl_admin.etl_cursor.task_id IS '关联 etl_task.task_id。';
+COMMENT ON COLUMN etl_admin.etl_cursor.store_id IS '门店/租户粒度。';
+COMMENT ON COLUMN etl_admin.etl_cursor.last_start IS '上次窗口开始时间(含重叠偏移)。';
+COMMENT ON COLUMN etl_admin.etl_cursor.last_end IS '上次窗口结束时间。';
+COMMENT ON COLUMN etl_admin.etl_cursor.last_id IS '上次处理的最大主键/游标值(可选)。';
+COMMENT ON COLUMN etl_admin.etl_cursor.last_run_id IS '上次运行ID,对应 etl_run.run_id。';
+COMMENT ON COLUMN etl_admin.etl_cursor.extra IS '附加游标信息 JSON。';
+COMMENT ON COLUMN etl_admin.etl_cursor.created_at IS '创建时间。';
+COMMENT ON COLUMN etl_admin.etl_cursor.updated_at IS '更新时间。';
+
+CREATE TABLE IF NOT EXISTS etl_admin.etl_run (
+ run_id BIGSERIAL PRIMARY KEY,
+ run_uuid 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
+);
+COMMENT ON TABLE etl_admin.etl_run IS '运行记录表:记录每次任务执行的窗口、状态、计数与日志路径。';
+COMMENT ON COLUMN etl_admin.etl_run.run_uuid IS '本次调度的唯一标识。';
+COMMENT ON COLUMN etl_admin.etl_run.task_id IS '关联 etl_task.task_id。';
+COMMENT ON COLUMN etl_admin.etl_run.store_id IS '门店/租户粒度。';
+COMMENT ON COLUMN etl_admin.etl_run.status IS '运行状态(SUCC/FAIL/PARTIAL 等)。';
+COMMENT ON COLUMN etl_admin.etl_run.started_at IS '开始时间。';
+COMMENT ON COLUMN etl_admin.etl_run.ended_at IS '结束时间。';
+COMMENT ON COLUMN etl_admin.etl_run.window_start IS '本次窗口开始时间。';
+COMMENT ON COLUMN etl_admin.etl_run.window_end IS '本次窗口结束时间。';
+COMMENT ON COLUMN etl_admin.etl_run.window_minutes IS '窗口跨度(分钟)。';
+COMMENT ON COLUMN etl_admin.etl_run.overlap_seconds IS '窗口重叠秒数。';
+COMMENT ON COLUMN etl_admin.etl_run.fetched_count IS '抓取/读取的记录数。';
+COMMENT ON COLUMN etl_admin.etl_run.loaded_count IS '插入的记录数。';
+COMMENT ON COLUMN etl_admin.etl_run.updated_count IS '更新的记录数。';
+COMMENT ON COLUMN etl_admin.etl_run.skipped_count IS '跳过的记录数。';
+COMMENT ON COLUMN etl_admin.etl_run.error_count IS '错误记录数。';
+COMMENT ON COLUMN etl_admin.etl_run.unknown_fields IS '未知字段计数(清洗阶段)。';
+COMMENT ON COLUMN etl_admin.etl_run.export_dir IS '抓取/导出目录。';
+COMMENT ON COLUMN etl_admin.etl_run.log_path IS '日志路径。';
+COMMENT ON COLUMN etl_admin.etl_run.request_params IS '请求参数 JSON。';
+COMMENT ON COLUMN etl_admin.etl_run.manifest IS '运行产出清单/统计 JSON。';
+COMMENT ON COLUMN etl_admin.etl_run.error_message IS '错误信息(若失败)。';
+COMMENT ON COLUMN etl_admin.etl_run.extra IS '附加字段,保留扩展。';
diff --git a/etl_billiards/database/schema_v2.sql b/etl_billiards/database/schema_v2.sql
deleted file mode 100644
index 392a9bd..0000000
--- a/etl_billiards/database/schema_v2.sql
+++ /dev/null
@@ -1,1128 +0,0 @@
--- 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.ods_member_profile (
- 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)
-);
-
-CREATE TABLE IF NOT EXISTS billiards_ods.ods_member_card (
- 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)
-);
-
-CREATE TABLE IF NOT EXISTS billiards_ods.ods_balance_change (
- 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)
-);
-
-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)
-);
-
-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)
-);
-
-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)
-);
-
-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)
-);
-
-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)
-);
-
-CREATE TABLE IF NOT EXISTS billiards_ods.ods_table_use_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)
-);
-
-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)
-);
-
-CREATE TABLE IF NOT EXISTS billiards_ods.ods_assistant_account (
- 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)
-);
-
-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)
-);
-
-CREATE TABLE IF NOT EXISTS billiards_ods.ods_group_package (
- 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)
-);
-
-CREATE TABLE IF NOT EXISTS billiards_ods.ods_group_package_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)
-);
-
-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)
-);
-
-CREATE TABLE IF NOT EXISTS billiards_ods.ods_inventory_change (
- 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)
-);
-
-CREATE TABLE IF NOT EXISTS billiards_ods.ods_order_settle (
- 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)
-);
-
-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)
-);
-
-CREATE TABLE IF NOT EXISTS billiards_ods.ods_payment_record (
- 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)
-);
-
-CREATE TABLE IF NOT EXISTS billiards_ods.ods_refund_record (
- 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)
-);
-
-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)
-);
-
--- ---------- 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),
- ('ODS_ORDER_SETTLE', 2790685415443269, TRUE),
- ('ODS_TABLE_USE', 2790685415443269, TRUE),
- ('ODS_ASSISTANT_LEDGER', 2790685415443269, TRUE),
- ('ODS_ASSISTANT_ABOLISH', 2790685415443269, TRUE),
- ('ODS_GOODS_LEDGER', 2790685415443269, TRUE),
- ('ODS_PAYMENT', 2790685415443269, TRUE),
- ('ODS_REFUND', 2790685415443269, TRUE),
- ('ODS_COUPON_VERIFY', 2790685415443269, TRUE),
- ('ODS_MEMBER', 2790685415443269, TRUE),
- ('ODS_MEMBER_CARD', 2790685415443269, TRUE),
- ('ODS_PACKAGE', 2790685415443269, TRUE),
- ('ODS_INVENTORY_STOCK', 2790685415443269, TRUE),
- ('ODS_INVENTORY_CHANGE', 2790685415443269, TRUE)
-ON CONFLICT (task_code, store_id) DO NOTHING;
diff --git a/etl_billiards/database/seed_ods_tasks.sql b/etl_billiards/database/seed_ods_tasks.sql
index 04de63f..c40bcbf 100644
--- a/etl_billiards/database/seed_ods_tasks.sql
+++ b/etl_billiards/database/seed_ods_tasks.sql
@@ -1,34 +1,35 @@
--- 将新的 ODS 任务注册到 etl_admin.etl_task(根据需要替换 store_id)
--- 使用方式(示例):
+-- 灏嗘柊鐨?ODS 浠诲姟娉ㄥ唽鍒?etl_admin.etl_task锛堟牴鎹渶瑕佹浛鎹?store_id锛?
+-- 浣跨敤鏂瑰紡锛堢ず渚嬶級锛?
-- psql "$PG_DSN" -f etl_billiards/database/seed_ods_tasks.sql
--- 或者在 psql 中执行本文件内容。
+-- 鎴栬€呭湪 psql 涓墽琛屾湰鏂囦欢鍐呭銆?
WITH target_store AS (
- SELECT 2790685415443269::bigint AS store_id -- TODO: 替换为实际 store_id
+ SELECT 2790685415443269::bigint AS store_id -- TODO: 鏇挎崲涓哄疄闄?store_id
),
task_codes AS (
SELECT unnest(ARRAY[
- 'ODS_ASSISTANT_ACCOUNTS',
- 'ODS_ASSISTANT_LEDGER',
- 'ODS_ASSISTANT_ABOLISH',
- 'ODS_INVENTORY_CHANGE',
+ 'assistant_accounts_masterS',
+ 'assistant_service_records',
+ 'assistant_cancellation_records',
+ 'goods_stock_movements',
'ODS_INVENTORY_STOCK',
'ODS_PACKAGE',
'ODS_GROUP_BUY_REDEMPTION',
'ODS_MEMBER',
'ODS_MEMBER_BALANCE',
- 'ODS_MEMBER_CARD',
+ 'member_stored_value_cards',
'ODS_PAYMENT',
'ODS_REFUND',
- 'ODS_COUPON_VERIFY',
- 'ODS_RECHARGE_SETTLE',
+ 'platform_coupon_redemption_records',
+ 'recharge_settlements',
'ODS_TABLES',
'ODS_GOODS_CATEGORY',
'ODS_STORE_GOODS',
- 'ODS_TABLE_DISCOUNT',
+ 'table_fee_discount_records',
'ODS_TENANT_GOODS',
'ODS_SETTLEMENT_TICKET',
- 'ODS_ORDER_SETTLE'
+ 'settlement_records',
+ 'INIT_ODS_SCHEMA'
]) AS task_code
)
INSERT INTO etl_admin.etl_task (task_code, store_id, enabled)
@@ -37,3 +38,4 @@ FROM task_codes t CROSS JOIN target_store s
ON CONFLICT (task_code, store_id) DO UPDATE
SET enabled = EXCLUDED.enabled;
+
diff --git a/etl_billiards/docs/dwd_quality_check.md b/etl_billiards/docs/dwd_quality_check.md
new file mode 100644
index 0000000..3ed8406
--- /dev/null
+++ b/etl_billiards/docs/dwd_quality_check.md
@@ -0,0 +1,9 @@
+# DWD 璐ㄩ噺鏍¢獙鎸囧紩
+璇存槑锛氱敤浜?ODS 鈫?DWD 钀藉湴鍚庣殑琛屾暟/閲戦鏍稿涓庢娊鏍峰洖鏌ャ€?
+## 琛屾暟瀵规瘮锛堢ず渚嬶級
+- 鏉ユ簮锛歚etl_billiards/ods_row_report.json` 璁板綍浜嗙ず渚?JSON 涓?ODS 琛屾暟锛屽彲浣滀负 DWD 瀵规瘮鍩虹嚎銆?- 鎵ц锛氬湪 DWD 璺戝畬鍚庯紝缁熻鍏抽敭琛ㄨ鏁帮紝涓?ODS 姹囨€绘垨 JSON 鍩虹嚎瀵归綈锛涘紓甯告椂杈撳嚭宸紓銆?
+## 閲戦/鎸囨爣鏍稿寤鸿
+- dwd_settlement_head / dwd_settlement_head_Ex锛氳仛鍚堣鍗曟€婚銆侀€€娆鹃锛屼笌 ODS settleList 閲戦鏍稿銆?- dwd_store_goods_sale锛氭寜鍟嗗搧姹囨€婚攢鍞/鏁伴噺锛屼笌 ODS store_goods_sales_records 鑱氬悎瀵规瘮銆?- dwd_member_balance_change锛氭寜浼氬憳姹囨€诲彉鍔ㄩ锛屼笌 ODS 鍚岃〃鑱氬悎瀵规瘮銆?- dwd_recharge_order / dwd_payment / dwd_refund锛氭寜鏀粯鏂瑰紡銆佹椂闂存鑱氬悎閲戦锛屾牳瀵瑰樊寮傘€?
+## 鎶芥牱鍥炴煡
+- 闅忔満鍙栬嫢骞?DWD 璁板綍锛屽洖鏌?ODS payload锛堥€氳繃涓婚敭鍦?ODS 琛ㄦ煡璇級纭瀛楁鏄犲皠姝g‘銆?- 瀵?SCD2 缁村害锛圖IM 琛級锛氭牎楠屽悓涓氬姟閿粎涓€鏉?is_current=1锛屾椂闂存涓嶉噸鍙狅紝鐗堟湰鍙烽€掑銆?
+## 鑷姩鍖栨牎楠岃剼鏈缓璁?- 缁熻鑴氭湰锛氳緭鍑?DWD 鍏抽敭琛ㄨ鏁?閲戦鍒?JSON锛屾柟渚夸笌鍩虹嚎瀵规瘮銆?- 寮傚父鍛婅锛氬彂鐜拌鏁板亸宸垨閲戦鍋忓樊瓒呰繃闃堝€兼椂鎵撳嵃璇︽儏锛堜富閿垪琛ㄣ€佽仛鍚堟槑缁嗭級銆?
diff --git a/etl_billiards/docs/ods_sample_json.md b/etl_billiards/docs/ods_sample_json.md
new file mode 100644
index 0000000..003c32d
--- /dev/null
+++ b/etl_billiards/docs/ods_sample_json.md
@@ -0,0 +1,28 @@
+# ODS 示例 JSON 对照表
+示例文件名与正式文件名的前缀一致(正式文件会附加 `_YYYYMMDDHHMMSS` 时间戳),表名与文件前缀保持一致,便于业务对照。示例目录默认:`C:\dev\LLTQ\export\test-json-doc`。
+
+| JSON 文件名(前缀) | ODS 表名 | 主键字段 | 备注 |
+| --- | --- | --- | --- |
+| assistant_accounts_master.json | assistant_accounts_master | id | 店员主数据 |
+| assistant_cancellation_records.json | assistant_cancellation_records | id | 店员作废事件 |
+| assistant_service_records.json | assistant_service_records | id | 店员服务流水 |
+| goods_stock_movements.json | goods_stock_movements | id | 进销存出入库 |
+| goods_stock_summary.json | goods_stock_summary | id | 库存汇总 |
+| group_buy_packages.json | group_buy_packages | id | 团购套餐定义 |
+| group_buy_redemption_records.json | group_buy_redemption_records | id | 团购核销/消耗 |
+| member_balance_changes.json | member_balance_changes | id | 储值余额变动 |
+| member_profiles.json | member_profiles | id | 会员档案 |
+| member_stored_value_cards.json | member_stored_value_cards | id | 储值卡账户 |
+| payment_transactions.json | payment_transactions | id | 支付流水 |
+| platform_coupon_redemption_records.json | platform_coupon_redemption_records | id | 平台券核销 |
+| recharge_settlements.json | recharge_settlements | id | 储值充值结算 |
+| refund_transactions.json | refund_transactions | id | 退款流水 |
+| settlement_records.json | settlement_records | id | 订单结算头 |
+| settlement_ticket_details.json | settlement_ticket_details | id | 小票/明细表 |
+| site_tables_master.json | site_tables_master | id | 台桌主数据 |
+| stock_goods_category_tree.json | stock_goods_category_tree | id | 商品类目树 |
+| store_goods_master.json | store_goods_master | id | 门店商品档案 |
+| store_goods_sales_records.json | store_goods_sales_records | id | 门店商品销售明细 |
+| table_fee_discount_records.json | table_fee_discount_records | id | 台桌减免/调价 |
+| table_fee_transactions.json | table_fee_transactions | id | 台桌计费流水 |
+| tenant_goods_master.json | tenant_goods_master | id | 品牌/租户级商品档案 |
diff --git a/etl_billiards/docs/ods_to_dwd_mapping.md b/etl_billiards/docs/ods_to_dwd_mapping.md
new file mode 100644
index 0000000..88616cd
--- /dev/null
+++ b/etl_billiards/docs/ods_to_dwd_mapping.md
@@ -0,0 +1,252 @@
+# ODS → DWD 映射文档(重建版)
+本文件基于最新 DWD 质检结果重构,列出 DWD 表的 ODS 来源与字段映射状态。DIM 表默认使用 SCD2(SCD2_start_time / SCD2_end_time / SCD2_is_current / SCD2_version)。
+
+## 表级映射概览
+| DWD 表 | 主键/提示 | 对应 ODS 表 | SCD2 |
+| --- | --- | --- | --- |
+| billiards_dwd.dim_site | 见 schema_dwd_doc.sql | billiards_ods.site_tables_master | 是 |
+| billiards_dwd.dim_site_ex | 见 schema_dwd_doc.sql | billiards_ods.site_tables_master | 是 |
+| billiards_dwd.dim_table | 见 schema_dwd_doc.sql | billiards_ods.site_tables_master | 是 |
+| billiards_dwd.dim_table_ex | 见 schema_dwd_doc.sql | billiards_ods.site_tables_master | 是 |
+| billiards_dwd.dim_assistant | 见 schema_dwd_doc.sql | billiards_ods.assistant_accounts_master | 是 |
+| billiards_dwd.dim_assistant_ex | 见 schema_dwd_doc.sql | billiards_ods.assistant_accounts_master | 是 |
+| billiards_dwd.dim_member | 见 schema_dwd_doc.sql | billiards_ods.member_profiles | 是 |
+| billiards_dwd.dim_member_ex | 见 schema_dwd_doc.sql | billiards_ods.member_profiles | 是 |
+| billiards_dwd.dim_member_card_account | 见 schema_dwd_doc.sql | billiards_ods.member_stored_value_cards | 是 |
+| billiards_dwd.dim_member_card_account_ex | 见 schema_dwd_doc.sql | billiards_ods.member_stored_value_cards | 是 |
+| billiards_dwd.dim_tenant_goods | 见 schema_dwd_doc.sql | billiards_ods.tenant_goods_master | 是 |
+| billiards_dwd.dim_tenant_goods_ex | 见 schema_dwd_doc.sql | billiards_ods.tenant_goods_master | 是 |
+| billiards_dwd.dim_store_goods | 见 schema_dwd_doc.sql | billiards_ods.store_goods_master | 是 |
+| billiards_dwd.dim_store_goods_ex | 见 schema_dwd_doc.sql | billiards_ods.store_goods_master | 是 |
+| billiards_dwd.dim_goods_category | 见 schema_dwd_doc.sql | billiards_ods.stock_goods_category_tree | 是 |
+| billiards_dwd.dim_groupbuy_package | 见 schema_dwd_doc.sql | billiards_ods.group_buy_packages | 是 |
+| billiards_dwd.dim_groupbuy_package_ex | 见 schema_dwd_doc.sql | billiards_ods.group_buy_packages | 是 |
+| billiards_dwd.dwd_settlement_head | 见 schema_dwd_doc.sql | billiards_ods.settlement_records | 否 |
+| billiards_dwd.dwd_settlement_head_ex | 见 schema_dwd_doc.sql | billiards_ods.settlement_records | 否 |
+| billiards_dwd.dwd_table_fee_log | 见 schema_dwd_doc.sql | billiards_ods.table_fee_transactions | 否 |
+| billiards_dwd.dwd_table_fee_log_ex | 见 schema_dwd_doc.sql | billiards_ods.table_fee_transactions | 否 |
+| billiards_dwd.dwd_table_fee_adjust | 见 schema_dwd_doc.sql | billiards_ods.table_fee_discount_records | 否 |
+| billiards_dwd.dwd_table_fee_adjust_ex | 见 schema_dwd_doc.sql | billiards_ods.table_fee_discount_records | 否 |
+| billiards_dwd.dwd_store_goods_sale | 见 schema_dwd_doc.sql | billiards_ods.store_goods_sales_records | 否 |
+| billiards_dwd.dwd_store_goods_sale_ex | 见 schema_dwd_doc.sql | billiards_ods.store_goods_sales_records | 否 |
+| billiards_dwd.dwd_assistant_service_log | 见 schema_dwd_doc.sql | billiards_ods.assistant_service_records | 否 |
+| billiards_dwd.dwd_assistant_service_log_ex | 见 schema_dwd_doc.sql | billiards_ods.assistant_service_records | 否 |
+| billiards_dwd.dwd_assistant_trash_event | 见 schema_dwd_doc.sql | billiards_ods.assistant_cancellation_records | 否 |
+| billiards_dwd.dwd_assistant_trash_event_ex | 见 schema_dwd_doc.sql | billiards_ods.assistant_cancellation_records | 否 |
+| billiards_dwd.dwd_member_balance_change | 见 schema_dwd_doc.sql | billiards_ods.member_balance_changes | 否 |
+| billiards_dwd.dwd_member_balance_change_ex | 见 schema_dwd_doc.sql | billiards_ods.member_balance_changes | 否 |
+| billiards_dwd.dwd_groupbuy_redemption | 见 schema_dwd_doc.sql | billiards_ods.group_buy_redemption_records | 否 |
+| billiards_dwd.dwd_groupbuy_redemption_ex | 见 schema_dwd_doc.sql | billiards_ods.group_buy_redemption_records | 否 |
+| billiards_dwd.dwd_platform_coupon_redemption | 见 schema_dwd_doc.sql | billiards_ods.platform_coupon_redemption_records | 否 |
+| billiards_dwd.dwd_platform_coupon_redemption_ex | 见 schema_dwd_doc.sql | billiards_ods.platform_coupon_redemption_records | 否 |
+| billiards_dwd.dwd_recharge_order | 见 schema_dwd_doc.sql | billiards_ods.recharge_settlements | 否 |
+| billiards_dwd.dwd_recharge_order_ex | 见 schema_dwd_doc.sql | billiards_ods.recharge_settlements | 否 |
+| billiards_dwd.dwd_payment | 见 schema_dwd_doc.sql | billiards_ods.payment_transactions | 否 |
+| billiards_dwd.dwd_refund | 见 schema_dwd_doc.sql | billiards_ods.refund_transactions | 否 |
+| billiards_dwd.dwd_refund_ex | 见 schema_dwd_doc.sql | billiards_ods.refund_transactions | 否 |
+
+## 字段级映射(同名直拷 / 需映射)
+同名直拷:DWD 字段与 ODS 同名,直接复制;需映射:ODS 无同名列,需要在装载逻辑中指定来源或默认值。
+
+
+## åæ®µçº§æ å°ï¼ååç´æ· / éæ å°ï¼
+ååç´æ·ï¼DWD åæ®µä¸ ODS ååï¼ç´æ¥å¤å¶ï¼éæ å°ï¼ODS æ åååï¼éè¦å¨è£
è½½é»è¾ä¸æå®æ¥æºæé»è®¤å¼ã
+### billiards_dwd.dim_site
+来源:billiards_ods.site_tables_master
+**同名直拷字段:** site_id
+**需映射/派生字段:** org_id, shop_name, business_tel, full_address, tenant_id, scd2_start_time, scd2_end_time, scd2_is_current, scd2_version
+
+### billiards_dwd.dim_site_ex
+来源:billiards_ods.site_tables_master
+**同名直拷字段:** site_id, light_status, create_time
+**需映射/派生字段:** avatar, address, longitude, latitude, tenant_site_region_id, auto_light, light_type, light_token, site_type, site_label, attendance_enabled, attendance_distance, customer_service_qrcode, customer_service_wechat, fixed_pay_qrcode, prod_env, shop_status, update_time, scd2_start_time, scd2_end_time, scd2_is_current, scd2_version
+
+### billiards_dwd.dim_table
+来源:billiards_ods.site_tables_master
+**同名直拷字段:** site_id, table_name, site_table_area_id, table_price
+**需映射/派生字段:** table_id, tenant_id, site_table_area_name, tenant_table_area_id, scd2_start_time, scd2_end_time, scd2_is_current, scd2_version
+
+### billiards_dwd.dim_table_ex
+来源:billiards_ods.site_tables_master
+**同名直拷字段:** show_status, is_online_reservation, table_cloth_use_time, table_cloth_use_cycle, table_status
+**需映射/派生字段:** table_id, last_maintenance_time, remark, scd2_start_time, scd2_end_time, scd2_is_current, scd2_version
+
+### billiards_dwd.dim_assistant
+来源:billiards_ods.assistant_accounts_master
+**同名直拷字段:** assistant_no, real_name, nickname, mobile, tenant_id, site_id, team_id, team_name, level, entry_time, resign_time, leave_status, assistant_status
+**需映射/派生字段:** assistant_id, user_id, scd2_start_time, scd2_end_time, scd2_is_current, scd2_version
+
+### billiards_dwd.dim_assistant_ex
+来源:billiards_ods.assistant_accounts_master
+**同名直拷字段:** gender, avatar, video_introduction_url, staff_id, staff_profile_id, sum_grade, get_grade_times, work_status, show_status, show_sort, create_time, update_time, start_time, end_time, order_trade_no
+**需映射/派生字段:** assistant_id, birth_date, introduce, height, weight, shop_name, group_id, group_name, person_org_id, assistant_grade, charge_way, allow_cx, is_guaranteed, salary_grant_enabled, entry_type, entry_sign_status, resign_sign_status, online_status, is_delete, criticism_status, last_table_id, last_table_name, last_update_name, ding_talk_synced, site_light_cfg_id, light_equipment_id, light_status, is_team_leader, serial_number, scd2_start_time, scd2_end_time, scd2_is_current, scd2_version
+
+### billiards_dwd.dim_member
+来源:billiards_ods.member_profiles
+**同名直拷字段:** system_member_id, tenant_id, register_site_id, mobile, nickname, member_card_grade_code, member_card_grade_name, create_time
+**需映射/派生字段:** member_id, update_time, scd2_start_time, scd2_end_time, scd2_is_current, scd2_version
+
+### billiards_dwd.dim_member_ex
+来源:billiards_ods.member_profiles
+**同名直拷字段:** referrer_member_id, point, growth_value, user_status, status
+**需映射/派生字段:** member_id, register_site_name, scd2_start_time, scd2_end_time, scd2_is_current, scd2_version
+
+### billiards_dwd.dim_member_card_account
+来源:billiards_ods.member_stored_value_cards
+**同名直拷字段:** tenant_id, register_site_id, tenant_member_id, system_member_id, card_type_id, member_card_grade_code, member_card_grade_code_name, member_card_type_name, member_name, member_mobile, balance, start_time, end_time, last_consume_time, status, is_delete
+**需映射/派生字段:** member_card_id, scd2_start_time, scd2_end_time, scd2_is_current, scd2_version
+
+### billiards_dwd.dim_member_card_account_ex
+来源:billiards_ods.member_stored_value_cards
+**同名直拷字段:** site_name, tenantavatar, effect_site_id, able_cross_site, card_physics_type, card_no, bind_password, use_scene, denomination, create_time, disable_start_time, disable_end_time, is_allow_give, is_allow_order_deduct, sort, table_discount, goods_discount, assistant_discount, assistant_reward_discount, table_service_discount, goods_service_discount, assistant_service_discount, coupon_discount, table_discount_sub_switch, goods_discount_sub_switch, assistant_discount_sub_switch, assistant_reward_discount_sub_switch, goods_discount_range_type, table_deduct_radio, goods_deduct_radio, assistant_deduct_radio, table_service_deduct_radio, goods_service_deduct_radio, assistant_service_deduct_radio, assistant_reward_deduct_radio, coupon_deduct_radio, cardsettlededuct, tablecarddeduct, tableservicecarddeduct, goodscardeduct, goodsservicecarddeduct, assistantcarddeduct, assistantservicecarddeduct, assistantrewardcarddeduct, couponcarddeduct, deliveryfeededuct, tableareaid, goodscategoryid, pdassisnatlevel, cxassisnatlevel
+**需映射/派生字段:** member_card_id, tenant_name, scd2_start_time, scd2_end_time, scd2_is_current, scd2_version
+
+### billiards_dwd.dim_tenant_goods
+来源:billiards_ods.tenant_goods_master
+**同名直拷字段:** tenant_id, supplier_id, goods_category_id, goods_second_category_id, goods_name, goods_number, unit, market_price, goods_state, create_time, update_time, is_delete
+**需映射/派生字段:** tenant_goods_id, category_name, scd2_start_time, scd2_end_time, scd2_is_current, scd2_version
+
+### billiards_dwd.dim_tenant_goods_ex
+来源:billiards_ods.tenant_goods_master
+**同名直拷字段:** remark_name, pinyin_initial, goods_cover, goods_bar_code, commodity_code, min_discount_price, cost_price, cost_price_type, able_discount, sale_channel, is_warehousing, able_site_transfer, common_sale_royalty, point_sale_royalty
+**需映射/派生字段:** tenant_goods_id, commodity_code_list, is_in_site, out_goods_id, scd2_start_time, scd2_end_time, scd2_is_current, scd2_version
+
+### billiards_dwd.dim_store_goods
+来源:billiards_ods.store_goods_master
+**同名直拷字段:** tenant_id, site_id, tenant_goods_id, goods_name, goods_category_id, goods_second_category_id, sale_price, goods_state, enable_status, send_state, is_delete
+**需映射/派生字段:** site_goods_id, category_level1_name, category_level2_name, batch_stock_qty, sale_qty, total_sales_qty, created_at, updated_at, avg_monthly_sales, scd2_start_time, scd2_end_time, scd2_is_current, scd2_version
+
+### billiards_dwd.dim_store_goods_ex
+来源:billiards_ods.store_goods_master
+**同名直拷字段:** unit, pinyin_initial, cost_price, cost_price_type, total_purchase_cost, min_discount_price, audit_status, sale_channel, is_warehousing, forbid_sell_status, able_site_transfer, custom_label_type, option_required, remark
+**需映射/派生字段:** site_goods_id, site_name, goods_barcode, goods_cover_url, stock_qty, stock_secondary_qty, safety_stock_qty, provisional_total_cost, is_discountable, days_on_shelf, freeze_status, sort_order, scd2_start_time, scd2_end_time, scd2_is_current, scd2_version
+
+### billiards_dwd.dim_goods_category
+来源:billiards_ods.stock_goods_category_tree
+**同名直拷字段:** tenant_id, category_name, alias_name, business_name, tenant_goods_business_id, open_salesman, is_warehousing
+**需映射/派生字段:** category_id, parent_category_id, category_level, is_leaf, sort_order, scd2_start_time, scd2_end_time, scd2_is_current, scd2_version
+
+### billiards_dwd.dim_groupbuy_package
+来源:billiards_ods.group_buy_packages
+**同名直拷字段:** tenant_id, site_id, package_name, selling_price, start_time, end_time, table_area_name, is_enabled, is_delete, create_time, tenant_table_area_id_list, card_type_ids
+**需映射/派生字段:** groupbuy_package_id, package_template_id, coupon_face_value, duration_seconds, scd2_start_time, scd2_end_time, scd2_is_current, scd2_version
+
+### billiards_dwd.dim_groupbuy_package_ex
+来源:billiards_ods.group_buy_packages
+**同名直拷字段:** site_name, usable_count, date_type, usable_range, date_info, start_clock, end_clock, add_start_clock, add_end_clock, area_tag_type, table_area_id, tenant_table_area_id, table_area_id_list, group_type, system_group_type, effective_status, max_selectable_categories, creator_name
+**需映射/派生字段:** groupbuy_package_id, package_type, scd2_start_time, scd2_end_time, scd2_is_current, scd2_version
+
+### billiards_dwd.dwd_settlement_head
+来源:billiards_ods.settlement_records
+**同名直拷字段:** 无
+**需映射/派生字段:** order_settle_id, tenant_id, site_id, site_name, table_id, settle_name, order_trade_no, create_time, pay_time, settle_type, revoke_order_id, member_id, member_name, member_phone, member_card_account_id, member_card_type_name, is_bind_member, member_discount_amount, consume_money, table_charge_money, goods_money, real_goods_money, assistant_pd_money, assistant_cx_money, adjust_amount, pay_amount, balance_amount, recharge_card_amount, gift_card_amount, coupon_amount, rounding_amount, point_amount
+
+### billiards_dwd.dwd_settlement_head_ex
+来源:billiards_ods.settlement_records
+**同名直拷字段:** 无
+**需映射/派生字段:** order_settle_id, serial_number, settle_status, can_be_revoked, revoke_order_name, revoke_time, is_first_order, service_money, cash_amount, card_amount, online_amount, refund_amount, prepay_money, payment_method, coupon_sale_amount, all_coupon_discount, goods_promotion_money, assistant_promotion_money, activity_discount, assistant_manual_discount, point_discount_price, point_discount_cost, is_use_coupon, is_use_discount, is_activity, operator_name, salesman_name, order_remark, operator_id, salesman_user_id
+
+### billiards_dwd.dwd_table_fee_log
+来源:billiards_ods.table_fee_transactions
+**同名直拷字段:** order_trade_no, order_settle_id, order_pay_id, tenant_id, site_id, site_table_id, site_table_area_id, site_table_area_name, tenant_table_area_id, member_id, ledger_name, ledger_unit_price, ledger_count, ledger_amount, real_table_charge_money, coupon_promotion_amount, member_discount_amount, adjust_amount, real_table_use_seconds, add_clock_seconds, start_use_time, ledger_end_time, create_time, ledger_status, is_single_order, is_delete
+**需映射/派生字段:** table_fee_log_id
+
+### billiards_dwd.dwd_table_fee_log_ex
+来源:billiards_ods.table_fee_transactions
+**同名直拷字段:** operator_name, salesman_name, used_card_amount, service_money, mgmt_fee, fee_total, ledger_start_time, last_use_time, operator_id, salesman_user_id, salesman_org_id
+**需映射/派生字段:** table_fee_log_id
+
+### billiards_dwd.dwd_table_fee_adjust
+来源:billiards_ods.table_fee_discount_records
+**同名直拷字段:** order_trade_no, order_settle_id, tenant_id, site_id, tenant_table_area_id, ledger_amount, ledger_status, is_delete
+**需映射/派生字段:** table_fee_adjust_id, table_id, table_area_id, table_area_name, adjust_time
+
+### billiards_dwd.dwd_table_fee_adjust_ex
+来源:billiards_ods.table_fee_discount_records
+**同名直拷字段:** adjust_type, ledger_count, ledger_name, applicant_name, operator_name, applicant_id, operator_id
+**需映射/派生字段:** table_fee_adjust_id
+
+### billiards_dwd.dwd_store_goods_sale
+来源:billiards_ods.store_goods_sales_records
+**同名直拷字段:** order_trade_no, order_settle_id, order_pay_id, order_goods_id, site_id, tenant_id, site_goods_id, tenant_goods_id, tenant_goods_category_id, tenant_goods_business_id, site_table_id, ledger_name, ledger_group_name, ledger_unit_price, ledger_count, ledger_amount, real_goods_money, cost_money, ledger_status, is_delete, create_time
+**需映射/派生字段:** store_goods_sale_id, discount_price
+
+### billiards_dwd.dwd_store_goods_sale_ex
+来源:billiards_ods.store_goods_sales_records
+**同名直拷字段:** goods_remark, option_value_name, operator_name, salesman_user_id, salesman_name, salesman_role_id, discount_money, coupon_deduct_money, member_discount_amount, point_discount_money, point_discount_money_cost, package_coupon_id, order_coupon_id, member_coupon_id, option_price, option_member_discount_money, option_coupon_deduct_money, push_money, is_single_order, sales_type, operator_id
+**需映射/派生字段:** store_goods_sale_id, legacy_order_goods_id, site_name, legacy_site_id, open_salesman_flag, salesman_org_id, returns_number
+
+### billiards_dwd.dwd_assistant_service_log
+来源:billiards_ods.assistant_service_records
+**同名直拷字段:** order_trade_no, order_settle_id, order_pay_id, order_assistant_id, order_assistant_type, tenant_id, site_id, site_table_id, nickname, assistant_team_id, person_org_id, assistant_level, ledger_unit_price, ledger_amount, projected_income, coupon_deduct_money, income_seconds, real_use_seconds, add_clock, create_time, start_use_time, last_use_time, is_delete
+**需映射/派生字段:** assistant_service_id, tenant_member_id, system_member_id, assistant_no, site_assistant_id, user_id, level_name, skill_id, skill_name
+
+### billiards_dwd.dwd_assistant_service_log_ex
+来源:billiards_ods.assistant_service_records
+**同名直拷字段:** ledger_name, ledger_group_name, ledger_count, member_discount_amount, manual_discount_amount, service_money, returns_clock, ledger_start_time, ledger_end_time, ledger_status, is_confirm, is_single_order, is_not_responding, is_trash, trash_applicant_id, trash_applicant_name, trash_reason, salesman_user_id, salesman_name, salesman_org_id, skill_grade, service_grade, composite_grade, sum_grade, get_grade_times, grade_status, composite_grade_time
+**需映射/派生字段:** assistant_service_id, table_name, assistant_name
+
+### billiards_dwd.dwd_assistant_trash_event
+来源:billiards_ods.assistant_cancellation_records
+**同名直拷字段:** 无
+**需映射/派生字段:** assistant_trash_event_id, site_id, table_id, table_area_id, assistant_no, assistant_name, charge_minutes_raw, abolish_amount, trash_reason, create_time
+
+### billiards_dwd.dwd_assistant_trash_event_ex
+来源:billiards_ods.assistant_cancellation_records
+**同名直拷字段:** 无
+**需映射/派生字段:** assistant_trash_event_id, table_name, table_area_name
+
+### billiards_dwd.dwd_member_balance_change
+来源:billiards_ods.member_balance_changes
+**同名直拷字段:** tenant_id, site_id, register_site_id, tenant_member_id, system_member_id, tenant_member_card_id, card_type_id, from_type, payment_method, is_delete, remark
+**需映射/派生字段:** balance_change_id, card_type_name, member_name, member_mobile, balance_before, change_amount, balance_after, change_time
+
+### billiards_dwd.dwd_member_balance_change_ex
+来源:billiards_ods.member_balance_changes
+**同名直拷字段:** refund_amount, operator_id, operator_name
+**需映射/派生字段:** balance_change_id, pay_site_name, register_site_name
+
+### billiards_dwd.dwd_groupbuy_redemption
+来源:billiards_ods.group_buy_redemption_records
+**同名直拷字段:** tenant_id, site_id, table_id, tenant_table_area_id, table_charge_seconds, order_trade_no, order_settle_id, order_coupon_id, coupon_origin_id, promotion_activity_id, promotion_coupon_id, order_coupon_channel, ledger_unit_price, ledger_count, ledger_amount, coupon_money, promotion_seconds, coupon_code, is_single_order, is_delete, ledger_name, create_time
+**需映射/派生字段:** redemption_id
+
+### billiards_dwd.dwd_groupbuy_redemption_ex
+来源:billiards_ods.group_buy_redemption_records
+**同名直拷字段:** order_pay_id, goods_promotion_money, table_service_promotion_money, assistant_promotion_money, assistant_service_promotion_money, reward_promotion_money, recharge_promotion_money, offer_type, ledger_status, operator_id, operator_name, salesman_user_id, salesman_name, salesman_role_id, ledger_group_name
+**需映射/派生字段:** redemption_id, site_name, table_name, table_area_name, goods_option_price, salesman_org_id
+
+### billiards_dwd.dwd_platform_coupon_redemption
+来源:billiards_ods.platform_coupon_redemption_records
+**同名直拷字段:** tenant_id, site_id, coupon_code, coupon_channel, coupon_name, sale_price, coupon_money, coupon_free_time, channel_deal_id, deal_id, group_package_id, site_order_id, table_id, certificate_id, verify_id, use_status, is_delete, create_time, consume_time
+**需映射/派生字段:** platform_coupon_redemption_id
+
+### billiards_dwd.dwd_platform_coupon_redemption_ex
+来源:billiards_ods.platform_coupon_redemption_records
+**同名直拷字段:** coupon_cover, coupon_remark, groupon_type, operator_id, operator_name
+**需映射/派生字段:** platform_coupon_redemption_id
+
+### billiards_dwd.dwd_recharge_order
+来源:billiards_ods.recharge_settlements
+**同名直拷字段:** 无
+**需映射/派生字段:** recharge_order_id, tenant_id, site_id, member_id, member_name_snapshot, member_phone_snapshot, tenant_member_card_id, member_card_type_name, settle_relate_id, settle_type, settle_name, is_first, pay_amount, refund_amount, point_amount, cash_amount, payment_method, create_time, pay_time
+
+### billiards_dwd.dwd_recharge_order_ex
+来源:billiards_ods.recharge_settlements
+**同名直拷字段:** 无
+**需映射/派生字段:** recharge_order_id, site_name_snapshot, settle_status, is_bind_member, is_activity, is_use_coupon, is_use_discount, can_be_revoked, online_amount, balance_amount, card_amount, coupon_amount, recharge_card_amount, gift_card_amount, prepay_money, consume_money, goods_money, real_goods_money, table_charge_money, service_money, activity_discount, all_coupon_discount, goods_promotion_money, assistant_promotion_money, assistant_pd_money, assistant_cx_money, assistant_manual_discount, coupon_sale_amount, member_discount_amount, point_discount_price, point_discount_cost, adjust_amount, rounding_amount, operator_id, operator_name_snapshot, salesman_user_id, salesman_name, order_remark, table_id, serial_number, revoke_order_id, revoke_order_name, revoke_time
+
+### billiards_dwd.dwd_payment
+来源:billiards_ods.payment_transactions
+**同名直拷字段:** site_id, relate_type, relate_id, pay_amount, pay_status, payment_method, online_pay_channel, create_time, pay_time
+**需映射/派生字段:** payment_id, pay_date
+
+### billiards_dwd.dwd_refund
+来源:billiards_ods.refund_transactions
+**同名直拷字段:** tenant_id, site_id, relate_type, relate_id, pay_amount, channel_fee, pay_time, create_time, payment_method, member_id, member_card_id
+**需映射/派生字段:** refund_id
+
+### billiards_dwd.dwd_refund_ex
+来源:billiards_ods.refund_transactions
+**同名直拷字段:** pay_sn, refund_amount, round_amount, balance_frozen_amount, card_frozen_amount, pay_status, action_type, is_revoke, is_delete, check_status, online_pay_channel, online_pay_type, pay_terminal, pay_config_id, cashier_point_id, operator_id, channel_payer_id, channel_pay_no
+**需映射/派生字段:** refund_id, tenant_name
diff --git a/etl_billiards/etl_billiards/reports/dwd_quality_report.json b/etl_billiards/etl_billiards/reports/dwd_quality_report.json
new file mode 100644
index 0000000..0a73396
--- /dev/null
+++ b/etl_billiards/etl_billiards/reports/dwd_quality_report.json
@@ -0,0 +1,692 @@
+{
+ "generated_at": "2025-12-09T01:38:19.992961",
+ "tables": [
+ {
+ "dwd_table": "billiards_dwd.dim_site",
+ "ods_table": "billiards_ods.table_fee_transactions",
+ "count": {
+ "dwd": 1,
+ "ods": 200,
+ "diff": -199
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_site_ex",
+ "ods_table": "billiards_ods.table_fee_transactions",
+ "count": {
+ "dwd": 1,
+ "ods": 200,
+ "diff": -199
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_table",
+ "ods_table": "billiards_ods.site_tables_master",
+ "count": {
+ "dwd": 71,
+ "ods": 71,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_table_ex",
+ "ods_table": "billiards_ods.site_tables_master",
+ "count": {
+ "dwd": 71,
+ "ods": 71,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_assistant",
+ "ods_table": "billiards_ods.assistant_accounts_master",
+ "count": {
+ "dwd": 50,
+ "ods": 50,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_assistant_ex",
+ "ods_table": "billiards_ods.assistant_accounts_master",
+ "count": {
+ "dwd": 50,
+ "ods": 50,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_member",
+ "ods_table": "billiards_ods.member_profiles",
+ "count": {
+ "dwd": 199,
+ "ods": 199,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_member_ex",
+ "ods_table": "billiards_ods.member_profiles",
+ "count": {
+ "dwd": 199,
+ "ods": 199,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_member_card_account",
+ "ods_table": "billiards_ods.member_stored_value_cards",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "balance",
+ "dwd_sum": 31061.03,
+ "ods_sum": 31061.03,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_member_card_account_ex",
+ "ods_table": "billiards_ods.member_stored_value_cards",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "deliveryfeededuct",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_tenant_goods",
+ "ods_table": "billiards_ods.tenant_goods_master",
+ "count": {
+ "dwd": 156,
+ "ods": 156,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_tenant_goods_ex",
+ "ods_table": "billiards_ods.tenant_goods_master",
+ "count": {
+ "dwd": 156,
+ "ods": 156,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_store_goods",
+ "ods_table": "billiards_ods.store_goods_master",
+ "count": {
+ "dwd": 161,
+ "ods": 161,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_store_goods_ex",
+ "ods_table": "billiards_ods.store_goods_master",
+ "count": {
+ "dwd": 161,
+ "ods": 161,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_goods_category",
+ "ods_table": "billiards_ods.stock_goods_category_tree",
+ "count": {
+ "dwd": 9,
+ "ods": 9,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_groupbuy_package",
+ "ods_table": "billiards_ods.group_buy_packages",
+ "count": {
+ "dwd": 17,
+ "ods": 17,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_groupbuy_package_ex",
+ "ods_table": "billiards_ods.group_buy_packages",
+ "count": {
+ "dwd": 17,
+ "ods": 17,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_settlement_head",
+ "ods_table": "billiards_ods.settlement_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_settlement_head_ex",
+ "ods_table": "billiards_ods.settlement_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_table_fee_log",
+ "ods_table": "billiards_ods.table_fee_transactions",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "adjust_amount",
+ "dwd_sum": 1157.45,
+ "ods_sum": 1157.45,
+ "diff": 0.0
+ },
+ {
+ "column": "coupon_promotion_amount",
+ "dwd_sum": 11244.49,
+ "ods_sum": 11244.49,
+ "diff": 0.0
+ },
+ {
+ "column": "ledger_amount",
+ "dwd_sum": 18107.0,
+ "ods_sum": 18107.0,
+ "diff": 0.0
+ },
+ {
+ "column": "member_discount_amount",
+ "dwd_sum": 1149.19,
+ "ods_sum": 1149.19,
+ "diff": 0.0
+ },
+ {
+ "column": "real_table_charge_money",
+ "dwd_sum": 5705.06,
+ "ods_sum": 5705.06,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_table_fee_log_ex",
+ "ods_table": "billiards_ods.table_fee_transactions",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "fee_total",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "mgmt_fee",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "service_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "used_card_amount",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_table_fee_adjust",
+ "ods_table": "billiards_ods.table_fee_discount_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "ledger_amount",
+ "dwd_sum": 20650.84,
+ "ods_sum": 20650.84,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_table_fee_adjust_ex",
+ "ods_table": "billiards_ods.table_fee_discount_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_store_goods_sale",
+ "ods_table": "billiards_ods.store_goods_sales_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "cost_money",
+ "dwd_sum": 22.3,
+ "ods_sum": 22.3,
+ "diff": 0.0
+ },
+ {
+ "column": "ledger_amount",
+ "dwd_sum": 4583.0,
+ "ods_sum": 4583.0,
+ "diff": 0.0
+ },
+ {
+ "column": "real_goods_money",
+ "dwd_sum": 3791.0,
+ "ods_sum": 3791.0,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_store_goods_sale_ex",
+ "ods_table": "billiards_ods.store_goods_sales_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "coupon_deduct_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "discount_money",
+ "dwd_sum": 792.0,
+ "ods_sum": 792.0,
+ "diff": 0.0
+ },
+ {
+ "column": "member_discount_amount",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "option_coupon_deduct_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "option_member_discount_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "point_discount_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "point_discount_money_cost",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "push_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_assistant_service_log",
+ "ods_table": "billiards_ods.assistant_service_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "coupon_deduct_money",
+ "dwd_sum": 626.83,
+ "ods_sum": 626.83,
+ "diff": 0.0
+ },
+ {
+ "column": "ledger_amount",
+ "dwd_sum": 63251.37,
+ "ods_sum": 63251.37,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_assistant_service_log_ex",
+ "ods_table": "billiards_ods.assistant_service_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "manual_discount_amount",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "member_discount_amount",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "service_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_assistant_trash_event",
+ "ods_table": "billiards_ods.assistant_cancellation_records",
+ "count": {
+ "dwd": 15,
+ "ods": 15,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_assistant_trash_event_ex",
+ "ods_table": "billiards_ods.assistant_cancellation_records",
+ "count": {
+ "dwd": 15,
+ "ods": 15,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_member_balance_change",
+ "ods_table": "billiards_ods.member_balance_changes",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_member_balance_change_ex",
+ "ods_table": "billiards_ods.member_balance_changes",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "refund_amount",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_groupbuy_redemption",
+ "ods_table": "billiards_ods.group_buy_redemption_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "coupon_money",
+ "dwd_sum": 12266.0,
+ "ods_sum": 12266.0,
+ "diff": 0.0
+ },
+ {
+ "column": "ledger_amount",
+ "dwd_sum": 12049.53,
+ "ods_sum": 12049.53,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_groupbuy_redemption_ex",
+ "ods_table": "billiards_ods.group_buy_redemption_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "assistant_promotion_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "assistant_service_promotion_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "goods_promotion_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "recharge_promotion_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "reward_promotion_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "table_service_promotion_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_platform_coupon_redemption",
+ "ods_table": "billiards_ods.platform_coupon_redemption_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "coupon_money",
+ "dwd_sum": 11956.0,
+ "ods_sum": 11956.0,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_platform_coupon_redemption_ex",
+ "ods_table": "billiards_ods.platform_coupon_redemption_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_recharge_order",
+ "ods_table": "billiards_ods.recharge_settlements",
+ "count": {
+ "dwd": 74,
+ "ods": 74,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_recharge_order_ex",
+ "ods_table": "billiards_ods.recharge_settlements",
+ "count": {
+ "dwd": 74,
+ "ods": 74,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_payment",
+ "ods_table": "billiards_ods.payment_transactions",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "pay_amount",
+ "dwd_sum": 10863.0,
+ "ods_sum": 10863.0,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_refund",
+ "ods_table": "billiards_ods.refund_transactions",
+ "count": {
+ "dwd": 11,
+ "ods": 11,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "channel_fee",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "pay_amount",
+ "dwd_sum": -62186.0,
+ "ods_sum": -62186.0,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_refund_ex",
+ "ods_table": "billiards_ods.refund_transactions",
+ "count": {
+ "dwd": 11,
+ "ods": 11,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "balance_frozen_amount",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "card_frozen_amount",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "refund_amount",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "round_amount",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ }
+ ]
+ }
+ ],
+ "note": "行数/金额核对,金额字段基于列名包含 amount/money/fee/balance 的数值列自动扫描。"
+}
\ No newline at end of file
diff --git a/etl_billiards/ods_row_report.json b/etl_billiards/ods_row_report.json
new file mode 100644
index 0000000..7ce930c
--- /dev/null
+++ b/etl_billiards/ods_row_report.json
@@ -0,0 +1,52 @@
+{
+ "source_counts": {
+ "assistant_accounts_master.json": 2,
+ "assistant_cancellation_records.json": 2,
+ "assistant_service_records.json": 2,
+ "goods_stock_movements.json": 2,
+ "goods_stock_summary.json": 161,
+ "group_buy_packages.json": 2,
+ "group_buy_redemption_records.json": 2,
+ "member_balance_changes.json": 2,
+ "member_profiles.json": 2,
+ "member_stored_value_cards.json": 2,
+ "payment_transactions.json": 200,
+ "platform_coupon_redemption_records.json": 200,
+ "recharge_settlements.json": 2,
+ "refund_transactions.json": 11,
+ "settlement_records.json": 2,
+ "settlement_ticket_details.json": 193,
+ "site_tables_master.json": 2,
+ "stock_goods_category_tree.json": 2,
+ "store_goods_master.json": 2,
+ "store_goods_sales_records.json": 2,
+ "table_fee_discount_records.json": 2,
+ "table_fee_transactions.json": 2,
+ "tenant_goods_master.json": 2
+ },
+ "ods_counts": {
+ "member_profiles": 199,
+ "member_balance_changes": 200,
+ "member_stored_value_cards": 200,
+ "recharge_settlements": 75,
+ "settlement_records": 200,
+ "assistant_cancellation_records": 15,
+ "assistant_accounts_master": 50,
+ "assistant_service_records": 200,
+ "site_tables_master": 71,
+ "table_fee_discount_records": 200,
+ "table_fee_transactions": 200,
+ "goods_stock_movements": 200,
+ "stock_goods_category_tree": 9,
+ "goods_stock_summary": 161,
+ "payment_transactions": 200,
+ "refund_transactions": 11,
+ "platform_coupon_redemption_records": 200,
+ "tenant_goods_master": 156,
+ "group_buy_packages": 17,
+ "group_buy_redemption_records": 200,
+ "settlement_ticket_details": 193,
+ "store_goods_master": 161,
+ "store_goods_sales_records": 200
+ }
+}
\ No newline at end of file
diff --git a/etl_billiards/orchestration/task_registry.py b/etl_billiards/orchestration/task_registry.py
index 5668174..3882b67 100644
--- a/etl_billiards/orchestration/task_registry.py
+++ b/etl_billiards/orchestration/task_registry.py
@@ -15,10 +15,14 @@ from tasks.table_discount_task import TableDiscountTask
from tasks.assistant_abolish_task import AssistantAbolishTask
from tasks.ledger_task import LedgerTask
from tasks.ods_tasks import ODS_TASK_CLASSES
-from tasks.ticket_dwd_task import TicketDwdTask
from tasks.manual_ingest_task import ManualIngestTask
from tasks.payments_dwd_task import PaymentsDwdTask
from tasks.members_dwd_task import MembersDwdTask
+from tasks.init_schema_task import InitOdsSchemaTask
+from tasks.init_dwd_schema_task import InitDwdSchemaTask
+from tasks.dwd_load_task import DwdLoadTask
+from tasks.ticket_dwd_task import TicketDwdTask
+from tasks.dwd_quality_task import DwdQualityTask
class TaskRegistry:
"""任务注册和工厂"""
@@ -64,5 +68,9 @@ default_registry.register("TICKET_DWD", TicketDwdTask)
default_registry.register("MANUAL_INGEST", ManualIngestTask)
default_registry.register("PAYMENTS_DWD", PaymentsDwdTask)
default_registry.register("MEMBERS_DWD", MembersDwdTask)
+default_registry.register("INIT_ODS_SCHEMA", InitOdsSchemaTask)
+default_registry.register("INIT_DWD_SCHEMA", InitDwdSchemaTask)
+default_registry.register("DWD_LOAD_FROM_ODS", DwdLoadTask)
+default_registry.register("DWD_QUALITY_CHECK", DwdQualityTask)
for code, task_cls in ODS_TASK_CLASSES.items():
default_registry.register(code, task_cls)
diff --git a/etl_billiards/reports/dwd_quality_report.json b/etl_billiards/reports/dwd_quality_report.json
new file mode 100644
index 0000000..6ab50be
--- /dev/null
+++ b/etl_billiards/reports/dwd_quality_report.json
@@ -0,0 +1,692 @@
+{
+ "generated_at": "2025-12-09T03:43:54.887796",
+ "tables": [
+ {
+ "dwd_table": "billiards_dwd.dim_site",
+ "ods_table": "billiards_ods.table_fee_transactions",
+ "count": {
+ "dwd": 1,
+ "ods": 200,
+ "diff": -199
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_site_ex",
+ "ods_table": "billiards_ods.table_fee_transactions",
+ "count": {
+ "dwd": 1,
+ "ods": 200,
+ "diff": -199
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_table",
+ "ods_table": "billiards_ods.site_tables_master",
+ "count": {
+ "dwd": 71,
+ "ods": 71,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_table_ex",
+ "ods_table": "billiards_ods.site_tables_master",
+ "count": {
+ "dwd": 71,
+ "ods": 71,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_assistant",
+ "ods_table": "billiards_ods.assistant_accounts_master",
+ "count": {
+ "dwd": 50,
+ "ods": 50,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_assistant_ex",
+ "ods_table": "billiards_ods.assistant_accounts_master",
+ "count": {
+ "dwd": 50,
+ "ods": 50,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_member",
+ "ods_table": "billiards_ods.member_profiles",
+ "count": {
+ "dwd": 199,
+ "ods": 199,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_member_ex",
+ "ods_table": "billiards_ods.member_profiles",
+ "count": {
+ "dwd": 199,
+ "ods": 199,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_member_card_account",
+ "ods_table": "billiards_ods.member_stored_value_cards",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "balance",
+ "dwd_sum": 31061.03,
+ "ods_sum": 31061.03,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_member_card_account_ex",
+ "ods_table": "billiards_ods.member_stored_value_cards",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "deliveryfeededuct",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_tenant_goods",
+ "ods_table": "billiards_ods.tenant_goods_master",
+ "count": {
+ "dwd": 156,
+ "ods": 156,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_tenant_goods_ex",
+ "ods_table": "billiards_ods.tenant_goods_master",
+ "count": {
+ "dwd": 156,
+ "ods": 156,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_store_goods",
+ "ods_table": "billiards_ods.store_goods_master",
+ "count": {
+ "dwd": 161,
+ "ods": 161,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_store_goods_ex",
+ "ods_table": "billiards_ods.store_goods_master",
+ "count": {
+ "dwd": 161,
+ "ods": 161,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_goods_category",
+ "ods_table": "billiards_ods.stock_goods_category_tree",
+ "count": {
+ "dwd": 9,
+ "ods": 9,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_groupbuy_package",
+ "ods_table": "billiards_ods.group_buy_packages",
+ "count": {
+ "dwd": 17,
+ "ods": 17,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dim_groupbuy_package_ex",
+ "ods_table": "billiards_ods.group_buy_packages",
+ "count": {
+ "dwd": 17,
+ "ods": 17,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_settlement_head",
+ "ods_table": "billiards_ods.settlement_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_settlement_head_ex",
+ "ods_table": "billiards_ods.settlement_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_table_fee_log",
+ "ods_table": "billiards_ods.table_fee_transactions",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "adjust_amount",
+ "dwd_sum": 1157.45,
+ "ods_sum": 1157.45,
+ "diff": 0.0
+ },
+ {
+ "column": "coupon_promotion_amount",
+ "dwd_sum": 11244.49,
+ "ods_sum": 11244.49,
+ "diff": 0.0
+ },
+ {
+ "column": "ledger_amount",
+ "dwd_sum": 18107.0,
+ "ods_sum": 18107.0,
+ "diff": 0.0
+ },
+ {
+ "column": "member_discount_amount",
+ "dwd_sum": 1149.19,
+ "ods_sum": 1149.19,
+ "diff": 0.0
+ },
+ {
+ "column": "real_table_charge_money",
+ "dwd_sum": 5705.06,
+ "ods_sum": 5705.06,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_table_fee_log_ex",
+ "ods_table": "billiards_ods.table_fee_transactions",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "fee_total",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "mgmt_fee",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "service_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "used_card_amount",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_table_fee_adjust",
+ "ods_table": "billiards_ods.table_fee_discount_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "ledger_amount",
+ "dwd_sum": 20650.84,
+ "ods_sum": 20650.84,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_table_fee_adjust_ex",
+ "ods_table": "billiards_ods.table_fee_discount_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_store_goods_sale",
+ "ods_table": "billiards_ods.store_goods_sales_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "cost_money",
+ "dwd_sum": 22.3,
+ "ods_sum": 22.3,
+ "diff": 0.0
+ },
+ {
+ "column": "ledger_amount",
+ "dwd_sum": 4583.0,
+ "ods_sum": 4583.0,
+ "diff": 0.0
+ },
+ {
+ "column": "real_goods_money",
+ "dwd_sum": 3791.0,
+ "ods_sum": 3791.0,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_store_goods_sale_ex",
+ "ods_table": "billiards_ods.store_goods_sales_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "coupon_deduct_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "discount_money",
+ "dwd_sum": 792.0,
+ "ods_sum": 792.0,
+ "diff": 0.0
+ },
+ {
+ "column": "member_discount_amount",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "option_coupon_deduct_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "option_member_discount_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "point_discount_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "point_discount_money_cost",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "push_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_assistant_service_log",
+ "ods_table": "billiards_ods.assistant_service_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "coupon_deduct_money",
+ "dwd_sum": 626.83,
+ "ods_sum": 626.83,
+ "diff": 0.0
+ },
+ {
+ "column": "ledger_amount",
+ "dwd_sum": 63251.37,
+ "ods_sum": 63251.37,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_assistant_service_log_ex",
+ "ods_table": "billiards_ods.assistant_service_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "manual_discount_amount",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "member_discount_amount",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "service_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_assistant_trash_event",
+ "ods_table": "billiards_ods.assistant_cancellation_records",
+ "count": {
+ "dwd": 15,
+ "ods": 15,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_assistant_trash_event_ex",
+ "ods_table": "billiards_ods.assistant_cancellation_records",
+ "count": {
+ "dwd": 15,
+ "ods": 15,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_member_balance_change",
+ "ods_table": "billiards_ods.member_balance_changes",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_member_balance_change_ex",
+ "ods_table": "billiards_ods.member_balance_changes",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "refund_amount",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_groupbuy_redemption",
+ "ods_table": "billiards_ods.group_buy_redemption_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "coupon_money",
+ "dwd_sum": 12266.0,
+ "ods_sum": 12266.0,
+ "diff": 0.0
+ },
+ {
+ "column": "ledger_amount",
+ "dwd_sum": 12049.53,
+ "ods_sum": 12049.53,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_groupbuy_redemption_ex",
+ "ods_table": "billiards_ods.group_buy_redemption_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "assistant_promotion_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "assistant_service_promotion_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "goods_promotion_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "recharge_promotion_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "reward_promotion_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "table_service_promotion_money",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_platform_coupon_redemption",
+ "ods_table": "billiards_ods.platform_coupon_redemption_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "coupon_money",
+ "dwd_sum": 11956.0,
+ "ods_sum": 11956.0,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_platform_coupon_redemption_ex",
+ "ods_table": "billiards_ods.platform_coupon_redemption_records",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_recharge_order",
+ "ods_table": "billiards_ods.recharge_settlements",
+ "count": {
+ "dwd": 74,
+ "ods": 74,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_recharge_order_ex",
+ "ods_table": "billiards_ods.recharge_settlements",
+ "count": {
+ "dwd": 74,
+ "ods": 74,
+ "diff": 0
+ },
+ "amounts": []
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_payment",
+ "ods_table": "billiards_ods.payment_transactions",
+ "count": {
+ "dwd": 200,
+ "ods": 200,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "pay_amount",
+ "dwd_sum": 10863.0,
+ "ods_sum": 10863.0,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_refund",
+ "ods_table": "billiards_ods.refund_transactions",
+ "count": {
+ "dwd": 11,
+ "ods": 11,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "channel_fee",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "pay_amount",
+ "dwd_sum": -62186.0,
+ "ods_sum": -62186.0,
+ "diff": 0.0
+ }
+ ]
+ },
+ {
+ "dwd_table": "billiards_dwd.dwd_refund_ex",
+ "ods_table": "billiards_ods.refund_transactions",
+ "count": {
+ "dwd": 11,
+ "ods": 11,
+ "diff": 0
+ },
+ "amounts": [
+ {
+ "column": "balance_frozen_amount",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "card_frozen_amount",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "refund_amount",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ },
+ {
+ "column": "round_amount",
+ "dwd_sum": 0.0,
+ "ods_sum": 0.0,
+ "diff": 0.0
+ }
+ ]
+ }
+ ],
+ "note": "行数/金额核对,金额字段基于列名包含 amount/money/fee/balance 的数值列自动扫描。"
+}
\ No newline at end of file
diff --git a/etl_billiards/run_ods.bat b/etl_billiards/run_ods.bat
new file mode 100644
index 0000000..c280d8d
--- /dev/null
+++ b/etl_billiards/run_ods.bat
@@ -0,0 +1,27 @@
+@echo off
+REM -*- coding: utf-8 -*-
+REM 说明:一键重建 ODS(执行 INIT_ODS_SCHEMA)并灌入示例 JSON(执行 MANUAL_INGEST)
+REM 使用配置:.env 中 PG_DSN、INGEST_SOURCE_DIR,或通过参数覆盖
+
+setlocal
+cd /d %~dp0
+
+REM 如果需要覆盖示例目录,可修改下面的 INGEST_DIR
+set "INGEST_DIR=C:\dev\LLTQ\export\test-json-doc"
+
+echo [INIT_ODS_SCHEMA] 准备执行,源目录=%INGEST_DIR%
+python -m cli.main --tasks INIT_ODS_SCHEMA --pipeline-flow INGEST_ONLY --ingest-source "%INGEST_DIR%"
+if errorlevel 1 (
+ echo INIT_ODS_SCHEMA 失败,退出
+ exit /b 1
+)
+
+echo [MANUAL_INGEST] 准备执行,源目录=%INGEST_DIR%
+python -m cli.main --tasks MANUAL_INGEST --pipeline-flow INGEST_ONLY --ingest-source "%INGEST_DIR%"
+if errorlevel 1 (
+ echo MANUAL_INGEST 失败,退出
+ exit /b 1
+)
+
+echo 全部完成。
+endlocal
diff --git a/etl_billiards/scripts/build_dwd_from_ods.py b/etl_billiards/scripts/build_dwd_from_ods.py
index fe80569..c93716f 100644
--- a/etl_billiards/scripts/build_dwd_from_ods.py
+++ b/etl_billiards/scripts/build_dwd_from_ods.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
"""Populate PRD DWD tables from ODS payload snapshots."""
from __future__ import annotations
@@ -16,9 +16,9 @@ SQL_STEPS: list[tuple[str, str]] = [
INSERT INTO billiards_dwd.dim_tenant (tenant_id, tenant_name, status)
SELECT DISTINCT tenant_id, 'default' AS tenant_name, 'active' AS status
FROM (
- SELECT tenant_id FROM billiards_ods.ods_order_settle
+ SELECT tenant_id FROM billiards_ods.settlement_records
UNION SELECT tenant_id FROM billiards_ods.ods_order_receipt_detail
- UNION SELECT tenant_id FROM billiards_ods.ods_member_profile
+ UNION SELECT tenant_id FROM billiards_ods.member_profiles
) s
WHERE tenant_id IS NOT NULL
ON CONFLICT (tenant_id) DO UPDATE SET updated_at = now();
@@ -30,7 +30,7 @@ SQL_STEPS: list[tuple[str, str]] = [
INSERT INTO billiards_dwd.dim_site (site_id, tenant_id, site_name, status)
SELECT DISTINCT site_id, MAX(tenant_id) AS tenant_id, 'default' AS site_name, 'active' AS status
FROM (
- SELECT site_id, tenant_id FROM billiards_ods.ods_order_settle
+ SELECT site_id, tenant_id FROM billiards_ods.settlement_records
UNION SELECT site_id, tenant_id FROM billiards_ods.ods_order_receipt_detail
UNION SELECT site_id, tenant_id FROM billiards_ods.ods_table_info
) s
@@ -84,7 +84,7 @@ SQL_STEPS: list[tuple[str, str]] = [
"""
INSERT INTO billiards_dwd.dim_member_card_type (card_type_id, card_type_name, discount_rate)
SELECT DISTINCT card_type_id, card_type_name, discount_rate
- FROM billiards_ods.ods_member_card
+ FROM billiards_ods.member_stored_value_cards
WHERE card_type_id IS NOT NULL
ON CONFLICT (card_type_id) DO UPDATE SET
card_type_name = EXCLUDED.card_type_name,
@@ -119,10 +119,10 @@ SQL_STEPS: list[tuple[str, str]] = [
prof.wechat_id,
prof.alipay_id,
prof.remarks
- FROM billiards_ods.ods_member_profile prof
+ FROM billiards_ods.member_profiles prof
LEFT JOIN (
SELECT DISTINCT site_id, member_id, card_type_id AS member_type_id, card_type_name AS member_type_name
- FROM billiards_ods.ods_member_card
+ FROM billiards_ods.member_stored_value_cards
) card
ON prof.site_id = card.site_id AND prof.member_id = card.member_id
WHERE prof.member_id IS NOT NULL
@@ -167,7 +167,7 @@ SQL_STEPS: list[tuple[str, str]] = [
"""
INSERT INTO billiards_dwd.dim_assistant (assistant_id, assistant_name, mobile, status)
SELECT DISTINCT assistant_id, assistant_name, mobile, status
- FROM billiards_ods.ods_assistant_account
+ FROM billiards_ods.assistant_accounts_master
WHERE assistant_id IS NOT NULL
ON CONFLICT (assistant_id) DO UPDATE SET
assistant_name = EXCLUDED.assistant_name,
@@ -181,7 +181,7 @@ SQL_STEPS: list[tuple[str, str]] = [
"""
INSERT INTO billiards_dwd.dim_pay_method (pay_method_code, pay_method_name, is_stored_value, status)
SELECT DISTINCT pay_method_code, pay_method_name, FALSE AS is_stored_value, 'active' AS status
- FROM billiards_ods.ods_payment_record
+ FROM billiards_ods.payment_transactions
WHERE pay_method_code IS NOT NULL
ON CONFLICT (pay_method_code) DO UPDATE SET
pay_method_name = EXCLUDED.pay_method_name,
@@ -250,7 +250,7 @@ SQL_STEPS: list[tuple[str, str]] = [
final_table_fee,
FALSE AS is_canceled,
NULL::TIMESTAMPTZ AS cancel_time
- FROM billiards_ods.ods_table_use_log
+ FROM billiards_ods.table_fee_transactions_log
ON CONFLICT (site_id, ledger_id) DO NOTHING;
""",
),
@@ -325,7 +325,7 @@ SQL_STEPS: list[tuple[str, str]] = [
pay_time,
relate_type,
relate_id
- FROM billiards_ods.ods_payment_record
+ FROM billiards_ods.payment_transactions
ON CONFLICT (site_id, pay_id) DO NOTHING;
""",
),
@@ -346,7 +346,7 @@ SQL_STEPS: list[tuple[str, str]] = [
refund_amount,
refund_time,
status
- FROM billiards_ods.ods_refund_record
+ FROM billiards_ods.refund_transactions
ON CONFLICT (site_id, refund_id) DO NOTHING;
""",
),
@@ -369,7 +369,7 @@ SQL_STEPS: list[tuple[str, str]] = [
balance_before,
balance_after,
change_time
- FROM billiards_ods.ods_balance_change
+ FROM billiards_ods.member_balance_changes
ON CONFLICT (site_id, change_id) DO NOTHING;
""",
),
@@ -423,3 +423,4 @@ def main() -> int:
if __name__ == "__main__":
raise SystemExit(main())
+
diff --git a/etl_billiards/scripts/check_ods_json_vs_table.py b/etl_billiards/scripts/check_ods_json_vs_table.py
new file mode 100644
index 0000000..6727566
--- /dev/null
+++ b/etl_billiards/scripts/check_ods_json_vs_table.py
@@ -0,0 +1,117 @@
+# -*- coding: utf-8 -*-
+"""
+ODS JSON 字段核对脚本:对照当前数据库中的 ODS 表字段,检查示例 JSON(默认目录 C:\\dev\\LLTQ\\export\\test-json-doc)
+是否包含同名键,并输出每表未命中的字段,便于补充映射或确认确实无源字段。
+
+使用方法:
+ set PG_DSN=postgresql://... # 如 .env 中配置
+ python -m etl_billiards.scripts.check_ods_json_vs_table
+"""
+from __future__ import annotations
+
+import json
+import os
+import pathlib
+from typing import Dict, Iterable, Set, Tuple
+
+import psycopg2
+
+from etl_billiards.tasks.manual_ingest_task import ManualIngestTask
+
+
+def _flatten_keys(obj, prefix: str = "") -> Set[str]:
+ """递归展开 JSON 所有键路径,返回形如 data.assistantInfos.id 的集合。列表不保留索引,仅继续向下展开。"""
+ keys: Set[str] = set()
+ if isinstance(obj, dict):
+ for k, v in obj.items():
+ new_prefix = f"{prefix}.{k}" if prefix else k
+ keys.add(new_prefix)
+ keys |= _flatten_keys(v, new_prefix)
+ elif isinstance(obj, list):
+ for item in obj:
+ keys |= _flatten_keys(item, prefix)
+ return keys
+
+
+def _load_json_keys(path: pathlib.Path) -> Tuple[Set[str], dict[str, Set[str]]]:
+ """读取单个 JSON 文件并返回展开后的键集合以及末段->路径列表映射,若文件不存在或无法解析则返回空集合。"""
+ if not path.exists():
+ return set(), {}
+ data = json.loads(path.read_text(encoding="utf-8"))
+ paths = _flatten_keys(data)
+ last_map: dict[str, Set[str]] = {}
+ for p in paths:
+ last = p.split(".")[-1].lower()
+ last_map.setdefault(last, set()).add(p)
+ return paths, last_map
+
+
+def _load_ods_columns(dsn: str) -> Dict[str, Set[str]]:
+ """从数据库读取 billiards_ods.* 的列名集合,按表返回。"""
+ conn = psycopg2.connect(dsn)
+ cur = conn.cursor()
+ cur.execute(
+ """
+ SELECT table_name, column_name
+ FROM information_schema.columns
+ WHERE table_schema='billiards_ods'
+ ORDER BY table_name, ordinal_position
+ """
+ )
+ result: Dict[str, Set[str]] = {}
+ for table, col in cur.fetchall():
+ result.setdefault(table, set()).add(col.lower())
+ cur.close()
+ conn.close()
+ return result
+
+
+def main() -> None:
+ """主流程:遍历 FILE_MAPPING 中的 ODS 表,检查 JSON 键覆盖情况并打印报告。"""
+ dsn = os.environ.get("PG_DSN")
+ json_dir = pathlib.Path(os.environ.get("JSON_DOC_DIR", r"C:\dev\LLTQ\export\test-json-doc"))
+
+ ods_cols_map = _load_ods_columns(dsn)
+
+ print(f"使用 JSON 目录: {json_dir}")
+ print(f"连接 DSN: {dsn}")
+ print("=" * 80)
+
+ for keywords, ods_table in ManualIngestTask.FILE_MAPPING:
+ table = ods_table.split(".")[-1]
+ cols = ods_cols_map.get(table, set())
+ file_name = f"{keywords[0]}.json"
+ file_path = json_dir / file_name
+ keys_full, path_map = _load_json_keys(file_path)
+ key_last_parts = set(path_map.keys())
+
+ missing: Set[str] = set()
+ extra_keys: Set[str] = set()
+ present: Set[str] = set()
+ for col in sorted(cols):
+ if col in key_last_parts:
+ present.add(col)
+ else:
+ missing.add(col)
+ for k in key_last_parts:
+ if k not in cols:
+ extra_keys.add(k)
+
+ print(f"[{table}] 文件={file_name} 列数={len(cols)} JSON键(末段)覆盖={len(present)}/{len(cols)}")
+ if missing:
+ print(" 未命中列:", ", ".join(sorted(missing)))
+ else:
+ print(" 未命中列: 无")
+ if extra_keys:
+ extras = []
+ for k in sorted(extra_keys):
+ paths = ", ".join(sorted(path_map.get(k, [])))
+ extras.append(f"{k} ({paths})")
+ print(" JSON 仅有(表无此列):", "; ".join(extras))
+ else:
+ print(" JSON 仅有(表无此列): 无")
+ print("-" * 80)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/etl_billiards/tasks/dwd_load_task.py b/etl_billiards/tasks/dwd_load_task.py
new file mode 100644
index 0000000..a546e0e
--- /dev/null
+++ b/etl_billiards/tasks/dwd_load_task.py
@@ -0,0 +1,907 @@
+# -*- coding: utf-8 -*-
+"""DWD 装载任务:从 ODS 增量写入 DWD(维度 SCD2,事实按时间增量)。"""
+from __future__ import annotations
+
+from datetime import datetime
+from typing import Any, Dict, Iterable, List, Sequence
+
+from psycopg2.extras import RealDictCursor
+
+from .base_task import BaseTask, TaskContext
+
+
+class DwdLoadTask(BaseTask):
+ """负责 DWD 装载:维度表做 SCD2 合并,事实表按时间增量写入。"""
+
+ # DWD -> ODS 表映射(ODS 表名已与示例 JSON 前缀统一)
+ TABLE_MAP: dict[str, str] = {
+ # 维度
+ # 门店:改用台费流水中的 siteprofile 快照,补齐 org/地址等字段
+ "billiards_dwd.dim_site": "billiards_ods.table_fee_transactions",
+ "billiards_dwd.dim_site_ex": "billiards_ods.table_fee_transactions",
+ "billiards_dwd.dim_table": "billiards_ods.site_tables_master",
+ "billiards_dwd.dim_table_ex": "billiards_ods.site_tables_master",
+ "billiards_dwd.dim_assistant": "billiards_ods.assistant_accounts_master",
+ "billiards_dwd.dim_assistant_ex": "billiards_ods.assistant_accounts_master",
+ "billiards_dwd.dim_member": "billiards_ods.member_profiles",
+ "billiards_dwd.dim_member_ex": "billiards_ods.member_profiles",
+ "billiards_dwd.dim_member_card_account": "billiards_ods.member_stored_value_cards",
+ "billiards_dwd.dim_member_card_account_ex": "billiards_ods.member_stored_value_cards",
+ "billiards_dwd.dim_tenant_goods": "billiards_ods.tenant_goods_master",
+ "billiards_dwd.dim_tenant_goods_ex": "billiards_ods.tenant_goods_master",
+ "billiards_dwd.dim_store_goods": "billiards_ods.store_goods_master",
+ "billiards_dwd.dim_store_goods_ex": "billiards_ods.store_goods_master",
+ "billiards_dwd.dim_goods_category": "billiards_ods.stock_goods_category_tree",
+ "billiards_dwd.dim_groupbuy_package": "billiards_ods.group_buy_packages",
+ "billiards_dwd.dim_groupbuy_package_ex": "billiards_ods.group_buy_packages",
+ # 事实
+ "billiards_dwd.dwd_settlement_head": "billiards_ods.settlement_records",
+ "billiards_dwd.dwd_settlement_head_ex": "billiards_ods.settlement_records",
+ "billiards_dwd.dwd_table_fee_log": "billiards_ods.table_fee_transactions",
+ "billiards_dwd.dwd_table_fee_log_ex": "billiards_ods.table_fee_transactions",
+ "billiards_dwd.dwd_table_fee_adjust": "billiards_ods.table_fee_discount_records",
+ "billiards_dwd.dwd_table_fee_adjust_ex": "billiards_ods.table_fee_discount_records",
+ "billiards_dwd.dwd_store_goods_sale": "billiards_ods.store_goods_sales_records",
+ "billiards_dwd.dwd_store_goods_sale_ex": "billiards_ods.store_goods_sales_records",
+ "billiards_dwd.dwd_assistant_service_log": "billiards_ods.assistant_service_records",
+ "billiards_dwd.dwd_assistant_service_log_ex": "billiards_ods.assistant_service_records",
+ "billiards_dwd.dwd_assistant_trash_event": "billiards_ods.assistant_cancellation_records",
+ "billiards_dwd.dwd_assistant_trash_event_ex": "billiards_ods.assistant_cancellation_records",
+ "billiards_dwd.dwd_member_balance_change": "billiards_ods.member_balance_changes",
+ "billiards_dwd.dwd_member_balance_change_ex": "billiards_ods.member_balance_changes",
+ "billiards_dwd.dwd_groupbuy_redemption": "billiards_ods.group_buy_redemption_records",
+ "billiards_dwd.dwd_groupbuy_redemption_ex": "billiards_ods.group_buy_redemption_records",
+ "billiards_dwd.dwd_platform_coupon_redemption": "billiards_ods.platform_coupon_redemption_records",
+ "billiards_dwd.dwd_platform_coupon_redemption_ex": "billiards_ods.platform_coupon_redemption_records",
+ "billiards_dwd.dwd_recharge_order": "billiards_ods.recharge_settlements",
+ "billiards_dwd.dwd_recharge_order_ex": "billiards_ods.recharge_settlements",
+ "billiards_dwd.dwd_payment": "billiards_ods.payment_transactions",
+ "billiards_dwd.dwd_refund": "billiards_ods.refund_transactions",
+ "billiards_dwd.dwd_refund_ex": "billiards_ods.refund_transactions",
+ }
+
+ SCD_COLS = {"scd2_start_time", "scd2_end_time", "scd2_is_current", "scd2_version"}
+ FACT_ORDER_CANDIDATES = [
+ "fetched_at",
+ "pay_time",
+ "create_time",
+ "update_time",
+ "occur_time",
+ "settle_time",
+ "start_use_time",
+ ]
+
+ # 特殊列映射:dwd 列名 -> 源列表达式(可选 CAST)
+ FACT_MAPPINGS: dict[str, list[tuple[str, str, str | None]]] = {
+ # 维度表(补齐主键/字段差异)
+ "billiards_dwd.dim_site": [
+ ("org_id", "siteprofile->>'org_id'", None),
+ ("shop_name", "siteprofile->>'shop_name'", None),
+ ("site_label", "siteprofile->>'site_label'", None),
+ ("full_address", "siteprofile->>'full_address'", None),
+ ("address", "siteprofile->>'address'", None),
+ ("longitude", "siteprofile->>'longitude'", "numeric"),
+ ("latitude", "siteprofile->>'latitude'", "numeric"),
+ ("tenant_site_region_id", "siteprofile->>'tenant_site_region_id'", None),
+ ("business_tel", "siteprofile->>'business_tel'", None),
+ ("site_type", "siteprofile->>'site_type'", None),
+ ("shop_status", "siteprofile->>'shop_status'", None),
+ ("tenant_id", "siteprofile->>'tenant_id'", None),
+ ],
+ "billiards_dwd.dim_site_ex": [
+ ("auto_light", "siteprofile->>'auto_light'", None),
+ ("attendance_enabled", "siteprofile->>'attendance_enabled'", None),
+ ("attendance_distance", "siteprofile->>'attendance_distance'", None),
+ ("prod_env", "siteprofile->>'prod_env'", None),
+ ("light_status", "siteprofile->>'light_status'", None),
+ ("light_type", "siteprofile->>'light_type'", None),
+ ("light_token", "siteprofile->>'light_token'", None),
+ ("address", "siteprofile->>'address'", None),
+ ("avatar", "siteprofile->>'avatar'", None),
+ ("wifi_name", "siteprofile->>'wifi_name'", None),
+ ("wifi_password", "siteprofile->>'wifi_password'", None),
+ ("customer_service_qrcode", "siteprofile->>'customer_service_qrcode'", None),
+ ("customer_service_wechat", "siteprofile->>'customer_service_wechat'", None),
+ ("fixed_pay_qrcode", "siteprofile->>'fixed_pay_qrCode'", None),
+ ("longitude", "siteprofile->>'longitude'", "numeric"),
+ ("latitude", "siteprofile->>'latitude'", "numeric"),
+ ("tenant_site_region_id", "siteprofile->>'tenant_site_region_id'", None),
+ ("site_type", "siteprofile->>'site_type'", None),
+ ("site_label", "siteprofile->>'site_label'", None),
+ ("shop_status", "siteprofile->>'shop_status'", None),
+ ("create_time", "siteprofile->>'create_time'", "timestamptz"),
+ ("update_time", "siteprofile->>'update_time'", "timestamptz"),
+ ],
+ "billiards_dwd.dim_table": [
+ ("table_id", "id", None),
+ ("site_table_area_name", "areaname", None),
+ ("tenant_table_area_id", "site_table_area_id", None),
+ ],
+ "billiards_dwd.dim_table_ex": [
+ ("table_id", "id", None),
+ ("table_cloth_use_time", "table_cloth_use_time", None),
+ ],
+ "billiards_dwd.dim_assistant": [("assistant_id", "id", None), ("user_id", "staff_id", None)],
+ "billiards_dwd.dim_assistant_ex": [
+ ("assistant_id", "id", None),
+ ("introduce", "introduce", None),
+ ("group_name", "group_name", None),
+ ("light_equipment_id", "light_equipment_id", None),
+ ],
+ "billiards_dwd.dim_member": [("member_id", "id", None)],
+ "billiards_dwd.dim_member_ex": [
+ ("member_id", "id", None),
+ ("register_site_name", "site_name", None),
+ ],
+ "billiards_dwd.dim_member_card_account": [("member_card_id", "id", None)],
+ "billiards_dwd.dim_member_card_account_ex": [
+ ("member_card_id", "id", None),
+ ("tenant_name", "tenantname", None),
+ ("tenantavatar", "tenantavatar", None),
+ ("card_no", "card_no", None),
+ ("bind_password", "bind_password", None),
+ ("use_scene", "use_scene", None),
+ ("tableareaid", "tableareaid", None),
+ ("goodscategoryid", "goodscategoryid", None),
+ ],
+ "billiards_dwd.dim_tenant_goods": [
+ ("tenant_goods_id", "id", None),
+ ("category_name", "categoryname", None),
+ ],
+ "billiards_dwd.dim_tenant_goods_ex": [
+ ("tenant_goods_id", "id", None),
+ ("remark_name", "remark_name", None),
+ ("goods_bar_code", "goods_bar_code", None),
+ ("commodity_code_list", "commodity_code", None),
+ ("is_in_site", "isinsite", "boolean"),
+ ],
+ "billiards_dwd.dim_store_goods": [
+ ("site_goods_id", "id", None),
+ ("category_level1_name", "onecategoryname", None),
+ ("category_level2_name", "twocategoryname", None),
+ ("created_at", "create_time", None),
+ ("updated_at", "update_time", None),
+ ("avg_monthly_sales", "average_monthly_sales", None),
+ ("batch_stock_qty", "stock", None),
+ ("sale_qty", "sale_num", None),
+ ("total_sales_qty", "total_sales", None),
+ ],
+ "billiards_dwd.dim_store_goods_ex": [
+ ("site_goods_id", "id", None),
+ ("goods_barcode", "goods_bar_code", None),
+ ("stock_qty", "stock", None),
+ ("stock_secondary_qty", "stock_a", None),
+ ("safety_stock_qty", "safe_stock", None),
+ ("site_name", "sitename", None),
+ ("goods_cover_url", "goods_cover", None),
+ ("provisional_total_cost", "total_purchase_cost", None),
+ ("is_discountable", "able_discount", None),
+ ("freeze_status", "freeze", None),
+ ("remark", "remark", None),
+ ("days_on_shelf", "days_available", None),
+ ("sort_order", "sort", None),
+ ],
+ "billiards_dwd.dim_goods_category": [
+ ("category_id", "id", None),
+ ("tenant_id", "tenant_id", None),
+ ("category_name", "category_name", None),
+ ("alias_name", "alias_name", None),
+ ("parent_category_id", "pid", None),
+ ("business_name", "business_name", None),
+ ("tenant_goods_business_id", "tenant_goods_business_id", None),
+ ("sort_order", "sort", None),
+ ("open_salesman", "open_salesman", None),
+ ("is_warehousing", "is_warehousing", None),
+ ("category_level", "CASE WHEN pid = 0 THEN 1 ELSE 2 END", None),
+ ("is_leaf", "CASE WHEN categoryboxes IS NULL OR jsonb_array_length(categoryboxes)=0 THEN 1 ELSE 0 END", None),
+ ],
+ "billiards_dwd.dim_groupbuy_package": [
+ ("groupbuy_package_id", "id", None),
+ ("package_template_id", "package_id", None),
+ ("coupon_face_value", "coupon_money", None),
+ ("duration_seconds", "duration", None),
+ ],
+ "billiards_dwd.dim_groupbuy_package_ex": [
+ ("groupbuy_package_id", "id", None),
+ ("table_area_id", "table_area_id", None),
+ ("tenant_table_area_id", "tenant_table_area_id", None),
+ ("usable_range", "usable_range", None),
+ ("table_area_id_list", "table_area_id_list", None),
+ ("package_type", "type", None),
+ ],
+ # 事实表主键及关键差异列
+ "billiards_dwd.dwd_table_fee_log": [("table_fee_log_id", "id", None)],
+ "billiards_dwd.dwd_table_fee_log_ex": [
+ ("table_fee_log_id", "id", None),
+ ("salesman_name", "salesman_name", None),
+ ],
+ "billiards_dwd.dwd_table_fee_adjust": [
+ ("table_fee_adjust_id", "id", None),
+ ("table_id", "site_table_id", None),
+ ("table_area_id", "tenant_table_area_id", None),
+ ("table_area_name", "tableprofile->>'table_area_name'", None),
+ ("adjust_time", "create_time", None),
+ ],
+ "billiards_dwd.dwd_table_fee_adjust_ex": [
+ ("table_fee_adjust_id", "id", None),
+ ("ledger_name", "ledger_name", None),
+ ],
+ "billiards_dwd.dwd_store_goods_sale": [("store_goods_sale_id", "id", None), ("discount_price", "discount_money", None)],
+ "billiards_dwd.dwd_store_goods_sale_ex": [
+ ("store_goods_sale_id", "id", None),
+ ("option_value_name", "option_value_name", None),
+ ("open_salesman_flag", "opensalesman", "integer"),
+ ("salesman_name", "salesman_name", None),
+ ("salesman_org_id", "sales_man_org_id", None),
+ ("legacy_order_goods_id", "ordergoodsid", None),
+ ("site_name", "sitename", None),
+ ("legacy_site_id", "siteid", None),
+ ],
+ "billiards_dwd.dwd_assistant_service_log": [
+ ("assistant_service_id", "id", None),
+ ("assistant_no", "assistantno", None),
+ ("site_assistant_id", "order_assistant_id", None),
+ ("level_name", "levelname", None),
+ ("skill_name", "skillname", None),
+ ],
+ "billiards_dwd.dwd_assistant_service_log_ex": [
+ ("assistant_service_id", "id", None),
+ ("assistant_name", "assistantname", None),
+ ("ledger_group_name", "ledger_group_name", None),
+ ("trash_applicant_name", "trash_applicant_name", None),
+ ("trash_reason", "trash_reason", None),
+ ("salesman_name", "salesman_name", None),
+ ("table_name", "tablename", None),
+ ],
+ "billiards_dwd.dwd_assistant_trash_event": [
+ ("assistant_trash_event_id", "id", None),
+ ("assistant_no", "assistantname", None),
+ ("abolish_amount", "assistantabolishamount", None),
+ ("charge_minutes_raw", "pdchargeminutes", None),
+ ("site_id", "siteid", None),
+ ("table_id", "tableid", None),
+ ("table_area_id", "tableareaid", None),
+ ("assistant_name", "assistantname", None),
+ ("trash_reason", "trashreason", None),
+ ("create_time", "createtime", None),
+ ],
+ "billiards_dwd.dwd_assistant_trash_event_ex": [
+ ("assistant_trash_event_id", "id", None),
+ ("table_area_name", "tablearea", None),
+ ("table_name", "tablename", None),
+ ],
+ "billiards_dwd.dwd_member_balance_change": [
+ ("balance_change_id", "id", None),
+ ("balance_before", "before", None),
+ ("change_amount", "account_data", None),
+ ("balance_after", "after", None),
+ ("card_type_name", "membercardtypename", None),
+ ("change_time", "create_time", None),
+ ("member_name", "membername", None),
+ ("member_mobile", "membermobile", None),
+ ],
+ "billiards_dwd.dwd_member_balance_change_ex": [
+ ("balance_change_id", "id", None),
+ ("pay_site_name", "paysitename", None),
+ ("register_site_name", "registersitename", None),
+ ],
+ "billiards_dwd.dwd_groupbuy_redemption": [("redemption_id", "id", None)],
+ "billiards_dwd.dwd_groupbuy_redemption_ex": [
+ ("redemption_id", "id", None),
+ ("table_area_name", "tableareaname", None),
+ ("site_name", "sitename", None),
+ ("table_name", "tablename", None),
+ ("goods_option_price", "goodsoptionprice", None),
+ ("salesman_name", "salesman_name", None),
+ ("salesman_org_id", "sales_man_org_id", None),
+ ("ledger_group_name", "ledger_group_name", None),
+ ],
+ "billiards_dwd.dwd_platform_coupon_redemption": [("platform_coupon_redemption_id", "id", None)],
+ "billiards_dwd.dwd_platform_coupon_redemption_ex": [
+ ("platform_coupon_redemption_id", "id", None),
+ ("coupon_cover", "coupon_cover", None),
+ ],
+ "billiards_dwd.dwd_payment": [("payment_id", "id", None), ("pay_date", "pay_time", "date")],
+ "billiards_dwd.dwd_refund": [("refund_id", "id", None)],
+ "billiards_dwd.dwd_refund_ex": [
+ ("refund_id", "id", None),
+ ("tenant_name", "tenantname", None),
+ ("channel_payer_id", "channel_payer_id", None),
+ ("channel_pay_no", "channel_pay_no", None),
+ ],
+ # 结算头:settlement_records(源列为小写驼峰/无下划线,需要显式映射)
+ "billiards_dwd.dwd_settlement_head": [
+ ("order_settle_id", "id", None),
+ ("tenant_id", "tenantid", None),
+ ("site_id", "siteid", None),
+ ("site_name", "sitename", None),
+ ("table_id", "tableid", None),
+ ("settle_name", "settlename", None),
+ ("order_trade_no", "settlerelateid", None),
+ ("create_time", "createtime", None),
+ ("pay_time", "paytime", None),
+ ("settle_type", "settletype", None),
+ ("revoke_order_id", "revokeorderid", None),
+ ("member_id", "memberid", None),
+ ("member_name", "membername", None),
+ ("member_phone", "memberphone", None),
+ ("member_card_account_id", "tenantmembercardid", None),
+ ("member_card_type_name", "membercardtypename", None),
+ ("is_bind_member", "isbindmember", None),
+ ("member_discount_amount", "memberdiscountamount", None),
+ ("consume_money", "consumemoney", None),
+ ("table_charge_money", "tablechargemoney", None),
+ ("goods_money", "goodsmoney", None),
+ ("real_goods_money", "realgoodsmoney", None),
+ ("assistant_pd_money", "assistantpdmoney", None),
+ ("assistant_cx_money", "assistantcxmoney", None),
+ ("adjust_amount", "adjustamount", None),
+ ("pay_amount", "payamount", None),
+ ("balance_amount", "balanceamount", None),
+ ("recharge_card_amount", "rechargecardamount", None),
+ ("gift_card_amount", "giftcardamount", None),
+ ("coupon_amount", "couponamount", None),
+ ("rounding_amount", "roundingamount", None),
+ ("point_amount", "pointamount", None),
+ ],
+ "billiards_dwd.dwd_settlement_head_ex": [
+ ("order_settle_id", "id", None),
+ ("serial_number", "serialnumber", None),
+ ("settle_status", "settlestatus", None),
+ ("can_be_revoked", "canberevoked", "boolean"),
+ ("revoke_order_name", "revokeordername", None),
+ ("revoke_time", "revoketime", None),
+ ("is_first_order", "isfirst", "boolean"),
+ ("service_money", "servicemoney", None),
+ ("cash_amount", "cashamount", None),
+ ("card_amount", "cardamount", None),
+ ("online_amount", "onlineamount", None),
+ ("refund_amount", "refundamount", None),
+ ("prepay_money", "prepaymoney", None),
+ ("payment_method", "paymentmethod", None),
+ ("coupon_sale_amount", "couponsaleamount", None),
+ ("all_coupon_discount", "allcoupondiscount", None),
+ ("goods_promotion_money", "goodspromotionmoney", None),
+ ("assistant_promotion_money", "assistantpromotionmoney", None),
+ ("activity_discount", "activitydiscount", None),
+ ("assistant_manual_discount", "assistantmanualdiscount", None),
+ ("point_discount_price", "pointdiscountprice", None),
+ ("point_discount_cost", "pointdiscountcost", None),
+ ("is_use_coupon", "isusecoupon", "boolean"),
+ ("is_use_discount", "isusediscount", "boolean"),
+ ("is_activity", "isactivity", "boolean"),
+ ("operator_name", "operatorname", None),
+ ("salesman_name", "salesmanname", None),
+ ("order_remark", "orderremark", None),
+ ("operator_id", "operatorid", None),
+ ("salesman_user_id", "salesmanuserid", None),
+ ],
+ # 充值结算:recharge_settlements(字段风格同 settlement_records)
+ "billiards_dwd.dwd_recharge_order": [
+ ("recharge_order_id", "id", None),
+ ("tenant_id", "tenantid", None),
+ ("site_id", "siteid", None),
+ ("member_id", "memberid", None),
+ ("member_name_snapshot", "membername", None),
+ ("member_phone_snapshot", "memberphone", None),
+ ("tenant_member_card_id", "tenantmembercardid", None),
+ ("member_card_type_name", "membercardtypename", None),
+ ("settle_relate_id", "settlerelateid", None),
+ ("settle_type", "settletype", None),
+ ("settle_name", "settlename", None),
+ ("is_first", "isfirst", None),
+ ("pay_amount", "payamount", None),
+ ("refund_amount", "refundamount", None),
+ ("point_amount", "pointamount", None),
+ ("cash_amount", "cashamount", None),
+ ("payment_method", "paymentmethod", None),
+ ("create_time", "createtime", None),
+ ("pay_time", "paytime", None),
+ ],
+ "billiards_dwd.dwd_recharge_order_ex": [
+ ("recharge_order_id", "id", None),
+ ("site_name_snapshot", "sitename", None),
+ ("salesman_name", "salesmanname", None),
+ ("order_remark", "orderremark", None),
+ ("revoke_order_name", "revokeordername", None),
+ ("settle_status", "settlestatus", None),
+ ("is_bind_member", "isbindmember", "boolean"),
+ ("is_activity", "isactivity", "boolean"),
+ ("is_use_coupon", "isusecoupon", "boolean"),
+ ("is_use_discount", "isusediscount", "boolean"),
+ ("can_be_revoked", "canberevoked", "boolean"),
+ ("online_amount", "onlineamount", None),
+ ("balance_amount", "balanceamount", None),
+ ("card_amount", "cardamount", None),
+ ("coupon_amount", "couponamount", None),
+ ("recharge_card_amount", "rechargecardamount", None),
+ ("gift_card_amount", "giftcardamount", None),
+ ("prepay_money", "prepaymoney", None),
+ ("consume_money", "consumemoney", None),
+ ("goods_money", "goodsmoney", None),
+ ("real_goods_money", "realgoodsmoney", None),
+ ("table_charge_money", "tablechargemoney", None),
+ ("service_money", "servicemoney", None),
+ ("activity_discount", "activitydiscount", None),
+ ("all_coupon_discount", "allcoupondiscount", None),
+ ("goods_promotion_money", "goodspromotionmoney", None),
+ ("assistant_promotion_money", "assistantpromotionmoney", None),
+ ("assistant_pd_money", "assistantpdmoney", None),
+ ("assistant_cx_money", "assistantcxmoney", None),
+ ("assistant_manual_discount", "assistantmanualdiscount", None),
+ ("coupon_sale_amount", "couponsaleamount", None),
+ ("member_discount_amount", "memberdiscountamount", None),
+ ("point_discount_price", "pointdiscountprice", None),
+ ("point_discount_cost", "pointdiscountcost", None),
+ ("adjust_amount", "adjustamount", None),
+ ("rounding_amount", "roundingamount", None),
+ ("operator_id", "operatorid", None),
+ ("operator_name_snapshot", "operatorname", None),
+ ("salesman_user_id", "salesmanuserid", None),
+ ("salesman_name", "salesmanname", None),
+ ("order_remark", "orderremark", None),
+ ("table_id", "tableid", None),
+ ("serial_number", "serialnumber", None),
+ ("revoke_order_id", "revokeorderid", None),
+ ("revoke_order_name", "revokeordername", None),
+ ("revoke_time", "revoketime", None),
+ ],
+ }
+
+ def get_task_code(self) -> str:
+ """返回任务编码。"""
+ return "DWD_LOAD_FROM_ODS"
+
+ def extract(self, context: TaskContext) -> dict[str, Any]:
+ """准备运行所需的上下文信息。"""
+ return {"now": datetime.now()}
+
+ def load(self, extracted: dict[str, Any], context: TaskContext) -> dict[str, Any]:
+ """遍历映射关系,维度执行 SCD2 合并,事实表按时间增量插入。"""
+ now = extracted["now"]
+ summary: List[Dict[str, Any]] = []
+ with self.db.conn.cursor(cursor_factory=RealDictCursor) as cur:
+ for dwd_table, ods_table in self.TABLE_MAP.items():
+ dwd_cols = self._get_columns(cur, dwd_table)
+ ods_cols = self._get_columns(cur, ods_table)
+ if not dwd_cols:
+ self.logger.warning("跳过 %s,未能获取 DWD 列信息", dwd_table)
+ continue
+
+ if self._table_base(dwd_table).startswith("dim_"):
+ processed = self._merge_dim_scd2(cur, dwd_table, ods_table, dwd_cols, ods_cols, now)
+ summary.append({"table": dwd_table, "mode": "SCD2", "processed": processed})
+ else:
+ dwd_types = self._get_column_types(cur, dwd_table, "billiards_dwd")
+ ods_types = self._get_column_types(cur, ods_table, "billiards_ods")
+ inserted = self._merge_fact_increment(
+ cur, dwd_table, ods_table, dwd_cols, ods_cols, dwd_types, ods_types
+ )
+ summary.append({"table": dwd_table, "mode": "INCREMENT", "inserted": inserted})
+
+ self.db.conn.commit()
+ return {"tables": summary}
+
+ # ---------------------- helpers ----------------------
+ def _get_columns(self, cur, table: str) -> List[str]:
+ """获取指定表的列名(小写)。"""
+ schema, name = self._split_table_name(table, default_schema="billiards_dwd")
+ cur.execute(
+ """
+ SELECT column_name
+ FROM information_schema.columns
+ WHERE table_schema = %s AND table_name = %s
+ """,
+ (schema, name),
+ )
+ return [r["column_name"].lower() for r in cur.fetchall()]
+
+ def _get_primary_keys(self, cur, table: str) -> List[str]:
+ """获取表的主键列名列表。"""
+ schema, name = self._split_table_name(table, default_schema="billiards_dwd")
+ cur.execute(
+ """
+ SELECT kcu.column_name
+ FROM information_schema.table_constraints tc
+ JOIN information_schema.key_column_usage kcu
+ ON tc.constraint_name = kcu.constraint_name
+ AND tc.table_schema = kcu.table_schema
+ AND tc.table_name = kcu.table_name
+ WHERE tc.table_schema = %s
+ AND tc.table_name = %s
+ AND tc.constraint_type = 'PRIMARY KEY'
+ ORDER BY kcu.ordinal_position
+ """,
+ (schema, name),
+ )
+ return [r["column_name"].lower() for r in cur.fetchall()]
+
+ def _get_column_types(self, cur, table: str, default_schema: str) -> Dict[str, str]:
+ """获取列的数据类型(information_schema.data_type)。"""
+ schema, name = self._split_table_name(table, default_schema=default_schema)
+ cur.execute(
+ """
+ SELECT column_name, data_type
+ FROM information_schema.columns
+ WHERE table_schema = %s AND table_name = %s
+ """,
+ (schema, name),
+ )
+ return {r["column_name"].lower(): r["data_type"].lower() for r in cur.fetchall()}
+
+ def _build_column_mapping(
+ self, dwd_table: str, pk_cols: Sequence[str], ods_cols: Sequence[str]
+ ) -> Dict[str, tuple[str, str | None]]:
+ """合并显式 FACT_MAPPINGS 与主键兜底映射。"""
+ mapping_entries = self.FACT_MAPPINGS.get(dwd_table, [])
+ mapping: Dict[str, tuple[str, str | None]] = {
+ dst.lower(): (src, cast_type) for dst, src, cast_type in mapping_entries
+ }
+ ods_set = {c.lower() for c in ods_cols}
+ for pk in pk_cols:
+ pk_lower = pk.lower()
+ if pk_lower not in mapping and pk_lower not in ods_set and "id" in ods_set:
+ mapping[pk_lower] = ("id", None)
+ return mapping
+
+ def _fetch_source_rows(
+ self, cur, table: str, columns: Sequence[str], where_sql: str = "", params: Sequence[Any] = None
+ ) -> List[Dict[str, Any]]:
+ """从源表读取指定列,返回小写键的字典列表。"""
+ schema, name = self._split_table_name(table, default_schema="billiards_ods")
+ cols_sql = ", ".join(f'"{c}"' for c in columns)
+ sql = f'SELECT {cols_sql} FROM "{schema}"."{name}" {where_sql}'
+ cur.execute(sql, params or [])
+ rows = []
+ for r in cur.fetchall():
+ rows.append({k.lower(): v for k, v in r.items()})
+ return rows
+
+ def _expand_goods_category_rows(self, rows: list[Dict[str, Any]]) -> list[Dict[str, Any]]:
+ """将分类表中的 categoryboxes 元素展开为子类记录。"""
+ expanded: list[Dict[str, Any]] = []
+ for r in rows:
+ expanded.append(r)
+ boxes = r.get("categoryboxes")
+ if isinstance(boxes, list):
+ for child in boxes:
+ if not isinstance(child, dict):
+ continue
+ child_row: Dict[str, Any] = {}
+ # 继承父级的租户与业务大类信息
+ child_row["tenant_id"] = r.get("tenant_id")
+ child_row["business_name"] = child.get("business_name", r.get("business_name"))
+ child_row["tenant_goods_business_id"] = child.get(
+ "tenant_goods_business_id", r.get("tenant_goods_business_id")
+ )
+ # 合并子类字段
+ child_row.update(child)
+ # 默认父子关系
+ child_row.setdefault("pid", r.get("id"))
+ # 衍生层级/叶子标记
+ child_boxes = child_row.get("categoryboxes")
+ if not isinstance(child_boxes, list):
+ is_leaf = 1
+ else:
+ is_leaf = 1 if len(child_boxes) == 0 else 0
+ child_row.setdefault("category_level", 2)
+ child_row.setdefault("is_leaf", is_leaf)
+ expanded.append(child_row)
+ return expanded
+
+ def _merge_dim_scd2(
+ self,
+ cur,
+ dwd_table: str,
+ ods_table: str,
+ dwd_cols: Sequence[str],
+ ods_cols: Sequence[str],
+ now: datetime,
+ ) -> int:
+ """对维表执行 SCD2 合并:对比变更关闭旧版并插入新版。"""
+ pk_cols = self._get_primary_keys(cur, dwd_table)
+ if not pk_cols:
+ raise ValueError(f"{dwd_table} 未配置主键,无法执行 SCD2 合并")
+
+ mapping = self._build_column_mapping(dwd_table, pk_cols, ods_cols)
+ ods_set = {c.lower() for c in ods_cols}
+ table_sql = self._format_table(ods_table, "billiards_ods")
+ # 构造 SELECT 表达式,支持 JSON/expression 映射
+ select_exprs: list[str] = []
+ added: set[str] = set()
+ for col in dwd_cols:
+ lc = col.lower()
+ if lc in self.SCD_COLS:
+ continue
+ if lc in mapping:
+ src, cast_type = mapping[lc]
+ select_exprs.append(f"{self._cast_expr(src, cast_type)} AS \"{lc}\"")
+ added.add(lc)
+ elif lc in ods_set:
+ select_exprs.append(f'"{lc}" AS "{lc}"')
+ added.add(lc)
+ # 分类维度需要额外读取 categoryboxes 以展开子类
+ if dwd_table == "billiards_dwd.dim_goods_category" and "categoryboxes" not in added and "categoryboxes" in ods_set:
+ select_exprs.append('"categoryboxes" AS "categoryboxes"')
+ added.add("categoryboxes")
+ # 主键兜底确保被选出
+ for pk in pk_cols:
+ lc = pk.lower()
+ if lc not in added:
+ if lc in mapping:
+ src, cast_type = mapping[lc]
+ select_exprs.append(f"{self._cast_expr(src, cast_type)} AS \"{lc}\"")
+ elif lc in ods_set:
+ select_exprs.append(f'"{lc}" AS "{lc}"')
+ added.add(lc)
+
+ if not select_exprs:
+ return 0
+
+ sql = f"SELECT {', '.join(select_exprs)} FROM {table_sql}"
+ cur.execute(sql)
+ rows = [{k.lower(): v for k, v in r.items()} for r in cur.fetchall()]
+
+ # 特殊:分类维度展开子类
+ if dwd_table == "billiards_dwd.dim_goods_category":
+ rows = self._expand_goods_category_rows(rows)
+
+ inserted_or_updated = 0
+ seen_pk = set()
+ for row in rows:
+ mapped_row: Dict[str, Any] = {}
+ for col in dwd_cols:
+ lc = col.lower()
+ if lc in self.SCD_COLS:
+ continue
+ value = row.get(lc)
+ if value is None and lc in mapping:
+ src, _ = mapping[lc]
+ value = row.get(src.lower())
+ mapped_row[lc] = value
+
+ pk_key = tuple(mapped_row.get(pk) for pk in pk_cols)
+ if pk_key in seen_pk:
+ continue
+ seen_pk.add(pk_key)
+ if self._upsert_scd2_row(cur, dwd_table, dwd_cols, pk_cols, mapped_row, now):
+ inserted_or_updated += 1
+ return len(rows)
+
+ def _upsert_scd2_row(
+ self,
+ cur,
+ dwd_table: str,
+ dwd_cols: Sequence[str],
+ pk_cols: Sequence[str],
+ src_row: Dict[str, Any],
+ now: datetime,
+ ) -> bool:
+ """SCD2 合并:若有变更则关闭旧版并插入新版本。"""
+ pk_values = [src_row.get(pk) for pk in pk_cols]
+ if any(v is None for v in pk_values):
+ self.logger.warning("跳过 %s:主键缺失 %s", dwd_table, dict(zip(pk_cols, pk_values)))
+ return False
+
+ where_clause = " AND ".join(f'"{pk}" = %s' for pk in pk_cols)
+ table_sql = self._format_table(dwd_table, "billiards_dwd")
+ cur.execute(
+ f"SELECT * FROM {table_sql} WHERE {where_clause} AND COALESCE(scd2_is_current,1)=1 LIMIT 1",
+ pk_values,
+ )
+ current = cur.fetchone()
+ if current:
+ current = {k.lower(): v for k, v in current.items()}
+
+ if current and not self._is_row_changed(current, src_row, dwd_cols):
+ return False
+
+ if current:
+ version = (current.get("scd2_version") or 1) + 1
+ self._close_current_dim(cur, dwd_table, pk_cols, pk_values, now)
+ else:
+ version = 1
+
+ self._insert_dim_row(cur, dwd_table, dwd_cols, src_row, now, version)
+ return True
+
+ def _close_current_dim(self, cur, table: str, pk_cols: Sequence[str], pk_values: Sequence[Any], now: datetime) -> None:
+ """关闭当前版本,标记 scd2_is_current=0 并填充结束时间。"""
+ set_sql = "scd2_end_time = %s, scd2_is_current = 0"
+ where_clause = " AND ".join(f'"{pk}" = %s' for pk in pk_cols)
+ table_sql = self._format_table(table, "billiards_dwd")
+ cur.execute(f"UPDATE {table_sql} SET {set_sql} WHERE {where_clause} AND COALESCE(scd2_is_current,1)=1", [now, *pk_values])
+
+ def _insert_dim_row(
+ self,
+ cur,
+ table: str,
+ dwd_cols: Sequence[str],
+ src_row: Dict[str, Any],
+ now: datetime,
+ version: int,
+ ) -> None:
+ """插入新的 SCD2 版本行。"""
+ insert_cols: List[str] = []
+ placeholders: List[str] = []
+ values: List[Any] = []
+ for col in sorted(dwd_cols):
+ lc = col.lower()
+ insert_cols.append(f'"{lc}"')
+ placeholders.append("%s")
+ if lc == "scd2_start_time":
+ values.append(now)
+ elif lc == "scd2_end_time":
+ values.append(datetime(9999, 12, 31, 0, 0, 0))
+ elif lc == "scd2_is_current":
+ values.append(1)
+ elif lc == "scd2_version":
+ values.append(version)
+ else:
+ values.append(src_row.get(lc))
+ table_sql = self._format_table(table, "billiards_dwd")
+ sql = f'INSERT INTO {table_sql} ({", ".join(insert_cols)}) VALUES ({", ".join(placeholders)})'
+ cur.execute(sql, values)
+
+ def _is_row_changed(self, current: Dict[str, Any], incoming: Dict[str, Any], dwd_cols: Sequence[str]) -> bool:
+ """比较非 SCD2 列,判断是否存在变更。"""
+ for col in dwd_cols:
+ lc = col.lower()
+ if lc in self.SCD_COLS:
+ continue
+ if current.get(lc) != incoming.get(lc):
+ return True
+ return False
+
+ def _merge_fact_increment(
+ self,
+ cur,
+ dwd_table: str,
+ ods_table: str,
+ dwd_cols: Sequence[str],
+ ods_cols: Sequence[str],
+ dwd_types: Dict[str, str],
+ ods_types: Dict[str, str],
+ ) -> int:
+ """事实表按时间增量插入,默认按列名交集写入。"""
+ mapping_entries = self.FACT_MAPPINGS.get(dwd_table) or []
+ mapping: Dict[str, tuple[str, str | None]] = {
+ dst.lower(): (src, cast_type) for dst, src, cast_type in mapping_entries
+ }
+
+ mapping_dest = [dst for dst, _, _ in mapping_entries]
+ insert_cols: List[str] = list(mapping_dest)
+ for col in dwd_cols:
+ if col in self.SCD_COLS:
+ continue
+ if col in insert_cols:
+ continue
+ if col in ods_cols:
+ insert_cols.append(col)
+
+ pk_cols = self._get_primary_keys(cur, dwd_table)
+ ods_set = {c.lower() for c in ods_cols}
+ existing_lower = [c.lower() for c in insert_cols]
+ for pk in pk_cols:
+ pk_lower = pk.lower()
+ if pk_lower in existing_lower:
+ continue
+ if pk_lower in ods_set:
+ insert_cols.append(pk)
+ existing_lower.append(pk_lower)
+ elif "id" in ods_set:
+ insert_cols.append(pk)
+ existing_lower.append(pk_lower)
+ mapping[pk_lower] = ("id", None)
+
+ # 保持列顺序同时去重
+ seen_cols: set[str] = set()
+ ordered_cols: list[str] = []
+ for col in insert_cols:
+ lc = col.lower()
+ if lc not in seen_cols:
+ seen_cols.add(lc)
+ ordered_cols.append(col)
+ insert_cols = ordered_cols
+
+ if not insert_cols:
+ self.logger.warning("跳过 %s:未找到可插入的列", dwd_table)
+ return 0
+
+ order_col = self._pick_order_column(dwd_cols, ods_cols)
+ where_sql = ""
+ params: List[Any] = []
+ dwd_table_sql = self._format_table(dwd_table, "billiards_dwd")
+ ods_table_sql = self._format_table(ods_table, "billiards_ods")
+ if order_col:
+ cur.execute(f'SELECT COALESCE(MAX("{order_col}"), %s) FROM {dwd_table_sql}', ("1970-01-01",))
+ row = cur.fetchone() or {}
+ watermark = list(row.values())[0] if row else "1970-01-01"
+ where_sql = f'WHERE "{order_col}" > %s'
+ params.append(watermark)
+
+ default_cols = [c for c in insert_cols if c.lower() not in mapping]
+ default_expr_map: Dict[str, str] = {}
+ if default_cols:
+ default_exprs = self._build_fact_select_exprs(default_cols, dwd_types, ods_types)
+ default_expr_map = dict(zip(default_cols, default_exprs))
+
+ select_exprs: List[str] = []
+ for col in insert_cols:
+ key = col.lower()
+ if key in mapping:
+ src, cast_type = mapping[key]
+ select_exprs.append(self._cast_expr(src, cast_type))
+ else:
+ select_exprs.append(default_expr_map[col])
+
+ select_cols_sql = ", ".join(select_exprs)
+ insert_cols_sql = ", ".join(f'"{c}"' for c in insert_cols)
+ sql = f'INSERT INTO {dwd_table_sql} ({insert_cols_sql}) SELECT {select_cols_sql} FROM {ods_table_sql} {where_sql}'
+
+ pk_cols = self._get_primary_keys(cur, dwd_table)
+ if pk_cols:
+ pk_sql = ", ".join(f'"{c}"' for c in pk_cols)
+ sql += f" ON CONFLICT ({pk_sql}) DO NOTHING"
+
+ cur.execute(sql, params)
+ return cur.rowcount
+
+ def _pick_order_column(self, dwd_cols: Iterable[str], ods_cols: Iterable[str]) -> str | None:
+ """选择用于增量的时间列(需同时存在于 DWD 与 ODS)。"""
+ lower_cols = {c.lower() for c in dwd_cols} & {c.lower() for c in ods_cols}
+ for candidate in self.FACT_ORDER_CANDIDATES:
+ if candidate.lower() in lower_cols:
+ return candidate.lower()
+ return None
+
+ def _build_fact_select_exprs(
+ self,
+ insert_cols: Sequence[str],
+ dwd_types: Dict[str, str],
+ ods_types: Dict[str, str],
+ ) -> List[str]:
+ """构造事实表 SELECT 列表,需要时做类型转换。"""
+ numeric_types = {"integer", "bigint", "smallint", "numeric", "double precision", "real", "decimal"}
+ text_types = {"text", "character varying", "varchar"}
+ exprs = []
+ for col in insert_cols:
+ d_type = dwd_types.get(col)
+ o_type = ods_types.get(col)
+ if d_type in numeric_types and o_type in text_types:
+ exprs.append(f"CAST(NULLIF(CAST(\"{col}\" AS text), '') AS numeric):: {d_type}")
+ else:
+ exprs.append(f'"{col}"')
+ return exprs
+
+ def _split_table_name(self, name: str, default_schema: str) -> tuple[str, str]:
+ """拆分 schema.table,若无 schema 则补默认 schema。"""
+ parts = name.split(".")
+ if len(parts) == 2:
+ return parts[0], parts[1].lower()
+ return default_schema, name.lower()
+
+ def _table_base(self, name: str) -> str:
+ """获取不含 schema 的表名。"""
+ return name.split(".")[-1]
+
+ def _format_table(self, name: str, default_schema: str) -> str:
+ """返回带引号的 schema.table 名称。"""
+ schema, table = self._split_table_name(name, default_schema)
+ return f'"{schema}"."{table}"'
+
+ def _cast_expr(self, col: str, cast_type: str | None) -> str:
+ """构造带可选 CAST 的列表达式。"""
+ if col.upper() == "NULL":
+ base = "NULL"
+ else:
+ is_expr = not col.isidentifier() or "->" in col or "#>>" in col or "::" in col or "'" in col
+ base = col if is_expr else f'"{col}"'
+ if cast_type:
+ cast_lower = cast_type.lower()
+ if cast_lower in {"bigint", "integer", "numeric", "decimal"}:
+ return f"CAST(NULLIF(CAST({base} AS text), '') AS numeric):: {cast_type}"
+ if cast_lower == "timestamptz":
+ return f"({base})::timestamptz"
+ return f"{base}::{cast_type}"
+ return base
diff --git a/etl_billiards/tasks/dwd_quality_task.py b/etl_billiards/tasks/dwd_quality_task.py
new file mode 100644
index 0000000..d2df657
--- /dev/null
+++ b/etl_billiards/tasks/dwd_quality_task.py
@@ -0,0 +1,105 @@
+# -*- coding: utf-8 -*-
+"""DWD 质量核对任务:按 dwd_quality_check.md 输出行数/金额对照报表。"""
+from __future__ import annotations
+
+import json
+from datetime import datetime
+from pathlib import Path
+from typing import Any, Dict, Iterable, List, Sequence, Tuple
+
+from psycopg2.extras import RealDictCursor
+
+from .base_task import BaseTask, TaskContext
+from .dwd_load_task import DwdLoadTask
+
+
+class DwdQualityTask(BaseTask):
+ """对 ODS 与 DWD 进行行数、金额对照核查,生成 JSON 报表。"""
+
+ REPORT_PATH = Path("etl_billiards/reports/dwd_quality_report.json")
+ AMOUNT_KEYWORDS = ("amount", "money", "fee", "balance")
+
+ def get_task_code(self) -> str:
+ """返回任务编码。"""
+ return "DWD_QUALITY_CHECK"
+
+ def extract(self, context: TaskContext) -> dict[str, Any]:
+ """准备运行时上下文。"""
+ return {"now": datetime.now()}
+
+ def load(self, extracted: dict[str, Any], context: TaskContext) -> dict[str, Any]:
+ """输出行数/金额差异报表到本地文件。"""
+ report: Dict[str, Any] = {
+ "generated_at": extracted["now"].isoformat(),
+ "tables": [],
+ "note": "行数/金额核对,金额字段基于列名包含 amount/money/fee/balance 的数值列自动扫描。",
+ }
+
+ with self.db.conn.cursor(cursor_factory=RealDictCursor) as cur:
+ for dwd_table, ods_table in DwdLoadTask.TABLE_MAP.items():
+ count_info = self._compare_counts(cur, dwd_table, ods_table)
+ amount_info = self._compare_amounts(cur, dwd_table, ods_table)
+ report["tables"].append(
+ {
+ "dwd_table": dwd_table,
+ "ods_table": ods_table,
+ "count": count_info,
+ "amounts": amount_info,
+ }
+ )
+
+ self.REPORT_PATH.parent.mkdir(parents=True, exist_ok=True)
+ self.REPORT_PATH.write_text(json.dumps(report, ensure_ascii=False, indent=2), encoding="utf-8")
+ self.logger.info("DWD 质检报表已生成:%s", self.REPORT_PATH)
+ return {"report_path": str(self.REPORT_PATH)}
+
+ # ---------------------- helpers ----------------------
+ def _compare_counts(self, cur, dwd_table: str, ods_table: str) -> Dict[str, Any]:
+ """统计两端行数并返回差异。"""
+ dwd_schema, dwd_name = self._split_table_name(dwd_table, default_schema="billiards_dwd")
+ ods_schema, ods_name = self._split_table_name(ods_table, default_schema="billiards_ods")
+ cur.execute(f'SELECT COUNT(1) AS cnt FROM "{dwd_schema}"."{dwd_name}"')
+ dwd_cnt = cur.fetchone()["cnt"]
+ cur.execute(f'SELECT COUNT(1) AS cnt FROM "{ods_schema}"."{ods_name}"')
+ ods_cnt = cur.fetchone()["cnt"]
+ return {"dwd": dwd_cnt, "ods": ods_cnt, "diff": dwd_cnt - ods_cnt}
+
+ def _compare_amounts(self, cur, dwd_table: str, ods_table: str) -> List[Dict[str, Any]]:
+ """扫描金额相关列,生成 ODS 与 DWD 的汇总对照。"""
+ dwd_schema, dwd_name = self._split_table_name(dwd_table, default_schema="billiards_dwd")
+ ods_schema, ods_name = self._split_table_name(ods_table, default_schema="billiards_ods")
+
+ dwd_amount_cols = self._get_numeric_amount_columns(cur, dwd_schema, dwd_name)
+ ods_amount_cols = self._get_numeric_amount_columns(cur, ods_schema, ods_name)
+ common_amount_cols = sorted(set(dwd_amount_cols) & set(ods_amount_cols))
+
+ results: List[Dict[str, Any]] = []
+ for col in common_amount_cols:
+ cur.execute(f'SELECT COALESCE(SUM("{col}"),0) AS val FROM "{dwd_schema}"."{dwd_name}"')
+ dwd_sum = cur.fetchone()["val"]
+ cur.execute(f'SELECT COALESCE(SUM("{col}"),0) AS val FROM "{ods_schema}"."{ods_name}"')
+ ods_sum = cur.fetchone()["val"]
+ results.append({"column": col, "dwd_sum": float(dwd_sum or 0), "ods_sum": float(ods_sum or 0), "diff": float(dwd_sum or 0) - float(ods_sum or 0)})
+ return results
+
+ def _get_numeric_amount_columns(self, cur, schema: str, table: str) -> List[str]:
+ """获取列名包含金额关键词的数值型字段。"""
+ cur.execute(
+ """
+ SELECT column_name
+ FROM information_schema.columns
+ WHERE table_schema = %s
+ AND table_name = %s
+ AND data_type IN ('numeric','double precision','integer','bigint','smallint','real','decimal')
+ """,
+ (schema, table),
+ )
+ cols = [r["column_name"].lower() for r in cur.fetchall()]
+ return [c for c in cols if any(key in c for key in self.AMOUNT_KEYWORDS)]
+
+ def _split_table_name(self, name: str, default_schema: str) -> Tuple[str, str]:
+ """拆分 schema 与表名,缺省使用 default_schema。"""
+ parts = name.split(".")
+ if len(parts) == 2:
+ return parts[0], parts[1]
+ return default_schema, name
diff --git a/etl_billiards/tasks/init_dwd_schema_task.py b/etl_billiards/tasks/init_dwd_schema_task.py
new file mode 100644
index 0000000..fa92aae
--- /dev/null
+++ b/etl_billiards/tasks/init_dwd_schema_task.py
@@ -0,0 +1,36 @@
+# -*- coding: utf-8 -*-
+"""初始化 DWD Schema:执行 schema_dwd_doc.sql,可选先 DROP SCHEMA。"""
+from __future__ import annotations
+
+from pathlib import Path
+from typing import Any
+
+from .base_task import BaseTask, TaskContext
+
+
+class InitDwdSchemaTask(BaseTask):
+ """通过调度执行 DWD schema 初始化。"""
+
+ def get_task_code(self) -> str:
+ """返回任务编码。"""
+ return "INIT_DWD_SCHEMA"
+
+ def extract(self, context: TaskContext) -> dict[str, Any]:
+ """读取 DWD SQL 文件与参数。"""
+ base_dir = Path(__file__).resolve().parents[1] / "database"
+ dwd_path = Path(self.config.get("schema.dwd_file", base_dir / "schema_dwd_doc.sql"))
+ if not dwd_path.exists():
+ raise FileNotFoundError(f"未找到 DWD schema 文件: {dwd_path}")
+
+ drop_first = self.config.get("dwd.drop_schema_first", False)
+ return {"dwd_sql": dwd_path.read_text(encoding="utf-8"), "dwd_file": str(dwd_path), "drop_first": drop_first}
+
+ def load(self, extracted: dict[str, Any], context: TaskContext) -> dict:
+ """可选 DROP schema,再执行 DWD DDL。"""
+ with self.db.conn.cursor() as cur:
+ if extracted["drop_first"]:
+ cur.execute("DROP SCHEMA IF EXISTS billiards_dwd CASCADE;")
+ self.logger.info("已执行 DROP SCHEMA billiards_dwd CASCADE")
+ self.logger.info("执行 DWD schema 文件: %s", extracted["dwd_file"])
+ cur.execute(extracted["dwd_sql"])
+ return {"executed": 1, "files": [extracted["dwd_file"]]}
diff --git a/etl_billiards/tasks/init_schema_task.py b/etl_billiards/tasks/init_schema_task.py
new file mode 100644
index 0000000..9e98caa
--- /dev/null
+++ b/etl_billiards/tasks/init_schema_task.py
@@ -0,0 +1,73 @@
+# -*- coding: utf-8 -*-
+"""任务:初始化运行环境,执行 ODS 与 etl_admin 的 DDL,并准备日志/导出目录。"""
+from __future__ import annotations
+
+from pathlib import Path
+from typing import Any
+
+from .base_task import BaseTask, TaskContext
+
+
+class InitOdsSchemaTask(BaseTask):
+ """通过调度执行初始化:创建必要目录,执行 ODS 与 etl_admin 的 DDL。"""
+
+ def get_task_code(self) -> str:
+ """返回任务编码。"""
+ return "INIT_ODS_SCHEMA"
+
+ def extract(self, context: TaskContext) -> dict[str, Any]:
+ """读取 SQL 文件路径,收集需创建的目录。"""
+ base_dir = Path(__file__).resolve().parents[1] / "database"
+ ods_path = Path(self.config.get("schema.ods_file", base_dir / "schema_ODS_doc.sql"))
+ admin_path = Path(self.config.get("schema.etl_admin_file", base_dir / "schema_etl_admin.sql"))
+ if not ods_path.exists():
+ raise FileNotFoundError(f"找不到 ODS schema 文件: {ods_path}")
+ if not admin_path.exists():
+ raise FileNotFoundError(f"找不到 etl_admin schema 文件: {admin_path}")
+
+ log_root = Path(self.config.get("io.log_root") or self.config["io"]["log_root"])
+ export_root = Path(self.config.get("io.export_root") or self.config["io"]["export_root"])
+ fetch_root = Path(self.config.get("pipeline.fetch_root") or self.config["pipeline"]["fetch_root"])
+ ingest_dir = Path(self.config.get("pipeline.ingest_source_dir") or fetch_root)
+
+ return {
+ "ods_sql": ods_path.read_text(encoding="utf-8"),
+ "admin_sql": admin_path.read_text(encoding="utf-8"),
+ "ods_file": str(ods_path),
+ "admin_file": str(admin_path),
+ "dirs": [log_root, export_root, fetch_root, ingest_dir],
+ }
+
+ def load(self, extracted: dict[str, Any], context: TaskContext) -> dict:
+ """执行 DDL 并创建必要目录。
+
+ 安全提示:
+ ODS DDL 文件可能携带头部说明或异常注释,为避免因非 SQL 文本导致执行失败,这里会做一次轻量清洗后再执行。
+ """
+ for d in extracted["dirs"]:
+ Path(d).mkdir(parents=True, exist_ok=True)
+ self.logger.info("已确保目录存在: %s", d)
+
+ # 处理 ODS SQL:去掉头部说明行,以及易出错的 COMMENT ON 行(如 CamelCase 未加引号)
+ ods_sql_raw: str = extracted["ods_sql"]
+ drop_idx = ods_sql_raw.find("DROP SCHEMA")
+ if drop_idx > 0:
+ ods_sql_raw = ods_sql_raw[drop_idx:]
+ cleaned_lines: list[str] = []
+ for line in ods_sql_raw.splitlines():
+ if line.strip().upper().startswith("COMMENT ON "):
+ continue
+ cleaned_lines.append(line)
+ ods_sql = "\n".join(cleaned_lines)
+
+ with self.db.conn.cursor() as cur:
+ self.logger.info("执行 etl_admin schema 文件: %s", extracted["admin_file"])
+ cur.execute(extracted["admin_sql"])
+ self.logger.info("执行 ODS schema 文件: %s", extracted["ods_file"])
+ cur.execute(ods_sql)
+
+ return {
+ "executed": 2,
+ "files": [extracted["admin_file"], extracted["ods_file"]],
+ "dirs_prepared": [str(p) for p in extracted["dirs"]],
+ }
diff --git a/etl_billiards/tasks/manual_ingest_task.py b/etl_billiards/tasks/manual_ingest_task.py
index 695f519..14ed8ae 100644
--- a/etl_billiards/tasks/manual_ingest_task.py
+++ b/etl_billiards/tasks/manual_ingest_task.py
@@ -1,58 +1,85 @@
# -*- coding: utf-8 -*-
-"""Manual ingestion task that replays archived JSON into ODS tables."""
+"""手工示例数据灌入:按 schema_ODS_doc.sql 的表结构写入 ODS。"""
from __future__ import annotations
import json
import os
from datetime import datetime
-from typing import Iterable, Iterator
+from typing import Any, Iterable
+
+from psycopg2.extras import Json
from .base_task import BaseTask
class ManualIngestTask(BaseTask):
- """
- Load archived API responses (tests/source-data-doc) into billiards_ods.* tables.
- Used when upstream API is unavailable and we need to replay captured payloads.
- """
+ """本地示例 JSON 灌入 ODS,确保表名/主键/插入列与 schema_ODS_doc.sql 对齐。"""
- # 仅保留已确认的新表映射,其余表待逐一校准后再添加
FILE_MAPPING: list[tuple[tuple[str, ...], str]] = [
- (("助教账号",), "billiards_ods.assistant_accounts_master"),
- (("助教流水",), "billiards_ods.assistant_service_records"),
- (("助教废除", "助教作废"), "billiards_ods.assistant_cancellation_records"),
- (("库存变化记录1",), "billiards_ods.goods_stock_movements"),
- (("库存汇总", "库存汇总记录"), "billiards_ods.goods_stock_summary"),
- (("团购套餐", "套餐定义"), "billiards_ods.group_buy_packages"),
- (("团购核销", "套餐使用", "团购使用"), "billiards_ods.group_buy_redemption_records"),
- (("余额变动", "余额变更"), "billiards_ods.member_balance_changes"),
- (("会员档案", "会员列表"), "billiards_ods.member_profiles"),
- (("储值卡", "会员储值卡"), "billiards_ods.member_stored_value_cards"),
- (("支付记录", "支付流水"), "billiards_ods.payment_transactions"),
- (("平台验券", "团购验券", "平台券核销"), "billiards_ods.platform_coupon_redemption_records"),
- (("充值结算", "充值记录"), "billiards_ods.recharge_settlements"),
- (("退款流水", "退款记录"), "billiards_ods.refund_transactions"),
- (("结账记录", "结算记录"), "billiards_ods.settlement_records"),
- (("小票详情", "结账小票"), "billiards_ods.settlement_ticket_details"),
- (("台桌列表", "台桌维表"), "billiards_ods.site_tables_master"),
- (("商品分类树", "库存分类"), "billiards_ods.stock_goods_category_tree"),
- (("门店商品档案",), "billiards_ods.store_goods_master"),
- (("门店商品销售", "商品销售流水"), "billiards_ods.store_goods_sales_records"),
- (("台费折扣", "台费调账"), "billiards_ods.table_fee_discount_records"),
- (("台费流水", "台费计费"), "billiards_ods.table_fee_transactions"),
- (("租户商品档案", "商品档案"), "billiards_ods.tenant_goods_master"),
+ (("member_profiles",), "billiards_ods.member_profiles"),
+ (("member_balance_changes",), "billiards_ods.member_balance_changes"),
+ (("member_stored_value_cards",), "billiards_ods.member_stored_value_cards"),
+ (("recharge_settlements",), "billiards_ods.recharge_settlements"),
+ (("settlement_records",), "billiards_ods.settlement_records"),
+ (("assistant_cancellation_records",), "billiards_ods.assistant_cancellation_records"),
+ (("assistant_accounts_master",), "billiards_ods.assistant_accounts_master"),
+ (("assistant_service_records",), "billiards_ods.assistant_service_records"),
+ (("site_tables_master",), "billiards_ods.site_tables_master"),
+ (("table_fee_discount_records",), "billiards_ods.table_fee_discount_records"),
+ (("table_fee_transactions",), "billiards_ods.table_fee_transactions"),
+ (("goods_stock_movements",), "billiards_ods.goods_stock_movements"),
+ (("stock_goods_category_tree",), "billiards_ods.stock_goods_category_tree"),
+ (("goods_stock_summary",), "billiards_ods.goods_stock_summary"),
+ (("payment_transactions",), "billiards_ods.payment_transactions"),
+ (("refund_transactions",), "billiards_ods.refund_transactions"),
+ (("platform_coupon_redemption_records",), "billiards_ods.platform_coupon_redemption_records"),
+ (("group_buy_redemption_records",), "billiards_ods.group_buy_redemption_records"),
+ (("group_buy_packages",), "billiards_ods.group_buy_packages"),
+ (("settlement_ticket_details",), "billiards_ods.settlement_ticket_details"),
+ (("store_goods_master",), "billiards_ods.store_goods_master"),
+ (("tenant_goods_master",), "billiards_ods.tenant_goods_master"),
+ (("store_goods_sales_records",), "billiards_ods.store_goods_sales_records"),
]
- WRAPPER_META_KEYS = {"code", "message", "msg", "success", "error", "status"}
+
+ TABLE_SPECS: dict[str, dict[str, Any]] = {
+ "billiards_ods.member_profiles": {"pk": "id"},
+ "billiards_ods.member_balance_changes": {"pk": "id"},
+ "billiards_ods.member_stored_value_cards": {"pk": "id"},
+ "billiards_ods.recharge_settlements": {"pk": "id"},
+ "billiards_ods.settlement_records": {"pk": "id"},
+ "billiards_ods.assistant_cancellation_records": {"pk": "id", "json_cols": ["siteProfile"]},
+ "billiards_ods.assistant_accounts_master": {"pk": "id"},
+ "billiards_ods.assistant_service_records": {"pk": "id", "json_cols": ["siteProfile"]},
+ "billiards_ods.site_tables_master": {"pk": "id"},
+ "billiards_ods.table_fee_discount_records": {"pk": "id", "json_cols": ["siteProfile", "tableProfile"]},
+ "billiards_ods.table_fee_transactions": {"pk": "id", "json_cols": ["siteProfile"]},
+ "billiards_ods.goods_stock_movements": {"pk": "siteGoodsStockId"},
+ "billiards_ods.stock_goods_category_tree": {"pk": "id", "json_cols": ["categoryBoxes"]},
+ "billiards_ods.goods_stock_summary": {"pk": "siteGoodsId"},
+ "billiards_ods.payment_transactions": {"pk": "id", "json_cols": ["siteProfile"]},
+ "billiards_ods.refund_transactions": {"pk": "id", "json_cols": ["siteProfile"]},
+ "billiards_ods.platform_coupon_redemption_records": {"pk": "id"},
+ "billiards_ods.tenant_goods_master": {"pk": "id"},
+ "billiards_ods.group_buy_packages": {"pk": "id"},
+ "billiards_ods.group_buy_redemption_records": {"pk": "id"},
+ "billiards_ods.settlement_ticket_details": {
+ "pk": "orderSettleId",
+ "json_cols": ["memberProfile", "orderItem", "tenantMemberCardLogs"],
+ },
+ "billiards_ods.store_goods_master": {"pk": "id"},
+ "billiards_ods.store_goods_sales_records": {"pk": "id"},
+ }
def get_task_code(self) -> str:
+ """返回任务编码。"""
return "MANUAL_INGEST"
- def execute(self) -> dict:
- self.logger.info("Starting Manual Ingest Task")
-
- data_dir = self.config.get(
- "manual.data_dir",
- r"c:\dev\LLTQ\ETL\feiqiu-ETL\etl_billiards\tests\testdata_json",
+ def execute(self, cursor_data: dict | None = None) -> dict:
+ """从目录读取 JSON,按表定义批量入库。"""
+ data_dir = (
+ self.config.get("manual.data_dir")
+ or self.config.get("pipeline.ingest_source_dir")
+ or r"c:\dev\LLTQ\ETL\feiqiu-ETL\etl_billiards\tests\testdata_json"
)
if not os.path.exists(data_dir):
self.logger.error("Data directory not found: %s", data_dir)
@@ -63,7 +90,6 @@ class ManualIngestTask(BaseTask):
for filename in sorted(os.listdir(data_dir)):
if not filename.endswith(".json"):
continue
-
filepath = os.path.join(data_dir, filename)
try:
with open(filepath, "r", encoding="utf-8") as fh:
@@ -73,59 +99,29 @@ class ManualIngestTask(BaseTask):
self.logger.exception("Failed to read %s", filename)
continue
- if not isinstance(raw_entries, list):
- raw_entries = [raw_entries]
-
- records = self._normalize_records(raw_entries)
+ entries = raw_entries if isinstance(raw_entries, list) else [raw_entries]
+ records = self._extract_records(entries)
if not records:
counts["skipped"] += 1
continue
- target_table = self._match_by_filename(filename) or self._match_by_content(
- records, raw_entries
- )
+ target_table = self._match_by_filename(filename)
if not target_table:
self.logger.warning("No mapping found for file: %s", filename)
counts["skipped"] += 1
continue
self.logger.info("Ingesting %s into %s", filename, target_table)
-
try:
- rows = []
- for record in records:
- site_id = self._extract_store_id(record) or self.config.get(
- "app.store_id"
- )
- pk_value = self._extract_pk(record, target_table)
- pk_tuple = self._ensure_tuple(pk_value)
- if not all(value not in (None, "") for value in pk_tuple):
- continue
-
- row = {
- "site_id": site_id,
- "payload": json.dumps(record, ensure_ascii=False),
- "source_file": filename,
- "fetched_at": datetime.now(),
- }
- for column, value in zip(
- self._get_conflict_columns(target_table), pk_tuple
- ):
- row[column] = value
- self._enrich_row(row, record, target_table)
- rows.append(row)
-
- if rows:
- self._bulk_insert(target_table, rows)
- counts["inserted"] += len(rows)
- else:
- counts["skipped"] += 1
- counts["fetched"] += 1
-
+ inserted, updated = self._ingest_table(target_table, records, filename)
+ counts["inserted"] += inserted
+ counts["updated"] += updated
+ counts["fetched"] += len(records)
except Exception:
counts["errors"] += 1
self.logger.exception("Error processing %s", filename)
self.db.rollback()
+ continue
try:
self.db.commit()
@@ -133,869 +129,219 @@ class ManualIngestTask(BaseTask):
self.db.rollback()
raise
- return self._build_result("SUCCESS", counts)
+ return {"status": "SUCCESS", "counts": counts}
- # ------------------------------------------------------------------ helpers
def _match_by_filename(self, filename: str) -> str | None:
+ """根据文件名关键字匹配目标表。"""
for keywords, table in self.FILE_MAPPING:
if any(keyword and keyword in filename for keyword in keywords):
return table
return None
- def _match_by_content(
- self, records: list[dict], raw_entries: list[dict]
- ) -> str | None:
- """
- Map content to PRD ODS tables.
- """
- sample_record = records[0] if records else None
- wrapper = self._extract_sample(raw_entries)
- data_node = wrapper.get("data") if isinstance(wrapper, dict) else None
- data_keys = set(data_node.keys()) if isinstance(data_node, dict) else set()
- record_keys = set(sample_record.keys()) if isinstance(sample_record, dict) else set()
-
- # Data node based hints
- if "tenantMemberInfos" in data_keys:
- return "billiards_ods.ods_member_profile"
- if "tenantMemberCards" in data_keys:
- return "billiards_ods.ods_member_card"
- if "queryDeliveryRecordsList" in data_keys:
- return "billiards_ods.ods_inventory_change"
- if "goodsStockA" in data_keys or "rangeStartStock" in data_keys:
- return "billiards_ods.ods_inventory_stock"
- if "goodsCategoryList" in data_keys:
- return "billiards_ods.ods_goods_category"
- if "orderAssistantDetails" in data_keys:
- return "billiards_ods.ods_assistant_service_log"
- if "abolitionAssistants" in data_keys:
- return "billiards_ods.ods_assistant_cancel_log"
- if "siteTableUseDetailsList" in data_keys:
- return "billiards_ods.ods_table_use_log"
- if "taiFeeAdjustInfos" in data_keys:
- return "billiards_ods.ods_table_fee_adjust"
- if "orderGoodsLedgers" in data_keys or "orderGoodsList" in data_keys:
- return "billiards_ods.ods_store_sale_item"
- if "tenantGoodsList" in data_keys:
- return "billiards_ods.ods_store_product"
- if "packageCouponList" in data_keys:
- return "billiards_ods.ods_group_package"
- if "settleList" in data_keys and "total" in data_keys:
- return "billiards_ods.ods_order_settle"
-
- # Record key based hints
- if sample_record:
- if {"pay_amount", "pay_status"} <= record_keys or {"payAmount", "payStatus"} <= record_keys:
- return "billiards_ods.ods_payment_record"
- if "refundAmount" in record_keys or "refund_amount" in record_keys:
- return "billiards_ods.ods_refund_record"
- if "orderSettleId" in record_keys or "order_settle_id" in record_keys:
- return "billiards_ods.ods_order_receipt_detail"
- if "coupon_channel" in record_keys or "groupPackageId" in record_keys:
- return "billiards_ods.ods_platform_coupon_log"
- if "packageId" in record_keys or "package_id" in record_keys:
- return "billiards_ods.ods_group_package_log"
- if "memberCardId" in record_keys or "cardId" in record_keys:
- return "billiards_ods.ods_member_card"
- if "memberId" in record_keys:
- return "billiards_ods.ods_member_profile"
- if "siteGoodsId" in record_keys and "currentStock" in record_keys:
- return "billiards_ods.ods_inventory_stock"
- if "goodsId" in record_keys:
- return "billiards_ods.ods_product"
-
- return None
-
- def _extract_sample(self, payloads: Iterable[dict]) -> dict:
- for item in payloads:
- if isinstance(item, dict):
- return item
- return {}
-
- def _normalize_records(self, payloads: list[dict]) -> list[dict]:
+ def _extract_records(self, raw_entries: Iterable[Any]) -> list[dict]:
+ """兼容多层 data/list 包装,抽取记录列表。"""
records: list[dict] = []
- for payload in payloads:
- records.extend(self._unwrap_payload(payload))
+ for entry in raw_entries:
+ if isinstance(entry, dict):
+ preferred = entry
+ if "data" in entry and not any(k not in {"data", "code"} for k in entry.keys()):
+ preferred = entry["data"]
+ data = preferred
+ if isinstance(data, dict):
+ # 特殊处理 settleList(充值、结算记录):展开 data.settleList 下的 settleList,抛弃上层 siteProfile
+ if "settleList" in data:
+ settle_list_val = data.get("settleList")
+ if isinstance(settle_list_val, dict):
+ settle_list_iter = [settle_list_val]
+ elif isinstance(settle_list_val, list):
+ settle_list_iter = settle_list_val
+ else:
+ settle_list_iter = []
+
+ handled = False
+ for item in settle_list_iter or []:
+ if not isinstance(item, dict):
+ continue
+ inner = item.get("settleList")
+ merged = dict(inner) if isinstance(inner, dict) else dict(item)
+ # 保留 siteProfile 供后续字段补充,但不落库
+ site_profile = data.get("siteProfile")
+ if isinstance(site_profile, dict):
+ merged.setdefault("siteProfile", site_profile)
+ records.append(merged)
+ handled = True
+ if handled:
+ continue
+
+ list_used = False
+ for v in data.values():
+ if isinstance(v, list) and v and isinstance(v[0], dict):
+ records.extend(v)
+ list_used = True
+ break
+ if list_used:
+ continue
+ if isinstance(data, list) and data and isinstance(data[0], dict):
+ records.extend(data)
+ elif isinstance(data, dict):
+ records.append(data)
+ elif isinstance(entry, list):
+ records.extend([item for item in entry if isinstance(item, dict)])
return records
- def _unwrap_payload(self, payload) -> list[dict]:
- if isinstance(payload, dict):
- data_node = payload.get("data")
- extra_keys = set(payload.keys()) - {"data"} - self.WRAPPER_META_KEYS
- if isinstance(data_node, dict) and not extra_keys:
- flattened: list[dict] = []
- found_list = False
- for value in data_node.values():
- if isinstance(value, list):
- flattened.extend(value)
- found_list = True
- if found_list:
- return flattened
- return [data_node]
- return [payload]
+ def _get_table_columns(self, table: str) -> list[tuple[str, str, str]]:
+ """查询 information_schema,获取目标表列信息。"""
+ cache = getattr(self, "_table_columns_cache", {})
+ if table in cache:
+ return cache[table]
+ if "." in table:
+ schema, name = table.split(".", 1)
+ else:
+ schema, name = "public", table
+ sql = """
+ SELECT column_name, data_type, udt_name
+ FROM information_schema.columns
+ WHERE table_schema = %s AND table_name = %s
+ ORDER BY ordinal_position
+ """
+ with self.db.conn.cursor() as cur:
+ cur.execute(sql, (schema, name))
+ cols = [(r[0], (r[1] or "").lower(), (r[2] or "").lower()) for r in cur.fetchall()]
+ cache[table] = cols
+ self._table_columns_cache = cache
+ return cols
- if isinstance(payload, list):
- flattened: list[dict] = []
- for item in payload:
- flattened.extend(self._unwrap_payload(item))
- return flattened
+ def _ingest_table(self, table: str, records: list[dict], source_file: str) -> tuple[int, int]:
+ """构建 INSERT/ON CONFLICT 语句并批量执行。"""
+ spec = self.TABLE_SPECS.get(table)
+ if not spec:
+ raise ValueError(f"No table spec for {table}")
- return []
+ pk_col = spec.get("pk")
+ json_cols = set(spec.get("json_cols", []))
+ json_cols_lower = {c.lower() for c in json_cols}
- def _extract_store_id(self, item: dict):
- """Extract site_id from record/siteProfile wrappers."""
- site_profile = item.get("siteProfile") or item.get("site_profile")
- if isinstance(site_profile, dict) and site_profile.get("id"):
- return site_profile["id"]
+ columns_info = self._get_table_columns(table)
+ columns = [c[0] for c in columns_info]
+ db_json_cols_lower = {
+ c[0].lower() for c in columns_info if c[1] in ("json", "jsonb") or c[2] in ("json", "jsonb")
+ }
+ pk_col_db = None
+ if pk_col:
+ pk_col_db = next((c for c in columns if c.lower() == pk_col.lower()), pk_col)
- for key in ("site_id", "siteId", "register_site_id"):
- if item.get(key):
- return item[key]
+ placeholders = ", ".join(["%s"] * len(columns))
+ col_list = ", ".join(f'"{c}"' for c in columns)
+ sql = f'INSERT INTO {table} ({col_list}) VALUES ({placeholders})'
+ if pk_col_db:
+ update_cols = [c for c in columns if c != pk_col_db]
+ set_clause = ", ".join(f'"{c}"=EXCLUDED."{c}"' for c in update_cols)
+ sql += f' ON CONFLICT ("{pk_col_db}") DO UPDATE SET {set_clause}'
+ sql += " RETURNING (xmax = 0) AS inserted"
- data_node = item.get("data")
- if isinstance(data_node, dict):
- return data_node.get("siteId") or data_node.get("site_id")
+ params = []
+ now = datetime.now()
+ json_dump = lambda v: json.dumps(v, ensure_ascii=False) # noqa: E731
+ for rec in records:
+ merged_rec = rec if isinstance(rec, dict) else {}
+ data_part = merged_rec.get("data")
+ while isinstance(data_part, dict):
+ merged_rec = {**data_part, **merged_rec}
+ data_part = data_part.get("data")
- return self.config.get("app.store_id")
+ # 针对充值/结算,补齐 siteProfile 中的店铺信息
+ if table in {
+ "billiards_ods.recharge_settlements",
+ "billiards_ods.settlement_records",
+ }:
+ site_profile = merged_rec.get("siteProfile") or merged_rec.get("site_profile")
+ if isinstance(site_profile, dict):
+ merged_rec.setdefault("tenantid", site_profile.get("tenant_id") or site_profile.get("tenantId"))
+ merged_rec.setdefault("siteid", site_profile.get("id") or site_profile.get("siteId"))
+ merged_rec.setdefault("sitename", site_profile.get("shop_name") or site_profile.get("siteName"))
- def _extract_pk(self, item: dict, table: str):
- if "ods_order_receipt_detail" in table:
- return item.get("orderSettleId") or item.get("order_settle_id") or item.get("id")
- if "ods_order_settle" in table:
- settle = item.get("settleList") or item.get("settle") or item
- if isinstance(settle, dict):
- return settle.get("id") or settle.get("settleId") or item.get("id")
- return item.get("id")
+ pk_val = self._get_value_case_insensitive(merged_rec, pk_col) if pk_col else None
+ if pk_col and (pk_val is None or pk_val == ""):
+ continue
- if "ods_payment_record" in table:
- return item.get("payId") or item.get("id")
+ row_vals = []
+ for col_name, data_type, udt in columns_info:
+ col_lower = col_name.lower()
+ if col_lower == "payload":
+ row_vals.append(Json(rec, dumps=json_dump))
+ continue
+ if col_lower == "source_file":
+ row_vals.append(source_file)
+ continue
+ if col_lower == "fetched_at":
+ row_vals.append(merged_rec.get(col_name, now))
+ continue
- if "ods_refund_record" in table:
- return item.get("refundId") or item.get("id")
+ value = self._normalize_scalar(self._get_value_case_insensitive(merged_rec, col_name))
- if "ods_platform_coupon_log" in table:
- return item.get("couponId") or item.get("id")
+ if col_lower in json_cols_lower or col_lower in db_json_cols_lower:
+ row_vals.append(Json(value, dumps=json_dump) if value is not None else None)
+ continue
- if "ods_assistant_service_log" in table or "ods_table_use_log" in table:
- return item.get("ledgerId") or item.get("ledger_id") or item.get("id")
+ casted = self._cast_value(value, data_type)
+ row_vals.append(casted)
+ params.append(tuple(row_vals))
- if "ods_assistant_cancel_log" in table:
- return item.get("cancel_id") or item.get("cancelId") or item.get("abolishId") or item.get("id")
+ if not params:
+ return 0, 0
- if "ods_store_sale_item" in table:
- return (
- item.get("sale_item_id")
- or item.get("saleItemId")
- or item.get("orderGoodsId")
- or item.get("order_goods_id")
- or item.get("id")
- )
+ inserted = 0
+ updated = 0
+ with self.db.conn.cursor() as cur:
+ for row in params:
+ cur.execute(sql, row)
+ flag = cur.fetchone()[0]
+ if flag:
+ inserted += 1
+ else:
+ updated += 1
+ return inserted, updated
- if "ods_inventory_change" in table:
- return item.get("siteGoodsStockId") or item.get("id")
-
- if "ods_inventory_stock" in table:
- return (
- item.get("siteGoodsId")
- or item.get("id"),
- item.get("snapshotKey") or item.get("snapshot_key") or "default",
- )
-
- if "ods_member_card" in table:
- return item.get("cardId") or item.get("memberCardId") or item.get("id")
-
- if "ods_member_profile" in table:
- return item.get("memberId") or item.get("id")
-
- if "ods_group_package_log" in table:
- return item.get("usage_id") or item.get("usageId") or item.get("couponId") or item.get("id")
-
- if "ods_group_package" in table:
- return item.get("package_id") or item.get("packageId") or item.get("groupPackageId") or item.get("id")
-
- if "ods_goods_category" in table:
- return item.get("category_id") or item.get("categoryId") or item.get("id")
-
- if "ods_table_fee_adjust" in table:
- return item.get("adjust_id") or item.get("adjustId") or item.get("id")
-
- if "ods_table_info" in table:
- return item.get("table_id") or item.get("tableId") or item.get("id")
-
- if "ods_assistant_account" in table:
- return item.get("assistantId") or item.get("assistant_id") or item.get("id")
-
- if "ods_store_product" in table:
- return item.get("siteGoodsId") or item.get("site_goods_id") or item.get("id")
-
- if "ods_product" in table:
- return item.get("goodsId") or item.get("goods_id") or item.get("id")
-
- if "ods_balance_change" in table:
- return item.get("change_id") or item.get("changeId") or item.get("id")
-
- if "ods_recharge_record" in table:
- return item.get("recharge_id") or item.get("rechargeId") or item.get("id")
-
- return item.get("id")
-
- def _get_conflict_columns(self, table: str) -> list[str]:
- if "ods_order_receipt_detail" in table:
- return ["order_settle_id"]
- if "ods_payment_record" in table:
- return ["pay_id"]
- if "ods_refund_record" in table:
- return ["refund_id"]
- if "ods_platform_coupon_log" in table:
- return ["coupon_id"]
- if "ods_assistant_service_log" in table or "ods_table_use_log" in table:
- return ["ledger_id"]
- if "ods_assistant_cancel_log" in table:
- return ["cancel_id"]
- if "ods_store_sale_item" in table:
- return ["sale_item_id"]
- if "ods_order_settle" in table:
- return ["order_settle_id"]
- if "ods_inventory_change" in table:
- return ["change_id"]
- if "ods_inventory_stock" in table:
- return ["site_goods_id", "snapshot_key"]
- if "ods_member_card" in table:
- return ["card_id"]
- if "ods_member_profile" in table:
- return ["member_id"]
- if "ods_group_package_log" in table:
- return ["usage_id"]
- if "ods_group_package" in table:
- return ["package_id"]
- if "ods_goods_category" in table:
- return ["category_id"]
- if "ods_table_info" in table:
- return ["table_id"]
- if "ods_table_fee_adjust" in table:
- return ["adjust_id"]
- if "ods_assistant_account" in table:
- return ["assistant_id"]
- if "ods_store_product" in table:
- return ["site_goods_id"]
- if "ods_product" in table:
- return ["goods_id"]
- if "ods_balance_change" in table:
- return ["change_id"]
- if "ods_recharge_record" in table:
- return ["recharge_id"]
- return ["id"]
-
- def _enrich_row(self, row: dict, record: dict, table: str):
- """Best-effort populate important columns from payload for PRD ODS schema."""
- def pick(obj, *keys):
- for k in keys:
- if isinstance(obj, dict) and obj.get(k) not in (None, ""):
- return obj.get(k)
+ @staticmethod
+ def _get_value_case_insensitive(record: dict, col: str | None):
+ """忽略大小写获取值,兼容 information_schema 与 JSON 原始字段。"""
+ if record is None or col is None:
return None
- def to_bool(value):
- if value in (None, ""):
- return None
- try:
- return bool(int(value))
- except Exception:
- if isinstance(value, bool):
- return value
- return None
- def to_int(value):
- if value in (None, ""):
- return None
+ if col in record:
+ return record.get(col)
+ col_lower = col.lower()
+ for k, v in record.items():
+ if isinstance(k, str) and k.lower() == col_lower:
+ return v
+ return None
+
+ @staticmethod
+ def _normalize_scalar(value):
+ """将空字符串/空 JSON 规范为 None,避免类型转换错误。"""
+ if value == "" or value == "{}" or value == "[]":
+ return None
+ return value
+
+ @staticmethod
+ def _cast_value(value, data_type: str):
+ """根据列类型做简单转换,保证批量插入兼容。"""
+ if value is None:
+ return None
+ dt = (data_type or "").lower()
+ if dt in ("integer", "bigint", "smallint"):
+ if isinstance(value, bool):
+ return int(value)
try:
return int(value)
except Exception:
return None
-
- if "ods_member_profile" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
- row["system_member_id"] = record.get("system_member_id")
- row["register_site_id"] = record.get("register_site_id")
- row["site_name"] = record.get("site_name")
- row["member_name"] = pick(record, "name", "memberName")
- row["nickname"] = record.get("nickname")
- row["mobile"] = record.get("mobile")
- row["gender"] = record.get("sex")
- row["birthday"] = record.get("birthday")
- row["register_time"] = record.get("register_time") or record.get("registerTime")
- row["member_type_id"] = pick(record, "cardTypeId", "member_type_id")
- row["member_type_name"] = record.get("cardTypeName")
- row["member_card_grade_code"] = record.get("member_card_grade_code")
- row["status"] = pick(record, "status", "state")
- row["user_status"] = record.get("user_status")
- row["balance"] = record.get("balance")
- row["points"] = record.get("points") or record.get("point")
- row["growth_value"] = record.get("growth_value")
- row["last_visit_time"] = record.get("lastVisitTime")
- row["wechat_id"] = record.get("wechatId")
- row["alipay_id"] = record.get("alipayId")
- row["member_card_no"] = record.get("cardNo")
- row["referrer_member_id"] = record.get("referrer_member_id")
- row["remarks"] = record.get("remark")
-
- if "ods_member_card" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
- row["member_id"] = pick(record, "memberId", "member_id")
- row["tenant_member_id"] = record.get("tenant_member_id")
- row["card_type_id"] = record.get("cardTypeId")
- row["card_type_name"] = record.get("cardTypeName")
- row["card_no"] = record.get("card_no") or record.get("cardNo")
- row["card_physics_type"] = record.get("card_physics_type")
- row["card_balance"] = record.get("balance")
- row["denomination"] = record.get("denomination")
- row["discount_rate"] = record.get("discount") or record.get("discount_rate")
- row["table_discount"] = record.get("table_discount")
- row["goods_discount"] = record.get("goods_discount")
- row["assistant_discount"] = record.get("assistant_discount")
- row["assistant_reward_discount"] = record.get("assistant_reward_discount")
- row["valid_start_date"] = record.get("validStart") or record.get("start_time")
- row["valid_end_date"] = record.get("validEnd") or record.get("end_time")
- row["disable_start_date"] = record.get("disable_start_time")
- row["disable_end_date"] = record.get("disable_end_time")
- row["last_consume_time"] = record.get("lastConsumeTime")
- row["status"] = record.get("status")
- row["is_delete"] = to_bool(record.get("is_delete"))
- row["activate_time"] = record.get("activateTime")
- row["deactivate_time"] = record.get("cancelTime")
- row["register_site_id"] = record.get("register_site_id")
- row["issuer_id"] = record.get("issuerId")
- row["issuer_name"] = record.get("issuerName")
-
- if "ods_recharge_record" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
- row["member_id"] = pick(record, "memberId", "member_id")
- row["recharge_amount"] = record.get("amount") or record.get("rechargeAmount")
- row["gift_amount"] = record.get("giftAmount")
- row["pay_method"] = record.get("payType") or record.get("pay_method")
- row["pay_trade_no"] = record.get("payTradeNo")
- row["order_trade_no"] = record.get("orderTradeNo")
- row["recharge_time"] = record.get("createTime") or record.get("rechargeTime")
- row["status"] = record.get("status")
- row["operator_id"] = record.get("operatorId")
- row["operator_name"] = record.get("operatorName")
-
- if "ods_balance_change" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
- row["site_id"] = row.get("site_id") or pick(record, "siteId", "site_id")
- row["member_id"] = pick(record, "memberId", "member_id")
- row["tenant_member_id"] = record.get("tenant_member_id")
- row["tenant_member_card_id"] = record.get("tenant_member_card_id")
- row["member_name"] = record.get("memberName")
- row["member_mobile"] = record.get("memberMobile")
- row["change_amount"] = record.get("change_amount") or record.get("account_data")
- row["balance_before"] = record.get("before_balance") or record.get("before")
- row["balance_after"] = record.get("after_balance") or record.get("after")
- row["change_type"] = record.get("from_type") or record.get("type")
- row["payment_method"] = record.get("payment_method")
- row["refund_amount"] = record.get("refund_amount")
- row["relate_id"] = record.get("relate_id")
- row["register_site_id"] = record.get("register_site_id")
- row["register_site_name"] = record.get("registerSiteName")
- row["pay_site_name"] = record.get("paySiteName")
- row["remark"] = record.get("remark")
- row["operator_id"] = record.get("operatorId")
- row["operator_name"] = record.get("operatorName")
- row["change_time"] = record.get("create_time") or record.get("changeTime")
- row["is_deleted"] = to_bool(record.get("is_delete") or record.get("is_deleted"))
- row["source_file"] = row.get("source_file")
- row["fetched_at"] = row.get("fetched_at")
-
- if "ods_assistant_account" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
- row["assistant_name"] = record.get("assistantName") or record.get("name")
- row["mobile"] = record.get("mobile")
- row["assistant_no"] = record.get("assistant_no") or record.get("assistantNo")
- row["team_id"] = record.get("teamId")
- row["team_name"] = record.get("teamName")
- row["group_id"] = record.get("group_id")
- row["group_name"] = record.get("group_name")
- row["job_num"] = record.get("job_num")
- row["entry_type"] = record.get("entry_type")
- row["leave_status"] = record.get("leave_status")
- row["assistant_status"] = record.get("assistant_status")
- row["allow_cx"] = to_bool(record.get("allow_cx"))
- row["status"] = record.get("status")
- row["hired_date"] = record.get("hireDate")
- row["left_date"] = record.get("leaveDate")
-
- if "ods_assistant_service_log" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
- row["assistant_id"] = record.get("assistantId") or record.get("site_assistant_id")
- row["assistant_name"] = record.get("assistantName") or record.get("ledger_name")
- row["service_type"] = record.get("serviceType") or record.get("order_assistant_type")
- row["order_trade_no"] = record.get("orderTradeNo")
- row["order_settle_id"] = record.get("orderSettleId")
- row["start_time"] = record.get("start_use_time") or record.get("startTime") or record.get("ledger_start_time")
- row["end_time"] = record.get("end_time") or record.get("last_use_time") or record.get("ledger_end_time")
- row["duration_seconds"] = record.get("real_use_seconds") or record.get("duration")
- row["original_fee"] = record.get("originFee") or record.get("original_fee") or record.get("ledger_amount")
- row["member_discount_amount"] = record.get("member_discount_amount")
- row["manual_discount_amount"] = record.get("manual_discount_amount")
- row["coupon_discount_amount"] = record.get("coupon_deduct_money")
- row["final_fee"] = record.get("finalFee") or record.get("final_fee") or record.get("service_money")
- row["member_id"] = record.get("memberId") or record.get("tenant_member_id")
- row["operator_id"] = record.get("operator_id")
- row["salesman_id"] = record.get("salesman_user_id")
- row["is_canceled"] = bool(record.get("is_trash"))
- row["cancel_time"] = record.get("trash_time")
- row["skill_grade"] = record.get("skill_grade")
- row["service_grade"] = record.get("service_grade")
- row["composite_grade"] = record.get("composite_grade")
- row["overall_score"] = record.get("sum_grade")
- row["status"] = record.get("status")
-
- if "ods_assistant_cancel_log" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
- row["ledger_id"] = record.get("ledgerId")
- row["assistant_id"] = record.get("assistantId")
- row["order_trade_no"] = record.get("orderTradeNo")
- row["table_id"] = record.get("tableId")
- row["table_area_id"] = record.get("tableAreaId")
- row["table_area_name"] = record.get("tableArea")
- row["table_name"] = record.get("tableName")
- row["assistant_on"] = record.get("assistantOn")
- row["pd_charge_minutes"] = record.get("pdChargeMinutes")
- row["assistant_abolish_amount"] = record.get("assistantAbolishAmount")
- row["reason"] = record.get("reason")
- row["cancel_time"] = record.get("cancel_time") or record.get("cancelTime")
- row["operator_id"] = record.get("operatorId")
- row["operator_name"] = record.get("operatorName")
-
- if "ods_table_info" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
- row["table_code"] = record.get("tableCode")
- row["table_name"] = record.get("tableName")
- row["table_type"] = record.get("tableType")
- row["area_name"] = record.get("areaName")
- row["site_table_area_id"] = record.get("site_table_area_id") or record.get("siteTableAreaId")
- row["tenant_table_area_id"] = record.get("tenant_table_area_id") or record.get("tenantTableAreaId")
- row["table_price"] = record.get("table_price") or record.get("tablePrice")
- row["table_status"] = record.get("table_status") or record.get("tableStatusName") or record.get("table_status")
- row["audit_status"] = record.get("audit_status")
- row["show_status"] = record.get("show_status")
- row["light_status"] = record.get("light_status")
- row["virtual_table"] = to_bool(record.get("virtual_table"))
- row["is_rest_area"] = to_bool(record.get("is_rest_area"))
- row["charge_free"] = to_bool(record.get("charge_free"))
- row["table_cloth_use_time"] = record.get("table_cloth_use_time")
- row["table_cloth_use_cycle"] = record.get("table_cloth_use_Cycle")
- row["status"] = record.get("status")
- row["created_time"] = record.get("createTime")
- row["updated_time"] = record.get("updateTime")
-
- if "ods_table_use_log" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
- row["table_id"] = record.get("tableId") or record.get("site_table_id")
- row["table_name"] = record.get("tableName") or record.get("ledger_name")
- row["order_trade_no"] = record.get("orderTradeNo")
- row["order_settle_id"] = record.get("orderSettleId")
- row["start_time"] = record.get("start_use_time") or record.get("startTime") or record.get("ledger_start_time")
- row["end_time"] = record.get("end_time") or record.get("ledger_end_time")
- row["duration_seconds"] = record.get("real_table_use_seconds") or record.get("duration")
- row["billing_unit_price"] = record.get("ledger_unit_price")
- row["billing_count"] = record.get("ledger_count")
- row["original_table_fee"] = record.get("originFee") or record.get("original_table_fee") or record.get("ledger_amount")
- row["member_discount_amount"] = record.get("member_discount_amount")
- row["coupon_discount_amount"] = record.get("coupon_promotion_amount")
- row["manual_discount_amount"] = record.get("adjust_amount") or record.get("discountAmount")
- row["service_fee"] = record.get("mgmt_fee") or record.get("service_money")
- row["final_table_fee"] = (
- record.get("finalFee")
- or record.get("final_table_fee")
- or record.get("real_table_charge_money")
- )
- row["member_id"] = record.get("memberId")
- row["operator_id"] = record.get("operator_id")
- row["salesman_id"] = record.get("salesman_user_id")
- row["is_canceled"] = bool(record.get("is_delete"))
- row["cancel_time"] = record.get("cancel_time")
- row["site_table_area_id"] = record.get("site_table_area_id")
- row["tenant_table_area_id"] = record.get("tenant_table_area_id")
- row["site_table_area_name"] = record.get("site_table_area_name")
- row["is_single_order"] = to_bool(record.get("is_single_order"))
- row["used_card_amount"] = record.get("used_card_amount")
- row["adjust_amount"] = record.get("adjust_amount")
- row["coupon_promotion_amount"] = record.get("coupon_promotion_amount")
- row["service_money"] = record.get("service_money")
- row["mgmt_fee"] = record.get("mgmt_fee")
- row["fee_total"] = record.get("fee_total")
- row["last_use_time"] = record.get("last_use_time")
- row["ledger_start_time"] = record.get("ledger_start_time")
- row["ledger_end_time"] = record.get("ledger_end_time")
- row["ledger_status"] = record.get("ledger_status")
- row["start_use_time"] = record.get("start_use_time")
- row["add_clock_seconds"] = record.get("add_clock_seconds")
- row["status"] = record.get("status")
-
- if "ods_table_fee_adjust" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
- row["ledger_id"] = record.get("ledgerId")
- row["order_trade_no"] = record.get("orderTradeNo")
- row["discount_amount"] = record.get("discountAmount")
- row["reason"] = record.get("reason")
- row["operator_id"] = record.get("operatorId")
- row["operator_name"] = record.get("operatorName")
- row["created_at"] = record.get("created_at") or record.get("createTime")
-
- if "ods_store_product" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
- row["goods_id"] = record.get("goodsId")
- row["goods_name"] = record.get("goodsName")
- row["category_id"] = record.get("categoryId")
- row["category_name"] = record.get("categoryName")
- row["unit"] = record.get("unit")
- row["sale_price"] = record.get("salePrice")
- row["cost_price"] = record.get("costPrice")
- row["sale_num"] = record.get("sale_num")
- row["stock_a"] = record.get("stock_A")
- row["stock"] = record.get("stock")
- row["provisional_total_cost"] = record.get("provisional_total_cost")
- row["total_purchase_cost"] = record.get("total_purchase_cost")
- row["batch_stock_quantity"] = record.get("batch_stock_quantity")
- row["goods_state"] = record.get("goods_state")
- row["status"] = record.get("status")
-
- if "ods_store_sale_item" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
- row["order_trade_no"] = record.get("orderTradeNo")
- row["order_settle_id"] = record.get("orderSettleId")
- row["order_goods_id"] = record.get("order_goods_id") or record.get("orderGoodsId")
- row["site_goods_id"] = record.get("site_goods_id") or record.get("siteGoodsId")
- row["goods_id"] = record.get("tenant_goods_id") or record.get("goodsId")
- row["goods_name"] = record.get("goodsName") or record.get("ledger_name")
- row["category_id"] = record.get("categoryId") or record.get("tenant_goods_category_id")
- row["quantity"] = record.get("quantity") or record.get("ledger_count")
- row["unit_price"] = record.get("unitPrice") or record.get("ledger_unit_price")
- row["original_amount"] = record.get("originalAmount") or record.get("ledger_amount")
- row["discount_amount"] = record.get("discountAmount") or record.get("discount_money")
- row["final_amount"] = record.get("finalAmount") or record.get("real_goods_money")
- row["discount_price"] = record.get("discount_price")
- row["cost_money"] = record.get("cost_money")
- row["coupon_deduct_amount"] = record.get("coupon_deduct_money")
- row["member_discount_amount"] = record.get("member_discount_amount")
- row["point_discount_money"] = record.get("point_discount_money")
- row["point_discount_cost"] = record.get("point_discount_money_cost")
- row["sales_type"] = record.get("sales_type")
- row["goods_remark"] = record.get("goods_remark")
- row["is_gift"] = to_bool(record.get("isGift"))
- row["sale_time"] = record.get("saleTime") or record.get("create_time")
- row["salesman_id"] = record.get("salesman_user_id")
- row["operator_id"] = record.get("operator_id")
- row["is_refunded"] = to_bool(record.get("is_delete")) or bool(record.get("returns_number"))
-
- if "ods_group_package_log" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
- row["package_id"] = record.get("packageId")
- row["coupon_id"] = record.get("couponId")
- row["order_trade_no"] = record.get("orderTradeNo")
- row["order_settle_id"] = record.get("orderSettleId")
- row["member_id"] = record.get("memberId")
- row["status"] = record.get("status")
- row["used_time"] = record.get("usedTime")
- row["deduct_amount"] = record.get("deductAmount")
- row["settle_price"] = record.get("settlePrice")
- row["coupon_code"] = record.get("coupon_code") or record.get("couponCode")
-
- if "ods_group_package" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
- row["package_name"] = record.get("packageName")
- row["table_area_id"] = record.get("table_area_id") or record.get("tableAreaId")
- row["table_area_name"] = record.get("tableAreaName")
- row["platform_code"] = record.get("platformCode")
- row["status"] = record.get("status")
- row["face_price"] = record.get("facePrice")
- row["settle_price"] = record.get("settlePrice")
- row["selling_price"] = record.get("selling_price")
- row["duration"] = record.get("duration")
- row["valid_from"] = record.get("validFrom") or record.get("start_time")
- row["valid_to"] = record.get("validTo") or record.get("end_time")
- row["start_time"] = record.get("start_time")
- row["end_time"] = record.get("end_time")
- row["is_enabled"] = to_bool(record.get("is_enabled"))
- row["is_delete"] = to_bool(record.get("is_delete"))
- row["package_type"] = record.get("type")
- row["usable_count"] = record.get("usable_count")
- row["creator_name"] = record.get("creator_name")
- row["tenant_table_area_id"] = record.get("tenant_table_area_id")
-
- if "ods_platform_coupon_log" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
- row["platform_code"] = record.get("platformCode")
- row["verify_code"] = record.get("verifyCode")
- row["order_trade_no"] = record.get("orderTradeNo")
- row["order_settle_id"] = record.get("orderSettleId")
- row["member_id"] = record.get("memberId")
- row["status"] = record.get("status")
- row["used_time"] = record.get("usedTime")
- row["deduct_amount"] = record.get("deductAmount")
- row["settle_price"] = record.get("settlePrice")
-
- if "ods_payment_record" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
- row["order_trade_no"] = record.get("orderTradeNo")
- row["order_settle_id"] = record.get("orderSettleId")
- row["member_id"] = record.get("memberId")
- row["pay_method_code"] = record.get("payMethodCode") or record.get("pay_type") or record.get("payment_method")
- row["pay_method_name"] = record.get("payMethodName")
- row["pay_status"] = record.get("pay_status")
- row["pay_amount"] = record.get("payAmount")
- row["pay_time"] = record.get("payTime")
- row["online_pay_channel"] = record.get("online_pay_channel")
- row["transaction_id"] = record.get("transaction_id")
- row["operator_id"] = record.get("operator_id")
- row["remark"] = record.get("remark")
- row["relate_type"] = record.get("relateType")
- row["relate_id"] = record.get("relateId")
-
- if "ods_refund_record" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
- row["order_trade_no"] = record.get("orderTradeNo")
- row["order_settle_id"] = record.get("orderSettleId")
- row["member_id"] = record.get("memberId")
- row["pay_sn"] = record.get("pay_sn")
- row["pay_amount"] = record.get("pay_amount")
- row["pay_status"] = record.get("pay_status")
- row["is_revoke"] = to_bool(record.get("is_revoke"))
- row["is_delete"] = to_bool(record.get("is_delete"))
- row["online_pay_channel"] = record.get("online_pay_channel")
- row["pay_method_code"] = record.get("payMethodCode")
- row["refund_amount"] = record.get("refundAmount")
- row["refund_time"] = record.get("refundTime")
- row["action_type"] = record.get("action_type")
- row["pay_terminal"] = record.get("pay_terminal")
- row["pay_config_id"] = record.get("pay_config_id")
- row["cashier_point_id"] = record.get("cashier_point_id")
- row["operator_id"] = record.get("operator_id")
- row["member_card_id"] = record.get("member_card_id")
- row["balance_frozen_amount"] = record.get("balance_frozen_amount")
- row["card_frozen_amount"] = record.get("card_frozen_amount")
- row["round_amount"] = record.get("round_amount")
- row["online_pay_type"] = record.get("online_pay_type")
- row["channel_payer_id"] = record.get("channel_payer_id")
- row["channel_pay_no"] = record.get("channel_pay_no")
- row["check_status"] = record.get("check_status")
- row["channel_fee"] = record.get("channel_fee")
- row["relate_type"] = record.get("relate_type")
- row["relate_id"] = record.get("relate_id")
- row["status"] = record.get("status")
- row["reason"] = record.get("reason")
- row["related_payment_id"] = record.get("related_payment_id") or record.get("payment_id")
-
- if "ods_inventory_change" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
- row["site_goods_id"] = record.get("siteGoodsId")
- row["goods_id"] = record.get("goodsId")
- row["stock_type"] = record.get("stockType")
- row["change_amount"] = record.get("changeAmount") or record.get("changeNum")
- row["before_stock"] = record.get("beforeStock") or record.get("startNum")
- row["after_stock"] = record.get("afterStock") or record.get("endNum")
- row["change_amount_alt"] = record.get("changeNumA")
- row["before_stock_alt"] = record.get("startNumA")
- row["after_stock_alt"] = record.get("endNumA")
- row["change_type"] = record.get("changeType")
- row["relate_id"] = record.get("relateId")
- row["unit"] = record.get("unit")
- row["price"] = record.get("price")
- row["goods_category_id"] = record.get("goodsCategoryId")
- row["goods_second_category_id"] = record.get("goodsSecondCategoryId")
- row["remark"] = record.get("remark")
- row["operator_id"] = record.get("operatorId")
- row["operator_name"] = record.get("operatorName")
- row["change_time"] = record.get("changeTime") or record.get("createTime")
-
- if "ods_inventory_stock" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
- row["goods_id"] = record.get("goodsId")
- row["goods_name"] = record.get("goodsName")
- row["goods_unit"] = record.get("goodsUnit")
- row["goods_category_id"] = record.get("goodsCategoryId")
- row["goods_second_category_id"] = record.get("goodsCategorySecondId")
- row["range_start_stock"] = record.get("rangeStartStock")
- row["range_end_stock"] = record.get("rangeEndStock")
- row["range_in"] = record.get("rangeIn")
- row["range_out"] = record.get("rangeOut")
- row["range_inventory"] = record.get("rangeInventory")
- row["range_sale"] = record.get("rangeSale")
- row["range_sale_money"] = record.get("rangeSaleMoney")
- row["current_stock"] = record.get("currentStock")
- row["cost_price"] = record.get("costPrice")
- row["category_name"] = record.get("categoryName")
-
- if "ods_goods_category" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
- row["category_name"] = record.get("categoryName")
- row["parent_id"] = record.get("parentId")
- row["level_no"] = record.get("levelNo")
- row["status"] = record.get("status")
- row["remark"] = record.get("remark")
-
- if "ods_order_receipt_detail" in table:
- detail = record
- if isinstance(record.get("data"), dict):
- detail = record["data"].get("data", record["data"])
- row["tenant_id"] = pick(detail, "tenantId", "tenant_id")
- row["order_trade_no"] = detail.get("orderTradeNo")
- row["order_settle_number"] = detail.get("orderSettleNumber")
- row["settle_type"] = to_int(detail.get("settleType"))
- row["receipt_no"] = detail.get("receiptNo")
- row["receipt_time"] = detail.get("receiptTime")
- row["total_amount"] = detail.get("totalAmount") or detail.get("ledgerAmount")
- row["discount_amount"] = detail.get("discountAmount")
- row["final_amount"] = detail.get("finalAmount")
- row["actual_payment"] = detail.get("actualPayment")
- row["ledger_amount"] = detail.get("ledgerAmount")
- row["member_offer_amount"] = detail.get("memberOfferAmount")
- row["delivery_fee"] = detail.get("deliveryFee")
- row["adjust_amount"] = detail.get("adjustAmount")
- row["payment_method"] = detail.get("paymentMethod")
- row["pay_time"] = detail.get("payTime")
- row["member_id"] = detail.get("memberId")
- row["order_remark"] = detail.get("orderRemark")
- row["cashier_name"] = detail.get("cashierName")
- row["ticket_remark"] = detail.get("ticketRemark")
- row["ticket_custom_content"] = detail.get("ticketCustomContent")
- row["voucher_money"] = detail.get("voucherMoney")
- row["reward_name"] = detail.get("rewardName")
- row["consume_money"] = detail.get("consumeMoney")
- row["refund_amount"] = detail.get("refundAmount")
- row["balance_amount"] = detail.get("balanceAmount")
- row["coupon_amount"] = detail.get("couponAmount")
- row["member_deduct_amount"] = detail.get("memberDeductAmount")
- row["prepay_money"] = detail.get("prepayMoney")
- row["delivery_address"] = detail.get("deliveryAddress")
- row["snapshot_raw"] = detail.get("siteProfile") or record.get("site_profile")
- row["member_snapshot"] = detail.get("memberProfile")
- if isinstance(row.get("snapshot_raw"), (dict, list)):
- row["snapshot_raw"] = json.dumps(row["snapshot_raw"], ensure_ascii=False)
- if isinstance(row.get("member_snapshot"), (dict, list)):
- row["member_snapshot"] = json.dumps(row["member_snapshot"], ensure_ascii=False)
-
- if "ods_order_settle" in table:
- settle_node = record.get("settleList") or record.get("settle")
- if not settle_node and isinstance(record.get("data"), dict):
- settle_node = record["data"].get("settleList") or record["data"].get("settle")
- if isinstance(settle_node, list):
- settle = settle_node[0] if settle_node else {}
- else:
- settle = settle_node or record
- if isinstance(settle, dict):
- row["site_id"] = row.get("site_id") or settle.get("siteId")
- row["tenant_id"] = pick(settle, "tenantId", "tenant_id")
- row["settle_relate_id"] = settle.get("settleRelateId")
- row["settle_name"] = settle.get("settleName")
- row["settle_type"] = settle.get("settleType")
- row["settle_status"] = settle.get("settleStatus")
- row["member_id"] = settle.get("memberId")
- row["member_name"] = settle.get("memberName")
- row["member_phone"] = settle.get("memberPhone")
- row["table_id"] = settle.get("tableId")
- row["consume_money"] = settle.get("consumeMoney")
- row["table_charge_money"] = settle.get("tableChargeMoney")
- row["goods_money"] = settle.get("goodsMoney")
- row["service_money"] = settle.get("serviceMoney")
- row["assistant_pd_money"] = settle.get("assistantPdMoney")
- row["assistant_cx_money"] = settle.get("assistantCxMoney")
- row["pay_amount"] = settle.get("payAmount")
- row["cash_amount"] = settle.get("cashAmount")
- row["online_amount"] = settle.get("onlineAmount")
- row["point_amount"] = settle.get("pointAmount")
- row["coupon_amount"] = settle.get("couponAmount")
- row["card_amount"] = settle.get("cardAmount")
- row["balance_amount"] = settle.get("balanceAmount")
- row["refund_amount"] = settle.get("refundAmount")
- row["prepay_money"] = settle.get("prepayMoney")
- row["adjust_amount"] = settle.get("adjustAmount")
- row["rounding_amount"] = settle.get("roundingAmount")
- row["member_discount_amount"] = settle.get("memberDiscountAmount")
- row["coupon_sale_amount"] = settle.get("couponSaleAmount")
- row["goods_promotion_money"] = settle.get("goodsPromotionMoney")
- row["assistant_promotion_money"] = settle.get("assistantPromotionMoney")
- row["point_discount_price"] = settle.get("pointDiscountPrice")
- row["point_discount_cost"] = settle.get("pointDiscountCost")
- row["real_goods_money"] = settle.get("realGoodsMoney")
- row["assistant_manual_discount"] = settle.get("assistantManualDiscount")
- row["all_coupon_discount"] = settle.get("allCouponDiscount")
- row["is_use_coupon"] = to_bool(settle.get("isUseCoupon"))
- row["is_use_discount"] = to_bool(settle.get("isUseDiscount"))
- row["is_activity"] = to_bool(settle.get("isActivity"))
- row["is_bind_member"] = to_bool(settle.get("isBindMember"))
- row["is_first"] = to_bool(settle.get("isFirst"))
- row["recharge_card_amount"] = settle.get("rechargeCardAmount")
- row["gift_card_amount"] = settle.get("giftCardAmount")
- row["payment_method"] = settle.get("paymentMethod")
- row["create_time"] = settle.get("createTime")
- row["pay_time"] = settle.get("payTime")
- row["revoke_order_id"] = settle.get("revokeOrderId")
- row["revoke_order_name"] = settle.get("revokeOrderName")
- row["revoke_time"] = settle.get("revokeTime")
- row["can_be_revoked"] = settle.get("canBeRevoked")
- row["serial_number"] = settle.get("serialNumber")
- row["sales_man_name"] = settle.get("salesManName")
- row["sales_man_user_id"] = settle.get("salesManUserId")
- row["order_remark"] = settle.get("orderRemark")
- row["operator_id"] = settle.get("operatorId")
- row["operator_name"] = settle.get("operatorName")
-
- if "ods_product" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
- row["goods_id"] = record.get("goodsId")
- row["goods_name"] = record.get("goodsName")
- row["goods_code"] = record.get("goodsCode")
- row["category_id"] = record.get("categoryId")
- row["category_name"] = record.get("categoryName")
- row["goods_second_category_id"] = record.get("goods_second_category_id") or record.get("goodsSecondCategoryId")
- row["unit"] = record.get("unit")
- row["price"] = record.get("price")
- row["cost_price"] = record.get("cost_price")
- row["market_price"] = record.get("market_price")
- row["goods_state"] = record.get("goods_state")
- row["goods_cover"] = record.get("goods_cover")
- row["goods_bar_code"] = record.get("goods_bar_code")
- row["able_discount"] = record.get("able_discount")
- row["is_delete"] = record.get("is_delete")
- row["status"] = record.get("status")
-
- if "ods_platform_coupon_log" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
- row["platform_code"] = record.get("platformCode")
- row["verify_code"] = record.get("verifyCode")
- row["coupon_code"] = record.get("coupon_code")
- row["coupon_channel"] = record.get("coupon_channel")
- row["order_trade_no"] = record.get("orderTradeNo")
- row["order_settle_id"] = record.get("orderSettleId")
- row["member_id"] = record.get("memberId")
- row["status"] = record.get("use_status") or record.get("status")
- row["used_time"] = record.get("consume_time") or record.get("usedTime")
- row["deduct_amount"] = record.get("deductAmount")
- row["settle_price"] = record.get("sale_price") or record.get("settlePrice")
- row["coupon_money"] = record.get("coupon_money")
-
- if "ods_table_use_log" in table:
- row["tenant_id"] = pick(record, "tenantId", "tenant_id")
-
- def _ensure_tuple(self, value):
- if isinstance(value, tuple):
- return value
- return (value,)
-
- def _bulk_insert(self, table: str, rows: list[dict]):
- if not rows:
- return
-
- columns = list(rows[0].keys())
- col_clause = ", ".join(columns)
- val_clause = ", ".join(f"%({col})s" for col in columns)
- conflict_cols = ["site_id"] + self._get_conflict_columns(table)
- conflict_clause = ", ".join(conflict_cols)
-
- sql = f"""
- INSERT INTO {table} ({col_clause})
- VALUES ({val_clause})
- ON CONFLICT ({conflict_clause}) DO UPDATE SET
- payload = EXCLUDED.payload,
- fetched_at = EXCLUDED.fetched_at,
- source_file = EXCLUDED.source_file
- """
- self.db.batch_execute(sql, rows)
+ if dt in ("numeric", "double precision", "real", "decimal"):
+ if isinstance(value, bool):
+ return int(value)
+ try:
+ return float(value)
+ except Exception:
+ return None
+ if dt.startswith("timestamp") or dt in ("date", "time", "interval"):
+ return value if isinstance(value, str) else None
+ return value
diff --git a/etl_billiards/tasks/members_dwd_task.py b/etl_billiards/tasks/members_dwd_task.py
index c191b80..12d8ea0 100644
--- a/etl_billiards/tasks/members_dwd_task.py
+++ b/etl_billiards/tasks/members_dwd_task.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
from .base_dwd_task import BaseDwdTask
from loaders.dimensions.member import MemberLoader
from models.parsers import TypeParser
@@ -7,7 +7,7 @@ import json
class MembersDwdTask(BaseDwdTask):
"""
DWD Task: Process Member Records from ODS to Dimension Table
- Source: billiards_ods.ods_member_profile
+ Source: billiards_ods.member_profiles
Target: billiards.dim_member
"""
@@ -29,7 +29,7 @@ class MembersDwdTask(BaseDwdTask):
# Iterate ODS Data
batches = self.iter_ods_rows(
- table_name="billiards_ods.ods_member_profile",
+ table_name="billiards_ods.member_profiles",
columns=["site_id", "member_id", "payload", "fetched_at"],
start_time=window_start,
end_time=window_end
@@ -87,3 +87,4 @@ class MembersDwdTask(BaseDwdTask):
except Exception as e:
self.logger.warning(f"Error parsing member: {e}")
return None
+
diff --git a/etl_billiards/tasks/ods_tasks.py b/etl_billiards/tasks/ods_tasks.py
index fce222f..6f503bd 100644
--- a/etl_billiards/tasks/ods_tasks.py
+++ b/etl_billiards/tasks/ods_tasks.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
"""ODS ingestion tasks."""
from __future__ import annotations
@@ -62,11 +62,11 @@ class BaseOdsTask(BaseTask):
def execute(self) -> dict:
spec = self.SPEC
- self.logger.info("开始执行 %s (ODS)", spec.code)
+ self.logger.info("寮€濮嬫墽琛?%s (ODS)", spec.code)
store_id = TypeParser.parse_int(self.config.get("app.store_id"))
if not store_id:
- raise ValueError("app.store_id 未配置,无法执行 ODS 任务")
+ raise ValueError("app.store_id 鏈厤缃紝鏃犳硶鎵ц ODS 浠诲姟")
page_size = self.config.get("api.page_size", 200)
params = self._build_params(spec, store_id)
@@ -122,13 +122,13 @@ class BaseOdsTask(BaseTask):
counts["fetched"] += len(page_records)
self.db.commit()
- self.logger.info("%s ODS 任务完成: %s", spec.code, counts)
+ self.logger.info("%s ODS 浠诲姟瀹屾垚: %s", spec.code, counts)
return self._build_result("SUCCESS", counts)
except Exception:
self.db.rollback()
counts["errors"] += 1
- self.logger.error("%s ODS 任务失败", spec.code, exc_info=True)
+ self.logger.error("%s ODS 浠诲姟澶辫触", spec.code, exc_info=True)
raise
def _build_params(self, spec: OdsTaskSpec, store_id: int) -> dict:
@@ -201,7 +201,7 @@ class BaseOdsTask(BaseTask):
value = self._extract_value(record, col_spec)
if value is None and col_spec.required:
self.logger.warning(
- "%s 缺少必填字段 %s,原始记录: %s",
+ "%s 缂哄皯蹇呭~瀛楁 %s锛屽師濮嬭褰? %s",
spec.code,
col_spec.column,
record,
@@ -265,9 +265,38 @@ def _int_col(name: str, *sources: str, required: bool = False) -> ColumnSpec:
)
+def _decimal_col(name: str, *sources: str) -> ColumnSpec:
+ """??????????????"""
+ return ColumnSpec(
+ column=name,
+ sources=sources,
+ transform=lambda v: TypeParser.parse_decimal(v, 2),
+ )
+
+
+def _bool_col(name: str, *sources: str) -> ColumnSpec:
+ """??????????????0/1?true/false ???"""
+
+ def _to_bool(value):
+ if value is None:
+ return None
+ if isinstance(value, bool):
+ return value
+ s = str(value).strip().lower()
+ if s in {"1", "true", "t", "yes", "y"}:
+ return True
+ if s in {"0", "false", "f", "no", "n"}:
+ return False
+ return bool(value)
+
+ return ColumnSpec(column=name, sources=sources, transform=_to_bool)
+
+
+
+
ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
OdsTaskSpec(
- code="ODS_ASSISTANT_ACCOUNTS",
+ code="ODS_ASSISTANT_ACCOUNT",
class_name="OdsAssistantAccountsTask",
table_name="billiards_ods.assistant_accounts_master",
endpoint="/PersonnelManagement/SearchAssistantInfo",
@@ -281,10 +310,10 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
include_fetched_at=False,
include_record_index=True,
conflict_columns_override=("source_file", "record_index"),
- description="助教账号档案 ODS:SearchAssistantInfo -> assistantInfos 原始 JSON",
+ description="鍔╂暀璐﹀彿妗f ODS锛歋earchAssistantInfo -> assistantInfos 鍘熷 JSON",
),
OdsTaskSpec(
- code="ODS_ORDER_SETTLE",
+ code="ODS_SETTLEMENT_RECORDS",
class_name="OdsOrderSettleTask",
table_name="billiards_ods.settlement_records",
endpoint="/Site/GetAllOrderSettleList",
@@ -299,7 +328,7 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
include_record_index=True,
conflict_columns_override=("source_file", "record_index"),
requires_window=False,
- description="结账记录 ODS:GetAllOrderSettleList -> settleList 原始 JSON",
+ description="缁撹处璁板綍 ODS锛欸etAllOrderSettleList -> settleList 鍘熷 JSON",
),
OdsTaskSpec(
code="ODS_TABLE_USE",
@@ -317,7 +346,7 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
include_record_index=True,
conflict_columns_override=("source_file", "record_index"),
requires_window=False,
- description="台费计费流水 ODS:GetSiteTableOrderDetails -> siteTableUseDetailsList 原始 JSON",
+ description="鍙拌垂璁¤垂娴佹按 ODS锛欸etSiteTableOrderDetails -> siteTableUseDetailsList 鍘熷 JSON",
),
OdsTaskSpec(
code="ODS_ASSISTANT_LEDGER",
@@ -334,7 +363,7 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
include_fetched_at=False,
include_record_index=True,
conflict_columns_override=("source_file", "record_index"),
- description="助教服务流水 ODS:GetOrderAssistantDetails -> orderAssistantDetails 原始 JSON",
+ description="鍔╂暀鏈嶅姟娴佹按 ODS锛欸etOrderAssistantDetails -> orderAssistantDetails 鍘熷 JSON",
),
OdsTaskSpec(
code="ODS_ASSISTANT_ABOLISH",
@@ -351,10 +380,10 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
include_fetched_at=False,
include_record_index=True,
conflict_columns_override=("source_file", "record_index"),
- description="助教废除记录 ODS:GetAbolitionAssistant -> abolitionAssistants 原始 JSON",
+ description="鍔╂暀搴熼櫎璁板綍 ODS锛欸etAbolitionAssistant -> abolitionAssistants 鍘熷 JSON",
),
OdsTaskSpec(
- code="ODS_GOODS_LEDGER",
+ code="ODS_STORE_GOODS_SALES",
class_name="OdsGoodsLedgerTask",
table_name="billiards_ods.store_goods_sales_records",
endpoint="/TenantGoods/GetGoodsSalesList",
@@ -369,7 +398,7 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
include_record_index=True,
conflict_columns_override=("source_file", "record_index"),
requires_window=False,
- description="门店商品销售流水 ODS:GetGoodsSalesList -> orderGoodsLedgers 原始 JSON",
+ description="闂ㄥ簵鍟嗗搧閿€鍞祦姘?ODS锛欸etGoodsSalesList -> orderGoodsLedgers 鍘熷 JSON",
),
OdsTaskSpec(
code="ODS_PAYMENT",
@@ -386,7 +415,7 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
include_record_index=True,
conflict_columns_override=("source_file", "record_index"),
requires_window=False,
- description="支付流水 ODS:GetPayLogListPage 原始 JSON",
+ description="鏀粯娴佹按 ODS锛欸etPayLogListPage 鍘熷 JSON",
),
OdsTaskSpec(
code="ODS_REFUND",
@@ -403,10 +432,10 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
include_record_index=True,
conflict_columns_override=("source_file", "record_index"),
requires_window=False,
- description="退款流水 ODS:GetRefundPayLogList 原始 JSON",
+ description="閫€娆炬祦姘?ODS锛欸etRefundPayLogList 鍘熷 JSON",
),
OdsTaskSpec(
- code="ODS_COUPON_VERIFY",
+ code="ODS_PLATFORM_COUPON",
class_name="OdsCouponVerifyTask",
table_name="billiards_ods.platform_coupon_redemption_records",
endpoint="/Promotion/GetOfflineCouponConsumePageList",
@@ -420,7 +449,7 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
include_record_index=True,
conflict_columns_override=("source_file", "record_index"),
requires_window=False,
- description="平台/团购券核销 ODS:GetOfflineCouponConsumePageList 原始 JSON",
+ description="骞冲彴/鍥㈣喘鍒告牳閿€ ODS锛欸etOfflineCouponConsumePageList 鍘熷 JSON",
),
OdsTaskSpec(
code="ODS_MEMBER",
@@ -438,7 +467,7 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
include_record_index=True,
conflict_columns_override=("source_file", "record_index"),
requires_window=False,
- description="会员档案 ODS:GetTenantMemberList -> tenantMemberInfos 原始 JSON",
+ description="浼氬憳妗f ODS锛欸etTenantMemberList -> tenantMemberInfos 鍘熷 JSON",
),
OdsTaskSpec(
code="ODS_MEMBER_CARD",
@@ -456,7 +485,7 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
include_record_index=True,
conflict_columns_override=("source_file", "record_index"),
requires_window=False,
- description="会员储值卡 ODS:GetTenantMemberCardList -> tenantMemberCards 原始 JSON",
+ description="浼氬憳鍌ㄥ€煎崱 ODS锛欸etTenantMemberCardList -> tenantMemberCards 鍘熷 JSON",
),
OdsTaskSpec(
code="ODS_MEMBER_BALANCE",
@@ -474,7 +503,7 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
include_record_index=True,
conflict_columns_override=("source_file", "record_index"),
requires_window=False,
- description="会员余额变动 ODS:GetMemberCardBalanceChange -> tenantMemberCardLogs 原始 JSON",
+ description="浼氬憳浣欓鍙樺姩 ODS锛欸etMemberCardBalanceChange -> tenantMemberCardLogs 鍘熷 JSON",
),
OdsTaskSpec(
code="ODS_RECHARGE_SETTLE",
@@ -483,19 +512,83 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
endpoint="/Site/GetRechargeSettleList",
data_path=("data",),
list_key="settleList",
- pk_columns=(),
+ pk_columns=(_int_col("recharge_order_id", "settleList.id", "id", required=True),),
+ extra_columns=(
+ _int_col("tenant_id", "settleList.tenantId", "tenantId"),
+ _int_col("site_id", "settleList.siteId", "siteId", "siteProfile.id"),
+ ColumnSpec("site_name_snapshot", sources=("siteProfile.shop_name", "settleList.siteName")),
+ _int_col("member_id", "settleList.memberId", "memberId"),
+ ColumnSpec("member_name_snapshot", sources=("settleList.memberName", "memberName")),
+ ColumnSpec("member_phone_snapshot", sources=("settleList.memberPhone", "memberPhone")),
+ _int_col("tenant_member_card_id", "settleList.tenantMemberCardId", "tenantMemberCardId"),
+ ColumnSpec("member_card_type_name", sources=("settleList.memberCardTypeName", "memberCardTypeName")),
+ _int_col("settle_relate_id", "settleList.settleRelateId", "settleRelateId"),
+ _int_col("settle_type", "settleList.settleType", "settleType"),
+ ColumnSpec("settle_name", sources=("settleList.settleName", "settleName")),
+ _int_col("is_first", "settleList.isFirst", "isFirst"),
+ _int_col("settle_status", "settleList.settleStatus", "settleStatus"),
+ _decimal_col("pay_amount", "settleList.payAmount", "payAmount"),
+ _decimal_col("refund_amount", "settleList.refundAmount", "refundAmount"),
+ _decimal_col("point_amount", "settleList.pointAmount", "pointAmount"),
+ _decimal_col("cash_amount", "settleList.cashAmount", "cashAmount"),
+ _decimal_col("online_amount", "settleList.onlineAmount", "onlineAmount"),
+ _decimal_col("balance_amount", "settleList.balanceAmount", "balanceAmount"),
+ _decimal_col("card_amount", "settleList.cardAmount", "cardAmount"),
+ _decimal_col("coupon_amount", "settleList.couponAmount", "couponAmount"),
+ _decimal_col("recharge_card_amount", "settleList.rechargeCardAmount", "rechargeCardAmount"),
+ _decimal_col("gift_card_amount", "settleList.giftCardAmount", "giftCardAmount"),
+ _decimal_col("prepay_money", "settleList.prepayMoney", "prepayMoney"),
+ _decimal_col("consume_money", "settleList.consumeMoney", "consumeMoney"),
+ _decimal_col("goods_money", "settleList.goodsMoney", "goodsMoney"),
+ _decimal_col("real_goods_money", "settleList.realGoodsMoney", "realGoodsMoney"),
+ _decimal_col("table_charge_money", "settleList.tableChargeMoney", "tableChargeMoney"),
+ _decimal_col("service_money", "settleList.serviceMoney", "serviceMoney"),
+ _decimal_col("activity_discount", "settleList.activityDiscount", "activityDiscount"),
+ _decimal_col("all_coupon_discount", "settleList.allCouponDiscount", "allCouponDiscount"),
+ _decimal_col("goods_promotion_money", "settleList.goodsPromotionMoney", "goodsPromotionMoney"),
+ _decimal_col("assistant_promotion_money", "settleList.assistantPromotionMoney", "assistantPromotionMoney"),
+ _decimal_col("assistant_pd_money", "settleList.assistantPdMoney", "assistantPdMoney"),
+ _decimal_col("assistant_cx_money", "settleList.assistantCxMoney", "assistantCxMoney"),
+ _decimal_col("assistant_manual_discount", "settleList.assistantManualDiscount", "assistantManualDiscount"),
+ _decimal_col("coupon_sale_amount", "settleList.couponSaleAmount", "couponSaleAmount"),
+ _decimal_col("member_discount_amount", "settleList.memberDiscountAmount", "memberDiscountAmount"),
+ _decimal_col("point_discount_price", "settleList.pointDiscountPrice", "pointDiscountPrice"),
+ _decimal_col("point_discount_cost", "settleList.pointDiscountCost", "pointDiscountCost"),
+ _decimal_col("adjust_amount", "settleList.adjustAmount", "adjustAmount"),
+ _decimal_col("rounding_amount", "settleList.roundingAmount", "roundingAmount"),
+ _int_col("payment_method", "settleList.paymentMethod", "paymentMethod"),
+ _bool_col("can_be_revoked", "settleList.canBeRevoked", "canBeRevoked"),
+ _bool_col("is_bind_member", "settleList.isBindMember", "isBindMember"),
+ _bool_col("is_activity", "settleList.isActivity", "isActivity"),
+ _bool_col("is_use_coupon", "settleList.isUseCoupon", "isUseCoupon"),
+ _bool_col("is_use_discount", "settleList.isUseDiscount", "isUseDiscount"),
+ _int_col("operator_id", "settleList.operatorId", "operatorId"),
+ ColumnSpec("operator_name_snapshot", sources=("settleList.operatorName", "operatorName")),
+ _int_col("salesman_user_id", "settleList.salesManUserId", "salesmanUserId", "salesManUserId"),
+ ColumnSpec("salesman_name", sources=("settleList.salesManName", "salesmanName", "settleList.salesmanName")),
+ ColumnSpec("order_remark", sources=("settleList.orderRemark", "orderRemark")),
+ _int_col("table_id", "settleList.tableId", "tableId"),
+ _int_col("serial_number", "settleList.serialNumber", "serialNumber"),
+ _int_col("revoke_order_id", "settleList.revokeOrderId", "revokeOrderId"),
+ ColumnSpec("revoke_order_name", sources=("settleList.revokeOrderName", "revokeOrderName")),
+ ColumnSpec("revoke_time", sources=("settleList.revokeTime", "revokeTime")),
+ ColumnSpec("create_time", sources=("settleList.createTime", "createTime")),
+ ColumnSpec("pay_time", sources=("settleList.payTime", "payTime")),
+ ColumnSpec("site_profile", sources=("siteProfile",)),
+ ),
include_site_column=False,
- include_source_endpoint=False,
+ include_source_endpoint=True,
include_page_no=False,
include_page_size=False,
- include_fetched_at=False,
- include_record_index=True,
- conflict_columns_override=("source_file", "record_index"),
+ include_fetched_at=True,
+ include_record_index=False,
+ conflict_columns_override=None,
requires_window=False,
- description="会员充值结算 ODS:GetRechargeSettleList -> settleList 原始 JSON",
+ description="?????? ODS?GetRechargeSettleList -> data.settleList ????",
),
+
OdsTaskSpec(
- code="ODS_PACKAGE",
+ code="ODS_GROUP_PACKAGE",
class_name="OdsPackageTask",
table_name="billiards_ods.group_buy_packages",
endpoint="/PackageCoupon/QueryPackageCouponList",
@@ -510,7 +603,7 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
include_record_index=True,
conflict_columns_override=("source_file", "record_index"),
requires_window=False,
- description="团购套餐定义 ODS:QueryPackageCouponList -> packageCouponList 原始 JSON",
+ description="鍥㈣喘濂楅瀹氫箟 ODS锛歈ueryPackageCouponList -> packageCouponList 鍘熷 JSON",
),
OdsTaskSpec(
code="ODS_GROUP_BUY_REDEMPTION",
@@ -528,7 +621,7 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
include_record_index=True,
conflict_columns_override=("source_file", "record_index"),
requires_window=False,
- description="团购套餐核销 ODS:GetSiteTableUseDetails -> siteTableUseDetailsList 原始 JSON",
+ description="鍥㈣喘濂楅鏍搁攢 ODS锛欸etSiteTableUseDetails -> siteTableUseDetailsList 鍘熷 JSON",
),
OdsTaskSpec(
code="ODS_INVENTORY_STOCK",
@@ -545,7 +638,7 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
include_record_index=True,
conflict_columns_override=("source_file", "record_index"),
requires_window=False,
- description="库存汇总 ODS:GetGoodsStockReport 原始 JSON",
+ description="搴撳瓨姹囨€?ODS锛欸etGoodsStockReport 鍘熷 JSON",
),
OdsTaskSpec(
code="ODS_INVENTORY_CHANGE",
@@ -562,7 +655,7 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
include_fetched_at=False,
include_record_index=True,
conflict_columns_override=("source_file", "record_index"),
- description="库存变化记录 ODS:QueryGoodsOutboundReceipt -> queryDeliveryRecordsList 原始 JSON",
+ description="搴撳瓨鍙樺寲璁板綍 ODS锛歈ueryGoodsOutboundReceipt -> queryDeliveryRecordsList 鍘熷 JSON",
),
OdsTaskSpec(
code="ODS_TABLES",
@@ -580,7 +673,7 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
include_record_index=True,
conflict_columns_override=("source_file", "record_index"),
requires_window=False,
- description="台桌维表 ODS:GetSiteTables -> siteTables 原始 JSON",
+ description="鍙版缁磋〃 ODS锛欸etSiteTables -> siteTables 鍘熷 JSON",
),
OdsTaskSpec(
code="ODS_GOODS_CATEGORY",
@@ -598,7 +691,7 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
include_record_index=True,
conflict_columns_override=("source_file", "record_index"),
requires_window=False,
- description="库存商品分类树 ODS:QueryPrimarySecondaryCategory -> goodsCategoryList 原始 JSON",
+ description="搴撳瓨鍟嗗搧鍒嗙被鏍?ODS锛歈ueryPrimarySecondaryCategory -> goodsCategoryList 鍘熷 JSON",
),
OdsTaskSpec(
code="ODS_STORE_GOODS",
@@ -616,10 +709,10 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
include_record_index=True,
conflict_columns_override=("source_file", "record_index"),
requires_window=False,
- description="门店商品档案 ODS:GetGoodsInventoryList -> orderGoodsList 原始 JSON",
+ description="闂ㄥ簵鍟嗗搧妗f ODS锛欸etGoodsInventoryList -> orderGoodsList 鍘熷 JSON",
),
OdsTaskSpec(
- code="ODS_TABLE_DISCOUNT",
+ code="ODS_TABLE_FEE_DISCOUNT",
class_name="OdsTableDiscountTask",
table_name="billiards_ods.table_fee_discount_records",
endpoint="/Site/GetTaiFeeAdjustList",
@@ -634,7 +727,7 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
include_record_index=True,
conflict_columns_override=("source_file", "record_index"),
requires_window=False,
- description="台费折扣/调账 ODS:GetTaiFeeAdjustList -> taiFeeAdjustInfos 原始 JSON",
+ description="鍙拌垂鎶樻墸/璋冭处 ODS锛欸etTaiFeeAdjustList -> taiFeeAdjustInfos 鍘熷 JSON",
),
OdsTaskSpec(
code="ODS_TENANT_GOODS",
@@ -652,7 +745,7 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
include_record_index=True,
conflict_columns_override=("source_file", "record_index"),
requires_window=False,
- description="租户商品档案 ODS:QueryTenantGoods -> tenantGoodsList 原始 JSON",
+ description="绉熸埛鍟嗗搧妗f ODS锛歈ueryTenantGoods -> tenantGoodsList 鍘熷 JSON",
),
OdsTaskSpec(
code="ODS_SETTLEMENT_TICKET",
@@ -671,7 +764,7 @@ ODS_TASK_SPECS: Tuple[OdsTaskSpec, ...] = (
conflict_columns_override=("source_file", "record_index"),
requires_window=False,
include_site_id=False,
- description="结账小票详情 ODS:GetOrderSettleTicketNew 原始 JSON",
+ description="缁撹处灏忕エ璇︽儏 ODS锛欸etOrderSettleTicketNew 鍘熷 JSON",
),
)
@@ -725,7 +818,7 @@ class OdsSettlementTicketTask(BaseOdsTask):
if not candidates:
self.logger.info(
- "%s: 窗口[%s ~ %s] 未发现需要抓取的小票",
+ "%s: 绐楀彛[%s ~ %s] 鏈彂鐜伴渶瑕佹姄鍙栫殑灏忕エ",
spec.code,
context.window_start,
context.window_end,
@@ -755,7 +848,7 @@ class OdsSettlementTicketTask(BaseOdsTask):
counts["updated"] += updated
self.db.commit()
self.logger.info(
- "%s: 小票抓取完成,候选=%s 插入=%s 更新=%s 跳过=%s",
+ "%s: 灏忕エ鎶撳彇瀹屾垚锛屽€欓€?%s 鎻掑叆=%s 鏇存柊=%s 璺宠繃=%s",
spec.code,
len(candidates),
inserted,
@@ -767,7 +860,7 @@ class OdsSettlementTicketTask(BaseOdsTask):
except Exception:
counts["errors"] += 1
self.db.rollback()
- self.logger.error("%s: 小票抓取失败", spec.code, exc_info=True)
+ self.logger.error("%s: 灏忕エ鎶撳彇澶辫触", spec.code, exc_info=True)
raise
# ------------------------------------------------------------------ helpers
@@ -782,7 +875,7 @@ class OdsSettlementTicketTask(BaseOdsTask):
try:
rows = self.db.query(sql)
except Exception:
- self.logger.warning("查询已有小票失败,按空集处理", exc_info=True)
+ self.logger.warning("鏌ヨ宸叉湁灏忕エ澶辫触锛屾寜绌洪泦澶勭悊", exc_info=True)
return set()
return {
@@ -819,7 +912,7 @@ class OdsSettlementTicketTask(BaseOdsTask):
try:
rows = self.db.query(sql, params)
except Exception:
- self.logger.warning("读取支付流水以获取结算单ID失败,将尝试调用支付接口回退", exc_info=True)
+ self.logger.warning("璇诲彇鏀粯娴佹按浠ヨ幏鍙栫粨绠楀崟ID澶辫触锛屽皢灏濊瘯璋冪敤鏀粯鎺ュ彛鍥為€€", exc_info=True)
return set()
return {
@@ -853,7 +946,7 @@ class OdsSettlementTicketTask(BaseOdsTask):
if relate_id:
candidate_ids.add(relate_id)
except Exception:
- self.logger.warning("调用支付接口获取结算单ID失败,当前批次将跳过回退来源", exc_info=True)
+ self.logger.warning("璋冪敤鏀粯鎺ュ彛鑾峰彇缁撶畻鍗旾D澶辫触锛屽綋鍓嶆壒娆″皢璺宠繃鍥為€€鏉ユ簮", exc_info=True)
return candidate_ids
def _fetch_ticket_payload(self, order_settle_id: int):
@@ -869,10 +962,10 @@ class OdsSettlementTicketTask(BaseOdsTask):
payload = response
except Exception:
self.logger.warning(
- "调用小票接口失败 orderSettleId=%s", order_settle_id, exc_info=True
+ "璋冪敤灏忕エ鎺ュ彛澶辫触 orderSettleId=%s", order_settle_id, exc_info=True
)
if isinstance(payload, dict) and isinstance(payload.get("data"), list) and len(payload["data"]) == 1:
- # 本地桩/回放可能把响应包装成单元素 list,这里展开以贴近真实结构
+ # 鏈湴妗?鍥炴斁鍙兘鎶婂搷搴斿寘瑁呮垚鍗曞厓绱?list锛岃繖閲屽睍寮€浠ヨ创杩戠湡瀹炵粨鏋?
payload = payload["data"][0]
return payload
@@ -899,27 +992,29 @@ def _build_task_class(spec: OdsTaskSpec) -> Type[BaseOdsTask]:
ENABLED_ODS_CODES = {
- "ODS_ASSISTANT_ACCOUNTS",
+ "ODS_ASSISTANT_ACCOUNT",
"ODS_ASSISTANT_LEDGER",
"ODS_ASSISTANT_ABOLISH",
"ODS_INVENTORY_CHANGE",
"ODS_INVENTORY_STOCK",
- "ODS_PACKAGE",
+ "ODS_GROUP_PACKAGE",
"ODS_GROUP_BUY_REDEMPTION",
"ODS_MEMBER",
"ODS_MEMBER_BALANCE",
"ODS_MEMBER_CARD",
"ODS_PAYMENT",
"ODS_REFUND",
- "ODS_COUPON_VERIFY",
+ "ODS_PLATFORM_COUPON",
"ODS_RECHARGE_SETTLE",
+ "ODS_TABLE_USE",
"ODS_TABLES",
"ODS_GOODS_CATEGORY",
"ODS_STORE_GOODS",
- "ODS_TABLE_DISCOUNT",
+ "ODS_TABLE_FEE_DISCOUNT",
+ "ODS_STORE_GOODS_SALES",
"ODS_TENANT_GOODS",
"ODS_SETTLEMENT_TICKET",
- "ODS_ORDER_SETTLE",
+ "ODS_SETTLEMENT_RECORDS",
}
ODS_TASK_CLASSES: Dict[str, Type[BaseOdsTask]] = {
@@ -931,3 +1026,4 @@ ODS_TASK_CLASSES: Dict[str, Type[BaseOdsTask]] = {
ODS_TASK_CLASSES["ODS_SETTLEMENT_TICKET"] = OdsSettlementTicketTask
__all__ = ["ODS_TASK_CLASSES", "ODS_TASK_SPECS", "BaseOdsTask", "ENABLED_ODS_CODES"]
+
diff --git a/etl_billiards/tasks/payments_dwd_task.py b/etl_billiards/tasks/payments_dwd_task.py
index 2bcb2b6..e811f7e 100644
--- a/etl_billiards/tasks/payments_dwd_task.py
+++ b/etl_billiards/tasks/payments_dwd_task.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
from .base_dwd_task import BaseDwdTask
from loaders.facts.payment import PaymentLoader
from models.parsers import TypeParser
@@ -29,7 +29,7 @@ class PaymentsDwdTask(BaseDwdTask):
# Iterate ODS Data
batches = self.iter_ods_rows(
- table_name="billiards_ods.ods_payment_record",
+ table_name="billiards_ods.payment_transactions",
columns=["site_id", "pay_id", "payload", "fetched_at"],
start_time=window_start,
end_time=window_end
@@ -136,3 +136,4 @@ class PaymentsDwdTask(BaseDwdTask):
except Exception as e:
self.logger.warning(f"Error parsing payment: {e}")
return None
+
diff --git a/etl_billiards/tests/unit/test_ods_tasks.py b/etl_billiards/tests/unit/test_ods_tasks.py
index 4584e52..41064a2 100644
--- a/etl_billiards/tests/unit/test_ods_tasks.py
+++ b/etl_billiards/tests/unit/test_ods_tasks.py
@@ -1,4 +1,4 @@
-# -*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
"""Unit tests for the new ODS ingestion tasks."""
import logging
import os
@@ -22,21 +22,21 @@ def _build_config(tmp_path):
return create_test_config("ONLINE", archive_dir, temp_dir)
-def test_ods_assistant_accounts_ingest(tmp_path):
- """Ensure ODS_ASSISTANT_ACCOUNTS task stores raw payload with record_index dedup keys."""
+def test_assistant_accounts_masters_ingest(tmp_path):
+ """Ensure assistant_accounts_masterS task stores raw payload with record_index dedup keys."""
config = _build_config(tmp_path)
sample = [
{
"id": 5001,
"assistant_no": "A01",
- "nickname": "小张",
+ "nickname": "灏忓紶",
}
]
api = FakeAPIClient({"/PersonnelManagement/SearchAssistantInfo": sample})
- task_cls = ODS_TASK_CLASSES["ODS_ASSISTANT_ACCOUNTS"]
+ task_cls = ODS_TASK_CLASSES["assistant_accounts_masterS"]
with get_db_operations() as db_ops:
- task = task_cls(config, db_ops, api, logging.getLogger("test_ods_assistant_accounts"))
+ task = task_cls(config, db_ops, api, logging.getLogger("test_assistant_accounts_masters"))
result = task.execute()
assert result["status"] == "SUCCESS"
@@ -49,21 +49,21 @@ def test_ods_assistant_accounts_ingest(tmp_path):
assert '"id": 5001' in row["payload"]
-def test_ods_inventory_change_ingest(tmp_path):
- """Ensure ODS_INVENTORY_CHANGE task stores raw payload with record_index dedup keys."""
+def test_goods_stock_movements_ingest(tmp_path):
+ """Ensure goods_stock_movements task stores raw payload with record_index dedup keys."""
config = _build_config(tmp_path)
sample = [
{
"siteGoodsStockId": 123456,
"stockType": 1,
- "goodsName": "测试商品",
+ "goodsName": "娴嬭瘯鍟嗗搧",
}
]
api = FakeAPIClient({"/GoodsStockManage/QueryGoodsOutboundReceipt": sample})
- task_cls = ODS_TASK_CLASSES["ODS_INVENTORY_CHANGE"]
+ task_cls = ODS_TASK_CLASSES["goods_stock_movements"]
with get_db_operations() as db_ops:
- task = task_cls(config, db_ops, api, logging.getLogger("test_ods_inventory_change"))
+ task = task_cls(config, db_ops, api, logging.getLogger("test_goods_stock_movements"))
result = task.execute()
assert result["status"] == "SUCCESS"
@@ -75,7 +75,7 @@ def test_ods_inventory_change_ingest(tmp_path):
assert '"siteGoodsStockId": 123456' in row["payload"]
-def test_ods_member_profiles_ingest(tmp_path):
+def test_member_profiless_ingest(tmp_path):
"""Ensure ODS_MEMBER task stores tenantMemberInfos raw JSON."""
config = _build_config(tmp_path)
sample = [{"tenantMemberInfos": [{"id": 101, "mobile": "13800000000"}]}]
@@ -110,14 +110,14 @@ def test_ods_payment_ingest(tmp_path):
def test_ods_settlement_records_ingest(tmp_path):
- """Ensure ODS_ORDER_SETTLE task stores settleList raw JSON."""
+ """Ensure settlement_records task stores settleList raw JSON."""
config = _build_config(tmp_path)
sample = [{"data": {"settleList": [{"id": 701, "orderTradeNo": 8001}]}}]
api = FakeAPIClient({"/Site/GetAllOrderSettleList": sample})
- task_cls = ODS_TASK_CLASSES["ODS_ORDER_SETTLE"]
+ task_cls = ODS_TASK_CLASSES["settlement_records"]
with get_db_operations() as db_ops:
- task = task_cls(config, db_ops, api, logging.getLogger("test_ods_order_settle"))
+ task = task_cls(config, db_ops, api, logging.getLogger("test_settlement_records"))
result = task.execute()
assert result["status"] == "SUCCESS"
@@ -158,3 +158,4 @@ def test_ods_settlement_ticket_by_payment_relate_ids(tmp_path):
and call.get("params", {}).get("orderSettleId") == 9001
for call in api.calls
)
+
diff --git a/etl_billiards/.env.example b/etl_billiards/tmp & Delete/.env.example
similarity index 100%
rename from etl_billiards/.env.example
rename to etl_billiards/tmp & Delete/.env.example
diff --git a/DWD层设计建议.docx b/etl_billiards/tmp & Delete/DWD层设计建议.docx
similarity index 100%
rename from DWD层设计建议.docx
rename to etl_billiards/tmp & Delete/DWD层设计建议.docx
diff --git a/DWD层设计草稿.md b/etl_billiards/tmp & Delete/DWD层设计草稿.md
similarity index 100%
rename from DWD层设计草稿.md
rename to etl_billiards/tmp & Delete/DWD层设计草稿.md
diff --git a/etl_billiards/tmp/dwd_schema_columns.txt b/etl_billiards/tmp & Delete/dwd_schema_columns.txt
similarity index 100%
rename from etl_billiards/tmp/dwd_schema_columns.txt
rename to etl_billiards/tmp & Delete/dwd_schema_columns.txt
diff --git a/etl_billiards/tmp & Delete/schema_v2.sql b/etl_billiards/tmp & Delete/schema_v2.sql
new file mode 100644
index 0000000..f16cca2
--- /dev/null
+++ b/etl_billiards/tmp & Delete/schema_v2.sql
@@ -0,0 +1,1772 @@
+-- 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锛涚鎴峰唴浼氬憳璐︽埛涓婚敭锛堝搴斿崱璐︽埛/妗fID锛?;
+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;
+
diff --git a/temp_chinese.txt b/temp_chinese.txt
new file mode 100644
index 0000000..e3a3e0d
--- /dev/null
+++ b/temp_chinese.txt
@@ -0,0 +1 @@
+含义
diff --git a/tmp/recharge_only/recharge_settlements.json b/tmp/recharge_only/recharge_settlements.json
new file mode 100644
index 0000000..4356334
--- /dev/null
+++ b/tmp/recharge_only/recharge_settlements.json
@@ -0,0 +1,6899 @@
+[
+ {
+ "data": {
+ "total": 74,
+ "settleList": [
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2956757480820613,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-11-09 03:49:17",
+ "memberId": 2799207159990021,
+ "memberName": "邓飛",
+ "tenantMemberCardId": 2799216107980549,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "13600009597",
+ "tableId": 0,
+ "consumeMoney": 1000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 1000.0,
+ "pointAmount": 1000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2956757480443781,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-11-09 03:49:17",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2956721495543301,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-11-09 03:12:40",
+ "memberId": 2955204541320325,
+ "memberName": "胡先生",
+ "tenantMemberCardId": 2955204541615237,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18620043391",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2956721495166469,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-11-09 03:12:41",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2956701447835141,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-11-09 02:52:17",
+ "memberId": 2799207519176453,
+ "memberName": "夏",
+ "tenantMemberCardId": 2799217048848133,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "19120942851",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2956701447507461,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-11-09 02:52:17",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2955465501214917,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-11-08 05:55:01",
+ "memberId": 2799207522600709,
+ "memberName": "轩哥",
+ "tenantMemberCardId": 2799217444914949,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18826267530",
+ "tableId": 0,
+ "consumeMoney": 5000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 5000.0,
+ "pointAmount": 5000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2955465500805317,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-11-08 05:55:01",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2955205277092101,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-11-08 01:30:18",
+ "memberId": 2955204541320325,
+ "memberName": "胡先生",
+ "tenantMemberCardId": 2955204541615237,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18620043391",
+ "tableId": 0,
+ "consumeMoney": 5000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 5000.0,
+ "pointAmount": 5000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2955205276682501,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-11-08 01:30:18",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 1,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2955202288371845,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-11-08 01:27:15",
+ "memberId": 2799207378798341,
+ "memberName": "羊",
+ "tenantMemberCardId": 2799216615507717,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18785445094",
+ "tableId": 0,
+ "consumeMoney": -5000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": -5000.0,
+ "pointAmount": 0.0,
+ "refundAmount": 0.0,
+ "settleName": "充值撤销",
+ "settleRelateId": 2955202288175237,
+ "settleStatus": 2,
+ "settleType": 7,
+ "payTime": "2025-11-08 01:27:15",
+ "roundingAmount": 0.0,
+ "paymentMethod": 1,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2955171778824325,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-11-08 00:56:13",
+ "memberId": 2799207378798341,
+ "memberName": "羊",
+ "tenantMemberCardId": 2799216615507717,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18785445094",
+ "tableId": 0,
+ "consumeMoney": -10000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": -10000.0,
+ "pointAmount": 0.0,
+ "refundAmount": 0.0,
+ "settleName": "充值撤销",
+ "settleRelateId": 2955171778627717,
+ "settleStatus": 2,
+ "settleType": 7,
+ "payTime": "2025-11-08 00:56:13",
+ "roundingAmount": 0.0,
+ "paymentMethod": 1,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2955153378510917,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-11-08 00:37:30",
+ "memberId": 2799207378798341,
+ "memberName": "羊",
+ "tenantMemberCardId": 2799216615507717,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18785445094",
+ "tableId": 0,
+ "consumeMoney": 10000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 10000.0,
+ "pointAmount": 10000.0,
+ "refundAmount": 10000.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2955153378117701,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-11-08 00:37:30",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2955100358478085,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-11-07 23:43:34",
+ "memberId": 2799207124305669,
+ "memberName": "陈腾鑫",
+ "tenantMemberCardId": 2799215988246277,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "17817318218",
+ "tableId": 0,
+ "consumeMoney": 1000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 1000.0,
+ "pointAmount": 1000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2955100358117637,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-11-07 23:43:34",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2955078217844933,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-11-07 23:21:03",
+ "memberId": 2799207378798341,
+ "memberName": "羊",
+ "tenantMemberCardId": 2799216615507717,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18785445094",
+ "tableId": 0,
+ "consumeMoney": 5000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 5000.0,
+ "pointAmount": 5000.0,
+ "refundAmount": 5000.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2955078217484485,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-11-07 23:21:03",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2954877830662341,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-11-07 19:57:12",
+ "memberId": 2799212491392773,
+ "memberName": "蔡总",
+ "tenantMemberCardId": 2799219205424901,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "15914338893",
+ "tableId": 0,
+ "consumeMoney": 5000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 5000.0,
+ "pointAmount": 5000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2954877830301893,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-11-07 19:57:12",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2953951073797829,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-11-07 04:14:27",
+ "memberId": 2799207290996485,
+ "memberName": "陈先生",
+ "tenantMemberCardId": 2799216397240069,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "15915782829",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2953951073437381,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-11-07 04:14:27",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2952293091821189,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-11-06 00:07:52",
+ "memberId": 2799207378798341,
+ "memberName": "羊",
+ "tenantMemberCardId": 2799216615507717,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18785445094",
+ "tableId": 0,
+ "consumeMoney": 1000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 1000.0,
+ "pointAmount": 1000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2952293091444357,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-11-06 00:07:52",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2951951831107333,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-11-05 18:20:43",
+ "memberId": 2799207519176453,
+ "memberName": "夏",
+ "tenantMemberCardId": 2799217048848133,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "19120942851",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2951951830763269,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-11-05 18:20:43",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2951082620324037,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-11-05 03:36:31",
+ "memberId": 2799207522600709,
+ "memberName": "轩哥",
+ "tenantMemberCardId": 2799217444914949,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18826267530",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2951082619291845,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-11-05 03:36:31",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2947940365815429,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-11-02 22:20:03",
+ "memberId": 2799207599212293,
+ "memberName": "小熊",
+ "tenantMemberCardId": 2799217260676869,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "13927020145",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2947940364979845,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-11-02 22:20:03",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2946627178694789,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-11-02 00:04:12",
+ "memberId": 2820625955784965,
+ "memberName": "江先生",
+ "tenantMemberCardId": 2820628725778629,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18819484838",
+ "tableId": 0,
+ "consumeMoney": 5000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 5000.0,
+ "pointAmount": 5000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2946627178154117,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-11-02 00:04:12",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2946587840219269,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-11-01 23:24:11",
+ "memberId": 2799207599212293,
+ "memberName": "小熊",
+ "tenantMemberCardId": 2799217260676869,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "13927020145",
+ "tableId": 0,
+ "consumeMoney": 1000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 1000.0,
+ "pointAmount": 1000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2946587839744133,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-11-01 23:24:11",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2945598741858373,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-11-01 06:38:01",
+ "memberId": 2799207545685765,
+ "memberName": "李先生",
+ "tenantMemberCardId": 2799217107142405,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "13128264000",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2945598741530693,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-11-01 06:38:02",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 1,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2945466615924805,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-11-01 04:23:37",
+ "memberId": 2799207522600709,
+ "memberName": "轩哥",
+ "tenantMemberCardId": 2799217444914949,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18826267530",
+ "tableId": 0,
+ "consumeMoney": 5000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 5000.0,
+ "pointAmount": 5000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2945466615203909,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-11-01 04:23:37",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2945300260718597,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-11-01 01:34:24",
+ "memberId": 2945299652708293,
+ "memberName": "万先生",
+ "tenantMemberCardId": 2945299653003205,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "13560399646",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2945300259784709,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-11-01 01:34:24",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 1,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2945086921656261,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-31 21:57:22",
+ "memberId": 2799207124305669,
+ "memberName": "陈腾鑫",
+ "tenantMemberCardId": 2799215988246277,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "17817318218",
+ "tableId": 0,
+ "consumeMoney": 1000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 1000.0,
+ "pointAmount": 1000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2945086921279429,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-31 21:57:23",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2944744609302533,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-31 16:09:09",
+ "memberId": 2799207378798341,
+ "memberName": "羊",
+ "tenantMemberCardId": 2799216615507717,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18785445094",
+ "tableId": 0,
+ "consumeMoney": 4000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 4000.0,
+ "pointAmount": 4000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2944744608794629,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-31 16:09:09",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2944743805700165,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-31 16:08:20",
+ "memberId": 2799207378798341,
+ "memberName": "羊",
+ "tenantMemberCardId": 2799216615507717,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18785445094",
+ "tableId": 0,
+ "consumeMoney": -44000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": -44000.0,
+ "pointAmount": 0.0,
+ "refundAmount": 0.0,
+ "settleName": "充值撤销",
+ "settleRelateId": 2944743804553285,
+ "settleStatus": 2,
+ "settleType": 7,
+ "payTime": "2025-10-31 16:08:20",
+ "roundingAmount": 0.0,
+ "paymentMethod": 1,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2944743412713605,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-31 16:07:56",
+ "memberId": 2799207378798341,
+ "memberName": "羊",
+ "tenantMemberCardId": 2799216615507717,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18785445094",
+ "tableId": 0,
+ "consumeMoney": 44000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 44000.0,
+ "pointAmount": 44000.0,
+ "refundAmount": 44000.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2944743412123781,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-31 16:07:56",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2944055920218181,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-31 04:28:35",
+ "memberId": 2799207522600709,
+ "memberName": "轩哥",
+ "tenantMemberCardId": 2799217444914949,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18826267530",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2944055919824965,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-31 04:28:35",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2941311379247045,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-29 05:56:42",
+ "memberId": 2799207522600709,
+ "memberName": "轩哥",
+ "tenantMemberCardId": 2799217444914949,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18826267530",
+ "tableId": 0,
+ "consumeMoney": 5000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 5000.0,
+ "pointAmount": 5000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2941311378837445,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-29 05:56:42",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2941006996098885,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-29 00:47:04",
+ "memberId": 2799207359858437,
+ "memberName": "罗先生",
+ "tenantMemberCardId": 2799218552833797,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "13924036996",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2941006995771205,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-29 00:47:04",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2940962797752133,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-29 00:02:06",
+ "memberId": 2799207124305669,
+ "memberName": "陈腾鑫",
+ "tenantMemberCardId": 2799215988246277,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "17817318218",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2940962797326149,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-29 00:02:06",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2939340051942533,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-27 20:31:21",
+ "memberId": 2939339802315269,
+ "memberName": "方先生",
+ "tenantMemberCardId": 2939339802626565,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "15360603185",
+ "tableId": 0,
+ "consumeMoney": 1000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 1000.0,
+ "pointAmount": 1000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2939340051532933,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-27 20:31:21",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 1,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2937958490294789,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 5000.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-26 21:05:57",
+ "memberId": 2799209806071557,
+ "memberName": "陈德韩",
+ "tenantMemberCardId": 2799218773034757,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "13431017864",
+ "tableId": 0,
+ "consumeMoney": 5000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 5000.0,
+ "pointAmount": 0.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2937958489655813,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-26 21:05:58",
+ "roundingAmount": 0.0,
+ "paymentMethod": 2,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2936513767819653,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-25 20:36:19",
+ "memberId": 2799207370163973,
+ "memberName": "歌神",
+ "tenantMemberCardId": 2799216599402245,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18819262164",
+ "tableId": 0,
+ "consumeMoney": 2000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 2000.0,
+ "pointAmount": 2000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2936513766836613,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-25 20:36:19",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2936177402742341,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-25 14:54:09",
+ "memberId": 2799207519176453,
+ "memberName": "夏",
+ "tenantMemberCardId": 2799217048848133,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "19120942851",
+ "tableId": 0,
+ "consumeMoney": 5000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 5000.0,
+ "pointAmount": 5000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2936177402349125,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-25 14:54:09",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2935512880154181,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-25 03:38:09",
+ "memberId": 2799207522600709,
+ "memberName": "轩哥",
+ "tenantMemberCardId": 2799217444914949,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18826267530",
+ "tableId": 0,
+ "consumeMoney": 10000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 10000.0,
+ "pointAmount": 10000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2935512879793733,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-25 03:38:09",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2935271550682758,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-24 23:32:40",
+ "memberId": 2935271033079557,
+ "memberName": "T",
+ "tenantMemberCardId": 2935271033390853,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18028579962",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2935271550289541,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-24 23:32:40",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 1,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2933648590063301,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-23 20:01:42",
+ "memberId": 2933647801731013,
+ "memberName": "桂先生",
+ "tenantMemberCardId": 2933647802009541,
+ "memberCardTypeName": "月卡",
+ "memberPhone": "16676777275",
+ "tableId": 0,
+ "consumeMoney": 985.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 985.0,
+ "pointAmount": 985.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2933648589670085,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-23 20:01:42",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 1,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2931088786392709,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-22 00:37:44",
+ "memberId": 2799207359858437,
+ "memberName": "罗先生",
+ "tenantMemberCardId": 2799218552833797,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "13924036996",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2931088785819269,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-22 00:37:44",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2930700262180549,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-21 18:02:30",
+ "memberId": 2799207519176453,
+ "memberName": "夏",
+ "tenantMemberCardId": 2799217048848133,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "19120942851",
+ "tableId": 0,
+ "consumeMoney": 2000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 2000.0,
+ "pointAmount": 2000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2930700261770949,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-21 18:02:31",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2929261501040197,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-20 17:38:55",
+ "memberId": 2799212430657285,
+ "memberName": "黄先生",
+ "tenantMemberCardId": 2799219055920901,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "13570163507",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2929261500696133,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-20 17:38:56",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2928709997495813,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-20 08:17:54",
+ "memberId": 2844990190242821,
+ "memberName": "叶总",
+ "tenantMemberCardId": 2844990190488581,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "13711223287",
+ "tableId": 0,
+ "consumeMoney": 5000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 5000.0,
+ "pointAmount": 5000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2928709997200901,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-20 08:17:54",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2928484764517765,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-20 04:28:47",
+ "memberId": 2799212499355397,
+ "memberName": "吕先生",
+ "tenantMemberCardId": 2799219220924165,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "15559110663",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2928484764091781,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-20 04:28:47",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2928450397291909,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-20 03:53:50",
+ "memberId": 2844990190242821,
+ "memberName": "叶总",
+ "tenantMemberCardId": 2844990190488581,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "13711223287",
+ "tableId": 0,
+ "consumeMoney": 700.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 700.0,
+ "pointAmount": 700.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2928450396915077,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-20 03:53:50",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2926790906103365,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-18 23:45:42",
+ "memberId": 2846153189592005,
+ "memberName": "黄先生",
+ "tenantMemberCardId": 2846153189837765,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "15818822109",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2926790905775685,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-18 23:45:42",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2926696810563077,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-18 22:09:59",
+ "memberId": 2799207124305669,
+ "memberName": "陈腾鑫",
+ "tenantMemberCardId": 2799215988246277,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "17817318218",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2926696810169861,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-18 22:09:59",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2925404001666501,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-18 00:14:52",
+ "memberId": 2799207359858437,
+ "memberName": "罗先生",
+ "tenantMemberCardId": 2799218552833797,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "13924036996",
+ "tableId": 0,
+ "consumeMoney": 1000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 1000.0,
+ "pointAmount": 1000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2925404000994757,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-18 00:14:52",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2924166423692805,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-17 03:15:57",
+ "memberId": 2799207599212293,
+ "memberName": "小熊",
+ "tenantMemberCardId": 2799217260676869,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "13927020145",
+ "tableId": 0,
+ "consumeMoney": 1000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 1000.0,
+ "pointAmount": 1000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2924166423332357,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-17 03:15:57",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2924164846847365,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-17 03:14:20",
+ "memberId": 2820625955784965,
+ "memberName": "江先生",
+ "tenantMemberCardId": 2820628725778629,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18819484838",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2924164846519685,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-17 03:14:20",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2923680677430661,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-16 19:01:49",
+ "memberId": 2799207342704389,
+ "memberName": "叶先生",
+ "tenantMemberCardId": 2799216610576133,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "13826479539",
+ "tableId": 0,
+ "consumeMoney": 307.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 307.0,
+ "pointAmount": 307.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2923680676955525,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-16 19:01:49",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2922805984527877,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-16 04:12:02",
+ "memberId": 2799207522600709,
+ "memberName": "轩哥",
+ "tenantMemberCardId": 2799217444914949,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18826267530",
+ "tableId": 0,
+ "consumeMoney": 5000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 5000.0,
+ "pointAmount": 5000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2922805984118277,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-16 04:12:02",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2922551421158789,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-15 23:53:05",
+ "memberId": 2799212499355397,
+ "memberName": "吕先生",
+ "tenantMemberCardId": 2799219220924165,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "15559110663",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2922551420749189,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-15 23:53:05",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 1,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2919713899613829,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-13 23:46:36",
+ "memberId": 2799207522600709,
+ "memberName": "轩哥",
+ "tenantMemberCardId": 2799217444914949,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18826267530",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2919713899269765,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-13 23:46:36",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2919691318627973,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 3000.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-13 23:23:38",
+ "memberId": 2919518015802181,
+ "memberName": "陶",
+ "tenantMemberCardId": 2919518016211781,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18924022151",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 0.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2919691318251141,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-13 23:23:38",
+ "roundingAmount": 0.0,
+ "paymentMethod": 2,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2919690721152517,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-13 23:23:01",
+ "memberId": 2919518015802181,
+ "memberName": "陶",
+ "tenantMemberCardId": 2919518016211781,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18924022151",
+ "tableId": 0,
+ "consumeMoney": -3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": -3000.0,
+ "pointAmount": 0.0,
+ "refundAmount": 0.0,
+ "settleName": "充值撤销",
+ "settleRelateId": 2919690720972293,
+ "settleStatus": 2,
+ "settleType": 7,
+ "payTime": "2025-10-13 23:23:01",
+ "roundingAmount": 0.0,
+ "paymentMethod": 1,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 1,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2919519810178693,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-13 20:29:10",
+ "memberId": 2919518015802181,
+ "memberName": "陶",
+ "tenantMemberCardId": 2919518016211781,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18924022151",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 3000.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2919519809605253,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-13 20:29:10",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 1,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2917921298729925,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-12 17:23:04",
+ "memberId": 2799207370163973,
+ "memberName": "歌神",
+ "tenantMemberCardId": 2799216599402245,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18819262164",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2917921298303941,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-12 17:23:05",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2917100006034181,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-12 03:27:37",
+ "memberId": 2799207522600709,
+ "memberName": "轩哥",
+ "tenantMemberCardId": 2799217444914949,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18826267530",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2917100005690117,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-12 03:27:37",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2916518262622981,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-11 17:35:50",
+ "memberId": 2799207522600709,
+ "memberName": "轩哥",
+ "tenantMemberCardId": 2799217444914949,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18826267530",
+ "tableId": 0,
+ "consumeMoney": 10000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 10000.0,
+ "pointAmount": 10000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2916518262262533,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-11 17:35:50",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2915510025685701,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-11 00:30:12",
+ "memberId": 2799209768765189,
+ "memberName": "罗先生",
+ "tenantMemberCardId": 2799217471063813,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "13922289222",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2915510025243333,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-11 00:30:12",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 1,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2915375205633029,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-10 22:13:03",
+ "memberId": 2799207519176453,
+ "memberName": "夏",
+ "tenantMemberCardId": 2799217048848133,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "19120942851",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2915375205174277,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-10 22:13:03",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2913844390610501,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-09 20:15:50",
+ "memberId": 2799207124305669,
+ "memberName": "陈腾鑫",
+ "tenantMemberCardId": 2799215988246277,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "17817318218",
+ "tableId": 0,
+ "consumeMoney": 1000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 1000.0,
+ "pointAmount": 1000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2913844390102597,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-09 20:15:50",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2913807879833221,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-09 19:38:41",
+ "memberId": 2848686922632133,
+ "memberName": "婉婉",
+ "tenantMemberCardId": 2848686922910661,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18345432742",
+ "tableId": 0,
+ "consumeMoney": 1000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 1000.0,
+ "pointAmount": 1000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2913807879308933,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-09 19:38:41",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2912561032529349,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-08 22:30:20",
+ "memberId": 2799207287523077,
+ "memberName": "汪先生",
+ "tenantMemberCardId": 2799218289641221,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "13925126339",
+ "tableId": 0,
+ "consumeMoney": 1000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 1000.0,
+ "pointAmount": 1000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2912561032152517,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-08 22:30:20",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2911305097709189,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-08 01:12:43",
+ "memberId": 2799207580059397,
+ "memberName": "罗超",
+ "tenantMemberCardId": 2799219299469061,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "13751780990",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2911305097201286,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-08 01:12:44",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 1,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2908450447476357,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-06 00:48:49",
+ "memberId": 2820625955784965,
+ "memberName": "江先生",
+ "tenantMemberCardId": 2820628725778629,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18819484838",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2908450447066757,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-06 00:48:50",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2908349322675589,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-05 23:05:57",
+ "memberId": 2799212845565701,
+ "memberName": "曾丹烨",
+ "tenantMemberCardId": 2799219999295237,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "13922213242",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2908349322151301,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-05 23:05:57",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2907419840054661,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-05 07:20:26",
+ "memberId": 2799207522600709,
+ "memberName": "轩哥",
+ "tenantMemberCardId": 2799217444914949,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18826267530",
+ "tableId": 0,
+ "consumeMoney": 5000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 5000.0,
+ "pointAmount": 5000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2907419839595909,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-05 07:20:26",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2907390916429189,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-05 06:51:01",
+ "memberId": 2799207342704389,
+ "memberName": "叶先生",
+ "tenantMemberCardId": 2799216610576133,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "13826479539",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2907390915954053,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-05 06:51:01",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2905666489108037,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-04 01:36:50",
+ "memberId": 2799207522600709,
+ "memberName": "轩哥",
+ "tenantMemberCardId": 2799217444914949,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18826267530",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2905666488649285,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-04 01:36:50",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2905552336307589,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-03 23:40:43",
+ "memberId": 2799207359858437,
+ "memberName": "罗先生",
+ "tenantMemberCardId": 2799218552833797,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "13924036996",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2905552335750533,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-03 23:40:43",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2904235940514821,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-03 01:21:36",
+ "memberId": 2799207522600709,
+ "memberName": "轩哥",
+ "tenantMemberCardId": 2799217444914949,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18826267530",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2904235939908613,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-03 01:21:37",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2903676739456197,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-02 15:52:45",
+ "memberId": 2799207159990021,
+ "memberName": "邓飛",
+ "tenantMemberCardId": 2799216107980549,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "13600009597",
+ "tableId": 0,
+ "consumeMoney": 1345.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 1345.0,
+ "pointAmount": 1345.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2903676739013829,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-02 15:52:46",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2902997454785733,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-02 04:21:45",
+ "memberId": 2799207342704389,
+ "memberName": "叶先生",
+ "tenantMemberCardId": 2799216610576133,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "13826479539",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2902997454326981,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-02 04:21:45",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2902496166988741,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-01 19:51:49",
+ "memberId": 2799207519176453,
+ "memberName": "夏",
+ "tenantMemberCardId": 2799217048848133,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "19120942851",
+ "tableId": 0,
+ "consumeMoney": 1000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 1000.0,
+ "pointAmount": 1000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2902496166398917,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-01 19:51:49",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ },
+ {
+ "siteProfile": {
+ "id": 2790685415443269,
+ "org_id": 2790684179467077,
+ "shop_name": "朗朗桌球",
+ "avatar": "https://oss.ficoo.vip/admin/hXcE4E_1752495052016.jpg",
+ "business_tel": "13316068642",
+ "full_address": "广东省广州市天河区丽阳街12号",
+ "address": "广东省广州市天河区天园街道朗朗桌球",
+ "longitude": 113.360321,
+ "latitude": 23.133629,
+ "tenant_site_region_id": 156440100,
+ "tenant_id": 2790683160709957,
+ "auto_light": 1,
+ "attendance_distance": 0,
+ "wifi_name": "",
+ "wifi_password": "",
+ "customer_service_qrcode": "",
+ "customer_service_wechat": "",
+ "fixed_pay_qrCode": "",
+ "prod_env": 1,
+ "light_status": 1,
+ "light_type": 0,
+ "site_type": 1,
+ "light_token": "",
+ "site_label": "A",
+ "attendance_enabled": 1,
+ "shop_status": 1
+ },
+ "settleList": {
+ "id": 2901346035322053,
+ "tenantId": 2790683160709957,
+ "siteId": 2790685415443269,
+ "siteName": "",
+ "balanceAmount": 0.0,
+ "cardAmount": 0.0,
+ "cashAmount": 0.0,
+ "couponAmount": 0.0,
+ "createTime": "2025-10-01 00:21:51",
+ "memberId": 2799207522600709,
+ "memberName": "轩哥",
+ "tenantMemberCardId": 2799217444914949,
+ "memberCardTypeName": "储值卡",
+ "memberPhone": "18826267530",
+ "tableId": 0,
+ "consumeMoney": 3000.0,
+ "onlineAmount": 0.0,
+ "operatorId": 2790687322443013,
+ "operatorName": "收银员:郑丽珊",
+ "revokeOrderId": 0,
+ "revokeOrderName": "",
+ "revokeTime": "0001-01-01 00:00:00",
+ "payAmount": 3000.0,
+ "pointAmount": 3000.0,
+ "refundAmount": 0.0,
+ "settleName": "充值订单",
+ "settleRelateId": 2901346034846917,
+ "settleStatus": 2,
+ "settleType": 5,
+ "payTime": "2025-10-01 00:21:51",
+ "roundingAmount": 0.0,
+ "paymentMethod": 4,
+ "adjustAmount": 0.0,
+ "assistantCxMoney": 0.0,
+ "assistantPdMoney": 0.0,
+ "couponSaleAmount": 0.0,
+ "memberDiscountAmount": 0.0,
+ "tableChargeMoney": 0.0,
+ "goodsMoney": 0.0,
+ "realGoodsMoney": 0.0,
+ "serviceMoney": 0.0,
+ "prepayMoney": 0.0,
+ "salesManName": "",
+ "orderRemark": "",
+ "salesManUserId": 0,
+ "canBeRevoked": false,
+ "pointDiscountPrice": 0.0,
+ "pointDiscountCost": 0.0,
+ "activityDiscount": 0.0,
+ "serialNumber": 0,
+ "assistantManualDiscount": 0.0,
+ "allCouponDiscount": 0.0,
+ "goodsPromotionMoney": 0.0,
+ "assistantPromotionMoney": 0.0,
+ "isUseCoupon": false,
+ "isUseDiscount": false,
+ "isActivity": false,
+ "isBindMember": false,
+ "isFirst": 2,
+ "rechargeCardAmount": 0,
+ "giftCardAmount": 0
+ }
+ }
+ ]
+ },
+ "code": 0
+ },
+ {
+ "data": {
+ "total": 74,
+ "settleList": []
+ },
+ "code": 0
+ }
+]
\ No newline at end of file
diff --git a/etl_billiards/database/schema_dwd.sql b/tmp/schema_dwd.sql
similarity index 100%
rename from etl_billiards/database/schema_dwd.sql
rename to tmp/schema_dwd.sql
diff --git a/tmp/single_ingest/goods_stock_movements.json b/tmp/single_ingest/goods_stock_movements.json
new file mode 100644
index 0000000..5588483
--- /dev/null
+++ b/tmp/single_ingest/goods_stock_movements.json
@@ -0,0 +1,4218 @@
+[
+ {
+ "data": {
+ "total": 5915,
+ "queryDeliveryRecordsList": [
+ {
+ "siteGoodsStockId": 2957911857581957,
+ "siteGoodsId": 2793026183532613,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "阿萨姆",
+ "createTime": "2025-11-09 23:23:34",
+ "startNum": 28,
+ "endNum": 27,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957908562546181,
+ "siteGoodsId": 2868240313094021,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "蜂蜜水",
+ "createTime": "2025-11-09 23:20:13",
+ "startNum": 60,
+ "endNum": 59,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 10.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957905405087621,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 23:17:01",
+ "startNum": 279,
+ "endNum": 278,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957886359998341,
+ "siteGoodsId": 2826003636177861,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "长寿街臭干子",
+ "createTime": "2025-11-09 22:57:38",
+ "startNum": 98,
+ "endNum": 96,
+ "changeNum": -2,
+ "unit": "包",
+ "price": 2.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2791948300259205
+ },
+ {
+ "siteGoodsStockId": 2957886359703429,
+ "siteGoodsId": 2793025849102405,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "火鸡面",
+ "createTime": "2025-11-09 22:57:38",
+ "startNum": 11,
+ "endNum": 10,
+ "changeNum": -1,
+ "unit": "桶",
+ "price": 10.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2793236829620037
+ },
+ {
+ "siteGoodsStockId": 2957886359408517,
+ "siteGoodsId": 2793025849593925,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "地道肠",
+ "createTime": "2025-11-09 22:57:38",
+ "startNum": 212,
+ "endNum": 211,
+ "changeNum": -1,
+ "unit": "根",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793220945250117,
+ "goodsSecondCategoryId": 2793221283104581
+ },
+ {
+ "siteGoodsStockId": 2957885299511173,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 22:56:33",
+ "startNum": 281,
+ "endNum": 279,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957881233444677,
+ "siteGoodsId": 2794695802065029,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "鸡翅三个一份",
+ "createTime": "2025-11-09 22:52:25",
+ "startNum": 7,
+ "endNum": 6,
+ "changeNum": -1,
+ "unit": "份",
+ "price": 18.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793220945250117,
+ "goodsSecondCategoryId": 2793221283104581
+ },
+ {
+ "siteGoodsStockId": 2957869009637061,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 22:39:59",
+ "startNum": 282,
+ "endNum": 281,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957864363347781,
+ "siteGoodsId": 2794695801409669,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "普通扑克",
+ "createTime": "2025-11-09 22:35:16",
+ "startNum": 16,
+ "endNum": 15,
+ "changeNum": -1,
+ "unit": "盒",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793217944864581,
+ "goodsSecondCategoryId": 2793218343257925
+ },
+ {
+ "siteGoodsStockId": 2957863619809093,
+ "siteGoodsId": 2868240313094021,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "蜂蜜水",
+ "createTime": "2025-11-09 22:34:30",
+ "startNum": 61,
+ "endNum": 60,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 10.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957863385878341,
+ "siteGoodsId": 2793026180993093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "农夫山泉苏打水",
+ "createTime": "2025-11-09 22:34:16",
+ "startNum": 34,
+ "endNum": 33,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 6.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957863385452357,
+ "siteGoodsId": 2794695800934533,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "一次性手套",
+ "createTime": "2025-11-09 22:34:16",
+ "startNum": 123,
+ "endNum": 122,
+ "changeNum": -1,
+ "unit": "个",
+ "price": 2.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793217944864581,
+ "goodsSecondCategoryId": 2793218343257925
+ },
+ {
+ "siteGoodsStockId": 2957861202365957,
+ "siteGoodsId": 2794695802065029,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "鸡翅三个一份",
+ "createTime": "2025-11-09 22:32:03",
+ "startNum": 8,
+ "endNum": 7,
+ "changeNum": -1,
+ "unit": "份",
+ "price": 18.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793220945250117,
+ "goodsSecondCategoryId": 2793221283104581
+ },
+ {
+ "siteGoodsStockId": 2957859847671621,
+ "siteGoodsId": 2793025849593925,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "地道肠",
+ "createTime": "2025-11-09 22:30:40",
+ "startNum": 214,
+ "endNum": 212,
+ "changeNum": -2,
+ "unit": "根",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793220945250117,
+ "goodsSecondCategoryId": 2793221283104581
+ },
+ {
+ "siteGoodsStockId": 2957858456276869,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 22:29:15",
+ "startNum": 283,
+ "endNum": 282,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957858455883653,
+ "siteGoodsId": 2793026183041093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "可乐",
+ "createTime": "2025-11-09 22:29:15",
+ "startNum": 96,
+ "endNum": 95,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957857677790725,
+ "siteGoodsId": 2793026180993093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "农夫山泉苏打水",
+ "createTime": "2025-11-09 22:28:28",
+ "startNum": 35,
+ "endNum": 34,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 6.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957857677364741,
+ "siteGoodsId": 2791953867886725,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "东方树叶",
+ "createTime": "2025-11-09 22:28:28",
+ "startNum": 119,
+ "endNum": 118,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957857132121925,
+ "siteGoodsId": 2793026174865477,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "水溶C",
+ "createTime": "2025-11-09 22:27:54",
+ "startNum": 55,
+ "endNum": 54,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957857131728709,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 22:27:54",
+ "startNum": 284,
+ "endNum": 283,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957821892152837,
+ "siteGoodsId": 2793025860145221,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "双中支中华",
+ "createTime": "2025-11-09 21:52:03",
+ "startNum": 4,
+ "endNum": 2,
+ "changeNum": -2,
+ "unit": "包",
+ "price": 72.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2792062778003333,
+ "goodsSecondCategoryId": 2792063209623429
+ },
+ {
+ "siteGoodsStockId": 2957815972531717,
+ "siteGoodsId": 2793025862438981,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "钻石荷花",
+ "createTime": "2025-11-09 21:46:02",
+ "startNum": 15,
+ "endNum": 13,
+ "changeNum": -2,
+ "unit": "包",
+ "price": 45.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2792062778003333,
+ "goodsSecondCategoryId": 2792063209623429
+ },
+ {
+ "siteGoodsStockId": 2957815972138501,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 21:46:02",
+ "startNum": 285,
+ "endNum": 284,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957815643639621,
+ "siteGoodsId": 2793025862438981,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "钻石荷花",
+ "createTime": "2025-11-09 21:45:42",
+ "startNum": 13,
+ "endNum": 15,
+ "changeNum": 2,
+ "unit": "包",
+ "price": 45.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2792062778003333,
+ "goodsSecondCategoryId": 2792063209623429
+ },
+ {
+ "siteGoodsStockId": 2957815530426053,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 21:45:35",
+ "startNum": 286,
+ "endNum": 285,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957815529950917,
+ "siteGoodsId": 2793025862438981,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "钻石荷花",
+ "createTime": "2025-11-09 21:45:35",
+ "startNum": 15,
+ "endNum": 13,
+ "changeNum": -2,
+ "unit": "包",
+ "price": 45.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2792062778003333,
+ "goodsSecondCategoryId": 2792063209623429
+ },
+ {
+ "siteGoodsStockId": 2957815167815365,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 21:45:13",
+ "startNum": 287,
+ "endNum": 286,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957814738996741,
+ "siteGoodsId": 2793026176503877,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "轻上椰子水",
+ "createTime": "2025-11-09 21:44:47",
+ "startNum": 50,
+ "endNum": 48,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 12.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957814478786373,
+ "siteGoodsId": 2793026176503877,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "轻上椰子水",
+ "createTime": "2025-11-09 21:44:31",
+ "startNum": 51,
+ "endNum": 50,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 12.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957795024752517,
+ "siteGoodsId": 2793026184974405,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "卡士",
+ "createTime": "2025-11-09 21:24:44",
+ "startNum": 2,
+ "endNum": 0,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 22.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957788100595589,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 21:17:41",
+ "startNum": 288,
+ "endNum": 287,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957788100300677,
+ "siteGoodsId": 2793026180993093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "农夫山泉苏打水",
+ "createTime": "2025-11-09 21:17:41",
+ "startNum": 41,
+ "endNum": 35,
+ "changeNum": -6,
+ "unit": "瓶",
+ "price": 6.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957787478183813,
+ "siteGoodsId": 2793026185154629,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "百威235毫升",
+ "createTime": "2025-11-09 21:17:03",
+ "startNum": 343,
+ "endNum": 307,
+ "changeNum": -36,
+ "unit": "瓶",
+ "price": 15.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350541
+ },
+ {
+ "siteGoodsStockId": 2957786810420933,
+ "siteGoodsId": 2793026184974405,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "卡士",
+ "createTime": "2025-11-09 21:16:22",
+ "startNum": 5,
+ "endNum": 2,
+ "changeNum": -3,
+ "unit": "瓶",
+ "price": 22.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957786577244037,
+ "siteGoodsId": 2793026185154629,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "百威235毫升",
+ "createTime": "2025-11-09 21:16:08",
+ "startNum": 307,
+ "endNum": 343,
+ "changeNum": 36,
+ "unit": "瓶",
+ "price": 15.0,
+ "operatorName": "系统",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350541
+ },
+ {
+ "siteGoodsStockId": 2957786541575685,
+ "siteGoodsId": 2793026185154629,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "百威235毫升",
+ "createTime": "2025-11-09 21:16:06",
+ "startNum": 343,
+ "endNum": 307,
+ "changeNum": -36,
+ "unit": "瓶",
+ "price": 15.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350541
+ },
+ {
+ "siteGoodsStockId": 2957786283101701,
+ "siteGoodsId": 2793026185154629,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "百威235毫升",
+ "createTime": "2025-11-09 21:15:50",
+ "startNum": 332,
+ "endNum": 343,
+ "changeNum": 11,
+ "unit": "瓶",
+ "price": 15.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350541
+ },
+ {
+ "siteGoodsStockId": 2957786211487237,
+ "siteGoodsId": 2793026185154629,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "百威235毫升",
+ "createTime": "2025-11-09 21:15:46",
+ "startNum": 331,
+ "endNum": 332,
+ "changeNum": 1,
+ "unit": "瓶",
+ "price": 15.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350541
+ },
+ {
+ "siteGoodsStockId": 2957786053463557,
+ "siteGoodsId": 2791953867886725,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "东方树叶",
+ "createTime": "2025-11-09 21:15:36",
+ "startNum": 120,
+ "endNum": 119,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957785947672069,
+ "siteGoodsId": 2793026185154629,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "百威235毫升",
+ "createTime": "2025-11-09 21:15:29",
+ "startNum": 319,
+ "endNum": 331,
+ "changeNum": 12,
+ "unit": "瓶",
+ "price": 15.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350541
+ },
+ {
+ "siteGoodsStockId": 2957785873894917,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 21:15:25",
+ "startNum": 287,
+ "endNum": 288,
+ "changeNum": 1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957785776590341,
+ "siteGoodsId": 2793026185154629,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "百威235毫升",
+ "createTime": "2025-11-09 21:15:19",
+ "startNum": 307,
+ "endNum": 319,
+ "changeNum": 12,
+ "unit": "瓶",
+ "price": 15.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350541
+ },
+ {
+ "siteGoodsStockId": 2957785236787013,
+ "siteGoodsId": 2793026180993093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "农夫山泉苏打水",
+ "createTime": "2025-11-09 21:14:46",
+ "startNum": 35,
+ "endNum": 41,
+ "changeNum": 6,
+ "unit": "瓶",
+ "price": 6.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957783492513477,
+ "siteGoodsId": 2793026183041093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "可乐",
+ "createTime": "2025-11-09 21:13:00",
+ "startNum": 97,
+ "endNum": 96,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957780975586821,
+ "siteGoodsId": 2793026183041093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "可乐",
+ "createTime": "2025-11-09 21:10:26",
+ "startNum": 98,
+ "endNum": 97,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957761222331909,
+ "siteGoodsId": 2791953867886725,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "东方树叶",
+ "createTime": "2025-11-09 20:50:20",
+ "startNum": 121,
+ "endNum": 120,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957750510145413,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 20:39:27",
+ "startNum": 289,
+ "endNum": 287,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957750509686661,
+ "siteGoodsId": 2793026183041093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "可乐",
+ "createTime": "2025-11-09 20:39:27",
+ "startNum": 99,
+ "endNum": 98,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957749929889285,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 20:38:51",
+ "startNum": 291,
+ "endNum": 289,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957749609319941,
+ "siteGoodsId": 2793026180993093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "农夫山泉苏打水",
+ "createTime": "2025-11-09 20:38:32",
+ "startNum": 36,
+ "endNum": 35,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 6.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957749608992261,
+ "siteGoodsId": 2793025849102405,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "火鸡面",
+ "createTime": "2025-11-09 20:38:32",
+ "startNum": 12,
+ "endNum": 11,
+ "changeNum": -1,
+ "unit": "桶",
+ "price": 10.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2793236829620037
+ },
+ {
+ "siteGoodsStockId": 2957730790199173,
+ "siteGoodsId": 2793025849593925,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "地道肠",
+ "createTime": "2025-11-09 20:19:23",
+ "startNum": 215,
+ "endNum": 214,
+ "changeNum": -1,
+ "unit": "根",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793220945250117,
+ "goodsSecondCategoryId": 2793221283104581
+ },
+ {
+ "siteGoodsStockId": 2957730789789573,
+ "siteGoodsId": 2791953867886725,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "东方树叶",
+ "createTime": "2025-11-09 20:19:23",
+ "startNum": 122,
+ "endNum": 121,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957724530724549,
+ "siteGoodsId": 2793026185154629,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "百威235毫升",
+ "createTime": "2025-11-09 20:13:01",
+ "startNum": 319,
+ "endNum": 307,
+ "changeNum": -12,
+ "unit": "瓶",
+ "price": 15.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350541
+ },
+ {
+ "siteGoodsStockId": 2957723760037701,
+ "siteGoodsId": 2794695800934533,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "一次性手套",
+ "createTime": "2025-11-09 20:12:14",
+ "startNum": 124,
+ "endNum": 123,
+ "changeNum": -1,
+ "unit": "个",
+ "price": 2.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793217944864581,
+ "goodsSecondCategoryId": 2793218343257925
+ },
+ {
+ "siteGoodsStockId": 2957714749919109,
+ "siteGoodsId": 2791953867886725,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "东方树叶",
+ "createTime": "2025-11-09 20:03:04",
+ "startNum": 124,
+ "endNum": 122,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957700557246149,
+ "siteGoodsId": 2793026184646725,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "冰红茶",
+ "createTime": "2025-11-09 19:48:38",
+ "startNum": 49,
+ "endNum": 48,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 6.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957700556820165,
+ "siteGoodsId": 2791953867886725,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "东方树叶",
+ "createTime": "2025-11-09 19:48:38",
+ "startNum": 125,
+ "endNum": 124,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957699263696389,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 19:47:19",
+ "startNum": 292,
+ "endNum": 291,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957684739952325,
+ "siteGoodsId": 2793026183041093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "可乐",
+ "createTime": "2025-11-09 19:32:32",
+ "startNum": 100,
+ "endNum": 99,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957678126419781,
+ "siteGoodsId": 2793026185154629,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "百威235毫升",
+ "createTime": "2025-11-09 19:25:49",
+ "startNum": 331,
+ "endNum": 319,
+ "changeNum": -12,
+ "unit": "瓶",
+ "price": 15.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350541
+ },
+ {
+ "siteGoodsStockId": 2957651515838277,
+ "siteGoodsId": 2793026185154629,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "百威235毫升",
+ "createTime": "2025-11-09 18:58:44",
+ "startNum": 343,
+ "endNum": 331,
+ "changeNum": -12,
+ "unit": "瓶",
+ "price": 15.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350541
+ },
+ {
+ "siteGoodsStockId": 2957651515428677,
+ "siteGoodsId": 2793026180993093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "农夫山泉苏打水",
+ "createTime": "2025-11-09 18:58:44",
+ "startNum": 42,
+ "endNum": 36,
+ "changeNum": -6,
+ "unit": "瓶",
+ "price": 6.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957650904927749,
+ "siteGoodsId": 2793026183041093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "可乐",
+ "createTime": "2025-11-09 18:58:07",
+ "startNum": 101,
+ "endNum": 100,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957648287797125,
+ "siteGoodsId": 2793025849593925,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "地道肠",
+ "createTime": "2025-11-09 18:55:27",
+ "startNum": 217,
+ "endNum": 215,
+ "changeNum": -2,
+ "unit": "根",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793220945250117,
+ "goodsSecondCategoryId": 2793221283104581
+ },
+ {
+ "siteGoodsStockId": 2957635479687045,
+ "siteGoodsId": 2793026180993093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "农夫山泉苏打水",
+ "createTime": "2025-11-09 18:42:26",
+ "startNum": 43,
+ "endNum": 42,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 6.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957635479392133,
+ "siteGoodsId": 2791953867886725,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "东方树叶",
+ "createTime": "2025-11-09 18:42:26",
+ "startNum": 126,
+ "endNum": 125,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957635296677381,
+ "siteGoodsId": 2794695801753733,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "掼蛋扑克",
+ "createTime": "2025-11-09 18:42:14",
+ "startNum": 54,
+ "endNum": 52,
+ "changeNum": -2,
+ "unit": "盒",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793217944864581,
+ "goodsSecondCategoryId": 2793218343257925
+ },
+ {
+ "siteGoodsStockId": 2957633426329285,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 18:40:20",
+ "startNum": 294,
+ "endNum": 292,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957633425870533,
+ "siteGoodsId": 2793026180993093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "农夫山泉苏打水",
+ "createTime": "2025-11-09 18:40:20",
+ "startNum": 45,
+ "endNum": 43,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 6.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957622553579013,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 18:29:17",
+ "startNum": 296,
+ "endNum": 294,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957610094841669,
+ "siteGoodsId": 2793025860145221,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "双中支中华",
+ "createTime": "2025-11-09 18:16:36",
+ "startNum": 5,
+ "endNum": 4,
+ "changeNum": -1,
+ "unit": "包",
+ "price": 72.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2792062778003333,
+ "goodsSecondCategoryId": 2792063209623429
+ },
+ {
+ "siteGoodsStockId": 2957609373077381,
+ "siteGoodsId": 2868240313094021,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "蜂蜜水",
+ "createTime": "2025-11-09 18:15:52",
+ "startNum": 62,
+ "endNum": 61,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 10.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957609372782469,
+ "siteGoodsId": 2793026177486917,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈AD钙奶",
+ "createTime": "2025-11-09 18:15:52",
+ "startNum": 78,
+ "endNum": 77,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957606919360325,
+ "siteGoodsId": 2826003636177861,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "长寿街臭干子",
+ "createTime": "2025-11-09 18:13:22",
+ "startNum": 100,
+ "endNum": 98,
+ "changeNum": -2,
+ "unit": "包",
+ "price": 2.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2791948300259205
+ },
+ {
+ "siteGoodsStockId": 2957606918901573,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 18:13:22",
+ "startNum": 302,
+ "endNum": 296,
+ "changeNum": -6,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957605951278789,
+ "siteGoodsId": 2793025862799429,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "软玉溪",
+ "createTime": "2025-11-09 18:12:23",
+ "startNum": 21,
+ "endNum": 20,
+ "changeNum": -1,
+ "unit": "包",
+ "price": 28.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2792062778003333,
+ "goodsSecondCategoryId": 2792063209623429
+ },
+ {
+ "siteGoodsStockId": 2957603839545221,
+ "siteGoodsId": 2793026184646725,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "冰红茶",
+ "createTime": "2025-11-09 18:10:14",
+ "startNum": 50,
+ "endNum": 49,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 6.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957601966706565,
+ "siteGoodsId": 2794695801753733,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "掼蛋扑克",
+ "createTime": "2025-11-09 18:08:20",
+ "startNum": 52,
+ "endNum": 54,
+ "changeNum": 2,
+ "unit": "盒",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793217944864581,
+ "goodsSecondCategoryId": 2793218343257925
+ },
+ {
+ "siteGoodsStockId": 2957601853853573,
+ "siteGoodsId": 2794695801753733,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "掼蛋扑克",
+ "createTime": "2025-11-09 18:08:13",
+ "startNum": 54,
+ "endNum": 52,
+ "changeNum": -2,
+ "unit": "盒",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793217944864581,
+ "goodsSecondCategoryId": 2793218343257925
+ },
+ {
+ "siteGoodsStockId": 2957599397908357,
+ "siteGoodsId": 2793026183041093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "可乐",
+ "createTime": "2025-11-09 18:05:43",
+ "startNum": 102,
+ "endNum": 101,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957599270195077,
+ "siteGoodsId": 2793026175356997,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "脉动",
+ "createTime": "2025-11-09 18:05:36",
+ "startNum": 26,
+ "endNum": 25,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957587268013765,
+ "siteGoodsId": 2793026180993093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "农夫山泉苏打水",
+ "createTime": "2025-11-09 17:53:23",
+ "startNum": 46,
+ "endNum": 45,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 6.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957585881730949,
+ "siteGoodsId": 2791953867886725,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "东方树叶",
+ "createTime": "2025-11-09 17:51:58",
+ "startNum": 127,
+ "endNum": 126,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957585881321349,
+ "siteGoodsId": 2793026185515077,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "雪碧",
+ "createTime": "2025-11-09 17:51:58",
+ "startNum": 62,
+ "endNum": 61,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957578616377029,
+ "siteGoodsId": 2791953867886725,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "东方树叶",
+ "createTime": "2025-11-09 17:44:35",
+ "startNum": 128,
+ "endNum": 127,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957573882465989,
+ "siteGoodsId": 2793025861505093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "红利群",
+ "createTime": "2025-11-09 17:39:46",
+ "startNum": 10,
+ "endNum": 9,
+ "changeNum": -1,
+ "unit": "包",
+ "price": 26.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2792062778003333,
+ "goodsSecondCategoryId": 2792063209623429
+ },
+ {
+ "siteGoodsStockId": 2957564018478597,
+ "siteGoodsId": 2794695800934533,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "一次性手套",
+ "createTime": "2025-11-09 17:29:44",
+ "startNum": 125,
+ "endNum": 124,
+ "changeNum": -1,
+ "unit": "个",
+ "price": 2.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793217944864581,
+ "goodsSecondCategoryId": 2793218343257925
+ },
+ {
+ "siteGoodsStockId": 2957550403538437,
+ "siteGoodsId": 2793026185154629,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "百威235毫升",
+ "createTime": "2025-11-09 17:15:53",
+ "startNum": 345,
+ "endNum": 343,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 15.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350541
+ },
+ {
+ "siteGoodsStockId": 2957543734349701,
+ "siteGoodsId": 2794695801409669,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "普通扑克",
+ "createTime": "2025-11-09 17:09:06",
+ "startNum": 17,
+ "endNum": 16,
+ "changeNum": -1,
+ "unit": "盒",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793217944864581,
+ "goodsSecondCategoryId": 2793218343257925
+ },
+ {
+ "siteGoodsStockId": 2957538712670021,
+ "siteGoodsId": 2794695800934533,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "一次性手套",
+ "createTime": "2025-11-09 17:03:59",
+ "startNum": 126,
+ "endNum": 125,
+ "changeNum": -1,
+ "unit": "个",
+ "price": 2.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793217944864581,
+ "goodsSecondCategoryId": 2793218343257925
+ },
+ {
+ "siteGoodsStockId": 2957535156031173,
+ "siteGoodsId": 2791953867886725,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "东方树叶",
+ "createTime": "2025-11-09 17:00:22",
+ "startNum": 131,
+ "endNum": 128,
+ "changeNum": -3,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957531838844613,
+ "siteGoodsId": 2791953867886725,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "东方树叶",
+ "createTime": "2025-11-09 16:57:00",
+ "startNum": 132,
+ "endNum": 131,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957531838467781,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 16:57:00",
+ "startNum": 303,
+ "endNum": 302,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957529797349189,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 16:54:55",
+ "startNum": 304,
+ "endNum": 303,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957529796890437,
+ "siteGoodsId": 2793026174865477,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "水溶C",
+ "createTime": "2025-11-09 16:54:55",
+ "startNum": 57,
+ "endNum": 55,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957529061461893,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 16:54:10",
+ "startNum": 301,
+ "endNum": 304,
+ "changeNum": 3,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957528487595717,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 16:53:35",
+ "startNum": 304,
+ "endNum": 301,
+ "changeNum": -3,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957528359833477,
+ "siteGoodsId": 2793026185154629,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "百威235毫升",
+ "createTime": "2025-11-09 16:53:28",
+ "startNum": 344,
+ "endNum": 345,
+ "changeNum": 1,
+ "unit": "瓶",
+ "price": 15.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350541
+ }
+ ]
+ },
+ "code": 0
+ },
+ {
+ "data": {
+ "total": 5915,
+ "queryDeliveryRecordsList": [
+ {
+ "siteGoodsStockId": 2957513359134405,
+ "siteGoodsId": 2794695800934533,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "一次性手套",
+ "createTime": "2025-11-09 16:38:12",
+ "startNum": 128,
+ "endNum": 126,
+ "changeNum": -2,
+ "unit": "个",
+ "price": 2.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793217944864581,
+ "goodsSecondCategoryId": 2793218343257925
+ },
+ {
+ "siteGoodsStockId": 2957511204048773,
+ "siteGoodsId": 2793026185154629,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "百威235毫升",
+ "createTime": "2025-11-09 16:36:00",
+ "startNum": 345,
+ "endNum": 344,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 15.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350541
+ },
+ {
+ "siteGoodsStockId": 2957493084458885,
+ "siteGoodsId": 2794695800934533,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "一次性手套",
+ "createTime": "2025-11-09 16:17:35",
+ "startNum": 129,
+ "endNum": 128,
+ "changeNum": -1,
+ "unit": "个",
+ "price": 2.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793217944864581,
+ "goodsSecondCategoryId": 2793218343257925
+ },
+ {
+ "siteGoodsStockId": 2957487737163269,
+ "siteGoodsId": 2794695801753733,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "掼蛋扑克",
+ "createTime": "2025-11-09 16:12:08",
+ "startNum": 56,
+ "endNum": 54,
+ "changeNum": -2,
+ "unit": "盒",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793217944864581,
+ "goodsSecondCategoryId": 2793218343257925
+ },
+ {
+ "siteGoodsStockId": 2957465626463749,
+ "siteGoodsId": 2794695800934533,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "一次性手套",
+ "createTime": "2025-11-09 15:49:39",
+ "startNum": 130,
+ "endNum": 129,
+ "changeNum": -1,
+ "unit": "个",
+ "price": 2.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793217944864581,
+ "goodsSecondCategoryId": 2793218343257925
+ },
+ {
+ "siteGoodsStockId": 2957465564696069,
+ "siteGoodsId": 2793026176503877,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "轻上椰子水",
+ "createTime": "2025-11-09 15:49:35",
+ "startNum": 52,
+ "endNum": 51,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 12.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957465565089285,
+ "siteGoodsId": 2793026176995397,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "维他柠檬茶",
+ "createTime": "2025-11-09 15:49:35",
+ "startNum": 37,
+ "endNum": 36,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957419716153157,
+ "siteGoodsId": 2793026180501573,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "东鹏特饮",
+ "createTime": "2025-11-09 15:02:56",
+ "startNum": 101,
+ "endNum": 99,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 7.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957416232717637,
+ "siteGoodsId": 2826003636177861,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 8,
+ "goodsName": "长寿街臭干子",
+ "createTime": "2025-11-09 14:59:24",
+ "startNum": 0,
+ "endNum": 100,
+ "changeNum": 100,
+ "unit": "包",
+ "price": 2.0,
+ "operatorName": "系统",
+ "changeNumA": -100,
+ "startNumA": 100,
+ "endNumA": 0,
+ "remark": "系统自动领用",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2791948300259205
+ },
+ {
+ "siteGoodsStockId": 2957416230948165,
+ "siteGoodsId": 2793025845399621,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 2,
+ "goodsName": "奥利奥饼干",
+ "createTime": "2025-11-09 14:59:24",
+ "startNum": 0,
+ "endNum": 0,
+ "changeNum": 0,
+ "unit": "盒",
+ "price": 12.0,
+ "operatorName": "收银员:郑丽珍",
+ "changeNumA": 10,
+ "startNumA": 0,
+ "endNumA": 10,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2791948300259205
+ },
+ {
+ "siteGoodsStockId": 2957416231013701,
+ "siteGoodsId": 2793025845399621,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 8,
+ "goodsName": "奥利奥饼干",
+ "createTime": "2025-11-09 14:59:24",
+ "startNum": 0,
+ "endNum": 10,
+ "changeNum": 10,
+ "unit": "盒",
+ "price": 12.0,
+ "operatorName": "系统",
+ "changeNumA": -10,
+ "startNumA": 10,
+ "endNumA": 0,
+ "remark": "系统自动领用",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2791948300259205
+ },
+ {
+ "siteGoodsStockId": 2957416231341381,
+ "siteGoodsId": 2793025848610885,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 8,
+ "goodsName": "麻辣王子",
+ "createTime": "2025-11-09 14:59:24",
+ "startNum": 1,
+ "endNum": 11,
+ "changeNum": 10,
+ "unit": "包",
+ "price": 12.0,
+ "operatorName": "系统",
+ "changeNumA": -10,
+ "startNumA": 10,
+ "endNumA": 0,
+ "remark": "系统自动领用",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2791948300259205
+ },
+ {
+ "siteGoodsStockId": 2957416232324421,
+ "siteGoodsId": 2793025847595077,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 2,
+ "goodsName": "鱿鱼丝",
+ "createTime": "2025-11-09 14:59:24",
+ "startNum": 0,
+ "endNum": 0,
+ "changeNum": 0,
+ "unit": "包",
+ "price": 30.0,
+ "operatorName": "收银员:郑丽珍",
+ "changeNumA": 15,
+ "startNumA": 0,
+ "endNumA": 15,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2791948300259205
+ },
+ {
+ "siteGoodsStockId": 2957416232668485,
+ "siteGoodsId": 2826003636177861,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 2,
+ "goodsName": "长寿街臭干子",
+ "createTime": "2025-11-09 14:59:24",
+ "startNum": 0,
+ "endNum": 0,
+ "changeNum": 0,
+ "unit": "包",
+ "price": 2.0,
+ "operatorName": "收银员:郑丽珍",
+ "changeNumA": 100,
+ "startNumA": 0,
+ "endNumA": 100,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2791948300259205
+ },
+ {
+ "siteGoodsStockId": 2957416233061701,
+ "siteGoodsId": 2793026434863237,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 8,
+ "goodsName": "酒鬼花生",
+ "createTime": "2025-11-09 14:59:24",
+ "startNum": 0,
+ "endNum": 15,
+ "changeNum": 15,
+ "unit": "包",
+ "price": 8.0,
+ "operatorName": "系统",
+ "changeNumA": -15,
+ "startNumA": 15,
+ "endNumA": 0,
+ "remark": "系统自动领用",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2791948300259205
+ },
+ {
+ "siteGoodsStockId": 2957416231292229,
+ "siteGoodsId": 2793025848610885,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 2,
+ "goodsName": "麻辣王子",
+ "createTime": "2025-11-09 14:59:24",
+ "startNum": 1,
+ "endNum": 1,
+ "changeNum": 0,
+ "unit": "包",
+ "price": 12.0,
+ "operatorName": "收银员:郑丽珍",
+ "changeNumA": 10,
+ "startNumA": 0,
+ "endNumA": 10,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2791948300259205
+ },
+ {
+ "siteGoodsStockId": 2957416233012549,
+ "siteGoodsId": 2793026434863237,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 2,
+ "goodsName": "酒鬼花生",
+ "createTime": "2025-11-09 14:59:24",
+ "startNum": 0,
+ "endNum": 0,
+ "changeNum": 0,
+ "unit": "包",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珍",
+ "changeNumA": 15,
+ "startNumA": 0,
+ "endNumA": 15,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2791948300259205
+ },
+ {
+ "siteGoodsStockId": 2957416231701829,
+ "siteGoodsId": 2793026187235397,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 8,
+ "goodsName": "奥利奥迷你可可",
+ "createTime": "2025-11-09 14:59:24",
+ "startNum": 0,
+ "endNum": 14,
+ "changeNum": 14,
+ "unit": "份",
+ "price": 8.0,
+ "operatorName": "系统",
+ "changeNumA": -14,
+ "startNumA": 14,
+ "endNumA": 0,
+ "remark": "系统自动领用",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2791948300259205
+ },
+ {
+ "siteGoodsStockId": 2957416232029509,
+ "siteGoodsId": 2793025848102981,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 8,
+ "goodsName": "透明袋无穷鸡翅",
+ "createTime": "2025-11-09 14:59:24",
+ "startNum": 0,
+ "endNum": 10,
+ "changeNum": 10,
+ "unit": "包",
+ "price": 20.0,
+ "operatorName": "系统",
+ "changeNumA": -10,
+ "startNumA": 10,
+ "endNumA": 0,
+ "remark": "系统自动领用",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2791948300259205
+ },
+ {
+ "siteGoodsStockId": 2957416231652677,
+ "siteGoodsId": 2793026187235397,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 2,
+ "goodsName": "奥利奥迷你可可",
+ "createTime": "2025-11-09 14:59:24",
+ "startNum": 0,
+ "endNum": 0,
+ "changeNum": 0,
+ "unit": "份",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珍",
+ "changeNumA": 14,
+ "startNumA": 0,
+ "endNumA": 14,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2791948300259205
+ },
+ {
+ "siteGoodsStockId": 2957416231980357,
+ "siteGoodsId": 2793025848102981,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 2,
+ "goodsName": "透明袋无穷鸡翅",
+ "createTime": "2025-11-09 14:59:24",
+ "startNum": 0,
+ "endNum": 0,
+ "changeNum": 0,
+ "unit": "包",
+ "price": 20.0,
+ "operatorName": "收银员:郑丽珍",
+ "changeNumA": 10,
+ "startNumA": 0,
+ "endNumA": 10,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2791948300259205
+ },
+ {
+ "siteGoodsStockId": 2957416232373573,
+ "siteGoodsId": 2793025847595077,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 8,
+ "goodsName": "鱿鱼丝",
+ "createTime": "2025-11-09 14:59:24",
+ "startNum": 0,
+ "endNum": 15,
+ "changeNum": 15,
+ "unit": "包",
+ "price": 30.0,
+ "operatorName": "系统",
+ "changeNumA": -15,
+ "startNumA": 15,
+ "endNumA": 0,
+ "remark": "系统自动领用",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2791948300259205
+ },
+ {
+ "siteGoodsStockId": 2957399093202437,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 14:41:58",
+ "startNum": 305,
+ "endNum": 304,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957365000277509,
+ "siteGoodsId": 2834064312256837,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "南北特卤豆干80g",
+ "createTime": "2025-11-09 14:07:17",
+ "startNum": 6,
+ "endNum": 5,
+ "changeNum": -1,
+ "unit": "包",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2791948300259205
+ },
+ {
+ "siteGoodsStockId": 2957223509691717,
+ "siteGoodsId": 2793025849593925,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 2,
+ "goodsName": "地道肠",
+ "createTime": "2025-11-09 11:43:21",
+ "startNum": 17,
+ "endNum": 17,
+ "changeNum": 0,
+ "unit": "根",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珍",
+ "changeNumA": 200,
+ "startNumA": 0,
+ "endNumA": 200,
+ "remark": "",
+ "goodsCategoryId": 2793220945250117,
+ "goodsSecondCategoryId": 2793221283104581
+ },
+ {
+ "siteGoodsStockId": 2957223509790021,
+ "siteGoodsId": 2793025849593925,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 8,
+ "goodsName": "地道肠",
+ "createTime": "2025-11-09 11:43:21",
+ "startNum": 17,
+ "endNum": 217,
+ "changeNum": 200,
+ "unit": "根",
+ "price": 5.0,
+ "operatorName": "系统",
+ "changeNumA": -200,
+ "startNumA": 200,
+ "endNumA": 0,
+ "remark": "系统自动领用",
+ "goodsCategoryId": 2793220945250117,
+ "goodsSecondCategoryId": 2793221283104581
+ },
+ {
+ "siteGoodsStockId": 2957223510052165,
+ "siteGoodsId": 2793025845825605,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 2,
+ "goodsName": "鱼蛋",
+ "createTime": "2025-11-09 11:43:21",
+ "startNum": 14,
+ "endNum": 14,
+ "changeNum": 0,
+ "unit": "份",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珍",
+ "changeNumA": 60,
+ "startNumA": 0,
+ "endNumA": 60,
+ "remark": "",
+ "goodsCategoryId": 2793220945250117,
+ "goodsSecondCategoryId": 2793221283104581
+ },
+ {
+ "siteGoodsStockId": 2957223510117701,
+ "siteGoodsId": 2793025845825605,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 8,
+ "goodsName": "鱼蛋",
+ "createTime": "2025-11-09 11:43:21",
+ "startNum": 14,
+ "endNum": 74,
+ "changeNum": 60,
+ "unit": "份",
+ "price": 5.0,
+ "operatorName": "系统",
+ "changeNumA": -60,
+ "startNumA": 60,
+ "endNumA": 0,
+ "remark": "系统自动领用",
+ "goodsCategoryId": 2793220945250117,
+ "goodsSecondCategoryId": 2793221283104581
+ },
+ {
+ "siteGoodsStockId": 2957011016961861,
+ "siteGoodsId": 2791953867886725,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "东方树叶",
+ "createTime": "2025-11-09 08:07:11",
+ "startNum": 133,
+ "endNum": 132,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957011017355077,
+ "siteGoodsId": 2793025861505093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "红利群",
+ "createTime": "2025-11-09 08:07:11",
+ "startNum": 11,
+ "endNum": 10,
+ "changeNum": -1,
+ "unit": "包",
+ "price": 26.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2792062778003333,
+ "goodsSecondCategoryId": 2792063209623429
+ },
+ {
+ "siteGoodsStockId": 2957001761820485,
+ "siteGoodsId": 2791953867886725,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "东方树叶",
+ "createTime": "2025-11-09 07:57:47",
+ "startNum": 132,
+ "endNum": 133,
+ "changeNum": 1,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957001653571397,
+ "siteGoodsId": 2793026184302661,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "红牛",
+ "createTime": "2025-11-09 07:57:40",
+ "startNum": 213,
+ "endNum": 214,
+ "changeNum": 1,
+ "unit": "瓶",
+ "price": 10.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957001570438981,
+ "siteGoodsId": 2793026183041093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "可乐",
+ "createTime": "2025-11-09 07:57:35",
+ "startNum": 100,
+ "endNum": 102,
+ "changeNum": 2,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957001428422469,
+ "siteGoodsId": 2793026184302661,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "红牛",
+ "createTime": "2025-11-09 07:57:26",
+ "startNum": 212,
+ "endNum": 213,
+ "changeNum": 1,
+ "unit": "瓶",
+ "price": 10.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957001365524293,
+ "siteGoodsId": 2793026184302661,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "红牛",
+ "createTime": "2025-11-09 07:57:22",
+ "startNum": 211,
+ "endNum": 212,
+ "changeNum": 1,
+ "unit": "瓶",
+ "price": 10.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957001257897477,
+ "siteGoodsId": 2793026433749125,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "香辣鱼皮",
+ "createTime": "2025-11-09 07:57:16",
+ "startNum": 6,
+ "endNum": 7,
+ "changeNum": 1,
+ "unit": "包",
+ "price": 12.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2791948300259205
+ },
+ {
+ "siteGoodsStockId": 2957001192721925,
+ "siteGoodsId": 2793026432585861,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "脆升升",
+ "createTime": "2025-11-09 07:57:12",
+ "startNum": 1,
+ "endNum": 2,
+ "changeNum": 1,
+ "unit": "包",
+ "price": 6.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2791948300259205
+ },
+ {
+ "siteGoodsStockId": 2957000886095365,
+ "siteGoodsId": 2791953867886725,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "东方树叶",
+ "createTime": "2025-11-09 07:56:53",
+ "startNum": 131,
+ "endNum": 132,
+ "changeNum": 1,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "系统",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2957000210648773,
+ "siteGoodsId": 2791953867886725,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "东方树叶",
+ "createTime": "2025-11-09 07:56:12",
+ "startNum": 132,
+ "endNum": 131,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956996538306245,
+ "siteGoodsId": 2906983124748485,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "1000服务费",
+ "createTime": "2025-11-09 07:52:28",
+ "startNum": 8,
+ "endNum": 10,
+ "changeNum": 2,
+ "unit": "个",
+ "price": 1000.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793217944864581,
+ "goodsSecondCategoryId": 2793218343257925
+ },
+ {
+ "siteGoodsStockId": 2956996336226117,
+ "siteGoodsId": 2906983124748485,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "1000服务费",
+ "createTime": "2025-11-09 07:52:15",
+ "startNum": 5,
+ "endNum": 8,
+ "changeNum": 3,
+ "unit": "个",
+ "price": 1000.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793217944864581,
+ "goodsSecondCategoryId": 2793218343257925
+ },
+ {
+ "siteGoodsStockId": 2956993780731589,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 07:49:39",
+ "startNum": 306,
+ "endNum": 305,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956993780436677,
+ "siteGoodsId": 2868240313094021,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "蜂蜜水",
+ "createTime": "2025-11-09 07:49:39",
+ "startNum": 64,
+ "endNum": 62,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 10.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956993662586757,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 07:49:32",
+ "startNum": 305,
+ "endNum": 306,
+ "changeNum": 1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "系统",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956993662406533,
+ "siteGoodsId": 2868240313094021,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "蜂蜜水",
+ "createTime": "2025-11-09 07:49:32",
+ "startNum": 62,
+ "endNum": 64,
+ "changeNum": 2,
+ "unit": "瓶",
+ "price": 10.0,
+ "operatorName": "系统",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956993627098949,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 07:49:30",
+ "startNum": 306,
+ "endNum": 305,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956993626804037,
+ "siteGoodsId": 2868240313094021,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "蜂蜜水",
+ "createTime": "2025-11-09 07:49:30",
+ "startNum": 64,
+ "endNum": 62,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 10.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956991904566789,
+ "siteGoodsId": 2791953867886725,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "东方树叶",
+ "createTime": "2025-11-09 07:47:45",
+ "startNum": 133,
+ "endNum": 132,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956991000448901,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 07:46:50",
+ "startNum": 307,
+ "endNum": 306,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956990831595333,
+ "siteGoodsId": 2793026178977861,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "白桦树汁",
+ "createTime": "2025-11-09 07:46:39",
+ "startNum": 40,
+ "endNum": 38,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 12.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956990830825285,
+ "siteGoodsId": 2793025855950917,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "明治小杯冰淇淋",
+ "createTime": "2025-11-09 07:46:39",
+ "startNum": 2,
+ "endNum": 1,
+ "changeNum": -1,
+ "unit": "杯",
+ "price": 15.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2791942087561093,
+ "goodsSecondCategoryId": 2792035069284229
+ },
+ {
+ "siteGoodsStockId": 2956990831218501,
+ "siteGoodsId": 2793025863503941,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "粗和天下",
+ "createTime": "2025-11-09 07:46:39",
+ "startNum": 5,
+ "endNum": 3,
+ "changeNum": -2,
+ "unit": "包",
+ "price": 125.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2792062778003333,
+ "goodsSecondCategoryId": 2792063209623429
+ },
+ {
+ "siteGoodsStockId": 2956990832004933,
+ "siteGoodsId": 2793026433077381,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "喜之郎果冻",
+ "createTime": "2025-11-09 07:46:39",
+ "startNum": 17,
+ "endNum": 14,
+ "changeNum": -3,
+ "unit": "包",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2791948300259205
+ },
+ {
+ "siteGoodsStockId": 2956979156586181,
+ "siteGoodsId": 2906983124748485,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "1000服务费",
+ "createTime": "2025-11-09 07:34:47",
+ "startNum": 7,
+ "endNum": 5,
+ "changeNum": -2,
+ "unit": "个",
+ "price": 1000.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793217944864581,
+ "goodsSecondCategoryId": 2793218343257925
+ },
+ {
+ "siteGoodsStockId": 2956968345538245,
+ "siteGoodsId": 2793025851560005,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "合味道泡面",
+ "createTime": "2025-11-09 07:23:47",
+ "startNum": 20,
+ "endNum": 18,
+ "changeNum": -2,
+ "unit": "桶",
+ "price": 12.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2793236829620037
+ },
+ {
+ "siteGoodsStockId": 2956968346291909,
+ "siteGoodsId": 2793026184482885,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "旺仔牛奶",
+ "createTime": "2025-11-09 07:23:47",
+ "startNum": 84,
+ "endNum": 83,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 10.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956968345915077,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 07:23:47",
+ "startNum": 308,
+ "endNum": 307,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956947893604229,
+ "siteGoodsId": 2793025855000645,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "明治炼乳红豆",
+ "createTime": "2025-11-09 07:02:59",
+ "startNum": 12,
+ "endNum": 11,
+ "changeNum": -1,
+ "unit": "个",
+ "price": 12.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2791942087561093,
+ "goodsSecondCategoryId": 2792035069284229
+ },
+ {
+ "siteGoodsStockId": 2956947893227397,
+ "siteGoodsId": 2793025851560005,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "合味道泡面",
+ "createTime": "2025-11-09 07:02:59",
+ "startNum": 21,
+ "endNum": 20,
+ "changeNum": -1,
+ "unit": "桶",
+ "price": 12.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2793236829620037
+ },
+ {
+ "siteGoodsStockId": 2956928116526981,
+ "siteGoodsId": 2793026176503877,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "轻上椰子水",
+ "createTime": "2025-11-09 06:42:52",
+ "startNum": 53,
+ "endNum": 52,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 12.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956928116920197,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 06:42:52",
+ "startNum": 309,
+ "endNum": 308,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956925698150085,
+ "siteGoodsId": 2793025849102405,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "火鸡面",
+ "createTime": "2025-11-09 06:40:24",
+ "startNum": 13,
+ "endNum": 12,
+ "changeNum": -1,
+ "unit": "桶",
+ "price": 10.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2793236829620037
+ },
+ {
+ "siteGoodsStockId": 2956925698543301,
+ "siteGoodsId": 2793025849593925,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "地道肠",
+ "createTime": "2025-11-09 06:40:24",
+ "startNum": 19,
+ "endNum": 17,
+ "changeNum": -2,
+ "unit": "根",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793220945250117,
+ "goodsSecondCategoryId": 2793221283104581
+ },
+ {
+ "siteGoodsStockId": 2956915514822469,
+ "siteGoodsId": 2791953867886725,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "东方树叶",
+ "createTime": "2025-11-09 06:30:02",
+ "startNum": 134,
+ "endNum": 133,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956906569944901,
+ "siteGoodsId": 2793025862438981,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "钻石荷花",
+ "createTime": "2025-11-09 06:20:57",
+ "startNum": 16,
+ "endNum": 15,
+ "changeNum": -1,
+ "unit": "包",
+ "price": 45.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2792062778003333,
+ "goodsSecondCategoryId": 2792063209623429
+ },
+ {
+ "siteGoodsStockId": 2956906015641093,
+ "siteGoodsId": 2793025859375173,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "50 和成天下",
+ "createTime": "2025-11-09 06:20:23",
+ "startNum": 7,
+ "endNum": 6,
+ "changeNum": -1,
+ "unit": "包",
+ "price": 65.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350533,
+ "goodsSecondCategoryId": 2790683528350534
+ },
+ {
+ "siteGoodsStockId": 2956903260835333,
+ "siteGoodsId": 2868240313094021,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "蜂蜜水",
+ "createTime": "2025-11-09 06:17:35",
+ "startNum": 65,
+ "endNum": 64,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 10.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956897887063749,
+ "siteGoodsId": 2793026176503877,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "轻上椰子水",
+ "createTime": "2025-11-09 06:12:07",
+ "startNum": 54,
+ "endNum": 53,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 12.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956897886654149,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 06:12:07",
+ "startNum": 310,
+ "endNum": 309,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956890625167173,
+ "siteGoodsId": 2793025844727877,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "红烧牛肉面",
+ "createTime": "2025-11-09 06:04:43",
+ "startNum": 41,
+ "endNum": 40,
+ "changeNum": -1,
+ "unit": "桶",
+ "price": 12.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2793236829620037
+ },
+ {
+ "siteGoodsStockId": 2956883444469573,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 05:57:25",
+ "startNum": 312,
+ "endNum": 310,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956848034664133,
+ "siteGoodsId": 2793025860145221,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "双中支中华",
+ "createTime": "2025-11-09 05:21:24",
+ "startNum": 6,
+ "endNum": 5,
+ "changeNum": -1,
+ "unit": "包",
+ "price": 72.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2792062778003333,
+ "goodsSecondCategoryId": 2792063209623429
+ },
+ {
+ "siteGoodsStockId": 2956836527771525,
+ "siteGoodsId": 2793025849102405,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "火鸡面",
+ "createTime": "2025-11-09 05:09:41",
+ "startNum": 14,
+ "endNum": 13,
+ "changeNum": -1,
+ "unit": "桶",
+ "price": 10.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2793236829620037
+ },
+ {
+ "siteGoodsStockId": 2956819500355397,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 04:52:22",
+ "startNum": 314,
+ "endNum": 312,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956811144335173,
+ "siteGoodsId": 2793025862438981,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "钻石荷花",
+ "createTime": "2025-11-09 04:43:52",
+ "startNum": 17,
+ "endNum": 16,
+ "changeNum": -1,
+ "unit": "包",
+ "price": 45.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2792062778003333,
+ "goodsSecondCategoryId": 2792063209623429
+ },
+ {
+ "siteGoodsStockId": 2956806838750917,
+ "siteGoodsId": 2793025863290949,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "跨越贵烟",
+ "createTime": "2025-11-09 04:39:29",
+ "startNum": 5,
+ "endNum": 4,
+ "changeNum": -1,
+ "unit": "包",
+ "price": 28.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2792062778003333,
+ "goodsSecondCategoryId": 2792063209623429
+ },
+ {
+ "siteGoodsStockId": 2956806838374085,
+ "siteGoodsId": 2793025860145221,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "双中支中华",
+ "createTime": "2025-11-09 04:39:29",
+ "startNum": 7,
+ "endNum": 6,
+ "changeNum": -1,
+ "unit": "包",
+ "price": 72.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2792062778003333,
+ "goodsSecondCategoryId": 2792063209623429
+ },
+ {
+ "siteGoodsStockId": 2956797945794373,
+ "siteGoodsId": 2802099478416453,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "清洁费150",
+ "createTime": "2025-11-09 04:30:27",
+ "startNum": 4,
+ "endNum": 5,
+ "changeNum": 1,
+ "unit": "份",
+ "price": 150.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793217944864581,
+ "goodsSecondCategoryId": 2793218343257925
+ },
+ {
+ "siteGoodsStockId": 2956795142950405,
+ "siteGoodsId": 2793026180993093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "农夫山泉苏打水",
+ "createTime": "2025-11-09 04:27:36",
+ "startNum": 47,
+ "endNum": 46,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 6.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956794370756485,
+ "siteGoodsId": 2793025845825605,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "鱼蛋",
+ "createTime": "2025-11-09 04:26:48",
+ "startNum": 16,
+ "endNum": 14,
+ "changeNum": -2,
+ "unit": "份",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793220945250117,
+ "goodsSecondCategoryId": 2793221283104581
+ },
+ {
+ "siteGoodsStockId": 2956792338583365,
+ "siteGoodsId": 2793026183041093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "可乐",
+ "createTime": "2025-11-09 04:24:44",
+ "startNum": 102,
+ "endNum": 100,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956792338190149,
+ "siteGoodsId": 2793026176012357,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "哇哈哈矿泉水",
+ "createTime": "2025-11-09 04:24:44",
+ "startNum": 316,
+ "endNum": 314,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956792338960197,
+ "siteGoodsId": 2791953867886725,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "东方树叶",
+ "createTime": "2025-11-09 04:24:44",
+ "startNum": 136,
+ "endNum": 134,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956792339353413,
+ "siteGoodsId": 2793026184302661,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "红牛",
+ "createTime": "2025-11-09 04:24:44",
+ "startNum": 213,
+ "endNum": 211,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 10.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956792337780549,
+ "siteGoodsId": 2793026180993093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "农夫山泉苏打水",
+ "createTime": "2025-11-09 04:24:44",
+ "startNum": 49,
+ "endNum": 47,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 6.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956787829510021,
+ "siteGoodsId": 2791953867886725,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "东方树叶",
+ "createTime": "2025-11-09 04:20:09",
+ "startNum": 138,
+ "endNum": 136,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 8.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956787829903237,
+ "siteGoodsId": 2793026183041093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "可乐",
+ "createTime": "2025-11-09 04:20:09",
+ "startNum": 104,
+ "endNum": 102,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956782769426117,
+ "siteGoodsId": 2793025849102405,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "火鸡面",
+ "createTime": "2025-11-09 04:15:00",
+ "startNum": 15,
+ "endNum": 14,
+ "changeNum": -1,
+ "unit": "桶",
+ "price": 10.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2793236829620037
+ },
+ {
+ "siteGoodsStockId": 2956782769049285,
+ "siteGoodsId": 2793025844727877,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "红烧牛肉面",
+ "createTime": "2025-11-09 04:15:00",
+ "startNum": 43,
+ "endNum": 41,
+ "changeNum": -2,
+ "unit": "桶",
+ "price": 12.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2793236829620037
+ },
+ {
+ "siteGoodsStockId": 2956779655155589,
+ "siteGoodsId": 2793026180993093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "农夫山泉苏打水",
+ "createTime": "2025-11-09 04:11:50",
+ "startNum": 50,
+ "endNum": 49,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 6.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956775329386309,
+ "siteGoodsId": 2793026180993093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "农夫山泉苏打水",
+ "createTime": "2025-11-09 04:07:26",
+ "startNum": 51,
+ "endNum": 50,
+ "changeNum": -1,
+ "unit": "瓶",
+ "price": 6.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956770987544261,
+ "siteGoodsId": 2793025845825605,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "鱼蛋",
+ "createTime": "2025-11-09 04:03:01",
+ "startNum": 18,
+ "endNum": 16,
+ "changeNum": -2,
+ "unit": "份",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793220945250117,
+ "goodsSecondCategoryId": 2793221283104581
+ },
+ {
+ "siteGoodsStockId": 2956769111445381,
+ "siteGoodsId": 2793025849102405,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "火鸡面",
+ "createTime": "2025-11-09 04:01:07",
+ "startNum": 17,
+ "endNum": 15,
+ "changeNum": -2,
+ "unit": "桶",
+ "price": 10.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2793236829620037
+ },
+ {
+ "siteGoodsStockId": 2956769111838597,
+ "siteGoodsId": 2793025844727877,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "红烧牛肉面",
+ "createTime": "2025-11-09 04:01:07",
+ "startNum": 44,
+ "endNum": 43,
+ "changeNum": -1,
+ "unit": "桶",
+ "price": 12.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2791941988405125,
+ "goodsSecondCategoryId": 2793236829620037
+ },
+ {
+ "siteGoodsStockId": 2956762351472325,
+ "siteGoodsId": 2793026183041093,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "可乐",
+ "createTime": "2025-11-09 03:54:14",
+ "startNum": 106,
+ "endNum": 104,
+ "changeNum": -2,
+ "unit": "瓶",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956762351865541,
+ "siteGoodsId": 2793026184302661,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "红牛",
+ "createTime": "2025-11-09 03:54:14",
+ "startNum": 216,
+ "endNum": 213,
+ "changeNum": -3,
+ "unit": "瓶",
+ "price": 10.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2790683528350539,
+ "goodsSecondCategoryId": 2790683528350540
+ },
+ {
+ "siteGoodsStockId": 2956752564407813,
+ "siteGoodsId": 2794695802065029,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "鸡翅三个一份",
+ "createTime": "2025-11-09 03:44:17",
+ "startNum": 10,
+ "endNum": 8,
+ "changeNum": -2,
+ "unit": "份",
+ "price": 18.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793220945250117,
+ "goodsSecondCategoryId": 2793221283104581
+ },
+ {
+ "siteGoodsStockId": 2956745942142789,
+ "siteGoodsId": 2793025849593925,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "地道肠",
+ "createTime": "2025-11-09 03:37:33",
+ "startNum": 22,
+ "endNum": 19,
+ "changeNum": -3,
+ "unit": "根",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793220945250117,
+ "goodsSecondCategoryId": 2793221283104581
+ },
+ {
+ "siteGoodsStockId": 2956741521739589,
+ "siteGoodsId": 2793025845825605,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 1,
+ "goodsName": "鱼蛋",
+ "createTime": "2025-11-09 03:33:03",
+ "startNum": 22,
+ "endNum": 18,
+ "changeNum": -4,
+ "unit": "份",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793220945250117,
+ "goodsSecondCategoryId": 2793221283104581
+ },
+ {
+ "siteGoodsStockId": 2956741348969989,
+ "siteGoodsId": 2793025845825605,
+ "siteId": 2790685415443269,
+ "tenantId": 2790683160709957,
+ "stockType": 4,
+ "goodsName": "鱼蛋",
+ "createTime": "2025-11-09 03:32:52",
+ "startNum": 20,
+ "endNum": 22,
+ "changeNum": 2,
+ "unit": "份",
+ "price": 5.0,
+ "operatorName": "收银员:郑丽珊",
+ "changeNumA": 0,
+ "startNumA": 0,
+ "endNumA": 0,
+ "remark": "",
+ "goodsCategoryId": 2793220945250117,
+ "goodsSecondCategoryId": 2793221283104581
+ }
+ ]
+ },
+ "code": 0
+ }
+]
\ No newline at end of file
diff --git a/tmp_debug_sql.py b/tmp_debug_sql.py
new file mode 100644
index 0000000..12dc104
--- /dev/null
+++ b/tmp_debug_sql.py
@@ -0,0 +1,29 @@
+import os, psycopg2
+from etl_billiards.tasks.dwd_load_task import DwdLoadTask
+
+dwd_table="billiards_dwd.dwd_table_fee_log"
+ods_table="billiards_ods.table_fee_transactions"
+conn=psycopg2.connect(os.environ["PG_DSN"])
+cur=conn.cursor()
+task=DwdLoadTask(config={}, db_connection=None, api_client=None, logger=None)
+cur.execute("SELECT column_name FROM information_schema.columns WHERE table_schema=%s AND table_name=%s", ("billiards_dwd", "dwd_table_fee_log"))
+dwd_cols=[r[0].lower() for r in cur.fetchall()]
+cur.execute("SELECT column_name FROM information_schema.columns WHERE table_schema=%s AND table_name=%s", ("billiards_ods", "table_fee_transactions"))
+ods_cols=[r[0].lower() for r in cur.fetchall()]
+cur.execute("SELECT column_name,data_type FROM information_schema.columns WHERE table_schema=%s AND table_name=%s", ("billiards_dwd", "dwd_table_fee_log"))
+dwd_types={r[0].lower(): r[1].lower() for r in cur.fetchall()}
+cur.execute("SELECT column_name,data_type FROM information_schema.columns WHERE table_schema=%s AND table_name=%s", ("billiards_ods", "table_fee_transactions"))
+ods_types={r[0].lower(): r[1].lower() for r in cur.fetchall()}
+mapping=task.FACT_MAPPINGS.get(dwd_table)
+if mapping:
+ insert_cols=[d for d,o,_ in mapping if o in ods_cols]
+ select_exprs=[task._cast_expr(o,cast_type) for d,o,cast_type in mapping if o in ods_cols]
+else:
+ insert_cols=[c for c in dwd_cols if c in ods_cols and c not in task.SCD_COLS]
+ select_exprs=task._build_fact_select_exprs(insert_cols,dwd_types,ods_types)
+print('insert_cols', insert_cols)
+print('select_exprs', select_exprs)
+sql=f"INSERT INTO {task._format_table(dwd_table,'billiards_dwd')} ({', '.join(f'\"{c}\"' for c in insert_cols)}) SELECT {', '.join(select_exprs)} FROM {task._format_table(ods_table,'billiards_ods')}"
+print(sql)
+cur.close(); conn.close()
+
diff --git a/tmp_drop_dwd.py b/tmp_drop_dwd.py
new file mode 100644
index 0000000..1ea2e57
--- /dev/null
+++ b/tmp_drop_dwd.py
@@ -0,0 +1,7 @@
+import os, psycopg2
+conn=psycopg2.connect(os.environ["PG_DSN"])
+conn.autocommit=True
+cur=conn.cursor()
+cur.execute('DROP SCHEMA IF EXISTS billiards_dwd CASCADE')
+cur.close(); conn.close()
+print('dropped billiards_dwd')
diff --git a/tmp_dwd_tasks.py b/tmp_dwd_tasks.py
new file mode 100644
index 0000000..5c07a51
--- /dev/null
+++ b/tmp_dwd_tasks.py
@@ -0,0 +1,19 @@
+import os
+import psycopg2
+
+DSN = os.environ.get('PG_DSN')
+store_id = int(os.environ.get('STORE_ID','2790685415443269'))
+conn = psycopg2.connect(DSN)
+conn.autocommit = True
+cur = conn.cursor()
+rows = []
+for code in ('INIT_DWD_SCHEMA','DWD_LOAD_FROM_ODS','DWD_QUALITY_CHECK'):
+ cur.execute("SELECT task_id FROM etl_admin.etl_task WHERE task_code=%s AND store_id=%s", (code, store_id))
+ if cur.fetchone():
+ cur.execute("UPDATE etl_admin.etl_task SET enabled=TRUE, updated_at=now() WHERE task_code=%s AND store_id=%s", (code, store_id))
+ rows.append((code, 'updated'))
+ else:
+ cur.execute("INSERT INTO etl_admin.etl_task(task_code,store_id,enabled,cursor_field,window_minutes_default,overlap_seconds,page_size,params) VALUES (%s,%s,TRUE,NULL,60,120,1000,'{}') RETURNING task_id", (code, store_id))
+ rows.append((code, 'inserted', cur.fetchone()[0]))
+print(rows)
+cur.close(); conn.close()
diff --git a/tmp_problems.py b/tmp_problems.py
new file mode 100644
index 0000000..2eb5869
--- /dev/null
+++ b/tmp_problems.py
@@ -0,0 +1,28 @@
+import os, psycopg2
+from etl_billiards.tasks.dwd_load_task import DwdLoadTask
+
+conn=psycopg2.connect(os.environ['PG_DSN'])
+cur=conn.cursor()
+problems=[]
+for dwd_table, ods_table in DwdLoadTask.TABLE_MAP.items():
+ if dwd_table.split('.')[-1].startswith('dwd_'):
+ if '.' in dwd_table:
+ dschema, dtable = dwd_table.split('.')
+ else:
+ dschema, dtable = 'billiards_dwd', dwd_table
+ if '.' in ods_table:
+ oschema, otable = ods_table.split('.')
+ else:
+ oschema, otable = 'billiards_ods', ods_table
+ cur.execute("SELECT column_name,data_type FROM information_schema.columns WHERE table_schema=%s AND table_name=%s", (dschema,dtable))
+ dcols={r[0].lower():r[1].lower() for r in cur.fetchall()}
+ cur.execute("SELECT column_name,data_type FROM information_schema.columns WHERE table_schema=%s AND table_name=%s", (oschema,otable))
+ ocols={r[0].lower():r[1].lower() for r in cur.fetchall()}
+ common=set(dcols)&set(ocols)
+ missing_dwd=list(set(ocols)-set(dcols))
+ missing_ods=list(set(dcols)-set(ocols))
+ mismatches=[(c,dcols[c],ocols[c]) for c in sorted(common) if dcols[c]!=ocols[c]]
+ problems.append((dwd_table,missing_dwd,missing_ods,mismatches))
+cur.close();conn.close()
+for p in problems:
+ print(p)
diff --git a/tmp_run_sql.py b/tmp_run_sql.py
new file mode 100644
index 0000000..8df87d3
--- /dev/null
+++ b/tmp_run_sql.py
@@ -0,0 +1,26 @@
+import os, psycopg2
+from etl_billiards.tasks.dwd_load_task import DwdLoadTask
+
+dwd_table="billiards_dwd.dwd_table_fee_log"
+ods_table="billiards_ods.table_fee_transactions"
+conn=psycopg2.connect(os.environ["PG_DSN"])
+cur=conn.cursor()
+task=DwdLoadTask(config={}, db_connection=None, api_client=None, logger=None)
+cur.execute("SELECT column_name FROM information_schema.columns WHERE table_schema=%s AND table_name=%s", ("billiards_dwd", "dwd_table_fee_log"))
+dwd_cols=[r[0].lower() for r in cur.fetchall()]
+cur.execute("SELECT column_name FROM information_schema.columns WHERE table_schema=%s AND table_name=%s", ("billiards_ods", "table_fee_transactions"))
+ods_cols=[r[0].lower() for r in cur.fetchall()]
+cur.execute("SELECT column_name,data_type FROM information_schema.columns WHERE table_schema=%s AND table_name=%s", ("billiards_dwd", "dwd_table_fee_log"))
+dwd_types={r[0].lower(): r[1].lower() for r in cur.fetchall()}
+cur.execute("SELECT column_name,data_type FROM information_schema.columns WHERE table_schema=%s AND table_name=%s", ("billiards_ods", "table_fee_transactions"))
+ods_types={r[0].lower(): r[1].lower() for r in cur.fetchall()}
+mapping=task.FACT_MAPPINGS.get(dwd_table)
+insert_cols=[d for d,o,_ in mapping if o in ods_cols]
+select_exprs=[task._cast_expr(o,cast_type) for d,o,cast_type in mapping if o in ods_cols]
+sql=f"INSERT INTO {task._format_table(dwd_table,'billiards_dwd')} ({', '.join(f'\"{c}\"' for c in insert_cols)}) SELECT {', '.join(select_exprs)} FROM {task._format_table(ods_table,'billiards_ods')} LIMIT 1"
+print(sql)
+cur.execute(sql)
+conn.commit()
+print('ok')
+cur.close(); conn.close()
+