Home

Outbound messaging > Real-time material stock quantities (ATP)

Generic selectors
Exact matches only
Search in title
Search in content
Post Type Selectors
page

How to message material stock quantities, real-time

Concept

Current material stock quantities (usually referred to as Available-to-promise or ATP stock) is widely required e.g. to present the current and orderable number of products in an online store. But ATP is not a static value within SAP systems, unfortunately. To determine current ATP quantities, SAP systems run an on-line calculation that considers reservations, inbound pipeline, planned shipment dates etc.

Therefore, sending real-time ATP stock per material requires the detection of all changes that can affect the stock quantity calculation, an actual calculation and the formatting to make it sendable as a message, with quantity per material, units etc.

ASAPIO provides that with its ATP extraction feature, including pre-delivered example function modules that can be adopted by customers.

 

Required configuration

SAP Business Objects that can be used and necessary BAdI/User Exit implementation.

Object name Object type Configuration
Sales Order BUS2032 Standard
Purchase Order BUS2012 Standard
Delivery LIKP Standard
Goods Movement BUS2017 BAdI (MB_DOCUMENT_UPDATE)
Material Reservation ZBUS2093 User Exit (MBCF0007)

Create Outbound ATP Configuration

Create Extracting Func. Module:

  • Transaction: SE37
  • Create function module: Z_ACI_EXTRACTOR_ATP

Example coding:

FUNCTION z_aci_extractor_atp .
*"----------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     VALUE(IV_INSTANCE) TYPE  /ASADEV/AMR_ARIBA_ARIBA_INST
*"     VALUE(IV_OBJECT) TYPE  /ASADEV/AMR_ARIBA_ARIBA_OBJECT
*"     VALUE(IT_BDCP_LINES) TYPE  /ASADEV/ACI_TT_BDCP
*"  EXPORTING
*"     VALUE(ET_CSV_LINES) TYPE  /ASADEV/AMR_TT_CSV_LINE
*"     VALUE(ET_RETURN) TYPE  /ASADEV/ACI_TT_BAPIRET2
*"----------------------------------------------------------------------
DATA:
ls_bdcp      TYPE bdcp,
ls_csv_line  TYPE /asadev/aci_any_string,
lv_tmp_event TYPE string,
lv_tmp_key   TYPE string,
lv_keyname   TYPE /asadev/aci_head_attr_value,
ls_return    TYPE bapiret2. 

" ATP check
DATA:   lv_werks      TYPE                   werks,
lv_matnr      TYPE                   matnr,
lv_meins      TYPE                   meins,
lt_iwmdvsx    TYPE STANDARD TABLE OF bapiwmdvs,"TABLES PARAM
ls_iwmdvsx    LIKE LINE OF           lt_iwmdvsx ,
lt_iwmdvex    TYPE STANDARD TABLE OF bapiwmdve,"TABLES PARAM
ls_iwmdvex    LIKE LINE OF           lt_iwmdvex.

DATA:   lv_bdcnt           TYPE string,
lv_req_date        TYPE string,
lv_req_qty         TYPE string,
lv_com_date        TYPE string,
lv_com_qty         TYPE string,
lv_av_qty_plt      TYPE bapicm61v-wkbst,
lv_av_qty_plt_str  TYPE string,
lv_lines           TYPE i,
ls_return_bapi     TYPE bapireturn.

DATA:   lb_last_row TYPE abap_bool VALUE abap_false.

"populate fields of struture and append to itab
APPEND ls_iwmdvsx TO lt_iwmdvsx.
"populate fields of struture and append to itab
APPEND ls_iwmdvex TO lt_iwmdvex.

CONSTANTS:   lc_auth_obj_rc           TYPE xuobject                   VALUE '/ASADEV/RC', "Mod-001++
lc_auth_fld_rf           TYPE fieldname                  VALUE '/ASADEV/RF', "Mod-001++
lc_message_id            TYPE symsgid                    VALUE '/ASADEV/AMR_MESSAGE', "Mod-001++
lc_message_number        TYPE symsgno                    VALUE '077', "Mod-001++
lc_autch_check_data_proc TYPE /asadev/aci_rfc_auth_check VALUE 'DATA_PROC'."Data processing "Mod-001++

* Check if user can execute RFC
AUTHORITY-CHECK OBJECT lc_auth_obj_rc
ID lc_auth_fld_rf
FIELD lc_autch_check_data_proc.

IF sy-subrc <> 0.
*   No authorization for user &1 to call ACI function!
ls_return-type = /asadev/cl_aci_helper=>mc_aci_error.
ls_return-id = lc_message_id.
ls_return-number = lc_message_number.
ls_return-message_v1 = sy-uname.
APPEND ls_return TO et_return.
CLEAR ls_return.
RETURN.
ENDIF.

/asadev/cl_aci_helper=>get_header_attribute(
EXPORTING
iv_instance  = iv_instance
iv_object    = iv_object
iv_attribute = /asadev/cl_aci_cloudev_helper=>mc_attr_em_key_name
RECEIVING
rv_value     = lv_keyname
).

DESCRIBE TABLE it_bdcp_lines LINES lv_lines.

LOOP AT it_bdcp_lines INTO ls_bdcp.

"lv_tmp_event = ls_bdcp-tabkey(32).
"lv_tmp_key = ls_bdcp-tabkey+35(70).
"ATP
lv_werks = ls_bdcp-tabkey+21(4).
lv_matnr = ls_bdcp-tabkey(18).
lv_meins = ls_bdcp-tabkey+18(3).

IF lv_lines = sy-tabix.
lb_last_row = abap_true.
ENDIF.

***********************************************************

CALL FUNCTION 'BAPI_MATERIAL_AVAILABILITY'
EXPORTING
plant              = lv_werks " Plant
material           = lv_matnr " Material number
unit               = lv_meins " Unit of measure for display
*       check_rule         =     " Checking rule
*       stge_loc           =     " Storage location
*       batch              =     " Batch
*       customer           =     " Customer number
*       doc_number         =     " Document number
*       itm_number         =     " Item number
*       wbs_elem           =     " WBS Element
*       stock_ind          =     " Special Stock Indicator
*       dec_for_rounding   =     " No. of decimal places to which rounding should be performed
*       dec_for_rounding_x =     " Updated information in related user data field
*       read_atp_lock      =     " Control indicator for availability check
*       read_atp_lock_x    =     " Updated information in related user data field
*       material_evg       =     " Updated information in related user data field
IMPORTING
*       endleadtme         =     " End of replenishment lead time
av_qty_plt         = lv_av_qty_plt   " Quantity available at plant level
*       dialogflag         =     " Indicator (X = not available, N = no check)
return             = ls_return_bapi   " Indicator (X = not available, N = no check)
TABLES
wmdvsx             = lt_iwmdvsx " Input table (date and quantity)
wmdvex             = lt_iwmdvex. " Output table (date and ATP quantity)
IF sy-subrc EQ 0.

lv_av_qty_plt_str = lv_av_qty_plt.

CONCATENATE ls_csv_line '{' '"objectType":"' ls_bdcp-tabname '", '
*             cl_abap_char_utilities=>newline ' "event":"' lv_tmp_event '", '
cl_abap_char_utilities=>newline ' "werks":"' lv_werks '", '
cl_abap_char_utilities=>newline ' "matnr":"' lv_matnr '", '
cl_abap_char_utilities=>newline ' "meins":"' lv_meins '", '
cl_abap_char_utilities=>newline ' "date":"' sy-datum '", '
cl_abap_char_utilities=>newline ' "quantity":"' lv_av_qty_plt_str '"}' INTO ls_csv_line.

AT FIRST.
CONCATENATE '{"records":[{"value":[' ls_csv_line INTO ls_csv_line.
ENDAT.

IF lb_last_row = abap_false.
CONCATENATE ls_csv_line ',' INTO ls_csv_line.
ENDIF.

AT LAST.
CONCATENATE ls_csv_line ']}]}' INTO ls_csv_line.
ENDAT.

APPEND ls_csv_line TO et_csv_lines.
CLEAR ls_csv_line.

ENDIF.
ENDLOOP.

ENDFUNCTION.

Create an outbound object configuration:

  • Transaction: SPRO
  • Go to IMG > ASAPIO Cloud IntegratorConnection and Replication Object Customizing
  • Or go directly to transaction: /ASADEV/68000202
  • Select the created Connection
  • Go to section Outbound Objects
  • Add New Entry and specify:
      • Object: name of the outbound configuration
      • Extraction Func. Module: Z_ACI_EXTRACTOR_ATP
      • Load Type: Incremental Load
      • Trace: activate for testing purposes

Set-up Business Object Event Linkage

Create Receiver Func. Module:

  • Transaction: SE37
  • Create function module: Z_ACI_EVENTS_TRIGGER_ATP

Example coding:

FUNCTION Z_ACI_EVENTS_TRIGGER_ATP.
*"--------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     VALUE(SENDER) TYPE  SIBFLPORB
*"     VALUE(EVENT) TYPE  SIBFEVENT
*"     VALUE(RECTYPE) TYPE  SWFERECTYP
*"     VALUE(HANDLER) TYPE  SIBFLPORB
*"     VALUE(EXCEPTIONS_ALLOWED) TYPE  SWEFLAGS-EXC_OK OPTIONAL
*"     VALUE(XML_SIZE) TYPE  SWF_XMLSIZ
*"     VALUE(EVENT_CONTAINER) TYPE  SWF_XMLCNT
*"  EXPORTING
*"     VALUE(RESULT) TYPE  SWFREVRSLT
*"--------------------------------------------------------------------

* Data declaration
* Definition of local constants
CONSTANTS:
lc_key                   TYPE sychar03   VALUE 'KEY',
lc_i                     TYPE cdchngind  VALUE 'I',
lc_bor_object            TYPE sibfcatid  VALUE 'BO',
lc_auth_obj_rc           TYPE xuobject                   VALUE '/ASADEV/RC',
lc_auth_fld_rf           TYPE fieldname                  VALUE '/ASADEV/RF',
lc_autch_check_framework TYPE /asadev/aci_rfc_auth_check VALUE 'FRAMEWORK'.

* Definition of local values
DATA: lv_bor_type         TYPE sibftypeid,
lv_msgtype          TYPE edi_mestyp,
lv_cpident          TYPE cdchangenr,
lv_instance         TYPE /asadev/amr_ariba_ariba_inst,
lv_object           TYPE /asadev/amr_ariba_ariba_object,
lv_qname            TYPE trfcqnam.

DATA: ls_aci_syn          TYPE /asadev/aci_sync,
ls_amr_obj          TYPE /asadev/amr_obj,
ls_bdcp_lines       TYPE bdcp.

DATA: lv_meins            TYPE meins,
lv_werks            TYPE werks,
lv_matnr            TYPE matnr,
lv_len              TYPE i,
lv_object_type      TYPE string,
lv_mblnr            TYPE mblnr,
lv_vbeln            TYPE vbeln,
lv_ebeln            TYPE ebeln,
lv_rsnum            TYPE rsnum.

* Definition of internal tables
DATA: lt_bdcp_lines       TYPE /asadev/aci_tt_bdcp,
lt_marc             TYPE STANDARD TABLE OF marc,
lt_vbap             TYPE STANDARD TABLE OF vbap,
lt_ekpo             TYPE STANDARD TABLE OF ekpo,
lt_mseg             TYPE STANDARD TABLE OF mseg,
lt_resb             TYPE STANDARD TABLE OF resb,
lt_lips             TYPE STANDARD TABLE OF lips.

DATA: l_event_container_handle TYPE REF TO if_swf_cnt_container,
lr_container             TYPE REF TO cl_swf_cnt_container.

FIELD-SYMBOLS:  TYPE marc,
 TYPE vbap,
 TYPE ekpo,
 TYPE mseg,
 TYPE resb,
 TYPE lips.

lv_msgtype = rectype.

" now check which outbound object to use
SELECT SINGLE * FROM /asadev/amr_obj
INTO ls_amr_obj
WHERE msgtype EQ lv_msgtype.

* Check if user can execute RFC
AUTHORITY-CHECK OBJECT lc_auth_obj_rc
ID lc_auth_fld_rf
FIELD lc_autch_check_framework.

IF sy-subrc <> 0.

* Authorization check has failed.
* To get a monitor and log entry we still call the framework with BDCP lines etc.
* That way a missing authorization error will be shown in the ACI monitor transaction
CALL FUNCTION '/ASADEV/ACI_RFC'
EXPORTING
iv_conn   = ls_amr_obj-instance
iv_object = ls_amr_obj-object.

ELSE. "Authorization to continue

* Refresh cp data
CLEAR: lv_bor_type.

lv_bor_type = sender-typeid.

