Newsletter moved to Frappeversion-14
@@ -137,6 +137,21 @@ def get_data(): | |||
"name": "Standard Reply", | |||
"description": _("Standard replies to common queries.") | |||
}, | |||
{ | |||
"type": "doctype", | |||
"name": "Newsletter", | |||
"description": _("Newsletters to contacts, leads."), | |||
}, | |||
{ | |||
"type": "doctype", | |||
"name": "Email Group", | |||
"description": _("Email Group List"), | |||
}, | |||
{ | |||
"type": "doctype", | |||
"name": "Email Group Member", | |||
"description": _("Email Group Member List"), | |||
}, | |||
] | |||
}, | |||
{ | |||
@@ -0,0 +1,49 @@ | |||
// Copyright (c) 2016, Frappe Technologies and contributors | |||
// For license information, please see license.txt | |||
frappe.ui.form.on("Email Group", "refresh", function(frm) { | |||
if(!frm.is_new()) { | |||
frm.add_custom_button(__("View Subscribers"), function() { | |||
frappe.route_options = {"email_group": frm.doc.name}; | |||
frappe.set_route("Report", "Email Group Member"); | |||
}, __("View")); | |||
frm.add_custom_button(__("Import Subscribers"), function() { | |||
frappe.prompt({fieldtype:"Select", options: frm.doc.__onload.import_types, | |||
label:__("Import Email From"), fieldname:"doctype", reqd:1}, function(data) { | |||
frappe.call({ | |||
method: "frappe.email.doctype.email_group.email_group.import_from", | |||
args: { | |||
"name": frm.doc.name, | |||
"doctype": data.doctype | |||
}, | |||
callback: function(r) { | |||
frm.set_value("total_subscribers", r.message); | |||
} | |||
}) | |||
}, __("Import Subscribers"), __("Import")); | |||
}, __("Action")); | |||
frm.add_custom_button(__("Add Subscribers"), function() { | |||
frappe.prompt({fieldtype:"Text", | |||
label:__("Email Ids"), fieldname:"email_list", reqd:1}, function(data) { | |||
frappe.call({ | |||
method: "frappe.email.doctype.email_group.email_group.add_subscribers", | |||
args: { | |||
"name": frm.doc.name, | |||
"email_list": data.email_list | |||
}, | |||
callback: function(r) { | |||
frm.set_value("total_subscribers", r.message); | |||
} | |||
}) | |||
}, __("Add Subscribers"), __("Add")); | |||
}, __("Action")); | |||
frm.add_custom_button(__("New Newsletter"), function() { | |||
frappe.route_options = {"email_group": frm.doc.name}; | |||
frappe.new_doc("Newsletter"); | |||
}, __("Action")); | |||
} | |||
}); |
@@ -0,0 +1,109 @@ | |||
{ | |||
"allow_copy": 0, | |||
"allow_import": 1, | |||
"allow_rename": 0, | |||
"autoname": "field:title", | |||
"beta": 0, | |||
"creation": "2015-03-18 06:08:32.729800", | |||
"custom": 0, | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"document_type": "Setup", | |||
"fields": [ | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "title", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Title", | |||
"length": 0, | |||
"no_copy": 1, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"default": "0", | |||
"fieldname": "total_subscribers", | |||
"fieldtype": "Int", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 1, | |||
"label": "Total Subscribers", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 1, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
} | |||
], | |||
"hide_heading": 0, | |||
"hide_toolbar": 0, | |||
"idx": 0, | |||
"image_view": 0, | |||
"in_create": 0, | |||
"in_dialog": 0, | |||
"is_submittable": 0, | |||
"issingle": 0, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2016-06-28 15:33:58.274566", | |||
"modified_by": "Administrator", | |||
"module": "Email", | |||
"name": "Email Group", | |||
"name_case": "", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"amend": 0, | |||
"apply_user_permissions": 0, | |||
"cancel": 0, | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 1, | |||
"if_owner": 0, | |||
"import": 1, | |||
"permlevel": 0, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Newsletter Manager", | |||
"set_user_permissions": 0, | |||
"share": 1, | |||
"submit": 0, | |||
"write": 1 | |||
} | |||
], | |||
"quick_entry": 0, | |||
"read_only": 0, | |||
"read_only_onload": 0, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"track_seen": 0 | |||
} |
@@ -0,0 +1,99 @@ | |||
# -*- coding: utf-8 -*- | |||
# Copyright (c) 2015, Frappe Technologies and contributors | |||
# For license information, please see license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
from frappe.model.document import Document | |||
class EmailGroup(Document): | |||
def onload(self): | |||
singles = [d.name for d in frappe.db.get_all("DocType", "name", {"issingle": 1})] | |||
self.get("__onload").import_types = [{"value": d.parent, "label": "{0} ({1})".format(d.parent, d.label)} \ | |||
for d in frappe.db.get_all("DocField", ("parent", "label"), {"options": "Email"}) | |||
if d.parent not in singles] | |||
def import_from(self, doctype): | |||
"""Extract email ids from given doctype and add them to the current list""" | |||
meta = frappe.get_meta(doctype) | |||
email_field = [d.fieldname for d in meta.fields | |||
if d.fieldtype in ("Data", "Small Text", "Text", "Code") and d.options=="Email"][0] | |||
unsubscribed_field = "unsubscribed" if meta.get_field("unsubscribed") else None | |||
added = 0 | |||
for user in frappe.db.get_all(doctype, [email_field, unsubscribed_field or "name"]): | |||
try: | |||
email = parseaddr(user.get(email_field))[1] | |||
if email: | |||
frappe.get_doc({ | |||
"doctype": "Email Group Member", | |||
"email_group": self.name, | |||
"email": email, | |||
"unsubscribed": user.get(unsubscribed_field) if unsubscribed_field else 0 | |||
}).insert(ignore_permissions=True) | |||
added += 1 | |||
except frappe.UniqueValidationError: | |||
pass | |||
frappe.msgprint(_("{0} subscribers added").format(added)) | |||
return self.update_total_subscribers() | |||
def update_total_subscribers(self): | |||
self.total_subscribers = self.get_total_subscribers() | |||
self.db_update() | |||
return self.total_subscribers | |||
def get_total_subscribers(self): | |||
return frappe.db.sql("""select count(*) from `tabEmail Group Member` | |||
where email_group=%s""", self.name)[0][0] | |||
def on_trash(self): | |||
for d in frappe.get_all("Email Group Member", "name", {"email_group": self.name}): | |||
frappe.delete_doc("Email Group Member", d.name) | |||
@frappe.whitelist() | |||
def import_from(name, doctype): | |||
nlist = frappe.get_doc("Email Group", name) | |||
if nlist.has_permission("write"): | |||
return nlist.import_from(doctype) | |||
@frappe.whitelist() | |||
def add_subscribers(name, email_list): | |||
if not isinstance(email_list, (list, tuple)): | |||
email_list = email_list.replace(",", "\n").split("\n") | |||
count = 0 | |||
for email in email_list: | |||
email = email.strip() | |||
valid = validate_email_add(email, False) | |||
if valid: | |||
if not frappe.db.get_value("Email Group Member", | |||
{"email_group": name, "email": email}): | |||
frappe.get_doc({ | |||
"doctype": "Email Group Member", | |||
"email_group": name, | |||
"email": email | |||
}).insert(ignore_permissions = frappe.flags.ignore_permissions) | |||
count += 1 | |||
else: | |||
pass | |||
else: | |||
frappe.msgprint(_("{0} is not a valid email id").format(email)) | |||
frappe.msgprint(_("{0} subscribers added").format(count)) | |||
return frappe.get_doc("Email Group", name).update_total_subscribers() | |||
def restrict_email_group(doc, method): | |||
from frappe.limits import get_limits | |||
email_group_limit = get_limits().get('newsletter_recipients') | |||
if not email_group_limit: | |||
return | |||
nl = frappe.get_doc("Email Group", doc.email_group) | |||
if nl.get_total_subscribers() >= email_group_limit: | |||
frappe.throw(_("Please Upgrade to add more than {0} subscribers").format(email_group_limit)) |
@@ -0,0 +1,12 @@ | |||
# -*- coding: utf-8 -*- | |||
# Copyright (c) 2015, Frappe Technologies and Contributors | |||
# See license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
import unittest | |||
# test_records = frappe.get_test_records('Email Group') | |||
class TestEmailGroup(unittest.TestCase): | |||
pass |
@@ -0,0 +1,6 @@ | |||
[ | |||
{ | |||
"doctype": "Email Group", | |||
"title": "_Test Email Group" | |||
} | |||
] |
@@ -0,0 +1,8 @@ | |||
// Copyright (c) 2016, Frappe Technologies and contributors | |||
// For license information, please see license.txt | |||
frappe.ui.form.on('Email Group Member', { | |||
refresh: function(frm) { | |||
} | |||
}); |
@@ -0,0 +1,135 @@ | |||
{ | |||
"allow_copy": 0, | |||
"allow_import": 1, | |||
"allow_rename": 0, | |||
"autoname": "hash", | |||
"beta": 0, | |||
"creation": "2015-03-18 06:15:59.321619", | |||
"custom": 0, | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"document_type": "Document", | |||
"fields": [ | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "email_group", | |||
"fieldtype": "Link", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 1, | |||
"label": "Email Group", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "Email Group", | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "email", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 1, | |||
"label": "Email", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "unsubscribed", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 1, | |||
"label": "Unsubscribed", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
} | |||
], | |||
"hide_heading": 0, | |||
"hide_toolbar": 0, | |||
"idx": 0, | |||
"image_view": 0, | |||
"in_create": 0, | |||
"in_dialog": 0, | |||
"is_submittable": 0, | |||
"issingle": 0, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"modified": "2016-06-28 17:00:27.546534", | |||
"modified_by": "Administrator", | |||
"module": "Email", | |||
"name": "Email Group Member", | |||
"name_case": "", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"amend": 0, | |||
"apply_user_permissions": 0, | |||
"cancel": 0, | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 1, | |||
"if_owner": 0, | |||
"import": 1, | |||
"permlevel": 0, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Newsletter Manager", | |||
"set_user_permissions": 0, | |||
"share": 1, | |||
"submit": 0, | |||
"write": 1 | |||
} | |||
], | |||
"quick_entry": 0, | |||
"read_only": 0, | |||
"read_only_onload": 0, | |||
"sort_field": "modified", | |||
"sort_order": "DESC", | |||
"title_field": "email", | |||
"track_seen": 0 | |||
} |
@@ -0,0 +1,13 @@ | |||
# -*- coding: utf-8 -*- | |||
# Copyright (c) 2015, Frappe Technologies and contributors | |||
# For license information, please see license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
from frappe.model.document import Document | |||
class EmailGroupMember(Document): | |||
pass | |||
def after_doctype_insert(): | |||
frappe.db.add_unique("Email Group Member", ("email_group", "email")) |
@@ -0,0 +1,12 @@ | |||
# -*- coding: utf-8 -*- | |||
# Copyright (c) 2015, Frappe Technologies and Contributors | |||
# See license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
import unittest | |||
# test_records = frappe.get_test_records('Email Group Member') | |||
class TestEmailGroupMember(unittest.TestCase): | |||
pass |
@@ -0,0 +1,63 @@ | |||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors | |||
// License: GNU General Public License v3. See license.txt | |||
cur_frm.cscript.onload = function(doc) { | |||
return frappe.call({ | |||
method: "frappe.email.doctype.newsletter.newsletter.get_lead_options", | |||
type: "GET", | |||
callback: function(r) { | |||
set_field_options("lead_source", r.message.sources.join("\n")) | |||
set_field_options("lead_status", r.message.statuses.join("\n")) | |||
} | |||
}); | |||
} | |||
cur_frm.cscript.refresh = function(doc) { | |||
erpnext.toggle_naming_series(); | |||
if(!doc.__islocal && !cint(doc.email_sent) && !doc.__unsaved | |||
&& inList(frappe.boot.user.can_write, doc.doctype)) { | |||
cur_frm.add_custom_button(__('Send'), function() { | |||
return $c_obj(doc, 'send_emails', '', function(r) { | |||
cur_frm.refresh(); | |||
}); | |||
}, "icon-play", "btn-success"); | |||
} | |||
cur_frm.cscript.setup_dashboard(); | |||
if(doc.__islocal && !doc.send_from) { | |||
cur_frm.set_value("send_from", | |||
repl("%(fullname)s <%(email)s>", frappe.user_info(doc.owner))); | |||
} | |||
} | |||
cur_frm.cscript.setup_dashboard = function() { | |||
cur_frm.dashboard.reset(); | |||
if(!cur_frm.doc.__islocal && cint(cur_frm.doc.email_sent) && cur_frm.doc.__onload && cur_frm.doc.__onload.status_count) { | |||
var stat = cur_frm.doc.__onload.status_count; | |||
var total = frappe.utils.sum($.map(stat, function(v) { return v; })); | |||
if(total) { | |||
$.each(stat, function(k, v) { | |||
stat[k] = flt(v * 100 / total, 2) + '%'; | |||
}); | |||
cur_frm.dashboard.add_progress("Status", [ | |||
{ | |||
title: stat["Sent"] + "% Sent", | |||
width: stat["Sent"], | |||
progress_class: "progress-bar-success" | |||
}, | |||
{ | |||
title: stat["Sending"] + "% Sending", | |||
width: stat["Sending"], | |||
progress_class: "progress-bar-warning" | |||
}, | |||
{ | |||
title: stat["Error"] + "% Error", | |||
width: stat["Error"], | |||
progress_class: "progress-bar-danger" | |||
} | |||
]); | |||
} | |||
} | |||
} |
@@ -0,0 +1,302 @@ | |||
{ | |||
"allow_copy": 0, | |||
"allow_import": 0, | |||
"allow_rename": 1, | |||
"autoname": "field:subject", | |||
"beta": 0, | |||
"creation": "2013-01-10 16:34:31", | |||
"custom": 0, | |||
"description": "Create and Send Newsletters", | |||
"docstatus": 0, | |||
"doctype": "DocType", | |||
"document_type": "Other", | |||
"fields": [ | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "email_group", | |||
"fieldtype": "Link", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Email Group", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "Email Group", | |||
"permlevel": 0, | |||
"precision": "", | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "subject", | |||
"fieldtype": "Small Text", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Subject", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"description": "", | |||
"fieldname": "send_from", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 1, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Sender", | |||
"length": 0, | |||
"no_copy": 1, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "email_sent", | |||
"fieldtype": "Check", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Email Sent?", | |||
"length": 0, | |||
"no_copy": 1, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 1, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "newsletter_content", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "message", | |||
"fieldtype": "Text Editor", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Message", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 1, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"description": "", | |||
"fieldname": "test_the_newsletter", | |||
"fieldtype": "Section Break", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"description": "A Lead with this email id should exist", | |||
"fieldname": "test_email_id", | |||
"fieldtype": "Data", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Test Email Id", | |||
"length": 0, | |||
"no_copy": 0, | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
}, | |||
{ | |||
"allow_on_submit": 0, | |||
"bold": 0, | |||
"collapsible": 0, | |||
"fieldname": "test_send", | |||
"fieldtype": "Button", | |||
"hidden": 0, | |||
"ignore_user_permissions": 0, | |||
"ignore_xss_filter": 0, | |||
"in_filter": 0, | |||
"in_list_view": 0, | |||
"label": "Test", | |||
"length": 0, | |||
"no_copy": 0, | |||
"options": "test_send", | |||
"permlevel": 0, | |||
"print_hide": 0, | |||
"print_hide_if_no_value": 0, | |||
"read_only": 0, | |||
"report_hide": 0, | |||
"reqd": 0, | |||
"search_index": 0, | |||
"set_only_once": 0, | |||
"unique": 0 | |||
} | |||
], | |||
"hide_heading": 0, | |||
"hide_toolbar": 0, | |||
"icon": "icon-envelope", | |||
"idx": 1, | |||
"image_view": 0, | |||
"in_create": 0, | |||
"in_dialog": 0, | |||
"is_submittable": 0, | |||
"issingle": 0, | |||
"istable": 0, | |||
"max_attachments": 0, | |||
"menu_index": 0, | |||
"modified": "2016-06-28 17:20:07.227578", | |||
"modified_by": "Administrator", | |||
"module": "Email", | |||
"name": "Newsletter", | |||
"owner": "Administrator", | |||
"permissions": [ | |||
{ | |||
"amend": 0, | |||
"apply_user_permissions": 1, | |||
"cancel": 0, | |||
"create": 1, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 1, | |||
"if_owner": 0, | |||
"import": 0, | |||
"permlevel": 0, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "All", | |||
"set_user_permissions": 0, | |||
"share": 1, | |||
"submit": 0, | |||
"write": 1 | |||
}, | |||
{ | |||
"amend": 0, | |||
"apply_user_permissions": 1, | |||
"cancel": 0, | |||
"create": 0, | |||
"delete": 1, | |||
"email": 1, | |||
"export": 1, | |||
"if_owner": 0, | |||
"import": 0, | |||
"permlevel": 0, | |||
"print": 1, | |||
"read": 1, | |||
"report": 1, | |||
"role": "Newsletter Manager", | |||
"set_user_permissions": 0, | |||
"share": 1, | |||
"submit": 0, | |||
"write": 0 | |||
} | |||
], | |||
"quick_entry": 1, | |||
"read_only": 0, | |||
"read_only_onload": 0, | |||
"sort_order": "ASC", | |||
"title_field": "subject", | |||
"track_seen": 0 | |||
} |
@@ -0,0 +1,189 @@ | |||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors | |||
# License: GNU General Public License v3. See license.txt | |||
from __future__ import unicode_literals | |||
import frappe | |||
import frappe.utils | |||
from frappe import throw, _ | |||
from frappe.model.document import Document | |||
from frappe.email.queue import check_email_limit | |||
from frappe.utils.verified_command import get_signed_params, verify_request | |||
from frappe.utils.background_jobs import enqueue | |||
from frappe.utils.scheduler import log | |||
from frappe.email.queue import send | |||
from frappe.email.doctype.email_group.email_group import add_subscribers | |||
class Newsletter(Document): | |||
def onload(self): | |||
if self.email_sent: | |||
self.get("__onload").status_count = dict(frappe.db.sql("""select status, count(name) | |||
from `tabEmail Queue` where reference_doctype=%s and reference_name=%s | |||
group by status""", (self.doctype, self.name))) or None | |||
def test_send(self, doctype="Lead"): | |||
self.recipients = frappe.utils.split_emails(self.test_email_id) | |||
self.queue_all() | |||
frappe.msgprint(_("Scheduled to send to {0}").format(self.test_email_id)) | |||
def send_emails(self): | |||
"""send emails to leads and customers""" | |||
if self.email_sent: | |||
throw(_("Newsletter has already been sent")) | |||
self.recipients = self.get_recipients() | |||
if getattr(frappe.local, "is_ajax", False): | |||
self.validate_send() | |||
# using default queue with a longer timeout as this isn't a scheduled task | |||
enqueue(send_newsletter, queue='default', timeout=1500, event='send_newsletter', newsletter=self.name) | |||
else: | |||
self.queue_all() | |||
frappe.msgprint(_("Scheduled to send to {0} recipients").format(len(self.recipients))) | |||
frappe.db.set(self, "email_sent", 1) | |||
def queue_all(self): | |||
if not self.get("recipients"): | |||
# in case it is called via worker | |||
self.recipients = self.get_recipients() | |||
self.validate_send() | |||
sender = self.send_from or frappe.utils.get_formatted_email(self.owner) | |||
if not frappe.flags.in_test: | |||
frappe.db.auto_commit_on_many_writes = True | |||
send(recipients = self.recipients, sender = sender, | |||
subject = self.subject, message = self.message, | |||
reference_doctype = self.doctype, reference_name = self.name, | |||
unsubscribe_method = "/api/method/frappe.email.doctype.newsletter.newsletter.unsubscribe", | |||
unsubscribe_params = {"name": self.email_group}, | |||
send_priority = 0) | |||
if not frappe.flags.in_test: | |||
frappe.db.auto_commit_on_many_writes = False | |||
def get_recipients(self): | |||
"""Get recipients from Email Group""" | |||
return [d.email for d in frappe.db.get_all("Email Group Member", ["email"], | |||
{"unsubscribed": 0, "email_group": self.email_group})] | |||
def validate_send(self): | |||
if self.get("__islocal"): | |||
throw(_("Please save the Newsletter before sending")) | |||
check_email_limit(self.recipients) | |||
@frappe.whitelist() | |||
def get_lead_options(): | |||
return { | |||
"sources": ["All"] + filter(None, | |||
frappe.db.sql_list("""select distinct source from tabLead""")), | |||
"statuses": ["All"] + filter(None, | |||
frappe.db.sql_list("""select distinct status from tabLead""")) | |||
} | |||
@frappe.whitelist(allow_guest=True) | |||
def unsubscribe(email, name): | |||
if not verify_request(): | |||
return | |||
subs_id = frappe.db.get_value("Email Group Member", {"email": email, "email_group": name}) | |||
if subs_id: | |||
subscriber = frappe.get_doc("Email Group Member", subs_id) | |||
subscriber.unsubscribed = 1 | |||
subscriber.save(ignore_permissions=True) | |||
frappe.db.commit() | |||
return_unsubscribed_page(email) | |||
def return_unsubscribed_page(email): | |||
frappe.respond_as_web_page(_("Unsubscribed"), _("{0} has been successfully unsubscribed from this list.").format(email)) | |||
def create_lead(email_id): | |||
"""create a lead if it does not exist""" | |||
from email.utils import parseaddr | |||
from frappe.model.naming import get_default_naming_series | |||
real_name, email_id = parseaddr(email_id) | |||
if frappe.db.get_value("Lead", {"email_id": email_id}): | |||
return | |||
lead = frappe.get_doc({ | |||
"doctype": "Lead", | |||
"email_id": email_id, | |||
"lead_name": real_name or email_id, | |||
"status": "Lead", | |||
"naming_series": get_default_naming_series("Lead"), | |||
"company": frappe.db.get_default("Company"), | |||
"source": "Email" | |||
}) | |||
lead.insert() | |||
@frappe.whitelist(allow_guest=True) | |||
def subscribe(email): | |||
url = frappe.utils.get_url("/api/method/frappe.email.doctype.newsletter.newsletter.confirm_subscription") +\ | |||
"?" + get_signed_params({"email": email}) | |||
messages = ( | |||
_("Thank you for your interest in subscribing to our updates"), | |||
_("Please verify your email id"), | |||
url, | |||
_("Click here to verify") | |||
) | |||
content = """ | |||
<p>{0}. {1}.</p> | |||
<p><a href="{2}">{3}</a></p> | |||
""" | |||
frappe.sendmail(email, subject=_("Confirm Your Email"), content=content.format(*messages)) | |||
@frappe.whitelist(allow_guest=True) | |||
def confirm_subscription(email): | |||
if not verify_request(): | |||
return | |||
if not frappe.db.exists("Email Group", _("Website")): | |||
frappe.get_doc({ | |||
"doctype": "Email Group", | |||
"title": _("Website") | |||
}).insert(ignore_permissions=True) | |||
frappe.flags.ignore_permissions = True | |||
add_subscribers(_("Website"), email) | |||
frappe.db.commit() | |||
frappe.respond_as_web_page(_("Confirmed"), _("{0} has been successfully added to our Email Group.").format(email)) | |||
def send_newsletter(newsletter): | |||
try: | |||
doc = frappe.get_doc("Newsletter", newsletter) | |||
doc.queue_all() | |||
except: | |||
frappe.db.rollback() | |||
# wasn't able to send emails :( | |||
doc.db_set("email_sent", 0) | |||
frappe.db.commit() | |||
log("send_newsletter") | |||
raise | |||
else: | |||
frappe.db.commit() | |||
@@ -0,0 +1,10 @@ | |||
frappe.listview_settings['Newsletter'] = { | |||
add_fields: ["subject", "email_sent"], | |||
get_indicator: function(doc) { | |||
if(doc.email_sent) { | |||
return [__("Sent"), "green", "email_sent,=,Yes"]; | |||
} else { | |||
return [__("Not Sent"), "orange", "email_sent,=,No"]; | |||
} | |||
} | |||
}; |
@@ -0,0 +1,49 @@ | |||
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors | |||
# License: GNU General Public License v3. See license.txt | |||
from __future__ import unicode_literals | |||
import frappe, unittest | |||
from frappe.email.doctype.newsletter.newsletter import unsubscribe | |||
from urllib import unquote | |||
class TestNewsletter(unittest.TestCase): | |||
def setUp(self): | |||
frappe.db.sql('delete from `tabEmail Group Member`') | |||
for email in ["test_subscriber1@example.com", "test_subscriber2@example.com", | |||
"test_subscriber3@example.com"]: | |||
frappe.get_doc({ | |||
"doctype": "Email Group Member", | |||
"email": email, | |||
"email_group": "_Test Email Group" | |||
}).insert() | |||
def test_send(self): | |||
self.send_newsletter() | |||
self.assertEquals(len(frappe.get_all("Email Queue")), 3) | |||
def test_unsubscribe(self): | |||
# test unsubscribe | |||
self.send_newsletter() | |||
email = unquote(frappe.local.flags.signed_query_string.split("email=")[1].split("&")[0]) | |||
unsubscribe(email, "_Test Email Group") | |||
self.send_newsletter() | |||
self.assertEquals(len(frappe.get_all("Email Queue")), 2) | |||
def send_newsletter(self): | |||
frappe.db.sql("delete from `tabEmail Queue`") | |||
frappe.delete_doc("Newsletter", "_Test Newsletter") | |||
newsletter = frappe.get_doc({ | |||
"doctype": "Newsletter", | |||
"subject": "_Test Newsletter", | |||
"email_group": "_Test Email Group", | |||
"send_from": "Test Sender <test_sender@example.com>", | |||
"message": "Testing my news." | |||
}).insert(ignore_permissions=True) | |||
newsletter.send_emails() | |||
test_dependencies = ["Email Group"] |
@@ -97,7 +97,10 @@ standard_queries = { | |||
doc_events = { | |||
"*": { | |||
"after_insert": "frappe.email.doctype.email_alert.email_alert.trigger_email_alerts", | |||
"validate": "frappe.email.doctype.email_alert.email_alert.trigger_email_alerts", | |||
"validate": [ | |||
"frappe.email.doctype.email_alert.email_alert.trigger_email_alerts", | |||
"frappe.email.doctype.email_group.email_group.restrict_email_group" | |||
], | |||
"on_update": [ | |||
"frappe.desk.notifications.clear_doctype_notifications", | |||
"frappe.email.doctype.email_alert.email_alert.trigger_email_alerts", | |||
@@ -132,3 +132,4 @@ frappe.patches.v7_0.setup_list_settings | |||
execute:frappe.db.sql('''delete from `tabSingles` where doctype="Email Settings"''') # 2016-06-13 | |||
execute:frappe.db.sql("delete from `tabWeb Page` where ifnull(template_path, '')!=''") | |||
frappe.patches.v7_0.re_route #2016-06-27 | |||
frappe.patches.v7_0.rename_newsletter_list_to_email_group |
@@ -0,0 +1,5 @@ | |||
import frappe | |||
def execute(): | |||
frappe.rename_doc('DocType', 'Newsletter List', 'Email Group') | |||
frappe.rename_doc('DocType', 'Newsletter List Subscriber', 'Email Group Member') |