Tipps zur Verwendung der Userexits

Die Userexits der Auftragserfassung sind komplex und nicht immer einfach zu bedienen. Hier sehen Sie, worauf Sie achten sollten und wie Sie sich das Leben in den Userexits leichter machen.

Legen Sie eine Steuertabelle je Verkaufsorganisation/ Vertriebsweg/ Auftragsart an. Felder: VKORG, VTWEG, AUART, EXIT001, EXIT002, …, EXIT030. Legen Sie auch einen Tabellenpflegedialog hierzu an.

Eventuell ist es sinnvoll, eine zweite Steuertabelle zu basteln, die Userexits je Positionstyp/ Werk/ Materialart/… aktiviert.

Variablen global mit einem klar erkennbaren Präfix definieren, evtl sogar mit der Nummer des Userexits, in dem sie verwendet wird. Z. B. ZXEXIT_… oder ZXEXIT003_…

Alle Variablen im USEREXIT_REFRESH_DOCUMENT initialisieren!!

Es kann hilfreich sein, alle Userexits in eigene Includes auszulagern. Dies hat den Vorteil, dass sich Entwickler, die an verschiedenen Routinen arbeiten, die aber in einem Include (z.B. MV45AFZZ) stehen, nicht gegenseitig behindern.

Variablen, die nur in einer Routine verwendet werden auch in dieser deklarieren.
FORM-Routinen müssen immer mit einem klar erkennbaren Präfix beginnen und evtl. die Nummer des Userexits beinhalten. Bsp: ZEXIT003_PHN_PRUEFEN.

Aufpassen bei Popups: Diese dürfen nur im Dialog erscheinen, nicht im Batchinput!

In eigenen Routinen immer die Arbeitsbereiche sichern (VBAP, *VBAP, XVBAP, SVBAP etc)!! Die SAPMV45A ist sehr anfällig für Fehler, wenn die Arbeitsbereiche nicht übereinstimmen, bzw doch übereinstimmen (je nach Situation). Änderungen in den Arbeitsbereichen sehr sorgfältig prüfen!! Gerade im Zusammenhang mit PP!

Beispiel:

form zxexit_003_pruefenxyz.
  data: 
    f_vbap  like xvbap,
    f_xvbap like xvbap.

  f_xvbap = xvbap.
  f_vbap  = vbap.
  read table xvbap with key posnr = vbap-posnr.
  …
  …
  xvbap = f_xvbap.
  vbap  = f_vbap.
endform.

Bei Daten, die in internen Tabellen gehalten werden (VBAP, VBEP, VBPA, VBKD etc) gilt: Die X-Tabelle enthält die aktuell gültigen Daten; Die Y-Tabelle die Daten vor der Änderung. Diese Tabellen haben alle ein UPDKZ — ein Updatekennzeichen. Hierbei gibt es:
  U für Update
  I für Insert
  D für Delete

Beim Ändern der internen X-Tabellen den Hinweis 216448 beachten. Hier wird beschrieben, welche Updatekennzeichen wann gesetzt werden müssen. Wichtig im Zusammemnhang mit Business Warehouse!! Hier können falsche Updatekennzeichen, die in der Verbuchung SAPMV45A korrekt funktionieren, doppelte Einträge erzeugen!

Alle Funktionen sollten in Unterroutinen gepackt werden. Je Userexit sollte es ein eigenes Include geben. Userexits können so einfach deaktiviert werden. Bei Änderungen an mehreren Userexits können die einzelnen Stände einzeln transportiert werden, ohne dass jeder Entwickler auf den anderen warten muss, bis das coding vollständig ist. Die Includes sollten in einer eigenen Entwicklungsklasse liegen (z. B. ZV45A_USEREXIT).

Die Beschreibung der Userexits sollte im entsprechenden Datenelement der Steuertabelle erfolgen. Das bedeutet zwar, dass für jeden Userexit ein eigenes Datenelement anzulegen ist, hat aber den vorteil, dass die Dokumentation direkt an diesem Feld verfügbar ist. Ausserdem kann eine Tabellendokumentation mit Ausgabe der Datenelementdokumentation gedruckt werden und schon gibt es eine vollständige Dokumentation über alle Exits.

Zu jeder Routine sollten zwei Ansprechpartner im Coding oder in der Dokumentation genannt werden, damit andere Programmierer bei evtl. Änderungen Fragen an diese beiden loswerden können.

In der Dokumentation sollte festgehalten werden, was betriebswirtschaftlich und technisch mit diesem Exit erreicht werden soll. Eine Beschreibung „Hier wird das Feld ‚VBAP-XYZ01‘ auf nicht eingabebereit gesetzt“ reicht nicht aus, da hieraus der Sinn des Exits nicht erkennbar ist. Besser: „Hier wird das Feld ‚VBAP-XYZ01‘ auf nicht eingabebereit gesetzt, um zu verhindern, dass bei Aufträgen mit Auftragsart ‚ABC‘ dieses und jenes passiert.“.

