diff --git a/jey_wizard/__init__.py b/jey_wizard/__init__.py index f3b4574..970659c 100644 --- a/jey_wizard/__init__.py +++ b/jey_wizard/__init__.py @@ -1 +1 @@ -__version__ = "0.1.15" +__version__ = "0.1.16" diff --git a/jey_wizard/etaxes.py b/jey_wizard/etaxes.py index ec6da82..a5a73f6 100644 --- a/jey_wizard/etaxes.py +++ b/jey_wizard/etaxes.py @@ -1103,24 +1103,22 @@ def _find_default_warehouse(company): def _drop_alert_messages(): - """Remove every entry from frappe.local.message_log that was queued via - frappe.msgprint(alert=True) (a.k.a. toast). Keeps non-alert msgprints so - the user still sees real warnings. + """Wipe everything in frappe.local.message_log that piled up during the + setup_complete request. We need the entire log gone, not just alerts: + besides the az_locale rename toasts (alert=True), HRMS Salary Component + warnings ("Hesablar təyin edilməyib") and Frappe's own user-creation + notes ("Employee Self Service rolu silindi") come through plain + msgprints — and they're noise for an automated setup. Genuine failures + would have raised an exception and been handled separately, so blanket + clearing is safe here. """ try: - log = list(getattr(frappe.local, "message_log", []) or []) + frappe.clear_messages() except Exception: - return - if not log: - return - def _is_alert(m): try: - if isinstance(m, dict): - return bool(m.get("alert")) - return bool(getattr(m, "alert", 0)) + frappe.local.message_log = [] except Exception: - return False - frappe.local.message_log = [m for m in log if not _is_alert(m)] + pass def _only_admin(): diff --git a/jey_wizard/public/js/jey_setup.js b/jey_wizard/public/js/jey_setup.js index fc3db77..627e7b3 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.1.15"; +const JEY_WIZARD_VERSION = "0.1.16"; // 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. @@ -415,11 +415,11 @@ frappe.setup.SetupWizard = class JeySetupWizard {
- +
- +
${__("Default: current calendar year (Jan 1 – Dec 31).")}
@@ -443,8 +443,25 @@ frappe.setup.SetupWizard = class JeySetupWizard { `); $body.find(".jey-company-name").val(this.data.company_name); - $body.find(".jey-fy-start").val(this.data.fy_start_date); - $body.find(".jey-fy-end").val(this.data.fy_end_date); + + // Mount native Frappe Date controls (Flatpickr-styled) into the + // jey-fy-start / jey-fy-end placeholders. Plain + // looks dated and inconsistent with the rest of Frappe's UI. The + // controls expose set_value / get_value; we wire those into the + // usual data dict. + this.fy_start_ctrl = frappe.ui.form.make_control({ + df: { fieldtype: "Date", fieldname: "fy_start_date", placeholder: "" }, + parent: $body.find(".jey-fy-start")[0], + render_input: true, + }); + this.fy_start_ctrl.set_value(this.data.fy_start_date || ""); + this.fy_end_ctrl = frappe.ui.form.make_control({ + df: { fieldtype: "Date", fieldname: "fy_end_date", placeholder: "" }, + parent: $body.find(".jey-fy-end")[0], + render_input: true, + }); + this.fy_end_ctrl.set_value(this.data.fy_end_date || ""); + $body.find(".jey-valuation-method").val(this.data.valuation_method || "FIFO"); $body.find(".jey-accounting-method").val(this.data.accounting_method || "Hesablama metodu"); // Show why the default landed where it did, only when the auto-pick @@ -676,8 +693,10 @@ frappe.setup.SetupWizard = class JeySetupWizard { return false; } this.data.company_abbr = abbr; - const fyStart = (this.$wrap.find(".jey-fy-start").val() || "").trim(); - const fyEnd = (this.$wrap.find(".jey-fy-end").val() || "").trim(); + // Frappe Date controls return the value as YYYY-MM-DD or "" when + // blank. Mirrors the previous .val() contract on . + const fyStart = String((this.fy_start_ctrl && this.fy_start_ctrl.get_value()) || "").trim(); + const fyEnd = String((this.fy_end_ctrl && this.fy_end_ctrl.get_value()) || "").trim(); if (!fyStart || !fyEnd) { this.$wrap.find(".jey-status").text(__("Fiscal year start and end dates are required")); return false; @@ -1322,35 +1341,75 @@ frappe.setup.SetupWizard = class JeySetupWizard { } finalize() { - this.$wrap.find(".jey-body").html( - `

${__("Setting up your system. This can take a minute...")}

` - ); + // Render an inline progress UI in place of the wizard form. We don't + // pass freeze:true to frappe.call — the freeze overlay would dim and + // hide the bar. process_setup_stages publishes realtime "setup_task" + // events with {progress: [idx, total], stage_status: "..."}; we + // subscribe and translate those into bar width + status text. + this.$wrap.find(".jey-body").html(` +

${__("Setting up your system")}

+
${__("Starting...")}
+
+
+
+
5%
+ `); this.$wrap.find(".jey-nav").empty(); this.$wrap.find(".jey-status").empty(); + const setProgress = (pct, status) => { + pct = Math.max(0, Math.min(100, Math.round(pct))); + this.$wrap.find(".jey-finalize-bar").css("width", pct + "%"); + this.$wrap.find(".jey-finalize-pct").text(pct + "%"); + if (status) this.$wrap.find(".jey-finalize-status").text(status); + }; + + // Realtime subscription. Each "setup_task" event carries either a + // progress tuple or a final status. Cap displayed pct at 95% during + // the run so the bar visibly completes when the HTTP response lands. + const onSetupTask = (data) => { + if (!data) return; + if (Array.isArray(data.progress)) { + const [done, total] = data.progress; + if (total > 0) { + const ratio = Math.min(done / total, 0.95); + setProgress(5 + ratio * 90, data.stage_status || __("Working...")); + } + } + if (data.status === "fail") { + this.show_error( + data.fail_msg || __("Setup failed"), + data.exc || data.exception || __("(check server logs)") + ); + } + }; + frappe.realtime.on("setup_task", onSetupTask); + const cleanup = () => frappe.realtime.off("setup_task", onSetupTask); + const values = this.build_setup_args(); frappe.call({ method: "frappe.desk.page.setup_wizard.setup_wizard.setup_complete", args: { args: values }, - freeze: true, callback: (r) => { const m = r.message || {}; if (m.status === "ok") { - this.$wrap.find(".jey-body").html( - `

${__("Setup complete! Redirecting...")}

` - ); + setProgress(100, __("Setup complete! Redirecting...")); + cleanup(); setTimeout(() => { window.location.href = "/app"; - }, 1500); + }, 800); } else if (m.status === "registered") { + cleanup(); this.show_error( __("Setup is running in background mode, not supported by skeleton"), JSON.stringify(m, null, 2) ); } else if (m.fail !== undefined) { + cleanup(); this.show_error(m.fail, JSON.stringify(m, null, 2)); } else { + cleanup(); this.show_error( __("Setup returned unexpected response"), JSON.stringify(m, null, 2) @@ -1358,6 +1417,7 @@ frappe.setup.SetupWizard = class JeySetupWizard { } }, error: () => { + cleanup(); const resp = frappe.last_response || {}; this.show_error( resp.setup_wizard_failure_message || __("Setup failed"),