From e166da49cc1ab40de00a3d44993ab4b1b70a2155 Mon Sep 17 00:00:00 2001 From: Ali <010109ali@gmail.com> Date: Fri, 24 Apr 2026 11:38:19 +0000 Subject: [PATCH] =?UTF-8?q?Auto-import=20all=20fetched=20=C6=8FMAS=20emplo?= =?UTF-8?q?yees;=20apply=20default=20language=20on=20boot?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove the manual employee selection UI. After loading, the wizard caches every record returned by emasValidEmploymentContractOnline and lands on the done sub-state. import_bulk_employees updates existing records on FIN match, so running on a populated site is safe. - On constructor, if the booted session lang differs from the wizard's default (az), trigger load_messages so the UI renders in that language without the user having to re-pick it from the dropdown. --- jey_wizard/__init__.py | 2 +- jey_wizard/public/js/jey_setup.js | 138 ++++++++++-------------------- 2 files changed, 47 insertions(+), 93 deletions(-) diff --git a/jey_wizard/__init__.py b/jey_wizard/__init__.py index 6526deb..a73339b 100644 --- a/jey_wizard/__init__.py +++ b/jey_wizard/__init__.py @@ -1 +1 @@ -__version__ = "0.0.7" +__version__ = "0.0.8" diff --git a/jey_wizard/public/js/jey_setup.js b/jey_wizard/public/js/jey_setup.js index b22cbee..dcc64e2 100644 --- a/jey_wizard/public/js/jey_setup.js +++ b/jey_wizard/public/js/jey_setup.js @@ -10,7 +10,7 @@ frappe.provide("jey_wizard"); // 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 // sync with __version__ in jey_wizard/__init__.py. -const JEY_WIZARD_VERSION = "0.0.7"; +const JEY_WIZARD_VERSION = "0.0.8"; // 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. @@ -72,6 +72,15 @@ frappe.setup.SetupWizard = class JeySetupWizard { this.current_step = 0; this.steps = ["language", "asan", "employees", "company", "confirm"]; this.render(); + + // Session arrives in whatever language Frappe booted in (usually English for + // the first-run Administrator). Pull the default language's translations + // immediately so every subsequent render runs in that language without the + // user having to re-pick it. + const bootLang = (frappe.boot.lang || "en").split("-")[0]; + if (bootLang !== this.data.language) { + this.change_language(this.data.language, /* force */ true); + } } // Frappe's on_page_show calls frappe.wizard.show_slide — no-op for us. @@ -334,71 +343,20 @@ frappe.setup.SetupWizard = class JeySetupWizard {
${__("Fetching from ƏMAS...")}
`); - } else if (this.amas_state === "select") { - const emps = this.amas_employees || []; - const existing = this.amas_existing_map || {}; - const newCount = emps.filter((e) => !existing[e.identification_number]).length; - const existingCount = emps.length - newCount; - - const rows = emps.map((e, i) => { - const fin = e.identification_number || ""; - const existingId = existing[fin]; - const statusCell = existingId - ? `${frappe.utils.escape_html(existingId)}` - : ""; - return ` - - - ${frappe.utils.escape_html(e.full_name || "")} - ${frappe.utils.escape_html(fin)} - ${frappe.utils.escape_html(e.work_position_text || "")} - ${frappe.utils.escape_html(String(e.monthly_salary || ""))} - ${frappe.utils.escape_html(e.contract_status || "")} - ${statusCell} - - `; - }).join(""); - - $body.html(` -

${__("Select employees from ƏMAS")}

-
- ${__("Organization:")} ${frappe.utils.escape_html(this.data.amas_organization_name || "")}
- ${__("Employees found:")} ${emps.length} - (${__("new")}: ${newCount}, ${__("already in system")}: ${existingCount}) -
- -
- - - - - - - - - - - - - ${rows} -
${__("Full Name")}${__("FIN")}${__("Position")}${__("Salary")}${__("Status")}${__("In System")}
-
- `); - - $body.find(".jey-emp-all").on("change", (e) => { - const checked = $(e.currentTarget).prop("checked"); - $body.find(".jey-emp-pick").prop("checked", checked); - }); } else if (this.amas_state === "done") { const n = (this.data.amas_selected_employees || []).length; + const existingCount = Object.keys(this.amas_existing_map || {}).length; + const newCount = n - existingCount; $body.html(` -

