diff --git a/erpnext_germany/erpnext_germany/doctype/vat_id_check/vat_id_check.js b/erpnext_germany/erpnext_germany/doctype/vat_id_check/vat_id_check.js index 7604ba8..07c1cfb 100644 --- a/erpnext_germany/erpnext_germany/doctype/vat_id_check/vat_id_check.js +++ b/erpnext_germany/erpnext_germany/doctype/vat_id_check/vat_id_check.js @@ -3,12 +3,22 @@ frappe.ui.form.on("VAT ID Check", { setup: function (frm) { - frm.set_query("customer_address", function (doc) { + frm.add_fetch("party", "tax_id", "party_vat_id"); + + frm.set_query("party_type", function (doc) { + return { + filters: { + name: ["in", ["Customer", "Supplier"]], + }, + }; + }); + + frm.set_query("party_address", function (doc) { return { query: "frappe.contacts.doctype.address.address.address_query", filters: { - link_doctype: "Customer", - link_name: doc.customer, + link_doctype: doc.party_type, + link_name: doc.party, }, }; }); diff --git a/erpnext_germany/erpnext_germany/doctype/vat_id_check/vat_id_check.json b/erpnext_germany/erpnext_germany/doctype/vat_id_check/vat_id_check.json index 242c164..af4a5d0 100644 --- a/erpnext_germany/erpnext_germany/doctype/vat_id_check/vat_id_check.json +++ b/erpnext_germany/erpnext_germany/doctype/vat_id_check/vat_id_check.json @@ -6,9 +6,10 @@ "editable_grid": 1, "engine": "InnoDB", "field_order": [ - "customer", - "customer_vat_id", - "customer_address", + "party_type", + "party", + "party_vat_id", + "party_address", "column_break_hmgxr", "status", "section_break_6ctcl", @@ -33,14 +34,6 @@ "request_id" ], "fields": [ - { - "fieldname": "customer", - "fieldtype": "Link", - "in_standard_filter": 1, - "label": "Customer", - "options": "Customer", - "set_only_once": 1 - }, { "fieldname": "column_break_hmgxr", "fieldtype": "Column Break" @@ -83,17 +76,6 @@ "fieldtype": "Section Break", "label": "Result" }, - { - "fetch_from": "customer.tax_id", - "fetch_if_empty": 1, - "fieldname": "customer_vat_id", - "fieldtype": "Data", - "in_list_view": 1, - "in_standard_filter": 1, - "label": "Customer VAT ID", - "reqd": 1, - "set_only_once": 1 - }, { "fetch_from": "company.tax_id", "fetch_if_empty": 1, @@ -110,13 +92,6 @@ "options": "Planned\nRunning\nCompleted\nService Unavailable\nInvalid Input\nError", "read_only": 1 }, - { - "fieldname": "customer_address", - "fieldtype": "Link", - "label": "Customer Address", - "options": "Address", - "set_only_once": 1 - }, { "fetch_from": "customer.customer_name", "fetch_if_empty": 1, @@ -207,10 +182,42 @@ { "fieldname": "column_break_cjvyk", "fieldtype": "Column Break" + }, + { + "fieldname": "party_type", + "fieldtype": "Link", + "label": "Party Type", + "options": "DocType" + }, + { + "fieldname": "party", + "fieldtype": "Dynamic Link", + "in_standard_filter": 1, + "label": "Party", + "options": "party_type", + "set_only_once": 1 + }, + { + "fieldname": "party_address", + "fieldtype": "Link", + "label": "Party Address", + "options": "Address", + "set_only_once": 1 + }, + { + "fetch_from": "customer.tax_id", + "fetch_if_empty": 1, + "fieldname": "party_vat_id", + "fieldtype": "Data", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Party VAT ID", + "reqd": 1, + "set_only_once": 1 } ], "links": [], - "modified": "2023-07-14 19:27:17.103880", + "modified": "2024-01-15 19:51:41.796509", "modified_by": "Administrator", "module": "ERPNext Germany", "name": "VAT ID Check", @@ -266,5 +273,5 @@ "sort_field": "creation", "sort_order": "DESC", "states": [], - "title_field": "customer_vat_id" + "title_field": "party_vat_id" } \ No newline at end of file diff --git a/erpnext_germany/erpnext_germany/doctype/vat_id_check/vat_id_check.py b/erpnext_germany/erpnext_germany/doctype/vat_id_check/vat_id_check.py index 17822f8..1fb0c52 100644 --- a/erpnext_germany/erpnext_germany/doctype/vat_id_check/vat_id_check.py +++ b/erpnext_germany/erpnext_germany/doctype/vat_id_check/vat_id_check.py @@ -16,8 +16,8 @@ def before_insert(self): ) self.requester_vat_id = f"{requester_country_code}{requester_vat_number}" - country_code, vat_number = parse_vat_id(self.customer_vat_id) - self.customer_vat_id = f"{country_code}{vat_number}" + country_code, vat_number = parse_vat_id(self.party_vat_id) + self.party_vat_id = f"{country_code}{vat_number}" def after_insert(self): frappe.enqueue( @@ -39,7 +39,7 @@ def run_check(doc: VATIDCheck): return try: - country_code, vat_number = parse_vat_id(doc.customer_vat_id) + country_code, vat_number = parse_vat_id(doc.party_vat_id) except ValueError: doc.db_set({"status": "Invalid Input", "is_valid": False}, notify=True) return diff --git a/erpnext_germany/hooks.py b/erpnext_germany/hooks.py index 531e413..6f1ee4b 100644 --- a/erpnext_germany/hooks.py +++ b/erpnext_germany/hooks.py @@ -384,7 +384,17 @@ def get_register_fields(insert_after: str): "parenttype": "Customize Form", "group": "Pre Sales", "link_doctype": "VAT ID Check", - "link_fieldname": "customer", + "link_fieldname": "party", + "custom": 1, + }, + { + "doctype": "DocType Link", + "parent": "Supplier", + "parentfield": "links", + "parenttype": "Customize Form", + "group": "Vendor Evaluation", + "link_doctype": "VAT ID Check", + "link_fieldname": "party", "custom": 1, }, ] diff --git a/erpnext_germany/patches.txt b/erpnext_germany/patches.txt index 95ccad4..3547cd0 100644 --- a/erpnext_germany/patches.txt +++ b/erpnext_germany/patches.txt @@ -1,3 +1,7 @@ +[pre_model_sync] + +[post_model_sync] execute:from erpnext_germany.install import after_install; after_install() # 7 erpnext_germany.patches.add_tax_exemption_reason_fields execute:from erpnext_germany.install import insert_custom_records; insert_custom_records() +erpnext_germany.patches.dynamic_party_in_vat_id_check diff --git a/erpnext_germany/patches/dynamic_party_in_vat_id_check.py b/erpnext_germany/patches/dynamic_party_in_vat_id_check.py new file mode 100644 index 0000000..2f794b2 --- /dev/null +++ b/erpnext_germany/patches/dynamic_party_in_vat_id_check.py @@ -0,0 +1,41 @@ +import frappe +from frappe.model.utils.rename_field import rename_field + + +def execute(): + """Copy data to renamed fields in VAT ID Check. + + party_type -> "Customer", + customer -> party, + customer_vat_id -> party_vat_id, + customer_address -> party_address, + + Add link to Supplier connections. + Update link in Customer connections. + """ + dt = "VAT ID Check" + + frappe.db.sql("UPDATE `tabVAT ID Check` SET party_type = 'Customer'") + + rename_field(dt, "customer", "party") + rename_field(dt, "customer_vat_id", "party_vat_id") + rename_field(dt, "customer_address", "party_address") + + # Add link to Supplier connections + frappe.get_doc( + { + "doctype": "DocType Link", + "parent": "Supplier", + "parentfield": "links", + "parenttype": "Customize Form", + "group": "Vendor Evaluation", + "link_doctype": dt, + "link_fieldname": "party", + "custom": 1, + } + ).insert(ignore_if_duplicate=True) + + # Update link in Customer connections + customer_link = frappe.db.exists("DocType Link", {"link_doctype": dt, "link_fieldname": "customer"}) + if customer_link: + frappe.db.set_value("DocType Link", customer_link, "link_fieldname", "party") diff --git a/erpnext_germany/tasks.py b/erpnext_germany/tasks.py index a567046..7aa1f04 100644 --- a/erpnext_germany/tasks.py +++ b/erpnext_germany/tasks.py @@ -1,38 +1,30 @@ import frappe from erpnext import get_default_company from erpnext_germany.utils.eu_vat import parse_vat_id +from frappe.query_builder import DocType +from pypika import Interval +from pypika import functions as fn def all(): - check_some_customers() + check_some_parties() def get_customers(batch_size=4): """Return a list of n customers who didn't have their VAT ID checked in the last 3 months.""" - from frappe.query_builder import DocType - from pypika import Interval - from pypika import functions as fn - customers = DocType("Customer") - vat_id_checks = DocType("VAT ID Check") - last_check = ( - frappe.qb.from_(vat_id_checks) - .select( - vat_id_checks.customer, - fn.Max(vat_id_checks.creation).as_("creation"), - ) - .groupby(vat_id_checks.customer) - ) + last_check = get_last_check_query("Customer") return ( frappe.qb.from_(customers) .left_join(last_check) - .on(customers.name == last_check.customer) + .on(customers.name == last_check.party) .select( + fn.LiteralValue("'Customer'"), customers.name, customers.customer_name, customers.customer_primary_address, - customers.tax_id + customers.tax_id, ) .where( customers.tax_id.notnull() @@ -47,22 +39,70 @@ def get_customers(batch_size=4): ) -def check_some_customers(): +def get_suppliers(batch_size=4): + """Return a list of n suppliers who didn't have their VAT ID checked in the last 3 months.""" + suppliers = DocType("Supplier") + last_check = get_last_check_query("Supplier") + + return ( + frappe.qb.from_(suppliers) + .left_join(last_check) + .on(suppliers.name == last_check.party) + .select( + fn.LiteralValue("'Supplier'"), + suppliers.name, + suppliers.supplier_name, + suppliers.supplier_primary_address, + suppliers.tax_id, + ) + .where( + suppliers.tax_id.notnull() + & (suppliers.disabled == 0) + & ( + last_check.creation.isnull() + | (last_check.creation < fn.Now() - Interval(months=3)) + ) + ) + .limit(batch_size) + .run() + ) + + +def get_last_check_query(party_type: str): + vat_id_checks = DocType("VAT ID Check") + return ( + frappe.qb.from_(vat_id_checks) + .select( + vat_id_checks.party, + fn.Max(vat_id_checks.creation).as_("creation"), + ) + .where( + (vat_id_checks.party_type == party_type) + & (vat_id_checks.status == "Completed") + ) + .groupby(vat_id_checks.party) + ) + + +def check_some_parties(): """Check VAT IDs of customers who didn't have their VAT ID checked in the last 3 months.""" requester_vat_id = None if company := get_default_company(): requester_vat_id = frappe.get_cached_value("Company", company, "tax_id") - for customer, customer_name, primary_address, vat_id in get_customers(): + for party_type, party, party_name, primary_address, vat_id in ( + get_customers() + get_suppliers() + ): try: parse_vat_id(vat_id) except ValueError: continue doc = frappe.new_doc("VAT ID Check") - doc.customer = customer - doc.trader_name = customer_name - doc.customer_vat_id = vat_id + doc.party_type = party_type + doc.party = party + doc.trader_name = party_name + doc.party_vat_id = vat_id doc.company = company doc.requester_vat_id = requester_vat_id if primary_address: