Übersicht In diesem Beispiel erstellen wir eine Anwendung, die die Messpunkte zu Equipments anzeigt. Der Benutzer kann neue Messungen eintragen und diese mit einer Unterschrift quittieren, oder bereits gespeicherte Messungen anzeigen. Diese Anwendung ist zum Beispiel für Servicetechniker geeignet, die unterwegs einen einfachen Zugriff auf Equipmentdaten benötigen sowie schnell Messwerte eintragen und direkt im SAP-System speichern möchten. Denkbar ist aber auch, diese App direkt Kunden zur Verfügung zu stellen, die so eigene Messpunkte rückmelden können. Beispiel Wird ein Messbeleg ausgewählt, werden Details zum Messpunkt, zur erfassten Messung sowie die getätigte Unterschrift angezeigt. Diese Ansicht kann dann direkt weiterverarbeitet werden, z.B. durch Ausrucken oder Weiterversand als PDF-Dokument:
Bei der Erfassung von Messungen können jeweils Werte
eingetragen werden, wobei vom S10 Framework automatisch das
richtige Format entsprechend der Mengeneinheit verwendet wird.
Erst nach dem eine Unterschrift erfolgt ist, kann der Beleg
gespeichert werden: |
|
Implementierung Die Implementierung der Anwendung erfolgt in folgenden Schritten:
Dies ist jedoch nur als Vorschlag zu betrachten, denn die HTML-Views können prinzipiell frei gestaltet werden, wobei nur die Verbindung zu den ABAP Objekten durch bestimmte Namenskonventionen sichergestellt werden muss. |
|
1. Ermitteln der entsprechenden SAP Tabellen für die anzuzeigenden Daten Wir möchten mit dieser S10 Anwendung Teile einer bestehenden SAP Transaktion abbilden. In diesem Fall starten wir mit der Transaktion IE03 (Equipment anzeigen) und können dort mit der F1-Taste die technischen Informationen zu Feldern anzeigen. Wie unten gezeigt, wird in der IE03 der Tabellenview ITOB verwendet, den wir auch als Basis für die Anwendung nehmen könnten.
Per Doppelklick auf den View sehen wir jedoch, dass hier die
SAP-Tabelle EQUI (Equipment Stammdaten) verknüpft wird und
nehmen daher diese als Ausgangspunkt für die Anwendungsgenerierung: |
|
2. Ermitteln einer Schnittstelle zum Speichern der
Eingabedaten (Messwerte) Für das Speichern von Daten sollten prinzipiell Funktionsbausteine verwendet werden, falls diese für den Anwendungsfall vorhanden und geeignet sind. Als weitere Möglichkeit können Sie auch eine Transaktion per Batch-Input aufzeichnen und als Funktionsaufruf verfügbar machen. Außer in eigene Tabellen sollte in SAP-Tabellen generell nicht direkt geschrieben werden. Geeignete Funktionen zum Speichern von Daten können Sie über die Transaktionen SE37 (Function Builder), SE38 (ABAP Editor), SE24 (Class Builder) oder auch BAPI (BAPI Explorer) finden oder zumeist auch im Internet an diversen Stellen. In dieser Anwendung verwenden wir den Funktionsbaustein MEASUREM_DOCUM_RFC_SINGLE_001 (Speichern von Messwerten) sowie die ABAP-Klasse CL_MIME_REPOSITORY_API (API für MIME Repository) zum Speichern der Bilddatei mit der Unterschrift. |
|
3. Generieren der Basisanwendung mit den S10
Utilities In der Regel ist es empfehlenswert, mit einer bestehenden Anwendung zu starten und diese anzupassen und zu erweitern. Dadurch sind bereits grundlegende Funktionen wie die Login-Seite vorhanden. In diesem Beispiel verwenden wir die S10 Utilities, um aus einer SAP-Tabelle eine bereits lauffähige Anwendung zu generieren. Details dazu finden Sie in der Dokumentation unter dem Punkt "Generierung". Wir rufen dazu zunächst die Transaktion /S10/UTIL auf und wechseln auf den Reiter "Listanzeige generieren". Wie in Schritt 1 festgestellt, möchten wir zunächst mit der Sicht auf die Equipments starten und geben daher als Tabelle "EQUI" ein. Anschließend wählen wir einige Felder für Anzeige der Tabelle, Suchfelder sowie für die Detailansicht aus. Nach dem Ausführen befindet sich in dem angegeben Ausgabeverzeichnis dann eine fertige S10 Anwendung, die wir noch erweitern werden. Eine S10 Anwendung ist im Prinzip aus einzelnen Views aufgebaut, das heißt separaten HTML-Seiten, die jeweils zu einer bestimmten ABAP-Klasse gehören. Das bedeutet, dass wir einzelne Teile der Anwendung getrennt entwickeln und testen können, um sie anschließend in einer komplexeren Anwendung gemeinsam zu verwenden. Wir generieren daher weitere Anwendungen, wobei das Ausgabeverzeichns durchaus gleich bleiben kann, es wird dann ein weiterer View mit zugehöriger ABAP-Klasse generiert. Die Tabelle mit den Messungen der Messpunkte eines Equipments setzt sich dann allerdings aus unterschiedlichen Spalten zusammen, so dass wir diesen Teil direkt im HTML editieren. Grundsätzlich besteht eine generierte S10 Anwendung aus einer Sicht auf die gewählten Felder der angegebenen Tabelle oder des Tabellenviews sowie der Möglichkeit, einzelne Zeilen der Tabelle aufzuklappen und so Details dieses Objekts anzuzeigen. Diese Detailansicht kann beliebig erweitert werden durch weitere Felder, aber auch komplexere Teile wie Bilder, weitere Tabellen oder Interaktions- und Navigationsmöglichkeiten. | |
4. Erweitern der generierten Anwendung Konkret fügen wir in der generierten Detailansicht nun eine Tabelle mit den bisherigen Messungen ein sowie einen Pushbutton, der einen neuen Screen zur Eingabe von Messwerten öffnet. Dieser Screen kann wiederum als eigenständiger View mit zugehöriger Klasse entwickelt werden (modularer Aufbau). So wird das Wiederverwenden einzelner Teile sowie das Testen stark vereinfacht. Die HTML-Views Öffnen Sie zunächst die generierte HTML-Datei für den View, in unserem Fall die Datei "equi_manager.list.html" im Verzeichnis "classes\equi_manager\views.de". Die Detailansicht zu einer Zeile beginnt mit folgendem Code Teil: <!-- detail view --> <div id="tabequi_detail" class='tabledetail'> Sie finden in diesem Abschnitt die generierten Felder und wir können dort weitere Elemente einfügen: Ein Pushbutton, um zu einem Screen zu navigieren, auf dem Messwerte eingetragen werden können: <div class="infoblock"> <button class="button" type="button" onclick="S10Apply('open_measurepoints');"> Messwerte eintragen </button> </div> Wenn der Benutzer auf diesen Pushbutton drückt, wird die ABAP-Methode 'open_measurepoints' in der aktiven Klasse aufgerufen. Für die Tabelle mit den Messwerten zunächst die Überschriften: <div class="colheaders"> <!-- Meßbeleg --> <div class='colhead output' style="width:80px; --landscape-width:100px;" name="mdocm"> </div> <!-- Meßpunkt --> <div class='colhead output landscape' style="width:90px; " name="point"> </div> <!-- weitere Spalten ... --> </div> Anschließend die Definition der Tabellenzeile, wobei wir die Zuordnung zu dem ABAP-Objekt wieder per name= angeben: <!-- list rows --> <form class='table' name='myequi.tabimptt'> <div class="tablerow"> <div class='outputcelldiv link' style="width:80px; --landscape-width:100px;" name="mdocm"> </div> <div class='outputcelldiv landscape' style="width:90px;" name="point"> </div> <!-- weitere Spalten ... --> </div> </form> Die ABAP-Methoden Wir haben in dem HTML-Coding an zwei Stellen Aufrufe in die ABAP-Klasse definiert:
* open measure points for this equipment method open_measurepoints. * Get number of row the user clicked in data: rownumber type i. rownumber = s10contextinfo( )->rownumber. * Read the object of this row read table tabequi index s10contextinfo( )->rownumber assigning field-symbol(<row>). data: mydiimpt type table of diimpt. data: mydiimpt_wa type diimpt. * Get measure points for the equipment in this selected row call function 'GET_MEASURING_POINTS_4_EQUIPM' exporting i_equnr = <row>->equnr tables et_diimpt = mydiimpt. * Copy the data data: myimptt type ref to imptt_short. clear tabimptt_input. loop at mydiimpt into mydiimpt_wa. create object myimptt. myimptt->mrngu = mydiimpt_wa-unitc. myimptt->point = mydiimpt_wa-point. myimptt->pttxt = mydiimpt_wa-pttxt. append myimptt to tabimptt_input. endloop. clear saved. s10dialog( 'measurepoints'). * The user might have saved some new measures, * so update the table read_detail_tabequi( <row>->equnr ). <row>->s10detailview = 'X'. endmethod. Hinweis Nachdem der Dialog bzw. der View "measurepoints" geschlossen wurde, z.B. in dem der Benutzer ein "zurück" ausgelöst hat, wird die Codeausführung in der nächsten Zeile fortgesetzt. In diesem Fall könnte der Benutzer neue Messungen eingetragen und gespeichert haben, so dass ein Auffrischen der vorherigen Anzeige angestoßen werden sollte. Die zweite Methode navigiert zu einem View, der die Details zu der jeweiligen Messungen bzw. dem Messbeleg anzeigt sowie ein Bild der geleisteten Unterschrift: * User clicked on a measurement document link method on_link_mdocm. data: mymdocm type imrc_mdocm. * Get the measurement document for this row call method s10fromcontextinfo exporting key = 'mdocm' changing result = mymdocm. * Create a new object for the measurement document data: my_imptt_short type ref to imptt_short. create object my_imptt_short. * Key = measurement document my_imptt_short->mdocm = mymdocm. data: my_imrg_ba type imrg. * Read the data for this measurement document call function 'MEASUREM_DOCUM_RFC_SINGLE_002' exporting measurement_document = mymdocm with_dialog_screen = '' importing imrg_ba = my_imrg_ba. if sy-subrc <> 0. * Something went wrong s10errormessage( exporting msgid = sy-msgid msgno = sy-msgno par1 = sy-msgv1 par2 = sy-msgv2 par3 = sy-msgv3 ). endif. * Copy the read data from the function call my_imptt_short->s10copy( my_imrg_ba ). * We read additional data from the database my_imptt_short->s10databaseread( ). * read details if not my_imptt_short->myimrg is bound. create object my_imptt_short->myimrg. endif. my_imptt_short->myimrg->mdocm = my_imrg_ba-mdocm. my_imptt_short->myimrg->s10databaseread( ). * Create the HTML code for the image of the signature my_imptt_short->signature_html = |<img style='padding:5px;border-radius:15px;background-color:white; max-height:200px' src='../../../signatures/| && mymdocm && |.png' onError="this.width=1; this.onError=null;">|. * Open the detail view as new dialog my_imptt_short->s10dialog( 'details' ). endmethod. Hinweise
|
|
5. Implementierung der Speicherung von Messungen Wir benötigen im Prinzip nur eine kleine Tabelle, die pro Messpunkt dessen Namen und die Erfassungseinheit anzeigt, sowie ein Eingabefeld für neue Messwerte anbietet. Hier sehen Sie die Verbindung zwischen den Elemente der HTML-Oberfläche und den jeweiligen Variablen in der ABAP Klasse (Details dazu unter dem Punkt "Datenbindung" in der Dokumentation): <!-- list rows --> <form class='table' name='tabimptt_input'> <div class="tablerow"> <div class='outputcelldiv landscape' style="width:100px;" name="point"></div> <div class='outputcelldiv' style="width:calc(100% - 255px); --landscape-width:calc(100% - 355px);" name="pttxt"> </div> <input class="inputcell" type="text" style="width:100px;" name="recorded_value"> <div class='outputcelldiv' style="width:100px;" name="mrngu"></div> </div> </form> Die Felder in der dazugehörigen ABAP-Klasse: * View for Measurement Document -> List View class imptt_short definition inheriting from /s10/any. public section. * table fields for list view, plus key fields data: point type imptt-point, " measuring point pttxt type imptt-pttxt, " designation mrngu type imrc_mrngu, " Unit using text recorded_value type rimr0-recdc, " Value using Text Wir benötigen nun noch einen einfachen Pushbutton, mit dem der Benutzer das Speichern der eingetragenen Messwerte auslösen kann: <div class="toolbar"> <button type="button" class="toolbarbutton" onclick="S10Apply('measures_save');"> Speichern </button> </div> Hinweis Hier sei noch einmal betont, dass keine Übergabe der eingegebene Werte an die ABAP-Methode notwendig ist, sondern das S10 Framework automatisch dafür sorgt, dass die jeweils am Front-End eingegebenen Daten des Benutzers in einer aufgerufenen ABAP-Methode direkt zur Verfügung stehen. Umgekehrt werden in der ABAP-Methode geänderte Daten nach Ablauf automatisch an das Front-End geschickt, so dass dort jeweils die aktuellen Daten angezeigt werden. Die entsprechende ABAP-Methode "measures_save" ist nicht besonders umfangreich:
Hinweis zum Datentyp der einzugebenden Messwerte Der Messwert, den der Benutzer eingibt, muss in diesem Beispiel nicht erst in einen anderen Datentyp umgewandelt werden, da er bereits in dem für den Funktionsbaustein erwarteten Typ definiert ist. Der Typ ist "rimr0-recdc welcher zur Domäne FLTP_INOUT (Ein-/Ausgabefeld für Gleitkommafelder, 22-stellig) gehört und im Prinzip ein CHAR, also Text ist. Sie können jedoch in dem ABAP-Programm dem S10 Framework mitteilen, welches Feld die Mengeneinheit definiert. Auf der Oberfläche wird dann die Einheit entsprechend formatiert, z.B. ohne Dezimalstellen bei ST (Stück), 2 Dezimalstellen bei Währungseinheiten und so weiter: data: recorded_value type rimr0-recdc, " Value mrngu type imrc_mrngu, " Unit * Units unit_recorded_value type string value 'mrngu', Hier definieren wir ein Feld für die Eingabe eines Messwerts, ein Feld für die Mengeneinheit sowie eine Verbindung zwischen beiden Feldern durch ein vorangestelltes "unit_" vor dem Namen des Feldes. Hinweis zu Übersetzungsmöglichkeiten Neben der Möglichkeit, im ABAP-Coding sog. Text-IDs zu verwenden für die Übersetzung von Texten, bietet das S10 Framework auch die Möglichkeit, kleine Textdateien zu pflegen und per "s10localize" den Text in der Anmeldesprache des Benutzers zu ermitteln. Details dazu finden Sie in der Referenz zu s10localize() . |
|
6. Implementierung der Speicherung der Unterschrift Die Möglichkeit zur Unterschrift wurde in Form einer JavaScript-Bibliothek, die als Open-Source Software unter github.com/szimek/signature_pad verfügbar ist, eingebunden. Sie bietet die Möglichkeit, das Bild der Unterschrift direkt als Zeichenfolge zu speichern (Base64). Somit kann es sehr einfach in einem versteckten S10 Feld an die ABAP-Methode übertragen werden. Anschließend wird dieser Text mit einem Funktionsbaustein wieder in das binäre Format umgewandelt und im MIME-Repository als Bilddatei abgelegt. Wir binden zunächst die JavaScript-Bibliothek in dem HTML-View ein: <script src="../../../scripts/signature_pad.js"></script> Für das Feld für die Unterschrift wird ein sog. HTML5 <canvas> Element verwendet, welches das Zeichnen von Grafiken ermöglicht. JavaScript bietet im Standard einen Befehl an, mit dem die Grafik als Textrepräsentation (Base64) gespeichert und weiterverarbeitet werden kann: <!-- Canvas element to draw graphics --> <canvas height="200" width="350" style="background-color: white" id="sketchpad"></canvas> <!-- Hidden S10 field for transfering data to ABAP--> <input type="hidden" class="input" id="signature" name="signature"> Nach dem der Benutzer unterschrieben hat, wird das Bild als Base64 String codiert und in das S10 Feld gestellt. Dadurch wird es automatisch vom S10 Framework in die ABAP Variable übertragen: var img = signaturePad.toDataURL(); img = img.replace('data:image/png;base64,', ''); document.getElementById("signature").value=img; Beim Speichern der Messwerte wird zusätzlich die Methode "save_signature" aufgerufen. Diese wandelt den Base64 Text in Binärdateien um und speichert diese im MIME-Repository als .PNG Bilddatei ab: method save_signature. clear mybase64. clear content. * Image of the signature as Base64 string mybase64 = signature. * Convert to xstring call function 'SSFC_BASE64_DECODE' exporting b64data = mybase64 importing bindata = content exceptions others = 8. * Get API for the MIME repository data(o_mime_rep) = cl_mime_repository_api=>get_api( ). * Get the path of our application as root for the image files data: mypath type string. mypath = projectpath. * append the filename mypath = mypath && '/' && filename. * Save image in MIME repository. * Object catalog entry is created, any existing files are overwritten * * -> local object in this case, no transport o_mime_rep->put( i_url = mypath i_content = content i_check_authority = abap_false i_suppress_dialogs = 'X' i_suppress_package_dialog = 'X' i_dev_package = '$TMP' ). if sy-subrc <> 0. * something went wrong s10errormessage( exporting msgid = sy-msgid msgno = sy-msgno par1 = sy-msgv1 par2 = sy-msgv2 par3 = sy-msgv3 ). endif. endmethod. |
|
Download Sie können alle Projektdateien hier herunterladen: s10_service_example.zip Das .ZIP Archiv enthält die HTML-Views sowie eine Textdatei mit dem ABAP Programm "/s10/service_demo". Zum Importieren der HTML-Views können Sie den Report "BSP_UPDATE_MIMEREPOS" verwenden wie in der Dokumentation unter dem Punkt Entwicklungsumgebung" beschrieben. Bitte passen Sie ggf. noch Nummer des Mandanten in der Datei "user.logon.html" an. Details dazu finden Sie in der Dokumentation unter dem Punkt S10Logon() |
|
Komponente: S10 Framework |