ƏMAS step: surface failure reason on intro, clearer 'cached' state
Symptom: after the second phone tap the wizard appeared to drop the
user back to the ƏMAS intro screen with no indication of what
happened — they couldn't tell if employees had been cached, the
import had run, or anything had failed.
Root cause was a UX bug in the JS layer: every error path in the
ƏMAS sub-flow (connect_amas, change_amas_account, get_employees_
report, cache_selected_employees) did
this.$wrap.find(".jey-status").text(error_message);
this.amas_state = "intro";
this.show_current_step();
but show_current_step() unconditionally calls .jey-status.empty()
at the top of the render, so the message was wiped before the user
could read it. They saw a clean intro screen and assumed nothing
ran or that it silently succeeded.
Fix:
- New persistent fields data.amas_last_error / data.asan_last_error
that survive show_current_step re-renders. Every ƏMAS error path
now writes to data.amas_last_error before flipping state.
- intro renderer reads data.amas_last_error and shows a red
"Previous attempt failed: <message>" banner above the usual
copy when set. amas_start_auth clears it on retry.
- Added .error callbacks to the four frappe.call sites that didn't
have one — network errors used to drop the user to intro with no
message at all.
Also rewrote the success "done" screen so it can't be misread:
heading is now "Cached and ready", body explicitly says "Cached on
the server. Actual import into Employee / ƏMAS Employees runs as a
background job right after you click Finish — you can keep working
in /app while it runs." Same data, just unmistakable.
This commit is contained in:
parent
29f277a7bf
commit
8c178524d9
|
|
@ -1 +1 @@
|
||||||
__version__ = "0.1.21"
|
__version__ = "0.1.22"
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ frappe.provide("jey_wizard");
|
||||||
// Bump this string in every commit that changes wizard code. Displayed in the badge so
|
// Bump this string in every commit that changes wizard code. Displayed in the badge so
|
||||||
// we can tell at a glance which version is actually running on a given machine. Kept in
|
// we can tell at a glance which version is actually running on a given machine. Kept in
|
||||||
// sync with __version__ in jey_wizard/__init__.py.
|
// sync with __version__ in jey_wizard/__init__.py.
|
||||||
const JEY_WIZARD_VERSION = "0.1.21";
|
const JEY_WIZARD_VERSION = "0.1.22";
|
||||||
|
|
||||||
// Wipe Frappe + ERPNext default slides so their `before_load`/`after_load` listeners
|
// Wipe Frappe + ERPNext default slides so their `before_load`/`after_load` listeners
|
||||||
// don't try to mutate a wizard that isn't slide-based anymore.
|
// don't try to mutate a wizard that isn't slide-based anymore.
|
||||||
|
|
@ -71,6 +71,12 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
||||||
amas_selected_employees: [],
|
amas_selected_employees: [],
|
||||||
amas_create_designation: 1,
|
amas_create_designation: 1,
|
||||||
amas_organization_name: "",
|
amas_organization_name: "",
|
||||||
|
// Survives show_current_step() re-renders so the user sees what
|
||||||
|
// failed when an error path resets amas_state to "intro" — the
|
||||||
|
// .jey-status helper is cleared by every render and would erase
|
||||||
|
// the message before they could read it.
|
||||||
|
amas_last_error: "",
|
||||||
|
asan_last_error: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
// Sub-state machines per step. `input` / `intro` is the always-safe fallback
|
// Sub-state machines per step. `input` / `intro` is the always-safe fallback
|
||||||
|
|
@ -314,8 +320,14 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
||||||
render_employees($body) {
|
render_employees($body) {
|
||||||
if (this.amas_state === "intro") {
|
if (this.amas_state === "intro") {
|
||||||
const alreadyLoaded = (this.data.amas_selected_employees || []).length;
|
const alreadyLoaded = (this.data.amas_selected_employees || []).length;
|
||||||
|
const lastError = this.data.amas_last_error || "";
|
||||||
$body.html(`
|
$body.html(`
|
||||||
<h3 style="margin-bottom:16px">${__("Load employees from ƏMAS")}</h3>
|
<h3 style="margin-bottom:16px">${__("Load employees from ƏMAS")}</h3>
|
||||||
|
${lastError
|
||||||
|
? `<div style="margin-bottom:12px;padding:12px;background:#fee2e2;border-left:3px solid #dc2626;border-radius:4px;color:#991b1b">
|
||||||
|
<b>${__("Previous attempt failed:")}</b> ${frappe.utils.escape_html(lastError)}
|
||||||
|
</div>`
|
||||||
|
: ""}
|
||||||
<p>${__("ƏMAS (e-social.gov.az) stores employment contracts. If your company has employees registered there, we can import them now.")}</p>
|
<p>${__("ƏMAS (e-social.gov.az) stores employment contracts. If your company has employees registered there, we can import them now.")}</p>
|
||||||
<div style="margin-top:12px;padding:12px;background:#fff8e1;border-left:3px solid #e0a800;border-radius:4px">
|
<div style="margin-top:12px;padding:12px;background:#fff8e1;border-left:3px solid #e0a800;border-radius:4px">
|
||||||
<b>${__("Heads up:")}</b> ${__("You will receive a second confirmation request on your phone from ASAN Sign / MyGovID. This is separate from the one you just approved for the tax portal.")}
|
<b>${__("Heads up:")}</b> ${__("You will receive a second confirmation request on your phone from ASAN Sign / MyGovID. This is separate from the one you just approved for the tax portal.")}
|
||||||
|
|
@ -400,12 +412,13 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
||||||
} else if (this.amas_state === "done") {
|
} else if (this.amas_state === "done") {
|
||||||
const n = (this.data.amas_selected_employees || []).length;
|
const n = (this.data.amas_selected_employees || []).length;
|
||||||
$body.html(`
|
$body.html(`
|
||||||
<h3 style="margin-bottom:16px;color:#080">✓ ${__("Employees ready to import")}</h3>
|
<h3 style="margin-bottom:16px;color:#080">✓ ${__("Cached and ready")}</h3>
|
||||||
<div style="padding:12px;background:#e8f5e9;border-radius:4px;margin-bottom:12px">
|
<div style="padding:12px;background:#e8f5e9;border-radius:4px;margin-bottom:12px">
|
||||||
${__("Organization:")} <b>${frappe.utils.escape_html(this.data.amas_organization_name || "")}</b><br>
|
${__("Organization:")} <b>${frappe.utils.escape_html(this.data.amas_organization_name || "")}</b><br>
|
||||||
${__("Employees found:")} <b>${n}</b>
|
${__("Employees cached:")} <b>${n}</b>
|
||||||
</div>
|
</div>
|
||||||
<p style="color:#666">${__("All employees will be imported into ƏMAS Employees and the standard Employee doctype after the wizard finishes.")}</p>
|
<p style="color:#666">${__("Cached on the server. Actual import into Employee / ƏMAS Employees runs as a background job right after you click Finish — you can keep working in /app while it runs.")}</p>
|
||||||
|
<p style="color:#888;font-size:12px;margin-top:8px">${__("Click Next to continue, or Back to re-select.")}</p>
|
||||||
`);
|
`);
|
||||||
// No extra buttons here — Back/Next in nav cover everything.
|
// No extra buttons here — Back/Next in nav cover everything.
|
||||||
}
|
}
|
||||||
|
|
@ -1157,6 +1170,7 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.data.amas_skipped = false;
|
this.data.amas_skipped = false;
|
||||||
|
this.data.amas_last_error = "";
|
||||||
this.amas_verification_code = "";
|
this.amas_verification_code = "";
|
||||||
this.amas_state = "auth";
|
this.amas_state = "auth";
|
||||||
this.show_current_step();
|
this.show_current_step();
|
||||||
|
|
@ -1170,7 +1184,7 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
||||||
if (this.amas_state !== "auth") return;
|
if (this.amas_state !== "auth") return;
|
||||||
const m = r.message || {};
|
const m = r.message || {};
|
||||||
if (!m.success) {
|
if (!m.success) {
|
||||||
this.$wrap.find(".jey-status").text(m.message || __("MyGovID authentication failed."));
|
this.data.amas_last_error = m.message || __("MyGovID authentication failed.");
|
||||||
this.amas_state = "intro";
|
this.amas_state = "intro";
|
||||||
this.show_current_step();
|
this.show_current_step();
|
||||||
return;
|
return;
|
||||||
|
|
@ -1179,7 +1193,7 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
||||||
},
|
},
|
||||||
error: () => {
|
error: () => {
|
||||||
if (this.amas_state !== "auth") return;
|
if (this.amas_state !== "auth") return;
|
||||||
this.$wrap.find(".jey-status").text(__("MyGovID request timed out."));
|
this.data.amas_last_error = __("MyGovID request timed out.");
|
||||||
this.amas_state = "intro";
|
this.amas_state = "intro";
|
||||||
this.show_current_step();
|
this.show_current_step();
|
||||||
},
|
},
|
||||||
|
|
@ -1213,7 +1227,7 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
||||||
callback: (r) => {
|
callback: (r) => {
|
||||||
const m = r.message || {};
|
const m = r.message || {};
|
||||||
if (!m.success) {
|
if (!m.success) {
|
||||||
this.$wrap.find(".jey-status").text(m.message || __("Failed to connect to ƏMAS."));
|
this.data.amas_last_error = m.message || __("Failed to connect to ƏMAS.");
|
||||||
this.amas_state = "intro";
|
this.amas_state = "intro";
|
||||||
this.show_current_step();
|
this.show_current_step();
|
||||||
return;
|
return;
|
||||||
|
|
@ -1233,7 +1247,7 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
||||||
} else if (this.amas_accounts.length === 1) {
|
} else if (this.amas_accounts.length === 1) {
|
||||||
this.amas_pick_account(0);
|
this.amas_pick_account(0);
|
||||||
} else if (this.amas_accounts.length === 0) {
|
} else if (this.amas_accounts.length === 0) {
|
||||||
this.$wrap.find(".jey-status").text(__("No organizations found in ƏMAS for this account."));
|
this.data.amas_last_error = __("No organizations found in ƏMAS for this account.");
|
||||||
this.amas_state = "intro";
|
this.amas_state = "intro";
|
||||||
this.show_current_step();
|
this.show_current_step();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1241,6 +1255,11 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
||||||
this.show_current_step();
|
this.show_current_step();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
error: () => {
|
||||||
|
this.data.amas_last_error = __("Network error while connecting to ƏMAS.");
|
||||||
|
this.amas_state = "intro";
|
||||||
|
this.show_current_step();
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1267,7 +1286,7 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
||||||
callback: (r) => {
|
callback: (r) => {
|
||||||
const m = r.message || {};
|
const m = r.message || {};
|
||||||
if (!m.success) {
|
if (!m.success) {
|
||||||
this.$wrap.find(".jey-status").text(m.message || __("Failed to select organization."));
|
this.data.amas_last_error = m.message || __("Failed to select organization.");
|
||||||
this.amas_state = "intro";
|
this.amas_state = "intro";
|
||||||
this.show_current_step();
|
this.show_current_step();
|
||||||
return;
|
return;
|
||||||
|
|
@ -1275,6 +1294,11 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
||||||
this.data.amas_organization_name = name;
|
this.data.amas_organization_name = name;
|
||||||
this.amas_load_employees();
|
this.amas_load_employees();
|
||||||
},
|
},
|
||||||
|
error: () => {
|
||||||
|
this.data.amas_last_error = __("Network error while selecting organization.");
|
||||||
|
this.amas_state = "intro";
|
||||||
|
this.show_current_step();
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1292,14 +1316,14 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
||||||
callback: (r) => {
|
callback: (r) => {
|
||||||
const m = r.message || {};
|
const m = r.message || {};
|
||||||
if (!m.success) {
|
if (!m.success) {
|
||||||
this.$wrap.find(".jey-status").text(m.message || __("Failed to fetch employees."));
|
this.data.amas_last_error = m.message || __("Failed to fetch employees.");
|
||||||
this.amas_state = "intro";
|
this.amas_state = "intro";
|
||||||
this.show_current_step();
|
this.show_current_step();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const employees = m.employees || [];
|
const employees = m.employees || [];
|
||||||
if (employees.length === 0) {
|
if (employees.length === 0) {
|
||||||
this.$wrap.find(".jey-status").text(__("No employees found in ƏMAS for this organization."));
|
this.data.amas_last_error = __("No employees found in ƏMAS for this organization.");
|
||||||
this.amas_state = "intro";
|
this.amas_state = "intro";
|
||||||
this.show_current_step();
|
this.show_current_step();
|
||||||
return;
|
return;
|
||||||
|
|
@ -1315,6 +1339,7 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
||||||
amas_commit_selection() {
|
amas_commit_selection() {
|
||||||
const all = this.amas_employees || [];
|
const all = this.amas_employees || [];
|
||||||
if (all.length === 0) {
|
if (all.length === 0) {
|
||||||
|
this.data.amas_last_error = __("Got empty employee list from ƏMAS.");
|
||||||
this.amas_state = "intro";
|
this.amas_state = "intro";
|
||||||
this.show_current_step();
|
this.show_current_step();
|
||||||
return;
|
return;
|
||||||
|
|
@ -1331,7 +1356,7 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
||||||
callback: (r) => {
|
callback: (r) => {
|
||||||
const m = r.message || {};
|
const m = r.message || {};
|
||||||
if (!m.ok) {
|
if (!m.ok) {
|
||||||
this.$wrap.find(".jey-status").text(__("Failed to cache selection."));
|
this.data.amas_last_error = __("Failed to cache employee selection on the server.");
|
||||||
this.amas_state = "intro";
|
this.amas_state = "intro";
|
||||||
this.show_current_step();
|
this.show_current_step();
|
||||||
return;
|
return;
|
||||||
|
|
@ -1341,6 +1366,11 @@ frappe.setup.SetupWizard = class JeySetupWizard {
|
||||||
this.amas_state = "done";
|
this.amas_state = "done";
|
||||||
this.show_current_step();
|
this.show_current_step();
|
||||||
},
|
},
|
||||||
|
error: () => {
|
||||||
|
this.data.amas_last_error = __("Network error while caching the employee selection.");
|
||||||
|
this.amas_state = "intro";
|
||||||
|
this.show_current_step();
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue