Introduced recurring invoices
diff --git a/erpnext/accounts/doctype/gl_control/gl_control.py b/erpnext/accounts/doctype/gl_control/gl_control.py
index 44a9e8d..5858920 100644
--- a/erpnext/accounts/doctype/gl_control/gl_control.py
+++ b/erpnext/accounts/doctype/gl_control/gl_control.py
@@ -4,8 +4,8 @@
 from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add
 from webnotes.model import db_exists
 from webnotes.model.doc import Document, addchild, removechild, getchildren, make_autoname, SuperDocType
-from webnotes.model.doclist import getlist, copy_doclist
-from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
+from webnotes.model.doclist import getlist, copy_doclist, clone
+from webnotes.model.code import get_obj
 from webnotes import session, form, is_testing, msgprint, errprint
 
 sql = webnotes.conn.sql
@@ -24,14 +24,8 @@
 	# Get Company List
 	# ----------------
 	def get_companies(self,arg=''):
-		#d = get_defaults()
 		ret = sql("select name, abbr from tabCompany where docstatus != 2")
-		#pl = {}
-		#for r in ret:
-		#	inc = get_value('Account','Income - '+r[1], 'balance')
-		#	exp = get_value('Account','Expenses - '+r[1], 'balance')
-		#	pl[r[0]] = flt(flt(inc) - flt(exp))
-		return {'cl':[r[0] for r in ret]}#, 'pl':pl}
+		return {'cl':[r[0] for r in ret]}
 
 	def get_company_currency(self,arg=''):
 		dcc = TransactionBase().get_company_currency(arg)
@@ -506,3 +500,38 @@
 			for a in set(ac_list):
 				fy_obj.repost(a)
 
+
+def manage_recurring_invoices():
+	""" 
+		Create recurring invoices on specific date by copying the original one
+		and notify the concerned people
+	"""	
+	rv = sql("""select name, recurring_id from `tabReceivable Voucher` where ifnull(convert_into_recurring_invoice, 0) = 1 
+			and next_date = %s and next_date <= end_date""", nowdate())
+	for d in rv:
+		if not sql("""select name from `tabReceivable Voucher` where posting_date = %s and recurring_id = %s""", (nowdate, d[1])):
+			prev_rv = get_obj('Receivable Voucher', d[0], with_children=1)
+			new_rv = create_new_invoice(prev_rv)
+
+			send_notification(new_rv)
+
+def create_new_invoice(prev_rv):
+	# clone rv
+	new_rv = clone(prev_rv)
+
+	# update new rv 
+	new_rv.doc.voucher_date = new_rv.doc.next_date
+	new_rv.doc.posting_date = new_rv.doc.next_date
+	new_rv.doc.aging_date = new_rv.doc.next_date
+	new_rv.doc.due_date = add_days(new_rv.doc.next_date, cint(date_diff(prev_rv.doc.due_date, prev_rv.doc.posting_date)))
+	new_rv.doc.save()
+
+	# submit and after submit
+	new_rv.submit()
+	new_rv.update_after_submit()
+
+	return new_rv
+
+def send_notification(new_rv):
+	"""Notify concerned persons about recurring invoice generation"""
+	pass
diff --git a/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.js b/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.js
index bb19681..363da2e 100644
--- a/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.js
+++ b/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.js
@@ -433,3 +433,12 @@
 	}
 	loadreport('GL Entry','General Ledger', callback);
 }
+
+// Default values for recurring invoices
+cur_frm.cscript.convert_into_recurring_invoice = function(doc) {
+	if (doc.convert_into_recurring_invoice) {
+		doc.repeat_on_day_of_month = doc.posting_date.split('-')[2];
+		doc.notification_email_address = doc.owner + ', ' + doc.contact_email;
+		refresh_field(['repeat_on_day_of_month', 'notification_email_address']);
+	}		
+}
diff --git a/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.py b/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.py
index 6d1f80a..13ed8d3 100644
--- a/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.py
+++ b/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.py
@@ -1,12 +1,13 @@
 # Please edit this list and import only required elements
 import webnotes
 
-from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add
+from webnotes.utils import add_days, add_months, add_years, cint, cstr,date_diff, default_fields, flt, fmt_money, formatdate, generate_hash,getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common,month_name, now, nowdate, replace_newlines, sendmail, set_default,str_esc_quote, user_format, validate_email_add
 from webnotes.model import db_exists
 from webnotes.model.doc import Document, addchild, removechild, getchildren, make_autoname, SuperDocType
 from webnotes.model.doclist import getlist, copy_doclist
 from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
 from webnotes import session, form, is_testing, msgprint, errprint
