Introduction
Direct debit is a financial transaction, where the company sends the instruction to the bank to collect the payment directly from the debtor’s bank account. Properly implemented direct debit simplifies the debt collection for the company. This process is well described / documented. But as a rule, the documentation covers the regular process i.e., when the bank managed to collect the payment. Direct debit returns (cancellations / rejections) are not described properly. This post aims to fill this knowledge gap.
Process Overview
Screenshot below provides high-level overview of the process around direct debit:
Direct debit is initiated in SAP via automated payment program (i.e., F110). The program generates the payment document that credits the customer account. This payment document automatically clears open items on customer’s account and generates an open item on clearing GL account for incoming bank payments. If everything goes fine, the bank will collect the payment from the customer and show the associated receipt in a bank statement. This is a simplified explanation, but I hope it provides a good explanation. Screenshot below provides an overview of the typical accounting postings.
Let’s now consider the case of direct debit return. The return might happen due to a variety of reasons e.g., insufficient funds, incomplete / erroneous direct debit mandate etc. The bank charges a return fee for each operation. What is even more complicated, your bank might provide the information in bank statement in aggregated format i.e., operation amount (1005,00 EUR) will include the original payment amount (1000,00 EUR) + return fee (5,00 EUR). Screenshot below shows a sample bank statement with such aggregated operation.
The screenshot below shows the expected postings in the bank statement with regards to direct debit return. Though we have only one line in bank statement, the system should be able to generate two separate postings:
- Direct debit return payment with 2 posting areas.
- Bank fee associated with direct debit return.
Let’s see how this process can be implemented in the system.
Process Flow in the System
Automatic payment program generated a payment document 2000000006 for total amount of 1000,00 EUR. This payment document number will be provided in the note to payee for the returned direct debit in the bank statement. See the example above, where this value is highlighted.
Screenshot of the payment document is provided below:
This payment run automatically cleared open item associated with the customer invoice 1800000007:
The interval of accounting document numbers should include the number range for payment documents. Screenshot below shows the appropriate selection screen block in the transaction FF_5.
If you work with S4 HANA system and use Fiori App F1680 “Manage Incoming Payment Files”, you’ll need to configure the parameter set, which stores the number ranges associated with bank statement.
Screenshot below shows the import log associated with upload of this bank statement. As you can see, the program split one item into two different items, assigned different posting rules and automatically posted the documents in both posting areas.
As you can see, the log for the second posting area shows that the program identified original payment document 2000000006/2023. The clearing was reset automatically. Besides, as you can see, the report shows the open item for customer invoice 1800000007. This invoice was cleared during the payment run, but is re-opened now.
The screenshot below shows the posting associated with return of the direct debit:
The screenshot below shows both line items in bank statement (transaction FEBAN/FEB_BSPROC):
What is interesting, the upload program generates a binary relationship between the original line item and the new line for bank charges. You can review this relationship by double clicking on the line in bank statement and navigating to the menu “Relationships”:
The program will display the related line in the dialog window:
If you’re using S4 HANA and Fiori App F1520 “Reprocess Bank Statement Items” for post-processing of bank statement items, you will not be able to see this relationship. This functionality was not implemented in Fiori. At least it is available as of version 9.0.21 of this app.
System Configuration
Use the following menu path or maintenance view VC_FIEB_RETURNS (via SM34) to configure the processing of returned direct debits:
SPRO → Financial Accounting → Bank Accounting → Business Transactions → Payment Transactions → Electronic Bank Statement → Configure Returns Processing.
Returns of direct debits, as a rule, are displayed with dedicated business transaction codes (BTC-codes) in bank statement. You need to identify these BTC-codes and assign them to internal return reasons (e.g. ZR1). In my case, BTC code is 108 and I use only one internal reason code.
External bank statement reason is provided in the note to payee in subfield 34. Return reason code in my example is 909. External reason code is stored in the field FEBEP-KKREF.
Assign two posting rules for each internal return reason: one rule for posting of returned direct debit, another for return fees. Also, activate the checkbox to reset the clearing of the payment document.
Screenshot below shows the settings for posting rules (in OT83) that were used for this example:
You can define additional automatic changes of the re-opened customer invoices. You can set the dunning / payment block, change payment method, or delete the payment terms. If these options are not enough, you can use BADI FIEB_RET_CHANGE_DOC to change other attributes of the open item.
Additionally, you can change direct debit mandate for the customer e.g., by setting its status to cancelled or obsolete.
The last component of the solution is to implement the BADI FIEB_RETURNS_ADDIN (available as of release 4.70). The purpose of this BADI is to fetch / calculate the amount of the return charges associated with the returned direct debit.
This BADI receives header of bank statement (I_FEBKO), line details (I_FEBEP) as well as a table with note to payee (T_FEBRE). Essentially, the enhancement should parse the lines associated with the note to payee to fetch the amount of the return charges. In my enhancement, I’ve prepared a utility method (i.e., GET_NOTE_TO_PAYEE_AS_STRING) within the BADI implementing class that transforms this table into a string. Once it is a string, you can define a regular expression to search for the charge amount.
Important! The BADI should return to the calling program the amount of return charges as a negative amount. Sample source code for the BADI is provided below:
class zcl_im_fieb_dd_returns definition
public
final
create public .
public section.
interfaces if_ex_fieb_returns_addin .
protected section.
private section.
class-methods get_note_to_payee_as_string
importing
!it_febre type any table
returning
value(rv_note_to_payee) type string .
endclass.
class zcl_im_fieb_dd_returns implementation.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Static Private Method ZCL_IM_FIEB_DD_RETURNS=>GET_NOTE_TO_PAYEE_AS_STRING
* +-------------------------------------------------------------------------------------------------+
* | [--->] IT_FEBRE TYPE ANY TABLE
* | [<-()] RV_NOTE_TO_PAYEE TYPE STRING
* +--------------------------------------------------------------------------------------</SIGNATURE>
method get_note_to_payee_as_string.
" Note to payee should not be empty
if lines( it_febre ) = 0.
return.
endif.
" Prepare string representation of note to payee
field-symbols: <line> type febre.
loop at it_febre assigning <line>.
if <line> is not assigned.
return.
endif.
concatenate rv_note_to_payee <line>-vwezw into rv_note_to_payee.
endloop.
condense rv_note_to_payee.
endmethod.
* <SIGNATURE>---------------------------------------------------------------------------------------+
* | Instance Public Method ZCL_IM_FIEB_DD_RETURNS->IF_EX_FIEB_RETURNS_ADDIN~CHANGE_RETURN_CHARGES
* +-------------------------------------------------------------------------------------------------+
* | [--->] I_FEBKO TYPE FEBKO
* | [--->] I_FEBEP TYPE FEBEP
* | [--->] T_FEBRE TYPE STANDARD TABLE
* | [<---] E_SUBRC TYPE SY-SUBRC
* | [<---] E_MSGID TYPE SY-MSGID
* | [<---] E_MSGTY TYPE SY-MSGTY
* | [<---] E_MSGNO TYPE SY-MSGNO
* | [<---] E_MSGV1 TYPE SY-MSGV1
* | [<---] E_MSGV2 TYPE SY-MSGV2
* | [<---] E_MSGV3 TYPE SY-MSGV3
* | [<---] E_MSGV4 TYPE SY-MSGV4
* | [<-->] C_RETURN_CHARGES TYPE FIEB_RET_CHARGES
* +--------------------------------------------------------------------------------------</SIGNATURE>
method if_ex_fieb_returns_addin~change_return_charges.
" Get string representation of note to payee
data: lv_note_to_payee type string.
lv_note_to_payee = get_note_to_payee_as_string( t_febre ).
if lv_note_to_payee = ''.
return.
endif.
" Use regular expression to fetch the amount of return fees
constants lc_fee_pattern type string value 'DRF\+(\d{5,15}.\d{2})'.
data lv_return_fee_amt type string.
find regex lc_fee_pattern in lv_note_to_payee
ignoring case
submatches lv_return_fee_amt.
" Format the resulting value
if sy-subrc = 0 and lv_return_fee_amt <> ''.
shift lv_return_fee_amt left deleting leading '0'.
replace first occurrence of ',' in lv_return_fee_amt with '.'.
else.
return.
endif.
" Return fee should be passed to calling program with a minus sign
c_return_charges-kwbtr = lv_return_fee_amt.
c_return_charges-kwbtr = c_return_charges-kwbtr * -1.
" Return reason code
c_return_charges-rrext = i_febep-kkref.
endmethod.
endclass.