"
mail = get_email(d.recipients, sender=d.sender, subject=d.subject,
diff --git a/frappe/core/doctype/custom_field/custom_field.js b/frappe/core/doctype/custom_field/custom_field.js
index 9e491dce79..040cb10616 100644
--- a/frappe/core/doctype/custom_field/custom_field.js
+++ b/frappe/core/doctype/custom_field/custom_field.js
@@ -48,7 +48,7 @@ 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 Options. Eg.: Customer';
- else if(doc.fieldtype == 'Select') cur_frm.fields_dict['options_help'].disp_area.innerHTML = 'Please enter values in Options separated by enter. Eg.: Field: Country Options: China India United States
OR You can also link it to existing Documents. Eg.: link:Customer';
+ else if(doc.fieldtype == 'Select') cur_frm.fields_dict['options_help'].disp_area.innerHTML = 'Please enter values in Options, with each option on a new line. Eg.: Field: Country Options: China India United States
';
else cur_frm.fields_dict['options_help'].disp_area.innerHTML = '';
}
@@ -64,9 +64,10 @@ cur_frm.cscript.dt = function(doc, dt, dn) {
args: { doctype: doc.dt, fieldname: doc.fieldname },
callback: function(r, rt) {
set_field_options('insert_after', r.message);
+ var fieldnames = $.map(r.message, function(v) { return v.value; });
- if(insert_after==null || !in_list(r.message.split("\n"), insert_after)) {
- insert_after = r.message.split("\n")[0];
+ if(insert_after==null || !in_list(fieldnames, insert_after)) {
+ insert_after = fieldnames[-1];
}
cur_frm.set_value('insert_after', insert_after);
diff --git a/frappe/core/doctype/custom_field/custom_field.py b/frappe/core/doctype/custom_field/custom_field.py
index e83c7df6ad..46b44d0e7d 100644
--- a/frappe/core/doctype/custom_field/custom_field.py
+++ b/frappe/core/doctype/custom_field/custom_field.py
@@ -1,5 +1,5 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
-# MIT License. See license.txt
+# MIT License. See license.txt
from __future__ import unicode_literals
import frappe
@@ -9,7 +9,7 @@ from frappe import _
from frappe.model.document import Document
class CustomField(Document):
-
+
def autoname(self):
self.set_fieldname()
self.name = self.dt + "-" + self.fieldname
@@ -19,16 +19,16 @@ class CustomField(Document):
if not self.label:
frappe.throw(_("Label is mandatory"))
# remove special characters from fieldname
- self.fieldname = filter(lambda x: x.isdigit() or x.isalpha() or '_',
+ self.fieldname = filter(lambda x: x.isdigit() or x.isalpha() or '_',
cstr(self.label).lower().replace(' ','_'))
def validate(self):
if not self.idx:
self.idx = len(frappe.get_meta(self.dt).get("fields")) + 1
-
+
if not self.fieldname:
frappe.throw(_("Fieldname not set for Custom Field"))
-
+
def on_update(self):
# validate field
from frappe.core.doctype.doctype.doctype import validate_fields_for_doctype
@@ -36,7 +36,7 @@ class CustomField(Document):
validate_fields_for_doctype(self.dt)
frappe.clear_cache(doctype=self.dt)
-
+
# create property setter to emulate insert after
self.create_property_setter()
@@ -44,7 +44,7 @@ class CustomField(Document):
if not frappe.flags.in_test:
from frappe.model.db_schema import updatedb
updatedb(self.dt)
-
+
def on_trash(self):
# delete property setter entries
frappe.db.sql("""\
@@ -57,57 +57,33 @@ class CustomField(Document):
def create_property_setter(self):
if not self.insert_after: return
- idx_label_list, field_list = get_fields_label(self.dt, 0)
- label_index = idx_label_list.index(self.insert_after)
- if label_index==-1: return
- prev_field = field_list[label_index]
+ dt_meta = frappe.get_meta(self.dt)
+ if not dt_meta.get_field(self.insert_after):
+ frappe.throw(_("Insert After field '{0}' mentioned in Custom Field '{1}', does not exist")
+ .format(dt_meta.get_label(self.insert_after), self.label), frappe.DoesNotExistError)
+
frappe.db.sql("""\
DELETE FROM `tabProperty Setter`
WHERE doc_type = %s
AND field_name = %s
AND property = 'previous_field'""", (self.dt, self.fieldname))
-
+
frappe.make_property_setter({
- "doctype":self.dt,
- "fieldname": self.fieldname,
+ "doctype":self.dt,
+ "fieldname": self.fieldname,
"property": "previous_field",
- "value": prev_field
+ "value": self.insert_after
})
-
+
@frappe.whitelist()
-def get_fields_label(dt=None, form=1):
- """
- if form=1: Returns a string of field labels separated by \n
- if form=0: Returns lists of field labels and field names
- """
- import frappe
- from frappe.utils import cstr
- fieldname = None
- if not dt:
- dt = frappe.form_dict.get('doctype')
- fieldname = frappe.form_dict.get('fieldname')
- if not dt: return ""
-
- docfields = frappe.get_meta(dt).get("fields")
-
- if fieldname:
- idx_label_list = [cstr(d.label) or cstr(d.fieldname) or cstr(d.fieldtype)
- for d in docfields if d.fieldname != fieldname]
- else:
- idx_label_list = [cstr(d.label) or cstr(d.fieldname) or cstr(d.fieldtype)
- for d in docfields]
- if form:
- return "\n".join(idx_label_list)
- else:
- # return idx_label_list, field_list
- field_list = [cstr(d.fieldname) for d in docfields]
- return idx_label_list, field_list
+def get_fields_label(doctype=None):
+ return [{"value": df.fieldname, "label": _(df.label)} for df in frappe.get_meta(doctype).get("fields")]
def create_custom_field_if_values_exist(doctype, df):
df = frappe._dict(df)
if df.fieldname in frappe.db.get_table_columns(doctype) and \
- frappe.db.sql("""select count(*) from `tab{doctype}`
+ frappe.db.sql("""select count(*) from `tab{doctype}`
where ifnull({fieldname},'')!=''""".format(doctype=doctype, fieldname=df.fieldname))[0][0] and \
not frappe.db.get_value("Custom Field", {"dt": doctype, "fieldname": df.fieldname}):
frappe.get_doc({
@@ -120,4 +96,4 @@ def create_custom_field_if_values_exist(doctype, df):
"options": df.options,
"insert_after": df.insert_after
}).insert()
-
+
diff --git a/frappe/core/doctype/customize_form/customize_form.json b/frappe/core/doctype/customize_form/customize_form.json
index 5db77d1bbf..a95988f208 100644
--- a/frappe/core/doctype/customize_form/customize_form.json
+++ b/frappe/core/doctype/customize_form/customize_form.json
@@ -1,6 +1,6 @@
{
"autoname": "DL.####",
- "creation": "2013-01-29 17:55:08.000000",
+ "creation": "2013-01-29 17:55:08",
"docstatus": 0,
"doctype": "DocType",
"fields": [
@@ -8,6 +8,7 @@
"fieldname": "doc_type",
"fieldtype": "Link",
"hidden": 0,
+ "in_list_view": 1,
"label": "Enter Form Type",
"no_copy": 0,
"options": "DocType",
@@ -25,23 +26,37 @@
"fieldtype": "Column Break",
"permlevel": 0
},
+ {
+ "fieldname": "default_print_format",
+ "fieldtype": "Link",
+ "in_list_view": 1,
+ "label": "Default Print Format",
+ "no_copy": 0,
+ "options": "Print Format",
+ "permlevel": 0,
+ "search_index": 0
+ },
{
"description": "Fields separated by comma (,) will be included in the Search By list of Search dialog box",
"fieldname": "search_fields",
"fieldtype": "Data",
+ "in_list_view": 1,
"label": "Search Fields",
"no_copy": 0,
"permlevel": 0,
"search_index": 0
},
{
- "fieldname": "default_print_format",
- "fieldtype": "Link",
- "label": "Default Print Format",
- "no_copy": 0,
- "options": "Print Format",
- "permlevel": 0,
- "search_index": 0
+ "fieldname": "sort_field",
+ "fieldtype": "Data",
+ "label": "Sort Field",
+ "permlevel": 0
+ },
+ {
+ "fieldname": "sort_order",
+ "fieldtype": "Data",
+ "label": "Sort Order",
+ "permlevel": 0
},
{
"fieldname": "column_break1",
@@ -111,7 +126,7 @@
"icon": "icon-glass",
"idx": 1,
"issingle": 1,
- "modified": "2014-01-15 16:16:22.000000",
+ "modified": "2014-05-08 09:27:44.167026",
"modified_by": "Administrator",
"module": "Core",
"name": "Customize Form",
diff --git a/frappe/core/doctype/customize_form/customize_form.py b/frappe/core/doctype/customize_form/customize_form.py
index 0af80da2fd..0e0eefdcfa 100644
--- a/frappe/core/doctype/customize_form/customize_form.py
+++ b/frappe/core/doctype/customize_form/customize_form.py
@@ -14,6 +14,8 @@ from frappe.core.doctype.doctype.doctype import validate_fields_for_doctype
class CustomizeForm(Document):
doctype_properties = {
'search_fields': 'Data',
+ 'sort_field': 'Data',
+ 'sort_order': 'Data',
'default_print_format': 'Data',
'read_only_onload': 'Check',
'allow_attach': 'Check',
diff --git a/frappe/core/doctype/doctype/doctype.json b/frappe/core/doctype/doctype/doctype.json
index 9b89f80b18..646600a471 100644
--- a/frappe/core/doctype/doctype/doctype.json
+++ b/frappe/core/doctype/doctype/doctype.json
@@ -138,6 +138,17 @@
"options": "\nTitle Case\nUPPER CASE",
"permlevel": 0
},
+ {
+ "fieldname": "description",
+ "fieldtype": "Small Text",
+ "hidden": 0,
+ "label": "Description",
+ "oldfieldname": "description",
+ "oldfieldtype": "Text",
+ "permlevel": 0,
+ "reqd": 0,
+ "search_index": 0
+ },
{
"fieldname": "column_break_15",
"fieldtype": "Column Break",
@@ -162,15 +173,20 @@
"search_index": 0
},
{
- "fieldname": "description",
- "fieldtype": "Small Text",
- "hidden": 0,
- "label": "Description",
- "oldfieldname": "description",
- "oldfieldtype": "Text",
- "permlevel": 0,
- "reqd": 0,
- "search_index": 0
+ "default": "modified",
+ "description": "",
+ "fieldname": "sort_field",
+ "fieldtype": "Data",
+ "label": "Sort Field",
+ "permlevel": 0
+ },
+ {
+ "default": "DESC",
+ "fieldname": "sort_order",
+ "fieldtype": "Select",
+ "label": "Sort Order",
+ "options": "ASC\nDESC",
+ "permlevel": 0
},
{
"depends_on": "eval:!doc.istable",
@@ -329,7 +345,7 @@
"idx": 1,
"issingle": 0,
"istable": 0,
- "modified": "2014-05-01 05:27:22.582492",
+ "modified": "2014-05-08 09:23:56.952829",
"modified_by": "Administrator",
"module": "Core",
"name": "DocType",
@@ -361,5 +377,7 @@
}
],
"read_only": 0,
- "search_fields": "module"
+ "search_fields": "module",
+ "sort_field": "name",
+ "sort_order": "ASC"
}
\ No newline at end of file
diff --git a/frappe/core/doctype/doctype/doctype.py b/frappe/core/doctype/doctype/doctype.py
index d8177e5b33..69e66017f0 100644
--- a/frappe/core/doctype/doctype/doctype.py
+++ b/frappe/core/doctype/doctype/doctype.py
@@ -10,6 +10,7 @@ import os
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
class DocType(Document):
def validate(self):
@@ -30,7 +31,6 @@ class DocType(Document):
validate_permissions(self)
self.make_amendable()
- self.check_link_replacement_error()
def change_modified_of_parent(self):
if frappe.flags.in_import:
@@ -93,12 +93,6 @@ class DocType(Document):
module.on_doctype_update()
frappe.clear_cache(doctype=self.name)
- def check_link_replacement_error(self):
- for d in self.get("fields", {"fieldtype":"Select"}):
- if (frappe.db.get_value("DocField", d.name, "options") or "").startswith("link:") \
- and not d.options.startswith("link:"):
- frappe.throw(_("'link:' type Select {0} getting replaced").format(d.label))
-
def on_trash(self):
frappe.db.sql("delete from `tabCustom Field` where dt = %s", self.name)
frappe.db.sql("delete from `tabCustom Script` where dt = %s", self.name)
@@ -176,7 +170,7 @@ def validate_fields(fields):
def check_unique_fieldname(fieldname):
duplicates = filter(None, map(lambda df: df.fieldname==fieldname and str(df.idx) or None, fields))
if len(duplicates) > 1:
- frappe.throw(_("Fieldname {0} appears multiple times in rows {1}").format(", ".join(duplicates)))
+ frappe.throw(_("Fieldname {0} appears multiple times in rows {1}").format(fieldname, ", ".join(duplicates)))
def check_illegal_mandatory(d):
if d.fieldtype in ('HTML', 'Button', 'Section Break', 'Column Break') and d.reqd:
@@ -198,7 +192,8 @@ def validate_fields(fields):
def check_min_items_in_list(fields):
if len(filter(lambda d: d.in_list_view, fields))==0:
for d in fields[:5]:
- d.in_list_view = 1
+ if d.fieldtype in type_map:
+ d.in_list_view = 1
def check_width(d):
if d.fieldtype == "Currency" and cint(d.width) < 100:
diff --git a/frappe/core/doctype/event_user/event_user.json b/frappe/core/doctype/event_user/event_user.json
index 8ed3cfe2e0..5886cd21ba 100644
--- a/frappe/core/doctype/event_user/event_user.json
+++ b/frappe/core/doctype/event_user/event_user.json
@@ -1,17 +1,17 @@
{
"autoname": "EVP.#####",
- "creation": "2013-02-22 01:27:33.000000",
+ "creation": "2013-02-22 01:27:33",
"docstatus": 0,
"doctype": "DocType",
"fields": [
{
"fieldname": "person",
- "fieldtype": "Select",
+ "fieldtype": "Link",
"in_list_view": 1,
"label": "Person",
"oldfieldname": "person",
"oldfieldtype": "Select",
- "options": "link:User",
+ "options": "User",
"permlevel": 0,
"print_width": "240px",
"search_index": 1,
@@ -20,9 +20,12 @@
],
"idx": 1,
"istable": 1,
- "modified": "2013-12-20 19:23:14.000000",
+ "modified": "2014-05-09 02:12:32.374008",
"modified_by": "Administrator",
"module": "Core",
"name": "Event User",
- "owner": "Administrator"
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/frappe/core/doctype/file_data/file_data.py b/frappe/core/doctype/file_data/file_data.py
index a457a3da5b..4d88a6adca 100644
--- a/frappe/core/doctype/file_data/file_data.py
+++ b/frappe/core/doctype/file_data/file_data.py
@@ -44,8 +44,8 @@ class FileData(Document):
pass
# if file not attached to any other record, delete it
- if self.file_name and not frappe.db.count("File Data",
- {"content_hash": self.content_hash, "name": ["!=", self.name]}):
+ if self.file_name and self.content_hash and (not frappe.db.count("File Data",
+ {"content_hash": self.content_hash, "name": ["!=", self.name]})):
delete_file_data_content(self)
def on_rollback(self):
diff --git a/frappe/core/doctype/letter_head/letter_head.json b/frappe/core/doctype/letter_head/letter_head.json
index 6ba72a5b6d..115570898b 100644
--- a/frappe/core/doctype/letter_head/letter_head.json
+++ b/frappe/core/doctype/letter_head/letter_head.json
@@ -1,7 +1,7 @@
{
"allow_attach": 1,
"autoname": "field:letter_head_name",
- "creation": "2012-11-22 17:45:46.000000",
+ "creation": "2012-11-22 17:45:46",
"docstatus": 0,
"doctype": "DocType",
"fields": [
@@ -9,6 +9,7 @@
"fieldname": "letter_head_name",
"fieldtype": "Data",
"in_filter": 0,
+ "in_list_view": 1,
"label": "Letter Head Name",
"oldfieldname": "letter_head_name",
"oldfieldtype": "Data",
@@ -19,6 +20,7 @@
"depends_on": "letter_head_name",
"fieldname": "disabled",
"fieldtype": "Check",
+ "in_list_view": 1,
"label": "Disabled",
"oldfieldname": "disabled",
"oldfieldtype": "Check",
@@ -29,6 +31,7 @@
"description": "Check this to make this the default letter head in all prints",
"fieldname": "is_default",
"fieldtype": "Check",
+ "in_list_view": 1,
"label": "Is Default",
"oldfieldname": "is_default",
"oldfieldtype": "Check",
@@ -39,6 +42,7 @@
"description": "Letter Head in HTML",
"fieldname": "content",
"fieldtype": "Text Editor",
+ "in_list_view": 1,
"label": "Content",
"oldfieldname": "content",
"oldfieldtype": "Text Editor",
@@ -48,7 +52,7 @@
"icon": "icon-font",
"idx": 1,
"max_attachments": 3,
- "modified": "2014-01-20 17:48:56.000000",
+ "modified": "2014-05-07 06:03:07.760995",
"modified_by": "Administrator",
"module": "Core",
"name": "Letter Head",
@@ -69,11 +73,11 @@
},
{
"delete": 0,
- "email": 1,
+ "email": 0,
"permlevel": 0,
- "print": 1,
+ "print": 0,
"read": 1,
- "report": 1,
+ "report": 0,
"role": "All"
}
]
diff --git a/frappe/core/doctype/notification_count/notification_count.json b/frappe/core/doctype/notification_count/notification_count.json
index 53cd755ee0..e43fcb7686 100644
--- a/frappe/core/doctype/notification_count/notification_count.json
+++ b/frappe/core/doctype/notification_count/notification_count.json
@@ -1,4 +1,5 @@
{
+ "autoname": "hash",
"creation": "2013-11-18 05:31:03.000000",
"docstatus": 0,
"doctype": "DocType",
@@ -25,9 +26,9 @@
}
],
"idx": 1,
- "modified": "2013-12-20 19:24:14.000000",
+ "modified": "2014-05-12 19:24:14.000000",
"modified_by": "Administrator",
"module": "Core",
"name": "Notification Count",
"owner": "Administrator"
-}
\ No newline at end of file
+}
diff --git a/frappe/core/doctype/page/page.py b/frappe/core/doctype/page/page.py
index a9c2e1ddbb..3227e7f9b8 100644
--- a/frappe/core/doctype/page/page.py
+++ b/frappe/core/doctype/page/page.py
@@ -71,19 +71,19 @@ class Page(Document):
fpath = os.path.join(path, scrub(self.name) + '.js')
if os.path.exists(fpath):
with open(fpath, 'r') as f:
- self.script = f.read()
+ self.script = unicode(f.read(), "utf-8")
# css
fpath = os.path.join(path, scrub(self.name) + '.css')
if os.path.exists(fpath):
with open(fpath, 'r') as f:
- self.style = f.read()
+ self.style = unicode(f.read(), "utf-8")
# html
fpath = os.path.join(path, scrub(self.name) + '.html')
if os.path.exists(fpath):
with open(fpath, 'r') as f:
- self.content = f.read()
+ self.content = unicode(f.read(), "utf-8")
if frappe.lang != 'en':
from frappe.translate import get_lang_js
diff --git a/frappe/core/doctype/print_format/print_format.js b/frappe/core/doctype/print_format/print_format.js
index 81e8829eed..d09f46c261 100644
--- a/frappe/core/doctype/print_format/print_format.js
+++ b/frappe/core/doctype/print_format/print_format.js
@@ -1,10 +1,13 @@
-cur_frm.cscript.refresh = function(doc, dt, dn) {
- if(user!="Administrator") {
- if(doc.standard == 'Yes') {
+cur_frm.cscript.refresh = function (doc) {
+ if (user!="Administrator") {
+ if (doc.standard == 'Yes') {
cur_frm.toggle_enable(["html", "doc_type", "module"], false);
cur_frm.disable_save();
+ } else {
+ cur_frm.toggle_enable(["html", "doc_type", "module"], true);
+ cur_frm.enable_save();
}
cur_frm.toggle_enable("standard", false);
}
-}
\ No newline at end of file
+}
diff --git a/frappe/core/doctype/print_format/print_format.json b/frappe/core/doctype/print_format/print_format.json
index 987023bf04..a8bcffd22e 100644
--- a/frappe/core/doctype/print_format/print_format.json
+++ b/frappe/core/doctype/print_format/print_format.json
@@ -3,21 +3,22 @@
"allow_copy": 0,
"allow_rename": 0,
"autoname": "Prompt",
- "creation": "2013-01-23 19:54:43.000000",
+ "creation": "2013-01-23 19:54:43",
"docstatus": 0,
"doctype": "DocType",
"fields": [
{
"allow_on_submit": 0,
"fieldname": "module",
- "fieldtype": "Select",
+ "fieldtype": "Link",
"hidden": 0,
"in_filter": 1,
+ "in_list_view": 1,
"label": "Module",
"no_copy": 0,
"oldfieldname": "module",
"oldfieldtype": "Select",
- "options": "link:Module Def",
+ "options": "Module Def",
"permlevel": 0,
"print_hide": 0,
"report_hide": 0,
@@ -27,10 +28,11 @@
{
"description": "Belongs to",
"fieldname": "doc_type",
- "fieldtype": "Select",
+ "fieldtype": "Link",
"in_filter": 1,
+ "in_list_view": 1,
"label": "DocType",
- "options": "link:DocType",
+ "options": "DocType",
"permlevel": 0,
"reqd": 0,
"search_index": 0
@@ -47,6 +49,7 @@
"fieldtype": "Select",
"hidden": 0,
"in_filter": 1,
+ "in_list_view": 1,
"label": "Standard",
"no_copy": 1,
"oldfieldname": "standard",
@@ -62,6 +65,7 @@
{
"fieldname": "print_format_type",
"fieldtype": "Select",
+ "in_list_view": 1,
"label": "Print Format Type",
"options": "Client\nServer",
"permlevel": 0
@@ -99,7 +103,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2014-01-20 17:49:00.000000",
+ "modified": "2014-05-09 02:12:39.540952",
"modified_by": "Administrator",
"module": "Core",
"name": "Print Format",
@@ -158,5 +162,7 @@
}
],
"read_only": 0,
- "read_only_onload": 0
+ "read_only_onload": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/frappe/core/doctype/report/report.js b/frappe/core/doctype/report/report.js
index 4f3e162577..d8d4bf90cc 100644
--- a/frappe/core/doctype/report/report.js
+++ b/frappe/core/doctype/report/report.js
@@ -2,7 +2,7 @@ cur_frm.cscript.refresh = function(doc) {
cur_frm.add_custom_button("Show Report", function() {
switch(doc.report_type) {
case "Report Builder":
- frappe.set_route("Report", doc.name);
+ frappe.set_route("Report", doc.ref_doctype, doc.name);
break;
case "Query Report":
frappe.set_route("query-report", doc.name);
@@ -12,7 +12,7 @@ cur_frm.cscript.refresh = function(doc) {
break;
}
}, "icon-table")
-
+
cur_frm.set_intro("");
switch(doc.report_type) {
case "Report Builder":
@@ -30,4 +30,4 @@ cur_frm.cscript.refresh = function(doc) {
cur_frm.set_intro(__("Write a Python file in the same folder where this is saved and return column and result."))
break;
}
-}
\ No newline at end of file
+}
diff --git a/frappe/core/doctype/report/report.json b/frappe/core/doctype/report/report.json
index f4a5bde8b2..62e81b08b9 100644
--- a/frappe/core/doctype/report/report.json
+++ b/frappe/core/doctype/report/report.json
@@ -1,6 +1,6 @@
{
"autoname": "field:report_name",
- "creation": "2013-03-09 15:45:57.000000",
+ "creation": "2013-03-09 15:45:57",
"docstatus": 0,
"doctype": "DocType",
"document_type": "System",
@@ -101,7 +101,7 @@
],
"icon": "icon-table",
"idx": 1,
- "modified": "2014-03-07 15:20:02.000000",
+ "modified": "2014-05-12 17:08:04.185601",
"modified_by": "Administrator",
"module": "Core",
"name": "Report",
@@ -157,5 +157,7 @@
"role": "All",
"submit": 0
}
- ]
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC"
}
\ No newline at end of file
diff --git a/frappe/core/page/applications/applications.js b/frappe/core/page/applications/applications.js
index ce0a0700a2..14c5941900 100644
--- a/frappe/core/page/applications/applications.js
+++ b/frappe/core/page/applications/applications.js
@@ -1,4 +1,4 @@
-frappe.pages['applications'].onload = function(wrapper) {
+frappe.pages['applications'].onload = function(wrapper) {
frappe.ui.make_app_page({
parent: wrapper,
title: __('Application Installer'),
@@ -10,7 +10,7 @@ frappe.pages['applications'].onload = function(wrapper) {
method:"frappe.core.page.applications.applications.get_app_list",
callback: function(r) {
var $main = $(wrapper).find(".layout-main");
-
+
if(!keys(r.message).length) {
$main.html('
No Apps Installed
');
return;
@@ -54,7 +54,7 @@ frappe.pages['applications'].onload = function(wrapper) {
\
', app))
$app.appendTo($main)
-
+
if(app.installed) {
$btn = $('');
@@ -63,7 +63,7 @@ frappe.pages['applications'].onload = function(wrapper) {
.attr("data-app", app.app_name)
.on("click", function() {
frappe.call({
- method:"frappe.installer.install_app",
+ method:"frappe.core.page.applications.applications.install_app",
args: {name: $(this).attr("data-app")},
callback: function(r) {
if(!r.exc) {
diff --git a/frappe/core/page/applications/applications.py b/frappe/core/page/applications/applications.py
index ade393014c..0162bf4530 100644
--- a/frappe/core/page/applications/applications.py
+++ b/frappe/core/page/applications/applications.py
@@ -3,6 +3,8 @@
from __future__ import unicode_literals
import frappe
+import frappe.installer
+from frappe import _
@frappe.whitelist()
def get_app_list():
@@ -19,8 +21,16 @@ def get_app_list():
"app_publisher", "app_version", "app_url", "app_color"):
val = app_hooks.get(key) or []
out[app][key] = val[0] if len(val) else ""
-
+
if app in installed:
out[app]["installed"] = 1
-
+
return out
+
+@frappe.whitelist()
+def install_app(name):
+ app_hooks = frappe.get_hooks(app_name=name)
+ if app_hooks.get('hide_in_installer'):
+ frappe.throw(_("You cannot install this app"))
+
+ frappe.installer.install_app(name)
diff --git a/frappe/core/page/data_import_tool/exporter.py b/frappe/core/page/data_import_tool/exporter.py
index b64b95b841..ab711e171b 100644
--- a/frappe/core/page/data_import_tool/exporter.py
+++ b/frappe/core/page/data_import_tool/exporter.py
@@ -108,8 +108,6 @@ def get_template(doctype=None, parent_doctype=None, all_doctypes="No", with_data
if docfield.fieldtype == 'Select':
if not docfield.options:
return ''
- elif docfield.options.startswith('link:'):
- return 'Valid %s' % docfield.options[5:]
else:
return 'One of: %s' % ', '.join(filter(None, docfield.options.split('\n')))
elif docfield.fieldtype == 'Link':
diff --git a/frappe/core/page/data_import_tool/importer.py b/frappe/core/page/data_import_tool/importer.py
index 7c05ceb5fe..36034b01bf 100644
--- a/frappe/core/page/data_import_tool/importer.py
+++ b/frappe/core/page/data_import_tool/importer.py
@@ -186,9 +186,6 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False,
doc = None
doc = get_doc(row_idx)
- if doc.get("name"):
- doc["_new_name_set"] = True
-
try:
frappe.local.message_log = []
if doc.get("parentfield"):
diff --git a/frappe/core/page/desktop/desktop.js b/frappe/core/page/desktop/desktop.js
index 411b9c0ce1..78012c9fec 100644
--- a/frappe/core/page/desktop/desktop.js
+++ b/frappe/core/page/desktop/desktop.js
@@ -73,7 +73,7 @@ frappe.desktop.render = function() {
$.each(modules_list, function(i, m) {
var module = frappe.modules[m];
if(module) {
- if(m!="Setup" && user_list.indexOf(m)!==-1)
+ if(!in_list(["Setup", "Core"], m) && user_list.indexOf(m)!==-1)
add_icon(m);
}
})
@@ -82,6 +82,9 @@ frappe.desktop.render = function() {
if(user_roles.indexOf('System Manager')!=-1)
add_icon('Setup')
+ if(user_roles.indexOf('Administrator')!=-1)
+ add_icon('Core')
+
// all applications
frappe.modules["All Applications"] = {
icon: "icon-th",
diff --git a/frappe/core/page/user_properties/user_properties.py b/frappe/core/page/user_properties/user_properties.py
index 47f58cec35..303329dc62 100644
--- a/frappe/core/page/user_properties/user_properties.py
+++ b/frappe/core/page/user_properties/user_properties.py
@@ -18,17 +18,17 @@ def get_users_and_links():
def get_properties(parent=None, defkey=None, defvalue=None):
if defkey and not frappe.permissions.can_restrict(defkey, defvalue):
raise frappe.PermissionError
-
+
conditions, values = _build_conditions(locals())
-
- properties = frappe.db.sql("""select name, parent, defkey, defvalue
+
+ properties = frappe.db.sql("""select name, parent, defkey, defvalue
from tabDefaultValue
where parent not in ('__default', '__global')
and substr(defkey,1,1)!='_'
and parenttype='Restriction'
{conditions}
order by parent, defkey""".format(conditions=conditions), values, as_dict=True)
-
+
if not defkey:
out = []
doctypes = get_restrictable_doctypes()
@@ -36,9 +36,9 @@ def get_properties(parent=None, defkey=None, defvalue=None):
if p.defkey in doctypes:
out.append(p)
properties = out
-
+
return properties
-
+
def _build_conditions(filters):
conditions = []
values = {}
@@ -46,7 +46,7 @@ def _build_conditions(filters):
if filters.get(key):
conditions.append("and `{key}`=%({key})s".format(key=key))
values[key] = value
-
+
return "\n".join(conditions), values
@frappe.whitelist()
@@ -54,35 +54,35 @@ def remove(user, name, defkey, defvalue):
if not frappe.permissions.can_restrict_user(user, defkey, defvalue):
raise frappe.PermissionError("Cannot Remove Restriction for User: {user} on DocType: {doctype} and Name: {name}".format(
user=user, doctype=defkey, name=defvalue))
-
- frappe.defaults.clear_default(name=name)
-
+
+ frappe.defaults.clear_default(key=defkey, value=defvalue, parent=user, name=name)
+
def clear_restrictions(doctype):
frappe.defaults.clear_default(parenttype="Restriction", key=doctype)
-
+
@frappe.whitelist()
def add(user, defkey, defvalue):
if not frappe.permissions.can_restrict_user(user, defkey, defvalue):
raise frappe.PermissionError("Cannot Restrict User: {user} for DocType: {doctype} and Name: {name}".format(
user=user, doctype=defkey, name=defvalue))
-
+
# check if already exists
- d = frappe.db.sql("""select name from tabDefaultValue
+ d = frappe.db.sql("""select name from tabDefaultValue
where parent=%s and parenttype='Restriction' and defkey=%s and defvalue=%s""", (user, defkey, defvalue))
-
+
if not d:
frappe.defaults.add_default(defkey, defvalue, user, "Restriction")
-
+
def get_restrictable_doctypes():
user_roles = frappe.get_roles()
condition = ""
values = []
if "System Manager" not in user_roles:
- condition = """and exists(select `tabDocPerm`.name from `tabDocPerm`
+ condition = """and exists(select `tabDocPerm`.name from `tabDocPerm`
where `tabDocPerm`.parent=`tabDocType`.name and `tabDocPerm`.`restrict`=1
and `tabDocPerm`.role in ({roles}))""".format(roles=", ".join(["%s"]*len(user_roles)))
values = user_roles
-
- return frappe.db.sql_list("""select name from tabDocType
+
+ 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))
diff --git a/frappe/data/Framework.sql b/frappe/data/Framework.sql
index f6055f257c..79c0990491 100644
--- a/frappe/data/Framework.sql
+++ b/frappe/data/Framework.sql
@@ -8,21 +8,21 @@
DROP TABLE IF EXISTS `tabDocField`;
CREATE TABLE `tabDocField` (
- `name` varchar(120) NOT NULL,
+ `name` varchar(255) NOT NULL,
`creation` datetime(6) DEFAULT NULL,
`modified` datetime(6) DEFAULT NULL,
- `modified_by` varchar(40) DEFAULT NULL,
- `owner` varchar(40) DEFAULT NULL,
+ `modified_by` varchar(255) DEFAULT NULL,
+ `owner` varchar(255) DEFAULT NULL,
`docstatus` int(1) DEFAULT '0',
- `parent` varchar(120) DEFAULT NULL,
- `parentfield` varchar(120) DEFAULT NULL,
- `parenttype` varchar(120) DEFAULT NULL,
+ `parent` varchar(255) DEFAULT NULL,
+ `parentfield` varchar(255) DEFAULT NULL,
+ `parenttype` varchar(255) DEFAULT NULL,
`idx` int(8) DEFAULT NULL,
- `fieldname` varchar(180) DEFAULT NULL,
- `label` varchar(180) DEFAULT NULL,
- `oldfieldname` varchar(180) DEFAULT NULL,
- `fieldtype` varchar(180) DEFAULT NULL,
- `oldfieldtype` varchar(180) DEFAULT NULL,
+ `fieldname` varchar(255) DEFAULT NULL,
+ `label` varchar(255) DEFAULT NULL,
+ `oldfieldname` varchar(255) DEFAULT NULL,
+ `fieldtype` varchar(255) DEFAULT NULL,
+ `oldfieldtype` varchar(255) DEFAULT NULL,
`options` text,
`search_index` int(1) DEFAULT NULL,
`hidden` int(1) DEFAULT NULL,
@@ -32,12 +32,12 @@ CREATE TABLE `tabDocField` (
`reqd` int(1) DEFAULT NULL,
`no_copy` int(1) DEFAULT NULL,
`allow_on_submit` int(1) DEFAULT NULL,
- `trigger` varchar(180) DEFAULT NULL,
- `depends_on` varchar(180) DEFAULT NULL,
+ `trigger` varchar(255) DEFAULT NULL,
+ `depends_on` varchar(255) DEFAULT NULL,
`permlevel` int(11) DEFAULT '0',
`ignore_restrictions` int(1) DEFAULT NULL,
- `width` varchar(180) DEFAULT NULL,
- `print_width` varchar(180) DEFAULT NULL,
+ `width` varchar(255) DEFAULT NULL,
+ `print_width` varchar(255) DEFAULT NULL,
`default` text,
`description` text,
`in_filter` int(1) DEFAULT NULL,
@@ -57,22 +57,20 @@ CREATE TABLE `tabDocField` (
--
DROP TABLE IF EXISTS `tabDocPerm`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `tabDocPerm` (
- `name` varchar(120) NOT NULL,
+ `name` varchar(255) NOT NULL,
`creation` datetime(6) DEFAULT NULL,
`modified` datetime(6) DEFAULT NULL,
- `modified_by` varchar(40) DEFAULT NULL,
- `owner` varchar(40) DEFAULT NULL,
+ `modified_by` varchar(255) DEFAULT NULL,
+ `owner` varchar(255) DEFAULT NULL,
`docstatus` int(1) DEFAULT '0',
- `parent` varchar(120) DEFAULT NULL,
- `parentfield` varchar(120) DEFAULT NULL,
- `parenttype` varchar(120) DEFAULT NULL,
+ `parent` varchar(255) DEFAULT NULL,
+ `parentfield` varchar(255) DEFAULT NULL,
+ `parenttype` varchar(255) DEFAULT NULL,
`idx` int(8) DEFAULT NULL,
`permlevel` int(11) DEFAULT '0',
- `role` varchar(180) DEFAULT NULL,
- `match` varchar(180) DEFAULT NULL,
+ `role` varchar(255) DEFAULT NULL,
+ `match` varchar(255) DEFAULT NULL,
`read` int(1) DEFAULT NULL,
`write` int(1) DEFAULT NULL,
`create` int(1) DEFAULT NULL,
@@ -89,43 +87,42 @@ CREATE TABLE `tabDocPerm` (
PRIMARY KEY (`name`),
KEY `parent` (`parent`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `tabDocType`
--
DROP TABLE IF EXISTS `tabDocType`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `tabDocType` (
- `name` varchar(180) NOT NULL DEFAULT '',
+ `name` varchar(255) NOT NULL DEFAULT '',
`creation` datetime(6) DEFAULT NULL,
`modified` datetime(6) DEFAULT NULL,
- `modified_by` varchar(40) DEFAULT NULL,
- `owner` varchar(180) DEFAULT NULL,
+ `modified_by` varchar(255) DEFAULT NULL,
+ `owner` varchar(255) DEFAULT NULL,
`docstatus` int(1) DEFAULT '0',
- `parent` varchar(120) DEFAULT NULL,
- `parentfield` varchar(120) DEFAULT NULL,
- `parenttype` varchar(120) DEFAULT NULL,
+ `parent` varchar(255) DEFAULT NULL,
+ `parentfield` varchar(255) DEFAULT NULL,
+ `parenttype` varchar(255) DEFAULT NULL,
`idx` int(8) DEFAULT NULL,
- `search_fields` varchar(180) DEFAULT NULL,
+ `search_fields` varchar(255) DEFAULT NULL,
`issingle` int(1) DEFAULT NULL,
`istable` int(1) DEFAULT NULL,
`version` int(11) DEFAULT NULL,
- `module` varchar(180) DEFAULT NULL,
- `plugin` varchar(180) DEFAULT NULL,
- `autoname` varchar(180) DEFAULT NULL,
- `name_case` varchar(180) DEFAULT NULL,
- `title_field` varchar(180) DEFAULT NULL,
+ `module` varchar(255) DEFAULT NULL,
+ `plugin` varchar(255) DEFAULT NULL,
+ `autoname` varchar(255) DEFAULT NULL,
+ `name_case` varchar(255) DEFAULT NULL,
+ `title_field` varchar(255) DEFAULT NULL,
+ `sort_field` varchar(255) DEFAULT NULL,
+ `sort_order` varchar(255) DEFAULT NULL,
`description` text,
- `colour` varchar(180) DEFAULT NULL,
+ `colour` varchar(255) DEFAULT NULL,
`read_only` int(1) DEFAULT NULL,
`in_create` int(1) DEFAULT NULL,
`show_in_menu` int(1) DEFAULT NULL,
`menu_index` int(11) DEFAULT NULL,
- `parent_node` varchar(180) DEFAULT NULL,
- `smallicon` varchar(180) DEFAULT NULL,
+ `parent_node` varchar(255) DEFAULT NULL,
+ `smallicon` varchar(255) DEFAULT NULL,
`allow_print` int(1) DEFAULT NULL,
`allow_email` int(1) DEFAULT NULL,
`allow_copy` int(1) DEFAULT NULL,
@@ -136,47 +133,33 @@ CREATE TABLE `tabDocType` (
`allow_attach` int(1) DEFAULT NULL,
`use_template` int(1) DEFAULT NULL,
`max_attachments` int(11) DEFAULT NULL,
- `section_style` varchar(180) DEFAULT NULL,
- `client_script` mediumtext,
- `client_script_core` mediumtext,
- `server_code` mediumtext,
- `server_code_core` mediumtext,
- `server_code_compiled` mediumtext,
- `client_string` mediumtext,
- `server_code_error` varchar(180) DEFAULT NULL,
- `print_outline` varchar(180) DEFAULT NULL,
- `dt_template` mediumtext,
+ `print_outline` varchar(255) DEFAULT NULL,
`is_transaction_doc` int(1) DEFAULT NULL,
- `change_log` mediumtext,
`read_only_onload` int(1) DEFAULT NULL,
`allow_trash` int(1) DEFAULT NULL,
`in_dialog` int(1) DEFAULT NULL,
- `document_type` varchar(180) DEFAULT NULL,
- `icon` varchar(180) DEFAULT NULL,
- `tag_fields` varchar(180) DEFAULT NULL,
- `subject` varchar(180) DEFAULT NULL,
+ `document_type` varchar(255) DEFAULT NULL,
+ `icon` varchar(255) DEFAULT NULL,
+ `tag_fields` varchar(255) DEFAULT NULL,
+ `subject` varchar(255) DEFAULT NULL,
`_last_update` varchar(32) DEFAULT NULL,
- `default_print_format` varchar(180) DEFAULT NULL,
+ `default_print_format` varchar(255) DEFAULT NULL,
`is_submittable` int(1) DEFAULT NULL,
- `_user_tags` varchar(180) DEFAULT NULL,
+ `_user_tags` varchar(255) DEFAULT NULL,
`custom` int(1) DEFAULT NULL,
PRIMARY KEY (`name`),
KEY `parent` (`parent`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Table structure for table `tabSeries`
--
DROP TABLE IF EXISTS `tabSeries`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `tabSeries` (
`name` varchar(100) DEFAULT NULL,
`current` int(10) DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -184,18 +167,15 @@ CREATE TABLE `tabSeries` (
--
DROP TABLE IF EXISTS `tabSessions`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `tabSessions` (
`user` varchar(255) DEFAULT NULL,
- `sid` varchar(120) DEFAULT NULL,
+ `sid` varchar(255) DEFAULT NULL,
`sessiondata` longtext,
`ipaddress` varchar(16) DEFAULT NULL,
`lastupdate` datetime(6) DEFAULT NULL,
`status` varchar(20) DEFAULT NULL,
KEY `sid` (`sid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
--
@@ -203,11 +183,9 @@ CREATE TABLE `tabSessions` (
--
DROP TABLE IF EXISTS `tabSingles`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `tabSingles` (
- `doctype` varchar(40) DEFAULT NULL,
- `field` varchar(40) DEFAULT NULL,
+ `doctype` varchar(255) DEFAULT NULL,
+ `field` varchar(255) DEFAULT NULL,
`value` text,
KEY `singles_doctype_field_index` (`doctype`, `field`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@@ -217,11 +195,9 @@ CREATE TABLE `tabSingles` (
--
DROP TABLE IF EXISTS `__Auth`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `__Auth` (
- `user` VARCHAR(180) NOT NULL PRIMARY KEY,
- `password` VARCHAR(180) NOT NULL,
+ `user` VARCHAR(255) NOT NULL PRIMARY KEY,
+ `password` VARCHAR(255) NOT NULL,
KEY `user` (`user`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@@ -231,22 +207,22 @@ CREATE TABLE `__Auth` (
DROP TABLE IF EXISTS `tabFile Data`;
CREATE TABLE `tabFile Data` (
- `name` varchar(120) NOT NULL,
+ `name` varchar(255) NOT NULL,
`creation` datetime(6) DEFAULT NULL,
`modified` datetime(6) DEFAULT NULL,
- `modified_by` varchar(40) DEFAULT NULL,
- `owner` varchar(40) DEFAULT NULL,
+ `modified_by` varchar(255) DEFAULT NULL,
+ `owner` varchar(255) DEFAULT NULL,
`docstatus` int(1) DEFAULT '0',
- `parent` varchar(120) DEFAULT NULL,
- `parentfield` varchar(120) DEFAULT NULL,
- `parenttype` varchar(120) DEFAULT NULL,
+ `parent` varchar(255) DEFAULT NULL,
+ `parentfield` varchar(255) DEFAULT NULL,
+ `parenttype` varchar(255) DEFAULT NULL,
`idx` int(8) DEFAULT NULL,
- `file_name` varchar(180) DEFAULT NULL,
- `file_url` varchar(180) DEFAULT NULL,
- `module` varchar(180) DEFAULT NULL,
- `attached_to_name` varchar(180) DEFAULT NULL,
+ `file_name` varchar(255) DEFAULT NULL,
+ `file_url` varchar(255) DEFAULT NULL,
+ `module` varchar(255) DEFAULT NULL,
+ `attached_to_name` varchar(255) DEFAULT NULL,
`file_size` int(11) DEFAULT NULL,
- `attached_to_doctype` varchar(180) DEFAULT NULL,
+ `attached_to_doctype` varchar(255) DEFAULT NULL,
PRIMARY KEY (`name`),
KEY `parent` (`parent`),
KEY `attached_to_name` (`attached_to_name`),
@@ -259,18 +235,18 @@ CREATE TABLE `tabFile Data` (
DROP TABLE IF EXISTS `tabDefaultValue`;
CREATE TABLE `tabDefaultValue` (
- `name` varchar(120) NOT NULL,
+ `name` varchar(255) NOT NULL,
`creation` datetime(6) DEFAULT NULL,
`modified` datetime(6) DEFAULT NULL,
- `modified_by` varchar(40) DEFAULT NULL,
- `owner` varchar(40) DEFAULT NULL,
+ `modified_by` varchar(255) DEFAULT NULL,
+ `owner` varchar(255) DEFAULT NULL,
`docstatus` int(1) DEFAULT '0',
- `parent` varchar(120) DEFAULT NULL,
- `parentfield` varchar(120) DEFAULT NULL,
- `parenttype` varchar(120) DEFAULT NULL,
+ `parent` varchar(255) DEFAULT NULL,
+ `parentfield` varchar(255) DEFAULT NULL,
+ `parenttype` varchar(255) DEFAULT NULL,
`idx` int(8) DEFAULT NULL,
`defvalue` text,
- `defkey` varchar(180) DEFAULT NULL,
+ `defkey` varchar(255) DEFAULT NULL,
PRIMARY KEY (`name`),
KEY `parent` (`parent`),
KEY `defaultvalue_parent_defkey_index` (`parent`,`defkey`)
diff --git a/frappe/data/languages.txt b/frappe/data/languages.txt
index a2938d24af..ed686d7802 100644
--- a/frappe/data/languages.txt
+++ b/frappe/data/languages.txt
@@ -7,11 +7,12 @@ fr français
hi हिंदी
hr hrvatski
it italiano
+kn ಕನ್ನಡ
nl nederlands
pt-BR português brasileiro
pt português
sr српски
ta தமிழ்
th ไทย
-zh-cn 中国(简体
-zh-tw 中國(繁體
\ No newline at end of file
+zh-cn 中国(简体)
+zh-tw 中國(繁體)
diff --git a/frappe/hooks.py b/frappe/hooks.py
index 5b551d841d..95f2299710 100644
--- a/frappe/hooks.py
+++ b/frappe/hooks.py
@@ -66,6 +66,7 @@ scheduler_events = {
"frappe.utils.email_lib.bulk.clear_outbox",
"frappe.core.doctype.notification_count.notification_count.delete_event_notification_count",
"frappe.core.doctype.event.event.send_event_digest",
+ "frappe.sessions.clear_expired_sessions",
],
"hourly": [
"frappe.templates.generators.website_group.clear_event_cache"
diff --git a/frappe/installer.py b/frappe/installer.py
index b5054e3191..2dc37116d1 100755
--- a/frappe/installer.py
+++ b/frappe/installer.py
@@ -13,6 +13,7 @@ import getpass
from frappe import _
from frappe.model.db_schema import DbManager
from frappe.model.sync import sync_for
+from frappe.utils.fixtures import sync_fixtures
def install_db(root_login="root", root_password=None, db_name=None, source_sql=None,
admin_password = 'admin', verbose=True, force=0, site_config=None, reinstall=False):
@@ -81,7 +82,6 @@ def make_connection(root_login, root_password):
root_password = getpass.getpass("MySQL root password: ")
return frappe.database.Database(user=root_login, password=root_password)
-@frappe.whitelist()
def install_app(name, verbose=False, set_as_patched=True):
frappe.flags.in_install_app = name
frappe.clear_cache()
@@ -105,6 +105,7 @@ def install_app(name, verbose=False, set_as_patched=True):
if name != "frappe":
add_module_defs(name)
+
sync_for(name, force=True, sync_everything=True, verbose=verbose)
add_to_installed_apps(name)
@@ -115,6 +116,8 @@ def install_app(name, verbose=False, set_as_patched=True):
for after_install in app_hooks.after_install or []:
frappe.get_attr(after_install)()
+ sync_fixtures()
+
frappe.flags.in_install_app = False
def add_to_installed_apps(app_name, rebuild_sitemap=True):
diff --git a/frappe/middlewares.py b/frappe/middlewares.py
index 6d5d61cb0e..cb84326249 100644
--- a/frappe/middlewares.py
+++ b/frappe/middlewares.py
@@ -1,5 +1,5 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
-# MIT License. See license.txt
+# MIT License. See license.txt
from __future__ import unicode_literals
@@ -16,7 +16,7 @@ class StaticDataMiddleware(SharedDataMiddleware):
def get_directory_loader(self, directory):
def loader(path):
- site = get_site_name(self.environ.get('HTTP_HOST'))
+ site = get_site_name(frappe.app._site or self.environ.get('HTTP_HOST'))
path = os.path.join(directory, site, 'public', 'files', cstr(path))
if os.path.isfile(path):
return os.path.basename(path), self._opener(path)
diff --git a/frappe/model/__init__.py b/frappe/model/__init__.py
index 5beafb2936..067df6bc27 100644
--- a/frappe/model/__init__.py
+++ b/frappe/model/__init__.py
@@ -1,9 +1,11 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
-# MIT License. See license.txt
+# MIT License. See license.txt
# model __init__.py
from __future__ import unicode_literals
import frappe
+import json
+
no_value_fields = ['Section Break', 'Column Break', 'HTML', 'Table', 'Button', 'Image']
default_fields = ['doctype','name','owner','creation','modified','modified_by','parent','parentfield','parenttype','idx','docstatus']
@@ -18,10 +20,10 @@ def insert(doclist):
d["__islocal"] = 1
else:
d.set("__islocal", 1)
-
+
wrapper = frappe.get_doc(doclist)
wrapper.save()
-
+
return wrapper
def rename(doctype, old, new, debug=False):
@@ -29,17 +31,17 @@ def rename(doctype, old, new, debug=False):
frappe.model.rename_doc.rename_doc(doctype, old, new, debug)
def copytables(srctype, src, srcfield, tartype, tar, tarfield, srcfields, tarfields=[]):
- if not tarfields:
+ if not tarfields:
tarfields = srcfields
l = []
data = src.get(srcfield)
for d in data:
newrow = tar.append(tarfield)
newrow.idx = d.idx
-
+
for i in range(len(srcfields)):
newrow.set(tarfields[i], d.get(srcfields[i]))
-
+
l.append(newrow)
return l
@@ -60,15 +62,15 @@ def delete_fields(args_dict, delete=0):
for dt in args_dict.keys():
fields = args_dict[dt]
if not fields: continue
-
+
frappe.db.sql("""\
DELETE FROM `tabDocField`
WHERE parent=%s AND fieldname IN (%s)
""" % ('%s', ", ".join(['"' + f + '"' for f in fields])), dt)
-
+
# Delete the data / column only if delete is specified
if not delete: continue
-
+
if frappe.db.get_value("DocType", dt, "issingle"):
frappe.db.sql("""\
DELETE FROM `tabSingles`
@@ -84,13 +86,13 @@ def delete_fields(args_dict, delete=0):
def rename_field(doctype, old_fieldname, new_fieldname):
"""This functions assumes that doctype is already synced"""
-
+
meta = frappe.get_meta(doctype)
new_field = meta.get_field(new_fieldname)
if not new_field:
print "rename_field: " + (new_fieldname) + " not found in " + doctype
return
-
+
if new_field.fieldtype == "Table":
# change parentfield of table mentioned in options
frappe.db.sql("""update `tab%s` set parentfield=%s
@@ -99,22 +101,82 @@ def rename_field(doctype, old_fieldname, new_fieldname):
elif new_field.fieldtype not in no_value_fields:
if meta.issingle:
frappe.db.sql("""update `tabSingles` set field=%s
- where doctype=%s and field=%s""",
+ where doctype=%s and field=%s""",
(new_fieldname, doctype, old_fieldname))
else:
# copy field value
frappe.db.sql("""update `tab%s` set `%s`=`%s`""" % \
(doctype, new_fieldname, old_fieldname))
-
+
# update in property setter
- frappe.db.sql("""update `tabProperty Setter` set field_name = %s
+ frappe.db.sql("""update `tabProperty Setter` set field_name = %s
where doc_type=%s and field_name=%s""", (new_fieldname, doctype, old_fieldname))
-
+
+ update_reports(doctype, old_fieldname, new_fieldname)
update_users_report_view_settings(doctype, old_fieldname)
-
+
+def update_reports(doctype, old_fieldname, new_fieldname):
+ def _get_new_sort_by(report_dict, report, key):
+ sort_by = report_dict.get(key) or ""
+ if sort_by:
+ sort_by = sort_by.split(".")
+ if len(sort_by) > 1:
+ if sort_by[0]==doctype and sort_by[1]==old_fieldname:
+ sort_by = doctype + "." + new_fieldname
+ report_dict["updated"] = True
+ elif report.ref_doctype == doctype and sort_by[0]==old_fieldname:
+ sort_by = doctype + "." + new_fieldname
+ report_dict["updated"] = True
+
+ if isinstance(sort_by, list):
+ sort_by = '.'.join(sort_by)
+
+ return sort_by
+
+ reports = frappe.db.sql("""select name, ref_doctype, json from tabReport
+ where report_type = 'Report Builder' and ifnull(is_standard, 'No') = 'No'
+ and json like %s and json like %s""",
+ ('%%%s%%' % old_fieldname , '%%%s%%' % doctype), as_dict=True)
+
+ for r in reports:
+ report_dict = json.loads(r.json)
+
+ # update filters
+ new_filters = []
+ for f in report_dict.get("filters"):
+ if f[0] == doctype and f[1] == old_fieldname:
+ new_filters.append([doctype, new_fieldname, f[2], f[3]])
+ report_dict["updated"] = True
+ else:
+ new_filters.append(f)
+
+ # update columns
+ new_columns = []
+ for c in report_dict.get("columns"):
+ if c[0] == old_fieldname and c[1] == doctype:
+ new_columns.append([new_fieldname, doctype])
+ report_dict["updated"] = True
+ else:
+ new_columns.append(c)
+
+ # update sort by
+ new_sort_by = _get_new_sort_by(report_dict, r, "sort_by")
+ new_sort_by_next = _get_new_sort_by(report_dict, r, "sort_by_next")
+
+ if report_dict.get("updated"):
+ new_val = json.dumps({
+ "filters": new_filters,
+ "columns": new_columns,
+ "sort_by": new_sort_by,
+ "sort_order": report_dict.get("sort_order"),
+ "sort_by_next": new_sort_by_next,
+ "sort_order_next": report_dict.get("sort_order_next")
+ })
+
+ frappe.db.sql("""update `tabReport` set `json`=%s where name=%s""", (new_val, r.name))
+
def update_users_report_view_settings(doctype, ref_fieldname):
- import json
- user_report_cols = frappe.db.sql("""select defkey, defvalue from `tabDefaultValue` where
+ user_report_cols = frappe.db.sql("""select defkey, defvalue from `tabDefaultValue` where
defkey like '_list_settings:%'""")
for key, value in user_report_cols:
new_columns = []
@@ -124,5 +186,5 @@ def update_users_report_view_settings(doctype, ref_fieldname):
new_columns.append([field, field_doctype])
columns_modified=True
if columns_modified:
- frappe.db.sql("""update `tabDefaultValue` set defvalue=%s
- where defkey=%s""" % ('%s', '%s'), (json.dumps(new_columns), key))
\ No newline at end of file
+ frappe.db.sql("""update `tabDefaultValue` set defvalue=%s
+ where defkey=%s""" % ('%s', '%s'), (json.dumps(new_columns), key))
diff --git a/frappe/model/base_document.py b/frappe/model/base_document.py
index df303b0699..e723579bce 100644
--- a/frappe/model/base_document.py
+++ b/frappe/model/base_document.py
@@ -163,6 +163,9 @@ class BaseDocument(object):
if self.get("__islocal"):
doc["__islocal"] = 1
+ elif self.get("__onload"):
+ doc["__onload"] = self.get("__onload")
+
return doc
def as_json(self):
@@ -189,6 +192,7 @@ class BaseDocument(object):
except Exception, e:
if e.args[0]==1062:
type, value, traceback = sys.exc_info()
+ frappe.msgprint(_("Duplicate name {0} {1}".format(self.doctype, self.name)))
raise frappe.NameError, (self.doctype, self.name, e), traceback
else:
raise
@@ -259,9 +263,6 @@ class BaseDocument(object):
if not doctype:
frappe.throw(_("Options not set for link field {0}").format(df.fieldname))
- elif doctype.lower().startswith("link:"):
- doctype = doctype[5:]
-
docname = self.get(df.fieldname)
if docname and not frappe.db.get_value(doctype, docname):
invalid_links.append((df.fieldname, docname, get_msg(df, docname)))
@@ -285,7 +286,7 @@ class BaseDocument(object):
current = frappe.db.get_value(self.doctype, self.name, "*", as_dict=True)
for key, value in current.iteritems():
df = self.meta.get_field(key)
- if df and not df.allow_on_submit and self.get(key) != value:
+ if df and not df.allow_on_submit and (self.get(key) or value) and self.get(key) != value:
frappe.throw(_("Not allowed to change {0} after submission").format(df.label),
frappe.UpdateAfterSubmitError)
diff --git a/frappe/model/create_new.py b/frappe/model/create_new.py
index 79d9ad5d10..ae3d12dc82 100644
--- a/frappe/model/create_new.py
+++ b/frappe/model/create_new.py
@@ -63,8 +63,7 @@ def get_new_doc(doctype, parent_doc = None, parentfield = None):
elif d.fieldtype == "Time":
doc.set(d.fieldname, nowtime())
- elif (d.fieldtype == "Select" and d.options and not d.options.startswith("link:")
- and d.options != "[Select]"):
+ elif (d.fieldtype == "Select" and d.options and d.options != "[Select]"):
doc.set(d.fieldname, d.options.split("\n")[0])
return doc
diff --git a/frappe/model/db_query.py b/frappe/model/db_query.py
index 905d8d53a3..da49f92fde 100644
--- a/frappe/model/db_query.py
+++ b/frappe/model/db_query.py
@@ -18,15 +18,17 @@ class DatabaseQuery(object):
self.ignore_permissions = False
self.fields = ["name"]
- def execute(self, query=None, filters=None, fields=None, docstatus=None,
- group_by=None, order_by=None, limit_start=0, limit_page_length=20,
- as_list=False, with_childnames=False, debug=False, ignore_permissions=False):
+ def execute(self, query=None, filters=None, fields=None, or_filters=None,
+ docstatus=None, group_by=None, order_by=None, limit_start=0,
+ limit_page_length=20, as_list=False, with_childnames=False, debug=False,
+ ignore_permissions=False):
if not frappe.has_permission(self.doctype, "read"):
raise frappe.PermissionError
if fields:
self.fields = fields
self.filters = filters or []
+ self.or_filters = or_filters or []
self.docstatus = docstatus or []
self.group_by = group_by
self.order_by = order_by
@@ -67,17 +69,19 @@ class DatabaseQuery(object):
# query dict
args.tables = ', '.join(self.tables)
+ if self.or_conditions:
+ self.conditions.append("({0})".format(" or ".join(self.or_conditions)))
args.conditions = ' and '.join(self.conditions)
args.fields = ', '.join(self.fields)
- args.order_by = self.order_by or self.tables[0] + '.modified desc'
+ self.set_order_by(args)
+
args.group_by = self.group_by and (" group by " + self.group_by) or ""
self.check_sort_by_table(args.order_by)
return args
-
def parse_args(self):
if isinstance(self.filters, basestring):
self.filters = json.loads(self.filters)
@@ -134,8 +138,10 @@ class DatabaseQuery(object):
def build_conditions(self):
self.conditions = []
+ self.or_conditions = []
self.add_docstatus_conditions()
- self.build_filter_conditions()
+ self.build_filter_conditions(self.filters, self.conditions)
+ self.build_filter_conditions(self.or_filters, self.or_conditions)
# join parent, child tables
for tname in self.tables[1:]:
@@ -153,11 +159,13 @@ class DatabaseQuery(object):
else:
self.conditions.append(self.tables[0] + '.docstatus < 2')
- def build_filter_conditions(self):
+ def build_filter_conditions(self, filters, conditions):
"""build conditions from user filters"""
- for f in self.filters:
+ if isinstance(filters, dict):
+ filters = [filters]
+ for f in filters:
if isinstance(f, basestring):
- self.conditions.append(f)
+ conditions.append(f)
else:
f = self.get_filter_tuple(f)
@@ -172,7 +180,7 @@ class DatabaseQuery(object):
opts = f[3].split(",")
opts = ["'" + t.strip().replace("'", "\\'") + "'" for t in opts]
f[3] = "(" + ', '.join(opts) + ")"
- self.conditions.append('ifnull(' + tname + '.' + f[1] + ", '') " + f[2] + " " + f[3])
+ conditions.append('ifnull(' + tname + '.' + f[1] + ", '') " + f[2] + " " + f[3])
else:
df = frappe.get_meta(f[0]).get("fields", {"fieldname": f[1]})
@@ -182,7 +190,7 @@ class DatabaseQuery(object):
else:
value, default_val = flt(f[3]), 0
- self.conditions.append('ifnull({tname}.{fname}, {default_val}) {operator} {value}'.format(
+ conditions.append('ifnull({tname}.{fname}, {default_val}) {operator} {value}'.format(
tname=tname, fname=f[1], default_val=default_val, operator=f[2],
value=value))
@@ -203,7 +211,7 @@ class DatabaseQuery(object):
"""add match conditions if applicable"""
self.match_filters = {}
self.match_conditions = []
- self.or_conditions = []
+ self.match_or_conditions = []
if not self.tables: self.extract_tables()
@@ -214,7 +222,7 @@ class DatabaseQuery(object):
restrictions = frappe.defaults.get_restrictions()
if restricted_by_user:
- self.or_conditions.append('`tab{doctype}`.`owner`="{user}"'.format(doctype=self.doctype,
+ self.match_or_conditions.append('`tab{doctype}`.`owner`="{user}"'.format(doctype=self.doctype,
user=frappe.local.session.user))
self.match_filters["owner"] = frappe.session.user
@@ -247,12 +255,12 @@ class DatabaseQuery(object):
if doctype_conditions:
conditions += ' and ' + doctype_conditions if conditions else doctype_conditions
- if self.or_conditions:
+ if self.match_or_conditions:
if conditions:
conditions = '({conditions}) or {or_conditions}'.format(conditions=conditions,
- or_conditions = ' or '.join(self.or_conditions))
+ or_conditions = ' or '.join(self.match_or_conditions))
else:
- conditions = " or ".join(self.or_conditions)
+ conditions = " or ".join(self.match_or_conditions)
return conditions
@@ -272,6 +280,14 @@ class DatabaseQuery(object):
query = query.replace('%(key)s', 'name')
return frappe.db.sql(query, as_dict = (not self.as_list))
+ def set_order_by(self, args):
+ meta = frappe.get_meta(self.doctype)
+ if self.order_by:
+ args.order_by = self.order_by
+ else:
+ args.order_by = "`tab{0}`.`{1}` {2}".format(self.doctype,
+ meta.sort_field or "modified", meta.sort_order or "desc")
+
def check_sort_by_table(self, order_by):
if "." in order_by:
tbl = order_by.split('.')[0]
diff --git a/frappe/model/db_schema.py b/frappe/model/db_schema.py
index 86f7c474e0..127f2de333 100644
--- a/frappe/model/db_schema.py
+++ b/frappe/model/db_schema.py
@@ -175,27 +175,37 @@ class DbTable:
for col in self.columns.values():
col.check(self.current_columns.get(col.fieldname, None))
+ query = []
+
for col in self.add_column:
- frappe.db.sql("alter table `%s` add column `%s` %s" % (self.name, col.fieldname, col.get_definition()))
+ query.append("add column `{}` {}".format(col.fieldname, col.get_definition()))
for col in self.change_type:
- frappe.db.sql("alter table `%s` change `%s` `%s` %s" % (self.name, col.fieldname, col.fieldname, col.get_definition()))
+ query.append("change `{}` `{}` {}".format(col.fieldname, col.fieldname, col.get_definition()))
for col in self.add_index:
# if index key not exists
if not frappe.db.sql("show index from `%s` where key_name = %s" %
(self.name, '%s'), col.fieldname):
- frappe.db.sql("alter table `%s` add index `%s`(`%s`)" % (self.name, col.fieldname, col.fieldname))
+ query.append("add index `{}`(`{}`)".format(col.fieldname, col.fieldname))
for col in self.drop_index:
if col.fieldname != 'name': # primary key
# if index key exists
if frappe.db.sql("show index from `%s` where key_name = %s" %
(self.name, '%s'), col.fieldname):
- frappe.db.sql("alter table `%s` drop index `%s`" % (self.name, col.fieldname))
+ query.append("drop index `{}`".format(col.fieldname))
- for col in self.set_default:
- frappe.db.sql("alter table `%s` alter column `%s` set default %s" % (self.name, col.fieldname, '%s'), (col.default,))
+ for col in list(set(self.set_default).difference(set(self.change_type))):
+ if not col.default:
+ col_default = "null"
+ else:
+ col_default = '"{}"'.format(col.default.replace('"', '\\"'))
+
+ query.append('alter column `{}` set default {}'.format(col.fieldname, col_default))
+
+ if query:
+ frappe.db.sql("alter table `{}` {}".format(self.name, ", ".join(query)))
class DbColumn:
def __init__(self, table, fieldname, fieldtype, length, default, set_index, options):
diff --git a/frappe/model/document.py b/frappe/model/document.py
index 6118f02d46..8ff78e119d 100644
--- a/frappe/model/document.py
+++ b/frappe/model/document.py
@@ -8,6 +8,7 @@ from frappe.utils import flt, cint, cstr, now
from frappe.modules import load_doctype_module
from frappe.model.base_document import BaseDocument
from frappe.model.naming import set_new_name
+from werkzeug.exceptions import NotFound, Forbidden
# once_only validation
# methods
@@ -156,6 +157,8 @@ class Document(BaseDocument):
self.set_parent_in_children()
self.run_before_save_methods()
self._validate()
+ if self._action == "update_after_submit":
+ self.validate_update_after_submit()
# parent
if self.meta.issingle:
@@ -283,7 +286,6 @@ class Document(BaseDocument):
elif docstatus==1:
if self.docstatus==1:
self._action = "update_after_submit"
- self.validate_update_after_submit()
if not self.has_permission("submit"):
self.raise_no_permission_to("submit")
elif self.docstatus==2:
@@ -387,6 +389,7 @@ class Document(BaseDocument):
elif self._action=="cancel":
self.run_method("before_cancel")
elif self._action=="update_after_submit":
+ self.run_method("validate")
self.run_method("before_update_after_submit")
def run_post_save_methods(self):
@@ -400,6 +403,11 @@ class Document(BaseDocument):
elif self._action=="update_after_submit":
self.run_method("on_update_after_submit")
+ @staticmethod
+ def whitelist(f):
+ f.whitelisted = True
+ return f
+
@staticmethod
def hook(f):
def add_to_return_value(self, new_return_value):
@@ -433,6 +441,13 @@ class Document(BaseDocument):
return composer
+ def is_whitelisted(self, method):
+ fn = getattr(self, method, None)
+ if not fn:
+ raise NotFound("Method {0} not found".format(method))
+ elif not getattr(fn, "whitelisted", False):
+ raise Forbidden("Method {0} not whitelisted".format(method))
+
def validate_value(self, fieldname, condition, val2, doc=None, raise_exception=None):
"""check that value of fieldname should be 'condition' val2
else throw exception"""
diff --git a/frappe/model/meta.py b/frappe/model/meta.py
index f4f2c099a8..c0e1ac0bca 100644
--- a/frappe/model/meta.py
+++ b/frappe/model/meta.py
@@ -59,11 +59,7 @@ class Meta(Document):
raise
def get_link_fields(self):
- tmp = self.get("fields", {"fieldtype":"Link", "options":["!=", "[Select]"]})
- for df in self.get("fields", {"fieldtype":"Select", "options": "^link:"}):
- tmp.append(frappe._dict({"fieldname":df.fieldname, "label":df.label,
- "fieldtype":"Link", "options": df.options[5:]}))
- return tmp
+ return self.get("fields", {"fieldtype": "Link", "options":["!=", "[Select]"]})
def get_table_fields(self):
if not hasattr(self, "_table_fields"):
@@ -99,6 +95,21 @@ class Meta(Document):
def get_options(self, fieldname):
return self.get_field(fieldname).options
+ def get_search_fields(self):
+ search_fields = self.search_fields or "name"
+ search_fields = [d.strip() for d in search_fields.split(",")]
+ if "name" not in search_fields:
+ search_fields.append("name")
+
+ return search_fields
+
+ def get_list_fields(self):
+ list_fields = ["name"] + [d.fieldname \
+ for d in self.fields if (d.in_list_view and d.fieldtype in type_map)]
+ if self.title_field and self.title_field not in list_fields:
+ list_fields.append(self.title_field)
+ return list_fields
+
def process(self):
# don't process for special doctypes
# prevent's circular dependency
@@ -203,7 +214,7 @@ doctype_table_fields = [
def is_single(doctype):
try:
return frappe.db.get_value("DocType", doctype, "issingle")
- except IndexError, e:
+ except IndexError:
raise Exception, 'Cannot determine whether %s is single' % doctype
def get_parent_dt(dt):
diff --git a/frappe/model/naming.py b/frappe/model/naming.py
index 782c88a91d..48b551f209 100644
--- a/frappe/model/naming.py
+++ b/frappe/model/naming.py
@@ -7,13 +7,9 @@ import frappe
from frappe.utils import now_datetime, cint
def set_new_name(doc):
- if getattr(doc, "_new_name_set", False):
- # already set by doc
+ if doc.name:
return
- doc._new_name_set = True
- autoname = frappe.get_meta(doc.doctype).autoname
-
# amendments
if getattr(doc, "amended_from", None):
return _get_amended_name(doc)
@@ -22,31 +18,35 @@ def set_new_name(doc):
if tmp and not isinstance(tmp, basestring):
# autoname in a function, not a property
doc.autoname()
- if doc.name:
- return
+ if doc.name:
+ return
+
+ autoname = frappe.get_meta(doc.doctype).autoname
# based on a field
- if autoname and autoname.startswith('field:'):
- n = doc.get(autoname[6:])
- if not n:
- raise Exception, 'Name is required'
- doc.name = n.strip()
+ if autoname:
+ if autoname.startswith('field:'):
+ n = doc.get(autoname[6:])
+ if not n:
+ raise Exception, 'Name is required'
+ doc.name = n.strip()
- elif autoname and autoname.startswith("naming_series:"):
- if not doc.naming_series:
- doc.naming_series = get_default_naming_series(doc.doctype)
+ elif autoname.startswith("naming_series:"):
+ if not doc.naming_series:
+ doc.naming_series = get_default_naming_series(doc.doctype)
- if not doc.naming_series:
- frappe.msgprint(frappe._("Naming Series mandatory"), raise_exception=True)
- doc.name = make_autoname(doc.naming_series+'.#####')
+ if not doc.naming_series:
+ frappe.msgprint(frappe._("Naming Series mandatory"), raise_exception=True)
+ doc.name = make_autoname(doc.naming_series+'.#####')
- # call the method!
- elif autoname and autoname!='Prompt':
- doc.name = make_autoname(autoname, doc.doctype)
+ # call the method!
+ elif autoname=='Prompt':
+ # set from __newname in save.py
+ if not doc.name:
+ frappe.throw(frappe._("Name not set via Prompt"))
- # given
- elif doc.get('__newname', None):
- doc.name = doc.get('__newname')
+ else:
+ doc.name = make_autoname(autoname, doc.doctype)
# default name for table
elif doc.meta.istable:
diff --git a/frappe/model/rename_doc.py b/frappe/model/rename_doc.py
index 32d7072c30..1f4b5fb180 100644
--- a/frappe/model/rename_doc.py
+++ b/frappe/model/rename_doc.py
@@ -11,7 +11,7 @@ from frappe.model.naming import validate_name
def rename_doc(doctype, old, new, force=False, merge=False, ignore_permissions=False):
"""
Renames a doc(dt, old) to doc(dt, new) and
- updates all linked fields of type "Link" or "Select" with "link:"
+ updates all linked fields of type "Link"
"""
if not frappe.db.exists(doctype, old):
return
@@ -138,10 +138,7 @@ def get_link_fields(doctype):
where dt.name = df.parent) as issingle
from tabDocField df
where
- df.parent not like "old%%%%" and df.parent != '0' and
- ((df.options=%s and df.fieldtype='Link') or
- (df.options='link:%s' and df.fieldtype='Select'))""" \
- % ('%s', doctype), (doctype,), as_dict=1)
+ df.options=%s and df.fieldtype='Link'""", (doctype,), as_dict=1)
# get link fields from tabCustom Field
custom_link_fields = frappe.db.sql("""\
@@ -150,10 +147,7 @@ def get_link_fields(doctype):
where dt.name = df.dt) as issingle
from `tabCustom Field` df
where
- df.dt not like "old%%%%" and df.dt != '0' and
- ((df.options=%s and df.fieldtype='Link') or
- (df.options='link:%s' and df.fieldtype='Select'))""" \
- % ('%s', doctype), (doctype,), as_dict=1)
+ df.options=%s and df.fieldtype='Link'""", (doctype,), as_dict=1)
# add custom link fields list to link fields list
link_fields += custom_link_fields
@@ -167,8 +161,7 @@ def get_link_fields(doctype):
where
ps.property_type='options' and
ps.field_name is not null and
- (ps.value=%s or ps.value='link:%s')""" \
- % ('%s', doctype), (doctype,), as_dict=1)
+ ps.value=%s""", (doctype,), as_dict=1)
link_fields += property_setter_link_fields
@@ -199,10 +192,8 @@ def get_select_fields(old, new):
where dt.name = df.parent) as issingle
from tabDocField df
where
- df.parent not like "old%%%%" and df.parent != '0' and
df.parent != %s and df.fieldtype = 'Select' and
- df.options not like "link:%%%%" and
- (df.options like "%%%%%s%%%%")""" \
+ df.options like "%%%%%s%%%%" """ \
% ('%s', old), (new,), as_dict=1)
# get link fields from tabCustom Field
@@ -212,10 +203,8 @@ def get_select_fields(old, new):
where dt.name = df.dt) as issingle
from `tabCustom Field` df
where
- df.dt not like "old%%%%" and df.dt != '0' and
df.dt != %s and df.fieldtype = 'Select' and
- df.options not like "link:%%%%" and
- (df.options like "%%%%%s%%%%")""" \
+ df.options like "%%%%%s%%%%" """ \
% ('%s', old), (new,), as_dict=1)
# add custom link fields list to link fields list
@@ -231,8 +220,7 @@ def get_select_fields(old, new):
ps.doc_type != %s and
ps.property_type='options' and
ps.field_name is not null and
- ps.value not like "link:%%%%" and
- (ps.value like "%%%%%s%%%%")""" \
+ ps.value like "%%%%%s%%%%" """ \
% ('%s', old), (new,), as_dict=1)
select_fields += property_setter_select_fields
@@ -243,16 +231,14 @@ def update_select_field_values(old, new):
frappe.db.sql("""\
update `tabDocField` set options=replace(options, %s, %s)
where
- parent != %s and parent not like "old%%%%" and
- fieldtype = 'Select' and options not like "link:%%%%" and
+ parent != %s and fieldtype = 'Select' and
(options like "%%%%\\n%s%%%%" or options like "%%%%%s\\n%%%%")""" % \
('%s', '%s', '%s', old, old), (old, new, new))
frappe.db.sql("""\
update `tabCustom Field` set options=replace(options, %s, %s)
where
- dt != %s and dt not like "old%%%%" and
- fieldtype = 'Select' and options not like "link:%%%%" and
+ dt != %s and fieldtype = 'Select' and
(options like "%%%%\\n%s%%%%" or options like "%%%%%s\\n%%%%")""" % \
('%s', '%s', '%s', old, old), (old, new, new))
@@ -260,7 +246,7 @@ def update_select_field_values(old, new):
update `tabProperty Setter` set value=replace(value, %s, %s)
where
doc_type != %s and field_name is not null and
- property='options' and value not like "link%%%%" and
+ property='options' and
(value like "%%%%\\n%s%%%%" or value like "%%%%%s\\n%%%%")""" % \
('%s', '%s', '%s', old, old), (old, new, new))
diff --git a/frappe/model/sync.py b/frappe/model/sync.py
index 1ad92d78ec..0c285f423a 100644
--- a/frappe/model/sync.py
+++ b/frappe/model/sync.py
@@ -25,14 +25,14 @@ def walk_and_sync(start_path, force=0, sync_everything = False, verbose=False):
"""walk and sync all doctypes and pages"""
modules = []
-
- document_type = ['doctype', 'page', 'report']
+
+ document_type = ['doctype', 'page', 'report', 'print_format']
for path, folders, files in os.walk(start_path):
# sort folders so that doctypes are synced before pages or reports
for dontwalk in (".git", "locale", "public"):
- if dontwalk in folders:
+ if dontwalk in folders:
folders.remove(dontwalk)
folders.sort()
@@ -47,10 +47,10 @@ def walk_and_sync(start_path, force=0, sync_everything = False, verbose=False):
module_name = path.split(os.sep)[-3]
doctype = path.split(os.sep)[-2]
name = path.split(os.sep)[-1]
-
+
if import_file_by_path(os.path.join(path, f), force=force) and verbose:
print module_name + ' | ' + doctype + ' | ' + name
frappe.db.commit()
-
+
return modules
diff --git a/frappe/modules/__init__.py b/frappe/modules/__init__.py
index 50950de9dc..9f8890c482 100644
--- a/frappe/modules/__init__.py
+++ b/frappe/modules/__init__.py
@@ -1,5 +1,5 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
-# MIT License. See license.txt
+# MIT License. See license.txt
from __future__ import unicode_literals
"""
@@ -8,12 +8,12 @@ from __future__ import unicode_literals
import frappe, os
import frappe.utils
-lower_case_files_for = ['DocType', 'Page', 'Report',
- "Workflow", 'Module Def', 'Desktop Item', 'Workflow State', 'Workflow Action']
+lower_case_files_for = ['DocType', 'Page', 'Report',
+ "Workflow", 'Module Def', 'Desktop Item', 'Workflow State', 'Workflow Action', 'Print Format']
def scrub(txt):
return frappe.scrub(txt)
-
+
def scrub_dt_dn(dt, dn):
"""Returns in lowercase and code friendly names of doctype and name for certain types"""
ndt, ndn = dt, dn
@@ -21,11 +21,11 @@ def scrub_dt_dn(dt, dn):
ndt, ndn = scrub(dt), scrub(dn)
return ndt, ndn
-
+
def get_module_path(module):
"""Returns path of the given module"""
return frappe.get_module_path(module)
-
+
def get_doc_path(module, doctype, name):
dt, dn = scrub_dt_dn(doctype, name)
return os.path.join(get_module_path(module), dt, dn)
@@ -48,9 +48,9 @@ def load_doctype_module(doctype, module=None, prefix=""):
if not module:
module = get_doctype_module(doctype)
return frappe.get_module(get_module_name(doctype, module, prefix))
-
+
def get_module_name(doctype, module, prefix=""):
from frappe.modules import scrub
return '{app}.{module}.doctype.{doctype}.{prefix}{doctype}'.format(\
- app = scrub(frappe.local.module_app[scrub(module)]),
+ app = scrub(frappe.local.module_app[scrub(module)]),
module = scrub(module), doctype = scrub(doctype), prefix=prefix)
diff --git a/frappe/modules/import_file.py b/frappe/modules/import_file.py
index 9c3a90ddae..87db8652aa 100644
--- a/frappe/modules/import_file.py
+++ b/frappe/modules/import_file.py
@@ -47,11 +47,11 @@ def import_file_by_path(path, force=False):
original_modified = doc.get("modified")
- import_doc(doc)
+ import_doc(doc, force=force)
if original_modified:
# since there is a new timestamp on the file, update timestamp in
- if doc["doctype"] == doc["name"]:
+ if doc["doctype"] == doc["name"] and doc["name"]!="DocType":
frappe.db.sql("""update tabSingles set value=%s where field="modified" and doctype=%s""",
(original_modified, doc["name"]))
else:
@@ -78,7 +78,7 @@ ignore_values = {
ignore_doctypes = ["Page Role", "DocPerm"]
-def import_doc(docdict):
+def import_doc(docdict, force=False):
docdict["__islocal"] = 1
doc = frappe.get_doc(docdict)
@@ -87,14 +87,14 @@ def import_doc(docdict):
if frappe.db.exists(doc.doctype, doc.name):
old_doc = frappe.get_doc(doc.doctype, doc.name)
- if doc.doctype in ignore_values:
+ if doc.doctype in ignore_values and not force:
# update ignore values
for key in ignore_values.get(doc.doctype) or []:
doc.set(key, old_doc.get(key))
# update ignored docs into new doc
for df in doc.meta.get_table_fields():
- if df.options in ignore_doctypes:
+ if df.options in ignore_doctypes and not force:
doc.set(df.fieldname, [])
ignore.append(df.options)
diff --git a/frappe/modules/patch_handler.py b/frappe/modules/patch_handler.py
index bd2b18941f..e7dbd01ff5 100644
--- a/frappe/modules/patch_handler.py
+++ b/frappe/modules/patch_handler.py
@@ -1,15 +1,15 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
-# MIT License. See license.txt
+# MIT License. See license.txt
from __future__ import unicode_literals
"""
Execute Patch Files
To run directly
-
+
python lib/wnf.py patch patch1, patch2 etc
python lib/wnf.py patch -f patch1, patch2 etc
-
+
where patch1, patch2 is module name
"""
import frappe, os
@@ -19,21 +19,21 @@ class PatchError(Exception): pass
def run_all():
"""run all pending patches"""
executed = [p[0] for p in frappe.db.sql("""select patch from `tabPatch Log`""")]
-
+
for patch in get_all_patches():
if patch and (patch not in executed):
if not run_single(patchmodule = patch):
log(patch + ': failed: STOPPED')
raise PatchError(patch)
-
+
def get_all_patches():
patches = []
for app in frappe.get_installed_apps():
# 3-to-4 fix
- if app=="webnotes":
+ if app=="webnotes":
app="frappe"
patches.extend(frappe.get_file_items(frappe.get_pymodule_path(app, "patches.txt")))
-
+
return patches
def reload_doc(args):
@@ -42,22 +42,23 @@ def reload_doc(args):
def run_single(patchmodule=None, method=None, methodargs=None, force=False):
from frappe import conf
-
+
# don't write txt files
conf.developer_mode = 0
-
+
if force or method or not executed(patchmodule):
return execute_patch(patchmodule, method, methodargs)
else:
return True
-
+
def execute_patch(patchmodule, method=None, methodargs=None):
"""execute the patch"""
success = False
block_user(True)
frappe.db.begin()
try:
- log('Executing %s in %s' % (patchmodule or str(methodargs), frappe.db.cur_db_name))
+ log('Executing {patch} in {site} ({db})'.format(patch=patchmodule or str(methodargs),
+ site=frappe.local.site, db=frappe.db.cur_db_name))
if patchmodule:
if patchmodule.startswith("execute:"):
exec patchmodule.split("execute:")[1] in globals()
@@ -66,66 +67,43 @@ def execute_patch(patchmodule, method=None, methodargs=None):
update_patch_log(patchmodule)
elif method:
method(**methodargs)
-
+
frappe.db.commit()
success = True
except Exception, e:
frappe.db.rollback()
tb = frappe.get_traceback()
log(tb)
- import os
- if frappe.request:
- add_to_patch_log(tb)
block_user(False)
if success:
log('Success')
return success
-def add_to_patch_log(tb):
- """add error log to patches/patch.log"""
- import conf, os
- # TODO use get_site_base_path
- with open(os.path.join(os.path.dirname(conf.__file__), 'app', 'patches','patch.log'),'a') as patchlog:
- patchlog.write('\n\n' + tb)
-
def update_patch_log(patchmodule):
- """update patch_file in patch log"""
- if frappe.db.table_exists("__PatchLog"):
- frappe.db.sql("""INSERT INTO `__PatchLog` VALUES (%s, now())""", \
- patchmodule)
- else:
- frappe.get_doc({"doctype": "Patch Log", "patch": patchmodule}).insert()
+ """update patch_file in patch log"""
+ frappe.get_doc({"doctype": "Patch Log", "patch": patchmodule}).insert()
def executed(patchmodule):
"""return True if is executed"""
- if frappe.db.table_exists("__PatchLog"):
- done = frappe.db.sql("""select patch from __PatchLog where patch=%s""", patchmodule)
- else:
- done = frappe.db.get_value("Patch Log", {"patch": patchmodule})
- if done:
- print "Patch %s already executed in %s" % (patchmodule, frappe.db.cur_db_name)
+ done = frappe.db.get_value("Patch Log", {"patch": patchmodule})
+ # if done:
+ # print "Patch %s already executed in %s" % (patchmodule, frappe.db.cur_db_name)
return done
-
+
def block_user(block):
"""stop/start execution till patch is run"""
+ frappe.local.flags.in_patch = block
frappe.db.begin()
msg = "Patches are being executed in the system. Please try again in a few moments."
frappe.db.set_global('__session_status', block and 'stop' or None)
frappe.db.set_global('__session_status_message', block and msg or None)
frappe.db.commit()
-
+
def check_session_stopped():
if frappe.db.get_global("__session_status")=='stop':
frappe.msgprint(frappe.db.get_global("__session_status_message"))
raise frappe.SessionStopped('Session Stopped')
-def setup():
- frappe.db.sql("""CREATE TABLE IF NOT EXISTS `__PatchLog` (
- patch TEXT, applied_on DATETIME) engine=InnoDB""")
-
def log(msg):
- if getattr(frappe.local, "patch_log_list", None) is None:
- frappe.local.patch_log_list = []
-
- frappe.local.patch_log_list.append(msg)
+ print msg
diff --git a/frappe/patches.txt b/frappe/patches.txt
index e424ab761a..3c8dbd23bd 100644
--- a/frappe/patches.txt
+++ b/frappe/patches.txt
@@ -1,5 +1,6 @@
execute:import inlinestyler # new requirement
+execute:frappe.db.sql("""update `tabPatch Log` set patch=replace(patch, '.4_0.', '.v4_0.')""") #2014-05-12
execute:frappe.reload_doc('core', 'doctype', 'doctype', force=True) #2014-01-24
execute:frappe.reload_doc('core', 'doctype', 'docfield', force=True) #2014-03-01
execute:frappe.reload_doc('core', 'doctype', 'docperm') #2013-13-26
@@ -8,21 +9,24 @@ execute:frappe.reload_doc('core', 'doctype', 'report') #2013-13-26
execute:frappe.reload_doc('core', 'doctype', 'version') #2014-02-21
execute:frappe.db.sql("alter table `tabSessions` modify `user` varchar(255), engine=InnoDB")
-frappe.patches.4_0.remove_index_sitemap
-frappe.patches.4_0.add_delete_permission
-frappe.patches.4_0.move_match_to_restricted
-frappe.patches.4_0.set_todo_checked_as_closed
-frappe.patches.4_0.website_sitemap_hierarchy
-frappe.patches.4_0.webnotes_to_frappe
+frappe.patches.v4_0.remove_old_parent
+frappe.patches.v4_0.remove_index_sitemap
+frappe.patches.v4_0.add_delete_permission
+frappe.patches.v4_0.move_match_to_restricted
+frappe.patches.v4_0.set_todo_checked_as_closed
+frappe.patches.v4_0.website_sitemap_hierarchy
+frappe.patches.v4_0.webnotes_to_frappe
execute:frappe.reset_perms("Module Def")
-frappe.patches.4_0.rename_sitemap_to_route
-frappe.patches.4_0.rename_profile_to_user
-frappe.patches.4_0.set_website_route_idx
+frappe.patches.v4_0.rename_sitemap_to_route
+frappe.patches.v4_0.rename_profile_to_user
+frappe.patches.v4_0.set_website_route_idx
execute:import frappe.installer;frappe.installer.make_site_dirs() #2014-02-19
-frappe.patches.4_0.private_backups
-frappe.patches.4_0.set_module_in_report
-frappe.patches.4_0.remove_old_parent
-frappe.patches.4_0.update_datetime
-frappe.patches.4_0.deprecate_control_panel
-frappe.patches.4_0.file_manager_hooks
+frappe.patches.v4_0.private_backups
+frappe.patches.v4_0.set_module_in_report
+frappe.patches.v4_0.update_datetime
+frappe.patches.v4_0.deprecate_control_panel
+frappe.patches.v4_0.file_manager_hooks
execute:frappe.get_doc("User", "Guest").save()
+frappe.patches.v4_0.deprecate_link_selects
+frappe.patches.v4_0.set_user_gravatar
+frappe.patches.v4_0.update_custom_field_insert_after
diff --git a/frappe/patches/4_0/__init__.py b/frappe/patches/v4_0/__init__.py
similarity index 100%
rename from frappe/patches/4_0/__init__.py
rename to frappe/patches/v4_0/__init__.py
diff --git a/frappe/patches/4_0/add_delete_permission.py b/frappe/patches/v4_0/add_delete_permission.py
similarity index 100%
rename from frappe/patches/4_0/add_delete_permission.py
rename to frappe/patches/v4_0/add_delete_permission.py
diff --git a/frappe/patches/4_0/deprecate_control_panel.py b/frappe/patches/v4_0/deprecate_control_panel.py
similarity index 100%
rename from frappe/patches/4_0/deprecate_control_panel.py
rename to frappe/patches/v4_0/deprecate_control_panel.py
diff --git a/frappe/patches/v4_0/deprecate_link_selects.py b/frappe/patches/v4_0/deprecate_link_selects.py
new file mode 100644
index 0000000000..317333b019
--- /dev/null
+++ b/frappe/patches/v4_0/deprecate_link_selects.py
@@ -0,0 +1,13 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ for name in frappe.db.sql_list("""select name from `tabCustom Field`
+ where fieldtype="Select" and options like "link:%" """):
+ custom_field = frappe.get_doc("Custom Field", name)
+ custom_field.fieldtype = "Link"
+ custom_field.options = custom_field.options[5:]
+ custom_field.save()
diff --git a/frappe/patches/4_0/file_manager_hooks.py b/frappe/patches/v4_0/file_manager_hooks.py
similarity index 72%
rename from frappe/patches/4_0/file_manager_hooks.py
rename to frappe/patches/v4_0/file_manager_hooks.py
index 5c72e62da3..ef043d4d31 100644
--- a/frappe/patches/4_0/file_manager_hooks.py
+++ b/frappe/patches/v4_0/file_manager_hooks.py
@@ -21,7 +21,16 @@ def execute():
b.file_url = os.path.normpath('/' + old_file_name)
else:
b.file_url = os.path.normpath('/files/' + old_file_name)
- _file_name, content = get_file(name)
- b.content_hash = get_content_hash(content)
- b.save()
+ try:
+ _file_name, content = get_file(name)
+ b.content_hash = get_content_hash(content)
+ except IOError:
+ print 'Warning: Error processing ', name
+ _file_name = old_file_name
+ b.content_hash = None
+
+ try:
+ b.save()
+ except frappe.DuplicateEntryError:
+ frappe.delete_doc(b.doctype, b.name)
diff --git a/frappe/patches/4_0/move_match_to_restricted.py b/frappe/patches/v4_0/move_match_to_restricted.py
similarity index 100%
rename from frappe/patches/4_0/move_match_to_restricted.py
rename to frappe/patches/v4_0/move_match_to_restricted.py
diff --git a/frappe/patches/4_0/private_backups.py b/frappe/patches/v4_0/private_backups.py
similarity index 100%
rename from frappe/patches/4_0/private_backups.py
rename to frappe/patches/v4_0/private_backups.py
diff --git a/frappe/patches/4_0/remove_index_sitemap.py b/frappe/patches/v4_0/remove_index_sitemap.py
similarity index 100%
rename from frappe/patches/4_0/remove_index_sitemap.py
rename to frappe/patches/v4_0/remove_index_sitemap.py
diff --git a/frappe/patches/4_0/remove_old_parent.py b/frappe/patches/v4_0/remove_old_parent.py
similarity index 84%
rename from frappe/patches/4_0/remove_old_parent.py
rename to frappe/patches/v4_0/remove_old_parent.py
index 7c738f43f4..588cda9121 100644
--- a/frappe/patches/4_0/remove_old_parent.py
+++ b/frappe/patches/v4_0/remove_old_parent.py
@@ -7,3 +7,4 @@ import frappe
def execute():
for doctype in frappe.db.sql_list("""select name from `tabDocType` where istable=1"""):
frappe.db.sql("""delete from `tab{0}` where parent like "old_par%:%" """.format(doctype))
+ frappe.db.sql("""delete from `tabDocField` where parent="0" """)
diff --git a/frappe/patches/4_0/rename_profile_to_user.py b/frappe/patches/v4_0/rename_profile_to_user.py
similarity index 100%
rename from frappe/patches/4_0/rename_profile_to_user.py
rename to frappe/patches/v4_0/rename_profile_to_user.py
diff --git a/frappe/patches/4_0/rename_sitemap_to_route.py b/frappe/patches/v4_0/rename_sitemap_to_route.py
similarity index 100%
rename from frappe/patches/4_0/rename_sitemap_to_route.py
rename to frappe/patches/v4_0/rename_sitemap_to_route.py
diff --git a/frappe/patches/4_0/set_module_in_report.py b/frappe/patches/v4_0/set_module_in_report.py
similarity index 100%
rename from frappe/patches/4_0/set_module_in_report.py
rename to frappe/patches/v4_0/set_module_in_report.py
diff --git a/frappe/patches/4_0/set_todo_checked_as_closed.py b/frappe/patches/v4_0/set_todo_checked_as_closed.py
similarity index 100%
rename from frappe/patches/4_0/set_todo_checked_as_closed.py
rename to frappe/patches/v4_0/set_todo_checked_as_closed.py
diff --git a/frappe/patches/v4_0/set_user_gravatar.py b/frappe/patches/v4_0/set_user_gravatar.py
new file mode 100644
index 0000000000..78bd72f4dc
--- /dev/null
+++ b/frappe/patches/v4_0/set_user_gravatar.py
@@ -0,0 +1,11 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ for name in frappe.db.sql_list("select name from `tabUser` where ifnull(user_image, '')=''"):
+ user = frappe.get_doc("User", name)
+ user.update_gravatar()
+ user.db_set("user_image", user.user_image)
diff --git a/frappe/patches/4_0/set_website_route_idx.py b/frappe/patches/v4_0/set_website_route_idx.py
similarity index 100%
rename from frappe/patches/4_0/set_website_route_idx.py
rename to frappe/patches/v4_0/set_website_route_idx.py
diff --git a/frappe/patches/v4_0/update_custom_field_insert_after.py b/frappe/patches/v4_0/update_custom_field_insert_after.py
new file mode 100644
index 0000000000..0e820cd0e3
--- /dev/null
+++ b/frappe/patches/v4_0/update_custom_field_insert_after.py
@@ -0,0 +1,18 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ for d in frappe.db.sql("""select name, dt, insert_after from `tabCustom Field`
+ where docstatus < 2""", as_dict=1):
+ dt_meta = frappe.get_meta(d.dt)
+ if not dt_meta.get_field(d.insert_after):
+ cf = frappe.get_doc("Custom Field", d.name)
+ df = dt_meta.get("fields", {"label": d.insert_after})
+ if df:
+ cf.insert_after = df[0].fieldname
+ else:
+ cf.insert_after = None
+ cf.save()
diff --git a/frappe/patches/4_0/update_datetime.py b/frappe/patches/v4_0/update_datetime.py
similarity index 100%
rename from frappe/patches/4_0/update_datetime.py
rename to frappe/patches/v4_0/update_datetime.py
diff --git a/frappe/patches/4_0/webnotes_to_frappe.py b/frappe/patches/v4_0/webnotes_to_frappe.py
similarity index 100%
rename from frappe/patches/4_0/webnotes_to_frappe.py
rename to frappe/patches/v4_0/webnotes_to_frappe.py
diff --git a/frappe/patches/4_0/website_sitemap_hierarchy.py b/frappe/patches/v4_0/website_sitemap_hierarchy.py
similarity index 100%
rename from frappe/patches/4_0/website_sitemap_hierarchy.py
rename to frappe/patches/v4_0/website_sitemap_hierarchy.py
diff --git a/frappe/permissions.py b/frappe/permissions.py
index 0663e11f8f..466318cd4f 100644
--- a/frappe/permissions.py
+++ b/frappe/permissions.py
@@ -71,11 +71,12 @@ def has_unrestricted_access(doc, verbose=True):
restrictions = get_restrictions()
meta = frappe.get_meta(doc.get("doctype"))
+ user_perms = get_user_perms(meta)
if get_user_perms(meta).restricted:
if doc.owner == frappe.session.user:
# owner is always allowed for restricted permissions
return True
- elif not restrictions:
+ elif not (restrictions and restrictions.get(doc.get("doctype"))):
return False
else:
if not restrictions:
diff --git a/frappe/public/css/desk.css b/frappe/public/css/desk.css
index 0ed2b89c01..4668115949 100644
--- a/frappe/public/css/desk.css
+++ b/frappe/public/css/desk.css
@@ -106,6 +106,10 @@ div#freeze {
/*margin-top: -15px;*/
}
+.form-control {
+ padding: 6px 8px;
+}
+
.form-headline {
margin-bottom: 10px;
font-size: 120%;
diff --git a/frappe/public/js/frappe/form/assign_to.js b/frappe/public/js/frappe/form/assign_to.js
index dac6ebd85b..6bf24bdd76 100644
--- a/frappe/public/js/frappe/form/assign_to.js
+++ b/frappe/public/js/frappe/form/assign_to.js
@@ -1,5 +1,5 @@
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
-// MIT License. See license.txt
+// MIT License. See license.txt
// assign to is lined to todo
// refresh - load todos
@@ -15,9 +15,9 @@ frappe.ui.form.AssignTo = Class.extend({
this.wrapper = $('
{%- block banner -%}
+ {% include "templates/includes/banner_extension.html" ignore missing %}
{% if banner_html -%}
{{ banner_html or "" }}
{%- endif %}
@@ -92,6 +89,10 @@ https://frappe.io/apps/frappe
{%- block footer -%}{% include "templates/includes/footer.html" %}{%- endblock -%}
+ {%- for link in web_include_js %}
+
+ {%- endfor -%}
+
{%- block script %}
+
diff --git a/frappe/templates/pages/about.html b/frappe/templates/pages/about.html
index e1242c86e5..77ba712e17 100644
--- a/frappe/templates/pages/about.html
+++ b/frappe/templates/pages/about.html
@@ -2,27 +2,27 @@
{% block content %}
- {{ obj.doc.company_introduction or """
Some Introduction about your company that you would
- like your website visitor to know.
- More people than you think will read your About page.
- People always like to know who the are doing business with.
- Be authentic and avoid using jargon like 'value added services' etc.
- Be sure to update your company history and
+ {{ doc.company_introduction or """
Some Introduction about your company that you would
+ like your website visitor to know.
+ More people than you think will read your About page.
+ People always like to know who the are doing business with.
+ Be authentic and avoid using jargon like 'value added services' etc.
+ Be sure to update your company history and
list of key team members in Website > About Us Settings
""" }}
-
- {% if obj.get({"doctype":"Company History"}) %}
-
{{ obj.doc.company_history_heading or "Company History" }}
- {% for d in obj.get({"doctype":"Company History"}) %}
+
+ {% if doc.get({"doctype":"Company History"}) %}
+
{{ doc.company_history_heading or "Company History" }}
+ {% for d in doc.get({"doctype":"Company History"}) %}
{{ d.year }}
{{ d.highlight }}
{% endfor %}
{% endif %}
-
- {% if obj.get({"doctype":"About Us Team Member"}) %}
-
{{ obj.doc.team_members_heading or "Team Members" }}
- {% for d in obj.get({"doctype":"About Us Team Member"}) %}
+
+ {% if doc.get({"doctype":"About Us Team Member"}) %}
+
{{ doc.team_members_heading or "Team Members" }}
+ {% for d in doc.get({"doctype":"About Us Team Member"}) %}
@@ -35,6 +35,6 @@
{% endfor %}
{% endif %}
- {{ obj.doc.footer or "" }}
+ {{ doc.footer or "" }}
{% endblock %}
diff --git a/frappe/templates/pages/about.py b/frappe/templates/pages/about.py
index 13554fe53b..b693a703c4 100644
--- a/frappe/templates/pages/about.py
+++ b/frappe/templates/pages/about.py
@@ -1,8 +1,8 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
-# MIT License. See license.txt
+# MIT License. See license.txt
from __future__ import unicode_literals
import frappe
def get_context(context):
- return { "obj": frappe.get_doc("About Us Settings", "About Us Settings") }
+ return { "doc": frappe.get_doc("About Us Settings", "About Us Settings") }
diff --git a/frappe/templates/pages/contact.html b/frappe/templates/pages/contact.html
index 9df1b84337..6b09f0d3f2 100644
--- a/frappe/templates/pages/contact.html
+++ b/frappe/templates/pages/contact.html
@@ -1,15 +1,17 @@
{% block title %}{{ heading or "Contact Us"}}{% endblock %}
{% block content %}
+
-
+
-
@@ -53,9 +55,8 @@
{% endif %}
- {{ introduction or ""}}
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/frappe/templates/pages/list.html b/frappe/templates/pages/list.html
new file mode 100644
index 0000000000..11a5b15512
--- /dev/null
+++ b/frappe/templates/pages/list.html
@@ -0,0 +1,84 @@
+{% block title %}{{ type }} {{ _("List") }}{% endblock %}
+
+{% block header %}
+
",
+A user can be restricted to multiple records of the same type.,ಬಳಕೆದಾರ ಅದೇ ರೀತಿಯ ಅನೇಕ ದಾಖಲೆಗಳನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ ಮಾಡಬಹುದು .
+About,ಕುರಿತು
+About Us Settings,ನಮ್ಮ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಬಗ್ಗೆ
+About Us Team Member,ನಮ್ಮ ತಂಡದ ಸದಸ್ಯರು ಬಗ್ಗೆ
+Action,ಕ್ರಿಯೆ
+Actions,ಕ್ರಿಯೆಗಳು
+"Actions for workflow (e.g. Approve, Cancel).","ಕೆಲಸದೊತ್ತಡದ ಕ್ರಿಯೆಗಳು ( ಇ ಜಿ ಅನುಮೋದಿಸಿ , ರದ್ದು ) ."
+Add,ಸೇರಿಸು
+Add A New Rule,ಹೊಸ ನಿಯಮ ಸೇರಿಸಿ
+Add A Restriction,ನಿರ್ಬಂಧದ ಸೇರಿಸಿ
+Add Attachments,ಲಗತ್ತುಗಳನ್ನು ಸೇರಿಸಿ
+Add Bookmark,ಸೇರಿಸಿ ಬುಕ್ಮಾರ್ಕ್
+Add CSS,ಸಿಎಸ್ಎಸ್ ಸೇರಿಸಿ
+Add Column,ಅಂಕಣ ಸೇರಿಸಿ
+Add Google Analytics ID: eg. UA-89XXX57-1. Please search help on Google Analytics for more information.,ಗೂಗಲ್ ಅನಾಲಿಟಿಕ್ಸ್ ID ಸೇರಿಸಿ : ಯುಎ ಉದಾ 89XXX57 - 1 . . ಹೆಚ್ಚಿನ ಮಾಹಿತಿಗಾಗಿ ಗೂಗಲ್ ಅನಾಲಿಟಿಕ್ಸ್ ಸಹಾಯ ಹುಡುಕಲು ದಯವಿಟ್ಟು .
+Add Message,ಸಂದೇಶ ಸೇರಿಸಿ
+Add New Permission Rule,ಒಂದು ಹೊಸ ಅನುಮತಿ ರೂಲ್ ಸೇರಿಸಿ
+Add Reply,ಉತ್ತರಿಸಿ ಸೇರಿಸಿ
+Add Serial No,ಸೀರಿಯಲ್ ನಂ ಸೇರಿಸಿ
+Add This To User's Restrictions,ಬಳಕೆದಾರರ ನಿರ್ಬಂಧಗಳು ಈ ಸೇರಿಸಿ
+Add Total Row,ಒಟ್ಟು ರೋ ಸೇರಿಸಿ
+Add a New Role,ಹೊಸ ಪಾತ್ರ ಸೇರಿಸಿ
+Add a banner to the site. (small banners are usually good),ಸೈಟ್ ಒಂದು ಬ್ಯಾನರ್ ಸೇರಿಸಿ . ( ಸಣ್ಣ ಬ್ಯಾನರ್ ಸಾಮಾನ್ಯವಾಗಿ ಉತ್ತಮ )
+Add all roles,ಎಲ್ಲಾ ಪಾತ್ರಗಳನ್ನು ಸೇರಿಸಿ
+Add attachment,ಲಗತ್ತು ಸೇರಿಸಿ
+Add code as <script>,