@dazitech/cli 3.0.7 → 3.0.9

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 (70) 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 +73 -22
  5. package/dist/clis/dazi.js +266 -171
  6. package/dist/docs/flow/flow-project-guide.md +1 -1
  7. package/dist/docs/guides/quickstart.md +18 -4
  8. package/dist/docs/guides/troubleshooting.md +12 -1
  9. package/dist/docs/guides/workspace-v3.md +43 -23
  10. package/dist/docs/index.json +28 -3
  11. package/dist/docs/onto/action-guide.md +3 -3
  12. package/dist/docs/onto/dazi_script_sdk_reference.md +244 -174
  13. package/dist/docs/onto/dazi_script_seed_data_guide.md +158 -155
  14. package/dist/docs/onto/function-guide.md +82 -27
  15. package/dist/docs/onto/space-management.md +3 -1
  16. 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 +168 -0
  17. 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
  18. 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 +200 -34
  19. package/dist/docs/onto//346/234/254/344/275/223/350/247/204/345/210/222/346/214/207/345/215/227.md +188 -38
  20. package/dist/docs/onto//350/204/232/346/234/254/350/277/220/350/241/214/347/272/240/351/224/231_/345/225/206/345/212/241/346/210/220/346/234/254/346/226/271/346/241/210/345/274/200/345/217/221/350/277/207/347/250/213.md +213 -0
  21. 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 +620 -0
  22. 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 +680 -541
  23. package/dist/examples/index.json +208 -22
  24. package/dist/examples/onto/README.md +51 -0
  25. package/dist/examples/onto/_templates/ontology_function_template.py +50 -0
  26. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_account_breakdown.py +62 -0
  27. 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
  28. 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
  29. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_get_summary.py +61 -0
  30. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_mom_analysis.py +82 -0
  31. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_top_accounts.py +61 -0
  32. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_yoy_analysis.py +79 -0
  33. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/save_test_arguments.ps1 +38 -0
  34. 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
  35. 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
  36. 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
  37. 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
  38. 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
  39. 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
  40. 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
  41. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/setup/profit_ontology_init.py +679 -0
  42. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/setup/profit_seed_data.py +216 -0
  43. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_channel_mix.py +89 -0
  44. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_customer_segmentation.py +121 -0
  45. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_get_summary.py +78 -0
  46. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_mom_analysis.py +89 -0
  47. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_region_breakdown.py +84 -0
  48. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_top_products.py +98 -0
  49. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_yoy_analysis.py +87 -0
  50. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/save_test_arguments.ps1 +38 -0
  51. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.channel_mix.json +5 -0
  52. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.customer_segmentation.json +5 -0
  53. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.get_summary.json +5 -0
  54. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.mom_analysis.json +5 -0
  55. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.region_breakdown.json +5 -0
  56. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.top_products.json +5 -0
  57. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/test_arguments/sales.fn.yoy_analysis.json +5 -0
  58. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/sales_ontology_init.py +539 -0
  59. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/sales_seed_data.py +163 -0
  60. package/dist/prompts/index.json +2 -2
  61. package/dist/prompts/onto/action-design.md +4 -1
  62. package/dist/prompts/onto/function-design.md +46 -19
  63. package/dist/prompts/onto/rule-seed.md +5 -1
  64. package/dist/prompts/onto/script-publish-run.md +87 -25
  65. package/package.json +1 -1
  66. package/dist/examples/onto/function/profit_fn_customer_segmentation.py +0 -117
  67. package/dist/examples/onto/function/profit_fn_mom_analysis.py +0 -89
  68. package/dist/examples/onto/function/profit_fn_top_products.py +0 -89
  69. package/dist/examples/onto/function/profit_fn_yoy_analysis.py +0 -89
  70. package/dist/examples/onto/setup/profit_ontology_init.py +0 -388
