mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-27 13:55:19 +00:00
[email] many fixes, newsletter, unsubscribe
This commit is contained in:
@@ -1 +0,0 @@
|
||||
Newsletter to be sent to Leads / Contacts.
|
||||
@@ -1 +0,0 @@
|
||||
from __future__ import unicode_literals
|
||||
@@ -1,63 +0,0 @@
|
||||
// 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: "erpnext.support.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"
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
{
|
||||
"autoname": "naming_series:",
|
||||
"creation": "2013-01-10 16:34:31",
|
||||
"description": "Create and Send Newsletters",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Other",
|
||||
"fields": [
|
||||
{
|
||||
"description": "Select who you want to send this newsletter to",
|
||||
"fieldname": "send_to",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Send To",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"default": "NL-",
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"label": "Series",
|
||||
"options": "NL-",
|
||||
"permlevel": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "send_to_type",
|
||||
"fieldtype": "Select",
|
||||
"label": "Send To Type",
|
||||
"options": "Lead\nContact\nEmployee\nCustom",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break1",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.send_to_type==\"Lead\"",
|
||||
"fieldname": "lead_source",
|
||||
"fieldtype": "Select",
|
||||
"label": "Lead Source",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.send_to_type==\"Lead\"",
|
||||
"fieldname": "lead_status",
|
||||
"fieldtype": "Select",
|
||||
"label": "Lead Status",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.send_to_type==\"Contact\"",
|
||||
"fieldname": "contact_type",
|
||||
"fieldtype": "Select",
|
||||
"label": "Contact Type",
|
||||
"options": "Customer\nSupplier",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.send_to_type==\"Custom\"",
|
||||
"description": "Comma separated list of email addresses",
|
||||
"fieldname": "email_list",
|
||||
"fieldtype": "Text",
|
||||
"label": "Send to this list",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "newsletter_content",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Newsletter Content",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"description": "If specified, send the newsletter using this email address",
|
||||
"fieldname": "send_from",
|
||||
"fieldtype": "Data",
|
||||
"label": "Send From",
|
||||
"no_copy": 1,
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "subject",
|
||||
"fieldtype": "Small Text",
|
||||
"in_list_view": 0,
|
||||
"label": "Subject",
|
||||
"permlevel": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "message",
|
||||
"fieldtype": "Text Editor",
|
||||
"label": "Message",
|
||||
"permlevel": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
{
|
||||
"description": "Check how the newsletter looks in an email by sending it to your email.",
|
||||
"fieldname": "test_the_newsletter",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Test the Newsletter",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"description": "A Lead with this email id should exist",
|
||||
"fieldname": "test_email_id",
|
||||
"fieldtype": "Data",
|
||||
"label": "Test Email Id",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "test_send",
|
||||
"fieldtype": "Button",
|
||||
"label": "Test",
|
||||
"options": "test_send",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "newsletter_status",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Newsletter Status",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "email_sent",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 0,
|
||||
"label": "Email Sent?",
|
||||
"no_copy": 1,
|
||||
"permlevel": 0,
|
||||
"read_only": 1
|
||||
}
|
||||
],
|
||||
"icon": "icon-envelope",
|
||||
"idx": 1,
|
||||
"modified": "2015-01-08 10:45:54.106948",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Support",
|
||||
"name": "Newsletter",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "Sales Manager",
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"cancel": 0,
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 0,
|
||||
"role": "Support Manager",
|
||||
"submit": 0,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"title_field": "subject"
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
# 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.utils import cstr
|
||||
from frappe import throw, _
|
||||
from frappe.model.document import Document
|
||||
import erpnext.tasks
|
||||
|
||||
class Newsletter(Document):
|
||||
def onload(self):
|
||||
if self.email_sent:
|
||||
self.get("__onload").status_count = dict(frappe.db.sql("""select status, count(name)
|
||||
from `tabBulk Email` where ref_doctype=%s and ref_docname=%s
|
||||
group by status""", (self.doctype, self.name))) or None
|
||||
|
||||
def test_send(self, doctype="Lead"):
|
||||
self.recipients = self.test_email_id.split(",")
|
||||
self.send_to_doctype = "Lead"
|
||||
self.send_bulk()
|
||||
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):
|
||||
# to avoid request timed out!
|
||||
self.validate_send()
|
||||
|
||||
# hack! event="bulk_long" to queue in longjob queue
|
||||
erpnext.tasks.send_newsletter.delay(frappe.local.site, self.name, event="bulk_long")
|
||||
else:
|
||||
self.send_bulk()
|
||||
|
||||
frappe.msgprint(_("Scheduled to send to {0} recipients").format(len(self.recipients)))
|
||||
|
||||
frappe.db.set(self, "email_sent", 1)
|
||||
|
||||
def get_recipients(self):
|
||||
self.email_field = None
|
||||
if self.send_to_type=="Contact":
|
||||
self.send_to_doctype = "Contact"
|
||||
if self.contact_type == "Customer":
|
||||
return frappe.db.sql_list("""select email_id from tabContact
|
||||
where ifnull(email_id, '') != '' and ifnull(customer, '') != ''""")
|
||||
|
||||
elif self.contact_type == "Supplier":
|
||||
return frappe.db.sql_list("""select email_id from tabContact
|
||||
where ifnull(email_id, '') != '' and ifnull(supplier, '') != ''""")
|
||||
|
||||
elif self.send_to_type=="Lead":
|
||||
self.send_to_doctype = "Lead"
|
||||
conditions = []
|
||||
if self.lead_source and self.lead_source != "All":
|
||||
conditions.append(" and source='%s'" % self.lead_source.replace("'", "\'"))
|
||||
if self.lead_status and self.lead_status != "All":
|
||||
conditions.append(" and status='%s'" % self.lead_status.replace("'", "\'"))
|
||||
|
||||
if conditions:
|
||||
conditions = "".join(conditions)
|
||||
|
||||
return frappe.db.sql_list("""select email_id from tabLead
|
||||
where ifnull(email_id, '') != '' %s""" % (conditions or ""))
|
||||
|
||||
elif self.send_to_type=="Employee":
|
||||
self.send_to_doctype = "Employee"
|
||||
self.email_field = "company_email"
|
||||
|
||||
return frappe.db.sql_list("""select
|
||||
if(ifnull(company_email, '')!='', company_email, personal_email) as email_id
|
||||
from `tabEmployee` where status='Active'""")
|
||||
|
||||
elif self.email_list:
|
||||
email_list = [cstr(email).strip() for email in self.email_list.split(",")]
|
||||
for email in email_list:
|
||||
create_lead(email)
|
||||
|
||||
self.send_to_doctype = "Lead"
|
||||
return email_list
|
||||
|
||||
def send_bulk(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)
|
||||
|
||||
from frappe.email.bulk import send
|
||||
|
||||
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,
|
||||
doctype = self.send_to_doctype, email_field = self.get("email_field") or "email_id",
|
||||
ref_doctype = self.doctype, ref_docname = self.name)
|
||||
|
||||
if not frappe.flags.in_test:
|
||||
frappe.db.auto_commit_on_many_writes = False
|
||||
|
||||
def validate_send(self):
|
||||
if self.get("__islocal"):
|
||||
throw(_("Please save the Newsletter before sending"))
|
||||
|
||||
@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"""))
|
||||
}
|
||||
|
||||
|
||||
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()
|
||||
@@ -1,10 +0,0 @@
|
||||
frappe.listview_settings['Newsletter'] = {
|
||||
add_fields: ["subject", "send_to_type", "email_sent"],
|
||||
get_indicator: function(doc) {
|
||||
if(doc.email_sent) {
|
||||
return [__("Sent"), "green", "email_sent,=,Yes"];
|
||||
} else {
|
||||
return [__("Not Sent"), "orange", "email_sent,=,No"];
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,43 +0,0 @@
|
||||
# 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
|
||||
|
||||
class TestNewsletter(unittest.TestCase):
|
||||
def test_get_recipients_lead(self):
|
||||
w = frappe.get_doc(test_records[0])
|
||||
w.insert()
|
||||
self.assertTrue("test_lead@example.com" in w.get_recipients())
|
||||
frappe.db.sql("""delete from `tabBulk Email`""")
|
||||
w.send_emails()
|
||||
self.assertTrue(frappe.db.get_value("Bulk Email", {"recipient": "test_lead@example.com"}))
|
||||
|
||||
def test_get_recipients_lead_by_status(self):
|
||||
w = frappe.get_doc(test_records[0])
|
||||
w.lead_status="Converted"
|
||||
w.insert()
|
||||
self.assertTrue("test_lead3@example.com" in w.get_recipients())
|
||||
|
||||
def test_get_recipients_contact_customer(self):
|
||||
w = frappe.get_doc(test_records[1])
|
||||
w.insert()
|
||||
self.assertTrue("test_contact_customer@example.com" in w.get_recipients())
|
||||
|
||||
def test_get_recipients_contact_supplier(self):
|
||||
w = frappe.get_doc(test_records[1])
|
||||
w.contact_type="Supplier"
|
||||
w.insert()
|
||||
self.assertTrue("test_contact_supplier@example.com" in w.get_recipients())
|
||||
|
||||
def test_get_recipients_custom(self):
|
||||
w = frappe.get_doc(test_records[2])
|
||||
w.insert()
|
||||
self.assertTrue("test_custom2@example.com" in w.get_recipients())
|
||||
self.assertTrue(frappe.db.get("Lead",
|
||||
{"email_id": "test_custom2@example.com"}))
|
||||
|
||||
|
||||
test_dependencies = ["Lead", "Contact"]
|
||||
|
||||
test_records = frappe.get_test_records('Newsletter')
|
||||
@@ -1,26 +0,0 @@
|
||||
[
|
||||
{
|
||||
"doctype": "Newsletter",
|
||||
"lead_source": "All",
|
||||
"message": "This is a test newsletter",
|
||||
"send_from": "admin@example.com",
|
||||
"send_to_type": "Lead",
|
||||
"subject": "_Test Newsletter to Lead"
|
||||
},
|
||||
{
|
||||
"contact_type": "Customer",
|
||||
"doctype": "Newsletter",
|
||||
"message": "This is a test newsletter",
|
||||
"send_from": "admin@example.com",
|
||||
"send_to_type": "Contact",
|
||||
"subject": "_Test Newsletter to Contact"
|
||||
},
|
||||
{
|
||||
"doctype": "Newsletter",
|
||||
"email_list": "test_custom@example.com, test_custom1@example.com, test_custom2@example.com",
|
||||
"message": "This is a test newsletter",
|
||||
"send_from": "admin@example.com",
|
||||
"send_to_type": "Custom",
|
||||
"subject": "_Test Newsletter to Custom"
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user