@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.
- package/README.md +1 -1
- package/dist/clis/dazi-app.js +1 -1
- package/dist/clis/dazi-flow.js +1 -1
- package/dist/clis/dazi-onto.js +7 -2
- package/dist/clis/dazi.js +1 -1
- package/dist/docs/flow/flow-project-guide.md +1 -1
- package/dist/docs/guides/troubleshooting.md +12 -1
- package/dist/docs/index.json +21 -2
- package/dist/docs/onto/dazi_script_sdk_reference.md +246 -178
- package/dist/docs/onto/function-guide.md +123 -95
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- package/dist/examples/index.json +22 -16
- package/dist/examples/onto/README.md +13 -5
- package/dist/examples/onto/_templates/ontology_function_template.py +50 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_account_breakdown.py +62 -0
- 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
- 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
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_get_summary.py +61 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_mom_analysis.py +82 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_top_accounts.py +61 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/profit_fn_yoy_analysis.py +79 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/functions/save_test_arguments.ps1 +38 -0
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/setup/profit_category_mount.py +85 -0
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/setup/profit_ontology_init.py +169 -74
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/setup/profit_seed_data.py +16 -13
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_channel_mix.py +19 -16
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_customer_segmentation.py +48 -50
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_get_summary.py +3 -6
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_mom_analysis.py +11 -12
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_region_breakdown.py +6 -7
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_top_products.py +5 -8
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/sales_fn_yoy_analysis.py +3 -6
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/save_test_arguments.ps1 +32 -19
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/sales_category_mount.py +82 -0
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/sales_ontology_init.py +240 -155
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/sales_seed_data.py +59 -20
- package/dist/prompts/index.json +8 -1
- package/dist/prompts/onto/function-design.md +73 -53
- package/dist/prompts/onto/planning-design.md +104 -0
- package/dist/prompts/onto/script-publish-run.md +229 -194
- package/package.json +1 -1
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_account_breakdown.py +0 -99
- 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
- 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
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_get_summary.py +0 -76
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_mom_analysis.py +0 -86
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_top_accounts.py +0 -103
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/profit_fn_yoy_analysis.py +0 -86
- package/dist/examples/onto//345/210/251/346/266/246/347/244/272/344/276/213/function/save_test_arguments.ps1 +0 -27
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/functions/README.md +0 -25
- package/dist/examples/onto//351/224/200/345/224/256/347/244/272/344/276/213/setup/README.md +0 -5
package/dist/examples/index.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": "3.1.0",
|
|
3
|
-
"updatedAt": "2026-06-
|
|
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/利润示例/
|
|
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/利润示例/
|
|
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/利润示例/
|
|
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/利润示例/
|
|
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/利润示例/
|
|
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/利润示例/
|
|
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/利润示例/
|
|
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/利润示例/
|
|
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/利润示例/
|
|
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/利润示例/
|
|
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/利润示例/
|
|
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/利润示例/
|
|
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/利润示例/
|
|
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/利润示例/
|
|
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/利润示例/
|
|
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
|
-
| `
|
|
12
|
-
| `
|
|
13
|
-
| `
|
|
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/利润示例/
|
|
36
|
-
资源/examples/onto/利润示例/
|
|
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
|
+
|