diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.js b/erpnext/accounts/doctype/accounts_settings/accounts_settings.js index 79d9138a886..89429cd66d8 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.js +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.js @@ -10,7 +10,7 @@ frappe.ui.form.on("Accounts Settings", { }, }; }); - if (!frm.naming_controller) frm.naming_controller = new erpnext.NamingSeriesController(frm); + if (!frm.naming_controller) frm.naming_controller = new frappe.ui.NamingSeriesController(frm); frm.naming_controller.render_table("transaction_naming_html", get_transactions(frm)); }, diff --git a/erpnext/buying/doctype/buying_settings/buying_settings.js b/erpnext/buying/doctype/buying_settings/buying_settings.js index 9cc43220226..453a816ac18 100644 --- a/erpnext/buying/doctype/buying_settings/buying_settings.js +++ b/erpnext/buying/doctype/buying_settings/buying_settings.js @@ -3,7 +3,7 @@ frappe.ui.form.on("Buying Settings", { refresh(frm) { - if (!frm.naming_controller) frm.naming_controller = new erpnext.NamingSeriesController(frm); + if (!frm.naming_controller) frm.naming_controller = new frappe.ui.NamingSeriesController(frm); const display = frm.doc.supp_master_name === "Naming Series"; frm.set_df_property("naming_series_details", "hidden", !display); diff --git a/erpnext/public/js/erpnext.bundle.js b/erpnext/public/js/erpnext.bundle.js index 69b587ba002..221e3a62c6a 100644 --- a/erpnext/public/js/erpnext.bundle.js +++ b/erpnext/public/js/erpnext.bundle.js @@ -37,6 +37,5 @@ import "./utils/demo.js"; import "./financial_statements.js"; import "./sales_trends_filters.js"; import "./purchase_trends_filters.js"; -import "./utils/naming_series.js"; // import { sum } from 'frappe/public/utils/util.js' diff --git a/erpnext/public/js/utils/naming_series.js b/erpnext/public/js/utils/naming_series.js deleted file mode 100644 index 9a1725529aa..00000000000 --- a/erpnext/public/js/utils/naming_series.js +++ /dev/null @@ -1,417 +0,0 @@ -frappe.provide("erpnext"); - -erpnext.NamingSeriesDialog = class NamingSeriesDialog { - constructor(opts = {}) { - this.opts = Object.assign( - { - title: __("Document Naming"), - single_doctype: "Document Naming Settings", - }, - opts - ); - - this.current_doctype = null; - this.loaded = false; - this.make_dialog(); - } - - make_dialog() { - this.dialog = new frappe.ui.Dialog({ - title: this.opts.title, - size: "medium", - fields: [ - { - fieldtype: "Table", - fieldname: "naming_series_options", - label: __("Add Series Prefix"), - reqd: 1, - in_place_edit: true, - data: [], - fields: [ - { - fieldtype: "Data", - fieldname: "series", - label: __("Series"), - in_list_view: 1, - change: async function () { - const preview = await this.grid_row.grid._naming_dialog.get_series_preview( - this.doc.series - ); - this.doc.preview = preview; - this.grid_row.refresh_field("preview"); - }, - }, - { - fieldtype: "Data", - fieldname: "preview", - label: __("Preview"), - in_list_view: 1, - placeholder: " ", - read_only: 1, - }, - ], - }, - { fieldtype: "Section Break", label: __("Rules for configuring series"), collapsible: 1 }, - { - fieldtype: "HTML", - fieldname: "naming_series_description", - }, - ], - primary_action_label: __("Update"), - primary_action: () => this.save(), - }); - - this.dialog.fields_dict.naming_series_options.grid._naming_dialog = this; - } - - async show() { - this.dialog.show(); - this.render_help(); - - if (this.opts.doctype && !this.loaded) { - await this.get_transaction(this.opts.doctype); - this.loaded = true; - return; - } - } - - render_help() { - this.dialog.get_field("naming_series_description").$wrapper.html(` - - Examples: - -
`); - } - - get_series_preview(series) { - if (!series) return ""; - - return this.get_document_naming_doc().then((doc) => { - doc.try_naming_series = series; - doc.transaction_type = this.current_doctype; - return frappe - .call({ - doc: doc, - method: "preview_series", - freeze: true, - }) - .then((r) => (r.message || "").split("\n")[0] || ""); - }); - } - - get_document_naming_doc() { - const dt = this.opts.single_doctype; - return frappe.model.with_doc(dt, dt).then(() => { - return frappe.model.get_doc(dt, dt); - }); - } - - async get_transaction(doctype) { - this.current_doctype = doctype; - - await frappe.model.with_doctype(doctype, async () => { - const meta = frappe.get_meta(doctype); - const naming_df = (meta?.fields || []).find((df) => df.fieldname === "naming_series"); - const series_list = (naming_df?.options || "").split("\n").filter(Boolean); - const rows = await Promise.all( - series_list.map(async (series) => ({ - series: series, - preview: await this.get_series_preview(series), - })) - ); - - this.dialog.fields_dict.naming_series_options.df.data = rows; - this.dialog.fields_dict.naming_series_options.grid.refresh(); - }); - } - - save() { - const rows = this.dialog.fields_dict.naming_series_options.grid.get_data(); - const naming_series_options = rows - .map((r) => (r.series || "").trim()) - .filter(Boolean) - .join("\n"); - - if (!this.current_doctype) { - frappe.msgprint(__("Please select a transaction.")); - return; - } - - if (!naming_series_options) { - frappe.msgprint(__("Please add at least one naming series.")); - return; - } - - this.get_document_naming_doc().then((doc) => { - doc.transaction_type = this.current_doctype; - doc.naming_series_options = naming_series_options; - - frappe.call({ - doc: doc, - method: "update_series", - freeze: true, - callback: async () => { - const updated_rows = await Promise.all( - naming_series_options - .split("\n") - .filter(Boolean) - .map(async (series) => ({ - series: series, - preview: await this.get_series_preview(series), - })) - ); - - this.dialog.fields_dict.naming_series_options.df.data = updated_rows; - this.dialog.fields_dict.naming_series_options.grid.refresh(); - - frappe.show_alert({ message: __("Naming Series updated"), indicator: "green" }); - this.dialog.hide(); - this.opts.on_update?.({ doctype: this.current_doctype, naming_series_options }); - }, - }); - }); - } -}; - -erpnext.NamingSeriesTable = class NamingSeriesTable { - constructor(opts = {}) { - this.frm = opts.frm; - this.transactions = opts.transactions || []; - this.$wrapper = opts.frm.get_field(opts.fieldname).$wrapper; - this.theme_observer = null; - } - render() { - this.$wrapper.html(` -
- - - - - - - - -
- ${__("Transaction")} - - ${__("Current Series")} -
-
- `); - - const $rows = this.$wrapper.find(".naming-series-table-rows"); - this.map_configure_button($rows); - this.get_row_data($rows); - - if (this.theme_observer) { - this.theme_observer.disconnect(); - } - - const observer = new MutationObserver(() => { - const badge_class = this.get_current_badge_class(); - - this.$wrapper.find(".badge").removeClass("badge-light badge-dark").addClass(badge_class); - }); - - observer.observe(document.documentElement, { - attributes: true, - attributeFilter: ["data-theme"], - }); - } - - map_configure_button($rows) { - $rows.on("click", ".configure-btn", (e) => { - const $btn = $(e.currentTarget); - const doctype = $btn.data("doctype"); - const label = $btn.data("label"); - - if (!this.frm._naming_dialogs) this.frm._naming_dialogs = {}; - - if (!this.frm._naming_dialogs[doctype]) { - this.frm._naming_dialogs[doctype] = new erpnext.NamingSeriesDialog({ - doctype: doctype, - title: __("{0} Naming Series", [__(label)]), - on_update: ({ naming_series_options }) => { - const series = naming_series_options.split("\n").filter(Boolean); - this.$wrapper - .find(`.series-cell-${frappe.scrub(doctype)}`) - .html(this.series_list_background(series)); - }, - }); - } - - this.frm._naming_dialogs[doctype].show(); - }); - } - - async get_row_data($rows) { - const rows = await Promise.all( - this.transactions.map(async (t) => { - await new Promise((resolve) => frappe.model.with_doctype(t.doctype, resolve)); - - const meta = frappe.get_meta(t.doctype); - const naming_df = (meta?.fields || []).find((df) => df.fieldname === "naming_series"); - const series = (naming_df?.options || "") - .split("\n") - .map((s) => s.trim()) - .filter(Boolean); - - return this.make_row(t, series); - }) - ); - - $rows.empty(); - rows.forEach(($row) => $rows.append($row)); - } - - make_row(t, series) { - return $(` - - - ${frappe.utils.escape_html(t.label)} - - - ${this.series_list_background(series)} - - - - ${frappe.utils.icon("edit", "sm")} - - - - `); - } - - get_current_badge_class() { - return document.documentElement.getAttribute("data-theme") === "dark" ? "badge-dark" : "badge-light"; - } - - series_list_background(series_list) { - if (!series_list.length) { - return `${__("Not configured")}`; - } - - const badge_class = this.get_current_badge_class(); - - return series_list - .map( - (s) => ` - ${frappe.utils.escape_html(s)} - ` - ) - .join(""); - } -}; - -/** - * @param {Object} frm - Frappe form instance. - */ -erpnext.NamingSeriesController = class NamingSeriesController { - constructor(frm) { - this.frm = frm; - } - - /** - * Renders the naming series table in the given field. - * - * @param {string} fieldname - Fieldname where the table should be rendered. - * @param {Array<{doctype: string, label: string}>} [transactions=[]] - Transactions to display. - * @returns {void} - */ - render_table(fieldname, transactions = []) { - this.frm._naming_series_table = new erpnext.NamingSeriesTable({ - frm: this.frm, - fieldname: fieldname, - transactions: transactions, - }); - this.frm._naming_series_table.render(); - } - - /** - * Loads naming series from the given master doctype into a field. - * - * @param {string} doctype - Master doctype name. - * @param {string} field - Fieldname where series should be shown. - * @returns {void} - */ - load_master_series(doctype, field) { - frappe.model.with_doctype(doctype, () => { - const meta = frappe.get_meta(doctype); - const naming_df = (meta?.fields || []).find((df) => df.fieldname === "naming_series"); - const options = naming_df?.options || ""; - const series_list = options - .split("\n") - .map((s) => s.trim()) - .filter(Boolean); - - this.frm.doc[field] = series_list.length - ? series_list.join("\n") - : __("No naming series defined"); - this.frm.refresh_field(field); - }); - } - - /** - * Opens the naming series dialog for a doctype. - * - * @param {string} doctype - Transaction doctype. - * @param {Function} [on_update] - Called after series are updated. - * @returns {void} - */ - show_naming_series_dialog(doctype, on_update) { - if (!this.frm._naming_dialogs) this.frm._naming_dialogs = {}; - - if (!this.frm._naming_dialogs[doctype]) { - this.frm._naming_dialogs[doctype] = new erpnext.NamingSeriesDialog({ - doctype: doctype, - title: __("{0} Naming Series", [__(doctype)]), - on_update: ({ naming_series_options }) => { - const series = naming_series_options.split("\n").filter(Boolean); - this.frm - .get_field(this.opts.table_field) - .$wrapper.find(`.series-cell-${frappe.scrub(doctype)}`) - .html(this.frm._naming_series_table?.series_list_background(series)); - on_update?.({ doctype, naming_series_options }); - }, - }); - } - - this.frm._naming_dialogs[doctype].show(); - } -}; diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.js b/erpnext/selling/doctype/selling_settings/selling_settings.js index ce22db3fff0..9ffe9390a24 100644 --- a/erpnext/selling/doctype/selling_settings/selling_settings.js +++ b/erpnext/selling/doctype/selling_settings/selling_settings.js @@ -3,7 +3,7 @@ frappe.ui.form.on("Selling Settings", { refresh(frm) { - if (!frm.naming_controller) frm.naming_controller = new erpnext.NamingSeriesController(frm); + if (!frm.naming_controller) frm.naming_controller = new frappe.ui.NamingSeriesController(frm); const display = frm.doc.cust_master_name === "Naming Series"; frm.set_df_property("naming_series_details", "hidden", !display); diff --git a/erpnext/stock/doctype/stock_settings/stock_settings.js b/erpnext/stock/doctype/stock_settings/stock_settings.js index e6289b1cca8..3d70c199d05 100644 --- a/erpnext/stock/doctype/stock_settings/stock_settings.js +++ b/erpnext/stock/doctype/stock_settings/stock_settings.js @@ -14,7 +14,7 @@ frappe.ui.form.on("Stock Settings", { frm.set_query("default_warehouse", filters); frm.set_query("sample_retention_warehouse", filters); - if (!frm.naming_controller) frm.naming_controller = new erpnext.NamingSeriesController(frm); + if (!frm.naming_controller) frm.naming_controller = new frappe.ui.NamingSeriesController(frm); const item_display = frm.doc.item_naming_by === "Naming Series"; const serial_and_batch_naming_display = frm.doc.set_serial_and_batch_bundle_naming_based_on_naming_series;