{% extends "base.html" %} {% load erp_tags %} {% block title %}{{ page_title }}{% endblock %} {% block content %}
Import QBO exports

Upload cleaned chart-of-accounts and/or transaction files. Company selection is required — accounts and entries are company-scoped and the wrong one corrupts the books.

{% if form.non_field_errors %}
{{ form.non_field_errors.0 }}
{% endif %}
{% csrf_token %}
{{ form.company|add_class:"form-select form-select-sm" }} {% if form.company.errors %}
{{ form.company.errors.0 }}
{% endif %} {% if form.company.help_text %}{{ form.company.help_text }}{% endif %}
{{ form.chart_of_accounts }} {% if form.chart_of_accounts.errors %}
{{ form.chart_of_accounts.errors.0 }}
{% endif %} {% if form.chart_of_accounts.help_text %}{{ form.chart_of_accounts.help_text }}{% endif %}
{{ form.transactions }} {% if form.transactions.errors %}
{{ form.transactions.errors.0 }}
{% endif %} {% if form.transactions.help_text %}{{ form.transactions.help_text }}{% endif %}
{{ form.dayfirst }} {% if form.dayfirst.help_text %}{{ form.dayfirst.help_text }}{% endif %}
{{ form.dry_run }}
Allowed formats

.csv .xlsx .xlsm — accepted.

.xls — legacy Excel, refused (openpyxl cannot read it; re-export as .xlsx or .csv).


Dry run is checked by default. It runs the true import inside a rolled-back transaction so the report shows exactly what would be written before anything commits.

{% if report %}
Import report{% if import_company %} — {{ import_company.name }}{% endif %}
{% if dry_run %} Dry run {% else %} Committed {% endif %}
{% if dry_run_text %}
{{ dry_run_text }}
{% endif %} {% if error_text %}
{{ error_text }}
{% endif %}
Accounts
{{ report.accounts_created }} created
{{ report.accounts_updated }} updated
Entries
{{ report.entries_created }} created
{{ report.entries_updated }} updated
Lines
{{ report.lines_created }} written
{{ report.skipped_zero }} zero-amount skipped
Issues
{{ report.errors|length }} error(s)
{{ report.skipped_unbalanced|length }} unbalanced skipped
{% if report.placeholders_created %}
Placeholder accounts ({{ report.placeholders_created|length }}) — referenced by transactions but absent from the chart:
    {% for name in report.placeholders_created %}
  • {{ name }}
  • {% endfor %}
{% endif %} {% if report.unmapped_detail_types %}
Unknown QBO detail types ({{ report.unmapped_detail_types|length }}, kept as provenance — not guessed):
    {% for t in report.unmapped_detail_types %}
  • {{ t }}
  • {% endfor %}
{% endif %} {% if report.skipped_unbalanced %}
Unbalanced groups — not written ({{ report.skipped_unbalanced|length }}):
    {% for s in report.skipped_unbalanced|slice:":20" %}
  • {{ s }}
  • {% endfor %}
{% if report.skipped_unbalanced|length > 20 %}
…and {{ report.skipped_unbalanced|length|add:"-20" }} more.
{% endif %}
{% endif %} {% if report.errors %}
Errors ({{ report.errors|length }}):
    {% for e in report.errors|slice:":20" %}
  • {{ e }}
  • {% endfor %}
{% if report.errors|length > 20 %}
…and {{ report.errors|length|add:"-20" }} more.
{% endif %}
{% endif %} {% if report_lines %}
Raw report lines
{% for line in report_lines %}{{ line }}
{% endfor %}
{% endif %}
{% endif %} {% endblock %}