Supply Chain Management Blogs by Members
Learn about SAP SCM software from firsthand experiences of community members. Share your own post and join the conversation about supply chain management.
cancel
Showing results for 
Search instead for 
Did you mean: 
Bohdan
Active Contributor
Dear SAPers,

SAP delivered a dedicated component called Dispute Management within FSCM module to manage the differences (i.e., disputes) that arise during clearing of incoming payments & customer invoices. Dispute Management uses the component Case Management as a technical basis to process the dispute cases. The purpose of this post is to explore the enhancement options behind the BADI SCMG_CHNG_BFR_STR_C. This post will focus mainly on the use of this BAdI for management of dispute cases. I’ll provide some recommendations on the architecture of the enhancements and some useful tips how to use the interface of this BAdI efficiently.

Overview of the BAdI interface


This BAdI uses the interface IF_EX_SCMG_CHNG_BFR_STR_C with one method CHANGE. The screenshot below shows the method’s signature:


This BAdI is a generic BAdI within case management framework and it is used in many processes. However, this BAdI can be implemented only once i.e., only one active implementation can exist at a time. The interface uses an importing parameter FLT_VAL to distinguish between various processes that call this BAdI. Typical filter values are:

  • F_DM – for dispute cases.

  • FDCD – for documented credit decision.


Screenshot below shows the implementation of this BAdI:



High-level architecture of the BAdI implementation


If you want to use this BAdI for implementation of custom logic, I’d recommend using the implementing class for this BAdI only as a controller, whereas the main logic should be implemented in separate global classes. Let me clarify what I mean.

BAdI implementing class ZCL_IM_SCMG_CHNG_BFR_ST as is shown below serves only one purpose: it checks the value of the filter and routes the execution to two other global classes: ZCL_IM_SCMG_CHNG_BFR_ST_DC & ZCL_IM_SCMG_CHNG_BFR_ST_DCD. The first class implements custom logic for dispute cases, the second one for documented credit decisions.

What are the benefits of this approach? Main benefit in my opinion is that the enhancement logic is split into separate classes. Each class follows the single responsibility principle and knows how to handle the objects of one type only. This architecture ensures smaller regression impact and means lower maintenance cost in the long run: if you need to adjust the logic for one component (e.g., dispute cases), you can be sure that other functionalities will not be impacted by these changes.
class zcl_im_scmg_chng_bfr_st definition
public
final
create public .

public section.

interfaces if_ex_scmg_chng_bfr_str_c .

protected section.
private section.

endclass.

class zcl_im_scmg_chng_bfr_st implementation.

* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_IM_SCMG_CHNG_BFR_ST->IF_EX_SCMG_CHNG_BFR_STR_C~CHANGE
* +-------------------------------------------------------------------------------------------------+
* | [--->] IM_CASE TYPE REF TO IF_SCMG_CASE
* | [--->] FLT_VAL TYPE SCMGPROCESS
* | [!CX!] CX_SCMG_CASE_BADI
* +--------------------------------------------------------------------------------------</SIGNATURE>
method if_ex_scmg_chng_bfr_str_c~change.

constants:
begin of lc_filter,
dispute_case type scmgprocess value 'F_DM',
doc_cred_decision type scmgprocess value 'FDCD',
end of lc_filter.

case flt_val.
when lc_filter-dispute_case.
zcl_im_scmg_chng_bfr_st_dc=>change_dc( im_case ).
when lc_filter-doc_cred_decision.
zcl_im_scmg_chng_bfr_st_dcd=>change_dcd( im_case ).
when others.
return.
endcase.

endmethod.
endclass.

Screenshots below show how new class for dispute cases was implemented:




Instance of the case as method parameter


If you’re a functional consultant and you analyze the interface of this BAdI for the first time, you might be confused a bit: the method has only one importing parameter IM_CASE and normally you cannot change the parameters of this type. Besides, even if you put a breakpoint in the code and will check the variable IM_CASE in debug mode, you’ll not find a lot of useful details. Screenshot below shows how this parameter looks like during debugging.