✓ ${__("Employees selected")}

-

${__("Selected {0} employee(s). They will be imported into ƏMAS Employees and the standard Employee doctype after the wizard finishes.", [n])}

+

✓ ${__("Employees ready to import")}

+
+ ${__("Organization:")} ${frappe.utils.escape_html(this.data.amas_organization_name || "")}
+ ${__("Employees found:")} ${n} + (${__("new")}: ${newCount < 0 ? n : newCount}, ${__("already in system")}: ${existingCount}) +
+

${__("All employees will be imported into ƏMAS Employees and the standard Employee doctype after the wizard finishes.")}

- +
`); $body.find(".jey-amas-back-intro").on("click", () => { @@ -479,13 +437,6 @@ frappe.setup.SetupWizard = class JeySetupWizard { // surfaces a standard Next. showStdNext = this.asan_state === "done"; } else if (step === "employees") { - if (this.amas_state === "select") { - // Commit selection instead of plain Next. - $(``) - .appendTo($nav) - .on("click", () => this.amas_commit_selection()); - return; - } // On intro the user uses explicit Skip / Load buttons, not Next. // Only the "done" sub-state surfaces a standard Next to move on. showStdNext = this.amas_state === "done"; @@ -565,8 +516,9 @@ frappe.setup.SetupWizard = class JeySetupWizard { // ---------- language ---------- - change_language(code) { - if (!code || code === this.data.language) return; + change_language(code, force = false) { + if (!code) return; + if (!force && code === this.data.language) return; const langName = LANG_NAME[code] || "English"; frappe._messages = {}; frappe.call({ @@ -943,21 +895,22 @@ frappe.setup.SetupWizard = class JeySetupWizard { this.show_current_step(); return; } - this.amas_employees = m.employees || []; - if (this.amas_employees.length === 0) { + const employees = m.employees || []; + if (employees.length === 0) { this.$wrap.find(".jey-status").text(__("No employees found in ƏMAS for this organization.")); this.amas_state = "intro"; this.show_current_step(); return; } - // Check which FINs are already in the Employee doctype. - const fins = this.amas_employees + this.amas_employees = employees; + // Populate existing_map purely for the summary UI; the actual import + // updates existing records rather than skipping them, so no filtering. + const fins = employees .map((e) => e.identification_number) .filter(Boolean); if (fins.length === 0) { this.amas_existing_map = {}; - this.amas_state = "select"; - this.show_current_step(); + this.amas_commit_selection(); return; } frappe.call({ @@ -974,43 +927,44 @@ frappe.setup.SetupWizard = class JeySetupWizard { if (emp.passport_number) map[emp.passport_number] = emp.name; }); this.amas_existing_map = map; - this.amas_state = "select"; - this.show_current_step(); + this.amas_commit_selection(); + }, + error: () => { + this.amas_existing_map = {}; + this.amas_commit_selection(); }, }); }, }); } + // Caches the full fetched list (user requested: import every active contract the + // report returned, no manual selection). Runs right after amas_load_employees. amas_commit_selection() { - const $body = this.$wrap.find(".jey-body"); - const selected = []; - $body.find(".jey-emp-pick:checked").each((i, el) => { - const idx = parseInt($(el).attr("data-idx"), 10); - if (!isNaN(idx)) selected.push(this.amas_employees[idx]); - }); - if (selected.length === 0) { - this.$wrap.find(".jey-status").text(__("Select at least one employee, or go back and skip this step.")); + const all = this.amas_employees || []; + if (all.length === 0) { + this.amas_state = "intro"; + this.show_current_step(); return; } - const createDesignation = $body.find(".jey-emp-create-desig").is(":checked") ? 1 : 0; + const createDesignation = 1; this.data.amas_create_designation = createDesignation; frappe.call({ method: "jey_wizard.amas.cache_selected_employees", args: { - employees_json: JSON.stringify(selected), + employees_json: JSON.stringify(all), create_designation: createDesignation, }, - freeze: true, - freeze_message: __("Saving selection..."), callback: (r) => { const m = r.message || {}; if (!m.ok) { this.$wrap.find(".jey-status").text(__("Failed to cache selection.")); + this.amas_state = "intro"; + this.show_current_step(); return; } - this.data.amas_selected_employees = selected; + this.data.amas_selected_employees = all; this.data.amas_skipped = false; this.amas_state = "done"; this.show_current_step();