Skip to content

Commit 2a8dbc5

Browse files
feat: new DocTypes "Code List" and "Common Code" (#43425)
Co-authored-by: David <[email protected]>
1 parent d3fb375 commit 2a8dbc5

18 files changed

+914
-0
lines changed

erpnext/edi/__init__.py

Whitespace-only changes.

erpnext/edi/doctype/__init__.py

Whitespace-only changes.

erpnext/edi/doctype/code_list/__init__.py

Whitespace-only changes.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
2+
// For license information, please see license.txt
3+
4+
frappe.ui.form.on("Code List", {
5+
refresh: (frm) => {
6+
if (!frm.doc.__islocal) {
7+
frm.add_custom_button(__("Import Genericode File"), function () {
8+
erpnext.edi.import_genericode(frm);
9+
});
10+
}
11+
},
12+
setup: (frm) => {
13+
frm.savetrash = () => {
14+
frm.validate_form_action("Delete");
15+
frappe.confirm(
16+
__(
17+
"Are you sure you want to delete {0}?<p>This action will also delete all associated Common Code documents.</p>",
18+
[frm.docname.bold()]
19+
),
20+
function () {
21+
return frappe.call({
22+
method: "frappe.client.delete",
23+
args: {
24+
doctype: frm.doctype,
25+
name: frm.docname,
26+
},
27+
freeze: true,
28+
freeze_message: __("Deleting {0} and all associated Common Code documents...", [
29+
frm.docname,
30+
]),
31+
callback: function (r) {
32+
if (!r.exc) {
33+
frappe.utils.play_sound("delete");
34+
frappe.model.clear_doc(frm.doctype, frm.docname);
35+
window.history.back();
36+
}
37+
},
38+
});
39+
}
40+
);
41+
};
42+
43+
frm.set_query("default_common_code", function (doc) {
44+
return {
45+
filters: {
46+
code_list: doc.name,
47+
},
48+
};
49+
});
50+
},
51+
});
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
{
2+
"actions": [],
3+
"allow_copy": 1,
4+
"allow_rename": 1,
5+
"autoname": "prompt",
6+
"creation": "2024-09-29 06:55:03.920375",
7+
"doctype": "DocType",
8+
"engine": "InnoDB",
9+
"field_order": [
10+
"title",
11+
"canonical_uri",
12+
"url",
13+
"default_common_code",
14+
"column_break_nkls",
15+
"version",
16+
"publisher",
17+
"publisher_id",
18+
"section_break_npxp",
19+
"description"
20+
],
21+
"fields": [
22+
{
23+
"fieldname": "title",
24+
"fieldtype": "Data",
25+
"label": "Title"
26+
},
27+
{
28+
"fieldname": "publisher",
29+
"fieldtype": "Data",
30+
"in_standard_filter": 1,
31+
"label": "Publisher"
32+
},
33+
{
34+
"columns": 1,
35+
"fieldname": "version",
36+
"fieldtype": "Data",
37+
"in_list_view": 1,
38+
"label": "Version"
39+
},
40+
{
41+
"fieldname": "description",
42+
"fieldtype": "Small Text",
43+
"label": "Description"
44+
},
45+
{
46+
"fieldname": "canonical_uri",
47+
"fieldtype": "Data",
48+
"in_list_view": 1,
49+
"label": "Canonical URI"
50+
},
51+
{
52+
"fieldname": "column_break_nkls",
53+
"fieldtype": "Column Break"
54+
},
55+
{
56+
"fieldname": "section_break_npxp",
57+
"fieldtype": "Section Break"
58+
},
59+
{
60+
"fieldname": "publisher_id",
61+
"fieldtype": "Data",
62+
"in_standard_filter": 1,
63+
"label": "Publisher ID"
64+
},
65+
{
66+
"fieldname": "url",
67+
"fieldtype": "Data",
68+
"label": "URL",
69+
"options": "URL"
70+
},
71+
{
72+
"description": "This value shall be used when no matching Common Code for a record is found.",
73+
"fieldname": "default_common_code",
74+
"fieldtype": "Link",
75+
"label": "Default Common Code",
76+
"options": "Common Code"
77+
}
78+
],
79+
"index_web_pages_for_search": 1,
80+
"links": [
81+
{
82+
"link_doctype": "Common Code",
83+
"link_fieldname": "code_list"
84+
}
85+
],
86+
"modified": "2024-11-16 17:01:40.260293",
87+
"modified_by": "Administrator",
88+
"module": "EDI",
89+
"name": "Code List",
90+
"naming_rule": "Set by user",
91+
"owner": "Administrator",
92+
"permissions": [
93+
{
94+
"create": 1,
95+
"delete": 1,
96+
"email": 1,
97+
"export": 1,
98+
"print": 1,
99+
"read": 1,
100+
"report": 1,
101+
"role": "System Manager",
102+
"share": 1,
103+
"write": 1
104+
}
105+
],
106+
"search_fields": "description",
107+
"show_title_field_in_link": 1,
108+
"sort_field": "creation",
109+
"sort_order": "DESC",
110+
"states": [],
111+
"title_field": "title"
112+
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
2+
# For license information, please see license.txt
3+
4+
from typing import TYPE_CHECKING
5+
6+
import frappe
7+
from frappe.model.document import Document
8+
9+
if TYPE_CHECKING:
10+
from lxml.etree import Element
11+
12+
13+
class CodeList(Document):
14+
# begin: auto-generated types
15+
# This code is auto-generated. Do not modify anything in this block.
16+
17+
from typing import TYPE_CHECKING
18+
19+
if TYPE_CHECKING:
20+
from frappe.types import DF
21+
22+
canonical_uri: DF.Data | None
23+
default_common_code: DF.Link | None
24+
description: DF.SmallText | None
25+
publisher: DF.Data | None
26+
publisher_id: DF.Data | None
27+
title: DF.Data | None
28+
url: DF.Data | None
29+
version: DF.Data | None
30+
# end: auto-generated types
31+
32+
def on_trash(self):
33+
if not frappe.flags.in_bulk_delete:
34+
self.__delete_linked_docs()
35+
36+
def __delete_linked_docs(self):
37+
self.db_set("default_common_code", None)
38+
39+
linked_docs = frappe.get_all(
40+
"Common Code",
41+
filters={"code_list": self.name},
42+
fields=["name"],
43+
)
44+
45+
for doc in linked_docs:
46+
frappe.delete_doc("Common Code", doc.name)
47+
48+
def get_codes_for(self, doctype: str, name: str) -> tuple[str]:
49+
"""Get the applicable codes for a doctype and name"""
50+
return get_codes_for(self.name, doctype, name)
51+
52+
def get_docnames_for(self, doctype: str, code: str) -> tuple[str]:
53+
"""Get the mapped docnames for a doctype and code"""
54+
return get_docnames_for(self.name, doctype, code)
55+
56+
def get_default_code(self) -> str | None:
57+
"""Get the default common code for this code list"""
58+
return (
59+
frappe.db.get_value("Common Code", self.default_common_code, "common_code")
60+
if self.default_common_code
61+
else None
62+
)
63+
64+
def from_genericode(self, root: "Element"):
65+
"""Extract Code List details from genericode XML"""
66+
self.title = root.find(".//Identification/ShortName").text
67+
self.version = root.find(".//Identification/Version").text
68+
self.canonical_uri = root.find(".//CanonicalUri").text
69+
# optionals
70+
self.description = getattr(root.find(".//Identification/LongName"), "text", None)
71+
self.publisher = getattr(root.find(".//Identification/Agency/ShortName"), "text", None)
72+
if not self.publisher:
73+
self.publisher = getattr(root.find(".//Identification/Agency/LongName"), "text", None)
74+
self.publisher_id = getattr(root.find(".//Identification/Agency/Identifier"), "text", None)
75+
self.url = getattr(root.find(".//Identification/LocationUri"), "text", None)
76+
77+
78+
def get_codes_for(code_list: str, doctype: str, name: str) -> tuple[str]:
79+
"""Return the common code for a given record"""
80+
CommonCode = frappe.qb.DocType("Common Code")
81+
DynamicLink = frappe.qb.DocType("Dynamic Link")
82+
83+
codes = (
84+
frappe.qb.from_(CommonCode)
85+
.join(DynamicLink)
86+
.on((CommonCode.name == DynamicLink.parent) & (DynamicLink.parenttype == "Common Code"))
87+
.select(CommonCode.common_code)
88+
.where(
89+
(DynamicLink.link_doctype == doctype)
90+
& (DynamicLink.link_name == name)
91+
& (CommonCode.code_list == code_list)
92+
)
93+
.distinct()
94+
.orderby(CommonCode.common_code)
95+
).run()
96+
97+
return tuple(c[0] for c in codes) if codes else ()
98+
99+
100+
def get_docnames_for(code_list: str, doctype: str, code: str) -> tuple[str]:
101+
"""Return the record name for a given common code"""
102+
CommonCode = frappe.qb.DocType("Common Code")
103+
DynamicLink = frappe.qb.DocType("Dynamic Link")
104+
105+
docnames = (
106+
frappe.qb.from_(CommonCode)
107+
.join(DynamicLink)
108+
.on((CommonCode.name == DynamicLink.parent) & (DynamicLink.parenttype == "Common Code"))
109+
.select(DynamicLink.link_name)
110+
.where(
111+
(DynamicLink.link_doctype == doctype)
112+
& (CommonCode.common_code == code)
113+
& (CommonCode.code_list == code_list)
114+
)
115+
.distinct()
116+
.orderby(DynamicLink.idx)
117+
).run()
118+
119+
return tuple(d[0] for d in docnames) if docnames else ()
120+
121+
122+
def get_default_code(code_list: str) -> str | None:
123+
"""Return the default common code for a given code list"""
124+
code_id = frappe.db.get_value("Code List", code_list, "default_common_code")
125+
return frappe.db.get_value("Common Code", code_id, "common_code") if code_id else None

0 commit comments

Comments
 (0)