The explanation is simple: this method receives an instance of the dispute case. Each dispute case as an instance has certain attributes (i.e., values associated with it) and methods (i.e., actions you can perform in relation to the instance). Let’s see how to access these attributes and what are some useful methods you can use to get / set the values of certain attributes.

Overview of Getter Methods


If you want to check a value of some attribute, you can use the method GET_SINGLE_ATTRIBUTE_VALUE. It will retrieve the current value of the attribute e.g., who is coordinator of the dispute case. Similarly, you can use another method GET_SINGLE_OLD_ATTR_VALUE to retrieve the value of the attribute before it was changed. See two examples below:
try.
data lv_coordinator type udmcaseattr00-fin_coordinator.
lv_coordinator = im_case->get_single_attribute_value( 'FIN_COORDINATOR' ).
catch cx_srm_framework .
catch cx_scmg_case_attribute .
endtry.

try.
data lv_previous_coordinator type udmcaseattr00-fin_coordinator.
lv_previous_coordinator = im_case->get_single_old_attr_value( 'FIN_COORDINATOR' ).
catch cx_srm_framework .
catch cx_scmg_case_attribute .
endtry.

The list of fields for these methods is essentially limited by the list of fields in the following two tables:
(1) Generic case attributes i.e., table SCMG_T_CASE_ATTR.
(2) Application specific case attributes: UDMCASEATTR00 – attributes of dispute cases, UKM_DCD_ATTR – attributes of document credit decision etc.

The first table stores common attributes e.g., case type, external reference, administrative details (who created, who changed and when etc.). The second table stores attributes that are specific to a given case type (e.g., dispute case).

Technically speaking, application specific table depends on the settings of the attribute profile associated with your case. You can check out the configuration in the transaction S_SE3_50000032 or maintenance view SCMGVC_ATTRPROF (SM34).


When you are referencing these variables in the code, you can use different approaches. Depending on your project’s rules: you can reference the variable name directly (e.g., RESPONSIBLE); you can use a constant from the interface IF_SCMG_CASE or you can use the case attribute directly.
data lv_responsible type scmg_t_case_attr-responsible.
lv_responsible = im_case->get_single_attribute_value( 'RESPONSIBLE' ).
lv_responsible = im_case->get_single_attribute_value( if_scmg_case=>if_scmg_case_read~responsible ).
lv_responsible = im_case->get_single_attribute_value( im_case->responsible ).

You can review the list of available constants in the interface IF_SCMG_CASE via transaction SE24:


There are a few other standard methods to get certain attributes. For example, there are predefined methods to get case type, creating user, creating date, case GUID, last changing date / user. These methods are useful shortcuts and you do not need to re-invent the logic from scratch.


Here is also a useful tip along the way. It is often necessary to check if BAdI is executed during initial creation of the case or in a change mode. You can do a simple check: get case GUID (i.e., global identifier) and select any attribute (e.g., case type) from the table SCMG_T_CASE_ATTR. When the BAdI is executed during case creation, case GUID is already assigned, but this table is still empty. If the select fails, it means that the BAdI is executed in creation mode.



" We already have a Case GUID at this point, but no entries in DB
data lv_guid type udmcaseattr00-case_guid.
lv_guid = im_case->get_guid( ).

data lv_case_type type scmg_t_case_attr-case_type.
select single case_type
from scmg_t_case_attr
into lv_case_type
where case_guid = lv_guid.

if sy-subrc <> 0.
" BAdI is executed in creation mode.
endif.

Another common requirement is to check if the case was changed by the user. Why would you need to do that? The answer is quite simple. The enhancement logic is often based on the assumption that the user changes the case, and this action triggers some additional changes (e.g., workflow, e-mail notification, change of some attributes etc.). However, if you simply open the dispute case in change mode via SAP GUI transaction UDM_DISPUTE save the case without changing anything, this action will also trigger the BAdI execution. This might lead to some unwanted automatic changes. To avoid that, you can use standard method IS_CHANGED. See sample code below.