IF sender-catid EQ lc_bor_object.
" we can use the BOR type as tabname as it will be only 10 characters long
ls_bdcp_lines-tabname = lv_bor_type.
ELSE.
" future option?: get the tabname from a customizing table? based on rectype?
ENDIF.

" get the changenr from the event container
TRY.
CALL METHOD cl_swf_cnt_factory=>create_from_xml
EXPORTING
im_xml_table = event_container
im_xml_size  = xml_size
RECEIVING
re_instance  = l_event_container_handle.

lr_container ?= l_event_container_handle.

lr_container->if_swf_cnt_element_access_1~element_get_value(
EXPORTING
name             = 'CPIDENT'    " Unique Name of Element
IMPORTING
value            = lv_cpident    " Element Value
).
CATCH cx_swf_cnt_elem_not_found
cx_swf_cnt_elem_type_conflict
cx_swf_cnt_unit_type_conflict
cx_swf_cnt_container
cx_swf_utl_no_instance_found
cx_swf_utl_obj_create_failed.
CLEAR lv_cpident.
ENDTRY.

ls_bdcp_lines-fldname = lc_key.
ls_bdcp_lines-cdchgid = lc_i.

"Subobjects? Last 7 characters from sender-typeid e.g. zzBUS1001
IF strlen( sender-typeid ) GT 7.
lv_len = strlen( sender-typeid ) - 7.
lv_object_type = sender-typeid+lv_len(7).
ELSE.
lv_object_type = sender-typeid.
ENDIF.
" Select material number, plant and units of messure.
CASE lv_object_type.
WHEN 'BUS1001'. " Material

lv_matnr = sender-instid.

SELECT werks INTO CORRESPONDING FIELDS OF TABLE lt_marc FROM marc WHERE matnr = lv_matnr.
SELECT SINGLE meins INTO lv_meins FROM mara WHERE matnr = lv_matnr.

LOOP AT lt_marc ASSIGNING .
CONCATENATE lv_matnr lv_meins -werks INTO ls_bdcp_lines-tabkey RESPECTING BLANKS.
APPEND ls_bdcp_lines TO lt_bdcp_lines.
" CLEAR ls_bdcp_lines.
ENDLOOP.

WHEN 'BUS2012'. " Purchase Order

lv_ebeln = sender-instid.

SELECT matnr meins werks INTO CORRESPONDING FIELDS OF TABLE lt_ekpo FROM ekpo WHERE ebeln = lv_ebeln.

LOOP AT lt_ekpo ASSIGNING .
CONCATENATE -matnr -meins -werks INTO ls_bdcp_lines-tabkey RESPECTING BLANKS.
APPEND ls_bdcp_lines TO lt_bdcp_lines.
ENDLOOP.

WHEN 'BUS2032'. " Sales Order

lv_vbeln = sender-instid.

SELECT matnr meins werks INTO CORRESPONDING FIELDS OF TABLE lt_vbap FROM vbap WHERE vbeln = lv_vbeln.

LOOP AT lt_vbap ASSIGNING .
CONCATENATE -matnr -meins -werks INTO ls_bdcp_lines-tabkey RESPECTING BLANKS.
APPEND ls_bdcp_lines TO lt_bdcp_lines.
ENDLOOP.

WHEN 'BUS2017'. " Goods Movement

lv_mblnr = sender-instid(10).

SELECT matnr werks meins FROM mseg INTO CORRESPONDING FIELDS OF TABLE lt_mseg WHERE mblnr = lv_mblnr.

LOOP AT lt_mseg ASSIGNING .
CONCATENATE -matnr -meins -werks INTO ls_bdcp_lines-tabkey RESPECTING BLANKS.
APPEND ls_bdcp_lines TO lt_bdcp_lines.
ENDLOOP.

WHEN 'BUS2093'. " Material Reservation

lv_rsnum = sender-instid.

SELECT matnr werks meins FROM resb INTO CORRESPONDING FIELDS OF TABLE lt_resb WHERE rsnum = lv_rsnum.

LOOP AT  lt_resb ASSIGNING .
CONCATENATE -matnr -meins -werks INTO ls_bdcp_lines-tabkey RESPECTING BLANKS.
APPEND ls_bdcp_lines TO lt_bdcp_lines.
ENDLOOP.

WHEN 'LIKP'. " Outbound Delivery

lv_vbeln = sender-instid.

