fix: Move field_order sync logic to DocType controller and introduce hooks

before_export, before_import and prepare_docdict_for_import
This commit is contained in:
Saif Ur Rehman 2019-04-18 17:24:08 +05:00
parent e2b199120f
commit 9db45f6fab
4 changed files with 65 additions and 52 deletions

View file

@ -17,7 +17,9 @@ from frappe.desk.notifications import delete_notification_count_for
from frappe.modules import make_boilerplate, get_doc_path
from frappe.model.db_schema import validate_column_name, validate_column_length, type_map
from frappe.model.docfield import supports_translation
from frappe.modules.import_file import get_file_path
import frappe.website.render
import json
# imports - third-party imports
import pymysql
@ -390,6 +392,57 @@ class DocType(Document):
if naming_series[0].default:
make_property_setter(self.name, "naming_series", "default", naming_series[0].default, "Text", validate_fields_for_doctype=False)
def before_export(self, docdict):
# retain order of 'fields' table and change order in 'field_order'
docdict["field_order"] = [f.fieldname for f in self.fields]
path = get_file_path(self.module, "DocType", self.name)
if os.path.exists(path):
try:
with open(path, 'r') as txtfile:
olddoc = json.loads(txtfile.read())
old_field_names = [f['fieldname'] for f in olddoc.get("fields", [])]
if old_field_names:
new_field_dicts = []
remaining_field_names = [f.fieldname for f in self.fields]
for fieldname in old_field_names:
field_dict = filter(lambda d: d['fieldname'] == fieldname, docdict['fields'])
if field_dict:
new_field_dicts.append(field_dict[0])
remaining_field_names.remove(fieldname)
for fieldname in remaining_field_names:
field_dict = filter(lambda d: d['fieldname'] == fieldname, docdict['fields'])
new_field_dicts.append(field_dict[0])
docdict['fields'] = new_field_dicts
except ValueError:
pass
@staticmethod
def prepare_docdict_for_import(docdict):
# set order of fields from field_order
if docdict.get("field_order"):
new_field_dicts = []
remaining_field_names = [f['fieldname'] for f in docdict.get('fields', [])]
for fieldname in docdict.get('field_order'):
field_dict = filter(lambda d: d['fieldname'] == fieldname, docdict.get('fields', []))
if field_dict:
new_field_dicts.append(field_dict[0])
remaining_field_names.remove(fieldname)
for fieldname in remaining_field_names:
field_dict = filter(lambda d: d['fieldname'] == fieldname, docdict.get('fields', []))
new_field_dicts.append(field_dict[0])
docdict['fields'] = new_field_dicts
if "field_order" in docdict:
del docdict["field_order"]
def export_doc(self):
"""Export to standard folder `[module]/doctype/[name]/[name].json`."""
from frappe.modules.export_file import export_to_files

View file

@ -106,7 +106,7 @@ class TestDocType(unittest.TestCase):
if condition:
self.assertFalse(re.match(pattern, condition))
def test_load_file_field_order(self):
def test_sync_field_order(self):
from frappe.modules.import_file import get_file_path
import os

View file

@ -24,6 +24,7 @@ def export_to_files(record_list=None, record_module=None, verbose=0, create_init
def write_document_file(doc, record_module=None, create_init=True):
newdoc = doc.as_dict(no_nulls=True)
doc.run_method("before_export", newdoc)
# strip out default fields from children
for df in doc.meta.get_table_fields():
@ -39,35 +40,7 @@ def write_document_file(doc, record_module=None, create_init=True):
# write the data file
fname = scrub(doc.name)
with open(os.path.join(folder, fname + ".json"), 'a+') as txtfile:
# if exporting DocType, retain order of 'fields' table and change order in 'field_order'
if doc.doctype == "DocType":
newdoc["field_order"] = [f.fieldname for f in doc.fields]
try:
olddoc = json.loads(txtfile.read())
old_field_names = [f['fieldname'] for f in olddoc.get("fields", [])]
if old_field_names:
new_field_dicts = []
remaining_field_names = [f.fieldname for f in doc.fields]
for fieldname in old_field_names:
field_dict = filter(lambda d: d['fieldname'] == fieldname, newdoc['fields'])
if field_dict:
new_field_dicts.append(field_dict[0])
remaining_field_names.remove(fieldname)
for fieldname in remaining_field_names:
field_dict = filter(lambda d: d['fieldname'] == fieldname, newdoc['fields'])
new_field_dicts.append(field_dict[0])
newdoc['fields'] = new_field_dicts
except ValueError:
pass
txtfile.seek(0)
txtfile.truncate()
with open(os.path.join(folder, fname + ".json"), 'w+') as txtfile:
txtfile.write(frappe.as_json(newdoc))
def get_module_name(doc):

View file

@ -4,8 +4,9 @@
from __future__ import unicode_literals, print_function
import frappe, os, json
from frappe.modules import get_module_path, scrub_dt_dn
from frappe.modules import get_module_path, scrub_dt_dn, load_doctype_module
from frappe.utils import get_datetime_str
from frappe.model.base_document import get_controller
ignore_values = {
"Report": ["disabled", "prepared_report"],
@ -89,27 +90,6 @@ def read_doc_from_file(path):
else:
raise IOError('%s missing' % path)
# set order of fields from field_order
if doc.get("doctype") == "DocType":
if doc.get("field_order") and doc.get("fields"):
new_field_dicts = []
remaining_field_names = [f['fieldname'] for f in doc['fields']]
for fieldname in doc['field_order']:
field_dict = filter(lambda d: d['fieldname'] == fieldname, doc['fields'])
if field_dict:
new_field_dicts.append(field_dict[0])
remaining_field_names.remove(fieldname)
for fieldname in remaining_field_names:
field_dict = filter(lambda d: d['fieldname'] == fieldname, doc['fields'])
new_field_dicts.append(field_dict[0])
doc['fields'] = new_field_dicts
if "field_order" in doc:
del doc['field_order']
return doc
ignore_doctypes = [""]
@ -118,8 +98,15 @@ def import_doc(docdict, force=False, data_import=False, pre_process=None,
ignore_version=None, reset_permissions=False):
frappe.flags.in_import = True
docdict["__islocal"] = 1
controller = get_controller(docdict['doctype'])
if controller and hasattr(controller, 'prepare_docdict_for_import') and callable(getattr(controller, 'prepare_docdict_for_import')):
controller.prepare_docdict_for_import(docdict)
doc = frappe.get_doc(docdict)
doc.run_method("before_import")
doc.flags.ignore_version = ignore_version
if pre_process:
pre_process(doc)