Friday, 10 September 2021

Auto Calculations for a Receipt in My Travel Expense Fiori App

While working on a “Travel Management Roll out using Fiori Apps” project for one of our client recently, I came across a requirement of calculating amount of a receipt based on some business rules. We were implementing “My Travel Expense” app Version 2.

A little dig into the implementation guide of the fiori app suggested implementing Badi PAOC_MTE_BADI. Unfortunately, i couldn’t find any help on implementing this Badi. The situation worsened when I tried implementing the badi and failed to save my changes to the trip data. Neither I was able to show custom messages.

After effort of hours and days, finally i was able to succeed. So i thought i must share it with community to help save others some precious time.

Note that this blog post was written for Fiori app “My Travel Expense” V2. It may or may not work for other versions.

Functional Requirement

The requirement is to auto calculate amount of a receipt in “My Travel Expense” (MTE) Fiori app.

Additionally, the code must be capable of throwing custom error/warning messages.

Solution Overview

1. We will implement Badi PAOC_MTE_BADI using T-code SE19. 

2. Two methods are of our interest:

IF_PAOC_MTE~RECEIPT_CREATE_ENTITY: This method is called every time a new receipt is entered/created. This essentially means selecting an “Expense Type” from the popup in MTE.

IF_PAOC_MTE~RECEIPT_UPDATE_ENTITY: This method is called every time a receipt is changed/edited. This essentially means selecting a receipt and clicking “Edit” link in MTE.

3. Retrieve memory data using method cl_trv_access=>retrieve_expense_from_cluster (refer note  2775801 )

4. Make changes to the receipt table retrieved from et_receipts parameter of cl_trv_access=>retrieve_expense_from_cluster.

5. Return messages through table retrieved from ct_return parameter of cl_trv_access=>retrieve_expense_from_cluster.

6. Write changed data to memory using method cl_trv_access=>save_expense_to_cluster  (refer note  2775801)

Lets dive into the details.

Solution Details

Step1: Implement PAOC_MTE_BADI

I will not go into details of implementing a Badi as it is readily available and out of scope of this blog. However, important is Badi name and the relevant method that will contain our code.

Step 2: Implementing method IF_PAOC_MTE~RECEIPT_CREATE_ENTITY

This method is called every time a new expense type is added to MTE. Its signature is like:

◉ I_PERNR: To get employee information e.g. IT0017

◉ I_TRIPNO: To get trip info, if trip number has been assigned.

◉ CS_RECEIPT : A changing structure to process receipt related information. We will save our changes in this structure first and then eventually pass these changes to et_receipt of cl_trv_access=>save_expense_to_cluster

◉ CT_RETURN : A changing table to keep all your custom messages. These messages are then appended to et_return of cl_trv_access=>save_expense_to_cluster

SAP maintains complete trip data in memory clusters. Changes to trip data must be written to these clusters. To ensure that trip data is not lost, we will first retrieve current data from clusters and then modify/amend it with our changes.

Retrieve memory Data

Use this code to retrieve memory data.

