Quantcast
Channel: Programmierung – Tricktresor
Viewing all 166 articles
Browse latest View live

Shortcuts bei Übersetzung in SE63

$
0
0

Übersetzungen sind immer ein leidiges Thema. Stephan hat mir einen Tipp zugesendet, wie man die Arbeit in der Transaktion SE63 Übersetzungseditor etwas zügiger gestalten kann.

Noch im Einstieg der SE63 kann man durch Eingabe eines Funktionscodes die Navigation abkürzen so dass man direkt zum Zielobjekt gelangt.

Einige Beispiele:

  • DE – Datenelement
  • NA – Nachricht
  • PR – Programm
  • OTRS – OTR-Text

Nach wie vor muss man jedoch erst einmal den richtigen Code für das jeweilige Objekt ermitteln. Wenn du den Objekttyp nicht kennst, dann kannst du den Joker „Transportobjekt“ einsetzen. Hier kannst du den aus dem Transportauftrag verwendeten R3TR-Objekttyp verwenden. Im Einstiegsbild der SE63 gelangst du über die Drucktaste Transportobjekt (STRG + F1) oder über den Funktionsode „T“ dorthin.

Der Beitrag Shortcuts bei Übersetzung in SE63 erschien zuerst auf Tricktresor.


Class Inspector

$
0
0

Heute hatte ich einen merkwürdigen Fehler: Ich konnte eine inaktive Klasse nicht aktivieren. Der Class Builder hat nur gemeldet: „Active class has been generated“, aber die Klasse war weiterhin inaktiv. Bei der Fehlersuche bin ich zwar nicht auf die Ursache gestoßen, habe aber einige Funktionsbausteine und Klassen kennengelernt, die bei der Fehlersuche hilfreich waren.

Mit Hilfe des Funktionsbausteins RS_INACTIVE_PART habe ich immerhin herausgefunden, welcher Teil der Klasse nicht aktiv war, aber da die Komponenten einer Klasse sehr uneinheitlich definiert werden, half es mir nicht weiter, dass der inaktive Part vom Typ „CLSD“ war. Über die Tabelle DWINACTIV habe ich den Include des inaktiven Klassenartefakts ermitteln können. Über den Objekttyp habe ich zwar herausgefunden, dass dies der Teil „CLSD – LIMU CLSD Class Definition (ABAP Objects)“ ist. Da der Definitionsteil im Class Builder jedoch als aktiv angezeigt wurde, wollte ich den Quelltext vergleichen. Im Artikel über die Classname Services habe ich bereits beschrieben, wie man über die Einzelteile an die technischen Details kommt. Das war mir natürlich deutlich zu Umständlich… Also habe ich letztendlich ein kleines Programm – einen Class Inspector – geschrieben, dass die einzelnen Includes einer Klasse auflistet und über Doppelklick den jeweiligen Quelltext anzeigt.

Tricktresor Class Inspector

Code github

Der Quelltext ist auf github verfügbar:

https://github.com/tricktresor/class_inspector

Da das Coding so lang aber auch nicht ist, hier auch noch mal direkt.

Code

REPORT ztrcktrsr_class_inspector.

PARAMETERS p_clas TYPE seoclsname DEFAULT 'CL_GUI_CONTAINER'.


CLASS lcl_main DEFINITION.
  PUBLIC SECTION.

    TYPES: BEGIN OF _include,
             repid    TYPE syrepid,
             descr    TYPE c LENGTH 60,
             exposure TYPE icon_d,
           END OF _include,
           _includes TYPE STANDARD TABLE OF _include WITH EMPTY KEY.

    METHODS on_double_click
                FOR EVENT double_click OF cl_salv_events_table
      IMPORTING row column.
    METHODS constructor
      IMPORTING
        container_grid TYPE REF TO cl_gui_container
        container_code TYPE REF TO cl_gui_container.
    METHODS display.
    METHODS editor.
    METHODS start
      IMPORTING
        i_class TYPE clike.
  PROTECTED SECTION.
    DATA mt_redef     TYPE STANDARD TABLE OF seoredef.
    DATA container_grid    TYPE REF TO cl_gui_container.
    DATA container_code    TYPE REF TO cl_gui_container.
    DATA mo_editor    TYPE REF TO cl_gui_abapedit.
    DATA class_includes TYPE _includes.
    DATA grid TYPE REF TO cl_salv_table.
    DATA classname TYPE seoclsname.
    METHODS display_source IMPORTING include TYPE programm.

ENDCLASS.

CLASS lcl_main IMPLEMENTATION.

  METHOD constructor.
    me->container_grid = container_grid.
    me->container_code = container_code.

  ENDMETHOD.

  METHOD on_double_click.
    editor( ).
    DATA(source) = class_includes[ row ].

    display_source( source-repid ).

  ENDMETHOD.

  METHOD display_source.
    DATA lt_source TYPE STANDARD TABLE OF string.

    READ REPORT include INTO lt_source.
    mo_editor->set_text( lt_source ).

  ENDMETHOD.

  METHOD editor.

    CHECK container_code IS BOUND.
    CHECK mo_editor IS INITIAL.

    mo_editor = NEW #( parent = container_code ).
    mo_editor->set_readonly_mode( 1 ).

  ENDMETHOD.

  METHOD display.

    IF grid IS INITIAL.

      TRY.
          " create SALV
          CALL METHOD cl_salv_table=>factory
            EXPORTING
              r_container  = container_grid
            IMPORTING
              r_salv_table = grid
            CHANGING
              t_table      = class_includes.

          grid->get_functions( )->set_all( ).
          grid->get_display_settings( )->set_list_header( CONV #( classname ) ).

          DATA(columns) = grid->get_columns( ).
          CAST cl_salv_column_table( columns->get_column( 'EXPOSURE' ) )->set_icon( abap_true ).
          columns->get_column( 'DESCR' )->set_medium_text( 'Description' ).
          columns->get_column( 'EXPOSURE' )->set_medium_text( 'Exposure' ).

          " register event DOUBLE_CLICK
          SET HANDLER on_double_click FOR grid->get_event( ).

          grid->display( ).
        CATCH cx_salv_error INTO DATA(error).
          MESSAGE error TYPE 'I'.
      ENDTRY.
    ELSE.
      grid->refresh( ).
    ENDIF.


  ENDMETHOD.

  METHOD start.

    DATA textpool TYPE table_of_textpool.
    DATA description TYPE string.

    CHECK classname <> i_class.
    classname = i_class.

    TRY.
        DATA(classinfo) = cl_oo_class=>get_instance( i_class ).
      CATCH cx_class_not_existent ##no_handler.
    ENDTRY.

    DATA(includes) = cl_oo_classname_service=>get_all_class_includes( class_name = i_class ).
    CLEAR class_includes.
    LOOP AT includes INTO DATA(include).
      READ TEXTPOOL include INTO textpool LANGUAGE sy-langu.

      IF include+30(1) = 'C'.

        IF include+30(2) = 'CM'.
          cl_oo_classname_service=>get_method_by_include(
            EXPORTING
              incname             = include
            RECEIVING
              mtdkey              = DATA(method)
            EXCEPTIONS
              class_not_existing  = 1
              method_not_existing = 2
              OTHERS              = 3  ).
          IF sy-subrc = 0.
            description = method-cpdname.
            TRY.
                DATA(methodexposure) = classinfo->get_component_exposure( cpdname = method-cpdname ).
              CATCH cx_component_not_existing ##no_handler.
            ENDTRY.
          ENDIF.
        ELSE.
          CASE include+30(5).
            WHEN 'CCDEF'.
              description = 'Local type definitions'.
            WHEN 'CCMAC'.
              description = 'Macros'.
            WHEN 'CCIMP'.
              description = 'Local class implementations'.
            WHEN 'CCAU'.
              description = 'Unit tests'.
            WHEN 'CU'.
              description = 'Class definition/ Public section'.
            WHEN 'CO'.
              description = 'Protected section'.
            WHEN 'CI'.
              description = 'Private Section'.
            WHEN 'CP'.
              description = 'Class pool'.
            WHEN 'CT'.
              description = ''.
            WHEN 'CL'.
              description = 'Local classes'.
            WHEN 'CS'.
              description = 'Complete source code'.

          ENDCASE.
        ENDIF.
      ENDIF.

      APPEND VALUE #(
        repid = include
        descr = description
        exposure = SWITCH #( methodexposure
          WHEN seoc_exposure_private THEN icon_led_red
          WHEN seoc_exposure_protected THEN icon_led_yellow
          WHEN seoc_exposure_public THEN icon_led_green )
          ) TO class_includes.
    ENDLOOP.
    display( ).

  ENDMETHOD.



ENDCLASS.

INITIALIZATION.
  DATA(docker) = NEW cl_gui_docking_container( side = cl_gui_docking_container=>dock_at_bottom ratio = 95 ).
  DATA(splitter) = NEW cl_gui_easy_splitter_container(
    parent      = docker
    orientation = cl_gui_easy_splitter_container=>orientation_horizontal ).

  DATA(container_grid) = splitter->top_left_container.
  DATA(container_code) = splitter->bottom_right_container.

  DATA(main) = NEW lcl_main(
    container_grid = container_grid
    container_code = container_code  ).


AT SELECTION-SCREEN.
  main->start( p_clas ).



START-OF-SELECTION.

Der Beitrag Class Inspector erschien zuerst auf Tricktresor.

Auftragserfassung: Automatische (Positions-) Texte

$
0
0

In der Auftragserfassung (Modulpool SAPMV45A) sollen bei Auftragsanlage oder -änderung kundenindividuelle Texte definiert werden.

Standard-Textfindung

Im Standard lässt sich bereits eine umfangreiche Textfindung einstellen. Hier geht es jedoch darum, Texte aus anderen Objekten (Vorgängerbelegen, Kunden, Materialien, …) zu finden und zu übernehmen.

Ausgangspunkt ist die Transaktion VOFM, Menü Kopierbedingungen • Texte oder Datenübernahme • Texte. Hier kannst du Bedingungen programmieren und zuordnen, die den gewünschten Text ermitteln.

Textverwaltung in SAP

In diesem Artikel geht es darum, individuelle Texte in eine Auftragsposition zu bekommen. Um das zu realisieren, muss man wissen, wie die Textverwaltung im SAP funktioniert. Darum hier ein kurzer Abriss zu den SAP-Langtexten.

Standardlangtexte können in der Transaktion SO10 erstellt und bearbeitet werden. Zur Bearbeitung hast die Auswahl zwischen dem uralten Zeilen-Editor und dem PC-Editor, der zwischenzeitlich durch Microsoft Word abgelöst wurde.

Absatzformate

Ein SAP-Langtext oder auch SAP-Script- oder ITF-Text, besteht aus einem Absatzformat und einer Zeile. Absatzformate können in Stilen definiert und zugeordnet werden (Transaktion SE72).

Das Sternchen * ist das Standardabsatzformat. Steht das * in der Spalte Absatzformat, dann erfolgt auf jeden Fall ein Zeilenumbruch. Bei einem Fließtext ist das Absatzformat leer.

Alter Zeileneditor
Microsoft Word Editor

Felder

Um einen Text eindeutig zu identifizieren, sind die folgenden Felder notwendig:

FeldnameBeschreibungInfos
TDOBJECTTextobjektDefiniert den Anwendungsbereich. Standardtexte haben das Textobjekt TEXT, Auftragskopftexte VBBK und Auftragspositionstexte VBBP, Materialstamm hat MATERIAL und MVKE. Textobjekte werden mit Hilfe der Transaktion SE75 definiert. Für eigene Anwendungen können im Kundennamensraum eigene Objekte definiert werden.
TDNAMETextnameDer Textname besteht bei Texten zu Anwendungsobjekten (Aufträge, Kunden, Materialien, etc.) aus den Schlüsselfeldern der zugehörigen Tabelle. Beispiel: Vertriebstext Material (MVKE): <matnr><vkorg><vtweg>
TDIDText-IDDie Id definiert Texte innerhalb eines Text-Objektes. Sie muss im Customizing definiert werden (Transaktion SE75).
TDSPRASSpracheSprache des Textes.
Schlüsselfelder STXH

Speicherort

Die Texte werden in den Tabellen STXH (Kopfdaten) und STXL (Textzeilen) gespeichert. Die Tabelle STXH kann man in der Tabellenanzeige (Transaktion SE16n) einsehen. In der STXL werden die Textzeilen jedoch komprimiert gespeichert und können nicht angesehen werden.

Texte lesen

Um Texte einzulesen, solltest du den Funktionsbaustein READ_TEXT verwenden. Um Texte zu suchen, kannst du direkt die Tabelle STXH durchsuchen oder du verwendest den Funktionsbaustein SELECT_TEXT.

Speichern von Texten

Die Speicherung von Texten erfolgt mit Hilfe des Funktionsbausteins SAVE_TEXT. Diesem Baustein müssen die Schlüsselfelder übergeben werden. Wenn man weiß, dass der Text noch nicht existiert, dann sollte aus Performancegründen der Parameter INSERT = X gesetzt werden. Möchte man den Text in einer eigenen Anwendung sofort sichern, so kann der Parameter SAVEMODE_DIRECT = X gesetzt werden. Beim Speichern von mehreren Texten sollte der Funktionsbaustein COMMIT_TEXT verwendet werden.