Please note: if you open the dispute case via Fiori App F0702AManage Dispute Case” in processing mode, do not change anything and save it once more - it will not trigger the BADI. If you change only dispute case notes and save the case without changing other parameters, it will also not trigger the BADI. I've raised an OSS-incident on this matter and was notified that this is a standard behavior.
" Method definition
class-methods is_changed
importing
im_case type ref to if_scmg_case
returning
value(rv_yes) type abap_bool.

" Method implementation
method is_changed.

try.
if im_case->is_changed( ) = abap_true.
rv_yes = abap_true.
endif.
catch cx_srm_framework .
endtry.

endmethod.

" Use of the check in the main method
method change_dc.

" Check if dispute case was changed
if is_changed( im_case ) = abap_false.
return.
endif.

endmethod.

Overview of Setter Methods


There is also a setter method that allows you to change the value of case attributes. You can use the method SET_SINGLE_ATTRIBUTE_VALUE to change the value of the case attribute. Source code below shows how to update the value of the case title:
try.
im_case->set_single_attribute_value(
im_srmadid = im_case->case_title
im_value = 'Case Title: New Value' ).
catch cx_srm_framework .
catch cx_scmg_case_attribute .
endtry.

Big advantage of using this BAdI is that you can update many different attributes within the same enhancement. FSCM module provides a lot of different BAdIs that can be used to update only one specific attribute (e.g., case priority, external references, processor etc.). The screenshot below shows the list of these BAdI in the configuration menu. In my opinion, it is better to use one enhancement to manage custom logic for dispute cases vs. many enhancements that update just one attribute. With one central enhancement you save time around administration / documentation of the WRICEFs and have better visibility / control over the enhancement logic.



Links to Disputed Objects


Each dispute case has links to a range of disputed objects including but not limited to a business partner, residual item & customer invoice. See the screenshot below:


These links are stored in the table FDM_DCOBJ. See the screenshot below with sample content of the table:


If you need additional information about disputed object for your enhancement logic, you can implement a utility method within BAdI implementing class that will select the object key and parse it into the accounting document line item. Sample source code for this method is provided below.
" Definition of the global type
types:
begin of ty_fidoc_key,
belnr type belnr_d,
bukrs type bukrs,
gjahr type gjahr,
buzei type buzei,
end of ty_fidoc_key.

" Definition of utility method
class-methods get_related_doc_key
importing
im_case type ref to if_scmg_case
iv_classification type fdm_classification
returning
value(rs_fidoc) type ty_fidoc_key.

" Implementation of utility method
method get_related_doc_key.

data lv_guid type udmcaseattr00-case_guid.
lv_guid = im_case->get_guid( ).

data lv_obj_key type fdm_dcobj-obj_key.

" Get object key of related payment documlent
select single obj_key
from fdm_dcobj
into lv_obj_key
where case_guid_loc = lv_guid
and obj_type = 'BSEG'
and classification = iv_classification.

" Parse object key into FI document key
if sy-subrc = 0 and strlen( lv_obj_key ) = 21.
rs_fidoc-bukrs = lv_obj_key(4).
rs_fidoc-belnr = lv_obj_key+4(10).
rs_fidoc-gjahr = lv_obj_key+14(4).
rs_fidoc-buzei = lv_obj_key+18(3).
endif.

endmethod.

" Use of utility method in the main method
method change_dc.

" Get the link to linked case object
data ls_fidoc_key type ty_fidoc_key.
ls_fidoc_key = get_related_doc_key(
im_case = im_case
iv_classification = fdmco_disp_residual ).

endmethod.

FDMCO_DISP_RESIDUAL – is a global constant defined by SAP for field FDM_DCOBJ-CLASSIFICATION, which is used to denote the residual item. Type group FDMCO stores the whole list of these global constants that can be used in your enhancement:


I’m mentioning this aspect about disputed objects on purpose here. There is one big limitation with regards to this BAdI. When it is executed in creation mode, the GUID of the dispute case is already assigned, but the table FDM_DCOBJ is not filled yet. Therefore, you cannot access these objects during creation of the dispute case, you can access them only in change mode. If you need to access the attributes from the disputed objects during creation of the dispute case, I’d recommend using BAdI FDM_AR_DISP_COMPLETE. This BAdI is execute before SCMG_CHNG_BFR_STR_C and offers many enhancement options. The method COMPLETE_DISPUTE of the BAdI FDM_AR_DISP_COMPLETE has a parameter T_OBJECTS, which stores the list of disputed objects.

Reading of Case Long Texts


Apart from case attributes & disputed objects you might also need to access the case long texts. Before accessing long texts, you need to know the text ID. You can check-out the settings of the text profile associated with the dispute case in the transaction S_SE3_50000056 (or maintenance view SCMGVC_TEXTPROF, SM34). If you do not know which text profile is being used, check out the customizing of the dispute case type in the transaction S_SE3_50000059 (or maintenance view SCMGV_CTYPE_PPF, SM30). See the screenshot of sample text profile below:


You can re-use the FM BDM_DISPUTE_NOTES_GET to fetch the text associated with dispute case. See the sample source code below:
" Get the value of case notes
data ls_return type bapiret2.
data lt_notes type bdm_t_notes.

call function 'BDM_DISPUTE_NOTES_GET'
exporting
im_guid = lv_guid
importing
es_return = ls_return
et_notes = lt_notes .

if lines( lt_notes ) = 0.
return.
endif.

data lv_text type string.
field-symbols <i> like line of lt_notes.
loop at lt_notes assigning <i> where tdobject = 'SCMG_CASE' and tdid = '0001'. " 0001 is a text ID
" Skip the first line
if sy-tabix = 1.
continue.
endif.

" Contcatenate the lines
if <i>-tdline = '' or <i>-tdline na sy-abcde.
continue.
else.
lv_text = <i>-tdline && lv_text.
endif.
endloop.

Text data is stored in the table LT_NOTES. The first line from the text should be skipped. This is automatically generated caption for the text.


Note: there is slight difference in the formatting of the caption line if you’re using S4 HANA system and the Fiori App F0702AManage Dispute Case” to maintain long texts. The comparison is in the screenshot highlighted above.

I hope you do net regret the time you spent if you reached the end of this post and you learnt something useful. I’m looking forward to your comments and remarks.

Regards,

Bohdan

 

 
15 Comments
Jigang_Zhang张吉刚
Active Contributor
Thanks for sharing this!
Bohdan
Active Contributor
0 Kudos
Hi jimmy.zhang3,

Thank you ! You shared much more with the community on topics related to FSCM. I'm trying to follow in your steps 🙂

Regards,

Bohdan
Jigang_Zhang张吉刚
Active Contributor
the.wirtschaftsmann

Thanks. I've no news from the FSCM aspect recently : P
krishnasakkara
Explorer
0 Kudos
Hi Bohdan petrushchak,

It was really good explantion on the Disputes and Related stuff.  we are having a requirement where we have external API which will call ECC Custom code . Everything is working as expected expect when we remove the assoicted invoice from dispute after that nomore actions taking place as it giving dump as DUPLICATE_KEY_ERRORS while updating FDM_DCPROC or FDM_DCOBJ.

Can you help me is there any method or class or code to handle this removal part .

 

Thank you.

Krishna
Bohdan
Active Contributor
0 Kudos
Hi rudramsh.s,

How do you approach the deletion in your custom code currently ? Which class method / FM do you use to delete the assignments ? Or you do it via direct update of the tables ?

Regards,

Bohdan
0 Kudos

Very informative and useful blog on usage for FSCM dispute cases. We recently implemented this for handling the approval process in UKM_CASE scenarios. I wanted to also understand if there is a way we can restrict the editing of certain attributes through BAdI, as we want to ensure that the user is not able to make changes to the values such as Approver 1, Approver 2 (assigned during creation) in change mode.