+from webnotes.utils.scheduler import set_event, cancel_event, Scheduler
 
 set = webnotes.conn.set
 sql = webnotes.conn.sql
@@ -528,7 +529,6 @@
 	def make_gl_entries(self, is_cancel=0):
 		mapper = self.doc.is_pos and self.doc.write_off_account and 'POS with write off' or self.doc.is_pos and not self.doc.write_off_account and 'POS' or ''
 		update_outstanding = self.doc.is_pos and self.doc.write_off_account and 'No' or 'Yes'
-
 		get_obj(dt='GL Control').make_gl_entries(self.doc, self.doclist,cancel = is_cancel, use_mapper = mapper, update_outstanding = update_outstanding, merge_entries = cint(self.doc.is_pos) != 1 and 1 or 0)
 		
 
@@ -546,7 +546,8 @@
 			get_obj("Sales Common").update_prevdoc_detail(1,self)
 
 			# Check for Approving Authority
-			get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, self.doc.company, self.doc.grand_total, self)
+			if not self.doc.recurring_id:
+				get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, self.doc.company, self.doc.grand_total, self)
 
 		# this sequence because outstanding may get -ve		
 		self.make_gl_entries()
@@ -618,9 +619,61 @@
 
 		set(self.doc,'outstanding_amount',flt(self.doc.grand_total) - flt(self.doc.total_advance) - flt(self.doc.paid_amount) - flt(self.doc.write_off_amount))
 
-
 ########################################################################
 # Repair Outstanding
 #######################################################################
 	def repair_rv_outstanding(self):
 		get_obj(dt = 'GL Control').repair_voucher_outstanding(self)
+
+	def on_update_after_submit(self):
+		self.convert_into_recurring()
+		
+
+	def convert_into_recurring(self):
+		if self.doc.convert_into_recurring_invoice:
+			event = 'accounts.doctype.gl_control.gl_control.manage_recurring_invoices'
+			self.set_next_date()
+			if not self.doc.recurring_id:
+				set(self.doc, 'recurring_id', make_autoname('RECINV/.#####'))
+
+			if sql("select name from `tabReceivable Voucher` where ifnull(convert_into_recurring_invoice, 0) = 1 and next_date <= end_date"):
+				if not self.check_event_exists(event):
+					set_event(event,  interval = 60*60, recurring = 1)
+			else:
+				cancel_event(event)
+
+		elif self.doc.recurring_id:
+			sql("""update `tabReceivable Voucher` set convert_into_recurring_invoice = 0 where recurring_id = %s""", self.doc.recurring_id)
+
+
+	def check_event_exists(self, event):
+		try:
+			ev = Scheduler().get_events()
+		except:
+			msgprint("Scheduler database not exists. Please mail to support@erpnext.com", raise_exception=1)
+
+		if event in [d['event'] for d in ev]:
+			return 1
+
+
+	def set_next_date(self):
+		""" Set next date on which auto invoice will be created"""
+
+		if not self.doc.repeat_on_day_of_month:
+			msgprint("""Please enter 'Repeat on Day of Month' field value. \nThe day of the month on which auto invoice 
+						will be generated e.g. 05, 28 etc.""", raise_exception=1)
+
+		import datetime
+		m = getdate(self.doc.posting_date).month + 1
+		y = getdate(self.doc.posting_date).year
+		if m > 12:
+			m, y = 1, y+1
+		try:
+			next_date = datetime.date(y, m, cint(self.doc.repeat_on_day_of_month))
+		except:
+			import calendar
+			last_day = calendar.monthrange(y, m)[1]
+			next_date = datetime.date(y, m, last_day)
+		next_date = next_date.strftime("%Y-%m-%d")
+
+		set(self.doc, 'next_date', next_date)
diff --git a/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.txt b/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.txt
index 1abd6a7..e2fc0c6 100644
--- a/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.txt
+++ b/erpnext/accounts/doctype/receivable_voucher/receivable_voucher.txt
@@ -5,7 +5,7 @@
 	{
 		'creation': '2010-08-08 17:09:18',
 		'docstatus': 0,
-		'modified': '2011-10-19 16:31:54',
+		'modified': '2011-12-06 13:17:26',
 		'modified_by': 'Administrator',
 		'owner': 'Administrator'
 	},
