Monday, December 28, 2020

SAP: How To Link Sent E-Mails to Business Objects

The so called 'Services for Object' are available for many central SAP objects, such as Purchase Orders, PM Notifications, Entry Sheets, etc. 


This post will focus on the function 'Services for Object -> Send -> Object Outbox'. 

The Object Outbox contains the E-Mails sent through the function 'Send object with note'.



The Object Outbox function displays the sent E-Mail as it is in the SOST transaction.

It is also possible to link E-Mails as services for the Business from customer specific business process and even from the message processing.

This post will discuss different ways of creating E-Mail Links depending on how the E-Mail is sent from the business process.

E-Mails sent through the function module 'SO_DOCUMENT_SEND_API1'

The approach of sending E-Mails through the function module 'SO_DOCUMENT_SEND_API1'  is obsolete but in case of enhancing an existing solution, there is a following way of linking the E-Mail from the business object:

We need to import the NEW_OBJECT_ID in our code. 


Throgh the method   get_bcs_obj_from_bci_key of the class cl_crm_email_utility_base we can retrieve the send request.

  CALL METHOD cl_crm_email_utility_base=>get_bcs_obj_from_bci_key
    EXPORTING
      is_bci_key          lv_new_object_id
    IMPORTING
      ev_send_request_bcs = data(lo_sendrequest).

Afterwards we can link the send request to the Business Object. 

lo_sendrequest->create_link( ls_borident ).

It is important to note that in this scenario we already have created the E-Mail send request and we create the Link to the Business Repository Object (BOR) in the next step.

The BORIDENT Structure is represented by the Object Type and the Object Key.
To make sure you have the right business object, you can refer to transaction SWO1. 

Example for entry sheets: Object Type BUS2091, object key is the fiels LBLINI from the table ESSR.

E-Mails sent through the Business Communication Service Class CL_BCS

The difference from the previous approach is that we link the E-Mail and the business object before the E-Mail was sent.

The BOR Object is linked to the request in the second step

* 1.Create persistent send request
      lx_send_request cl_bcs=>create_persistent).

* 2.Create Link between the Send Request and the BOR 
          CALL METHOD lx_send_request->create_link
            EXPORTING
              i_appl_object ls_borident
* 3.Send document
      CALL METHOD lx_send_request->send).


This is a very simple, clean code approach and recommended for new implementations or for enhancing functions that already use the Business Communication Service Class.

E-Mails that have already been sent from an Output Type as External Send

The NAST Table contains the E-Mail titles in the field TDCOVTITLE. 
Through the Title, you can find the SOOD record of the sent E-Mail.

The BOR Object and objekt key are also contained in the NAST Table (OBJTYPE, OBJKY), which makes it easy to link the mail.

Configuring  E-Mail Linking from Output Type 

Output types customized in the NACE transaction often send E-Mails, for example to customers or vendors. If the medium '5 - External Send' is used, the SAP Standard Logic (the parent program RSNASTSO) sends the mail through the function SO_OBJECT_SEND. 
Linking the E-Mail to the BOR Object is not easily possible.

If you use the medium '8 - Special Funktion', you can use the CL_BCS class.








Monday, July 6, 2020

SAP EHS: How to select Dangerous Goods Data for Sales&Distribution Printouts

Depending on the setup of your ERP System  and the regional requirements, orders, deliveries and shipments in the Sales&Distribution module produce different kinds of printouts (delivery notes, shipment lists, bills of lading, etc. ).

Usually, those printouts contain Dangerous Goods Data, which is relevant for transport.
If the prinouts use the standard DG Data retrieval logic and your system has a standard DG Data maintenance & customizing, there is nothing to worry about.
The standard logic takes the material and the route from the SD document and determines the DG regulation for which the DG Data is retrieved.

These checks are specified in the customizing activity 'Assign DG Check Schema Determination Routines' per Sales Organisation.

There you can check which check schema is assigned.

You can check your printing settings in transaction NACE.



However, if the prinouts use customer specific data retrieval, z-logic, direct selects on the DGTMD and DGTM2 tables for every printout, then you might opt for a central, reusable solution to include in your retrieval code for all printouts.

The central function can use following logic available in standard function modules.

