feat: Email Campaign
This commit is contained in:
parent
191a0bd43c
commit
9e35bff55c
@ -4,8 +4,8 @@
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"send_after_days",
|
||||
"email_template"
|
||||
"email_template",
|
||||
"send_after_days"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@ -25,7 +25,7 @@
|
||||
}
|
||||
],
|
||||
"istable": 1,
|
||||
"modified": "2019-06-30 15:56:20.306901",
|
||||
"modified": "2019-07-12 11:46:43.184123",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Campaign Email Schedule",
|
||||
|
@ -5,4 +5,7 @@ frappe.ui.form.on('Email Campaign', {
|
||||
// refresh: function(frm) {
|
||||
|
||||
// }
|
||||
email_campaign_for: function(frm) {
|
||||
frm.set_value('recipient', '');
|
||||
}
|
||||
});
|
||||
|
@ -1,35 +1,25 @@
|
||||
{
|
||||
"autoname": "naming_series:",
|
||||
"autoname": "format:MAIL-CAMP-{YYYY}-{#####}",
|
||||
"creation": "2019-06-30 16:05:30.015615",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"campaign_section",
|
||||
"campaign_name",
|
||||
"email_campaign_for",
|
||||
"start_date",
|
||||
"column_break_4",
|
||||
"sender",
|
||||
"recipient",
|
||||
"sender",
|
||||
"column_break_4",
|
||||
"start_date",
|
||||
"end_date",
|
||||
"status",
|
||||
"email_schedule_section",
|
||||
"email_schedule",
|
||||
"unsubscribed",
|
||||
"naming_series"
|
||||
"status"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "campaign_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Campaign"
|
||||
},
|
||||
{
|
||||
"fieldname": "campaign_name",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Campaign Name",
|
||||
"label": "Campaign",
|
||||
"options": "Campaign",
|
||||
"reqd": 1
|
||||
},
|
||||
@ -37,7 +27,8 @@
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"label": "Status",
|
||||
"options": "\nScheduled\nIn Progress\nCompleted\nUnsubscribed"
|
||||
"options": "\nScheduled\nIn Progress\nCompleted\nUnsubscribed",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_4",
|
||||
@ -49,25 +40,6 @@
|
||||
"label": "Start Date",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "email_schedule_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Email Schedule"
|
||||
},
|
||||
{
|
||||
"fieldname": "email_schedule",
|
||||
"fieldtype": "Table",
|
||||
"label": "Email Schedule",
|
||||
"options": "Campaign Email Schedule",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "naming_series",
|
||||
"fieldtype": "Select",
|
||||
"label": "Naming Series",
|
||||
"options": "MAIL-CAMP-.YYYY.-",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "end_date",
|
||||
"fieldtype": "Date",
|
||||
@ -95,15 +67,9 @@
|
||||
"fieldtype": "Link",
|
||||
"label": "Sender",
|
||||
"options": "User"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "unsubscribed",
|
||||
"fieldtype": "Check",
|
||||
"label": "Unsubscribed"
|
||||
}
|
||||
],
|
||||
"modified": "2019-07-09 15:07:03.328591",
|
||||
"modified": "2019-07-12 13:47:37.261213",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Email Campaign",
|
||||
|
@ -15,7 +15,6 @@ class EmailCampaign(Document):
|
||||
#checking if email is set for lead. Not checking for contact as email is a mandatory field for contact.
|
||||
if self.email_campaign_for == "Lead":
|
||||
self.validate_lead()
|
||||
self.set_end_date()
|
||||
self.update_status()
|
||||
|
||||
def validate_dates(self):
|
||||
@ -25,114 +24,73 @@ class EmailCampaign(Document):
|
||||
if campaign.from_date and getdate(self.start_date) < getdate(campaign.from_date):
|
||||
frappe.throw(_("Email Campaign Start Date cannot be before Campaign Start Date"))
|
||||
|
||||
#check if email_schedule is exceeding the campaign end date
|
||||
no_of_days = 0
|
||||
for entry in self.get("email_schedule"):
|
||||
no_of_days += entry.send_after_days
|
||||
email_schedule_end_date = add_days(getdate(self.start_date), no_of_days)
|
||||
if campaign.to_date and getdate(email_schedule_end_date) > getdate(campaign.to_date):
|
||||
#set the end date as start date + max(send after days) in campaign schedule
|
||||
send_after_days = []
|
||||
for entry in campaign.get("campaign_schedule"):
|
||||
send_after_days.append(entry.send_after_days)
|
||||
end_date = add_days(getdate(self.start_date), max(send_after_days))
|
||||
|
||||
if campaign.to_date and getdate(end_date) > getdate(campaign.to_date):
|
||||
frappe.throw(_("Email Schedule cannot extend Campaign End Date"))
|
||||
else:
|
||||
self.end_date = end_date
|
||||
|
||||
def validate_lead(self):
|
||||
lead = frappe.get_doc("Lead", self.recipient)
|
||||
if not lead.get("email_id"):
|
||||
lead_email_id = frappe.db.get_value("Lead", self.recipient, 'email_id')
|
||||
if not lead_email_id:
|
||||
frappe.throw(_("Please set an email id for lead communication"))
|
||||
|
||||
def set_end_date(self):
|
||||
#set the end date as start date + max(send after days) in email schedule
|
||||
send_after_days = []
|
||||
for entry in self.get("email_schedule"):
|
||||
send_after_days.append(entry.send_after_days)
|
||||
self.end_date = add_days(getdate(self.start_date), max(send_after_days))
|
||||
|
||||
def update_status(self):
|
||||
start_date = getdate(self.start_date)
|
||||
end_date = getdate(self.end_date)
|
||||
today_date = getdate(today())
|
||||
if self.unsubscribed:
|
||||
self.status = "Unsubscribed"
|
||||
else:
|
||||
if start_date > today_date:
|
||||
self.status = "Scheduled"
|
||||
elif end_date >= today_date:
|
||||
self.status = "In Progress"
|
||||
elif end_date < today_date:
|
||||
self.status = "Completed"
|
||||
if start_date > today_date:
|
||||
self.status = "Scheduled"
|
||||
elif end_date >= today_date:
|
||||
self.status = "In Progress"
|
||||
elif end_date < today_date:
|
||||
self.status = "Completed"
|
||||
|
||||
#called through hooks to send campaign mails to leads
|
||||
def send_email_to_leads():
|
||||
email_campaigns = frappe.get_all("Email Campaign", filters = { 'status': ('not in', ['Unsubscribed', 'Completed', 'Scheduled']), 'unsubscribed': 0 })
|
||||
for campaign in email_campaigns:
|
||||
email_campaign = frappe.get_doc("Email Campaign", campaign.name)
|
||||
for entry in email_campaign.get("email_schedule"):
|
||||
email_campaigns = frappe.get_all("Email Campaign", filters = { 'status': ('not in', ['Unsubscribed', 'Completed', 'Scheduled']) })
|
||||
for camp in email_campaigns:
|
||||
email_campaign = frappe.get_doc("Email Campaign", camp.name)
|
||||
campaign = frappe.get_doc("Campaign", email_campaign.campaign_name)
|
||||
for entry in campaign.get("campaign_schedule"):
|
||||
scheduled_date = add_days(email_campaign.get('start_date'), entry.get('send_after_days'))
|
||||
if scheduled_date == getdate(today()):
|
||||
send_mail(entry, email_campaign)
|
||||
|
||||
def send_mail(entry, email_campaign):
|
||||
if email_campaign.email_campaign_for == "Lead":
|
||||
lead = frappe.get_doc("Lead", email_campaign.get("recipient"))
|
||||
recipient_email = lead.email_id
|
||||
elif email_campaign.email_campaign_for == "Contact":
|
||||
recipient = frappe.get_doc("Contact", email_campaign.get("recipient"))
|
||||
recipient_email = recipient.email_id
|
||||
recipient = frappe.db.get_value(email_campaign.email_campaign_for, email_campaign.get("recipient"), 'email_id')
|
||||
|
||||
email_template = frappe.get_doc("Email Template", entry.get("email_template"))
|
||||
sender = frappe.get_doc("User", email_campaign.get("sender"))
|
||||
sender_email = sender.email
|
||||
sender = frappe.db.get_value("User", email_campaign.get("sender"), 'email')
|
||||
|
||||
# send mail and link communication to document
|
||||
comm = make(
|
||||
doctype = "Email Campaign",
|
||||
name = email_campaign.name,
|
||||
subject = email_template.get("subject"),
|
||||
content = email_template.get("response"),
|
||||
sender = sender_email,
|
||||
recipients = recipient_email,
|
||||
sender = sender,
|
||||
recipients = recipient,
|
||||
communication_medium = "Email",
|
||||
sent_or_received = "Sent",
|
||||
send_email = False,
|
||||
send_email = True,
|
||||
email_template = email_template.name
|
||||
)
|
||||
frappe.sendmail(
|
||||
recipients = recipient_email,
|
||||
sender = sender_email,
|
||||
subject = email_template.get("subject"),
|
||||
content = email_template.get("response"),
|
||||
reference_doctype = "Email Campaign",
|
||||
reference_name = email_campaign.name,
|
||||
unsubscribe_method = "/api/method/erpnext.crm.doctype.email_campaign.email_campaign.unsubscribe_recipient",
|
||||
unsubscribe_params = {"name": email_campaign.name, "email": recipient_email},
|
||||
unsubscribe_message = "Stop Getting Email Campaign Mails",
|
||||
communication = comm.get("name")
|
||||
)
|
||||
|
||||
@frappe.whitelist(allow_guest=True)
|
||||
def unsubscribe_recipient(name, email):
|
||||
# unsubsribe from comments and communications
|
||||
try:
|
||||
frappe.get_doc({
|
||||
"doctype": "Email Unsubscribe",
|
||||
"email": email,
|
||||
"reference_doctype": "Email Campaign",
|
||||
"reference_name": name
|
||||
}).insert(ignore_permissions=True)
|
||||
|
||||
except frappe.DuplicateEntryError:
|
||||
frappe.db.rollback()
|
||||
|
||||
else:
|
||||
frappe.db.commit()
|
||||
frappe.db.set_value("Email Campaign", name, "unsubscribed", 1)
|
||||
frappe.db.set_value("Email Campaign", name, "status", "Unsubscribed")
|
||||
frappe.db.commit()
|
||||
return_unsubscribed_page(email, name)
|
||||
|
||||
def return_unsubscribed_page(email, name):
|
||||
frappe.respond_as_web_page(_("Unsubscribed"),
|
||||
_("{0} has left the Email Campaign {1}").format(email, name),
|
||||
indicator_color='green')
|
||||
#called from hooks on doc_event Email Unsubscribe
|
||||
def unsubscribe_recipient(unsubscribe, method):
|
||||
if unsubscribe.reference_doctype == 'Email Campaign':
|
||||
frappe.db.set_value("Email Campaign", unsubscribe.reference_name, "status", "Unsubscribed")
|
||||
|
||||
#called through hooks to update email campaign status daily
|
||||
def set_email_campaign_status():
|
||||
email_campaigns = frappe.get_all("Email Campaign")
|
||||
for email_campaign in email_campaigns:
|
||||
email_campaigns = frappe.get_all("Email Campaign", filters = { 'status': ('!=', 'Unsubscribed')})
|
||||
for entry in email_campaigns:
|
||||
email_campaign = frappe.get_doc("Email Campaign", entry.name)
|
||||
email_campaign.update_status()
|
||||
|
@ -233,6 +233,9 @@ doc_events = {
|
||||
},
|
||||
"Contact":{
|
||||
"on_trash": "erpnext.support.doctype.issue.issue.update_issue"
|
||||
},
|
||||
"Email Unsubscribe": {
|
||||
"after_insert": "erpnext.crm.doctype.email_campaign.email_campaign.unsubscribe_recipient"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
"description": "Keep Track of Sales Campaigns. Keep track of Leads, Quotations, Sales Order etc from Campaigns to gauge Return on Investment. ",
|
||||
"doctype": "DocType",
|
||||
"document_type": "Setup",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"campaign",
|
||||
"campaign_name",
|
||||
@ -18,6 +19,9 @@
|
||||
"currency",
|
||||
"column_break2",
|
||||
"budget",
|
||||
"schedule_section",
|
||||
"campaign_schedule_section",
|
||||
"campaign_schedule",
|
||||
"description_section",
|
||||
"description"
|
||||
],
|
||||
@ -53,13 +57,13 @@
|
||||
"width": "300px"
|
||||
},
|
||||
{
|
||||
"default": "Planned",
|
||||
"fieldname": "status",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Status",
|
||||
"options": "\nPlanned\nIn Progress\nCompleted\nCancelled",
|
||||
"reqd": 1,
|
||||
"default": "Planned"
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "from_date",
|
||||
@ -98,11 +102,26 @@
|
||||
"fieldname": "budget_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "BUDGET"
|
||||
},
|
||||
{
|
||||
"fieldname": "campaign_schedule_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Campaign Schedule"
|
||||
},
|
||||
{
|
||||
"fieldname": "campaign_schedule",
|
||||
"fieldtype": "Table",
|
||||
"label": "Campaign Schedule",
|
||||
"options": "Campaign Email Schedule"
|
||||
},
|
||||
{
|
||||
"fieldname": "schedule_section",
|
||||
"fieldtype": "Section Break"
|
||||
}
|
||||
],
|
||||
"icon": "fa fa-bullhorn",
|
||||
"idx": 1,
|
||||
"modified": "2019-04-29 22:09:39.251884",
|
||||
"modified": "2019-07-12 11:52:47.196736",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Campaign",
|
||||
@ -140,5 +159,7 @@
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1
|
||||
}
|
||||
"quick_entry": 1,
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
13
erpnext/selling/doctype/campaign/campaign_dashboard.py
Normal file
13
erpnext/selling/doctype/campaign/campaign_dashboard.py
Normal file
@ -0,0 +1,13 @@
|
||||
from __future__ import unicode_literals
|
||||
from frappe import _
|
||||
|
||||
def get_data():
|
||||
return {
|
||||
'fieldname': 'campaign_name',
|
||||
'transactions': [
|
||||
{
|
||||
'label': _('Email Campaigns'),
|
||||
'items': ['Email Campaign']
|
||||
}
|
||||
],
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user