sapbuddy-dsh 0.0.6 → 0.0.7
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/LICENSE +21 -21
- package/README.md +12 -4
- package/defaults/AGENTS.md +114 -114
- package/defaults/connections.example.json +21 -21
- package/defaults/prompts/Memory.md +21 -21
- package/defaults/prompts/SYSTEM.md +110 -110
- package/defaults/settings.example.json +3 -3
- package/dist/sap-tools/adtManager.d.ts +11 -1
- package/dist/sap-tools/adtManager.js +176 -9
- package/dist/sap-tools/connections-store.js +4 -1
- package/dist/sap-tools/execution.js +1 -1
- package/dist/tools.js +5 -3
- package/package.json +5 -3
- package/skills/abap-code-review/SKILL.md +75 -75
- package/skills/abap-code-review/assets/report-template.html +142 -142
- package/skills/abap-code-review/references/checklist.md +114 -114
- package/skills/abap-explain/SKILL.md +126 -126
- package/skills/abap-templates/SKILL.md +764 -764
- package/skills/abap-wiki/SKILL.md +104 -104
- package/skills/clean-abap/SKILL.md +91 -91
- package/skills/clean-abap/references/CleanABAP_zh.md +4309 -4309
- package/skills/dev-write/SKILL.md +137 -137
- package/skills/sap-abap-skills/README.md +205 -205
- package/skills/sap-abap-skills/SKILL.md +498 -498
- package/skills/sap-abap-skills/references/abap-dictionary.md +211 -211
- package/skills/sap-abap-skills/references/abap-sql.md +588 -588
- package/skills/sap-abap-skills/references/amdp.md +279 -279
- package/skills/sap-abap-skills/references/authorization.md +149 -149
- package/skills/sap-abap-skills/references/bits-bytes.md +92 -92
- package/skills/sap-abap-skills/references/builtin-functions.md +373 -373
- package/skills/sap-abap-skills/references/cds-views.md +412 -412
- package/skills/sap-abap-skills/references/cloud-development.md +299 -299
- package/skills/sap-abap-skills/references/constructor-expressions.md +458 -458
- package/skills/sap-abap-skills/references/date-time.md +415 -415
- package/skills/sap-abap-skills/references/design-patterns.md +292 -292
- package/skills/sap-abap-skills/references/dynamic-programming.md +426 -426
- package/skills/sap-abap-skills/references/exceptions.md +432 -432
- package/skills/sap-abap-skills/references/generative-ai.md +180 -180
- package/skills/sap-abap-skills/references/internal-tables.md +578 -578
- package/skills/sap-abap-skills/references/numeric-operations.md +219 -219
- package/skills/sap-abap-skills/references/object-orientation.md +518 -518
- package/skills/sap-abap-skills/references/performance.md +428 -428
- package/skills/sap-abap-skills/references/program-flow.md +302 -302
- package/skills/sap-abap-skills/references/rap-eml.md +549 -549
- package/skills/sap-abap-skills/references/released-classes.md +308 -308
- package/skills/sap-abap-skills/references/sap-luw.md +203 -203
- package/skills/sap-abap-skills/references/skill-reference-guide.md +98 -98
- package/skills/sap-abap-skills/references/sql-hierarchies.md +180 -180
- package/skills/sap-abap-skills/references/string-processing.md +488 -488
- package/skills/sap-abap-skills/references/table-grouping.md +150 -150
- package/skills/sap-abap-skills/references/tool-guide.md +285 -285
- package/skills/sap-abap-skills/references/unit-testing.md +512 -512
- package/skills/sap-abap-skills/references/where-conditions.md +223 -223
- package/skills/sap-abap-skills/references/xml-json.md +315 -315
- package/skills/translate-workflow/SKILL.md +69 -69
|
@@ -1,764 +1,764 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: abap-templates
|
|
3
|
-
description: >-
|
|
4
|
-
ABAP 开发模板库——报表(Report)与函数模块(Function Module)的具体代码模板:
|
|
5
|
-
ALV 输出(cl_salv_table / cl_gui_alv_grid / REUSE_ALV / 层次 ALV)、选择屏幕、
|
|
6
|
-
数据查询最佳实践、导出导入、函数组结构、接口参数写法、异常处理模式、BAPI 选型、单元测试。
|
|
7
|
-
触发场景:编写或修改 ABAP 报表/函数模块代码,需要具体语法模板时。
|
|
8
|
-
规范(命名/字段类型/消息类等)以 dev-write 技能(默认 SAP 官方 Clean ABAP)为唯一权威,本文件只提供写法参考。
|
|
9
|
-
category: software-development
|
|
10
|
-
agent_created: true
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
# ABAP 开发模板库(报表 + 函数模块)
|
|
14
|
-
|
|
15
|
-
> 命名与编码规则、字段类型、消息类等一律以 `dev-write` 技能为唯一权威;本文件只提供具体代码模板与写法参考。
|
|
16
|
-
|
|
17
|
-
# 一、ABAP 报表(Report)
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
name: abap-report
|
|
21
|
-
description: ABAP 报表(Report)开发参考——ALV 输出、选择屏幕、数据查询最佳实践、导入导出。触发场景:编写或修改 ABAP 报表程序代码,需要代码模板、选择屏幕写法、查询写法、ALV 用法时。
|
|
22
|
-
category: software-development
|
|
23
|
-
agent_created: true
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
# ABAP 报表开发参考
|
|
27
|
-
|
|
28
|
-
> 命名与编码规则以 `dev-write` 技能(默认 SAP 官方 Clean ABAP)为唯一权威;本文件只提供代码模板与写法参考。
|
|
29
|
-
|
|
30
|
-
## 报表类型
|
|
31
|
-
|
|
32
|
-
### 1. cl_salv_table(首选,SapBuddy 标准,符合 Clean ABAP OO 优先)
|
|
33
|
-
|
|
34
|
-
```abap
|
|
35
|
-
TRY.
|
|
36
|
-
cl_salv_table=>factory(
|
|
37
|
-
IMPORTING r_salv_table = DATA(lo_salv)
|
|
38
|
-
CHANGING t_table = lt_data ).
|
|
39
|
-
|
|
40
|
-
lo_salv->get_functions( )->set_all( abap_true ).
|
|
41
|
-
lo_salv->get_columns( )->set_optimize( abap_true ).
|
|
42
|
-
lo_salv->display( ).
|
|
43
|
-
|
|
44
|
-
CATCH cx_salv_msg INTO DATA(lx_msg).
|
|
45
|
-
MESSAGE lx_msg->get_text( ) TYPE 'E'.
|
|
46
|
-
ENDTRY.
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
> Clean ABAP 推荐面向对象 API;`cl_salv_table` 代码最简、无布局对象,适合多数报表。
|
|
50
|
-
> 需要行高亮/编辑/事件等高级交互时用 `cl_gui_alv_grid`(备选)。
|
|
51
|
-
|
|
52
|
-
### 2. CL_GUI_ALV_GRID(备选,需要交互/事件场景)
|
|
53
|
-
|
|
54
|
-
```abap
|
|
55
|
-
DATA: lo_alv TYPE REF TO cl_gui_alv_grid,
|
|
56
|
-
lo_container TYPE REF TO cl_gui_custom_container.
|
|
57
|
-
|
|
58
|
-
CREATE OBJECT lo_container
|
|
59
|
-
EXPORTING container_name = 'ALV_CONTAINER'.
|
|
60
|
-
|
|
61
|
-
CREATE OBJECT lo_alv
|
|
62
|
-
EXPORTING i_parent = lo_container.
|
|
63
|
-
|
|
64
|
-
lo_alv->set_table_for_first_display(
|
|
65
|
-
EXPORTING is_layout = ls_layout
|
|
66
|
-
CHANGING it_outtab = lt_data
|
|
67
|
-
it_fieldcatalog = lt_fieldcat ).
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### 3. REUSE_ALV_GRID_DISPLAY_LVC(兼容备选:遗留系统/存量代码风格)
|
|
71
|
-
|
|
72
|
-
> 仅当目标系统版本旧或存量代码已用此风格时采用;新代码优先前两种 OO 方案。
|
|
73
|
-
> 注:`lt_`/`ls_` 前缀仅限 ALV 字段目录/输出内表等业界通行场景(本技能模板沿用),普通变量遵循 Clean ABAP 无前缀。
|
|
74
|
-
|
|
75
|
-
```abap
|
|
76
|
-
DATA: lt_fieldcat TYPE lvc_t_fcat,
|
|
77
|
-
ls_fieldcat TYPE lvc_s_fcat,
|
|
78
|
-
ls_layout TYPE lvc_s_layo.
|
|
79
|
-
|
|
80
|
-
" 字段目录必须显式逐字段定义,禁止用 FORM 或宏自动生成
|
|
81
|
-
CLEAR ls_fieldcat.
|
|
82
|
-
ls_fieldcat-fieldname = 'VBELN'.
|
|
83
|
-
ls_fieldcat-coltext = TEXT-001. " 列文本在文本池维护(TEXT-001),禁止硬编码中文
|
|
84
|
-
APPEND ls_fieldcat TO lt_fieldcat.
|
|
85
|
-
|
|
86
|
-
CLEAR ls_fieldcat.
|
|
87
|
-
ls_fieldcat-fieldname = 'NETWR'.
|
|
88
|
-
ls_fieldcat-coltext = TEXT-002. " 列文本在文本池维护(TEXT-002),禁止硬编码中文
|
|
89
|
-
ls_fieldcat-no_zero = abap_true.
|
|
90
|
-
APPEND ls_fieldcat TO lt_fieldcat.
|
|
91
|
-
|
|
92
|
-
ls_layout-zebra = abap_true.
|
|
93
|
-
ls_layout-cwidth_opt = abap_true.
|
|
94
|
-
|
|
95
|
-
CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY_LVC'
|
|
96
|
-
EXPORTING
|
|
97
|
-
i_callback_program = sy-repid
|
|
98
|
-
is_layout_lvc = ls_layout
|
|
99
|
-
it_fieldcat_lvc = lt_fieldcat
|
|
100
|
-
TABLES
|
|
101
|
-
t_outtab = lt_data
|
|
102
|
-
EXCEPTIONS
|
|
103
|
-
program_error = 1
|
|
104
|
-
OTHERS = 2.
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### 4. 层次 ALV(备选,抬头-行项目双层展示)
|
|
108
|
-
|
|
109
|
-
```abap
|
|
110
|
-
cl_salv_hierseq_table=>factory(
|
|
111
|
-
IMPORTING r_salv_hierseq = DATA(lo_hier)
|
|
112
|
-
CHANGING t_table1 = lt_header
|
|
113
|
-
t_table2 = item_data ).
|
|
114
|
-
|
|
115
|
-
lo_lo_hier->display( ).
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
## 选择屏幕
|
|
119
|
-
|
|
120
|
-
### 常用元素
|
|
121
|
-
|
|
122
|
-
```abap
|
|
123
|
-
" 单值输入(必填)
|
|
124
|
-
PARAMETERS: p_vkorg TYPE vbak-vkorg OBLIGATORY.
|
|
125
|
-
|
|
126
|
-
" 多值区间
|
|
127
|
-
SELECT-OPTIONS: s_vbeln FOR vbak-vbeln,
|
|
128
|
-
s_erdat FOR vbak-erdat.
|
|
129
|
-
|
|
130
|
-
" 复选框
|
|
131
|
-
PARAMETERS: p_detail AS CHECKBOX DEFAULT 'X'.
|
|
132
|
-
|
|
133
|
-
" 单选按钮
|
|
134
|
-
PARAMETERS: p_alv RADIOBUTTON GROUP g1 DEFAULT 'X',
|
|
135
|
-
p_list RADIOBUTTON GROUP g1.
|
|
136
|
-
|
|
137
|
-
" 下拉列表(状态/选项:可用 xfeld 等标准数据元素,也允许 TYPE char1)
|
|
138
|
-
PARAMETERS: p_type TYPE xfeld AS LISTBOX VISIBLE LENGTH 20.
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
### 块与文本元素
|
|
142
|
-
|
|
143
|
-
```abap
|
|
144
|
-
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001.
|
|
145
|
-
SELECT-OPTIONS: s_bukrs FOR bkpf-bukrs OBLIGATORY,
|
|
146
|
-
s_gjahr FOR bkpf-gjahr OBLIGATORY.
|
|
147
|
-
SELECTION-SCREEN END OF BLOCK b1.
|
|
148
|
-
```
|
|
149
|
-
块标题和选择项文本必须用文本元素(TEXT-001),禁止硬编码。
|
|
150
|
-
|
|
151
|
-
> **禁止硬编码中文(强制)**:所有用户可见文案(提示/错误/说明)禁止直接写在代码里:
|
|
152
|
-
> - MESSAGE 语句 → 消息类(`MESSAGE e001(zxxx) WITH ...`,消息类用 `manage_transport_requests` 查/建或 MSAG/N 创建)
|
|
153
|
-
> - ALV 列文本/标题/选择文本 → 文本元素(`TEXT-xxx`,`manage_text_elements` 维护)
|
|
154
|
-
> - 屏幕块标题 → 文本元素;仅技术注释可用中文。
|
|
155
|
-
|
|
156
|
-
### 屏幕事件
|
|
157
|
-
|
|
158
|
-
```abap
|
|
159
|
-
AT SELECTION-SCREEN OUTPUT.
|
|
160
|
-
" 默认值:最近 30 天
|
|
161
|
-
s_erdat-low = sy-datum - 30.
|
|
162
|
-
s_erdat-high = sy-datum.
|
|
163
|
-
APPEND s_erdat.
|
|
164
|
-
|
|
165
|
-
AT SELECTION-SCREEN.
|
|
166
|
-
" 输入校验,输出合适的错误消息
|
|
167
|
-
IF s_bukrs IS INITIAL.
|
|
168
|
-
" 消息文案在消息类 ZFI 的 e001 中维护(禁止 WITH 传中文文案)
|
|
169
|
-
MESSAGE e001(zfi).
|
|
170
|
-
ENDIF.
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
## 数据查询最佳实践
|
|
174
|
-
|
|
175
|
-
### 标准 JOIN 查询(最多 3 张表)
|
|
176
|
-
|
|
177
|
-
```abap
|
|
178
|
-
SELECT v~vbeln, v~erdat, v~vkorg, v~kunnr,
|
|
179
|
-
p~posnr, p~matnr, p~kwmeng, p~netwr,
|
|
180
|
-
k~name1 AS customer_name,
|
|
181
|
-
m~maktx AS material_desc
|
|
182
|
-
FROM vbak AS v
|
|
183
|
-
INNER JOIN vbap AS p ON v~vbeln = p~vbeln
|
|
184
|
-
LEFT JOIN kna1 AS k ON v~kunnr = k~kunnr
|
|
185
|
-
LEFT JOIN makt AS m ON p~matnr = m~matnr AND m~spras = @sy-langu
|
|
186
|
-
INTO TABLE @DATA(lt_result)
|
|
187
|
-
WHERE v~vbeln IN @s_vbeln
|
|
188
|
-
AND v~erdat IN @s_erdat
|
|
189
|
-
AND v~vkorg IN @s_vkorg
|
|
190
|
-
ORDER BY v~vbeln, p~posnr.
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
### FOR ALL ENTRIES(必须先检非空)
|
|
194
|
-
|
|
195
|
-
```abap
|
|
196
|
-
" 先取主表
|
|
197
|
-
SELECT vbeln, erdat, vkorg FROM vbak
|
|
198
|
-
INTO TABLE @DATA(lt_vbak)
|
|
199
|
-
WHERE vkorg IN @s_vkorg
|
|
200
|
-
AND erdat IN @s_erdat.
|
|
201
|
-
|
|
202
|
-
" 再取明细
|
|
203
|
-
IF lt_vbak IS NOT INITIAL.
|
|
204
|
-
SELECT vbeln, posnr, matnr, kwmeng, netwr FROM vbap
|
|
205
|
-
INTO TABLE @DATA(lt_vbap)
|
|
206
|
-
FOR ALL ENTRIES IN @lt_vbak
|
|
207
|
-
WHERE vbeln = @lt_vbak-vbeln.
|
|
208
|
-
ENDIF.
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
### 从已取数据批量补字段(WITH +DATA,禁止全表 SELECT)
|
|
212
|
-
|
|
213
|
-
已取到 GT_ALV 后需要补其他表的字段时,**禁止 SELECT * FROM 全表**。
|
|
214
|
-
必须先从 GT_ALV 取 distinct key,再 JOIN 目标表:
|
|
215
|
-
|
|
216
|
-
```abap
|
|
217
|
-
" 错误 — 全表取数
|
|
218
|
-
SELECT kunnr, name1 FROM kna1 INTO TABLE @DATA(lt_kna1).
|
|
219
|
-
SORT lt_kna1 BY kunnr.
|
|
220
|
-
|
|
221
|
-
" 正确 — 只取 GT_ALV 里有的 key
|
|
222
|
-
WITH +DATA AS ( SELECT DISTINCT kunnr FROM @gt_alv AS a )
|
|
223
|
-
SELECT a~kunnr, b~name1
|
|
224
|
-
FROM +data AS a
|
|
225
|
-
INNER JOIN kna1 AS b ON a~kunnr = b~kunnr
|
|
226
|
-
INTO TABLE @DATA(lt_kna1).
|
|
227
|
-
SORT lt_kna1 BY kunnr.
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
同样适用于 LOOP 中 READ TABLE 取描述的场景。
|
|
231
|
-
|
|
232
|
-
## 输出格式
|
|
233
|
-
|
|
234
|
-
### 导出 CSV(应用服务器)
|
|
235
|
-
|
|
236
|
-
```abap
|
|
237
|
-
" 文件路径:可用合适的数据元素;无合适元素时也允许 TYPE string
|
|
238
|
-
DATA: lv_file TYPE zz_path VALUE '/tmp/export.csv'.
|
|
239
|
-
|
|
240
|
-
OPEN DATASET lv_file FOR OUTPUT IN TEXT MODE ENCODING UTF-8.
|
|
241
|
-
|
|
242
|
-
LOOP AT lt_data INTO DATA(ls_row).
|
|
243
|
-
TRANSFER ls_row TO lv_file.
|
|
244
|
-
ENDLOOP.
|
|
245
|
-
|
|
246
|
-
CLOSE DATASET lv_file.
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
### 读取 Excel(前台上传)
|
|
250
|
-
|
|
251
|
-
```abap
|
|
252
|
-
DATA: lt_excel TYPE TABLE OF alsmex_tabline.
|
|
253
|
-
|
|
254
|
-
CALL FUNCTION 'ALSM_EXCEL_TO_INTERNAL_TABLE'
|
|
255
|
-
EXPORTING
|
|
256
|
-
filename = p_file
|
|
257
|
-
i_begin_col = 1
|
|
258
|
-
i_begin_row = 1
|
|
259
|
-
i_end_col = 10
|
|
260
|
-
i_end_row = 1000
|
|
261
|
-
TABLES
|
|
262
|
-
intern = lt_excel
|
|
263
|
-
EXCEPTIONS
|
|
264
|
-
inconsistent_parameters = 1
|
|
265
|
-
upload_ole = 2.
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
## 常见错误修复
|
|
269
|
-
|
|
270
|
-
| 错误 | 原因 | 修复 |
|
|
271
|
-
|------|------|------|
|
|
272
|
-
| 字段不存在 | 表名字段名拼错 | 用内置 `get_abap_object_info`(TABL)确认字段名 |
|
|
273
|
-
| 类型不匹配 | 数据类型不一致 | 用 `CONV #( )` 或 `CORRESPONDING` |
|
|
274
|
-
| 未声明变量 | 缺少 DATA 声明 | 用内联声明 `@DATA(...)` |
|
|
275
|
-
| 表未声明 | TABLES 缺失 | 添加 `TABLES:` 声明(选择屏幕 FOR 字段需要) |
|
|
276
|
-
| 选择屏幕错误 | FOR 引用字段不存在 | 确认表已声明在 TABLES 中 |
|
|
277
|
-
| `Comma without preceding colon` | `TYPES:` 冒号链内结构体误用 `.` 终止 | 见 `Memory.md` 避坑指南 |
|
|
278
|
-
|
|
279
|
-
## 常用事务码参考
|
|
280
|
-
|
|
281
|
-
| 事务码 | 用途 |
|
|
282
|
-
|--------|------|
|
|
283
|
-
| SE38 | ABAP 编辑器 |
|
|
284
|
-
| SE80 | 对象导航器 |
|
|
285
|
-
| SE11 | 数据字典 |
|
|
286
|
-
| SE16N | 数据浏览器 |
|
|
287
|
-
| ST22 | DUMP 分析 |
|
|
288
|
-
| SM37 | 后台作业 |
|
|
289
|
-
| SU53 | 权限检查 |
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
# 二、ABAP 函数模块(Function Module)
|
|
293
|
-
|
|
294
|
-
---
|
|
295
|
-
name: abap-function
|
|
296
|
-
description: ABAP 函数模块(Function Module)开发参考——函数组结构、参数接口、异常处理模式、常用 BAPI、单元测试。触发场景:编写或修改函数模块/函数组代码,需要接口模板、异常处理写法、BAPI 选型时。
|
|
297
|
-
category: software-development
|
|
298
|
-
agent_created: true
|
|
299
|
-
---
|
|
300
|
-
|
|
301
|
-
# ABAP 函数模块开发参考
|
|
302
|
-
|
|
303
|
-
> 命名与编码规则以 `dev-write` 技能(默认 SAP 官方 Clean ABAP)为唯一权威;本文件只提供代码模板与写法参考。
|
|
304
|
-
> **字段类型建议**:自建表/结构字段允许裸内置类型(`i`/`c`/`n`/`p`/`string`/`char1` 等),保存时仅提示;有合适的 DDIC 数据元素可优先使用。程序内局部变量/参数也允许裸类型(见 dev-write 技能)。
|
|
305
|
-
> **函数模块接口参数命名**:`IV_`/`EV_`/`ET_`/`ES_` 前缀是 SAP 函数模块接口的通行惯例(SE37 界面/社区代码广泛使用),
|
|
306
|
-
> 与类方法的 Clean ABAP 无前缀规则**不同场景不同规则**,接口参数沿用 IV_/EV_ 惯例;函数体内局部变量仍遵循 Clean ABAP(行内声明、无前缀)。
|
|
307
|
-
> 函数模块命名:`Z_<模块>_FM_<描述>`;函数组命名:`Z<模块>G<3位编号>`。
|
|
308
|
-
|
|
309
|
-
## 函数组结构
|
|
310
|
-
|
|
311
|
-
```abap
|
|
312
|
-
FUNCTION-POOL zmmg001.
|
|
313
|
-
|
|
314
|
-
" 全局数据声明(可选,尽量避免)
|
|
315
|
-
DATA: gv_initialized TYPE abap_bool.
|
|
316
|
-
|
|
317
|
-
" 子程序声明(可选)
|
|
318
|
-
FORM f_init.
|
|
319
|
-
ENDFORM.
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
## 完整函数模板
|
|
323
|
-
|
|
324
|
-
```abap
|
|
325
|
-
FUNCTION z_mm_fm_get_material.
|
|
326
|
-
*"----------------------------------------------------------------------
|
|
327
|
-
*"*"Local Interface:
|
|
328
|
-
*" IMPORTING
|
|
329
|
-
*" VALUE(IV_MATNR) TYPE MATNR
|
|
330
|
-
*" VALUE(IV_WERKS) TYPE WERKS_D OPTIONAL
|
|
331
|
-
*" EXPORTING
|
|
332
|
-
*" VALUE(ES_MARA) TYPE MARA
|
|
333
|
-
*" VALUE(ES_MARC) TYPE MARC
|
|
334
|
-
*" VALUE(EV_RETURN) TYPE BAPIRET2
|
|
335
|
-
*" TABLES
|
|
336
|
-
*" ET_MARD TYPE MARD_TT OPTIONAL
|
|
337
|
-
*" EXCEPTIONS
|
|
338
|
-
*" MATERIAL_NOT_FOUND
|
|
339
|
-
*" PLANT_NOT_FOUND
|
|
340
|
-
*" INVALID_INPUT
|
|
341
|
-
*"----------------------------------------------------------------------
|
|
342
|
-
|
|
343
|
-
" 输入校验
|
|
344
|
-
IF iv_matnr IS INITIAL.
|
|
345
|
-
RAISE invalid_input.
|
|
346
|
-
ENDIF.
|
|
347
|
-
|
|
348
|
-
" 读取物料主数据(必须写字段列表,禁止 SELECT *)
|
|
349
|
-
SELECT SINGLE matnr, mtart, matkl, meins, maktx
|
|
350
|
-
FROM mara
|
|
351
|
-
INTO CORRESPONDING FIELDS OF @es_mara
|
|
352
|
-
WHERE matnr = @iv_matnr.
|
|
353
|
-
|
|
354
|
-
IF sy-subrc <> 0.
|
|
355
|
-
" 文案走消息类(禁止硬编码中文):MESSAGE ... INTO 取回文本给 BAPIRET2
|
|
356
|
-
MESSAGE e001(zmm) WITH iv_matnr INTO DATA(lv_msg).
|
|
357
|
-
ev_return = VALUE #( type = 'E' id = 'ZMM' number = '001' message = lv_msg ).
|
|
358
|
-
RAISE material_not_found.
|
|
359
|
-
ENDIF.
|
|
360
|
-
|
|
361
|
-
" 读取工厂数据
|
|
362
|
-
IF iv_werks IS NOT INITIAL.
|
|
363
|
-
SELECT SINGLE matnr, werks, dispo, beskz
|
|
364
|
-
FROM marc
|
|
365
|
-
INTO CORRESPONDING FIELDS OF @es_marc
|
|
366
|
-
WHERE matnr = @iv_matnr AND werks = @iv_werks.
|
|
367
|
-
|
|
368
|
-
IF sy-subrc <> 0.
|
|
369
|
-
RAISE plant_not_found.
|
|
370
|
-
ENDIF.
|
|
371
|
-
ENDIF.
|
|
372
|
-
|
|
373
|
-
" 读取库存数据
|
|
374
|
-
SELECT matnr, werks, lgort, labst, umlme
|
|
375
|
-
FROM mard
|
|
376
|
-
INTO CORRESPONDING FIELDS OF TABLE @et_mard
|
|
377
|
-
WHERE matnr = @iv_matnr.
|
|
378
|
-
|
|
379
|
-
ENDFUNCTION.
|
|
380
|
-
```
|
|
381
|
-
|
|
382
|
-
## 参数类型详解
|
|
383
|
-
|
|
384
|
-
### IMPORTING 参数
|
|
385
|
-
```abap
|
|
386
|
-
*" IMPORTING
|
|
387
|
-
*" VALUE(IV_MATNR) TYPE MATNR " 必填
|
|
388
|
-
*" VALUE(IV_WERKS) TYPE WERKS_D OPTIONAL " 可选
|
|
389
|
-
*" REFERENCE(IS_DATA) TYPE ZFIS_DATA " 引用传递(结构)
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
### EXPORTING 参数
|
|
393
|
-
```abap
|
|
394
|
-
*" EXPORTING
|
|
395
|
-
*" VALUE(EV_COUNT) TYPE MENGE_D " 计数:可用数量类数据元素,也允许 TYPE i
|
|
396
|
-
*" VALUE(ES_HEADER) TYPE ZFIS_HEADER
|
|
397
|
-
*" REFERENCE(ET_DATA) TYPE ZFITT_DATA
|
|
398
|
-
```
|
|
399
|
-
|
|
400
|
-
### TABLES 参数
|
|
401
|
-
```abap
|
|
402
|
-
*" TABLES
|
|
403
|
-
*" ET_ITEMS TYPE ZFITT_ITEMS
|
|
404
|
-
*" ET_LOG TYPE BAPIRET2_TT OPTIONAL
|
|
405
|
-
```
|
|
406
|
-
|
|
407
|
-
### CHANGING 参数
|
|
408
|
-
```abap
|
|
409
|
-
*" CHANGING
|
|
410
|
-
*" VALUE(CV_FLAG) TYPE ABAP_BOOL
|
|
411
|
-
*" REFERENCE(CT_DATA) TYPE ZFITT_DATA
|
|
412
|
-
```
|
|
413
|
-
|
|
414
|
-
## 异常处理模式
|
|
415
|
-
|
|
416
|
-
### 模式1:RAISE 异常
|
|
417
|
-
```abap
|
|
418
|
-
IF sy-subrc <> 0.
|
|
419
|
-
RAISE material_not_found.
|
|
420
|
-
ENDIF.
|
|
421
|
-
```
|
|
422
|
-
|
|
423
|
-
### 模式2:BAPIRET2 返回(文案必须走消息类,禁止硬编码中文)
|
|
424
|
-
```abap
|
|
425
|
-
DATA: ls_return TYPE bapiret2.
|
|
426
|
-
|
|
427
|
-
" 从消息类 ZMM 取文案(维护在 SE91/文本元素,代码零硬编码)
|
|
428
|
-
MESSAGE e001(zmm) WITH iv_matnr INTO DATA(lv_msg).
|
|
429
|
-
|
|
430
|
-
ls_return = VALUE #(
|
|
431
|
-
type = 'E'
|
|
432
|
-
id = 'ZMM'
|
|
433
|
-
number = '001'
|
|
434
|
-
message = lv_msg
|
|
435
|
-
message_v1 = iv_matnr
|
|
436
|
-
).
|
|
437
|
-
|
|
438
|
-
APPEND ls_return TO et_return.
|
|
439
|
-
```
|
|
440
|
-
|
|
441
|
-
### 模式3:TRY-CATCH
|
|
442
|
-
```abap
|
|
443
|
-
TRY.
|
|
444
|
-
DATA(lo_helper) = NEW zcl_mm_material_helper( ).
|
|
445
|
-
lo_helper->validate( iv_matnr ).
|
|
446
|
-
lo_helper->process( iv_matnr ).
|
|
447
|
-
|
|
448
|
-
CATCH zcx_mm_material_error INTO DATA(lx_err).
|
|
449
|
-
ev_return = VALUE #( type = 'E' message = lx_err->get_text( ) ).
|
|
450
|
-
RAISE material_not_found.
|
|
451
|
-
ENDTRY.
|
|
452
|
-
```
|
|
453
|
-
|
|
454
|
-
## 调用方式
|
|
455
|
-
|
|
456
|
-
```abap
|
|
457
|
-
CALL FUNCTION 'Z_MM_FM_GET_MATERIAL'
|
|
458
|
-
EXPORTING
|
|
459
|
-
iv_matnr = lv_matnr
|
|
460
|
-
IMPORTING
|
|
461
|
-
es_mara = ls_mara
|
|
462
|
-
EXCEPTIONS
|
|
463
|
-
material_not_found = 1
|
|
464
|
-
invalid_input = 2
|
|
465
|
-
OTHERS = 3.
|
|
466
|
-
|
|
467
|
-
CASE sy-subrc.
|
|
468
|
-
WHEN 1. MESSAGE e001(zmm) WITH lv_msg1. " 消息文本在消息类 ZMM 维护,禁止 WITH 硬编码中文
|
|
469
|
-
WHEN 2. MESSAGE e002(zmm) WITH lv_msg2.
|
|
470
|
-
WHEN 3. MESSAGE e003(zmm) WITH lv_msg3.
|
|
471
|
-
ENDCASE.
|
|
472
|
-
```
|
|
473
|
-
|
|
474
|
-
## 常用 BAPI 参考
|
|
475
|
-
|
|
476
|
-
### 数据读取
|
|
477
|
-
| 函数 | 用途 |
|
|
478
|
-
|------|------|
|
|
479
|
-
| BAPI_MATERIAL_GET_DETAIL | 读取物料主数据 |
|
|
480
|
-
| BAPI_CUSTOMER_GETDETAIL | 读取客户主数据 |
|
|
481
|
-
| BAPI_SALESORDER_GETDETAIL | 读取销售订单 |
|
|
482
|
-
| ME_READ_INFORECORD | 读取采购信息记录 |
|
|
483
|
-
|
|
484
|
-
### 数据创建
|
|
485
|
-
| 函数 | 用途 |
|
|
486
|
-
|------|------|
|
|
487
|
-
| BAPI_MATERIAL_SAVEDATA | 创建/修改物料 |
|
|
488
|
-
| BAPI_SALESORDER_CREATEFROMDAT2 | 创建销售订单 |
|
|
489
|
-
| BAPI_PO_CREATE1 | 创建采购订单 |
|
|
490
|
-
| BAPI_GOODSMVT_CREATE | 物料移动过账 |
|
|
491
|
-
|
|
492
|
-
### 事务控制
|
|
493
|
-
| 函数 | 用途 |
|
|
494
|
-
|------|------|
|
|
495
|
-
| BAPI_TRANSACTION_COMMIT | 提交事务 |
|
|
496
|
-
| BAPI_TRANSACTION_ROLLBACK | 回滚事务 |
|
|
497
|
-
|
|
498
|
-
## 函数模块测试(ABAP Unit)
|
|
499
|
-
|
|
500
|
-
```abap
|
|
501
|
-
CLASS ltc_material DEFINITION FOR TESTING
|
|
502
|
-
RISK LEVEL HARMLESS
|
|
503
|
-
DURATION SHORT.
|
|
504
|
-
|
|
505
|
-
PRIVATE SECTION.
|
|
506
|
-
DATA: mo_cut TYPE REF TO zcl_mm_material_helper.
|
|
507
|
-
|
|
508
|
-
METHODS: setup,
|
|
509
|
-
test_validate FOR TESTING,
|
|
510
|
-
test_process FOR TESTING.
|
|
511
|
-
|
|
512
|
-
ENDCLASS.
|
|
513
|
-
|
|
514
|
-
CLASS ltc_material IMPLEMENTATION.
|
|
515
|
-
METHOD setup.
|
|
516
|
-
mo_cut = NEW #( ).
|
|
517
|
-
ENDMETHOD.
|
|
518
|
-
|
|
519
|
-
METHOD test_validate.
|
|
520
|
-
DATA(lv_result) = mo_cut->validate( '000000000000001234' ).
|
|
521
|
-
cl_abap_unit_assert=>assert_true( lv_result ).
|
|
522
|
-
ENDMETHOD.
|
|
523
|
-
|
|
524
|
-
METHOD test_process.
|
|
525
|
-
DATA(lv_result) = mo_cut->process( '000000000000001234' ).
|
|
526
|
-
cl_abap_unit_assert=>assert_not_initial( lv_result ).
|
|
527
|
-
ENDMETHOD.
|
|
528
|
-
ENDCLASS.
|
|
529
|
-
```
|
|
530
|
-
|
|
531
|
-
## 函数组设计规范
|
|
532
|
-
|
|
533
|
-
1. **一个函数组一个业务领域**
|
|
534
|
-
- `ZMMG001` — 物料相关函数
|
|
535
|
-
- `ZSDG001` — 销售相关函数
|
|
536
|
-
- `ZFIG001` — 财务相关函数
|
|
537
|
-
|
|
538
|
-
2. **函数命名:`Z<模块>_FM_<动词>_<描述>`**
|
|
539
|
-
- `ZMM_FM_GET_MATERIAL` — 读取数据(GET)
|
|
540
|
-
- `ZSD_FM_CREATE_ORDER` — 创建数据(CREATE)
|
|
541
|
-
- `ZMM_FM_UPDATE_MATERIAL` — 更新数据(UPDATE)
|
|
542
|
-
- `ZSD_FM_CHECK_CREDIT` — 校验数据(CHECK)
|
|
543
|
-
- `ZFI_FM_CALC_TAX` — 计算数据(CALC)
|
|
544
|
-
|
|
545
|
-
3. **避免函数间共享全局数据** — 除非必要,使用参数传递。
|
|
546
|
-
|
|
547
|
-
4. **每个函数只做一件事** — 单一职责原则。
|
|
548
|
-
|
|
549
|
-
# 三、ABAP 类(Class / 面向对象)
|
|
550
|
-
|
|
551
|
-
> Clean ABAP 推荐面向对象优先;新功能优先用类实现。类命名 `ZCL_<模块>_<对象>`(如 ZCL_MM_MATERIAL_HELPER)、异常类 `ZCX_<模块>_<错误>`、接口 `ZIF_<模块>_<能力>`。
|
|
552
|
-
|
|
553
|
-
## 完整类模板
|
|
554
|
-
|
|
555
|
-
```abap
|
|
556
|
-
CLASS zcl_mm_material_helper DEFINITION
|
|
557
|
-
PUBLIC
|
|
558
|
-
FINAL
|
|
559
|
-
CREATE PUBLIC.
|
|
560
|
-
|
|
561
|
-
PUBLIC SECTION.
|
|
562
|
-
" 构造函数:显式声明(需要依赖时)
|
|
563
|
-
METHODS constructor
|
|
564
|
-
IMPORTING
|
|
565
|
-
iv_matnr TYPE matnr OPTIONAL.
|
|
566
|
-
|
|
567
|
-
" 命令式方法:动词命名
|
|
568
|
-
METHODS validate
|
|
569
|
-
IMPORTING
|
|
570
|
-
iv_matnr TYPE matnr
|
|
571
|
-
RETURNING
|
|
572
|
-
VALUE(rv_valid) TYPE abap_bool.
|
|
573
|
-
|
|
574
|
-
" 查询式方法:is_/has_/get_ 命名
|
|
575
|
-
METHODS get_material
|
|
576
|
-
IMPORTING
|
|
577
|
-
iv_matnr TYPE matnr
|
|
578
|
-
RETURNING
|
|
579
|
-
VALUE(rs_mara) TYPE mara
|
|
580
|
-
RAISING
|
|
581
|
-
zcx_mm_material_error.
|
|
582
|
-
|
|
583
|
-
" 类方法(工厂/工具)
|
|
584
|
-
CLASS-METHODS create_instance
|
|
585
|
-
RETURNING
|
|
586
|
-
VALUE(ro_instance) TYPE REF TO zcl_mm_material_helper.
|
|
587
|
-
|
|
588
|
-
PRIVATE SECTION.
|
|
589
|
-
" 实例属性:mv_ / mo_ / mt_ 前缀(DDIC 数据元素类型)
|
|
590
|
-
DATA mv_matnr TYPE matnr.
|
|
591
|
-
DATA mt_items TYPE STANDARD TABLE OF mard WITH EMPTY KEY.
|
|
592
|
-
|
|
593
|
-
" 私有方法
|
|
594
|
-
METHODS read_material
|
|
595
|
-
IMPORTING
|
|
596
|
-
iv_matnr TYPE matnr
|
|
597
|
-
RETURNING
|
|
598
|
-
VALUE(rs_mara) TYPE mara.
|
|
599
|
-
ENDCLASS.
|
|
600
|
-
|
|
601
|
-
CLASS zcl_mm_material_helper IMPLEMENTATION.
|
|
602
|
-
METHOD constructor.
|
|
603
|
-
mv_matnr = iv_matnr.
|
|
604
|
-
ENDMETHOD.
|
|
605
|
-
|
|
606
|
-
METHOD create_instance.
|
|
607
|
-
ro_instance = NEW #( ).
|
|
608
|
-
ENDMETHOD.
|
|
609
|
-
|
|
610
|
-
METHOD validate.
|
|
611
|
-
rv_valid = boolc( iv_matnr IS NOT INITIAL ).
|
|
612
|
-
ENDMETHOD.
|
|
613
|
-
|
|
614
|
-
METHOD get_material.
|
|
615
|
-
rs_mara = read_material( iv_matnr ).
|
|
616
|
-
IF rs_mara-matnr IS INITIAL.
|
|
617
|
-
RAISE EXCEPTION TYPE zcx_mm_material_error
|
|
618
|
-
EXPORTING
|
|
619
|
-
textid = zcx_mm_material_error=>not_found.
|
|
620
|
-
ENDIF.
|
|
621
|
-
ENDMETHOD.
|
|
622
|
-
|
|
623
|
-
METHOD read_material.
|
|
624
|
-
" 显式字段列表,禁 SELECT *
|
|
625
|
-
SELECT SINGLE matnr, mtart, matkl, meins, maktx
|
|
626
|
-
FROM mara
|
|
627
|
-
INTO CORRESPONDING FIELDS OF @rs_mara
|
|
628
|
-
WHERE matnr = @iv_matnr.
|
|
629
|
-
ENDMETHOD.
|
|
630
|
-
ENDCLASS.
|
|
631
|
-
```
|
|
632
|
-
|
|
633
|
-
## 接口实现(IF_OO_* 解耦)
|
|
634
|
-
|
|
635
|
-
```abap
|
|
636
|
-
INTERFACE zif_material_read.
|
|
637
|
-
METHODS get_material
|
|
638
|
-
IMPORTING
|
|
639
|
-
iv_matnr TYPE matnr
|
|
640
|
-
RETURNING
|
|
641
|
-
VALUE(rs_mara) TYPE mara
|
|
642
|
-
RAISING
|
|
643
|
-
zcx_mm_material_error.
|
|
644
|
-
ENDINTERFACE.
|
|
645
|
-
|
|
646
|
-
CLASS zcl_mm_material_reader DEFINITION PUBLIC FINAL CREATE PUBLIC.
|
|
647
|
-
PUBLIC SECTION.
|
|
648
|
-
INTERFACES zif_material_read.
|
|
649
|
-
ENDCLASS.
|
|
650
|
-
|
|
651
|
-
CLASS zcl_mm_material_reader IMPLEMENTATION.
|
|
652
|
-
METHOD zif_material_read~get_material.
|
|
653
|
-
" 实现接口方法(接口名~方法名)
|
|
654
|
-
SELECT SINGLE matnr, mtart, matkl FROM mara
|
|
655
|
-
INTO CORRESPONDING FIELDS OF @rs_mara
|
|
656
|
-
WHERE matnr = @iv_matnr.
|
|
657
|
-
IF sy-subrc <> 0.
|
|
658
|
-
RAISE EXCEPTION TYPE zcx_mm_material_error.
|
|
659
|
-
ENDIF.
|
|
660
|
-
ENDMETHOD.
|
|
661
|
-
ENDCLASS.
|
|
662
|
-
```
|
|
663
|
-
|
|
664
|
-
## 异常类(继承 CX_STATIC_CHECK)
|
|
665
|
-
|
|
666
|
-
```abap
|
|
667
|
-
CLASS zcx_mm_material_error DEFINITION
|
|
668
|
-
INHERITING FROM cx_static_check
|
|
669
|
-
PUBLIC FINAL CREATE PUBLIC.
|
|
670
|
-
|
|
671
|
-
PUBLIC SECTION.
|
|
672
|
-
" 文本 ID:绑定消息类 ZMM 的文本(SE91 维护,禁止硬编码中文)
|
|
673
|
-
CONSTANTS:
|
|
674
|
-
not_found TYPE sotr_conc VALUE '001',
|
|
675
|
-
invalid TYPE sotr_conc VALUE '002'.
|
|
676
|
-
|
|
677
|
-
METHODS get_text REDEFINITION. " 消息文本由 cx_static_check 从消息类取回
|
|
678
|
-
ENDCLASS.
|
|
679
|
-
|
|
680
|
-
CLASS zcx_mm_material_error IMPLEMENTATION.
|
|
681
|
-
ENDCLASS.
|
|
682
|
-
```
|
|
683
|
-
|
|
684
|
-
## 工厂方法 / 单例
|
|
685
|
-
|
|
686
|
-
```abap
|
|
687
|
-
" 单例(惰性)
|
|
688
|
-
CLASS zcl_mm_manager DEFINITION PUBLIC FINAL CREATE PRIVATE.
|
|
689
|
-
PUBLIC SECTION.
|
|
690
|
-
CLASS-METHODS get_instance
|
|
691
|
-
RETURNING
|
|
692
|
-
VALUE(ro_instance) TYPE REF TO zcl_mm_manager.
|
|
693
|
-
PRIVATE SECTION.
|
|
694
|
-
CLASS-DATA go_instance TYPE REF TO zcl_mm_manager.
|
|
695
|
-
ENDCLASS.
|
|
696
|
-
|
|
697
|
-
CLASS zcl_mm_manager IMPLEMENTATION.
|
|
698
|
-
METHOD get_instance.
|
|
699
|
-
IF go_instance IS NOT BOUND.
|
|
700
|
-
go_instance = NEW #( ).
|
|
701
|
-
ENDIF.
|
|
702
|
-
ro_instance = go_instance.
|
|
703
|
-
ENDMETHOD.
|
|
704
|
-
ENDCLASS.
|
|
705
|
-
```
|
|
706
|
-
|
|
707
|
-
## 调用示例
|
|
708
|
-
|
|
709
|
-
```abap
|
|
710
|
-
DATA(lo_helper) = NEW zcl_mm_material_helper( iv_matnr = lv_matnr ).
|
|
711
|
-
|
|
712
|
-
IF lo_helper->validate( lv_matnr ).
|
|
713
|
-
DATA(ls_mara) = lo_helper->get_material( lv_matnr ).
|
|
714
|
-
ENDIF.
|
|
715
|
-
|
|
716
|
-
" 通过接口调用(解耦)
|
|
717
|
-
DATA(lo_reader) = NEW zcl_mm_material_reader( ).
|
|
718
|
-
lo_reader->zif_material_read~get_material( lv_matnr ).
|
|
719
|
-
```
|
|
720
|
-
|
|
721
|
-
## 类单元测试(ABAP Unit)
|
|
722
|
-
|
|
723
|
-
```abap
|
|
724
|
-
CLASS ltc_material DEFINITION FOR TESTING
|
|
725
|
-
RISK LEVEL HARMLESS
|
|
726
|
-
DURATION SHORT.
|
|
727
|
-
|
|
728
|
-
PRIVATE SECTION.
|
|
729
|
-
DATA mo_cut TYPE REF TO zcl_mm_material_helper.
|
|
730
|
-
|
|
731
|
-
METHODS setup,
|
|
732
|
-
test_validate_ok FOR TESTING,
|
|
733
|
-
test_get_material_raises FOR TESTING.
|
|
734
|
-
|
|
735
|
-
ENDCLASS.
|
|
736
|
-
|
|
737
|
-
CLASS ltc_material IMPLEMENTATION.
|
|
738
|
-
METHOD setup.
|
|
739
|
-
mo_cut = NEW #( ).
|
|
740
|
-
ENDMETHOD.
|
|
741
|
-
|
|
742
|
-
METHOD test_validate_ok.
|
|
743
|
-
cl_abap_unit_assert=>assert_true( mo_cut->validate( '000000000000001234' ) ).
|
|
744
|
-
ENDMETHOD.
|
|
745
|
-
|
|
746
|
-
METHOD test_get_material_raises.
|
|
747
|
-
TRY.
|
|
748
|
-
mo_cut->get_material( '000000000000009999' ).
|
|
749
|
-
cl_abap_unit_assert=>fail( 'expected exception was not raised' ).
|
|
750
|
-
CATCH zcx_mm_material_error.
|
|
751
|
-
" 预期异常,测试通过
|
|
752
|
-
ENDTRY.
|
|
753
|
-
ENDMETHOD.
|
|
754
|
-
ENDCLASS.
|
|
755
|
-
```
|
|
756
|
-
|
|
757
|
-
## 设计规范(Clean ABAP 核心)
|
|
758
|
-
|
|
759
|
-
1. **单一职责**:一个类只做一件事;方法短小(≤15 行)
|
|
760
|
-
2. **依赖注入**:构造函数收依赖(`mo_dep`),不内部 `NEW` 硬编码
|
|
761
|
-
3. **属性私有**:`PRIVATE SECTION` 收好状态,通过方法暴露行为
|
|
762
|
-
4. **异常而非返回码**:错误用 `RAISE EXCEPTION`,不返回 `ev_error`
|
|
763
|
-
5. **不可变优先**:能 `READ-ONLY` / `FINAL` 就声明
|
|
764
|
-
6. **命名**:类=名词、方法=动词(命令式)、查询=is_/has_/get_;属性 `mv_/mo_/mt_` 前缀
|
|
1
|
+
---
|
|
2
|
+
name: abap-templates
|
|
3
|
+
description: >-
|
|
4
|
+
ABAP 开发模板库——报表(Report)与函数模块(Function Module)的具体代码模板:
|
|
5
|
+
ALV 输出(cl_salv_table / cl_gui_alv_grid / REUSE_ALV / 层次 ALV)、选择屏幕、
|
|
6
|
+
数据查询最佳实践、导出导入、函数组结构、接口参数写法、异常处理模式、BAPI 选型、单元测试。
|
|
7
|
+
触发场景:编写或修改 ABAP 报表/函数模块代码,需要具体语法模板时。
|
|
8
|
+
规范(命名/字段类型/消息类等)以 dev-write 技能(默认 SAP 官方 Clean ABAP)为唯一权威,本文件只提供写法参考。
|
|
9
|
+
category: software-development
|
|
10
|
+
agent_created: true
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# ABAP 开发模板库(报表 + 函数模块)
|
|
14
|
+
|
|
15
|
+
> 命名与编码规则、字段类型、消息类等一律以 `dev-write` 技能为唯一权威;本文件只提供具体代码模板与写法参考。
|
|
16
|
+
|
|
17
|
+
# 一、ABAP 报表(Report)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
name: abap-report
|
|
21
|
+
description: ABAP 报表(Report)开发参考——ALV 输出、选择屏幕、数据查询最佳实践、导入导出。触发场景:编写或修改 ABAP 报表程序代码,需要代码模板、选择屏幕写法、查询写法、ALV 用法时。
|
|
22
|
+
category: software-development
|
|
23
|
+
agent_created: true
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
# ABAP 报表开发参考
|
|
27
|
+
|
|
28
|
+
> 命名与编码规则以 `dev-write` 技能(默认 SAP 官方 Clean ABAP)为唯一权威;本文件只提供代码模板与写法参考。
|
|
29
|
+
|
|
30
|
+
## 报表类型
|
|
31
|
+
|
|
32
|
+
### 1. cl_salv_table(首选,SapBuddy 标准,符合 Clean ABAP OO 优先)
|
|
33
|
+
|
|
34
|
+
```abap
|
|
35
|
+
TRY.
|
|
36
|
+
cl_salv_table=>factory(
|
|
37
|
+
IMPORTING r_salv_table = DATA(lo_salv)
|
|
38
|
+
CHANGING t_table = lt_data ).
|
|
39
|
+
|
|
40
|
+
lo_salv->get_functions( )->set_all( abap_true ).
|
|
41
|
+
lo_salv->get_columns( )->set_optimize( abap_true ).
|
|
42
|
+
lo_salv->display( ).
|
|
43
|
+
|
|
44
|
+
CATCH cx_salv_msg INTO DATA(lx_msg).
|
|
45
|
+
MESSAGE lx_msg->get_text( ) TYPE 'E'.
|
|
46
|
+
ENDTRY.
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
> Clean ABAP 推荐面向对象 API;`cl_salv_table` 代码最简、无布局对象,适合多数报表。
|
|
50
|
+
> 需要行高亮/编辑/事件等高级交互时用 `cl_gui_alv_grid`(备选)。
|
|
51
|
+
|
|
52
|
+
### 2. CL_GUI_ALV_GRID(备选,需要交互/事件场景)
|
|
53
|
+
|
|
54
|
+
```abap
|
|
55
|
+
DATA: lo_alv TYPE REF TO cl_gui_alv_grid,
|
|
56
|
+
lo_container TYPE REF TO cl_gui_custom_container.
|
|
57
|
+
|
|
58
|
+
CREATE OBJECT lo_container
|
|
59
|
+
EXPORTING container_name = 'ALV_CONTAINER'.
|
|
60
|
+
|
|
61
|
+
CREATE OBJECT lo_alv
|
|
62
|
+
EXPORTING i_parent = lo_container.
|
|
63
|
+
|
|
64
|
+
lo_alv->set_table_for_first_display(
|
|
65
|
+
EXPORTING is_layout = ls_layout
|
|
66
|
+
CHANGING it_outtab = lt_data
|
|
67
|
+
it_fieldcatalog = lt_fieldcat ).
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 3. REUSE_ALV_GRID_DISPLAY_LVC(兼容备选:遗留系统/存量代码风格)
|
|
71
|
+
|
|
72
|
+
> 仅当目标系统版本旧或存量代码已用此风格时采用;新代码优先前两种 OO 方案。
|
|
73
|
+
> 注:`lt_`/`ls_` 前缀仅限 ALV 字段目录/输出内表等业界通行场景(本技能模板沿用),普通变量遵循 Clean ABAP 无前缀。
|
|
74
|
+
|
|
75
|
+
```abap
|
|
76
|
+
DATA: lt_fieldcat TYPE lvc_t_fcat,
|
|
77
|
+
ls_fieldcat TYPE lvc_s_fcat,
|
|
78
|
+
ls_layout TYPE lvc_s_layo.
|
|
79
|
+
|
|
80
|
+
" 字段目录必须显式逐字段定义,禁止用 FORM 或宏自动生成
|
|
81
|
+
CLEAR ls_fieldcat.
|
|
82
|
+
ls_fieldcat-fieldname = 'VBELN'.
|
|
83
|
+
ls_fieldcat-coltext = TEXT-001. " 列文本在文本池维护(TEXT-001),禁止硬编码中文
|
|
84
|
+
APPEND ls_fieldcat TO lt_fieldcat.
|
|
85
|
+
|
|
86
|
+
CLEAR ls_fieldcat.
|
|
87
|
+
ls_fieldcat-fieldname = 'NETWR'.
|
|
88
|
+
ls_fieldcat-coltext = TEXT-002. " 列文本在文本池维护(TEXT-002),禁止硬编码中文
|
|
89
|
+
ls_fieldcat-no_zero = abap_true.
|
|
90
|
+
APPEND ls_fieldcat TO lt_fieldcat.
|
|
91
|
+
|
|
92
|
+
ls_layout-zebra = abap_true.
|
|
93
|
+
ls_layout-cwidth_opt = abap_true.
|
|
94
|
+
|
|
95
|
+
CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY_LVC'
|
|
96
|
+
EXPORTING
|
|
97
|
+
i_callback_program = sy-repid
|
|
98
|
+
is_layout_lvc = ls_layout
|
|
99
|
+
it_fieldcat_lvc = lt_fieldcat
|
|
100
|
+
TABLES
|
|
101
|
+
t_outtab = lt_data
|
|
102
|
+
EXCEPTIONS
|
|
103
|
+
program_error = 1
|
|
104
|
+
OTHERS = 2.
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### 4. 层次 ALV(备选,抬头-行项目双层展示)
|
|
108
|
+
|
|
109
|
+
```abap
|
|
110
|
+
cl_salv_hierseq_table=>factory(
|
|
111
|
+
IMPORTING r_salv_hierseq = DATA(lo_hier)
|
|
112
|
+
CHANGING t_table1 = lt_header
|
|
113
|
+
t_table2 = item_data ).
|
|
114
|
+
|
|
115
|
+
lo_lo_hier->display( ).
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## 选择屏幕
|
|
119
|
+
|
|
120
|
+
### 常用元素
|
|
121
|
+
|
|
122
|
+
```abap
|
|
123
|
+
" 单值输入(必填)
|
|
124
|
+
PARAMETERS: p_vkorg TYPE vbak-vkorg OBLIGATORY.
|
|
125
|
+
|
|
126
|
+
" 多值区间
|
|
127
|
+
SELECT-OPTIONS: s_vbeln FOR vbak-vbeln,
|
|
128
|
+
s_erdat FOR vbak-erdat.
|
|
129
|
+
|
|
130
|
+
" 复选框
|
|
131
|
+
PARAMETERS: p_detail AS CHECKBOX DEFAULT 'X'.
|
|
132
|
+
|
|
133
|
+
" 单选按钮
|
|
134
|
+
PARAMETERS: p_alv RADIOBUTTON GROUP g1 DEFAULT 'X',
|
|
135
|
+
p_list RADIOBUTTON GROUP g1.
|
|
136
|
+
|
|
137
|
+
" 下拉列表(状态/选项:可用 xfeld 等标准数据元素,也允许 TYPE char1)
|
|
138
|
+
PARAMETERS: p_type TYPE xfeld AS LISTBOX VISIBLE LENGTH 20.
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 块与文本元素
|
|
142
|
+
|
|
143
|
+
```abap
|
|
144
|
+
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001.
|
|
145
|
+
SELECT-OPTIONS: s_bukrs FOR bkpf-bukrs OBLIGATORY,
|
|
146
|
+
s_gjahr FOR bkpf-gjahr OBLIGATORY.
|
|
147
|
+
SELECTION-SCREEN END OF BLOCK b1.
|
|
148
|
+
```
|
|
149
|
+
块标题和选择项文本必须用文本元素(TEXT-001),禁止硬编码。
|
|
150
|
+
|
|
151
|
+
> **禁止硬编码中文(强制)**:所有用户可见文案(提示/错误/说明)禁止直接写在代码里:
|
|
152
|
+
> - MESSAGE 语句 → 消息类(`MESSAGE e001(zxxx) WITH ...`,消息类用 `manage_transport_requests` 查/建或 MSAG/N 创建)
|
|
153
|
+
> - ALV 列文本/标题/选择文本 → 文本元素(`TEXT-xxx`,`manage_text_elements` 维护)
|
|
154
|
+
> - 屏幕块标题 → 文本元素;仅技术注释可用中文。
|
|
155
|
+
|
|
156
|
+
### 屏幕事件
|
|
157
|
+
|
|
158
|
+
```abap
|
|
159
|
+
AT SELECTION-SCREEN OUTPUT.
|
|
160
|
+
" 默认值:最近 30 天
|
|
161
|
+
s_erdat-low = sy-datum - 30.
|
|
162
|
+
s_erdat-high = sy-datum.
|
|
163
|
+
APPEND s_erdat.
|
|
164
|
+
|
|
165
|
+
AT SELECTION-SCREEN.
|
|
166
|
+
" 输入校验,输出合适的错误消息
|
|
167
|
+
IF s_bukrs IS INITIAL.
|
|
168
|
+
" 消息文案在消息类 ZFI 的 e001 中维护(禁止 WITH 传中文文案)
|
|
169
|
+
MESSAGE e001(zfi).
|
|
170
|
+
ENDIF.
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## 数据查询最佳实践
|
|
174
|
+
|
|
175
|
+
### 标准 JOIN 查询(最多 3 张表)
|
|
176
|
+
|
|
177
|
+
```abap
|
|
178
|
+
SELECT v~vbeln, v~erdat, v~vkorg, v~kunnr,
|
|
179
|
+
p~posnr, p~matnr, p~kwmeng, p~netwr,
|
|
180
|
+
k~name1 AS customer_name,
|
|
181
|
+
m~maktx AS material_desc
|
|
182
|
+
FROM vbak AS v
|
|
183
|
+
INNER JOIN vbap AS p ON v~vbeln = p~vbeln
|
|
184
|
+
LEFT JOIN kna1 AS k ON v~kunnr = k~kunnr
|
|
185
|
+
LEFT JOIN makt AS m ON p~matnr = m~matnr AND m~spras = @sy-langu
|
|
186
|
+
INTO TABLE @DATA(lt_result)
|
|
187
|
+
WHERE v~vbeln IN @s_vbeln
|
|
188
|
+
AND v~erdat IN @s_erdat
|
|
189
|
+
AND v~vkorg IN @s_vkorg
|
|
190
|
+
ORDER BY v~vbeln, p~posnr.
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### FOR ALL ENTRIES(必须先检非空)
|
|
194
|
+
|
|
195
|
+
```abap
|
|
196
|
+
" 先取主表
|
|
197
|
+
SELECT vbeln, erdat, vkorg FROM vbak
|
|
198
|
+
INTO TABLE @DATA(lt_vbak)
|
|
199
|
+
WHERE vkorg IN @s_vkorg
|
|
200
|
+
AND erdat IN @s_erdat.
|
|
201
|
+
|
|
202
|
+
" 再取明细
|
|
203
|
+
IF lt_vbak IS NOT INITIAL.
|
|
204
|
+
SELECT vbeln, posnr, matnr, kwmeng, netwr FROM vbap
|
|
205
|
+
INTO TABLE @DATA(lt_vbap)
|
|
206
|
+
FOR ALL ENTRIES IN @lt_vbak
|
|
207
|
+
WHERE vbeln = @lt_vbak-vbeln.
|
|
208
|
+
ENDIF.
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### 从已取数据批量补字段(WITH +DATA,禁止全表 SELECT)
|
|
212
|
+
|
|
213
|
+
已取到 GT_ALV 后需要补其他表的字段时,**禁止 SELECT * FROM 全表**。
|
|
214
|
+
必须先从 GT_ALV 取 distinct key,再 JOIN 目标表:
|
|
215
|
+
|
|
216
|
+
```abap
|
|
217
|
+
" 错误 — 全表取数
|
|
218
|
+
SELECT kunnr, name1 FROM kna1 INTO TABLE @DATA(lt_kna1).
|
|
219
|
+
SORT lt_kna1 BY kunnr.
|
|
220
|
+
|
|
221
|
+
" 正确 — 只取 GT_ALV 里有的 key
|
|
222
|
+
WITH +DATA AS ( SELECT DISTINCT kunnr FROM @gt_alv AS a )
|
|
223
|
+
SELECT a~kunnr, b~name1
|
|
224
|
+
FROM +data AS a
|
|
225
|
+
INNER JOIN kna1 AS b ON a~kunnr = b~kunnr
|
|
226
|
+
INTO TABLE @DATA(lt_kna1).
|
|
227
|
+
SORT lt_kna1 BY kunnr.
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
同样适用于 LOOP 中 READ TABLE 取描述的场景。
|
|
231
|
+
|
|
232
|
+
## 输出格式
|
|
233
|
+
|
|
234
|
+
### 导出 CSV(应用服务器)
|
|
235
|
+
|
|
236
|
+
```abap
|
|
237
|
+
" 文件路径:可用合适的数据元素;无合适元素时也允许 TYPE string
|
|
238
|
+
DATA: lv_file TYPE zz_path VALUE '/tmp/export.csv'.
|
|
239
|
+
|
|
240
|
+
OPEN DATASET lv_file FOR OUTPUT IN TEXT MODE ENCODING UTF-8.
|
|
241
|
+
|
|
242
|
+
LOOP AT lt_data INTO DATA(ls_row).
|
|
243
|
+
TRANSFER ls_row TO lv_file.
|
|
244
|
+
ENDLOOP.
|
|
245
|
+
|
|
246
|
+
CLOSE DATASET lv_file.
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### 读取 Excel(前台上传)
|
|
250
|
+
|
|
251
|
+
```abap
|
|
252
|
+
DATA: lt_excel TYPE TABLE OF alsmex_tabline.
|
|
253
|
+
|
|
254
|
+
CALL FUNCTION 'ALSM_EXCEL_TO_INTERNAL_TABLE'
|
|
255
|
+
EXPORTING
|
|
256
|
+
filename = p_file
|
|
257
|
+
i_begin_col = 1
|
|
258
|
+
i_begin_row = 1
|
|
259
|
+
i_end_col = 10
|
|
260
|
+
i_end_row = 1000
|
|
261
|
+
TABLES
|
|
262
|
+
intern = lt_excel
|
|
263
|
+
EXCEPTIONS
|
|
264
|
+
inconsistent_parameters = 1
|
|
265
|
+
upload_ole = 2.
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## 常见错误修复
|
|
269
|
+
|
|
270
|
+
| 错误 | 原因 | 修复 |
|
|
271
|
+
|------|------|------|
|
|
272
|
+
| 字段不存在 | 表名字段名拼错 | 用内置 `get_abap_object_info`(TABL)确认字段名 |
|
|
273
|
+
| 类型不匹配 | 数据类型不一致 | 用 `CONV #( )` 或 `CORRESPONDING` |
|
|
274
|
+
| 未声明变量 | 缺少 DATA 声明 | 用内联声明 `@DATA(...)` |
|
|
275
|
+
| 表未声明 | TABLES 缺失 | 添加 `TABLES:` 声明(选择屏幕 FOR 字段需要) |
|
|
276
|
+
| 选择屏幕错误 | FOR 引用字段不存在 | 确认表已声明在 TABLES 中 |
|
|
277
|
+
| `Comma without preceding colon` | `TYPES:` 冒号链内结构体误用 `.` 终止 | 见 `Memory.md` 避坑指南 |
|
|
278
|
+
|
|
279
|
+
## 常用事务码参考
|
|
280
|
+
|
|
281
|
+
| 事务码 | 用途 |
|
|
282
|
+
|--------|------|
|
|
283
|
+
| SE38 | ABAP 编辑器 |
|
|
284
|
+
| SE80 | 对象导航器 |
|
|
285
|
+
| SE11 | 数据字典 |
|
|
286
|
+
| SE16N | 数据浏览器 |
|
|
287
|
+
| ST22 | DUMP 分析 |
|
|
288
|
+
| SM37 | 后台作业 |
|
|
289
|
+
| SU53 | 权限检查 |
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
# 二、ABAP 函数模块(Function Module)
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
name: abap-function
|
|
296
|
+
description: ABAP 函数模块(Function Module)开发参考——函数组结构、参数接口、异常处理模式、常用 BAPI、单元测试。触发场景:编写或修改函数模块/函数组代码,需要接口模板、异常处理写法、BAPI 选型时。
|
|
297
|
+
category: software-development
|
|
298
|
+
agent_created: true
|
|
299
|
+
---
|
|
300
|
+
|
|
301
|
+
# ABAP 函数模块开发参考
|
|
302
|
+
|
|
303
|
+
> 命名与编码规则以 `dev-write` 技能(默认 SAP 官方 Clean ABAP)为唯一权威;本文件只提供代码模板与写法参考。
|
|
304
|
+
> **字段类型建议**:自建表/结构字段允许裸内置类型(`i`/`c`/`n`/`p`/`string`/`char1` 等),保存时仅提示;有合适的 DDIC 数据元素可优先使用。程序内局部变量/参数也允许裸类型(见 dev-write 技能)。
|
|
305
|
+
> **函数模块接口参数命名**:`IV_`/`EV_`/`ET_`/`ES_` 前缀是 SAP 函数模块接口的通行惯例(SE37 界面/社区代码广泛使用),
|
|
306
|
+
> 与类方法的 Clean ABAP 无前缀规则**不同场景不同规则**,接口参数沿用 IV_/EV_ 惯例;函数体内局部变量仍遵循 Clean ABAP(行内声明、无前缀)。
|
|
307
|
+
> 函数模块命名:`Z_<模块>_FM_<描述>`;函数组命名:`Z<模块>G<3位编号>`。
|
|
308
|
+
|
|
309
|
+
## 函数组结构
|
|
310
|
+
|
|
311
|
+
```abap
|
|
312
|
+
FUNCTION-POOL zmmg001.
|
|
313
|
+
|
|
314
|
+
" 全局数据声明(可选,尽量避免)
|
|
315
|
+
DATA: gv_initialized TYPE abap_bool.
|
|
316
|
+
|
|
317
|
+
" 子程序声明(可选)
|
|
318
|
+
FORM f_init.
|
|
319
|
+
ENDFORM.
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## 完整函数模板
|
|
323
|
+
|
|
324
|
+
```abap
|
|
325
|
+
FUNCTION z_mm_fm_get_material.
|
|
326
|
+
*"----------------------------------------------------------------------
|
|
327
|
+
*"*"Local Interface:
|
|
328
|
+
*" IMPORTING
|
|
329
|
+
*" VALUE(IV_MATNR) TYPE MATNR
|
|
330
|
+
*" VALUE(IV_WERKS) TYPE WERKS_D OPTIONAL
|
|
331
|
+
*" EXPORTING
|
|
332
|
+
*" VALUE(ES_MARA) TYPE MARA
|
|
333
|
+
*" VALUE(ES_MARC) TYPE MARC
|
|
334
|
+
*" VALUE(EV_RETURN) TYPE BAPIRET2
|
|
335
|
+
*" TABLES
|
|
336
|
+
*" ET_MARD TYPE MARD_TT OPTIONAL
|
|
337
|
+
*" EXCEPTIONS
|
|
338
|
+
*" MATERIAL_NOT_FOUND
|
|
339
|
+
*" PLANT_NOT_FOUND
|
|
340
|
+
*" INVALID_INPUT
|
|
341
|
+
*"----------------------------------------------------------------------
|
|
342
|
+
|
|
343
|
+
" 输入校验
|
|
344
|
+
IF iv_matnr IS INITIAL.
|
|
345
|
+
RAISE invalid_input.
|
|
346
|
+
ENDIF.
|
|
347
|
+
|
|
348
|
+
" 读取物料主数据(必须写字段列表,禁止 SELECT *)
|
|
349
|
+
SELECT SINGLE matnr, mtart, matkl, meins, maktx
|
|
350
|
+
FROM mara
|
|
351
|
+
INTO CORRESPONDING FIELDS OF @es_mara
|
|
352
|
+
WHERE matnr = @iv_matnr.
|
|
353
|
+
|
|
354
|
+
IF sy-subrc <> 0.
|
|
355
|
+
" 文案走消息类(禁止硬编码中文):MESSAGE ... INTO 取回文本给 BAPIRET2
|
|
356
|
+
MESSAGE e001(zmm) WITH iv_matnr INTO DATA(lv_msg).
|
|
357
|
+
ev_return = VALUE #( type = 'E' id = 'ZMM' number = '001' message = lv_msg ).
|
|
358
|
+
RAISE material_not_found.
|
|
359
|
+
ENDIF.
|
|
360
|
+
|
|
361
|
+
" 读取工厂数据
|
|
362
|
+
IF iv_werks IS NOT INITIAL.
|
|
363
|
+
SELECT SINGLE matnr, werks, dispo, beskz
|
|
364
|
+
FROM marc
|
|
365
|
+
INTO CORRESPONDING FIELDS OF @es_marc
|
|
366
|
+
WHERE matnr = @iv_matnr AND werks = @iv_werks.
|
|
367
|
+
|
|
368
|
+
IF sy-subrc <> 0.
|
|
369
|
+
RAISE plant_not_found.
|
|
370
|
+
ENDIF.
|
|
371
|
+
ENDIF.
|
|
372
|
+
|
|
373
|
+
" 读取库存数据
|
|
374
|
+
SELECT matnr, werks, lgort, labst, umlme
|
|
375
|
+
FROM mard
|
|
376
|
+
INTO CORRESPONDING FIELDS OF TABLE @et_mard
|
|
377
|
+
WHERE matnr = @iv_matnr.
|
|
378
|
+
|
|
379
|
+
ENDFUNCTION.
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
## 参数类型详解
|
|
383
|
+
|
|
384
|
+
### IMPORTING 参数
|
|
385
|
+
```abap
|
|
386
|
+
*" IMPORTING
|
|
387
|
+
*" VALUE(IV_MATNR) TYPE MATNR " 必填
|
|
388
|
+
*" VALUE(IV_WERKS) TYPE WERKS_D OPTIONAL " 可选
|
|
389
|
+
*" REFERENCE(IS_DATA) TYPE ZFIS_DATA " 引用传递(结构)
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### EXPORTING 参数
|
|
393
|
+
```abap
|
|
394
|
+
*" EXPORTING
|
|
395
|
+
*" VALUE(EV_COUNT) TYPE MENGE_D " 计数:可用数量类数据元素,也允许 TYPE i
|
|
396
|
+
*" VALUE(ES_HEADER) TYPE ZFIS_HEADER
|
|
397
|
+
*" REFERENCE(ET_DATA) TYPE ZFITT_DATA
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### TABLES 参数
|
|
401
|
+
```abap
|
|
402
|
+
*" TABLES
|
|
403
|
+
*" ET_ITEMS TYPE ZFITT_ITEMS
|
|
404
|
+
*" ET_LOG TYPE BAPIRET2_TT OPTIONAL
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### CHANGING 参数
|
|
408
|
+
```abap
|
|
409
|
+
*" CHANGING
|
|
410
|
+
*" VALUE(CV_FLAG) TYPE ABAP_BOOL
|
|
411
|
+
*" REFERENCE(CT_DATA) TYPE ZFITT_DATA
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
## 异常处理模式
|
|
415
|
+
|
|
416
|
+
### 模式1:RAISE 异常
|
|
417
|
+
```abap
|
|
418
|
+
IF sy-subrc <> 0.
|
|
419
|
+
RAISE material_not_found.
|
|
420
|
+
ENDIF.
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### 模式2:BAPIRET2 返回(文案必须走消息类,禁止硬编码中文)
|
|
424
|
+
```abap
|
|
425
|
+
DATA: ls_return TYPE bapiret2.
|
|
426
|
+
|
|
427
|
+
" 从消息类 ZMM 取文案(维护在 SE91/文本元素,代码零硬编码)
|
|
428
|
+
MESSAGE e001(zmm) WITH iv_matnr INTO DATA(lv_msg).
|
|
429
|
+
|
|
430
|
+
ls_return = VALUE #(
|
|
431
|
+
type = 'E'
|
|
432
|
+
id = 'ZMM'
|
|
433
|
+
number = '001'
|
|
434
|
+
message = lv_msg
|
|
435
|
+
message_v1 = iv_matnr
|
|
436
|
+
).
|
|
437
|
+
|
|
438
|
+
APPEND ls_return TO et_return.
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### 模式3:TRY-CATCH
|
|
442
|
+
```abap
|
|
443
|
+
TRY.
|
|
444
|
+
DATA(lo_helper) = NEW zcl_mm_material_helper( ).
|
|
445
|
+
lo_helper->validate( iv_matnr ).
|
|
446
|
+
lo_helper->process( iv_matnr ).
|
|
447
|
+
|
|
448
|
+
CATCH zcx_mm_material_error INTO DATA(lx_err).
|
|
449
|
+
ev_return = VALUE #( type = 'E' message = lx_err->get_text( ) ).
|
|
450
|
+
RAISE material_not_found.
|
|
451
|
+
ENDTRY.
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
## 调用方式
|
|
455
|
+
|
|
456
|
+
```abap
|
|
457
|
+
CALL FUNCTION 'Z_MM_FM_GET_MATERIAL'
|
|
458
|
+
EXPORTING
|
|
459
|
+
iv_matnr = lv_matnr
|
|
460
|
+
IMPORTING
|
|
461
|
+
es_mara = ls_mara
|
|
462
|
+
EXCEPTIONS
|
|
463
|
+
material_not_found = 1
|
|
464
|
+
invalid_input = 2
|
|
465
|
+
OTHERS = 3.
|
|
466
|
+
|
|
467
|
+
CASE sy-subrc.
|
|
468
|
+
WHEN 1. MESSAGE e001(zmm) WITH lv_msg1. " 消息文本在消息类 ZMM 维护,禁止 WITH 硬编码中文
|
|
469
|
+
WHEN 2. MESSAGE e002(zmm) WITH lv_msg2.
|
|
470
|
+
WHEN 3. MESSAGE e003(zmm) WITH lv_msg3.
|
|
471
|
+
ENDCASE.
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
## 常用 BAPI 参考
|
|
475
|
+
|
|
476
|
+
### 数据读取
|
|
477
|
+
| 函数 | 用途 |
|
|
478
|
+
|------|------|
|
|
479
|
+
| BAPI_MATERIAL_GET_DETAIL | 读取物料主数据 |
|
|
480
|
+
| BAPI_CUSTOMER_GETDETAIL | 读取客户主数据 |
|
|
481
|
+
| BAPI_SALESORDER_GETDETAIL | 读取销售订单 |
|
|
482
|
+
| ME_READ_INFORECORD | 读取采购信息记录 |
|
|
483
|
+
|
|
484
|
+
### 数据创建
|
|
485
|
+
| 函数 | 用途 |
|
|
486
|
+
|------|------|
|
|
487
|
+
| BAPI_MATERIAL_SAVEDATA | 创建/修改物料 |
|
|
488
|
+
| BAPI_SALESORDER_CREATEFROMDAT2 | 创建销售订单 |
|
|
489
|
+
| BAPI_PO_CREATE1 | 创建采购订单 |
|
|
490
|
+
| BAPI_GOODSMVT_CREATE | 物料移动过账 |
|
|
491
|
+
|
|
492
|
+
### 事务控制
|
|
493
|
+
| 函数 | 用途 |
|
|
494
|
+
|------|------|
|
|
495
|
+
| BAPI_TRANSACTION_COMMIT | 提交事务 |
|
|
496
|
+
| BAPI_TRANSACTION_ROLLBACK | 回滚事务 |
|
|
497
|
+
|
|
498
|
+
## 函数模块测试(ABAP Unit)
|
|
499
|
+
|
|
500
|
+
```abap
|
|
501
|
+
CLASS ltc_material DEFINITION FOR TESTING
|
|
502
|
+
RISK LEVEL HARMLESS
|
|
503
|
+
DURATION SHORT.
|
|
504
|
+
|
|
505
|
+
PRIVATE SECTION.
|
|
506
|
+
DATA: mo_cut TYPE REF TO zcl_mm_material_helper.
|
|
507
|
+
|
|
508
|
+
METHODS: setup,
|
|
509
|
+
test_validate FOR TESTING,
|
|
510
|
+
test_process FOR TESTING.
|
|
511
|
+
|
|
512
|
+
ENDCLASS.
|
|
513
|
+
|
|
514
|
+
CLASS ltc_material IMPLEMENTATION.
|
|
515
|
+
METHOD setup.
|
|
516
|
+
mo_cut = NEW #( ).
|
|
517
|
+
ENDMETHOD.
|
|
518
|
+
|
|
519
|
+
METHOD test_validate.
|
|
520
|
+
DATA(lv_result) = mo_cut->validate( '000000000000001234' ).
|
|
521
|
+
cl_abap_unit_assert=>assert_true( lv_result ).
|
|
522
|
+
ENDMETHOD.
|
|
523
|
+
|
|
524
|
+
METHOD test_process.
|
|
525
|
+
DATA(lv_result) = mo_cut->process( '000000000000001234' ).
|
|
526
|
+
cl_abap_unit_assert=>assert_not_initial( lv_result ).
|
|
527
|
+
ENDMETHOD.
|
|
528
|
+
ENDCLASS.
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
## 函数组设计规范
|
|
532
|
+
|
|
533
|
+
1. **一个函数组一个业务领域**
|
|
534
|
+
- `ZMMG001` — 物料相关函数
|
|
535
|
+
- `ZSDG001` — 销售相关函数
|
|
536
|
+
- `ZFIG001` — 财务相关函数
|
|
537
|
+
|
|
538
|
+
2. **函数命名:`Z<模块>_FM_<动词>_<描述>`**
|
|
539
|
+
- `ZMM_FM_GET_MATERIAL` — 读取数据(GET)
|
|
540
|
+
- `ZSD_FM_CREATE_ORDER` — 创建数据(CREATE)
|
|
541
|
+
- `ZMM_FM_UPDATE_MATERIAL` — 更新数据(UPDATE)
|
|
542
|
+
- `ZSD_FM_CHECK_CREDIT` — 校验数据(CHECK)
|
|
543
|
+
- `ZFI_FM_CALC_TAX` — 计算数据(CALC)
|
|
544
|
+
|
|
545
|
+
3. **避免函数间共享全局数据** — 除非必要,使用参数传递。
|
|
546
|
+
|
|
547
|
+
4. **每个函数只做一件事** — 单一职责原则。
|
|
548
|
+
|
|
549
|
+
# 三、ABAP 类(Class / 面向对象)
|
|
550
|
+
|
|
551
|
+
> Clean ABAP 推荐面向对象优先;新功能优先用类实现。类命名 `ZCL_<模块>_<对象>`(如 ZCL_MM_MATERIAL_HELPER)、异常类 `ZCX_<模块>_<错误>`、接口 `ZIF_<模块>_<能力>`。
|
|
552
|
+
|
|
553
|
+
## 完整类模板
|
|
554
|
+
|
|
555
|
+
```abap
|
|
556
|
+
CLASS zcl_mm_material_helper DEFINITION
|
|
557
|
+
PUBLIC
|
|
558
|
+
FINAL
|
|
559
|
+
CREATE PUBLIC.
|
|
560
|
+
|
|
561
|
+
PUBLIC SECTION.
|
|
562
|
+
" 构造函数:显式声明(需要依赖时)
|
|
563
|
+
METHODS constructor
|
|
564
|
+
IMPORTING
|
|
565
|
+
iv_matnr TYPE matnr OPTIONAL.
|
|
566
|
+
|
|
567
|
+
" 命令式方法:动词命名
|
|
568
|
+
METHODS validate
|
|
569
|
+
IMPORTING
|
|
570
|
+
iv_matnr TYPE matnr
|
|
571
|
+
RETURNING
|
|
572
|
+
VALUE(rv_valid) TYPE abap_bool.
|
|
573
|
+
|
|
574
|
+
" 查询式方法:is_/has_/get_ 命名
|
|
575
|
+
METHODS get_material
|
|
576
|
+
IMPORTING
|
|
577
|
+
iv_matnr TYPE matnr
|
|
578
|
+
RETURNING
|
|
579
|
+
VALUE(rs_mara) TYPE mara
|
|
580
|
+
RAISING
|
|
581
|
+
zcx_mm_material_error.
|
|
582
|
+
|
|
583
|
+
" 类方法(工厂/工具)
|
|
584
|
+
CLASS-METHODS create_instance
|
|
585
|
+
RETURNING
|
|
586
|
+
VALUE(ro_instance) TYPE REF TO zcl_mm_material_helper.
|
|
587
|
+
|
|
588
|
+
PRIVATE SECTION.
|
|
589
|
+
" 实例属性:mv_ / mo_ / mt_ 前缀(DDIC 数据元素类型)
|
|
590
|
+
DATA mv_matnr TYPE matnr.
|
|
591
|
+
DATA mt_items TYPE STANDARD TABLE OF mard WITH EMPTY KEY.
|
|
592
|
+
|
|
593
|
+
" 私有方法
|
|
594
|
+
METHODS read_material
|
|
595
|
+
IMPORTING
|
|
596
|
+
iv_matnr TYPE matnr
|
|
597
|
+
RETURNING
|
|
598
|
+
VALUE(rs_mara) TYPE mara.
|
|
599
|
+
ENDCLASS.
|
|
600
|
+
|
|
601
|
+
CLASS zcl_mm_material_helper IMPLEMENTATION.
|
|
602
|
+
METHOD constructor.
|
|
603
|
+
mv_matnr = iv_matnr.
|
|
604
|
+
ENDMETHOD.
|
|
605
|
+
|
|
606
|
+
METHOD create_instance.
|
|
607
|
+
ro_instance = NEW #( ).
|
|
608
|
+
ENDMETHOD.
|
|
609
|
+
|
|
610
|
+
METHOD validate.
|
|
611
|
+
rv_valid = boolc( iv_matnr IS NOT INITIAL ).
|
|
612
|
+
ENDMETHOD.
|
|
613
|
+
|
|
614
|
+
METHOD get_material.
|
|
615
|
+
rs_mara = read_material( iv_matnr ).
|
|
616
|
+
IF rs_mara-matnr IS INITIAL.
|
|
617
|
+
RAISE EXCEPTION TYPE zcx_mm_material_error
|
|
618
|
+
EXPORTING
|
|
619
|
+
textid = zcx_mm_material_error=>not_found.
|
|
620
|
+
ENDIF.
|
|
621
|
+
ENDMETHOD.
|
|
622
|
+
|
|
623
|
+
METHOD read_material.
|
|
624
|
+
" 显式字段列表,禁 SELECT *
|
|
625
|
+
SELECT SINGLE matnr, mtart, matkl, meins, maktx
|
|
626
|
+
FROM mara
|
|
627
|
+
INTO CORRESPONDING FIELDS OF @rs_mara
|
|
628
|
+
WHERE matnr = @iv_matnr.
|
|
629
|
+
ENDMETHOD.
|
|
630
|
+
ENDCLASS.
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
## 接口实现(IF_OO_* 解耦)
|
|
634
|
+
|
|
635
|
+
```abap
|
|
636
|
+
INTERFACE zif_material_read.
|
|
637
|
+
METHODS get_material
|
|
638
|
+
IMPORTING
|
|
639
|
+
iv_matnr TYPE matnr
|
|
640
|
+
RETURNING
|
|
641
|
+
VALUE(rs_mara) TYPE mara
|
|
642
|
+
RAISING
|
|
643
|
+
zcx_mm_material_error.
|
|
644
|
+
ENDINTERFACE.
|
|
645
|
+
|
|
646
|
+
CLASS zcl_mm_material_reader DEFINITION PUBLIC FINAL CREATE PUBLIC.
|
|
647
|
+
PUBLIC SECTION.
|
|
648
|
+
INTERFACES zif_material_read.
|
|
649
|
+
ENDCLASS.
|
|
650
|
+
|
|
651
|
+
CLASS zcl_mm_material_reader IMPLEMENTATION.
|
|
652
|
+
METHOD zif_material_read~get_material.
|
|
653
|
+
" 实现接口方法(接口名~方法名)
|
|
654
|
+
SELECT SINGLE matnr, mtart, matkl FROM mara
|
|
655
|
+
INTO CORRESPONDING FIELDS OF @rs_mara
|
|
656
|
+
WHERE matnr = @iv_matnr.
|
|
657
|
+
IF sy-subrc <> 0.
|
|
658
|
+
RAISE EXCEPTION TYPE zcx_mm_material_error.
|
|
659
|
+
ENDIF.
|
|
660
|
+
ENDMETHOD.
|
|
661
|
+
ENDCLASS.
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
## 异常类(继承 CX_STATIC_CHECK)
|
|
665
|
+
|
|
666
|
+
```abap
|
|
667
|
+
CLASS zcx_mm_material_error DEFINITION
|
|
668
|
+
INHERITING FROM cx_static_check
|
|
669
|
+
PUBLIC FINAL CREATE PUBLIC.
|
|
670
|
+
|
|
671
|
+
PUBLIC SECTION.
|
|
672
|
+
" 文本 ID:绑定消息类 ZMM 的文本(SE91 维护,禁止硬编码中文)
|
|
673
|
+
CONSTANTS:
|
|
674
|
+
not_found TYPE sotr_conc VALUE '001',
|
|
675
|
+
invalid TYPE sotr_conc VALUE '002'.
|
|
676
|
+
|
|
677
|
+
METHODS get_text REDEFINITION. " 消息文本由 cx_static_check 从消息类取回
|
|
678
|
+
ENDCLASS.
|
|
679
|
+
|
|
680
|
+
CLASS zcx_mm_material_error IMPLEMENTATION.
|
|
681
|
+
ENDCLASS.
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
## 工厂方法 / 单例
|
|
685
|
+
|
|
686
|
+
```abap
|
|
687
|
+
" 单例(惰性)
|
|
688
|
+
CLASS zcl_mm_manager DEFINITION PUBLIC FINAL CREATE PRIVATE.
|
|
689
|
+
PUBLIC SECTION.
|
|
690
|
+
CLASS-METHODS get_instance
|
|
691
|
+
RETURNING
|
|
692
|
+
VALUE(ro_instance) TYPE REF TO zcl_mm_manager.
|
|
693
|
+
PRIVATE SECTION.
|
|
694
|
+
CLASS-DATA go_instance TYPE REF TO zcl_mm_manager.
|
|
695
|
+
ENDCLASS.
|
|
696
|
+
|
|
697
|
+
CLASS zcl_mm_manager IMPLEMENTATION.
|
|
698
|
+
METHOD get_instance.
|
|
699
|
+
IF go_instance IS NOT BOUND.
|
|
700
|
+
go_instance = NEW #( ).
|
|
701
|
+
ENDIF.
|
|
702
|
+
ro_instance = go_instance.
|
|
703
|
+
ENDMETHOD.
|
|
704
|
+
ENDCLASS.
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
## 调用示例
|
|
708
|
+
|
|
709
|
+
```abap
|
|
710
|
+
DATA(lo_helper) = NEW zcl_mm_material_helper( iv_matnr = lv_matnr ).
|
|
711
|
+
|
|
712
|
+
IF lo_helper->validate( lv_matnr ).
|
|
713
|
+
DATA(ls_mara) = lo_helper->get_material( lv_matnr ).
|
|
714
|
+
ENDIF.
|
|
715
|
+
|
|
716
|
+
" 通过接口调用(解耦)
|
|
717
|
+
DATA(lo_reader) = NEW zcl_mm_material_reader( ).
|
|
718
|
+
lo_reader->zif_material_read~get_material( lv_matnr ).
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
## 类单元测试(ABAP Unit)
|
|
722
|
+
|
|
723
|
+
```abap
|
|
724
|
+
CLASS ltc_material DEFINITION FOR TESTING
|
|
725
|
+
RISK LEVEL HARMLESS
|
|
726
|
+
DURATION SHORT.
|
|
727
|
+
|
|
728
|
+
PRIVATE SECTION.
|
|
729
|
+
DATA mo_cut TYPE REF TO zcl_mm_material_helper.
|
|
730
|
+
|
|
731
|
+
METHODS setup,
|
|
732
|
+
test_validate_ok FOR TESTING,
|
|
733
|
+
test_get_material_raises FOR TESTING.
|
|
734
|
+
|
|
735
|
+
ENDCLASS.
|
|
736
|
+
|
|
737
|
+
CLASS ltc_material IMPLEMENTATION.
|
|
738
|
+
METHOD setup.
|
|
739
|
+
mo_cut = NEW #( ).
|
|
740
|
+
ENDMETHOD.
|
|
741
|
+
|
|
742
|
+
METHOD test_validate_ok.
|
|
743
|
+
cl_abap_unit_assert=>assert_true( mo_cut->validate( '000000000000001234' ) ).
|
|
744
|
+
ENDMETHOD.
|
|
745
|
+
|
|
746
|
+
METHOD test_get_material_raises.
|
|
747
|
+
TRY.
|
|
748
|
+
mo_cut->get_material( '000000000000009999' ).
|
|
749
|
+
cl_abap_unit_assert=>fail( 'expected exception was not raised' ).
|
|
750
|
+
CATCH zcx_mm_material_error.
|
|
751
|
+
" 预期异常,测试通过
|
|
752
|
+
ENDTRY.
|
|
753
|
+
ENDMETHOD.
|
|
754
|
+
ENDCLASS.
|
|
755
|
+
```
|
|
756
|
+
|
|
757
|
+
## 设计规范(Clean ABAP 核心)
|
|
758
|
+
|
|
759
|
+
1. **单一职责**:一个类只做一件事;方法短小(≤15 行)
|
|
760
|
+
2. **依赖注入**:构造函数收依赖(`mo_dep`),不内部 `NEW` 硬编码
|
|
761
|
+
3. **属性私有**:`PRIVATE SECTION` 收好状态,通过方法暴露行为
|
|
762
|
+
4. **异常而非返回码**:错误用 `RAISE EXCEPTION`,不返回 `ev_error`
|
|
763
|
+
5. **不可变优先**:能 `READ-ONLY` / `FINAL` 就声明
|
|
764
|
+
6. **命名**:类=名词、方法=动词(命令式)、查询=is_/has_/get_;属性 `mv_/mo_/mt_` 前缀
|