@dazitech/cli 3.0.8 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +1 -1
  2. package/dist/clis/dazi-app.js +1 -1
  3. package/dist/clis/dazi-flow.js +1 -1
  4. package/dist/clis/dazi-onto.js +7 -2
  5. package/dist/clis/dazi.js +1 -1
  6. package/dist/docs/flow/flow-project-guide.md +1 -1
  7. package/dist/docs/guides/troubleshooting.md +12 -1
  8. package/dist/docs/index.json +21 -2
  9. package/dist/docs/onto/dazi_script_sdk_reference.md +246 -178
  10. package/dist/docs/onto/function-guide.md +123 -95
  11. package/dist/docs/onto//346/234/254/344/275/223/345/210/206/347/261/273/350/247/204/345/210/222/344/270/216SDK/346/211/251/345/261/225/346/226/271/346/241/210.md +169 -0
  12. package/dist/docs/onto//346/234/254/344/275/223/345/221/275/345/220/215/350/247/204/350/214/203_/347/211/251/347/220/206/350/241/250Cube/344/270/216/345/257/271/350/261/241.md +402 -0
  13. package/dist/docs/onto//346/234/254/344/275/223/345/274/200/345/217/221/344/274/230/345/214/226/346/200/273/347/273/223.md +242 -0
  14. package/dist/docs/onto//346/234/254/344/275/223/350/204/232/346/234/254/347/274/226/345/206/231/346/214/207/345/215/227.md +339 -249
  15. package/dist/docs/onto//346/234/254/344/275/223/350/247/204/345/210/222/346/214/207/345/215/227.md +304 -173
  16. package/dist/docs/onto//350/204/232/346/234/254/350/277/220/350/241/214/345/270/270/350/247/201/351/224/231/350/257/257/345/244/204/347/220/206.md +242 -0
  17. package/dist/docs/onto//350/247/204/345/210/222/347/244/272/344/276/213_/344/272/247/345/223/201/351/224/200/345/224/256/346/234/254/344/275/223/350/247/204/345/210/222/346/226/271/346/241/210.md +361 -238
  18. package/dist/docs/onto//350/247/204/345/210/222/347/244/272/344/276/213_/345/210/251/346/266/246/345/210/206/346/236/220/346/234/254/344/275/223/346/226/271/346/241/210.md +385 -300
  19. package/dist/examples/index.json +22 -16
  20. package/dist/examples/onto/README.md +13 -5
  21. package/dist/examples/onto/_templates/ontology_function_template.py +50 -0
  22. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_account_breakdown.py +62 -0
  23. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_budget_vs_actual.py +69 -0
  24. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_cost_center_profit.py +64 -0
  25. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_get_summary.py +61 -0
  26. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_mom_analysis.py +82 -0
  27. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_top_accounts.py +61 -0
  28. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_yoy_analysis.py +79 -0
  29. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/save_test_arguments.ps1 +38 -0
  30. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/test_arguments/profit.fn.account_breakdown.json +1 -0
  31. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/test_arguments/profit.fn.budget_vs_actual.json +1 -0
  32. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/test_arguments/profit.fn.cost_center_profit.json +1 -0
  33. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/test_arguments/profit.fn.get_summary.json +1 -0
  34. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/test_arguments/profit.fn.mom_analysis.json +1 -0
  35. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/test_arguments/profit.fn.top_accounts.json +1 -0
  36. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/test_arguments/profit.fn.yoy_analysis.json +1 -0
  37. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/setup/profit_category_mount.py +85 -0
  38. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/setup/profit_ontology_init.py +169 -74
  39. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/setup/profit_seed_data.py +16 -13
  40. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_channel_mix.py +19 -16
  41. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_customer_segmentation.py +48 -50
  42. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_get_summary.py +3 -6
  43. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_mom_analysis.py +11 -12
  44. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_region_breakdown.py +6 -7
  45. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_top_products.py +5 -8
  46. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_yoy_analysis.py +3 -6
  47. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/save_test_arguments.ps1 +32 -19
  48. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.channel_mix.json +3 -6
  49. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.customer_segmentation.json +2 -7
  50. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.get_summary.json +2 -5
  51. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.mom_analysis.json +2 -5
  52. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.region_breakdown.json +2 -5
  53. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.top_products.json +2 -7
  54. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.yoy_analysis.json +2 -5
  55. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/sales_category_mount.py +82 -0
  56. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/sales_ontology_init.py +240 -155
  57. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/sales_seed_data.py +59 -20
  58. package/dist/prompts/index.json +8 -1
  59. package/dist/prompts/onto/function-design.md +73 -53
  60. package/dist/prompts/onto/planning-design.md +104 -0
  61. package/dist/prompts/onto/script-publish-run.md +229 -194
  62. package/package.json +1 -1
  63. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_account_breakdown.py +0 -99
  64. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_budget_vs_actual.py +0 -116
  65. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_cost_center_profit.py +0 -85
  66. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_get_summary.py +0 -76
  67. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_mom_analysis.py +0 -86
  68. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_top_accounts.py +0 -103
  69. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_yoy_analysis.py +0 -86
  70. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/save_test_arguments.ps1 +0 -27
  71. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.account_breakdown.json +0 -10
  72. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.budget_vs_actual.json +0 -10
  73. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.cost_center_profit.json +0 -9
  74. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.get_summary.json +0 -9
  75. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.mom_analysis.json +0 -9
  76. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.top_accounts.json +0 -11
  77. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.yoy_analysis.json +0 -9
  78. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/README.md +0 -25
  79. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/README.md +0 -5
@@ -1,32 +1,133 @@
1
- """产品销售本体初始化脚本 — space__zlj
1
+ """产品销售本体初始化脚本 — space__misc_01
2
2
 
3
3
  初始化内容:
4
- 1. 创建物理表(4 张:产品表、销售表、客户维表、渠道维表)
4
+ 1. 创建物理表(dim_date + 3 维表 + 1 事实表)
5
5
  2. 注册表到空间
6
- 3. 注册表间关系(3 条:事实表维表)
7
- 4. 注册 Cube(5 个)及派生度量
6
+ 3. 注册表间关系(4 条,含 fact dim_date)
7
+ 4. 注册 Cube(4 个)及派生度量
8
8
  5. 定义对象类型(5 种)、绑定数据源、属性、链接
9
9
  6. 同步指标引用
10
+ 7. 配置 平台分类对齐分类(ads_categories + 桥表)
10
11
 
11
- 放置:项目/潘达石化/本体/ontos/产品销售本体方案/setup/sales_ontology_init.py
12
- 发布:dazi onto script publish 项目/潘达石化/本体/ontos/产品销售本体方案/setup/sales_ontology_init.py --space space__zlj --type setup
12
+ 放置:资源/examples/onto/销售示例/setup/sales_ontology_init.py(复制到项目 ontos/<实现名>/setup/)
13
+ 发布:dazi onto script publish <item-path>/setup/sales_ontology_init.py --space <space-id> --type setup
14
+ 规划对照:资源/docs/onto/规划示例_产品销售本体规划方案.md
13
15
  """
14
16
 
15
17
  import json
16
18
 
19
+ # 与 规划示例_产品销售本体规划方案.md §2.3、§3.x 对齐:display_name=侧栏显示名,description=业务说明
20
+ TABLE_REGISTRY = {
21
+ "dim_date": {
22
+ "display_name": "日期维表",
23
+ "description": "全空间共享日历,事实表通过 date_key 关联",
24
+ "columns": [
25
+ {"name": "date_key", "display_name": "日期键", "description": "YYYYMMDD,主键"},
26
+ {"name": "calendar_date", "display_name": "自然日"},
27
+ {"name": "year", "display_name": "公历年"},
28
+ {"name": "quarter", "display_name": "季度", "description": "1-4"},
29
+ {"name": "month", "display_name": "月", "description": "1-12"},
30
+ {"name": "week_of_year", "display_name": "周"},
31
+ {"name": "day_of_week", "display_name": "星期"},
32
+ {"name": "is_weekend", "display_name": "是否周末", "description": "0/1"},
33
+ {"name": "year_month", "display_name": "年月", "description": "如 2025-06"},
34
+ ],
35
+ },
36
+ "dim_product": {
37
+ "display_name": "产品维表",
38
+ "description": "可售产品主数据",
39
+ "columns": [
40
+ {"name": "product_id", "display_name": "产品 ID", "description": "主键"},
41
+ {"name": "product_code", "display_name": "产品编码"},
42
+ {"name": "product_name", "display_name": "产品名称"},
43
+ {"name": "product_category", "display_name": "产品大类"},
44
+ {"name": "product_subcategory", "display_name": "产品小类"},
45
+ {"name": "brand", "display_name": "品牌"},
46
+ {"name": "unit", "display_name": "计量单位"},
47
+ {"name": "list_price", "display_name": "挂牌价"},
48
+ {"name": "cost_price", "display_name": "成本单价"},
49
+ {"name": "status", "display_name": "状态", "description": "在售/停售"},
50
+ {"name": "created_at", "display_name": "创建时间"},
51
+ {"name": "updated_at", "display_name": "更新时间"},
52
+ ],
53
+ },
54
+ "dim_customer": {
55
+ "display_name": "客户维表",
56
+ "description": "购买方主数据",
57
+ "columns": [
58
+ {"name": "customer_id", "display_name": "客户 ID", "description": "主键"},
59
+ {"name": "customer_code", "display_name": "客户编码"},
60
+ {"name": "customer_name", "display_name": "客户名称"},
61
+ {"name": "customer_region", "display_name": "销售区域"},
62
+ {"name": "customer_type", "display_name": "客户类型"},
63
+ {"name": "industry", "display_name": "所属行业"},
64
+ {"name": "created_at", "display_name": "创建时间"},
65
+ ],
66
+ },
67
+ "dim_channel": {
68
+ "display_name": "渠道维表",
69
+ "description": "销售渠道主数据",
70
+ "columns": [
71
+ {"name": "channel_id", "display_name": "渠道 ID", "description": "主键"},
72
+ {"name": "channel_code", "display_name": "渠道编码"},
73
+ {"name": "channel_name", "display_name": "渠道名称"},
74
+ {"name": "channel_type", "display_name": "渠道类型"},
75
+ ],
76
+ },
77
+ "fact_sales_order_line": {
78
+ "display_name": "销售订单行事实表",
79
+ "description": "订单行粒度销售流水",
80
+ "columns": [
81
+ {"name": "order_id", "display_name": "订单 ID"},
82
+ {"name": "order_line_id", "display_name": "订单行 ID", "description": "主键组合"},
83
+ {"name": "date_key", "display_name": "日期键", "description": "关联 dim_date"},
84
+ {"name": "order_date", "display_name": "订单日期"},
85
+ {"name": "product_id", "display_name": "产品 ID", "description": "关联 dim_product"},
86
+ {"name": "product_category", "display_name": "产品大类", "description": "冗余"},
87
+ {"name": "customer_id", "display_name": "客户 ID", "description": "关联 dim_customer"},
88
+ {"name": "customer_region", "display_name": "销售区域", "description": "冗余"},
89
+ {"name": "customer_type", "display_name": "客户类型", "description": "冗余"},
90
+ {"name": "channel_id", "display_name": "渠道 ID", "description": "关联 dim_channel"},
91
+ {"name": "quantity", "display_name": "销售数量"},
92
+ {"name": "unit_price", "display_name": "成交单价"},
93
+ {"name": "discount_amount", "display_name": "折扣金额"},
94
+ {"name": "sales_amount", "display_name": "销售金额"},
95
+ {"name": "currency", "display_name": "币种"},
96
+ {"name": "order_status", "display_name": "订单状态"},
97
+ ],
98
+ },
99
+ }
17
100
 
18
101
  def main():
19
- space_id = "space__zlj"
102
+ space_id = "space__misc_01"
20
103
  s = space.get(space_id)
21
104
 
22
105
  output.print("=== 产品销售本体初始化 ===")
23
106
  output.print(f"空间: {space_id}")
24
107
 
25
108
  # 1. 创建物理表
26
- output.print("\n[1/9] 创建物理表...")
109
+ output.print("\n[1/10] 创建物理表...")
110
+
111
+ # dim_date(强制时间维)
112
+ s.sql.execute("""
113
+ CREATE TABLE IF NOT EXISTS dim_date (
114
+ date_key Int32,
115
+ calendar_date Date,
116
+ year Int16,
117
+ quarter Int8,
118
+ month Int8,
119
+ week_of_year Int8,
120
+ day_of_week Int8,
121
+ is_weekend UInt8,
122
+ year_month String
123
+ ) ENGINE = MergeTree()
124
+ ORDER BY (date_key)
125
+ """)
126
+ output.print("OK dim_date")
27
127
 
128
+ # dim_product
28
129
  s.sql.execute("""
