@dazitech/cli 3.0.7 → 3.0.8

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 (68) 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 +1 -1
  9. package/dist/docs/guides/workspace-v3.md +43 -23
  10. package/dist/docs/index.json +9 -3
  11. package/dist/docs/onto/action-guide.md +3 -3
  12. package/dist/docs/onto/dazi_script_sdk_reference.md +178 -174
  13. package/dist/docs/onto/dazi_script_seed_data_guide.md +158 -155
  14. package/dist/docs/onto/function-guide.md +37 -10
  15. package/dist/docs/onto/space-management.md +3 -1
  16. 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 +138 -34
  17. package/dist/docs/onto//346/234/254/344/275/223/350/247/204/345/210/222/346/214/207/345/215/227.md +73 -31
  18. 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 +497 -0
  19. 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 +597 -541
  20. package/dist/examples/index.json +202 -22
  21. package/dist/examples/onto/README.md +43 -0
  22. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_account_breakdown.py +99 -0
  23. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_budget_vs_actual.py +116 -0
  24. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_cost_center_profit.py +85 -0
  25. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_get_summary.py +76 -0
  26. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_mom_analysis.py +86 -0
  27. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_top_accounts.py +103 -0
  28. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_yoy_analysis.py +86 -0
  29. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/save_test_arguments.ps1 +27 -0
  30. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.account_breakdown.json +10 -0
  31. 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 +10 -0
  32. 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 +9 -0
  33. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.get_summary.json +9 -0
  34. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.mom_analysis.json +9 -0
  35. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.top_accounts.json +11 -0
  36. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/test_arguments/profit.fn.yoy_analysis.json +9 -0
  37. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/setup/profit_ontology_init.py +521 -0
  38. package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/setup/profit_seed_data.py +213 -0
  39. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/README.md +25 -0
  40. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_channel_mix.py +86 -0
  41. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_customer_segmentation.py +123 -0
  42. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_get_summary.py +81 -0
  43. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_mom_analysis.py +90 -0
  44. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_region_breakdown.py +85 -0
  45. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_top_products.py +101 -0
  46. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_yoy_analysis.py +90 -0
  47. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/save_test_arguments.ps1 +25 -0
  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 +8 -0
  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 +10 -0
  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 +8 -0
  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 +8 -0
  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 +8 -0
  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 +10 -0
  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 +8 -0
  55. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/README.md +5 -0
  56. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/sales_ontology_init.py +403 -0
  57. package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/sales_seed_data.py +124 -0
  58. package/dist/prompts/index.json +2 -2
  59. package/dist/prompts/onto/action-design.md +4 -1
  60. package/dist/prompts/onto/function-design.md +9 -2
  61. package/dist/prompts/onto/rule-seed.md +5 -1
  62. package/dist/prompts/onto/script-publish-run.md +72 -24
  63. package/package.json +1 -1
  64. package/dist/examples/onto/function/profit_fn_customer_segmentation.py +0 -117
  65. package/dist/examples/onto/function/profit_fn_mom_analysis.py +0 -89
  66. package/dist/examples/onto/function/profit_fn_top_products.py +0 -89
  67. package/dist/examples/onto/function/profit_fn_yoy_analysis.py +0 -89
  68. package/dist/examples/onto/setup/profit_ontology_init.py +0 -388