Mit dem Funktionsbaustein INIT_TEXT können Texte angelegt werden.

Zentrales Textmemory

Die Textverwaltung hat ein zentrales Memory. Aus diesem Grund sollte immer mit den entsprechenden Funktionsbausteinen auf die Texte zugegriffen werden. Der READ_TEXT liest den Text aus dem Textmemory, sofern vorhanden.

Textverwaltung SAPMV45A

Kommen wir nun endlich zum Ausgangsthema zurück: Programmatische Bearbeitung von Texten in der Auftragsbearbeitung (Modulpool SAPMV45A). Du solltest wegen des zentralen Textmemories zur Bearbeitung immer die oben beschriebenen Funktionsbausteine verwenden. So kannst du in der Transaktion den Baustein READ_TEXT verwenden, um zu prüfen, ob bereits ein Auftragskopftext zu einer bestimmten ID oder zu einer Position schon ein Text angelegt wurde, auch wenn diese noch nicht auf der Datenbank gespeichert wurde.

Eine separate Speicherung ist nicht notwendig bzw. sogar verboten -, denn die Speicherung erfolgt zentral durch die Applikation. Wird die Transaktion abgebrochen, dann werden die Texte auch nicht gespeichert.

Auf keinen Fall darfst du im Baustein SAVE_TEXT den Parameter SAVEMODE_DIRECT setzen, den Baustein COMMIT_TEXT oder COMMIT WORK verwenden! Das wird von der Applikation SAPMV45A beim Sichern gemacht!

Verwendest du doch einen COMMIT in den Exits, dann riskierst du einen Datenschiefstand und Fehlfunktionen von BAPIs.

Codebeispiel

In folgendem Code-Beispiel wird der Text zu einem neu eingegebenen Material aus dem Literal „ARKTX:“ und dem aktuellen Artikeltext erstellt.

FORM userexit_move_field_to_vbap.
  DATA ls_header     TYPE thead.
  DATA lt_lines      TYPE STANDARD TABLE OF tline.

  IF vbap-vbeln IS INITIAL.
    ls_header-tdname   = 'XXXXXXXXXX' && vbap-posnr.
  ELSE.
    ls_header-tdname   = vbap-vbeln && vbap-posnr.
  ENDIF.
  ls_header-tdobject = 'VBBP'.
  ls_header-tdid     = '0001'.
  ls_header-tdspras  = sy-langu.
  CALL FUNCTION 'READ_TEXT'
    EXPORTING
      id        = ls_header-tdid
      language  = ls_header-tdspras
      name      = ls_header-tdname
      object    = ls_header-tdobject
      local_cat = space
    IMPORTING
      header    = ls_header
    TABLES
      lines     = lt_lines
    EXCEPTIONS
      OTHERS    = 8.
  IF sy-subrc <> 0.
    lt_lines = VALUE #( ( tdformat = '*' tdline = |test { vbap-arktx }| ) ).
    CALL FUNCTION 'SAVE_TEXT'
      EXPORTING
        header          = ls_header
        insert          = abap_true
        savemode_direct = space
        local_cat       = space
      TABLES
        lines           = lt_lines
      EXCEPTIONS
        OTHERS          = 5.
  ENDIF.

ENDFORM.

Der Beitrag Auftragserfassung: Automatische (Positions-) Texte erschien zuerst auf Tricktresor.

Startbildschirm festlegen

$
0
0

Im SAPGUI Easy Access Menu gibt es die Möglichkeit, ein Bild anzuzeigen. Das ist einerseits hilfreich, um das Unternehmens-Branding direkt beim Anmelden an das R/3-System zu präsentieren. Andererseits kann man auf diese Weise die unterschiedlichen Systeme gut und einfach kennzeichnen, so dass die Anwendenden auf Anhieb wissen, in welchem System sie sich angemeldet haben.

In unserem Entwicklungssystem sieht das zum Beispiel wie folgt aus:

Inwerken SAP-System

Einstellungen

Um ein Bild für das Easy Access Startmenü festzulegen, gehst du wie folgt vor:

  • Hochladen eines Bildes in Transaktion SMW0
  • Einstellen der Parameter
    • START_IMAGE – Name des Bildes
    • RESIZE_IMAGE (YES/NO) – Anpassen des Bildes an die Fenstergröße

Hochladen des Bildes

Starte die Transaktion SMW0 und wähle die Option Binary data for WebRFC applications und führe das Programm mit F8 aus. Du kannst auch direkt das Programm RSWWWSHW aufrufen.

Im folgenden Selektionsbild kannst du die Auswahl einschränken, musst du aber nicht. Führe den Report mit F8 aus.

Report RSWWWSHW

Lege einen neuen Eintrag an. Drücke hierzu das Anlegen-Symbol in der Drucktastenleiste oder drücke F5. Im Popup musst du einen Namen und eine Beschreibung vergeben. Der Name muss mit Z beginnen (Kundennamensraum!). Drücke danach das Import-Symbol oder die Tastenkombination SHIFT+F6. Es erscheint ein Dateiauswahldialog in dem du deine Bilddatei auswählst. Ordne noch ein Paket zu und du bist fertig. Den Namen des Bildes benötigst du gleich.

Weitere Informationen findest du in meinem Artikel zur Anzeige von Bildern aus der SMW0.

Einstellen der Parameter

Das Startbild wird über Parameter in der Tabelle SSM_CUST definiert. Rufe die Transaktion SM30 auf, um die Parameter zu pflegen. Oder rufe direkt die Transaktion SM30_SSM_CUST auf.

Gib die folgenden Parameter ein:

ParameternameWertBeschreibung
START_IMAGE<NAME>Name des in SMW0 angelegten Bildes in Großbuchstaben
RESIZE_IMAGEYES oder NOBildgröße an Fenstergröße anpassen ja/ nein
HIDE_START_IMAGEYES oder NOStartbild ignorieren ja/nein
Parametertabelle SSM_CUST

Ein genaues Vorgehen mit weiteren Hinweisen findest du in SAP-Hinweis 1638985.

Die Einstellungen sind Mandanten-unabhängig. Das bedeutet, dass du leider keine unterschiedlichen Bilder in unterschiedlichen Mandanten einstellen kannst (Siehe SAP-Hinweis 1337986).

Animiertes GIF anzeigen

Anstelle eines JPG oder PNG Bildes kannst du auch ein animierten GIF anzeigen. Hierfür musst du das Bild jedoch im Mime Repository ablegen. Wie das genau geht, steht in SAP-Hinweis 2693398.

URL anzeigen

Seit Release 7.00 kannst du auch Webseiten anzeigen. Dazu musst du den Parameter SESS_URL setzen (SAP-Hinweis 1387086). Die URL darf maximal 200 Zeichen lang sein. Eine interessante Möglichkeit also, um ein internes Wiki, die neuesten Tricks oder ähnliche Webseiten einzublenden.

Achtung: Die Verwendung eine URL verzögert gegebenenfalls den Start des SAPGUI, da die Daten erst geladen werden müssen. Das Quartz-Theme hat auf unserem System auf jeden Fall große Schwierigkeiten mit der Anzeige einer URL: Der Start dauert extrem lange, bzw. werden neue Modi gar nicht geöffnet.

Tipps zum Bild

Folgende Tipps helfen dir eventuell bei der Auswahl des Bildes weiter.

Bild ausblenden

Mit dem Parameter HIDE_START_IMAGE kannst du steuern, dass das Startbild nicht angezeigt wird. Falls das Bild nicht angezeigt wird, stelle sicher, dass der Parameter auf NO steht.

Bildgröße

Wähle ein Bild, das nicht zu groß ist. Der Parameter RESIZE_IMAGE passt das Bild nämlich nicht im gleichen Größenverhältnis an, sondern verzerrt es. Das hat zwar den Vorteil, dass das Bild vollflächig angezeigt wird, allerdings sehen – auch leicht – verzerrte Bilder sehr unprofessionell aus.

Leider wird in dem zur Anzeige verwendeten Baustein WB_BITMAP_SHOW für die Darstellung mit CL_GUI_PICTURE die Option DISPLAY_MODE_STRETCH anstelle DISPLAY_MODE_FIT bzw. DISPLAY_MODE_FIT_CENTER verwendet. Mit FIT wird das Bild mit korrektem Seitenverhältnis an die Fenstergröße angepasst.

Bildformat

Als Bildformat kann ich dir PNG empfehlen, denn hier hast du die Möglichkeit, einen transparenten Hintergrund zu definieren. Dadurch sieht das Bild auch dann ordentlich aus, wenn ein anderes GUI-Theme eine andere Hintergrundfarbe hat:

Quartz-Theme (links) und Blue-Crystal-Theme (rechts)

Der Beitrag Startbildschirm festlegen erschien zuerst auf Tricktresor.

ALV-Grid aus SALV ermitteln (ab Release 7.55)

$
0
0

In dem Beitrag ALV-Grid aus SALV ermitteln habe ich beschrieben, wie du bei einem SALV-Grid an das zugrundeliegende ALV-Grid (Klasse CL_GUI_ALV_GRID) heran kommst. Die Vorgehensweise funktioniert allerdings ab Release 7.55 nicht mehr. Deswegen hier ein Coding, das für SAP-Releases ab 7.55 funktioniert.

Danke an Stefan für den Hinweis!

Coding Hilfsklasse

CLASS access_salv DEFINITION INHERITING FROM cl_salv_model_base FINAL.
  PUBLIC SECTION.
    CLASS-METHODS get_grid_from_salv
      IMPORTING
        salv        TYPE REF TO cl_salv_table
      RETURNING
        VALUE(grid) TYPE REF TO cl_gui_alv_grid.

  PRIVATE SECTION.
    " We need to get to r_controller which is protected
    " --> access inherits from cl_salv_model_base where controller is defined.
    CLASS-METHODS get_cl_gui_alv_grid
      IMPORTING
        salv_base   TYPE REF TO cl_salv_model_base
        salv        TYPE REF TO cl_salv_table
      RETURNING
        VALUE(grid) TYPE REF TO cl_gui_alv_grid.
ENDCLASS.


CLASS access_salv IMPLEMENTATION.
  METHOD get_cl_gui_alv_grid.
    DATA adapter TYPE REF TO if_salv_table_display_adapter.

    " Adapter must be bound
    IF   salv_base->r_controller IS NOT BOUND
      OR salv_base->r_controller->r_adapter IS NOT BOUND.
      MESSAGE 'programming error: Call GET_GRID_FROM_SALV after SALV->DISPLAY( )!'
         TYPE 'S' DISPLAY LIKE 'W'.
      salv->display( ).
    ENDIF.
    IF   salv_base->r_controller IS NOT BOUND
      OR salv_base->r_controller->r_adapter IS NOT BOUND.
      RETURN.  " Still not bound  --> can't do anything
    ENDIF.

    " Get grid
    TRY.
        IF salv_base->r_controller->r_adapter
           IS INSTANCE OF if_salv_table_display_adapter.
          grid = CAST if_salv_table_display_adapter(
                   salv_base->r_controller->r_adapter )->get_grid( ).
        ENDIF.
      CATCH cx_root ##CATCH_ALL.
        RETURN.
    ENDTRY.
  ENDMETHOD.

  METHOD get_grid_from_salv.

    DATA extended_grid_api TYPE REF TO cl_salv_gui_om_table_info.

    " Must be bound
    IF salv IS NOT BOUND.
      RETURN.
    ENDIF.

    " Get extended API
    " Comment to API: Restricted Use (maintained dev.packages) of extended Grid API
    extended_grid_api ?= salv->if_salv_gui_om_table_info~extended_grid_api( ).
    grid = access_salv=>get_cl_gui_alv_grid(
      salv      = salv
      salv_base = extended_grid_api ).

  ENDMETHOD.
ENDCLASS.

Coding Verwendung

In folgendem Beispiel erzeuge ich ein SALV-Grid und zeige es auf dem Selektionsbildschirm an. Mit der oben genannten Hilfsklasse ermittele ich die CL_GUI_ALV_GRID-Instanz zum SALV und setze mit dieser Instanz zwei Zeilenmarkierungen.

Damit der Report funktioniert, musst du die oben gezeigte Klasse lokal in den Report einbinden, oder du definierst die Hilfsklasse global im Kundennamensraum – was sinnvoll wäre, um sie systemweit nutzen zu können – und musst dann natürlich den Aufruf anpassen.

REPORT.

PARAMETERS test.

INITIALIZATION.

  SELECT * FROM t006a INTO TABLE @DATA(demo_data)
   UP TO 20 ROWS
   WHERE spras = @sy-langu.

  TRY.
      cl_salv_table=>factory(
        EXPORTING
          r_container  = NEW cl_gui_docking_container( 
              ratio = 50 side = cl_gui_docking_container=>dock_at_right )
        IMPORTING
          r_salv_table = DATA(demo_salv)
        CHANGING
          t_table      = demo_data ).
      demo_salv->display( ).
    CATCH cx_salv_msg. " ALV: General Error Class with Message
  ENDTRY.

  "access grid
  DATA(grid) = access_salv=>get_grid_from_salv( demo_salv ).
  "use grid
  grid->set_selected_rows(
    it_row_no = VALUE #(
      ( row_id = 2 )
      ( row_id = 4 ) ) ).

