Improve Autotask customer mapping with auto-search
Added automatic search for similar company names when opening unmapped customers in the edit modal. This speeds up the mapping process by eliminating manual searches. Changes: - Clear search box when opening customer edit modal - Auto-populate search with customer name for unmapped customers - Automatically display matching Autotask companies as suggestions - Refactor search logic into reusable performAutotaskSearch() function Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
282d34af2d
commit
9388ec4c01
@ -370,6 +370,7 @@
|
|||||||
if (atResults) {
|
if (atResults) {
|
||||||
clearResults();
|
clearResults();
|
||||||
}
|
}
|
||||||
|
if (atSearchInput) atSearchInput.value = '';
|
||||||
setSelectedCompanyId(null);
|
setSelectedCompanyId(null);
|
||||||
setMsg("", false);
|
setMsg("", false);
|
||||||
|
|
||||||
@ -379,66 +380,80 @@
|
|||||||
var atStatus = btn.getAttribute("data-autotask-mapping-status") || "";
|
var atStatus = btn.getAttribute("data-autotask-mapping-status") || "";
|
||||||
var atLast = btn.getAttribute("data-autotask-last-sync-at") || "";
|
var atLast = btn.getAttribute("data-autotask-last-sync-at") || "";
|
||||||
renderCurrentMapping(atCompanyId, atCompanyName, atStatus, atLast);
|
renderCurrentMapping(atCompanyId, atCompanyName, atStatus, atLast);
|
||||||
|
|
||||||
|
// Auto-search for similar companies if not yet mapped
|
||||||
|
if (!atCompanyId && name && atSearchInput) {
|
||||||
|
atSearchInput.value = name;
|
||||||
|
performAutotaskSearch(name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Reusable Autotask search function
|
||||||
|
async function performAutotaskSearch(query) {
|
||||||
|
if (!atResults) return;
|
||||||
|
|
||||||
|
var q = (query || "").trim();
|
||||||
|
if (!q) {
|
||||||
|
setMsg("Enter a search term.", true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setMsg("Searching...", false);
|
||||||
|
setSelectedCompanyId(null);
|
||||||
|
atResults.innerHTML = "<div class=\"text-muted small\">Searching...</div>";
|
||||||
|
|
||||||
|
try {
|
||||||
|
var resp = await fetch("/api/autotask/companies/search?q=" + encodeURIComponent(q), {
|
||||||
|
method: "GET",
|
||||||
|
credentials: "same-origin",
|
||||||
|
});
|
||||||
|
var data = await resp.json();
|
||||||
|
if (!resp.ok || !data || data.status !== "ok") {
|
||||||
|
throw new Error((data && data.message) ? data.message : "Search failed.");
|
||||||
|
}
|
||||||
|
var items = data.items || [];
|
||||||
|
if (!items.length) {
|
||||||
|
atResults.innerHTML = "<div class=\"text-muted small\">No companies found.</div>";
|
||||||
|
setMsg("No companies found.", false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var html = "";
|
||||||
|
items.forEach(function (it) {
|
||||||
|
var cid = it.id;
|
||||||
|
var name = it.companyName || it.name || ("Company #" + cid);
|
||||||
|
var active = (it.isActive === false) ? " (inactive)" : "";
|
||||||
|
html +=
|
||||||
|
"<div class=\"form-check\">" +
|
||||||
|
"<input class=\"form-check-input\" type=\"radio\" name=\"autotaskCompanyPick\" id=\"at_company_" + cid + "\" value=\"" + cid + "\" />" +
|
||||||
|
"<label class=\"form-check-label\" for=\"at_company_" + cid + "\">" +
|
||||||
|
name.replace(/</g, "<").replace(/>/g, ">") +
|
||||||
|
" <span class=\"text-muted\">(ID: " + cid + ")</span>" +
|
||||||
|
"<span class=\"text-muted\">" + active + "</span>" +
|
||||||
|
"</label>" +
|
||||||
|
"</div>";
|
||||||
|
});
|
||||||
|
atResults.innerHTML = html;
|
||||||
|
|
||||||
|
var radios = atResults.querySelectorAll("input[name='autotaskCompanyPick']");
|
||||||
|
radios.forEach(function (r) {
|
||||||
|
r.addEventListener("change", function () {
|
||||||
|
setSelectedCompanyId(r.value);
|
||||||
|
setMsg("Selected company ID: " + r.value, false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
setMsg("Select a company and click Set mapping.", false);
|
||||||
|
} catch (e) {
|
||||||
|
atResults.innerHTML = "<div class=\"text-muted small\">No results.</div>";
|
||||||
|
setMsg(e && e.message ? e.message : "Search failed.", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (atSearchBtn && atSearchInput && atResults) {
|
if (atSearchBtn && atSearchInput && atResults) {
|
||||||
atSearchBtn.addEventListener("click", async function () {
|
atSearchBtn.addEventListener("click", async function () {
|
||||||
var q = (atSearchInput.value || "").trim();
|
var q = (atSearchInput.value || "").trim();
|
||||||
if (!q) {
|
await performAutotaskSearch(q);
|
||||||
setMsg("Enter a search term.", true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setMsg("Searching...", false);
|
|
||||||
setSelectedCompanyId(null);
|
|
||||||
atResults.innerHTML = "<div class=\"text-muted small\">Searching...</div>";
|
|
||||||
|
|
||||||
try {
|
|
||||||
var resp = await fetch("/api/autotask/companies/search?q=" + encodeURIComponent(q), {
|
|
||||||
method: "GET",
|
|
||||||
credentials: "same-origin",
|
|
||||||
});
|
|
||||||
var data = await resp.json();
|
|
||||||
if (!resp.ok || !data || data.status !== "ok") {
|
|
||||||
throw new Error((data && data.message) ? data.message : "Search failed.");
|
|
||||||
}
|
|
||||||
var items = data.items || [];
|
|
||||||
if (!items.length) {
|
|
||||||
atResults.innerHTML = "<div class=\"text-muted small\">No companies found.</div>";
|
|
||||||
setMsg("No companies found.", false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var html = "";
|
|
||||||
items.forEach(function (it) {
|
|
||||||
var cid = it.id;
|
|
||||||
var name = it.companyName || it.name || ("Company #" + cid);
|
|
||||||
var active = (it.isActive === false) ? " (inactive)" : "";
|
|
||||||
html +=
|
|
||||||
"<div class=\"form-check\">" +
|
|
||||||
"<input class=\"form-check-input\" type=\"radio\" name=\"autotaskCompanyPick\" id=\"at_company_" + cid + "\" value=\"" + cid + "\" />" +
|
|
||||||
"<label class=\"form-check-label\" for=\"at_company_" + cid + "\">" +
|
|
||||||
name.replace(/</g, "<").replace(/>/g, ">") +
|
|
||||||
" <span class=\"text-muted\">(ID: " + cid + ")</span>" +
|
|
||||||
"<span class=\"text-muted\">" + active + "</span>" +
|
|
||||||
"</label>" +
|
|
||||||
"</div>";
|
|
||||||
});
|
|
||||||
atResults.innerHTML = html;
|
|
||||||
|
|
||||||
var radios = atResults.querySelectorAll("input[name='autotaskCompanyPick']");
|
|
||||||
radios.forEach(function (r) {
|
|
||||||
r.addEventListener("change", function () {
|
|
||||||
setSelectedCompanyId(r.value);
|
|
||||||
setMsg("Selected company ID: " + r.value, false);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
setMsg("Select a company and click Set mapping.", false);
|
|
||||||
} catch (e) {
|
|
||||||
atResults.innerHTML = "<div class=\"text-muted small\">No results.</div>";
|
|
||||||
setMsg(e && e.message ? e.message : "Search failed.", true);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,10 @@ This file documents all changes made to this project via Claude Code.
|
|||||||
## [2026-02-05]
|
## [2026-02-05]
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
- Autotask customer mapping now auto-searches for similar company names when opening unmapped customers:
|
||||||
|
- Automatically populates search box with customer name
|
||||||
|
- Displays matching Autotask companies as suggestions
|
||||||
|
- Speeds up mapping process by eliminating manual search for most customers
|
||||||
- Autotask "Link existing ticket" now supports cross-company ticket search:
|
- Autotask "Link existing ticket" now supports cross-company ticket search:
|
||||||
- Added `query_tickets_by_number()` to search tickets by number across all companies
|
- Added `query_tickets_by_number()` to search tickets by number across all companies
|
||||||
- When searching with a ticket number (e.g., "T20260205.0001"), results include:
|
- When searching with a ticket number (e.g., "T20260205.0001"), results include:
|
||||||
@ -29,6 +33,7 @@ This file documents all changes made to this project via Claude Code.
|
|||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Autotask "Link existing" search box now clears when opening the modal instead of retaining previous search text
|
- Autotask "Link existing" search box now clears when opening the modal instead of retaining previous search text
|
||||||
|
- Autotask customer mapping search box now clears when opening the edit modal instead of retaining previous search text
|
||||||
- Autotask ticket resolution update now correctly preserves exact field values from GET response in PUT payload.
|
- Autotask ticket resolution update now correctly preserves exact field values from GET response in PUT payload.
|
||||||
The `issueType`, `subIssueType`, and `source` fields are copied with their exact values (including null)
|
The `issueType`, `subIssueType`, and `source` fields are copied with their exact values (including null)
|
||||||
from the GET response, as required by Autotask API. Previously these fields were being skipped or modified.
|
from the GET response, as required by Autotask API. Previously these fields were being skipped or modified.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user