Also, the idea of using the BAdI implementation as controller is very helpful. In my case instead of directing to a global class we decided to have a new separate Kernel BAdI for each filter value, this gives us more flexibility and control over individual implementations in future and hence reduces the dependencies.

Thanks & Regards,

Noman Hanif

Bohdan
Active Contributor
0 Kudos
Hi noman.mohamedhanif,

Thank you for good feedback ! I think there are at least three options to achieve that:

  • Implement a validation via BADI SCMG_VLDT_BFR_STR_C to make sure that the user is not changing the values.

  • Check if the values of the attributes Approver 1 / 2 were changed during processing and reset them via SCMG_CHNG_BFR_STR_C. The methods GET_SINGLE_OLD_ATTR_VALUE & GET_SINGLE_ATTRIBUTE_VALUE will be useful for that request.

  • You can adjust the settings of the relevant attributes in the attribute profile that is assigned to your dispute case. You can check these settings via t-code iS_SE3_50000032 or view SCMGVC_ATTRPROF (SM34). There is an option to mark attribute either as "non-editable" or "editable only during creation". It might be even better solution.



 

Regards,

Bohdan
krishnasakkara
Explorer
0 Kudos
Hi Bohdan,

Thank you and sorry for the delay in Response.

Actually i didnt get any FM to update the tables for deletion. so i have updated Tables directly .

Tables that i have updated are :

1. FDM_DCPROC  2 .DFPM_NUMB .3 .FDM_DCOBJ.
Bohdan
Active Contributor
0 Kudos
Hi rudramsh.s,

From what I can see, SAP is using the following two FMs FDM_AR_ITEM_REMOVE -> FDM_AR_DOC_OBJ_TO_REMOVE_GET during deletion of items from dispute case. At least they are used when you delete line items from the dispute case in transaction UDM_DISPUTE. Please take a look at these FMs. I think they might be helpful for you.

Regards,

Bohdan
krishnasakkara
Explorer
Hi Bohdan.

I think i checked it . let me recheck and let u know.
Thanks for the update.

 

Thank you.

Rudramsh.
0 Kudos
Hi Bohdan,

 

Thank you for your brief explanation and options enlisted with regard to the restriction and assignment of certain fields.

In our case to be specific we needed to set the attributes for the approval process based on the custom threshold which we define separately (custom table), also a check is made in our code to see if this is in change mode and the current system user is not part of the custom approval hierarchy then we revert the changes. Everything works perfectly until the changes are released and we notice that during release this BAdI is not called and somehow after the release message the document status is still 'Blocked'.

Could you please suggest what might be needed to align with the release process?



* Fist for assignment of approval we need to ensure to execute
* only during the automatic case creation mode
IF determine_creation_mode( im_case ) = abap_true.

* Set the attributes during creation mode
TRY. " Person Responsible
im_case->set_single_attribute_value(
im_srmadid = lc_responsible
im_value = CONV #( lv_person_resp_grp ) ).
CATCH cx_srm_framework .
CATCH cx_scmg_case_attribute .
ENDTRY.

TRY. " Approver 1
im_case->set_single_attribute_value(
im_srmadid = lc_dcd_approver1
im_value = CONV #( lv_one_approver_grp ) ).
CATCH cx_srm_framework .
CATCH cx_scmg_case_attribute .
ENDTRY.

TRY. " Approver 2
im_case->set_single_attribute_value(
im_srmadid = lc_dcd_approver2
im_value = CONV #( lv_two_approver_grp ) ).
CATCH cx_srm_framework .
CATCH cx_scmg_case_attribute .
ENDTRY.

ELSE. " Case Change mode

TRY. "Check if changed?
IF im_case->is_changed( ) = abap_true.
* Check if current user is not in approval hierarchy group
IF ( lv_person_resp_grp IS NOT INITIAL
AND sy-uname NOT IN lt_person_resp_grp ) " Person Responsible
OR ( lv_one_approver_grp IS NOT INITIAL
AND sy-uname NOT IN lt_one_approver_grp ) " Approver 1
OR ( lv_two_approver_grp IS NOT INITIAL
AND sy-uname NOT IN lt_two_approver_grp )." Approver 2

* Display message that user not authorized to save changes
MESSAGE i025(z0000fi).

TRY.
* Undo attribute changes if changed
im_case->undo_attribute_changes( ).
CATCH cx_srm_framework .
ENDTRY.
ENDIF.

ENDIF.
CATCH cx_srm_framework .
ENDTRY.

ENDIF.
Bohdan
Active Contributor
0 Kudos
Hi Noman,

Thank you for detailed suggestion ! So far, I do not have a clear idea what might be wrong with the BADI triggering in this particular case and to be honest, when I was working with this BADI, I focused most efforts on the dispute management. With regards to DCD-cases, the logic I've implemented was relatively simple (setting of default values during creation, assignment of users & e-mail notifications).

Eventually, there are just two solutions:

  • extensive debug (which would be complicated considering that the management of DCD-case is essentially a Fiori-landscape).

  • to issue an OSS-incident and let SAP check on that. Maybe there is indeed a bug in the program. Considering that this (i.e. DCD-case) is  a relatively fresh technology, I'd not be surprised.


Anyway, please let me know the results of your investigation ! I'd be really interested to know what is the issue.

Regards,

Bohdan
0 Kudos

Hi Bohdan,

I did try to do some deep analysis by extensive Debugging. I found out that the SD document gets released but just the document status in UKM_CASE is not updated when we use this BAdI. Without the BAdI implementation the standards process this gets updated.

Now I want to get details on the f_code in this BAdI when the case is released. It does get called but in order to set it to released I need to know the event details. I found out CL_IM_UKM_FCODE_DCD / Implementation UKM_FCODE_DCD_SD of BAdI SCMG_CASE_FCODE_S where our enhancement is also called internally at lo_class_wrapper->check_and_save_case and afterwards the SD document is also released and updated.

But somehow this does not update the document status to released if our custom implementation is assigning the approvers during automatic case creation. I just need to know if there is a way to determine when release or reject is selected so that I can set the attribute to released accordingly.

Do you happen to know if we can do that in some way?

Thanks.

Bohdan
Active Contributor
0 Kudos
Hi Noman,

As I mentioned earlier, I really do not have that much experience with the DCD-cases. I'll try to test this process in my system and will see how it works in terms of BADI triggering.

Regards,

Bohdan
mhughes2
Participant
0 Kudos

@Bohdan 

I have a question about changing the user who created an active Case ID but the user is no longer in SAP.     (I am in security and we have audit restrictions of recreating terminated users in PRD).

It looks like we could utilize the "SET_SINGLE_ATTRIBUTE_VALUE" method to create a customized update process to change the value of the "processor" (i guess is would be) from the old value to a new value and potentially do it off of the Case GUID which is unique.

I was going to pitch this idea to my development team but wanted to get your thoughts on this as a way to correct the dreaded "UDM_DISPUTE Error - Entry XXXXX does not exist in USR02"

If not can you think of another solution besides adding back the ID in the SYSTEM?

From above:


There is also a setter method that allows you to change the value of case attributes. You can use the method SET_SINGLE_ATTRIBUTE_VALUE to change the value of the case attribute. Source code below shows how to update the value of the case title:

try.
  im_case->set_single_attribute_value(
    im_srmadid = im_case->case_title
    im_value   = 'Case Title: New Value' ).
  catch cx_srm_framework .
  catch cx_scmg_case_attribute .
endtry.


Big advantage of using this BAdI is that you can update many different attributes within the same enhancement. FSCM module provides a lot of different BAdIs that can be used to update only one specific attribute (e.g., case priority, external references, processor etc.).

 

Labels in this area