feat(regional): a central place for regional address templates (#19862)
* feat: a central place for regional address templates
* set up address templates during install
* why don't the tests run?
* fix: remove unused variables, fix cwd
* fix: .get() dicts contents
* fix: choose the right default
* fix: fieldname is template, not html
* fix: import unittest
* fix: remove unnecessary code
* fix: ensure country exists
* fix: ensure country exists
* feat: test updating an existing template
* fix(regional): DuplicateEntryError in test_update_address_template
* refactor and set 'is_default'
* fix codacy
* fix: patch gst_fixes
* fix: patch update_address_template_for_india
Co-authored-by: Nabin Hait <nabinhait@gmail.com>
diff --git a/erpnext/patches/v10_0/update_address_template_for_india.py b/erpnext/patches/v10_0/update_address_template_for_india.py
index 145ed45..1ddca93 100644
--- a/erpnext/patches/v10_0/update_address_template_for_india.py
+++ b/erpnext/patches/v10_0/update_address_template_for_india.py
@@ -3,10 +3,10 @@
from __future__ import unicode_literals
import frappe
-from erpnext.regional.india.setup import update_address_template
+from erpnext.regional.address_template.setup import set_up_address_templates
def execute():
if frappe.db.get_value('Company', {'country': 'India'}, 'name'):
address_template = frappe.db.get_value('Address Template', 'India', 'template')
if not address_template or "gstin" not in address_template:
- update_address_template()
+ set_up_address_templates(default_country='India')
diff --git a/erpnext/patches/v8_1/gst_fixes.py b/erpnext/patches/v8_1/gst_fixes.py
index 22fa53b..34255eb 100644
--- a/erpnext/patches/v8_1/gst_fixes.py
+++ b/erpnext/patches/v8_1/gst_fixes.py
@@ -1,7 +1,8 @@
from __future__ import unicode_literals
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
-from erpnext.regional.india.setup import update_address_template
+from erpnext.regional.address_template.setup import set_up_address_templates
+
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
@@ -10,9 +11,10 @@
update_existing_custom_fields()
add_custom_fields()
- update_address_template()
+ set_up_address_templates(default_country='India')
frappe.reload_doc("regional", "print_format", "gst_tax_invoice")
+
def update_existing_custom_fields():
frappe.db.sql("""update `tabCustom Field` set label = 'HSN/SAC'
where fieldname='gst_hsn_code' and label='GST HSN Code'
@@ -34,6 +36,7 @@
where fieldname='gst_hsn_code' and dt in ('Sales Invoice Item', 'Purchase Invoice Item')
""")
+
def add_custom_fields():
hsn_sac_field = dict(fieldname='gst_hsn_code', label='HSN/SAC',
fieldtype='Data', options='item_code.gst_hsn_code', insert_after='description')
diff --git a/erpnext/regional/address_template/README.md b/erpnext/regional/address_template/README.md
new file mode 100644
index 0000000..9915734
--- /dev/null
+++ b/erpnext/regional/address_template/README.md
@@ -0,0 +1,18 @@
+To add an **Address Template** for your country, place a new file in this directory:
+
+ * File name: `your_country.html` (lower case with underscores)
+ * File content: a [Jinja Template](http://jinja.pocoo.org/docs/templates/).
+
+All the fields of **Address** (including Custom Fields, if any) will be available to the template. Example:
+
+```jinja
+{{ address_line1 }}<br>
+{% if address_line2 %}{{ address_line2 }}<br>{% endif -%}
+{{ city }}<br>
+{% if state %}{{ state }}<br>{% endif -%}
+{% if pincode %} PIN: {{ pincode }}<br>{% endif -%}
+{{ country }}<br>
+{% if phone %}Phone: {{ phone }}<br>{% endif -%}
+{% if fax %}Fax: {{ fax }}<br>{% endif -%}
+{% if email_id %}Email: {{ email_id }}<br>{% endif -%}
+```
diff --git a/erpnext/regional/address_template/__init__.py b/erpnext/regional/address_template/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/regional/address_template/__init__.py
diff --git a/erpnext/regional/address_template/setup.py b/erpnext/regional/address_template/setup.py
new file mode 100644
index 0000000..9f318de
--- /dev/null
+++ b/erpnext/regional/address_template/setup.py
@@ -0,0 +1,53 @@
+"""Import Address Templates from ./templates directory."""
+import os
+import frappe
+
+def set_up_address_templates(default_country=None):
+ for country, html in get_address_templates():
+ is_default = 1 if country == default_country else 0
+ update_address_template(country, html, is_default)
+
+def get_address_templates():
+ """
+ Return country and path for all HTML files in this directory.
+
+ Returns a list of dicts.
+ """
+ def country(file_name):
+ """Convert 'united_states.html' to 'United States'."""
+ suffix_pos = file_name.find(".html")
+ country_snake_case = file_name[:suffix_pos]
+ country_title_case = " ".join(country_snake_case.split("_")).title()
+ return country_title_case
+
+ def get_file_content(file_name):
+ """Convert 'united_states.html' to '/path/to/united_states.html'."""
+ full_path = os.path.join(template_dir, file_name)
+ with open(full_path, "r") as f:
+ content = f.read()
+ return content
+
+ dir_name = os.path.dirname(__file__)
+ template_dir = os.path.join(dir_name, "templates")
+ file_names = os.listdir(template_dir)
+ html_files = [file for file in file_names if file.endswith(".html")]
+
+ return [(country(file_name), get_file_content(file_name)) for file_name in html_files]
+
+
+def update_address_template(country, html, is_default=0):
+ """Update existing Address Template or create a new one."""
+ if not frappe.db.exists("Country", country):
+ frappe.log_error("Country {} for regional Address Template does not exist.".format(country))
+ return
+
+ if frappe.db.exists("Address Template", country):
+ frappe.db.set_value("Address Template", country, "template", html)
+ frappe.db.set_value("Address Template", country, "is_default", is_default)
+ else:
+ frappe.get_doc(dict(
+ doctype="Address Template",
+ country=country,
+ is_default=is_default,
+ template=html
+ )).insert()
diff --git a/erpnext/regional/germany/address_template.html b/erpnext/regional/address_template/templates/germany.html
similarity index 100%
rename from erpnext/regional/germany/address_template.html
rename to erpnext/regional/address_template/templates/germany.html
diff --git a/erpnext/regional/india/address_template.html b/erpnext/regional/address_template/templates/india.html
similarity index 99%
rename from erpnext/regional/india/address_template.html
rename to erpnext/regional/address_template/templates/india.html
index 55cc9af..ffb9d05 100644
--- a/erpnext/regional/india/address_template.html
+++ b/erpnext/regional/address_template/templates/india.html
@@ -6,4 +6,4 @@
{% if phone %}Phone: {{ phone }}<br>{% endif -%}
{% if fax %}Fax: {{ fax }}<br>{% endif -%}
{% if email_id %}Email: {{ email_id }}<br>{% endif -%}
-{% if gstin %}GSTIN: {{ gstin }}<br>{% endif -%}
\ No newline at end of file
+{% if gstin %}GSTIN: {{ gstin }}<br>{% endif -%}
diff --git a/erpnext/regional/united_states/address_template.html b/erpnext/regional/address_template/templates/united_states.html
similarity index 100%
rename from erpnext/regional/united_states/address_template.html
rename to erpnext/regional/address_template/templates/united_states.html
diff --git a/erpnext/regional/address_template/test_regional_address_template.py b/erpnext/regional/address_template/test_regional_address_template.py
new file mode 100644
index 0000000..8a05ea2
--- /dev/null
+++ b/erpnext/regional/address_template/test_regional_address_template.py
@@ -0,0 +1,45 @@
+from __future__ import unicode_literals
+from unittest import TestCase
+
+import frappe
+from erpnext.regional.address_template.setup import get_address_templates
+from erpnext.regional.address_template.setup import update_address_template
+
+def ensure_country(country):
+ if frappe.db.exists("Country", country):
+ return frappe.get_doc("Country", country)
+ else:
+ c = frappe.get_doc({
+ "doctype": "Country",
+ "country_name": country
+ })
+ c.insert()
+ return c
+
+class TestRegionalAddressTemplate(TestCase):
+ def test_get_address_templates(self):
+ """Get the countries and paths from the templates directory."""
+ templates = get_address_templates()
+ self.assertIsInstance(templates, list)
+ self.assertIsInstance(templates[0], tuple)
+
+ def test_create_address_template(self):
+ """Create a new Address Template."""
+ country = ensure_country("Germany")
+ update_address_template(country.name, "TEST")
+ doc = frappe.get_doc("Address Template", country.name)
+ self.assertEqual(doc.template, "TEST")
+
+ def test_update_address_template(self):
+ """Update an existing Address Template."""
+ country = ensure_country("Germany")
+ if not frappe.db.exists("Address Template", country.name):
+ template = frappe.get_doc({
+ "doctype": "Address Template",
+ "country": country.name,
+ "template": "EXISTING"
+ }).insert()
+
+ update_address_template(country.name, "NEW")
+ doc = frappe.get_doc("Address Template", country.name)
+ self.assertEqual(doc.template, "NEW")
diff --git a/erpnext/regional/germany/setup.py b/erpnext/regional/germany/setup.py
index a547136..d6047e8 100644
--- a/erpnext/regional/germany/setup.py
+++ b/erpnext/regional/germany/setup.py
@@ -3,29 +3,4 @@
def setup(company=None, patch=True):
- if not patch:
- update_address_template()
-
-
-def update_address_template():
- """
- Read address template from file. Update existing Address Template or create a
- new one.
- """
- dir_name = os.path.dirname(__file__)
- template_path = os.path.join(dir_name, 'address_template.html')
-
- with open(template_path, 'r') as template_file:
- template_html = template_file.read()
-
- address_template = frappe.db.get_value('Address Template', 'Germany')
-
- if address_template:
- frappe.db.set_value('Address Template', 'Germany', 'template', template_html)
- else:
- # make new html template for Germany
- frappe.get_doc(dict(
- doctype='Address Template',
- country='Germany',
- template=template_html
- )).insert()
+ pass
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 75f29b8..28b1f8f 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -13,7 +13,6 @@
def setup(company=None, patch=True):
setup_company_independent_fixtures()
if not patch:
- update_address_template()
make_fixtures(company)
# TODO: for all countries
@@ -24,21 +23,6 @@
frappe.enqueue('erpnext.regional.india.setup.add_hsn_sac_codes', now=frappe.flags.in_test)
add_print_formats()
-def update_address_template():
- with open(os.path.join(os.path.dirname(__file__), 'address_template.html'), 'r') as f:
- html = f.read()
-
- address_template = frappe.db.get_value('Address Template', 'India')
- if address_template:
- frappe.db.set_value('Address Template', 'India', 'template', html)
- else:
- # make new html template for India
- frappe.get_doc(dict(
- doctype='Address Template',
- country='India',
- template=html
- )).insert()
-
def add_hsn_sac_codes():
# HSN codes
with open(os.path.join(os.path.dirname(__file__), 'hsn_code_data.json'), 'r') as f:
diff --git a/erpnext/regional/united_states/setup.py b/erpnext/regional/united_states/setup.py
index cb82b63..6d34402 100644
--- a/erpnext/regional/united_states/setup.py
+++ b/erpnext/regional/united_states/setup.py
@@ -5,12 +5,9 @@
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
-
def setup(company=None, patch=True):
make_custom_fields()
add_print_formats()
- update_address_template()
-
def make_custom_fields():
custom_fields = {
@@ -21,22 +18,7 @@
}
create_custom_fields(custom_fields)
-
def add_print_formats():
frappe.reload_doc("regional", "print_format", "irs_1099_form")
frappe.db.sql(""" update `tabPrint Format` set disabled = 0 where
name in('IRS 1099 Form') """)
-
-
-def update_address_template():
- html = """{{ address_line1 }}<br>
- {% if address_line2 %}{{ address_line2 }}<br>{% endif -%}
- {{ city }}, {% if state %}{{ state }}{% endif -%}{% if pincode %} {{ pincode }}<br>{% endif -%}
- {% if country != "United States" %}{{ country|upper }}{% endif -%}
- """
-
- address_template = frappe.db.get_value('Address Template', 'United States')
- if address_template:
- frappe.db.set_value('Address Template', 'United States', 'template', html)
- else:
- frappe.get_doc(dict(doctype='Address Template', country='United States', template=html)).insert()
diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py
index ebd7b50..e4986e3 100644
--- a/erpnext/setup/setup_wizard/operations/install_fixtures.py
+++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py
@@ -8,9 +8,11 @@
from frappe import _
from frappe.desk.page.setup_wizard.setup_wizard import make_records
from frappe.utils import cstr, getdate
-from erpnext.accounts.doctype.account.account import RootNotEditable
from frappe.desk.doctype.global_search_settings.global_search_settings import update_global_search_doctypes
+from erpnext.accounts.doctype.account.account import RootNotEditable
+from erpnext.regional.address_template.setup import set_up_address_templates
+
default_lead_sources = ["Existing Customer", "Reference", "Advertisement",
"Cold Calling", "Exhibition", "Supplier Reference", "Mass Mailing",
"Customer's Vendor", "Campaign", "Walk In"]
@@ -30,7 +32,7 @@
{ 'doctype': 'Domain', 'domain': 'Agriculture'},
{ 'doctype': 'Domain', 'domain': 'Non Profit'},
- # address template
+ # ensure at least an empty Address Template exists for this Country
{'doctype':"Address Template", "country": country},
# item group
@@ -269,12 +271,11 @@
# Records for the Supplier Scorecard
from erpnext.buying.doctype.supplier_scorecard.supplier_scorecard import make_default_records
+
make_default_records()
-
make_records(records)
-
+ set_up_address_templates(default_country=country)
set_more_defaults()
-
update_global_search_doctypes()
# path = frappe.get_app_path('erpnext', 'regional', frappe.scrub(country))