@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,6 +1,6 @@
1
1
  {
2
2
  "version": "3.1.0",
3
- "updatedAt": "2026-06-06T12:00:00.000Z",
3
+ "updatedAt": "2026-06-05T18:00:00.000Z",
4
4
  "examples": [
5
5
  {
6
6
  "id": "onto/readme",
@@ -8,6 +8,12 @@
8
8
  "category": "onto",
9
9
  "file": "onto/README.md"
10
10
  },
11
+ {
12
+ "id": "onto/template/ontology-function",
13
+ "title": "本体函数脚本模板(标准 main + function_result)",
14
+ "category": "onto-模板",
15
+ "file": "onto/_templates/ontology_function_template.py"
16
+ },
11
17
  {
12
18
  "id": "onto/profit/setup/ontology-init",
13
19
  "title": "利润分析 · 本体初始化",
@@ -24,91 +30,91 @@
24
30
  "id": "onto/profit/function/get-summary",
25
31
  "title": "利润分析 · 利润总览",
26
32
  "category": "onto-利润-函数",
27
- "file": "onto/利润示例/function/profit_fn_get_summary.py"
33
+ "file": "onto/利润示例/functions/profit_fn_get_summary.py"
28
34
  },
29
35
  {
30
36
  "id": "onto/profit/function/yoy",
31
37
  "title": "利润分析 · 同比 (YoY)",
32
38
  "category": "onto-利润-函数",
33
- "file": "onto/利润示例/function/profit_fn_yoy_analysis.py"
39
+ "file": "onto/利润示例/functions/profit_fn_yoy_analysis.py"
34
40
  },
35
41
  {
36
42
  "id": "onto/profit/function/mom",
37
43
  "title": "利润分析 · 环比 (MoM)",
38
44
  "category": "onto-利润-函数",
39
- "file": "onto/利润示例/function/profit_fn_mom_analysis.py"
45
+ "file": "onto/利润示例/functions/profit_fn_mom_analysis.py"
40
46
  },
41
47
  {
42
48
  "id": "onto/profit/function/budget-vs-actual",
43
49
  "title": "利润分析 · 预实对比",
44
50
  "category": "onto-利润-函数",
45
- "file": "onto/利润示例/function/profit_fn_budget_vs_actual.py"
51
+ "file": "onto/利润示例/functions/profit_fn_budget_vs_actual.py"
46
52
  },
47
53
  {
48
54
  "id": "onto/profit/function/account-breakdown",
49
55
  "title": "利润分析 · 科目结构",
50
56
  "category": "onto-利润-函数",
51
- "file": "onto/利润示例/function/profit_fn_account_breakdown.py"
57
+ "file": "onto/利润示例/functions/profit_fn_account_breakdown.py"
52
58
  },
53
59
  {
54
60
  "id": "onto/profit/function/cost-center-profit",
55
61
  "title": "利润分析 · 组织利润",
56
62
  "category": "onto-利润-函数",
57
- "file": "onto/利润示例/function/profit_fn_cost_center_profit.py"
63
+ "file": "onto/利润示例/functions/profit_fn_cost_center_profit.py"
58
64
  },
59
65
  {
60
66
  "id": "onto/profit/function/top-accounts",
61
67
  "title": "利润分析 · 科目 Top N",
62
68
  "category": "onto-利润-函数",
63
- "file": "onto/利润示例/function/profit_fn_top_accounts.py"
69
+ "file": "onto/利润示例/functions/profit_fn_top_accounts.py"
64
70
  },
65
71
  {
66
72
  "id": "onto/profit/function/save-test-arguments",
67
73
  "title": "利润分析 · 批量保存 test_arguments",
68
74
  "category": "onto-利润-工具",
69
- "file": "onto/利润示例/function/save_test_arguments.ps1"
75
+ "file": "onto/利润示例/functions/save_test_arguments.ps1"
70
76
  },
71
77
  {
72
78
  "id": "onto/profit/test-args/get-summary",
73
79
  "title": "test_arguments · profit.fn.get_summary",
74
80
  "category": "onto-利润-测试参数",
75
- "file": "onto/利润示例/function/test_arguments/profit.fn.get_summary.json"
81
+ "file": "onto/利润示例/functions/test_arguments/profit.fn.get_summary.json"
76
82
  },
77
83
  {
78
84
  "id": "onto/profit/test-args/yoy",
79
85
  "title": "test_arguments · profit.fn.yoy_analysis",
80
86
  "category": "onto-利润-测试参数",
81
- "file": "onto/利润示例/function/test_arguments/profit.fn.yoy_analysis.json"
87
+ "file": "onto/利润示例/functions/test_arguments/profit.fn.yoy_analysis.json"
82
88
  },
83
89
  {
84
90
  "id": "onto/profit/test-args/mom",
85
91
  "title": "test_arguments · profit.fn.mom_analysis",
86
92
  "category": "onto-利润-测试参数",
87
- "file": "onto/利润示例/function/test_arguments/profit.fn.mom_analysis.json"
93
+ "file": "onto/利润示例/functions/test_arguments/profit.fn.mom_analysis.json"
88
94
  },
89
95
  {
90
96
  "id": "onto/profit/test-args/budget-vs-actual",
91
97
  "title": "test_arguments · profit.fn.budget_vs_actual",
92
98
  "category": "onto-利润-测试参数",
93
- "file": "onto/利润示例/function/test_arguments/profit.fn.budget_vs_actual.json"
99
+ "file": "onto/利润示例/functions/test_arguments/profit.fn.budget_vs_actual.json"
94
100
  },
95
101
  {
96
102
  "id": "onto/profit/test-args/account-breakdown",
97
103
  "title": "test_arguments · profit.fn.account_breakdown",
98
104
  "category": "onto-利润-测试参数",
99
- "file": "onto/利润示例/function/test_arguments/profit.fn.account_breakdown.json"
105
+ "file": "onto/利润示例/functions/test_arguments/profit.fn.account_breakdown.json"
100
106
  },
101
107
  {
102
108
  "id": "onto/profit/test-args/cost-center-profit",
103
109
  "title": "test_arguments · profit.fn.cost_center_profit",
104
110
  "category": "onto-利润-测试参数",
105
- "file": "onto/利润示例/function/test_arguments/profit.fn.cost_center_profit.json"
111
+ "file": "onto/利润示例/functions/test_arguments/profit.fn.cost_center_profit.json"
106
112
  },
107
113
  {
108
114
  "id": "onto/profit/test-args/top-accounts",
109
115
  "title": "test_arguments · profit.fn.top_accounts",
110
116
  "category": "onto-利润-测试参数",
111
- "file": "onto/利润示例/function/test_arguments/profit.fn.top_accounts.json"
117
+ "file": "onto/利润示例/functions/test_arguments/profit.fn.top_accounts.json"
112
118
  },
113
119
  {
114
120
  "id": "onto/sales/setup/ontology-init",
@@ -8,9 +8,9 @@
8
8
  |------|------|----------|
9
9
  | `setup/profit_ontology_init.py` | GL 域 init(科目/分录/预算表、Cube、对象、链接) | [规划示例_利润分析本体方案](../../docs/onto/规划示例_利润分析本体方案.md) |
10
10
  | `setup/profit_seed_data.py` | 演示灌数(科目树、成本中心、实际分录、预算) | 同上 |
11
- | `function/profit_fn_*.py` | 7 个 GL 分析函数(总览/同比/环比/预实/科目/组织/Top 科目) | 同上 |
12
- | `function/test_arguments/*.json` | 各 `profit.fn.*` 默认测试入参 | 规划 §6.5 |
13
- | `function/save_test_arguments.ps1` | 批量写入平台 `test_arguments` | 发布函数后执行 |
11
+ | `functions/profit_fn_*.py` | 7 个 GL 分析函数(总览/同比/环比/预实/科目/组织/Top 科目) | 同上 |
12
+ | `functions/test_arguments/*.json` | 各 `profit.fn.*` 默认测试入参 | 规划 §6.5 |
13
+ | `functions/save_test_arguments.ps1` | 批量写入平台 `test_arguments` | 发布函数后执行 |
14
14
 
15
15
  发布后须 **`function run` 验证** → **`save-test-arguments`** 写入默认测试入参(见规划 §6.5)。
16
16
 
@@ -28,12 +28,20 @@
28
28
 
29
29
  推荐空间:`space__zlj`(以你的实现单元 README 为准)。
30
30
 
31
+ ## 模板(`_templates/`)
32
+
33
+ | 路径 | 说明 |
34
+ |------|------|
35
+ | `_templates/ontology_function_template.py` | **新建本体函数时复制此文件**;`main()` → `return _ontology_fn_body(p)`,禁止 `output.print_json()` |
36
+
37
+ `dazi examples show onto/template/ontology-function`
38
+
31
39
  ## 复制示例
32
40
 
33
41
  ```text
34
42
  资源/examples/onto/利润示例/setup/*.py → 项目/<业务>/本体/ontos/<实现>/setup/
35
- 资源/examples/onto/利润示例/function/*.py → 项目/<业务>/本体/ontos/<实现>/functions/
36
- 资源/examples/onto/利润示例/function/test_arguments/ → .../functions/test_arguments/
43
+ 资源/examples/onto/利润示例/functions/*.py → 项目/<业务>/本体/ontos/<实现>/functions/
44
+ 资源/examples/onto/利润示例/functions/test_arguments/ → .../functions/test_arguments/
37
45
 
38
46
  资源/examples/onto/销售示例/setup/*.py → 项目/<业务>/本体/ontos/<实现>/setup/
39
47
  资源/examples/onto/销售示例/functions/*.py → 项目/<业务>/本体/ontos/<实现>/functions/
@@ -0,0 +1,50 @@
1
+ """本体函数模板 — 复制到 项目/<业务名>/本体/ontos/<实现名>/functions/ 后修改
2
+
3
+ function_id 示例:domain.fn.my_analysis
4
+ 发布:dazi onto script publish .../functions/my_fn_xxx.py --space <space-id> --register-function-id domain.fn.my_analysis
5
+
6
+ ★ 本体函数输出规范(勿改 main 结构):
7
+ - main() 无参;通过 ctx.space_id / ctx.params 读入参
8
+ - 业务逻辑写在 _ontology_fn_body(p)
9
+ - 返回 p.function_result(...) 或 return _ontology_fn_body(p)
10
+ - 禁止 output.print_json()(OutputModule 无此方法)
11
+ 参考:资源/examples/onto/销售示例/functions/sales_fn_get_summary.py
12
+ """
13
+
14
+ TEST_ARGUMENTS = {
15
+ "v": 1,
16
+ "arguments": {"start_date": "2025-01-01", "end_date": "2026-06-30"},
17
+ "object_type_code": "MyObjectTypeCode",
18
+ }
19
+
20
+
21
+ def _ontology_fn_body(p):
22
+ params = dict(p.get_params() or {})
23
+ # start_date = params.get("start_date", "")
24
+ # end_date = params.get("end_date", "")
25
+
26
+ # rows = p.sql.query("SELECT ...")
27
+ # row = rows[0] if rows else {}
28
+
29
+ data = [{"example_metric": 0}]
30
+
31
+ return p.function_result(
32
+ columns=["example_metric"],
33
+ data=data,
34
+ row_count=len(data),
35
+ )
36
+
37
+
38
+ def main():
39
+ s = space.get(ctx.space_id or "")
40
+ _Ports = type(
41
+ "_Ports",
42
+ (),
43
+ {
44
+ "get_params": lambda self: dict(ctx.params or {}),
45
+ "function_result": lambda self, **kw: onto.function_result(**kw),
46
+ },
47
+ )
48
+ p = _Ports()
49
+ p.sql = s.sql
50
+ return _ontology_fn_body(p)
@@ -0,0 +1,62 @@
1
+ """科目结构分析函数
2
+
3
+ 功能:按科目层级展开损益结构
4
+ 参数:start_date, end_date, account_level(可选,默认显示全部层级), pl_category(可选)
5
+
6
+ 放置:项目/DAZI_TEST/本体/ontos/利润分析示例/functions/profit_fn_account_breakdown.py
7
+ 发布:dazi onto script publish 项目/DAZI_TEST/本体/ontos/利润分析示例/functions/profit_fn_account_breakdown.py --space space__misc_01 --register-function-id profit.fn.account_breakdown
8
+ """
9
+
10
+ from datetime import datetime
11
+ import json
12
+
13
+
14
+ def _ontology_fn_body(p):
15
+ start_date = p.get("start_date", "2025-01-01")
16
+ end_date = p.get("end_date", datetime.now().strftime("%Y-%m-%d"))
17
+ account_level = int(p.get("account_level", 0))
18
+ pl_category = p.get("pl_category", None)
19
+
20
+ output.print(f"期间: {start_date} ~ {end_date}, 层级: {'全部' if account_level == 0 else account_level}")
21
+
22
+ level_cond = "" if account_level == 0 else f"AND account_level = {account_level}"
23
+ cat_cond = "" if not pl_category else f"AND pl_category = '{pl_category}'"
24
+
25
+ sql = f"""
26
+ SELECT
27
+ account_code,
28
+ account_name,
29
+ account_level,
30
+ pl_category,
31
+ account_type,
32
+ SUM(amount_signed) as net_impact
33
+ FROM fact_gl_journal_entry
34
+ WHERE posting_date >= '{start_date}' AND posting_date <= '{end_date}'
35
+ {level_cond}
36
+ {cat_cond}
37
+ GROUP BY account_code, account_name, account_level, pl_category, account_type
38
+ ORDER BY pl_category, account_level, account_code
39
+ """
40
+
41
+ rows = p.space.sql.query(sql)
42
+
43
+ total = sum(row.get("net_impact", 0) or 0 for row in rows)
44
+
45
+ result = []
46
+ for row in rows:
47
+ net_impact = row.get("net_impact", 0) or 0
48
+ share_pct = net_impact / total if total != 0 else 0
49
+
50
+ result.append({
51
+ "account_code": row.get("account_code"),
52
+ "account_name": row.get("account_name"),
53
+ "account_level": row.get("account_level"),
54
+ "pl_category": row.get("pl_category"),
55
+ "account_type": row.get("account_type"),
56
+ "net_impact": round(net_impact, 2),
57
+ "share_pct": round(share_pct, 4),
58
+ })
59
+
60
+ p.function_result(result)
61
+
62
+
@@ -0,0 +1,69 @@
1
+ """预算对比实际分析函数
2
+
3
+ 功能:按科目/成本中心对比预算与实际,输出差异与执行率
4
+ 参数:fiscal_year, fiscal_period(可选,0=全年), budget_version, cost_center_id(可选)
5
+
6
+ 放置:项目/DAZI_TEST/本体/ontos/利润分析示例/functions/profit_fn_budget_vs_actual.py
7
+ 发布:dazi onto script publish 项目/DAZI_TEST/本体/ontos/利润分析示例/functions/profit_fn_budget_vs_actual.py --space space__misc_01 --register-function-id profit.fn.budget_vs_actual
8
+ """
9
+
10
+ from datetime import datetime
11
+ import json
12
+
13
+
14
+ def _ontology_fn_body(p):
15
+ fiscal_year = int(p.get("fiscal_year", datetime.now().year))
16
+ fiscal_period = int(p.get("fiscal_period", 0))
17
+ budget_version = p.get("budget_version", "2026年度预算")
18
+ cost_center_id = p.get("cost_center_id", None)
19
+
20
+ output.print(f"预算年度: {fiscal_year}, 期间: {'全年' if fiscal_period == 0 else fiscal_period}月, 版本: {budget_version}")
21
+
22
+ period_cond = "" if fiscal_period == 0 else f"AND be.fiscal_period = {fiscal_period}"
23
+ cc_cond = "" if not cost_center_id else f"AND be.cost_center_id = '{cost_center_id}'"
24
+
25
+ sql = f"""
26
+ SELECT
27
+ be.account_code,
28
+ be.account_name,
29
+ be.pl_category,
30
+ be.cost_center_name,
31
+ SUM(be.budget_amount) as budget_amount,
32
+ COALESCE(SUM(fe.amount_signed), 0) as actual_amount
33
+ FROM fact_budget_entry be
34
+ LEFT JOIN fact_gl_journal_entry fe
35
+ ON be.account_id = fe.account_id
36
+ AND be.cost_center_id = fe.cost_center_id
37
+ AND be.fiscal_year = fe.fiscal_year
38
+ AND be.fiscal_period = fe.fiscal_period
39
+ WHERE be.fiscal_year = {fiscal_year}
40
+ AND be.budget_version = '{budget_version}'
41
+ {period_cond}
42
+ {cc_cond}
43
+ GROUP BY be.account_code, be.account_name, be.pl_category, be.cost_center_name
44
+ ORDER BY be.pl_category, be.account_code
45
+ """
46
+
47
+ rows = p.space.sql.query(sql)
48
+
49
+ result = []
50
+ for row in rows:
51
+ budget = row.get("budget_amount", 0) or 0
52
+ actual = row.get("actual_amount", 0) or 0
53
+ variance = actual - budget
54
+ execution_rate = actual / budget if budget != 0 else 0
55
+
56
+ result.append({
57
+ "account_code": row.get("account_code"),
58
+ "account_name": row.get("account_name"),
59
+ "pl_category": row.get("pl_category"),
60
+ "cost_center_name": row.get("cost_center_name"),
61
+ "budget_amount": round(budget, 2),
62
+ "actual_amount": round(actual, 2),
63
+ "variance": round(variance, 2),
64
+ "execution_rate": round(execution_rate, 4),
65
+ })
66
+
67
+ p.function_result(result)
68
+
69
+
@@ -0,0 +1,64 @@
1
+ """成本中心利润分析函数
2
+
3
+ 功能:按成本中心/部门分析利润贡献
4
+ 参数:start_date, end_date, department(可选)
5
+
6
+ 放置:项目/DAZI_TEST/本体/ontos/利润分析示例/functions/profit_fn_cost_center_profit.py
7
+ 发布:dazi onto script publish 项目/DAZI_TEST/本体/ontos/利润分析示例/functions/profit_fn_cost_center_profit.py --space space__misc_01 --register-function-id profit.fn.cost_center_profit
8
+ """
9
+
10
+ from datetime import datetime
11
+ import json
12
+
13
+
14
+ def _ontology_fn_body(p):
15
+ start_date = p.get("start_date", "2025-01-01")
16
+ end_date = p.get("end_date", datetime.now().strftime("%Y-%m-%d"))
17
+ department = p.get("department", None)
18
+
19
+ output.print(f"期间: {start_date} ~ {end_date}, 部门: {'全部' if not department else department}")
20
+
21
+ dept_cond = "" if not department else f"AND department = '{department}'"
22
+
23
+ sql = f"""
24
+ SELECT
25
+ cost_center_id,
26
+ cost_center_name,
27
+ department,
28
+ profit_center,
29
+ SUM(amount_signed) as total_amount,
30
+ SUM(if(account_type='收入', amount_signed, 0)) as revenue,
31
+ SUM(if(account_type='成本', amount_signed, 0)) as cost,
32
+ SUM(if(account_type='费用', amount_signed, 0)) as expense
33
+ FROM fact_gl_journal_entry
34
+ WHERE posting_date >= '{start_date}' AND posting_date <= '{end_date}'
35
+ {dept_cond}
36
+ GROUP BY cost_center_id, cost_center_name, department, profit_center
37
+ ORDER BY department, cost_center_name
38
+ """
39
+
40
+ rows = p.space.sql.query(sql)
41
+
42
+ result = []
43
+ for row in rows:
44
+ revenue = row.get("revenue", 0) or 0
45
+ cost = row.get("cost", 0) or 0
46
+ expense = row.get("expense", 0) or 0
47
+ operating_profit = revenue - cost - expense
48
+ profit_margin = operating_profit / revenue if revenue > 0 else 0
49
+
50
+ result.append({
51
+ "cost_center_id": row.get("cost_center_id"),
52
+ "cost_center_name": row.get("cost_center_name"),
53
+ "department": row.get("department"),
54
+ "profit_center": row.get("profit_center"),
55
+ "revenue": round(revenue, 2),
56
+ "cost": round(cost, 2),
57
+ "expense": round(expense, 2),
58
+ "operating_profit": round(operating_profit, 2),
59
+ "profit_margin": round(profit_margin, 4),
60
+ })
61
+
62
+ p.function_result(result)
63
+
64
+
@@ -0,0 +1,61 @@
1
+ """利润总览函数
2
+
3
+ 功能:获取指定期间的损益汇总数据
4
+ 参数:start_date, end_date(可选,默认2025-01-01至当前)
5
+
6
+ 放置:项目/DAZI_TEST/本体/ontos/利润分析示例/functions/profit_fn_get_summary.py
7
+ 发布:dazi onto script publish 项目/DAZI_TEST/本体/ontos/利润分析示例/functions/profit_fn_get_summary.py --space space__misc_01 --register-function-id profit.fn.get_summary
8
+ """
9
+
10
+ from datetime import datetime
11
+ import json
12
+
13
+
14
+ def _ontology_fn_body(p):
15
+ start_date = p.get("start_date", "2025-01-01")
16
+ end_date = p.get("end_date", datetime.now().strftime("%Y-%m-%d"))
17
+
18
+ output.print(f"查询期间: {start_date} ~ {end_date}")
19
+
20
+ sql = """
21
+ SELECT
22
+ sumIf(amount_signed, account_type='收入') as total_revenue,
23
+ sumIf(amount_signed, account_type='成本') as total_cost,
24
+ sumIf(amount_signed, account_type='费用') as total_expense,
25
+ count(*) as line_count
26
+ FROM fact_gl_journal_entry
27
+ WHERE posting_date >= '{start_date}' AND posting_date <= '{end_date}'
28
+ """.format(start_date=start_date, end_date=end_date)
29
+
30
+ result = p.space.sql.query_one(sql)
31
+
32
+ if result:
33
+ total_revenue = result.get("total_revenue", 0) or 0
34
+ total_cost = result.get("total_cost", 0) or 0
35
+ total_expense = result.get("total_expense", 0) or 0
36
+ line_count = result.get("line_count", 0) or 0
37
+
38
+ operating_profit = total_revenue - total_cost - total_expense
39
+ profit_margin = operating_profit / total_revenue if total_revenue > 0 else 0
40
+
41
+ p.function_result({
42
+ "total_revenue": round(total_revenue, 2),
43
+ "total_cost": round(total_cost, 2),
44
+ "total_expense": round(total_expense, 2),
45
+ "operating_profit": round(operating_profit, 2),
46
+ "profit_margin": round(profit_margin, 4),
47
+ "line_count": line_count,
48
+ "period": f"{start_date} ~ {end_date}",
49
+ })
50
+ else:
51
+ p.function_result({
52
+ "total_revenue": 0,
53
+ "total_cost": 0,
54
+ "total_expense": 0,
55
+ "operating_profit": 0,
56
+ "profit_margin": 0,
57
+ "line_count": 0,
58
+ "period": f"{start_date} ~ {end_date}",
59
+ })
60
+
61
+
@@ -0,0 +1,82 @@
1
+ """环比分析函数
2
+
3
+ 功能:对比当期与上一期的利润指标变化
4
+ 参数:start_date, end_date
5
+
6
+ 放置:项目/DAZI_TEST/本体/ontos/利润分析示例/functions/profit_fn_mom_analysis.py
7
+ 发布:dazi onto script publish 项目/DAZI_TEST/本体/ontos/利润分析示例/functions/profit_fn_mom_analysis.py --space space__misc_01 --register-function-id profit.fn.mom_analysis
8
+ """
9
+
10
+ from datetime import datetime, timedelta
11
+ import calendar
12
+ import json
13
+
14
+
15
+ def _ontology_fn_body(p):
16
+ start_date = p.get("start_date", "2025-01-01")
17
+ end_date = p.get("end_date", datetime.now().strftime("%Y-%m-%d"))
18
+
19
+ start_dt = datetime.strptime(start_date, "%Y-%m-%d")
20
+ end_dt = datetime.strptime(end_date, "%Y-%m-%d")
21
+
22
+ days_diff = (end_dt - start_dt).days
23
+
24
+ prev_start = (start_dt - timedelta(days=days_diff)).strftime("%Y-%m-%d")
25
+ prev_end = (end_dt - timedelta(days=days_diff)).strftime("%Y-%m-%d")
26
+
27
+ output.print(f"当期: {start_date} ~ {end_date}")
28
+ output.print(f"上期: {prev_start} ~ {prev_end}")
29
+
30
+ def get_period_data(sd, ed):
31
+ sql = """
32
+ SELECT
33
+ sumIf(amount_signed, account_type='收入') as revenue,
34
+ sumIf(amount_signed, account_type='成本') as cost,
35
+ sumIf(amount_signed, account_type='费用') as expense
36
+ FROM fact_gl_journal_entry
37
+ WHERE posting_date >= '{sd}' AND posting_date <= '{ed}'
38
+ """.format(sd=sd, ed=ed)
39
+ result = p.space.sql.query_one(sql)
40
+ return {
41
+ "revenue": result.get("revenue", 0) or 0,
42
+ "cost": result.get("cost", 0) or 0,
43
+ "expense": result.get("expense", 0) or 0,
44
+ }
45
+
46
+ current = get_period_data(start_date, end_date)
47
+ previous = get_period_data(prev_start, prev_end)
48
+
49
+ current_profit = current["revenue"] - current["cost"] - current["expense"]
50
+ previous_profit = previous["revenue"] - previous["cost"] - previous["expense"]
51
+
52
+ def calc_mom(current, prev):
53
+ if prev == 0:
54
+ return 0 if current == 0 else None
55
+ return (current - prev) / prev
56
+
57
+ result = {
58
+ "period": f"{start_date} ~ {end_date}",
59
+ "previous_period": f"{prev_start} ~ {prev_end}",
60
+ "current": {
61
+ "revenue": round(current["revenue"], 2),
62
+ "cost": round(current["cost"], 2),
63
+ "expense": round(current["expense"], 2),
64
+ "operating_profit": round(current_profit, 2),
65
+ },
66
+ "previous": {
67
+ "revenue": round(previous["revenue"], 2),
68
+ "cost": round(previous["cost"], 2),
69
+ "expense": round(previous["expense"], 2),
70
+ "operating_profit": round(previous_profit, 2),
71
+ },
72
+ "mom": {
73
+ "revenue": round(calc_mom(current["revenue"], previous["revenue"]), 4) if calc_mom(current["revenue"], previous["revenue"]) is not None else None,
74
+ "cost": round(calc_mom(current["cost"], previous["cost"]), 4) if calc_mom(current["cost"], previous["cost"]) is not None else None,
75
+ "expense": round(calc_mom(current["expense"], previous["expense"]), 4) if calc_mom(current["expense"], previous["expense"]) is not None else None,
76
+ "operating_profit": round(calc_mom(current_profit, previous_profit), 4) if calc_mom(current_profit, previous_profit) is not None else None,
77
+ },
78
+ }
79
+
80
+ p.function_result(result)
81
+
82
+
@@ -0,0 +1,61 @@
1
+ """科目Top N分析函数
2
+
3
+ 功能:获取损益影响最大的前N个科目
4
+ 参数:limit(默认10), metric(net_impact/revenue/cost/expense), start_date, end_date, account_type(可选)
5
+
6
+ 放置:项目/DAZI_TEST/本体/ontos/利润分析示例/functions/profit_fn_top_accounts.py
7
+ 发布:dazi onto script publish 项目/DAZI_TEST/本体/ontos/利润分析示例/functions/profit_fn_top_accounts.py --space space__misc_01 --register-function-id profit.fn.top_accounts
8
+ """
9
+
10
+ from datetime import datetime
11
+ import json
12
+
13
+
14
+ def _ontology_fn_body(p):
15
+ limit = int(p.get("limit", 10))
16
+ metric = p.get("metric", "net_impact")
17
+ start_date = p.get("start_date", "2025-01-01")
18
+ end_date = p.get("end_date", datetime.now().strftime("%Y-%m-%d"))
19
+ account_type = p.get("account_type", None)
20
+
21
+ output.print(f"期间: {start_date} ~ {end_date}, 取前{limit}个, 指标: {metric}")
22
+
23
+ type_cond = "" if not account_type else f"AND account_type = '{account_type}'"
24
+
25
+ metric_expr = {
26
+ "net_impact": "SUM(amount_signed)",
27
+ "revenue": "SUM(if(account_type='收入', amount_signed, 0))",
28
+ "cost": "SUM(if(account_type='成本', amount_signed, 0))",
29
+ "expense": "SUM(if(account_type='费用', amount_signed, 0))",
30
+ }.get(metric, "SUM(amount_signed)")
31
+
32
+ sql = f"""
33
+ SELECT
34
+ account_code,
35
+ account_name,
36
+ account_type,
37
+ pl_category,
38
+ {metric_expr} as metric_value
39
+ FROM fact_gl_journal_entry
40
+ WHERE posting_date >= '{start_date}' AND posting_date <= '{end_date}'
41
+ {type_cond}
42
+ GROUP BY account_code, account_name, account_type, pl_category
43
+ ORDER BY metric_value DESC
44
+ LIMIT {limit}
45
+ """
46
+
47
+ rows = p.space.sql.query(sql)
48
+
49
+ result = []
50
+ for row in rows:
51
+ result.append({
52
+ "account_code": row.get("account_code"),
53
+ "account_name": row.get("account_name"),
54
+ "account_type": row.get("account_type"),
55
+ "pl_category": row.get("pl_category"),
56
+ "metric_value": round(row.get("metric_value", 0) or 0, 2),
57
+ })
58
+
59
+ p.function_result(result)
60
+
61
+