Merge branch 'develop' into new-subscription
diff --git a/erpnext/accounts/doctype/subscriber/__init__.py b/erpnext/accounts/doctype/subscriber/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/doctype/subscriber/__init__.py
diff --git a/erpnext/accounts/doctype/subscriber/subscriber.js b/erpnext/accounts/doctype/subscriber/subscriber.js
new file mode 100644
index 0000000..f5ea804
--- /dev/null
+++ b/erpnext/accounts/doctype/subscriber/subscriber.js
@@ -0,0 +1,2 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
diff --git a/erpnext/accounts/doctype/subscriber/subscriber.json b/erpnext/accounts/doctype/subscriber/subscriber.json
new file mode 100644
index 0000000..28a57d8
--- /dev/null
+++ b/erpnext/accounts/doctype/subscriber/subscriber.json
@@ -0,0 +1,126 @@
+{
+ "allow_copy": 0, 
+ "allow_guest_to_view": 0, 
+ "allow_import": 0, 
+ "allow_rename": 0, 
+ "autoname": "field:subscriber_name", 
+ "beta": 0, 
+ "creation": "2018-02-24 11:17:46.809140", 
+ "custom": 0, 
+ "docstatus": 0, 
+ "doctype": "DocType", 
+ "document_type": "", 
+ "editable_grid": 1, 
+ "engine": "InnoDB", 
+ "fields": [
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "subscriber_name", 
+   "fieldtype": "Data", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Subscriber Name", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "customer", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Customer", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Customer", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }
+ ], 
+ "has_web_view": 0, 
+ "hide_heading": 0, 
+ "hide_toolbar": 0, 
+ "idx": 0, 
+ "image_view": 0, 
+ "in_create": 0, 
+ "is_submittable": 0, 
+ "issingle": 0, 
+ "istable": 0, 
+ "max_attachments": 0, 
+ "modified": "2018-02-26 04:40:16.510290", 
+ "modified_by": "Administrator", 
+ "module": "Accounts", 
+ "name": "Subscriber", 
+ "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": 0, 
+   "permlevel": 0, 
+   "print": 1, 
+   "read": 1, 
+   "report": 1, 
+   "role": "System Manager", 
+   "set_user_permissions": 0, 
+   "share": 1, 
+   "submit": 0, 
+   "write": 1
+  }
+ ], 
+ "quick_entry": 1, 
+ "read_only": 0, 
+ "read_only_onload": 0, 
+ "show_name_in_global_search": 0, 
+ "sort_field": "modified", 
+ "sort_order": "DESC", 
+ "track_changes": 1, 
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/subscriber/subscriber.py b/erpnext/accounts/doctype/subscriber/subscriber.py
new file mode 100644
index 0000000..03eb0f5
--- /dev/null
+++ b/erpnext/accounts/doctype/subscriber/subscriber.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from frappe.model.document import Document
+
+class Subscriber(Document):
+	pass
diff --git a/erpnext/accounts/doctype/subscriber/test_subscriber.js b/erpnext/accounts/doctype/subscriber/test_subscriber.js
new file mode 100644
index 0000000..1fd4a1e
--- /dev/null
+++ b/erpnext/accounts/doctype/subscriber/test_subscriber.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Subscriber", function (assert) {
+	let done = assert.async();
+
+	// number of asserts
+	assert.expect(1);
+
+	frappe.run_serially([
+		// insert a new Subscriber
+		() => frappe.tests.make('Subscriber', [
+			// values to be set
+			{key: 'value'}
+		]),
+		() => {
+			assert.equal(cur_frm.doc.key, 'value');
+		},
+		() => done()
+	]);
+
+});
diff --git a/erpnext/accounts/doctype/subscriber/test_subscriber.py b/erpnext/accounts/doctype/subscriber/test_subscriber.py
new file mode 100644
index 0000000..3e2fc07
--- /dev/null
+++ b/erpnext/accounts/doctype/subscriber/test_subscriber.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import unittest
+
+class TestSubscriber(unittest.TestCase):
+	pass
diff --git a/erpnext/accounts/doctype/subscription_invoice/__init__.py b/erpnext/accounts/doctype/subscription_invoice/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/doctype/subscription_invoice/__init__.py
diff --git a/erpnext/accounts/doctype/subscription_invoice/subscription_invoice.js b/erpnext/accounts/doctype/subscription_invoice/subscription_invoice.js
new file mode 100644
index 0000000..f5ea804
--- /dev/null
+++ b/erpnext/accounts/doctype/subscription_invoice/subscription_invoice.js
@@ -0,0 +1,2 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
diff --git a/erpnext/accounts/doctype/subscription_invoice/subscription_invoice.json b/erpnext/accounts/doctype/subscription_invoice/subscription_invoice.json
new file mode 100644
index 0000000..c4bae1d
--- /dev/null
+++ b/erpnext/accounts/doctype/subscription_invoice/subscription_invoice.json
@@ -0,0 +1,73 @@
+{
+ "allow_copy": 0, 
+ "allow_guest_to_view": 0, 
+ "allow_import": 0, 
+ "allow_rename": 0, 
+ "beta": 0, 
+ "creation": "2018-02-26 04:21:41.265055", 
+ "custom": 0, 
+ "docstatus": 0, 
+ "doctype": "DocType", 
+ "document_type": "", 
+ "editable_grid": 1, 
+ "engine": "InnoDB", 
+ "fields": [
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "invoice", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Invoice", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Sales Invoice", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 1, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }
+ ], 
+ "has_web_view": 0, 
+ "hide_heading": 0, 
+ "hide_toolbar": 0, 
+ "idx": 0, 
+ "image_view": 0, 
+ "in_create": 0, 
+ "is_submittable": 0, 
+ "issingle": 0, 
+ "istable": 1, 
+ "max_attachments": 0, 
+ "modified": "2018-02-26 10:48:07.033422", 
+ "modified_by": "Administrator", 
+ "module": "Accounts", 
+ "name": "Subscription Invoice", 
+ "name_case": "", 
+ "owner": "Administrator", 
+ "permissions": [], 
+ "quick_entry": 1, 
+ "read_only": 0, 
+ "read_only_onload": 0, 
+ "show_name_in_global_search": 0, 
+ "sort_field": "modified", 
+ "sort_order": "DESC", 
+ "track_changes": 1, 
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/subscription_invoice/subscription_invoice.py b/erpnext/accounts/doctype/subscription_invoice/subscription_invoice.py
new file mode 100644
index 0000000..6f459b4
--- /dev/null
+++ b/erpnext/accounts/doctype/subscription_invoice/subscription_invoice.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from frappe.model.document import Document
+
+class SubscriptionInvoice(Document):
+	pass
diff --git a/erpnext/accounts/doctype/subscription_invoice/test_subscription_invoice.js b/erpnext/accounts/doctype/subscription_invoice/test_subscription_invoice.js
new file mode 100644
index 0000000..15d3df2
--- /dev/null
+++ b/erpnext/accounts/doctype/subscription_invoice/test_subscription_invoice.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Subscription Invoice", function (assert) {
+	let done = assert.async();
+
+	// number of asserts
+	assert.expect(1);
+
+	frappe.run_serially([
+		// insert a new Subscription Invoice
+		() => frappe.tests.make('Subscription Invoice', [
+			// values to be set
+			{key: 'value'}
+		]),
+		() => {
+			assert.equal(cur_frm.doc.key, 'value');
+		},
+		() => done()
+	]);
+
+});
diff --git a/erpnext/accounts/doctype/subscription_invoice/test_subscription_invoice.py b/erpnext/accounts/doctype/subscription_invoice/test_subscription_invoice.py
new file mode 100644
index 0000000..e60a4ee
--- /dev/null
+++ b/erpnext/accounts/doctype/subscription_invoice/test_subscription_invoice.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import unittest
+
+class TestSubscriptionInvoice(unittest.TestCase):
+	pass
diff --git a/erpnext/accounts/doctype/subscription_plan/__init__.py b/erpnext/accounts/doctype/subscription_plan/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/doctype/subscription_plan/__init__.py
diff --git a/erpnext/accounts/doctype/subscription_plan/subscription_plan.js b/erpnext/accounts/doctype/subscription_plan/subscription_plan.js
new file mode 100644
index 0000000..f5ea804
--- /dev/null
+++ b/erpnext/accounts/doctype/subscription_plan/subscription_plan.js
@@ -0,0 +1,2 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
diff --git a/erpnext/accounts/doctype/subscription_plan/subscription_plan.json b/erpnext/accounts/doctype/subscription_plan/subscription_plan.json
new file mode 100644
index 0000000..ab58e7c
--- /dev/null
+++ b/erpnext/accounts/doctype/subscription_plan/subscription_plan.json
@@ -0,0 +1,255 @@
+{
+ "allow_copy": 0, 
+ "allow_guest_to_view": 0, 
+ "allow_import": 0, 
+ "allow_rename": 1, 
+ "autoname": "field:plan_name", 
+ "beta": 0, 
+ "creation": "2018-02-24 11:31:23.066506", 
+ "custom": 0, 
+ "docstatus": 0, 
+ "doctype": "DocType", 
+ "document_type": "", 
+ "editable_grid": 1, 
+ "engine": "InnoDB", 
+ "fields": [
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "plan_name", 
+   "fieldtype": "Data", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Plan Name", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "item", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Item", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Item", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "currency", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Currency", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Currency", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "cost", 
+   "fieldtype": "Currency", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Cost", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "default": "Day", 
+   "fieldname": "billing_interval", 
+   "fieldtype": "Select", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Billing Interval", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Day\nWeek\nMonth\nYear", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "default": "1", 
+   "description": "Number of intervals for the interval field e.g if Interval is 'Days' and Billing Interval Count is 3, invoices will be generated every 3 days", 
+   "fieldname": "billing_interval_count", 
+   "fieldtype": "Int", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Billing Interval Count", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }
+ ], 
+ "has_web_view": 0, 
+ "hide_heading": 0, 
+ "hide_toolbar": 0, 
+ "idx": 0, 
+ "image_view": 0, 
+ "in_create": 0, 
+ "is_submittable": 0, 
+ "issingle": 0, 
+ "istable": 0, 
+ "max_attachments": 0, 
+ "modified": "2018-02-27 09:12:58.330140", 
+ "modified_by": "Administrator", 
+ "module": "Accounts", 
+ "name": "Subscription Plan", 
+ "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": 0, 
+   "permlevel": 0, 
+   "print": 1, 
+   "read": 1, 
+   "report": 1, 
+   "role": "System Manager", 
+   "set_user_permissions": 0, 
+   "share": 1, 
+   "submit": 0, 
+   "write": 1
+  }
+ ], 
+ "quick_entry": 1, 
+ "read_only": 0, 
+ "read_only_onload": 0, 
+ "show_name_in_global_search": 0, 
+ "sort_field": "modified", 
+ "sort_order": "DESC", 
+ "track_changes": 1, 
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/subscription_plan/subscription_plan.py b/erpnext/accounts/doctype/subscription_plan/subscription_plan.py
new file mode 100644
index 0000000..4b8c8fc
--- /dev/null
+++ b/erpnext/accounts/doctype/subscription_plan/subscription_plan.py
@@ -0,0 +1,15 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class SubscriptionPlan(Document):
+	def validate(self):
+		self.validate_interval_count()
+
+	def validate_interval_count(self):
+		if self.billing_interval_count < 1:
+			frappe.throw('Billing Interval Count cannot be less than 1')
diff --git a/erpnext/accounts/doctype/subscription_plan/test_subscription_plan.js b/erpnext/accounts/doctype/subscription_plan/test_subscription_plan.js
new file mode 100644
index 0000000..3ceb9a6
--- /dev/null
+++ b/erpnext/accounts/doctype/subscription_plan/test_subscription_plan.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Subscription Plan", function (assert) {
+	let done = assert.async();
+
+	// number of asserts
+	assert.expect(1);
+
+	frappe.run_serially([
+		// insert a new Subscription Plan
+		() => frappe.tests.make('Subscription Plan', [
+			// values to be set
+			{key: 'value'}
+		]),
+		() => {
+			assert.equal(cur_frm.doc.key, 'value');
+		},
+		() => done()
+	]);
+
+});
diff --git a/erpnext/accounts/doctype/subscription_plan/test_subscription_plan.py b/erpnext/accounts/doctype/subscription_plan/test_subscription_plan.py
new file mode 100644
index 0000000..73afbf6
--- /dev/null
+++ b/erpnext/accounts/doctype/subscription_plan/test_subscription_plan.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import unittest
+
+class TestSubscriptionPlan(unittest.TestCase):
+	pass
diff --git a/erpnext/accounts/doctype/subscription_plan_detail/__init__.py b/erpnext/accounts/doctype/subscription_plan_detail/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/doctype/subscription_plan_detail/__init__.py
diff --git a/erpnext/accounts/doctype/subscription_plan_detail/subscription_plan_detail.json b/erpnext/accounts/doctype/subscription_plan_detail/subscription_plan_detail.json
new file mode 100644
index 0000000..c112923
--- /dev/null
+++ b/erpnext/accounts/doctype/subscription_plan_detail/subscription_plan_detail.json
@@ -0,0 +1,73 @@
+{
+ "allow_copy": 0, 
+ "allow_guest_to_view": 0, 
+ "allow_import": 0, 
+ "allow_rename": 0, 
+ "beta": 0, 
+ "creation": "2018-02-25 07:35:07.736146", 
+ "custom": 0, 
+ "docstatus": 0, 
+ "doctype": "DocType", 
+ "document_type": "", 
+ "editable_grid": 1, 
+ "engine": "InnoDB", 
+ "fields": [
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "plan", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Plan", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Subscription Plan", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }
+ ], 
+ "has_web_view": 0, 
+ "hide_heading": 0, 
+ "hide_toolbar": 0, 
+ "idx": 0, 
+ "image_view": 0, 
+ "in_create": 0, 
+ "is_submittable": 0, 
+ "issingle": 0, 
+ "istable": 1, 
+ "max_attachments": 0, 
+ "modified": "2018-02-25 07:35:07.736146", 
+ "modified_by": "Administrator", 
+ "module": "Accounts", 
+ "name": "Subscription Plan Detail", 
+ "name_case": "", 
+ "owner": "Administrator", 
+ "permissions": [], 
+ "quick_entry": 1, 
+ "read_only": 0, 
+ "read_only_onload": 0, 
+ "show_name_in_global_search": 0, 
+ "sort_field": "modified", 
+ "sort_order": "DESC", 
+ "track_changes": 1, 
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/subscription_plan_detail/subscription_plan_detail.py b/erpnext/accounts/doctype/subscription_plan_detail/subscription_plan_detail.py
new file mode 100644
index 0000000..1d9606f
--- /dev/null
+++ b/erpnext/accounts/doctype/subscription_plan_detail/subscription_plan_detail.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from frappe.model.document import Document
+
+class SubscriptionPlanDetail(Document):
+	pass
diff --git a/erpnext/accounts/doctype/subscription_settings/__init__.py b/erpnext/accounts/doctype/subscription_settings/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/doctype/subscription_settings/__init__.py
diff --git a/erpnext/accounts/doctype/subscription_settings/subscription_settings.js b/erpnext/accounts/doctype/subscription_settings/subscription_settings.js
new file mode 100644
index 0000000..f5ea804
--- /dev/null
+++ b/erpnext/accounts/doctype/subscription_settings/subscription_settings.js
@@ -0,0 +1,2 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
diff --git a/erpnext/accounts/doctype/subscription_settings/subscription_settings.json b/erpnext/accounts/doctype/subscription_settings/subscription_settings.json
new file mode 100644
index 0000000..8c7c6f3
--- /dev/null
+++ b/erpnext/accounts/doctype/subscription_settings/subscription_settings.json
@@ -0,0 +1,179 @@
+{
+ "allow_copy": 0, 
+ "allow_guest_to_view": 0, 
+ "allow_import": 0, 
+ "allow_rename": 0, 
+ "beta": 0, 
+ "creation": "2018-02-26 06:13:37.910139", 
+ "custom": 0, 
+ "docstatus": 0, 
+ "doctype": "DocType", 
+ "document_type": "", 
+ "editable_grid": 1, 
+ "engine": "InnoDB", 
+ "fields": [
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "default": "1", 
+   "description": "Number of days after invoice date has elapsed before canceling subscription or marking subscription as unpaid", 
+   "fieldname": "grace_period", 
+   "fieldtype": "Int", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Grace Period", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "default": "0", 
+   "fieldname": "cancel_after_grace", 
+   "fieldtype": "Check", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Cancel Invoice After Grace Period", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "default": "1", 
+   "fieldname": "prorate", 
+   "fieldtype": "Check", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Prorate", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }
+ ], 
+ "has_web_view": 0, 
+ "hide_heading": 0, 
+ "hide_toolbar": 0, 
+ "idx": 0, 
+ "image_view": 0, 
+ "in_create": 0, 
+ "is_submittable": 0, 
+ "issingle": 1, 
+ "istable": 0, 
+ "max_attachments": 0, 
+ "modified": "2018-02-26 13:58:09.455832", 
+ "modified_by": "Administrator", 
+ "module": "Accounts", 
+ "name": "Subscription Settings", 
+ "name_case": "", 
+ "owner": "Administrator", 
+ "permissions": [
+  {
+   "amend": 0, 
+   "apply_user_permissions": 0, 
+   "cancel": 0, 
+   "create": 1, 
+   "delete": 1, 
+   "email": 1, 
+   "export": 0, 
+   "if_owner": 0, 
+   "import": 0, 
+   "permlevel": 0, 
+   "print": 1, 
+   "read": 1, 
+   "report": 0, 
+   "role": "System Manager", 
+   "set_user_permissions": 0, 
+   "share": 1, 
+   "submit": 0, 
+   "write": 1
+  }, 
+  {
+   "amend": 0, 
+   "apply_user_permissions": 0, 
+   "cancel": 0, 
+   "create": 1, 
+   "delete": 1, 
+   "email": 1, 
+   "export": 0, 
+   "if_owner": 0, 
+   "import": 0, 
+   "permlevel": 0, 
+   "print": 1, 
+   "read": 1, 
+   "report": 0, 
+   "role": "Administrator", 
+   "set_user_permissions": 0, 
+   "share": 1, 
+   "submit": 0, 
+   "write": 1
+  }
+ ], 
+ "quick_entry": 1, 
+ "read_only": 0, 
+ "read_only_onload": 0, 
+ "show_name_in_global_search": 0, 
+ "sort_field": "modified", 
+ "sort_order": "DESC", 
+ "track_changes": 1, 
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/subscription_settings/subscription_settings.py b/erpnext/accounts/doctype/subscription_settings/subscription_settings.py
new file mode 100644
index 0000000..cc378e4
--- /dev/null
+++ b/erpnext/accounts/doctype/subscription_settings/subscription_settings.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from frappe.model.document import Document
+
+class SubscriptionSettings(Document):
+	pass
diff --git a/erpnext/accounts/doctype/subscription_settings/test_subscription_settings.js b/erpnext/accounts/doctype/subscription_settings/test_subscription_settings.js
new file mode 100644
index 0000000..5a751ea
--- /dev/null
+++ b/erpnext/accounts/doctype/subscription_settings/test_subscription_settings.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Subscription Settings", function (assert) {
+	let done = assert.async();
+
+	// number of asserts
+	assert.expect(1);
+
+	frappe.run_serially([
+		// insert a new Subscription Settings
+		() => frappe.tests.make('Subscription Settings', [
+			// values to be set
+			{key: 'value'}
+		]),
+		() => {
+			assert.equal(cur_frm.doc.key, 'value');
+		},
+		() => done()
+	]);
+
+});
diff --git a/erpnext/accounts/doctype/subscription_settings/test_subscription_settings.py b/erpnext/accounts/doctype/subscription_settings/test_subscription_settings.py
new file mode 100644
index 0000000..82c7e1d
--- /dev/null
+++ b/erpnext/accounts/doctype/subscription_settings/test_subscription_settings.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import unittest
+
+class TestSubscriptionSettings(unittest.TestCase):
+	pass
diff --git a/erpnext/accounts/doctype/subscriptions/__init__.py b/erpnext/accounts/doctype/subscriptions/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/accounts/doctype/subscriptions/__init__.py
diff --git a/erpnext/accounts/doctype/subscriptions/subscriptions.js b/erpnext/accounts/doctype/subscriptions/subscriptions.js
new file mode 100644
index 0000000..92cb93f
--- /dev/null
+++ b/erpnext/accounts/doctype/subscriptions/subscriptions.js
@@ -0,0 +1,78 @@
+// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+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},
+			freeze: true,
+			callback: function(data){
+				if(!data.exc){
+					frm.reload_doc();
+				}
+			}
+		});
+	}
+});
diff --git a/erpnext/accounts/doctype/subscriptions/subscriptions.json b/erpnext/accounts/doctype/subscriptions/subscriptions.json
new file mode 100644
index 0000000..90949e3
--- /dev/null
+++ b/erpnext/accounts/doctype/subscriptions/subscriptions.json
@@ -0,0 +1,695 @@
+{
+ "allow_copy": 0, 
+ "allow_guest_to_view": 0, 
+ "allow_import": 0, 
+ "allow_rename": 0, 
+ "autoname": "SUB.####", 
+ "beta": 0, 
+ "creation": "2018-02-26 04:13:14.153718", 
+ "custom": 0, 
+ "docstatus": 0, 
+ "doctype": "DocType", 
+ "document_type": "", 
+ "editable_grid": 1, 
+ "engine": "InnoDB", 
+ "fields": [
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "subscriber", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 1, 
+   "in_standard_filter": 0, 
+   "label": "Subscriber", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Subscriber", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 1, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "default": "0", 
+   "fieldname": "cancel_at_period_end", 
+   "fieldtype": "Check", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Cancel At End Of Period", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "start", 
+   "fieldtype": "Date", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Subscription Start Date", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 1, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "cancelation_date", 
+   "fieldtype": "Date", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Cancelation Date", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 1, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "current_invoice_start", 
+   "fieldtype": "Date", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Current Invoice Start Date", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 1, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "current_invoice_end", 
+   "fieldtype": "Date", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Current Invoice End Date", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 1, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "trial_period_start", 
+   "fieldtype": "Date", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Trial Period Start Date", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 1, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "depends_on": "eval:doc.trial_period_start", 
+   "fieldname": "trial_period_end", 
+   "fieldtype": "Date", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Trial Period End Date", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 1, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "default": "0", 
+   "description": "Number of days that the subscriber has to pay invoices generated by this subscription", 
+   "fieldname": "days_until_due", 
+   "fieldtype": "Int", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Days Until Due", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "default": "1", 
+   "fieldname": "quantity", 
+   "fieldtype": "Int", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Quantity", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "plans", 
+   "fieldtype": "Table", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Plans", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Subscription Plan Detail", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "sb_1", 
+   "fieldtype": "Section Break", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Taxes", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "tax_template", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Sales Taxes and Charges Template", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Sales Taxes and Charges Template", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "sb_2", 
+   "fieldtype": "Section Break", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Discounts", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "apply_additional_discount", 
+   "fieldtype": "Select", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Apply Additional Discount On", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "\nGrand Total\nNet total", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "additional_discount_percentage", 
+   "fieldtype": "Percent", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Additional DIscount Percentage", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "additional_discount_amount", 
+   "fieldtype": "Currency", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Additional DIscount Amount", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "status", 
+   "fieldtype": "Select", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Status", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Trialling\nActive\nPast Due Date\nCanceled\nUnpaid", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 1, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "depends_on": "eval:doc.invoices", 
+   "fieldname": "sb_3", 
+   "fieldtype": "Section Break", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Invoices", 
+   "length": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "invoices", 
+   "fieldtype": "Table", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Invoices", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Subscription Invoice", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "translatable": 0, 
+   "unique": 0
+  }
+ ], 
+ "has_web_view": 0, 
+ "hide_heading": 0, 
+ "hide_toolbar": 0, 
+ "idx": 0, 
+ "image_view": 0, 
+ "in_create": 0, 
+ "is_submittable": 0, 
+ "issingle": 0, 
+ "istable": 0, 
+ "max_attachments": 0, 
+ "modified": "2018-03-01 17:12:11.105074", 
+ "modified_by": "Administrator", 
+ "module": "Accounts", 
+ "name": "Subscriptions", 
+ "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": 0, 
+   "permlevel": 0, 
+   "print": 1, 
+   "read": 1, 
+   "report": 1, 
+   "role": "System Manager", 
+   "set_user_permissions": 0, 
+   "share": 1, 
+   "submit": 0, 
+   "write": 1
+  }
+ ], 
+ "quick_entry": 0, 
+ "read_only": 0, 
+ "read_only_onload": 0, 
+ "show_name_in_global_search": 0, 
+ "sort_field": "modified", 
+ "sort_order": "DESC", 
+ "track_changes": 1, 
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/subscriptions/subscriptions.py b/erpnext/accounts/doctype/subscriptions/subscriptions.py
new file mode 100644
index 0000000..a193e69
--- /dev/null
+++ b/erpnext/accounts/doctype/subscriptions/subscriptions.py
@@ -0,0 +1,499 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+
+import frappe
+from frappe import _
+from frappe.model.document import Document
+from frappe.utils.data import nowdate, getdate, cint, add_days, date_diff, get_last_day, add_to_date, flt
+
+
+class Subscriptions(Document):
+	def before_insert(self):
+		# update start just before the subscription doc is created
+		self.update_subscription_period(self.start)
+
+	def update_subscription_period(self, date=None):
+		"""
+		Subscription period is the period to be billed. This method updates the
+		beginning of the billing period and end of the billing period.
+
+		The beginning of the billing period is represented in the doctype as
+		`current_invoice_start` and the end of the billing period is represented
+		as `current_invoice_end`.
+		"""
+		self.set_current_invoice_start(date)
+		self.set_current_invoice_end()
+
+	def set_current_invoice_start(self, date=None):
+		"""
+		This sets the date of the beginning of the current billing period.
+		If the `date` parameter is not given , it will be automatically set as today's
+		date.
+		"""
+		if self.trial_period_start and self.is_trialling():
+			self.current_invoice_start = self.trial_period_start
+		elif not date:
+			self.current_invoice_start = nowdate()
+		elif date:
+			self.current_invoice_start = date
+
+	def set_current_invoice_end(self):
+		"""
+		This sets the date of the end of the current billing period.
+
+		If the subscription is in trial period, it will be set as the end of the
+		trial period.
+
+		If is not in a trial period, it will be `x` days from the beginning of the
+		current billing period where `x` is the billing interval from the
+		`Subscription Plan` in the `Subscription`.
+		"""
+		if self.is_trialling():
+			self.current_invoice_end = self.trial_period_end
+		else:
+			billing_cycle_info = self.get_billing_cycle()
+			if billing_cycle_info:
+				self.current_invoice_end = add_to_date(self.current_invoice_start, **billing_cycle_info)
+			else:
+				self.current_invoice_end = get_last_day(self.current_invoice_start)
+
+	def get_billing_cycle(self):
+		"""
+		Returns a dict containing billing cycle information deduced from the
+		`Subscription Plan` in the `Subscription`.
+		"""
+		return self.get_billing_cycle_data()
+
+	@staticmethod
+	def validate_plans_billing_cycle(billing_cycle_data):
+		"""
+		Makes sure that all `Subscription Plan` in the `Subscription` have the
+		same billing interval
+		"""
+		if billing_cycle_data and len(billing_cycle_data) != 1:
+			frappe.throw(_('You can only have Plans with the same billing cycle in a Subscription'))
+
+	def get_billing_cycle_and_interval(self):
+		"""
+		Returns a dict representing the billing interval and cycle for this `Subscription`.
+
+		You shouldn't need to call this directly. Use `get_billing_cycle` instead.
+		"""
+		plan_names = [plan.plan for plan in self.plans]
+		billing_info = frappe.db.sql(
+			'select distinct `billing_interval`, `billing_interval_count` '
+			'from `tabSubscription Plan` '
+			'where name in %s',
+			(plan_names,), as_dict=1
+		)
+
+		return billing_info
+
+	def get_billing_cycle_data(self):
+		"""
+		Returns dict contain the billing cycle data.
+
+		You shouldn't need to call this directly. Use `get_billing_cycle` instead.
+		"""
+		billing_info = self.get_billing_cycle_and_interval()
+
+		self.validate_plans_billing_cycle(billing_info)
+
+		if billing_info:
+			data = dict()
+			interval = billing_info[0]['billing_interval']
+			interval_count = billing_info[0]['billing_interval_count']
+			if interval not in ['Day', 'Week']:
+				data['days'] = -1
+			if interval == 'Day':
+				data['days'] = interval_count - 1
+			elif interval == 'Month':
+				data['months'] = interval_count
+			elif interval == 'Year':
+				data['years'] = interval_count
+			# todo: test week
+			elif interval == 'Week':
+				data['days'] = interval_count * 7 - 1
+
+			return data
+
+	def set_status_grace_period(self):
+		"""
+		Sets the `Subscription` `status` based on the preference set in `Subscription Settings`.
+
+		Used when the `Subscription` needs to decide what to do after the current generated
+		invoice is past it's due date and grace period.
+		"""
+		subscription_settings = frappe.get_single('Subscription Settings')
+		if self.status == 'Past Due Date' and self.is_past_grace_period():
+			self.status = 'Canceled' if cint(subscription_settings.cancel_after_grace) else 'Unpaid'
+
+	def set_subscription_status(self):
+		"""
+		Sets the status of the `Subscription`
+		"""
+		if self.is_trialling():
+			self.status = 'Trialling'
+		elif self.status == 'Past Due Date' and self.is_past_grace_period():
+			subscription_settings = frappe.get_single('Subscription Settings')
+			self.status = 'Canceled' if cint(subscription_settings.cancel_after_grace) else 'Unpaid'
+		elif self.status == 'Past Due Date' and not self.has_outstanding_invoice():
+			self.status = 'Active'
+		elif self.current_invoice_is_past_due():
+			self.status = 'Past Due Date'
+		elif self.is_new_subscription():
+			self.status = 'Active'
+			# todo: then generate new invoice
+		self.save()
+
+	def is_trialling(self):
+		"""
+		Returns `True` if the `Subscription` is trial period.
+		"""
+		return not self.period_has_passed(self.trial_period_end) and self.is_new_subscription()
+
+	@staticmethod
+	def period_has_passed(end_date):
+		"""
+		Returns true if the given `end_date` has passed
+		"""
+		# todo: test for illegal time
+		if not end_date:
+			return True
+
+		end_date = getdate(end_date)
+		return getdate(nowdate()) > getdate(end_date)
+
+	def is_past_grace_period(self):
+		"""
+		Returns `True` if the grace period for the `Subscription` has passed
+		"""
+		current_invoice = self.get_current_invoice()
+		if self.current_invoice_is_past_due(current_invoice):
+			subscription_settings = frappe.get_single('Subscription Settings')
+			grace_period = cint(subscription_settings.grace_period)
+
+			return getdate(nowdate()) > add_days(current_invoice.due_date, grace_period)
+
+	def current_invoice_is_past_due(self, current_invoice=None):
+		"""
+		Returns `True` if the current generated invoice is overdue
+		"""
+		if not current_invoice:
+			current_invoice = self.get_current_invoice()
+
+		if not current_invoice:
+			return False
+		else:
+			return getdate(nowdate()) > getdate(current_invoice.due_date)
+
+	def get_current_invoice(self):
+		"""
+		Returns the most recent generated invoice.
+		"""
+		if len(self.invoices):
+			current = self.invoices[-1]
+			if frappe.db.exists('Sales Invoice', current.invoice):
+				doc = frappe.get_doc('Sales Invoice', current.invoice)
+				return doc
+			else:
+				frappe.throw(_('Invoice {0} no longer exists'.format(current.invoice)))
+
+	def is_new_subscription(self):
+		"""
+		Returns `True` if `Subscription` has never generated an invoice
+		"""
+		return len(self.invoices) == 0
+
+	def validate(self):
+		self.validate_trial_period()
+		self.validate_plans_billing_cycle(self.get_billing_cycle_and_interval())
+
+	def validate_trial_period(self):
+		"""
+		Runs sanity checks on trial period dates for the `Subscription`
+		"""
+		if self.trial_period_start and self.trial_period_end:
+			if getdate(self.trial_period_end) < getdate(self.trial_period_start):
+				frappe.throw(_('Trial Period End Date Cannot be before Trial Period Start Date'))
+
+		elif self.trial_period_start or self.trial_period_end:
+			frappe.throw(_('Both Trial Period Start Date and Trial Period End Date must be set'))
+
+	def after_insert(self):
+		# todo: deal with users who collect prepayments. Maybe a new Subscription Invoice doctype?
+		self.set_subscription_status()
+
+	def generate_invoice(self, prorate=0):
+		"""
+		Creates a `Sales Invoice` for the `Subscription`, updates `self.invoices` and
+		saves the `Subscription`.
+		"""
+		invoice = self.create_invoice(prorate)
+		self.append('invoices', {'invoice': invoice.name})
+		self.save()
+
+		return invoice
+
+	def create_invoice(self, prorate):
+		"""
+		Creates a `Sales Invoice`, submits it and returns it
+		"""
+		invoice = frappe.new_doc('Sales Invoice')
+		invoice.set_posting_time = 1
+		invoice.posting_date = self.current_invoice_start
+		invoice.customer = self.get_customer(self.subscriber)
+
+		# Subscription is better suited for service items. I won't update `update_stock`
+		# for that reason
+		items_list = self.get_items_from_plans(self.plans, prorate)
+		for item in items_list:
+			item['qty'] = self.quantity
+			invoice.append('items',	item)
+
+		# Taxes
+		if self.tax_template:
+			invoice.taxes_and_charges = self.tax_template
+			invoice.set_taxes()
+
+		# Due date
+		invoice.append(
+			'payment_schedule',
+			{
+				'due_date': add_days(self.current_invoice_end, cint(self.days_until_due)),
+				'invoice_portion': 100
+			}
+		)
+
+		# Discounts
+		if self.additional_discount_percentage:
+			invoice.additional_discount_percentage = self.additional_discount_percentage
+
+		if self.additional_discount_amount:
+			invoice.discount_amount = self.additional_discount_amount
+
+		if self.additional_discount_percentage or self.additional_discount_amount:
+			discount_on = self.apply_additional_discount
+			invoice.apply_additional_discount = discount_on if discount_on else 'Grand Total'
+
+		invoice.save()
+		invoice.submit()
+
+		return invoice
+
+	@staticmethod
+	def get_customer(subscriber_name):
+		"""
+		Returns the `Customer` linked to the `Subscriber`
+		"""
+		return frappe.get_value('Subscriber', subscriber_name)
+
+	def get_items_from_plans(self, plans, prorate=0):
+		"""
+		Returns the `Item`s linked to `Subscription Plan`
+		"""
+		plan_items = [plan.plan for plan in plans]
+		item_names = None
+
+		if plan_items and not prorate:
+			item_names = frappe.db.sql(
+				'select item as item_code, cost as rate from `tabSubscription Plan` where name in %s',
+				(plan_items,), as_dict=1
+			)
+
+		elif plan_items:
+			prorate_factor = get_prorata_factor(self.current_invoice_end, self.current_invoice_start)
+
+			item_names = frappe.db.sql(
+				'select item as item_code, cost * %s as rate from `tabSubscription Plan` where name in %s',
+				(prorate_factor, plan_items,), as_dict=1
+			)
+
+		return item_names
+
+	def process(self):
+		"""
+		To be called by task periodically. It checks the subscription and takes appropriate action
+		as need be. It calls either of these methods depending the `Subscription` status:
+		1. `process_for_active`
+		2. `process_for_past_due`
+		"""
+		if self.status == 'Active':
+			self.process_for_active()
+		elif self.status in ['Past Due Date', 'Unpaid']:
+			self.process_for_past_due_date()
+
+		self.save()
+
+	def process_for_active(self):
+		"""
+		Called by `process` if the status of the `Subscription` is 'Active'.
+
+		The possible outcomes of this method are:
+		1. Generate a new invoice
+		2. Change the `Subscription` status to 'Past Due Date'
+		3. Change the `Subscription` status to 'Canceled'
+		"""
+		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() and getdate(nowdate()) > getdate(self.current_invoice_end):
+			self.status = 'Past Due Date'
+
+		if self.cancel_at_period_end and getdate(nowdate()) > self.current_invoice_end:
+			self.cancel_subscription_at_period_end()
+
+	def cancel_subscription_at_period_end(self):
+		"""
+		Called when `Subscription.cancel_at_period_end` is truthy
+		"""
+		self.status = 'Canceled'
+		if not self.cancelation_date:
+			self.cancelation_date = nowdate()
+
+	def process_for_past_due_date(self):
+		"""
+		Called by `process` if the status of the `Subscription` is 'Past Due Date'.
+
+		The possible outcomes of this method are:
+		1. Change the `Subscription` status to 'Active'
+		2. Change the `Subscription` status to 'Canceled'
+		3. Change the `Subscription` status to 'Unpaid'
+		"""
+		current_invoice = self.get_current_invoice()
+		if not current_invoice:
+			frappe.throw(_('Current invoice {0} is missing'.format(current_invoice.invoice)))
+		else:
+			if self.is_not_outstanding(current_invoice):
+				self.status = 'Active'
+				self.update_subscription_period(nowdate())
+			else:
+				self.set_status_grace_period()
+
+	@staticmethod
+	def is_not_outstanding(invoice):
+		"""
+		Return `True` if the given invoice is paid
+		"""
+		return invoice.status == 'Paid'
+
+	def has_outstanding_invoice(self):
+		"""
+		Returns `True` if the most recent invoice for the `Subscription` is not paid
+		"""
+		current_invoice = self.get_current_invoice()
+		if not current_invoice:
+			return False
+		else:
+			return not self.is_not_outstanding(current_invoice)
+
+	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.
+		"""
+		if self.status != 'Canceled':
+			to_generate_invoice = True if self.status == 'Active' else False
+			to_prorate = frappe.db.get_single_value('Subscription Settings', 'prorate')
+			self.status = 'Canceled'
+			self.cancelation_date = nowdate()
+			if to_generate_invoice:
+				self.generate_invoice(prorate=to_prorate)
+			self.save()
+
+	def restart_subscription(self):
+		"""
+		This sets the subscription as active. The subscription will be made to be like a new
+		subscription and the `Subscription` will lose all the history of generated invoices
+		it has.
+		"""
+		if self.status == 'Canceled':
+			self.status = 'Active'
+			self.db_set('start', nowdate())
+			self.update_subscription_period(nowdate())
+			self.invoices = []
+			self.save()
+		else:
+			frappe.throw(_('You cannot restart a Subscription that is not cancelled.'))
+
+	def get_precision(self):
+		invoice = self.get_current_invoice()
+		if invoice:
+			return invoice.precision('grand_total')
+
+
+def get_prorata_factor(period_end, period_start):
+	diff = flt(date_diff(nowdate(), period_start) + 1)
+	plan_days = flt(date_diff(period_end, period_start) + 1)
+	prorate_factor = diff / plan_days
+
+	return prorate_factor
+
+
+def process_all():
+	"""
+	Task to updates the status of all `Subscription` apart from those that are cancelled
+	"""
+	subscriptions = get_all_subscriptions()
+	for subscription in subscriptions:
+		process(subscription)
+
+
+def get_all_subscriptions():
+	"""
+	Returns all `Subscription` documents
+	"""
+	return frappe.db.sql(
+		'select name from `tabSubscriptions` where status != "Canceled"',
+		as_dict=1
+	)
+
+
+def process(data):
+	"""
+	Checks a `Subscription` and updates it status as necessary
+	"""
+	if data:
+		try:
+			subscription = frappe.get_doc('Subscriptions', data['name'])
+			subscription.process()
+			frappe.db.commit()
+		except frappe.ValidationError:
+			frappe.db.rollback()
+			frappe.db.begin()
+			frappe.log_error(frappe.get_traceback())
+			frappe.db.commit()
+
+
+@frappe.whitelist()
+def cancel_subscription(name):
+	"""
+	Cancels a `Subscription`. This will stop the `Subscription` from further invoicing the
+	`Subscriber` but all already outstanding invoices will not be affected.
+	"""
+	subscription = frappe.get_doc('Subscriptions', name)
+	subscription.cancel_subscription()
+
+
+@frappe.whitelist()
+def restart_subscription(name):
+	"""
+	Restarts a cancelled `Subscription`. The `Subscription` will 'forget' the history of
+	all invoices it has generated
+	"""
+	subscription = frappe.get_doc('Subscriptions', name)
+	subscription.restart_subscription()
+
+
+@frappe.whitelist()
+def get_subscription_updates(name):
+	"""
+	Use this to get the latest state of the given `Subscription`
+	"""
+	subscription = frappe.get_doc('Subscriptions', name)
+	subscription.process()
diff --git a/erpnext/accounts/doctype/subscriptions/test_subscriptions.js b/erpnext/accounts/doctype/subscriptions/test_subscriptions.js
new file mode 100644
index 0000000..b5fe4ef
--- /dev/null
+++ b/erpnext/accounts/doctype/subscriptions/test_subscriptions.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Subscriptions", function (assert) {
+	let done = assert.async();
+
+	// number of asserts
+	assert.expect(1);
+
+	frappe.run_serially([
+		// insert a new Subscriptions
+		() => frappe.tests.make('Subscriptions', [
+			// values to be set
+			{key: 'value'}
+		]),
+		() => {
+			assert.equal(cur_frm.doc.key, 'value');
+		},
+		() => done()
+	]);
+
+});
diff --git a/erpnext/accounts/doctype/subscriptions/test_subscriptions.py b/erpnext/accounts/doctype/subscriptions/test_subscriptions.py
new file mode 100644
index 0000000..75c2bf2
--- /dev/null
+++ b/erpnext/accounts/doctype/subscriptions/test_subscriptions.py
@@ -0,0 +1,498 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+import unittest
+
+import frappe
+from erpnext.accounts.doctype.subscriptions.subscriptions import get_prorata_factor
+from frappe.utils.data import nowdate, add_days, add_to_date, add_months, date_diff, flt
+
+
+def create_plan():
+	if not frappe.db.exists('Subscription Plan', '_Test Plan Name'):
+		plan = frappe.new_doc('Subscription Plan')
+		plan.plan_name = '_Test Plan Name'
+		plan.item = '_Test Non Stock Item'
+		plan.cost = 900
+		plan.billing_interval = 'Month'
+		plan.billing_interval_count = 1
+		plan.insert()
+
+	if not frappe.db.exists('Subscription Plan', '_Test Plan Name 2'):
+		plan = frappe.new_doc('Subscription Plan')
+		plan.plan_name = '_Test Plan Name 2'
+		plan.item = '_Test Non Stock Item'
+		plan.cost = 1999
+		plan.billing_interval = 'Month'
+		plan.billing_interval_count = 1
+		plan.insert()
+
+	if not frappe.db.exists('Subscription Plan', '_Test Plan Name 3'):
+		plan = frappe.new_doc('Subscription Plan')
+		plan.plan_name = '_Test Plan Name 3'
+		plan.item = '_Test Non Stock Item'
+		plan.cost = 1999
+		plan.billing_interval = 'Day'
+		plan.billing_interval_count = 14
+		plan.insert()
+
+
+def create_subscriber():
+	if not frappe.db.exists('Subscriber', '_Test Customer'):
+		subscriber = frappe.new_doc('Subscriber')
+		subscriber.subscriber_name = '_Test Customer'
+		subscriber.customer = '_Test Customer'
+		subscriber.insert()
+
+
+class TestSubscriptions(unittest.TestCase):
+
+	def setUp(self):
+		create_plan()
+		create_subscriber()
+
+	def test_create_subscription_with_trial_with_correct_period(self):
+		subscription = frappe.new_doc('Subscriptions')
+		subscription.subscriber = '_Test Customer'
+		subscription.trial_period_start = nowdate()
+		subscription.trial_period_end = add_days(nowdate(), 30)
+		subscription.append('plans', {'plan': '_Test Plan Name'})
+		subscription.save()
+
+		self.assertEqual(subscription.trial_period_start, nowdate())
+		self.assertEqual(subscription.trial_period_end, add_days(nowdate(), 30))
+		self.assertEqual(subscription.trial_period_start, subscription.current_invoice_start)
+		self.assertEqual(subscription.trial_period_end, subscription.current_invoice_end)
+		self.assertEqual(subscription.invoices, [])
+		self.assertEqual(subscription.status, 'Trialling')
+
+		subscription.delete()
+
+	def test_create_subscription_without_trial_with_correct_period(self):
+		subscription = frappe.new_doc('Subscriptions')
+		subscription.subscriber = '_Test Customer'
+		subscription.append('plans', {'plan': '_Test Plan Name'})
+		subscription.save()
+
+		self.assertEqual(subscription.trial_period_start, None)
+		self.assertEqual(subscription.trial_period_end, None)
+		self.assertEqual(subscription.current_invoice_start, nowdate())
+		self.assertEqual(subscription.current_invoice_end, add_to_date(nowdate(), months=1, days=-1))
+		# No invoice is created
+		self.assertEqual(len(subscription.invoices), 0)
+		self.assertEqual(subscription.status, 'Active')
+
+		subscription.delete()
+
+	def test_create_subscription_trial_with_wrong_dates(self):
+		subscription = frappe.new_doc('Subscriptions')
+		subscription.subscriber = '_Test Customer'
+		subscription.trial_period_end = nowdate()
+		subscription.trial_period_start = add_days(nowdate(), 30)
+		subscription.append('plans', {'plan': '_Test Plan Name'})
+
+		self.assertRaises(frappe.ValidationError, subscription.save)
+		subscription.delete()
+
+	def test_create_subscription_multi_with_different_billing_fails(self):
+		subscription = frappe.new_doc('Subscriptions')
+		subscription.subscriber = '_Test Customer'
+		subscription.trial_period_end = nowdate()
+		subscription.trial_period_start = add_days(nowdate(), 30)
+		subscription.append('plans', {'plan': '_Test Plan Name'})
+		subscription.append('plans', {'plan': '_Test Plan Name 3'})
+
+		self.assertRaises(frappe.ValidationError, subscription.save)
+		subscription.delete()
+
+	def test_invoice_is_generated_at_end_of_billing_period(self):
+		subscription = frappe.new_doc('Subscriptions')
+		subscription.subscriber = '_Test Customer'
+		subscription.start = '2018-01-01'
+		subscription.append('plans', {'plan': '_Test Plan Name'})
+		subscription.insert()
+
+		self.assertEqual(subscription.status, 'Active')
+		self.assertEqual(subscription.current_invoice_start, '2018-01-01')
+		self.assertEqual(subscription.current_invoice_end, '2018-01-31')
+		subscription.process()
+
+		self.assertEqual(len(subscription.invoices), 1)
+		self.assertEqual(subscription.current_invoice_start, '2018-01-01')
+		self.assertEqual(subscription.status, 'Past Due Date')
+		subscription.delete()
+
+	def test_status_goes_back_to_active_after_invoice_is_paid(self):
+		subscription = frappe.new_doc('Subscriptions')
+		subscription.subscriber = '_Test Customer'
+		subscription.append('plans', {'plan': '_Test Plan Name'})
+		subscription.start = '2018-01-01'
+		subscription.insert()
+		subscription.process()	# generate first invoice
+		self.assertEqual(len(subscription.invoices), 1)
+		self.assertEqual(subscription.status, 'Past Due Date')
+
+		subscription.get_current_invoice()
+		current_invoice = subscription.get_current_invoice()
+
+		self.assertIsNotNone(current_invoice)
+
+		current_invoice.db_set('outstanding_amount', 0)
+		current_invoice.db_set('status', 'Paid')
+		subscription.process()
+
+		self.assertEqual(subscription.status, 'Active')
+		self.assertEqual(subscription.current_invoice_start, nowdate())
+		self.assertEqual(len(subscription.invoices), 1)
+
+		subscription.delete()
+
+	def test_subscription_cancel_after_grace_period(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.start = '2018-01-01'
+		subscription.insert()
+		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, 'Canceled')
+
+		settings.cancel_after_grace = default_grace_period_action
+		settings.save()
+		subscription.delete()
+
+	def test_subscription_unpaid_after_grace_period(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.start = '2018-01-01'
+		subscription.insert()
+		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')
+
+		settings.cancel_after_grace = default_grace_period_action
+		settings.save()
+		subscription.delete()
+
+	def test_subscription_invoice_days_until_due(self):
+		subscription = frappe.new_doc('Subscriptions')
+		subscription.subscriber = '_Test Customer'
+		subscription.append('plans', {'plan': '_Test Plan Name'})
+		subscription.days_until_due = 10
+		subscription.start = add_months(nowdate(), -1)
+		subscription.insert()
+		subscription.process()		# generate first invoice
+		self.assertEqual(len(subscription.invoices), 1)
+		self.assertEqual(subscription.status, 'Active')
+
+		subscription.delete()
+
+	def test_subscription_is_past_due_doesnt_change_within_grace_period(self):
+		settings = frappe.get_single('Subscription Settings')
+		grace_period = settings.grace_period
+		settings.grace_period = 1000
+		settings.save()
+
+		subscription = frappe.new_doc('Subscriptions')
+		subscription.subscriber = '_Test Customer'
+		subscription.append('plans', {'plan': '_Test Plan Name'})
+		subscription.start = '2018-01-01'
+		subscription.insert()
+		subscription.process()		# generate first invoice
+
+		self.assertEqual(subscription.status, 'Past Due Date')
+
+		subscription.process()
+		# Grace period is 1000 days so status should remain as Past Due Date
+		self.assertEqual(subscription.status, 'Past Due Date')
+
+		subscription.process()
+		self.assertEqual(subscription.status, 'Past Due Date')
+
+		subscription.process()
+		self.assertEqual(subscription.status, 'Past Due Date')
+
+		settings.grace_period = grace_period
+		settings.save()
+		subscription.delete()
+
+	def test_subscription_remains_active_during_invoice_period(self):
+		subscription = frappe.new_doc('Subscriptions')
+		subscription.subscriber = '_Test Customer'
+		subscription.append('plans', {'plan': '_Test Plan Name'})
+		subscription.save()
+		subscription.process()		# no changes expected
+
+		self.assertEqual(subscription.status, 'Active')
+		self.assertEqual(subscription.current_invoice_start, nowdate())
+		self.assertEqual(subscription.current_invoice_end, add_to_date(nowdate(), months=1, days=-1))
+		self.assertEqual(len(subscription.invoices), 0)
+
+		subscription.process()		# no changes expected still
+		self.assertEqual(subscription.status, 'Active')
+		self.assertEqual(subscription.current_invoice_start, nowdate())
+		self.assertEqual(subscription.current_invoice_end, add_to_date(nowdate(), months=1, days=-1))
+		self.assertEqual(len(subscription.invoices), 0)
+
+		subscription.process()		# no changes expected yet still
+		self.assertEqual(subscription.status, 'Active')
+		self.assertEqual(subscription.current_invoice_start, nowdate())
+		self.assertEqual(subscription.current_invoice_end, add_to_date(nowdate(), months=1, days=-1))
+		self.assertEqual(len(subscription.invoices), 0)
+
+		subscription.delete()
+
+	def test_subscription_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_subscription_cancellation_invoices(self):
+		settings = frappe.get_single('Subscription Settings')
+		to_prorate = settings.prorate
+		settings.prorate = 1
+		settings.save()
+
+		subscription = frappe.new_doc('Subscriptions')
+		subscription.subscriber = '_Test Customer'
+		subscription.append('plans', {'plan': '_Test Plan Name'})
+		subscription.save()
+
+		self.assertEqual(subscription.status, 'Active')
+
+		subscription.cancel_subscription()
+		# Invoice must have been generated
+		self.assertEqual(len(subscription.invoices), 1)
+
+		invoice = subscription.get_current_invoice()
+		diff = flt(date_diff(nowdate(), subscription.current_invoice_start) + 1)
+		plan_days = flt(date_diff(subscription.current_invoice_end, subscription.current_invoice_start) + 1)
+		prorate_factor = flt(diff/plan_days)
+
+		self.assertEqual(
+			flt(
+				get_prorata_factor(subscription.current_invoice_end, subscription.current_invoice_start),
+				2),
+			flt(prorate_factor, 2)
+		)
+		self.assertEqual(flt(invoice.grand_total, 2), flt(prorate_factor * 900, 2))
+		self.assertEqual(subscription.status, 'Canceled')
+
+		subscription.delete()
+		settings.prorate = to_prorate
+		settings.save()
+
+	def test_subscription_cancellation_invoices_with_prorata_false(self):
+		settings = frappe.get_single('Subscription Settings')
+		to_prorate = settings.prorate
+		settings.prorate = 0
+		settings.save()
+
+		subscription = frappe.new_doc('Subscriptions')
+		subscription.subscriber = '_Test Customer'
+		subscription.append('plans', {'plan': '_Test Plan Name'})
+		subscription.save()
+		subscription.cancel_subscription()
+		invoice = subscription.get_current_invoice()
+
+		self.assertEqual(invoice.grand_total, 900)
+
+		settings.prorate = to_prorate
+		settings.save()
+
+		subscription.delete()
+
+	def test_subscription_cancellation_invoices_with_prorata_true(self):
+		settings = frappe.get_single('Subscription Settings')
+		to_prorate = settings.prorate
+		settings.prorate = 1
+		settings.save()
+
+		subscription = frappe.new_doc('Subscriptions')
+		subscription.subscriber = '_Test Customer'
+		subscription.append('plans', {'plan': '_Test Plan Name'})
+		subscription.save()
+		subscription.cancel_subscription()
+
+		invoice = subscription.get_current_invoice()
+		diff = flt(date_diff(nowdate(), subscription.current_invoice_start) + 1)
+		plan_days = flt(date_diff(subscription.current_invoice_end, subscription.current_invoice_start) + 1)
+		prorate_factor = flt(diff / plan_days)
+
+		self.assertEqual(flt(invoice.grand_total, 2), flt(prorate_factor * 900, 2))
+
+		settings.prorate = to_prorate
+		settings.save()
+
+		subscription.delete()
+
+	def test_subcription_cancellation_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.start = '2018-01-01'
+		subscription.insert()
+		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.start = '2018-01-01'
+		subscription.insert()
+		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.start = '2018-01-01'
+		subscription.insert()
+		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_restart_active_subscription(self):
+		subscription = frappe.new_doc('Subscriptions')
+		subscription.subscriber = '_Test Customer'
+		subscription.append('plans', {'plan': '_Test Plan Name'})
+		subscription.save()
+
+		self.assertRaises(frappe.ValidationError, subscription.restart_subscription)
+
+		subscription.delete()
+
+	def test_subscription_invoice_discount_percentage(self):
+		subscription = frappe.new_doc('Subscriptions')
+		subscription.subscriber = '_Test Customer'
+		subscription.additional_discount_percentage = 10
+		subscription.append('plans', {'plan': '_Test Plan Name'})
+		subscription.save()
+		subscription.cancel_subscription()
+
+		invoice = subscription.get_current_invoice()
+
+		self.assertEqual(invoice.additional_discount_percentage, 10)
+		self.assertEqual(invoice.apply_discount_on, 'Grand Total')
+
+		subscription.delete()
+
+	def test_subscription_invoice_discount_amount(self):
+		subscription = frappe.new_doc('Subscriptions')
+		subscription.subscriber = '_Test Customer'
+		subscription.additional_discount_amount = 11
+		subscription.append('plans', {'plan': '_Test Plan Name'})
+		subscription.save()
+		subscription.cancel_subscription()
+
+		invoice = subscription.get_current_invoice()
+
+		self.assertEqual(invoice.discount_amount, 11)
+		self.assertEqual(invoice.apply_discount_on, 'Grand Total')
+
+		subscription.delete()
diff --git a/erpnext/docs/assets/img/articles/subscriber.png b/erpnext/docs/assets/img/articles/subscriber.png
new file mode 100644
index 0000000..e4ce64d
--- /dev/null
+++ b/erpnext/docs/assets/img/articles/subscriber.png
Binary files differ
diff --git a/erpnext/docs/assets/img/articles/subscription-1.png b/erpnext/docs/assets/img/articles/subscription-1.png
new file mode 100644
index 0000000..cbff30f9
--- /dev/null
+++ b/erpnext/docs/assets/img/articles/subscription-1.png
Binary files differ
diff --git a/erpnext/docs/assets/img/articles/subscription-plan.png b/erpnext/docs/assets/img/articles/subscription-plan.png
new file mode 100644
index 0000000..b60f796
--- /dev/null
+++ b/erpnext/docs/assets/img/articles/subscription-plan.png
Binary files differ
diff --git a/erpnext/docs/assets/img/articles/subscription-settings.png b/erpnext/docs/assets/img/articles/subscription-settings.png
new file mode 100644
index 0000000..405f0bf
--- /dev/null
+++ b/erpnext/docs/assets/img/articles/subscription-settings.png
Binary files differ
diff --git a/erpnext/docs/user/manual/en/accounts/articles/how-to-manage-subscriptions-with-erpnext.md b/erpnext/docs/user/manual/en/accounts/articles/how-to-manage-subscriptions-with-erpnext.md
new file mode 100644
index 0000000..97e6638
--- /dev/null
+++ b/erpnext/docs/user/manual/en/accounts/articles/how-to-manage-subscriptions-with-erpnext.md
@@ -0,0 +1,104 @@
+# How To Manage Subscriptions With ERPNext
+
+ERPNext now allows you to manage your subscriptions easily. A single subscription can contain multiple plans. At 
+the same time, A single subscriber can also have multiple subscriptions. ERPNext also automatically manages your 
+subscriptions for you by generating new invoices when due and changing the subscription status for you.
+
+## Related Doctypes
+### Subscriber
+Like its name suggests, the Subscriber Doctype represents your subscribers and each record is linked to a single
+Customer.
+
+<img alt="Subscriber form" class="screenshot" src="{{docs_base_url}}/assets/img/articles/subscriber.png">
+
+### Subscription Plan
+Each Subscription Plan is linked to a single Item and contains billing and pricing information on the Item. You can have 
+multiple Subscription Plans for a single Item. An example of a situation where you would want this is where you have 
+different prices for the same Item like when you have a basic option and premium option for a service.
+
+<img alt="Subscription Plan Form" class="screenshot" src="{{docs_base_url}}/assets/img/articles/subscription-plan.png">
+
+### Subscription Settings
+Subscription Settings is where you tweak the behaviour of the Subscription Doctype. For example, you can set a grace 
+period for overdue invoices from it. You can also elect to have a subscription cancelled if an overdue invoice is not 
+paid after the grace period.
+
+<img alt="Subscription Settings Form" class="screenshot" src="{{docs_base_url}}/assets/img/articles/subscription-settings.png">
+
+## Creating A Subscription
+To create a Subscription, go to the Subscription creation form
+`Explore > Accounts > Subscriptions`
+
+<img alt="Subscription form" class="screenshot" src="{{docs_base_url}}/assets/img/articles/subscription-1.png">
+
+Select a Subscriber.
+
+If you want to cancel a subscription at the end of the present billing cycle, check the 'Cancel At End Of Period' 
+check box.
+
+Select the start date for the subscription. By default, the start date is today's date. (Optional).
+
+If you are giving the subscriber a trial, enter the Trial Period Start Date and Trial Period End Date.
+
+If your invoice is not payable immediately, you can set the number of days before the invoice will be due in the 
+'Days Until Due' field.
+
+If you require more than one unit of a plan, set it in the 'Quantity' field. For instance, a web developer is subscribed 
+to your web hosting service. The developer buys a plan for each customer. Instead of having multiple subscriptions for 
+the same plan, you can simply increase the quantity as needed.
+
+In the 'Plan' table, add Subscription Plans as required. You may have multiple Subscription Plans in a single 
+Subscription as long as they all have the same billing period cycle. If the same Subscriber needs to subscribe to 
+plans with different billing cycles, you will have to use a separate subscription.
+
+Select a Sales Taxes and Charges Template if you need to charge tax in your invoices.
+
+Fill the relevant fields in the 'Discounts' section if you need to add discounts to your invoices.
+
+Click Save.
+
+### Subscription Status
+ERPNext Subscription has five status values:
+- **Trialling** - A subscription that is in trial period
+- **Active** - A subscription that does not have any unpaid invoice
+- **Past Due** -  A subscription whose most recent invoice is unpaid but is still within the grace period
+- **Unpaid** - A subscription whose most recent invoice is unpaid and past the grace period
+- **Canceled** - A subscription whose most recent invoice is unpaid and past the grace period. In this state, ERPNext no longer monitors the subscription.
+
+### Subscription Processing In The Background
+Every one hour interval, ERPNext processes all Subscriptions and updates each for any change in status. It will 
+create new invoices if need be. When an outstanding invoice is paid, ERPNext updates the subscription accordingly.
+
+### Manually Updating Subscriptions
+Once you have saved a subscription, you can change the 'Days Until Due', 'Quantity', 'Plans', 'Sales Taxes and Charges 
+Template', 'Apply Additional Discount On', 'Additional Discount Percentage' and 'Additional Discount Amount' fields.
+
+Note that changing any of the values will reflect in newly generated invoices only. Previously generated invoices will 
+not be changed.
+
+### Cancelling Subscriptions
+To cancel a Subscription, simply click the 'Cancel Subscription' button. The subscription will update its 'Cancellation 
+Date' field and the subscription will no longer be monitored.
+
+If you are cancelling an active subscription, an invoice will immediately be generated. The generated invoice will be on 
+pro-rata basis by default. If you want ERPNext always create an invoice for the full amount, uncheck the 'Prorate' field 
+in Subsciption Settings.
+
+### Restarting Subscriptions
+To restart a canceled subscription, simply click the 'Restart Subscription' button. Note the Subscription will empty 
+its invoices table. Note that the invoices will still exist but the Subscription will no longer track them. The start 
+date of the subscription will also be changed to the date the Subscription is restarted. The start of the billing 
+cycle will also be set to the date the Subscription is restarted.
+
+### Recalculating Subscriptions
+Some times, a Subscription's status might have changed but might not yet be reflected in the Subscription. You can force 
+ERPNext to update the subscription by clicking 'Fetch Subscription Updates'.
+
+### Subscription Settings
+**Grace Period** represents the number of days after a subscriber's invoice becomes overdue that ERPNext should delay 
+before changing the Subscription status to 'Canceled' or 'Unpaid'.
+
+**Cancel Invoice After Grace Period** would cause ERPNext to automatically cancel a subscription if it is not paid before the grace period elapses. This setting is off by default.
+
+**Prorate** would cause ERPNext to generate a prorated invoice when an active subscription is canceled by default. 
+If you would prefer a full invoice, uncheck the setting.
\ No newline at end of file
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 3935f22..844763d 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -218,7 +218,8 @@
 scheduler_events = {
 	"hourly": [
 		"erpnext.accounts.doctype.subscription.subscription.make_subscription_entry",
-		'erpnext.hr.doctype.daily_work_summary_group.daily_work_summary_group.trigger_emails'
+		'erpnext.hr.doctype.daily_work_summary_group.daily_work_summary_group.trigger_emails',
+		"erpnext.assets.doctype.subscriptions.subscriptions.process_all"
 	],
 	"daily": [
 		"erpnext.stock.reorder_item.reorder_item",