Merge pull request #10292 from prssanna/notification-in-notifications

feat: Show Notification in notifications dropdown
This commit is contained in:
mergify[bot] 2020-06-01 05:35:20 +00:00 committed by GitHub
commit 90cd0b786b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 294 additions and 86 deletions

View file

@ -3,10 +3,43 @@
frappe.ui.form.on('Notification Log', {
refresh: function(frm) {
let dt = frm.doc.document_type;
let dn = frm.doc.document_name;
frm.fields_dict.document_name.$input_wrapper
.find('.control-value')
.wrapInner(`<a href='#Form/${dt}/${dn}'></a>`);
if (frm.doc.attached_file) {
frm.trigger('set_attachment');
} else {
frm.get_field('attachment_link').$wrapper.empty();
}
},
open_reference_document: function(frm) {
const dt = frm.doc.document_type;
const dn = frm.doc.document_name;
frappe.set_route('Form', dt, dn);
},
set_attachment: function(frm) {
const attachment = JSON.parse(frm.doc.attached_file);
const $wrapper = frm.get_field('attachment_link').$wrapper;
$wrapper.html(`
<div class="attached-file text-medium">
<div class="ellipsis">
<i class="fa fa-paperclip"></i>
<a class="attached-file-link">${attachment.name}.pdf</a>
</div>
</div>
`);
$wrapper.find(".attached-file-link").click(() => {
const w = window.open(
frappe.urllib.get_full_url(`/api/method/frappe.utils.print_format.download_pdf?
doctype=${encodeURIComponent(attachment.doctype)}
&name=${encodeURIComponent(attachment.name)}
&format=${encodeURIComponent(attachment.print_format)}
&lang=${encodeURIComponent(attachment.lang)}`)
);
if (!w) {
frappe.msgprint(__("Please enable pop-ups"));
}
});
}
});

View file

@ -1,4 +1,5 @@
{
"actions": [],
"creation": "2019-08-26 13:37:34.165254",
"doctype": "DocType",
"editable_grid": 1,
@ -8,10 +9,12 @@
"for_user",
"type",
"email_content",
"column_break_4",
"document_type",
"read",
"document_name",
"attached_file",
"attachment_link",
"open_reference_document",
"from_user"
],
"fields": [
@ -20,57 +23,65 @@
"fieldtype": "Text",
"in_list_view": 1,
"label": "Subject",
"read_only": 1
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "for_user",
"fieldtype": "Link",
"hidden": 1,
"label": "For User",
"options": "User",
"read_only": 1
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "type",
"fieldtype": "Select",
"hidden": 1,
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Type",
"options": "Mention\nEnergy Point\nAssignment\nShare",
"read_only": 1,
"search_index": 1
"options": "Mention\nEnergy Point\nAssignment\nShare\nAlert",
"search_index": 1,
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "email_content",
"fieldtype": "Text",
"label": "Email Content",
"read_only": 1
},
{
"fieldname": "column_break_4",
"fieldtype": "Column Break"
"fieldtype": "Text Editor",
"label": "Message",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "document_type",
"fieldtype": "Link",
"hidden": 1,
"label": "Document Type",
"options": "DocType",
"read_only": 1,
"search_index": 1
"search_index": 1,
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "document_name",
"fieldtype": "Data",
"label": "Document Name",
"read_only": 1,
"search_index": 1
"hidden": 1,
"label": "Document Link",
"search_index": 1,
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "from_user",
"fieldtype": "Link",
"hidden": 1,
"label": "From User",
"options": "User",
"read_only": 1,
"search_index": 1
"search_index": 1,
"show_days": 1,
"show_seconds": 1
},
{
"default": "0",
@ -78,26 +89,51 @@
"fieldtype": "Check",
"hidden": 1,
"ignore_user_permissions": 1,
"label": "Read"
"label": "Read",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "open_reference_document",
"fieldtype": "Button",
"label": "Open Reference Document",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "attached_file",
"fieldtype": "Code",
"hidden": 1,
"label": "Attached File",
"options": "JSON",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "attachment_link",
"fieldtype": "HTML",
"label": "Attachment Link",
"show_days": 1,
"show_seconds": 1
}
],
"hide_toolbar": 1,
"in_create": 1,
"modified": "2019-11-12 15:22:35.283678",
"links": [],
"modified": "2020-05-31 22:31:12.886950",
"modified_by": "umair@erpnext.com",
"module": "Desk",
"name": "Notification Log",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "All",
"share": 1,
"write": 1
"share": 1
}
],
"sort_field": "modified",

View file

@ -48,6 +48,7 @@ def enqueue_create_notification(users, doc):
if isinstance(users, frappe.string_types):
users = [user.strip() for user in users.split(',') if user.strip()]
users = list(set(users))
frappe.enqueue(
'frappe.desk.doctype.notification_log.notification_log.make_notification_logs',
@ -58,6 +59,7 @@ def enqueue_create_notification(users, doc):
def make_notification_logs(doc, users):
from frappe.social.doctype.energy_point_settings.energy_point_settings import is_energy_point_enabled
for user in users:
if frappe.db.exists('User', user):
if is_notifications_enabled(user):
@ -68,7 +70,7 @@ def make_notification_logs(doc, users):
_doc.update(doc)
_doc.for_user = user
_doc.subject = _doc.subject.replace('<div>', '').replace('</div>', '')
if _doc.for_user != _doc.from_user or doc.type == 'Energy Point':
if _doc.for_user != _doc.from_user or doc.type == 'Energy Point' or doc.type == 'Alert':
_doc.insert(ignore_permissions=True)
def send_notification_email(doc):

View file

@ -1,4 +1,5 @@
{
"actions": [],
"autoname": "Prompt",
"creation": "2019-09-11 22:15:44.851526",
"doctype": "DocType",
@ -21,52 +22,68 @@
"default": "1",
"fieldname": "enabled",
"fieldtype": "Check",
"label": "Enabled"
"label": "Enabled",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "subscribed_documents",
"fieldtype": "Table MultiSelect",
"label": "Subscribed Documents",
"options": "Notification Subscribed Document"
"options": "Notification Subscribed Document",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "column_break_3",
"fieldtype": "Section Break",
"label": "Email Settings"
"label": "Email Settings",
"show_days": 1,
"show_seconds": 1
},
{
"default": "1",
"fieldname": "enable_email_notifications",
"fieldtype": "Check",
"label": "Enable Email Notifications"
"label": "Enable Email Notifications",
"show_days": 1,
"show_seconds": 1
},
{
"default": "1",
"depends_on": "enable_email_notifications",
"fieldname": "enable_email_mention",
"fieldtype": "Check",
"label": "Mentions"
"label": "Mentions",
"show_days": 1,
"show_seconds": 1
},
{
"default": "1",
"depends_on": "enable_email_notifications",
"fieldname": "enable_email_assignment",
"fieldtype": "Check",
"label": "Assignments"
"label": "Assignments",
"show_days": 1,
"show_seconds": 1
},
{
"default": "1",
"depends_on": "enable_email_notifications",
"fieldname": "enable_email_energy_point",
"fieldtype": "Check",
"label": "Energy Points"
"label": "Energy Points",
"show_days": 1,
"show_seconds": 1
},
{
"default": "1",
"depends_on": "enable_email_notifications",
"fieldname": "enable_email_share",
"fieldtype": "Check",
"label": "Document Share"
"label": "Document Share",
"show_days": 1,
"show_seconds": 1
},
{
"default": "__user",
@ -75,18 +92,23 @@
"hidden": 1,
"label": "User",
"options": "User",
"read_only": 1
"read_only": 1,
"show_days": 1,
"show_seconds": 1
},
{
"default": "0",
"fieldname": "seen",
"fieldtype": "Check",
"hidden": 1,
"label": "Seen"
"label": "Seen",
"show_days": 1,
"show_seconds": 1
}
],
"in_create": 1,
"modified": "2019-11-19 12:57:59.356786",
"links": [],
"modified": "2020-05-31 22:16:40.798019",
"modified_by": "Administrator",
"module": "Desk",
"name": "Notification Settings",

View file

@ -28,6 +28,9 @@ def is_email_notifications_enabled_for_type(user, notification_type):
if not is_email_notifications_enabled(user):
return False
if notification_type == 'Alert':
return False
fieldname = 'enable_email_' + frappe.scrub(notification_type)
enabled = frappe.db.get_value('Notification Settings', user, fieldname)
if enabled is None:

View file