@@ -0,0 +1,521 @@
1
+ """利润分析本体初始化脚本 — space__zlj
2
+
3
+ 初始化内容:
4
+ 1. 创建物理表(4 张:科目表、成本中心维表、实际分录表、预算表)
5
+ 2. 注册表到空间
6
+ 3. 注册表间关系(6 条)
7
+ 4. 注册 Cube(5 个)及派生度量
8
+ 5. 定义对象类型(6 种)、绑定数据源、属性、链接
9
+ 6. 同步指标引用
10
+
11
+ 放置:项目/潘达石化/本体/ontos/利润分析本体方案/setup/profit_ontology_init.py
12
+ 发布:dazi onto script publish 项目/潘达石化/本体/ontos/利润分析本体方案/setup/profit_ontology_init.py --space space__zlj --type setup
13
+ """
14
+
15
+ import json
16
+
17
+
18
+ def main():
19
+ space_id = "space__zlj"
20
+ s = space.get(space_id)
21
+
22
+ output.print("=== 利润分析本体初始化 ===")
23
+ output.print(f"空间: {space_id}")
24
+
25
+ # 1. 创建物理表
26
+ output.print("\n[1/9] 创建物理表...")
27
+
28
+ s.sql.execute("""
29
+ CREATE TABLE IF NOT EXISTS account_master (
30
+ account_id String,
31
+ account_code String,
32
+ account_name String,
33
+ account_type String,
34
+ pl_category String,
35
+ parent_account_id String,
36
+ account_level Int32,
37
+ is_leaf Boolean,
38
+ normal_balance String,
39
+ status String,
40
+ created_at DateTime DEFAULT now()
41
+ ) ENGINE = MergeTree()
42
+ ORDER BY (account_code)
43
+ """)
44
+ output.print("OK account_master")
45
+
46
+ s.sql.execute("""
47
+ CREATE TABLE IF NOT EXISTS cost_center_dimension (
48
+ cost_center_id String,
49
+ cost_center_code String,
50
+ cost_center_name String,
51
+ department String,
52
+ company_code String,
53
+ profit_center String,
54
+ status String,
55
+ created_at DateTime DEFAULT now()
56
+ ) ENGINE = MergeTree()
57
+ ORDER BY (cost_center_id)
58
+ """)
59
+ output.print("OK cost_center_dimension")
60
+
61
+ s.sql.execute("""
62
+ CREATE TABLE IF NOT EXISTS actual_journal_entry (
63
+ entry_id String,
64
+ line_id String,
65
+ posting_date Date,
66
+ fiscal_year Int32,
67
+ fiscal_period Int32,
68
+ account_id String,
69
+ account_code String,
70
+ account_name String,
71
+ account_type String,
72
+ pl_category String,
73
+ account_level Int32,
74
+ cost_center_id String,
75
+ cost_center_name String,
76
+ department String,
77
+ profit_center String,
78
+ debit_amount Float64,
79
+ credit_amount Float64,
80
+ amount_signed Float64,
81
+ currency String,
82
+ voucher_no String,
83
+ source_system String,
84
+ description String,
85
+ created_at DateTime DEFAULT now()
86
+ ) ENGINE = MergeTree()
87
+ ORDER BY (posting_date, entry_id, line_id)
88
+ """)
89
+ output.print("OK actual_journal_entry")
90
+
91
+ s.sql.execute("""
92
+ CREATE TABLE IF NOT EXISTS budget_entry (
93
+ budget_id String,
94
+ line_id String,
95
+ budget_version String,
96
+ fiscal_year Int32,
97
+ fiscal_period Int32,
98
+ account_id String,
99
+ account_code String,
100
+ account_name String,
101
+ account_type String,
102
+ pl_category String,
103
+ cost_center_id String,
104
+ cost_center_name String,
105
+ department String,
106
+ budget_amount Float64,
107
+ currency String,
108
+ status String,
109
+ created_at DateTime DEFAULT now()
110
+ ) ENGINE = MergeTree()
111
+ ORDER BY (fiscal_year, fiscal_period, account_id, line_id)
112
+ """)
113
+ output.print("OK budget_entry")
114
+
115
+ # 2. 注册表
116
+ output.print("\n[2/9] 注册表到空间...")
117
+
118
+ for tbl, label in [
119
+ ("account_master", "会计科目主数据表"),
120
+ ("cost_center_dimension", "成本中心维表"),
121
+ ("actual_journal_entry", "实际分录事实表"),
122
+ ("budget_entry", "预算事实表"),
123
+ ]:
124
+ s.tables.register(tbl, label=label)
125
+ s.tables.sync_columns(tbl)
126
+ output.print(f"OK {tbl}")
127
+
128
+ # 3. 注册表间关系
129
+ output.print("\n[3/9] 注册表间关系...")
130
+
131
+ table_relationships = [
132
+ {
133
+ "from_table": "actual_journal_entry",
134
+ "to_table": "account_master",
135
+ "join_sql": "actual_journal_entry.account_id = account_master.account_id",
136
+ "join_keys": [{"from": "account_id", "to": "account_id"}],
137
+ "relationship_type": "many_to_one",
138
+ "description": "实际分录关联会计科目",
139
+ },
140
+ {
141
+ "from_table": "actual_journal_entry",
142
+ "to_table": "cost_center_dimension",
143
+ "join_sql": "actual_journal_entry.cost_center_id = cost_center_dimension.cost_center_id",
144
+ "join_keys": [{"from": "cost_center_id", "to": "cost_center_id"}],
145
+ "relationship_type": "many_to_one",
146
+ "description": "实际分录关联成本中心",
147
+ },
148
+ {
149
+ "from_table": "budget_entry",
150
+ "to_table": "account_master",
151
+ "join_sql": "budget_entry.account_id = account_master.account_id",
152
+ "join_keys": [{"from": "account_id", "to": "account_id"}],
153
+ "relationship_type": "many_to_one",
154
+ "description": "预算关联会计科目",
155
+ },
156
+ {
157
+ "from_table": "budget_entry",
158
+ "to_table": "cost_center_dimension",
159
+ "join_sql": "budget_entry.cost_center_id = cost_center_dimension.cost_center_id",
160
+ "join_keys": [{"from": "cost_center_id", "to": "cost_center_id"}],
161
+ "relationship_type": "many_to_one",
162
+ "description": "预算关联成本中心",
163
+ },
164
+ {
165
+ "from_table": "account_master",
166
+ "to_table": "account_master",
167
+ "join_sql": "account_master.parent_account_id = account_master.account_id",
168
+ "join_keys": [{"from": "parent_account_id", "to": "account_id"}],
169
+ "relationship_type": "many_to_one",
170
+ "description": "科目上级(树形)",
171
+ },
172
+ {
173
+ "from_table": "budget_entry",
174
+ "to_table": "actual_journal_entry",
175
+ "join_sql": "budget_entry.account_id = actual_journal_entry.account_id AND budget_entry.cost_center_id = actual_journal_entry.cost_center_id AND budget_entry.fiscal_year = actual_journal_entry.fiscal_year AND budget_entry.fiscal_period = actual_journal_entry.fiscal_period",
176
+ "join_keys": [
177
+ {"from": "account_id", "to": "account_id"},
178
+ {"from": "cost_center_id", "to": "cost_center_id"},
179
+ {"from": "fiscal_year", "to": "fiscal_year"},
180
+ {"from": "fiscal_period", "to": "fiscal_period"},
181
+ ],
182
+ "relationship_type": "many_to_one",
183
+ "description": "预算与实际同维对齐",
184
+ },
185
+ ]
186
+ for rel in table_relationships:
187
+ rid = s.tables.add_relationship(**rel)
188
+ output.print(f"OK {rel['from_table']} -> {rel['to_table']} ({rid})")
189
+
190
+ # 4. 注册 Cube
191
+ output.print("\n[4/9] 注册 Cube...")
192
+
193
+ actual = "actual_journal_entry"
194
+ budget = "budget_entry"
195
+
196
+ s.register_cube(
197
+ name="ActualCube",
198
+ table=actual,
199
+ title="实际发生主Cube",
200
+ measures=[
201
+ {"name": "debit_total", "col": "debit_amount", "agg": "sum", "title": "借方合计"},
202
+ {"name": "credit_total", "col": "credit_amount", "agg": "sum", "title": "贷方合计"},
203
+ {"name": "net_amount", "col": "amount_signed", "agg": "sum", "title": "损益符号额"},
204
+ {"name": "line_count", "col": "line_id", "agg": "count", "title": "分录行数"},
205
+ ],
206
+ dimensions=[
207
+ {"name": "entry_id", "col": "entry_id", "type": "string", "title": "凭证ID"},
208
+ {"name": "line_id", "col": "line_id", "type": "string", "title": "行ID"},
209
+ {"name": "posting_date", "col": "posting_date", "type": "date", "title": "记账日期"},
210
+ {"name": "fiscal_year", "col": "fiscal_year", "type": "int", "title": "会计年度"},
211
+ {"name": "fiscal_period", "col": "fiscal_period", "type": "int", "title": "会计期间"},
212
+ {"name": "account_id", "col": "account_id", "type": "string", "title": "科目ID"},
213
+ {"name": "account_code", "col": "account_code", "type": "string", "title": "科目编码"},
214
+ {"name": "account_name", "col": "account_name", "type": "string", "title": "科目名称"},
215
+ {"name": "account_type", "col": "account_type", "type": "string", "title": "科目类型"},
216
+ {"name": "pl_category", "col": "pl_category", "type": "string", "title": "损益大类"},
217
+ {"name": "cost_center_id", "col": "cost_center_id", "type": "string", "title": "成本中心ID"},
218
+ {"name": "cost_center_name", "col": "cost_center_name", "type": "string", "title": "成本中心"},
219
+ {"name": "department", "col": "department", "type": "string", "title": "部门"},
220
+ {"name": "voucher_no", "col": "voucher_no", "type": "string", "title": "凭证号"},
221
+ ],
222
+ )
223
+ output.print("OK ActualCube")
224
+
225
+ s.register_cube(
226
+ name="AccountActualCube",
227
+ table=actual,
228
+ title="科目实际Cube",
229
+ measures=[
230
+ {"name": "net_amount", "col": "amount_signed", "agg": "sum", "title": "实际发生"},
231
+ {"name": "line_count", "col": "line_id", "agg": "count", "title": "分录行数"},
232
+ ],
233
+ dimensions=[
234
+ {"name": "account_id", "col": "account_id", "type": "string", "title": "科目ID"},
235
+ {"name": "account_code", "col": "account_code", "type": "string", "title": "科目编码"},
236
+ {"name": "account_name", "col": "account_name", "type": "string", "title": "科目名称"},
237
+ {"name": "account_type", "col": "account_type", "type": "string", "title": "科目类型"},
238
+ {"name": "pl_category", "col": "pl_category", "type": "string", "title": "损益大类"},
239
+ {"name": "account_level", "col": "account_level", "type": "int", "title": "科目层级"},
240
+ {"name": "fiscal_year", "col": "fiscal_year", "type": "int", "title": "会计年度"},
241
+ {"name": "fiscal_period", "col": "fiscal_period", "type": "int", "title": "会计期间"},
242
+ ],
243
+ )
244
+ output.print("OK AccountActualCube")
245
+
246
+ s.register_cube(
247
+ name="CostCenterActualCube",
248
+ table=actual,
249
+ title="成本中心实际Cube",
250
+ measures=[
251
+ {"name": "net_amount", "col": "amount_signed", "agg": "sum", "title": "实际发生"},
252
+ {"name": "line_count", "col": "line_id", "agg": "count", "title": "分录行数"},
253
+ ],
254
+ dimensions=[
255
+ {"name": "cost_center_id", "col": "cost_center_id", "type": "string", "title": "成本中心ID"},
256
+ {"name": "cost_center_name", "col": "cost_center_name", "type": "string", "title": "成本中心"},
257
+ {"name": "department", "col": "department", "type": "string", "title": "部门"},
258
+ {"name": "profit_center", "col": "profit_center", "type": "string", "title": "利润中心"},
259
+ {"name": "fiscal_year", "col": "fiscal_year", "type": "int", "title": "会计年度"},
260
+ {"name": "fiscal_period", "col": "fiscal_period", "type": "int", "title": "会计期间"},
261
+ ],
262
+ )
263
+ output.print("OK CostCenterActualCube")
264
+
265
+ s.register_cube(
266
+ name="BudgetCube",
267
+ table=budget,
268
+ title="预算Cube",
269
+ measures=[
270
+ {"name": "budget_amount", "col": "budget_amount", "agg": "sum", "title": "预算金额"},
271
+ {"name": "budget_lines", "col": "line_id", "agg": "count", "title": "预算行数"},
272
+ ],
273
+ dimensions=[
274
+ {"name": "line_id", "col": "line_id", "type": "string", "title": "预算行ID"},
275
+ {"name": "budget_version", "col": "budget_version", "type": "string", "title": "预算版本"},
276
+ {"name": "fiscal_year", "col": "fiscal_year", "type": "int", "title": "预算年度"},
277
+ {"name": "fiscal_period", "col": "fiscal_period", "type": "int", "title": "预算期间"},
278
+ {"name": "account_id", "col": "account_id", "type": "string", "title": "科目ID"},
279
+ {"name": "account_code", "col": "account_code", "type": "string", "title": "科目编码"},
280
+ {"name": "account_type", "col": "account_type", "type": "string", "title": "科目类型"},
281
+ {"name": "pl_category", "col": "pl_category", "type": "string", "title": "损益大类"},
282
+ {"name": "cost_center_id", "col": "cost_center_id", "type": "string", "title": "成本中心ID"},
283
+ {"name": "department", "col": "department", "type": "string", "title": "部门"},
284
+ ],
285
+ )
286
+ output.print("OK BudgetCube")
287
+
288
+ s.register_cube(
289
+ name="TimeActualCube",
290
+ table=actual,
291
+ title="时间维度实际Cube",
292
+ measures=[
293
+ {"name": "net_amount", "col": "amount_signed", "agg": "sum", "title": "损益符号额"},
294
+ {"name": "line_count", "col": "line_id", "agg": "count", "title": "分录行数"},
295
+ ],
296
+ dimensions=[
297
+ {"name": "posting_date", "col": "posting_date", "type": "date", "title": "记账日期"},
298
+ {"name": "fiscal_year", "col": "fiscal_year", "type": "int", "title": "会计年度"},
299
+ {"name": "fiscal_period", "col": "fiscal_period", "type": "int", "title": "会计期间"},
300
+ {"name": "year_month", "col": "posting_date", "type": "string", "title": "年月"},
301
+ {"name": "quarter", "col": "posting_date", "type": "string", "title": "季度"},
302
+ ],
303
+ )
304
+ output.print("OK TimeActualCube")
305
+
306
+ # 5. 派生度量
307
+ output.print("\n[5/9] 配置派生度量...")
308
+
309
+ def _pl_measures(cube_name, full=False):
310
+ base = [
311
+ {
312
+ "name": "revenue",
313
+ "title": "收入",
314
+ "expression": "sum(if(account_type='收入', amount_signed, 0))",
315
+ "description": "收入类科目发生额",
316
+ },
317
+ {
318
+ "name": "cost",
319
+ "title": "成本",
320
+ "expression": "sum(if(account_type='成本', amount_signed, 0))",
321
+ "description": "成本类科目发生额",
322
+ },
323
+ {
324
+ "name": "expense",
325
+ "title": "费用",
326
+ "expression": "sum(if(account_type='费用', amount_signed, 0))",
327
+ "description": "费用类科目发生额",
328
+ },
329
+ ]
330
+ if not full:
331
+ return base
332
+ return base + [
333
+ {
334
+ "name": "operating_profit",
335
+ "title": "营业利润",
336
+ "expression": f"{cube_name}.revenue - {cube_name}.cost - {cube_name}.expense",
337
+ "description": "收入-成本-费用",
338
+ },
339
+ {
340
+ "name": "profit_margin",
341
+ "title": "利润率",
342
+ "expression": f"if({cube_name}.revenue > 0, {cube_name}.operating_profit / {cube_name}.revenue, 0)",
343
+ "description": "营业利润/收入",
344
+ },
345
+ ]
346
+
347
+ s.upsert_derived_measures("ActualCube", _pl_measures("ActualCube", True))
348
+ s.upsert_derived_measures("AccountActualCube", _pl_measures("AccountActualCube", False))
349
+ s.upsert_derived_measures("CostCenterActualCube", _pl_measures("CostCenterActualCube", True))
350
+ s.upsert_derived_measures("TimeActualCube", _pl_measures("TimeActualCube", True))
351
+
352
+ s.upsert_derived_measures(
353
+ "BudgetCube",
354
+ [
355
+ {
356
+ "name": "budget_revenue",
357
+ "title": "预算收入",
358
+ "expression": "sum(if(account_type='收入', budget_amount, 0))",
359
+ "description": "预算收入",
360
+ },
361
+ {
362
+ "name": "budget_cost",
363
+ "title": "预算成本",
364
+ "expression": "sum(if(account_type='成本', budget_amount, 0))",
365
+ "description": "预算成本",
366
+ },
367
+ {
368
+ "name": "budget_expense",
369
+ "title": "预算费用",
370
+ "expression": "sum(if(account_type='费用', budget_amount, 0))",
371
+ "description": "预算费用",
372
+ },
373
+ ],
374
+ )
375
+ output.print("OK 派生度量")
376
+
377
+ # 6. 对象类型
378
+ output.print("\n[6/9] 定义对象类型...")
379
+
380
+ object_types = [
381
+ ("Account", "会计科目", "会计科目业务对象"),
382
+ ("CostCenter", "成本中心", "组织/利润中心业务对象"),
383
+ ("JournalEntry", "实际分录", "凭证行实际发生业务对象"),
384
+ ("BudgetLine", "预算行", "预算编制明细业务对象"),
385
+ ("ProfitAnalysis", "利润分析", "多维度损益指标聚合对象"),
386
+ ("BudgetAnalysis", "预算分析", "预算执行与差异分析对象"),
387
+ ]
388
+ for code, name, desc in object_types:
389
+ s.onto.define_object_type(code, name, description=desc)
390
+ output.print(f"OK {code}")
391
+
392
+ # 7. 绑定数据源
393
+ output.print("\n[7/9] 绑定数据源...")
394
+
395
+ bindings = [
396
+ ("Account", "AccountActualCube"),
397
+ ("CostCenter", "CostCenterActualCube"),
398
+ ("JournalEntry", "ActualCube"),
399
+ ("BudgetLine", "BudgetCube"),
400
+ ("ProfitAnalysis", "ActualCube"),
401
+ ("BudgetAnalysis", "BudgetCube"),
402
+ ]
403
+ for obj, cube in bindings:
404
+ s.onto.bind_source(obj, "dazi_cube", config={"cube": cube})
405
+ output.print(f"OK {obj} -> {cube}")
406
+
407
+ # 8. 属性
408
+ output.print("\n[8/9] 定义属性...")
409
+
410
+ def define_props(obj_code, props):
411
+ for code, name, role, qn in props:
412
+ s.onto.define_property(obj_code, code, name, semantic_role=role, qualified_name=qn)
413
+
414
+ define_props("Account", [
415
+ ("id", "科目ID", "dimension", "AccountActualCube.account_id"),
416
+ ("code", "科目编码", "dimension", "AccountActualCube.account_code"),
417
+ ("name", "科目名称", "dimension", "AccountActualCube.account_name"),
418
+ ("type", "科目类型", "dimension", "AccountActualCube.account_type"),
419
+ ("pl_category", "损益大类", "dimension", "AccountActualCube.pl_category"),
420
+ ("level", "科目层级", "dimension", "AccountActualCube.account_level"),
421
+ ("net_amount", "实际发生", "measure", "AccountActualCube.net_amount"),
422
+ ("revenue", "收入", "measure", "AccountActualCube.revenue"),
423
+ ("cost", "成本", "measure", "AccountActualCube.cost"),
424
+ ("expense", "费用", "measure", "AccountActualCube.expense"),
425
+ ])
426
+ output.print("OK Account 属性 (10)")
427
+
428
+ define_props("CostCenter", [
429
+ ("id", "成本中心ID", "dimension", "CostCenterActualCube.cost_center_id"),
430
+ ("name", "成本中心", "dimension", "CostCenterActualCube.cost_center_name"),
431
+ ("department", "部门", "dimension", "CostCenterActualCube.department"),
432
+ ("profit_center", "利润中心", "dimension", "CostCenterActualCube.profit_center"),
433
+ ("revenue", "收入", "measure", "CostCenterActualCube.revenue"),
434
+ ("cost", "成本", "measure", "CostCenterActualCube.cost"),
435
+ ("expense", "费用", "measure", "CostCenterActualCube.expense"),
436
+ ("operating_profit", "营业利润", "measure", "CostCenterActualCube.operating_profit"),
437
+ ])
438
+ output.print("OK CostCenter 属性 (8)")
439
+
440
+ define_props("JournalEntry", [
441
+ ("id", "行ID", "dimension", "ActualCube.line_id"),
442
+ ("posting_date", "记账日期", "dimension", "ActualCube.posting_date"),
443
+ ("fiscal_period", "会计期间", "dimension", "ActualCube.fiscal_period"),
444
+ ("net_amount", "损益金额", "measure", "ActualCube.net_amount"),
445
+ ("debit", "借方", "measure", "ActualCube.debit_total"),
446
+ ("credit", "贷方", "measure", "ActualCube.credit_total"),
447
+ ])
448
+ output.print("OK JournalEntry 属性 (6)")
449
+
450
+ define_props("BudgetLine", [
451
+ ("id", "预算行ID", "dimension", "BudgetCube.line_id"),
452
+ ("version", "预算版本", "dimension", "BudgetCube.budget_version"),
453
+ ("fiscal_period", "预算期间", "dimension", "BudgetCube.fiscal_period"),
454
+ ("budget_amount", "预算金额", "measure", "BudgetCube.budget_amount"),
455
+ ])
456
+ output.print("OK BudgetLine 属性 (4)")
457
+
458
+ define_props("ProfitAnalysis", [
459
+ ("date", "日期", "dimension", "ActualCube.posting_date"),
460
+ ("pl_category", "损益大类", "dimension", "ActualCube.pl_category"),
461
+ ("department", "部门", "dimension", "ActualCube.department"),
462
+ ("revenue", "收入", "measure", "ActualCube.revenue"),
463
+ ("cost", "成本", "measure", "ActualCube.cost"),
464
+ ("expense", "费用", "measure", "ActualCube.expense"),
465
+ ("operating_profit", "营业利润", "measure", "ActualCube.operating_profit"),
466
+ ("profit_margin", "利润率", "measure", "ActualCube.profit_margin"),
467
+ ])
468
+ output.print("OK ProfitAnalysis 属性 (8)")
469
+
470
+ define_props("BudgetAnalysis", [
471
+ ("version", "预算版本", "dimension", "BudgetCube.budget_version"),
472
+ ("fiscal_period", "预算期间", "dimension", "BudgetCube.fiscal_period"),
473
+ ("budget_amount", "预算金额", "measure", "BudgetCube.budget_amount"),
474
+ ("budget_revenue", "预算收入", "measure", "BudgetCube.budget_revenue"),
475
+ ("budget_cost", "预算成本", "measure", "BudgetCube.budget_cost"),
476
+ ("budget_expense", "预算费用", "measure", "BudgetCube.budget_expense"),
477
+ ])
478
+ output.print("OK BudgetAnalysis 属性 (6)")
479
+
480
+ # 9. 链接类型
481
+ output.print("\n[9/9] 定义链接与同步指标...")
482
+
483
+ link_types = [
484
+ ("entry_belongs_account", "分录归属科目", "JournalEntry", "Account", "分录行对应科目"),
485
+ ("entry_belongs_cost_center", "分录归属成本中心", "JournalEntry", "CostCenter", "分录行对应组织"),
486
+ ("budget_for_account", "预算对应科目", "BudgetLine", "Account", "预算行对应科目"),
487
+ ("budget_for_cost_center", "预算对应成本中心", "BudgetLine", "CostCenter", "预算行对应组织"),
488
+ ("account_has_parent", "科目上级", "Account", "Account", "科目树父级"),
489
+ ("budget_compared_to_actual", "预算对比实际", "BudgetAnalysis", "ProfitAnalysis", "预实差异分析"),
490
+ ("analysis_by_account", "分析归因科目", "ProfitAnalysis", "Account", "指标按科目切片"),
491
+ ("analysis_by_cost_center", "分析归因成本中心", "ProfitAnalysis", "CostCenter", "指标按组织切片"),
492
+ ("account_contributes_profit", "科目贡献利润", "Account", "ProfitAnalysis", "科目损益贡献"),
493
+ ("cost_center_contributes_profit", "组织贡献利润", "CostCenter", "ProfitAnalysis", "成本中心利润贡献"),
494
+ ]
495
+ for code, name, from_obj, to_obj, desc in link_types:
496
+ s.onto.define_link_type(
497
+ code=code,
498
+ name=name,
499
+ from_object_type_code=from_obj,
500
+ to_object_type_code=to_obj,
501
+ description=desc,
502
+ )
503
+ output.print(f"OK {code}")
504
+
505
+ s.sync_metric_refs()
506
+ output.print("OK sync_metric_refs")
507
+
508
+ summary = {
509
+ "ok": True,
510
+ "space_id": space_id,
511
+ "tables": 4,
512
+ "table_relationships": 6,
513
+ "cubes": 5,
514
+ "object_types": 6,
515
+ "properties": 42,
516
+ "link_types": 10,
517
+ }
518
+
519
+ output.print("\n=== 利润分析本体初始化完成 ===")
520
+ output.success("初始化成功")
521
+ output.print("__JSON_SUMMARY__" + json.dumps(summary, ensure_ascii=True, default=str))