In this post I will focus on the deliveries:


  • Read the delivery item data using 'RV_DELIVERY_PRINT_VIEW'. Maybe this step is already there in the data retrieval logic.








  •  CALL FUNCTION 'DG56_GET_TRM_CNTRIES_DELV'
          EXPORTING
            e_vbdkl                 <s_vbdkl>
            i_nspras                iv_nspras
          TABLES
            e_tvbdpl                it_vbdpl
            e_rdgcountryreglang_tab lt_rdgcountryreglang
          EXCEPTIONS
            get_data_error          1
            OTHERS                  2.
        APPEND LINES OF lt_rdgcountryreglang TO lt_rdgcountryreglang_all.


      LOOP AT lt_rdgcountryreglang_all ASSIGNING <s_rdgcountryreglang>.
        CLEAR ls_rdgmdsel.
        ls_rdgmdsel-matnr  <s_rdgcountryreglang>-matnr.
        ls_rdgmdsel-lwdg   <s_rdgcountryreglang>-lwdg.
        ls_rdgmdsel-valdat sy-datum.
        APPEND ls_rdgmdsel TO lt_rdgmdsel.
      ENDLOOP.




  •       CALL FUNCTION 'HAZMAT_RECORD_READ_FROM_DB'
        EXPORTING
          i_flg_read_undeleted_only  abap_true
        TABLES
          i_rdgmdsel_tab             lt_rdgmdsel
          e_buftab                   lt_rdgma
        EXCEPTIONS
          no_records_found           1
          no_records_for_all_entries 2
          OTHERS                     3.



The same can be done for shipments using the standard module 'DG56_GET_TRM_CNTRIES_SHIP'
 or for orders.

The return structure RDGMA contains all print-relevant fields from the DGTMD and DGTM2 tables.

We can  easily and simply read the DG Data using standard functions according to the system customizing without writing any direct  select statements on DGTMD / DGTM2 tables.

This approach makes sure that you are selecting the correct DG Data for the SD Document.

For more information about DG Data, please check my
previos post.






Wednesday, June 24, 2020

SAP ABAP: Object Oriented Design for Reports

In this post I would like to demonstrate the possibilty to use Object Oriented Code in a classic report.

I often face pseudo object orieted code in ABAP reports (classes containing only statis methods that serve as wrappers for procedural code, performs wrapped in methods).

That is why I would like demonstrate a simple and flexible OO solution, using local classes.


REPORT zxyz.
TABLESestvhestvaestrh.


SELECTION-SCREEN BEGIN OF SCREEN 900.
SELECT-OPTIONSs_estcat FOR estvh-estcat DEFAULT 'SAP_EHS_XYZ'.
SELECT-OPTIONSs_subid FOR estrh-subid.
SELECTION-SCREEN END OF SCREEN 900.


*--------------------------------
*CLASS lcl_main DEFINITION
*--------------------------------
CLASS lcl_main DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS :start_report.

  PRIVATE SECTION.
    METHODS fetch,
              check_auth,
              display.
    CLASS-DATA lr_main TYPE REF TO lcl_main.
    DATA it_table TYPE TABLE OF zasi_cds_count_inst.
ENDCLASS.                   
*------------------------------------
*       CLASS lcl_main IMPLEMENTATION
*-------------------------------------
CLASS lcl_main IMPLEMENTATION.
  METHOD start_report.
BREAK-POINT.
    CALL SELECTION-SCREEN 900.
    IF sy-subrc IS INITIAL.

      CREATE OBJECT lr_main.
      lr_main->fetch).
      lr_main->display).
    ENDIF.

  ENDMETHOD.                   
  METHOD fetch.
SELECT INTO TABLE @it_table FROM zasi_cds_count_inst WHERE subid IN @s_subid AND estcat IN @s_estcat.
  ENDMETHOD.                    
  METHOD check_auth.
-->>perform authorization checks here
  ENDMETHOD.
  METHOD display.
    DATA lr_table TYPE REF TO cl_salv_table.
    cl_salv_table=>factory(  IMPORTING    r_salv_table   lr_table
    CHANGING     t_table        =   me->it_table  )    .
    lr_table->display).
  ENDMETHOD.                    
ENDCLASS.  



START-OF-SELECTION.

  lcl_main=>start_report).


This solution provides more control and more flexibility compared to the procedural approach over events.

The selection screen is defined with a dedicated number and called later at start_report.
This allows flexibilty. We can define more selection screens and call the one we need based on authorization checks, for example. 

This approach might seem strange for those of us who are used to the START-OF-SELECTION, PERFORM xyz, END-OF-SELECTION type of programming but it is worth trying.








Tuesday, May 26, 2020

SAP ABAP CDS Views: Data-to-Code vs Code-to-Data - an example with aggregation

I am going to discuss two approaches to a requirement that I have received often from customers.

EH&S: Business wants to know the specifications where there is an instance maintained for a certain property.

In EH&S it is possible to maintain more than one intance per property. Multiple property  instantes can be confusing for the business, so  customers wanted to have an evaluation if they have EH&S specifications with multiple instances (same sort) for certain properties.

Of course, it was possible to solve the requirement with the help of an ABAP Report looking something like that:

Back-End SAP, ABAP:

The logic is in my report. (Data-to-Code Approach)


REPORT zehs_r_inst_count.

TABLES: estvh, estva, estrh.

SELECT-OPTIONS: s_estcat FOR estvh-estcat DEFAULT 'SAP_EHS_1023_094'.
select-OPTIONS: s_subid for estrh-subid.

SELECT COUNT( DISTINCT estva~recn ) AS count, estva~ord,estva~recnroot, estva~recntvh, estvh~estcat, estrh~subid
INTO TABLE @DATA(lt_inst)
FROM estva INNER JOIN estvh ON estvh~recn = estva~recntvh JOIN estrh ON estva~recnroot = estrh~recnroot
WHERE estvh~estcat IN @s_estcat and estrh~subid in @s_subid AND estva~delflg EQ @space AND estvh~delflg EQ @space
and estrh~delflg eq @space
GROUP BY estva~recnroot, estva~recntvh, estva~ord, estvh~estcat, estrh~subid.

 perform show_alv.

Nonetheless, it is far more flexible and efficient to use CDS Views and not to hold so much DB logic in the application:


Eclipse, Open SQL:

The logic is contained in the view (Code-to-Data or code pushdown Approach)




For developers who are new to SAP CDS Views appear very easy, intuitive and sql-like.

I habe been usng the data-to-code a lot in the past, so that I notice a huge efficiency improvement when using CDS Views.

I can check my view in transaction se16n:


This new programming model supports clean code and reusability.
It is satisfying to clean the application from  sql statements and to push them to the data base. 

There are many options for using the newly created view:

 - If the evaluation should be pulled only once, this can be done using transaction se16n
-  If the evaluation should be done by a user, a report or transaction can be created
-  For views that will be checked often by many users, a FIORI App can be created by publishing the view as an oData Service

Sunday, April 26, 2020

SAP EHS: From Procedural Code to Clean Object Oriented ABAP Part 1

Programming in the SAP EH&S Module can often be callenging due to the concept of properties and characteristis, as well as the different usages (validity areas and ratings).

The BAPIs  BAPI_BUS1077_* from the function group 1077 are still very widely used in procedural code.

Nonetheless, it is the  Object Oriented concept that supports Clean Code. 

Therefore, in order to achieve clean ABAP code for EH&S Developments we can use the class CL_EHCSM_SPC_ACCESS instead of the 1077 BAPIs.

Simple Example:

Here I am going to demonstrate a rework of a procedural function module into a clean code method.

Reading specification properties using the function module BAPI_BUS1077_GETDETAIL:

Procedural code:

SELECT matnr recnroot FROM estmj INTO CORRESPONDING FIELDS OF TABLE lt_estmj WHERE matnr iv_matnr AND delflg abap_false.

  lv_lines lineslt_estmj ).

  CASE lv_lines.
    WHEN 0.
      ev_return '1'
      RETURN.
    WHEN 1.
      READ TABLE lt_estmj INTO ls_estmj INDEX 1.
    WHEN OTHERS.
      ev_return '2'
      RETURN.
  ENDCASE.



  CLEARls_subheader.

  ls_subheader-record_no ls_estmj-recnroot.
  APPEND ls_subheader TO lt_subheader.

  ls_propheader-subchacat 'SAP_EHS_XXX_YYY'.
  APPEND ls_propheader TO lt_propheader.

  ls_propheader-subchacat 'SAP_EHS_XXX_YYY'.
  APPEND ls_propheader TO lt_propheader.

  ls_propheader-subchacat 'SAP_EHS_XXX_YYY'.
  APPEND ls_propheader TO lt_propheader.

  ls_propheader-subchacat 'SAP_EHS_XXX_YYY'.
  APPEND ls_propheader TO lt_propheader.

  ls_propheader-subchacat 'SAP_EHS_XXX_YYY'.
  APPEND ls_propheader TO lt_propheader.

  CALL FUNCTION 'BAPI_BUS1077_GETDETAIL'
    EXPORTING
      scenario         '01'
      key_date         sy-datum
      flg_header       'X'
      flg_matjoin      'X'
      flg_properties   'X'
      flg_prop_data    'X'
      flg_prop_details 'X'
    TABLES
      return           lt_return
      sub_header       lt_subheader
      matjoin          lt_matjoin
      prop_header      lt_propheader
      prop_val         lt_propval
      prop_data        lt_propdata
      prop_usage       lt_propusage.