Der Beitrag ALV-Grid aus SALV ermitteln (ab Release 7.55) erschien zuerst auf Tricktresor.

BASE64-kodiertes Pony anzeigen

$
0
0

In diesem Beispielprogramm zeige ich dir, wie du ein niedliches Pony anzeigen kannst. Grüße gehen raus an Marco Matjes. Das Coding ist nicht schön, aber es zeigt, wie man ein BASE64-Codiertes Bild (in diesem Fall ein GIF) in einem Container anzeigen kann. Kleine Bilder oder Icons können so relativ einfach im Quelltext eingebunden werden.

So sieht das Pony aus

Code

REPORT.

DATA picture       TYPE REF TO cl_gui_picture.
DATA pic_container TYPE REF TO cl_gui_docking_container.
DATA graphic_url(255).

TYPES: BEGIN OF graphic_str,
         line(255) TYPE x,
       END OF graphic_str,
       graphic_tab TYPE STANDARD TABLE OF graphic_str.
DATA graphic_table TYPE graphic_tab.
DATA graphic_size TYPE i.

PARAMETERS p_dummy.

INITIALIZATION.
  PERFORM show.

START-OF-SELECTION.

  DEFINE a.
    concatenate l_graphic_str &1 into l_graphic_str.
  END-OF-DEFINITION.

FORM show.

  DATA: l_graphic_xstr TYPE xstring,
        l_graphic_x    TYPE x,
        l_graphic_conv TYPE i,
        l_graphic_str  TYPE string,
        l_graphic_offs TYPE i.


  pic_container = NEW #( extension = 300 no_autodef_progid_dynnr = 'X' ).
  picture = NEW #( parent = pic_container ).

  CLEAR graphic_table.

  "GIF rennpony 16 colors
  a 'R0lGODlhFQATADMAACH5BAAAAAAALAAAAAAVABMAg////19qcHaPjo6ij5XL/p3Mx6rR3qTS+LPUksPessjcysvl+ufbrvrclPfv1Or'.
  a '0+wSMEMg5F1mY6g0eztzmNA3TKEu4LYaptI2jShbBMIahlDNwXCwDYcdQeQ6HwEDxOyiKmyNhKhj8pobYBjkl6K5TokZRKBe+3enhRn'.
  a 'Eg3u/EbwH2aiWJfB6hfjzAa3d6ewYHDzRpWQ0SCoMJBoc0gCYOMo15hho1aiaLAAqgkRR/aYE9iKVQPZtppwCsXREAOw=='.

  CALL FUNCTION 'SSFC_BASE64_DECODE'
    EXPORTING
      b64data = l_graphic_str
    IMPORTING
      bindata = l_graphic_xstr
    EXCEPTIONS
      OTHERS  = 8.


  graphic_size = xstrlen( l_graphic_xstr ).
  CHECK graphic_size > 0.

  l_graphic_conv = graphic_size.
  l_graphic_offs = 0.

  WHILE l_graphic_conv > 255.
    APPEND VALUE #( line = l_graphic_xstr+l_graphic_offs(255) ) TO graphic_table.
    l_graphic_offs = l_graphic_offs + 255.
    l_graphic_conv = l_graphic_conv - 255.
  ENDWHILE.

  APPEND VALUE #( line = l_graphic_xstr+l_graphic_offs(l_graphic_conv) ) TO graphic_table.


  CALL FUNCTION 'DP_CREATE_URL'
    EXPORTING
      type      = 'image'                                    "#EC NOTEXT
      subtype   = 'gif'
      cacheable = space
      size      = graphic_size
      lifetime  = cndp_lifetime_transaction
    TABLES
      data      = graphic_table
    CHANGING
      url       = graphic_url.

  picture->clear_picture( ).
  picture->load_picture_from_url( url = graphic_url ).
  picture->set_display_mode( cl_gui_picture=>display_mode_fit ).

ENDFORM.

Der Beitrag BASE64-kodiertes Pony anzeigen erschien zuerst auf Tricktresor.

Einfacher systemübergreifender Versionsvergleich (2)

$
0
0

In diesem Beitrag schrieb ich bereits darüber, wie du den Funktionsbaustein SVRS_MASSCOMPARE_ACT_OBJECTS nutzen kannst, um einen detaillierten Versionsvergleich über Systemgrenzen hinweg zu bekommen.

Durch Zufall bin ich nun auf den Funktionsbaustein SVRS_MASSCOMPARE_ACT_AND_SHOW gestoßen, der alles noch viel einfacher macht. Den Baustein kannst du für kleinere Vergleiche direkt aus der Testumgebung heraus verwenden. Du musst lediglich die RFC-Destination für das entfernte System in Parameter IV_RFCDEST_B eintragen sowie die Tabelle IT_E071:

Eingabeparameter Testumgebung

In Parameter IT_E071 reicht es, die Felder PGMID, OBJECT und OBJ_NAME zu füllen:

Parameter IT_E071

Als Ergebnis erhältst du eine Liste mit allen Teilobjekten und der Info, ob diese unterschiedlich sind. Mit einem Doppelklick gelangst zur direkten Gegenüberstellung der Unterschiede:

Der Beitrag Einfacher systemübergreifender Versionsvergleich (2) erschien zuerst auf Tricktresor.

CL_SALV_TABLE als Auswahl-Popup

$
0
0

Die Klasse CL_SALV_TABLE ist super für alle Arbeiten rund um Grid-basierte Listen. Der riesengroße Vorteil des CL_SALV_TABLE ist der Umstand, dass man den Feldkatalog nicht selbst ermitteln muss, sondern die anzuzeigende Tabelle einfach der Methode CL_SALV_TABLE=>FACTORY übergeben kann. Das funktioniert selbst mit lokal im Programm definierten internen Tabellen.

Was liegt also näher, um dieses Verfahren auch für die Auswahl von Einträgen aus einer Liste zu verwenden? Um das SALV als Popup anzuzeigen, nutzt du die Methode SET_SCREEN_POPUP. Beim darauffolgenden DISPLAY wird das SALV als Popup angezeigt.

Einschränkungen

Leider hat diese Methode einige Einschränkungen, die es notwendig machen, doch wieder mehr drumherum zu programmieren, als eigentlich notwendig.

  • Es gibt keine Abbrechen-Drucktaste
  • Es kann kein Wert mit Doppelklick ausgewählt werden

Beiden Funktionen sind jedoch notwendig, um dem Anwendenden einen sinnvollen Dialog zu bieten, um einen Eintrag aus einer Liste auszuwählen.

Es gibt zwei schöne Beispiele in der Codezentrale, die zeigen, dass es möglich ist:

Das erste Beispiel verwendet sehr viel Coding, denn die fehlenden Drucktasten werden umständlich durch eine Toolbar und Splitter-Container realisiert. Die Lösung ist sehr schick und einmal programmiert, kann diese auch wieder verwendet werden.

In der zweiten Lösung, in der der SALV-Table als F4-Suchhilfe verwendet wird, fehlt leider der Doppelklick, um einen Eintrag auszuwählen.

Einfache Lösung

Meine Lösung nutzt die Registrierung des Doppelklick-Events vom SALV-Table und wertet den implizit vorhandenen Abbrechen-Funktionscode aus.

CL_SALV_TABLE als Auswahl-Popup

Abbruch

Das SAL-Popup hat zwar keine Abbrechen-Drucktaste, jedoch ist der Funktionscode über die Taste ESC aktiv, so dass der Dialog durch das Drücken der Escape-Taste beendet werden kann.

Der Funktionscode wird in der Systemvariablen SY-UCOMM gespeichert. Alle Funktionscodes der Klasse CL_SALV_TABLE sind in dem Interface IF_SALV_C_FUNCTION verfügbar. Nach Aufruf von salv->display() kann also SY-UCOMM abgefragt werden. Leider ist nach Drücken der Enter-Taste SY-UCOMM leer, so dass nicht nur if_salv_c_function=>continue sondern auch SPACE abgefragt werden müssen.

Doppelklick

Um der anwendenden Person einen Doppelklick zu ermöglichen, registriere ich das Ereignis DOUBLE_CLICK der Klasse CL_SALV_EVENTS_TABLE. Um direkt darauf das Popup auch schließen und die Auswahl bestätigen zu können, rufe ich den Funktionsbaustein SAPGUI_SET_FUNCTIONCODE mit dem Funktionscode für „Continue“ auf.

Coding

PARAMETERS p_title TYPE string DEFAULT 'Weekday selection'.

PARAMETERS p_item1 TYPE c LENGTH 30 LOWER CASE DEFAULT 'MONMonday'.
PARAMETERS p_item2 TYPE c LENGTH 30 LOWER CASE DEFAULT 'TUETuesday'.
PARAMETERS p_item3 TYPE c LENGTH 30 LOWER CASE DEFAULT 'WEDWednesday'.
PARAMETERS p_item4 TYPE c LENGTH 30 LOWER CASE DEFAULT 'THUThursday'.
PARAMETERS p_item5 TYPE c LENGTH 30 LOWER CASE DEFAULT 'FRIFriday'.
PARAMETERS p_item6 TYPE c LENGTH 30 LOWER CASE DEFAULT 'SATSaturday'.
PARAMETERS p_item7 TYPE c LENGTH 30 LOWER CASE DEFAULT 'SUNSunday'.
CLASS cancelled DEFINITION INHERITING FROM cx_static_check.
ENDCLASS.

CLASS main DEFINITION.
  PUBLIC SECTION.
    TYPES: BEGIN OF _item,
             key   TYPE c LENGTH 3,
             value TYPE c LENGTH 20,
           END OF _item,
           _items TYPE STANDARD TABLE OF _item WITH DEFAULT KEY.
    METHODS set_items
      IMPORTING
        items TYPE _items.
    METHODS ask
      IMPORTING
        title         TYPE clike
      RETURNING
        VALUE(result) TYPE _item
      RAISING
        cancelled.
  PRIVATE SECTION.
    DATA salv_popup TYPE REF TO cl_salv_table.
    DATA items TYPE _items.


    METHODS: on_double_click FOR EVENT double_click OF cl_salv_events_table
      IMPORTING
        row
        column
        sender.
ENDCLASS.

