IFRS16: Migration of Foreign Currency Assets
A couple of days ago a customer came up with the following question:
Having all data in either SAP ERP Financials or SAP Contract and Lease Management on our SAP ERP system, the question is, how to transfer foreign currency leasing contracts from our old SAP ERP system having no foreign currency depreciation area to our new SAP S/4HANA system. And, in addition to that, how can we reconcile the migrated figures?
My initial idea was, why not use the valuation cashflow and transform it, so it looks like data that is coming from the standard SAP ERP database tables where fixed asset data is stored?
At first sight I thought this should be a no-brainer since all data is recorded somewhere and all what is left to do is some data transformation. However, as often things are different if you start having a closer look…
From my experience the basis of any migration approach for fixed assets in SAP ERP is the relevant content of the according database tables, i.e. ANLC, ANEK, ANEP etc. To keep things simple, I solemnly focus on the aspect of leased assets and how to get the data out of the system, in a format that is alike to how data is recorded in the above mentioned database tables.
Since I want to focus on the principle of the data transformation I assume that there is only one depreciation area that needs to be considered.
Since there is no real-time integration between the cash flow in SAP Contract and Lease Management and the fixed assets in SAP ERP data, migrated figures might be not comparable and the possibility of retro-active changes in SAP Contract and Lease Management can make things even worse. On the other hand, the cash flow in SAP Contract and Lease Management is the best we have when it comes to foreign currency figures that are not posted in SAP ERP as part of fixed asset accounting.
In other words, what I present here is not a 100% solution but it is better than just using fixed asset data and performing a foreign currency migration on a defined key date.
Having a closer at the cashflow data from SAP Contract and Lease Management that generated in a valuation run it shows that despite of the deviating format nearly all necessary information is available to obtain an output similar to what is recorded e.g. in the tables ANLC, ANLP and ANEP in SAP ERP.
All cashflow items are recorded in database table VICECFPROCESS. However, it is much more convenient to use the function module API_RE_CE_GET_CASHFLOW to obtain the cashflow, since setting parameter IF_CFNEWEST to ‘X’ allows us to get the latest valid cashflow for a specific contract.
Having a closer look at the cashflow the relevant information for fixed assets,
- APC changes and
could easily be identified using the transaction type from SAP Contract and Lease Management. However, the cashflow type, i.e. field CFTYPE, already classifies items as acquisition, i.e. CFTYPE 1, and depreciation, i.e. CFTYPE 2. Having a closer look to both acquisition items also include impairments whereas depreciation only include normal depreciation. The split between real acquisitions and impairments is also easily by using the reference flow type relation, i.e. REFFLOWREL.
Now, that all information is available to transform the cashflow into the structure of both tables ANLP and ANLC, we are set to perform a year-end data migration. To perform a mid-year migration, however, transactional values, i.e. ANEP records, are still to be generated in the required format.
Starting from the cash flow, the goal is to find the original transaction and enrich the according data.
The tricky part about the transactional data is the asset transaction type since in the cashflow we only have the according transaction type from the SAP Contract and Lease Management. Technical there are two options, either go through the logic that is processed when documents are posted in daily business, or try to identify the asset document. Since customizing is likely to change I decided to take the latter approach.
The steps are:
- Once an accounting document has been created for a valuation cashflow item from database table VICECFRULE
- the according identifier is recorded in this very item and
- the linked record in database table VIRADOCITEM can be identified.
- Using the reference document number from the header record from database table VIRADOC
- the corresponding record in database table ANEK can be looked up and
- finally the line item in ANEP with the asset transaction type is identified.
The import parameters are the company code, the fiscal year – normally the fiscal year of the migration -, the valuation rule and the pseudo-depreciaton area, that is used for the output, in combination with the requested currency.
For productive use the currency will be one where there is no according depreciation area in place, since this is what the whole function module is designed for. For testing purpose, however, I also used the function module in test-mode with the local currency. In this case the exported data should match with what is recorded in the database tables ANLC and ANEP.
So far I was able to test the functionality of the following code in only a few systems, so there might be some glitches left. Especially the impairment has not yet been well tested due to missing data. Beside adaptions on the migration programs are required on your side.
function Z_REFX_GET_ASSET_VALUES. *"---------------------------------------------------------------------- *"*"Local Interface: *" IMPORTING *" REFERENCE(IV_BUKRS) TYPE BUKRS *" REFERENCE(IV_GJAHR) TYPE GJAHR OPTIONAL *" REFERENCE(IV_CERULE) TYPE RECECERULE *" REFERENCE(IV_AFABE) TYPE AFABE_D DEFAULT '99' *" REFERENCE(IV_WAERS) TYPE WAERS *" EXPORTING *" REFERENCE(ET_ANLC) TYPE FAA_T_ANLC *" REFERENCE(ET_ANLP) TYPE AA_T_ANLP *" REFERENCE(ET_ANEP) TYPE FAA_T_ANEP *" EXCEPTIONS *" UNKNOWN_TRANSACTION *"---------------------------------------------------------------------- data: LT_INTRENO type RE_T_INTRENO, LT_CE_CASHFLOW type BAPI_RE_T_CE_CASHFLOW_INT, LS_ANLC type ANLC, LS_ANLP type ANLP, LS_ANEP type ANEP, LV_ASSETOBJ type RECEASOBJNR, LV_DEPPOST type D, LV_DETAILVALIDTO type RECADETAILVALIDTO, LV_ANBTR type ANBTR. clear: ET_ANLC, ET_ANLP, ET_ANEP. * * get relevant contracts * concatenate `AN` IV_BUKRS into LV_ASSETOBJ. LV_ASSETOBJ+6(1) = '%'. * after the latest update the currency is recorded in the cash flow items select distinct INTRENO from VICERULE where ASSETOBJNR like @LV_ASSETOBJ and RULECURR eq @IV_WAERS union * old valuation runs may have the currency not available in the cash flow select distinct VICNCN~INTRENO from VICERULE inner join VICNCN on VICERULE~INTRENO eq VICNCN~INTRENO where VICERULE~ASSETOBJNR like @LV_ASSETOBJ and VICERULE~RULECURR eq '' and VICNCN~RECNCNCURR eq @IV_WAERS order by INTRENO into table @LT_INTRENO. * any contract found check sy-dbcnt gt 0. * get date of last depreciation run select AFBLGJ, AFBLPE up to 1 rows from TABA into @data(LS_TABA) where BUKRS eq @IV_BUKRS order by AFBLGJ descending, AFBLPE descending. endselect. concatenate LS_TABA-AFBLGJ LS_TABA-AFBLPE+1(2) '01' into LV_DEPPOST. LV_DEPPOST = CL_RECA_DATE=>SET_TO_END_OF_MONTH( LV_DEPPOST ). * get highest open year for asset postings select single T093C~LGJAHR from T093C where BUKRS eq @IV_BUKRS into @data(LV_LGJAHR). if SY-SUBRC eq 0. LV_DETAILVALIDTO(4) = LV_LGJAHR. LV_DETAILVALIDTO+4(4) = '1231'. else. * if not defined select all available values LV_DETAILVALIDTO = RECA0_DATE-MAX. endif. * * loop through all relevant contracts * loop at LT_INTRENO into data(LV_INTRENO). call function 'API_RE_CE_GET_CASHFLOW' exporting * ID_BUKRS = * ID_RECNNR = ID_INTRENO = LV_INTRENO * IO_OBJECT = * ID_DETAIL_DATA_FROM = * ID_DETAIL_DATA_TO = * ID_TERMNO = ID_CERULE = IV_CERULE * ID_CFTYPE = * ID_CFSTATUS = * IF_CFNEWEST = ABAP_TRUE importing ET_CE_CASHFLOW = LT_CE_CASHFLOW exceptions ERROR = 1 others = 2. if SY-SUBRC ne 0. continue. endif. * collect values for each year. loop at LT_CE_CASHFLOW assigning field-symbol(<LS_CE_CASHFLOW>) where ASSETOBJNR cp 'AN*'. LS_ANLC = value #( BUKRS = <LS_CE_CASHFLOW>-ASSETOBJNR+2(4) ANLN1 = <LS_CE_CASHFLOW>-ASSETOBJNR+6(12) ANLN2 = <LS_CE_CASHFLOW>-ASSETOBJNR+18(4) ). * use identifier for the pseudeo 'depreciation area' from import parameter LS_ANLC-AFABE = IV_AFABE. LS_ANLC-GJAHR = cond #( when <LS_CE_CASHFLOW>-POSTINGDATE is initial then <LS_CE_CASHFLOW>-DFAELL(4) else <LS_CE_CASHFLOW>-POSTINGDATE(4) ). LV_ANBTR = cond #( when CL_RECDC_FLOW_TYPE=>GET_DETAIL( ID_FLOWTYPE = <LS_CE_CASHFLOW>-BOOK_FLOWTYPE )-SSOLHAB eq 'S' then - <LS_CE_CASHFLOW>-BBWHR else <LS_CE_CASHFLOW>-BBWHR ). case <LS_CE_CASHFLOW>-CFTYPE. when RECE2_CFTYPE-ACQUISITION. if <LS_CE_CASHFLOW>-REFFLOWREL eq RECE3_REFFLOWREL-UNPLANNED_DEPRECIATION or <LS_CE_CASHFLOW>-REFFLOWREL eq RECE3_REFFLOWREL-UNPLANNED_APPRECIATION. * Impairment LS_ANLP = corresponding #( LS_ANLC ). LS_ANLP-AFABER = LS_ANLC-AFABE. LS_ANLP-PERAF = <LS_CE_CASHFLOW>-DFAELL+4(2). LS_ANLP-AAFAP = LV_ANBTR. LS_ANLC-AAFAP = LV_ANBTR. if <LS_CE_CASHFLOW>-DFAELL le LV_DEPPOST. LS_ANLP-AAFAG = LS_ANLP-AAFAP. LS_ANLC-AAFAG = LS_ANLC-AAFAP. endif. collect LS_ANLP into ET_ANLP. " collect periodic value changes else. * APC change LS_ANLC-ANSWL = LV_ANBTR. endif. * Only transactions in the current are of any interest if IV_GJAHR is initial or IV_GJAHR eq <LS_CE_CASHFLOW>-DFAELL(4). LS_ANEP = corresponding #( LS_ANLC ). LS_ANEP-BZDAT = <LS_CE_CASHFLOW>-DFAELL. LS_ANEP-ANBTR = LV_ANBTR. * get original asset transaction type select single ANEP~LNRAN, ANEP~BELNR, ANEP~BUZEI, ANEP~BZDAT, ANEP~BWASL from ANEP inner join ANEK on ANEP~BUKRS eq ANEK~BUKRS and ANEP~ANLN1 eq ANEK~ANLN1 and ANEP~ANLN2 eq ANEK~ANLN2 and ANEP~LNRAN eq ANEK~LNRAN inner join VIRADOC on VIRADOC~PROCESSID eq ANEK~XBLNR inner join VIRADOCITEM on VIRADOC~DOCGUID eq VIRADOCITEM~DOCGUID inner join TIVCERULECC on TIVCERULECC~BUKRS eq ANEP~BUKRS and TIVCERULECC~DEPRAREA eq ANEP~AFABE where VIRADOCITEM~REFGUID eq @<LS_CE_CASHFLOW>-CFGUID and ANEP~BUKRS eq @LS_ANLC-BUKRS and ANEP~ANLN1 eq @LS_ANLC-ANLN1 and ANEP~ANLN2 eq @LS_ANLC-ANLN2 and VIRADOCITEM~OBJNR eq @<LS_CE_CASHFLOW>-ASSETOBJNR and TIVCERULECC~CERULE eq @IV_CERULE into ( @LS_ANEP-LNRAN, @LS_ANEP-BELNR, @LS_ANEP-BUZEI, @LS_ANEP-BZDAT, @LS_ANEP-BWASL ). * skip if no transaction type was found if SY-SUBRC ne 0. CONTINUE. endif. append LS_ANEP to ET_ANEP. endif. when RECE2_CFTYPE-DEPRECIATION. * Ordinary Depreciation LS_ANLP = corresponding #( LS_ANLC ). LS_ANLP-AFABER = LS_ANLC-AFABE. LS_ANLP-PERAF = <LS_CE_CASHFLOW>-DFAELL+4(2). LS_ANLP-NAFAP = LS_ANLC-NAFAP = - LV_ANBTR. if <LS_CE_CASHFLOW>-DFAELL le LV_DEPPOST. LS_ANLP-NAFAG = LS_ANLP-NAFAP. LS_ANLC-NAFAG = LS_ANLC-NAFAP. endif. collect LS_ANLP into ET_ANLP. " collect periodic value changes when others. * should never happen raise UNKNOWN_TRANSACTION. endcase. collect LS_ANLC into ET_ANLC. " collect value changes endloop. endloop. * ensure values are properly sorted for the periodic summarization sort ET_ANLP by BUKRS ANLN1 ANLN2 AFABER GJAHR PERAF. * calculate periodic values loop at ET_ANLP into LS_ANLP. loop at ET_ANLP assigning field-symbol(<LS_ANLP>) where BUKRS eq LS_ANLP-BUKRS and ANLN1 eq LS_ANLP-ANLN1 and ANLN2 eq LS_ANLP-ANLN2 and AFABER eq LS_ANLP-AFABER and GJAHR eq LS_ANLP-GJAHR. if <LS_ANLP>-PERAF gt LS_ANLP-PERAF. add LS_ANLP-NAFAZ to -NAFAG. endif. add LS_ANLP-NAFAZ to <LS_ANLP>-NAFAP. endloop. endloop. * calculate cumulated values loop at ET_ANLC into LS_ANLC. loop at ET_ANLC assigning field-symbol(<LS_ANLC>) where BUKRS eq LS_ANLC-BUKRS and ANLN1 eq LS_ANLC-ANLN1 and ANLN2 eq LS_ANLC-ANLN2 and AFABE eq LS_ANLC-AFABE and GJAHR gt LS_ANLC-GJAHR. add LS_ANLC-ANSWL to <LS_ANLC>-KANSW. add LS_ANLC-NAFAP to <LS_ANLC>-KNAFA. add LS_ANLC-AAFAP to <LS_ANLC>-KAAFA. endloop. endloop. * restrict values to selected fiscal year if IV_GJAHR is not initial. delete ET_ANLC where GJAHR ne IV_GJAHR. endif. sort: ET_ANLC, ET_ANLP, ET_ANEP. endfunction.
So, what do we get calling the above function module?
What we have to think of is how in general in fixed asset accounting transactional figures are migrated, i.e. extracting data from the database tables ANLC, ANLP and ANEP. All what there is to do is to call the above function module using correct import parameters, i.e. the company code, the fiscal year of the migrated figures, the name of the valuation rule, e.g. IFRS16, a currency – likely that of the controlling area, and a deprecation area that must not be part of the chart of depreciation.
The output is three tables, i.e. ANLC, ANLP and ANEP, that just needs to be merged to database extract of theses tables. Focusing on the existing migration programs the existing workaround to generated foreign currency values must be omitted for all fixed assets where there is data available from SAP Contract and Lease Management.
Since the assumption was to only have one depreciation area we are done and the migration does respect both,
- local currency values that are – as before – extracted from the database tables ANLC, ANLP, ANEP, and some others, and
- foreign currency values that – if available – are coming from the SAP Contract and Lease Management, or – as before – are determined elsewise.
I’m curious about your experience in the migration of foreign currency leasing contracts.