@@ -81,6 +81,12 @@ def application(request): | |||||
frappe.db.commit() | frappe.db.commit() | ||||
rollback = False | rollback = False | ||||
# update session | |||||
if getattr(frappe.local, "session_obj", None): | |||||
updated_in_db = frappe.local.session_obj.update() | |||||
if updated_in_db: | |||||
frappe.db.commit() | |||||
finally: | finally: | ||||
if frappe.local.request.method in ("POST", "PUT") and frappe.db and rollback: | if frappe.local.request.method in ("POST", "PUT") and frappe.db and rollback: | ||||
frappe.db.rollback() | frappe.db.rollback() | ||||
@@ -121,6 +121,11 @@ def get_data(): | |||||
"name": "Outgoing Email Settings", | "name": "Outgoing Email Settings", | ||||
"description": _("Set outgoing mail server.") | "description": _("Set outgoing mail server.") | ||||
}, | }, | ||||
{ | |||||
"type": "doctype", | |||||
"name": "Standard Reply", | |||||
"description": _("Standard replies to common queries.") | |||||
}, | |||||
] | ] | ||||
}, | }, | ||||
{ | { | ||||
@@ -1,6 +1,6 @@ | |||||
{ | { | ||||
"autoname": "CustomScript.####", | "autoname": "CustomScript.####", | ||||
"creation": "2013-01-10 16:34:01.000000", | |||||
"creation": "2013-01-10 16:34:01", | |||||
"description": "Adds a custom script (client or server) to a DocType", | "description": "Adds a custom script (client or server) to a DocType", | ||||
"docstatus": 0, | "docstatus": 0, | ||||
"doctype": "DocType", | "doctype": "DocType", | ||||
@@ -8,6 +8,7 @@ | |||||
{ | { | ||||
"fieldname": "dt", | "fieldname": "dt", | ||||
"fieldtype": "Link", | "fieldtype": "Link", | ||||
"in_list_view": 1, | |||||
"label": "DocType", | "label": "DocType", | ||||
"oldfieldname": "dt", | "oldfieldname": "dt", | ||||
"oldfieldtype": "Link", | "oldfieldtype": "Link", | ||||
@@ -19,6 +20,7 @@ | |||||
"fieldname": "script_type", | "fieldname": "script_type", | ||||
"fieldtype": "Select", | "fieldtype": "Select", | ||||
"hidden": 1, | "hidden": 1, | ||||
"in_list_view": 1, | |||||
"label": "Script Type", | "label": "Script Type", | ||||
"oldfieldname": "script_type", | "oldfieldname": "script_type", | ||||
"oldfieldtype": "Select", | "oldfieldtype": "Select", | ||||
@@ -29,16 +31,24 @@ | |||||
{ | { | ||||
"fieldname": "script", | "fieldname": "script", | ||||
"fieldtype": "Code", | "fieldtype": "Code", | ||||
"in_list_view": 1, | |||||
"label": "Script", | "label": "Script", | ||||
"oldfieldname": "script", | "oldfieldname": "script", | ||||
"oldfieldtype": "Code", | "oldfieldtype": "Code", | ||||
"options": "Script", | "options": "Script", | ||||
"permlevel": 0 | "permlevel": 0 | ||||
}, | |||||
{ | |||||
"fieldname": "sample", | |||||
"fieldtype": "HTML", | |||||
"label": "Sample", | |||||
"options": "<h3>Custom Script Help</h3>\n<p>Custom Scripts are executed only on the client-side (i.e. in Forms). Here are some examples to get you started</p>\n<pre><code>\n// additional validation on dates\ncur_frm.cscript.custom_validate = function(doc) {\n if (doc.from_date < get_today()) {\n msgprint(\"You can not select past date in From Date\");\n validated = false;\n }\n}\n\n// make a field read-only after saving\ncur_frm.cscript.custom_refresh = function(doc) {\n // use the __islocal value of doc, to check if the doc is saved or not\n cur_frm.set_df_property(\"myfield\", \"read_only\", doc.__islocal ? 0 : 1);\n}\n\n// addtional permission checking\ncur_frm.cscript.custom_validate = function(doc) {\n if(user==\"user1@example.com\" && doc.purpose!=\"Material Receipt\") {\n msgprint(\"You are only allowed Material Receipt\");\n validated = false;\n }\n}\n\n// calculate sales incentive\ncur_frm.cscript.custom_validate = function(doc) {\n // calculate incentives for each person on the deal\n total_incentive = 0\n $.each(wn.model.get(\"Sales Team\", {parent:doc.name}), function(i, d) {\n\n // calculate incentive\n var incentive_percent = 2;\n if(doc.grand_total > 400) incentive_percent = 4;\n\n // actual incentive\n d.incentives = flt(doc.grand_total) * incentive_percent / 100;\n total_incentive += flt(d.incentives)\n });\n\n doc.total_incentive = total_incentive;\n}\n</code>\n</pre>", | |||||
"permlevel": 0 | |||||
} | } | ||||
], | ], | ||||
"icon": "icon-glass", | "icon": "icon-glass", | ||||
"idx": 1, | "idx": 1, | ||||
"modified": "2014-01-20 17:48:31.000000", | |||||
"modified": "2014-06-19 06:55:02.522204", | |||||
"modified_by": "Administrator", | "modified_by": "Administrator", | ||||
"module": "Core", | "module": "Core", | ||||
"name": "Custom Script", | "name": "Custom Script", | ||||
@@ -41,7 +41,7 @@ class DocType(Document): | |||||
frappe.db.sql('UPDATE tabDocType SET modified=%s WHERE `name`=%s', (now(), p[0])) | frappe.db.sql('UPDATE tabDocType SET modified=%s WHERE `name`=%s', (now(), p[0])) | ||||
def scrub_field_names(self): | def scrub_field_names(self): | ||||
restricted = ('name','parent','idx','owner','creation','modified','modified_by', | |||||
restricted = ('name','parent','creation','modified','modified_by', | |||||
'parentfield','parenttype',"file_list") | 'parentfield','parenttype',"file_list") | ||||
for d in self.get("fields"): | for d in self.get("fields"): | ||||
if d.fieldtype: | if d.fieldtype: | ||||
@@ -0,0 +1,71 @@ | |||||
{ | |||||
"allow_import": 1, | |||||
"autoname": "field:subject", | |||||
"creation": "2014-06-19 05:20:26.331041", | |||||
"docstatus": 0, | |||||
"doctype": "DocType", | |||||
"document_type": "Transaction", | |||||
"fields": [ | |||||
{ | |||||
"fieldname": "subject", | |||||
"fieldtype": "Data", | |||||
"in_list_view": 1, | |||||
"label": "Subject", | |||||
"permlevel": 0, | |||||
"reqd": 1 | |||||
}, | |||||
{ | |||||
"fieldname": "response", | |||||
"fieldtype": "Text Editor", | |||||
"in_list_view": 1, | |||||
"label": "Response", | |||||
"permlevel": 0, | |||||
"reqd": 1 | |||||
}, | |||||
{ | |||||
"default": "user", | |||||
"fieldname": "owner", | |||||
"fieldtype": "Link", | |||||
"hidden": 1, | |||||
"label": "Owner", | |||||
"options": "User", | |||||
"permlevel": 0 | |||||
} | |||||
], | |||||
"icon": "icon-comment", | |||||
"modified": "2014-06-19 05:45:09.855045", | |||||
"modified_by": "Administrator", | |||||
"module": "Core", | |||||
"name": "Standard Reply", | |||||
"name_case": "", | |||||
"owner": "Administrator", | |||||
"permissions": [ | |||||
{ | |||||
"permlevel": 0, | |||||
"read": 1, | |||||
"role": "All" | |||||
}, | |||||
{ | |||||
"apply_user_permissions": 1, | |||||
"create": 1, | |||||
"permlevel": 0, | |||||
"read": 1, | |||||
"role": "All", | |||||
"write": 1 | |||||
}, | |||||
{ | |||||
"create": 1, | |||||
"delete": 1, | |||||
"email": 1, | |||||
"export": 1, | |||||
"import": 1, | |||||
"permlevel": 0, | |||||
"read": 1, | |||||
"report": 1, | |||||
"role": "System Manager", | |||||
"write": 1 | |||||
} | |||||
], | |||||
"sort_field": "modified", | |||||
"sort_order": "DESC" | |||||
} |
@@ -0,0 +1,9 @@ | |||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||||
# For license information, please see license.txt | |||||
from __future__ import unicode_literals | |||||
import frappe | |||||
from frappe.model.document import Document | |||||
class StandardReply(Document): | |||||
pass |
@@ -1,100 +1,100 @@ | |||||
{ | { | ||||
"creation": "2014-04-17 16:53:52.640856", | |||||
"docstatus": 0, | |||||
"doctype": "DocType", | |||||
"document_type": "System", | |||||
"creation": "2014-04-17 16:53:52.640856", | |||||
"docstatus": 0, | |||||
"doctype": "DocType", | |||||
"document_type": "System", | |||||
"fields": [ | "fields": [ | ||||
{ | { | ||||
"fieldname": "localization", | |||||
"fieldtype": "Section Break", | |||||
"label": "Localization", | |||||
"fieldname": "localization", | |||||
"fieldtype": "Section Break", | |||||
"label": "Localization", | |||||
"permlevel": 0 | "permlevel": 0 | ||||
}, | |||||
}, | |||||
{ | { | ||||
"fieldname": "language", | |||||
"fieldtype": "Select", | |||||
"in_list_view": 1, | |||||
"label": "Language", | |||||
"options": "Loading...", | |||||
"permlevel": 0, | |||||
"reqd": 1, | |||||
"fieldname": "language", | |||||
"fieldtype": "Select", | |||||
"in_list_view": 1, | |||||
"label": "Language", | |||||
"options": "Loading...", | |||||
"permlevel": 0, | |||||
"reqd": 1, | |||||
"search_index": 0 | "search_index": 0 | ||||
}, | |||||
}, | |||||
{ | { | ||||
"fieldname": "time_zone", | |||||
"fieldtype": "Select", | |||||
"label": "Time Zone", | |||||
"permlevel": 0, | |||||
"fieldname": "time_zone", | |||||
"fieldtype": "Select", | |||||
"label": "Time Zone", | |||||
"permlevel": 0, | |||||
"reqd": 1 | "reqd": 1 | ||||
}, | |||||
}, | |||||
{ | { | ||||
"fieldname": "date_and_number_format", | |||||
"fieldtype": "Section Break", | |||||
"label": "Date and Number Format", | |||||
"fieldname": "date_and_number_format", | |||||
"fieldtype": "Section Break", | |||||
"label": "Date and Number Format", | |||||
"permlevel": 0 | "permlevel": 0 | ||||
}, | |||||
}, | |||||
{ | { | ||||
"fieldname": "date_format", | |||||
"fieldtype": "Select", | |||||
"label": "Date Format", | |||||
"options": "yyyy-mm-dd\ndd-mm-yyyy\ndd/mm/yyyy\ndd.mm.yyyy\nmm/dd/yyyy\nmm-dd-yyyy", | |||||
"permlevel": 0, | |||||
"fieldname": "date_format", | |||||
"fieldtype": "Select", | |||||
"label": "Date Format", | |||||
"options": "yyyy-mm-dd\ndd-mm-yyyy\ndd/mm/yyyy\ndd.mm.yyyy\nmm/dd/yyyy\nmm-dd-yyyy", | |||||
"permlevel": 0, | |||||
"reqd": 1 | "reqd": 1 | ||||
}, | |||||
}, | |||||
{ | { | ||||
"fieldname": "number_format", | |||||
"fieldtype": "Select", | |||||
"label": "Number Format", | |||||
"options": "#,###.##\n#.###,##\n# ###.##\n# ###,##\n#,###.###\n#,##,###.##\n#.###\n#,###", | |||||
"permlevel": 0, | |||||
"fieldname": "number_format", | |||||
"fieldtype": "Select", | |||||
"label": "Number Format", | |||||
"options": "#,###.##\n#.###,##\n# ###.##\n# ###,##\n#'###.##\n#, ###.##\n#,##,###.##\n#,###.###\n#.###\n#,###", | |||||
"permlevel": 0, | |||||
"reqd": 1 | "reqd": 1 | ||||
}, | |||||
}, | |||||
{ | { | ||||
"fieldname": "float_precision", | |||||
"fieldtype": "Select", | |||||
"label": "Float Precision", | |||||
"options": "\n2\n3\n4\n5\n6", | |||||
"fieldname": "float_precision", | |||||
"fieldtype": "Select", | |||||
"label": "Float Precision", | |||||
"options": "\n2\n3\n4\n5\n6", | |||||
"permlevel": 0 | "permlevel": 0 | ||||
}, | |||||
}, | |||||
{ | { | ||||
"fieldname": "security", | |||||
"fieldtype": "Section Break", | |||||
"label": "Security", | |||||
"fieldname": "security", | |||||
"fieldtype": "Section Break", | |||||
"label": "Security", | |||||
"permlevel": 0 | "permlevel": 0 | ||||
}, | |||||
}, | |||||
{ | { | ||||
"default": "06:00", | |||||
"description": "Session Expiry in Hours e.g. 06:00", | |||||
"fieldname": "session_expiry", | |||||
"fieldtype": "Data", | |||||
"label": "Session Expiry", | |||||
"options": "", | |||||
"default": "06:00", | |||||
"description": "Session Expiry in Hours e.g. 06:00", | |||||
"fieldname": "session_expiry", | |||||
"fieldtype": "Data", | |||||
"label": "Session Expiry", | |||||
"options": "", | |||||
"permlevel": 0 | "permlevel": 0 | ||||
}, | |||||
}, | |||||
{ | { | ||||
"description": "Run scheduled jobs only if checked", | |||||
"fieldname": "enable_scheduler", | |||||
"fieldtype": "Check", | |||||
"in_list_view": 0, | |||||
"label": "Enable Scheduled Jobs", | |||||
"description": "Run scheduled jobs only if checked", | |||||
"fieldname": "enable_scheduler", | |||||
"fieldtype": "Check", | |||||
"in_list_view": 0, | |||||
"label": "Enable Scheduled Jobs", | |||||
"permlevel": 0 | "permlevel": 0 | ||||
} | } | ||||
], | |||||
"icon": "icon-cog", | |||||
"issingle": 1, | |||||
"modified": "2014-06-02 02:09:03.623094", | |||||
"modified_by": "Administrator", | |||||
"module": "Core", | |||||
"name": "System Settings", | |||||
"name_case": "", | |||||
"owner": "Administrator", | |||||
], | |||||
"icon": "icon-cog", | |||||
"issingle": 1, | |||||
"modified": "2014-06-18 02:09:03.623094", | |||||
"modified_by": "Administrator", | |||||
"module": "Core", | |||||
"name": "System Settings", | |||||
"name_case": "", | |||||
"owner": "Administrator", | |||||
"permissions": [ | "permissions": [ | ||||
{ | { | ||||
"create": 1, | |||||
"permlevel": 0, | |||||
"read": 1, | |||||
"role": "System Manager", | |||||
"create": 1, | |||||
"permlevel": 0, | |||||
"read": 1, | |||||
"role": "System Manager", | |||||
"write": 1 | "write": 1 | ||||
} | } | ||||
] | ] | ||||
} | |||||
} |
@@ -161,7 +161,8 @@ frappe.pages['data-import-tool'].onload = function(wrapper) { | |||||
$("#dit-output").empty(); | $("#dit-output").empty(); | ||||
$.each(r.messages, function(i, v) { | $.each(r.messages, function(i, v) { | ||||
var $p = $('<p>').html(v).appendTo('#dit-output'); | |||||
var $p = $('<p></p>').html(frappe.markdown(v)).appendTo('#dit-output'); | |||||
$("<hr>").appendTo('#dit-output'); | |||||
if(v.substr(0,5)=='Error') { | if(v.substr(0,5)=='Error') { | ||||
$p.css('color', 'red'); | $p.css('color', 'red'); | ||||
} else if(v.substr(0,8)=='Inserted') { | } else if(v.substr(0,8)=='Inserted') { | ||||
@@ -217,7 +217,7 @@ def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, | |||||
error = True | error = True | ||||
if doc: | if doc: | ||||
frappe.errprint(doc if isinstance(doc, dict) else doc.as_dict()) | frappe.errprint(doc if isinstance(doc, dict) else doc.as_dict()) | ||||
err_msg = frappe.local.message_log and "<br>".join(frappe.local.message_log) or cstr(e) | |||||
err_msg = frappe.local.message_log and "\n\n".join(frappe.local.message_log) or cstr(e) | |||||
ret.append('Error for row (#%d) %s : %s' % (row_idx + 1, | ret.append('Error for row (#%d) %s : %s' % (row_idx + 1, | ||||
len(row)>1 and row[1] or "", err_msg)) | len(row)>1 and row[1] or "", err_msg)) | ||||
frappe.errprint(frappe.get_traceback()) | frappe.errprint(frappe.get_traceback()) | ||||
@@ -2556,7 +2556,7 @@ | |||||
"code": "ve", | "code": "ve", | ||||
"number_format": "#,###.##" | "number_format": "#,###.##" | ||||
}, | }, | ||||
"Viet Nam": { | |||||
"Vietnam": { | |||||
"code": "vn", | "code": "vn", | ||||
"currency": "VND", | "currency": "VND", | ||||
"currency_name": "Dong", | "currency_name": "Dong", | ||||
@@ -87,11 +87,6 @@ def execute_cmd(cmd): | |||||
if ret: | if ret: | ||||
frappe.response['message'] = ret | frappe.response['message'] = ret | ||||
# update session | |||||
if "session_obj" in frappe.local: | |||||
frappe.local.session_obj.update() | |||||
def get_attr(cmd): | def get_attr(cmd): | ||||
"""get method object from cmd""" | """get method object from cmd""" | ||||
if '.' in cmd: | if '.' in cmd: | ||||
@@ -13,6 +13,7 @@ class BaseDocument(object): | |||||
def __init__(self, d): | def __init__(self, d): | ||||
self.update(d) | self.update(d) | ||||
self.dont_update_if_missing = [] | |||||
@property | @property | ||||
def meta(self): | def meta(self): | ||||
@@ -42,7 +43,8 @@ class BaseDocument(object): | |||||
if "doctype" in d: | if "doctype" in d: | ||||
self.set("doctype", d.get("doctype")) | self.set("doctype", d.get("doctype")) | ||||
for key, value in d.iteritems(): | for key, value in d.iteritems(): | ||||
if self.get(key) is None: | |||||
# dont_update_if_missing is a list of fieldnames, for which, you don't want to set default value | |||||
if (self.get(key) is None) and (value is not None) and (key not in self.dont_update_if_missing): | |||||
self.set(key, value) | self.set(key, value) | ||||
def get_db_value(self, key): | def get_db_value(self, key): | ||||
@@ -162,6 +164,9 @@ class BaseDocument(object): | |||||
if doc[k] is None: | if doc[k] is None: | ||||
del doc[k] | del doc[k] | ||||
if self.get("_user_tags"): | |||||
doc["_user_tags"] = self.get("_user_tags") | |||||
if self.get("__islocal"): | if self.get("__islocal"): | ||||
doc["__islocal"] = 1 | doc["__islocal"] = 1 | ||||
@@ -275,6 +280,33 @@ class BaseDocument(object): | |||||
return invalid_links | return invalid_links | ||||
def _validate_selects(self): | |||||
if frappe.flags.in_import: | |||||
return | |||||
for df in self.meta.get_select_fields(): | |||||
if not (self.get(df.fieldname) and df.options): | |||||
continue | |||||
options = (df.options or "").split("\n") | |||||
# if only empty options | |||||
if not filter(None, options): | |||||
continue | |||||
# strip and set | |||||
self.set(df.fieldname, cstr(self.get(df.fieldname)).strip()) | |||||
value = self.get(df.fieldname) | |||||
if value not in options and not (frappe.flags.in_test and value.startswith("_T-")): | |||||
# show an elaborate message | |||||
prefix = _("Row #{0}:").format(self.idx) if self.get("parentfield") else "" | |||||
label = _(self.meta.get_label(df.fieldname)) | |||||
comma_options = '", "'.join(_(each) for each in options) | |||||
frappe.throw(_('{0} {1} cannot be "{2}". It should be one of "{3}"').format(prefix, label, | |||||
value, comma_options)) | |||||
def _validate_constants(self): | def _validate_constants(self): | ||||
if frappe.flags.in_import: | if frappe.flags.in_import: | ||||
return | return | ||||
@@ -48,6 +48,7 @@ def get_controller(doctype): | |||||
class Document(BaseDocument): | class Document(BaseDocument): | ||||
def __init__(self, arg1, arg2=None): | def __init__(self, arg1, arg2=None): | ||||
self.doctype = self.name = None | self.doctype = self.name = None | ||||
if arg1 and isinstance(arg1, basestring): | if arg1 and isinstance(arg1, basestring): | ||||
if not arg2: | if not arg2: | ||||
# single | # single | ||||
@@ -72,6 +73,8 @@ class Document(BaseDocument): | |||||
# incorrect arguments. let's not proceed. | # incorrect arguments. let's not proceed. | ||||
raise frappe.DataError("Document({0}, {1})".format(arg1, arg2)) | raise frappe.DataError("Document({0}, {1})".format(arg1, arg2)) | ||||
self.dont_update_if_missing = [] | |||||
def load_from_db(self): | def load_from_db(self): | ||||
if not getattr(self, "_metaclass", False) and self.meta.issingle: | if not getattr(self, "_metaclass", False) and self.meta.issingle: | ||||
self.update(frappe.db.get_singles_dict(self.doctype)) | self.update(frappe.db.get_singles_dict(self.doctype)) | ||||
@@ -225,8 +228,10 @@ class Document(BaseDocument): | |||||
def _validate(self): | def _validate(self): | ||||
self._validate_mandatory() | self._validate_mandatory() | ||||
self._validate_links() | self._validate_links() | ||||
self._validate_selects() | |||||
self._validate_constants() | self._validate_constants() | ||||
for d in self.get_all_children(): | for d in self.get_all_children(): | ||||
d._validate_selects() | |||||
d._validate_constants() | d._validate_constants() | ||||
self._extract_images_from_text_editor() | self._extract_images_from_text_editor() | ||||
@@ -61,6 +61,10 @@ class Meta(Document): | |||||
def get_link_fields(self): | def get_link_fields(self): | ||||
return self.get("fields", {"fieldtype": "Link", "options":["!=", "[Select]"]}) | return self.get("fields", {"fieldtype": "Link", "options":["!=", "[Select]"]}) | ||||
def get_select_fields(self): | |||||
return self.get("fields", {"fieldtype": "Select", "options":["not in", | |||||
["[Select]", "Loading...", "attach_files:"]]}) | |||||
def get_table_fields(self): | def get_table_fields(self): | ||||
if not hasattr(self, "_table_fields"): | if not hasattr(self, "_table_fields"): | ||||
if self.name!="DocType": | if self.name!="DocType": | ||||
@@ -40,3 +40,4 @@ execute:import frappe.website.render; frappe.website.render.clear_cache("login") | |||||
frappe.patches.v4_0.fix_attach_field_file_url | frappe.patches.v4_0.fix_attach_field_file_url | ||||
execute:frappe.reset_perms("User") #2014-06-13 | execute:frappe.reset_perms("User") #2014-06-13 | ||||
execute:frappe.db.sql("""delete from `tabUserRole` where ifnull(parentfield, '')=''""") #2014-06-17 | execute:frappe.db.sql("""delete from `tabUserRole` where ifnull(parentfield, '')=''""") #2014-06-17 | ||||
frappe.patches.v4_0.remove_user_owner_custom_field |
@@ -0,0 +1,10 @@ | |||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | |||||
# MIT License. See license.txt | |||||
from __future__ import unicode_literals | |||||
import frappe | |||||
def execute(): | |||||
user_owner = frappe.db.get_value("Custom Field", {"fieldname": "user_owner"}) | |||||
if user_owner: | |||||
frappe.delete_doc("Custom Field", user_owner) |
@@ -1,14 +1,6 @@ | |||||
// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors | ||||
// MIT License. See license.txt | // MIT License. See license.txt | ||||
if(!console) { | |||||
var console = { | |||||
log: function(txt) { | |||||
// suppress | |||||
} | |||||
} | |||||
} | |||||
$(document).ready(function() { | $(document).ready(function() { | ||||
frappe.assets.check(); | frappe.assets.check(); | ||||
frappe.provide('frappe.app'); | frappe.provide('frappe.app'); | ||||
@@ -60,8 +60,10 @@ frappe.number_format_info = { | |||||
"#.###,##": {decimal_str:",", group_sep:".", precision:2}, | "#.###,##": {decimal_str:",", group_sep:".", precision:2}, | ||||
"# ###.##": {decimal_str:".", group_sep:" ", precision:2}, | "# ###.##": {decimal_str:".", group_sep:" ", precision:2}, | ||||
"# ###,##": {decimal_str:",", group_sep:" ", precision:2}, | "# ###,##": {decimal_str:",", group_sep:" ", precision:2}, | ||||
"#,###.###": {decimal_str:".", group_sep:",", precision:3}, | |||||
"#'###.##": {decimal_str:".", group_sep:"'", precision:2}, | |||||
"#, ###.##": {decimal_str:".", group_sep:", ", precision:2}, | |||||
"#,##,###.##": {decimal_str:".", group_sep:",", precision:2}, | "#,##,###.##": {decimal_str:".", group_sep:",", precision:2}, | ||||
"#,###.###": {decimal_str:".", group_sep:",", precision:3}, | |||||
"#.###": {decimal_str:"", group_sep:".", precision:0}, | "#.###": {decimal_str:"", group_sep:".", precision:0}, | ||||
"#,###": {decimal_str:"", group_sep:",", precision:0}, | "#,###": {decimal_str:"", group_sep:",", precision:0}, | ||||
} | } | ||||
@@ -255,7 +255,7 @@ frappe.ui.Filter = Class.extend({ | |||||
if(df.fieldtype=='Check') { | if(df.fieldtype=='Check') { | ||||
df.fieldtype='Select'; | df.fieldtype='Select'; | ||||
df.options='No\nYes'; | df.options='No\nYes'; | ||||
} else if(['Text','Small Text','Text Editor','Code','Tags','Comments'].indexOf(df.fieldtype)!=-1) { | |||||
} else if(['Text','Small Text','Text Editor','Code','Tag','Comments'].indexOf(df.fieldtype)!=-1) { | |||||
df.fieldtype = 'Data'; | df.fieldtype = 'Data'; | ||||
} else if(df.fieldtype=='Link' && this.$w.find('.condition').val()!="=") { | } else if(df.fieldtype=='Link' && this.$w.find('.condition').val()!="=") { | ||||
df.fieldtype = 'Data'; | df.fieldtype = 'Data'; | ||||
@@ -45,7 +45,7 @@ frappe.ui.toolbar.Toolbar = Class.extend({ | |||||
placeholder="' + __("Search or type a command") + '" \ | placeholder="' + __("Search or type a command") + '" \ | ||||
style="padding: 2px 6px; height: 24px; margin-top: 5px; \ | style="padding: 2px 6px; height: 24px; margin-top: 5px; \ | ||||
margin-left: 10px; background-color: #ddd; \ | margin-left: 10px; background-color: #ddd; \ | ||||
min-width: 230px; \ | |||||
min-width: 230px; font-size: 85%;\ | |||||
border-radius: 10px;">\ | border-radius: 10px;">\ | ||||
</div>\ | </div>\ | ||||
</form>\ | </form>\ | ||||
@@ -113,6 +113,7 @@ frappe.views.CommunicationList = Class.extend({ | |||||
}); | }); | ||||
frappe.last_edited_communication = {}; | frappe.last_edited_communication = {}; | ||||
frappe.standard_replies = {}; | |||||
frappe.views.CommunicationComposer = Class.extend({ | frappe.views.CommunicationComposer = Class.extend({ | ||||
init: function(opts) { | init: function(opts) { | ||||
@@ -129,6 +130,8 @@ frappe.views.CommunicationComposer = Class.extend({ | |||||
description:__("Email addresses, separted by commas")}, | description:__("Email addresses, separted by commas")}, | ||||
{label:__("Subject"), fieldtype:"Data", reqd: 1, | {label:__("Subject"), fieldtype:"Data", reqd: 1, | ||||
fieldname:"subject"}, | fieldname:"subject"}, | ||||
{label:__("Standard Reply"), fieldtype:"Link", options:"Standard Reply", | |||||
fieldname:"standard_reply"}, | |||||
{label:__("Message"), fieldtype:"Text Editor", reqd: 1, | {label:__("Message"), fieldtype:"Text Editor", reqd: 1, | ||||
fieldname:"content"}, | fieldname:"content"}, | ||||
{label:__("Send As Email"), fieldtype:"Check", | {label:__("Send As Email"), fieldtype:"Check", | ||||
@@ -155,6 +158,7 @@ frappe.views.CommunicationComposer = Class.extend({ | |||||
this.dialog.$wrapper.find("[data-edit='outdent']").remove(); | this.dialog.$wrapper.find("[data-edit='outdent']").remove(); | ||||
this.dialog.get_input("send").addClass("btn-primary"); | this.dialog.get_input("send").addClass("btn-primary"); | ||||
$(document).on("upload_complete", function(event, attachment) { | $(document).on("upload_complete", function(event, attachment) { | ||||
if(me.dialog.display) { | if(me.dialog.display) { | ||||
var wrapper = $(me.dialog.fields_dict.select_attachments.wrapper); | var wrapper = $(me.dialog.fields_dict.select_attachments.wrapper); | ||||
@@ -185,10 +189,39 @@ frappe.views.CommunicationComposer = Class.extend({ | |||||
this.setup_email(); | this.setup_email(); | ||||
this.setup_autosuggest(); | this.setup_autosuggest(); | ||||
this.setup_last_edited_communication(); | this.setup_last_edited_communication(); | ||||
this.setup_standard_reply(); | |||||
$(this.dialog.fields_dict.recipients.input).val(this.recipients || "").change(); | $(this.dialog.fields_dict.recipients.input).val(this.recipients || "").change(); | ||||
$(this.dialog.fields_dict.subject.input).val(this.subject || "").change(); | $(this.dialog.fields_dict.subject.input).val(this.subject || "").change(); | ||||
this.setup_earlier_reply(); | this.setup_earlier_reply(); | ||||
}, | }, | ||||
setup_standard_reply: function() { | |||||
var me = this; | |||||
this.dialog.get_input("standard_reply").on("change", function() { | |||||
var standard_reply = $(this).val(); | |||||
var prepend_reply = function() { | |||||
var content_field = me.dialog.fields_dict.content; | |||||
var content = content_field.get_value() || ""; | |||||
content_field.set_input( | |||||
frappe.standard_replies[standard_reply] | |||||
+ "<br><br>" + content); | |||||
} | |||||
if(frappe.standard_replies[standard_reply]) { | |||||
prepend_reply(); | |||||
} else { | |||||
$.ajax({ | |||||
url:"/api/resource/Standard Reply/" + standard_reply, | |||||
statusCode: { | |||||
200: function(data) { | |||||
frappe.standard_replies[standard_reply] = data.data.response; | |||||
prepend_reply(); | |||||
} | |||||
} | |||||
}); | |||||
} | |||||
}); | |||||
}, | |||||
setup_last_edited_communication: function() { | setup_last_edited_communication: function() { | ||||
var me = this; | var me = this; | ||||
this.dialog.onhide = function() { | this.dialog.onhide = function() { | ||||
@@ -238,7 +238,7 @@ frappe.views.DocListView = frappe.ui.Listing.extend({ | |||||
init_minbar: function() { | init_minbar: function() { | ||||
var me = this; | var me = this; | ||||
this.appframe.add_icon_btn("2", 'icon-tag', __('Show Tags'), function() { me.toggle_tags(); }); | this.appframe.add_icon_btn("2", 'icon-tag', __('Show Tags'), function() { me.toggle_tags(); }); | ||||
this.wrapper.on("click", ".list-tag-preview", function() { me.toggle_tags(); }); | |||||
this.$page.on("click", ".list-tag-preview", function() { me.toggle_tags(); }); | |||||
if(this.can_delete || this.listview.settings.selectable) { | if(this.can_delete || this.listview.settings.selectable) { | ||||
this.appframe.add_icon_btn("2", 'icon-remove', __('Delete'), function() { me.delete_items(); }); | this.appframe.add_icon_btn("2", 'icon-remove', __('Delete'), function() { me.delete_items(); }); | ||||
this.appframe.add_icon_btn("2", 'icon-ok', __('Select All'), function() { | this.appframe.add_icon_btn("2", 'icon-ok', __('Select All'), function() { | ||||
@@ -397,12 +397,14 @@ frappe.views.ReportView = frappe.ui.Listing.extend({ | |||||
this.$w.find('.result-list').on("click", ".label-info", function() { | this.$w.find('.result-list').on("click", ".label-info", function() { | ||||
if($(this).attr("data-label")) { | if($(this).attr("data-label")) { | ||||
me.set_filter("_user_tags", $(this).attr("data-label")); | me.set_filter("_user_tags", $(this).attr("data-label")); | ||||
me.refresh(); | |||||
} | } | ||||
}); | }); | ||||
this.$w.find('.result-list').on("click", "[data-workflow-state]", function() { | this.$w.find('.result-list').on("click", "[data-workflow-state]", function() { | ||||
if($(this).attr("data-workflow-state")) { | if($(this).attr("data-workflow-state")) { | ||||
me.set_filter(me.state_fieldname, | me.set_filter(me.state_fieldname, | ||||
$(this).attr("data-workflow-state")); | $(this).attr("data-workflow-state")); | ||||
me.refresh(); | |||||
} | } | ||||
}); | }); | ||||
}, | }, | ||||
@@ -3,7 +3,7 @@ | |||||
frappe.provide('frappe.views'); | frappe.provide('frappe.views'); | ||||
// opts: | |||||
// opts: | |||||
// stats = list of fields | // stats = list of fields | ||||
// doctype | // doctype | ||||
// parent | // parent | ||||
@@ -29,7 +29,7 @@ frappe.views.SidebarStats = Class.extend({ | |||||
$.each(me.stats, function(i, v) { | $.each(me.stats, function(i, v) { | ||||
me.render_stat(v, (r.message || {})[v]); | me.render_stat(v, (r.message || {})[v]); | ||||
}); | }); | ||||
// reload button at the end | // reload button at the end | ||||
if(me.stats.length) { | if(me.stats.length) { | ||||
$('<a class="small"><i class="refresh"></i> '+__('Refresh')+'</a>') | $('<a class="small"><i class="refresh"></i> '+__('Refresh')+'</a>') | ||||
@@ -46,11 +46,14 @@ frappe.views.SidebarStats = Class.extend({ | |||||
}, | }, | ||||
render_stat: function(field, stat) { | render_stat: function(field, stat) { | ||||
var me = this; | var me = this; | ||||
var show_tags = '<a class="list-tag-preview small" style="margin-left: 7px;">' | |||||
+__("Show tags") +'</a>'; | |||||
if(!stat || !stat.length) { | if(!stat || !stat.length) { | ||||
if(field==='_user_tags') { | if(field==='_user_tags') { | ||||
$('<div class="side-panel">\ | $('<div class="side-panel">\ | ||||
<h5 class="text-muted"><i class="icon-tag"></i> '+__('Tags')+'</h5>\ | |||||
<h5 class="text-muted"><i class="icon-tag">\ | |||||
</i> '+__('Tags')+show_tags+'</h5>\ | |||||
<div class="side-panel-body">\ | <div class="side-panel-body">\ | ||||
<div class="text-muted small"><i>'+__('No records tagged.')+'</i><br>' | <div class="text-muted small"><i>'+__('No records tagged.')+'</i><br>' | ||||
+'</div>\ | +'</div>\ | ||||
@@ -59,9 +62,9 @@ frappe.views.SidebarStats = Class.extend({ | |||||
return; | return; | ||||
} | } | ||||
var label = frappe.meta.docfield_map[this.doctype][field] ? | |||||
var label = frappe.meta.docfield_map[this.doctype][field] ? | |||||
frappe.meta.docfield_map[this.doctype][field].label : field; | frappe.meta.docfield_map[this.doctype][field].label : field; | ||||
if(label==='_user_tags') label = 'Tags'; | |||||
if(label==='_user_tags') label = 'Tags' + show_tags; | |||||
// grid | // grid | ||||
var $w = $('<div class="side-panel">\ | var $w = $('<div class="side-panel">\ | ||||
@@ -76,12 +79,12 @@ frappe.views.SidebarStats = Class.extend({ | |||||
$.each(stat, function(i,v) { sum = sum + v[1]; }) | $.each(stat, function(i,v) { sum = sum + v[1]; }) | ||||
// render items | // render items | ||||
$.each(stat, function(i, v) { | |||||
$.each(stat, function(i, v) { | |||||
me.render_stat_item(i, v, sum, field).appendTo($w.find('.side-panel-body')); | me.render_stat_item(i, v, sum, field).appendTo($w.find('.side-panel-body')); | ||||
}); | }); | ||||
$w.appendTo(this.wrapper); | $w.appendTo(this.wrapper); | ||||
}, | |||||
}, | |||||
render_stat_item: function(i, v, max, field) { | render_stat_item: function(i, v, max, field) { | ||||
var me = this; | var me = this; | ||||
var args = {} | var args = {} | ||||
@@ -91,8 +94,8 @@ frappe.views.SidebarStats = Class.extend({ | |||||
args.count = v[1]; | args.count = v[1]; | ||||
args.field = field; | args.field = field; | ||||
args.bar_style = ""; | args.bar_style = ""; | ||||
$item = $(repl('<div class="progress">\ | |||||
$item = $(repl('<div class="progress" style="height: 7px;">\ | |||||
<div class="progress-bar %(bar_style)s" style="width: %(width)s%"></div>\ | <div class="progress-bar %(bar_style)s" style="width: %(width)s%"></div>\ | ||||
</div>\ | </div>\ | ||||
<div class="stat-label" style="margin-top: -19px; text-align: center; \ | <div class="stat-label" style="margin-top: -19px; text-align: center; \ | ||||
@@ -100,7 +103,7 @@ frappe.views.SidebarStats = Class.extend({ | |||||
<a href="#" data-label="%(label)s" data-field="%(field)s">\ | <a href="#" data-label="%(label)s" data-field="%(field)s">\ | ||||
%(_label)s</a> (%(count)s)\ | %(_label)s</a> (%(count)s)\ | ||||
</div>', args)); | </div>', args)); | ||||
this.setup_stat_item_click($item); | this.setup_stat_item_click($item); | ||||
return $item; | return $item; | ||||
}, | }, | ||||
@@ -116,5 +119,5 @@ frappe.views.SidebarStats = Class.extend({ | |||||
me.set_filter(fieldname, label); | me.set_filter(fieldname, label); | ||||
return false; | return false; | ||||
}); | }); | ||||
}, | |||||
}); | |||||
}, | |||||
}); |
@@ -285,8 +285,9 @@ $.extend(_p, { | |||||
// This is used to calculate and substitude values in the HTML | // This is used to calculate and substitude values in the HTML | ||||
run_embedded_js: function(container, doc) { | run_embedded_js: function(container, doc) { | ||||
script_list = $(container).find("script"); | |||||
for(var i=0; i<script_list.length; i++) { | |||||
var script_list = $(container).find("script"); | |||||
for(var i=0, j=script_list.length; i<j; i++) { | |||||
var element = script_list[i]; | var element = script_list[i]; | ||||
var code = element.innerHTML; | var code = element.innerHTML; | ||||
var new_html = code ? (eval(code) || "") : ""; | var new_html = code ? (eval(code) || "") : ""; | ||||
@@ -294,6 +295,9 @@ $.extend(_p, { | |||||
$(element).replaceWith(this.add_span(new_html + "")); | $(element).replaceWith(this.add_span(new_html + "")); | ||||
} | } | ||||
} | } | ||||
// remove scripts once executed | |||||
$(container).find("script").remove(); | |||||
}, | }, | ||||
add_span: function(html) { | add_span: function(html) { | ||||
@@ -250,29 +250,32 @@ class Session: | |||||
def update(self, force=False): | def update(self, force=False): | ||||
"""extend session expiry""" | """extend session expiry""" | ||||
self.data['data']['last_updated'] = frappe.utils.now() | |||||
self.data['data']['lang'] = unicode(frappe.lang) | |||||
if (frappe.session['user'] == "Guest" or frappe.form_dict.cmd=="logout"): | |||||
return | |||||
now = frappe.utils.now() | |||||
self.data['data']['last_updated'] = now | |||||
self.data['data']['lang'] = unicode(frappe.lang) | |||||
# update session in db | # update session in db | ||||
time_diff = None | |||||
last_updated = frappe.cache().get_value("last_db_session_update:" + self.sid) | last_updated = frappe.cache().get_value("last_db_session_update:" + self.sid) | ||||
time_diff = frappe.utils.time_diff_in_seconds(now, last_updated) if last_updated else None | |||||
if last_updated: | |||||
time_diff = frappe.utils.time_diff_in_seconds(frappe.utils.now(), | |||||
last_updated) | |||||
if force or (frappe.session['user'] != 'Guest' and \ | |||||
((time_diff==None) or (time_diff > 1800))): | |||||
# database persistence is secondary, don't update it too often | |||||
# database persistence is secondary, don't update it too often | |||||
updated_in_db = False | |||||
if force or (time_diff==None) or (time_diff > 600): | |||||
frappe.db.sql("""update tabSessions set sessiondata=%s, | frappe.db.sql("""update tabSessions set sessiondata=%s, | ||||
lastupdate=NOW() where sid=%s""" , (str(self.data['data']), | lastupdate=NOW() where sid=%s""" , (str(self.data['data']), | ||||
self.data['sid'])) | self.data['sid'])) | ||||
if frappe.form_dict.cmd not in ("frappe.sessions.clear", "logout"): | |||||
frappe.cache().set_value("last_db_session_update:" + self.sid, | |||||
frappe.utils.now()) | |||||
frappe.cache().set_value("session:" + self.sid, self.data) | |||||
updated_in_db = True | |||||
# set in memcache | |||||
frappe.cache().set_value("last_db_session_update:" + self.sid, now) | |||||
frappe.cache().set_value("session:" + self.sid, self.data) | |||||
return updated_in_db | |||||
def get_expiry_period(): | def get_expiry_period(): | ||||
exp_sec = frappe.defaults.get_global_default("session_expiry") or "06:00:00" | exp_sec = frappe.defaults.get_global_default("session_expiry") or "06:00:00" | ||||
@@ -55,9 +55,8 @@ | |||||
{%- endfor -%} | {%- endfor -%} | ||||
</ul> | </ul> | ||||
</li> | </li> | ||||
{% if not disable_signup %} | |||||
<li class="btn-login-area"><a href="/login">Sign Up / Login</a></li> | |||||
{% endif %} | |||||
<li class="btn-login-area"><a href="/login"> | |||||
{%- if not disable_signup %}Sign Up / {% endif -%} Login</a></li> | |||||
</ul> | </ul> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -393,13 +393,16 @@ def fmt_money(amount, precision=None, currency=None): | |||||
return amount | return amount | ||||
number_format_info = { | number_format_info = { | ||||
"#.###": ("", ".", 0), | |||||
"#,###": ("", ",", 0), | |||||
"#,###.##": (".", ",", 2), | "#,###.##": (".", ",", 2), | ||||
"#,##,###.##": (".", ",", 2), | |||||
"#.###,##": (",", ".", 2), | "#.###,##": (",", ".", 2), | ||||
"# ###.##": (".", " ", 2), | "# ###.##": (".", " ", 2), | ||||
"# ###,##": (",", " ", 2), | |||||
"#'###.##": (".", "'", 2), | |||||
"#, ###.##": (".", ", ", 2), | |||||
"#,##,###.##": (".", ",", 2), | |||||
"#,###.###": (".", ",", 3), | "#,###.###": (".", ",", 3), | ||||
"#.###": ("", ".", 0), | |||||
"#,###": ("", ",", 0) | |||||
} | } | ||||
def get_number_format_info(format): | def get_number_format_info(format): | ||||