29
- CREATE TABLE IF NOT EXISTS product_master (
130
+ CREATE TABLE IF NOT EXISTS dim_product (
30
131
  product_id String,
31
132
  product_code String,
32
133
  product_name String,
@@ -42,10 +143,11 @@ def main():
42
143
  ) ENGINE = MergeTree()
43
144
  ORDER BY (product_id)
44
145
  """)
45
- output.print("OK product_master")
146
+ output.print("OK dim_product")
46
147
 
148
+ # dim_customer
47
149
  s.sql.execute("""
48
- CREATE TABLE IF NOT EXISTS customer_dimension (
150
+ CREATE TABLE IF NOT EXISTS dim_customer (
49
151
  customer_id String,
50
152
  customer_code String,
51
153
  customer_name String,
@@ -56,10 +158,11 @@ def main():
56
158
  ) ENGINE = MergeTree()
57
159
  ORDER BY (customer_id)
58
160
  """)
59
- output.print("OK customer_dimension")
161
+ output.print("OK dim_customer")
60
162
 
163
+ # dim_channel
61
164
  s.sql.execute("""
62
- CREATE TABLE IF NOT EXISTS channel_dimension (
165
+ CREATE TABLE IF NOT EXISTS dim_channel (
63
166
  channel_id String,
64
167
  channel_code String,
65
168
  channel_name String,
@@ -67,12 +170,14 @@ def main():
67
170
  ) ENGINE = MergeTree()
68
171
  ORDER BY (channel_id)
69
172
  """)
70
- output.print("OK channel_dimension")
173
+ output.print("OK dim_channel")
71
174
 
175
+ # fact_sales_order_line(含 date_key)
72
176
  s.sql.execute("""
73
- CREATE TABLE IF NOT EXISTS sales_order_fact (
177
+ CREATE TABLE IF NOT EXISTS fact_sales_order_line (
74
178
  order_id String,
75
179
  order_line_id String,
180
+ date_key Int32,
76
181
  order_date Date,
77
182
  product_id String,
78
183
  product_category String,
@@ -87,60 +192,68 @@ def main():
87
192
  currency String,
88
193
  order_status String
89
194
  ) ENGINE = MergeTree()
90
- ORDER BY (order_date, order_id, order_line_id)
195
+ ORDER BY (date_key, order_id, order_line_id)
91
196
  """)
92
- output.print("OK sales_order_fact")
93
-
94
- # 2. 注册表
95
- output.print("\n[2/9] 注册表到空间...")
96
-
97
- for tbl, label in [
98
- ("product_master", "产品主数据表"),
99
- ("customer_dimension", "客户维度表"),
100
- ("channel_dimension", "销售渠道表"),
101
- ("sales_order_fact", "销售订单事实表"),
102
- ]:
103
- s.tables.register(tbl, label=label)
104
- s.tables.sync_columns(tbl)
105
- output.print(f"OK {tbl}")
197
+ output.print("OK fact_sales_order_line")
198
+
199
+ # 2. 注册表(含 display_name / description)
200
+ output.print("\n[2/10] 注册表到空间...")
201
+
202
+ for tbl_name, meta in TABLE_REGISTRY.items():
203
+ s.tables.register_with_meta(
204
+ table_name=tbl_name,
205
+ display_name=meta["display_name"],
206
+ description=meta.get("description"),
207
+ columns=meta["columns"],
208
+ force_column_meta=True,
209
+ )
210
+ output.print(f"OK {tbl_name} ({meta['display_name']})")
106
211
 
107
- # 3. 注册表间关系(数据空间「表间关系」,供 JOIN / 侧栏展示)
108
- output.print("\n[3/9] 注册表间关系...")
212
+ # 3. 注册表间关系(4 条,含 fact → dim_date)
213
+ output.print("\n[3/10] 注册表间关系...")
109
214
 
110
215
  table_relationships = [
111
216
  {
112
- "from_table": "sales_order_fact",
113
- "to_table": "product_master",
114
- "join_sql": "sales_order_fact.product_id = product_master.product_id",
217
+ "from_table": "fact_sales_order_line",
218
+ "to_table": "dim_date",
219
+ "join_sql": "fact_sales_order_line.date_key = dim_date.date_key",
220
+ "join_keys": [{"from": "date_key", "to": "date_key"}],
221
+ "relationship_type": "many_to_one",
222
+ "description": "销售订单行关联日期",
223
+ },
224
+ {
225
+ "from_table": "fact_sales_order_line",
226
+ "to_table": "dim_product",
227
+ "join_sql": "fact_sales_order_line.product_id = dim_product.product_id",
115
228
  "join_keys": [{"from": "product_id", "to": "product_id"}],
116
229
  "relationship_type": "many_to_one",
117
- "description": "销售订单行关联产品主数据",
230
+ "description": "销售订单行关联产品",
118
231
  },
119
232
  {
120
- "from_table": "sales_order_fact",
121
- "to_table": "customer_dimension",
122
- "join_sql": "sales_order_fact.customer_id = customer_dimension.customer_id",
233
+ "from_table": "fact_sales_order_line",
234
+ "to_table": "dim_customer",
235
+ "join_sql": "fact_sales_order_line.customer_id = dim_customer.customer_id",
123
236
  "join_keys": [{"from": "customer_id", "to": "customer_id"}],
124
237
  "relationship_type": "many_to_one",
125
238
  "description": "销售订单行关联客户",
126
239
  },
127
240
  {
128
- "from_table": "sales_order_fact",
129
- "to_table": "channel_dimension",
130
- "join_sql": "sales_order_fact.channel_id = channel_dimension.channel_id",
241
+ "from_table": "fact_sales_order_line",
242
+ "to_table": "dim_channel",
243
+ "join_sql": "fact_sales_order_line.channel_id = dim_channel.channel_id",
131
244
  "join_keys": [{"from": "channel_id", "to": "channel_id"}],
132
245
  "relationship_type": "many_to_one",
133
- "description": "销售订单行关联销售渠道",
246
+ "description": "销售订单行关联渠道",
134
247
  },
135
248
  ]
136
249
  for rel in table_relationships:
137
250
  rid = s.tables.add_relationship(**rel)
138
251
  output.print(f"OK {rel['from_table']} -> {rel['to_table']} ({rid})")
139
252
 
140
- # 4. 注册 Cube
141
- output.print("\n[4/9] 注册 Cube...")
253
+ # 4. 注册 Cube(4 个)
254
+ output.print("\n[4/10] 注册 Cube...")
142
255
 
143
- fact = "sales_order_fact"
256
+ fact = "fact_sales_order_line"
144
257
  common_measures = [
145
258
  {"name": "quantity", "col": "quantity", "agg": "sum", "title": "销售数量"},
146
259
  {"name": "sales_amount", "col": "sales_amount", "agg": "sum", "title": "销售金额"},
@@ -149,6 +262,7 @@ def main():
149
262
  {"name": "line_count", "col": "order_line_id", "agg": "uniq", "title": "订单行数"},
150
263
  ]
151
264
 
265
+ # SalesCube(Process · 销售分析主 Cube)
152
266
  s.register_cube(
153
267
  name="SalesCube",
154
268
  table=fact,
@@ -157,16 +271,19 @@ def main():
157
271
  dimensions=[
158
272
  {"name": "order_id", "col": "order_id", "type": "string", "title": "订单ID"},
159
273
  {"name": "order_line_id", "col": "order_line_id", "type": "string", "title": "订单行ID"},
274
+ {"name": "date_key", "col": "date_key", "type": "int32", "title": "日期键"},
160
275
  {"name": "order_date", "col": "order_date", "type": "date", "title": "订单日期"},
161
276
  {"name": "product_id", "col": "product_id", "type": "string", "title": "产品ID"},
162
277
  {"name": "product_category", "col": "product_category", "type": "string", "title": "产品大类"},
163
278
  {"name": "customer_id", "col": "customer_id", "type": "string", "title": "客户ID"},
164
279
  {"name": "customer_region", "col": "customer_region", "type": "string", "title": "销售区域"},
280
+ {"name": "customer_type", "col": "customer_type", "type": "string", "title": "客户类型"},
165
281
  {"name": "channel_id", "col": "channel_id", "type": "string", "title": "渠道ID"},
166
282
  ],
167
283
  )
168
284
  output.print("OK SalesCube")
169
285
 
286
+ # ProductSalesCube(Subject · 产品销售)
170
287
  s.register_cube(
171
288
  name="ProductSalesCube",
172
289
  table=fact,
@@ -183,6 +300,7 @@ def main():
183
300
  )
184
301
  output.print("OK ProductSalesCube")
185
302
 
303
+ # CustomerSalesCube(Subject · 客户销售)
186
304
  s.register_cube(
187
305
  name="CustomerSalesCube",
188
306
  table=fact,
@@ -200,6 +318,7 @@ def main():
200
318
  )
201
319
  output.print("OK CustomerSalesCube")
202
320
 
321
+ # ChannelSalesCube(Subject · 渠道销售)
203
322
  s.register_cube(
204
323
  name="ChannelSalesCube",
205
324
  table=fact,
@@ -215,26 +334,8 @@ def main():
215
334
  )
216
335
  output.print("OK ChannelSalesCube")
217
336
 
218
- s.register_cube(
219
- name="TimeSalesCube",
220
- table=fact,
221
- title="时间维度销售Cube",
222
- measures=[
223
- {"name": "sales_amount", "col": "sales_amount", "agg": "sum", "title": "销售金额"},
224
- {"name": "quantity", "col": "quantity", "agg": "sum", "title": "销售数量"},
225
- {"name": "order_count", "col": "order_id", "agg": "uniq", "title": "订单数"},
226
- ],
227
- dimensions=[
228
- {"name": "order_date", "col": "order_date", "type": "date", "title": "订单日期"},
229
- {"name": "year_month", "col": "order_date", "type": "string", "title": "年月"},
230
- {"name": "quarter", "col": "order_date", "type": "string", "title": "季度"},
231
- {"name": "year", "col": "order_date", "type": "date", "title": "年份"},
232
- ],
233
- )
234
- output.print("OK TimeSalesCube")
235
-
236
337
  # 5. 派生度量
237
- output.print("\n[5/9] 配置派生度量...")
338
+ output.print("\n[5/10] 配置派生度量...")
238
339
 
239
340
  s.upsert_derived_measures(
240
341
  "SalesCube",
@@ -253,6 +354,8 @@ def main():
253
354
  },
254
355
  ],
255
356
  )
357
+ output.print("OK SalesCube 派生度量")
358
+
256
359
  s.upsert_derived_measures(
257
360
  "ProductSalesCube",
258
361
  [
@@ -264,6 +367,8 @@ def main():
264
367
  },
265
368
  ],
266
369
  )
370
+ output.print("OK ProductSalesCube 派生度量")
371
+
267
372
  s.upsert_derived_measures(
268
373
  "CustomerSalesCube",
269
374
  [
@@ -275,10 +380,10 @@ def main():
275
380
  },
276
381
  ],
277
382
  )
278
- output.print("OK 派生度量")
383
+ output.print("OK CustomerSalesCube 派生度量")
279
384
 
280
385
  # 6. 对象类型
281
- output.print("\n[6/9] 定义对象类型...")
386
+ output.print("\n[6/10] 定义对象类型...")
282
387
 
283
388
  object_types = [
284
389
  ("Product", "产品", "可售产品业务对象"),
@@ -292,7 +397,7 @@ def main():
292
397
  output.print(f"OK {code}")
293
398
 
294
399
  # 7. 绑定数据源
295
- output.print("\n[7/9] 绑定数据源...")
400
+ output.print("\n[7/10] 绑定数据源...")
296
401
 
297
402
  bindings = [
298
403
  ("Product", "ProductSalesCube"),
@@ -301,103 +406,83 @@ def main():
301
406
  ("SalesOrder", "SalesCube"),
302
407
  ("SalesAnalysis", "SalesCube"),
303
408
  ]
304
- for obj, cube in bindings:
305
- s.onto.bind_source(obj, "dazi_cube", config={"cube": cube})
306
- output.print(f"OK {obj} -> {cube}")
307
-
308
- # 8. 属性
309
- output.print("\n[8/9] 定义属性...")
310
-
311
- def define_props(obj_code, props):
312
- for code, name, role, qn in props:
313
- s.onto.define_property(obj_code, code, name, semantic_role=role, qualified_name=qn)
314
-
315
- define_props("Product", [
316
- ("id", "产品ID", "dimension", "ProductSalesCube.product_id"),
317
- ("category", "产品大类", "dimension", "ProductSalesCube.product_category"),
318
- ("quantity", "累计销量", "measure", "ProductSalesCube.quantity"),
319
- ("sales_amount", "累计销售额", "measure", "ProductSalesCube.sales_amount"),
320
- ("order_count", "订单数", "measure", "ProductSalesCube.order_count"),
321
- ("avg_unit_price", "平均单价", "measure", "ProductSalesCube.avg_unit_price"),
322
- ])
323
- output.print("OK Product 属性 (6)")
324
-
325
- define_props("Customer", [
326
- ("id", "客户ID", "dimension", "CustomerSalesCube.customer_id"),
327
- ("region", "销售区域", "dimension", "CustomerSalesCube.customer_region"),
328
- ("type", "客户类型", "dimension", "CustomerSalesCube.customer_type"),
329
- ("sales_amount", "累计销售额", "measure", "CustomerSalesCube.sales_amount"),
330
- ("order_count", "订单数", "measure", "CustomerSalesCube.order_count"),
331
- ("avg_order_value", "客单价", "measure", "CustomerSalesCube.avg_order_value"),
332
- ])
333
- output.print("OK Customer 属性 (6)")
334
-
335
- define_props("SalesChannel", [
336
- ("id", "渠道ID", "dimension", "ChannelSalesCube.channel_id"),
337
- ("sales_amount", "销售额", "measure", "ChannelSalesCube.sales_amount"),
338
- ("order_count", "订单数", "measure", "ChannelSalesCube.order_count"),
339
- ])
340
- output.print("OK SalesChannel 属性 (3)")
341
-
342
- define_props("SalesOrder", [
343
- ("id", "订单ID", "dimension", "SalesCube.order_id"),
344
- ("line_id", "订单行", "dimension", "SalesCube.order_line_id"),
345
- ("date", "订单日期", "dimension", "SalesCube.order_date"),
346
- ("quantity", "数量", "measure", "SalesCube.quantity"),
347
- ("sales_amount", "销售金额", "measure", "SalesCube.sales_amount"),
348
- ("unit_price", "成交单价", "measure", "SalesCube.avg_unit_price"),
349
- ])
350
- output.print("OK SalesOrder 属性 (6)")
351
-
352
- define_props("SalesAnalysis", [
353
- ("date", "日期", "dimension", "SalesCube.order_date"),
354
- ("product_category", "产品大类", "dimension", "SalesCube.product_category"),
355
- ("customer_region", "销售区域", "dimension", "SalesCube.customer_region"),
356
- ("channel_id", "渠道", "dimension", "SalesCube.channel_id"),
357
- ("quantity", "销量", "measure", "SalesCube.quantity"),
358
- ("sales_amount", "销售额", "measure", "SalesCube.sales_amount"),
359
- ("order_count", "订单数", "measure", "SalesCube.order_count"),
360
- ("avg_order_value", "客单价", "measure", "SalesCube.avg_order_value"),
361
- ])
362
- output.print("OK SalesAnalysis 属性 (8)")
363
-
364
- # 9. 链接类型
365
- output.print("\n[9/9] 定义链接与同步指标...")
409
+ for code, cube in bindings:
410
+ s.onto.bind_source(code, "dazi_cube", config={"cube": cube})
411
+ output.print(f"OK {code} -> {cube}")
412
+
413
+ # 8. 定义属性
414
+ output.print("\n[8/10] 定义属性...")
415
+
416
+ properties = [
417
+ # Product 属性
418
+ ("Product", "id", "产品ID", "dimension", "ProductSalesCube.product_id"),
419
+ ("Product", "category", "产品大类", "dimension", "ProductSalesCube.product_category"),
420
+ ("Product", "quantity", "累计销量", "measure", "ProductSalesCube.quantity"),
421
+ ("Product", "sales_amount", "累计销售额", "measure", "ProductSalesCube.sales_amount"),
422
+ ("Product", "order_count", "订单数", "measure", "ProductSalesCube.order_count"),
423
+ ("Product", "avg_unit_price", "平均单价", "measure", "ProductSalesCube.avg_unit_price"),
424
+ # Customer 属性
425
+ ("Customer", "id", "客户ID", "dimension", "CustomerSalesCube.customer_id"),
426
+ ("Customer", "region", "销售区域", "dimension", "CustomerSalesCube.customer_region"),
427
+ ("Customer", "type", "客户类型", "dimension", "CustomerSalesCube.customer_type"),
428
+ ("Customer", "quantity", "累计销量", "measure", "CustomerSalesCube.quantity"),
429
+ ("Customer", "sales_amount", "累计销售额", "measure", "CustomerSalesCube.sales_amount"),
430
+ ("Customer", "order_count", "订单数", "measure", "CustomerSalesCube.order_count"),
431
+ ("Customer", "avg_order_value", "客单价", "measure", "CustomerSalesCube.avg_order_value"),
432
+ # SalesChannel 属性
433
+ ("SalesChannel", "id", "渠道ID", "dimension", "ChannelSalesCube.channel_id"),
434
+ ("SalesChannel", "quantity", "累计销量", "measure", "ChannelSalesCube.quantity"),
435
+ ("SalesChannel", "sales_amount", "累计销售额", "measure", "ChannelSalesCube.sales_amount"),
436
+ ("SalesChannel", "order_count", "订单数", "measure", "ChannelSalesCube.order_count"),
437
+ # SalesOrder 属性
438
+ ("SalesOrder", "id", "订单ID", "dimension", "SalesCube.order_id"),
439
+ ("SalesOrder", "line_id", "订单行", "dimension", "SalesCube.order_line_id"),
440
+ ("SalesOrder", "date", "订单日期", "dimension", "SalesCube.order_date"),
441
+ ("SalesOrder", "quantity", "数量", "measure", "SalesCube.quantity"),
442
+ ("SalesOrder", "sales_amount", "销售金额", "measure", "SalesCube.sales_amount"),
443
+ ("SalesOrder", "unit_price", "成交单价", "measure", "SalesCube.avg_unit_price"),
444
+ # SalesAnalysis 属性
445
+ ("SalesAnalysis", "total_sales", "总销售额", "measure", "SalesCube.sales_amount"),
446
+ ("SalesAnalysis", "total_quantity", "总销量", "measure", "SalesCube.quantity"),
447
+ ("SalesAnalysis", "order_count", "订单数", "measure", "SalesCube.order_count"),
448
+ ("SalesAnalysis", "avg_order_value", "客单价", "measure", "SalesCube.avg_order_value"),
449
+ ("SalesAnalysis", "avg_unit_price", "平均单价", "measure", "SalesCube.avg_unit_price"),
450
+ ]
451
+ for obj_code, prop_code, title, role, qualified_name in properties:
452
+ s.onto.define_property(obj_code, prop_code, title, semantic_role=role, qualified_name=qualified_name)
453
+ output.print(f"OK {len(properties)} 个属性")
454
+
455
+ # 9. 定义链接类型
456
+ output.print("\n[9/10] 定义链接类型...")
366
457
 
367
458
  link_types = [
368
- ("order_contains_product", "订单包含产品", "SalesOrder", "Product", "订单行对应产品"),
369
- ("order_belongs_customer", "订单归属客户", "SalesOrder", "Customer", "订单归属客户"),
370
- ("order_via_channel", "订单经渠道成交", "SalesOrder", "SalesChannel", "订单销售渠道"),
371
- ("product_has_orders", "产品有订单", "Product", "SalesOrder", "产品被哪些订单购买"),
372
- ("customer_places_orders", "客户下单", "Customer", "SalesOrder", "客户历史订单"),
373
- ("analysis_by_product", "分析归因产品", "SalesAnalysis", "Product", "指标按产品切片"),
374
- ("analysis_by_customer", "分析归因客户", "SalesAnalysis", "Customer", "指标按客户切片"),
375
- ("analysis_by_channel", "分析归因渠道", "SalesAnalysis", "SalesChannel", "指标按渠道切片"),
459
+ ("order_contains_product", "订单包含产品", "SalesOrder", "Product"),
460
+ ("order_belongs_customer", "订单归属客户", "SalesOrder", "Customer"),
461
+ ("order_via_channel", "订单经渠道成交", "SalesOrder", "SalesChannel"),
462
+ ("product_has_orders", "产品有订单", "Product", "SalesOrder"),
463
+ ("customer_places_orders", "客户下单", "Customer", "SalesOrder"),
464
+ ("analysis_by_product", "分析归因产品", "SalesAnalysis", "Product"),
465
+ ("analysis_by_customer", "分析归因客户", "SalesAnalysis", "Customer"),
466
+ ("analysis_by_channel", "分析归因渠道", "SalesAnalysis", "SalesChannel"),
376
467
  ]
377
- for code, name, from_obj, to_obj, desc in link_types:
378
- s.onto.define_link_type(
379
- code=code,
380
- name=name,
381
- from_object_type_code=from_obj,
382
- to_object_type_code=to_obj,
383
- description=desc,
384
- )
468
+ for code, name, from_obj, to_obj in link_types:
469
+ s.onto.define_link_type(code, name, from_object_type_code=from_obj, to_object_type_code=to_obj)
385
470
  output.print(f"OK {code}")
386
471
 
472
+ # 同步指标引用
387
473
  s.sync_metric_refs()
388
474
  output.print("OK sync_metric_refs")
389
475
 
390
476
  summary = {
391
477
  "ok": True,
392
478
  "space_id": space_id,
393
- "tables": 4,
394
- "table_relationships": 3,
395
- "cubes": 5,
479
+ "tables": 5,
480
+ "table_relationships": 4,
481
+ "cubes": 4,
396
482
  "object_types": 5,
397
- "properties": 29,
398
- "link_types": 8,
483
+ "properties": len(properties),
484
+ "link_types": len(link_types),
399
485
  }
400
-
401
- output.print("\n=== 产品销售本体初始化完成 ===")
402
- output.success("初始化成功")
403
- output.print("__JSON_SUMMARY__" + json.dumps(summary, ensure_ascii=True, default=str))
486
+ output.success("本体初始化完成")
487
+ output.print(f"space_id: {space_id}")
488
+ output.print("__JSON_SUMMARY__" + json.dumps(summary, ensure_ascii=False))