Repetitive checks within one period

Hi,

We are looking for a Silverfin template that allows us to display a series of recurring checks based on the number of quarters or months in a financial year, regardless of the configured reporting frequency (monthly or quarterly).

A key requirement is that the input fields remain unique per period:
checks completed for Q1 should not be copied or overwritten in Q2, Q3, or Q4. Each period should therefore start with empty input fields.

We have already tried implementing this using a for loop in Liquid. While this correctly repeats the checks visually, the issue is that the same underlying input key is reused, causing values entered for one period to automatically appear in the other periods.

In addition, we would like to know whether there is a robust solution for extended or shortened financial years, where:

  • the number of months or quarters differs from the standard structure (e.g. not exactly 12 months or 4 quarters), and

  • the template can automatically adapt to this without manual adjustments.

Does anyone have an idea how we can technically structure this template in Liquid in such a way that:

  • checks are repeated using a loop,

  • input fields remain fully independent per quarter or month,

  • and extended or shortened financial years are handled correctly?

Thanks in advance!

Hi @Lohra!

First and foremost, my apologies for the delayed reply, I just got back from holiday :blush:.

Why a plain {% for %} loop does not work

When you write something like this:

{% for i in (1..4) %}
  Quarter {{ i }}: {% input custom.number_checks.check_done as:boolean %}
{% endfor %}

Silverfin renders 4 rows visually, but all 4 rows are backed by the exact same storage key (`custom.quarter.check_done`). Checking the box in Q1 will show as checked in Q2, Q3 and Q4 as well because they all point to the same value in the database.

The solution is {% addnewinputs %}

Silverfin provides the {% addnewinputs %} specifically for this situation. When you combine it with an indexed custom namespace inside your loop, each iteration gets its own unique storage slot:

{% for date in periods %}
  {% addnewinputs %}
    {% assign p = custom.checks[forloop.index] %}
  {% endaddnewinputs %}

  {% input p.check_done as:boolean %}

{% endfor %}

What happens here is that custom.checks[forloop.index] resolves to a different namespace on each iteration:

  • Iteration 1 → custom.checks.1.check_done
  • Iteration 2 → custom.checks.2.check_done
  • Iteration 3 → custom.checks.3.check_done
  • and so on…

Each of those is a completely separate value in the database. Checking Q1 has no effect on Q2, Q3, or Q4.

The {% addnewinputs %}...{% endaddnewinputs %} block must wrap the {% assign %} that resolves the indexed namespace, and must sit inside the loop body.

Handling any fiscal year length: period.month_end_dates

Silverfin exposes period.month_end_dates, which returns the real month-end dates for the current fiscal year, no matter how long or short it is.

From that list you can build your quarters dynamically:

  {% for month in period.month_end_dates %}
    {% assign m = month | date:'%-m' %}
    {% if m == '3' or m == '6' or m == '9' or m == '12' %}
      {% assign period_dates = period_dates | append:month | append:"|" %}
    {% endif %}
  {% endfor %}

  {% comment %}If the fiscal year ends on a non-standard month, include that last partial quarter too{% endcomment %}
  {% assign year_end = period.year_end_date %}
  {% unless period_dates contains year_end %}
    {% assign period_dates = period_dates | append:year_end | append:"|" %}
  {% endunless %}

  {% assign periods = period_dates | split:'|' %}

For a monthly ferquency you can skip the filtering entirely and loop directly over period.month_end_dates

Working example

Putting it all together, here is a clean working example that support both quarterly and monthly mode:

{% comment %}Frequency selector{% endcomment %}
{% input custom.period_dates.frequency as:select options:"Quarter|Month" option_values:"quarter|month" %}

{% comment %}Build period list{% endcomment %}
{% stripnewlines %}
  {% assign reporting = custom.period_dates.frequency | default:"quarter" %}

  {% for month in period.month_end_dates %}
    {% assign m = month | date:'%-m' %}
    {% if reporting == "quarter" %}
      {% if m == '3' or m == '6' or m == '9' or m == '12' %}
        {% assign period_dates = period_dates | append:month | append:"|" %}
      {% endif %}
    {% else %}
      {% assign period_dates = period_dates | append:month | append:"|" %}
    {% endif %}
  {% endfor %}

  {% comment %}Non-standard year end: add it if not already a quarter boundary{% endcomment %}
  {% if reporting == "quarter" %}
    {% assign year_end = period.year_end_date %}
    {% unless period_dates contains year_end %}
      {% assign period_dates = period_dates | append:year_end | append:"|" %}
    {% endunless %}
  {% endif %}

  {% assign periods = period_dates | split:'|' %}
{% endstripnewlines %}

{% comment %}Checks table{% endcomment %}
<table class="usr-width-100">
  <thead>
    <tr>
      <th>Period</th>
      <th>Check 1</th>
      <th>Check 2</th>
      <th>Notes</th>
    </tr>
  </thead>
  <tbody>
    {% for date in periods %}
      {% addnewinputs %}
        {% assign p = custom.checks[forloop.index] %}
      {% endaddnewinputs %}
      <tr>
        <td>{{ date | date:'%b %Y' }}</td>
        <td>{% input p.check_1 as:boolean %}</td>
        <td>{% input p.check_2 as:boolean %}</td>
        <td>{% input p.notes %}</td>
      </tr>
    {% endfor %}
  </tbody>
</table>

I hope this helps clarify things for you! Please let me know if anything is still unclear or if you have any further questions.

Kind regards

Delphine

Hi Delphine,

Thank you for your help!

We’ve managed to write a piece of code that is already working quite well.

However, we are still facing an issue regarding the logging of the name and date per check line. Currently, as soon as one line is completed within a given period, all lines in that same period are automatically filled with the same name and date.

Is there a way to resolve this so that each line retains its own individual name and date?

Thank you in advance!