Hi @Lohra!
First and foremost, my apologies for the delayed reply, I just got back from holiday
.
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