@ -80,7 +80,6 @@ frappe.ui.form.on("Notification", {
});
},
refresh: function(frm) {
frm.toggle_reqd("recipients", frm.doc.channel=="Email");
frappe.notification.setup_fieldname_select(frm);
frm.get_field("is_standard").toggle(frappe.boot.developer_mode);
frm.trigger('event');

View file

@ -1,4 +1,5 @@
{
"actions": [],
"allow_rename": 1,
"autoname": "Prompt",
"creation": "2014-07-11 17:18:09.923399",
@ -22,6 +23,7 @@
"days_in_advance",
"value_changed",
"sender",
"send_system_notification",
"sender_email",
"section_break_9",
"condition",
@ -46,32 +48,43 @@
"default": "1",
"fieldname": "enabled",
"fieldtype": "Check",
"label": "Enabled"
"label": "Enabled",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "column_break_2",
"fieldtype": "Column Break"
"fieldtype": "Column Break",
"show_days": 1,
"show_seconds": 1
},
{
"default": "Email",
"depends_on": "eval: !doc.disable_channel",
"fieldname": "channel",
"fieldtype": "Select",
"label": "Channel",
"options": "Email\nSlack",
"options": "Email\nSlack\nSystem Notification",
"reqd": 1,
"set_only_once": 1
"show_days": 1,
"show_seconds": 1
},
{
"depends_on": "eval:doc.channel=='Slack'",
"fieldname": "slack_webhook_url",
"fieldtype": "Link",
"label": "Slack Channel",
"options": "Slack Webhook URL"
"mandatory_depends_on": "eval:doc.channel=='Slack'",
"options": "Slack Webhook URL",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "filters",
"fieldtype": "Section Break",
"label": "Filters"
"label": "Filters",
"show_days": 1,
"show_seconds": 1
},
{
"description": "To add dynamic subject, use jinja tags like\n\n<div><pre><code>{{ doc.name }} Delivered</code></pre></div>",
@ -80,7 +93,9 @@
"ignore_xss_filter": 1,
"in_list_view": 1,
"label": "Subject",
"reqd": 1
"reqd": 1,
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "document_type",
@ -90,13 +105,17 @@
"label": "Document Type",
"options": "DocType",
"reqd": 1,
"search_index": 1
"search_index": 1,
"show_days": 1,
"show_seconds": 1
},
{
"default": "0",
"fieldname": "is_standard",
"fieldtype": "Check",
"label": "Is Standard"
"label": "Is Standard",
"show_days": 1,
"show_seconds": 1
},
{
"depends_on": "is_standard",
@ -104,11 +123,15 @@
"fieldtype": "Link",
"in_standard_filter": 1,
"label": "Module",
"options": "Module Def"
"options": "Module Def",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "col_break_1",
"fieldtype": "Column Break"
"fieldtype": "Column Break",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "event",
@ -117,21 +140,27 @@
"label": "Send Alert On",
"options": "\nNew\nSave\nSubmit\nCancel\nDays After\nDays Before\nValue Change\nMethod\nCustom",
"reqd": 1,
"search_index": 1
"search_index": 1,
"show_days": 1,
"show_seconds": 1
},
{
"depends_on": "eval:doc.event=='Method'",
"description": "Trigger on valid methods like \"before_insert\", \"after_update\", etc (will depend on the DocType selected)",
"fieldname": "method",
"fieldtype": "Data",
"label": "Trigger Method"
"label": "Trigger Method",
"show_days": 1,
"show_seconds": 1
},
{
"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": "Reference Date"
"label": "Reference Date",
"show_days": 1,
"show_seconds": 1
},
{
"default": "0",
@ -139,31 +168,41 @@
"description": "Send days before or after the reference date",
"fieldname": "days_in_advance",
"fieldtype": "Int",
"label": "Days Before or After"
"label": "Days Before or After",
"show_days": 1,
"show_seconds": 1
},
{
"depends_on": "eval:doc.event==\"Value Change\"",
"description": "Send alert if this field's value changes",
"fieldname": "value_changed",
"fieldtype": "Select",
"label": "Value Changed"
"label": "Value Changed",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "sender",
"fieldtype": "Link",
"label": "Sender",
"options": "Email Account"
"options": "Email Account",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "sender_email",
"fieldtype": "Data",
"label": "Sender Email",
"options": "Email",
"read_only": 1
"read_only": 1,
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "section_break_9",
"fieldtype": "Section Break"
"fieldtype": "Section Break",
"show_days": 1,
"show_seconds": 1
},
{
"description": "Optional: The alert will be sent if this expression is true",
@ -171,99 +210,143 @@
"fieldtype": "Code",
"ignore_xss_filter": 1,
"in_list_view": 1,
"label": "Condition"
"label": "Condition",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "column_break_6",
"fieldtype": "Column Break"
"fieldtype": "Column Break",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "html_7",
"fieldtype": "HTML",
"options": "<p><strong>Condition Examples:</strong></p>\n<pre>doc.status==\"Open\"<br>doc.due_date==nowdate()<br>doc.total &gt; 40000\n</pre>\n"
"options": "<p><strong>Condition Examples:</strong></p>\n<pre>doc.status==\"Open\"<br>doc.due_date==nowdate()<br>doc.total &gt; 40000\n</pre>\n",
"show_days": 1,
"show_seconds": 1
},
{
"collapsible": 1,
"fieldname": "property_section",
"fieldtype": "Section Break",
"label": "Set Property After Alert"
"label": "Set Property After Alert",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "set_property_after_alert",
"fieldtype": "Select",
"label": "Set Property After Alert"
"label": "Set Property After Alert",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "property_value",
"fieldtype": "Data",
"label": "Value To Be Set"
"label": "Value To Be Set",
"show_days": 1,
"show_seconds": 1
},
{
"depends_on": "eval:doc.channel=='Email'",
"depends_on": "eval:doc.channel!=='Slack'",
"fieldname": "column_break_5",
"fieldtype": "Section Break",
"label": "Recipients"
"label": "Recipients",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "recipients",
"fieldtype": "Table",
"label": "Recipients",
"options": "Notification Recipient"
"mandatory_depends_on": "eval:doc.channel!=='Slack'",
"options": "Notification Recipient",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "message_sb",
"fieldtype": "Section Break",
"label": "Message"
"label": "Message",
"show_days": 1,
"show_seconds": 1
},
{
"default": "Add your message here",
"fieldname": "message",
"fieldtype": "Code",
"ignore_xss_filter": 1,
"label": "Message"
"label": "Message",
"show_days": 1,
"show_seconds": 1
},
{
"depends_on": "eval:doc.channel=='Email'",
"fieldname": "message_examples",
"fieldtype": "HTML",
"label": "Message Examples",
"options": "<h5>Message Example</h5>\n\n<pre>&lt;h3&gt;Order Overdue&lt;/h3&gt;\n\n&lt;p&gt;Transaction {{ doc.name }} has exceeded Due Date. Please take necessary action.&lt;/p&gt;\n\n&lt;!-- show last comment --&gt;\n{% if comments %}\nLast comment: {{ comments[-1].comment }} by {{ comments[-1].by }}\n{% endif %}\n\n&lt;h4&gt;Details&lt;/h4&gt;\n\n&lt;ul&gt;\n&lt;li&gt;Customer: {{ doc.customer }}\n&lt;li&gt;Amount: {{ doc.grand_total }}\n&lt;/ul&gt;\n</pre>"
"options": "<h5>Message Example</h5>\n\n<pre>&lt;h3&gt;Order Overdue&lt;/h3&gt;\n\n&lt;p&gt;Transaction {{ doc.name }} has exceeded Due Date. Please take necessary action.&lt;/p&gt;\n\n&lt;!-- show last comment --&gt;\n{% if comments %}\nLast comment: {{ comments[-1].comment }} by {{ comments[-1].by }}\n{% endif %}\n\n&lt;h4&gt;Details&lt;/h4&gt;\n\n&lt;ul&gt;\n&lt;li&gt;Customer: {{ doc.customer }}\n&lt;li&gt;Amount: {{ doc.grand_total }}\n&lt;/ul&gt;\n</pre>",
"show_days": 1,
"show_seconds": 1
},
{
"depends_on": "eval:doc.channel=='Slack'",
"fieldname": "slack_message_examples",
"fieldtype": "HTML",
"label": "Message Examples",
"options": "<h5>Message Example</h5>\n\n<pre>*Order Overdue*\n\nTransaction {{ doc.name }} has exceeded Due Date. Please take necessary action.\n\n<!-- show last comment -->\n{% if comments %}\nLast comment: {{ comments[-1].comment }} by {{ comments[-1].by }}\n{% endif %}\n\n*Details*\n\n\u2022 Customer: {{ doc.customer }}\n\u2022 Amount: {{ doc.grand_total }}\n</pre>"
"options": "<h5>Message Example</h5>\n\n<pre>*Order Overdue*\n\nTransaction {{ doc.name }} has exceeded Due Date. Please take necessary action.\n\n<!-- show last comment -->\n{% if comments %}\nLast comment: {{ comments[-1].comment }} by {{ comments[-1].by }}\n{% endif %}\n\n*Details*\n\n\u2022 Customer: {{ doc.customer }}\n\u2022 Amount: {{ doc.grand_total }}\n</pre>",
"show_days": 1,
"show_seconds": 1
},
{
"fieldname": "view_properties",
"fieldtype": "Button",
"label": "View Properties (via Customize Form)"
"label": "View Properties (via Customize Form)",
"show_days": 1,
"show_seconds": 1
},
{
"collapsible": 1,
"collapsible_depends_on": "attach_print",
"fieldname": "column_break_25",
"fieldtype": "Section Break",
"label": "Print Settings"
"label": "Print Settings",
"show_days": 1,
"show_seconds": 1
},
{
"default": "0",
"fieldname": "attach_print",
"fieldtype": "Check",
"label": "Attach Print"
"label": "Attach Print",
"show_days": 1,
"show_seconds": 1
},
{
"depends_on": "attach_print",
"fieldname": "print_format",
"fieldtype": "Link",
"label": "Print Format",
"options": "Print Format"
"options": "Print Format",
"show_days": 1,
"show_seconds": 1
},
{
"default": "0",
"depends_on": "eval: doc.channel !== 'System Notification'",
"description": "If enabled, the notification will show up in the notifications dropdown on the top right corner of the navigation bar.",
"fieldname": "send_system_notification",
"fieldtype": "Check",
"label": "Send System Notification",
"show_days": 1,
"show_seconds": 1
}
],
"icon": "fa fa-envelope",
"modified": "2019-07-15 13:17:02.585013",
"links": [],
"modified": "2020-05-29 16:03:10.914526",
"modified_by": "Administrator",
"module": "Email",
"name": "Notification",

View file

@ -13,6 +13,7 @@ from frappe.utils.jinja import validate_template
from frappe.modules.utils import export_module_json, get_doc_module
from six import string_types
from frappe.integrations.doctype.slack_webhook_url.slack_webhook_url import send_slack_message
from frappe.desk.doctype.notification_log.notification_log import enqueue_create_notification
class Notification(Document):
def onload(self):
@ -125,6 +126,9 @@ def get_context(context):
if self.channel == 'Slack':
self.send_a_slack_msg(doc, context)
if self.channel == 'System Notification' or self.send_system_notification:
self.create_system_notification(doc, context)
if self.set_property_after_alert:
allow_update = True
if doc.docstatus == 1 and not doc.meta.get_field(self.set_property_after_alert).allow_on_submit:
@ -143,6 +147,25 @@ def get_context(context):
except Exception:
frappe.log_error(title='Document update failed', message=frappe.get_traceback())
def create_system_notification(self, doc, context):
subject = self.subject
if "{" in subject:
subject = frappe.render_template(self.subject, context)
attachments = self.get_attachment(doc)
recipients, cc, bcc = self.get_list_of_recipients(doc, context)
users = recipients + cc + bcc
notification_doc = {
'type': 'Alert',
'document_type': doc.doctype,
'document_name': doc.name,
'subject': subject,
'email_content': frappe.render_template(self.message, context),
'attached_file': attachments and json.dumps(attachments[0])
}
enqueue_create_notification(users, notification_doc)
def send_an_email(self, doc, context):
from email.utils import formataddr
subject = self.subject
@ -228,8 +251,7 @@ def get_context(context):
# ignoring attachment as draft and cancelled documents are not allowed to print
status = "Draft" if doc.docstatus == 0 else "Cancelled"
frappe.throw(_("""Not allowed to attach {0} document,
please enable Allow Print For {0} in Print Settings""".format(status)),
frappe.throw(_("""Not allowed to attach {0} document, please enable Allow Print For {0} in Print Settings""").format(status),
title=_("Error in Notification"))
else:
return [{

View file

@ -304,10 +304,7 @@ frappe.ui.Notifications = class Notifications {
}
get_dropdown_item_html(field) {
let doc_link = frappe.utils.get_form_link(
field.document_type,
field.document_name
);
let doc_link = this.get_item_link(field);
let read_class = field.read ? '' : 'unread';
let mark_read_action = field.read ? '': 'data-action="mark_as_read"';
let message = field.subject;
@ -336,6 +333,17 @@ frappe.ui.Notifications = class Notifications {
return item_html;
}
get_item_link(notification_doc) {
const link_doctype =
notification_doc.type == 'Alert' ? 'Notification Log': notification_doc.document_type;
const link_docname =
notification_doc.type == 'Alert' ? notification_doc.name: notification_doc.document_name;
return frappe.utils.get_form_link(
link_doctype,
link_docname
);
}
render_dropdown_headers() {
this.categories = [
{