From abeb2af0c8d876e6993ab6d5898eeb9626e7d595 Mon Sep 17 00:00:00 2001 From: kurogeek Date: Sat, 12 Sep 2026 13:13:49 +0000 Subject: [PATCH] refactor: ship Custom Fields and Property Setters as module customizations Move the Sales Invoice withholding fields and both Property Setters from fixtures to default_thai_company/custom/{sales_invoice,payment_entry}.json with sync_on_migrate. sync_customizations updates Custom Fields in place instead of the delete/re-insert that fixtures do on every migrate. --- .../custom/payment_entry.json | 32 +++ .../custom/sales_invoice.json | 225 ++++++++++++++++++ .../fixtures/custom_field.json | 50 ---- .../fixtures/property_setter.json | 34 --- default_thai_company/hooks.py | 29 +-- .../tests/test_tax_withholding.py | 10 +- 6 files changed, 266 insertions(+), 114 deletions(-) create mode 100644 default_thai_company/default_thai_company/custom/payment_entry.json create mode 100644 default_thai_company/default_thai_company/custom/sales_invoice.json delete mode 100644 default_thai_company/fixtures/custom_field.json delete mode 100644 default_thai_company/fixtures/property_setter.json diff --git a/default_thai_company/default_thai_company/custom/payment_entry.json b/default_thai_company/default_thai_company/custom/payment_entry.json new file mode 100644 index 0000000..8a3b20e --- /dev/null +++ b/default_thai_company/default_thai_company/custom/payment_entry.json @@ -0,0 +1,32 @@ +{ + "custom_fields": [], + "custom_perms": [], + "doctype": "Payment Entry", + "links": [], + "property_setters": [ + { + "_assign": null, + "_comments": null, + "_liked_by": null, + "_user_tags": null, + "creation": "2026-09-11 17:18:28.670630", + "default_value": null, + "doc_type": "Payment Entry", + "docstatus": 0, + "doctype_or_field": "DocField", + "field_name": "apply_tax_withholding_amount", + "idx": 0, + "is_system_generated": 0, + "modified": "2026-09-11 12:00:00", + "modified_by": "Administrator", + "module": null, + "name": "Payment Entry-apply_tax_withholding_amount-depends_on", + "owner": "Administrator", + "property": "depends_on", + "property_type": "Data", + "row_name": null, + "value": "eval:doc.party_type == 'Supplier' || (doc.party_type == 'Customer' && doc.payment_type == 'Receive')" + } + ], + "sync_on_migrate": 1 +} diff --git a/default_thai_company/default_thai_company/custom/sales_invoice.json b/default_thai_company/default_thai_company/custom/sales_invoice.json new file mode 100644 index 0000000..ccc5bd6 --- /dev/null +++ b/default_thai_company/default_thai_company/custom/sales_invoice.json @@ -0,0 +1,225 @@ +{ + "custom_fields": [ + { + "_assign": null, + "_comments": null, + "_liked_by": null, + "_user_tags": null, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 1, + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "creation": "2026-09-11 17:18:48.182536", + "default": null, + "depends_on": "eval:doc.tax_withholding_category", + "description": null, + "docstatus": 0, + "dt": "Sales Invoice", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "amount_after_withholding", + "fieldtype": "Currency", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "idx": 80, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "withholding_tax_amount", + "is_system_generated": 0, + "is_virtual": 0, + "label": "Net Payable After Withholding Tax", + "length": 0, + "link_filters": null, + "mandatory_depends_on": null, + "modified": "2026-09-11 17:18:48.182536", + "modified_by": "Administrator", + "module": null, + "name": "Sales Invoice-amount_after_withholding", + "no_copy": 1, + "non_negative": 0, + "options": "currency", + "owner": "Administrator", + "permlevel": 0, + "placeholder": null, + "precision": null, + "print_hide": 0, + "print_hide_if_no_value": 1, + "print_width": null, + "read_only": 1, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "show_dashboard": 0, + "sort_options": 0, + "translatable": 0, + "unique": 0, + "width": null + }, + { + "_assign": null, + "_comments": null, + "_liked_by": null, + "_user_tags": null, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "creation": "2026-09-11 17:18:44.710456", + "default": null, + "depends_on": null, + "description": null, + "docstatus": 0, + "dt": "Sales Invoice", + "fetch_from": "customer.tax_withholding_category", + "fetch_if_empty": 1, + "fieldname": "tax_withholding_category", + "fieldtype": "Link", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "idx": 57, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "taxes_and_charges", + "is_system_generated": 0, + "is_virtual": 0, + "label": "Tax Withholding Category", + "length": 0, + "link_filters": null, + "mandatory_depends_on": null, + "modified": "2026-09-11 18:00:00", + "modified_by": "Administrator", + "module": null, + "name": "Sales Invoice-tax_withholding_category", + "no_copy": 0, + "non_negative": 0, + "options": "Tax Withholding Category", + "owner": "Administrator", + "permlevel": 0, + "placeholder": null, + "precision": null, + "print_hide": 1, + "print_hide_if_no_value": 0, + "print_width": null, + "read_only": 0, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "show_dashboard": 0, + "sort_options": 0, + "translatable": 0, + "unique": 0, + "width": null + }, + { + "_assign": null, + "_comments": null, + "_liked_by": null, + "_user_tags": null, + "allow_in_quick_entry": 0, + "allow_on_submit": 0, + "bold": 0, + "collapsible": 0, + "collapsible_depends_on": null, + "columns": 0, + "creation": "2026-09-11 17:18:47.244523", + "default": null, + "depends_on": "eval:doc.tax_withholding_category", + "description": null, + "docstatus": 0, + "dt": "Sales Invoice", + "fetch_from": null, + "fetch_if_empty": 0, + "fieldname": "withholding_tax_amount", + "fieldtype": "Currency", + "hidden": 0, + "hide_border": 0, + "hide_days": 0, + "hide_seconds": 0, + "idx": 79, + "ignore_user_permissions": 0, + "ignore_xss_filter": 0, + "in_global_search": 0, + "in_list_view": 0, + "in_preview": 0, + "in_standard_filter": 0, + "insert_after": "rounded_total", + "is_system_generated": 0, + "is_virtual": 0, + "label": "Withholding Tax", + "length": 0, + "link_filters": null, + "mandatory_depends_on": null, + "modified": "2026-09-11 18:00:00", + "modified_by": "Administrator", + "module": null, + "name": "Sales Invoice-withholding_tax_amount", + "no_copy": 1, + "non_negative": 0, + "options": "currency", + "owner": "Administrator", + "permlevel": 0, + "placeholder": null, + "precision": null, + "print_hide": 0, + "print_hide_if_no_value": 1, + "print_width": null, + "read_only": 1, + "read_only_depends_on": null, + "report_hide": 0, + "reqd": 0, + "search_index": 0, + "show_dashboard": 0, + "sort_options": 0, + "translatable": 0, + "unique": 0, + "width": null + } + ], + "custom_perms": [], + "doctype": "Sales Invoice", + "links": [], + "property_setters": [ + { + "_assign": null, + "_comments": null, + "_liked_by": null, + "_user_tags": null, + "creation": "2026-09-11 17:18:28.581896", + "default_value": null, + "doc_type": "Sales Invoice", + "docstatus": 0, + "doctype_or_field": "DocType", + "field_name": null, + "idx": 0, + "is_system_generated": 1, + "modified": "2026-09-10 13:55:13.996942", + "modified_by": "Administrator", + "module": null, + "name": "Sales Invoice-main-default_print_format", + "owner": "Administrator", + "property": "default_print_format", + "property_type": "Data", + "row_name": null, + "value": "Default Standard Sales Invoice" + } + ], + "sync_on_migrate": 1 +} diff --git a/default_thai_company/fixtures/custom_field.json b/default_thai_company/fixtures/custom_field.json deleted file mode 100644 index 0329ce5..0000000 --- a/default_thai_company/fixtures/custom_field.json +++ /dev/null @@ -1,50 +0,0 @@ -[ - { - "docstatus": 0, - "doctype": "Custom Field", - "dt": "Sales Invoice", - "fetch_from": "customer.tax_withholding_category", - "fetch_if_empty": 1, - "fieldname": "tax_withholding_category", - "fieldtype": "Link", - "insert_after": "taxes_and_charges", - "label": "Tax Withholding Category", - "modified": "2026-09-11 18:00:00.000000", - "name": "Sales Invoice-tax_withholding_category", - "options": "Tax Withholding Category", - "print_hide": 1 - }, - { - "depends_on": "eval:doc.tax_withholding_category", - "docstatus": 0, - "doctype": "Custom Field", - "dt": "Sales Invoice", - "fieldname": "withholding_tax_amount", - "fieldtype": "Currency", - "insert_after": "rounded_total", - "label": "Withholding Tax", - "modified": "2026-09-11 18:00:00.000000", - "name": "Sales Invoice-withholding_tax_amount", - "no_copy": 1, - "options": "currency", - "print_hide_if_no_value": 1, - "read_only": 1 - }, - { - "bold": 1, - "depends_on": "eval:doc.tax_withholding_category", - "docstatus": 0, - "doctype": "Custom Field", - "dt": "Sales Invoice", - "fieldname": "amount_after_withholding", - "fieldtype": "Currency", - "insert_after": "withholding_tax_amount", - "label": "Net Payable After Withholding Tax", - "modified": "2026-09-11 18:00:00.000000", - "name": "Sales Invoice-amount_after_withholding", - "no_copy": 1, - "options": "currency", - "print_hide_if_no_value": 1, - "read_only": 1 - } -] diff --git a/default_thai_company/fixtures/property_setter.json b/default_thai_company/fixtures/property_setter.json deleted file mode 100644 index 5f8fdef..0000000 --- a/default_thai_company/fixtures/property_setter.json +++ /dev/null @@ -1,34 +0,0 @@ -[ - { - "default_value": null, - "doc_type": "Sales Invoice", - "docstatus": 0, - "doctype": "Property Setter", - "doctype_or_field": "DocType", - "field_name": null, - "is_system_generated": 1, - "modified": "2026-09-10 13:55:13.996942", - "module": null, - "name": "Sales Invoice-main-default_print_format", - "property": "default_print_format", - "property_type": "Data", - "row_name": null, - "value": "Default Standard Sales Invoice" - }, - { - "default_value": null, - "doc_type": "Payment Entry", - "docstatus": 0, - "doctype": "Property Setter", - "doctype_or_field": "DocField", - "field_name": "apply_tax_withholding_amount", - "is_system_generated": 0, - "modified": "2026-09-11 12:00:00.000000", - "module": null, - "name": "Payment Entry-apply_tax_withholding_amount-depends_on", - "property": "depends_on", - "property_type": "Data", - "row_name": null, - "value": "eval:doc.party_type == 'Supplier' || (doc.party_type == 'Customer' && doc.payment_type == 'Receive')" - } -] \ No newline at end of file diff --git a/default_thai_company/hooks.py b/default_thai_company/hooks.py index 4457c44..eb734b1 100644 --- a/default_thai_company/hooks.py +++ b/default_thai_company/hooks.py @@ -84,38 +84,13 @@ jinja = { # Fixtures # -------- +# Custom Fields and Property Setters live in default_thai_company/custom/*.json +# (synced in place on install and migrate); fixtures are for whole documents. fixtures = [ {"doctype": "Letter Head", "filters": [["name", "in", ["Default Letter Head"]]]}, {"doctype": "Address Template", "filters": [["name", "in", ["Thailand"]]]}, {"doctype": "Print Format", "filters": [["name", "in", ["Default Standard Sales Invoice"]]]}, - { - "doctype": "Property Setter", - "filters": [ - [ - "name", - "in", - [ - "Sales Invoice-main-default_print_format", - "Payment Entry-apply_tax_withholding_amount-depends_on", - ], - ] - ], - }, {"doctype": "Tax Withholding Category", "filters": [["name", "like", "WHT %"]]}, - { - "doctype": "Custom Field", - "filters": [ - [ - "name", - "in", - [ - "Sales Invoice-tax_withholding_category", - "Sales Invoice-withholding_tax_amount", - "Sales Invoice-amount_after_withholding", - ], - ] - ], - }, ] # Installation diff --git a/default_thai_company/tests/test_tax_withholding.py b/default_thai_company/tests/test_tax_withholding.py index e7447e0..37e270c 100644 --- a/default_thai_company/tests/test_tax_withholding.py +++ b/default_thai_company/tests/test_tax_withholding.py @@ -1,5 +1,8 @@ +import json + import frappe from frappe.modules.import_file import import_file_by_path +from frappe.modules.utils import sync_customizations_for_doctype from frappe.tests.utils import FrappeTestCase from frappe.utils import nowdate @@ -10,7 +13,7 @@ ABBR = "_TWC" CUSTOMER = "_Test WHT Customer" ITEM = "_Test WHT Service" FIXTURE = frappe.get_app_path("default_thai_company", "fixtures", "tax_withholding_category.json") -CUSTOM_FIELDS = frappe.get_app_path("default_thai_company", "fixtures", "custom_field.json") +CUSTOM_DIR = frappe.get_app_path("default_thai_company", "default_thai_company", "custom") class TestTaxWithholding(FrappeTestCase): @@ -20,8 +23,9 @@ class TestTaxWithholding(FrappeTestCase): # Fixture categories must exist before the company is created so the # Company hook has something to link; force=True re-imports. import_file_by_path(FIXTURE, force=True, data_import=True) - import_file_by_path(CUSTOM_FIELDS, force=True, data_import=True) - frappe.clear_cache(doctype="Sales Invoice") + for fname in ("sales_invoice.json", "payment_entry.json"): + with open(f"{CUSTOM_DIR}/{fname}") as f: + sync_customizations_for_doctype(json.load(f), CUSTOM_DIR, fname) frappe.get_doc( {