Commonify Recurring Sales Order/Invoice
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index 76092ed..5228b0e 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -228,7 +228,7 @@
 	par_flds = ['project_name', 'due_date', 'is_opening', 'source', 'total_advance', 'gross_profit',
 	'gross_profit_percent', 'get_advances_received',
 	'advance_adjustment_details', 'sales_partner', 'commission_rate',
-	'total_commission', 'advances', 'invoice_period_from_date', 'invoice_period_to_date'];
+	'total_commission', 'advances', 'period_from', 'period_to'];
 
 	item_flds_normal = ['sales_order', 'delivery_note']
 
@@ -414,18 +414,18 @@
 	refresh_many(["notification_email_address", "repeat_on_day_of_month"]);
 }
 
-cur_frm.cscript.invoice_period_from_date = function(doc, dt, dn) {
-	// set invoice_period_to_date
-	if(doc.invoice_period_from_date) {
+cur_frm.cscript.period_from = function(doc, dt, dn) {
+	// set period_to
+	if(doc.period_from) {
 		var recurring_type_map = {'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6,
 			'Yearly': 12};
 
 		var months = recurring_type_map[doc.recurring_type];
 		if(months) {
-			var to_date = frappe.datetime.add_months(doc.invoice_period_from_date,
+			var to_date = frappe.datetime.add_months(doc.period_from,
 				months);
-			doc.invoice_period_to_date = frappe.datetime.add_days(to_date, -1);
-			refresh_field('invoice_period_to_date');
+			doc.period_to = frappe.datetime.add_days(to_date, -1);
+			refresh_field('period_to');
 		}
 	}
 }
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index ff256dc..7cab4c2 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -1,5 +1,6 @@
 {
-  "allow_import": 1, 
+ "allow_attach": 1, 
+ "allow_import": 1, 
  "autoname": "naming_series:", 
  "creation": "2013-05-24 19:29:05", 
  "default_print_format": "Standard", 
@@ -172,7 +173,7 @@
    "allow_on_submit": 1, 
    "depends_on": "", 
    "description": "Start date of current invoice's period", 
-   "fieldname": "invoice_period_from_date", 
+   "fieldname": "period_from", 
    "fieldtype": "Date", 
    "label": "Invoice Period From", 
    "no_copy": 1, 
@@ -184,7 +185,7 @@
    "allow_on_submit": 1, 
    "depends_on": "", 
    "description": "End date of current invoice's period", 
-   "fieldname": "invoice_period_to_date", 
+   "fieldname": "period_to", 
    "fieldtype": "Date", 
    "label": "Invoice Period To", 
    "no_copy": 1, 
@@ -1087,7 +1088,7 @@
    "allow_on_submit": 1, 
    "depends_on": "eval:doc.docstatus<2", 
    "description": "Check if recurring invoice, uncheck to stop recurring or put proper End Date", 
-   "fieldname": "convert_into_recurring_invoice", 
+   "fieldname": "convert_into_recurring", 
    "fieldtype": "Check", 
    "label": "Convert into Recurring Invoice", 
    "no_copy": 1, 
@@ -1097,7 +1098,7 @@
   }, 
   {
    "allow_on_submit": 1, 
-   "depends_on": "eval:doc.convert_into_recurring_invoice==1", 
+   "depends_on": "eval:doc.convert_into_recurring==1", 
    "description": "Select the period when the invoice will be generated automatically", 
    "fieldname": "recurring_type", 
    "fieldtype": "Select", 
@@ -1110,7 +1111,7 @@
   }, 
   {
    "allow_on_submit": 1, 
-   "depends_on": "eval:doc.convert_into_recurring_invoice==1", 
+   "depends_on": "eval:doc.convert_into_recurring==1", 
    "description": "The day of the month on which auto invoice will be generated e.g. 05, 28 etc ", 
    "fieldname": "repeat_on_day_of_month", 
    "fieldtype": "Int", 
@@ -1121,7 +1122,7 @@
    "read_only": 0
   }, 
   {
-   "depends_on": "eval:doc.convert_into_recurring_invoice==1", 
+   "depends_on": "eval:doc.convert_into_recurring==1", 
    "description": "The date on which next invoice will be generated. It is generated on submit.\n", 
    "fieldname": "next_date", 
    "fieldtype": "Date", 
@@ -1133,7 +1134,7 @@
   }, 
   {
    "allow_on_submit": 1, 
-   "depends_on": "eval:doc.convert_into_recurring_invoice==1", 
+   "depends_on": "eval:doc.convert_into_recurring==1", 
    "description": "The date on which recurring invoice will be stop", 
    "fieldname": "end_date", 
    "fieldtype": "Date", 
@@ -1153,7 +1154,7 @@
    "width": "50%"
   }, 
   {
-   "depends_on": "eval:doc.convert_into_recurring_invoice==1", 
+   "depends_on": "eval:doc.convert_into_recurring==1", 
    "description": "The unique id for tracking all recurring invoices.\u00a0It is generated on submit.", 
    "fieldname": "recurring_id", 
    "fieldtype": "Data", 
@@ -1165,7 +1166,7 @@
   }, 
   {
    "allow_on_submit": 1, 
-   "depends_on": "eval:doc.convert_into_recurring_invoice==1", 
+   "depends_on": "eval:doc.convert_into_recurring==1", 
    "description": "Enter email id separated by commas, invoice will be mailed automatically on particular date", 
    "fieldname": "notification_email_address", 
    "fieldtype": "Small Text", 
@@ -1192,7 +1193,7 @@
  "icon": "icon-file-text", 
  "idx": 1, 
  "is_submittable": 1, 
- "modified": "2014-08-14 02:13:09.673510", 
+ "modified": "2014-08-25 17:41:35.367233", 
  "modified_by": "Administrator", 
  "module": "Accounts", 
  "name": "Sales Invoice", 
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 481ae09..69a7def 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -75,7 +75,7 @@
 		self.set_against_income_account()
 		self.validate_c_form()
 		self.validate_time_logs_are_submitted()
-		self.validate_recurring_invoice()
+		self.validate_recurring_document()
 		self.validate_multiple_billing("Delivery Note", "dn_detail", "amount",
 			"delivery_note_details")
 
@@ -103,7 +103,7 @@
 
 		self.update_c_form()
 		self.update_time_log_batch(self.name)
-		self.convert_to_recurring()
+		self.convert_to_recurring("RECINV.#####", self.transaction_date)
 
 	def before_cancel(self):
 		self.update_time_log_batch(None)
@@ -144,8 +144,8 @@
 			})
 
 	def on_update_after_submit(self):
-		self.validate_recurring_invoice()
-		self.convert_to_recurring()
+		self.validate_recurring_document()
+		self.convert_to_recurring("RECINV.#####", self.transaction_date)
 
 	def get_portal_page(self):
 		return "invoice" if self.docstatus==1 else None
@@ -592,157 +592,157 @@
 				grand_total = %s where invoice_no = %s and parent = %s""",
 				(self.name, self.amended_from, self.c_form_no))
 
-	def validate_recurring_invoice(self):
-		if self.convert_into_recurring_invoice:
-			self.validate_notification_email_id()
+# 	def validate_recurring_invoice(self):
+# 		if self.convert_into_recurring_invoice:
+# 			self.validate_notification_email_id()
 
-			if not self.recurring_type:
-				msgprint(_("Please select {0}").format(self.meta.get_label("recurring_type")),
-				raise_exception=1)
+# 			if not self.recurring_type:
+# 				msgprint(_("Please select {0}").format(self.meta.get_label("recurring_type")),
+# 				raise_exception=1)
 
-			elif not (self.invoice_period_from_date and \
-					self.invoice_period_to_date):
-				throw(_("Invoice Period From and Invoice Period To dates mandatory for recurring invoice"))
+# 			elif not (self.period_from and \
+# 					self.period_to):
+# 				throw(_("Invoice Period From and Invoice Period To dates mandatory for recurring invoice"))
 
-	def convert_to_recurring(self):
-		if self.convert_into_recurring_invoice:
-			if not self.recurring_id:
-				frappe.db.set(self, "recurring_id",
-					make_autoname("RECINV/.#####"))
+# 	def convert_to_recurring(self):
+# 		if self.convert_into_recurring_invoice:
+# 			if not self.recurring_id:
+# 				frappe.db.set(self, "recurring_id",
+# 					make_autoname("RECINV/.#####"))
 
-			self.set_next_date()
+# 			self.set_next_date()
 
-		elif self.recurring_id:
-			frappe.db.sql("""update `tabSales Invoice`
-				set convert_into_recurring_invoice = 0
-				where recurring_id = %s""", (self.recurring_id,))
+# 		elif self.recurring_id:
+# 			frappe.db.sql("""update `tabSales Invoice`
+# 				set convert_into_recurring_invoice = 0
+# 				where recurring_id = %s""", (self.recurring_id,))
 
-	def validate_notification_email_id(self):
-		if self.notification_email_address:
-			email_list = filter(None, [cstr(email).strip() for email in
-				self.notification_email_address.replace("\n", "").split(",")])
+# 	def validate_notification_email_id(self):
+# 		if self.notification_email_address:
+# 			email_list = filter(None, [cstr(email).strip() for email in
+# 				self.notification_email_address.replace("\n", "").split(",")])
 
-			from frappe.utils import validate_email_add
-			for email in email_list:
-				if not validate_email_add(email):
-					throw(_("{0} is an invalid email address in 'Notification Email Address'").format(email))
+# 			from frappe.utils import validate_email_add
+# 			for email in email_list:
+# 				if not validate_email_add(email):
+# 					throw(_("{0} is an invalid email address in 'Notification Email Address'").format(email))
 
-		else:
-			throw(_("'Notification Email Addresses' not specified for recurring invoice"))
+# 		else:
+# 			throw(_("'Notification Email Addresses' not specified for recurring invoice"))
 
-	def set_next_date(self):
-		""" Set next date on which auto invoice will be created"""
-		if not self.repeat_on_day_of_month:
-			msgprint(_("Please enter 'Repeat on Day of Month' field value"), raise_exception=1)
+# 	def set_next_date(self):
+# 		""" Set next date on which auto invoice will be created"""
+# 		if not self.repeat_on_day_of_month:
+# 			msgprint(_("Please enter 'Repeat on Day of Month' field value"), raise_exception=1)
 
-		next_date = get_next_date(self.posting_date,
-			month_map[self.recurring_type], cint(self.repeat_on_day_of_month))
+# 		next_date = get_next_date(self.posting_date,
+# 			month_map[self.recurring_type], cint(self.repeat_on_day_of_month))
 
-		frappe.db.set(self, 'next_date', next_date)
+# 		frappe.db.set(self, 'next_date', next_date)
 
-def get_next_date(dt, mcount, day=None):
-	dt = getdate(dt)
+# def get_next_date(dt, mcount, day=None):
+# 	dt = getdate(dt)
 
-	from dateutil.relativedelta import relativedelta
-	dt += relativedelta(months=mcount, day=day)
+# 	from dateutil.relativedelta import relativedelta
+# 	dt += relativedelta(months=mcount, day=day)
 
-	return dt
+# 	return dt
 
-def manage_recurring_invoices(next_date=None, commit=True):
-	"""
-		Create recurring invoices on specific date by copying the original one
-		and notify the concerned people
-	"""
-	next_date = next_date or nowdate()
-	recurring_invoices = frappe.db.sql("""select name, recurring_id
-		from `tabSales Invoice` where ifnull(convert_into_recurring_invoice, 0)=1
-		and docstatus=1 and next_date=%s
-		and next_date <= ifnull(end_date, '2199-12-31')""", next_date)
+# def manage_recurring_invoices(next_date=None, commit=True):
+# 	"""
+# 		Create recurring invoices on specific date by copying the original one
+# 		and notify the concerned people
+# 	"""
+# 	next_date = next_date or nowdate()
+# 	recurring_invoices = frappe.db.sql("""select name, recurring_id
+# 		from `tabSales Invoice` where ifnull(convert_into_recurring_invoice, 0)=1
+# 		and docstatus=1 and next_date=%s
+# 		and next_date <= ifnull(end_date, '2199-12-31')""", next_date)
 
-	exception_list = []
-	for ref_invoice, recurring_id in recurring_invoices:
-		if not frappe.db.sql("""select name from `tabSales Invoice`
-				where posting_date=%s and recurring_id=%s and docstatus=1""",
-				(next_date, recurring_id)):
-			try:
-				ref_wrapper = frappe.get_doc('Sales Invoice', ref_invoice)
-				new_invoice_wrapper = make_new_invoice(ref_wrapper, next_date)
-				send_notification(new_invoice_wrapper)
-				if commit:
-					frappe.db.commit()
-			except:
-				if commit:
-					frappe.db.rollback()
+# 	exception_list = []
+# 	for ref_invoice, recurring_id in recurring_invoices:
+# 		if not frappe.db.sql("""select name from `tabSales Invoice`
+# 				where posting_date=%s and recurring_id=%s and docstatus=1""",
+# 				(next_date, recurring_id)):
+# 			try:
+# 				ref_wrapper = frappe.get_doc('Sales Invoice', ref_invoice)
+# 				new_invoice_wrapper = make_new_invoice(ref_wrapper, next_date)
+# 				send_notification(new_invoice_wrapper)
+# 				if commit:
+# 					frappe.db.commit()
+# 			except:
+# 				if commit:
+# 					frappe.db.rollback()
 
-					frappe.db.begin()
-					frappe.db.sql("update `tabSales Invoice` set \
-						convert_into_recurring_invoice = 0 where name = %s", ref_invoice)
-					notify_errors(ref_invoice, ref_wrapper.customer, ref_wrapper.owner)
-					frappe.db.commit()
+# 					frappe.db.begin()
+# 					frappe.db.sql("update `tabSales Invoice` set \
+# 						convert_into_recurring_invoice = 0 where name = %s", ref_invoice)
+# 					notify_errors(ref_invoice, ref_wrapper.customer, ref_wrapper.owner)
+# 					frappe.db.commit()
 
-				exception_list.append(frappe.get_traceback())
-			finally:
-				if commit:
-					frappe.db.begin()
+# 				exception_list.append(frappe.get_traceback())
+# 			finally:
+# 				if commit:
+# 					frappe.db.begin()
 
-	if exception_list:
-		exception_message = "\n\n".join([cstr(d) for d in exception_list])
-		frappe.throw(exception_message)
+# 	if exception_list:
+# 		exception_message = "\n\n".join([cstr(d) for d in exception_list])
+# 		frappe.throw(exception_message)
 
-def make_new_invoice(ref_wrapper, posting_date):
-	from erpnext.accounts.utils import get_fiscal_year
-	new_invoice = frappe.copy_doc(ref_wrapper)
+# def make_new_invoice(ref_wrapper, posting_date):
+# 	from erpnext.accounts.utils import get_fiscal_year
+# 	new_invoice = frappe.copy_doc(ref_wrapper)
 
-	mcount = month_map[ref_wrapper.recurring_type]
+# 	mcount = month_map[ref_wrapper.recurring_type]
 
-	invoice_period_from_date = get_next_date(ref_wrapper.invoice_period_from_date, mcount)
+# 	period_from = get_next_date(ref_wrapper.period_from, mcount)
 
-	# get last day of the month to maintain period if the from date is first day of its own month
-	# and to date is the last day of its own month
-	if (cstr(get_first_day(ref_wrapper.invoice_period_from_date)) == \
-			cstr(ref_wrapper.invoice_period_from_date)) and \
-		(cstr(get_last_day(ref_wrapper.invoice_period_to_date)) == \
-			cstr(ref_wrapper.invoice_period_to_date)):
-		invoice_period_to_date = get_last_day(get_next_date(ref_wrapper.invoice_period_to_date,
-			mcount))
-	else:
-		invoice_period_to_date = get_next_date(ref_wrapper.invoice_period_to_date, mcount)
+# 	# get last day of the month to maintain period if the from date is first day of its own month
+# 	# and to date is the last day of its own month
+# 	if (cstr(get_first_day(ref_wrapper.period_from)) == \
+# 			cstr(ref_wrapper.period_from)) and \
+# 		(cstr(get_last_day(ref_wrapper.period_to)) == \
+# 			cstr(ref_wrapper.period_to)):
+# 		period_to = get_last_day(get_next_date(ref_wrapper.period_to,
+# 			mcount))
+# 	else:
+# 		period_to = get_next_date(ref_wrapper.period_to, mcount)
 
-	new_invoice.update({
-		"posting_date": posting_date,
-		"aging_date": posting_date,
-		"due_date": add_days(posting_date, cint(date_diff(ref_wrapper.due_date,
-			ref_wrapper.posting_date))),
-		"invoice_period_from_date": invoice_period_from_date,
-		"invoice_period_to_date": invoice_period_to_date,
-		"fiscal_year": get_fiscal_year(posting_date)[0],
-		"owner": ref_wrapper.owner,
-	})
+# 	new_invoice.update({
+# 		"posting_date": posting_date,
+# 		"aging_date": posting_date,
+# 		"due_date": add_days(posting_date, cint(date_diff(ref_wrapper.due_date,
+# 			ref_wrapper.posting_date))),
+# 		"period_from": period_from,
+# 		"period_to": period_to,
+# 		"fiscal_year": get_fiscal_year(posting_date)[0],
+# 		"owner": ref_wrapper.owner,
+# 	})
 
-	new_invoice.submit()
+# 	new_invoice.submit()
 
-	return new_invoice
+# 	return new_invoice
 
-def send_notification(new_rv):
-	"""Notify concerned persons about recurring invoice generation"""
-	frappe.sendmail(new_rv.notification_email_address,
-		subject="New Invoice : " + new_rv.name,
-		message = _("Please find attached Sales Invoice #{0}").format(new_rv.name),
-		attachments = [{
-			"fname": new_rv.name + ".pdf",
-			"fcontent": frappe.get_print_format(new_rv.doctype, new_rv.name, as_pdf=True)
-		}])
+# def send_notification(new_rv):
+# 	"""Notify concerned persons about recurring invoice generation"""
+# 	frappe.sendmail(new_rv.notification_email_address,
+# 		subject="New Invoice : " + new_rv.name,
+# 		message = _("Please find attached Sales Invoice #{0}").format(new_rv.name),
+# 		attachments = [{
+# 			"fname": new_rv.name + ".pdf",
+# 			"fcontent": frappe.get_print_format(new_rv.doctype, new_rv.name, as_pdf=True)
+# 		}])
 
-def notify_errors(inv, customer, owner):
-	from frappe.utils.user import get_system_managers
-	recipients=get_system_managers(only_name=True)
+# def notify_errors(inv, customer, owner):
+# 	from frappe.utils.user import get_system_managers
+# 	recipients=get_system_managers(only_name=True)
 
-	frappe.sendmail(recipients + [frappe.db.get_value("User", owner, "email")],
-		subject="[Urgent] Error while creating recurring invoice for %s" % inv,
-		message = frappe.get_template("templates/emails/recurring_invoice_failed.html").render({
-			"name": inv,
-			"customer": customer
-		}))
+# 	frappe.sendmail(recipients + [frappe.db.get_value("User", owner, "email")],
+# 		subject="[Urgent] Error while creating recurring invoice for %s" % inv,
+# 		message = frappe.get_template("templates/emails/recurring_invoice_failed.html").render({
+# 			"name": inv,
+# 			"customer": customer
+# 		}))
 
 	assign_task_to_owner(inv, "Recurring Invoice Failed", recipients)
 
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index ab361d8..44bd451 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -677,8 +677,8 @@
 			"posting_date": today,
 			"due_date": None,
 			"fiscal_year": get_fiscal_year(today)[0],
-			"invoice_period_from_date": get_first_day(today),
-			"invoice_period_to_date": get_last_day(today)
+			"period_from": get_first_day(today),
+			"period_to": get_last_day(today)
 		})
 
 		# monthly
@@ -690,8 +690,8 @@
 		# monthly without a first and last day period
 		si2 = frappe.copy_doc(base_si)
 		si2.update({
-			"invoice_period_from_date": today,
-			"invoice_period_to_date": add_to_date(today, days=30)
+			"period_from": today,
+			"period_to": add_to_date(today, days=30)
 		})
 		si2.insert()
 		si2.submit()
@@ -701,8 +701,8 @@
 		si3 = frappe.copy_doc(base_si)
 		si3.update({
 			"recurring_type": "Quarterly",
-			"invoice_period_from_date": get_first_day(today),
-			"invoice_period_to_date": get_last_day(add_to_date(today, months=3))
+			"period_from": get_first_day(today),
+			"period_to": get_last_day(add_to_date(today, months=3))
 		})
 		si3.insert()
 		si3.submit()
@@ -712,8 +712,8 @@
 		si4 = frappe.copy_doc(base_si)
 		si4.update({
 			"recurring_type": "Quarterly",
-			"invoice_period_from_date": today,
-			"invoice_period_to_date": add_to_date(today, months=3)
+			"period_from": today,
+			"period_to": add_to_date(today, months=3)
 		})
 		si4.insert()
 		si4.submit()
@@ -723,8 +723,8 @@
 		si5 = frappe.copy_doc(base_si)
 		si5.update({
 			"recurring_type": "Yearly",
-			"invoice_period_from_date": get_first_day(today),
-			"invoice_period_to_date": get_last_day(add_to_date(today, years=1))
+			"period_from": get_first_day(today),
+			"period_to": get_last_day(add_to_date(today, years=1))
 		})
 		si5.insert()
 		si5.submit()
@@ -734,8 +734,8 @@
 		si6 = frappe.copy_doc(base_si)
 		si6.update({
 			"recurring_type": "Yearly",
-			"invoice_period_from_date": today,
-			"invoice_period_to_date": add_to_date(today, years=1)
+			"period_from": today,
+			"period_to": add_to_date(today, years=1)
 		})
 		si6.insert()
 		si6.submit()
@@ -784,16 +784,16 @@
 
 			self.assertEquals(new_si.posting_date, unicode(next_date))
 
-			self.assertEquals(new_si.invoice_period_from_date,
-				unicode(add_months(base_si.invoice_period_from_date, no_of_months)))
+			self.assertEquals(new_si.period_from,
+				unicode(add_months(base_si.period_from, no_of_months)))
 
 			if first_and_last_day:
-				self.assertEquals(new_si.invoice_period_to_date,
-					unicode(get_last_day(add_months(base_si.invoice_period_to_date,
+				self.assertEquals(new_si.period_to,
+					unicode(get_last_day(add_months(base_si.period_to,
 						no_of_months))))
 			else:
-				self.assertEquals(new_si.invoice_period_to_date,
-					unicode(add_months(base_si.invoice_period_to_date, no_of_months)))
+				self.assertEquals(new_si.period_to,
+					unicode(add_months(base_si.period_to, no_of_months)))
 
 
 			return new_si
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 59a49af..9aa93ac 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -444,6 +444,57 @@
 		if total_outstanding:
 			frappe.get_doc('Account', account).check_credit_limit(total_outstanding)
 
+	def validate_recurring_document(self):
+		if self.convert_into_recurring:
+			self.validate_notification_email_id()
+
+			if not self.recurring_type:
+				msgprint(_("Please select {0}").format(self.meta.get_label("recurring_type")),
+				raise_exception=1)
+
+			elif not (self.period_from and self.period_to):
+				throw(_("Period From and Period To dates mandatory for recurring %s") % self.doctype)
+
+	def convert_to_recurring(self, autoname, posting_date):
+		if self.convert_into_recurring:
+			if not self.recurring_id:
+				frappe.db.set(self, "recurring_id",
+					make_autoname(autoname))
+
+			self.set_next_date(posting_date)
+
+		elif self.recurring_id:
+			frappe.db.sql("""update `tab%s` \
+				set convert_into_recurring = 0 \
+				where recurring_id = %s""", % (self.doctype, '%s'), (self.recurring_id))
+
+	def validate_notification_email_id(self):
+		if self.notification_email_address:
+			email_list = filter(None, [cstr(email).strip() for email in
+				self.notification_email_address.replace("\n", "").split(",")])
+
+			from frappe.utils import validate_email_add
+			for email in email_list:
+				if not validate_email_add(email):
+					throw(_("{0} is an invalid email address in 'Notification \
+						Email Address'").format(email))
+
+		else:
+			frappe.throw(_("'Notification Email Addresses' not specified for recurring %s") \
+				% self.doctype)
+
+	def set_next_date(self, posting_date):
+		""" Set next date on which recurring document will be created"""
+		from erpnext.controllers.recurring_document import get_next_date
+
+		if not self.repeat_on_day_of_month:
+			msgprint(_("Please enter 'Repeat on Day of Month' field value"), raise_exception=1)
+
+		next_date = get_next_date(posting_date, month_map[self.recurring_type], 
+			cint(self.repeat_on_day_of_month))
+
+		frappe.db.set(self, 'next_date', next_date)
+
 
 @frappe.whitelist()
 def get_tax_rate(account_head):
diff --git a/erpnext/controllers/recurring_document.py b/erpnext/controllers/recurring_document.py
new file mode 100644
index 0000000..ad32371
--- /dev/null
+++ b/erpnext/controllers/recurring_document.py
@@ -0,0 +1,121 @@
+from __future__ import unicode_literals
+import frappe
+import frappe.utils
+import frappe.defaults
+
+from frappe.utils import add_days, cint, cstr, date_diff, flt, getdate, nowdate, \
+	get_first_day, get_last_day, comma_and
+from frappe.model.naming import make_autoname
+
+from frappe import _, msgprint, throw
+from erpnext.accounts.party import get_party_account, get_due_date, get_party_details
+from frappe.model.mapper import get_mapped_doc
+
+def manage_recurring_documents(doctype, next_date=None, commit=True):
+	"""
+		Create recurring documents on specific date by copying the original one
+		and notify the concerned people
+	"""
+	next_date = next_date or nowdate()
+	recurring_documents = frappe.db.sql("""select name, recurring_id
+		from `tab%s` where ifnull(convert_into_recurring, 0)=1
+		and docstatus=1 and next_date=%s
+		and next_date <= ifnull(end_date, '2199-12-31')""", % (doctype, '%s'), (next_date))
+
+	exception_list = []
+	for ref_document, recurring_id in recurring_documents:
+		if not frappe.db.sql("""select name from `tab%s`
+				where transaction_date=%s and recurring_id=%s and docstatus=1""",
+				% (doctype, '%s', '%s'), (next_date, recurring_id)):
+			try:
+				ref_wrapper = frappe.get_doc(doctype, ref_document)
+				new_document_wrapper = make_new_document(ref_wrapper, next_date)
+				send_notification(new_document_wrapper)
+				if commit:
+					frappe.db.commit()
+			except:
+				if commit:
+					frappe.db.rollback()
+
+					frappe.db.begin()
+					frappe.db.sql("update `tab%s` \
+						set convert_into_recurring = 0 where name = %s", % (doctype, '%s'), 
+						(ref_document))
+					notify_errors(ref_document, doctype, ref_wrapper.customer, ref_wrapper.owner)
+					frappe.db.commit()
+
+				exception_list.append(frappe.get_traceback())
+			finally:
+				if commit:
+					frappe.db.begin()
+
+	if exception_list:
+		exception_message = "\n\n".join([cstr(d) for d in exception_list])
+		frappe.throw(exception_message)
+
+def make_new_document(ref_wrapper, posting_date):
+	from erpnext.accounts.utils import get_fiscal_year
+	new_document = frappe.copy_doc(ref_wrapper)
+
+	mcount = month_map[ref_wrapper.recurring_type]
+
+	period_from = get_next_date(ref_wrapper.period_from, mcount)
+
+	# get last day of the month to maintain period if the from date is first day of its own month
+	# and to date is the last day of its own month
+	if (cstr(get_first_day(ref_wrapper.period_from)) == \
+			cstr(ref_wrapper.period_from)) and \
+		(cstr(get_last_day(ref_wrapper.period_to)) == \
+			cstr(ref_wrapper.period_to)):
+		period_to = get_last_day(get_next_date(ref_wrapper.period_to,
+			mcount))
+	else:
+		period_to = get_next_date(ref_wrapper.period_to, mcount)
+
+	new_document.update({
+		"transaction_date": posting_date,
+		"period_from": period_from,
+		"period_to": period_to,
+		"fiscal_year": get_fiscal_year(posting_date)[0],
+		"owner": ref_wrapper.owner,
+	})
+
+	if ref_wrapper.doctype == "Sales Order":
+		new_document.update({
+			"delivery_date": get_next_date(ref_wrapper.delivery_date, mcount, 
+				cint(ref_wrapper.repeat_on_day_of_month))
+	})
+
+	new_document.submit()
+	
+	return new_document
+
+def get_next_date(dt, mcount, day=None):
+	dt = getdate(dt)
+
+	from dateutil.relativedelta import relativedelta
+	dt += relativedelta(months=mcount, day=day)
+
+	return dt
+
+def send_notification(new_rv):
+	"""Notify concerned persons about recurring document generation"""
+	frappe.sendmail(new_rv.notification_email_address,
+		subject=  _("New {0}: #{1}").format(new_rv.doctype, new_rv.name),
+		message = _("Please find attached {0} #{1}").format(new_rv.doctype, new_rv.name),
+		attachments = [{
+			"fname": new_rv.name + ".pdf",
+			"fcontent": frappe.get_print_format(new_rv.doctype, new_rv.name, as_pdf=True)
+		}])
+
+def notify_errors(doc, doctype, customer, owner):
+	from frappe.utils.user import get_system_managers
+	recipients = get_system_managers(only_name=True)
+
+	frappe.sendmail(recipients + [frappe.db.get_value("User", owner, "email")],
+		subject="[Urgent] Error while creating recurring %s for %s" % (doctype, doc),
+		message = frappe.get_template("templates/emails/recurring_sales_invoice_failed.html").render({
+			"type": doctype,
+			"name": doc,
+			"customer": customer
+		}))
\ No newline at end of file
diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json
index fb7e360..e418ee9 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.json
+++ b/erpnext/selling/doctype/sales_order/sales_order.json
@@ -1,5 +1,6 @@
 {
-  "allow_import": 1, 
+ "allow_attach": 1, 
+ "allow_import": 1, 
  "autoname": "naming_series:", 
  "creation": "2013-06-18 12:39:59", 
  "docstatus": 0, 
@@ -170,6 +171,24 @@
    "width": "160px"
   }, 
   {
+   "allow_on_submit": 1, 
+   "description": "Start date of current order's period", 
+   "fieldname": "period_from", 
+   "fieldtype": "Date", 
+   "label": "Order Period From", 
+   "no_copy": 1, 
+   "permlevel": 0
+  }, 
+  {
+   "allow_on_submit": 1, 
+   "description": "End date of current order's period", 
+   "fieldname": "period_to", 
+   "fieldtype": "Date", 
+   "label": "Order Period To", 
+   "no_copy": 1, 
+   "permlevel": 0
+  }, 
+  {
    "description": "Customer's Purchase Order Number", 
    "fieldname": "po_no", 
    "fieldtype": "Data", 
@@ -888,13 +907,121 @@
    "options": "Sales Team", 
    "permlevel": 0, 
    "print_hide": 1
+  }, 
+  {
+   "fieldname": "recurring_order", 
+   "fieldtype": "Section Break", 
+   "label": "Recurring Order", 
+   "options": "icon-time", 
+   "permlevel": 0
+  }, 
+  {
+   "fieldname": "column_break82", 
+   "fieldtype": "Column Break", 
+   "label": "Column Break", 
+   "permlevel": 0
+  }, 
+  {
+   "allow_on_submit": 1, 
+   "depends_on": "eval:doc.docstatus<2", 
+   "description": "Check if recurring order, uncheck to stop recurring or put proper End Date", 
+   "fieldname": "convert_into_recurring", 
+   "fieldtype": "Check", 
+   "label": "Convert into Recurring Order", 
+   "no_copy": 1, 
+   "permlevel": 0, 
+   "print_hide": 1
+  }, 
+  {
+   "allow_on_submit": 1, 
+   "depends_on": "eval:doc.convert_into_recurring==1", 
+   "description": "Select the period when the invoice will be generated automatically", 
+   "fieldname": "recurring_type", 
+   "fieldtype": "Select", 
+   "label": "Recurring Type", 
+   "no_copy": 1, 
+   "options": "\nMonthly\nQuarterly\nHalf-yearly\nYearly", 
+   "permlevel": 0, 
+   "print_hide": 1
+  }, 
+  {
+   "allow_on_submit": 1, 
+   "depends_on": "eval:doc.convert_into_recurring==1", 
+   "description": "The day of the month on which auto order will be generated e.g. 05, 28 etc ", 
+   "fieldname": "repeat_on_day_of_month", 
+   "fieldtype": "Int", 
+   "label": "Repeat on Day of Month", 
+   "no_copy": 1, 
+   "permlevel": 0, 
+   "print_hide": 1
+  }, 
+  {
+   "depends_on": "eval:doc.convert_into_recurring==1", 
+   "description": "The date on which next invoice will be generated. It is generated on submit.", 
+   "fieldname": "next_date", 
+   "fieldtype": "Date", 
+   "label": "Next Date", 
+   "no_copy": 1, 
+   "permlevel": 0, 
+   "print_hide": 1, 
+   "read_only": 1
+  }, 
+  {
+   "allow_on_submit": 1, 
+   "depends_on": "eval:doc.convert_into_recurring==1", 
+   "description": "The date on which recurring order will be stop", 
+   "fieldname": "end_date", 
+   "fieldtype": "Date", 
+   "label": "End Date", 
+   "no_copy": 1, 
+   "permlevel": 0, 
+   "print_hide": 1
+  }, 
+  {
+   "fieldname": "column_break83", 
+   "fieldtype": "Column Break", 
+   "label": "Column Break", 
+   "permlevel": 0, 
+   "print_hide": 1
+  }, 
+  {
+   "depends_on": "eval:doc.convert_into_recurring==1", 
+   "fieldname": "recurring_id", 
+   "fieldtype": "Data", 
+   "label": "Recurring Id", 
+   "no_copy": 1, 
+   "permlevel": 0, 
+   "print_hide": 1, 
+   "read_only": 1
+  }, 
+  {
+   "allow_on_submit": 1, 
+   "depends_on": "eval:doc.convert_into_recurring==1", 
+   "description": "Enter email id separated by commas, order will be mailed automatically on particular date", 
+   "fieldname": "notification_email_address", 
+   "fieldtype": "Small Text", 
+   "ignore_user_permissions": 0, 
+   "label": "Notification Email Address", 
+   "no_copy": 1, 
+   "permlevel": 0, 
+   "print_hide": 1
+  }, 
+  {
+   "fieldname": "against_income_account", 
+   "fieldtype": "Small Text", 
+   "hidden": 1, 
+   "label": "Against Income Account", 
+   "no_copy": 1, 
+   "permlevel": 0, 
+   "print_hide": 1, 
+   "report_hide": 1
   }
  ], 
  "icon": "icon-file-text", 
  "idx": 1, 
  "is_submittable": 1, 
  "issingle": 0, 
- "modified": "2014-08-11 07:28:11.362232", 
+ "modified": "2014-08-25 17:41:39.456399", 
  "modified_by": "Administrator", 
  "module": "Selling", 
  "name": "Sales Order", 
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 37b26fd..37aca0a 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -120,6 +120,8 @@
 		if not self.billing_status: self.billing_status = 'Not Billed'
 		if not self.delivery_status: self.delivery_status = 'Not Delivered'
 
+		self.validate_recurring_document()
+
 	def validate_warehouse(self):
 		from erpnext.stock.utils import validate_warehouse_company
 
@@ -161,6 +163,8 @@
 
 		self.update_prevdoc_status('submit')
 		frappe.db.set(self, 'status', 'Submitted')
+		
+		self.convert_to_recurring("SO/REC/.#####", self.transaction_date)
 
 	def on_cancel(self):
 		# Cannot cancel stopped SO
@@ -249,6 +253,10 @@
 	def get_portal_page(self):
 		return "order" if self.docstatus==1 else None
 
+	def on_update_after_submit(self):
+		self.validate_recurring_document()
+		self.convert_to_recurring("SO/REC/.#####", self.transaction_date)
+
 
 @frappe.whitelist()
 def make_material_request(source_name, target_doc=None):
diff --git a/erpnext/templates/emails/recurring_invoice_failed.html b/erpnext/templates/emails/recurring_invoice_failed.html
index 39690d8..a216e28 100644
--- a/erpnext/templates/emails/recurring_invoice_failed.html
+++ b/erpnext/templates/emails/recurring_invoice_failed.html
@@ -1,12 +1,12 @@
-<h2>Recurring Invoice Failed</h2>
+<h2>Recurring {{ type }} Failed</h2>
 
-<p>An error occured while creating recurring invoice <b>{{ name }}</b> for <b>{{ customer }}</b>.</p>
-<p>This could be because of some invalid email ids in the invoice.</p>
+<p>An error occured while creating recurring {{ type }} <b>{{ name }}</b> for <b>{{ customer }}</b>.</p>
+<p>This could be because of some invalid email ids in the {{ type }}.</p>
 <p>To stop sending repetitive error notifications from the system, we have unchecked
-"Convert into Recurring" field in the invoice {{ name }}.</p>
-<p><b>Please correct the invoice and make the invoice recurring again.</b></p>
+"Convert into Recurring" field in the {{ type }} {{ name }}.</p>
+<p><b>Please correct the {{ type }} and make the {{ type }} recurring again.</b></p>
 <hr>
-<p><b>It is necessary to take this action today itself for the above mentioned recurring invoice
+<p><b>It is necessary to take this action today itself for the above mentioned recurring {{ type }}
 to be generated. If delayed, you will have to manually change the "Repeat on Day of Month" field
-of this invoice for generating the recurring invoice.</b></p>
+of this {{ type }} for generating the recurring {{ type }}.</b></p>
 <p>[This email is autogenerated]</p>