diff --git a/frappe/boot.py b/frappe/boot.py
index 43a112548a..7d1618e5b3 100644
--- a/frappe/boot.py
+++ b/frappe/boot.py
@@ -21,7 +21,7 @@ def get_bootinfo():
get_user(bootinfo)
# system info
- bootinfo['control_panel'] = frappe.get_doc('Control Panel').as_dict()
+ bootinfo['control_panel'] = frappe._dict(frappe.get_doc('Control Panel').as_dict())
bootinfo['sysdefaults'] = frappe.defaults.get_defaults()
bootinfo['server_date'] = frappe.utils.nowdate()
bootinfo["send_print_in_body_and_attachment"] = frappe.db.get_value("Outgoing Email Settings",
diff --git a/frappe/core/doctype/customize_form/customize_form.js b/frappe/core/doctype/customize_form/customize_form.js
index 2a9bc3842b..2b95d6ba6e 100644
--- a/frappe/core/doctype/customize_form/customize_form.js
+++ b/frappe/core/doctype/customize_form/customize_form.js
@@ -41,37 +41,39 @@ frappe.ui.form.on("Customize Form", "doc_type", function(frm) {
frappe.ui.form.on("Customize Form", "refresh", function(frm) {
frm.disable_save();
frm.frm_head.appframe.iconbar.clear("1");
- frm.appframe.set_title_right("Update", function() {
- if(frm.doc.doc_type) {
- return frm.call({
- doc: frm.doc,
- method: "save_customization",
- callback: function(r) {
- if(!r.exc && r.server_messages) {
- frm.script_manager.trigger("doc_type");
- frm.frm_head.set_label(['Updated', 'label-success']);
+
+ if(frm.doc.doc_type) {
+ frm.appframe.set_title_right("Update", function() {
+ if(frm.doc.doc_type) {
+ return frm.call({
+ doc: frm.doc,
+ method: "save_customization",
+ callback: function(r) {
+ if(!r.exc) {
+ frappe.customize_form.clear_locals_and_refresh(frm);
+ }
}
- }
- });
- }
- });
+ });
+ }
+ });
- frm.add_custom_button('Refresh Form', function() {
- frm.script_manager.trigger("doc_type");
- }, "icon-refresh");
+ frm.add_custom_button('Refresh Form', function() {
+ frm.script_manager.trigger("doc_type");
+ }, "icon-refresh");
- frm.add_custom_button('Reset to defaults', function() {
- frappe.customize_form.confirm('This will remove the customizations defined for this form.
'
- + 'Are you sure you want to reset to defaults?', frm);
- }, "icon-eraser");
-
- if(!frm.doc.doc_type) {
- var frm_head = frm.frm_head.appframe;
- $(frm_head.buttons['Update']).prop('disabled', true);
- $(frm_head.buttons['Refresh Form']).prop('disabled', true);
- $(frm_head.buttons['Reset to defaults']).prop('disabled', true);
+ frm.add_custom_button('Reset to defaults', function() {
+ frappe.customize_form.confirm('This will remove the customizations defined for this form.
'
+ + 'Are you sure you want to reset to defaults?', frm);
+ }, "icon-eraser");
}
+ // if(!frm.doc.doc_type) {
+ // var frm_head = frm.frm_head.appframe;
+ // $(frm_head.buttons['Update']).prop('disabled', true);
+ // $(frm_head.buttons['Refresh Form']).prop('disabled', true);
+ // $(frm_head.buttons['Reset to defaults']).prop('disabled', true);
+ // }
+
if(frappe.route_options) {
frappe.model.set_value("Customize Form", null, "doc_type", frappe.route_options.doctype)
frappe.route_options = null;
@@ -79,6 +81,8 @@ frappe.ui.form.on("Customize Form", "refresh", function(frm) {
});
frappe.customize_form.confirm = function(msg, frm) {
+ if(!frm.doc.doc_type) return;
+
var d = new frappe.ui.Dialog({
title: 'Reset To Defaults',
width: 500
@@ -94,14 +98,13 @@ frappe.customize_form.confirm = function(msg, frm) {
var proceed_btn = $btn(button_wrapper, 'Proceed', function() {
return frm.call({
doc: frm.doc,
- method: "delete",
+ method: "reset_to_defaults",
callback: function(r) {
if(r.exc) {
msgprint(r.exc);
} else {
- frm.confirm.dialog.hide();
- frm.refresh();
- frm.frm_head.set_label(['Saved', 'label-success']);
+ frappe.customize_form.confirm.dialog.hide();
+ frappe.customize_form.clear_locals_and_refresh(frm);
}
}
});
@@ -110,16 +113,23 @@ frappe.customize_form.confirm = function(msg, frm) {
$y(proceed_btn, {marginRight: '20px', fontWeight: 'bold'});
var cancel_btn = $btn(button_wrapper, 'Cancel', function() {
- frm.confirm.dialog.hide();
+ frappe.customize_form.confirm.dialog.hide();
});
$(cancel_btn).addClass('btn-small btn-info');
$y(cancel_btn, {fontWeight: 'bold'});
- frm.confirm.dialog = d;
+ frappe.customize_form.confirm.dialog = d;
d.show();
}
+frappe.customize_form.clear_locals_and_refresh = function(frm) {
+ // clear doctype from locals
+ frappe.model.clear_doc("DocType", frm.doc.doc_type);
+ delete frappe.meta.docfield_copy[frm.doc.doc_type];
+
+ frm.refresh();
+}
frappe.customize_form.add_fields_help = function(frm) {
$(frm.grids[0].parent).before(
diff --git a/frappe/core/doctype/customize_form/customize_form.py b/frappe/core/doctype/customize_form/customize_form.py
index a48ec4be2d..b871cab778 100644
--- a/frappe/core/doctype/customize_form/customize_form.py
+++ b/frappe/core/doctype/customize_form/customize_form.py
@@ -12,7 +12,7 @@ from frappe.utils import cstr
from frappe.model.document import Document
class CustomizeForm(Document):
- doctype_properties = [
+ doctype_properties = (
'search_fields',
'default_print_format',
'read_only_onload',
@@ -21,9 +21,9 @@ class CustomizeForm(Document):
'allow_copy',
'allow_attach',
'max_attachments'
- ]
+ )
- docfield_properties = [
+ docfield_properties = (
'idx',
'label',
'fieldtype',
@@ -44,69 +44,65 @@ class CustomizeForm(Document):
'description',
'default',
'name',
- ]
+ )
+
+ allowed_fieldtype_change = (('Currency', 'Float'), ('Small Text', 'Data'),
+ ('Text', 'Text Editor', 'Code'))
- property_restrictions = {
- 'fieldtype': [['Currency', 'Float'], ['Small Text', 'Data'], ['Text', 'Text Editor', 'Code']],
- }
+ # property_restrictions = {
+ # 'fieldtype': (('Currency', 'Float'), ('Small Text', 'Data'), ('Text', 'Text Editor', 'Code')),
+ # }
def on_update(self):
frappe.db.sql("delete from tabSingles where doctype='Customize Form'")
frappe.db.sql("delete from `tabCustomize Form Field`")
def fetch_to_customize(self):
- pass
+ self.clear_existing_doc()
+ if not self.doc_type:
+ return
+
+ meta = frappe.get_meta(self.doc_type)
+
+ # doctype properties
+ for fieldname in self.doctype_properties:
+ self.set(fieldname, meta.get(fieldname))
+
+ for d in meta.get("fields"):
+ new_d = {}
+ for fieldname in self.docfield_properties:
+ new_d[fieldname] = d.get(fieldname)
+ self.append("fields", new_d)
+
+ # NOTE doc is sent to clientside by run_method
+
+ def clear_existing_doc(self):
+ doc_type = self.doc_type
+
+ for fieldname in self.meta.get_valid_columns():
+ self.set(fieldname, None)
+
+ for df in self.meta.get_table_fields():
+ self.set(df.fieldname, [])
+
+ self.doc_type = doc_type
+ self.name = "Customize Form"
def save_customization(self):
- pass
-
- def _get(self):
- """
- Gets DocFields applied with Property Setter customizations via Customize Form Field
- """
- self.clear()
-
- if self.doc_type:
- meta = frappe.get_meta(self.doc_type)
- for d in meta.get("fields"):
- new = self.append('fields', {})
- self._set({ 'list': self.docfield_properties, 'doc' : d, 'doc_to_set': new })
- self._set({ 'list': self.doctype_properties, 'doc': d })
-
- def clear(self):
- """
- Clear fields in the doc
- """
- # Clear table before adding new doctype's fields
- self.set('fields', [])
- self._set({ 'list': self.doctype_properties, 'value': None })
-
-
- def _set(self, args):
- """
- Set a list of attributes of a doc to a value
- or to attribute values of a doc passed
+ if not self.doc_type:
+ return
- args can contain:
- * list --> list of attributes to set
- * doc_to_set --> defaults to self
- * value --> to set all attributes to one value eg. None
- * doc --> copy attributes from doc to doc_to_set
- """
- if not 'doc_to_set' in args:
- args['doc_to_set'] = self
-
- if 'list' in args:
- if 'value' in args:
- for f in args['list']:
- args['doc_to_set'].set(f, None)
- elif 'doc' in args:
- for f in args['list']:
- args['doc_to_set'].set(f, args['doc'].get(f))
- else:
- frappe.msgprint("Please specify args['list'] to set", raise_exception=1)
-
-
+ frappe.clear_cache(doctype=self.doc_type)
+ self.fetch_to_customize()
+
+ def reset_to_defaults(self):
+ if not self.doc_type:
+ return
+
+ frappe.db.sql("""delete from `tabProperty Setter` where doc_type=%s""", self.doc_type)
+ frappe.clear_cache(doctype=self.doc_type)
+ self.fetch_to_customize()
+
def post(self):
"""
Save diff between Customize Form Bean and DocType Bean as property setter entries
@@ -310,25 +306,4 @@ class CustomizeForm(Document):
if not d.delete:
d.insert()
-
- def delete(self):
- """
- Deletes all property setter entries for the selected doctype
- and resets it to standard
- """
- if self.doc_type:
- frappe.db.sql("""
- DELETE FROM `tabProperty Setter`
- WHERE doc_type = %s""", self.doc_type)
-
- frappe.clear_cache(doctype=self.doc_type)
-
- self._get()
-
- def remove_forbidden(self, string):
- """
- Replace forbidden characters with a space
- """
- forbidden = ['%', "'", '"', '#', '*', '?', '`']
- for f in forbidden:
- string.replace(f, ' ')
+
\ No newline at end of file
diff --git a/frappe/core/page/data_import_tool/data_import_tool.py b/frappe/core/page/data_import_tool/data_import_tool.py
index 5bff89723b..674b226962 100644
--- a/frappe/core/page/data_import_tool/data_import_tool.py
+++ b/frappe/core/page/data_import_tool/data_import_tool.py
@@ -48,7 +48,7 @@ def export_json(doctype, name, path):
if not name or name=="-":
name = doctype
with open(path, "w") as outfile:
- doc = frappe.get_doc(doctype, name).as_dict()
+ doc = frappe.get_doc(doctype, name)
for d in doc.get_all_children():
d.set("parent", None)
d.set("name", None)
diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py
index 0999149545..b0ad4a95a3 100644
--- a/frappe/model/base_document.py
+++ b/frappe/model/base_document.py
@@ -8,12 +8,14 @@ from frappe.utils import cint, flt, cstr, now
from frappe.model.naming import set_new_name
class BaseDocument(object):
+ ignore_in_getter = ("doctype", "_meta", "meta", "_table_fields", "_valid_columns")
+
def __init__(self, d):
self.update(d)
def __getattr__(self, key):
# this is called only when something is not found in dir or __dict__
- if not key.startswith("__") and key not in ("doctype", "_meta", "meta", "_table_fields", "_valid_columns") \
+ if not key.startswith("__") and key not in self.ignore_in_getter \
and key in self.meta.get_valid_columns():
return None
else:
@@ -44,7 +46,8 @@ class BaseDocument(object):
else:
value = self.__dict__.get(key, default)
- if value is None and key!="_meta" and key in (d.fieldname for d in self.meta.get_table_fields()):
+ if value is None and key not in self.ignore_in_getter \
+ and key in (d.fieldname for d in self.meta.get_table_fields()):
self.set(key, [])
value = self.__dict__.get(key)
@@ -62,7 +65,7 @@ class BaseDocument(object):
def append(self, key, value=None):
if value==None:
value={}
- if isinstance(value, dict):
+ if isinstance(value, (dict, BaseDocument)):
if not self.get(key):
self.__dict__[key] = []
value = self._init_child(value, key)
@@ -97,7 +100,7 @@ class BaseDocument(object):
return value
def get_valid_dict(self):
- d = frappe._dict()
+ d = {}
for fieldname in self.meta.get_valid_columns():
d[fieldname] = self.get(fieldname)
return d
diff --git a/frappe/model/document.py b/frappe/model/document.py
index b8d7f073b7..d17150cbd2 100644
--- a/frappe/model/document.py
+++ b/frappe/model/document.py
@@ -383,16 +383,21 @@ class Document(BaseDocument):
@staticmethod
def hook(f):
- def add_to_response(new_response):
- if isinstance(new_response, dict):
- frappe.local.response.update(new_response)
+ def add_to_return_value(self, new_return_value):
+ if isinstance(new_return_value, dict):
+ if not self.get("_return_value"):
+ self._return_value = {}
+ self._return_value.update(new_return_value)
+ else:
+ self._return_value = new_return_value or self.get("_return_value")
def compose(fn, *hooks):
def runner(self, method, *args, **kwargs):
- add_to_response(fn(self, *args, **kwargs))
+ add_to_return_value(self, fn(self, *args, **kwargs))
for f in hooks:
- add_to_response(f(self, method, *args, **kwargs))
- return frappe.local.response
+ add_to_return_value(self, f(self, method, *args, **kwargs))
+
+ return self._return_value
return runner
diff --git a/frappe/model/meta.py b/frappe/model/meta.py
index 3b7b854c83..534b03ad4d 100644
--- a/frappe/model/meta.py
+++ b/frappe/model/meta.py
@@ -23,14 +23,16 @@ class Meta(Document):
_metaclass = True
_fields = {}
default_fields = default_fields[1:]
+ special_doctypes = ("DocField", "DocPerm", "Role", "DocType", "Module Def")
def __init__(self, doctype):
super(Meta, self).__init__("DocType", doctype)
+ self.process()
def load_from_db(self):
try:
super(Meta, self).load_from_db()
except frappe.DoesNotExistError:
- if self.doctype=="DocType" and self.name in ("DocField", "DocPerm", "Role", "DocType", "Module Def"):
+ if self.doctype=="DocType" and self.name in self.special_doctypes:
fname = frappe.scrub(self.name)
with open(frappe.get_app_path("frappe", "core", "doctype", fname, fname + ".json"), "r") as f:
txt = f.read()
@@ -60,7 +62,7 @@ class Meta(Document):
def get_valid_columns(self):
if not hasattr(self, "_valid_columns"):
- if self.name in ("DocType", "DocField", "DocPerm"):
+ if self.name in ("DocType", "DocField", "DocPerm", "Property Setter"):
self._valid_columns = frappe.db.get_table_columns(self.name)
else:
self._valid_columns = self.default_fields + \
@@ -84,6 +86,11 @@ class Meta(Document):
return self.get_field(fieldname).options
def process(self):
+ # don't process for special doctypes
+ # prevent's circular dependency
+ if self.name in self.special_doctypes:
+ return
+
self.add_custom_fields()
self.apply_property_setters()
self.sort_fields()
@@ -91,7 +98,7 @@ class Meta(Document):
def add_custom_fields(self):
try:
self.extend("fields", frappe.db.sql("""SELECT * FROM `tabCustom Field`
- WHERE dt = %s AND docstatus < 2""", (doctype,), as_dict=1))
+ WHERE dt = %s AND docstatus < 2""", (self.name,), as_dict=1))
except Exception, e:
if e.args[0]==1146:
return
@@ -100,7 +107,7 @@ class Meta(Document):
def apply_property_setters(self):
for ps in frappe.db.sql("""select * from `tabProperty Setter` where
- doc_type=%s""", (doctype,), as_dict=1):
+ doc_type=%s""", (self.name,), as_dict=1):
if ps['doctype_or_field']=='DocType':
if ps.get('property_type', None) in ('Int', 'Check'):
ps['value'] = cint(ps['value'])
@@ -131,7 +138,7 @@ class Meta(Document):
while (pending and maxloops>0):
maxloops -= 1
for d in pending[:]:
- if d.previous_field:
+ if d.get("previous_field"):
# field already added
for n in newlist:
if n.fieldname==d.previous_field:
@@ -190,20 +197,6 @@ def get_parent_dt(dt):
def set_fieldname(field_id, fieldname):
frappe.db.set_value('DocField', field_id, 'fieldname', fieldname)
-def get_table_fields(doctype):
- child_tables = [[d[0], d[1]] for d in frappe.db.sql("""select options, fieldname
- from tabDocField where parent=%s and fieldtype='Table'""", doctype, as_list=1)]
-
- try:
- custom_child_tables = [[d[0], d[1]] for d in frappe.db.sql("""select options, fieldname
- from `tabCustom Field` where dt=%s and fieldtype='Table'""", doctype, as_list=1)]
- except Exception, e:
- if e.args[0]!=1146:
- raise
- custom_child_tables = []
-
- return child_tables + custom_child_tables
-
def get_field_currency(df, doc):
"""get currency based on DocField options and fieldvalue in doc"""
currency = None
diff --git a/frappe/utils/response.py b/frappe/utils/response.py
index 356cdf6061..ea13fe8bf2 100644
--- a/frappe/utils/response.py
+++ b/frappe/utils/response.py
@@ -100,7 +100,6 @@ def compressBuf(buf):
def json_handler(obj):
"""serialize non-serializable data for json"""
-
# serialize date
if isinstance(obj, (datetime.date, datetime.timedelta, datetime.datetime)):
return unicode(obj)
diff --git a/frappe/website/sitemap.py b/frappe/website/sitemap.py
index d8bc775a2c..cb16efc62a 100644
--- a/frappe/website/sitemap.py
+++ b/frappe/website/sitemap.py
@@ -21,7 +21,7 @@ def get_sitemap_options(path):
return frappe._dict(sitemap_options)
def build_sitemap_options(path):
- sitemap_options = frappe.get_doc("Website Route", path).as_dict()
+ sitemap_options = frappe._dict(frappe.get_doc("Website Route", path).as_dict())
home_page = get_home_page()
sitemap_config = frappe.get_doc("Website Template",
diff --git a/frappe/widgets/form/run_method.py b/frappe/widgets/form/run_method.py
index 79ffaaf9c2..eb8919ddef 100644
--- a/frappe/widgets/form/run_method.py
+++ b/frappe/widgets/form/run_method.py
@@ -35,6 +35,8 @@ def runserverobj():
args = json.loads(args)
except ValueError:
r = doc.run_method(method, args)
+ except TypeError:
+ r = doc.run_method(method)
else:
r = doc.run_method(method, **args)