*---------------------------------------------------------------------*
* Z _ B J H _ E X C E L _ D O I *
* *
* Autor: Bernd Haase (BJH Software) *
*---------------------------------------------------------------------*
* SAP R/3 DOI - Desktop Office Integration. Excel Mappe am Bildschirm *
* Beispielprogramm zum Aufblenden einer Excel-Mappe. In das Excel kann*
* der Tabelleninhalt einer beliebigen SAP Tabelle importiert werden. *
* Nach dortiger Bearbeitung werden die Daten wieder nach SAP expor- *
* tiert und stehen dort für die weitere Bearbeitung bereit. *
*---------------------------------------------------------------------*
* Hinweis beim Vergleich: um keine Includes in diesem Programm zu ver-*
* wenden, ist der vergleich auf numerische Zahlen und Datumsfelder *
* immer negativ, wegen der unterschiedlichen Aufbereitungsweise in SAP*
* und Excel *
*---------------------------------------------------------------------*
* (DX) DOI, Excel OO *
*---------------------------------------------------------------------*
* 06.06.2005 BHaa: Programm erstellt aus Vorlage *
*---------------------------------------------------------------------*
REPORT z_bjh_excel_doi MESSAGE-ID sap_doi.
TYPE-POOLS: soi.
CONSTANTS:
* Bereichsnamen für die Excel-Mappe festlegen, Formatzuordnung
co_format_char(04) TYPE c VALUE 'CHAR',
co_format_num(04) TYPE c VALUE 'NUM ',
co_format_dats(04) TYPE c VALUE 'DATS',
co_format_titel(05) TYPE c VALUE 'TITEL',
co_format_kommentar(05) TYPE c VALUE 'NOTIZ'.
DATA:
* SAP DOI (Desktop Office Integration) Interfaces
c_container TYPE REF TO cl_gui_custom_container,
c_kontrolle TYPE REF TO i_oi_container_control,
document TYPE REF TO i_oi_document_proxy,
spreadsheet TYPE REF TO i_oi_spreadsheet,
error TYPE REF TO i_oi_error,
errors TYPE REF TO i_oi_error OCCURS 0 WITH HEADER LINE.
DATA:
* Variablen speziell zur Klasse document
retcode TYPE soi_ret_string,
oo_interface_verfuegbar TYPE i.
****************************
* Formatierung Excel-Mappe *
****************************
DATA:
wa_bereich TYPE soi_range_item,
itab_bereich TYPE soi_range_list,
wa_def_bereich TYPE soi_full_range_item,
itab_def_bereich TYPE soi_full_range_table.
***************
* Dynpro 0100 *
***************
DATA:
erster_lauf(1) TYPE c VALUE ' ',
okcode LIKE sy-ucomm.
***************
* Excel - SAP *
***************
DATA:
wa_excel_out TYPE soi_generic_item,
itab_excel_out TYPE soi_generic_table,
z_excel_reihe(4) TYPE n,
z_excel_spalte LIKE z_excel_reihe,
zw_excel TYPE soi_generic_item,
zw_out_row TYPE soi_generic_item-row,
* Eingabestruktur und Ausgabestruktur der Daten gleich
wa_in_out_gleich(1) TYPE c.
FIELD-SYMBOLS:
<fs_excel> LIKE wa_excel_out.
******************
* Eingabetabelle *
******************
TYPES:
max_ausrichtung(500) TYPE c,
max_schluessel(100) TYPE c.
DATA:
wa_input TYPE max_ausrichtung,
wa_output TYPE max_ausrichtung,
itab_input TYPE TABLE OF max_ausrichtung,
itab_output TYPE TABLE OF max_ausrichtung,
wa_in_schl TYPE max_schluessel,
BEGIN OF wa_out_schl,
idx LIKE sy-tabix, "Referenz auf Datensatz itab_output
gef(1) TYPE c, "Abgleich beim Vergleich. Satz gefunden
t TYPE max_schluessel, "Schlüsselbegriff
END OF wa_out_schl,
itab_out_schl LIKE HASHED TABLE OF wa_out_schl WITH UNIQUE KEY t,
* Referenztabelle bei Vergleichsform "ohne Protokoll". Es wird nur
* protokolliert, welche Einträge aus der Eingabetabelle einem Schlüssel
* der Ausgabetabelle entsprachen. Bei nachfolgenden Abprüfen der
* Eingabetabelle auf nicht zugeordnete Ausgabetabellenschlüssel braucht
* nur über den Positionzeiger der Eingangstabelle geprüft werden
BEGIN OF wa_ohne_schl,
idx LIKE sy-tabix,
END OF wa_ohne_schl,
itab_ohne_schl LIKE HASHED TABLE OF wa_ohne_schl WITH UNIQUE KEY idx,
* Vergleich gegen die Struktur, bei Bedarf anpassen
anzahl_i TYPE i,
laenge_input LIKE anzahl_i,
laenge_out_schl LIKE anzahl_i,
anzahl_zeilen_in LIKE anzahl_i,
anzahl_spalten_in LIKE anzahl_i,
anzahl_zeilen_out LIKE anzahl_i,
anzahl_spalten_out LIKE anzahl_i.
DATA:
* Felder und Struktur der eingegebenen Tabelle
BEGIN OF wk_dd03l,
fieldname LIKE dd03l-fieldname,
position LIKE dd03l-position,
keyflag LIKE dd03l-keyflag,
rollname LIKE dd03l-rollname,
intlen LIKE dd03l-intlen,
inttype LIKE dd03l-inttype,
ddtext LIKE dd04t-ddtext,
* ab welcher Position (Spalte) beginnt das Feld, Anfang =0
offset TYPE ioff,
END OF wk_dd03l,
wktab_dd03l LIKE TABLE OF wk_dd03l,
* Schlüssel, beginnt immer ab Position 0, hat aber wieviele Stellen
wa_schl_offset TYPE ioff.
FIELD-SYMBOLS:
<fs_dd03l> LIKE wk_dd03l.
*********************
* Daten importieren *
*********************
DATA:
dref TYPE REF TO data,
tabname LIKE x030l-tabname,
* Länge der Struktur, wird zum Vergleich benötigt, ob die Struktur noch
* in die Inputtabelle zu übertragen ist
laenge_tabelle TYPE i,
* wieviele Datensätze einlesen
anzahl_saetze(3) TYPE n.
FIELD-SYMBOLS:
<fs_tabelle> TYPE ANY.
****************
* Markierungen *
****************
* beim Rücksprung aus der Excel-Mappe feststellen, welche Bereiche
* markiert worden sind
DATA:
* Einzelbereich markiert
wa_markiert TYPE soi_area_item,
* Bereiche markiert
itab_markiert TYPE soi_area_table,
itab_rowsid TYPE soi_map_table,
itab_columnsid TYPE soi_map_table.
***********************************************************************
* *
* P R O G R A M M S T A R T *
* *
***********************************************************************
* durchstarten mit Bildschirm 100
CALL SCREEN 100.
AT USER-COMMAND.
CASE sy-ucomm.
WHEN 'DYN'.
* um wieder aus der Reporting-Statistik herauszukommen.
LEAVE LIST-PROCESSING.
ENDCASE.
*---------------------------------------------------------------------*
* D Y N P R O _ 0 1 0 0 _ P B O *
*---------------------------------------------------------------------*
* Container Dynpro für die Excel-Mappe generieren beim ersten Durch- *
* lauf. Die Daten werden erst auf Eingabe aufgebaut, da dort die *
* Tabelle eingegeben wird. *
*---------------------------------------------------------------------*
MODULE status_0100 OUTPUT.
* Funktionstasten und Titelzeile
* bei den Funktionstasten muß mindestens eine mit dem Funktionscode
* 'DYN' vorhanden sein zum Rücksprung auf das Dynpro
SET PF-STATUS '100'.
* SET TITLEBAR '100'.
* wurde bereits die Basisumgebungung aufgebaut, wenn nicht, dieses
* jetzt durchführen
CHECK erster_lauf IS INITIAL.
MOVE 'N' TO erster_lauf.
* die SAP DOI Schnittstellenreferenzen holen
* als erstes die SAP DOI i_oi_container_control Schnittstelle
CALL METHOD c_oi_container_control_creator=>get_container_control
IMPORTING
control = c_kontrolle
error = error.
* prüfen, ob ein Fehler aufgetreten ist oder erfolgreich
CALL METHOD error->raise_message
EXPORTING
type = 'E'.
* den Container im Bildschirm generieren. Der Containername muß genauso
* heißen wie das Custom Control im Dynpro !!!
CREATE OBJECT c_container
EXPORTING
container_name = 'CONTAINER'.
* den SAP DOI Container initialisieren. Dem den eine Anweisung zuvor
* aufgebauten Objekt zuordnen und referenzieren
CALL METHOD c_kontrolle->init_control
EXPORTING
r3_application_name = 'R/3 Basis'
inplace_enabled = 'X'
inplace_scroll_documents = 'X'
parent = c_container
register_on_close_event = 'X'
register_on_custom_event = 'X'
no_flush = 'X'
IMPORTING
error = errors.
* Fehlerprotokolltabelle erweitern
APPEND errors.
* dem SAP DOI container sagen, daß eine Excel-Mappe eingespeist werden
* soll
CALL METHOD c_kontrolle->get_document_proxy
EXPORTING
document_type = 'Excel.Sheet'
no_flush = 'X'
* REGISTER_CONTAINER = 'X'
IMPORTING
document_proxy = document
error = errors.
* Fehlerprotokolltabelle erweitern
APPEND errors.
* und nun das Dokument (die Excel-Mappe) generieren
CALL METHOD document->create_document
EXPORTING
open_inplace = 'X'
document_title = 'R/3 Tabelle in Excel darstellen'
no_flush = 'X'
IMPORTING
error = errors.
* Fehlerprotokolltabelle erweitern
APPEND errors.
* prüfen, ob das Dokument (Excel-Mappe) erfolgreich angelegt werden
* konnte und auf diese dann mit der Klasse 'spreadsheet' referenzieren
CALL METHOD document->has_spreadsheet_interface
EXPORTING
no_flush = 'X'
IMPORTING
is_available = oo_interface_verfuegbar
error = errors.
APPEND errors.
CALL METHOD document->get_spreadsheet_interface
EXPORTING
no_flush = ' '
IMPORTING
sheet_interface = spreadsheet
error = errors.
APPEND errors.
* Schleife über alle gefundenen Fehler, da Get_spreadsheet_interface
* flushed und synchronisiert the automation queue !
LOOP AT errors.
CALL METHOD errors->raise_message
EXPORTING
type = 'E'.
ENDLOOP.
REFRESH: errors. FREE errors.
ENDMODULE.
*---------------------------------------------------------------------*
* D Y N P R O _ 0 1 0 0 _ E N D E *
*---------------------------------------------------------------------*
* Programm beenden und die Klassenobjekte löschen und freigeben. *
*---------------------------------------------------------------------*
MODULE upro-dynpro_0100_ende INPUT.
CASE okcode.
WHEN 'STOP'.
IF NOT document IS INITIAL.
CALL METHOD document->close_document.
FREE document.
ENDIF.
IF NOT c_kontrolle IS INITIAL.
CALL METHOD c_kontrolle->destroy_control.
FREE c_kontrolle.
ENDIF.
LEAVE PROGRAM.
ENDCASE.
ENDMODULE.
*---------------------------------------------------------------------*
* D Y N P R O _ 0 1 0 0 *
*---------------------------------------------------------------------*
* auf die Druckknöpfe im Bildschirm (auch die der Gui-Status reagieren*
*---------------------------------------------------------------------*
MODULE user_command_0100 INPUT.
CASE okcode.
**********
* Import *
**********
WHEN 'IMP'.
* Aufbauen der Objekte und die ausgewählte Tabelle einlesen
PERFORM upro-daten_import.
* Überschriftszeile
PERFORM upro-daten_import_titel.
* Daten in die am Bildschirm aufgebaute Excel-Maske importieren, auf
* die Excel-Tabelle umschiften und anzeigen.
PERFORM upro-daten_import_bs.
**********
* Export *
**********
WHEN 'EXP'.
* Daten aus dem Excel exportieren. Die bereit gestellte Tabelle dient
* dann zur weiteren Verarbeitung
PERFORM upro-daten_export.
IF anzahl_spalten_in <> anzahl_spalten_out.
MESSAGE i000(zc) WITH 'Spaltenanzahl unterschiedlich'.
ENDIF.
*************
* Vergleich *
*************
WHEN 'PRT'.
* Protokoll ausgeben, ganz billig als Reporting Liste. Ausrichtungsform
* beim Vergleich beachten
PERFORM upro-protokoll_ohne.
* PERFORM upro-protokoll_mit.
**************
* Markierung *
**************
WHEN 'MARK'.
* markierte Bereiche einlesen
* für den einfacheren Zugriff (der erst markierte Bereich gewinnt)
CALL METHOD spreadsheet->get_selection
EXPORTING
no_flush = ' '
IMPORTING
top = wa_markiert-top
left = wa_markiert-left
rows = wa_markiert-rows
columns = wa_markiert-columns
error = errors
retcode = retcode.
* alle Bereiche, die markiert worden sind, auswerten. Interessant sind
* die Wert von itab_markiert.
CALL METHOD spreadsheet->get_selected_areas
EXPORTING
no_flush = ' '
IMPORTING
areas = itab_markiert
rowsid = itab_rowsid
columnsid = itab_columnsid
error = errors
retcode = retcode.
**************
* Rücksprung *
**************
WHEN 'BACK'.
LEAVE TO SCREEN 0.
****************
* Programmende *
****************
* bitte auch Modul Direktabbruch beachten
WHEN 'STOP'.
IF NOT document IS INITIAL.
CALL METHOD document->close_document.
FREE document.
ENDIF.
IF NOT c_kontrolle IS INITIAL.
CALL METHOD c_kontrolle->destroy_control.
FREE c_kontrolle.
ENDIF.
LEAVE PROGRAM.
ENDCASE.
CLEAR okcode.
ENDMODULE.
*---------------------------------------------------------------------*
* D A T E N _ I M P O R T I E R E N *
*---------------------------------------------------------------------*
* aus Excel-Sicht: Daten werden aus dem SAP in Excel importiert. Diese*
* Section übernimmt nur die allgemeinen Definitionen für die Excel- *
* Mappe. Die Felder der gewünschten Tabelle werden eingelsen sowie die*
* Daten selber. Dabei ist es möglich, den Einlesebereich zu begrenzen *
*---------------------------------------------------------------------*
FORM upro-daten_import.
* wurde überhaupt ein Tabellenname vergeben
CHECK NOT tabname IS INITIAL.
* Felder und Struktur zur Tabelle einlesen
PERFORM upro-daten_import_felder.
* die Tabelle umfaßt wieviel Spalten
DESCRIBE TABLE wktab_dd03l LINES anzahl_spalten_in.
IF anzahl_spalten_in > 0.
* eingebener Tabellenname ist tatsächlich eine Tabelle.
* generieren eines Objektes der Struktur der ausgewählten Tabelle.
* Damit kann auf jedes Feld in der Stuktur referenziert werden. Die
* Feldname werden etwas später in diesem Unterprogramm eingelesen und
* können in Kombination abgeglichen werden
CREATE DATA dref TYPE (tabname).
ELSE.
* Keine R/3 Tabelle, Abbruch und raus
MESSAGE i001 WITH tabname.
EXIT.
ENDIF.
ASSIGN dref->* TO <fs_tabelle>.
DESCRIBE FIELD <fs_tabelle> LENGTH laenge_tabelle.
DESCRIBE FIELD wa_input LENGTH laenge_input.
IF laenge_tabelle > laenge_input.
* Struktur der einzulesenden Tabelle kann nicht komplett abgebildet
* werden. Die einzulesende Tabellenstruktur ist zu lang
MESSAGE i002 WITH tabname laenge_input.
* könnte auch weiterlaufen mit abschneiden, aber Abbruch
EXIT.
ENDIF.
* Input-Tabelle füllen, beachten, ob im Dynpro eine Anzahl vorgegeben
* wurde, wieviele Sätze einzulesen sind
IF anzahl_saetze = 0.
SELECT * FROM (tabname)
INTO TABLE itab_input.
ELSE.
SELECT * FROM (tabname)
INTO TABLE itab_input
UP TO anzahl_saetze ROWS.
ENDIF.
* wieviel Datensätze sind gepuffert
DESCRIBE TABLE itab_input LINES anzahl_zeilen_in.
* Range-Bereich für die verschiedensten Formen festlegen. Diese Art der
* Festlegung wäre den CSS-Style in der HTML-Programmierung vergleichbar
CALL METHOD spreadsheet->insert_range_dim
EXPORTING
name = co_format_char
top = 2
left = 2
no_flush = 'X'
rows = anzahl_zeilen_in
columns = anzahl_spalten_in
IMPORTING
error = errors.
APPEND errors.
* für mehrere Bereich gleichzeitig
* CALL METHOD spreadsheet->insert_ranges
* Formatierung eines Bereiches in der Excel-Mappe vornehmen
* Wert für "typ"
* 0 = Standard (auch führende Nullen werden ausgegeben)
* 1 = Zahl mit 2 Dezimalstellen, wenn nicht anders angegeben
* 2 = Exponential-Zahl. 115 wird als 1,15 E+02 dargestellt
* 3 = Prozentwert
* 4 = Datum
CALL METHOD spreadsheet->set_format
EXPORTING
no_flush = 'X' "sammeln und noch keine Anzeige
rangename = co_format_char
typ = 0 "Textformat"
currency = ' '
* DECIMALS = 4
IMPORTING
error = errors.
APPEND errors.
* Farbe setzen
* Vordergrundfarbe 0/1= schwarz, 2= weiß, 3= rot, 4= grün, 5= blau
* 6= gelb,7= mangenta,8= cyano,9= braun,10= dunkelgrün,11=dunkelblau ...
CALL METHOD spreadsheet->set_color
EXPORTING
no_flush = 'X'
rangename = co_format_char
back = 6
front = 21
IMPORTING
error = errors.
APPEND errors.
* nächsten Bereich aufbauen
* Titelzeile und Überschriften festlegen plus das Element für den
* Kommentar und alles in einer anderen Farbe
COMPUTE anzahl_i = anzahl_spalten_in + 1.
CALL METHOD spreadsheet->insert_range_dim
EXPORTING
no_flush = 'X'
name = co_format_titel
top = 1
left = 1
rows = 1
columns = anzahl_i
IMPORTING
error = errors.
APPEND errors.
CALL METHOD spreadsheet->set_color
EXPORTING
no_flush = 'X'
rangename = co_format_titel
back = '25'
front = '2'
IMPORTING
error = errors.
APPEND errors.
* Spalte 1, Bereich für eigene Kommentare
CALL METHOD spreadsheet->insert_range_dim
EXPORTING
no_flush = 'X'
name = co_format_kommentar
top = 2
left = 1
rows = anzahl_zeilen_in
columns = 1
IMPORTING
error = errors.
APPEND errors.
ENDFORM.
*---------------------------------------------------------------------*
* D A T E N _ I M P O R T _ F E L D E R *
*---------------------------------------------------------------------*
* Zu der gewünschten Tabelle die Felder einlesen und die Zusatzdaten *
* dafür bereitstellen. Die Felder werden benötigt, um die unterschied-*
* lichen Strukturen, die alle über ein einheitliches Caharakter-Feld *
* laufen, aufschlüsseln zu können und den Inhalt zu dem gefragten Feld*
* liefern zu können *
*---------------------------------------------------------------------*
FORM upro-daten_import_felder.
* ausgewählte Tabelle beinhaltet welche Felder
DATA:
p_feld TYPE rfc_fields,
ptab_felder TYPE TABLE OF rfc_fields.
FIELD-SYMBOLS:
<fs_feld> LIKE p_feld.
*= = = = = = = = = = = = = =
CLEAR: wktab_dd03l, ptab_felder, wa_schl_offset.
REFRESH: wktab_dd03l, ptab_felder.
* dieser Join hat Mehrfachfunktion.
* 1.) ist der Eingabewert im Data Dictionary bekannt
* 2.) ist der Eingabewert tatsächlich eine echte Tabelle
* 3.) ist die Tabelle und deren Felder aktiv
* 4.) gebraucht werden die Schlüsselfelder der Tabelle
SELECT
ij_03~fieldname
ij_03~position
ij_03~keyflag
ij_03~rollname
ij_03~intlen
ij_03~inttype
FROM dd02l AS ij_02
INNER JOIN dd03l AS ij_03
ON ij_02~tabname = ij_03~tabname
INTO TABLE wktab_dd03l
WHERE ij_02~tabname = tabname
AND ij_02~as4local = 'A' "nur aktive Versionen Tabelle
AND ij_02~as4vers = '0000'
AND ij_02~tabclass = 'TRANSP' "muß eine transparente Tabelle sein
AND ij_03~fieldname => 'A' "nur echte Felder
AND ij_03~fieldname <= 'Z'
AND ij_03~as4local = 'A' "nur aktive Versionen Felder
AND ij_03~as4vers = '0000'.
IF sy-subrc = 0.
* Berechnung des Offsets über den Baustein ist sicherer
CALL FUNCTION 'RFC_GET_STRUCTURE_DEFINITION'
EXPORTING
tabname = tabname
TABLES
fields = ptab_felder
EXCEPTIONS
table_not_active = 1
OTHERS = 2.
ENDIF.
LOOP AT ptab_felder ASSIGNING <fs_feld>.
LOOP AT wktab_dd03l ASSIGNING <fs_dd03l>
WHERE fieldname = <fs_feld>-fieldname.
* durch Include oder Append kann sich die Zählung verschoben haben, das
* hat der Baustein aber alles bereits inklusive, somit diese Daten über-
* nehmen
MOVE <fs_feld>-position TO <fs_dd03l>-position.
MOVE <fs_feld>-offset TO <fs_dd03l>-offset.
* Offset für den Schlüssel berechnen. Die Schlüsselfelder sind immer
* hintereinander und beginnen in der Struktur bei Position 0.
IF <fs_dd03l>-keyflag = 'X'.
p_feld-offset = <fs_feld>-offset + <fs_feld>-intlength.
IF p_feld-offset > wa_schl_offset.
MOVE p_feld-offset TO wa_schl_offset.
ENDIF.
ENDIF.
* Kurztext zum Feld dazumischen
IF <fs_dd03l>-rollname IS INITIAL.
* keine Referenz auf eine Domäne, den eingegebenen Text zum Feld in der
* Tabelle lesen
SELECT SINGLE ddtext FROM dd03t INTO <fs_dd03l>-ddtext
WHERE tabname = tabname
AND ddlanguage = sy-langu
AND as4local = 'A'
AND fieldname = <fs_dd03l>-fieldname.
ELSE.
* Referenz auf eine Domäne, den Domänentext einlesen
SELECT SINGLE ddtext FROM dd04t INTO <fs_dd03l>-ddtext
WHERE rollname = <fs_dd03l>-rollname
AND ddlanguage = sy-langu
AND as4local = 'A'
AND as4vers = '0000'.
ENDIF.
IF sy-subrc <> 0.
CLEAR <fs_dd03l>-ddtext.
ENDIF.
ENDLOOP.
ENDLOOP.
* Sortieren der Feldertabelle, daß das Ergebnis des Vergleiches auch so
* angezeigt wird, wie es auch in der DDIC-Tabelle in der SE11 geschieht
SORT wktab_dd03l BY position.
* Sicherheitsprüfung, ob Schlüssellänge ausreichend ist. Sollte beachtet
* werden, da es keine Abfrage beim Exportieren gibt, welche den Offset
* gegen die Maximallänge prüft
DESCRIBE FIELD wa_out_schl LENGTH laenge_out_schl.
IF wa_schl_offset > laenge_out_schl.
MESSAGE e010(zc) WITH 'Schlüssellänge überschritten'.
ENDIF.
* Data-Objekt generieren und prüfen ob die Tabelle eine R/3 Tabelle ist
* Catch-Befehl klappt nicht immer
* CATCH SYSTEM-EXCEPTIONS
* create_data_unknown_type = 1
* others = 2.
* ENDCATCH.
ENDFORM.
*---------------------------------------------------------------------*
* D A T E N _ I M P O R T _ T I T E L *
*---------------------------------------------------------------------*
* Titelzeile in Excel. Dafür die oberste Zeile nutzen. Die Texte erge-*
* ben sich für die Domänentexte oder die Texte, welche zum selbst *
* generierten Feld in der Tabelle eingetippt wurden *
*---------------------------------------------------------------------*
FORM upro-daten_import_titel.
DATA:
wa_excel_titel TYPE soi_generic_item,
itab_excel_titel TYPE soi_generic_table.
*= = = = = = = = = = =
CLEAR: itab_bereich, itab_excel_titel, wa_bereich, wa_excel_titel.
REFRESH: itab_bereich, itab_excel_titel.
wa_bereich-name = co_format_titel.
wa_bereich-rows = 1.
wa_bereich-columns = anzahl_spalten_in + 1.
APPEND wa_bereich TO itab_bereich.
* Excel typische SAP Tabelle aufbauen für Zeile 1
MOVE 1 TO z_excel_reihe.
MOVE z_excel_reihe TO wa_excel_titel-row.
CONCATENATE 'R/3 Tabelle'
tabname
'- Kommentar'
INTO wa_excel_titel-value SEPARATED BY space.
MOVE 1 TO z_excel_spalte.
MOVE z_excel_spalte TO wa_excel_titel-column.
APPEND wa_excel_titel TO itab_excel_titel.
LOOP AT wktab_dd03l ASSIGNING <fs_dd03l>.
* Text zum aktuellen Feld. Tabelle liegt sortiert vor
MOVE <fs_dd03l>-ddtext TO wa_excel_titel-value.
* Spaltenzähler berechnen. Die Kommentarspalte beachten, deswegen
* Offset um 1 erhöhen
COMPUTE z_excel_spalte = <fs_dd03l>-position + 1.
MOVE z_excel_spalte TO wa_excel_titel-column.
APPEND wa_excel_titel TO itab_excel_titel.
ENDLOOP.
* Überschriftszeile ausgeben (der Bereich grenzt ein, welche Zeilen /
* Spalten gefüllt werden), Referenz auf die SAP-Excel-Tabellen-
* Definition
CALL METHOD spreadsheet->set_ranges_data
EXPORTING
no_flush = 'X'
ranges = itab_bereich
contents = itab_excel_titel
IMPORTING
error = errors.
APPEND errors.
FREE itab_excel_titel.
ENDFORM.
*---------------------------------------------------------------------*
* D A T E N _ I M P O R T _ B S *
*---------------------------------------------------------------------*
* ein eingelesene Tabelle an den Bildschirm bringen. Der Container ist*
* vorbereitet, die Daten sind eingelesen, nun nur noch den Container *
* mit Leben füllen. BS = Bildschirm *
*---------------------------------------------------------------------*
FORM upro-daten_import_bs.
* Die Referenz ist diesmal die interne Tabelle selber und keine umge-
* schiftete, somit eine andere Methode, aber es muß die Struktur in
* Form der Tabelle mitgegeben werden, da sonst die Trennzeichen nicht
* gesetzt werden können
CALL METHOD spreadsheet->insert_one_table
EXPORTING
data_table = itab_input
ddic_name = tabname
rangename = co_format_char
no_flush = 'X'
wholetable = 'X'
IMPORTING
error = errors.
APPEND errors.
* Anpassen der Spalte an den breitesten Eintrag der Spalte
CALL METHOD spreadsheet->fit_widest
EXPORTING
name = space
no_flush = 'X'.
* in diesem SAP Beispielprogramm sollen aber gerade in den Spalten, die
* hier geschützt würden, Veränderungen erfolgen. Somit ist diese
* Methode kommentiert
* Bereich gegen Eingaben schützen
* CALL METHOD spreadsheet->protect_range
* EXPORTING
* name = co_format_char
* protect = 'X'
* no_flush = 'X'
* IMPORTING
* error = errors.
* APPEND errors.
* die automatisch erstellte Queue nun aktivieren und anzeigen
CALL METHOD c_kontrolle->set_focus
EXPORTING
no_flush = ' '
IMPORTING
error = errors.
APPEND errors.
LOOP AT errors.
CALL METHOD errors->raise_message
EXPORTING
type = 'E'.
ENDLOOP.
FREE errors.
REFRESH: itab_bereich.
CLEAR: itab_bereich, wa_bereich.
ENDFORM.
*---------------------------------------------------------------------*
* D A T E N _ E X P O R T *
*---------------------------------------------------------------------*
* Die Daten sind in Exel bearbeitet und sollen nun wieder an das SAP *
* zurücktransferiert werden. *
*---------------------------------------------------------------------*
* Hinweis: Spalte 1 des Bereiches muß dem ersten Feld der Tabelle *
* entsprechen, keine Lücken in den Spalten, keine neuen Spalten, keine*
* Spalten gelöscht. Die Spalte dient den Suchalgorithmus für das Feld *
* als Referenz. *
*---------------------------------------------------------------------*
FORM upro-daten_export.
CLEAR: wa_bereich, wa_excel_out, wa_output, wa_out_schl,
anzahl_zeilen_out, anzahl_spalten_out, zw_out_row,
itab_excel_out, itab_output, itab_out_schl, itab_bereich.
REFRESH: itab_excel_out, itab_output, itab_out_schl, itab_bereich.
wa_bereich-name = co_format_char.
APPEND wa_bereich TO itab_bereich.
* wa_bereich-name = co_format_num.
* APPEND wa_bereich TO itab_bereich.
* wa_bereich-name = co_format_dats.
* APPEND wa_bereich TO itab_bereich.
* alle Daten im Bereich von "co_format_char" einlesen
* durch die Festlegung auf den Bereich, daß nur dort Daten wieder
* eingelesen werden, sind Prüfungen oder EIngaben außerhalb des
* Bereiches ohne Wirkung
CALL METHOD spreadsheet->get_ranges_data
EXPORTING
all = ' '
no_flush = ' '
IMPORTING
contents = itab_excel_out
CHANGING
ranges = itab_bereich.
* check no errors occured
CALL METHOD error->raise_message
EXPORTING
type = 'E'.
LOOP AT itab_excel_out ASSIGNING <fs_excel>.
* neue Reihe, war vorher sortiert worden. Aktuelle Zeile fortschreiben
IF <fs_excel>-row <> zw_out_row
AND zw_out_row > 0.
PERFORM upro-daten_export_element.
ENDIF.
* umwandeln der Spaltenzahl auf ein echtes NUMC-Feld, wegen der
* Abfragen im Vergleich. Die Reihe braucht nicht betrachtet werden
SHIFT <fs_excel>-column RIGHT DELETING TRAILING ' '.
REPLACE ' ' WITH '0' INTO <fs_excel>-column.
REPLACE ' ' WITH '0' INTO <fs_excel>-column.
REPLACE ' ' WITH '0' INTO <fs_excel>-column.
* die Spalten- und Reihenanzahl feststellen. Sollte sich die Spalten-
* anzahl verändert haben, kann kein direkter Vergleich stattfindet, da
* in diesem Beispielprogramm ein Spaltenflag mitgeschleift wurde
IF <fs_excel>-column > anzahl_spalten_out.
MOVE <fs_excel>-column TO anzahl_spalten_out.
ENDIF.
* wandeln von der Excel-Enlesetabelle auf eine Strukturtabelle ohne
* Formatierung sowie einer Schlüsseltabelle. Dadurch kann der Doppel-
* loop bei Vergleich sich erspart werden => System wird schneller
MOVE <fs_excel>-column TO z_excel_spalte.
* feststellen, was die aktuelle Spalte für ein Feld ist und wo in der
* Struktur es sich befindet
READ TABLE wktab_dd03l ASSIGNING <fs_dd03l>
WITH KEY position = z_excel_spalte.
IF sy-subrc = 0.
IF <fs_dd03l>-keyflag = 'X'.
MOVE <fs_excel>-value(<fs_dd03l>-intlen)
TO: wa_output+<fs_dd03l>-offset(<fs_dd03l>-intlen),
wa_out_schl-t+<fs_dd03l>-offset(<fs_dd03l>-intlen).
ELSE.
MOVE <fs_excel>-value(<fs_dd03l>-intlen)
TO wa_output+<fs_dd03l>-offset(<fs_dd03l>-intlen).
ENDIF.
ENDIF.
MOVE <fs_excel>-row TO zw_out_row.
ENDLOOP.
PERFORM upro-daten_export_element.
* Zellen ohne Inhalt löschen, diese blähen die interne Tabelle
* unnötig auf und werden nicht gebraucht. Erst jetzt löschen, wegen der
* Berechnung der Spaltenzahl, falls die letzten Spalten immer initial
* haben, kann es so zu Abweichungen kommen
DELETE itab_excel_out
WHERE value IS initial.
ENDFORM.
*---------------------------------------------------------------------*
* D A T E N _ E X P O R T _ E L E M E N T *
*---------------------------------------------------------------------*
* eine Zeile der typischen Excel-SAP-Definition ist aufgebaut und kann*
* an die internen Tabellen der Ausgabe angehangen werden. Die eine *
* Tabelle beinhaltet die Wertefelder, diese ist unkritisch. Die andere*
* Tabelle beinhaltet nur die Schlüsselbegriffe, diese Tabelle ist *
* jedoch mit einem Hash-Zugriff ausgestattet, somit erst prüfen, ob *
* der Eintrag nicht schon vorhanden ist *
*---------------------------------------------------------------------*
FORM upro-daten_export_element.
* ohne Schlüssel keine Aktion.
CHECK NOT wa_out_schl-t IS INITIAL.
* Datensatz Schlüssel und Wertefelder in interne Tabelle anhängen
APPEND wa_output TO itab_output.
* Referenz merken, auf welchen Datensatz der Schlüsselsatz zeigen soll.
* Es sollte 1:1 sein, aber Excel stellt keinen doppelten Schlüssel fest
MOVE sy-tabix TO wa_out_schl-idx.
* schauen, ob der Schlüssel schonmal im Umlauf war
READ TABLE itab_out_schl TRANSPORTING NO FIELDS
WITH TABLE KEY t = wa_out_schl-t.
IF sy-subrc <> 0.
* Schlüssel schon nicht vorhanden, interne Tabelle auffüllen
INSERT wa_out_schl INTO TABLE itab_out_schl.
ENDIF.
CLEAR: wa_output, wa_out_schl.
ENDFORM.
*---------------------------------------------------------------------*
* P R O T O K O L L _ M I T *
*---------------------------------------------------------------------*
* Vergleich der Eingabetabelle (Import) mit der Ausgabetabelle *
* (Export). Dieses Unterprogramm vergleicht MIT einer umgewandelteten *
* Ausgabetabelle, d.h. das Programm hat zuvor die Excel-Mappe in eine *
* Strukturtabelle gewandelt, so daß auch die Struktur direkt vergli- *
* chen werden kann, anstatt einzelne Elemente *
*---------------------------------------------------------------------*
* Vergleichsform: Eingangstabelle als Basis vergleicht die Ausgangs- *
* tabelle *
*---------------------------------------------------------------------*
FORM upro-protokoll_mit.
LEAVE TO LIST-PROCESSING.
SORT itab_excel_out BY row column.
* Eingangstabelle als Basis für die Anzeige wählen
LOOP AT itab_input INTO wa_input.
* Schlüssel extra speichern
MOVE wa_input(wa_schl_offset) TO wa_in_schl.
* prüfen, ob es den Schlüssel der Eingabetabelle (für den Import) auch
* noch in der Ausgabetabelle (Export) gibt
READ TABLE itab_out_schl INTO wa_out_schl
WITH TABLE KEY t = wa_in_schl.
IF sy-subrc <> 0.
CLEAR: wa_out_schl, wa_output.
* Datensatz gelöscht, Zeile rot markiert ausgeben
FORMAT COLOR 6 ON INTENSIFIED OFF.
WRITE: / wa_in_schl(wa_schl_offset).
FORMAT COLOR 6 OFF INTENSIFIED ON.
ELSE.
* Schlüssel gefunden, dieses in der Ausgabetabelle sichern
MOVE 'X' TO wa_out_schl-gef.
MODIFY TABLE itab_out_schl FROM wa_out_schl TRANSPORTING gef.
* Datensatz auch mit den Empfansgfeldern nachlesen
READ TABLE itab_output INTO wa_output INDEX wa_out_schl-idx.
IF sy-subrc <> 0.
CLEAR: wa_output.
ENDIF.
WRITE: / wa_in_schl(wa_schl_offset).
PERFORM upro-protokoll_empfangsfelder.
ENDIF.
ENDLOOP.
* Ausgangstabelle durchforsten auf Schlüssel, auf die noch nicht
* abgefragt wurde. Diese sind neu hinzugekommen
LOOP AT itab_out_schl INTO wa_out_schl
WHERE gef = ' '.
FORMAT COLOR 5 ON INTENSIFIED OFF.
WRITE: / wa_out_schl-t(wa_schl_offset).
FORMAT COLOR 5 OFF INTENSIFIED ON.
ENDLOOP.
ENDFORM.
*---------------------------------------------------------------------*
* P R O T O K O L L _ O H N E *
*---------------------------------------------------------------------*
* Vergleich der Ausgabetabelle (Export) mit der Eingabetabelle *
* (Import). Dieses Unterprogramm vergleicht OHNE eine umgewandeltete *
* Ausgabetabelle. Somit entfällt die Zwischentabelle. Nachteil ist die*
* Ausrichtungsform (Ausgangstabelle als Basis), wenn die Eingabeta- *
* belle als Basis hier genommen würde, wäre das ein doppelter Loop => *
* zu jedem Eingabedatensatz müsste komplett die Ausgabetabelle durch- *
* sucht werden, die jedoch nut felderweise vorliegt. Das wäre ein *
* Performancefresser und somit bei großen Tabelle nicht effektiv. *
*---------------------------------------------------------------------*
* Vergleichsform: Ausgangstabelle als Basis vergleicht die Eingangs- *
* tabelle *
*---------------------------------------------------------------------*
* Hinweis: Spalte 1 des Bereiches muß dem ersten Feld der Tabelle *
* entsprechen. Siehe auch Beschreibung Export. *
*---------------------------------------------------------------------*
FORM upro-protokoll_ohne.
LEAVE TO LIST-PROCESSING.
SORT itab_excel_out BY row column.
CLEAR: zw_out_row, wa_in_out_gleich, wa_out_schl, wa_output,
itab_ohne_schl.
REFRESH: itab_ohne_schl.
* die gesamte Ausgabetabelle durchgehen, alle Schlüssel und Inhalte
* aufbauen und prüfen, es einen Schlüssel gibt, der dem der Eingabe-
* tabelle entspricht
LOOP AT itab_excel_out INTO wa_excel_out
WHERE column <> '9999'.
IF wa_excel_out-row <> zw_out_row
AND zw_out_row > 0.
PERFORM upro-protokoll_ohne_vgl.
ENDIF.
* wandeln von der Excel-Enlesetabelle auf eine Strukturtabelle ohne
* Formatierung sowie einer Schlüsseltabelle. Dadurch kann der Doppel-
* loop bei Vergleich sich erspart werden => System wird schneller
MOVE wa_excel_out-column TO z_excel_spalte.
* feststellen, was die aktuelle Spalte für ein Feld ist und wo in der
* Struktur es sich befindet. Bei Schlüssel zusätzlich auch den
* Schlüssel auffüllen für den Reihenvergleich
READ TABLE wktab_dd03l ASSIGNING <fs_dd03l>
WITH KEY position = z_excel_spalte.
IF sy-subrc = 0.
IF <fs_dd03l>-keyflag = 'X'.
MOVE wa_excel_out-value(<fs_dd03l>-intlen)
TO: wa_output+<fs_dd03l>-offset(<fs_dd03l>-intlen),
wa_out_schl-t+<fs_dd03l>-offset(<fs_dd03l>-intlen).
ELSE.
MOVE wa_excel_out-value(<fs_dd03l>-intlen)
TO wa_output+<fs_dd03l>-offset(<fs_dd03l>-intlen).
ENDIF.
ENDIF.
MOVE wa_excel_out-row TO zw_out_row.
ENDLOOP.
PERFORM upro-protokoll_ohne_vgl.
* nun noch die Eingangstabelle durchlaufen und Schlüssel suchen, welche
* nicht mehr in der Ausgangstabelle vorhanden sind
LOOP AT itab_input INTO wa_input.
READ TABLE itab_ohne_schl TRANSPORTING NO FIELDS
WITH TABLE KEY idx = sy-tabix.
IF sy-subrc <> 0.
* Datensatz gelöscht, Zeile rot markiert ausgeben
FORMAT COLOR 6 ON INTENSIFIED OFF.
WRITE: / wa_input(wa_schl_offset).
FORMAT COLOR 6 OFF INTENSIFIED ON.
ENDIF.
ENDLOOP.
ENDFORM.
*---------------------------------------------------------------------*
* P R O T O K O L L _ O H N E _ V G L *
*---------------------------------------------------------------------*
* alle Spalten zu einer Reihe in der Ausgangstabelle sind durchgegan- *
* gen worden und der Datensatz ist in seiner Struktur aufgebaut. Diese*
* Struktur und den Schlüssel gegen die Eingangstabelle laufen lassen. *
* Sollte der Schlüssel auch in der Eingangstabelle gefunden sein, dann*
* einen Vergleich auf die einzelnen Wertefelder durchführen und Diffe-*
* renzen feststellen und anzeigen. *
*---------------------------------------------------------------------*
* =>] wa_out_schl: Schlüssel der Reihe der Ausgabetabelle *
*---------------------------------------------------------------------*
FORM upro-protokoll_ohne_vgl.
CLEAR: wa_in_out_gleich.
* gegen die Eingangstabelle prüfen
LOOP AT itab_input INTO wa_input.
IF wa_out_schl-t = wa_input(wa_schl_offset).
* die Schlüsseltabelle für "ohne-Protokoll-Eingangstabelle" erweitern
MOVE sy-tabix TO wa_ohne_schl-idx.
READ TABLE itab_ohne_schl TRANSPORTING NO FIELDS
WITH TABLE KEY idx = wa_ohne_schl-idx.
IF sy-subrc <> 0.
INSERT wa_ohne_schl INTO TABLE itab_ohne_schl.
ENDIF.
* da ein Treffer gefunden wurde, braucht nicht weiter kontrolliert zu
* werden. Abbruch.
MOVE 'X' TO wa_in_out_gleich.
EXIT.
ENDIF.
ENDLOOP.
IF wa_in_out_gleich IS INITIAL.
* Ausgangstabellenschlüssel ist nicht in der Eingabetabelle vorhanden
* Schlüssel ist neu angelegt worden
FORMAT COLOR 5 ON INTENSIFIED OFF.
WRITE: / wa_out_schl-t(wa_schl_offset).
FORMAT COLOR 5 OFF INTENSIFIED ON.
ELSE.
WRITE: / wa_out_schl-t(wa_schl_offset).
PERFORM upro-protokoll_empfangsfelder.
ENDIF.
CLEAR: wa_out_schl, wa_output.
ENDFORM.
*---------------------------------------------------------------------*
* P R O T O K O L L _ E M P F A N G S F E L D E R *
*---------------------------------------------------------------------*
* Struktur der Eingangstabelle und der Ausgangstabelle gegeneinander *
* vergleichen. Beide Strukturen sind aufgebaut, die Felder bekannt. *
* Es werden nur die Empfangsfelder verglichen, die Schlüsselfelder *
* wurden bereits zuvor behandelt. *
*---------------------------------------------------------------------*
* Hinweis: im dieser Version findet KEIN Umwandeln numerischer oder *
* Datumsfelder statt. Der korrekte Abgleich kann so nur bei CHAR-Fel- *
* dern erfolgen *
*---------------------------------------------------------------------*
FORM upro-protokoll_empfangsfelder.
* Abgleich nur noch auf Empfangsfelder
LOOP AT wktab_dd03l ASSIGNING <fs_dd03l>
WHERE keyflag <> 'X'.
IF wa_output+<fs_dd03l>-offset(<fs_dd03l>-intlen)
<> wa_input+<fs_dd03l>-offset(<fs_dd03l>-intlen).
* Eingabe- und Ausgabewert sind unterschiedlich, gelb anzeigen
FORMAT COLOR 3 ON INTENSIFIED OFF.
WRITE: '.'.
FORMAT COLOR 3 OFF INTENSIFIED ON.
ELSE.
* sind gleich, neutral bleiben
WRITE: '.'.
ENDIF.
ENDLOOP.
ENDFORM.
***** Ende *****
* Copyright BJH Software, Datei überarbeitet am: 23.7.2005