Enterprise Resource Planning Blogs by Members
Gain new perspectives and knowledge about enterprise resource planning in blog posts from community members. Share your own comments and ERP insights today!
cancel
Showing results for 
Search instead for 
Did you mean: 
nandikaganesan
Explorer
1,134

Introduction:

This blog provides an extensive overview of the steps required to implement a Scan QR functionality in a module pool program by triggering an HTML QR service with a pushbutton and returning the retrieved data to the screen after scanning, ensuring seamless integration between the SAP module pool program and the HTML QR scanning service to enable efficient QR code processing.

Steps:

Step 1: Create a class using transaction se24 and specify IF_HTTP_EXTENSION in the interface section. This class is intended to handle HTTPS requests and responses in the context of web-based applications or services, particularly custom handlers in the Internet Communication Framework.

Screenshot 2025-03-03 104138.png

Step 2: Declare IF_HTTP_EXTENSION~HANDLE_REQUEST in the methods section by keeping it in public visibility.

Screenshot 2025-03-03 104022.png

Step 3: Click on the method and go to source code to deploy the HTML QR scan code in it.

Screenshot 2025-03-03 104334.png

Step 4: To retrieve the HTTP request method of an incoming request in SAP's ICF (Internet Communication Framework) service, attach the below available HTML code for scan QR functionality.

 

 

 

METHOD IF_HTTP_EXTENSION~HANDLE_REQUEST.
DATA: lv_request_method TYPE string,
      lv_html           TYPE string,
      lt_html_table     TYPE TABLE OF string,
      gv_json           TYPE char250, "string,
      gs_session        TYPE zpp_tab_sess_id,
      lv_var1           TYPE string,
      lv_var2           TYPE string,
      lv_var3           TYPE string,
      lv_var4           TYPE string,
      lv_var5           TYPE string,
      lv_var6           TYPE string,
      lv_var7           TYPE string,
      lv_var8           TYPE string,
      lv_var9           TYPE string.
      lv_request_method = server->request->get_method( ).
  CASE lv_request_method.
      WHEN 'GET'.
        CLEAR : gv_json.
        lt_html_table = VALUE #(
        ( CONV string( '<!DOCTYPE html>' ) )
        ( CONV string( '<html lang="en">' ) )
        ( CONV string( '<head>' ) )
        ( CONV string( '<meta charset="UTF-8">' ) )
        ( CONV string( '<meta name="viewport" content="width=device-width, initial-scale=1.0">' ) )
        ( CONV string( '<link rel="stylesheet" href="style.css">' ) )
        ( CONV string( '<title>QR Code Scanner</title>' ) )
        ( CONV string( '<style>' ) )
        ( CONV string( '    .message-container {' ) )
        ( CONV string( '        display: flex; flex-direction: column; align-items: center; justify-content: center; margin-top: 20px;' ) )
        ( CONV string( '    }' ) )
        ( CONV string( '    #statusMessage {' ) )
        ( CONV string( '        text-align: center; font-size: 15px; margin-bottom: 5px;' ) )
        ( CONV string( '    }' ) )
        ( CONV string( '    #rescanButton {' ) )
        ( CONV string( '        display: none; margin: 0 auto; padding: 5px 10px; font-size: 10px; cursor: pointer;' ) )
        ( CONV string( '    }' ) )
        ( CONV string( '</style>' ) )
        ( CONV string( '</head>' ) )
        ( CONV string( '<body>' ) )
        ( CONV string( '<div class="container">' ) )
        ( CONV string( '    <h1>Scan QR Codes</h1>' ) )
        ( CONV string( '    <div class="section">' ) )
        ( CONV string( '        <div style="width: 500px" id="reader" name="QRCodeData"></div>' ) )
        ( CONV string( '        <div class="message-container">' ) )
        ( CONV string( '            <p id="statusMessage"></p>' ) )
        ( CONV string( '            <button id="rescanButton" onclick="rescan()">Rescan</button>' ) )
        ( CONV string( '        </div>' ) )
        ( CONV string( '    </div>' ) )
        ( CONV string( '</div>' ) )
        ( CONV string( '<script src="https://unpkg.com/html5-qrcode"></script>' ) )
        ( CONV string( '<script>' ) )
        ( CONV string( '    function onScanSuccess(decodedText, decodedResult) {' ) )
        ( CONV string( '        const barcodetxt = decodedText;' ) )
        ( CONV string( '        console.log(decodedText);' ) )
        ( CONV string( '        const urlParams = new URLSearchParams(window.location.search);' ) )
        ( CONV string( '        const sessionID = urlParams.get("SESSION_ID") || '''';' ) )
        ( CONV string( '        const port = window.location.port;' ) )
        ( CONV string( '        const senddata = async (barcodetxt, sessionID, port) => {' ) )
        ( CONV string( '            try {' ) )
        ( CONV string( '                const res = await fetch(`https://<server>:${port}/sap/bc/zsrv_evp_qrscan`, {' ) )
        ( CONV string( '                    method: "POST",' ) )
        ( CONV string( '                    headers: {' ) )
        ( CONV string( '                        "Content-Type": "application/json"' ) )
        ( CONV string( '                    },' ) )
        ( CONV string( '                    body: JSON.stringify({ barcodetxt, sessionID })' ) )
        ( CONV string( '                });' ) )
        ( CONV string( '                if (res.ok) {' ) )
        ( CONV string( '                    document.getElementById("statusMessage").innerText = "Updated Successfully!";' ) )
        ( CONV string( '                    document.getElementById("statusMessage").style.color = "green";' ) )
        ( CONV string( '                    setTimeout(() => {' ) )
        ( CONV string( '                        window.open("", "_self", "");' ) )
        ( CONV string( '                        window.close();' ) )
        ( CONV string( '                    }, 2000);' ) )
        ( CONV string( '                } else {' ) )
        ( CONV string( '                    showErrorMessage();' ) )
        ( CONV string( '                }' ) )
        ( CONV string( '            } catch (error) {' ) )
        ( CONV string( '                showErrorMessage();' ) )
        ( CONV string( '                console.error("Error updating data:", error);' ) )
        ( CONV string( '            }' ) )
        ( CONV string( '        };' ) )
        ( CONV string( '        senddata(barcodetxt, sessionID, port);' ) )
        ( CONV string( '        html5QrcodeScanner.clear();' ) )
        ( CONV string( '    }' ) )
        ( CONV string( '    function showErrorMessage() {' ) )
        ( CONV string( '        const statusMessage = document.getElementById("statusMessage");' ) )
        ( CONV string( '        statusMessage.innerText = "Request failed. Please try again.";' ) )
        ( CONV string( '        statusMessage.style.color = "red";' ) )
        ( CONV string( '        const rescanButton = document.getElementById("rescanButton");' ) )
        ( CONV string( '        rescanButton.style.display = "inline-block";' ) )
        ( CONV string( '    }' ) )
        ( CONV string( '    function rescan() {' ) )
        ( CONV string( '        document.getElementById("statusMessage").innerText = "";' ) )
        ( CONV string( '        document.getElementById("rescanButton").style.display = "none";' ) )
        ( CONV string( '        html5QrcodeScanner.render(onScanSuccess);' ) )
        ( CONV string( '    }' ) )
        ( CONV string( '    var html5QrcodeScanner = new Html5QrcodeScanner(' ) )
        ( CONV string( '        "reader", { fps: 10, qrbox: 250 });' ) )
        ( CONV string( '    html5QrcodeScanner.render(onScanSuccess);' ) )
        ( CONV string( '</script>' ) )
        ( CONV string( '</body>' ) )
        ( CONV string( '</html>' ) )
        ).

        CONCATENATE LINES OF lt_html_table INTO lv_html SEPARATED BY cl_abap_char_utilities=>cr_lf.
        server->response->set_cdata( lv_html ).
        server->response->set_status( code = 200 reason = 'OK' ).

      WHEN 'POST'.
        server->request->get_cdata( RECEIVING data = gv_json ).
        lv_html = gv_json.
        server->response->set_content_type( 'text/html' ).
        server->response->set_cdata( lv_html ).
        SPLIT gv_json AT '"' INTO lv_var1  lv_var2 lv_var3 lv_var4 lv_var5 
                                  lv_var6 lv_var7 lv_var8 lv_var9.
        IF lv_var4 IS NOT INITIAL AND lv_var8 IS NOT INITIAL.
          gs_session = VALUE #( session_id = lv_var8
                                qr_value   = lv_var4
                                created_on = sy-datum
                                created_at = sy-uzeit
                                created_by = sy-uname ).
        IF gs_session IS NOT INITIAL.
          MODIFY  zpp_tab_sess_id FROM gs_session.
        IF sy-subrc = 0.
          COMMIT WORK AND WAIT.
        ELSE.
           ROLLBACK WORK.
        ENDIF.
        ENDIF.
        ENDIF.
        CLEAR : gv_json,gs_session.
    ENDCASE.
ENDMETHOD.

 

 

 

Step 5: After building the logic in se24, bind the class in SICF transaction by giving hierarchy name as SERVICE.

Screenshot 2025-02-18 163438.png

Step 6:  Create a service name in the below navigated hierarchy.

Screenshot 2025-02-18 163702.png

Screenshot 2025-03-03 104704.png

Step 7: Assign the class in which the HTML code has been embedded in the handler list of the created service by double clicking on the service.

Screenshot 2025-03-03 104852.png

Step 8: Create a z-table to store the session id and its data while scanning the QR to avoid the data mismatch.

Screenshot 2025-02-18 180335.png

Step 7: Create a pushbutton in your required screen by using module pool program and name it as Scan QR by keeping its function code as ‘SCAN’

nandikaganesan_6-1739872790040.png

Step 9: In the PAI part write the logic to scan the QR

Code Explanation:

9.1: cl_system_uuid=>create_uuid_c32_static( RECEIVING uuid = gv_uuid ) will be used to create GUID’s for the new session while triggering the scan pushbutton.

9.2: gc_srv refers to the service path which is created in SICF t-code along with the session ID .

9.3: gc_host is the HTTPS host link lv_post is the port for the particular server and gv_uuid is the created guid for each session.

 

 

 

gc_srv  TYPE string   VALUE '/sap/bc/zsrv_evp_qrscan?SESSION_ID=',
gv_qr         TYPE char50,
gv_uuid       TYPE guid_32.
gv_url        TYPE char200,

 

 

 

 

 

 

WHEN 'SCAN'.
      CLEAR : gv_qr, gv_uuid.
*****************To get GUID for each new session***********************
      cl_system_uuid=>create_uuid_c32_static( RECEIVING uuid = gv_uuid ).
****************Changing the URL according to development and production client*******************
      zcl_ril_constant=>fetch_constant_data(
  EXPORTING
    iv_program_name = 'EVP_PORT'
    iv_field        = 'PORT'
    iv_active_flag  = ''
  IMPORTING
    et_table        = DATA(lt_const)
       ).
      DATA(lv_port) = VALUE #( lt_const[ field_name = 'PORT']-zlow OPTIONAL ).

      CONCATENATE gc_host lv_port gc_srv gv_uuid INTO gv_url.
********************Call Browser triggers the browser for QR scan*********************************
      CALL FUNCTION 'CALL_BROWSER'
        EXPORTING
          url                    = gv_url
          window_name            = 'NEW'
        EXCEPTIONS
          frontend_not_supported = 1
          frontend_error         = 2
          prog_not_found         = 3
          no_batch               = 4
          unspecified_error      = 5
          OTHERS                 = 6.
      IF sy-subrc = 0.
        CLEAR : gv_url.
        MESSAGE text-069 TYPE 'I'.
      ELSE.
        MESSAGE text-072 TYPE 'S' DISPLAY LIKE 'E'.
      ENDIF.
*******************Mapping the GUID to the Scan QR field*******************************
      SELECT * FROM zpp_tab_sess_id
      INTO TABLE (lt_id)
      WHERE session_id = _uuid.
      IF sy-subrc = 0.
        DATA(lv_qr_data) = VALUE #( lt_id[ session_id = gv_uuid ]-qr_value OPTIONAL ).
        IF lv_qr_data IS NOT INITIAL .
          gv_qr = lv_qr_data.
        ENDIF.
      ELSE.
        MESSAGE text-072 TYPE 'S' DISPLAY LIKE 'E'.
      ENDIF.

 

 

 

Conclusion:

Incorporating QR Code Scanning in a SAP Module Pool with HTML Service offers easy data capture and real-time processing within the SAP GUI. Users can efficiently scan and process QR codes by embedding an HTML page in a Custom Container, using SAP SICF services, and storing scanned data through ABAP methods. This method improves user experience, eliminates human data entry, and enhances system automation. 

5 Comments
saranramu
Explorer

Nice blog and well explained.

Sandra_Rossi
Active Contributor

It was difficult to understand the logic, here's my description of what I understand (I hope it's clear):

First, the ABAP screen is displayed:

Sandra_Rossi_0-1741075375185.png

The user presses a button "Scan the Material QR" on the ABAP screen, which adds an entry in the table zpp_tab_sess_id and opens a Web page in the Web browser, starting the ABAP ICF service via GET method. This Web page allows scanning via the Web utility Html5QRCodeScanner:

<screenshot to add>

The user does the scan via the Web page which then triggers the ABAP ICF service via POST method, the scanned QR code text is stored back into the table zpp_tab_sess_id.

In the ABAP screen, some action (or an automatic scan till the scanned QR code in table zpp_tab_sess_id is filled?) reads the scanned QR code from the table zpp_tab_sess_id and displays it in the ABAP screen.

nandikaganesan
Explorer

Hi  @Sandra_Rossi 
Good catch! That aligns with what I have posted.

nandikaganesan
Explorer

Thanks for your comments @saranramu 

zfiori
Participant
0 Kudos

Hi Community,

"by triggering an HTML QR service with a pushbutton and returning the retrieved data to the screen after scanning, ensuring seamless integration between the SAP module pool program and the HTML QR scanning service to enable efficient QR code processing."

 

Thanks for your selfless sharing, it really help us a lot.

 

🙂

Regards,

ZFiori.

Labels in this area