Jeder (!!!) Userexit sollte durch einen globalen Parameter abgestellt werden können. Es könnte eine Tabelle geben, in der lediglich ein Eintrag steht: „Userexits Aktiv“ oder „Userexits nicht aktiv„, den jede Unterroutine prüfen muss. Hiermit ist es möglich, alle Userexits mit einem Klick auszuschalten und das Standard-Systemverhalten zu prüfen. Dies ist hilfreich bei Fehlern, die schwer nachzuvollziehen sind. Oftmals haben falsch programmierte Userexits große Auswirkungen, die man gar nicht den Exits in Verbindung bringt. Ein kurzer Klick bringt in diesem Falls schnell Gewißheit.

Mit Error-Meldungen (MESSAGE E123) sollte vorsichtig umgegangen werden, da sie oft nicht wie erwartet reagieren. So kann es schnell passieren, dass eine Error-Meldung ausgegeben wird, weil ein inhaltlich falscher Wert in einem Feld in der Positionsübersicht steht. Wenn der Anwender nun ohne <Enter> zu drücken über „Springen – Kopf – …“ in eine andere Sicht springt, kann die Fehlermeldung evtl. erst auf diesem Bild erscheinen. Der Anwender erhält die Meldung „Feld XYZ Wert ABC nicht erlaubt.“, obwohl dieses Feld auf dieser Sicht gar nicht vorhanden ist. Ausserdem sind durch die Fehlermeldung keine Felder mehr eingabebereit. Besser bzw. sicherer ist es, in diesem Fall nur eine Warnmeldung auszugeben und die selbe Prüfung beim Sichern des Beleges noch einmal durchzuführen. Beim Sichern können alle Meldungen gesammelt und dann ausgegeben werden (Funktionsbausteine MESSAGES_INITIALIZE, MESSAGE_STORE und MESSAGES_SHOW). Der FCODE sollte dann auf „ENT1“ gesetzt werden und eine Fehlermeldung erzeugt werden, um das Sichern des Beleges zu verhindern. Durch setzen der Variablen FCODE auf „ENT1“, kann die Fehlermeldung wie eine Warnmeldung bestätigt werden.

So weit es geht und vom Aufwand her sinnvoll ist, sollten standardisierte Popupfenster benutzt werden. Je nachdem, wie sie gebraucht werden etwa:
           Meldung/ Beschreibung 
           Zeile 2
           Zeile 3

           [Ja] [Nein] [Abbrechen].

Beachten Sie: [Nein] und [Abbrechen] haben oftmals die gleiche Bedeutung!! Deshalb sollte bei gleicher Bedeutung der beiden Tasten eine davon weggelassen werden!

Falls viele unterschiedliche Prüfungen bei der Eingabe gemacht werden und jede Prüfung eine eigene Warnmeldung erzeugt, könnte man über das Sammeln der Meldungen zu einer Position nachdenken, die dann zusammen angezeigt werden, damit der Anwender nicht unnötig viele Warnungen bestätigen muss. Hier könnte es etwas diffizil sein, den geeigneten Zeitpunkt zu finden, die Meldungen auszugeben, da ja nicht jeder Userexit immer durchlaufen wird, sondern nur wenn entsprechende Felder geändert wurden.

Die Gefahr, dass eine wichtige Warnung unter vielen anderen untergeht, ist stets gegeben. Deshalb sollten Warnungen oder Informationsmeldungen, die für den Anwender keinen Nutzen bzw. keine Auswirkung haben auch nicht angezeigt werden. Eventuell könnte sogar über eine Tabelle mit „Fehlermeldungen, die bestimmte Anwender/ Anwendergruppen/ ab einem bestimmten Auftragsstaus nicht interessieren“ nachgedacht werden… In einer zentralen Routine „Meldung vom Typ X ausgeben“ könnte dies dann abgefragt werden.

Nützlich zur Fehlersuche wäre evtl. eine Debug-Funktion für jeden Userexit. Diese Debug-Routine könnte in jedem Userexit implementiert werden, um die Aufrufreihenfolge der einzelnen Userexits bei bestimmten Datenänderungen zu Protokollieren. Der Funktionscode, Datum/Uhrzeit Routinen und bestimmte Variablen könnten in einer separaten Debugtabelle gespeichert werden.

Prüfen Sie, ob Aufträge per BAPI angelegt werden! Beim Aufruf des BAPI_SALESDOCUMENT_CREATE gibt es die Möglichkeit der Simulation! Hierbei werden jedoch weder Routine USEREXIT_SAVE_DOCUMENT_PREPARE noch USEREXIT_SAVE_DOCUMENT durchlaufen!
Prüfungen, die direkt vor dem Sichern des Beleges erfolgen (SAVE_DOCUMENT_PREPARE) und ein Sichern verhindern würden, greifen also im Simulationsmodus nicht! Der BAPI würden melden „Auftrag konnte angelegt werden“!

Enno Wulff
follow me