In the procedural code we find select statements, which should be avoided.
It is very common in the EH&S Development to be trying to read the specification to a certain material.

Recommendations:

  • Avoid direct Selects


First try to find an existing function in your framework and only if nothing is available, write a select statement.

  • A BAPI is better than a direct select.  
  • The method of a class is better than a BAPI. 
In this example I recommend to capsule the often needed function get_recn_by_matnr in a method. In my method I still had to use the BAPI BAPI_BUS1077_GETLIST  but it is reusable and in case of change, I will change it once.

zcl_ehs_hazard=>get_recn_by_matnr. 



  • Use INSERT VALUE instead of APPEND
Appended lines need a defined type. The INSERT VALUE is more flexible and can be used even if some structure type gets changed.

  • DRY (DO NOT REPEAT YOURSEF)
In the above code we see that many properties were hard-coded and appended to the properties  header table. In similar cases it is worth considering to move such logic to the configuration (you can use a z-table instead of the hard code). The advantage is that when business asks for an additional property to be evaluated, you can simple do this as a customizing activity, not affecting your code.
You can see in the clean code that the logic is capsuled in the method 
zcl_ehs_hazard=>get_XYZ_vat.

  • Use ABAP OO instead of procedural code
In this example ( BAPI_BUS1077_GETDETAIL vs. CL_EHCSM_SPC_ACCESS) we can easily see the advantages of using the dedicated method retrieve_val_char_data of the class 
 CL_EHCSM_SPC_ACCESS. 

The method  retrieve_val_char_data  provides the option to filter the characteristics by usage. This means that if I want to evaluate a certain usage, for e.g. Validity Area Korea, I can filter before I get the data and don't have to worry afterwards. 

  • Prefer inline declaration always when it is possible, when not declare the variables close to their usage

With the OO Style we can use inline declarations for the import parameters (clean code)


  • Avoid hard code or the so called magic words
You can see the hard coded scenario '01' in the procedural code. Usually, you can find the constants that you need in the interface. In the clean code, for example, we use if_ehcsm_spc_const_c=>gc_lockmode-no_lock.

Not everyone knows what '01' or 'N' is but everyone will understand 'no lock'.

  • Call your variable and methods in a way that they can be pronounced
This makes your code more readable and the hand-over process more efficient.


Clean ABAP Code:


    METHOD XYZ.
    DATA(lo_accesscl_ehcsm_spc_access=>get_instance).
    DATA lt_key TYPE ehcsmt_spc_key.
    DATA lt_usage_filter TYPE ehcsmt_spc_usage_filter.
    INSERT VALUE #recn zcl_ehs_hazard=>get_recn_by_matnriv_matnr INTO TABLE lt_key .
    INSERT VALUE #rvlid iv_country vaclid zcl_ehs_hazard=>c_vaclid INTO TABLE lt_usage_filter.
    lo_access->retrieve_val_char_data(
      EXPORTING
        it_spc_header_key    lt_key
        it_vat               zcl_ehs_hazard=>get_XYZ_vat
        it_spc_usg_filter    lt_usage_filter
        iv_lock_mode         if_ehcsm_spc_const_c=>gc_lockmode-no_lock
       IMPORTING
         et_spc_val_char_data DATA(lt_spc_char_data)
         et_message           DATA(lt_message)
         ev_severity          DATA(lv_severity)
    ).





The most important is to use your framework and what it offers because it is tested!
Good luck!



Friday, April 24, 2020

SAP: Error Analysis in Output Processing, example Sales&Distribution (VL02N)

Having worked for customers in the logstics branche, I often had to analyze the output processing in the Sales&Distribution Module

Here I would like to share some error examples and the approach to them.


  • Wrong Data in the Output
The output processing is executed successfully but the data is not correct:
In order to debug cases with wrong output data, it is helpful to check transaction NACE.
There we go to the output type V2 (Shipping) and navigate to our output type.
We can check the processing routines:


By placing a break-point in the Form Routine, we can easily debug the data retrieval.

  • Critical errors 
Thee output processing is not executed, a red error message is there in the log:
In this case the partner agreements are not maintained correctly. A customizing activuty needs to be done in transaction WE20. Then we can reexecute the output.



Some error messages in the output processing are nonthreatening but they appear and can be confusing for the end users.

  • Minor errors
