Overview In this example we create an application that displays the measurement points for equipment. The user can enter new measurements and confirm them with a signature, or display measurements that have already been saved. This application is suitable, for example, for service technicians who need easy access to equipment data while on the road and who want to quickly enter measurement values and save them directly in the SAP system. It is also conceivable, however, to make this app directly available to customers, who can then report their own measurement points. Example If a measurement document is selected, details of the measurement point, the recorded measurement and the signature made are displayed. This view can then be processed directly, e.g. by printing it out or forwarding it as a PDF document:
When entering measurements, values can be entered in each case,
whereby the S10 Framework automatically uses the correct format according to the unit of measure.
Only after a signature has been made, can the document be saved:
|
|
Implementation The application is implemented in the following steps: :
However, this is only to be considered as a suggestion, because the HTML views can in principle be designed freely, whereby only the connection to the ABAP objects must be ensured by certain naming conventions. |
|
1. Determine the appropriate SAP tables for the data to be displayed We want to map parts of an existing SAP transaction with this S10 application. In this case we start with the transaction IE03 (Display Equipment) and can display the technical information about fields there with the F1 key. As shown below, the table view ITOB is used in IE03, which we could also take as a basis for the application.
By double-clicking on the view, however, we see that the SAP
table EQUI (Equipment Master Data) is linked here and
therefore we use this as the starting point for generating
the application: |
|
2. Determining an interface for saving the input data
(measured values) In principle, function modules should be used for saving data if they are available and suitable for the application. As a further option, you can also record a transaction via batch input and make it available as a function call. Except for your own tables, you should generally not write directly to SAP tables. You can find suitable functions for saving data via transactions SE37 (Function Builder), SE38 (ABAP Editor), SE24 (Class Builder) or also BAPI (BAPI Explorer) or mostly on the Internet in various places. In this application we use the function module MEASUREM_DOCUM_RFC_SINGLE_001 (Saving of measured values) and the ABAP class CL_MIME_REPOSITORY_API (API for MIME Repository) to save the image file with the signature into the SAP MIME-Repository. |
|
3. Generating the basic application with the S10
Utilities As a general rule, it is recommended to start with an existing application and to adjust and extend it. This way, basic functions such as the login page are already available. In this example we use the S10 utilities to generate an already executable application from an SAP table. Details can be found in the documentation under the point "Generating application parts". To do this, we first call transaction /S10/UTIL and switch to the "Generate list display" tab. As stated in step 1, we want to start with the view of the equipment and therefore enter "EQUI" as table. Then we select some fields for displaying the table, search fields as well as for the detail view. After the execution, there is a finished S10 application in the specified output directory, which we will extend. ![]() ![]() In principle, an S10 application is built from individual views, i.e. separate HTML pages, each belonging to a specific ABAP class. This means that we can develop and test individual parts of the application separately, and then use them together in a more complex application. We therefore generate further applications, whereby the output directory may well remain the same, another view with associated ABAP class is then generated. However, the table with the measurements of the measuring points of a piece of equipment is then composed of different columns, so that we edit this part directly in the HTML file. Basically, a generated S10 application consists of a view on the selected fields of the specified table or table view as well as the possibility to expand individual rows of the table and thus display details of this object. This detail view can be extended as needed by further fields, but also more complex parts like images, further tables or interaction and navigation options. | |
4. Extending the generated application In concrete terms, we now insert a table with the previous measurements in the generated detail view as well as a pushbutton that opens a new screen for entering measured values. This screen can in turn be developed as an independent view with an associated class (modular structure). This greatly simplifies the reuse of individual parts as well as testing. The HTML views First open the generated HTML file for the view, in our case the file "equi_manager.list.html" in the directory "classes\equi_manager\views.en". The detail view for a line starts with the following code part: <!-- detail view --> <div id="tabequi_detail" class='tabledetail'> You can find the generated fields in this section and we can add more elements there: A pushbutton to navigate to a screen where measured values can be entered: <div class="infoblock"> <button class="button" type="button" onclick="S10Apply('open_measurepoints');"> Enter measurement values </button> </div> When the user presses this pushbutton, the ABAP method 'open_measurepoints' is called in the active class. For the table with the measurement values first the headers: <div class="colheaders"> <!-- Measurement document --> <div class='colhead output' style="width:80px; --landscape-width:100px;" name="mdocm"> </div> <!-- Measuring point --> <div class='colhead output landscape' style="width:90px; " name="point"> </div> <!-- additional columns ... --> </div> Following this, the definition of the table row, where we again specify the assignment to the ABAP object by name=: <!-- 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> <!-- additional columns ... --> </div> </form> The ABAP methods We have defined calls to the ABAP class in two places in the HTML code:
* 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. Hint After the dialog or the view "measurepoints" has been closed, e.g. in which the user has triggered a "back", the code execution is continued in the next line. In this case, the user might have entered and saved new measurements, so a refresh of the previous view should be triggered. The second method navigates to a view that displays the details of the respective measurement or measurement document as well as an image of the signature made: * 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. Hints
|
|
5. Implementation of the saving of measurements In principle, we only need a small table that displays the name of each measuring point and the unit of entry, as well as offering an input field for new measured values. Here you can see the connection between the elements of the HTML interface and the respective variables in the ABAP class (for details see the tropic "Data binding" in the documentation): <!-- 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> The fields in the associated ABAP class: * 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 We now need a simple pushbutton with which the user can trigger the saving of the entered measured values: <div class="toolbar"> <button type="button" class="toolbarbutton" onclick="S10Apply('measures_save');"> Speichern </button> </div> Hint It should be pointed out once again that no passing of the entered values to the ABAP method is necessary, instead the S10 Framework automatically ensures that the user data entered at the front end is directly available in a called ABAP method. The other way round, data changed in the ABAP method is automatically sent to the front end after execution, so that the current data is displayed there in each case. The corresponding ABAP method "measures_save" is not very complex:
Note on the data type of the measured values to be entered The measured value that the user enters does not first have to be converted into another data type in this example, since it is already defined in the type expected for the function call. The type is "rimr0-recdc which belongs to the domain FLTP_INOUT (input/output field for floating point fields, 22 digits) and is basically a CHAR, i.e. text. However, you can inform the S10 framework in the ABAP program which field defines the unit of measure. On the interface, the unit is then formatted accordingly, e.g. without decimal places for ST (pieces), 2 decimal places for currency units and so on: data: recorded_value type rimr0-recdc, " Value mrngu type imrc_mrngu, " Unit * Units unit_recorded_value type string value 'mrngu', Here we define a field for entering a measurement value, a field for the unit of measure, and a link between the two fields by prefixing the name of the field with "unit_". ![]() Note on translation capabilities In addition to the possibility of using so-called text IDs in ABAP coding for the translation of texts, the S10 framework also offers the possibility of maintaining small text files and using "s10localize" to determine the text in the user's logon language. For details, see the reference to s10localize() . |
|
6. Implementation of the saving of the signature The signature feature was included by using an open-source JavaScript library available at github.com/szimek/signature_pad. It offers the possibility to save the signature image directly as a string (Base64). Thus, it can be transferred to the ABAP method very easily in a hidden S10 field. Afterwards, this text is converted back into binary format with a function call and stored in the MIME Repository as an image file. We first include the JavaScript library in the HTML view: <script src="../../../scripts/signature_pad.js"></script> For the signature field, a so-called HTML5 <canvas> element is used, which allows drawing graphics. JavaScript offers a function in the standard with which the graphic can be saved and processed as a text representation (Base64): <!-- 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"> After the user has signed, the image is encoded as a Base64 string and inserted into the S10 field. This will automatically transfer it from the S10 framework to the ABAP variable: var img = signaturePad.toDataURL(); img = img.replace('data:image/png;base64,', ''); document.getElementById("signature").value=img; When saving the measured values, the "save_signature" method is also called. This converts the Base64 text into binary files and saves them in the MIME Repository as .PNG image file: 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 You can download all project files here: s10_service_example.zip The .ZIP archive contains the HTML views and a text file with the ABAP program "/s10/service_demo". To import the HTML views you can use the report "BSP_UPDATE_MIMEREPOS" as described in the documentation on "Development environment". If necessary, adjust the number of the client in the "user.logon.html" file. For details, see the documentation on S10Logon() |
|
Component: S10 Framework |