Generische Objekte in der Massenverarbeitung

Posten Sie hier Tutorials & Cookbooks.
2 Beiträge Seite 1 von 1
2 Beiträge Seite 1 von 1

Generische Objekte in der Massenverarbeitung

Beitrag von TravellingEntwickler (ForumUser / 13 / 3 / 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.

1. Upload
2. Download
3. Löschung

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.
Zuletzt geändert von TravellingEntwickler am 11. Dez 2019 14:34, insgesamt 3-mal geändert.

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)



Generische Objekte in der Massenverarbeitung - Download

Beitrag von TravellingEntwickler (ForumUser / 13 / 3 / 3 ) » 11. Dez 2019 14:33

Kommen wir heute zum Download der Anhänge aus dem SAP-System, diese hatte ich zunächst nur für einzelne Materialien erstellt, später kamen noch die gleichen Modus des Uploads hinzu.

Prinzipiell läuft das nicht viel anders als der Upload ab, bleibe auch hier wieder nur beim Material.

Die globale Datendeklaration ist doch noch etwas mehr geworden als beim letzten Teil

Code: Alles auswählen.

"Typendefinition Key
TYPES: BEGIN OF sty_key,
         foltp     TYPE so_fol_tp,  "Foldertyp
         folyr     TYPE so_fol_yr,  "Folderjahr
         folno     TYPE so_fol_no,  "Foldernummer
         objtp     TYPE so_obj_tp,  "Objektyp
         objyr     TYPE so_obj_yr,  "Objektjahr
         objno     TYPE so_obj_no,  "Objektnummer
         forwarder TYPE so_usr_nam, "Weiterleiter
       END OF sty_key.

"Typendefinition Anhang
TYPES: BEGIN OF sty_attach,
         foltp    TYPE so_fol_tp,  "Foldertyp
         folyr    TYPE so_fol_yr,  "Folderjahr
         folno    TYPE so_fol_no,  "Foldernummer
         objtp    TYPE so_obj_tp,  "Objektyp
         objyr    TYPE so_obj_yr,  "Objektjahr
         objno    TYPE so_obj_no,  "Objektnummer
         brelguid TYPE oblguid32,  "GUI-ID Länge 32
         roletype TYPE oblroltype, "Rollentyp
       END OF sty_attach.

****** GLOBALE TABELLEN & STRUKTUREN
DATA: gt_rel           TYPE obl_t_relt,                 "Tabelle Beziehungstyen
      gs_rel           TYPE obl_s_relt,                 "Struktur -"-
      gs_object        TYPE sibflporb,                  "Struktur Objekt
      gt_links         TYPE obl_t_link,                 "Tabelle Objektlinks
      gs_document_data TYPE sofolenti1,                 "Struktur Dokumentdaten
      gt_header        TYPE STANDARD TABLE OF solisti1, "Tabelle Header
      gs_documentid    TYPE sofmk,                      "Struktur Dokument-ID
      gt_content       TYPE swftlisti1.                 "Tabelle Dateiinhalte (binär)

******* DEKLARATION für Ausgabe
"Defintionen für Ausgabeprotokoll
TYPE-POOLS slis.

DATA: gt_fieldcat TYPE slis_t_fieldcat_alv ,            " Tabelle für die Ausgabe
      gs_fieldcat TYPE slis_fieldcat_alv,               " Struktur für Ausgabe
      gs_layout   TYPE slis_layout_alv,                 " Struktur für das Ausgabelayout
      gv_repid    TYPE sy-repid,                        " Report-ID
      gt_prot     TYPE TABLE OF zlog_gos_attach_s,  " Ausgabe mit globaler Struktur
      gs_prot     TYPE zlog_gos_attach_s.           " Struktur für Protokoll

******* GLOBALE VARIABLEN
DATA: gv_extct    TYPE so_extct,    "Ablagetyp Extern
      gv_doc_size TYPE so_doc_len,  "Dateilänge in Byte
      gv_filename TYPE cacl_string, "Dateiname
      gv_filetyp  TYPE sychar10,    "Dateityp
      gv_var      TYPE cacl_string, "Dummy
      gv_document TYPE so_entryid,  "Dokument
      gv_sys      TYPE logsys,      "Systemvariable
      gv_error    TYPE c LENGTH 1,  "Fehlerkennzeichen für Protokoll
      gv_langtext TYPE c LENGTH 60, "Variable Langtext für Fehler in FuBa
      gv_docname  TYPE so_obj_des,  "Dokumentname ohne Extension
      gv_matnr    TYPE matnr,
      gv_vbeln    TYPE vbeln,
      gv_equnr    TYPE equnr.


"Businessobjects Variablen
DATA: gv_instid TYPE sibfboriid,
      gv_typeid TYPE sibftypeid,
      gv_catid  TYPE sibfcatid.

**** GLOBALE KONSTANTEN ************
CONSTANTS:
  gc_atta  TYPE oblreltype VALUE 'ATTA',    "Anhang
  gc_note  TYPE oblreltype VALUE 'NOTE',    "Mitteilung
  gc_extct TYPE so_extct VALUE 'K'.         "Ablage extern Typ K

**** FELDSYMBOLE ************
FIELD-SYMBOLS:
  <links>   TYPE obl_s_link,  "Objektlinks
  <header>  TYPE solisti1,    "Kopfdaten
  <content> TYPE solisti1.    "Inhalte

**** TABELLEN ******
TABLES: mara.   "Material
Im Selektionscreen brauchen wir noch neben der Angabe der Materialien noch einen Downloadpfad, wo die Bilder (etc) hin sollen:

Code: Alles auswählen.

PARAMETERS:     p_path TYPE c LENGTH 50 OBLIGATORY DEFAULT 'C:\temp'. "Zielpfad

SELECT-OPTIONS: se_matnr FOR mara-matnr NO INTERVALS MODIF ID mm.     "Material
PARAMETERS: p_mm02 RADIOBUTTON GROUP r1 USER-COMMAND flag DEFAULT 'X',  "Materialnr.
ich spiele ganz gerne mit Modif-IDs rum, um es dem Anwender einfacher/übersichtlicher zu machen, wenn die Auswahl es bedingt (hier wären es x-Radiobuttons mit entsprechenden Select-Options).

Für die Auswahl des Pfades könnte man noch eine F4 Hilfe anbieten, das ganze sähe dann so aus:

Code: Alles auswählen.

  CALL FUNCTION '/SAPDMC/LSM_F4_FRONTEND_FILE'
    EXPORTING
      pathname = 'C:\'
    CHANGING
      pathfile = p_path
    EXCEPTIONS
      OTHERS   = 0.

Die BUS-Typen sind die gleichen wie beim Upload

Code: Alles auswählen.

  
IF p_mm02 EQ 'X'.
    gv_typeid = 'BUS1001006'.
    gv_catid  = 'BO'.     "BOR Objekttyp
ENDIF.
Die Dokumentenbeziehungen brauchen wir zwar erst später, aber ehe wir sie vergessen:

Code: Alles auswählen.

  gs_rel-sign   = 'I'.
  gs_rel-option = 'EQ'.
  gs_rel-low    = gc_atta.
  APPEND gs_rel TO gt_rel.

  CLEAR gs_rel-low.
  gs_rel-low    = gc_note.
  APPEND gs_rel TO gt_rel.
Bevor es an den Download geht, prüfe ich noch, ob es die selektierten überhaupt im System gibt, und übergebe anschließend die Materialnummer im LOOP an die GS_OBJECT, um das Programm schlank zu halten werden auch hier ein paar Schritte gekapselt.

Code: Alles auswählen.

FORM check_object_existence.

  "Lokale Deklarationen
  DATA: lt_mara TYPE TABLE OF mara,
        ls_mara TYPE mara,
        lt_vbak TYPE TABLE OF vbak,
        ls_vbak TYPE vbak,
        lt_equi TYPE TABLE OF equi,
        ls_equi TYPE equi.

  CLEAR: gs_object.

  IF p_mm02 EQ 'X'.   "Material auf Existenz prüfen

    SELECT matnr
      FROM mara
      INTO CORRESPONDING FIELDS OF TABLE lt_mara
    WHERE matnr IN se_matnr.

    IF sy-subrc EQ 0.

      LOOP AT lt_mara INTO ls_mara.
        gv_matnr = ls_mara-matnr.
        SHIFT gv_matnr LEFT DELETING LEADING '0'.

        gs_object-instid = ls_mara-matnr.
        gs_object-typeid = gv_typeid.
        gs_object-catid  = gv_catid.

        "Auslesen der Objektlinks
        PERFORM read_links USING    gs_object gt_rel
                           CHANGING gt_links.

        "Dokumentdaten lesen und Download ausführen
        PERFORM prepare_objects_for_download CHANGING gt_links gt_header gt_content gs_document_data.
        CLEAR gv_matnr.
      ENDLOOP.
    ENDIF.
ELSEIF.... 
ENDIF.
In der Routine READ_LINKS werden mittels Methode die entsprechenden Objektverlinkungen ausgelesen und für die Downloadvorbereitungen vorgehalten.

Code: Alles auswählen.

  TRY.
      "Links auslesen
      CALL METHOD cl_binary_relation=>read_links
        EXPORTING
          is_object           = p_gs_object
          ip_logsys           = gv_sys
          it_relation_options = p_gt_rel
        IMPORTING
          et_links            = p_gt_links.

    CATCH cx_obl_parameter_error
          cx_obl_internal_error
          cx_obl_model_error.

      RAISE no_link_found.

  ENDTRY.
Mit den ausgelesenen Links gehen wir in den nächsten FuBa und lesen entsprechende Binärdaten aus, im Fehlerfall wird der Fehlertext analog zum SUBRC ins Protokoll übertragen. Dummys nutze ich auch hier wieder für die einfachste Übertragung und zur Verschlankung.

Beim Testen ist es hin und wieder vorgekommen, dass der Filetype gänzlich in der GT_HEADER fehlte, dies löste sich dann über das direkte reinschreiben von "BIN" in die Variable.

Code: Alles auswählen.


  "lokale Datendeklarationen
  DATA: lv_codepage TYPE abap_encoding,
        lv_dummy    TYPE c LENGTH 10,
        lv_dummy2   TYPE c LENGTH 25.

  TRY.

      LOOP AT gt_links ASSIGNING <links>.

        MOVE <links>-instid_b TO gv_document.
        IF gv_document IS NOT INITIAL.

          "Objekt auslesen, Kopfdaten für Dateiname & Typ und Inhalte (binär) für 
          " Übertragung
          CALL FUNCTION 'SO_DOCUMENT_READ_API1'
            EXPORTING
              document_id                = gv_document
            IMPORTING
              document_data              = gs_document_data
            TABLES
              object_header              = gt_header
              object_content             = gt_content
            EXCEPTIONS
              document_id_not_exist      = 1
              operation_no_authorization = 2
              x_error                    = 3
              OTHERS                     = 4.

          IF sy-subrc <> 0.

            "im Fehlerfall wird direkt ans Protokoll übergeben.
            IF sy-subrc EQ '1'.
              gv_langtext = text-990. "Dokument-ID existiert nicht
            ELSEIF sy-subrc EQ '2'.
              gv_langtext = text-991. "Keine Berechtigung für den Vorgang
            ELSEIF sy-subrc EQ '3'
                OR sy-subrc EQ '4'.
              gv_langtext = text-999. "unbestimmter Fehler im Ablauf
            ENDIF.

            gv_error = '1'. "Merker für's Protokoll
            PERFORM create_protocol USING gv_error.

          ELSE.

            "Objekt in Dateinamen einbinden
            IF p_mm02 EQ 'X'.
              lv_dummy2 = gv_matnr.
            ENDIF.

            SPLIT gs_document_data-obj_descr AT '.' INTO gv_docname lv_dummy.
            CONCATENATE p_path lv_dummy2 '_' gv_docname '.' gs_document_data-obj_type
                   INTO gv_filename.

            "Format aus dem Header ziehen, ansonsten BIN verwenden.
            IF p_mm02 EQ 'X'.     "Material

              READ TABLE gt_header ASSIGNING <header> INDEX 2.
              IF sy-subrc IS INITIAL.
                IF <header>-line CS '&SO_FORMAT='.
                  SPLIT <header>-line AT '=' INTO gv_var gv_filetyp.
                ELSE.
                  gv_filetyp = 'BIN'.
                ENDIF.
              ELSE.
                gv_filetyp = 'BIN'.
              ENDIF.
Nachdem wir nun die Binären Daten und Datentypen auslesen konnten, wollen wir das ganze natürlich auch runterladen, hierzu kommt wieder ein Standard FuBa zum Zuge.

Code: Alles auswählen.

    
            gs_documentid = <links>-instid_b.
            gv_doc_size = gs_document_data-doc_size.

            "Download des Objekts
            CALL FUNCTION 'SO_OBJECT_DOWNLOAD'
              EXPORTING
                bin_filesize     = gv_doc_size
                filetype         = gv_filetyp
                path_and_file    = gv_filename
                extct            = gv_extct
                no_dialog        = abap_true
                codepage         = lv_codepage
              IMPORTING
                act_filename     = gv_filename
              TABLES
                objcont          = gt_content
              EXCEPTIONS
                file_write_error = 1
                invalid_type     = 2
                x_error          = 3
                kpro_error       = 4
                OTHERS           = 5.

            IF sy-subrc <> 0.
              "im Fehlerfall wird direkt ans Protokoll übergeben.
Im Fehlerfall wird wieder wie oben der SUBRC abgefragt und entsprechender Text ans Protokoll übergeben. GV_ERROR ist im Protokoll nur zur Abfrage, ob ein Fehler vorkam (1) oder nicht (0), kann natürlich auch über X und space etc. geregelt werden.

Ins Protokoll übernehme ich noch den Zielpfad, dazu je nach Modus die Objektnummern _ Titel in den Dateinamen sowie ein Anlagekennzeichen bei Erfolg und entsprechende Erfolgsmeldung. Bei Misserfolg kommt der Langtext aus dem Funktionsbaustein in den Infotext.

Am Schluss erfolgt noch die Ausgabe in den ALV, wenn immer die gleichen Nummern/Belege abgefragt werden sollen ließe sich das ganze natürlich auch in den Hintergrund legen und entsprechend in den Spool speichern.

Bei Fragen fragen 😉

Seite 1 von 1