Add optional Autotask ID import toggle

This commit is contained in:
Ivo Oskamp 2026-02-19 12:56:45 +01:00
parent 1fb99dc6e7
commit 53b028ef78
5 changed files with 47 additions and 14 deletions

View File

@ -505,6 +505,7 @@ def customers_export():
@roles_required("admin", "operator") @roles_required("admin", "operator")
def customers_import(): def customers_import():
file = request.files.get("file") file = request.files.get("file")
include_autotask_ids = bool(request.form.get("include_autotask_ids"))
if not file or not getattr(file, "filename", ""): if not file or not getattr(file, "filename", ""):
flash("No file selected.", "warning") flash("No file selected.", "warning")
return redirect(url_for("main.customers")) return redirect(url_for("main.customers"))
@ -541,10 +542,11 @@ def customers_import():
# Detect Autotask columns (backwards compatible - these are optional) # Detect Autotask columns (backwards compatible - these are optional)
autotask_id_idx = None autotask_id_idx = None
autotask_name_idx = None autotask_name_idx = None
if "autotask_company_id" in header: if include_autotask_ids:
autotask_id_idx = header.index("autotask_company_id") if "autotask_company_id" in header:
if "autotask_company_name" in header: autotask_id_idx = header.index("autotask_company_id")
autotask_name_idx = header.index("autotask_company_name") if "autotask_company_name" in header:
autotask_name_idx = header.index("autotask_company_name")
for r in rows[start_idx:]: for r in rows[start_idx:]:
if not r: if not r:
@ -582,7 +584,7 @@ def customers_import():
if active_val is not None: if active_val is not None:
existing.active = active_val existing.active = active_val
# Update Autotask mapping if provided in CSV # Update Autotask mapping if provided in CSV
if autotask_company_id is not None: if include_autotask_ids and autotask_company_id is not None:
existing.autotask_company_id = autotask_company_id existing.autotask_company_id = autotask_company_id
existing.autotask_company_name = autotask_company_name existing.autotask_company_name = autotask_company_name
existing.autotask_mapping_status = None # Will be resynced existing.autotask_mapping_status = None # Will be resynced
@ -600,7 +602,10 @@ def customers_import():
try: try:
db.session.commit() db.session.commit()
flash(f"Import finished. Created: {created}, Updated: {updated}, Skipped: {skipped}.", "success") flash(
f"Import finished. Created: {created}, Updated: {updated}, Skipped: {skipped}. Autotask IDs imported: {'yes' if include_autotask_ids else 'no'}.",
"success",
)
# Audit logging # Audit logging
import json import json
@ -609,6 +614,7 @@ def customers_import():
f"Imported customers from CSV", f"Imported customers from CSV",
details=json.dumps({ details=json.dumps({
"format": "CSV", "format": "CSV",
"include_autotask_ids": include_autotask_ids,
"created": created, "created": created,
"updated": updated, "updated": updated,
"skipped": skipped "skipped": skipped
@ -620,4 +626,3 @@ def customers_import():
flash("Failed to import customers.", "danger") flash("Failed to import customers.", "danger")
return redirect(url_for("main.customers")) return redirect(url_for("main.customers"))

View File

@ -585,6 +585,7 @@ def settings_jobs_export():
@roles_required("admin") @roles_required("admin")
def settings_jobs_import(): def settings_jobs_import():
upload = request.files.get("jobs_file") upload = request.files.get("jobs_file")
include_autotask_ids = bool(request.form.get("include_autotask_ids"))
if not upload or not upload.filename: if not upload or not upload.filename:
flash("No import file was provided.", "danger") flash("No import file was provided.", "danger")
return redirect(url_for("main.settings", section="general")) return redirect(url_for("main.settings", section="general"))
@ -621,14 +622,17 @@ def settings_jobs_import():
if not cust_name: if not cust_name:
continue continue
# Read Autotask fields (backwards compatible - optional) autotask_company_id = None
autotask_company_id = cust_item.get("autotask_company_id") autotask_company_name = None
autotask_company_name = cust_item.get("autotask_company_name") if include_autotask_ids:
# Read Autotask fields (backwards compatible - optional)
autotask_company_id = cust_item.get("autotask_company_id")
autotask_company_name = cust_item.get("autotask_company_name")
existing_customer = Customer.query.filter_by(name=cust_name).first() existing_customer = Customer.query.filter_by(name=cust_name).first()
if existing_customer: if existing_customer:
# Update Autotask mapping if provided # Update Autotask mapping only when explicitly allowed by import option.
if autotask_company_id is not None: if include_autotask_ids and autotask_company_id is not None:
existing_customer.autotask_company_id = autotask_company_id existing_customer.autotask_company_id = autotask_company_id
existing_customer.autotask_company_name = autotask_company_name existing_customer.autotask_company_name = autotask_company_name
existing_customer.autotask_mapping_status = None # Will be resynced existing_customer.autotask_mapping_status = None # Will be resynced
@ -747,7 +751,7 @@ def settings_jobs_import():
db.session.commit() db.session.commit()
flash( flash(
f"Import completed. Customers created: {created_customers}, updated: {updated_customers}. Jobs created: {created_jobs}, updated: {updated_jobs}.", f"Import completed. Customers created: {created_customers}, updated: {updated_customers}. Jobs created: {created_jobs}, updated: {updated_jobs}. Autotask IDs imported: {'yes' if include_autotask_ids else 'no'}.",
"success", "success",
) )
@ -758,6 +762,7 @@ def settings_jobs_import():
details=json.dumps({ details=json.dumps({
"format": "JSON", "format": "JSON",
"schema": payload.get("schema"), "schema": payload.get("schema"),
"include_autotask_ids": include_autotask_ids,
"customers_created": created_customers, "customers_created": created_customers,
"customers_updated": updated_customers, "customers_updated": updated_customers,
"jobs_created": created_jobs, "jobs_created": created_jobs,

View File

@ -15,6 +15,10 @@
<form method="post" action="{{ url_for('main.customers_import') }}" enctype="multipart/form-data" class="d-flex align-items-center gap-2 mb-0"> <form method="post" action="{{ url_for('main.customers_import') }}" enctype="multipart/form-data" class="d-flex align-items-center gap-2 mb-0">
<input type="file" name="file" accept=".csv,text/csv" class="form-control form-control-sm" required style="max-width: 420px;" /> <input type="file" name="file" accept=".csv,text/csv" class="form-control form-control-sm" required style="max-width: 420px;" />
<div class="form-check mb-0">
<input class="form-check-input" type="checkbox" value="1" id="include_autotask_ids_customers" name="include_autotask_ids" />
<label class="form-check-label small" for="include_autotask_ids_customers">Include Autotask IDs</label>
</div>
<button type="submit" class="btn btn-outline-secondary btn-sm" style="white-space: nowrap;">Import CSV</button> <button type="submit" class="btn btn-outline-secondary btn-sm" style="white-space: nowrap;">Import CSV</button>
</form> </form>

View File

@ -528,8 +528,16 @@
<div class="col-md-4 d-flex align-items-end"> <div class="col-md-4 d-flex align-items-end">
<button type="submit" class="btn btn-primary w-100">Import jobs</button> <button type="submit" class="btn btn-primary w-100">Import jobs</button>
</div> </div>
<div class="col-12">
<div class="form-check">
<input class="form-check-input" type="checkbox" value="1" id="include_autotask_ids_jobs" name="include_autotask_ids" />
<label class="form-check-label" for="include_autotask_ids_jobs">
Include Autotask IDs from import file
</label>
</div>
</div>
<div class="col-md-8"> <div class="col-md-8">
<div class="form-text">Use a JSON export created by this application.</div> <div class="form-text">Use a JSON export created by this application. Leave Autotask IDs unchecked for sandbox/development environments with a different Autotask database.</div>
</div> </div>
</div> </div>
</form> </form>

View File

@ -2,6 +2,17 @@
This file documents all changes made to this project via Claude Code. This file documents all changes made to this project via Claude Code.
## [2026-02-19]
### Added
- Added an explicit `Include Autotask IDs` import option to the Approved Jobs JSON import form in Settings → Maintenance
- Added an explicit `Include Autotask IDs` import option to the Customers CSV import form
### Changed
- Changed Approved Jobs import behavior to only apply `autotask_company_id` and `autotask_company_name` when the new import option is checked
- Changed Customers CSV import behavior to only apply Autotask mapping fields when the new import option is checked
- Changed import success/audit output for both jobs and customers imports to include whether Autotask IDs were imported
## [2026-02-16] ## [2026-02-16]
### Added ### Added