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.
Files changed (55) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +12 -4
  3. package/defaults/AGENTS.md +114 -114
  4. package/defaults/connections.example.json +21 -21
  5. package/defaults/prompts/Memory.md +21 -21
  6. package/defaults/prompts/SYSTEM.md +110 -110
  7. package/defaults/settings.example.json +3 -3
  8. package/dist/sap-tools/adtManager.d.ts +11 -1
  9. package/dist/sap-tools/adtManager.js +176 -9
  10. package/dist/sap-tools/connections-store.js +4 -1
  11. package/dist/sap-tools/execution.js +1 -1
  12. package/dist/tools.js +5 -3
  13. package/package.json +5 -3
  14. package/skills/abap-code-review/SKILL.md +75 -75
  15. package/skills/abap-code-review/assets/report-template.html +142 -142
  16. package/skills/abap-code-review/references/checklist.md +114 -114
  17. package/skills/abap-explain/SKILL.md +126 -126
  18. package/skills/abap-templates/SKILL.md +764 -764
  19. package/skills/abap-wiki/SKILL.md +104 -104
  20. package/skills/clean-abap/SKILL.md +91 -91
  21. package/skills/clean-abap/references/CleanABAP_zh.md +4309 -4309
  22. package/skills/dev-write/SKILL.md +137 -137
  23. package/skills/sap-abap-skills/README.md +205 -205
  24. package/skills/sap-abap-skills/SKILL.md +498 -498
  25. package/skills/sap-abap-skills/references/abap-dictionary.md +211 -211
  26. package/skills/sap-abap-skills/references/abap-sql.md +588 -588
  27. package/skills/sap-abap-skills/references/amdp.md +279 -279
  28. package/skills/sap-abap-skills/references/authorization.md +149 -149
  29. package/skills/sap-abap-skills/references/bits-bytes.md +92 -92
  30. package/skills/sap-abap-skills/references/builtin-functions.md +373 -373
  31. package/skills/sap-abap-skills/references/cds-views.md +412 -412
  32. package/skills/sap-abap-skills/references/cloud-development.md +299 -299
  33. package/skills/sap-abap-skills/references/constructor-expressions.md +458 -458
  34. package/skills/sap-abap-skills/references/date-time.md +415 -415
  35. package/skills/sap-abap-skills/references/design-patterns.md +292 -292
  36. package/skills/sap-abap-skills/references/dynamic-programming.md +426 -426
  37. package/skills/sap-abap-skills/references/exceptions.md +432 -432
  38. package/skills/sap-abap-skills/references/generative-ai.md +180 -180
  39. package/skills/sap-abap-skills/references/internal-tables.md +578 -578
  40. package/skills/sap-abap-skills/references/numeric-operations.md +219 -219
  41. package/skills/sap-abap-skills/references/object-orientation.md +518 -518
  42. package/skills/sap-abap-skills/references/performance.md +428 -428
  43. package/skills/sap-abap-skills/references/program-flow.md +302 -302
  44. package/skills/sap-abap-skills/references/rap-eml.md +549 -549
  45. package/skills/sap-abap-skills/references/released-classes.md +308 -308
  46. package/skills/sap-abap-skills/references/sap-luw.md +203 -203
  47. package/skills/sap-abap-skills/references/skill-reference-guide.md +98 -98
  48. package/skills/sap-abap-skills/references/sql-hierarchies.md +180 -180
  49. package/skills/sap-abap-skills/references/string-processing.md +488 -488
  50. package/skills/sap-abap-skills/references/table-grouping.md +150 -150
  51. package/skills/sap-abap-skills/references/tool-guide.md +285 -285
  52. package/skills/sap-abap-skills/references/unit-testing.md +512 -512
  53. package/skills/sap-abap-skills/references/where-conditions.md +223 -223
  54. package/skills/sap-abap-skills/references/xml-json.md +315 -315
  55. 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_` 前缀