add ability to cancel, restart and refresh subscription
diff --git a/erpnext/accounts/doctype/subscriptions/subscriptions.js b/erpnext/accounts/doctype/subscriptions/subscriptions.js
index 14eb9b6..ae572d2 100644
--- a/erpnext/accounts/doctype/subscriptions/subscriptions.js
+++ b/erpnext/accounts/doctype/subscriptions/subscriptions.js
@@ -3,6 +3,75 @@
 
 frappe.ui.form.on('Subscriptions', {
 	refresh: function(frm) {
+		if(!frm.is_new()){
+			if(frm.doc.status !== 'Canceled'){
+				frm.add_custom_button(
+					__('Cancel Subscription'),
+					() => frm.events.cancel_this_subscription(frm)
+				);
+				frm.add_custom_button(
+					__('Fetch Subscription Updates'),
+					() => frm.events.get_subscription_updates(frm)
+				);
+			}
+			else if(frm.doc.status === 'Canceled'){
+				frm.add_custom_button(
+					__('Restart Subscription'),
+					() => frm.events.renew_this_subscription(frm)
+				);
+			}
+		}
+	},
 
+	cancel_this_subscription: function(frm) {
+		const doc = frm.doc;
+		frappe.confirm(
+			__('This action will stop future billing. Are you sure you want to cancel this subscription?'),
+			function() {
+				frappe.call({
+					method:
+					"erpnext.accounts.doctype.subscriptions.subscriptions.cancel_subscription",
+					args: {name: doc.name},
+					callback: function(data){
+						if(!data.exc){
+							frm.reload_doc();
+						}
+					}
+				});
+			}
+		);
+	},
+
+	renew_this_subscription: function(frm) {
+		const doc = frm.doc;
+		frappe.confirm(
+			__('You will lose records of previously generated invoices. Are you sure you want to restart this subscription?'),
+			function() {
+				frappe.call({
+					method:
+					"erpnext.accounts.doctype.subscriptions.subscriptions.restart_subscription",
+					args: {name: doc.name},
+					callback: function(data){
+						if(!data.exc){
+							frm.reload_doc();
+						}
+					}
+				});
+			}
+		);
+	},
+
+	get_subscription_updates: function(frm) {
+		const doc = frm.doc;
+		frappe.call({
+			method:
+			"erpnext.accounts.doctype.subscriptions.subscriptions.get_subscription_updates",
+			args: {name: doc.name},
+			callback: function(data){
+				if(!data.exc){
+					frm.reload_doc();
+				}
+			}
+		});
 	}
 });
diff --git a/erpnext/accounts/doctype/subscriptions/subscriptions.py b/erpnext/accounts/doctype/subscriptions/subscriptions.py
index 123cd32..cd43a9c 100644
--- a/erpnext/accounts/doctype/subscriptions/subscriptions.py
+++ b/erpnext/accounts/doctype/subscriptions/subscriptions.py
@@ -14,8 +14,8 @@
 		# update start just before the subscription doc is created
 		self.update_subscription_period()
 
-	def update_subscription_period(self):
-		self.set_current_invoice_start()
+	def update_subscription_period(self, date=None):
+		self.set_current_invoice_start(date)
 		self.set_current_invoice_end()
 
 	def set_current_invoice_start(self, date=None):
