Functiemodules, BAPI's & RFC
Code opdelen en hergebruiken: subroutines (legacy), functiemodules en function groups, BAPI's als officiële API's, RFC-varianten en het BAPIRET2-foutafhandelingspatroon.
01Subroutines: PERFORM & FORM (legacy)
Subroutines zijn de oudste vorm van modularisatie in ABAP. Nieuwe code hoort ze niet meer te gebruiken (schrijf methoden), maar je komt ze in vrijwel elk bestaand programma tegen — dus je moet ze kunnen lezen.
PERFORM bereken_totaal
USING lv_aantal lv_prijs
CHANGING lv_totaal.
FORM bereken_totaal
USING iv_aantal TYPE i
iv_prijs TYPE p
CHANGING cv_totaal TYPE p.
cv_totaal = iv_aantal * iv_prijs.
ENDFORM.
USING-parameters zijn bedoeld als invoer,CHANGINGals in/uitvoer — maar let op: USING beschermt niet tegen wijzigen. Beide worden standaard by-reference doorgegeven; alleen metUSING VALUE(iv_x)krijg je een kopie.- Parameters zonder
TYPEzijn volledig ongetypeerd — een bekende bron van fouten in oude code. TABLES-parameters bij FORM's geven interne tabellen (met header line!) door; ook dit is verouderd.- Sinds ABAP 7.50+ zijn FORM's officieel obsoleet; in ABAP Cloud zijn ze verboden. Zie Clean ABAP.
02Functiemodules & function groups
Een functiemodule (FM) is een globaal aanroepbare procedure, beheerd in transactie SE37. FM's leven altijd in een function group (SE80/SE37), die de gedeelde globale data en includes bevat. Een function group wordt als geheel in het geheugen geladen zodra je één van zijn FM's aanroept — en blijft geladen voor de rest van de sessie (dus globale data blijft bewaard tussen aanroepen!).
CALL FUNCTION 'CONVERSION_EXIT_ALPHA_INPUT'
EXPORTING
input = lv_matnr_ruw
IMPORTING
output = lv_matnr.
Parametersoorten
| Soort | Richting (vanuit de aanroeper) | Opmerking |
|---|---|---|
EXPORTING | Jij geeft data aan de FM | In de FM-definitie heet dit IMPORTING — de richting is altijd vanuit het eigen perspectief. |
IMPORTING | Jij krijgt data terug | Optioneel weg te laten als je het resultaat niet nodig hebt. |
CHANGING | Beide richtingen | In/uitvoer. |
TABLES | Interne tabellen, beide richtingen | Verouderd maar alomtegenwoordig (o.a. in BAPI's). |
EXCEPTIONS | Foutcodes | Klassieke, niet-class-based fouten; zie hieronder. |
Klassieke exceptions afhandelen
CALL FUNCTION 'ENQUEUE_EZMIJN_LOCK'
EXPORTING
matnr = lv_matnr
EXCEPTIONS
foreign_lock = 1
system_failure = 2
OTHERS = 3.
CASE sy-subrc.
WHEN 0. " ok
WHEN 1. MESSAGE e001(zmm) WITH lv_matnr. " al vergrendeld
WHEN OTHERS. " onverwacht
ENDCASE.
Je koppelt elke exception aan een getal; na de aanroep staat dat getal in sy-subrc. Vergeet je de EXCEPTIONS-lijst en de FM gooit toch een exception, dan volgt een runtime-dump. Moderne code gebruikt class-based exceptions.
- RFC-enabled FM's (vinkje "Remote-Enabled Module") kunnen vanaf andere systemen worden aangeroepen — zie RFC.
- Update-FM's (processing type "Update module") worden gebruikt met
IN UPDATE TASK— zie SAP LUW. - Eigen FM's beginnen met
Z_; testbaar direct vanuit SE37 (F8) — heel handig om standaard-FM's te verkennen.
03BAPI's: de officiële API van SAP
Een BAPI (Business Application Programming Interface) is een door SAP vrijgegeven, stabiele, RFC-enabled functiemodule om businessobjecten te lezen of te muteren. Naamconventie: BAPI_<object>_<werkwoord>, bijvoorbeeld BAPI_SALESORDER_CREATEFROMDAT2, BAPI_MATERIAL_SAVEDATA, BAPI_USER_GET_DETAIL. Overzicht per module: zie Tabellen & BAPI's per module.
Het vaste patroon
DATA lt_return TYPE STANDARD TABLE OF bapiret2.
CALL FUNCTION 'BAPI_SALESORDER_CREATEFROMDAT2'
EXPORTING
order_header_in = ls_header
order_header_inx = ls_headerx " X-structuur: welke velden tellen
IMPORTING
salesdocument = lv_vbeln
TABLES
return = lt_return
order_items_in = lt_items
order_items_inx = lt_itemsx
order_partners = lt_partners.
" Fouten checken vóór de commit
IF line_exists( lt_return[ type = 'E' ] )
OR line_exists( lt_return[ type = 'A' ] ).
CALL FUNCTION 'BAPI_TRANSACTION_ROLLBACK'.
ELSE.
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
EXPORTING wait = abap_true. " wacht tot de update-task klaar is
ENDIF.
BAPI_TRANSACTION_COMMIT (of ROLLBACK) aan. ② Controleer altijd de RETURN-tabel op type E (error) en A (abort) vóór je commit. ③ Gebruik wait = abap_true als je direct daarna de aangemaakte data wilt lezen — anders is de asynchrone update mogelijk nog niet klaar.X-structuren (update-vlaggen)
Bij wijzigings-BAPI's (bijv. BAPI_SALESORDER_CHANGE) geef je náást de datastructuur een gelijknamige X-structuur mee. Elk veld daarin krijgt 'X' als het corresponderende dataveld daadwerkelijk gewijzigd moet worden — velden zonder X worden genegeerd. Zo kan de BAPI onderscheid maken tussen "leegmaken" en "niet aanraken".
ls_header-purch_no_c = 'PO-4711'.
ls_headerx-purch_no_c = 'X'.
ls_headerx-updateflag = 'U'. " U = update (bij CHANGE-BAPI's)
04BAPIRET2: de standaard-retourstructuur
Vrijwel elke BAPI retourneert meldingen in tabelvorm met regeltype BAPIRET2. Leer deze structuur uit je hoofd — je gebruikt hem dagelijks.
| Veld | Betekenis |
|---|---|
TYPE | S succes, I info, W waarschuwing, E fout, A abort. Zie MESSAGE-types. |
ID | Berichtklasse (SE91), bijv. V1. |
NUMBER | Berichtnummer binnen de klasse, bijv. 045. |
MESSAGE | De volledig samengestelde, vertaalde tekst. |
MESSAGE_V1..V4 | De vier variabele delen (&-plaatshouders). |
PARAMETER / ROW / FIELD | Op welk invoerveld/regel de melding slaat. |
LOOP AT lt_return ASSIGNING FIELD-SYMBOL(<ls_ret>)
WHERE type CA 'EA'.
MESSAGE ID <ls_ret>-id TYPE 'S' NUMBER <ls_ret>-number
WITH <ls_ret>-message_v1 <ls_ret>-message_v2
<ls_ret>-message_v3 <ls_ret>-message_v4
DISPLAY LIKE 'E'.
ENDLOOP.
De truc TYPE 'S' ... DISPLAY LIKE 'E' toont de melding als fout (rood) zonder de programmastroom hard af te breken.
05RFC: aanroepen over systeemgrenzen
Remote Function Call is SAP's protocol om functiemodules in een ander systeem aan te roepen. Bestemmingen (destinations) beheer je in transactie SM59.
| Variant | Syntax | Gedrag |
|---|---|---|
| Synchroon (sRFC) | CALL FUNCTION 'Z_X' DESTINATION 'SYSB' | Wacht op het antwoord. Standaard. |
| Asynchroon (aRFC) | CALL FUNCTION ... STARTING NEW TASK 'T1' | Loopt parallel; resultaat optioneel via RECEIVE RESULTS in een callback. Ook lokaal bruikbaar voor parallellisatie. |
| Transactioneel (tRFC) | CALL FUNCTION ... IN BACKGROUND TASK | Gegarandeerd precies één keer uitgevoerd, bij de eerstvolgende COMMIT WORK. Monitoring: SM58. |
| Gequeued (qRFC) | tRFC + queuenaam | Als tRFC, maar met gegarandeerde volgorde binnen de queue. Monitoring: SMQ1/SMQ2. |
CALL FUNCTION 'RFC_READ_TABLE' DESTINATION 'ERPCLNT100'
EXPORTING query_table = 'T001'
TABLES data = lt_data
EXCEPTIONS
communication_failure = 1 MESSAGE lv_msg
system_failure = 2 MESSAGE lv_msg.
- De speciale destination
'NONE'roept aan in dezelfde systeeminstantie maar in een aparte werkprocescontext. - De twee systeem-exceptions
communication_failureensystem_failurehoren bij élke RFC-aanroep afgevangen te worden; metMESSAGE lv_msgvang je de fouttekst. - Modernere alternatieven voor systeemintegratie: OData-services, IDocs, en (in cloudscenario's) HTTP/REST via
CL_HTTP_CLIENTofIF_WEB_HTTP_CLIENT.