@@ -21,7 +21,7 @@
 
 	# These values are common for all DocType
 	{
-		'_last_update': '1319014846',
+		'_last_update': '1323156733',
 		'change_log': '1. Change in pull_details method dt.-26-06-2009',
 		'colour': 'White:FFF',
 		'default_print_format': 'Standard',
@@ -34,7 +34,7 @@
 		'server_code_error': ' ',
 		'show_in_menu': 0,
 		'subject': 'To %(customer_name)s worth %(currency)s %(grand_total_export)s due on %(due_date)s | %(outstanding_amount)s outstanding',
-		'version': 363
+		'version': 383
 	},
 
 	# These values are common for all DocFormat
@@ -1343,5 +1343,115 @@
 		'permlevel': 0,
 		'print_hide': 1,
 		'report_hide': 1
+	},
+
+	# DocField
+	{
+		'depends_on': 'eval:doc.docstatus==1',
+		'doctype': 'DocField',
+		'fieldtype': 'Section Break',
+		'label': 'Recurring Invoice',
+		'permlevel': 0
+	},
+
+	# DocField
+	{
+		'doctype': 'DocField',
+		'fieldtype': 'Column Break',
+		'permlevel': 0,
+		'width': '50%'
+	},
+
+	# DocField
+	{
+		'allow_on_submit': 1,
+		'colour': 'White:FFF',
+		'depends_on': 'eval:doc.docstatus==1',
+		'description': 'Check if recurring invoice, uncheck to stop recurring or put proper End Date',
+		'doctype': 'DocField',
+		'fieldname': 'convert_into_recurring_invoice',
+		'fieldtype': 'Check',
+		'label': 'Convert into Recurring Invoice',
+		'no_copy': 1,
+		'permlevel': 0,
+		'print_hide': 1,
+		'trigger': 'Client'
+	},
+
+	# DocField
+	{
+		'allow_on_submit': 1,
+		'depends_on': 'eval:doc.convert_into_recurring_invoice==1',
+		'description': 'The day of the month on which auto invoice will be generated e.g. 05, 28 etc ',
+		'doctype': 'DocField',
+		'fieldname': 'repeat_on_day_of_month',
+		'fieldtype': 'Data',
+		'label': 'Repeat on Day of Month',
+		'no_copy': 1,
+		'permlevel': 0,
+		'print_hide': 1
+	},
+
+	# DocField
+	{
+		'allow_on_submit': 1,
+		'depends_on': 'eval:doc.convert_into_recurring_invoice==1',
+		'description': 'The date on which recurring invoice will be stop',
+		'doctype': 'DocField',
+		'fieldname': 'end_date',
+		'fieldtype': 'Date',
+		'label': 'End Date',
+		'no_copy': 1,
+		'permlevel': 0,
+		'print_hide': 1
+	},
+
+	# DocField
+	{
+		'doctype': 'DocField',
+		'fieldtype': 'Column Break',
+		'no_copy': 0,
+		'permlevel': 0,
+		'width': '50%'
+	},
+
+	# DocField
+	{
+		'allow_on_submit': 1,
+		'depends_on': 'eval:doc.convert_into_recurring_invoice==1',
+		'description': 'Enter email id separated by commas, invoice will be mailed automatically on particular date',
+		'doctype': 'DocField',
+		'fieldname': 'notification_email_address',
+		'fieldtype': 'Small Text',
+		'label': 'Notification Email Address',
+		'no_copy': 1,
+		'permlevel': 0,
+		'print_hide': 1
+	},
+
+	# DocField
+	{
+		'depends_on': 'eval:doc.convert_into_recurring_invoice==1',
+		'description': 'The unique id for tracking all recurring invoices ',
+		'doctype': 'DocField',
+		'fieldname': 'recurring_id',
+		'fieldtype': 'Data',
+		'label': 'Recurring Id',
+		'no_copy': 1,
+		'permlevel': 1,
+		'print_hide': 1
+	},
+
+	# DocField
+	{
+		'depends_on': 'eval:doc.convert_into_recurring_invoice==1',
+		'description': 'The date on which next invoice will be generated ',
+		'doctype': 'DocField',
+		'fieldname': 'next_date',
+		'fieldtype': 'Date',
+		'label': 'Next Date',
+		'no_copy': 1,
+		'permlevel': 1,
+		'print_hide': 1
 	}
 ]
\ No newline at end of file