For example, in deliveries (transaction VL02N) ,after processing the output routines, the paper is printed correctly or the IDoc is sent but when you go to the log you find errors like missing translations or missing phrases / phrase sets.

Let's look at one example where we get the error  message DG523:


The message is almost self-explanatory and it is clear there is master EH&S Data missing.
After maintaining the missing phrase set assignment, we reprocess and the log is green.
In case of missing master data, do not forget to maintain in the production system.






SAP EHS: Getting started with Mixed Loading Checks





Many SAP Customers execute manual mixed loading checks, which is time consuming and error prone.

To automate this process, they should provide customizing for mixed loading rules, which is regulation specific and can be switched on and off per sales organization. If the mixed loading rules are violated, a delivery split should take place.

In the SAP standard system the danger label is used as the segregation key.

There is a Sales Organization specific Mixed Loading Rule Activation.
The mixed loading checks in SD are executed by the Standard Function Module DG63_CHK_MLOAD which should be customizied as a dangerous goods check method together with the function module DG63_CHK_INIT_HEADER.
For the mixed loading checks a dangerous goods check schema (matrix) can be defined.

It contains the mixed loading checks and can be assigned to a particular sales organisation and delivery type.

After maintaining the Customizing for Segregation Rules, one example can be created at Sales Order Level.

The delivery cannot be saved because the mixed loading rules are violated.
The next step is to have a delivery split in this case.






Thursday, April 16, 2020

SAP EHS: Dangerous Goods Data for Sales and Distribution Documents

In my experience I have seen many SAP Customers struggling with the output of Dangerous Goods (DG) Data on Sales and Distribution(SD) Documents, such as printouts or IDocs.

The Standard SAP Solution for this topic is quite simple and straightforward. The Problem is that it has the prerequisite of the EH&S Master Data Data being available on the system.

Many customers, who recently introduced the EH&S module, have already implemented custom solutions based on custom data (the z-table solution).

When trying to show DG Data on SD Documents, you have to make sure following conditions are met on the system:

Master Data:

  • Material Master Data (TCode MM03), Dangerous Goods Indicator  MARA-PROFL should be set

  • Dangerous Goods Mater (TCode DGP3):, There should be a valid DG Record for the document date of the SD Document, the validity area and the mode of transport dtermined by the route in the delivery.
e.g. The delivery is sent from Germany to Slovenia by road - the system finds the regulation ADR
(This Customzing can be found in Transaction 




If there is no record in the DGP3 Transaction, it can be filled through transaction DGE5 in a system with EH&S master data available. Otherwise it can be maintained manually in transaction DGP1.
  • SD Delivery Document: The route should be maintained in the delivery document
Customizing Activities:

  • Activate Dangerous Goods Checks
  • Specify Dangerous Goods Check Methods
  • Specify Usage Profiles for Dangerous Goods Check Methods
  • Assign Dangerous Goods Check Schemas
Once you have a Dangerous Goods schema assigned to your sales organization, you can execute the dangerous goods in Sales&Distribution, for example in TCode VL02N.



You can either execute the DG Checks on the SD Document or execute the output procedure for the relevant paper or IDoc.

There are customers who have their special master data maintenance. For example, some customers don't maintain a DG indicator (MARA-PROFL) on material master lever, the field for this is simply empty. 

They should be advised to update the master data and make sure that newly created data contains it as well.




Other customers have to provide the DG Data to third party interface, such as transport companies or systems who take care of the SD orders.

A classic problem is the route not being maintained on the SD Document. This results in the DG Data not being retrieved, since each and every standard module from the already mentioned DG Check methods 'gives up' if there is no route.

Some companies will have their route determination customized and automatically filled. Others will be maintaining it manually. 

The SAP Standard doesn't throw a message if the route is not maintained, it just leaves the DG Data empty. 

This functionality can fortunately be enhanced. For example, a custom function can be created to show an error message or write an error in the application log if critical data for the DG determination is not available.

Following enhancements can be implemented:

  • Develop Enhancement for Material Exchange Multi-Component Explosion
  • Develop Enh. for Determ. Country/MTC Combination in Shipping/Sales
  • Develop Enh. for Determ. Country/MTC Combination in Shipment Document
  • Develop Enhancement for Country/Mode-of-Transport Category Combination
  • Develop Enhancement for Editing DG Data in Shipping Document
  • Develop Enhancement for Editing DG Data in Sales Document
You can check my post:
SAP: Implement a User Exit (Customer Exit) but How?
 to see how to implement a user exit.