Dear SAPers!
With my blog post “Enhancements in EBS – BADI FIEB_CHANGE_BS_DATA” I’ve started a series of posts around enhancements in electronic bank statement processing. This post is a continuation of this series. Please check out my previous post, because this post relies on the logic to split the implementation into two classes, which was described earlier.
I’ve described in my original post how to use this BADI to update some of the attributes for accounting documents e.g., Reference (XBLNR), Assignment (ZUONR), Cost center (KOSTL), Business area (GSBER), Profit center (PRCTR) and Line text (SGTXT). These attributes are included into the parameter C_FEBEP of the BADI interface and you can easily change them. The question is: can we use this BADI to adjust other attributes of accounting documents? The short answer is yes. My explanation is specific to Ukrainian legal specifics across, but the solution in essence is universal and can be used for any other country.
Let’s return to my original example with incoming down-payment. Down-payments in Ukraine should be posted with VAT on so called gross-basis and require assignment of the tax code and ideally speaking a reference to sales order or pro-forma invoice (i.e., local VAT requirements). Standard SAP solution (i.e., add-of for Ukraine) allows the references to be maintained in the fields BSEG-VBEL2 for sales order or BSEG-XREF2 for proforma invoices. Both fields are not available in the BADI interface. Let’s see how we can fill them automatically based on the details from note to payee.
I’ve prepared the following bank statement for the purpose of this blog post. As you can see, there is a reference to a pro-forma invoice 90000475 in the bank statement’s note to payee:
I use standard billing type F5 to generate a proforma invoice. This billing type does not generate any accounting postings but can be used to generate a print form i.e., preliminary invoice that is used to request the down-payment from the customer. The requirement is to save this number into the field BSEG-XREF2 for a customer down-payment posting.
Note: I’m working on another blog post that explores how to automate handling of incoming down-payments based on down-payment requests. I’ll update the link here upon completion.
The interface of the BADI allows you to fill in and pass into an accounting document up to three fields. I’m not sure what is the official name for this, but let me call it “BDC-approach“. I’ve stumbled on this idea when I was exploring various capabilities of the search string functionality. I’m attaching the screenshot of the standard SAP documentation for a search string that provides some explanation on this topic.
The idea is simple. If you want to fill some field, you should specify the following three attributes:
Type of the field is essentially a specification which says which posting area is impacted and which line should be updated. X refers to the ID of these fields. As I mentioned you can pass up to three different fields, therefore X is just a sequential number 1, 2 or 3.
For the purposes of this post, I’ve added a couple of additional methods into the BADI implementing class. I also added a class attribute C_BDC to store constant values for the BDC field types.
class zcl_ua_fieb_change_bs_data definition
public
final
create public .
public section.
types:
tt_febcl type standard table of febcl with default key .
class-methods process_line
importing
!iv_note_to_payee type string
changing
!cs_febko type febko
!cs_febep type febep
!ct_febcl type standard table .
protected section.
private section.
constants:
begin of c_bdc,
first_line_1st_area type febep-fkoa1 value '0',
first_line_2nd_area type febep-fkoa1 value '1',
second_line_1st_area type febep-fkoa1 value '2',
second_line_2nd_area type febep-fkoa1 value '3',
end of c_bdc.
class-methods handle_inc_down_payment
importing
iv_note type string
changing
cs_febep type febep.
class-methods get_pro_forma_invoice_nr
importing
iv_note type string
returning
value(rv_vbeln) type vbeln_vf.
class-methods is_valid_vbeln
importing
iv_vbeln type vbeln
returning
value(rv_yes) type abap_bool.
class-methods get_default_tax_code
returning
value(rv_mwskz) type mwskz.
endclass.
Now let’s come to the implementation details. The logic is triggered from the main method PROCESS_LINE. First, I call a method that caches a default posting rule for down-payment posting. Please check my previous post “Update of posting rules in BADI FIEB_CHANGE_BS_DATA” for more details on this method. Next, I call a dedicated method HANDLE_INC_DOWN_PAYMENT to update the attributes for incoming down-payment:
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Public Method ZCL_UA_FIEB_CHANGE_BS_DATA=>PROCESS_LINE
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_NOTE_TO_PAYEE TYPE STRING
* | [<-->] CS_FEBKO TYPE FEBKO
* | [<-->] CS_FEBEP TYPE FEBEP
* | [<-->] CT_FEBCL TYPE STANDARD TABLE
* +--------------------------------------------------------------------------------------</SIGNATURE>
method process_line.
cache_default_posting_rules( cs_febko ).
handle_inc_down_payment(
exporting
iv_note = iv_note_to_payee
changing
cs_febep = cs_febep ).
endmethod.
Method HANDLE_INC_DOWN_PAYMENT handles the update of the posting rule and updates three attributes for the accounting document: reference to proforma invoice (BSEG-XREF2), default tax code (BSEG-MWSKZ) and a flag “Calculate tax” (BKPF-XMWST). Source code below provides an example how to use these fields:
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_UA_FIEB_CHANGE_BS_DATA=>HANDLE_INC_DOWN_PAYMENT
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_NOTE TYPE STRING
* | [<-->] CS_FEBEP TYPE FEBEP
* +--------------------------------------------------------------------------------------</SIGNATURE>
method handle_inc_down_payment.
" Adjust the posting rule
cs_febep-vgint = ms_default_posting_rules-inc_down_payment.
" Extract the reference to proforma invoice number
data lv_vbeln type vbeln.
lv_vbeln = get_pro_forma_invoice_nr( iv_note ).
" Fill the reference to proforma invoice number
if lv_vbeln <> ''.
cs_febep-fnam1 = 'BSEG-XREF2'.
cs_febep-fval1 = lv_vbeln.
cs_febep-fkoa1 = c_bdc-second_line_2nd_area.
else.
return.
endif.
" Get tax code for a down-payment posting
data lv_tax_code type mwskz.
lv_tax_code = get_default_tax_code( ).
" Fill tax code & the flag "Calculate tax"
if lv_tax_code <> ''.
cs_febep-fnam2 = 'BSEG-MWSKZ'.
cs_febep-fval2 = lv_tax_code.
cs_febep-fkoa2 = c_bdc-second_line_2nd_area.
cs_febep-fnam3 = 'BKPF-XMWST'.
cs_febep-fval3 = 'X'.
cs_febep-fkoa3 = c_bdc-second_line_2nd_area.
endif.
endmethod.
The logic to retrieve proforma invoice number is implemented in a separate method GET_PRO_FORMA_INVOICE_NR. This method relies on the regular expression to recognize the proforma invoice number as the following pattern: 8-digit number that starts with 90, where numbers might be separated by a space. Once the number is found, the additional utility method IS_VALID_VBELN is triggered to check if this proforma invoice exists in the database.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_UA_FIEB_CHANGE_BS_DATA=>GET_PRO_FORMA_INVOICE_NR
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_NOTE TYPE STRING
* | [<-()] RV_VBELN TYPE VBELN_VF
* +--------------------------------------------------------------------------------------</SIGNATURE>
method get_pro_forma_invoice_nr.
" Utility method to extract proforma invoice number
" Proforma invoice numbers begin with 90, have 8 digits and might be separated by space
constants: lc_proforma_pattern type string value '(?=90)((\s?\d\s?){8})'.
" Find numbers that might be proforma numbers
data lv_proforma_nr type string.
find regex lc_proforma_pattern in iv_note
ignoring case
submatches lv_proforma_nr.
if sy-subrc is not initial.
return.
else.
condense lv_proforma_nr no-gaps. " Remove all spaces
unpack lv_proforma_nr to rv_vbeln. " Add leading zeros i.e. padding
endif.
" Check if proforma number exists in the system
if is_valid_vbeln( rv_vbeln ) = abap_false.
clear: rv_vbeln.
endif.
endmethod.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_UA_FIEB_CHANGE_BS_DATA=>IS_VALID_VBELN
* +-------------------------------------------------------------------------------------------------+
* | [--->] IV_VBELN TYPE VBELN
* | [<-()] RV_YES TYPE ABAP_BOOL
* +--------------------------------------------------------------------------------------</SIGNATURE>
method is_valid_vbeln.
data lv_vbeln type vbeln.
select single vbeln
from vbrk
into lv_vbeln
where vbeln = iv_vbeln.
if sy-subrc = 0.
rv_yes = abap_true.
endif.
endmethod.
Method GET_DEFAULT_TAX_CODE retrieves the default output tax code for incoming down-payment. An important note here: this example is quite simple, and it assumes that the company’s business operations are subject to one tax rate only. In some cases that might be true, while in others you might need more complicated logic. The source code for the method is as follows:
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_UA_FIEB_CHANGE_BS_DATA=>GET_DEFAULT_TAX_CODE
* +-------------------------------------------------------------------------------------------------+
* | [<-()] RV_MWSKZ TYPE MWSKZ
* +--------------------------------------------------------------------------------------</SIGNATURE>
method get_default_tax_code.
constants: lc_country type land1 value 'UA'.
constants: lc_group_version type t007k-version value 'EBS'.
" Select the tax code from the grouping version EBS
select single mwskz
from t007k
into rv_mwskz
where land1 = lc_country
and version = lc_group_version.
endmethod.
What is behind this code? Where do we store this default tax code? My proposal is to use the transaction OBCG. This transaction allows you to maintain custom tax grouping version for a variety of purposes. There are some pre-defined tax grouping versions for various country-specific VAT reports, but you are free to define your own versions. I’ve defined a tax grouping version EBS:
In the configuration I added one tax code with a transaction key MWS and a grouping number 1. For the purposes of the bank statement enhancement, neither the transaction key, nor the grouping number play any role. You can define them freely.
You are essentially using the benefits of configurable constants i.e., you define tax grouping version as a local constant in the enhancement (e.g. EBS), but the actual value (i.e., tax code I2) is configurable.
For the purposes of this post, I’m using the posting rule Z+DP for incoming down-payments. Posting rule Z+CP is a posting for customer’s post payment. We’re trying to update the second line of the accounting posting in the second posting area. It corresponds to the credit posting to the customer.
Screenshot below shows the posting log for bank statement upload:
Accounting document for the down-payment looks as follows. The tax code as well as the reference to proforma invoice were filled automatically by the BADI:
Screenshot below shows how the values were updated in the bank statement:
I have used this approach many times to update various attributes in the accounting postings associated with the bank statement. The main drawback of this solution is that it allows you to adjust only three other fields in addition to those that are available in the definition of the attribute C_FEBEP. If you need to update more fields or introduce more complicated logic e.g. to split the posting into several lines, you will have to explore other enhancement spots in particular BADI FEB_BADI. I also plan another big blog post on this BADI, so stay tuned 🙂
Also, you have to be careful about this mechanism. This approach works and is in general quite reliable. But I encountered situations, where I properly filled the BDC-variables in the enhancement, but for some reason they were not passed to accounting interface. So before you commit to a full scale development, please implement a simple proof-of-concept to ensure that your intended solution works properly.
I hope that this post was useful and you have a better understanding of this enhancement mechanism.
Regards,
Bohdan