feat: Email Campaign
diff --git a/erpnext/crm/doctype/campaign_email_schedule/campaign_email_schedule.json b/erpnext/crm/doctype/campaign_email_schedule/campaign_email_schedule.json
index 2d90094..1481a32 100644
--- a/erpnext/crm/doctype/campaign_email_schedule/campaign_email_schedule.json
+++ b/erpnext/crm/doctype/campaign_email_schedule/campaign_email_schedule.json
@@ -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",
diff --git a/erpnext/crm/doctype/email_campaign/email_campaign.js b/erpnext/crm/doctype/email_campaign/email_campaign.js
index 6020028..09ed848 100644
--- a/erpnext/crm/doctype/email_campaign/email_campaign.js
+++ b/erpnext/crm/doctype/email_campaign/email_campaign.js
@@ -5,4 +5,7 @@
 	// refresh: function(frm) {
 
 	// }
+  email_campaign_for: function(frm) {
+    frm.set_value('recipient', '');
+  }
 });
diff --git a/erpnext/crm/doctype/email_campaign/email_campaign.json b/erpnext/crm/doctype/email_campaign/email_campaign.json
index 66b3546..3259136 100644
--- a/erpnext/crm/doctype/email_campaign/email_campaign.json
+++ b/erpnext/crm/doctype/email_campaign/email_campaign.json
@@ -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",
@@ -50,25 +41,6 @@
    "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",
    "label": "End 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",
diff --git a/erpnext/crm/doctype/email_campaign/email_campaign.py b/erpnext/crm/doctype/email_campaign/email_campaign.py
index 1132226..005c2b8 100644
--- a/erpnext/crm/doctype/email_campaign/email_campaign.py
+++ b/erpnext/crm/doctype/email_campaign/email_campaign.py
@@ -15,7 +15,6 @@
 		#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 @@
 		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()
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index e7a4bc4..48d133f 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -233,6 +233,9 @@
 	},
 	"Contact":{
 		"on_trash": "erpnext.support.doctype.issue.issue.update_issue"
+	},
+	"Email Unsubscribe": {
+		"after_insert": "erpnext.crm.doctype.email_campaign.email_campaign.unsubscribe_recipient"
 	}
 }
 
diff --git a/erpnext/selling/doctype/campaign/campaign.json b/erpnext/selling/doctype/campaign/campaign.json
index d120699..371a9d5 100644
--- a/erpnext/selling/doctype/campaign/campaign.json
+++ b/erpnext/selling/doctype/campaign/campaign.json
@@ -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"
+}
\ No newline at end of file
diff --git a/erpnext/selling/doctype/campaign/campaign_dashboard.py b/erpnext/selling/doctype/campaign/campaign_dashboard.py
new file mode 100644
index 0000000..a9d8eca
--- /dev/null
+++ b/erpnext/selling/doctype/campaign/campaign_dashboard.py
@@ -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']
+			}
+		],
+	}