Merge remote-tracking branch 'frappe/develop' into wip-4.1
Conflicts: frappe/patches.txt
This commit is contained in:
commit
714f4ed4d0
28 changed files with 355 additions and 72 deletions
|
|
@ -47,9 +47,18 @@ cur_frm.fields_dict['dt'].get_query = function(doc, dt, dn) {
|
|||
}
|
||||
|
||||
cur_frm.cscript.fieldtype = function(doc, dt, dn) {
|
||||
if(doc.fieldtype == 'Link') cur_frm.fields_dict['options_help'].disp_area.innerHTML = 'Please enter name of the document you want this field to be linked to in <b>Options</b>.<br> Eg.: Customer';
|
||||
else if(doc.fieldtype == 'Select') cur_frm.fields_dict['options_help'].disp_area.innerHTML = 'Please enter values in <b>Options</b>, with each option on a new line. <br>Eg.: <b>Field:</b> Country <br><b>Options:</b><br>China<br>India<br>United States<br><br><b>';
|
||||
else cur_frm.fields_dict['options_help'].disp_area.innerHTML = '';
|
||||
if(doc.fieldtype == 'Link') {
|
||||
cur_frm.fields_dict['options_help'].disp_area.innerHTML =
|
||||
__('Name of the Document Type (DocType) you want this field to be linked to. e.g. Customer');
|
||||
} else if(doc.fieldtype == 'Select') {
|
||||
cur_frm.fields_dict['options_help'].disp_area.innerHTML =
|
||||
__('Options for select. Each option on a new line. e.g.: <br>Option 1<br>Option 2<br>Option 3<br>');
|
||||
} else if(doc.fieldtype == 'Dynamic Link') {
|
||||
cur_frm.fields_dict['options_help'].disp_area.innerHTML =
|
||||
__('Fieldname which will be the DocType for this link field.');
|
||||
} else {
|
||||
cur_frm.fields_dict['options_help'].disp_area.innerHTML = '';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@
|
|||
"no_copy": 0,
|
||||
"oldfieldname": "fieldtype",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "Button\nCheck\nCode\nColumn Break\nCurrency\nData\nDate\nDatetime\nFloat\nHTML\nImage\nInt\nLink\nLong Text\nPassword\nPercent\nRead Only\nSection Break\nSelect\nSmall Text\nTable\nText\nText Editor\nTime",
|
||||
"options": "Button\nCheck\nCode\nColumn Break\nCurrency\nData\nDate\nDatetime\nDynamic Link\nFloat\nHTML\nImage\nInt\nLink\nLong Text\nPassword\nPercent\nRead Only\nSection Break\nSelect\nSmall Text\nTable\nText\nText Editor\nTime",
|
||||
"permlevel": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 0
|
||||
|
|
@ -257,7 +257,7 @@
|
|||
],
|
||||
"icon": "icon-glass",
|
||||
"idx": 1,
|
||||
"modified": "2014-05-26 03:21:02.832530",
|
||||
"modified": "2014-06-20 05:54:17.225853",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "Custom Field",
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
"label": "Type",
|
||||
"oldfieldname": "fieldtype",
|
||||
"oldfieldtype": "Select",
|
||||
"options": "Attach\nButton\nCheck\nCode\nColumn Break\nCurrency\nData\nDate\nDatetime\nFloat\nHTML\nImage\nInt\nLink\nLong Text\nPassword\nPercent\nRead Only\nSection Break\nSelect\nSmall Text\nTable\nText\nText Editor\nTime",
|
||||
"options": "Attach\nButton\nCheck\nCode\nColumn Break\nCurrency\nData\nDate\nDatetime\nDynamic Link\nFloat\nHTML\nImage\nInt\nLink\nLong Text\nPassword\nPercent\nRead Only\nSection Break\nSelect\nSmall Text\nTable\nText\nText Editor\nTime",
|
||||
"permlevel": 0,
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
|
|
@ -304,7 +304,7 @@
|
|||
"in_dialog": 1,
|
||||
"issingle": 0,
|
||||
"istable": 1,
|
||||
"modified": "2014-05-26 03:00:13.705058",
|
||||
"modified": "2014-06-20 05:42:29.975498",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "DocField",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ from frappe.utils import now, cint
|
|||
from frappe.model import no_value_fields
|
||||
from frappe.model.document import Document
|
||||
from frappe.model.db_schema import type_map
|
||||
from frappe.core.doctype.property_setter.property_setter import make_property_setter
|
||||
|
||||
class DocType(Document):
|
||||
def validate(self):
|
||||
|
|
@ -106,6 +107,29 @@ class DocType(Document):
|
|||
else:
|
||||
frappe.db.sql("rename table `tab%s` to `tab%s`" % (old, new))
|
||||
|
||||
def before_reload(self):
|
||||
if not (self.issingle and self.istable):
|
||||
self.preserve_naming_series_options_in_property_setter()
|
||||
|
||||
def preserve_naming_series_options_in_property_setter(self):
|
||||
"""preserve naming_series as property setter if it does not exist"""
|
||||
naming_series = self.get("fields", {"fieldname": "naming_series"})
|
||||
|
||||
if not naming_series:
|
||||
return
|
||||
|
||||
# check if atleast 1 record exists
|
||||
if not (frappe.db.table_exists("tab" + self.name) and frappe.db.sql("select name from `tab{}` limit 1".format(self.name))):
|
||||
return
|
||||
|
||||
existing_property_setter = frappe.db.get_value("Property Setter", {"doc_type": self.name,
|
||||
"property": "options", "field_name": "naming_series"})
|
||||
|
||||
if not existing_property_setter:
|
||||
make_property_setter(self.name, "naming_series", "options", naming_series[0].options, "Text")
|
||||
if naming_series[0].default:
|
||||
make_property_setter(self.name, "naming_series", "default", naming_series[0].default, "Text")
|
||||
|
||||
def export_doc(self):
|
||||
from frappe.modules.export_file import export_to_files
|
||||
export_to_files(record_list=[['DocType', self.name]])
|
||||
|
|
@ -157,6 +181,7 @@ class DocType(Document):
|
|||
def validate_fields_for_doctype(doctype):
|
||||
validate_fields(frappe.get_meta(doctype).get("fields"))
|
||||
|
||||
# this is separate because it is also called via custom field
|
||||
def validate_fields(fields):
|
||||
def check_illegal_characters(fieldname):
|
||||
for c in ['.', ',', ' ', '-', '&', '%', '=', '"', "'", '*', '$',
|
||||
|
|
@ -200,6 +225,13 @@ def validate_fields(fields):
|
|||
if d.in_list_view and d.fieldtype!="Image" and (d.fieldtype in no_value_fields):
|
||||
frappe.throw(_("'In List View' not allowed for type {0} in row {1}").format(d.fieldtype, d.idx))
|
||||
|
||||
def check_dynamic_link_options(d):
|
||||
if d.fieldtype=="Dynamic Link":
|
||||
doctype_pointer = filter(lambda df: df.fieldname==d.options, fields)
|
||||
if not doctype_pointer or (doctype_pointer[0].fieldtype!="Link") \
|
||||
or (doctype_pointer[0].options!="DocType"):
|
||||
frappe.throw(_("Options 'Dynamic Link' type of field must point to another Link Field with options as 'DocType'"))
|
||||
|
||||
for d in fields:
|
||||
if not d.permlevel: d.permlevel = 0
|
||||
if not d.fieldname:
|
||||
|
|
@ -208,6 +240,7 @@ def validate_fields(fields):
|
|||
check_unique_fieldname(d.fieldname)
|
||||
check_illegal_mandatory(d)
|
||||
check_link_table_options(d)
|
||||
check_dynamic_link_options(d)
|
||||
check_hidden_and_mandatory(d)
|
||||
check_in_list_view(d)
|
||||
|
||||
|
|
|
|||
|
|
@ -218,24 +218,26 @@
|
|||
},
|
||||
{
|
||||
"fieldname": "ref_type",
|
||||
"fieldtype": "Data",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"label": "Ref Type",
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "ref_type",
|
||||
"oldfieldtype": "Data",
|
||||
"options": "DocType",
|
||||
"permlevel": 0,
|
||||
"read_only": 1,
|
||||
"read_only": 0,
|
||||
"search_index": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "ref_name",
|
||||
"fieldtype": "Data",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"hidden": 0,
|
||||
"label": "Ref Name",
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "ref_name",
|
||||
"oldfieldtype": "Data",
|
||||
"options": "ref_type",
|
||||
"permlevel": 0,
|
||||
"read_only": 1,
|
||||
"search_index": 0
|
||||
|
|
@ -244,7 +246,7 @@
|
|||
"icon": "icon-calendar",
|
||||
"idx": 1,
|
||||
"in_create": 1,
|
||||
"modified": "2014-05-27 03:49:10.612463",
|
||||
"modified": "2014-06-20 06:40:05.415405",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "Event",
|
||||
|
|
|
|||
|
|
@ -91,13 +91,14 @@
|
|||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "reference_type",
|
||||
"fieldtype": "Data",
|
||||
"fieldtype": "Link",
|
||||
"hidden": 0,
|
||||
"in_filter": 0,
|
||||
"label": "Reference Type",
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "reference_type",
|
||||
"oldfieldtype": "Data",
|
||||
"options": "DocType",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"report_hide": 0,
|
||||
|
|
@ -107,13 +108,14 @@
|
|||
{
|
||||
"allow_on_submit": 0,
|
||||
"fieldname": "reference_name",
|
||||
"fieldtype": "Data",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"hidden": 0,
|
||||
"in_filter": 0,
|
||||
"label": "Reference Name",
|
||||
"no_copy": 0,
|
||||
"oldfieldname": "reference_name",
|
||||
"oldfieldtype": "Data",
|
||||
"options": "reference_type",
|
||||
"permlevel": 0,
|
||||
"print_hide": 0,
|
||||
"report_hide": 0,
|
||||
|
|
@ -158,7 +160,7 @@
|
|||
"in_dialog": 0,
|
||||
"issingle": 0,
|
||||
"max_attachments": 0,
|
||||
"modified": "2014-05-27 03:49:21.667888",
|
||||
"modified": "2014-06-20 06:20:11.947183",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Core",
|
||||
"name": "ToDo",
|
||||
|
|
|
|||
|
|
@ -77,6 +77,22 @@ frappe.UserPermissions = Class.extend({
|
|||
options: "[Select]"
|
||||
});
|
||||
|
||||
if(user_roles.indexOf("System Manager")!==-1) {
|
||||
me.download = me.wrapper.appframe.add_field({
|
||||
fieldname: "download",
|
||||
label: __("Download"),
|
||||
fieldtype: "Button",
|
||||
icon: "icon-download"
|
||||
});
|
||||
|
||||
me.upload = me.wrapper.appframe.add_field({
|
||||
fieldname: "upload",
|
||||
label: __("Upload"),
|
||||
fieldtype: "Button",
|
||||
icon: "icon-upload"
|
||||
});
|
||||
}
|
||||
|
||||
// bind change event
|
||||
$.each(me.filters, function(k, f) {
|
||||
f.$input.on("change", function() {
|
||||
|
|
@ -90,9 +106,51 @@ frappe.UserPermissions = Class.extend({
|
|||
});
|
||||
|
||||
me.set_from_route();
|
||||
me.setup_download_upload();
|
||||
}
|
||||
});
|
||||
},
|
||||
setup_download_upload: function() {
|
||||
var me = this;
|
||||
me.download.$input.on("click", function() {
|
||||
window.location.href = frappe.urllib.get_base_url()
|
||||
+ "/api/method/frappe.core.page.user_permissions.user_permissions.get_user_permissions_csv";
|
||||
});
|
||||
|
||||
me.upload.$input.on("click", function() {
|
||||
var d = new frappe.ui.Dialog({
|
||||
title: "Upload User Permissions",
|
||||
fields: [
|
||||
{
|
||||
fieldtype:"HTML",
|
||||
options: '<div class="alert alert-warning"><ol>'+
|
||||
"<li>"+__("Upload CSV file containing all user permissions in the same format as Download.")+"</li>"+
|
||||
"<li><strong>"+__("Any existing permission will be deleted / overwritten.")+"</strong></li>"+
|
||||
'</div>'
|
||||
},
|
||||
{
|
||||
fieldtype:"Attach", fieldname:"attach",
|
||||
}
|
||||
],
|
||||
primary_action_label: __("Upload and Sync"),
|
||||
primary_action: function() {
|
||||
frappe.call({
|
||||
method:"frappe.core.page.user_permissions.user_permissions.import_user_permissions",
|
||||
args: {
|
||||
filedata: d.fields_dict.attach.get_value()
|
||||
},
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
msgprint("Permissions Updated");
|
||||
d.hide();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
d.show();
|
||||
})
|
||||
},
|
||||
get_link_names: function() {
|
||||
return this.options.link_fields;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ from frappe import _
|
|||
import frappe.defaults
|
||||
import frappe.permissions
|
||||
from frappe.core.doctype.user.user import get_system_users
|
||||
from frappe.utils.datautils import UnicodeWriter, read_csv_content_from_uploaded_file
|
||||
from frappe.defaults import clear_default
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_users_and_links():
|
||||
|
|
@ -79,3 +81,28 @@ def get_doctypes_for_user_permissions():
|
|||
return frappe.db.sql_list("""select name from tabDocType
|
||||
where ifnull(issingle,0)=0 and ifnull(istable,0)=0 {condition}""".format(condition=condition),
|
||||
tuple(values))
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_user_permissions_csv():
|
||||
out = [["User Permissions"], ["User", "Document Type", "Value"]]
|
||||
out += [[a.parent, a.defkey, a.defvalue] for a in get_permissions()]
|
||||
|
||||
csv = UnicodeWriter()
|
||||
for row in out:
|
||||
csv.writerow(row)
|
||||
|
||||
frappe.response['result'] = str(csv.getvalue())
|
||||
frappe.response['type'] = 'csv'
|
||||
frappe.response['doctype'] = "User Permissions"
|
||||
|
||||
@frappe.whitelist()
|
||||
def import_user_permissions():
|
||||
frappe.only_for("System Manager")
|
||||
rows = read_csv_content_from_uploaded_file(ignore_encoding=True)
|
||||
clear_default(parenttype="User Permission")
|
||||
|
||||
if rows[0][0]!="User Permissions" and rows[1][0] != "User":
|
||||
frappe.throw(frappe._("Please upload using the same template as download."))
|
||||
|
||||
for row in rows[2:]:
|
||||
frappe.permissions.add_user_permission(row[1], row[2], row[0])
|
||||
|
|
|
|||
|
|
@ -485,6 +485,9 @@ class Database:
|
|||
def table_exists(self, tablename):
|
||||
return tablename in [d[0] for d in self.sql("show tables")]
|
||||
|
||||
def a_row_exists(self, doctype):
|
||||
return self.sql("select name from `tab{doctype}` limit 1".format(doctype=doctype))
|
||||
|
||||
def exists(self, dt, dn=None):
|
||||
if isinstance(dt, basestring):
|
||||
if dt!="DocType" and dt==dn:
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@
|
|||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
# Note: DefaultValue records are identified by parenttype
|
||||
# __default, __global or 'User Permission'
|
||||
|
||||
common_keys = ["__default", "__global"]
|
||||
|
||||
def set_user_default(key, value, user=None, parenttype=None):
|
||||
|
|
|
|||
|
|
@ -264,14 +264,21 @@ class BaseDocument(object):
|
|||
return "{}: {}".format(_(df.label), docname)
|
||||
|
||||
invalid_links = []
|
||||
for df in self.meta.get_link_fields():
|
||||
doctype = df.options
|
||||
for df in self.meta.get_link_fields() + self.meta.get("fields",
|
||||
{"fieldtype":"Dynamic Link"}):
|
||||
|
||||
if not doctype:
|
||||
frappe.throw(_("Options not set for link field {0}").format(df.fieldname))
|
||||
|
||||
docname = self.get(df.fieldname)
|
||||
if docname:
|
||||
if df.fieldtype=="Link":
|
||||
doctype = df.options
|
||||
if not doctype:
|
||||
frappe.throw(_("Options not set for link field {0}").format(df.fieldname))
|
||||
else:
|
||||
doctype = self.get(df.options)
|
||||
if not doctype:
|
||||
frappe.throw(_("{0} must be set first").format(self.meta.get_label(df.options)))
|
||||
|
||||
# MySQL is case insensitive. Preserve case of the original docname in the Link Field.
|
||||
value = frappe.db.get_value(doctype, docname)
|
||||
setattr(self, df.fieldname, value)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ type_map = {
|
|||
,'Text': ('text', '')
|
||||
,'Data': ('varchar', '255')
|
||||
,'Link': ('varchar', '255')
|
||||
,'Dynamic Link':('varchar', '255')
|
||||
,'Password': ('varchar', '255')
|
||||
,'Select': ('varchar', '255')
|
||||
,'Read Only': ('varchar', '255')
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import frappe.model.meta
|
|||
import frappe.defaults
|
||||
from frappe.utils.file_manager import remove_all
|
||||
from frappe import _
|
||||
from rename_doc import dynamic_link_queries
|
||||
|
||||
def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reload=False, ignore_permissions=False):
|
||||
"""
|
||||
|
|
@ -31,7 +32,16 @@ def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reloa
|
|||
remove_all(doctype, name)
|
||||
|
||||
if doctype=="DocType":
|
||||
if not for_reload:
|
||||
if for_reload:
|
||||
|
||||
try:
|
||||
doc = frappe.get_doc(doctype, name)
|
||||
except frappe.DoesNotExistError:
|
||||
pass
|
||||
else:
|
||||
doc.run_method("before_reload")
|
||||
|
||||
else:
|
||||
frappe.db.sql("delete from `tabCustom Field` where dt = %s", name)
|
||||
frappe.db.sql("delete from `tabCustom Script` where dt = %s", name)
|
||||
frappe.db.sql("delete from `tabProperty Setter` where doc_type = %s", name)
|
||||
|
|
@ -48,6 +58,7 @@ def delete_doc(doctype=None, name=None, force=0, ignore_doctypes=None, for_reloa
|
|||
# check if links exist
|
||||
if not force:
|
||||
check_if_doc_is_linked(doc)
|
||||
check_if_doc_is_dynamically_linked(doc)
|
||||
|
||||
delete_from_table(doctype, name, ignore_doctypes, doc)
|
||||
|
||||
|
|
@ -106,3 +117,21 @@ def check_if_doc_is_linked(doc, method="Delete"):
|
|||
frappe.throw(_("Cannot delete or cancel because {0} {1} is linked with {2} {3}").format(doc.doctype,
|
||||
doc.name, item.parent or item.name, item.parenttype if item.parent else link_dt),
|
||||
frappe.LinkExistsError)
|
||||
|
||||
def check_if_doc_is_dynamically_linked(doc):
|
||||
for query in dynamic_link_queries:
|
||||
for df in frappe.db.sql(query, as_dict=True):
|
||||
if frappe.get_meta(df.parent).issingle:
|
||||
|
||||
# dynamic link in single doc
|
||||
refdoc = frappe.get_singles_dict(df.parent)
|
||||
if refdoc.get(df.options)==doc.doctype and refdoc.get(df.fieldname)==doc.name:
|
||||
frappe.throw(_("Cannot delete or cancel because {0} {1} is linked with {2} {3}").format(doc.doctype,
|
||||
doc.name, df.parent, ""), frappe.LinkExistsError)
|
||||
else:
|
||||
|
||||
# dynamic link in table
|
||||
for name in frappe.db.sql_list("""select name from `tab{parent}` where
|
||||
{options}=%s and {fieldname}=%s""".format(**df), (doc.doctype, doc.name)):
|
||||
frappe.throw(_("Cannot delete or cancel because {0} {1} is linked with {2} {3}").format(doc.doctype,
|
||||
doc.name, df.parent, name), frappe.LinkExistsError)
|
||||
|
|
|
|||
|
|
@ -159,7 +159,10 @@ class Document(BaseDocument):
|
|||
self.check_if_latest()
|
||||
self.set_parent_in_children()
|
||||
self.run_before_save_methods()
|
||||
self._validate()
|
||||
|
||||
if self._action != "cancel":
|
||||
self._validate()
|
||||
|
||||
if self._action == "update_after_submit":
|
||||
self.validate_update_after_submit()
|
||||
|
||||
|
|
@ -491,7 +494,7 @@ class Document(BaseDocument):
|
|||
val1 = cint(val1)
|
||||
val2 = cint(val2)
|
||||
elif df.fieldtype in ("Data", "Text", "Small Text", "Long Text",
|
||||
"Text Editor", "Select", "Link"):
|
||||
"Text Editor", "Select", "Link", "Dynamic Link"):
|
||||
val1 = cstr(val1)
|
||||
val2 = cstr(val2)
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ def rename_doc(doctype, old, new, force=False, merge=False, ignore_permissions=F
|
|||
link_fields = get_link_fields(doctype)
|
||||
update_link_field_values(link_fields, old, new, doctype)
|
||||
|
||||
rename_dynamic_links(doctype, old, new)
|
||||
|
||||
if doctype=='DocType':
|
||||
rename_doctype(doctype, old, new, force)
|
||||
|
||||
|
|
@ -274,3 +276,27 @@ def update_parenttype_values(old, new):
|
|||
update `tab%s` set parenttype=%s
|
||||
where parenttype=%s""" % (doctype, '%s', '%s'),
|
||||
(new, old))
|
||||
|
||||
dynamic_link_queries = [
|
||||
"""select parent, fieldname, options from tabDocField where fieldtype='Dynamic Link'""",
|
||||
"""select dt as parent, fieldname, options from `tabCustom Field` where fieldtype='Dynamic Link'""",
|
||||
]
|
||||
|
||||
def rename_dynamic_links(doctype, old, new):
|
||||
for query in dynamic_link_queries:
|
||||
for df in frappe.db.sql(query, as_dict=True):
|
||||
|
||||
# dynamic link in single, just one value to check
|
||||
if frappe.get_meta(df.parent).issingle:
|
||||
refdoc = frappe.get_singles_dict(df.parent)
|
||||
if refdoc.get(df.options)==doctype and refdoc.get(df.fieldname)==old:
|
||||
|
||||
frappe.db.sql("""update tabSingles set value=%s where
|
||||
field=%s and value=%s and doctype=%s""", (new, df.fieldname, old, df.parent))
|
||||
else:
|
||||
# replace for each value where renamed
|
||||
for to_change in frappe.db.sql_list("""select name from `tab{parent}` where
|
||||
{options}=%s and {fieldname}=%s""".format(**df), (doctype, old)):
|
||||
|
||||
frappe.db.sql("""update `tab{parent}` set {fieldname}=%s
|
||||
where name=%s""".format(**df), (new, to_change))
|
||||
|
|
|
|||
|
|
@ -43,3 +43,4 @@ execute:frappe.db.sql("""delete from `tabUserRole` where ifnull(parentfield, '')
|
|||
frappe.patches.v4_0.remove_user_owner_custom_field
|
||||
execute:frappe.delete_doc("DocType", "Website Template")
|
||||
execute:frappe.reload_doc('website', 'doctype', 'website_route') #2014-06-17
|
||||
execute:frappe.db.sql("""update `tabProperty Setter` set property_type='Text' where property in ('options', 'default')""") #2014-06-20
|
||||
|
|
|
|||
|
|
@ -37,12 +37,13 @@ def has_permission(doctype, ptype="read", doc=None, verbose=True, user=None):
|
|||
if not role_permissions.get(ptype):
|
||||
return False
|
||||
|
||||
if doc and role_permissions["apply_user_permissions"].get(ptype):
|
||||
if doc:
|
||||
if isinstance(doc, basestring):
|
||||
doc = frappe.get_doc(meta.name, doc)
|
||||
|
||||
if not user_has_permission(doc, verbose=verbose, user=user):
|
||||
return False
|
||||
if role_permissions["apply_user_permissions"].get(ptype):
|
||||
if not user_has_permission(doc, verbose=verbose, user=user):
|
||||
return False
|
||||
|
||||
if not has_controller_permissions(doc, ptype, user=user):
|
||||
return False
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ frappe.ui.form.Attachments = Class.extend({
|
|||
},
|
||||
add_attachment: function(attachment) {
|
||||
var file_name = attachment.file_name;
|
||||
var file_url = attachment.file_url;
|
||||
var file_url = this.get_file_url(attachment);
|
||||
var fileid = attachment.name;
|
||||
if (!file_name) {
|
||||
file_name = file_url;
|
||||
|
|
@ -96,6 +96,18 @@ frappe.ui.form.Attachments = Class.extend({
|
|||
$close.remove();
|
||||
}
|
||||
},
|
||||
get_file_url: function(attachment) {
|
||||
var file_url = attachment.file_url;
|
||||
if (!file_url) {
|
||||
if (attachment.file_name.indexOf('files/') === 0) {
|
||||
file_url = '/' + attachment.file_name;
|
||||
}
|
||||
else {
|
||||
file_url = '/files/' + attachment.file_name;
|
||||
}
|
||||
}
|
||||
return encodeURI(file_url);
|
||||
},
|
||||
remove_attachment_by_filename: function(filename, callback) {
|
||||
this.remove_attachment(this.get_attachments()[filename], callback);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ frappe.ui.form.Comments = Class.extend({
|
|||
c.fullname = frappe.user_info(c.comment_by).fullname;
|
||||
c.comment = frappe.markdown(c.comment);
|
||||
|
||||
$(repl('<div class="media col-md-10" data-name="%(name)s">\
|
||||
$(repl('<div class="media col-md-10 comment" data-name="%(name)s">\
|
||||
<span class="pull-left avatar avatar-small">\
|
||||
<img class="media-object" src="%(image)s">\
|
||||
</span>\
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||
// MIT License. See license.txt
|
||||
|
||||
frappe.ui.form.make_control = function(opts) {
|
||||
frappe.ui.form.make_control = function (opts) {
|
||||
var control_class_name = "Control" + opts.df.fieldtype.replace(/ /g, "");
|
||||
if(frappe.ui.form[control_class_name]) {
|
||||
return new frappe.ui.form[control_class_name](opts);
|
||||
|
|
@ -538,7 +538,8 @@ frappe.ui.form.ControlButton = frappe.ui.form.ControlData.extend({
|
|||
},
|
||||
set_label: function() {
|
||||
$(this.label_span).html(" ");
|
||||
this.$input && this.$input.html(this.df.label);
|
||||
this.$input && this.$input.html((this.df.icon ?
|
||||
('<i class="'+this.df.icon+' icon-fixed-width"></i> ') : "") + this.df.label);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -551,7 +552,8 @@ frappe.ui.form.ControlAttach = frappe.ui.form.ControlData.extend({
|
|||
.on("click", function() {
|
||||
me.onclick();
|
||||
});
|
||||
this.$value = $('<div class="alert alert-info">\
|
||||
this.$value = $('<div style="margin-top: 5px;">\
|
||||
<i class="icon-paper-clip" style="overflow: hidden; display: inline-block"></i> \
|
||||
<a class="attached-file text-ellipsis" style="width: 80%" target="_blank"></a>\
|
||||
<a class="close">×</a></div>')
|
||||
.prependTo(me.input_area)
|
||||
|
|
@ -802,32 +804,36 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
|
|||
this.setup_buttons();
|
||||
this.setup_autocomplete();
|
||||
},
|
||||
get_options: function() {
|
||||
return this.df.options;
|
||||
},
|
||||
setup_buttons: function() {
|
||||
var me = this;
|
||||
|
||||
// magnifier - search
|
||||
this.$input_area.find(".btn-search").on("click", function() {
|
||||
var doctype = me.get_options();
|
||||
if(!doctype) return;
|
||||
new frappe.ui.form.LinkSelector({
|
||||
doctype: me.df.options,
|
||||
doctype: doctype,
|
||||
target: me,
|
||||
txt: me.get_value()
|
||||
});
|
||||
});
|
||||
|
||||
// open
|
||||
if(frappe.model.can_read(me.df.options)) {
|
||||
this.$input_area.find(".btn-open").on("click", function() {
|
||||
var value = me.get_value();
|
||||
if(value && me.df.options) frappe.set_route("Form", me.df.options, value);
|
||||
});
|
||||
} else {
|
||||
this.$input_area.find(".btn-open").remove();
|
||||
}
|
||||
this.$input_area.find(".btn-open").on("click", function() {
|
||||
var value = me.get_value();
|
||||
if(value && me.get_options())
|
||||
frappe.set_route("Form", me.get_options(), value);
|
||||
});
|
||||
|
||||
// new
|
||||
if(frappe.model.can_create(me.df.options)) {
|
||||
if(this.df.fieldtype==="Dynamic Link" || frappe.model.can_create(me.df.options)) {
|
||||
this.$input_area.find(".btn-new").on("click", function() {
|
||||
me.frm.new_doc(me.df.options, me);
|
||||
var doctype = me.get_options();
|
||||
if(!doctype) return;
|
||||
me.frm.new_doc(doctype, me);
|
||||
});
|
||||
} else {
|
||||
this.$input_area.find(".btn-new").remove();
|
||||
|
|
@ -854,18 +860,20 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
|
|||
this.$input.autocomplete({
|
||||
minLength: 0,
|
||||
source: function(request, response) {
|
||||
if (!me.$input.cache[me.df.options]) {
|
||||
me.$input.cache[me.df.options] = {};
|
||||
var doctype = me.get_options();
|
||||
if(!doctype) return;
|
||||
if (!me.$input.cache[doctype]) {
|
||||
me.$input.cache[doctype] = {};
|
||||
}
|
||||
|
||||
if (me.$input.cache[me.df.options][request.term]!=null) {
|
||||
if (me.$input.cache[doctype][request.term]!=null) {
|
||||
// immediately show from cache
|
||||
response(me.$input.cache[me.df.options][request.term]);
|
||||
response(me.$input.cache[doctype][request.term]);
|
||||
}
|
||||
|
||||
var args = {
|
||||
'txt': request.term,
|
||||
'doctype': me.df.options,
|
||||
'doctype': doctype,
|
||||
};
|
||||
|
||||
me.set_custom_query(args);
|
||||
|
|
@ -876,13 +884,13 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
|
|||
no_spinner: true,
|
||||
args: args,
|
||||
callback: function(r) {
|
||||
if(frappe.model.can_create(me.df.options)) {
|
||||
if(frappe.model.can_create(doctype)) {
|
||||
r.results.push({
|
||||
value: "<i class='icon-plus'></i> <em>" + __("Create a new {0}", [me.df.options]) + "</em>",
|
||||
make_new: true
|
||||
});
|
||||
};
|
||||
me.$input.cache[me.df.options][request.term] = r.results;
|
||||
me.$input.cache[doctype][request.term] = r.results;
|
||||
response(r.results);
|
||||
},
|
||||
});
|
||||
|
|
@ -901,10 +909,13 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
|
|||
select: function(event, ui) {
|
||||
me.autocomplete_open = false;
|
||||
if(ui.item.make_new) {
|
||||
var doctype = me.get_options();
|
||||
if(!doctype) return;
|
||||
|
||||
if (me.frm) {
|
||||
me.frm.new_doc(me.df.options, me);
|
||||
me.frm.new_doc(doctype, me);
|
||||
} else {
|
||||
new_doc(me.df.options);
|
||||
new_doc(doctype);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -968,10 +979,21 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
|
|||
return;
|
||||
}
|
||||
|
||||
this.frm.script_manager.validate_link_and_fetch(this.df, this.docname, value, callback);
|
||||
this.frm.script_manager.validate_link_and_fetch(this.df, this.get_options(),
|
||||
this.docname, value, callback);
|
||||
},
|
||||
});
|
||||
|
||||
frappe.ui.form.ControlDynamicLink = frappe.ui.form.ControlLink.extend({
|
||||
get_options: function() {
|
||||
var options = frappe.model.get_value(this.df.parent, this.docname, this.df.options);
|
||||
if(!options) {
|
||||
msgprint(__("Please set {0} first",
|
||||
[frappe.meta.get_docfield(this.df.parent, this.df.options, this.docname).label]));
|
||||
}
|
||||
return options;
|
||||
},
|
||||
});
|
||||
|
||||
frappe.ui.form.ControlCode = frappe.ui.form.ControlText.extend({
|
||||
make_input: function() {
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ frappe.form.formatters = {
|
|||
return value ? "<i class='icon-check'></i>" : "<i class='icon-check-empty'></i>";
|
||||
},
|
||||
Link: function(value, docfield, options) {
|
||||
var doctype = docfield._options || docfield.options;
|
||||
if(options && options.for_print)
|
||||
return value;
|
||||
if(!value)
|
||||
|
|
@ -40,13 +41,13 @@ frappe.form.formatters = {
|
|||
if(docfield && docfield.link_onclick) {
|
||||
return repl('<a onclick="%(onclick)s">%(value)s</a>',
|
||||
{onclick: docfield.link_onclick.replace(/"/g, '"'), value:value});
|
||||
} else if(docfield && docfield.options) {
|
||||
} else if(docfield && doctype) {
|
||||
return repl('%(icon)s<a href="#Form/%(doctype)s/%(name)s">%(label)s</a>', {
|
||||
doctype: encodeURIComponent(docfield.options),
|
||||
doctype: encodeURIComponent(doctype),
|
||||
name: encodeURIComponent(value),
|
||||
label: value,
|
||||
icon: (options && options.no_icon) ? "" :
|
||||
('<i class="icon-fixed-width '+frappe.boot.doctype_icons[docfield.options]+'"></i> ')
|
||||
('<i class="icon-fixed-width '+frappe.boot.doctype_icons[doctype]+'"></i> ')
|
||||
});
|
||||
} else {
|
||||
return value;
|
||||
|
|
@ -119,11 +120,20 @@ frappe.form.formatters = {
|
|||
}
|
||||
|
||||
frappe.form.get_formatter = function(fieldtype) {
|
||||
if(!fieldtype) fieldtype = "Data";
|
||||
if(!fieldtype)
|
||||
fieldtype = "Data";
|
||||
return frappe.form.formatters[fieldtype.replace(/ /g, "")] || frappe.form.formatters.Data;
|
||||
}
|
||||
|
||||
frappe.format = function(value, df, options, doc) {
|
||||
if(!df) df = {"fieldtype":"Data"};
|
||||
return frappe.form.get_formatter(df.fieldtype)(value, df, options, doc);
|
||||
var fieldtype = df.fieldtype || "Data";
|
||||
|
||||
// format Dynamic Link as a Link
|
||||
if(fieldtype==="Dynamic Link") {
|
||||
fieldtype = "Link";
|
||||
df._options = doc ? doc[df.options] : null;
|
||||
}
|
||||
|
||||
return frappe.form.get_formatter(fieldtype)(value, df, options, doc);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -116,13 +116,27 @@ frappe.ui.form.InfoBar = Class.extend({
|
|||
},
|
||||
|
||||
go_prev_next: function(prev) {
|
||||
var me = this;
|
||||
var me = this,
|
||||
filters = null,
|
||||
order_by = "modified desc",
|
||||
doclistview = frappe.pages["List/" + me.frm.doctype];
|
||||
|
||||
// filters / order defined in listview
|
||||
if(doclistview) {
|
||||
filters = doclistview.doclistview.filter_list.get_filters();
|
||||
if(doclistview.doclistview.listview.order_by) {
|
||||
order_by = doclistview.doclistview.listview.order_by;
|
||||
}
|
||||
}
|
||||
|
||||
return frappe.call({
|
||||
method: "frappe.widgets.form.utils.get_next",
|
||||
args: {
|
||||
doctype: me.frm.doctype,
|
||||
name: me.frm.docname,
|
||||
prev: prev ? 1 : 0
|
||||
value: me.frm.doc[order_by.split(" ")[0]],
|
||||
prev: prev ? 1 : 0,
|
||||
filters: filters,
|
||||
order_by: order_by
|
||||
},
|
||||
callback: function(r) {
|
||||
if(r.message)
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ frappe.ui.form.ScriptManager = Class.extend({
|
|||
console.log("----- end of error message -----");
|
||||
console.group && console.groupEnd();
|
||||
},
|
||||
validate_link_and_fetch: function(df, docname, value, callback) {
|
||||
validate_link_and_fetch: function(df, doctype, docname, value, callback) {
|
||||
var me = this;
|
||||
|
||||
if(value) {
|
||||
|
|
@ -94,7 +94,7 @@ frappe.ui.form.ScriptManager = Class.extend({
|
|||
type: "GET",
|
||||
args: {
|
||||
'value': value,
|
||||
'options': df.options,
|
||||
'options': doctype,
|
||||
'fetch': fetch
|
||||
},
|
||||
no_spinner: true,
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ frappe.ui.Filter = Class.extend({
|
|||
if(df.fieldtype=='Check') {
|
||||
df.fieldtype='Select';
|
||||
df.options='No\nYes';
|
||||
} else if(['Text','Small Text','Text Editor','Code','Tag','Comments'].indexOf(df.fieldtype)!=-1) {
|
||||
} else if(['Text','Small Text','Text Editor','Code','Tag','Comments','Dynamic Link'].indexOf(df.fieldtype)!=-1) {
|
||||
df.fieldtype = 'Data';
|
||||
} else if(df.fieldtype=='Link' && this.$w.find('.condition').val()!="=") {
|
||||
df.fieldtype = 'Data';
|
||||
|
|
|
|||
|
|
@ -87,9 +87,11 @@ frappe.views.DocListView = frappe.ui.Listing.extend({
|
|||
this.make_help();
|
||||
this.$page.find(".show_filters").css({"padding":"15px", "margin":"0px -15px"});
|
||||
var me = this;
|
||||
// this.$w.on("render-complete", function() {
|
||||
// me.set_sidebar_height();
|
||||
// });
|
||||
this.$w.on("render-complete", function() {
|
||||
if(me.data.length===1) {
|
||||
frappe.set_route("Form", me.doctype, me.data[0].name);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
set_sidebar_height: function() {
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ desktop_template = """from frappe import _
|
|||
|
||||
def get_data():
|
||||
return {{
|
||||
"{app_title}": {{
|
||||
"{app_name}": {{
|
||||
"color": "{app_color}",
|
||||
"icon": "{app_icon}",
|
||||
"type": "module",
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@ def save_url(file_url, dt, dn):
|
|||
def get_uploaded_content():
|
||||
# should not be unicode when reading a file, hence using frappe.form
|
||||
if 'filedata' in frappe.form_dict:
|
||||
if "," in frappe.form_dict.filedata:
|
||||
frappe.form_dict.filedata = frappe.form_dict.filedata.rsplit(",", 1)[1]
|
||||
frappe.uploaded_content = base64.b64decode(frappe.form_dict.filedata)
|
||||
frappe.uploaded_filename = frappe.form_dict.filename
|
||||
return frappe.uploaded_filename, frappe.uploaded_content
|
||||
|
|
@ -144,12 +146,12 @@ def save_file_on_filesystem(fname, content, content_type=None):
|
|||
}
|
||||
|
||||
def check_max_file_size(content):
|
||||
max_file_size = conf.get('max_file_size') or 1000000
|
||||
max_file_size = conf.get('max_file_size') or 3145728
|
||||
file_size = len(content)
|
||||
|
||||
if file_size > max_file_size:
|
||||
frappe.msgprint(_("File size exceeded the maximum allowed size of {0} MB").format(
|
||||
max_file_size / 1000000.0),
|
||||
max_file_size / 1048576),
|
||||
raise_exception=MaxFileSizeReachedError)
|
||||
|
||||
return file_size
|
||||
|
|
|
|||
|
|
@ -63,15 +63,31 @@ def add_comment(doc):
|
|||
return doc.as_dict()
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_next(doctype, name, prev):
|
||||
def get_next(doctype, value, prev, filters=None, order_by="modified desc"):
|
||||
import frappe.widgets.reportview
|
||||
|
||||
prev = int(prev)
|
||||
field = "`tab%s`.name" % doctype
|
||||
sort_field, sort_order = order_by.split(" ")
|
||||
|
||||
if not filters: filters = []
|
||||
if isinstance(filters, basestring):
|
||||
filters = json.loads(filters)
|
||||
|
||||
# condition based on sort order
|
||||
condition = ">" if sort_order.lower()=="desc" else "<"
|
||||
|
||||
# switch the condition
|
||||
if prev:
|
||||
condition = "<" if condition==">" else "<"
|
||||
|
||||
# add condition for next or prev item
|
||||
if not order_by[0] in [f[1] for f in filters]:
|
||||
filters.append([doctype, sort_field, condition, value])
|
||||
|
||||
res = frappe.widgets.reportview.execute(doctype,
|
||||
fields = [field],
|
||||
filters = [[doctype, "name", "<" if prev else ">", name]],
|
||||
order_by = field + " " + ("desc" if prev else "asc"),
|
||||
fields = ["name"],
|
||||
filters = filters,
|
||||
order_by = sort_field + " " + sort_order,
|
||||
limit_start=0, limit_page_length=1, as_list=True)
|
||||
|
||||
if not res:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue