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.
MeinerEiner sagt:
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
Jürgen Spranz sagt:
Der Link bei “hier” herunterladen – passt nicht (mehr).
https://developers4sap.blog/transport-management-system-auftragsmonitor/