Die Übersicht über SAP Transportaufträge im Transport Management System zu behalten, ist ohne ChaRM nicht einfach. In welche Systeme, welche Aufträge importiert sind, wird häufig manuell und fehleranfällig über eine Schattenbuchhaltung in Excel realisiert. In diesem Beitrag implementieren wir einen TMS Auftragsmonitor, der uns die Übersicht über die Importe liefert. Damit wird kein Auftrag mehr irgendwo vergessen. Dies ist der 2. Teil unserer TMS Helpertools, nachdem wir im 1. Teil einen Transport von Kopien Erzeuger implementiert haben.
Benutzung des TMS Auftragsmonitor
Beim Start des Programms ZBC_TMS_REQUEST_MONITOR öffnet sich der Selection Screen. Über das Start- und Endedatum wählst Du den zu analysierenden Zeitraum aus. Das Programm analysiert alle in diesem Zeitraum freigegebenen Aufträge. Optional kannst Du die Selektion auf ein oder mehrere Transportaufträge weiter einschränken.

Das Programm selektiert die Aufträge und ermittelt aus der TMS Konfiguration die beteiligten Systeme (Test, PreProd, Produktion…). Für jedes gefundene System liest das Programm per Remote Function Call die Import Historie.
Die Ausgabe des Programms ist ein ALV Grid, in dem eine einzelne Zeile den Importstatus des Auftrags in den beteiligten Systemen anzeigt. Auf der Abbildung sieht man, dass die Systemlandschaft in diesem Fall aus dem Testsystem CC2, einem weiteren Testsystem CC7, dem PreProd System PL2 und dem Produktivsystem PC2 besteht. Für jedes System ist der Import Returncode sowie der Importzeitpunkt sichtbar. Die Erzeugung der Grid Spalten erfolgt dynamisch, da die SAP Systemlandschaft bei Dir sicherlich anders aussieht.
In unserem Beispiel ist noch kein Auftrag in CC7 importiert. Der Auftrag EC2K915770 ist in alle Systeme bis zur Produktion PC2 importiert. Der Auftrag EC2K915837 ist nur in das CC2 importiert. Die Importe in die Folgesysteme sind noch ausstehend. Im Grid siehst Du ausstehende Importe daran, dass die Zellen leer sind.
Über Hyperlinks im Grid kann zum einen zum Transportauftrag und zum anderen zum Transportprotokoll navigiert werden. Die Abbildung zeigt den Aufrag EC2K915837. Gut zu sehen ist, dass er für den Import in PC2 und PL2 vorgemerkt ist und in CC2 bereits importiert wurde. Dies ist also ein Auftrag, der das Produktivsystem noch nicht erreicht hat und im Status Test ist.

TMS Import Historie
Die Importhistorie ist im SAPGUI in Transaktion STMS nach Auswahl des Systems und Wählen des Menüpunkt Springen\Import Historie zugreifbar. Das Programm kann also aus dem Entwicklungssystem heraus ermitteln, wo die Aufträge bereits importiert wurden. Deshalb ist dieses Programm vollständig funktionsfähig, wenn Du es in Deinem Entwicklungssystem implementierst.

