Archive-Link, Ablage protokollieren
Intension
Für die Ablage von Rechnungsdokumenten in das elektr. Archiv, über die Transaktion OAWD, soll die Protokollierung erweitert werden. Während der Ablage geht die Verknüpfung zum Ursprungsbeleg (Datei) verloren. Um nachzuvollziehen, ob die Dateien auch tatsächlich eingelesen wurden, soll der Dateiname in Verbindung zur docID des Archivs protokolliert werden. Der Dateiname enthält von Anfang an den gelesenen eindeutigen Barcode der Rechnung. So wird sichergestellt, dass jederzeit eine Kontrolle über abgelegte Dateien stattfinden kann.
Abgrenzung
Zur Transaktion existiert leider kein Userexit. Zum FuB ARCHIVELINK_FUNCTION gibt es zwar ein Exit aber leider wird dieses zum falschen Zeitpunkt angesprungen. Eine weitere Möglichkeit, eine BadI (ALINK_AUTH_CON) wird auch zu früh angesprungen und kann hier nicht verwendet werden.
Die Daten werden in zwei Tabellen gespeichert. Die hier verwendete Tabelle /PSIIC/CAPT stammt vom Hersteller der Software zur optischen Erfassung und Weiterverarbeitung der Rechnungsbelege. In anderen Systemen wird sich das unterscheiden. Eine zweite zusätzliche Tabelle ZFI_ARCHLNK_LOG wurde von mir angelegt und enthält unter anderem die Archiv-Doc-ID. Über diese Doc-Id kann ein Bezug der Tabellen zueinander hergestellt werden.
Lösung
Erweiterungsimplementierung in den Funktionsbaustein HTTP_POST_FILES_255 einbauen und eine Methode zur weiteren Verarbeitung erstellen.
Den FuB se37 anzeigen und dort auf den Button „Erweitern“ klicken.
Erweiterungs-Optionen einblenden
Den Cursor auf eine Erweiterung stellen und über das Menü Bearbeiten->Erweiterungsoptionen entweder Implementierung anlegen oder ändern.
Hier ist ein Methodenaufruf mit zwei Übergabeparametern als Erweiterung angelegt worden. Der Parameter „ABSOLUTE_URI“ enthält hier den kompletten String, wie er an das elektr. Archiv gesendet wird.
Aus diesem String wird, durch den Methodenaufruf, die docID extrahiert. Über die docID wird eine Verknüpfung zum Dateinamen erstellt.
Den dazu gehörenden Dateinamen finden wir in dem Übergabeparameter COMM_ERR-Name.
Barcode
Die abzulegenden Papierdokumente werden mit einem Barcodeklebeetikett versehen. Das Scannprogramm erkennt diesen Barcode als Dokumententrennung. Nach jedem erkannten Barcode wird ein neues PDF-Dokument erzeugt. Der Dateiname wird aus dem Datums- und Zeitstempel, einer laufenden Nummer und dem erkannten Barcode mit Prefix gebildet.
Beispiel: 20131217_083849_014_BAR99999998.PDF
Das Prefix (_BAR) wird in der nachfolgend beschriebenen Methode erkannt und leitet den Barcode ein. Dieser wird als Zusatzinformation, zusammen mit dem Dateinamen in der Log-Tabelle gespeichert.
Methode
Klasse: Z_ARCHIVE_LINK
Methode: ZIF_ARCHIVE_LINK~FGET
Die Methode dient dazu, die Archivelink Dokument-ID aus der URL zu extrahieren und den Dateinamen festzustellen, um diese in der DB-Tabelle ZFI_ARCHLNK_LOG zu speichern.
* | Static Public Method Z_ARCHIVE_LINK=>ZIF_ARCHIVE_LINK~FGET
* +————————————————————————————————-+
* | [—>] ABSOLUTE_URI TYPE C
* | [—>] COMPONENT_PATH TYPE C
* +————————————————————————————–
METHOD ZIF_ARCHIVE_LINK~FGET.
DATA: PATT TYPE STRING VALUE `docId=`,
TEXT TYPE STRING,
OFF TYPE I,
MOFF TYPE I,
MLEN TYPE I,
DOCID TYPE C LENGTH 32,
FNAME TYPE C LENGTH 50,
LV_SMRTFX TYPE C LENGTH 1,
LV_TEXT TYPE STRING.
DATA: LT_WA TYPE ZFI_ARCHLNK_LOG.
IF SY-TCODE ‚OAWD‘. „Nur bei Transaktion OAWD
EXIT.
ENDIF.
OFF = 0.
WHILE SY-SUBRC = 0.
* Finde die Position, an der die ArchivID mitgegeben wird
FIND PATT IN SECTION OFFSET OFF OF
ABSOLUTE_URI
MATCH OFFSET MOFF
MATCH LENGTH MLEN.
IF SY-SUBRC = 0.
OFF = MOFF + MLEN.
ENDIF.
ENDWHILE.
LT_WA-DOCID = ABSOLUTE_URI+OFF(32).
PATT = ‚_BAR‘. „Der Barcode im Dateinamen wird an diesem Prefix erkannt
OFF = 0.
* Benutzerparameter: Wenn dieser gestzt ist, dann findet eine Prüfung auf doppelt erfasste Dateien statt
GET PARAMETER ID ‚ZSMARTFIX_ABLAGE‘ FIELD LV_SMRTFX.
IF SY-TCODE = ‚OAWD‘. „der SY-SUBRC wird wieder zurückgesetzt
ENDIF.
WHILE SY-SUBRC = 0.
* Finde die Position, an der der Barcode im Dateinamen steckt
FIND PATT IN SECTION OFFSET OFF OF
COMPONENT_PATH
MATCH OFFSET MOFF
MATCH LENGTH MLEN.
IF SY-SUBRC = 0.
OFF = MOFF + MLEN.
ENDIF.
ENDWHILE.
LT_WA-FNAME = COMPONENT_PATH.
IF LV_SMRTFX = ‚X‘.
IF OFF GT 4.
LT_WA-BARCODE = COMPONENT_PATH+OFF(8). „Barcode gefunden?
SELECT COUNT(*) FROM ZFI_ARCHLNK_LOG
WHERE BARCODE = LT_WA-BARCODE.
ELSE. „kein Barcode im Dateinamen, dann prüfe nur Dateiname
SELECT COUNT(*) FROM ZFI_ARCHLNK_LOG
WHERE FNAME EQ COMPONENT_PATH.
ENDIF.
IF SY-SUBRC = 0.
CONCATENATE ‚Die Datei:‘ COMPONENT_PATH ‚wurde bereits eingelesen‘ INTO LV_TEXT SEPARATED BY ‚ ‚.
MESSAGE LV_TEXT TYPE ‚I‘.
ENDIF.
ENDIF.
INSERT ZFI_ARCHLNK_LOG FROM LT_WA.
* ein Commit der DB erfolgt später im Hauptprogramm sowieso!
ENDMETHOD. „ZIF_ARCHIVE_LINK~FGET
Auswertereport
Das Ergebnis wird als ALV-Grid dargestellt. Hier mal ein Beispiel:
In diesem Beispiel hier werden die beiden Tabellen ZFI_ARCHLNK_LOG und /PSIIC/CAPT über einen Join ausgelesen.
Das Coding zum Report:
*&———————————————————————*
*& Report ZFI_MOMI_VERIFIER
*&
*&———————————————————————*
*&
*&
*&———————————————————————*
REPORT ZFI_MOMI_VERIFIER.
TABLES: /PSIIC/CAPT, ZFI_ARCHLNK_LOG, ZPSIICCAPT, USR02.
*DATA: ZPSIICCAPT LIKE TABLE OF /PSIIC/CAPT WITH HEADER LINE.
DATA: BEGIN OF LT_ZPSIICCAPT OCCURS 0.
INCLUDE STRUCTURE ZPSIICCAPT.
DATA: END OF LT_ZPSIICCAPT.
DATA: BEGIN OF LT_ZPSIICCAPT_D OCCURS 0.
INCLUDE STRUCTURE ZPSIICCAPT.
DATA: END OF LT_ZPSIICCAPT_D.
TYPE-POOLS: SLIS.
DATA: G_REPID LIKE SY-REPID.
DATA: GS_LAYOUT TYPE SLIS_LAYOUT_ALV,
WA_AKTUELLE_ZEILE LIKE LINE OF LT_ZPSIICCAPT,
LT_RETURN TYPE SY-SUBRC,
LINE TYPE I,
LT_TMP LIKE LT_ZPSIICCAPT,
INDEX TYPE SY–INDEX
.
TYPES: BEGIN OF TY_DATA.
INCLUDE STRUCTURE ZPSIICCAPT.
TYPES: END OF TY_DATA.
FIELD-SYMBOLS TYPE TY_DATA.
DATA: SELTAB TYPE RANGE OF I,
SELECTION LIKE LINE OF SELTAB,
INT TYPE I,
RSPAR TYPE TABLE OF RSPARAMS,
WA_RSPAR LIKE LINE OF RSPAR.
SELECTION–SCREEN: BEGIN OF BLOCK EIN WITH FRAME TITLE TEXT-EIN.
SELECT-OPTIONS P_BLNUM FOR /PSIIC/CAPT-BLNUM.
SELECT-OPTIONS DATUM FOR /PSIIC/CAPT-ERDAT.
SELECT-OPTIONS NAME FOR USR02-BNAME.
PARAMETERS: P_DUB TYPE ZFI_DUB.
SELECTION–SCREEN: END OF BLOCK EIN.
SELECTION–SCREEN: BEGIN OF BLOCK ZWE WITH FRAME TITLE TEXT-ZWE.
SELECT-OPTIONS STATUS FOR /PSIIC/CAPT-PSTAT.
SELECT-OPTIONS OBJECT FOR /PSIIC/CAPT-INP_OBJTYPE DEFAULT ‚/PSIIC/CAPT‘.
SELECTION–SCREEN: END OF BLOCK ZWE.
SELECTION–SCREEN: BEGIN OF BLOCK DRE WITH FRAME TITLE TEXT-DRE.
SELECT-OPTIONS P_FNAME FOR ZFI_ARCHLNK_LOG-FNAME.
SELECTION–SCREEN: END OF BLOCK DRE.
CLEAR LT_ZPSIICCAPT[].
* Nach einzelner Rechnung (Dateiname/Barcode) suchen
IF NOT P_FNAME IS INITIAL.
SELECT * INTO CORRESPONDING FIELDS OF TABLE LT_ZPSIICCAPT
FROM ZFI_ARCHLNK_LOG AS ARC LEFT JOIN /PSIIC/CAPT AS CAPT
ON ARC~DOCID = CAPT~ORG_ARC_DOC_ID
WHERE FNAME IN P_FNAME.
APPEND LT_ZPSIICCAPT.
ELSEIF NOT P_DUB IS INITIAL.
PERFORM DUPLIKATE.
ELSE.
SELECT * INTO CORRESPONDING FIELDS OF TABLE LT_ZPSIICCAPT
FROM /PSIIC/CAPT AS CAPT LEFT JOIN ZFI_ARCHLNK_LOG AS ARC
ON CAPT~ORG_ARC_DOC_ID = ARC~DOCID
WHERE
PSTAT IN STATUS AND
ERNAM IN NAME AND
ERDAT IN DATUM AND
BLNUM IN P_BLNUM.
APPEND LT_ZPSIICCAPT.
ENDIF.
*———————————————————————–
* Beginn ALV-Ausgabe
* Layout bestimmen.
PERFORM LAYOUT_ALLG_BUILD USING GS_LAYOUT.
* Daten als ALV-Liste anzeigen.
PERFORM ALV_ANZEIGEN.
*———————————————————————–
* Ende ALV-Ausgabe
* Jetzt kann END-OF-SELECTION folgen
*———————————————————————–
*———————————————————————–
* Unterprogramm fuer Ausgabe der ALV-Liste
*———————————————————————–
FORM ALV_ANZEIGEN.
G_REPID = SY-REPID.
CALL FUNCTION ‚REUSE_ALV_GRID_DISPLAY‘
EXPORTING
I_CALLBACK_PROGRAM = G_REPID
I_CALLBACK_USER_COMMAND = ‚REAKTION_AUF_DOPPELKLICK‘
I_GRID_TITLE = ‚in Erkennung‘
I_SAVE = ‚A‘
I_STRUCTURE_NAME = ‚ZPSIICCAPT‘
IS_LAYOUT = GS_LAYOUT
TABLES
T_OUTTAB = LT_ZPSIICCAPT.
IF SY-SUBRC 0.
„Hier koennen Sie auf Fehler beim ALV-Aufruf reagieren“
ENDIF.
ENDFORM. „alv_anzeigen.
*———————————————————————
* Unterprogramm fuer Layoutangaben
*———————————————————————
FORM LAYOUT_ALLG_BUILD USING LS_LAYOUT TYPE SLIS_LAYOUT_ALV.
LS_LAYOUT-ZEBRA = ‚X‘.
LS_LAYOUT-COLWIDTH_OPTIMIZE = ‚X‘.
ENDFORM. „layout_allg_build.
*&———————————————————————*
*& Form REAKTION_AUF_DOPPELKLICK
*&———————————————————————*
* text
*———————————————————————-*
* –>I_UCOMM text
* –>I_SELFIELD text
*———————————————————————-*
FORM REAKTION_AUF_DOPPELKLICK USING I_UCOMM
I_SELFIELD TYPE SLIS_SELFIELD.
CASE I_UCOMM.
WHEN ‚&IC1‘. „bei Doppelklick
READ TABLE LT_ZPSIICCAPT INTO WA_AKTUELLE_ZEILE
INDEX I_SELFIELD-TABINDEX.
* Klick auf die Dokument-ID
IF I_SELFIELD-FIELDNAME = ‚WI_ID‘.
CLEAR LT_RETURN.
CALL FUNCTION ‚SAP_WAPI_DIALOG_PROTOCOL‘
EXPORTING
WORKITEM_ID = WA_AKTUELLE_ZEILE-WI_ID
IMPORTING
RETURN_CODE = LT_RETURN
* TABLES
* MESSAGE_LINES =
* MESSAGE_STRUCT =
.
IF NOT LT_RETURN IS INITIAL.
MESSAGE ‚Zu diesem Workflow kein Protokoll gefunden.‘ TYPE ‚I‘.
ENDIF.
ELSE.
PERFORM FILL_SELECT.
SUBMIT OAFIND_2 USING SELECTION-SCREEN ‚1000‘
WITH SELECTION-TABLE RSPAR
AND RETURN.
ENDIF.
.
* Hier koennen Sie auf den Doppelklick reagieren.
* wa_aktuelle_zeile enthaelt die Zeile,
* die doppelgeklickt wurde.
* I_SELFIELD-FIELDNAME enthaelt den Namen
* des angeklickten Felds in der internen Tabelle.
ENDCASE.
ENDFORM. „REAKTION_AUF_DOPPELKLICK
*&———————————————————————*
*& Form Fill_Select
*&———————————————————————*
* text
*———————————————————————-*
* –> p1 text
*
*———————————————————————-*
FORM FILL_SELECT .
CLEAR RSPAR[].
WA_RSPAR-SELNAME = ‚OBJECT‘.
WA_RSPAR-KIND = ‚S‘.
WA_RSPAR–SIGN = ‚I‘.
WA_RSPAR-OPTION = “.
WA_RSPAR-LOW = OBJECT-LOW.
WA_RSPAR-HIGH = “.
APPEND WA_RSPAR TO RSPAR.
WA_RSPAR-SELNAME = ‚OBJECTID‘.
WA_RSPAR-KIND = ‚S‘.
WA_RSPAR–SIGN = ‚I‘.
WA_RSPAR-OPTION = “.
WA_RSPAR-LOW = ‚*‘ .
WA_RSPAR-HIGH = “.
APPEND WA_RSPAR TO RSPAR.
WA_RSPAR-SELNAME = ‚ARCHIVE‘.
WA_RSPAR-KIND = ‚S‘.
WA_RSPAR–SIGN = ‚I‘.
WA_RSPAR-OPTION = “.
WA_RSPAR-LOW = ‚ZY‘ .
WA_RSPAR-HIGH = “.
APPEND WA_RSPAR TO RSPAR.
WA_RSPAR-SELNAME = ‚ARCDOCID‘.
WA_RSPAR-KIND = ‚S‘.
WA_RSPAR–SIGN = ‚I‘.
WA_RSPAR-OPTION = “.
WA_RSPAR-LOW = WA_AKTUELLE_ZEILE-ORG_ARC_DOC_ID.
WA_RSPAR-HIGH = “.
APPEND WA_RSPAR TO RSPAR.
ENDFORM. “ Fill_Select
*&———————————————————————*
*& Form duplikate
*&———————————————————————*
* text
*———————————————————————-*
* –> p1 text
*
*———————————————————————-*
FORM DUPLIKATE .
SELECT * INTO CORRESPONDING FIELDS OF TABLE LT_ZPSIICCAPT_D
FROM /PSIIC/CAPT AS CAPT LEFT JOIN ZFI_ARCHLNK_LOG AS ARC
ON CAPT~ORG_ARC_DOC_ID = ARC~DOCID
WHERE
PSTAT IN STATUS AND
ERNAM IN NAME AND
ERDAT IN DATUM AND
BLNUM IN P_BLNUM.
APPEND LT_ZPSIICCAPT_D.
SORT LT_ZPSIICCAPT_D BY FNAME.
CLEAR LINE.
LOOP AT LT_ZPSIICCAPT_D.
* lese schon den nächsten Datensatz in den Speicher
INDEX = SY-TABIX + 1.
READ TABLE LT_ZPSIICCAPT_D INDEX INDEX INTO LT_TMP TRANSPORTING ALL FIELDS
.
* Vergleiche mit dem aktuellen Datensatz
IF LT_ZPSIICCAPT_D-FNAME = LT_TMP-FNAME.
* aktuellen und nächsten Datensatz in die Ausgabetabelle schreiben
APPEND LT_ZPSIICCAPT_D TO LT_ZPSIICCAPT.
APPEND LT_TMP TO LT_ZPSIICCAPT.
CLEAR LT_TMP.
ENDIF.
ENDLOOP.
DELETE ADJACENT DUPLICATES FROM LT_ZPSIICCAPT.
ENDFORM. “ duplikate
Tabellendefinition
Tabelle ZFI_ARCHLNK_LOG anlegen: In dieser Tabelle wird der Dateiname und der Barcode abgelegt.
Struktur ZPSIICCAPT anlegen: Die Struktur wird für die Ausgabe und Anzeige benötigt.
Dazu wird In der se11 eine Struktur angelegt und zwei Tabellen inkludiert.
Benutzerparameter
Die Methode prüft auch, ob die gleiche Datei bereits abgelegt wurde und gibt eine Warnmeldung aus. Damit dies steuerbar ist, wurde ein Benutzerparameter angelegt. Der Parameter ZSMARTFIX_ABLAGE hat einen Wert „X“ oder ist initial.
Einen Benutzerparameter kann man mit der TA se80 -> Objekt bearbeiten erzeugen.