CLASS main IMPLEMENTATION.
  METHOD set_items.

    me->items = items.
  ENDMETHOD.

  METHOD on_double_click.
    DATA(selections) = salv_popup->get_selections( ).
    selections->set_selected_rows( VALUE #( ( row ) ) ).
*    cl_gui_cfw=>set_new_ok_code( if_salv_c_function=>continue ).
    CALL FUNCTION 'SAPGUI_SET_FUNCTIONCODE'
      EXPORTING
        functioncode = if_salv_c_function=>continue.

  ENDMETHOD.

  METHOD ask.
    TRY.
        cl_salv_table=>factory(
          IMPORTING
            r_salv_table   = salv_popup
          CHANGING
            t_table        = items ).
        DATA(display) = salv_popup->get_display_settings( ).
        display->set_list_header( CONV #( title ) ).
        DATA(selections) = salv_popup->get_selections( ).
        selections->set_selection_mode( if_salv_c_selection_mode=>single ).
        selections->set_selected_rows( VALUE #( ( 1 ) ) ).
        DATA(columns) = salv_popup->get_columns( ).
        columns->set_optimize( abap_true ).
        salv_popup->set_screen_popup(
          start_column = 10
          end_column   = 30
          start_line   = 10
          end_line     = 17 ).
        SET HANDLER on_double_click FOR salv_popup->get_event( ).
        salv_popup->display( ).

        CASE sy-ucomm.
          WHEN space OR if_salv_c_function=>continue.
            DATA(selected_rows) = selections->get_selected_rows( ).
            DATA(selected_row) = selected_rows[ 1 ].
            result = items[ selected_row ].
          WHEN if_salv_c_function=>cancel.
            RAISE EXCEPTION TYPE cancelled.
        ENDCASE.

      CATCH cx_salv_msg INTO DATA(error).
        MESSAGE error TYPE 'I'.
    ENDTRY.

  ENDMETHOD.
ENDCLASS.

INITIALIZATION.
  DATA(my_popup) = NEW main( ).

AT SELECTION-SCREEN.
  my_popup->set_items(
    VALUE #(
      ( key = p_item1(3) value = p_item1+3(20) )
      ( key = p_item2(3) value = p_item2+3(20) )
      ( key = p_item3(3) value = p_item3+3(20) )
      ( key = p_item4(3) value = p_item4+3(20) )
      ( key = p_item5(3) value = p_item5+3(20) )
      ( key = p_item6(3) value = p_item6+3(20) )
      ( key = p_item7(3) value = p_item7+3(20) ) ) ).

  TRY.
      DATA(selected_entry) = my_popup->ask( p_title ).

      MESSAGE |you selected { selected_entry-value }| TYPE 'I'.
    CATCH cancelled.
      MESSAGE 'you cancelled the selection' TYPE 'I'.
  ENDTRY.

Der Beitrag CL_SALV_TABLE als Auswahl-Popup erschien zuerst auf Tricktresor.


SALV-Table-Popup als Suchhilfe

$
0
0

In diesem Artikel habe ich dir gezeigt, wie du die Klasse CL_SALV_TABLE als Popup und zur Auswahl von Daten nutzen kannst. Heute möchte ich dir zeigen, wie du diese Funktion in einer Suchhilfe mit Hilfe eines Suchhilfe-Exits nutzen kannst. In diesem Beispiel rufen wir, wie in dem verlinkten Artikel, eine Liste der Wochentage auf aus denen der Anwender einen auswählen kann.

Auswahl Wochentag

Der einzige Unterschied zum verlinkten Code ist, dass ich für die Schlüsselkomponente nun ein einstelliges Kennzeichen vom Typ WEEKDAY verwende.

Suchhilfe

In der Codezentrale kannst du dir ansehen, wie du einen Wert in einem Report über eine eigenprogrammierte F4-Suchhilfe übergeben kannst:

Das Verfahren nützt dir jedoch nichts, wenn du die F4-Hilfe ohne Programmierung in einem Dynprofeld nutzen möchtest. Hierfür musst du in der Transaktion SE11 eine separate Suchhilfe anlegen:

Suchhilfe mit Suchhilfe-Exit

Suchhilfe-Exit

Die Anlage der Suchhilfe ist in diesem Fall jedoch erst Schritt zwei. Im ersten Schritt musst du einen Funktionsbaustein anlegen, der die Werte anzeigt und mit der Suchhilfe kommuniziert.

Für den Suchhilfe-Exit benötigst du einen Funktionsbaustein mit einer definierten Schnittstelle. In der F1-Hilfe zum Suchhilfe-Exit erfährst du, dass du den Baustein F4IF_SHLP_EXIT_EXAMPLE als Vorlage verwenden kannst. Du musst eine neue Funktionsgruppe anlegen (Transaktion SE37: Springen • Funktionsgruppe • Funktionsgruppe anlegen) und den Vorlage-Baustein in diese Gruppe kopieren.

Vorlagebaustein kopieren

Am Ende des kopierten Funktionsbausteins setzt du das folgende Coding ein:

  IF callcontrol-step = 'DISP'.
    DATA(my_popup) = NEW main( ).

    my_popup->set_items(
      VALUE #(
        ( key = '1' value = 'Monday' )
        ( key = '2' value = 'Tuesday' )
        ( key = '3' value = 'Wednesday' )
        ( key = '4' value = 'Thursday' )
        ( key = '5' value = 'Friday' )
        ( key = '6' value = 'Saturday' )
        ( key = '7' value = 'Sunday' ) ) ).

    TRY.
        DATA(selected_entry) = my_popup->ask( 'Select day' ).
        append value #( string = conv #( selected_entry-key ) ) to record_tab.
        callcontrol-step = 'RETURN'.
      CATCH cancelled.
        callcontrol-step = 'EXIT'.
    ENDTRY.
  ENDIF.

In diesem Beispiel habe ich das Coding (Siehe CL_SALV_TABLE als Auswahl-Popup) als lokale Klasse im Funktionsbaustein verwendet. Sinnvoller wäre es jedoch, die Klasse MAIN als globale Klasse anzulegen (Transaktion SE24). In diesem Fall musst du bei der Instanziierung natürlich nicht MAIN verwenden, sondern den Namen der globalen Klasse.

Wichtig ist, dass bei Auswahl eines Eintrags die RECORD_TAB mit dem gewählten Eintrag angereichert wird und der CALLCONTROL-STEP auf „RETURN“ gesetzt wird. Bricht der Benutzer den Dialog ab, dann muss CALLCONTROL-STEP auf „EXIT“ gesetzt werden.

Den Funktionsbaustein und die Funktionsgruppe musst du selbstverständlich aktivieren.

Aktivierung Suchhilfe

Nachdem du den Suchhilfe-Exit Funktionsbaustein in die Suchhilfe eingetragen hast, musst du die Suchhilfe aktivieren und kannst sie testen:

Test der Suchhilfe

Suchhilfe einbinden

Du kannst diese Suchhilfe nun in einem Datenelement unter der Registerkarte „Weitere Eigenschaften“ festlegen:

Suchhilfe im Datenelement definieren

Die Suchhilfe steht dir nun immer zur Verfügung, wenn du dieses Datenelement in einer Struktur verwendest.

Suchhilfe testen

Wenn du Suchhilfen mit Suchhilfe-Exits testest, dann achte darauf, dass du nach jeder Codeänderung im Suchhilfe-Exit-Funktionsbaustein die Transaktion SE11 neu aufrufst. Andernfalls ist das alte Coding noch geladen und du wirst die Änderungen nicht sehen!

Der Beitrag SALV-Table-Popup als Suchhilfe erschien zuerst auf Tricktresor.

Einfügen von vielen Daten in Tabellenpflegedialog

$
0
0

Das Einfügen von Daten aus der Zwischenablage in einen Tabellenpflegedialog ist leider nur eingeschränkt möglich. Es können immer nur so viele Daten eingetragen werden, wie auf dem Bildschirm dargestellt werden. Möchte man von einem System in ein anderes Daten kopieren, dann geht man in der Regel wie folgt vor:

  1. Quell-Pflegedialog auswählen
  2. STRG -Y drücken um den Block-Markiermodus zu aktivieren
  3. Mit der Maus die Felder markieren, die kopiert werden sollen
  4. Mit STRG – C die ausgewählten Daten kopieren
  5. In den Ziel-Pflegedialog wechseln
  6. Kopierte Daten mit STRG – V einfügen

Alternativ können die Daten – sofern sie die gleiche Struktur haben, wie der Pflegedialog – auch aus Excel kopiert werden. Allerdings auch immer nur so viele Zeilen, wie in den Pflegedialog eingefügt werden können.

Möchte man also mehrere hundert oder sogar tausende von Einträgen kopieren, dann möchte man schnell eine andere Möglichkeit haben…

Alternative

Das folgende Programm zeigt auf, wie Daten auf zwei Möglichkeiten in einen Tabellenpflegedialog eingefügt werden können:

  1. Import als CSV (Comma-separated-values) mit einem Semikolon als Trennzeichen
  2. Import eines kopierten Bereiches aus Microsoft Excel mit einem Tabulator als Trennzeichen.

Die Daten werden mit der korrekten Struktur der zu importierenden Tabelle an den Funktionsbaustein VIEW_MAINTENANCE_GIVEN_DATA und Anzeige der Daten. Sind alle Daten korrekt, können sie gespeichert werden.

Das Verfahren habe ich bereits in dem Artikel Speichern per Pflegedialog beschrieben.

Code

TYPES: BEGIN OF _text,
         line TYPE c LENGTH 1000,
       END OF _text,
       _text_tab TYPE STANDARD TABLE OF _text WITH DEFAULT KEY.

PARAMETERS p_demo RADIOBUTTON GROUP a DEFAULT 'X'.
PARAMETERS p_clpb RADIOBUTTON GROUP a.


START-OF-SELECTION.

  DATA(import_table) = CONV tabname( 'ZMVDIMP' ).
  IF p_demo = abap_true.
    DATA(import_data_csv) = VALUE _text_tab(
        ( line = '100;123;1000;6600' )
        ( line = '100;333;1000;6600' )
        ( line = '100;56;3000;2200' )
        ).
    DATA(delimiter) = ';'.
  ELSE.

    cl_gui_frontend_services=>clipboard_import(
      IMPORTING
        data  = import_data_csv ).
    delimiter = cl_abap_char_utilities=>horizontal_tab.
  ENDIF.

  FIELD-SYMBOLS <import_data_line> TYPE any.
  FIELD-SYMBOLS <import_data_tab> TYPE table.

  DATA import_data_table_ref TYPE REF TO data.
  DATA import_data_struc_ref TYPE REF TO data.
  DATA(import_data_struc) = CAST cl_abap_structdescr(      
          cl_abap_structdescr=>describe_by_name( 'ZMVDIMP' ) ).
  DATA(vimflagtab_struc) = CAST cl_abap_structdescr( 
          cl_abap_structdescr=>describe_by_name( 'VIMFLAGTAB' ) ).

  DATA(maint_struc_components) = import_data_struc->get_components( ).
  APPEND LINES OF vimflagtab_struc->get_components( ) TO maint_struc_components.

  DATA(import_maint_struc) = cl_abap_structdescr=>create( maint_struc_components ).

  DATA(import_data_table) = cl_abap_tabledescr=>create( p_line_type = import_maint_struc ).

  CREATE DATA import_data_struc_ref TYPE HANDLE import_maint_struc.
  ASSIGN import_data_struc_ref->* TO <import_data_line>.


  CREATE DATA import_data_table_ref TYPE HANDLE import_data_table.
  ASSIGN import_data_table_ref->* TO <import_data_tab>.


  LOOP AT import_data_csv INTO DATA(csv_line).
    CLEAR <import_data_line>.
    SPLIT csv_line AT delimiter INTO TABLE DATA(import_data_values).
    LOOP AT import_data_values INTO DATA(value).
      ASSIGN COMPONENT sy-tabix OF STRUCTURE <import_data_line> TO FIELD-SYMBOL(<field>).
      <field> = value.
    ENDLOOP.
    ASSIGN COMPONENT 'ACTION' OF STRUCTURE <import_data_line> TO FIELD-SYMBOL(<action>).
    <action> = 'N'.
    APPEND <import_data_line> TO <import_data_tab>.
  ENDLOOP.


  CALL FUNCTION 'VIEW_MAINTENANCE_GIVEN_DATA'
    EXPORTING
      action                       = 'U'
      view_name                    = import_table
    TABLES
      data                         = <import_data_tab>
    EXCEPTIONS
      client_reference             = 1   " View is tied to another client
      foreign_lock                 = 2   " View/Table is locked by another user
      invalid_action               = 3   " ACTION contains invalid values
      no_clientindependent_auth    = 4   " no auth. for maintaining client-indep. tables/v
      no_database_function         = 5   " Fct. mod. for data capture/disposal is missing
      no_show_auth                 = 6   " no display authorization
      no_tvdir_entry               = 7   " View/table is not entered in TVDIR
      no_upd_auth                  = 8   " no maintenance or display authorization
      only_show_allowed            = 9   " Display, but not maintain authorization
      system_failure               = 10  " System locking error
      unknown_field_in_dba_sellist = 11  " Selection table contains unknown field
      view_not_found               = 12  " View/table not found in DDIC
      OTHERS                       = 13.
  IF sy-subrc <> 0.
    MESSAGE |Error: { sy-subrc }| TYPE 'I'.
  ENDIF.

Der Beitrag Einfügen von vielen Daten in Tabellenpflegedialog erschien zuerst auf Tricktresor.

Komplexe Datenobjekte editieren

$
0
0

Wer schon einmal einen Funktionsbaustein getestet hat, der kennt mit Sicherheit den Dialog zur Eingabe von strukturierten Daten und Tabellen. Der Funktionsbaustein RS_COMPLEX_OBJECT_EDIT bietet dir genau diese Möglichkeit für deine eigenen Daten an. Folgend ein kleines Demoprogramm, das die Verwendung zeigt.

Ändern von zwei Datensätzen
Anzeige der Struktur (Meta-Daten)
Ändern der internen Tabelle der ersten Zeile

Code

REPORT zz_edit_complex_data.

PARAMETERS p_edit RADIOBUTTON GROUP mode DEFAULT 'X'.
PARAMETERS p_show RADIOBUTTON GROUP mode.
PARAMETERS p_meta RADIOBUTTON GROUP mode.

START-OF-SELECTION.
  TYPES: BEGIN OF ts_detail,
           a TYPE c LENGTH 1,
           b TYPE c LENGTH 3,
         END OF ts_detail,
         tt_detail TYPE STANDARD TABLE OF ts_detail WITH EMPTY KEY.
  TYPES: BEGIN OF ts_data,
           land1  TYPE land1,
           landx  TYPE landx,
           detail TYPE tt_detail,
         END OF ts_data.

  DATA gt_data TYPE STANDARD TABLE OF ts_data WITH DEFAULT KEY.
  DATA gv_mode TYPE c LENGTH 1.

  SELECT * FROM t005t INTO CORRESPONDING FIELDS OF TABLE gt_data UP TO 20 ROWS.

  gt_data = VALUE #(
    ( land1 = 'DE' landx = 'Germany' detail = VALUE #(
          ( a = '1' b = 'AA' )
          ( a = '2' b = 'BB' ) ) )
    ( land1 = 'FR' landx = 'France' detail = VALUE #(
          ( a = 'X' b = 'RR' )
          ( a = 'Y' b = 'SS' ) ) )
    ).

  gv_mode = COND #(
    WHEN p_edit = 'X' THEN 'X'
    WHEN p_meta = 'X' THEN 'M'
    ELSE space ).

  CALL FUNCTION 'RS_COMPLEX_OBJECT_EDIT'
    EXPORTING
      object_name          = 'Edit country details'
      mode                 = gv_mode
      insert_tab           = ' '
      upper_case           = ' '
      popup                = 'X'
      display_accessible   = 'X'
    CHANGING
      object               = gt_data
    EXCEPTIONS
      object_not_supported = 1
      OTHERS               = 2.
  IF sy-subrc <> 0.
    MESSAGE ID sy-msgid
          TYPE sy-msgty
        NUMBER sy-msgty
          WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.