Implementierung
Den Code kannst Du hier herunterladen. Das Programm ZBC_TMS_REQUEST_MONITOR besteht aus den folgenden Teilen
- Klasse LCL_UI_CTR: UI Logik zur Darstellung der Infos im Grid
- Klasse LCL_TMS_CTR: Auswertung der Aufträge und Import Historien
- Interface LIF_CONST: Typen und Konstanten, welche durch UI- und TMS-Controller benutzt werden
- Klasse LCL_TEST: Unit Test Klasse für den TMS-Controller
- Klasse LCX_T100: Ausnahmeklasse, welche eine T100-Nachricht kapselt
Implementierung Importhistorie auswerten
Die Logik zur Auswertung der Import Historie steckt zum größten Teil in der Methode lcl_tms_ctr, query_request. Die Aufträge werden aus den Tabellen e070 und e07t selektiert. Die Importhistorie für einen Zeitraum und einem SAP System geschieht über Funktionsbaustein TMS_TM_GET_HISTORY. Intern nutzt der Baustein RFCs, um via den RFC-Destinationen TMSADM* die Informationen aus den Systemen zu ermitteln. Das ist übrigens unter dem Sicherheitsaspekt kein Problem, da der verwendete Systembenutzer TMSADM im Mandanten 000 nur die relevanten TMS-Funktionsbausteine aufrufen kann und sonst nichts.
METHOD query_request.
DATA lt_request TYPE lif_const=>tt_request.
DATA lt_sysnam TYPE lif_const=>tt_synam.
DATA lv_domnam TYPE tmsdomnam.
FIELD-SYMBOLS <lv_sysnam> TYPE tmssysnam.
DATA lv_start_date TYPE d.
DATA lv_start_time TYPE t VALUE '000000'.
DATA lv_end_date TYPE d.
DATA lv_end_time TYPE t VALUE '235959'.
DATA lt_alog TYPE tmstpalogs.
DATA ls_alert TYPE stmscalert.
REFRESH et_request_mon.
* Aufträge gemäß Selektion selektieren
SELECT
e070~trkorr
e070~trfunction
e070~as4date
e070~as4time
e07t~as4text
FROM e070 LEFT OUTER JOIN e07t ON
e070~trkorr = e07t~trkorr
* Keine Selektion über e07t~langu, weil es unterschiedliche
* Sprachen sein können
INTO TABLE lt_request WHERE
e070~trfunction IN (lif_const=>gc_enum_trfunction-workbench_request, lif_const=>gc_enum_trfunction-customizing_request) AND
e070~trstatus = lif_const=>gc_enum_trstatus-released AND
e070~trkorr IN it_rng_trkorr AND
e070~as4date BETWEEN iv_start_date AND iv_end_date.
IF sy-subrc <> 0.
lcx_t100=>raise_exc_by_msg( |Keine freigegebenen Cust/Wrkb-Aufträge in Zeitraum gefunden| ).
ENDIF.
* Aus der TMS Konfiguration die beteiligten System sowie die Domäne ermitteln
read_tms_config(
IMPORTING
et_sysnam = lt_sysnam
ev_domnam = lv_domnam ).
lv_start_date = iv_start_date.
lv_end_date = iv_end_date.
* Für jeden System die Importhistorie ermitteln
LOOP AT lt_sysnam ASSIGNING <lv_sysnam>.
CALL FUNCTION 'TMS_TM_GET_HISTORY'
EXPORTING
iv_system = <lv_sysnam>
iv_domain = lv_domnam
IMPORTING
et_tmstpalog = lt_alog
es_exception = ls_alert
CHANGING
cv_start_date = lv_start_date
cv_start_time = lv_start_time
cv_end_date = lv_end_date
cv_end_time = lv_end_time
EXCEPTIONS
alert = 1
OTHERS = 2.
IF sy-subrc <> 0.
* Adaptiert aus FuBa TMW_TM_GET_HISTORY.
* Nachricht TP 702: Keine Protokolleinträge im selektierten Bereich
IF ( lt_alog IS INITIAL AND
ls_alert-msgid = 'TP' AND
ls_alert-msgno = '702' ) OR
ls_alert-error <> 'OK'. "Fehler bei Zugriff auf das System
* System ignorieren
CONTINUE.
ELSE.
lcx_t100=>raise_exc_by_sy( ).
ENDIF.
ENDIF.
* Sortierung des alogs wegen Binary Search in Methode fill_request_mon
SORT lt_alog BY trkorr.
* Ausgabetabelle in Parameter et_request_mon füllen
fill_request_mon(
EXPORTING
iv_sysnam = <lv_sysnam>
it_request = lt_request
it_alog = lt_alog
CHANGING
ct_request_mon = et_request_mon ).
ENDLOOP.
ENDMETHOD.
Die Methode fill_request_mon bereitet die Infos aus der Importhistorie auf. Der folgende Debugger Screenshot zeigt die in dieser Methode aufgebaute Datenstruktur.
Implementierung UI Grid aufbauen
Die Implementierung des UI Controllers ist nicht ganz so einfach, weil die Datenstruktur für das Grid nicht statisch definierbar ist. Für jedes SAP System der Transportdomäne werden 2 Spalten für Returncode und Importzeitpunkt benötigt. Der Code nutzt deshalb exzessiv dynamische Programmierung zur Erzeugung von Datentypen -objekten (Klassen cl_abap_structdescr etc., ABAP-Kommando CREATE DATA). Die folgende Methode lcl_ui_ctr, init_ui_data_structure zeigt exemplarisch den dynamischen Aufbau der UI Struktur für das ALV Grid. Ergebnis der Methode ist eine Referenz auf eine interne Tabelle, welche die Felder passend zur SAP Systeminfrastruktur enthält.
METHOD init_ui_data_structure.
DATA lr_tabledescr TYPE REF TO cl_abap_tabledescr.
DATA lr_structdescr TYPE REF TO cl_abap_structdescr.
DATA lt_comp TYPE abap_component_tab.
DATA ls_comp TYPE abap_componentdescr.
* Jedes Feld aus Type lif_const=>ts_request aufnehmen
ls_comp-name = 'TRKORR'.
ls_comp-type ?= cl_abap_elemdescr=>describe_by_name( 'TRKORR' ).
APPEND ls_comp TO lt_comp.
ls_comp-name = 'TRFUNCTION'.
ls_comp-type ?= cl_abap_elemdescr=>describe_by_name( 'TRFUNCTION' ).
APPEND ls_comp TO lt_comp.
ls_comp-name = 'AS4DATE'.
ls_comp-type ?= cl_abap_elemdescr=>describe_by_name( 'AS4DATE' ).
APPEND ls_comp TO lt_comp.
ls_comp-name = 'AS4TIME'.
ls_comp-type ?= cl_abap_elemdescr=>describe_by_name( 'AS4TIME' ).
APPEND ls_comp TO lt_comp.
ls_comp-name = 'AS4TEXT'.
ls_comp-type ?= cl_abap_elemdescr=>describe_by_name( 'AS4TEXT' ).
APPEND ls_comp TO lt_comp.
* Jetzt für jedes System die Infos aus lif_const=>ts_request_imp aufnehmen
LOOP AT it_sysnam ASSIGNING FIELD-SYMBOL().
ls_comp-name = get_fieldname(
iv_fieldname = 'RETCODE'
iv_sysnam = ).
ls_comp-type ?= cl_abap_elemdescr=>describe_by_name( 'TRRETCODE' ).
APPEND ls_comp TO lt_comp.
ls_comp-name = get_fieldname(
iv_fieldname = 'TRTIME'
iv_sysnam = ).
ls_comp-type ?= cl_abap_elemdescr=>describe_by_name( 'TSTAMP' ).
APPEND ls_comp TO lt_comp.
ENDLOOP.
lr_structdescr = cl_abap_structdescr=>create(
p_components = lt_comp ).
lr_tabledescr = cl_abap_tabledescr=>create(
p_line_type = lr_structdescr ).
CREATE DATA rr_request_mon_ui TYPE HANDLE lr_tabledescr.
ENDMETHOD.
Die folgende Abbildung aus dem Debugger zeigt die gefüllte interne Tabelle, mit welcher das Grid befüllt wird.

Fazit
Der TMS Auftragsmonitor liefert eine gute Übersicht, in welche Zielsysteme freigegebene Transportaufträge noch zu transportieren sind. Er ist ein Workaround, wenn kein ChaRM eingesetzt wird. In unseren Projekten finden wir jedoch häufig diese Situation vor und müssen entsprechend damit umgehen. Von der Implementierung her zeigt er, wie man in ABAP gegen dynamische Datenstrukturen programmiert.
Hast du noch Fragen?
Nutze gerne unsere Kommentarfunktion!
Du programmierst, bist ABAP-interessiert und hast Lust coole Projekte mit uns zu machen? Wir suchen dich! Schau doch mal in unserer Stellenbeschreibung vorbei.



Hallo,
Mir gefällt der Beitrag sehr gut – danke dafür!
Habe allerdings festgestellt, dass der Link zu den Sourcen nicht funktioniert …
Sind diese absichtlich nicht mehr verfügbar, oder kann das gefixt werden?
Danke und lG
Der Link bei „hier“ herunterladen – passt nicht (mehr).
https://developers4sap.blog/transport-management-system-auftragsmonitor/