{# Import wizard body — swapped via HTMX into #pv-import-wizard. #} {% if error %}

{{ error }}

{% endif %} {% if test_message %}

{{ test_message }}

{% endif %} {% if step == 'upload' %}

Import records from an Excel file (.xlsx) or CSV. Column headers are matched automatically to field names or labels. Related fields (Many2one) accept a record ID or a matching name — countries also accept the ISO code (e.g. US, KE).

Template columns

Drag to reorder columns in the downloaded file.

{% if list_search %} {% endif %} {% if list_order %} {% endif %} {% if list_filters %} {% endif %}
{% if csrf_token %} {% endif %}
{% elif step == 'preview' %}

{{ filename }} — {{ total_rows }} row{{ 's' if total_rows != 1 else '' }} to import. Map each file column to a field, then test or import.

{% if csrf_token %} {% endif %}
{% for idx in range(headers|length) %} {% endfor %} {% if show_row_errors %} {% endif %} {% for row in preview_rows %} {% set line_no = loop.index0 + 2 %} {% set row_error = row_errors.get(line_no, '') %} {% for cell in row %} {% endfor %} {% if show_row_errors %} {% endif %} {% endfor %}
{{ headers[idx] }} Error
{{ cell }}{{ row_error or '—' }}
{% if not show_row_errors and total_rows > preview_rows|length %}

Preview: first {{ preview_rows|length }} data rows.

{% elif show_row_errors and total_rows > preview_rows|length %}

Showing {{ preview_rows|length }} of {{ total_rows }} rows.

{% endif %}
File column Field
{% for idx in range(headers|length) %}
{{ headers[idx] }}
{% endfor %}
{% elif step == 'result' %}
{% if import_rolled_back %}

Import aborted

No records were saved. Fix every error below, then test or import again.

{% elif result.errors and import_had_success %}

Import partially complete

Failed rows are downloading as Excel with an Error column. Fix them and import again.

{% elif result.errors %}

Import failed

No records were imported. Failed rows are downloading as Excel with an Error column.

{% else %}

Import complete

{% endif %} {% if result.errors and not auto_download_failed %}
{% for err in result.errors[:20] %}

Line {{ err.line }}: {{ err.error }}

{% endfor %} {% if result.errors|length > 20 %}

… and {{ result.errors|length - 20 }} more

{% endif %}
{% endif %}
{% if auto_download_failed and payload and result.errors %}

{% endif %}
{% endif %}