Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: new DocTypes "Code List" and "Common Code" #43425

Open
wants to merge 25 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
0c76edd
feat: new DocTypes "Code List" and "Common Code"
barredterra Sep 29, 2024
85ef706
feat: add Common Code to Code List's connections
barredterra Sep 29, 2024
e871069
fix(Common Code): naming and unique constraint
barredterra Sep 29, 2024
f8d1751
feat(Common Code): add nicer, user-facing uniqueness validation
barredterra Sep 29, 2024
b83efa1
refactor: create edi module
blaggacao Sep 29, 2024
ed947d9
feat: Add index for code_list and common_code in CommonCode doctype
blaggacao Sep 29, 2024
8123c12
feat: add genericode importers
blaggacao Sep 29, 2024
33cb489
feat: validate distinct references
barredterra Sep 30, 2024
d6991de
fix: additional data import
blaggacao Sep 30, 2024
dc9fdb0
style: semgrep
blaggacao Sep 30, 2024
e39d56f
fix: show title field in links
blaggacao Sep 30, 2024
22af1eb
fix: add agency id and fall back to longname on agency
blaggacao Oct 1, 2024
d540d03
fix: gacefully handle parsing errors
blaggacao Oct 1, 2024
454518b
feat: add column selection heuristics
blaggacao Oct 1, 2024
05d0fd1
feat: add optional code list URL
blaggacao Oct 1, 2024
4b15e69
fix: guard against undeclared columns
blaggacao Oct 1, 2024
8f28447
fix: creation tracking
blaggacao Oct 1, 2024
3040aef
fix: uniqueness on common_code does not hold true
blaggacao Oct 1, 2024
8d6aa6d
fix: add description to common code to help uniquely identify a code
blaggacao Oct 1, 2024
a508feb
fix: make additional data read-only and avoid accidential schema inva…
blaggacao Oct 1, 2024
52dcb2b
fix: add code list identifier to the import modal
blaggacao Oct 1, 2024
46ab6ef
fix(edi-import): Add description column only when more than two colum…
blaggacao Oct 1, 2024
e16533c
chore: pass already parsed root
blaggacao Oct 1, 2024
94bd743
fix(edi-import): support link & library files, too
blaggacao Oct 1, 2024
d68d808
fix(edi-import): require title on common code
blaggacao Oct 2, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added erpnext/edi/__init__.py
Empty file.
Empty file added erpnext/edi/doctype/__init__.py
Empty file.
Empty file.
45 changes: 45 additions & 0 deletions erpnext/edi/doctype/code_list/code_list.js
Original file line number Diff line number Diff line change
@@ -0,0 +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) => {
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}?<p>This action will also delete all associated Common Code documents.</p>",
[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();
}
},
});
}
);
};
},
});
103 changes: 103 additions & 0 deletions erpnext/edi/doctype/code_list/code_list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
{
"actions": [],
"allow_copy": 1,
"allow_rename": 1,
"autoname": "prompt",
"creation": "2024-09-29 06:55:03.920375",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"title",
"canonical_uri",
"url",
"column_break_nkls",
"version",
"publisher",
"publisher_id",
"section_break_npxp",
"description"
],
"fields": [
{
"fieldname": "title",
"fieldtype": "Data",
"label": "Title"
},
{
"fieldname": "publisher",
"fieldtype": "Data",
"in_standard_filter": 1,
"label": "Publisher"
},
{
"columns": 1,
"fieldname": "version",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Version"
},
{
"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"
},
{
"fieldname": "publisher_id",
"fieldtype": "Data",
"in_standard_filter": 1,
"label": "Publisher ID"
},
{
"fieldname": "url",
"fieldtype": "Data",
"label": "URL",
"options": "URL"
}
],
"index_web_pages_for_search": 1,
"links": [
{
"link_doctype": "Common Code",
"link_fieldname": "code_list"
}
],
"modified": "2024-10-01 12:32:27.990888",
"modified_by": "Administrator",
"module": "EDI",
"name": "Code List",
"naming_rule": "Set by user",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
}
],
"show_title_field_in_link": 1,
"sort_field": "creation",
"sort_order": "DESC",
"states": [],
"title_field": "title"
}
119 changes: 119 additions & 0 deletions erpnext/edi/doctype/code_list/code_list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt

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):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.

from typing import TYPE_CHECKING

if TYPE_CHECKING:
from frappe.types import DF

canonical_uri: DF.Data | None
description: DF.SmallText | None
publisher: DF.Data | None
publisher_id: DF.Data | None
title: DF.Data | None
url: 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")
DynamicLink = frappe.qb.DocType("Dynamic Link")

code = (
frappe.qb.from_(CommonCode)
.join(DynamicLink)
.on((CommonCode.name == DynamicLink.parent) & (DynamicLink.parenttype == "Common Code"))
.select(CommonCode.common_code)
.where(
(DynamicLink.link_doctype == doctype)
& (DynamicLink.link_name == name)
& (CommonCode.code_list == self.name)
)
).run()

return code[0][0] if code else None

def import_genericode(
self, file_path, code_column, title_column=None, description_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)
if not self.publisher:
self.publisher = getattr(root.find(".//Identification/Agency/LongName"), "text", None)
self.publisher_id = getattr(root.find(".//Identification/Agency/Identifier"), "text", None)
self.url = getattr(root.find(".//Identification/LocationUri"), "text", None)

self.save()

common_codes = CommonCode.import_genericode(
file_path, self.name, code_column, title_column, description_column, filters
)

# Bulk insert common codes
if common_codes:
now = frappe.utils.data.now()
user = frappe.session.user
frappe.db.bulk_insert(
"Common Code",
fields=[
"name",
"code_list",
"common_code",
"title",
"description",
"additional_data",
"owner",
"creation",
],
values=[
(
cc["name"],
cc["code_list"],
cc["common_code"],
cc["title"],
cc["description"],
cc["additional_data"],
user,
now,
)
for cc in common_codes
],
)

return {"code_list": self, "common_codes_count": len(common_codes)}
Loading
Loading