diff --git a/erpnext/edi/doctype/code_list/code_list.js b/erpnext/edi/doctype/code_list/code_list.js index af804c3e5254..16a8a9e9fac2 100644 --- a/erpnext/edi/doctype/code_list/code_list.js +++ b/erpnext/edi/doctype/code_list/code_list.js @@ -1,8 +1,45 @@ // Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors // For license information, please see license.txt -// frappe.ui.form.on("Code List", { -// refresh(frm) { - -// }, -// }); +frappe.ui.form.on("Code List", { + refresh: (frm) => { + frm.add_custom_button( + __("Genericode"), + function () { + erpnext.edi.import_genericode(frm); + }, + __("Import") + ); + }, + setup: (frm) => { + frm.savetrash = () => { + frm.validate_form_action("Delete"); + frappe.confirm( + __( + "Are you sure you want to delete {0}?
This action will also delete all associated Common Code documents.
", + [frm.docname.bold()] + ), + function () { + return frappe.call({ + method: "frappe.client.delete", + args: { + doctype: frm.doctype, + name: frm.docname, + }, + freeze: true, + freeze_message: __("Deleting {0} and all associated Common Code documents...", [ + frm.docname, + ]), + callback: function (r) { + if (!r.exc) { + frappe.utils.play_sound("delete"); + frappe.model.clear_doc(frm.doctype, frm.docname); + window.history.back(); + } + }, + }); + } + ); + }; + }, +}); diff --git a/erpnext/edi/doctype/code_list/code_list.json b/erpnext/edi/doctype/code_list/code_list.json index 6da9dbbcb23c..15ce92321c44 100644 --- a/erpnext/edi/doctype/code_list/code_list.json +++ b/erpnext/edi/doctype/code_list/code_list.json @@ -1,5 +1,6 @@ { "actions": [], + "allow_copy": 1, "allow_rename": 1, "autoname": "prompt", "creation": "2024-09-29 06:55:03.920375", @@ -7,8 +8,11 @@ "engine": "InnoDB", "field_order": [ "title", - "publisher", + "canonical_uri", + "column_break_nkls", "version", + "publisher", + "section_break_npxp", "description" ], "fields": [ @@ -24,6 +28,7 @@ "label": "Publisher" }, { + "columns": 1, "fieldname": "version", "fieldtype": "Data", "in_list_view": 1, @@ -33,6 +38,20 @@ "fieldname": "description", "fieldtype": "Small Text", "label": "Description" + }, + { + "fieldname": "canonical_uri", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Canonical URI" + }, + { + "fieldname": "column_break_nkls", + "fieldtype": "Column Break" + }, + { + "fieldname": "section_break_npxp", + "fieldtype": "Section Break" } ], "index_web_pages_for_search": 1, @@ -42,7 +61,7 @@ "link_fieldname": "code_list" } ], - "modified": "2024-09-29 07:24:21.123903", + "modified": "2024-09-29 22:46:37.878075", "modified_by": "Administrator", "module": "EDI", "name": "Code List", @@ -66,4 +85,4 @@ "sort_order": "DESC", "states": [], "title_field": "title" -} +} \ No newline at end of file diff --git a/erpnext/edi/doctype/code_list/code_list.py b/erpnext/edi/doctype/code_list/code_list.py index a8300a9114d5..d01fa7d69301 100644 --- a/erpnext/edi/doctype/code_list/code_list.py +++ b/erpnext/edi/doctype/code_list/code_list.py @@ -3,6 +3,9 @@ import frappe from frappe.model.document import Document +from lxml import etree + +from erpnext.edi.doctype.common_code.common_code import CommonCode class CodeList(Document): @@ -14,12 +17,27 @@ class CodeList(Document): if TYPE_CHECKING: from frappe.types import DF + canonical_uri: DF.Data | None description: DF.SmallText | None publisher: DF.Data | None title: DF.Data | None version: DF.Data | None # end: auto-generated types + def on_trash(self): + if not frappe.flags.in_bulk_delete: + self.__delete_linked_docs() + + def __delete_linked_docs(self): + linked_docs = frappe.get_all( + "Common Code", + filters={"code_list": self.name}, + fields=["name"], + ) + + for doc in linked_docs: + frappe.delete_doc("Common Code", doc.name, force=1) + def get_code_for(self, doctype: str, name: str): """Get code for a doctype and name""" CommonCode = frappe.qb.DocType("Common Code") @@ -38,3 +56,31 @@ def get_code_for(self, doctype: str, name: str): ).run() return code[0][0] if code else None + + def import_genericode(self, file_path, code_column, title_column=None, filters=None): + """Import genericode file and create Common Code entries""" + parser = etree.XMLParser(remove_blank_text=True) + tree = etree.parse(file_path, parser=parser) + root = tree.getroot() + + # Extract Code List details + self.title = root.find(".//Identification/ShortName").text + self.version = root.find(".//Identification/Version").text + self.canonical_uri = root.find(".//CanonicalUri").text + # optionals + self.description = getattr(root.find(".//Identification/LongName"), "text", None) + self.publisher = getattr(root.find(".//Identification/Agency/ShortName"), "text", None) + + self.save() + + common_codes = CommonCode.import_genericode(file_path, self.name, code_column, title_column, filters) + + # Bulk insert common codes + if common_codes: + frappe.db.bulk_insert( + "Common Code", + fields=["name", "code_list", "common_code", "title"], + values=[(cc["name"], cc["code_list"], cc["common_code"], cc["title"]) for cc in common_codes], + ) + + return {"code_list": self, "common_codes_count": len(common_codes)} diff --git a/erpnext/edi/doctype/code_list/code_list_import.js b/erpnext/edi/doctype/code_list/code_list_import.js new file mode 100644 index 000000000000..73092758dafa --- /dev/null +++ b/erpnext/edi/doctype/code_list/code_list_import.js @@ -0,0 +1,160 @@ +frappe.provide("erpnext.edi"); + +erpnext.edi.import_genericode = function (listview_or_form) { + let doctype = "Code List"; + let docname = undefined; + if (listview_or_form.doc !== undefined) { + docname = listview_or_form.doc.name; + } + new frappe.ui.FileUploader({ + method: "erpnext.edi.doctype.code_list.code_list_import.import_genericode", + doctype: doctype, + docname: docname, + allow_toggle_private: false, + on_success: function (_file_doc, r) { + listview_or_form.refresh(); + show_column_selection_dialog(r.message); + }, + }); +}; + +function show_column_selection_dialog(context) { + let fields = [ + { + fieldname: "import_column", + label: __("Import"), + fieldtype: "Column Break", + }, + { + fieldname: "title_column", + label: __("as Title"), + fieldtype: "Select", + options: [null].concat(context.columns), + }, + { + fieldname: "code_column", + label: __("as Code"), + fieldtype: "Select", + options: context.columns, + reqd: 1, + }, + { + fieldname: "filters_column", + label: __("Filter"), + fieldtype: "Column Break", + }, + ]; + + // Add filterable columns + for (let column in context.filterable_columns) { + fields.push({ + fieldname: `filter_${column}`, + label: __(`by ${column}`), + fieldtype: "Select", + options: [null].concat(context.filterable_columns[column]), + }); + } + + fields.push( + { + fieldname: "preview_section", + label: __("Preview"), + fieldtype: "Section Break", + }, + { + fieldname: "preview_html", + fieldtype: "HTML", + } + ); + + let d = new frappe.ui.Dialog({ + title: __("Select Columns and Filters"), + fields: fields, + primary_action_label: __("Import"), + size: "large", // This will make the modal wider + primary_action(values) { + let filters = {}; + for (let field in values) { + if (field.startsWith("filter_") && values[field]) { + filters[field.replace("filter_", "")] = values[field]; + } + } + frappe.call({ + method: "erpnext.edi.doctype.code_list.code_list_import.process_genericode_import", + args: { + code_list_name: context.code_list, + file_path: context.file_path, + code_column: values.code_column, + title_column: values.title_column, + filters: filters, + }, + callback: function (r) { + frappe.msgprint( + __("Import completed. {0} common codes created.", [r.message.common_codes_count]) + ); + }, + }); + d.hide(); + }, + }); + + d.fields_dict.code_column.df.onchange = () => update_preview(d, context); + d.fields_dict.title_column.df.onchange = () => update_preview(d, context); + + // Add onchange events for filterable columns + for (let column in context.filterable_columns) { + d.fields_dict[`filter_${column}`].df.onchange = () => update_preview(d, context); + } + + d.show(); + update_preview(d, context); +} + +function update_preview(dialog, context) { + let code_column = dialog.get_value("code_column"); + let title_column = dialog.get_value("title_column"); + + let html = '${__("Title")} | `; + if (code_column) html += `${__("Code")} | `; + + // Add headers for filterable columns + for (let column in context.filterable_columns) { + if (dialog.get_value(`filter_${column}`)) { + html += `${__(column)} | `; + } + } + + html += "
---|---|---|
${truncate(title)} | `; + } + if (code_column) { + let code = context.example_values[code_column][i] || ""; + html += `${truncate(code)} | `; + } + + // Add values for filterable columns + for (let column in context.filterable_columns) { + if (dialog.get_value(`filter_${column}`)) { + let value = context.example_values[column][i] || ""; + html += `${truncate(value)} | `; + } + } + + html += "
{}
"
+ ).format(code_column, escape_html(content))
+ )
+ seen_common_codes.add(code_value)
+ code_hash = CommonCode.simple_hash(code_value, 10)
+
+ title = None
+ if title_column:
+ title = code.find(f"./Value[@ColumnRef='{title_column}']/SimpleValue").text
+
+ codes.append(
+ {
+ "name": f"{list_hash}|{code_hash}|{idx}", # according to autoname + row index
+ "code_list": list_name,
+ "common_code": code_value,
+ "title": title,
+ "additional_data": content,
+ }
+ )
+
+ return codes
+
def on_doctype_update():
frappe.db.add_unique(
diff --git a/erpnext/edi/doctype/common_code/common_code_list.js b/erpnext/edi/doctype/common_code/common_code_list.js
new file mode 100644
index 000000000000..71b036f1f162
--- /dev/null
+++ b/erpnext/edi/doctype/common_code/common_code_list.js
@@ -0,0 +1,12 @@
+frappe.listview_settings["Common Code"] = {
+ onload: function (listview) {
+ listview.page.add_inner_button(
+ __("Genericode"),
+ function () {
+ erpnext.edi.import_genericode(listview);
+ },
+ __("Import")
+ );
+ },
+ hide_name_column: true,
+};
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 059075fe321d..ca7f72809434 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -35,6 +35,14 @@
"Newsletter": "public/js/newsletter.js",
"Contact": "public/js/contact.js",
}
+doctype_list_js = {
+ "Code List": [
+ "edi/doctype/code_list/code_list_import.js",
+ ],
+ "Common Code": [
+ "edi/doctype/code_list/code_list_import.js",
+ ],
+}
override_doctype_class = {"Address": "erpnext.accounts.custom.address.ERPNextAddress"}