*TRY.

    DATA:

      ev_mode               TYPE ptrv_trip_action_s,

      iv_crud               TYPE com_crud  VALUE 'R',

      ev_editable           TYPE xfeld,

      ev_deletable          TYPE xfeld,

      ev_tripnumber         TYPE bapitrip-tripno,

      ev_periodnumber       TYPE bapitrvxxx-period,

      ev_periodversion      TYPE ptrv_perio-pdvrs,

      ev_persistencystatus  TYPE com_persistancy_status,

      ev_locked_by          TYPE sy-uname,

      es_header             TYPE ptrv_web_general_data_ext,

      et_receipts           TYPE ptrv_web_receipts_ext_t_2,

      et_deductions         TYPE ptrv_web_deductions_ext_t,

      et_itinerary          TYPE ptrv_web_itinerary_ext_t,

      et_costdist_trip      TYPE ptrv_web_costdist_ext_t,

      et_costdist_itin      TYPE ptrv_web_costdist_ext_t,

      et_costdist_rece      TYPE ptrv_web_costdist_ext_t,

      et_costdist_mile      TYPE ptrv_web_costdist_ext_t,

      ev_fm_posting_date    TYPE fm_posting_date,

      et_mastercost_default TYPE ptrv_web_costdist_trip_ext_t,

      et_advances           TYPE ptrv_web_advances_ext_t,

      et_mileage            TYPE ptrv_web_mileage_ext_t,

      et_amounts            TYPE ptra_web_bapitrvsum_t,

      et_paufa              TYPE ptrv_util_paufa_t,

      et_ccc_trans_rec      TYPE ptrv_util_ccc_trans_rec_t,

      et_ccc_buffer         TYPE ptrv_util_ccc_buf_t,

      et_history            TYPE ptrv_web_history_t,

      et_return             TYPE bapirettab,

      ev_subrc              TYPE sy-subrc

      .

    data: ls_return type bapiret2.

    CALL METHOD cl_trv_access=>retrieve_expense_from_cluster

      EXPORTING

        iv_employeenumber     = i_pernr

        iv_tripnumber         = i_tripno

*       iv_crud               = 'R'

      IMPORTING

        ev_mode               = ev_mode

        ev_editable           = ev_editable

        ev_deletable          = ev_deletable

        ev_tripnumber         = ev_tripnumber

        ev_periodnumber       = ev_periodnumber

        ev_periodversion      = ev_periodversion

        ev_persistencystatus  = ev_persistencystatus

        ev_locked_by          = ev_locked_by

        es_header             = es_header

        et_receipts           = et_receipts

        et_deductions         = et_deductions

        et_itinerary          = et_itinerary

        et_costdist_trip      = et_costdist_trip

        et_costdist_itin      = et_costdist_itin

        et_costdist_rece      = et_costdist_rece

        et_costdist_mile      = et_costdist_mile

        ev_fm_posting_date    = ev_fm_posting_date

        et_mastercost_default = et_mastercost_default

        et_advances           = et_advances

        et_mileage            = et_mileage

        et_amounts            = et_amounts

        et_paufa              = et_paufa

        et_ccc_trans_rec      = et_ccc_trans_rec

        et_ccc_buffer         = et_ccc_buffer

        et_history            = et_history

        et_return             = et_return

        ev_subrc              = ev_subrc.

*  CATCH /iwbep/cx_mgw_busi_exception.

*ENDTRY.

After this code, complete current data related to trip being created/modified is in data objects provided in importing clause.

Perform Calculations

Use cs_receipt structure to prepare your changes to the receipt data. Following are important fields of this structure:

◉ rec_amount

◉ rec_curr

◉ pay_amount

◉ pay_curr

◉ shorttxt

◉ descript

Using your business logic, perform needful calculations and set fields of cs_receipt appropriately.

Example code is listed below:

cs_receipt-shorttxt = 'This is a short description.'.

*calculate receipt amount

cs_receipt-rec_amount = rate * number * multiplier.

          IF cs_receipt-rec_amount > 0.

            cs_receipt-rec_curr = curr.

            cs_receipt-descript = |Days = { number }; Rate/Day = { rate } { curr }; Factor = { multiplier }; |.

          ENDIF.

*set amount reimbursed

    CALL FUNCTION 'CONVERT_AMOUNT_TO_CURRENCY'

      EXPORTING

        DATE                   = cs_receipt-rec_date

        foreign_currency       = cs_receipt-rec_curr

        foreign_amount         = cs_receipt-rec_amount

        local_currency         = cs_receipt-pay_curr

     IMPORTING

       LOCAL_AMOUNT           = cs_receipt-pay_amount

*     TABLES

*       T_C_ERRORS             =

     EXCEPTIONS

       ERROR                  = 1

       OTHERS                 = 2

              .

Add custom Error/warning messages

In case you want to add your custom error/warning messages, make changes to ct_return data object. Note that row and parameter fields are very important while making changes to ct_return.

Example code is:

 data: ls_return type bapiret2.

IF sy-subrc <> 0.

* Currency conversion error

      ls_return-type = 'E'.

      ls_return-id = 'ZFFF_TRIP'.

      ls_return-number = '007'.

      CALL FUNCTION 'MESSAGE_TEXT_BUILD'

        EXPORTING

          msgid                     = ls_return-id

          msgnr                     = ls_return-number

*         MSGV1                     = ' '

*         MSGV2                     = ' '

*         MSGV3                     = ' '

*         MSGV4                     = ' '

       IMPORTING

         MESSAGE_TEXT_OUTPUT       = ls_return-message

                .

      ls_return-row = cs_receipt-receiptno. "this is must to add to FIORI messages

      ls_return-parameter = 'PTRV_WEB_RECEIPTS_INT_2'. "this is must to add to FIORI messages

      append ls_return to ct_return.

ENDIF.

Save changes (i.e. Write changes back to cluster)

Finally, the changes made to cs_receipt and ct_return must be saved / written to the cluster to make them persistent.

Sample code is as follows:

DATA: wa_receipt TYPE ptrv_web_receipts_ext_2.

    MOVE-CORRESPONDING: cs_receipt TO wa_receipt.

    MODIFY et_receipts FROM wa_receipt TRANSPORTING rec_amount rec_curr pay_amount pay_curr shorttxt descript WHERE receiptno = wa_receipt-receiptno.

*TRY.

    CALL METHOD cl_trv_access=>save_expense_to_cluster

      EXPORTING

        iv_employeenumber     = i_pernr

        iv_tripnumber         = i_tripno

        iv_mode               = ev_mode

        iv_editable           = ev_editable

        iv_deletable          = ev_deletable

        iv_periodnumber       = ev_periodnumber

        iv_periodversion      = ev_periodversion

        iv_persistencystatus  = ev_persistencystatus

        iv_locked_by          = ev_locked_by

        is_header             = es_header

        it_receipts           = et_receipts

        it_deductions         = et_deductions

        it_itinerary          = et_itinerary

        it_costdist_trip      = et_costdist_trip

        it_costdist_itin      = et_costdist_itin

        it_costdist_rece      = et_costdist_rece

        it_costdist_mile      = et_costdist_mile

        iv_fm_posting_date    = ev_fm_posting_date

        iv_mastercost_default = et_mastercost_default

        it_advances           = et_advances

        it_mileage            = et_mileage

        it_amounts            = et_amounts

        it_paufa              = et_paufa

        it_ccc_buffer         = et_ccc_buffer

        it_ccc_trans_rec      = et_ccc_trans_rec

        it_history            = et_history

        it_return             = ct_return

      IMPORTING

        ev_subrc              = ev_subrc.

*  CATCH /iwbep/cx_mgw_busi_exception.

*ENDTRY.

And this will add receipt to a trip with prefilled auto calculated amounts!

Step 3: Implementing method IF_PAOC_MTE~RECEIPT_UPDATE_ENTITY

Consider a scenario where user selects a receipt and edit “from date” or “to date” of a receipt. consequently, the amount for the receipt must be recalculated to cater changed no. of days. Such calculations which are required on changes in receipt data must be performed in IF_PAOC_MTE~RECEIPT_UPDATE_ENTITY method of Badi PAOC_MTE_BADI.

The principal is same as in IF_PAOC_MTE~RECEIPT_CREATE_ENTITY method. i.e. retrieve cluster data, make necessary changes, save changes to cluster data.

However, while adding custom messages, a small change in above code is required as follow:

ls_return–row = I_RECEIPT_NUMBER.

No comments:

Post a Comment