Der Beitrag Komplexe Datenobjekte editieren erschien zuerst auf Tricktresor.

Subscreen-Bereiche anzeigen

$
0
0

Dynprogrammierung ist eine Angelegenheit mit, sagen wir mal, viel Historie. Gerade wenn man ein Programm mit Historie und Subscreens vor sich hat, ist es mitunter schwer, herauszufinden, in welchem Programm welcher Subscreen definiert wurde und welche Nummer der Subscreen hat.

In Hinweis 324687 (direkter Download) wird beschrieben, wie du die Subscreen-Bereiche kenntlich machen kannst. In einem Business Partner sieht das zum Beispiel so aus:

Aktivierung der Funktionalität

Um die Funktionalität nutzen zu können, müssen in der Registry des Testrechners folgende Einträge erstellt werden: [HKEY_CURRENT_USER\Software\SAP\SAPGUI Front\SAP Frontend Server\ReleaseDebug\ShowBorders]

  • „ENABLED“ (REG_DWORD) mit Wert 1
  • „SHOW_ALL“ (REG_DWORD) mit Wert 0
  • „CMyManager.ShowBorders“ (REG_DWORD) mit Wert 1
  • „CMyManager.ShowNames“ (REG_DWORD) mit Wert 1

Gegebenenfalls müssen zuerst der Key „ReleaseDebug“ und dann innerhalb dieses Keys „ShowBorders“ angelegt werden. Die Namen der Keys und Werte oben sind jeweils ohne Anführungszeichen einzutragen.

Der Beitrag Subscreen-Bereiche anzeigen erschien zuerst auf Tricktresor.

ALV-Grid Tabelle direkt ändern

$
0
0

Bei einem ALV-Grid wird die anzuzeigende Datentabelle der Methode SET_TABLE_FOR_FIRST_DISPLAY mitgegeben. Eine Änderung kann eigentlich nur aus der aufrufenden Klasse oder im Ereignis DATA_CHANGED erfolgen. Wird die Datentabelle im Programm geändert, so muss die Methode REFRESH_TABLE_DISPLAY aufgerufen werden, damit die Änderungen auch im Frontend angezeigt werden.

In einigen Fällen kann es jedoch erforderlich sein, die Daten von außen zu ändern. Dies ist jedoch nicht möglich, da das Attribut MT_OUTTAB, das die Datenreferenz zur Datentabelle hält, geschützt (protected) ist. Zudem werden die folgenden beiden öffentlichen Methoden, die es ermöglichen könnten, die Daten zu ändern, nicht unterstützt:

  • SET_DATA_CELLS
  • CHANGE_DATA_FROM_INSIDE

Wenn ich diese verwende, erhalte ich den Shortdump ASSERTION_FAILED in Klasse CL_DATAPTABLECACHE.

Glücklicherweise gibt es das If you wanna be my lover – Das FRIENDS-Konzept. Das können wir uns zunutze machen, indem wir die ALV-Grid-Instanz an eine Klasse übergeben, die mit CL_GUI_ALV_GRID befreundet ist und uns die Datenreferenz von MT_OUTTAB zurückgeben lassen.

Friends-Klasse

CLASS alv_data DEFINITION.
  PUBLIC SECTION.
    INTERFACES if_alv_rm_grid_friend .
    CLASS-METHODS get_outtab
      IMPORTING
        ir_grid          TYPE REF TO cl_gui_alv_grid
      RETURNING
        VALUE(ro_outtab) TYPE REF TO data.

ENDCLASS.

CLASS alv_data IMPLEMENTATION.
  METHOD get_outtab.
    ro_outtab = ir_grid->mt_outtab.
  ENDMETHOD.
ENDCLASS.

Nutzung

Wenn wir also die Instanz eines ALV-Grids haben, dann können wir dieses an die Klasse ALV_DATA=>GET_OUTTAB übergeben und erhalten eine nutzbare Datenreferenz. Diese Datenreferenz können wir zu einem Feldsymbol zuweisen:

DATA(my_outtab) = alv_data=>get_outtab( my_grid ).
FIELD-SYMBOLS <outtab> TYPE TABLE.
ASSIGN my_outtab->* TO <outtab>.

Anwendungsbeispiel „Navigationsprofil“

Wenn du dich bisher gefragt hast, wo zum Geier man sowas machen wollen würde, dann schau dir dieses Beispiel an. Es gibt die Funktionalität Navigationsprofil. Mit dieser Funktionalität kannst du ein ALV-Grid erweitern und modifikationsfrei Funktionalitäten hinzufügen. Das kann zum Beispiel durch eine Klasse erfolgen, die das Interface IF_NAVIGATION_PROFILE implementiert. In der Methode USER_COMMAND werden eine Referenz auf die Daten und die Instanz des ALV-Grid übergeben. mit GET_SELECTED_ROWS ist es dann möglich, ausgewählte Zeilen zu ermitteln und aufgrund dieser eine andere Funktionalität aufzurufen.

Allerdings ist es nicht möglich, die Daten selbst zu ändern. Es sei denn, du verwendest den oben genannten Trick.

Wie das Beispiel im Detail funktioniert, kannst du mit dem Demoprogramm NAVP_DEMO_TABLE nachvollziehen. Hierzu musst du das Navigationsprofil ändern und einen Button hinzufügen. Wie genau das geht, kannst du hier erfahren.

Zuerst benötigst du jedoch eine Klasse, die die Datenänderungen vornimmt.

CLASS zcl_navigation_profile_enno DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.

    INTERFACES if_navigation_profile .
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.



CLASS ZCL_NAVIGATION_PROFILE_ENNO IMPLEMENTATION.


* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_NAVIGATION_PROFILE_ENNO->IF_NAVIGATION_PROFILE~USER_COMMAND
* +-------------------------------------------------------------------------------------------------+
* | [--->] IO_ALV                         TYPE REF TO OBJECT
* | [--->] ID_TABLE                       TYPE REF TO DATA
* | [--->] IS_PROFILE_KEY                 TYPE        NAVP_S_PROFILE_KEY
* | [--->] IV_PARAMETER                   TYPE        NAVP_FUNCTION_PARAMETER
* +--------------------------------------------------------------------------------------</SIGNATURE>
  METHOD if_navigation_profile~user_command.
    DATA outtab TYPE REF TO data.
    FIELD-SYMBOLS <table> TYPE table.

    DATA(alv) = CAST cl_gui_alv_grid( io_alv ).
    outtab = lcl_data=>get_outtab( alv ).
    ASSIGN outtab->* TO <table>.

    DATA lt_delta TYPE lvc_t_modi.

    alv->get_selected_rows( IMPORTING et_row_no = DATA(lt_row_no) ).

    LOOP AT lt_row_no INTO DATA(ls_row).
      ASSIGN <table>[ ls_row-row_id ] TO FIELD-SYMBOL(<line>).
      ASSIGN COMPONENT 'FLDATE' OF STRUCTURE <line> TO FIELD-SYMBOL(<fldate>).
      <fldate> = sy-datum.
    ENDLOOP.

    FIELD-SYMBOLS <outtab> TYPE table.

    alv->refresh_table_display(
      i_soft_refresh = abap_true
      is_stable      = VALUE #( row = abap_true col = abap_true ) ).

    alv->set_selected_rows( it_row_no = lt_row_no ).

  ENDMETHOD.
ENDCLASS.

Danach kannst du die neue Drucktaste anlegen:

Drucktaste „Set Date“

Die Drucktaste wird nun – modifikationsfrei – in der Toolbar angezeigt:

Wenn du Einträge markierst und die Drucktaste drückst, dann wird das Flugdatum der markierten Einträge auf das Tagesdatum gesetzt.

Der Beitrag ALV-Grid Tabelle direkt ändern erschien zuerst auf Tricktresor.

Massenkopie von Klassen

$
0
0

Im Standard gibt es keine Möglichkeit, eine Klasse massenhaft, also mit vielen verschiedenen Namen zu kopieren. Gerade für Schulungen kann es jedoch sinnvoll sein, eine Klasse für viele Benutzer zu kopieren. Besonders sinnvoll ist es zum Beispiel für das UnitTest Koan von Damir Majer. Bei diesem Koan geht es darum, die verschiedenen Techniken der Unit-Tests zu erlernen.

Mit dem folgenden Programm ist es möglich, eine Klasse auf verschiedene Klassen zu kopieren. Es werden alle Benutzer einer bestimmten Benutzergruppe ermittelt. Für jeden Benutzer wird eine Klasse mit dem Benutzernamen aus der zu kopierenden Klasse erstellt.

Zusätzlich kannst du entscheiden, ob für jeden Benutzer eine eigene Entwicklungsklasse angelegt wird.

Mit der Testoption kannst du dir die Klassen, die angelegt werden würden, ausgeben lassen.

Code

REPORT zt9r_copy_class.

PARAMETERS p_test  AS CHECKBOX       DEFAULT 'X'.
PARAMETERS p_crdev AS CHECKBOX       DEFAULT 'X'.
PARAMETERS p_class TYPE seoclskey    DEFAULT 'ZCL_KOANS_ABOUT_ABAPUNIT'.
PARAMETERS p_newcl TYPE seoclskey    DEFAULT 'ZCL_KOANS_<USER>'.
PARAMETERS p_usrcls TYPE usr02-class DEFAULT 'DEV'.
SELECT-OPTIONS so_user FOR sy-uname.

START-OF-SELECTION.

  PERFORM copy.

FORM copy.
  DATA ls_newcls     TYPE seoclskey.
  DATA lt_class_keys TYPE seoc_class_keys.
  DATA lv_save       TYPE sap_bool.
  DATA lv_devclass   TYPE devclass.

  SELECT bname
    FROM usr02
    INTO TABLE @DATA(lt_users)
   WHERE bname IN @so_user
     AND class = @p_usrcls. "do not change DDIC, SAP*, etc

  LOOP AT lt_users INTO DATA(ls_user)
    WHERE bname <> 'DDIC'
      AND bname <> 'SAP*'.

    IF p_crdev = abap_true.
      PERFORM create_devclass USING ls_user-bname.
    ENDIF.

    lv_devclass = |${ ls_user-bname }|.

    ls_newcls-clsname = p_newcl.
    REPLACE '<USER>' WITH ls_user-bname INTO ls_newcls-clsname.
    WRITE: / ls_newcls-clsname.

    CHECK p_test = space.

    CALL FUNCTION 'SEO_CLASS_COPY'
      EXPORTING
        clskey       = p_class
        new_clskey   = ls_newcls
        save         = lv_save
      CHANGING
        devclass     = lv_devclass
      EXCEPTIONS
        not_existing = 1
        deleted      = 2
        is_interface = 3
        not_copied   = 4
        db_error     = 5
        no_access    = 6
        OTHERS       = 7.
    IF sy-subrc = 0.
      WRITE: 'copied'.
      lt_class_keys = VALUE #( ( ls_newcls ) ).
      CALL FUNCTION 'SEO_CLASS_ACTIVATE'
        EXPORTING
          clskeys       = lt_class_keys
        EXCEPTIONS
          not_specified = 1
          not_existing  = 2
          inconsistent  = 3
          OTHERS        = 4.
      .  IF sy-subrc = 0.
        WRITE: 'und aktiviert'.
      ENDIF.
    ELSE.
      WRITE: / ls_newcls-clsname, 'NOT copied'.
    ENDIF.


  ENDLOOP.
ENDFORM.

FORM create_devclass USING name.

  DATA lv_devclass TYPE devclass.
  DATA ls_devclass TYPE trdevclass.
  DATA lv_changed  TYPE c LENGTH 1.
  DATA lv_text     TYPE c LENGTH 80.

  ls_devclass-devclass  = |${ name }|.
  CALL FUNCTION 'TRINT_DEVCLASS_GET'
    EXPORTING
      iv_devclass        = ls_devclass-devclass
    EXCEPTIONS
      devclass_not_found = 1           " Package Does Not Exist
      OTHERS             = 2.
  IF sy-subrc = 0.
    RETURN.
  ENDIF.

  ls_devclass-ctext     = |local package for { name }|.
  ls_devclass-as4user   = name.
  ls_devclass-pdevclass = space.
  ls_devclass-dlvunit   = 'LOCAL'.
  ls_devclass-component = space.
  ls_devclass-comp_appr = space.
  ls_devclass-comp_text = space.
  ls_devclass-korrflag  = 'X'.
  ls_devclass-namespace = space.
  ls_devclass-tpclass    = space.
  ls_devclass-type       = 'N'.
  ls_devclass-target     = space.
  ls_devclass-packtype   = space.
  ls_devclass-restricted = space.
  ls_devclass-mainpack   = space.
  ls_devclass-created_by = 'COPYREPORT'.
  ls_devclass-created_on = sy-datum.

  CALL FUNCTION 'TRINT_MODIFY_DEVCLASS'
    EXPORTING
      iv_action             = 'CREA'
      iv_dialog             = space
      is_devclass           = ls_devclass
      iv_request            = space
    IMPORTING
      es_devclass           = ls_devclass
      ev_something_changed  = lv_changed
    EXCEPTIONS
      no_authorization      = 1
      invalid_devclass      = 2
      invalid_action        = 3
      enqueue_failed        = 4
      db_access_error       = 5
      system_not_configured = 6
      OTHERS                = 7.
  IF sy-subrc > 0.
    MESSAGE i000(oo) WITH 'error creating package' lv_devclass.
    STOP.
  ELSE.
    WRITE: / 'Package created:', name, lv_text.
  ENDIF.
ENDFORM.                    "create_devclass

Der Beitrag Massenkopie von Klassen erschien zuerst auf Tricktresor.

Code-Inspector-Prüfungen auflisten

$
0
0

Heute stand ich vor der Herausforderung, dass ich alle Code-Inspector-Prüfungen herausfinden wollte, die in einer Prüfvariante aktiv sind. Natürlich kann man sich diese über die Pflege der Varianten im Code-Inspector über Transaktion SCI anzeigen lassen. Allerdings wird hier der gesamte Baum der verfügbaren Prüfungen aufgelistet und man muss sich die heraussuchen, die aktiviert sind. Eine nervige und Fehleranfällige Aufgabe, wenn man die aktiven Prüfungen irgendwie dokumentieren möchte.

So sieht die Baumstruktur der Prüfungen aus:

Um die technischen Texte anstelle der Beschreibungen anzuzeigen, gehe über das Menü Prüfvariante • Anzeigen • Technische Namen.

Auflistung der aktiven Prüfvarianten

Mit dem folgenden Code werden die aktiven Prüfungen zu einer Prüfvariante ermittelt und ausgegeben.

Wenn du die Prüfungen einer globalen Prüfvariante ermitteln möchtest, dann muss OWNER leer bleiben. Für eine lokale Prüfvariante setze den entsprechenden User ein.

Code

PARAMETERS name  TYPE scichkv_hd-checkvname DEFAULT 'DEFAULT'.
PARAMETERS owner TYPE scichkv_hd-ciuser     DEFAULT space.

START-OF-SELECTION.

  SELECT SINGLE * FROM scichkv_hd
      WHERE checkvname = @name     ##WARN_OK
        AND ciuser     = @owner                         "#EC CI_NOORDER
       INTO @DATA(variant_header).

  DATA(main) =  cl_ci_checkvariant=>get_ref(
     p_user                   = owner
     p_name                   = name ).
  CHECK main IS BOUND.

  main->get_info(
    EXCEPTIONS
      could_not_read_variant = 1
      OTHERS                 = 2 ).

  IF sy-subrc = 0.
    cl_demo_output=>display_data(
      VALUE string_table(
        FOR variant IN main->variant (
          CONV #( variant-testname ) ) ) ).
  ENDIF.

Der Beitrag Code-Inspector-Prüfungen auflisten erschien zuerst auf Tricktresor.


Termin an Outlook versenden

$
0
0

In einem Projekt entstand die Idee, einen Termin, den eine SAP-Applikation ermittelt hat, als Termin an die verantwortliche Person zu schicken. Technisch muss man hierzu eine ICS-Datei erstellen und diese per E-Mail versenden. Wie ich gehofft hatte, hatte jemand bei SAP auch vorher schon eine ähnliche Idee und hat die Klasse CL_APPOINTMENT programmiert.

Das folgende Beispielprogramm ist eine Abwandlung des Demo-Reports RSSC_DEMO_CL_APPOINTMENT_APPL mit dem Zusatz, den erstellten Termin zu versenden.

Termintyp

Mit der Methode SET_TYPE kannst du den Termintypen setzen. In meinem Beispiel nutze ich den Wert “MEETING”. Die möglichen Termintypen stehen in Tabelle SCAPPTTYPE. Ich schätze, dass dieser Termintyp in erster Linie für die Speicherung im SAP-Office notwendig ist.

In meinem System habe ich den Termintyp ZREMINDER angelegt. Dieser wird in dem Termin entsprechend angezeigt:

Das Icon, das man auswählen kann (in meinem Fall die Alarm-Glocke), wird nur im SAP-Office angezeigt:

Termin senden

Die Methode CREATE_SEND_REQUEST liefert eine Klasse vom Typ CL_BCS zurück. Das bedeutet, das Versenden sowie weitere Parameter können wie gewohnt verwendet werden.

Erinnerung oder Meeting?

Das Programm ermöglicht es, bis zu zwei Teilnehmende zu definieren. Ein Teilnehmer muss vorhanden sein; denn einer soll schließlich den Termin auf jeden Fall bekommen. Die Person, an die die Erinnerung gesendet wird, hat dann die Möglichkeit, den Termin (unter Vorbehalt) anzunehmen oder abzusagen. Sind mehrere Personen im Termin definiert, dann muss ausgewählt werden, ob die Antwort jeweils gesendet, nicht gesendet oder vor dem Senden bearbeitet werden soll.

HTML-Body

Der Informationstext im Mailbody ist reiner Text. Mit Methode SET_TEXT kannst du diesen einfachen Text hinzufügen. Leider habe ich es nicht geschafft, einen Termin mit HTML-Text auszustatten. Wenn du mit SET_DOCUMENT der Klasse CL_BCS einen HTML-Text hinzufügst, dann wird das erzeugte ICS-Dokument ersetzt und du versendest am Ende eine normale E-Mail. Eventuell ist es möglich, wenn man eine Multipart-E-Mail erzeugt, bei der das ICS-Dokument eben ein Part der Nachricht ist.

Wenn du einen Tipp hast, wie das funktioniert, schreib mir gerne eine E-Mail.

Code

Der folgende Code zeigt exemplarisch die notwendigen Methodenaufrufe. Der Code ist ebenfalls im Github-Projek Appointment zu finden.

REPORT zt9tr_send_appointment.

INCLUDE <cntn01>.
TYPE-POOLS: sccon.

PARAMETERS p_orga  TYPE xubname    DEFAULT sy-uname OBLIGATORY.
PARAMETERS p_mail  TYPE ad_smtpadr DEFAULT 'ewf@inwerken.de' OBLIGATORY.
PARAMETERS p_mail2 TYPE ad_smtpadr DEFAULT 'lmr@inwerken.de'.
PARAMETERS p_title TYPE sc_txtshor DEFAULT 'Geschäftsessen'.
PARAMETERS p_loc   TYPE sc_room    DEFAULT 'La Civetta'.
PARAMETERS p_date  TYPE sy-datum   DEFAULT sy-datum.
PARAMETERS p_from  TYPE sc_timefro DEFAULT '120000'.
PARAMETERS p_to    TYPE sc_timeto  DEFAULT '130000'.
SELECTION-SCREEN BEGIN OF BLOCK body WITH FRAME TITLE TEXT-bdy.
PARAMETERS p_line1 TYPE so_text255 DEFAULT 'Wichtiges Essen'.
PARAMETERS p_line2 TYPE so_text255 DEFAULT 'Schickes Hemd anziehen'.
PARAMETERS p_line3 TYPE so_text255 DEFAULT 'Blumen mitbringen'.
SELECTION-SCREEN END OF BLOCK body.

CLASS main DEFINITION.
  PUBLIC SECTION.

    CONSTANTS c_status_confirmation_never    TYPE bcs_rqst VALUE 'N'.  "Never
    CONSTANTS c_status_confirmation_on_error TYPE bcs_rqst VALUE 'E'.  "Only if errors occur
    CONSTANTS c_status_confirmation_if_sent  TYPE bcs_rqst VALUE 'D'.  "If sent
    CONSTANTS c_status_confirmation_if_read  TYPE bcs_rqst VALUE 'R'.  "If read
    CONSTANTS c_status_confirmation_always   TYPE bcs_rqst VALUE 'A'.  "Always

    METHODS start.
  PRIVATE SECTION.
    DATA appointment       TYPE REF TO cl_appointment.
    DATA participant       TYPE scspart.

    METHODS add_participant IMPORTING i_mail_address TYPE clike.
ENDCLASS.

CLASS main IMPLEMENTATION.
  METHOD start.
    appointment = NEW #( ).

    "MEETING, VACATION, CUSTOMER, ABSENT
    appointment->set_type( 'ZREMINDER' ).

    appointment->set_organizer( organizer = p_orga ).

    add_participant( p_mail ).
    IF p_mail2 IS NOT INITIAL.
      add_participant( p_mail2 ).
    ENDIF.

    " add detail body text
    appointment->set_text( VALUE #(
     ( line = p_line1 ) ( line = cl_abap_char_utilities=>cr_lf )
     ( line = p_line2 ) ( line = cl_abap_char_utilities=>cr_lf )
     ( line = p_line3 )
     ) ).

    " set title and location
    appointment->set_title( p_title ).
    appointment->set_location( p_loc ).

    " set date and time using default settings
    " date_to will be the same as date_from
    " time zone will be the one from the user master records settings
    appointment->set_date( date_from = p_date
                           time_from = p_from
                           time_to   = p_to ).
    " set it to a high priority meeting
    appointment->set_priority( sccon_prio_very_high ).

    " this meeting is not yet confirmed
    appointment->set_status( sccon_status_planned ).
    " Important to set this one to space. Otherwise SAP will send a not user-friendly e-mail
    appointment->save( send_invitation = space ).

    TRY.
        " Now that we have the appointment, we can send a good one for outlook by switching to BCS
        DATA(send_request) = appointment->create_send_request( ).
        DATA(recipient) = cl_cam_address_bcs=>create_internet_address( p_mail ).
        send_request->add_recipient(
          i_recipient = recipient
          i_copy = abap_true ).
        IF p_mail2 IS NOT INITIAL.
          DATA(recipient2) = cl_cam_address_bcs=>create_internet_address( p_mail2 ).
          send_request->add_recipient(
            i_recipient = recipient2
            i_copy = abap_true ).
        ENDIF.
      CATCH cx_address_bcs INTO DATA(error_address).
        MESSAGE error_address TYPE 'I'.
        RETURN.
      CATCH cx_send_req_bcs INTO DATA(error_add_recipient).
        MESSAGE error_add_recipient TYPE 'I'.
        RETURN.
      CATCH cx_bcs INTO DATA(error_create_send_request).
        MESSAGE error_create_send_request TYPE 'I'.
        RETURN.
    ENDTRY.

    TRY.
        " don't request read/delivery receipts
        send_request->set_status_attributes(
          i_requested_status = c_status_confirmation_never
          i_status_mail      = c_status_confirmation_never ).
        "sent mail immediately
        send_request->set_send_immediately( abap_true ).
        " Send it to the world
        DATA(appointment_sent) = send_request->send( i_with_error_screen = abap_true ).
        IF appointment_sent = abap_true.
          COMMIT WORK AND WAIT.
          MESSAGE 'Einladung verschickt' TYPE 'S'.
        ELSE.
          MESSAGE 'Fehler beim Senden der Einladung' TYPE 'I'.
        ENDIF.
      CATCH cx_send_req_bcs INTO DATA(error_send).
        MESSAGE error_send TYPE 'I'.
    ENDTRY.

  ENDMETHOD.

  METHOD add_participant.

    DATA address           TYPE swc_object.
    DATA address_container TYPE STANDARD TABLE OF swcont.

    "set an internet address as a second partcipant of that appointment
    swc_create_object address 'ADDRESS' space.
    swc_set_element address_container 'AddressString'  i_mail_address.
    swc_set_element address_container 'TypeId' 'U'.
    swc_set_element address_container 'NoAdradmi' 'X'.
    swc_set_element address_container 'NoIntern' 'X'.
    swc_call_method address 'Create' address_container.
    CHECK sy-subrc = 0.
    "get key and type of object
    swc_get_object_key address participant-objkey.
    CHECK sy-subrc = 0.
    swc_get_object_type address participant-objtype.
    CHECK sy-subrc = 0.
    participant-send_mail = abap_true.
    appointment->add_participant( participant = participant ).

  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.

  NEW main( )->start( ).

Der Beitrag Termin an Outlook versenden erschien zuerst auf Tricktresor.

ABAP und Stellenanzeigen

$
0
0

Den Tricktresor gibt es nun seit über zwanzig Jahren. Am 17.4.2003 habe ich meinen ersten Beitrag verfasst: Drucktaste neben AUSFÜHREN-Button. Anhand des Screenshots kann man das Alter erahnen…

Seit ich angefangen habe, den Tricktresor zu betreiben, habe ich darüber nachgedacht, wie ich mit der Arbeit und der Mühe, die ich investiere, auch Geld verdienen kann. Die erste Idee war, Werbung zu schalten. Da ich selber jedoch Webseiten, die in erster Linie aus Werbung bestehen, hasse wie die Pest, habe ich nur ausgewählte Werbebanner aus einem Affiliate-Programm aufgenommen. Dadurch ist die Reichweite jedoch stark eingeschränkt und meine Interessen entsprechen nicht unbedingt deinen Interessen. Zudem wurde mir auch klar, dass Werbung mit Bannern nicht gut funktioniert. Der Grund ist ziemlich einfach: Wenn du durch die Suche in einer Suchmaschine auf meiner Seite landest, dann hast wahrscheinlich gerade ein Problem, das du Lösen musst. Dementsprechend schnell verlässt du meine Seite wieder. Und ziemlich wahrscheinlich wirst du in dieser Situation nicht die Muße haben, auf irgendwelche Banner zu achten, geschweige denn, eines anzuklicken. Zudem funktionieren Banner in der Regel nur dann gut, wenn man sich in einem Blogeintrag zu etwas informiert und dann Werbung angezeigt wird, die zum Thema passt. Naja, was soll ich sagen: Willst du ein SAP-System kaufen?

Ich habe es also relativ schnell wieder aufgegeben, Werbeanzeigen anzuzeigen. Im Laufe der Zeit wurde mir klar, dass ich froh sein kann, wenn ich die Betriebskosten hereinbekomme. Aber auch da war mir dann der Aufwand für buchstäblich EUR 12,40 pro Quartal zu groß und ich sah den Tricktresor in erster Linie als Werbung für mich und meine Fähigkeiten sowie für meine eigene Wissensspeicherung. Es passiert durchaus mal, dass ich nach einer Lösung suche, die mich dann zu meinem Artikel im Tricktresor führt. Sehr häufig weiß ich, dass ich etwas im Tricktresor finde und suche gezielt danach.

Ich komme ohne weitere Umschweife zum Hauptthema dieses Artikels: den

ABAP Stellenanzeigen

Das Schlagwort ABAP, das ich – wahrscheinlich genau wie du auch – in den verschiedenen Internet-Profilen stehen habe, reicht für viele RecruiterInnen aus, mir ein tolles Jobangebot anzubieten, das mich auf den nächsten Karrierelevel heben wird. Ich finde das sehr nervig, da ich nicht auf Stellensuche bin. Glücklicherweise schreiben die meisten: “Wenn ich Ihr Interesse geweckt habe, melden Sie sich”. Deswegen muss ich nicht mal ein schlechtes Gewissen haben, wenn ich mich nicht melde.

Und natürlich bin ich mir bewusst, dass es viele Firmen gibt, die mehr oder weniger händeringend SAP-Entwicklerinnen und -Entwickler suchen. Deswegen kam einem Kollegen, der seit Jahren das ABAP-Forum betreut, und mir die Idee, dass wir unsere Seiten, die sich wirklich fast ausschließlich mit ABAP-Entwicklung beschäftigen, für maßgeschneiderte Stellenanzeigen nutzen.

Vielleicht ist dir bereits aufgefallen, dass Inwerken seit einiger Zeit ABAP-EntwicklerInnen sucht?

Die Anzeigen tauchen seit ein paar Wochen im Tricktresor und dem ABAP-Forum zwischen den Beiträgen und im Seitenrand auf.

Wir erhoffen uns damit, dass wir dich als Zielgruppe unaufgeregt und dezent erreichen können, wenn du als ABAP-EntwicklerIn gerade auf Jobsuche bist. Beziehungsweise hoffen wir, dass Firmen auf unseren Plattformen mit dem richtigen Publikum mehr Erfolg haben dich zu finden, als auf anderen Jobbörsen.

Wenn du selber eine – oder auch mehrere – Anzeigen schalten möchtest, weil du Mitarbeiter und Mitarbeiterinnen suchst, die dein Team in der ABAP-Entwicklung unterstützen, dann lade ich dich herzlich ein, unser spezialisiertes Angebot zu besuchen (Preisliste).

Die Geschichte der letzten 20 Jahre…

Wenn du wissen möchtest, was ich die letzten zwei Jahrzehnte noch unternommen habe, um mit dem Tricktresor ein paar Mark nebenbei zu verdienen, dann lies gerne weiter.

T-Shirts

Eine Zeitlang fand ich es cool, ABAP-spezifische Designs und Sprüche zu entwerfen, die du dir bei Spreadshirt auf alle möglichen T-Shirts, Hoodies oder Caps hättest drucken lassen können. Diese “Sparte” habe ich dann jedoch irgendwann eingestellt. Die Gründe findest du im Artikel Warum ich meinen Spreadshirt-Shop gelöscht habe

Eines der meistverkauften Motive war der ABAP-Magician. Wobei “meistverkauft” eventuell irreführend ist; wir sprechen hier über maximal 10 T-Shirts… Ich schätze mal, dass man so viele ABAP’s NOT DEAD T-Shirts bereits auf jeder kleineren SAP-Veranstaltung sieht. Du kannst das T-Shirt übrigens bei Uwe im Spreadshirt-Shop kaufen: SE38.

Zudem scheine ich von meinen eigenen Designs deutlich mehr überzeugt gewesen zu sein, als du. Vielleicht hast du die Entwürfe und meinen Shop aber auch nicht gefunden, weil ich zu wenig Werbung dafür gemacht habe? Ich werde es nicht mehr erfahren.

Das ABAP-Kochbuch – Erfolgsrezepte für Entwickler

Dass man mit einem Fachbuch nicht reich wird, war uns ziemlich klar. Trotzdem waren meine Kollegen Maic, Dennis, Udo und Sascha und ich fasziniert von der Idee, ein Buch zu schreiben, in dem wir unsere Erfahrungen zur ABAP-Programmierung kund tun konnten.

Ursprünglich sollte das Buch ABAP – Jetzt helfe ich mir selbst heißen. Angelehnt an die legendäre Buchreihe mit der wahrscheinlich viele Tausend Menschen ihre Autos repariert haben.

Herausgekommen ist letztlich ein Kochbuch, über dessen Titel ich nur bedingt glücklich war. Einerseits ist die Assoziation Programmieren – Kochen ziemlich abgedroschen und zweitens gab es bereits das ABAP Cookbook, das es inzwischen jedoch nur noch im Antiquariat gibt. Das ABAP Cookbook war bereits in englischer Sprache erschienen und hatte mit unserem ABAP Kochbuch wirklich gar nichts zu tun. Der Rheinwerk-Verlag hat sich letztendlich durchgesetzt und mit deren professionellen und geduldigen Unterstützung ist auch ein tolles Buch dabei heraus gekommen.

Es ist ein schönes Gefühl, als Programmierer mal etwas handfestes produziert zu haben. Auch wenn SAPGUI-Programmierung nicht mehr up-to-date sind und die neuen ABAP-Features gänzlich fehlen, weil es sie damals einfach noch nicht gab, enthält das Buch meiner Meinung nach viele tolle Hinweise und Anleitungen, die immer noch relevant sind.

Aber, wie gesagt, zur Finanzierung des Tricktresors taugte diese Aktion wenig bis gar nicht.

SimDia²

Die Firma ERSAsoft Gmbh aus Maisach ist einer der wenigen Partner mit denen die Zusammenarbeit aus verschiedenen Gründen wirklich viel Spaß macht. Als Programmierer sollte ich ein Tool, das den Datenimport aus Excel in das SAP-System für AnwenderInnen sehr vereinfacht eigentlich nicht mögen, denn wenn ein Kunde das im Einsatz hat, darf ich mit Sicherheit keine Programme für den Import schreiben. Aber gerade deswegen mag ich das Produkt SimDia², denn gerade das Schreiben von Importprogrammen gehört für mich eher zu den nervigeren Arbeiten, denen man als Programmierer begegnet:

  • Es fehlen häufig genaue Definitionen für den Import oder die Verbuchung.
  • Daten sind nicht korrekt.
  • Fehler müssen penibel abgefangen und kundenfreundlich präsentiert werden.
  • Entwicklertests sind umständlich weil viele Objekte mit dem Import genau definiert werden. Hat man also einen Fehler, müssen eventuell die Daten manipuliert werden, damit man erneut buchen kann.
  • Durch Tests der AnwenderInnen und häufige Testzyklen dauert die Entwicklung lange.

Zusätzlich gibt es auch Nachteile für die AnwenderInnen, die das Programm verwenden müssen:

  • Die Bedienung ist evtl. nicht intuitiv und anwenderfreundlich, da mehr Wert auf andere Aspekte gelegt wurde.
  • Wenn sich Daten oder Anforderungen ändern, muss die IT-Abteilung mit einer Programmänderung beauftragt werden, die in der Regel lange dauert.
  • Das Programm ist unflexibel und kann nur für genau den Zweck verwendet werden, für den es konzipiert wurde. Schon leichte Abweichungen führen zu einem hohen nachträglichen Aufwand.

Ich persönlich bin also froh, wenn AnwenderInnen ihre Daten selber “ins System kloppen” können. Und SimDia² ist wirklich leicht zu erlernen, hochflexibel und vielseitig anwendbar. Die Arbeitsweise und einige Anwendungsmöglichkeiten kannst du gut in den Videos sehen.

Auch im Tricktresor gibt es einige Artikel, in denen ich auf die Funktionsweise von SimDia² eingehe:

Espresso-Tutorials

Da ich zusammen mit meinen Kollegen selbst das ABAP-Kochbuch geschrieben habe, unterstütze ich die Idee der Espresso-Tutorials. Die Fachbücher, die hauptsächlich auf den SAP-Kosmos abzielen, haben eine hohe Qualität und decken Bereiche ab, die in herkömmlichen SAP-Fachbüchern häufig zu kurz kommen. Die Bücher sind deutlich “leichter” als die Exemplare des Rheinwerk-Verlages, in dem unser Kochbuch erschienen ist. Die Bücher sind also nicht so umfangreich (maximal 120 Seiten), bieten aber gerade zu speziellen Themen einen tollen Mehrwert. Du kannst die Bücher einzeln kaufen oder eine Flatrate buchen. Mit der Flatrate hast du für den Bezahlzeitraum Zugriff auf alle Inhalte. Und das ist inzwischen eine Menge! Neben Büchern kannst du auch Videos und Kurse ansehen. Wenn du die Bibliothek von Espresso-Tutorials noch nicht kennst, solltest du unbedingt einen Blick riskieren!

Webhosting all-inkl

Der Tricktresor läuft seit einigen Jahren problemlos und günstig bei all-inkl.com. Wenn ich mal ein Problem hatte, hat der Support zeitnah, persönlich und kompetent geholfen. Insgesamt bin ich sehr zufrieden mit diesem Webhoster. Die Weboberfläche wirkt altbacken, ist jedoch funktionabel. Es gibt viele andere Webhoster, die vielleicht für WordPress schneller sind, aber dann sind sie in der Regel teurer. Oder sie sind noch günstiger, aber dann reicht die Leistung nicht.

Inwerken

Die Firma Inwerken, bei der ich seit inzwischen 15 Jahren als Entwickler tätig bin, unterstützt mich in vielen Dingen. Eine Zeitlang hat die Firma die Serverkosten für den Tricktresor übernommen, wofür ich sehr dankbar bin. Der Tricktresor wäre kaum möglich, wenn ich nicht das interne SAP-System von Inwerken nutzen könnte. Auf diese Weise kann ich viele Dinge entwickeln und prüfen und zusätzlich haben meine Kolleginnen und Kollegen eine stetig wachsende Programmsammlung für verschiedenste Problemlösungen “griffbereit”.

Der Beitrag ABAP und Stellenanzeigen erschien zuerst auf Tricktresor.

Auftragskonsistenz prüfen

$
0
0

Transportaufträge und das Transportmanagementsystem sind ein zentraler Bestandteil einer SAP-Systemlandschaft. In der Regel werden erstelle oder geänderte Objekte automatisch in einen Transportauftrag aufgenommen und gesperrt. Nach erfolgreichem Test werden die beteiligten Transportaufträge in das Produktivsystem transportiert.

Prüfungen

Eine Aufgabe oder Transportauftrag kann auf folgende zwei Dinge überprüft werden:

  • Konsistenz
  • Objektsyntax

Die Prüfungen rufst du im Menü Auftrag/ Aufgabe • Prüfen auf

Konsistenzprüfung

Die Konsistenzprüfung prüft zum Beispiel, ob die Transportschicht der den Objekten zugeordneten Pakete mit dem Transportziel des Auftrags übereinstimmt oder dass sich in einer Reparaturaufgabe auch nur reparierte Objekte befinden.

Solche Fehler können auftreten, wenn Objekte nach der Aufnahme in den Transportauftrag geändert werden.

Syntaxprüfung der Objekte

Diese Prüfung stellt sicher, dass alle Objekte syntaktisch fehlerfrei sind.

Massenprüfungen

Wenn es in einer Systemlandschaft zu umfangreichen oder elementaren Änderungen kommt, dann kann es sein, dass Transportaufträge vieler Leute betroffen sind. Ich habe keine Möglichkeit gefunden, Transportaufträge massenhaft zu prüfen. Aber zum Glück kann ich ja programmieren…

Der folgende Report übernimmt die Konsistenzprüfung aller selektieren Aufträge und deren Aufgaben. Die Meldungen werden in einer SALV-Liste ausgegeben.

Code

Den Sourcecode gibt es Dank abapGit auch auf github.

REPORT zt9r_request_consistency_check.

DATA request TYPE e070.

SELECT-OPTIONS so_nam FOR request-as4user    DEFAULT sy-uname.
SELECT-OPTIONS so_dat FOR request-as4date    DEFAULT '20200101' TO sy-datum.
SELECT-OPTIONS so_req FOR request-trkorr.
SELECT-OPTIONS so_fnc FOR request-trfunction DEFAULT 'K'.
SELECT-OPTIONS so_sta FOR request-trstatus   DEFAULT 'D'.

CLASS app DEFINITION.
  PUBLIC SECTION.
    METHODS start.
  PRIVATE SECTION.
    TYPES: BEGIN OF _data,
             trkorr   TYPE trkorr,
             as4user  TYPE e070-as4user,
             as4date  TYPE e070-as4date,
             as4text  TYPE e07t-as4text,
             strkorr  TYPE strkorr,
             message  TYPE text100,
             pgmid    TYPE e071-pgmid,
             object   TYPE e071-object,
             obj_name TYPE e071-obj_name,
           END OF _data,
           _data_tab TYPE STANDARD TABLE OF _data WITH DEFAULT KEY.
    DATA result_table TYPE _data_tab.
    DATA requests TYPE SORTED TABLE OF e070 WITH UNIQUE KEY trkorr.
    DATA tasks TYPE SORTED TABLE OF e070 WITH UNIQUE KEY trkorr.
    DATA messages TYPE ctsgerrmsgs.
    METHODS select.
    METHODS prepare.
    METHODS display.
ENDCLASS.


CLASS app IMPLEMENTATION.
  METHOD start.
    select( ).
    prepare( ).
    display( ).
  ENDMETHOD.
  METHOD select.
    SELECT * FROM e070 INTO TABLE @requests
      WHERE trkorr     IN @so_req
        AND trfunction IN @so_fnc
        AND trstatus   IN @so_sta
        AND as4user    IN @so_nam
        AND as4date    IN @so_dat
      ORDER BY PRIMARY KEY.

    IF sy-subrc = 0 AND lines( requests  ) > 0.
      SELECT * FROM e070 INTO TABLE @tasks
         FOR ALL ENTRIES IN @requests
        WHERE strkorr = @requests-trkorr
        ORDER BY PRIMARY KEY.
    ENDIF.

  ENDMETHOD.

  METHOD prepare.

    DATA full_request  TYPE trwbo_request.

    LOOP AT requests INTO DATA(request).

      LOOP AT tasks INTO DATA(task) WHERE strkorr = request-trkorr.
        CLEAR full_request.
        full_request-h = CORRESPONDING #( task ).

        CALL FUNCTION 'TR_READ_REQUEST'
          EXPORTING
            iv_read_e070       = 'X'
            iv_read_e07t       = 'X'
            iv_read_e070c      = ' '
            iv_read_e070m      = ' '
            iv_read_objs_keys  = 'X'
            iv_read_attributes = ' '
            iv_trkorr          = task-trkorr
          CHANGING
            cs_request         = full_request
          EXCEPTIONS
            error_occured      = 1
            no_authorization   = 2
            OTHERS             = 3.
        IF sy-subrc <> 0.
          APPEND VALUE #(
            trkorr   = request-trkorr
            as4user  = request-as4user
            as4date  = request-as4date
            as4text  = full_request-h-as4text
            strkorr  = task-trkorr
            message  = 'Error TR_READ_REQUEST' ##no_Text
           ) TO result_table.
          CONTINUE.
        ENDIF.

        CLEAR messages.
        CALL FUNCTION 'TR_CHECK_REQUEST'
          EXPORTING
            is_request           = full_request
            iv_check_lockability = space
            iv_collect_mode      = 'X'
          IMPORTING
            et_messages          = messages.

        LOOP AT messages INTO DATA(message).
          MESSAGE ID message-msgid
                TYPE message-msgty
              NUMBER message-msgno
                WITH message-msgv1 message-msgv2 message-msgv3 message-msgv4
                INTO DATA(message_text).
          DATA(err) = VALUE #( full_request-objects[ message-pos ] OPTIONAL ).
          APPEND VALUE #(
            trkorr   = request-trkorr
            as4user  = request-as4user
            as4date  = request-as4date
            as4text  = full_request-h-as4text
            strkorr  = task-trkorr
            pgmid    = err-pgmid
            object   = err-object
            obj_name = err-obj_name
            message  = message_text
           ) TO result_table.
        ENDLOOP.
      ENDLOOP.
    ENDLOOP.

  ENDMETHOD.
  METHOD display.

    IF result_table IS INITIAL.
      MESSAGE s477(tk) WITH 'selected'.
    ELSE.

      TRY.
          cl_salv_table=>factory(
            IMPORTING
              r_salv_table   = DATA(salv)
            CHANGING
              t_table        = result_table ).
          salv->get_functions( )->set_all( ).
          salv->get_columns( )->set_optimize( ).
          salv->display( ).
        CATCH cx_salv_msg INTO DATA(salv_error).
          MESSAGE salv_error TYPE 'I'.
      ENDTRY.
    ENDIF.

  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.

  NEW app( )->start( ).

Der Beitrag Auftragskonsistenz prüfen erschien zuerst auf Tricktresor.

Übersicht Code-Inspector-Prüfungen

$
0
0

Das folgende Programm liefert eine Übersicht über die Prüfungen, die in einer Code-Inspector-Variante aktiv sind.

Code

PARAMETERS name  TYPE scichkv_hd-checkvname DEFAULT 'DEFAULT'.
PARAMETERS owner TYPE scichkv_hd-ciuser     DEFAULT space.

START-OF-SELECTION.

  SELECT SINGLE * FROM scichkv_hd
      WHERE checkvname = @name     ##WARN_OK
        AND ciuser     = @owner    "#EC CI_NOORDER
       INTO @DATA(variant_header).

  DATA(main) =  cl_ci_checkvariant=>get_ref(
       p_user                   = owner
       p_name                   = name ).
  CHECK main IS BOUND.

  main->get_info(
    EXCEPTIONS
      could_not_read_variant = 1
      OTHERS                 = 2 ).

  IF sy-subrc = 0.
    cl_demo_output=>display_data(
      VALUE string_table(
        FOR variant IN main->variant (
          CONV #( variant-testname ) ) ) ).
  ENDIF.

Der Beitrag Übersicht Code-Inspector-Prüfungen erschien zuerst auf Tricktresor.

Finden ─ nicht suchen

$
0
0

Ich denke, nach beinahe 30 Jahren Erfahrung mit SAP-Systemen kann ich mich als alten Fuchs bezeichnen und es gibt wenig im ABAP-Umfeld, das ich noch nicht kenne (RAP und CAP und UI5 und so’n neumodischen Kram mal außen vor gelassen… 🙂 ). Diesen Monat sind mir jedoch bereits zwei Dinge begegnet, dir mir wirklich absolut neu sind. Das erste ist die Möglichkeit, einen Doppelklick in der Code-Vervollständigung von TYPES machen zu können. Das zweite ist ein Programm, über das ich heute gestolpert bin und das mir in Zukunft viel Sucharbeit ersparen wird:

RDOCFINDER – Full Text Search for Short and Long Texts

Bilder sagen mehr, als tausend Worte. Also bitteschön:

Selektionsbild

Ergebnisliste

Unterstützte Objekte

Suche nach Terminologie-Begriffen in folgenden Objekten:
- DDIC-Objekte "Datenelemente (F1) DE +
"Datenelementzusätze (F1) DZ +
"Schlüsselwörter der Datenelemente DS +
"Kurztext der Datenelemente DK +
"Reportüberschrift Datenelement DR +
"Domänen (F1) DO +
"Kurztext der Domänen DK +
"Domänen-Festwerte (F1) DV +
"Tabellen/Strukturen (F1) TB +
"Kurztext der Tabellen TK +
"Feld/Komponente der Tabellen TF +
"Indizes der Tabellen TX +
"Kurztext der Tabellentypen TT +
"Kurztext der Views TV +
"Kurztext der Suchhilfen SH +
"Kurztext der Sperrobjekte EQ +
- Benutzerstamm "Benutzerstamm Objekte (F1) UO +
"Kurztext der Objekte OK +
"Benutzerstamm Profile (F1) UP +
"Kurztext der Profile PK +
- Nachrichten "Nachrichten (F1) NA +
"Kurztext der Nachrichten NK +
"Kurztext der Nachrichtenklassen NN +
"Syslog-Meldungen (F1) SL +
"Kurztext der Syslog-Meldung SK +
- Reports "Reports (F1) RE +
"numerierte Texte usw. R... +
"Dynpro-Texte DY +
"Dynpro-Titel DX +
- Klassenbibliotheken CL/IF
"Klassen - Kurztext KT +
"Klassen - Langtext CL +
"Klassen Attribute - Kurztext KT +
"Klassen Attribute - Langtext CA +
"Klassen Methoden - Kurztext KT +
"Klassen Methoden - Langtext CO +
"Klassen Ereignisse - Kurztext KT +
"Klassen Ereignisse - Langtext CE +
"Klassen Typen - Kurztext KT +
"Klassen Typen - Langtext CT +
"Interface - Kurztext KT +
"Interface - Langtext IF +
"Interface Attribute - Kurztext KT +
"Interface Attribute - Langtext IA +
"Interface Methoden - Kurztext KT +
"Interface Methoden - Langtext IO +
"Interface Ereignisse - Langtext IE +
"Interface Typen - Kurztext KT +
"Meth. Parameter/Ausnahmen- Kurztext SC +
- Oberfläche "Oberfläche (F1) CF
"Titel TI +
"Funktionstastentext FM +
"Ikonentext FI +
"Quickinfo Ikone FQ +
"Menüleiste MA +
"Drucktastenbelegung MB +
"GUI-Status MC +
"Funktionstext MM +
"Funktionstastenbelegung MP +
- Modellierungsobjekte IM
"Entitätstypen - Kurztext ET +
"Entitätstypen - Langtext UE +
"Entitätstypen - Aliasname EA +
"Datenmodelle - Kurztext DM +
"Datenmodelle - Langtext UD +
"Beziehung - Kurztext ER +
"Beziehung - Langtext UH/UR/UK +
"Spezialisierungsart - Kurztext ES +
"Spezialisierungsart - Langtext US +
"Entitätstyp Kommentare - Langtext UC +
"Entitätstyp Beispiel - Langtext UB +
- IMG
"IMG-Struktur I +
"IMG-Aktivität I0 +
"IMG-Pflegeobjekt I1 +
"IMG-Attribute I2 +
"IMG-Doku IG +
- Test-Objekte
"CATT-Testfall - Kurztext GK +
"CATT-Testfall - Langtext GT +
"eCATT-Testskript - Titel E0 +
"eCATT-Testskript - Par./Kommandosch.E5 +
"eCATT-Testskript - Langtext E +
"eCATT-Testkonfig. - Titel E1 +
"eCATT-Testkonfig. - Variante E6 +
"eCATT-Testkonfig. - Langtext E +
"eCATT-Testdaten - Titel E2 +
"eCATT-Testdaten - Param./Variante E7 +
"eCATT-Testdaten - Langtext E +
"eCATT-Systemdaten - Titel E3 +
"eCATT-Systemdaten - Zielsystem E8 +
"eCATT-Systemdaten - Langtext E +
"eCATT-Validierungsobjekt - Titel E4 +
"eCATT-Validierungsobjekt - Langtext E +
- Erweiterungen
"SAP-Erweiterung (Modifik.) - Kurzt. MK +
"SAP-Erweiterung (Modifik.) - Langt. MO +
"Klassisches BAdI BA +
"Implementierung Klassisches BAdI BI +
"Zusammengesetzter Erweiterungsspot BJ +
"Impl. Zusammenges. Erweiterungsspot BK +
"Erweiterungsspot BS +
"Erweiterungsspot - BAdI B0 +
"Erweiterungsspot - BAdI TechDoku B1 +
"Erweiterungsspot - BAdI - Filter B2 +
"Erweiterungsspot - BAdI - Menü-Erw. B3 +
"Erweiterungsspot - BAdI - Scr.-Erw. B4 +
"Impl. Erweiterungsspot BT +
"Impl. Erweiterungsspot - BAdI B5 +
"Impl. Erweiterungsspot - BAdI TechD.B6 +
- allg. Text (TX) TX +
- Migrationstext (nur Langtext) MG +
- Release-Infos (IN RELN) (nur Langtext) IN +
- SAPscript-Formulare (Langtext + Kurztext) SF +-
- SAPscript-Stile (Kurztext) SS -
- Funktionsbaustein-Doku (FU) FU +
- Funktionsbaustein-Ausnahme-Doku (FX) FX +
- Funktionsbaustein-Parameter/Ausnahme-Kurztext FP +
- Dialogbaustein-Doku
"Kurztext der Dialogbausteine DB +
"Langtext Dialogbaustein DI +
- Syntax-Doku (SD)
"ABAP S0 +
"Umgebung ABAP S1 +
"CONT S2 +
"Dynpro S3 +
"Editor S4 +
"RSYN S5 +
- Texte im Dialog (DT) DT +
- Kurzdump KD +
- SET/GET-Parameter SG +
- Bereichsmenüs AM +
- verschiedene Kurztexte
"Kurztext der Transaktionen TA +
"Kurztext der log. Datenbank LD +
- Gateway texts
"Data Object Hierarchy - long text GH
"Data Object Hierarchy - short text GJ
"Data Object - long text GD
"Data Object - short text GE
"Operation - long text GO
"Operation - short text GP
"Consumption Model - long text GS
"Consumption Model - short text GU

Der Beitrag Finden ─ nicht suchen erschien zuerst auf Tricktresor.

Viewing all 166 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>