SELECT matnr werks meins FROM lips INTO CORRESPONDING FIELDS OF TABLE lt_lips WHERE vbeln = lv_vbeln.

LOOP AT  lt_lips ASSIGNING .
CONCATENATE -matnr -meins -werks INTO ls_bdcp_lines-tabkey RESPECTING BLANKS.
APPEND ls_bdcp_lines TO lt_bdcp_lines.
ENDLOOP.

ENDCASE.

CLEAR ls_bdcp_lines.

/asadev/cl_aci_helper=>create_change_pointers(
EXPORTING
iv_message_type = lv_msgtype
CHANGING
ct_bdcp_lines   = lt_bdcp_lines
).

COMMIT WORK AND WAIT.

IF sy-subrc EQ 0.

SELECT SINGLE * FROM /asadev/aci_sync INTO ls_aci_syn WHERE msgtype = lv_msgtype.

IF sy-subrc = 0.

IF ls_aci_syn-sync_enabled = 'X' AND ls_aci_syn-queue_enabled = 'X'.

"Create Queue Name - first 22 chars of msg type
lv_qname = lv_msgtype+0(22).

"Set Queue Name
CALL FUNCTION 'TRFC_SET_QUEUE_NAME'
EXPORTING
qname              = lv_qname
EXCEPTIONS
invalid_queue_name = 1
OTHERS             = 2.

"Call FM as qRFC
CALL FUNCTION '/ASADEV/ACI_RFC'
IN BACKGROUND TASK
EXPORTING
iv_conn           = ls_amr_obj-instance
iv_object         = ls_amr_obj-object
it_bdcp_lines_ext = lt_bdcp_lines
iv_http           = abap_true.

COMMIT WORK.

ELSEIF ls_aci_syn-sync_enabled = 'X' AND ls_aci_syn-queue_enabled = ''.

*           Perform synchronous call
CALL FUNCTION '/ASADEV/ACI_RFC'
EXPORTING
iv_conn           = ls_amr_obj-instance
iv_object         = ls_amr_obj-object
it_bdcp_lines_ext = lt_bdcp_lines
iv_http           = abap_true.
ELSE.
" in this case only write the change pointers and don't call the ACI framework
ENDIF.

ELSE.
" defaults to synchronous calls
CALL FUNCTION '/ASADEV/ACI_RFC'
EXPORTING
iv_conn           = ls_amr_obj-instance
iv_object         = ls_amr_obj-object
it_bdcp_lines_ext = lt_bdcp_lines
iv_http           = abap_true.
ENDIF.

ELSE.
" no customized outbound object found - just store the change pointer for now
ENDIF.
ENDIF.
ENDFUNCTION.

Link the Business Objects that will trigger the ATP:

  • Go to section Event Linkage
  • Add New Entry and specify:
    • Object Category: BOR Object Type
    • Object Type: The Business Object Type sending the event
    • Event: Event to react to
    • Receiver Function Module: Z_ACI_EVENTS_TRIGGER_ATP
    • Type linkage active: tick the checkbox
Object name Object type Event TABLES Transaction
Sales Order BUS2032 Created, Changed VBAK, VBAP VA01, VA02
Purchase Order BUS2012 Created, Changed EKKO, EKPO ME21N, ME22n
Delivery LIKP Created, Changed LIKP, LIPS VL01, VL02
Goods Movement BUS2017 Created MKPF, MSEG MB11
Material Reservation ZBUS2093 Created, Changed RKPF, RESB MB21, MB22

Test example

With the available trigger inside the Add-on a notification of the ATP will be sent as a JSON-File.


Payload structure:

{
"value": [
{
"objectType": "BUS2012",
"werks": "1200",
"matnr": "DPC1002",
"meins": "ST",
"date": "20221011",
"quantity": "4216.000 "
},
{
"objectType": "BUS2012",
"werks": "1200",
"matnr": "DPC1003",
"meins": "ST",
"date": "20221011",
"quantity": "2063.000 "
},
{
"objectType": "BUS2012",
"werks": "1200",
"matnr": "DPC1004",
"meins": "ST",
"date": "20221011",
"quantity": "1385.000 "
},
{
"objectType": "BUS2012",
"werks": "1200",
"matnr": "DPC1005",
"meins": "ST",
"date": "20221011",
"quantity": "4886.000 "
}
]
}
Scroll to Top