feat(customize form): add links and actions to customize form and cleanup code
This commit is contained in:
parent
8ec26175ed
commit
1e48ced097
14 changed files with 811 additions and 768 deletions
|
|
@ -1154,6 +1154,7 @@ def make_property_setter(args, ignore_validate=False, validate_fields_for_doctyp
|
|||
'doctype_or_field': args.doctype_or_field,
|
||||
'doc_type': doctype,
|
||||
'field_name': args.fieldname,
|
||||
'row_name': args.row_name,
|
||||
'property': args.property,
|
||||
'value': args.value,
|
||||
'property_type': args.property_type or "Data",
|
||||
|
|
|
|||
|
|
@ -159,6 +159,7 @@ def handle_exception(e):
|
|||
response = None
|
||||
http_status_code = getattr(e, "http_status_code", 500)
|
||||
return_as_message = False
|
||||
print(frappe.get_traceback())
|
||||
|
||||
if frappe.get_request_header('Accept') and (frappe.local.is_ajax or 'application/json' in frappe.get_request_header('Accept')):
|
||||
# handle ajax responses first
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@
|
|||
"action_type",
|
||||
"action",
|
||||
"group",
|
||||
"hidden"
|
||||
"hidden",
|
||||
"custom"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
|
|
@ -48,12 +49,19 @@
|
|||
"fieldname": "hidden",
|
||||
"fieldtype": "Check",
|
||||
"label": "Hidden"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "custom",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 1,
|
||||
"label": "Custom"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-08-21 14:44:03.845315",
|
||||
"modified": "2020-09-24 14:19:05.549835",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "DocType Action",
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@
|
|||
"field_order": [
|
||||
"link_doctype",
|
||||
"link_fieldname",
|
||||
"group"
|
||||
"group",
|
||||
"hidden",
|
||||
"custom"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
|
|
@ -30,10 +32,25 @@
|
|||
"fieldtype": "Data",
|
||||
"in_list_view": 1,
|
||||
"label": "Group"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "hidden",
|
||||
"fieldtype": "Check",
|
||||
"label": "Hidden"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "custom",
|
||||
"fieldtype": "Check",
|
||||
"hidden": 1,
|
||||
"label": "Custom"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"modified": "2019-09-24 11:41:25.291377",
|
||||
"links": [],
|
||||
"modified": "2020-09-24 14:19:23.189511",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "DocType Link",
|
||||
|
|
|
|||
|
|
@ -5,13 +5,14 @@ frappe.provide("frappe.customize_form");
|
|||
|
||||
frappe.ui.form.on("Customize Form", {
|
||||
onload: function(frm) {
|
||||
frm.disable_save();
|
||||
frm.set_query("doc_type", function() {
|
||||
return {
|
||||
translate_values: false,
|
||||
filters: [
|
||||
['DocType', 'issingle', '=', 0],
|
||||
['DocType', 'custom', '=', 0],
|
||||
['DocType', 'name', 'not in', frappe.model.core_doctypes_list],
|
||||
//['DocType', 'name', 'not in', frappe.model.core_doctypes_list],
|
||||
['DocType', 'restrict_to_domain', 'in', frappe.boot.active_domains]
|
||||
]
|
||||
};
|
||||
|
|
@ -27,7 +28,7 @@ frappe.ui.form.on("Customize Form", {
|
|||
});
|
||||
|
||||
$(frm.wrapper).on("grid-row-render", function(e, grid_row) {
|
||||
if(grid_row.doc && grid_row.doc.fieldtype=="Section Break") {
|
||||
if (grid_row.doc && grid_row.doc.fieldtype=="Section Break") {
|
||||
$(grid_row.row).css({"font-weight": "bold"});
|
||||
}
|
||||
});
|
||||
|
|
@ -40,19 +41,25 @@ frappe.ui.form.on("Customize Form", {
|
|||
frm.trigger("setup_sortable");
|
||||
});
|
||||
|
||||
if (localStorage['customize_doctype']) {
|
||||
// set default value from customize form
|
||||
frm.set_value('doc_type', localStorage['customize_doctype']);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
doc_type: function(frm) {
|
||||
if(frm.doc.doc_type) {
|
||||
if (frm.doc.doc_type) {
|
||||
return frm.call({
|
||||
method: "fetch_to_customize",
|
||||
doc: frm.doc,
|
||||
freeze: true,
|
||||
callback: function(r) {
|
||||
if(r) {
|
||||
if(r._server_messages && r._server_messages.length) {
|
||||
if (r) {
|
||||
if (r._server_messages && r._server_messages.length) {
|
||||
frm.set_value("doc_type", "");
|
||||
} else {
|
||||
localStorage['customize_doctype'] = frm.doc.doc_type;
|
||||
frm.refresh();
|
||||
frm.trigger("setup_sortable");
|
||||
}
|
||||
|
|
@ -69,7 +76,7 @@ frappe.ui.form.on("Customize Form", {
|
|||
frm.doc.fields.forEach(function(f, i) {
|
||||
var data_row = frm.page.body.find('[data-fieldname="fields"] [data-idx="'+ f.idx +'"] .data-row');
|
||||
|
||||
if(f.is_custom_field) {
|
||||
if (f.is_custom_field) {
|
||||
data_row.addClass("highlight");
|
||||
} else {
|
||||
f._sortable = false;
|
||||
|
|
@ -82,7 +89,7 @@ frappe.ui.form.on("Customize Form", {
|
|||
frm.disable_save();
|
||||
frm.page.clear_icons();
|
||||
|
||||
if(frm.doc.doc_type) {
|
||||
if (frm.doc.doc_type) {
|
||||
frappe.customize_form.set_primary_action(frm);
|
||||
|
||||
frm.add_custom_button(__('Go to {0} List', [frm.doc.doc_type]), function() {
|
||||
|
|
@ -101,7 +108,7 @@ frappe.ui.form.on("Customize Form", {
|
|||
frappe.set_route('permission-manager', frm.doc.doc_type);
|
||||
}, "fa fa-lock", "btn-default");
|
||||
|
||||
if(frappe.boot.developer_mode) {
|
||||
if (frappe.boot.developer_mode) {
|
||||
frm.add_custom_button(__('Export Customizations'), function() {
|
||||
frappe.prompt(
|
||||
[
|
||||
|
|
@ -129,29 +136,29 @@ frappe.ui.form.on("Customize Form", {
|
|||
}
|
||||
|
||||
// sort order select
|
||||
if(frm.doc.doc_type) {
|
||||
if (frm.doc.doc_type) {
|
||||
var fields = $.map(frm.doc.fields,
|
||||
function(df) { return frappe.model.is_value_type(df.fieldtype) ? df.fieldname : null; });
|
||||
function(df) { return frappe.model.is_value_type(df.fieldtype) ? df.fieldname : null; });
|
||||
fields = ["", "name", "modified"].concat(fields);
|
||||
frm.set_df_property("sort_field", "options", fields);
|
||||
}
|
||||
|
||||
if(frappe.route_options && frappe.route_options.doc_type) {
|
||||
if (frappe.route_options && frappe.route_options.doc_type) {
|
||||
setTimeout(function() {
|
||||
frm.set_value("doc_type", frappe.route_options.doc_type);
|
||||
frappe.route_options = null;
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// can't delete standard fields
|
||||
frappe.ui.form.on("Customize Form Field", {
|
||||
before_fields_remove: function(frm, doctype, name) {
|
||||
var row = frappe.get_doc(doctype, name);
|
||||
if(!(row.is_custom_field || row.__islocal)) {
|
||||
if (!(row.is_custom_field || row.__islocal)) {
|
||||
frappe.msgprint(__("Cannot delete standard field. You can hide it if you want"));
|
||||
throw "cannot delete custom field";
|
||||
throw "cannot delete standard field";
|
||||
}
|
||||
},
|
||||
fields_add: function(frm, cdt, cdn) {
|
||||
|
|
@ -160,16 +167,46 @@ frappe.ui.form.on("Customize Form Field", {
|
|||
}
|
||||
});
|
||||
|
||||
// can't delete standard links
|
||||
frappe.ui.form.on("DocType Link", {
|
||||
before_links_remove: function(frm, doctype, name) {
|
||||
let row = frappe.get_doc(doctype, name);
|
||||
if (!(row.custom || row.__islocal)) {
|
||||
frappe.msgprint(__("Cannot delete standard link. You can hide it if you want"));
|
||||
throw "cannot delete standard link";
|
||||
}
|
||||
},
|
||||
links_add: function(frm, cdt, cdn) {
|
||||
let f = frappe.model.get_doc(cdt, cdn);
|
||||
f.custom = 1;
|
||||
}
|
||||
});
|
||||
|
||||
// can't delete standard actions
|
||||
frappe.ui.form.on("DocType Action", {
|
||||
before_actions_remove: function(frm, doctype, name) {
|
||||
let row = frappe.get_doc(doctype, name);
|
||||
if (!(row.custom || row.__islocal)) {
|
||||
frappe.msgprint(__("Cannot delete standard action. You can hide it if you want"));
|
||||
throw "cannot delete standard action";
|
||||
}
|
||||
},
|
||||
actions_add: function(frm, cdt, cdn) {
|
||||
let f = frappe.model.get_doc(cdt, cdn);
|
||||
f.custom = 1;
|
||||
}
|
||||
});
|
||||
|
||||
frappe.customize_form.set_primary_action = function(frm) {
|
||||
frm.page.set_primary_action(__("Update"), function() {
|
||||
if(frm.doc.doc_type) {
|
||||
if (frm.doc.doc_type) {
|
||||
return frm.call({
|
||||
doc: frm.doc,
|
||||
freeze: true,
|
||||
btn: frm.page.btn_primary,
|
||||
method: "save_customization",
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
if (!r.exc) {
|
||||
frappe.customize_form.clear_locals_and_refresh(frm);
|
||||
frm.script_manager.trigger("doc_type");
|
||||
}
|
||||
|
|
@ -180,7 +217,7 @@ frappe.customize_form.set_primary_action = function(frm) {
|
|||
};
|
||||
|
||||
frappe.customize_form.confirm = function(msg, frm) {
|
||||
if(!frm.doc.doc_type) return;
|
||||
if (!frm.doc.doc_type) return;
|
||||
|
||||
var d = new frappe.ui.Dialog({
|
||||
title: 'Reset To Defaults',
|
||||
|
|
@ -192,7 +229,7 @@ frappe.customize_form.confirm = function(msg, frm) {
|
|||
doc: frm.doc,
|
||||
method: "reset_to_defaults",
|
||||
callback: function(r) {
|
||||
if(r.exc) {
|
||||
if (r.exc) {
|
||||
frappe.msgprint(r.exc);
|
||||
} else {
|
||||
d.hide();
|
||||
|
|
|
|||
|
|
@ -10,8 +10,9 @@
|
|||
"doc_type",
|
||||
"properties",
|
||||
"label",
|
||||
"default_print_format",
|
||||
"max_attachments",
|
||||
"search_fields",
|
||||
"column_break_5",
|
||||
"allow_copy",
|
||||
"istable",
|
||||
"editable_grid",
|
||||
|
|
@ -20,22 +21,27 @@
|
|||
"track_views",
|
||||
"allow_auto_repeat",
|
||||
"allow_import",
|
||||
"show_preview_popup",
|
||||
"image_view",
|
||||
"column_break_5",
|
||||
"fields_section_break",
|
||||
"fields",
|
||||
"view_settings_section",
|
||||
"title_field",
|
||||
"image_field",
|
||||
"search_fields",
|
||||
"section_break_8",
|
||||
"sort_field",
|
||||
"column_break_10",
|
||||
"sort_order",
|
||||
"section_break_23",
|
||||
"default_print_format",
|
||||
"column_break_29",
|
||||
"show_preview_popup",
|
||||
"image_view",
|
||||
"email_settings_section",
|
||||
"email_append_to",
|
||||
"sender_field",
|
||||
"subject_field",
|
||||
"fields_section_break",
|
||||
"fields"
|
||||
"document_actions_section",
|
||||
"actions",
|
||||
"document_links_section",
|
||||
"links",
|
||||
"section_break_8",
|
||||
"sort_field",
|
||||
"column_break_10",
|
||||
"sort_order"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
|
|
@ -130,9 +136,11 @@
|
|||
"label": "Search Fields"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"depends_on": "doc_type",
|
||||
"fieldname": "section_break_8",
|
||||
"fieldtype": "Section Break"
|
||||
"fieldtype": "Section Break",
|
||||
"label": "List Settings"
|
||||
},
|
||||
{
|
||||
"fieldname": "sort_field",
|
||||
|
|
@ -161,7 +169,8 @@
|
|||
"fieldname": "fields",
|
||||
"fieldtype": "Table",
|
||||
"label": "Fields",
|
||||
"options": "Customize Form Field"
|
||||
"options": "Customize Form Field",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
|
|
@ -200,24 +209,67 @@
|
|||
"fieldtype": "Check",
|
||||
"label": "Allow document creation via Email"
|
||||
},
|
||||
{
|
||||
"depends_on": "doc_type",
|
||||
"fieldname": "section_break_23",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "show_preview_popup",
|
||||
"fieldtype": "Check",
|
||||
"label": "Show Preview Popup"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"depends_on": "doc_type",
|
||||
"fieldname": "view_settings_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "View Settings"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_29",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"collapsible_depends_on": "email_append_to",
|
||||
"depends_on": "doc_type",
|
||||
"fieldname": "email_settings_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Email Settings"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"collapsible_depends_on": "links",
|
||||
"depends_on": "doc_type",
|
||||
"fieldname": "document_links_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Document Links"
|
||||
},
|
||||
{
|
||||
"fieldname": "links",
|
||||
"fieldtype": "Table",
|
||||
"label": "Links",
|
||||
"options": "DocType Link"
|
||||
},
|
||||
{
|
||||
"collapsible": 1,
|
||||
"collapsible_depends_on": "actions",
|
||||
"depends_on": "doc_type",
|
||||
"fieldname": "document_actions_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Document Actions"
|
||||
},
|
||||
{
|
||||
"fieldname": "actions",
|
||||
"fieldtype": "Table",
|
||||
"label": "Actions",
|
||||
"options": "DocType Action"
|
||||
}
|
||||
],
|
||||
"hide_toolbar": 1,
|
||||
"icon": "fa fa-glass",
|
||||
"idx": 1,
|
||||
"index_web_pages_for_search": 1,
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2020-04-10 12:16:01.320411",
|
||||
"modified": "2020-09-24 14:16:49.594012",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Custom",
|
||||
"name": "Customize Form",
|
||||
|
|
|
|||
|
|
@ -6,9 +6,10 @@ from __future__ import unicode_literals
|
|||
Customize Form is a Single DocType used to mask the Property Setter
|
||||
Thus providing a better UI from user perspective
|
||||
"""
|
||||
import json
|
||||
import frappe
|
||||
import frappe.translate
|
||||
from frappe import _
|
||||
from frappe import _, scrub
|
||||
from frappe.utils import cint
|
||||
from frappe.model.document import Document
|
||||
from frappe.model import no_value_fields, core_doctypes_list
|
||||
|
|
@ -16,6 +17,440 @@ from frappe.core.doctype.doctype.doctype import validate_fields_for_doctype, che
|
|||
from frappe.custom.doctype.custom_field.custom_field import create_custom_field
|
||||
from frappe.model.docfield import supports_translation
|
||||
|
||||
class CustomizeForm(Document):
|
||||
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):
|
||||
self.clear_existing_doc()
|
||||
if not self.doc_type:
|
||||
return
|
||||
|
||||
meta = frappe.get_meta(self.doc_type)
|
||||
|
||||
self.validate_doctype(meta)
|
||||
|
||||
# load the meta properties on the customize (self) object
|
||||
self.load_properties(meta)
|
||||
|
||||
# load custom translation
|
||||
translation = self.get_name_translation()
|
||||
self.label = translation.translated_text if translation else ''
|
||||
|
||||
self.create_auto_repeat_custom_field_if_requried(meta)
|
||||
|
||||
# NOTE doc (self) is sent to clientside by run_method
|
||||
|
||||
def validate_doctype(self, meta):
|
||||
'''
|
||||
Check if the doctype is allowed to be customized.
|
||||
'''
|
||||
#if self.doc_type in core_doctypes_list:
|
||||
# frappe.throw(_("Core DocTypes cannot be customized."))
|
||||
|
||||
if meta.issingle:
|
||||
frappe.throw(_("Single DocTypes cannot be customized."))
|
||||
|
||||
if meta.custom:
|
||||
frappe.throw(_("Only standard DocTypes are allowed to be customized from Customize Form."))
|
||||
|
||||
def load_properties(self, meta):
|
||||
'''
|
||||
Load the customize object (this) with the metadata properties
|
||||
'''
|
||||
# doctype properties
|
||||
for prop in doctype_properties:
|
||||
self.set(prop, meta.get(prop))
|
||||
|
||||
for d in meta.get("fields"):
|
||||
new_d = {"fieldname": d.fieldname, "is_custom_field": d.get("is_custom_field"), "name": d.name}
|
||||
for prop in docfield_properties:
|
||||
new_d[prop] = d.get(prop)
|
||||
self.append("fields", new_d)
|
||||
|
||||
for fieldname in ('links', 'actions'):
|
||||
for d in meta.get(fieldname):
|
||||
self.append(fieldname, d)
|
||||
|
||||
def create_auto_repeat_custom_field_if_requried(self, meta):
|
||||
if self.allow_auto_repeat:
|
||||
if not frappe.db.exists('Custom Field', {'fieldname': 'auto_repeat',
|
||||
'dt': self.doc_type}):
|
||||
insert_after = self.fields[len(self.fields) - 1].fieldname
|
||||
df = dict(
|
||||
fieldname='auto_repeat',
|
||||
label='Auto Repeat',
|
||||
fieldtype='Link',
|
||||
options='Auto Repeat',
|
||||
insert_after=insert_after,
|
||||
read_only=1, no_copy=1, print_hide=1)
|
||||
create_custom_field(self.doc_type, df)
|
||||
|
||||
|
||||
def get_name_translation(self):
|
||||
'''Get translation object if exists of current doctype name in the default language'''
|
||||
return frappe.get_value('Translation', {
|
||||
'source_text': self.doc_type,
|
||||
'language': frappe.local.lang or 'en'
|
||||
}, ['name', 'translated_text'], as_dict=True)
|
||||
|
||||
def set_name_translation(self):
|
||||
'''Create, update custom translation for this doctype'''
|
||||
current = self.get_name_translation()
|
||||
if current:
|
||||
if self.label and current.translated_text != self.label:
|
||||
frappe.db.set_value('Translation', current.name, 'translated_text', self.label)
|
||||
frappe.translate.clear_cache()
|
||||
else:
|
||||
# clear translation
|
||||
frappe.delete_doc('Translation', current.name)
|
||||
|
||||
else:
|
||||
if self.label:
|
||||
frappe.get_doc(dict(doctype='Translation',
|
||||
source_text=self.doc_type,
|
||||
translated_text=self.label,
|
||||
language_code=frappe.local.lang or 'en')).insert()
|
||||
|
||||
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):
|
||||
if not self.doc_type:
|
||||
return
|
||||
|
||||
self.flags.update_db = False
|
||||
self.flags.rebuild_doctype_for_global_search = False
|
||||
self.set_property_setters()
|
||||
self.update_custom_fields()
|
||||
self.set_name_translation()
|
||||
validate_fields_for_doctype(self.doc_type)
|
||||
check_email_append_to(self)
|
||||
|
||||
if self.flags.update_db:
|
||||
frappe.db.updatedb(self.doc_type)
|
||||
|
||||
if not hasattr(self, 'hide_success') or not self.hide_success:
|
||||
frappe.msgprint(_("{0} updated").format(_(self.doc_type)), alert=True)
|
||||
frappe.clear_cache(doctype=self.doc_type)
|
||||
self.fetch_to_customize()
|
||||
|
||||
if self.flags.rebuild_doctype_for_global_search:
|
||||
frappe.enqueue('frappe.utils.global_search.rebuild_for_doctype',
|
||||
now=True, doctype=self.doc_type)
|
||||
|
||||
def set_property_setters(self):
|
||||
meta = frappe.get_meta(self.doc_type)
|
||||
|
||||
# doctype
|
||||
self.set_property_setters_for_doctype(meta)
|
||||
|
||||
# docfield
|
||||
for df in self.get("fields"):
|
||||
meta_df = meta.get("fields", {"fieldname": df.fieldname})
|
||||
if not meta_df or meta_df[0].get("is_custom_field"):
|
||||
continue
|
||||
self.set_property_setters_for_docfield(meta, df, meta_df)
|
||||
|
||||
# action and links
|
||||
self.set_property_setters_for_actions_and_links(meta)
|
||||
|
||||
def set_property_setters_for_doctype(self, meta):
|
||||
for prop, prop_type in doctype_properties.items():
|
||||
if self.get(prop) != meta.get(prop):
|
||||
print(prop, self.get(prop), prop_type)
|
||||
self.make_property_setter(prop, self.get(prop), prop_type)
|
||||
|
||||
def set_property_setters_for_docfield(self, meta, df, meta_df):
|
||||
for prop, prop_type in docfield_properties.items():
|
||||
if prop != "idx" and (df.get(prop) or '') != (meta_df[0].get(prop) or ''):
|
||||
if not self.allow_property_change(prop, meta_df, df):
|
||||
continue
|
||||
|
||||
self.make_property_setter(prop, df.get(prop), prop_type,
|
||||
fieldname=df.fieldname)
|
||||
|
||||
def allow_property_change(self, prop, meta_df, df):
|
||||
if prop == "fieldtype":
|
||||
self.validate_fieldtype_change(df, meta_df[0].get(prop), df.get(prop))
|
||||
|
||||
elif prop == "allow_on_submit" and df.get(prop):
|
||||
if not frappe.db.get_value("DocField",
|
||||
{"parent": self.doc_type, "fieldname": df.fieldname}, "allow_on_submit"):
|
||||
frappe.msgprint(_("Row {0}: Not allowed to enable Allow on Submit for standard fields")\
|
||||
.format(df.idx))
|
||||
return False
|
||||
|
||||
elif prop == "reqd" and \
|
||||
((frappe.db.get_value("DocField",
|
||||
{"parent":self.doc_type,"fieldname":df.fieldname}, "reqd") == 1) \
|
||||
and (df.get(prop) == 0)):
|
||||
frappe.msgprint(_("Row {0}: Not allowed to disable Mandatory for standard fields")\
|
||||
.format(df.idx))
|
||||
return False
|
||||
|
||||
elif prop == "in_list_view" and df.get(prop) \
|
||||
and df.fieldtype!="Attach Image" and df.fieldtype in no_value_fields:
|
||||
frappe.msgprint(_("'In List View' not allowed for type {0} in row {1}")
|
||||
.format(df.fieldtype, df.idx))
|
||||
return False
|
||||
|
||||
elif prop == "precision" and cint(df.get("precision")) > 6 \
|
||||
and cint(df.get("precision")) > cint(meta_df[0].get("precision")):
|
||||
self.flags.update_db = True
|
||||
|
||||
elif prop == "unique":
|
||||
self.flags.update_db = True
|
||||
|
||||
elif (prop == "read_only" and cint(df.get("read_only"))==0
|
||||
and frappe.db.get_value("DocField", {"parent": self.doc_type,
|
||||
"fieldname": df.fieldname}, "read_only")==1):
|
||||
# if docfield has read_only checked and user is trying to make it editable, don't allow it
|
||||
frappe.msgprint(_("You cannot unset 'Read Only' for field {0}").format(df.label))
|
||||
return False
|
||||
|
||||
elif prop == "options" and df.get("fieldtype") not in ALLOWED_OPTIONS_CHANGE:
|
||||
frappe.msgprint(_("You can't set 'Options' for field {0}").format(df.label))
|
||||
return False
|
||||
|
||||
elif prop == 'translatable' and not supports_translation(df.get('fieldtype')):
|
||||
frappe.msgprint(_("You can't set 'Translatable' for field {0}").format(df.label))
|
||||
return False
|
||||
|
||||
elif (prop == 'in_global_search' and
|
||||
df.in_global_search != meta_df[0].get("in_global_search")):
|
||||
self.flags.rebuild_doctype_for_global_search = True
|
||||
|
||||
return True
|
||||
|
||||
def set_property_setters_for_actions_and_links(self, meta):
|
||||
'''
|
||||
Apply property setters or create custom records for DocType Action and DocType Link
|
||||
'''
|
||||
for doctype, fieldname, field_map in (
|
||||
('DocType Link', 'links', doctype_link_properties),
|
||||
('DocType Action', 'actions', doctype_action_properties)
|
||||
):
|
||||
has_custom = False
|
||||
for d in self.get(fieldname):
|
||||
if not (d.custom and frappe.db.exists(doctype, d.name)):
|
||||
# check property and apply property setter
|
||||
original = frappe.get_doc(doctype, d.name)
|
||||
for prop, prop_type in field_map.items():
|
||||
if d.get(prop) != original.get(prop):
|
||||
self.make_property_setter(prop, d.get(prop), prop_type,
|
||||
apply_on=doctype, row_name=d.name)
|
||||
else:
|
||||
# add or update custom object
|
||||
if frappe.db.exists(doctype, d.name):
|
||||
doc = frappe.get_doc(doctype, d.name)
|
||||
else:
|
||||
doc = frappe.new_doc(doctype)
|
||||
doc.parent = self.doc_type
|
||||
doc.parenttype = '_Custom' # dummy parenttype since its mandatory
|
||||
doc.custom = 1
|
||||
|
||||
for prop, prop_type in field_map.items():
|
||||
doc.set(prop, d.get(prop))
|
||||
|
||||
doc.save(ignore_permissions=True)
|
||||
has_custom = True
|
||||
|
||||
if has_custom:
|
||||
# save the order of the actions and links
|
||||
self.make_property_setter('{}_order'.format(fieldname),
|
||||
json.dumps([d.name for d in self.get(fieldname)]), 'Small Text')
|
||||
|
||||
|
||||
def update_custom_fields(self):
|
||||
for i, df in enumerate(self.get("fields")):
|
||||
if df.get("is_custom_field"):
|
||||
if not frappe.db.exists('Custom Field', {'dt': self.doc_type, 'fieldname': df.fieldname}):
|
||||
self.add_custom_field(df, i)
|
||||
self.flags.update_db = True
|
||||
else:
|
||||
self.update_in_custom_field(df, i)
|
||||
|
||||
self.delete_custom_fields()
|
||||
|
||||
def add_custom_field(self, df, i):
|
||||
d = frappe.new_doc("Custom Field")
|
||||
|
||||
d.dt = self.doc_type
|
||||
|
||||
for prop in docfield_properties:
|
||||
d.set(prop, df.get(prop))
|
||||
|
||||
if i!=0:
|
||||
d.insert_after = self.fields[i-1].fieldname
|
||||
d.idx = i
|
||||
|
||||
d.insert()
|
||||
df.fieldname = d.fieldname
|
||||
|
||||
def update_in_custom_field(self, df, i):
|
||||
meta = frappe.get_meta(self.doc_type)
|
||||
meta_df = meta.get("fields", {"fieldname": df.fieldname})
|
||||
if not (meta_df and meta_df[0].get("is_custom_field")):
|
||||
# not a custom field
|
||||
return
|
||||
|
||||
custom_field = frappe.get_doc("Custom Field", meta_df[0].name)
|
||||
changed = False
|
||||
for prop in docfield_properties:
|
||||
if df.get(prop) != custom_field.get(prop):
|
||||
if prop == "fieldtype":
|
||||
self.validate_fieldtype_change(df, meta_df[0].get(prop), df.get(prop))
|
||||
|
||||
custom_field.set(prop, df.get(prop))
|
||||
changed = True
|
||||
|
||||
# check and update `insert_after` property
|
||||
if i!=0:
|
||||
insert_after = self.fields[i-1].fieldname
|
||||
if custom_field.insert_after != insert_after:
|
||||
custom_field.insert_after = insert_after
|
||||
custom_field.idx = i
|
||||
changed = True
|
||||
|
||||
if changed:
|
||||
custom_field.db_update()
|
||||
self.flags.update_db = True
|
||||
#custom_field.save()
|
||||
|
||||
def delete_custom_fields(self):
|
||||
meta = frappe.get_meta(self.doc_type)
|
||||
fields_to_remove = (set([df.fieldname for df in meta.get("fields")])
|
||||
- set(df.fieldname for df in self.get("fields")))
|
||||
|
||||
for fieldname in fields_to_remove:
|
||||
df = meta.get("fields", {"fieldname": fieldname})[0]
|
||||
if df.get("is_custom_field"):
|
||||
frappe.delete_doc("Custom Field", df.name)
|
||||
|
||||
def make_property_setter(self, prop, value, property_type, fieldname=None,
|
||||
apply_on=None, row_name = None):
|
||||
self.delete_existing_property_setter(prop, fieldname)
|
||||
|
||||
property_value = self.get_existing_property_value(prop, fieldname)
|
||||
|
||||
if property_value==value:
|
||||
return
|
||||
|
||||
if not apply_on:
|
||||
apply_on = "DocField" if fieldname else "DocType"
|
||||
|
||||
# create a new property setter
|
||||
# ignore validation becuase it will be done at end
|
||||
frappe.make_property_setter({
|
||||
"doctype": self.doc_type,
|
||||
"doctype_or_field": apply_on,
|
||||
"fieldname": fieldname,
|
||||
"row_name": row_name,
|
||||
"property": prop,
|
||||
"value": value,
|
||||
"property_type": property_type
|
||||
}, ignore_validate=True)
|
||||
|
||||
def delete_existing_property_setter(self, prop, fieldname=None):
|
||||
# first delete existing property setter
|
||||
existing_property_setter = frappe.db.get_value("Property Setter", {"doc_type": self.doc_type,
|
||||
"property": prop, "field_name['']": fieldname or ''})
|
||||
|
||||
if existing_property_setter:
|
||||
frappe.db.sql("delete from `tabProperty Setter` where name=%s", existing_property_setter)
|
||||
|
||||
def get_existing_property_value(self, property_name, fieldname=None):
|
||||
# check if there is any need to make property setter!
|
||||
if fieldname:
|
||||
property_value = frappe.db.get_value("DocField", {"parent": self.doc_type,
|
||||
"fieldname": fieldname}, property_name)
|
||||
else:
|
||||
try:
|
||||
property_value = frappe.db.get_value("DocType", self.doc_type, property_name)
|
||||
except Exception as e:
|
||||
if frappe.db.is_column_missing(e):
|
||||
property_value = None
|
||||
else:
|
||||
raise
|
||||
|
||||
return property_value
|
||||
|
||||
def validate_fieldtype_change(self, df, old_value, new_value):
|
||||
allowed = False
|
||||
self.check_length_for_fieldtypes = []
|
||||
for allowed_changes in ALLOWED_FIELDTYPE_CHANGE:
|
||||
if (old_value in allowed_changes and new_value in allowed_changes):
|
||||
allowed = True
|
||||
old_value_length = cint(frappe.db.type_map.get(old_value)[1])
|
||||
new_value_length = cint(frappe.db.type_map.get(new_value)[1])
|
||||
|
||||
# Ignore fieldtype check validation if new field type has unspecified maxlength
|
||||
# Changes like DATA to TEXT, where new_value_lenth equals 0 will not be validated
|
||||
if new_value_length and (old_value_length > new_value_length):
|
||||
self.check_length_for_fieldtypes.append({'df': df, 'old_value': old_value})
|
||||
self.validate_fieldtype_length()
|
||||
else:
|
||||
self.flags.update_db = True
|
||||
break
|
||||
if not allowed:
|
||||
frappe.throw(_("Fieldtype cannot be changed from {0} to {1} in row {2}").format(old_value, new_value, df.idx))
|
||||
|
||||
def validate_fieldtype_length(self):
|
||||
for field in self.check_length_for_fieldtypes:
|
||||
df = field.get('df')
|
||||
max_length = cint(frappe.db.type_map.get(df.fieldtype)[1])
|
||||
fieldname = df.fieldname
|
||||
docs = frappe.db.sql('''
|
||||
SELECT name, {fieldname}, LENGTH({fieldname}) AS len
|
||||
FROM `tab{doctype}`
|
||||
WHERE LENGTH({fieldname}) > {max_length}
|
||||
'''.format(
|
||||
fieldname=fieldname,
|
||||
doctype=self.doc_type,
|
||||
max_length=max_length
|
||||
), as_dict=True)
|
||||
links = []
|
||||
label = df.label
|
||||
for doc in docs:
|
||||
links.append(frappe.utils.get_link_to_form(self.doc_type, doc.name))
|
||||
links_str = ', '.join(links)
|
||||
|
||||
if docs:
|
||||
frappe.throw(_('Value for field {0} is too long in {1}. Length should be lesser than {2} characters')
|
||||
.format(
|
||||
frappe.bold(label),
|
||||
links_str,
|
||||
frappe.bold(max_length)
|
||||
), title=_('Data Too Long'), is_minimizable=len(docs) > 1)
|
||||
|
||||
self.flags.update_db = True
|
||||
|
||||
def reset_to_defaults(self):
|
||||
if not self.doc_type:
|
||||
return
|
||||
|
||||
reset_customization(self.doc_type)
|
||||
self.fetch_to_customize()
|
||||
|
||||
def reset_customization(doctype):
|
||||
frappe.db.sql("""
|
||||
DELETE FROM `tabProperty Setter` WHERE doc_type=%s
|
||||
and `field_name`!='naming_series'
|
||||
and `property`!='options'
|
||||
""", doctype)
|
||||
frappe.clear_cache(doctype=doctype)
|
||||
|
||||
doctype_properties = {
|
||||
'search_fields': 'Data',
|
||||
'title_field': 'Data',
|
||||
|
|
@ -82,356 +517,31 @@ docfield_properties = {
|
|||
'hide_seconds': 'Check'
|
||||
}
|
||||
|
||||
allowed_fieldtype_change = (('Currency', 'Float', 'Percent'), ('Small Text', 'Data'),
|
||||
('Text', 'Data'), ('Text', 'Text Editor', 'Code', 'Signature', 'HTML Editor'), ('Data', 'Select'),
|
||||
('Text', 'Small Text'), ('Text', 'Data', 'Barcode'), ('Code', 'Geolocation'), ('Table', 'Table MultiSelect'))
|
||||
|
||||
allowed_fieldtype_for_options_change = ('Read Only', 'HTML', 'Select', 'Data')
|
||||
|
||||
class CustomizeForm(Document):
|
||||
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):
|
||||
self.clear_existing_doc()
|
||||
if not self.doc_type:
|
||||
return
|
||||
|
||||
meta = frappe.get_meta(self.doc_type)
|
||||
|
||||
if self.doc_type in core_doctypes_list:
|
||||
return frappe.msgprint(_("Core DocTypes cannot be customized."))
|
||||
|
||||
if meta.issingle:
|
||||
return frappe.msgprint(_("Single DocTypes cannot be customized."))
|
||||
|
||||
if meta.custom:
|
||||
return frappe.msgprint(_("Only standard DocTypes are allowed to be customized from Customize Form."))
|
||||
|
||||
# doctype properties
|
||||
for property in doctype_properties:
|
||||
self.set(property, meta.get(property))
|
||||
|
||||
for d in meta.get("fields"):
|
||||
new_d = {"fieldname": d.fieldname, "is_custom_field": d.get("is_custom_field"), "name": d.name}
|
||||
for property in docfield_properties:
|
||||
new_d[property] = d.get(property)
|
||||
self.append("fields", new_d)
|
||||
|
||||
# load custom translation
|
||||
translation = self.get_name_translation()
|
||||
self.label = translation.translated_text if translation else ''
|
||||
|
||||
#If allow_auto_repeat is set, add auto_repeat custom field.
|
||||
if self.allow_auto_repeat:
|
||||
if not frappe.db.exists('Custom Field', {'fieldname': 'auto_repeat', 'dt': self.doc_type}):
|
||||
insert_after = self.fields[len(self.fields) - 1].fieldname
|
||||
df = dict(fieldname='auto_repeat', label='Auto Repeat', fieldtype='Link', options='Auto Repeat', insert_after=insert_after, read_only=1, no_copy=1, print_hide=1)
|
||||
create_custom_field(self.doc_type, df)
|
||||
|
||||
# NOTE doc is sent to clientside by run_method
|
||||
|
||||
def get_name_translation(self):
|
||||
'''Get translation object if exists of current doctype name in the default language'''
|
||||
return frappe.get_value('Translation', {
|
||||
'source_text': self.doc_type,
|
||||
'language': frappe.local.lang or 'en'
|
||||
}, ['name', 'translated_text'], as_dict=True)
|
||||
|
||||
def set_name_translation(self):
|
||||
'''Create, update custom translation for this doctype'''
|
||||
current = self.get_name_translation()
|
||||
if current:
|
||||
if self.label and current.translated_text != self.label:
|
||||
frappe.db.set_value('Translation', current.name, 'translated_text', self.label)
|
||||
frappe.translate.clear_cache()
|
||||
else:
|
||||
# clear translation
|
||||
frappe.delete_doc('Translation', current.name)
|
||||
|
||||
else:
|
||||
if self.label:
|
||||
frappe.get_doc(dict(doctype='Translation',
|
||||
source_text=self.doc_type,
|
||||
translated_text=self.label,
|
||||
language_code=frappe.local.lang or 'en')).insert()
|
||||
|
||||
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):
|
||||
if not self.doc_type:
|
||||
return
|
||||
|
||||
self.flags.update_db = False
|
||||
self.flags.rebuild_doctype_for_global_search = False
|
||||
self.set_property_setters()
|
||||
self.update_custom_fields()
|
||||
self.set_name_translation()
|
||||
validate_fields_for_doctype(self.doc_type)
|
||||
check_email_append_to(self)
|
||||
|
||||
if self.flags.update_db:
|
||||
frappe.db.updatedb(self.doc_type)
|
||||
|
||||
if not hasattr(self, 'hide_success') or not self.hide_success:
|
||||
frappe.msgprint(_("{0} updated").format(_(self.doc_type)), alert=True)
|
||||
frappe.clear_cache(doctype=self.doc_type)
|
||||
self.fetch_to_customize()
|
||||
|
||||
if self.flags.rebuild_doctype_for_global_search:
|
||||
frappe.enqueue('frappe.utils.global_search.rebuild_for_doctype',
|
||||
now=True, doctype=self.doc_type)
|
||||
|
||||
def set_property_setters(self):
|
||||
meta = frappe.get_meta(self.doc_type)
|
||||
# doctype property setters
|
||||
|
||||
for property in doctype_properties:
|
||||
if self.get(property) != meta.get(property):
|
||||
self.make_property_setter(property=property, value=self.get(property),
|
||||
property_type=doctype_properties[property])
|
||||
|
||||
for df in self.get("fields"):
|
||||
meta_df = meta.get("fields", {"fieldname": df.fieldname})
|
||||
|
||||
if not meta_df or meta_df[0].get("is_custom_field"):
|
||||
continue
|
||||
|
||||
for property in docfield_properties:
|
||||
if property != "idx" and (df.get(property) or '') != (meta_df[0].get(property) or ''):
|
||||
if property == "fieldtype":
|
||||
self.validate_fieldtype_change(df, meta_df[0].get(property), df.get(property))
|
||||
|
||||
elif property == "allow_on_submit" and df.get(property):
|
||||
if not frappe.db.get_value("DocField",
|
||||
{"parent": self.doc_type, "fieldname": df.fieldname}, "allow_on_submit"):
|
||||
frappe.msgprint(_("Row {0}: Not allowed to enable Allow on Submit for standard fields")\
|
||||
.format(df.idx))
|
||||
continue
|
||||
|
||||
elif property == "reqd" and \
|
||||
((frappe.db.get_value("DocField",
|
||||
{"parent":self.doc_type,"fieldname":df.fieldname}, "reqd") == 1) \
|
||||
and (df.get(property) == 0)):
|
||||
frappe.msgprint(_("Row {0}: Not allowed to disable Mandatory for standard fields")\
|
||||
.format(df.idx))
|
||||
continue
|
||||
|
||||
elif property == "in_list_view" and df.get(property) \
|
||||
and df.fieldtype!="Attach Image" and df.fieldtype in no_value_fields:
|
||||
frappe.msgprint(_("'In List View' not allowed for type {0} in row {1}")
|
||||
.format(df.fieldtype, df.idx))
|
||||
continue
|
||||
|
||||
elif property == "precision" and cint(df.get("precision")) > 6 \
|
||||
and cint(df.get("precision")) > cint(meta_df[0].get("precision")):
|
||||
self.flags.update_db = True
|
||||
|
||||
elif property == "unique":
|
||||
self.flags.update_db = True
|
||||
|
||||
elif (property == "read_only" and cint(df.get("read_only"))==0
|
||||
and frappe.db.get_value("DocField", {"parent": self.doc_type, "fieldname": df.fieldname}, "read_only")==1):
|
||||
# if docfield has read_only checked and user is trying to make it editable, don't allow it
|
||||
frappe.msgprint(_("You cannot unset 'Read Only' for field {0}").format(df.label))
|
||||
continue
|
||||
|
||||
elif property == "options" and df.get("fieldtype") not in allowed_fieldtype_for_options_change:
|
||||
frappe.msgprint(_("You can't set 'Options' for field {0}").format(df.label))
|
||||
continue
|
||||
|
||||
elif property == 'translatable' and not supports_translation(df.get('fieldtype')):
|
||||
frappe.msgprint(_("You can't set 'Translatable' for field {0}").format(df.label))
|
||||
continue
|
||||
|
||||
elif (property == 'in_global_search' and
|
||||
df.in_global_search != meta_df[0].get("in_global_search")):
|
||||
self.flags.rebuild_doctype_for_global_search = True
|
||||
|
||||
self.make_property_setter(property=property, value=df.get(property),
|
||||
property_type=docfield_properties[property], fieldname=df.fieldname)
|
||||
|
||||
def update_custom_fields(self):
|
||||
for i, df in enumerate(self.get("fields")):
|
||||
if df.get("is_custom_field"):
|
||||
if not frappe.db.exists('Custom Field', {'dt': self.doc_type, 'fieldname': df.fieldname}):
|
||||
self.add_custom_field(df, i)
|
||||
self.flags.update_db = True
|
||||
else:
|
||||
self.update_in_custom_field(df, i)
|
||||
|
||||
self.delete_custom_fields()
|
||||
|
||||
def add_custom_field(self, df, i):
|
||||
d = frappe.new_doc("Custom Field")
|
||||
|
||||
d.dt = self.doc_type
|
||||
|
||||
for property in docfield_properties:
|
||||
d.set(property, df.get(property))
|
||||
|
||||
if i!=0:
|
||||
d.insert_after = self.fields[i-1].fieldname
|
||||
d.idx = i
|
||||
|
||||
d.insert()
|
||||
df.fieldname = d.fieldname
|
||||
|
||||
def update_in_custom_field(self, df, i):
|
||||
meta = frappe.get_meta(self.doc_type)
|
||||
meta_df = meta.get("fields", {"fieldname": df.fieldname})
|
||||
if not (meta_df and meta_df[0].get("is_custom_field")):
|
||||
# not a custom field
|
||||
return
|
||||
|
||||
custom_field = frappe.get_doc("Custom Field", meta_df[0].name)
|
||||
changed = False
|
||||
for property in docfield_properties:
|
||||
if df.get(property) != custom_field.get(property):
|
||||
if property == "fieldtype":
|
||||
self.validate_fieldtype_change(df, meta_df[0].get(property), df.get(property))
|
||||
|
||||
custom_field.set(property, df.get(property))
|
||||
changed = True
|
||||
|
||||
# check and update `insert_after` property
|
||||
if i!=0:
|
||||
insert_after = self.fields[i-1].fieldname
|
||||
if custom_field.insert_after != insert_after:
|
||||
custom_field.insert_after = insert_after
|
||||
custom_field.idx = i
|
||||
changed = True
|
||||
|
||||
if changed:
|
||||
custom_field.db_update()
|
||||
self.flags.update_db = True
|
||||
#custom_field.save()
|
||||
|
||||
def delete_custom_fields(self):
|
||||
meta = frappe.get_meta(self.doc_type)
|
||||
fields_to_remove = (set([df.fieldname for df in meta.get("fields")])
|
||||
- set(df.fieldname for df in self.get("fields")))
|
||||
|
||||
for fieldname in fields_to_remove:
|
||||
df = meta.get("fields", {"fieldname": fieldname})[0]
|
||||
if df.get("is_custom_field"):
|
||||
frappe.delete_doc("Custom Field", df.name)
|
||||
|
||||
def make_property_setter(self, property, value, property_type, fieldname=None):
|
||||
self.delete_existing_property_setter(property, fieldname)
|
||||
|
||||
property_value = self.get_existing_property_value(property, fieldname)
|
||||
|
||||
if property_value==value:
|
||||
return
|
||||
|
||||
# create a new property setter
|
||||
# ignore validation becuase it will be done at end
|
||||
frappe.make_property_setter({
|
||||
"doctype": self.doc_type,
|
||||
"doctype_or_field": "DocField" if fieldname else "DocType",
|
||||
"fieldname": fieldname,
|
||||
"property": property,
|
||||
"value": value,
|
||||
"property_type": property_type
|
||||
}, ignore_validate=True)
|
||||
|
||||
def delete_existing_property_setter(self, property, fieldname=None):
|
||||
# first delete existing property setter
|
||||
existing_property_setter = frappe.db.get_value("Property Setter", {"doc_type": self.doc_type,
|
||||
"property": property, "field_name['']": fieldname or ''})
|
||||
|
||||
if existing_property_setter:
|
||||
frappe.db.sql("delete from `tabProperty Setter` where name=%s", existing_property_setter)
|
||||
|
||||
def get_existing_property_value(self, property_name, fieldname=None):
|
||||
# check if there is any need to make property setter!
|
||||
if fieldname:
|
||||
property_value = frappe.db.get_value("DocField", {"parent": self.doc_type,
|
||||
"fieldname": fieldname}, property_name)
|
||||
else:
|
||||
try:
|
||||
property_value = frappe.db.get_value("DocType", self.doc_type, property_name)
|
||||
except Exception as e:
|
||||
if frappe.db.is_column_missing(e):
|
||||
property_value = None
|
||||
else:
|
||||
raise
|
||||
|
||||
return property_value
|
||||
|
||||
def validate_fieldtype_change(self, df, old_value, new_value):
|
||||
allowed = False
|
||||
self.check_length_for_fieldtypes = []
|
||||
for allowed_changes in allowed_fieldtype_change:
|
||||
if (old_value in allowed_changes and new_value in allowed_changes):
|
||||
allowed = True
|
||||
old_value_length = cint(frappe.db.type_map.get(old_value)[1])
|
||||
new_value_length = cint(frappe.db.type_map.get(new_value)[1])
|
||||
|
||||
# Ignore fieldtype check validation if new field type has unspecified maxlength
|
||||
# Changes like DATA to TEXT, where new_value_lenth equals 0 will not be validated
|
||||
if new_value_length and (old_value_length > new_value_length):
|
||||
self.check_length_for_fieldtypes.append({'df': df, 'old_value': old_value})
|
||||
self.validate_fieldtype_length()
|
||||
else:
|
||||
self.flags.update_db = True
|
||||
break
|
||||
if not allowed:
|
||||
frappe.throw(_("Fieldtype cannot be changed from {0} to {1} in row {2}").format(old_value, new_value, df.idx))
|
||||
|
||||
def validate_fieldtype_length(self):
|
||||
for field in self.check_length_for_fieldtypes:
|
||||
df = field.get('df')
|
||||
max_length = cint(frappe.db.type_map.get(df.fieldtype)[1])
|
||||
fieldname = df.fieldname
|
||||
docs = frappe.db.sql('''
|
||||
SELECT name, {fieldname}, LENGTH({fieldname}) AS len
|
||||
FROM `tab{doctype}`
|
||||
WHERE LENGTH({fieldname}) > {max_length}
|
||||
'''.format(
|
||||
fieldname=fieldname,
|
||||
doctype=self.doc_type,
|
||||
max_length=max_length
|
||||
), as_dict=True)
|
||||
links = []
|
||||
label = df.label
|
||||
for doc in docs:
|
||||
links.append(frappe.utils.get_link_to_form(self.doc_type, doc.name))
|
||||
links_str = ', '.join(links)
|
||||
|
||||
if docs:
|
||||
frappe.throw(_('Value for field {0} is too long in {1}. Length should be lesser than {2} characters')
|
||||
.format(
|
||||
frappe.bold(label),
|
||||
links_str,
|
||||
frappe.bold(max_length)
|
||||
), title=_('Data Too Long'), is_minimizable=len(docs) > 1)
|
||||
|
||||
self.flags.update_db = True
|
||||
|
||||
def reset_to_defaults(self):
|
||||
if not self.doc_type:
|
||||
return
|
||||
|
||||
reset_customization(self.doc_type)
|
||||
self.fetch_to_customize()
|
||||
|
||||
def reset_customization(doctype):
|
||||
frappe.db.sql("""
|
||||
DELETE FROM `tabProperty Setter` WHERE doc_type=%s
|
||||
and `field_name`!='naming_series'
|
||||
and `property`!='options'
|
||||
""", doctype)
|
||||
frappe.clear_cache(doctype=doctype)
|
||||
doctype_link_properties = {
|
||||
'link_doctype': 'Link',
|
||||
'link_fieldname': 'Data',
|
||||
'group': 'Data',
|
||||
'hidden': 'Check'
|
||||
}
|
||||
|
||||
doctype_action_properties = {
|
||||
'label': 'Link',
|
||||
'action_type': 'Select',
|
||||
'action': 'Small Text',
|
||||
'group': 'Data',
|
||||
'hidden': 'Check'
|
||||
}
|
||||
|
||||
|
||||
ALLOWED_FIELDTYPE_CHANGE = (
|
||||
('Currency', 'Float', 'Percent'),
|
||||
('Small Text', 'Data'),
|
||||
('Text', 'Data'),
|
||||
('Text', 'Text Editor', 'Code', 'Signature', 'HTML Editor'),
|
||||
('Data', 'Select'),
|
||||
('Text', 'Small Text'),
|
||||
('Text', 'Data', 'Barcode'),
|
||||
('Code', 'Geolocation'),
|
||||
('Table', 'Table MultiSelect'))
|
||||
|
||||
ALLOWED_OPTIONS_CHANGE = ('Read Only', 'HTML', 'Select', 'Data')
|
||||
|
|
|
|||
|
|
@ -11,8 +11,6 @@
|
|||
"label",
|
||||
"fieldtype",
|
||||
"fieldname",
|
||||
"hide_seconds",
|
||||
"hide_days",
|
||||
"reqd",
|
||||
"unique",
|
||||
"in_list_view",
|
||||
|
|
@ -23,6 +21,7 @@
|
|||
"allow_in_quick_entry",
|
||||
"translatable",
|
||||
"column_break_7",
|
||||
"default",
|
||||
"precision",
|
||||
"length",
|
||||
"options",
|
||||
|
|
@ -47,8 +46,9 @@
|
|||
"column_break_33",
|
||||
"read_only_depends_on",
|
||||
"display",
|
||||
"default",
|
||||
"in_filter",
|
||||
"hide_seconds",
|
||||
"hide_days",
|
||||
"column_break_21",
|
||||
"description",
|
||||
"print_hide",
|
||||
|
|
@ -100,6 +100,7 @@
|
|||
"depends_on": "eval:!in_list([\"Section Break\", \"Column Break\", \"Button\", \"HTML\"], doc.fieldtype)",
|
||||
"fieldname": "reqd",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Mandatory",
|
||||
"oldfieldname": "reqd",
|
||||
"oldfieldtype": "Check",
|
||||
|
|
@ -283,7 +284,7 @@
|
|||
},
|
||||
{
|
||||
"fieldname": "default",
|
||||
"fieldtype": "Text",
|
||||
"fieldtype": "Small Text",
|
||||
"label": "Default",
|
||||
"oldfieldname": "default",
|
||||
"oldfieldtype": "Text"
|
||||
|
|
@ -419,7 +420,7 @@
|
|||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2020-08-28 11:28:59.084060",
|
||||
"modified": "2020-09-24 14:05:31.093927",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Custom",
|
||||
"name": "Customize Form Field",
|
||||
|
|
|
|||
|
|
@ -1,358 +1,133 @@
|
|||
{
|
||||
"allow_copy": 0,
|
||||
"allow_import": 0,
|
||||
"allow_rename": 0,
|
||||
"beta": 0,
|
||||
"creation": "2013-01-10 16:34:04",
|
||||
"custom": 0,
|
||||
"description": "Property Setter overrides a standard DocType or Field property",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"editable_grid": 0,
|
||||
"engine": "InnoDB",
|
||||
"actions": [],
|
||||
"creation": "2013-01-10 16:34:04",
|
||||
"description": "Property Setter overrides a standard DocType or Field property",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"help",
|
||||
"sb0",
|
||||
"doctype_or_field",
|
||||
"doc_type",
|
||||
"field_name",
|
||||
"row_name",
|
||||
"column_break0",
|
||||
"property",
|
||||
"property_type",
|
||||
"value",
|
||||
"default_value"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "help",
|
||||
"fieldtype": "HTML",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Help",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "<div class=\"alert\">Please don't update it as it can mess up your form. Use the Customize Form View and Custom Fields to set properties!</div>",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "help",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Help",
|
||||
"options": "<div class=\"alert\">Please don't update it as it can mess up your form. Use the Customize Form View and Custom Fields to set properties!</div>"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "sb0",
|
||||
"fieldtype": "Section Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "sb0",
|
||||
"fieldtype": "Section Break"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.__islocal",
|
||||
"fieldname": "doctype_or_field",
|
||||
"fieldtype": "Select",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "DocType or Field",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "\nDocField\nDocType",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "doctype_or_field",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Applied On",
|
||||
"options": "\nDocField\nDocType\nDocType Link\nDocType Action",
|
||||
"read_only_depends_on": "eval:!doc.__islocal",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"description": "New value to be set",
|
||||
"fieldname": "value",
|
||||
"fieldtype": "Text",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Set Value",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"description": "New value to be set",
|
||||
"fieldname": "value",
|
||||
"fieldtype": "Small Text",
|
||||
"in_list_view": 1,
|
||||
"label": "Set Value"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "column_break0",
|
||||
"fieldtype": "Column Break",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "column_break0",
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "doc_type",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "DocType",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"options": "DocType",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 1,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "doc_type",
|
||||
"fieldtype": "Link",
|
||||
"in_standard_filter": 1,
|
||||
"label": "DocType",
|
||||
"options": "DocType",
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"depends_on": "eval:doc.doctype_or_field=='DocField'",
|
||||
"description": "ID (name) of the entity whose property is to be set",
|
||||
"fieldname": "field_name",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Field Name",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 1,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"depends_on": "eval:doc.doctype_or_field=='DocField'",
|
||||
"description": "ID (name) of the entity whose property is to be set",
|
||||
"fieldname": "field_name",
|
||||
"fieldtype": "Data",
|
||||
"in_standard_filter": 1,
|
||||
"label": "Field Name",
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "property",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Property",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 1,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "property",
|
||||
"fieldtype": "Data",
|
||||
"in_standard_filter": 1,
|
||||
"label": "Property",
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "property_type",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Property Type",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
},
|
||||
"fieldname": "property_type",
|
||||
"fieldtype": "Data",
|
||||
"label": "Property Type"
|
||||
},
|
||||
{
|
||||
"allow_on_submit": 0,
|
||||
"bold": 0,
|
||||
"collapsible": 0,
|
||||
"columns": 0,
|
||||
"fieldname": "default_value",
|
||||
"fieldtype": "Data",
|
||||
"hidden": 0,
|
||||
"ignore_user_permissions": 0,
|
||||
"ignore_xss_filter": 0,
|
||||
"in_filter": 0,
|
||||
"in_list_view": 0,
|
||||
"in_standard_filter": 0,
|
||||
"label": "Default Value",
|
||||
"length": 0,
|
||||
"no_copy": 0,
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"print_hide_if_no_value": 0,
|
||||
"read_only": 0,
|
||||
"remember_last_selected_value": 0,
|
||||
"report_hide": 0,
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"unique": 0
|
||||
"fieldname": "default_value",
|
||||
"fieldtype": "Data",
|
||||
"label": "Default Value"
|
||||
},
|
||||
{
|
||||
"description": "For DocType Link / DocType Action",
|
||||
"fieldname": "row_name",
|
||||
"fieldtype": "Data",
|
||||
"label": "Row Name"
|
||||
}
|
||||
],
|
||||
"hide_heading": 0,
|
||||
"hide_toolbar": 0,
|
||||
"icon": "fa fa-glass",
|
||||
"idx": 1,
|
||||
"image_view": 0,
|
||||
"in_create": 0,
|
||||
|
||||
"is_submittable": 0,
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2016-12-29 14:39:50.172883",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Custom",
|
||||
"name": "Property Setter",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"icon": "fa fa-glass",
|
||||
"idx": 1,
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2020-09-24 14:42:38.599684",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Custom",
|
||||
"name": "Property Setter",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Administrator",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Administrator",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"amend": 0,
|
||||
"apply_user_permissions": 0,
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 0,
|
||||
"if_owner": 0,
|
||||
"import": 0,
|
||||
"is_custom": 0,
|
||||
"permlevel": 0,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"set_user_permissions": 0,
|
||||
"share": 1,
|
||||
"submit": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 0,
|
||||
"read_only": 0,
|
||||
"read_only_onload": 0,
|
||||
"search_fields": "doc_type,property",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1,
|
||||
"track_seen": 0
|
||||
],
|
||||
"search_fields": "doc_type,property",
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"track_changes": 1
|
||||
}
|
||||
|
|
@ -11,9 +11,11 @@ not_allowed_fieldtype_change = ['naming_series']
|
|||
|
||||
class PropertySetter(Document):
|
||||
def autoname(self):
|
||||
self.name = self.doc_type + "-" \
|
||||
+ (self.field_name and (self.field_name + "-") or "") \
|
||||
+ self.property
|
||||
self.name = '{doctype}-{field}-{property}'.format(
|
||||
doctype = self.doc_type,
|
||||
field = self.field_name or self.row_name or 'main',
|
||||
property = self.property
|
||||
)
|
||||
|
||||
def validate(self):
|
||||
self.validate_fieldtype_change()
|
||||
|
|
|
|||
|
|
@ -3,11 +3,6 @@
|
|||
|
||||
frappe.ui.form.on("Email Group", "refresh", function(frm) {
|
||||
if(!frm.is_new()) {
|
||||
frm.add_custom_button(__("View Subscribers"), function() {
|
||||
frappe.route_options = {"email_group": frm.doc.name};
|
||||
frappe.set_route("List", "Email Group Member");
|
||||
}, __("View"));
|
||||
|
||||
frm.add_custom_button(__("Import Subscribers"), function() {
|
||||
frappe.prompt({fieldtype:"Select", options: frm.doc.__onload.import_types,
|
||||
label:__("Import Email From"), fieldname:"doctype", reqd:1},
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
"creation": "2015-03-18 06:08:32.729800",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"title",
|
||||
"total_subscribers",
|
||||
|
|
@ -41,8 +42,15 @@
|
|||
"options": "Email Template"
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2020-02-21 14:12:48.884738",
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [
|
||||
{
|
||||
"group": "Members",
|
||||
"link_doctype": "Email Group Member",
|
||||
"link_fieldname": "email_group"
|
||||
}
|
||||
],
|
||||
"modified": "2020-09-24 16:41:55.286377",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Email",
|
||||
"name": "Email Group",
|
||||
|
|
|
|||
|
|
@ -42,9 +42,12 @@ def get_dynamic_link_map(for_delete=False):
|
|||
# always check in Single DocTypes
|
||||
dynamic_link_map.setdefault(meta.name, []).append(df)
|
||||
else:
|
||||
links = frappe.db.sql_list("""select distinct {options} from `tab{parent}`""".format(**df))
|
||||
for doctype in links:
|
||||
dynamic_link_map.setdefault(doctype, []).append(df)
|
||||
try:
|
||||
links = frappe.db.sql_list("""select distinct {options} from `tab{parent}`""".format(**df))
|
||||
for doctype in links:
|
||||
dynamic_link_map.setdefault(doctype, []).append(df)
|
||||
except frappe.db.TableMissingError: # noqa: E722
|
||||
pass
|
||||
|
||||
frappe.local.dynamic_link_map = dynamic_link_map
|
||||
return frappe.local.dynamic_link_map
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ from __future__ import unicode_literals, print_function
|
|||
from datetime import datetime
|
||||
from six.moves import range
|
||||
import frappe, json, os
|
||||
from frappe.utils import cstr, cint
|
||||
from frappe.utils import cstr, cint, cast_fieldtype
|
||||
from frappe.model import default_fields, no_value_fields, optional_fields, data_fieldtypes, table_fields
|
||||
from frappe.model.document import Document
|
||||
from frappe.model.base_document import BaseDocument
|
||||
|
|
@ -103,6 +103,7 @@ class Meta(Document):
|
|||
self.sort_fields()
|
||||
self.get_valid_columns()
|
||||
self.set_custom_permissions()
|
||||
self.add_custom_links_and_actions()
|
||||
|
||||
def as_dict(self, no_nulls = False):
|
||||
def serialize(doc):
|
||||
|
|
@ -305,6 +306,11 @@ class Meta(Document):
|
|||
self.extend("fields", custom_fields)
|
||||
|
||||
def apply_property_setters(self):
|
||||
"""
|
||||
Property Setters are set via Customize Form. They override standard properties
|
||||
of the doctype or its child properties like fields, links etc. This method
|
||||
applies the customized properties over the standard meta object
|
||||
"""
|
||||
if not frappe.db.table_exists('Property Setter'):
|
||||
return
|
||||
|
||||
|
|
@ -313,26 +319,50 @@ class Meta(Document):
|
|||
|
||||
if not property_setters: return
|
||||
|
||||
integer_docfield_properties = [d.fieldname for d in frappe.get_meta('DocField').fields
|
||||
if d.fieldtype in ('Int', 'Check')]
|
||||
|
||||
for ps in property_setters:
|
||||
if ps.doctype_or_field=='DocType':
|
||||
if ps.property_type in ('Int', 'Check'):
|
||||
ps.value = cint(ps.value)
|
||||
self.set(ps.property, cast_fieldtype(ps.property_type, ps.value))
|
||||
|
||||
self.set(ps.property, ps.value)
|
||||
else:
|
||||
docfield = self.get("fields", {"fieldname":ps.field_name}, limit=1)
|
||||
if docfield:
|
||||
docfield = docfield[0]
|
||||
else:
|
||||
continue
|
||||
elif ps.doctype_or_field=='DocField':
|
||||
for d in self.fields:
|
||||
if d.fieldname == ps.fieldname:
|
||||
d.set(ps.property, cast_fieldtype(ps.property_type, ps.value))
|
||||
break
|
||||
|
||||
if ps.property in integer_docfield_properties:
|
||||
ps.value = cint(ps.value)
|
||||
elif ps.doctype_or_field=='DocType Link':
|
||||
for d in self.links:
|
||||
if d.name == ps.row_name:
|
||||
d.set(ps.property, cast_fieldtype(ps.property_type, ps.value))
|
||||
break
|
||||
|
||||
docfield.set(ps.property, ps.value)
|
||||
elif ps.doctype_or_field=='DocType Action':
|
||||
for d in self.actions:
|
||||
if d.name == ps.row_name:
|
||||
d.set(ps.property, cast_fieldtype(ps.property_type, ps.value))
|
||||
break
|
||||
|
||||
def add_custom_links_and_actions(self):
|
||||
for doctype, fieldname in (('DocType Link', 'links'), ('DocType Action', 'actions')):
|
||||
for d in frappe.get_all(doctype, dict(parent=self.name, custom=1)):
|
||||
self.get(fieldname).append(d)
|
||||
|
||||
# set the fields in order if specified
|
||||
# order is saved as `links_order`
|
||||
order = json.loads(self.get('{}_order'.format(fieldname)) or '[]')
|
||||
if order:
|
||||
name_map = {d.name:d for d in self.get(fieldname)}
|
||||
new_list = []
|
||||
for name in order:
|
||||
new_list.append(name_map[name])
|
||||
name_map[name].__added = True
|
||||
|
||||
# add the missing items that have not be added
|
||||
# maybe these items were added to the standard product
|
||||
# after the customization was done
|
||||
for d in self.get(fieldname):
|
||||
if not d.__added: new_list.append(d)
|
||||
|
||||
self.set(fieldname, new_list)
|
||||
|
||||
def sort_fields(self):
|
||||
"""sort on basis of insert_after"""
|
||||
|
|
@ -458,6 +488,9 @@ class Meta(Document):
|
|||
|
||||
for link in dashboard_links:
|
||||
link.added = False
|
||||
if link.hidden:
|
||||
continue
|
||||
|
||||
for group in data.transactions:
|
||||
group = frappe._dict(group)
|
||||
# group found
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue