{% extends "base.html" %} {% import "_bank.html" as bank with context %} {% block title %}{{ statement.statement_id }} — painfree{% endblock %} {% block body %} {# A `pain.002` read against the payment it answers. The rows below are the *message's*, not the report's. A bank reports by exception, so the report for a file it took whole names no transaction at all and rendering what it carries would leave this page empty in the ordinary case. The three status levels stay three. Every answer says which level it was read at, because a status inherited from the file is not the bank having spoken about that payment, and a page that let those look alike would be telling an operator something the document does not say. #} {% set known = status_codes.get(outcome.status or '') %} {# One chip per status, tinted by what this service does with the code rather than by the code itself: `PART` and `ACSP` are both acknowledgements and a reader should not have to know the vocabulary to see that. #} {% macro verdict(status) %} {% set code = status_codes.get(status or '') %} {{ status }} {%- endmacro %}

{%- if known and known.disposition == 'accepts' %}{{ t('response.heading_accepted') }} {%- elif known and known.disposition == 'partial' %}{{ t('response.heading_partial') }} {%- elif known and known.disposition == 'refuses' %}{{ t('response.heading_refused') }} {%- elif known %}{{ t('response.heading_undecided') }} {%- elif outcome.status %}{{ t('response.heading_unknown') }} {%- else %}{{ t('response.heading_silent') }}{% endif %}

{% if order %}{{ t('statements.reports_on') }} {{ order.order_id }}. {% elif statement.order_id %}{{ t('statements.reports_on') }} {{ statement.order_id }}. {% endif %} {{ statement.message_type }}. {{ t('response.received') }} {{ statement.ingested_at | moment }}.

{# What the report does to the order, in the words of the table the reconciler decides with. The code and the ISO name are the standard's; the sentence beside them is this service's gloss and is what a locale changes. #}
{% if known %}

{{ outcome.status }} {{ known.name }}: {{ t.maybe('status_code.' ~ known.code, known.meaning) }}.

{% if known.disposition == 'accepts' %}

{{ t('response.not_settled') }}

{% elif known.disposition == 'partial' %}

{{ t('response.part_note') }}

{% elif known.disposition == 'undecided' %}

{{ t('response.undecided_note') }}

{% endif %} {% elif outcome.status %}

{{ outcome.status }} {{ t('response.unknown_note') }} {{ t('order.status_code_page') }}.

{% else %}

{{ t('response.silent_note') }}

{% endif %}
{% if not statement.order_id %}

{{ t('response.unmatched_heading') }} {{ t('statement.no_order') }} {{ statement.identification or '—' }}.

{{ t('response.unmatched_body') }}

{% endif %} {# The three levels, side by side, with the one that decided marked. Nothing here is derived from anything else here: a level the bank left out says so rather than repeating the level above it. #}
{{ t('response.level_group') }} GrpSts
{% if report.group.status %}{{ verdict(report.group.status) }} {% else %}{{ t('response.not_reported') }}{% endif %} {% if outcome.status %}{{ t('response.decides') }}{% endif %}
{{ t('response.group_is_headline') }}
{{ t('response.level_payment') }} PmtInfSts
{% for block in report.blocks %} {% if block.answer.status %}{{ verdict(block.answer.status) }} {% else %}{{ t('response.not_reported') }}{% endif %} {% if block.payment_information_id %}{{ block.payment_information_id }}{% endif %} {% else %} {{ t('response.not_reported') }} {% endfor %}
{{ t('response.level_transaction') }} TxSts
{% if report.named %} {{ t('order.accepted_count') }} {{ outcome.accepted | count }} {{ t('order.rejected_count') }} {{ outcome.rejected | count }} {% else %}{{ t('response.not_reported') }}{% endif %}
{{ t('response.by_exception') }}
{% if answers %}
{# Two blocks of columns, and the boundary between them is the point of the table: the left half is the message this service sent and the right half is what the bank wrote about it. Neither is derived from the other. #} {% for transfer, answer in answers %} {% endfor %}
{{ t('response.we_sent') }} pain.001 {{ t('response.bank_said') }} {{ statement.message_type }}
{{ t('order.creditor') }} {{ t('order.amount') }} {{ t('order.requested_execution') }} {{ t('order.status') }} {{ t('order.reason') }}
{{ transfer.creditor.name or '—' }} {% if transfer.creditor.iban %}
{{ transfer.creditor.iban }}{% endif %} {% if transfer.remittance %}
{{ transfer.remittance }}{% endif %} {% if transfer.reference %}
{{ transfer.reference_type }} {{ transfer.reference }}{% endif %}
{{ transfer.amount | amount(transfer.currency) }} {% if transfer.end_to_end_id %}
{{ transfer.end_to_end_id }}{% endif %}
{{ payment.execution_date | day }} {% set code = answer.code %} {% if answer.status %} {{ verdict(answer.status) }} {%- if answer.inherited %}{{ code.name if code else t('response.unknown_status') }}, {% if answer.level == 'payment' %}{{ t('response.from_payment') }}{% else %}{{ t('response.from_group') }}{% endif %} {%- else %}{{ code.name if code else t('response.unknown_status') }}{% endif %} {% if answer.accepted_at %}{{ t('response.accepted_at') }} {{ answer.accepted_at }}{% endif %} {% else %}{{ t('response.unanswered') }}{% endif %} {% for reason in answer.reasons %}
{% if reason.get('code') or reason.get('proprietary') %}{{ reason.get('code') or reason.get('proprietary') }}{% endif %} {{ bank.quiet((reason.get('additional_information') or []) | join(' ')) }}
{% if reason.get('originator') %}{{ reason.get('originator') }}{% endif %} {% else %}—{% endfor %}
{# What the bank refused, in money. The counts on the report are the bank's own and are counted by exception; this is counted over the message. #} {% for total in totals %} {% endfor %}
{{ t('response.sent') }} {{ total.count | count }} · {{ total.sent | amount(total.currency) }} {% if total.refused_count %}
{{ t('order.rejected_count') }} {{ total.refused_count | count }} · {{ total.refused | amount(total.currency) }} {% endif %}
{# The bank restating the count and the control sum is a check, not a field: two records of one message that can disagree, and a disagreement is the report being about something else. A bank that restates neither says so rather than printing two dashes. #} {% set sent_count = payment.transfers | length %}

{% if original.get('transactions') or original.get('control_sum') %} {% if original.get('transactions') and original.get('transactions') | int == sent_count %}{{ t('response.restated_matches') }} {% else %}{{ t('response.restated_differs') }}{% endif %} {% else %}{{ t('response.not_restated') }}{% endif %}

{{ t('bank.note') }}

{% elif statement.order_id %}

{%- if sees_payment %}{{ t('response.no_transfers') }} {%- else %}{{ t('response.needs_payments_read') }}{% endif %}

{% endif %} {% if unsent %}

{{ t('response.unsent_heading') }} {{ t('response.unsent_body') }}

{% for reference in unsent %}{{ reference }} {% endfor %}

{% endif %} {# The payload is the normalised document: an interchange shape whose field names and values are the same in every locale. It is kept, closed, because the page above is a reading of it and a reading is not the record. #}
{{ t('statement.normalised') }}
{{ t('common.connection') }}{{ statement.connection_id }}
{{ t('statement.identification') }}{{ statement.identification or '—' }}
{{ t('order.reported_at') }}{{ statement.created_at | moment }}
{{ t('statement.download_run') }}{{ statement.run_id or '—' }}
{{ t('statement.content_hash') }}{{ statement.content_hash }}
{{ statement.payload | pretty_json }}
{% endblock %}