Generische Objekte in der Massenverarbeitung

Posten Sie hier Tutorials & Cookbooks.
1 Beitrag Seite 1 von 1
1 Beitrag Seite 1 von 1

Generische Objekte in der Massenverarbeitung

Beitrag von TravellingEntwickler (ForumUser / 11 / 2 / 3 ) » 22. Nov 2019 15:50

Da ich mich in den letzten Wochen mit dem Thema auseinander gesetzt habe, wie man GOS (Generic Object Services / Dienste zum Objekt) in der Massenverarbeitung ins SAP System rein bekommt, aber auch wieder runterladen kann. Zuletzt kam noch das Löschen dazu.
Im WWW gibt es enorm viele Lösungen, aber die meisten sind nur halbgar, irgendwo fehlt immer ein Teil, oft der essentielle.
Fangen wir mit dem Hochladen der Anhänge ins SAP System an. Hierzu ist noch ein wenig Vorarbeit der SAP-Basis nötig. Damit wir auf einen externen Serverpfad zugreifen können, muss dieser erst in der AL11 aufgenommen werden.

Zunächst einmal die globalen Deklarationen:

Code: Alles auswählen.

"Datendeklaration
DATA:
  " Verknüpfung: Quelle & Ziel
  gs_object   TYPE sibflporb,
  gs_objtgt   TYPE sibflporb,

  " Dokumenten-Grunddaten
  gs_doc_info TYPE sofolenti1,
  gs_doc_data TYPE sodocchgi1,
  gd_doc_type TYPE soodk-objtp,

  "Daten für binäre Umschlüsselung
  x_xstring   TYPE xstring,
  lt_solix    TYPE solix_tab,

  "E-Mail Select-Option
  mail        TYPE ad_smtpadr.

"Tabellendefinition CSV-Datei
TYPES: BEGIN OF files,
         name      TYPE string,        "Dateiname
         path      TYPE string,        "Dateipfad
         object    TYPE string,        "Objekt
         anlage_kz TYPE c LENGTH 1,    "Anlage Kennzeichen
         infotext  TYPE c LENGTH 255.  "Infotext
TYPES: END OF files.

DATA: gs_files    TYPE files,
      gt_files    TYPE TABLE OF files,
      gv_filem    TYPE string,
      gt_contents TYPE STANDARD TABLE OF soli.

"Businessobjects Variablen
DATA: gv_instid TYPE sibfboriid,
      gv_typeid TYPE sibftypeid,
      gv_catid  TYPE sibfcatid.
Im Selection-Screen nehmen wir einen Parameter für den Dateipfad

Code: Alles auswählen.

PARAMETERS: p_path TYPE dirname_al11  OBLIGATORY DEFAULT '.\'.  "Dateipfad
sowie weitere Möglichkeit der Auswahl von verschiedenen Ausführungsarten (da wir diverse Themen in der Masse mit unterschiedlichsten Logiken versorgen müssen, werde ich mich an dieser Stelle auf die Materialien beschränken).

Darüber hinaus gibt's bei uns noch die Möglichkeit, die Ergebnisse als E-Mailprotokoll zu versenden, die Auswahl zwischen Initiallauf und Updatelauf bezieht sich bei uns nur auf das Datum der Ablage im Verzeichnis, da der Job täglich eingeplant ist.
An dieser Stelle daher nur Initiallauf.

Die verschiedenen Bereiche besitzen natürlich verschiedene BOR-Objekttypen, diese definieren wir nach Auswahlmodus.

Code: Alles auswählen.

*&---------------------------------------------------------------------*
*       text BUS-Typen nach Auswahlmodus definieren
*----------------------------------------------------------------------*
FORM typ_definieren.

  CLEAR: gv_typeid, gv_catid.

  "Bustypen nach Modus bestimmen
  IF p_mm02 EQ 'X'.

    gv_typeid = 'BUS1001006'.   "
    gv_catid  = 'BO'.     "BOR Objekttyp

  ELSEIF ... 
  ENDIF.
Danach lese ich den Dateipfad aus der AL11 mittels Standard-Funktionsbaustein aus

Code: Alles auswählen.

FORM get_files_from_dir  USING    p_p_path.

  DATA: lv_dir     TYPE eps2filnam,
        lt_dir     TYPE STANDARD TABLE OF eps2fili,
        ls_dir     TYPE eps2fili,
        lv_cnt     TYPE epsf-epsfilsiz,
        lv_ect     TYPE epsf-epsfilsiz.

  lv_dir = p_p_path.  

  CALL FUNCTION 'EPS2_GET_DIRECTORY_LISTING'
    EXPORTING
      iv_dir_name            = lv_dir
*     FILE_MASK              = ' '
    IMPORTING
*     DIR_NAME               = DIR_NAME
      file_counter           = lv_cnt
      error_counter          = lv_ect
    TABLES
      dir_list               = lt_dir
    EXCEPTIONS
      invalid_eps_subdir     = 1
      sapgparam_failed       = 2
      build_directory_failed = 3
      no_authorization       = 4
      read_directory_failed  = 5
      too_many_read_errors   = 6
      empty_directory_list   = 7
      OTHERS                 = 8.

Da wir nur bestimmte Dateianhänge haben wollen, wird die LT_DIR einmal mittel Wildcard + Dateiendung ausgesiebt und die Arbeitstabelle GT_FILES gefüllt. Beim Updatelauf wird dazu noch der Zeitstempel beachtet.

Und nun kommt der interessante Part, wie kommen die nun bekannten Dateien an die richtige Stelle?

Erstmal müssen die Dateien in für das System verständliche Sprache umgewandelt werden. Das Ganze geschieht im LOOP über die GT_FILES.

Code: Alles auswählen.

    CONCATENATE gs_files-path gs_files-name INTO gv_filem.

    OPEN DATASET gv_filem FOR INPUT IN BINARY MODE.
    IF sy-subrc EQ 0.
      READ DATASET gv_filem INTO x_xstring.
      IF sy-subrc NE 0.
        gs_files-infotext = 'Datei konnte nicht gelesen werden'.
        MODIFY gt_files FROM gs_files.
        CONTINUE.
      ENDIF.
    CLOSE DATASET gv_filem.
Ich öffne die Daten in Binär und schreibe sie in den xstring (vordefinierter ABAP Typ). Allein damit kann ich allerdings auch nicht arbeiten, hier kommt folgende Methode zum Einsatz, um das Ganze in eine Tabelle zu schieben.

Code: Alles auswählen.

    CALL METHOD cl_document_bcs=>xstring_to_solix
      EXPORTING
        ip_xstring = x_xstring
      RECEIVING
        rt_solix   = lt_solix.
Aus dem LOOP rufen wir nun die nächste Routine auf, um die Anlagen anzufügen.
Bitte nicht von der lokalen Datendeklaration erschlagen lassen

Code: Alles auswählen.


  DATA: folder_id            TYPE soodk, 
        lv_file              TYPE string,
        lv_matnr             TYPE mara-matnr,
        lv_check             TYPE i,
        lv_ext               TYPE c LENGTH 3,
        lv_bezei             TYPE c LENGTH 50,
        lv_date              TYPE c LENGTH 8,
        lv_name              TYPE c LENGTH 50,
        lv_check_date        TYPE c LENGTH 8,
        lv_timestamp         TYPE c LENGTH 15,
        v_timestampl         TYPE timestampl,
        ls_object_fl_change  TYPE sofm1,
        ls_obj_change        TYPE sood1,
        lv_originator_id     TYPE soudk,
        ls_object_fl_display TYPE sofm2,
        ls_object_hd_display TYPE sood2,
        lv_object_id         TYPE soodk,
        lt_objcont           TYPE STANDARD TABLE OF soli,
        lt_objhead           TYPE STANDARD TABLE OF soli,
        ls_objhead           TYPE soli,
        lt_objpara           TYPE STANDARD TABLE OF selc,
        lt_objparb           TYPE STANDARD TABLE OF soop1,
        lt_solitab           TYPE soli_tab,
        lv_mat1              TYPE c LENGTH 8,
        lv_instid_b          TYPE srgbtbrel-instid_b.

  "Lokale Definitionen für Existenzprüfung
  DATA: lv_chrel TYPE c LENGTH 1,
        lt_sood  TYPE TABLE OF sood,
        ls_sood  TYPE sood.

  "Lokale Definition für Binary_Relation_Create_Commit
  DATA:  ls_obj_rolea     TYPE borident,
         ls_obj_roleb     TYPE borident,
         lv_relationtype  TYPE breltyp-reltype,
         ls_binrel        TYPE gbinrel,
         lt_binrel_attrib TYPE STANDARD TABLE OF brelattr,
         lv_ep_note       TYPE borident-objkey,
         ls_folmem_k      TYPE sofmk.
