CASE: Liquid migration

The purpose of this case is to give a practical example of a liquid migration where data form individual input fields is copied from one period to the next into a fori loop.

For example, when entering an asset in the Hire Purchase scheme, this was initially done as an individual input, we then realised that users wanted to include more than one asset per account/account template and a fori loop was introduced. We couldn’t remove the initial individual inputs as legacy data would then be hidden, so in order to overcome that challenge we made use of a liquid migration with rollforward in order to transfer the data from the individual inputs to the first iteration of the fori.

This case will explain how to roll forward the individual data input fields into the first iteration of fori loop for the next period.

To begin, here is our code as well as the output, you will see the individual inputs at the beginning, followed by a fori loop thereafter for FY 2020.

{% capture current_date %}{{ period.end_date | date:'%Y-%m-%d' }}{% endcapture %}

{% if current_date <= '2020-12-31' %}

    Individual inputs
  
  Asset description: {% input custom.asset.description %}
  Asset value: {% input custom.asset.value as:currency %}
  Purchase date: {% input custom.asset.date | date:"%d/%m/%Y" %}
    
{% endif %}

Fori loop

{% fori item in custom.group %}

Asset description: {% input item.description %}
Asset value: {% input item.value as:currency %}
Purchase date: {% input item.date | date:"%d/%m/%Y" %}

{% endfori %}

The input fields are shown in relation to the code above. E.g. “asset 1” refers to {% input custom.asset.description %} and so on.

If we then move to 2021, the output will be a blank fori loop and no individual inputs. To bring in this legacy data, we will need to go to actions and copy data from the relevant period.

The problem here is that this functionality will only copy the fori loop data but not the individual inputs.

We will need to copy the individual inputs into the first iteration of the fori loop using the rollforward tag outside of the fori loop in our code.

{% rollforward previous_value custom.some.value %}

When updating the code, previous_value will refer to the value we want to roll forward, which in our case is custom.asset.description . The next part of our code, custom.some.value will then refer to our collection name, which in our case is custom.group .

Remember, you will also need to add in here the iteration that you want (i.e. for iteration 1 we will add custom.group.group_1 ) the iteration has to be entered after the namespace “group.”

It should be named as follows:
“namespace_[iteration number]”

Please note: (if the namespace ends in “s” we should remove it for the iteration (e.g. if the collection is custom.employees then our iteration would be custom.employees.employee_1)

You will also add in the key , for the item it relates to, which in our case is description .

So now your code should look like this:

{% rollforward custom.asset.description custom.group.group_1.description %}

We can then use the above format to roll forward all other individual data items above.

Your output will now include the individual inputs, however we will need to rearrange the data in the fori loop, as you can see below (the asset 2 has now disappeared):

To overcome this, we will use the roll forward also inside the fori loop in our code. This will be as we have seen above, however we will now automate the iteration number using the capture tag.

{% capture fori_index %}group_{{ INT(forloop.index+1) }}{% endcapture %}

In the above, we have used forloop.index+1 so that the previously entered first iteration is now moved to a position lower and so on, we use this to avoid hard coding the iterations.

We will then put the fori_index inside our rollforward as follows:

{% rollforward item.description custom.group.[fori_index].description %}

Your output should now appear as expected.

Finally please note, this particular rollforward functionality should only be applicable for periods where the new version runs (i.e. without individual inputs), to do this we will need to include a basic if statement . For the example above, we will only want to roll forward data for periods after 31.12.2020 and therefore the following if statement was included:

{% if fy_to > '2020-12-31' %}
  {% capture fori_index %}group_{{ INT(forloop.index+1) }}{% endcapture %}
  {% rollforward item.description custom.group.[fori_index].description %}
  {% rollforward item.value custom.group.[fori_index].value %}
  {% rollforward item.date custom.group.[fori_index].date %}
{% endif %}

For a more in-depth explanation on rollforward periods please visit the community article here

In summary, the whole code should look like this:

{% capture current_date %}{{ period.end_date | date:'%Y-%m-%d' }}{% endcapture %}
{% assign rfwd_date = rollforward.period.end_date %}
{% capture fy_to %}{{ rfwd_date | date:'%Y-%m-%d' }}{% endcapture %}


{% if current_date <= '2020-12-31' %}

  Individual inputs
  
    Asset description: {% input custom.asset.description %}
    Asset value: {% input custom.asset.value as:currency %}
    Purchase date: {% input custom.asset.date | date:"%d/%m/%Y" %}

{% endif %}

Fori loop

{% fori item in custom.group %}

  Asset description: {% input item.description %}
  Asset value: {% input item.value as:currency %}
  Purchase date: {% input item.date | date:"%d/%m/%Y" %}

  {% if fy_to > '2020-12-31' %}
    {% capture fori_index %}group_{{ INT(forloop.index+1) }}{% endcapture %}
    {% rollforward item.description custom.group.[fori_index].description %}
    {% rollforward item.value custom.group.[fori_index].value %}
    {% rollforward item.date custom.group.[fori_index].date %}
  {% endif %}
  
{% endfori %}


{% if fy_to > '2020-12-31' %}
  {% rollforward custom.asset.description custom.group.group_1.description %}
  {% rollforward custom.asset.value custom.group.group_1.value %}
  {% rollforward custom.asset.date custom.group.group_1.date %}
{% endif %}

Giving the following output: