CASE: use arrays into results to call upon data

Whenever you need data that is stored in another template, you might have the urge to access that data directly on the (custom) drop of that particular reconciliation.

Let’s say you have a reconciliation A, in which you create specific data for auditors (very basic: name, type of mandate and tasks):

{% comment %}
-------------
  VARIABLES
-------------
{% endcomment %}

{% comment %}create options for mandate{% endcomment %}
{% assign auditor_options = "A|B|C" %}


{% comment %}
===================
  AUDITOR DETAILS
===================
{% endcomment %}

{% stripnewlines %}
<table class="usr-width-100">
  
  {% comment %}
  ----------
    HEADER
  ----------
  {% endcomment %}
  
  <thead>
    <tr>
      {% comment %}NAME{% endcomment %}
      <th class="usr-width-25"><b>Name</b></th>
      {% comment %}TYPE MANDATE{% endcomment %}
      <th class="usr-width-25"><b>Type of mandate</b></th>
      {% comment %}TASKS{% endcomment %}
      <th class=""><b>Tasks</b></th>
    </tr>
  </thead>
  
  {% comment %}
  -----------
    DETAILS
  -----------
  {% endcomment %}
  <tbody>

    {% fori item in custom.auditors %}
    
      <tr>
        <td class="">{% input item.name %}</td>
        <td class="">{% input item.mandate as:select options:auditor_options %}</td>
        <td class="">{% input item.tasks as:text %}</td>
      </tr>    
    
    {% endfori %}

  </tbody>
</table>
{% endstripnewlines %}

So, when you would need this data again in another reconciliation (let’s call it reconciliation B), your first instinct might be to access that data directly on the custom drop:

{% comment %}link to reconciliation where data is stored{% endcomment %}
{% assign auditor_details = period.reconciliations.auditor_details %}

{% comment %}access custom drop with auditor details{% endcomment %}
{% for item in auditor_details.custom.auditors %}

  {{ item.name }} with mandate {{ item.mandate }} .... 

{% endfor %} 

Obviously, above example is very straight forward and easy, but let’s say (for the sake of argument), you need to add logic to the reconciliation, in which you add a default to the type of mandate:

    {% fori item in custom.auditors %}
    
      {% comment %}from 2022 onwards, we will display a default type of mandate{% endcomment %}
      {% assign check_date = "31/12/2021" | date:"%F" %}
      {% assign period_date = period.end_date | date:"%F" %}
      {% assign add_type_def = false %}
      {% if period_date >= check_date %}
        {% assign add_type_def = true %}
      {% endif %}
      
      {% comment %}create default value for type mandate{% endcomment %}
      {% assign mandate_def = "" %}
      {% if add_type_def %}
        {% assign mandate_def = "A" %}
      {% endif %}
    
      <tr>
        <td class="">{% input item.name %}</td>
        <td class="">{% input item.mandate as:select options:auditor_options default:mandate_def %}</td>
        <td class="">{% input item.tasks as:text %}</td>
      </tr>    
    
    {% endfori %}

As you can see, the following logic has been added:

      {% comment %}from 2022 onwards, we will display a default type of mandate{% endcomment %}
      {% assign check_date = "31/12/2021" | date:"%F" %}
      {% assign period_date = period.end_date | date:"%F" %}
      {% assign add_type_def = false %}
      {% if period_date >= check_date %}
        {% assign add_type_def = true %}
      {% endif %}
      
      {% comment %}create default value for type mandate{% endcomment %}
      {% assign mandate_def = "" %}
      {% if add_type_def %}
        {% assign mandate_def = "A" %}
      {% endif %}

to create a default value for the type of mandate:

{% input item.mandate as:select options:auditor_options default:mandate_def %}

Now, because of this update, it will break the details that are generated in reconciliation B, because you would need to re-build all that logic again (which is also never a good idea, when you find yourself in a situation where you need to duplicate logic).

How can you tackle this in a better and more efficient way, in which you make sure details cannot get broken in reconciliation B?

The better alternative here, would be to push all data of reconciliation A into a result, and then use that result in reconciliation B. Of course, that result would need to be built up in a specific way, so you can access the needed data in a structured manner.

And that’s where arrays come into play: with the push functionality you can create a structured array, store that in a result and access it somewhere else.

For example: “auditor name X; auditor mandate type|auditor name B; auditor ” which means your array should consist of 2 levels:

  • level 1: is all the data related to one auditor, separated in the array with a pipe |
  • level 2: all the individual data of the auditor, separated in the array with ; (meaning the structure in this, is that element 1 would be the name, element 2 would be the type, … )

Let’s create this array first in reconciliation A:

{% comment %}create array{% endcomment %}
{% assign auditor_array = "" | split:"|" %}

Now, for each auditor, you will create another array as well, which you will use to gather all individual data of an auditor:

      {% comment %}create array for info of auditor{% endcomment %}
      {% assign auditor_info = "" | split:";" %}
    
      <tr>
        <td class="">{% input item.name assign:name %}</td>
        <td class="">{% input item.mandate as:select options:auditor_options default:mandate_def assign:mandate %}</td>
        <td class="">{% input item.tasks as:text %}</td>
      </tr>

You also added variables for each data element that is needed, which you will use to push this into our array:

      {% comment %}
      ---------------------------------
        assign data auditor to arrays
      ---------------------------------
      {% endcomment %}
      {% if item.persisted %}
      
        {% comment %}name{% endcomment %}
        {% push name to:auditor_info %}
        {% comment %}type mandate{% endcomment %}
        {% push mandate to:auditor_info %}
        
          {% comment %}push to main array{% endcomment %}
          {% assign auditor_info = auditor_info | join:";" %}
          {% push auditor_info to:auditor_array %}      
      
      {% endif %}

One thing to note here, is that you only want to push data if there is actual data in the loop. Hence you should use if item.persisted (more info here) as this is a fori and it would also create an element in the array for the very last loop in which no data has been entered.

You then store this array in a result.

{% comment %}create result for auditor array so others can access it{% endcomment %}
{% result 'auditor_array' auditor_array %} 

and in reconciliation B, you can now access this result:

{% comment %}access auditor array{% endcomment %}
{% assign auditor_array = auditor_details.results.auditor_array %}

{% for item in auditor_array %}

  {% comment %}create vars{% endcomment %}
  {% assign item_parts = item | split:";" %}
    {% assign name = item_parts[0] %}
    {% assign type_mandate = item_parts[1] %}

  {{ name }} with mandate {{ type_mandate }} ... 


{% endfor %}

Because of this flow, no logic needs to be duplicated. If you would’ve kept the original flow (in which you access data directly), you would always have to keep in mind that reconciliations that use this data, also would need to be updated (which is too dangerous as one could forget to do so).

Using arrays in results is an easy way to make sure maintenance is only needed in the source reconciliation.