Als nächstes müssen wir den "Ordner" im SAP ermitteln, hierbei hilft uns ein Funktionsbaustein

Code: Alles auswählen.

  "Folder ermitteln
  CALL FUNCTION 'SO_FOLDER_ROOT_ID_GET'
    EXPORTING
      region    = 'B'
    IMPORTING
      folder_id = folder_id
    EXCEPTIONS
      OTHERS    = 0.
Diesen brauchen wir erst später wieder. Wenn wir uns angewöhnt haben, die Dateien entsprechend der Materialnummer zu benennen, geht's mit dem Split einfach und man muss nicht zig Fälle abfangen. Im Zweiten Schritt prüfe ich, ob es die Anlage bereits in der SOOD gibt, mit Bezug auf das Tagesdatum und den Objekttitel entsprechend des Dateinamens, wenn's schon vorhanden ist, gibt's eine Markierung und entsprechenden Text ins Protokoll und es wird mit dem Satz der GT_FILES fortgefahren.

Code: Alles auswählen.

...  
ELSE. "wenn Datei eindeutig -> autom. Split MM02 

    " Dateipfad in Name, Extension und Datei auflösen
    CALL FUNCTION 'CH_SPLIT_FILENAME'
      EXPORTING
        complete_filename = lv_file
      IMPORTING
        extension         = gd_doc_type
        name              = gs_doc_data-obj_descr
        name_with_ext     = gs_doc_data-obj_name.

    SPLIT gs_doc_data-obj_name AT '.'  INTO lv_matnr lv_dummy2.
    lv_ext = gd_doc_type.

  TRANSLATE lv_ext TO UPPER CASE.
   TRANSLATE gs_files-name TO UPPER CASE.

 SELECT *
        FROM sood
        INTO CORRESPONDING FIELDS OF TABLE lt_sood
       WHERE objdes EQ gs_files-name
         AND crdat  EQ sy-datum.
An diese Stelle werden der Dateititel und Name festgelegt (diese sieht man später in der Anlagenliste) und konvertieren die Daten nochmal in ein anderes Format.

Code: Alles auswählen.

    
CONCATENATE '&SO_FILENAME=' gs_doc_data-obj_descr '_' lv_matnr '.' gd_doc_type INTO ls_objhead.

    APPEND ls_objhead TO lt_objhead.

    TRANSLATE gd_doc_type TO UPPER CASE.

*  "RAW in TEXT konvertieren
      CALL FUNCTION 'SO_SOLIXTAB_TO_SOLITAB'
        EXPORTING
          ip_solixtab = lt_solix
        IMPORTING
          ep_solitab  = lt_solitab.

        "Titel der Anlage
        CONCATENATE gs_doc_data-obj_descr '.' gd_doc_type
               INTO ls_obj_change-objdes.

Die MATNR muss evtl. nochmal ins 18-Stellige Format über ein Conversion-Exit gebracht werden.

Jetzt kommt der wichtigste Part, wir bestimmen noch die Dateiart, also die Vertraulichkeit, konvertieren die Tabelle nochmal in einen anderen Aufbau und hängen das Objekt an.

Code: Alles auswählen.


      "OBJSNS: F - Funktional, C - Firmenvertraulich, O - Vertraulich, P -
      "Privat
      ls_obj_change-objsns   = 'O'.
      ls_obj_change-objla    = sy-langu.
      ls_obj_change-file_ext = gd_doc_type.

*  "Konvertierung von Text nach Binär
      CALL FUNCTION 'SO_CONVERT_CONTENTS_BIN'
        EXPORTING
          it_contents_bin = lt_solitab
        IMPORTING
          et_contents_bin = lt_objcont.

      "Länge des Anhangs berechnen
      ls_obj_change-objlen = lines( lt_objcont ) * 255.

      "FuBa zum Einfügen des Anhangs zum Element (Material, Vertriebsbeleg,
      "Equipment)
      CALL FUNCTION 'SO_OBJECT_INSERT'
        EXPORTING
          folder_id                  = folder_id
          object_hd_change           = ls_obj_change
          object_type                = 'EXT'
        IMPORTING
          object_id                  = lv_object_id
        TABLES
          objcont                    = lt_objcont
          objhead                    = lt_objhead
        EXCEPTIONS
          active_user_not_exist      = 1
          communication_failure      = 2
          component_not_available    = 3
          dl_name_exist              = 4
          folder_not_exist           = 5
          folder_no_authorization    = 6
          object_type_not_exist      = 7
          operation_no_authorization = 8
          owner_not_exist            = 9
          parameter_error            = 10
          substitute_not_active      = 11
          substitute_not_defined     = 12
          system_failure             = 13
          x_error                    = 14
          OTHERS                     = 15.

      IF sy-subrc <> 0.
* Implement suitable error handling here
        MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
                 WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
      ENDIF.
Jetzt ist es physisch angelegt, die Verknüpfung muss jetzt noch sichtbar gemacht werden.

Code: Alles auswählen.

      "Füllen wird für die Verlinkung benötigt
      ls_folmem_k-foltp = folder_id-objtp.
      ls_folmem_k-folyr = folder_id-objyr.
      ls_folmem_k-folno = folder_id-objno.

      ls_folmem_k-doctp = lv_object_id-objtp.
      ls_folmem_k-docyr = lv_object_id-objyr.
      ls_folmem_k-docno = lv_object_id-objno.

      lv_ep_note = ls_folmem_k.

      "GS_OBJECT für Linkcreation aufbereiten
      "Variablen aus Routine TYP_DEFINIEREN übertragen
      gs_object-instid = lv_matnr.
      gs_object-catid  = gv_catid.
      gs_object-typeid = gv_typeid.

  " Aufbau für OBJ_ROLEA
        ls_obj_rolea-objkey  = lv_matnr.
      ls_obj_rolea-objtype = gv_typeid.     "Bustyp

      "Aufbau für OBJ_ROLEB
      ls_obj_roleb-objtype = 'MESSAGE'.
      ls_obj_roleb-objkey = lv_ep_note.

      "Link zum Anhang wird erstellt
      CALL FUNCTION 'BINARY_RELATION_CREATE_COMMIT'
        EXPORTING
          obj_rolea      = ls_obj_rolea
          obj_roleb      = ls_obj_roleb
          relationtype   = 'ATTA'
        EXCEPTIONS
          no_model       = 1
          internal_error = 2
          unknown        = 3
          OTHERS         = 4.

IF sy-subrc EQ 0.
        COMMIT WORK AND WAIT.   "Verknüpfung wird angelegt
ELSE.
        ROLLBACK WORK.
     "Fehler ins Protokoll schreiben
ENDIF.
Am Schluss erfolgt noch die Ausgabe in die ALV Liste bzw. Spool und die Erstellung und Versendung des E-Mail-Protokolls mittels Standard-Methoden.

Fragen & Anmerkungen sind gerne gesehen. Im nächsten Teil gehe ich dann auf den Download ein.

Folgende Benutzer bedankten sich beim Autor TravellingEntwickler für den Beitrag (Insgesamt 3):
Legxis (25. Nov 2019 09:38) • ewx (25. Nov 2019 10:28) • Lukas Sanders (29. Nov 2019 07:12)



Seite 1 von 1

Aktuelle Forenbeiträge

Struktur besorgen
vor 54 Minuten von NLengner 1 / 13
Dirty assign auf Feld in interner Tabelle mit Index
vor einer Stunde von Romaniac 1 / 15
Zweite Zeile vorhanden, dann überprüfen auf Feld Gleichheit
vor 5 Stunden von DeathAndPain 6 / 143

Unbeantwortete Forenbeiträge

Struktur besorgen
vor 54 Minuten von NLengner 1 / 13
Dirty assign auf Feld in interner Tabelle mit Index
vor einer Stunde von Romaniac 1 / 15
Transaktionen MEIS / VE01
vor 2 Tagen von SAP_ENTWICKLER 1 / 52
Cl_gui_html_viewer Problem
vor 6 Tagen von YoeBoy 1 / 28
Namensänderung von PSP Elementen
vor einer Woche von jamyr 1 / 46