@@ -0,0 +1,679 @@
1
+ """利润分析本体初始化脚本 — space__misc_01
2
+
3
+ 初始化内容:
4
+ 1. 创建物理表(科目表、成本中心维表、实际分录表、预算表)
5
+ 2. 注册表到空间(含 display_name / description)
6
+ 3. 注册表间关系(7条)
7
+ 4. 注册Cube(5个)及派生度量
8
+ 5. 定义对象类型(6种)、绑定数据源、属性、链接
9
+ 6. 同步指标引用
10
+ 7. 配置 347 对齐分类(ads_categories + 桥表)
11
+
12
+ 放置:资源/examples/onto/利润示例/setup/profit_ontology_init.py(复制到项目 ontos/<实现名>/setup/)
13
+ 发布:dazi onto script publish <item-path>/setup/profit_ontology_init.py --space <space-id> --type setup
14
+ 规划对照:资源/docs/onto/规划示例_利润分析本体方案.md
15
+ """
16
+
17
+ import json
18
+
19
+ # 与 规划示例_利润分析本体方案.md §2.3、§3.x 对齐:display_name=侧栏显示名,description=业务说明
20
+ TABLE_REGISTRY = {
21
+ "dim_account": {
22
+ "display_name": "科目维表",
23
+ "description": "会计科目主数据",
24
+ "columns": [
25
+ {"name": "account_id", "display_name": "科目 ID", "description": "主键"},
26
+ {"name": "account_code", "display_name": "科目编码"},
27
+ {"name": "account_name", "display_name": "科目名称"},
28
+ {"name": "account_type", "display_name": "科目类型", "description": "资产/负债/权益/收入/成本/费用"},
29
+ {"name": "pl_category", "display_name": "损益大类"},
30
+ {"name": "parent_account_id", "display_name": "上级科目"},
31
+ {"name": "account_level", "display_name": "层级"},
32
+ {"name": "is_leaf", "display_name": "末级"},
33
+ {"name": "normal_balance", "display_name": "余额方向", "description": "借/贷"},
34
+ {"name": "status", "display_name": "状态", "description": "启用/停用"},
35
+ {"name": "created_at", "display_name": "创建时间"},
36
+ ],
37
+ },
38
+ "dim_cost_center": {
39
+ "display_name": "成本中心维表",
40
+ "description": "组织/利润中心主数据",
41
+ "columns": [
42
+ {"name": "cost_center_id", "display_name": "成本中心 ID", "description": "主键"},
43
+ {"name": "cost_center_code", "display_name": "编码"},
44
+ {"name": "cost_center_name", "display_name": "名称"},
45
+ {"name": "department", "display_name": "部门"},
46
+ {"name": "company_code", "display_name": "公司代码"},
47
+ {"name": "profit_center", "display_name": "利润中心"},
48
+ {"name": "status", "display_name": "状态"},
49
+ {"name": "created_at", "display_name": "创建时间"},
50
+ ],
51
+ },
52
+ "fact_gl_journal_entry": {
53
+ "display_name": "总账实际分录",
54
+ "description": "凭证行粒度损益流水",
55
+ "columns": [
56
+ {"name": "entry_id", "display_name": "凭证 ID"},
57
+ {"name": "line_id", "display_name": "凭证行 ID"},
58
+ {"name": "date_key", "display_name": "日期键", "description": "关联 dim_date,YYYYMMDD"},
59
+ {"name": "posting_date", "display_name": "记账日期"},
60
+ {"name": "fiscal_year", "display_name": "会计年度"},
61
+ {"name": "fiscal_period", "display_name": "会计期间"},
62
+ {"name": "account_id", "display_name": "科目 ID", "description": "关联 dim_account"},
63
+ {"name": "account_code", "display_name": "科目编码", "description": "冗余"},
64
+ {"name": "account_name", "display_name": "科目名称", "description": "冗余"},
65
+ {"name": "account_type", "display_name": "科目类型", "description": "冗余"},
66
+ {"name": "pl_category", "display_name": "损益大类", "description": "冗余"},
67
+ {"name": "account_level", "display_name": "科目层级", "description": "冗余"},
68
+ {"name": "cost_center_id", "display_name": "成本中心 ID", "description": "关联 dim_cost_center"},
69
+ {"name": "cost_center_name", "display_name": "成本中心", "description": "冗余"},
70
+ {"name": "department", "display_name": "部门", "description": "冗余"},
71
+ {"name": "profit_center", "display_name": "利润中心", "description": "冗余"},
72
+ {"name": "debit_amount", "display_name": "借方"},
73
+ {"name": "credit_amount", "display_name": "贷方"},
74
+ {"name": "amount_signed", "display_name": "损益金额", "description": "收入为正、成本费用为负"},
75
+ {"name": "currency", "display_name": "币种"},
76
+ {"name": "voucher_no", "display_name": "凭证号"},
77
+ {"name": "source_system", "display_name": "来源系统"},
78
+ {"name": "description", "display_name": "摘要", "description": "凭证行摘要文本"},
79
+ {"name": "created_at", "display_name": "创建时间"},
80
+ ],
81
+ },
82
+ "fact_budget_entry": {
83
+ "display_name": "预算明细",
84
+ "description": "预算行粒度编制数据",
85
+ "columns": [
86
+ {"name": "budget_id", "display_name": "预算批次"},
87
+ {"name": "line_id", "display_name": "预算行 ID"},
88
+ {"name": "date_key", "display_name": "日期键", "description": "关联 dim_date"},
89
+ {"name": "budget_version", "display_name": "预算版本"},
90
+ {"name": "fiscal_year", "display_name": "预算年度"},
91
+ {"name": "fiscal_period", "display_name": "预算期间", "description": "1-12"},
92
+ {"name": "account_id", "display_name": "科目 ID", "description": "关联 dim_account"},
93
+ {"name": "account_code", "display_name": "科目编码", "description": "冗余"},
94
+ {"name": "account_name", "display_name": "科目名称", "description": "冗余"},
95
+ {"name": "account_type", "display_name": "科目类型", "description": "冗余"},
96
+ {"name": "pl_category", "display_name": "损益大类", "description": "冗余"},
97
+ {"name": "cost_center_id", "display_name": "成本中心 ID", "description": "关联 dim_cost_center"},
98
+ {"name": "cost_center_name", "display_name": "成本中心", "description": "冗余"},
99
+ {"name": "department", "display_name": "部门", "description": "冗余"},
100
+ {"name": "budget_amount", "display_name": "预算金额"},
101
+ {"name": "currency", "display_name": "币种"},
102
+ {"name": "status", "display_name": "状态", "description": "草稿/已发布"},
103
+ {"name": "created_at", "display_name": "创建时间"},
104
+ ],
105
+ },
106
+ }
107
+
108
+ # 与 347 + 附录 B 对齐;category 值必须是 347 标准中文名
109
+ CATEGORY_REGISTRY = {
110
+ "table": {
111
+ "维度表": ["dim_account", "dim_cost_center"],
112
+ "事实表": ["fact_gl_journal_entry", "fact_budget_entry"],
113
+ },
114
+ "cube": {
115
+ "流程型": ["ActualCube", "BudgetCube"],
116
+ "主体型": ["AccountActualCube", "CostCenterActualCube", "TimeActualCube"],
117
+ },
118
+ "object": {
119
+ "主数据": ["Account", "CostCenter"],
120
+ "事务": ["JournalEntry", "BudgetLine"],
121
+ "分析": ["ProfitAnalysis", "BudgetAnalysis"],
122
+ },
123
+ "relation": {
124
+ "时间关联": [
125
+ ("fact_gl_journal_entry", "dim_date"),
126
+ ("fact_budget_entry", "dim_date"),
127
+ ],
128
+ "主数据关联": [
129
+ ("fact_gl_journal_entry", "dim_account"),
130
+ ("fact_gl_journal_entry", "dim_cost_center"),
131
+ ("fact_budget_entry", "dim_account"),
132
+ ("fact_budget_entry", "dim_cost_center"),
133
+ ],
134
+ "层级自关联": [("dim_account", "dim_account")],
135
+ },
136
+ "link": {
137
+ "归属关系": [
138
+ "entry_belongs_account",
139
+ "entry_belongs_cost_center",
140
+ "budget_for_account",
141
+ "budget_for_cost_center",
142
+ ],
143
+ "分析归因": [
144
+ "analysis_by_account",
145
+ "analysis_by_cost_center",
146
+ "account_contributes_profit",
147
+ "cost_center_contributes_profit",
148
+ ],
149
+ "层级关系": ["account_has_parent"],
150
+ "对比关系": ["budget_compared_to_actual"],
151
+ },
152
+ "function": {
153
+ "总览分析": ["profit.fn.get_summary"],
154
+ "趋势分析": ["profit.fn.yoy_analysis", "profit.fn.mom_analysis"],
155
+ "结构分析": ["profit.fn.account_breakdown", "profit.fn.top_accounts"],
156
+ "预实分析": ["profit.fn.budget_vs_actual"],
157
+ "组织分析": ["profit.fn.cost_center_profit"],
158
+ },
159
+ }
160
+
161
+
162
+ def main():
163
+ space_id = "space__misc_01"
164
+ s = space.get(space_id)
165
+
166
+ output.print("=== 利润分析本体初始化 ===")
167
+ output.print(f"空间: {space_id}")
168
+
169
+ # 1. 创建物理表
170
+ output.print("\n[1/10] 创建物理表...")
171
+
172
+ s.sql.execute("""
173
+ CREATE TABLE IF NOT EXISTS dim_account (
174
+ account_id String,
175
+ account_code String,
176
+ account_name String,
177
+ account_type String,
178
+ pl_category String,
179
+ parent_account_id String,
180
+ account_level Int32,
181
+ is_leaf Boolean,
182
+ normal_balance String,
183
+ status String,
184
+ created_at DateTime DEFAULT now()
185
+ ) ENGINE = MergeTree()
186
+ ORDER BY (account_code)
187
+ """)
188
+ output.print("OK dim_account")
189
+
190
+ s.sql.execute("""
191
+ CREATE TABLE IF NOT EXISTS dim_cost_center (
192
+ cost_center_id String,
193
+ cost_center_code String,
194
+ cost_center_name String,
195
+ department String,
196
+ company_code String,
197
+ profit_center String,
198
+ status String,
199
+ created_at DateTime DEFAULT now()
200
+ ) ENGINE = MergeTree()
201
+ ORDER BY (cost_center_id)
202
+ """)
203
+ output.print("OK dim_cost_center")
204
+
205
+ s.sql.execute("""
206
+ CREATE TABLE IF NOT EXISTS fact_gl_journal_entry (
207
+ entry_id String,
208
+ line_id String,
209
+ date_key Int32,
210
+ posting_date Date,
211
+ fiscal_year Int32,
212
+ fiscal_period Int32,
213
+ account_id String,
214
+ account_code String,
215
+ account_name String,
216
+ account_type String,
217
+ pl_category String,
218
+ account_level Int32,
219
+ cost_center_id String,
220
+ cost_center_name String,
221
+ department String,
222
+ profit_center String,
223
+ debit_amount Float64,
224
+ credit_amount Float64,
225
+ amount_signed Float64,
226
+ currency String,
227
+ voucher_no String,
228
+ source_system String,
229
+ description String,
230
+ created_at DateTime DEFAULT now()
231
+ ) ENGINE = MergeTree()
232
+ ORDER BY (date_key, entry_id, line_id)
233
+ """)
234
+ output.print("OK fact_gl_journal_entry")
235
+
236
+ s.sql.execute("""
237
+ CREATE TABLE IF NOT EXISTS fact_budget_entry (
238
+ budget_id String,
239
+ line_id String,
240
+ date_key Int32,
241
+ budget_version String,
242
+ fiscal_year Int32,
243
+ fiscal_period Int32,
244
+ account_id String,
245
+ account_code String,
246
+ account_name String,
247
+ account_type String,
248
+ pl_category String,
249
+ cost_center_id String,
250
+ cost_center_name String,
251
+ department String,
252
+ budget_amount Float64,
253
+ currency String,
254
+ status String,
255
+ created_at DateTime DEFAULT now()
256
+ ) ENGINE = MergeTree()
257
+ ORDER BY (fiscal_year, fiscal_period, account_id, line_id)
258
+ """)
259
+ output.print("OK fact_budget_entry")
260
+
261
+ # 2. 注册表(含 display_name / description)
262
+ output.print("\n[2/10] 注册表到空间...")
263
+
264
+ for tbl_name, meta in TABLE_REGISTRY.items():
265
+ s.tables.register_with_meta(
266
+ table_name=tbl_name,
267
+ display_name=meta["display_name"],
268
+ description=meta.get("description"),
269
+ columns=meta["columns"],
270
+ force_column_meta=True,
271
+ )
272
+ output.print(f"OK {tbl_name} ({meta['display_name']})")
273
+
274
+ # 3. 注册表间关系
275
+ output.print("\n[3/10] 注册表间关系...")
276
+
277
+ table_relationships = [
278
+ {
279
+ "from_table": "fact_gl_journal_entry",
280
+ "to_table": "dim_date",
281
+ "join_sql": "fact_gl_journal_entry.date_key = dim_date.date_key",
282
+ "join_keys": [{"from": "date_key", "to": "date_key"}],
283
+ "relationship_type": "many_to_one",
284
+ "description": "分录关联日历",
285
+ },
286
+ {
287
+ "from_table": "fact_budget_entry",
288
+ "to_table": "dim_date",
289
+ "join_sql": "fact_budget_entry.date_key = dim_date.date_key",
290
+ "join_keys": [{"from": "date_key", "to": "date_key"}],
291
+ "relationship_type": "many_to_one",
292
+ "description": "预算关联日历",
293
+ },
294
+ {
295
+ "from_table": "fact_gl_journal_entry",
296
+ "to_table": "dim_account",
297
+ "join_sql": "fact_gl_journal_entry.account_id = dim_account.account_id",
298
+ "join_keys": [{"from": "account_id", "to": "account_id"}],
299
+ "relationship_type": "many_to_one",
300
+ "description": "实际分录关联会计科目",
301
+ },
302
+ {
303
+ "from_table": "fact_gl_journal_entry",
304
+ "to_table": "dim_cost_center",
305
+ "join_sql": "fact_gl_journal_entry.cost_center_id = dim_cost_center.cost_center_id",
306
+ "join_keys": [{"from": "cost_center_id", "to": "cost_center_id"}],
307
+ "relationship_type": "many_to_one",
308
+ "description": "实际分录关联成本中心",
309
+ },
310
+ {
311
+ "from_table": "fact_budget_entry",
312
+ "to_table": "dim_account",
313
+ "join_sql": "fact_budget_entry.account_id = dim_account.account_id",
314
+ "join_keys": [{"from": "account_id", "to": "account_id"}],
315
+ "relationship_type": "many_to_one",
316
+ "description": "预算关联会计科目",
317
+ },
318
+ {
319
+ "from_table": "fact_budget_entry",
320
+ "to_table": "dim_cost_center",
321
+ "join_sql": "fact_budget_entry.cost_center_id = dim_cost_center.cost_center_id",
322
+ "join_keys": [{"from": "cost_center_id", "to": "cost_center_id"}],
323
+ "relationship_type": "many_to_one",
324
+ "description": "预算关联成本中心",
325
+ },
326
+ {
327
+ "from_table": "dim_account",
328
+ "to_table": "dim_account",
329
+ "join_sql": "dim_account.parent_account_id = dim_account.account_id",
330
+ "join_keys": [{"from": "parent_account_id", "to": "account_id"}],
331
+ "relationship_type": "many_to_one",
332
+ "description": "科目上级(树形)",
333
+ },
334
+ ]
335
+ for rel in table_relationships:
336
+ rid = s.tables.add_relationship(**rel)
337
+ output.print(f"OK {rel['from_table']} -> {rel['to_table']}")
338
+
339
+ # 4. 注册 Cube
340
+ output.print("\n[4/10] 注册 Cube...")
341
+
342
+ actual = "fact_gl_journal_entry"
343
+ budget = "fact_budget_entry"
344
+
345
+ s.register_cube(
346
+ name="ActualCube",
347
+ table=actual,
348
+ title="实际发生主Cube",
349
+ measures=[
350
+ {"name": "debit_total", "col": "debit_amount", "agg": "sum", "title": "借方合计"},
351
+ {"name": "credit_total", "col": "credit_amount", "agg": "sum", "title": "贷方合计"},
352
+ {"name": "net_amount", "col": "amount_signed", "agg": "sum", "title": "损益符号额"},
353
+ {"name": "line_count", "col": "line_id", "agg": "count", "title": "分录行数"},
354
+ ],
355
+ dimensions=[
356
+ {"name": "entry_id", "col": "entry_id", "type": "string", "title": "凭证ID"},
357
+ {"name": "line_id", "col": "line_id", "type": "string", "title": "行ID"},
358
+ {"name": "date_key", "col": "date_key", "type": "int", "title": "日期键"},
359
+ {"name": "posting_date", "col": "posting_date", "type": "date", "title": "记账日期"},
360
+ {"name": "fiscal_year", "col": "fiscal_year", "type": "int", "title": "会计年度"},
361
+ {"name": "fiscal_period", "col": "fiscal_period", "type": "int", "title": "会计期间"},
362
+ {"name": "account_id", "col": "account_id", "type": "string", "title": "科目ID"},
363
+ {"name": "account_code", "col": "account_code", "type": "string", "title": "科目编码"},
364
+ {"name": "account_name", "col": "account_name", "type": "string", "title": "科目名称"},
365
+ {"name": "account_type", "col": "account_type", "type": "string", "title": "科目类型"},
366
+ {"name": "pl_category", "col": "pl_category", "type": "string", "title": "损益大类"},
367
+ {"name": "cost_center_id", "col": "cost_center_id", "type": "string", "title": "成本中心ID"},
368
+ {"name": "cost_center_name", "col": "cost_center_name", "type": "string", "title": "成本中心"},
369
+ {"name": "department", "col": "department", "type": "string", "title": "部门"},
370
+ {"name": "voucher_no", "col": "voucher_no", "type": "string", "title": "凭证号"},
371
+ ],
372
+ )
373
+ output.print("OK ActualCube")
374
+
375
+ s.register_cube(
376
+ name="AccountActualCube",
377
+ table=actual,
378
+ title="科目实际Cube",
379
+ measures=[
380
+ {"name": "net_amount", "col": "amount_signed", "agg": "sum", "title": "实际发生"},
381
+ {"name": "line_count", "col": "line_id", "agg": "count", "title": "分录行数"},
382
+ ],
383
+ dimensions=[
384
+ {"name": "account_id", "col": "account_id", "type": "string", "title": "科目ID"},
385
+ {"name": "account_code", "col": "account_code", "type": "string", "title": "科目编码"},
386
+ {"name": "account_name", "col": "account_name", "type": "string", "title": "科目名称"},
387
+ {"name": "account_type", "col": "account_type", "type": "string", "title": "科目类型"},
388
+ {"name": "pl_category", "col": "pl_category", "type": "string", "title": "损益大类"},
389
+ {"name": "account_level", "col": "account_level", "type": "int", "title": "科目层级"},
390
+ {"name": "fiscal_year", "col": "fiscal_year", "type": "int", "title": "会计年度"},
391
+ {"name": "fiscal_period", "col": "fiscal_period", "type": "int", "title": "会计期间"},
392
+ ],
393
+ )
394
+ output.print("OK AccountActualCube")
395
+
396
+ s.register_cube(
397
+ name="CostCenterActualCube",
398
+ table=actual,
399
+ title="成本中心实际Cube",
400
+ measures=[
401
+ {"name": "net_amount", "col": "amount_signed", "agg": "sum", "title": "实际发生"},
402
+ {"name": "line_count", "col": "line_id", "agg": "count", "title": "分录行数"},
403
+ ],
404
+ dimensions=[
405
+ {"name": "cost_center_id", "col": "cost_center_id", "type": "string", "title": "成本中心ID"},
406
+ {"name": "cost_center_name", "col": "cost_center_name", "type": "string", "title": "成本中心"},
407
+ {"name": "department", "col": "department", "type": "string", "title": "部门"},
408
+ {"name": "profit_center", "col": "profit_center", "type": "string", "title": "利润中心"},
409
+ {"name": "fiscal_year", "col": "fiscal_year", "type": "int", "title": "会计年度"},
410
+ {"name": "fiscal_period", "col": "fiscal_period", "type": "int", "title": "会计期间"},
411
+ ],
412
+ )
413
+ output.print("OK CostCenterActualCube")
414
+
415
+ s.register_cube(
416
+ name="BudgetCube",
417
+ table=budget,
418
+ title="预算Cube",
419
+ measures=[
420
+ {"name": "budget_amount", "col": "budget_amount", "agg": "sum", "title": "预算金额"},
421
+ {"name": "budget_lines", "col": "line_id", "agg": "count", "title": "预算行数"},
422
+ ],
423
+ dimensions=[
424
+ {"name": "line_id", "col": "line_id", "type": "string", "title": "预算行ID"},
425
+ {"name": "budget_version", "col": "budget_version", "type": "string", "title": "预算版本"},
426
+ {"name": "fiscal_year", "col": "fiscal_year", "type": "int", "title": "预算年度"},
427
+ {"name": "fiscal_period", "col": "fiscal_period", "type": "int", "title": "预算期间"},
428
+ {"name": "account_id", "col": "account_id", "type": "string", "title": "科目ID"},
429
+ {"name": "account_code", "col": "account_code", "type": "string", "title": "科目编码"},
430
+ {"name": "account_type", "col": "account_type", "type": "string", "title": "科目类型"},
431
+ {"name": "pl_category", "col": "pl_category", "type": "string", "title": "损益大类"},
432
+ {"name": "cost_center_id", "col": "cost_center_id", "type": "string", "title": "成本中心ID"},
433
+ {"name": "department", "col": "department", "type": "string", "title": "部门"},
434
+ ],
435
+ )
436
+ output.print("OK BudgetCube")
437
+
438
+ s.register_cube(
439
+ name="TimeActualCube",
440
+ table=actual,
441
+ title="时间维度实际Cube",
442
+ measures=[
443
+ {"name": "net_amount", "col": "amount_signed", "agg": "sum", "title": "损益符号额"},
444
+ {"name": "line_count", "col": "line_id", "agg": "count", "title": "分录行数"},
445
+ ],
446
+ dimensions=[
447
+ {"name": "date_key", "col": "date_key", "type": "int", "title": "日期键"},
448
+ {"name": "posting_date", "col": "posting_date", "type": "date", "title": "记账日期"},
449
+ {"name": "fiscal_year", "col": "fiscal_year", "type": "int", "title": "会计年度"},
450
+ {"name": "fiscal_period", "col": "fiscal_period", "type": "int", "title": "会计期间"},
451
+ ],
452
+ )
453
+ output.print("OK TimeActualCube")
454
+
455
+ # 5. 派生度量
456
+ output.print("\n[5/10] 配置派生度量...")
457
+
458
+ def _pl_measures(cube_name, full=False):
459
+ base = [
460
+ {
461
+ "name": "revenue",
462
+ "title": "收入",
463
+ "expression": "sum(if(account_type='收入', amount_signed, 0))",
464
+ "description": "收入类科目发生额",
465
+ },
466
+ {
467
+ "name": "cost",
468
+ "title": "成本",
469
+ "expression": "sum(if(account_type='成本', amount_signed, 0))",
470
+ "description": "成本类科目发生额",
471
+ },
472
+ {
473
+ "name": "expense",
474
+ "title": "费用",
475
+ "expression": "sum(if(account_type='费用', amount_signed, 0))",
476
+ "description": "费用类科目发生额",
477
+ },
478
+ ]
479
+ if not full:
480
+ return base
481
+ return base + [
482
+ {
483
+ "name": "operating_profit",
484
+ "title": "营业利润",
485
+ "expression": f"{cube_name}.revenue - {cube_name}.cost - {cube_name}.expense",
486
+ "description": "收入-成本-费用",
487
+ },
488
+ {
489
+ "name": "profit_margin",
490
+ "title": "利润率",
491
+ "expression": f"if({cube_name}.revenue > 0, {cube_name}.operating_profit / {cube_name}.revenue, 0)",
492
+ "description": "营业利润/收入",
493
+ },
494
+ ]
495
+
496
+ s.upsert_derived_measures("ActualCube", _pl_measures("ActualCube", True))
497
+ s.upsert_derived_measures("AccountActualCube", _pl_measures("AccountActualCube", False))
498
+ s.upsert_derived_measures("CostCenterActualCube", _pl_measures("CostCenterActualCube", True))
499
+ s.upsert_derived_measures("TimeActualCube", _pl_measures("TimeActualCube", True))
500
+
501
+ s.upsert_derived_measures(
502
+ "BudgetCube",
503
+ [
504
+ {
505
+ "name": "budget_revenue",
506
+ "title": "预算收入",
507
+ "expression": "sum(if(account_type='收入', budget_amount, 0))",
508
+ "description": "预算收入",
509
+ },
510
+ {
511
+ "name": "budget_cost",
512
+ "title": "预算成本",
513
+ "expression": "sum(if(account_type='成本', budget_amount, 0))",
514
+ "description": "预算成本",
515
+ },
516
+ {
517
+ "name": "budget_expense",
518
+ "title": "预算费用",
519
+ "expression": "sum(if(account_type='费用', budget_amount, 0))",
520
+ "description": "预算费用",
521
+ },
522
+ ],
523
+ )
524
+ output.print("OK 派生度量")
525
+
526
+ # 6. 对象类型
527
+ output.print("\n[6/10] 定义对象类型...")
528
+
529
+ object_types = [
530
+ ("Account", "会计科目", "会计科目业务对象"),
531
+ ("CostCenter", "成本中心", "组织/利润中心业务对象"),
532
+ ("JournalEntry", "实际分录", "凭证行实际发生业务对象"),
533
+ ("BudgetLine", "预算行", "预算编制明细业务对象"),
534
+ ("ProfitAnalysis", "利润分析", "多维度损益指标聚合对象"),
535
+ ("BudgetAnalysis", "预算分析", "预算执行与差异分析对象"),
536
+ ]
537
+ for code, name, desc in object_types:
538
+ s.onto.define_object_type(code, name, description=desc)
539
+ output.print(f"OK {code}")
540
+
541
+ # 7. 绑定数据源
542
+ output.print("\n[7/10] 绑定数据源...")
543
+
544
+ bindings = [
545
+ ("Account", "AccountActualCube"),
546
+ ("CostCenter", "CostCenterActualCube"),
547
+ ("JournalEntry", "ActualCube"),
548
+ ("BudgetLine", "BudgetCube"),
549
+ ("ProfitAnalysis", "ActualCube"),
550
+ ("BudgetAnalysis", "BudgetCube"),
551
+ ]
552
+ for obj, cube in bindings:
553
+ s.onto.bind_source(obj, "dazi_cube", config={"cube": cube})
554
+ output.print(f"OK {obj} -> {cube}")
555
+
556
+ # 8. 属性
557
+ output.print("\n[8/10] 定义属性...")
558
+
559
+ def define_props(obj_code, props):
560
+ for code, name, role, qn in props:
561
+ s.onto.define_property(obj_code, code, name, semantic_role=role, qualified_name=qn)
562
+
563
+ define_props("Account", [
564
+ ("id", "科目ID", "dimension", "AccountActualCube.account_id"),
565
+ ("code", "科目编码", "dimension", "AccountActualCube.account_code"),
566
+ ("name", "科目名称", "dimension", "AccountActualCube.account_name"),
567
+ ("type", "科目类型", "dimension", "AccountActualCube.account_type"),
568
+ ("pl_category", "损益大类", "dimension", "AccountActualCube.pl_category"),
569
+ ("level", "科目层级", "dimension", "AccountActualCube.account_level"),
570
+ ("net_amount", "实际发生", "measure", "AccountActualCube.net_amount"),
571
+ ("revenue", "收入", "measure", "AccountActualCube.revenue"),
572
+ ("cost", "成本", "measure", "AccountActualCube.cost"),
573
+ ("expense", "费用", "measure", "AccountActualCube.expense"),
574
+ ])
575
+ output.print("OK Account 属性 (10)")
576
+
577
+ define_props("CostCenter", [
578
+ ("id", "成本中心ID", "dimension", "CostCenterActualCube.cost_center_id"),
579
+ ("name", "成本中心", "dimension", "CostCenterActualCube.cost_center_name"),
580
+ ("department", "部门", "dimension", "CostCenterActualCube.department"),
581
+ ("profit_center", "利润中心", "dimension", "CostCenterActualCube.profit_center"),
582
+ ("revenue", "收入", "measure", "CostCenterActualCube.revenue"),
583
+ ("cost", "成本", "measure", "CostCenterActualCube.cost"),
584
+ ("expense", "费用", "measure", "CostCenterActualCube.expense"),
585
+ ("operating_profit", "营业利润", "measure", "CostCenterActualCube.operating_profit"),
586
+ ])
587
+ output.print("OK CostCenter 属性 (8)")
588
+
589
+ define_props("JournalEntry", [
590
+ ("id", "行ID", "dimension", "ActualCube.line_id"),
591
+ ("posting_date", "记账日期", "dimension", "ActualCube.posting_date"),
592
+ ("fiscal_period", "会计期间", "dimension", "ActualCube.fiscal_period"),
593
+ ("net_amount", "损益金额", "measure", "ActualCube.net_amount"),
594
+ ("debit", "借方", "measure", "ActualCube.debit_total"),
595
+ ("credit", "贷方", "measure", "ActualCube.credit_total"),
596
+ ])
597
+ output.print("OK JournalEntry 属性 (6)")
598
+
599
+ define_props("BudgetLine", [
600
+ ("id", "预算行ID", "dimension", "BudgetCube.line_id"),
601
+ ("version", "预算版本", "dimension", "BudgetCube.budget_version"),
602
+ ("fiscal_period", "预算期间", "dimension", "BudgetCube.fiscal_period"),
603
+ ("budget_amount", "预算金额", "measure", "BudgetCube.budget_amount"),
604
+ ])
605
+ output.print("OK BudgetLine 属性 (4)")
606
+
607
+ define_props("ProfitAnalysis", [
608
+ ("date", "日期", "dimension", "ActualCube.posting_date"),
609
+ ("pl_category", "损益大类", "dimension", "ActualCube.pl_category"),
610
+ ("department", "部门", "dimension", "ActualCube.department"),
611
+ ("revenue", "收入", "measure", "ActualCube.revenue"),
612
+ ("cost", "成本", "measure", "ActualCube.cost"),
613
+ ("expense", "费用", "measure", "ActualCube.expense"),
614
+ ("operating_profit", "营业利润", "measure", "ActualCube.operating_profit"),
615
+ ("profit_margin", "利润率", "measure", "ActualCube.profit_margin"),
616
+ ])
617
+ output.print("OK ProfitAnalysis 属性 (8)")
618
+
619
+ define_props("BudgetAnalysis", [
620
+ ("version", "预算版本", "dimension", "BudgetCube.budget_version"),
621
+ ("fiscal_period", "预算期间", "dimension", "BudgetCube.fiscal_period"),
622
+ ("budget_amount", "预算金额", "measure", "BudgetCube.budget_amount"),
623
+ ("budget_revenue", "预算收入", "measure", "BudgetCube.budget_revenue"),
624
+ ("budget_cost", "预算成本", "measure", "BudgetCube.budget_cost"),
625
+ ("budget_expense", "预算费用", "measure", "BudgetCube.budget_expense"),
626
+ ])
627
+ output.print("OK BudgetAnalysis 属性 (6)")
628
+
629
+ # 9. 链接类型
630
+ output.print("\n[9/10] 定义链接与同步指标...")
631
+
632
+ link_types = [
633
+ ("entry_belongs_account", "分录归属科目", "JournalEntry", "Account", "分录行对应科目"),
634
+ ("entry_belongs_cost_center", "分录归属成本中心", "JournalEntry", "CostCenter", "分录行对应组织"),
635
+ ("budget_for_account", "预算对应科目", "BudgetLine", "Account", "预算行对应科目"),
636
+ ("budget_for_cost_center", "预算对应成本中心", "BudgetLine", "CostCenter", "预算行对应组织"),
637
+ ("account_has_parent", "科目上级", "Account", "Account", "科目树父级"),
638
+ ("budget_compared_to_actual", "预算对比实际", "BudgetAnalysis", "ProfitAnalysis", "预实差异分析"),
639
+ ("analysis_by_account", "分析归因科目", "ProfitAnalysis", "Account", "指标按科目切片"),
640
+ ("analysis_by_cost_center", "分析归因成本中心", "ProfitAnalysis", "CostCenter", "指标按组织切片"),
641
+ ("account_contributes_profit", "科目贡献利润", "Account", "ProfitAnalysis", "科目损益贡献"),
642
+ ("cost_center_contributes_profit", "组织贡献利润", "CostCenter", "ProfitAnalysis", "成本中心利润贡献"),
643
+ ]
644
+ for code, name, from_obj, to_obj, desc in link_types:
645
+ s.onto.define_link_type(
646
+ code=code,
647
+ name=name,
648
+ from_object_type_code=from_obj,
649
+ to_object_type_code=to_obj,
650
+ description=desc,
651
+ )
652
+ output.print(f"OK {code}")
653
+
654
+ s.sync_metric_refs()
655
+ output.print("OK sync_metric_refs")
656
+
657
+ # 10. 347 对齐分类
658
+ output.print("\n[10/10] 配置对象分类(347 对齐)...")
659
+
660
+ cat_counts = s.categories.apply_registry(CATEGORY_REGISTRY, skip_missing=True)
661
+ for kind, cnt in cat_counts.items():
662
+ if cnt:
663
+ output.print(f"OK 分类[{kind}] 挂载 {cnt} 项")
664
+
665
+ summary = {
666
+ "ok": True,
667
+ "space_id": space_id,
668
+ "tables": 4,
669
+ "table_relationships": 7,
670
+ "cubes": 5,
671
+ "object_types": 6,
672
+ "properties": 42,
673
+ "link_types": 10,
674
+ "category_mounts": cat_counts,
675
+ }
676
+
677
+ output.print("\n=== 利润分析本体初始化完成 ===")
678
+ output.success("初始化成功")
679
+ output.print("__JSON_SUMMARY__" + json.dumps(summary, ensure_ascii=True, default=str))