diff --git a/frappe/boot.py b/frappe/boot.py index 05ba9f2cc6..664269efef 100644 --- a/frappe/boot.py +++ b/frappe/boot.py @@ -10,6 +10,7 @@ import frappe import frappe.defaults import frappe.desk.desk_page from frappe.utils import get_gravatar +from frappe.desk.form.load import get_meta_bundle def get_bootinfo(): """build and return boot info""" @@ -50,6 +51,7 @@ def get_bootinfo(): add_timezone_info(bootinfo) load_conf_settings(bootinfo) load_print(bootinfo, doclist) + doclist.append(get_meta_bundle("Page")) # ipinfo if frappe.session['data'].get('ipinfo'): diff --git a/frappe/custom/doctype/customize_form/customize_form.json b/frappe/custom/doctype/customize_form/customize_form.json index efe792b421..2334905ac4 100644 --- a/frappe/custom/doctype/customize_form/customize_form.json +++ b/frappe/custom/doctype/customize_form/customize_form.json @@ -19,12 +19,7 @@ "depends_on": "doc_type", "fieldname": "properties", "fieldtype": "Section Break", - "label": "Properties", - "permlevel": 0 - }, - { - "fieldname": "column_break0", - "fieldtype": "Column Break", + "label": "", "permlevel": 0 }, { @@ -48,22 +43,19 @@ "search_index": 0 }, { - "fieldname": "sort_field", - "fieldtype": "Select", - "label": "Sort Field", - "permlevel": 0 - }, - { - "fieldname": "sort_order", - "fieldtype": "Select", - "label": "Sort Order", - "options": "ASC\nDESC", - "permlevel": 0 - }, - { - "fieldname": "column_break1", + "fieldname": "column_break_5", "fieldtype": "Column Break", - "permlevel": 0 + "permlevel": 0, + "precision": "" + }, + { + "depends_on": "", + "fieldname": "max_attachments", + "fieldtype": "Int", + "label": "Max Attachments", + "no_copy": 0, + "permlevel": 0, + "search_index": 0 }, { "fieldname": "allow_copy", @@ -74,13 +66,30 @@ "search_index": 0 }, { - "depends_on": "", - "fieldname": "max_attachments", - "fieldtype": "Int", - "label": "Max Attachments", - "no_copy": 0, + "depends_on": "doc_type", + "fieldname": "section_break_8", + "fieldtype": "Section Break", "permlevel": 0, - "search_index": 0 + "precision": "" + }, + { + "fieldname": "sort_field", + "fieldtype": "Select", + "label": "Sort Field", + "permlevel": 0 + }, + { + "fieldname": "column_break_10", + "fieldtype": "Column Break", + "permlevel": 0, + "precision": "" + }, + { + "fieldname": "sort_order", + "fieldtype": "Select", + "label": "Sort Order", + "options": "ASC\nDESC", + "permlevel": 0 }, { "depends_on": "doc_type", @@ -104,7 +113,7 @@ "icon": "icon-glass", "idx": 1, "issingle": 1, - "modified": "2015-03-20 07:13:20.652676", + "modified": "2015-03-25 06:18:19.010091", "modified_by": "Administrator", "module": "Custom", "name": "Customize Form", diff --git a/frappe/desk/moduleview.py b/frappe/desk/moduleview.py index 16a89d8c47..ee9bac5e5b 100644 --- a/frappe/desk/moduleview.py +++ b/frappe/desk/moduleview.py @@ -186,13 +186,26 @@ def set_last_modified(data): item["last_modified"] = get_last_modified(item["name"]) def get_last_modified(doctype): - try: - last_modified = frappe.get_all(doctype, fields=["max(modified)"], as_list=True, limit_page_length=1)[0][0] - except Exception, e: - if e.args[0]==1146: - last_modified = None - else: - raise + def _get(): + try: + last_modified = frappe.get_all(doctype, fields=["max(modified)"], as_list=True, limit_page_length=1)[0][0] + except Exception, e: + if e.args[0]==1146: + last_modified = None + else: + raise + + # hack: save as -1 so that it is cached + if last_modified==None: + last_modified = -1 + + return last_modified + + last_modified = frappe.cache().get_value("last_modified:" + doctype, _get) + + if last_modified==-1: + last_modified = None + return last_modified def get_report_list(module, is_standard="No"): diff --git a/frappe/email/doctype/email_account/email_account.json b/frappe/email/doctype/email_account/email_account.json index d177d17642..7cb41fd768 100644 --- a/frappe/email/doctype/email_account/email_account.json +++ b/frappe/email/doctype/email_account/email_account.json @@ -83,16 +83,6 @@ "search_index": 0, "set_only_once": 0 }, - { - "description": "Append as communication against this DocType (must have fields, \"Status\", \"Subject\")", - "fieldname": "append_to", - "fieldtype": "Link", - "in_list_view": 1, - "label": "Append To", - "options": "DocType", - "permlevel": 0, - "precision": "" - }, { "allow_on_submit": 0, "fieldname": "mailbox_settings", @@ -184,6 +174,17 @@ "permlevel": 0, "precision": "" }, + { + "depends_on": "enable_incoming", + "description": "Append as communication against this DocType (must have fields, \"Status\", \"Subject\")", + "fieldname": "append_to", + "fieldtype": "Link", + "in_list_view": 1, + "label": "Append To", + "options": "DocType", + "permlevel": 0, + "precision": "" + }, { "depends_on": "enable_incoming", "description": "e.g. replies@yourcomany.com. All replies will come to this inbox.", @@ -403,7 +404,7 @@ "is_submittable": 0, "issingle": 0, "istable": 0, - "modified": "2015-03-23 02:09:54.864019", + "modified": "2015-03-25 05:32:14.036800", "modified_by": "Administrator", "module": "Email", "name": "Email Account", diff --git a/frappe/email/doctype/email_account/email_account.py b/frappe/email/doctype/email_account/email_account.py index 1835657ef3..a9720a2b32 100644 --- a/frappe/email/doctype/email_account/email_account.py +++ b/frappe/email/doctype/email_account/email_account.py @@ -195,6 +195,10 @@ class EmailAccount(Document): out = [e.strip() for e in self.send_notification_to.split("\n")] return out + def on_trash(self): + """Clear communications where email account is linked""" + frappe.db.sql("update `tabCommunication` set email_account='' where email_account=%s", self.name) + def pull(now=False): """Will be called via scheduler, pull emails from all enabled POP3 email accounts.""" import frappe.tasks diff --git a/frappe/email/doctype/email_alert/email_alert.js b/frappe/email/doctype/email_alert/email_alert.js index 9bad01d3b3..2c46cc90e2 100644 --- a/frappe/email/doctype/email_alert/email_alert.js +++ b/frappe/email/doctype/email_alert/email_alert.js @@ -32,10 +32,15 @@ frappe.email_alert = { } } -frappe.ui.form.on("Email Alert", "refresh", function(frm) { - frappe.email_alert.setup_fieldname_select(frm); -}); - -frappe.ui.form.on("Email Alert", "document_type", function(frm) { - frappe.email_alert.setup_fieldname_select(frm); +frappe.ui.form.on("Email Alert", { + refresh: function(frm) { + frappe.email_alert.setup_fieldname_select(frm); + }, + document_type: function(frm) { + frappe.email_alert.setup_fieldname_select(frm); + }, + view_properties: function(frm) { + frappe.route_options = {doc_type:frm.doc.document_type}; + frappe.set_route("Form", "Customize Form"); + } }); diff --git a/frappe/email/doctype/email_alert/email_alert.json b/frappe/email/doctype/email_alert/email_alert.json index a97d396651..bc60787f95 100644 --- a/frappe/email/doctype/email_alert/email_alert.json +++ b/frappe/email/doctype/email_alert/email_alert.json @@ -41,26 +41,26 @@ "fieldtype": "Select", "in_list_view": 1, "label": "Send Alert On", - "options": "\nNew\nSave\nSubmit\nCancel\nDate Change\nValue Change", + "options": "\nNew\nSave\nSubmit\nCancel\nDays After\nDays Before\nValue Change", "permlevel": 0, "reqd": 1, "search_index": 1 }, { - "depends_on": "eval:doc.event==\"Date Change\"", + "depends_on": "eval:doc.event==\"Days After\" || doc.event==\"Days Before\"", "description": "Send alert if date matches this field's value", "fieldname": "date_changed", "fieldtype": "Select", - "label": "Date Changed", + "label": "Reference Date", "permlevel": 0 }, { "default": "0", - "depends_on": "eval:doc.event==\"Date Change\"", - "description": "[Optional] Send the email X days in advance of the specified date. 0 equals same day.", + "depends_on": "eval:doc.event==\"Days After\" || doc.event==\"Days Before\"", + "description": "Send days before or after the reference date", "fieldname": "days_in_advance", "fieldtype": "Int", - "label": "Days in Advance", + "label": "Days Before or After", "permlevel": 0 }, { @@ -131,10 +131,17 @@ "label": "Message Examples", "options": "
Message Example (Markdown)
\n
Transaction {{ doc.name }} has exceeded Due Date. Please take relevant action\n\n#### Details\n\nCustomer: {{ doc.customer }}\nAmount: {{ doc.total_amount }}
", "permlevel": 0 + }, + { + "fieldname": "view_properties", + "fieldtype": "Button", + "label": "View Properties (via Customize Form)", + "permlevel": 0, + "precision": "" } ], "icon": "icon-envelope", - "modified": "2015-03-11 16:43:51.288063", + "modified": "2015-03-25 06:20:07.472953", "modified_by": "Administrator", "module": "Email", "name": "Email Alert", diff --git a/frappe/email/doctype/email_alert/email_alert.py b/frappe/email/doctype/email_alert/email_alert.py index d4cea4a3ab..9aaf186c8a 100644 --- a/frappe/email/doctype/email_alert/email_alert.py +++ b/frappe/email/doctype/email_alert/email_alert.py @@ -27,15 +27,20 @@ def trigger_email_alerts(doc, method=None): # don't send email alerts while syncing or patching return - if method=="Date Change": + if method in ("Days Before", "Days After"): + for alert in frappe.db.sql_list("""select name from `tabEmail Alert` where event='Date Change' and enabled=1"""): alert = frappe.get_doc("Email Alert", alert) + diff_days = alert.days_in_advance + if method=="Days After": + diff_days = -diff_days + for name in frappe.db.sql_list("""select name from `tab{0}` where DATE({1}) = ADDDATE(DATE(%s), INTERVAL %s DAY)""".format(alert.document_type, alert.date_changed), - (nowdate(), alert.days_in_advance or 0)): + (nowdate(), diff_days or 0)): evaluate_alert(frappe.get_doc(alert.document_type, name), alert, "Date Change") diff --git a/frappe/model/document.py b/frappe/model/document.py index 0d4d418da1..7d0237c4d0 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -577,6 +577,8 @@ class Document(BaseDocument): elif self._action=="update_after_submit": self.run_method("on_update_after_submit") + frappe.cache().set_value("last_modified:" + self.doctype, self.modified) + def check_no_back_links_exist(self): """Check if document links to any active document before Cancel.""" diff --git a/frappe/patches.txt b/frappe/patches.txt index 19e12f0f50..8f90c7f946 100644 --- a/frappe/patches.txt +++ b/frappe/patches.txt @@ -67,3 +67,4 @@ frappe.patches.v5_0.update_shared frappe.patches.v5_0.bookmarks_to_stars frappe.patches.v5_0.style_settings_to_website_theme frappe.patches.v5_0.rename_ref_type_fieldnames +frappe.patches.v5_0.fix_email_alert diff --git a/frappe/patches/v5_0/fix_email_alert.py b/frappe/patches/v5_0/fix_email_alert.py new file mode 100644 index 0000000000..5c7b198dad --- /dev/null +++ b/frappe/patches/v5_0/fix_email_alert.py @@ -0,0 +1,16 @@ +from __future__ import unicode_literals + +import frappe + +def execute(): + frappe.reload_doctype("Email Alert") + for e in frappe.get_all("Email Alert"): + email_alert = frappe.get_doc("Email Alert", e.name) + if email_alert.event == "Date Change": + if email_alert.days_in_advance < 0: + email_alert.event = "Days After" + email_alert.days_in_advance = -email_alert.days_in_advance + else: + email_alert.event = "Days Before" + + email_alert.save() diff --git a/frappe/public/css/sidebar.css b/frappe/public/css/sidebar.css index 3219888e0e..aa04584a8f 100644 --- a/frappe/public/css/sidebar.css +++ b/frappe/public/css/sidebar.css @@ -114,6 +114,7 @@ body[data-route^="Module"] .main-menu .form-sidebar { } .sidebar-menu li { position: relative; + margin-bottom: 7px; } .form-sidebar .form-tags .tag-area { margin-top: -3px; diff --git a/frappe/public/js/frappe/list/doclistview.js b/frappe/public/js/frappe/list/doclistview.js index 5078bba8a4..e043c2667d 100644 --- a/frappe/public/js/frappe/list/doclistview.js +++ b/frappe/public/js/frappe/list/doclistview.js @@ -455,6 +455,7 @@ frappe.views.DocListView = frappe.ui.Listing.extend({ me.set_working(true); return frappe.call({ method: 'frappe.desk.reportview.delete_items', + freeze: true, args: { items: $.map(dl, function(d, i) { return d.name }), doctype: me.doctype diff --git a/frappe/public/js/frappe/ui/listing.js b/frappe/public/js/frappe/ui/listing.js index 5be5ba1b15..def285ef1a 100644 --- a/frappe/public/js/frappe/ui/listing.js +++ b/frappe/public/js/frappe/ui/listing.js @@ -120,6 +120,8 @@ frappe.ui.Listing = Class.extend({ if(this.new_doctype) { var make_new_doc = function() { (me.custom_new_doc || me.make_new_doc).apply(me, [me.new_doctype]); }; this.page.set_primary_action(__("New"), function() { make_new_doc(); }, "octicon octicon-plus"); + } else { + this.page.clear_primary_action(); } }, @@ -171,6 +173,7 @@ frappe.ui.Listing = Class.extend({ return frappe.call({ method: this.opts.method || 'frappe.desk.query_builder.runquery', type: "GET", + freeze: true, args: this.get_call_args(), callback: function(r) { if(!me.opts.no_loading) diff --git a/frappe/public/less/sidebar.less b/frappe/public/less/sidebar.less index 64279e1974..f213ddfe00 100644 --- a/frappe/public/less/sidebar.less +++ b/frappe/public/less/sidebar.less @@ -81,6 +81,7 @@ body[data-route^="Module"] .main-menu { li { position: relative; + margin-bottom: 7px; } } diff --git a/frappe/website/template.py b/frappe/website/template.py index ec82c7eb02..903bf6cca8 100644 --- a/frappe/website/template.py +++ b/frappe/website/template.py @@ -119,7 +119,7 @@ def add_index(out, context): next_item = context.doc.get_next() if next_item: if next_item.name[0]!="/": next_item.name = "/" + next_item.name - html = ('


'+_("Next")+': {title}

').format(**next_item) + html = ('


'+_("Next")+': {title}

').format(**next_item) out["content"] = out["content"].replace("{next}", html) def add_hero(out, context):