@@ -228,16 +228,19 @@
 		"""
 		if self.status == 'Active':
 			self.process_for_active()
-		elif self.status == 'Past Due Date':
+		elif self.status in ['Past Due Date', 'Unpaid']:
 			self.process_for_past_due_date()
-		self.save()
-		# process_for_unpaid()
+
+		if self.status != 'Canceled':
+			self.save()
 
 	def process_for_active(self):
 		if getdate(nowdate()) > getdate(self.current_invoice_end) and not self.has_outstanding_invoice():
 			self.generate_invoice()
+			if self.current_invoice_is_past_due():
+				self.status = 'Past Due Date'
 
-		if self.current_invoice_is_past_due():
+		if self.current_invoice_is_past_due() and getdate(nowdate()) > getdate(self.current_invoice_end):
 			self.status = 'Past Due Date'
 
 	def process_for_past_due_date(self):
@@ -247,7 +250,7 @@
 		else:
 			if self.is_not_outstanding(current_invoice):
 				self.status = 'Active'
-				self.update_subscription_period()
+				self.update_subscription_period(nowdate())
 			else:
 				self.set_status_grace_period()
 
@@ -261,3 +264,41 @@
 		else:
 			return not self.is_not_outstanding(current_invoice)
 		return True
+
+	def cancel_subscription(self):
+		"""
+		This sets the subscription as cancelled. It will stop invoices from being generated
+		but it will not affect already created invoices.
+		"""
+		self.status = 'Canceled'
+		self.cancelation_date = nowdate()
+		self.save()
+
+	def restart_subscription(self):
+		"""
+		This sets the subscription as active. The subscription will be made to be like a new
+		subscription but new trial periods will not be allowed.
+		"""
+		self.status = 'Active'
+		self.cancelation_date = None
+		self.update_subscription_period(nowdate())
+		self.invoices = []
+		self.save()
+
+
+@frappe.whitelist()
+def cancel_subscription(name):
+	subscription = frappe.get_doc('Subscriptions', name)
+	subscription.cancel_subscription()
+
+
+@frappe.whitelist()
+def restart_subscription(name):
+	subscription = frappe.get_doc('Subscriptions', name)
+	subscription.restart_subscription()
+
+
+@frappe.whitelist()
+def get_subscription_updates(name):
+	subscription = frappe.get_doc('Subscriptions', name)
+	subscription.process()
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/subscriptions/test_subscriptions.py b/erpnext/accounts/doctype/subscriptions/test_subscriptions.py
index a3413c7..a0f9400 100644
--- a/erpnext/accounts/doctype/subscriptions/test_subscriptions.py
+++ b/erpnext/accounts/doctype/subscriptions/test_subscriptions.py
@@ -267,5 +267,123 @@
 
 		subscription.delete()
 
+	def test_subcription_cancelation(self):
+		subscription = frappe.new_doc('Subscriptions')
+		subscription.subscriber = '_Test Customer'
+		subscription.append('plans', {'plan': '_Test Plan Name'})
+		subscription.save()
+		subscription.cancel_subscription()
+
+		self.assertEqual(subscription.status, 'Canceled')
+
+		subscription.delete()
+
+	def test_subcription_cancelation_and_process(self):
+		settings = frappe.get_single('Subscription Settings')
+		default_grace_period_action = settings.cancel_after_grace
+		settings.cancel_after_grace = 1
+		settings.save()
+
+		subscription = frappe.new_doc('Subscriptions')
+		subscription.subscriber = '_Test Customer'
+		subscription.append('plans', {'plan': '_Test Plan Name'})
+		subscription.insert()
+		subscription.set_current_invoice_start('2018-01-01')
+		subscription.set_current_invoice_end()
+		subscription.process()	# generate first invoice
+		invoices = len(subscription.invoices)
+
+		self.assertEqual(subscription.status, 'Past Due Date')
+		self.assertEqual(len(subscription.invoices), invoices)
+
+		subscription.cancel_subscription()	
+		self.assertEqual(subscription.status, 'Canceled')
+		self.assertEqual(len(subscription.invoices), invoices)
+
+		subscription.process()
+		self.assertEqual(subscription.status, 'Canceled')
+		self.assertEqual(len(subscription.invoices), invoices)
+
+		subscription.process()
+		self.assertEqual(subscription.status, 'Canceled')
+		self.assertEqual(len(subscription.invoices), invoices)
+
+		settings.cancel_after_grace = default_grace_period_action
+		settings.save()
+		subscription.delete()
+
+	def test_subscription_restart_and_process(self):
+		settings = frappe.get_single('Subscription Settings')
+		default_grace_period_action = settings.cancel_after_grace
+		settings.grace_period = 0
+		settings.cancel_after_grace = 0
+		settings.save()
+
+		subscription = frappe.new_doc('Subscriptions')
+		subscription.subscriber = '_Test Customer'
+		subscription.append('plans', {'plan': '_Test Plan Name'})
+		subscription.insert()
+		subscription.set_current_invoice_start('2018-01-01')
+		subscription.set_current_invoice_end()
+		subscription.process()	# generate first invoice
+
+		self.assertEqual(subscription.status, 'Past Due Date')
+
+		subscription.process()	
+		self.assertEqual(subscription.status, 'Unpaid')
+
+		subscription.cancel_subscription()
+		self.assertEqual(subscription.status, 'Canceled')
+
+		subscription.restart_subscription()
+		self.assertEqual(subscription.status, 'Active')
+		self.assertEqual(len(subscription.invoices), 0)
+
+		subscription.process()
+		self.assertEqual(subscription.status, 'Active')
+		self.assertEqual(len(subscription.invoices), 0)
+
+		subscription.process()
+		self.assertEqual(subscription.status, 'Active')
+		self.assertEqual(len(subscription.invoices), 0)
+
+		settings.cancel_after_grace = default_grace_period_action
+		settings.save()
+		subscription.delete()
+
+	def test_subscription_unpaid_back_to_active(self):
+		settings = frappe.get_single('Subscription Settings')
+		default_grace_period_action = settings.cancel_after_grace
+		settings.cancel_after_grace = 0
+		settings.save()
+
+		subscription = frappe.new_doc('Subscriptions')
+		subscription.subscriber = '_Test Customer'
+		subscription.append('plans', {'plan': '_Test Plan Name'})
+		subscription.insert()
+		subscription.set_current_invoice_start('2018-01-01')
+		subscription.set_current_invoice_end()
+		subscription.process()	# generate first invoice
+
+		self.assertEqual(subscription.status, 'Past Due Date')
+
+		subscription.process()	
+		# This should change status to Canceled since grace period is 0
+		self.assertEqual(subscription.status, 'Unpaid')
+
+		invoice = subscription.get_current_invoice()
+		invoice.db_set('outstanding_amount', 0)
+		invoice.db_set('status', 'Paid')
+
+		subscription.process()
+		self.assertEqual(subscription.status, 'Active')
+
+		subscription.process()
+		self.assertEqual(subscription.status, 'Active')
+
+		settings.cancel_after_grace = default_grace_period_action
+		settings.save()
+		subscription.delete()
+
 	def test_subscription_creation_with_multiple_plans(self):
 		pass