diff --git a/accounts/doctype/gl_control/gl_control.py b/accounts/doctype/gl_control/gl_control.py
index ef6093df60..9c5bade944 100644
--- a/accounts/doctype/gl_control/gl_control.py
+++ b/accounts/doctype/gl_control/gl_control.py
@@ -397,194 +397,3 @@ class DocType:
fy_obj = get_obj('Fiscal Year', fy[0])
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 = webnotes.conn.sql("""select name, recurring_id from `tabSales Invoice` \
- where ifnull(convert_into_recurring_invoice, 0) = 1 and next_date = %s \
- and next_date <= ifnull(end_date, '2199-12-31') and docstatus=1""", nowdate())
-
-
- exception_list = []
- for d in rv:
- if not webnotes.conn.sql("""select name from `tabSales Invoice` \
- where posting_date = %s and recurring_id = %s and docstatus=1""", (nowdate(), d[1])):
- try:
- prev_rv = get_obj('Sales Invoice', d[0], with_children=1)
- new_rv = create_new_invoice(prev_rv)
-
- send_notification(new_rv)
- webnotes.conn.commit()
- except Exception, e:
- webnotes.conn.rollback()
-
- webnotes.conn.begin()
- webnotes.conn.sql("update `tabSales Invoice` set \
- convert_into_recurring_invoice = 0 where name = %s", d[0])
- notify_errors(d[0], prev_rv.doc.owner)
- webnotes.conn.commit()
-
- exception_list.append(e)
- finally:
- webnotes.conn.begin()
-
- if exception_list:
- exception_message = "\n\n".join([cstr(d) for d in exception_list])
- raise Exception, exception_message
-
-
-def notify_errors(inv, owner):
- import webnotes
- import website
-
- exception_msg = """
- Dear User,
-
- An error occured while creating recurring invoice from %s (at %s).
-
- May be there are some invalid email ids mentioned in the invoice.
-
- To stop sending repetitive error notifications from the system, we have unchecked
- "Convert into Recurring" field in the invoice %s.
-
-
- Please correct the invoice and make the invoice recurring again.
-
- It is necessary to take this action today itself for the above mentioned recurring invoice \
- 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.
-
- Regards,
- Administrator
-
- """ % (inv, website.get_site_address(), inv)
- subj = "[Urgent] Error while creating recurring invoice from %s" % inv
-
- from webnotes.profile import get_system_managers
- recipients = get_system_managers()
- owner_email = webnotes.conn.get_value("Profile", owner, "email")
- if not owner_email in recipients:
- recipients.append(owner_email)
-
- assign_task_to_owner(inv, exception_msg, recipients)
- sendmail(recipients, subject=subj, msg = exception_msg)
-
-
-
-def assign_task_to_owner(inv, msg, users):
- for d in users:
- if d.lower() == 'administrator':
- d = webnotes.conn.sql("select ifnull(email_id, '') \
- from `tabProfile` where name = 'Administrator'")[0][0]
- from webnotes.widgets.form import assign_to
- args = {
- 'assign_to' : d,
- 'doctype' : 'Sales Invoice',
- 'name' : inv,
- 'description' : msg,
- 'priority' : 'Urgent'
- }
- assign_to.add(args)
-
-
-def create_new_invoice(prev_rv):
- # clone rv
- new_rv = clone(prev_rv)
-
- mdict = {'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6, 'Yearly': 12}
- mcount = mdict[prev_rv.doc.recurring_type]
-
- # update new rv
-
- 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.invoice_period_from_date = get_next_date(new_rv.doc.invoice_period_from_date, mcount)
- new_rv.doc.invoice_period_to_date = get_next_date(new_rv.doc.invoice_period_to_date, mcount)
- new_rv.doc.owner = prev_rv.doc.owner
- new_rv.doc.save()
-
- # submit and after submit
- new_rv.submit()
- new_rv.update_after_submit()
-
- return new_rv
-
-def get_next_date(dt, mcount):
- import datetime
- m = getdate(dt).month + mcount
- y = getdate(dt).year
- d = getdate(dt).day
- if m > 12:
- m, y = m-12, y+1
- try:
- next_month_date = datetime.date(y, m, d)
- except:
- import calendar
- last_day = calendar.monthrange(y, m)[1]
- next_month_date = datetime.date(y, m, last_day)
- return next_month_date.strftime("%Y-%m-%d")
-
-
-def send_notification(new_rv):
- """Notify concerned persons about recurring invoice generation"""
- subject = "Invoice : " + new_rv.doc.name
-
- com = new_rv.doc.company # webnotes.conn.get_value('Control Panel', '', 'letter_head')
-
- hd = '''
%s
- Invoice: %s
-
-
- Customer %s %s |
- Invoice Date : %s Invoice Period : %s to %s Due Date : %s |
-
-
- ''' % (com, new_rv.doc.name, new_rv.doc.customer_name, new_rv.doc.address_display, getdate(new_rv.doc.posting_date).strftime("%d-%m-%Y"), \
- getdate(new_rv.doc.invoice_period_from_date).strftime("%d-%m-%Y"), getdate(new_rv.doc.invoice_period_to_date).strftime("%d-%m-%Y"),\
- getdate(new_rv.doc.due_date).strftime("%d-%m-%Y"))
-
-
- tbl = '''
-
- Item |
- Description |
- Qty |
- Rate |
- Amount |
-
- '''
- for d in getlist(new_rv.doclist, 'entries'):
- tbl += '' + d.item_code +' | ' + d.description+' | ' + cstr(d.qty) +' | ' + cstr(d.basic_rate) +' | ' + cstr(d.amount) +' |
'
- tbl += '
'
-
- totals ='''
-
- |
-
-
-
- Net Total: | %s |
-
- Total Tax: | %s |
-
- Grand Total: | %s |
-
- In Words: | %s |
-
-
- |
-
- Terms and Conditions: |
- %s |
-
- ''' % (new_rv.doc.net_total, new_rv.doc.other_charges_total,new_rv.doc.grand_total, new_rv.doc.in_words,new_rv.doc.terms)
-
-
- msg = hd + tbl + totals
- recipients = new_rv.doc.notification_email_address.replace('\n', '').replace(' ', '').split(",")
- sendmail(recipients, subject=subject, msg = msg)
diff --git a/accounts/doctype/sales_invoice/sales_invoice.js b/accounts/doctype/sales_invoice/sales_invoice.js
index ad774fe0e8..b0e5a9d167 100644
--- a/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/accounts/doctype/sales_invoice/sales_invoice.js
@@ -94,8 +94,6 @@ cur_frm.cscript.hide_fields = function(doc, cdt, cdn) {
for(f in item_flds_normal) cur_frm.fields_dict['entries'].grid.set_column_disp(item_flds_normal[f], true);
for(f in item_flds_pos) cur_frm.fields_dict['entries'].grid.set_column_disp(item_flds_pos[f], false);
}
- if (doc.docstatus==1) unhide_field('recurring_invoice');
- else hide_field('recurring_invoice');
if(doc.customer) unhide_field('contact_section');
else hide_field('contact_section');
@@ -499,12 +497,6 @@ cur_frm.cscript.view_ledger_entry = function(){
wn.set_route('Report', 'GL Entry', 'General Ledger', 'Voucher No='+cur_frm.doc.name);
}
-// Default values for recurring invoices
-cur_frm.cscript.convert_into_recurring_invoice = function(doc, dt, dn) {
- if (doc.convert_into_recurring_invoice)
- get_server_fields('set_default_recurring_values','','',doc, dt, dn, 0);
-}
-
cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
var args = {
type: 'Sales Invoice',
@@ -513,11 +505,28 @@ cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
cur_frm.cscript.notify(doc, args);
}
-cur_frm.cscript.invoice_period_from_date = function(doc, dt, dn) {
- if(doc.invoice_period_from_date) {
- var recurring_type_map = { 'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6, 'Yearly': 12 };
+cur_frm.cscript.convert_into_recurring_invoice = function(doc, dt, dn) {
+ // set default values for recurring invoices
+ if(doc.convert_into_recurring_invoice) {
+ var owner_email = doc.owner=="Administrator"
+ ? wn.user_info("Administrator").email
+ : doc.owner;
+
+ doc.notification_email_address = $.map([cstr(owner_email),
+ cstr(doc.contact_email)], function(v) { return v || null; }).join(", ");
+ doc.repeat_on_day_of_month = wn.datetime.str_to_obj(doc.posting_date).getDate();
+ }
+
+ refresh_many(["notification_email_address", "repeat_on_day_of_month"]);
+}
- var months = $(recurring_type_map).attr(doc.recurring_type);
+cur_frm.cscript.invoice_period_from_date = function(doc, dt, dn) {
+ // set invoice_period_to_date
+ if(doc.invoice_period_from_date) {
+ 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 = wn.datetime.add_months(doc.invoice_period_from_date,
months);
@@ -525,4 +534,4 @@ cur_frm.cscript.invoice_period_from_date = function(doc, dt, dn) {
refresh_field('invoice_period_to_date');
}
}
-}
\ No newline at end of file
+}
diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py
index 3763abb872..c1e8f28243 100644
--- a/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/accounts/doctype/sales_invoice/sales_invoice.py
@@ -40,9 +40,90 @@ class DocType(TransactionBase):
self.tname = 'Sales Invoice Item'
self.fname = 'entries'
-
def autoname(self):
self.doc.name = make_autoname(self.doc.naming_series+ '.#####')
+
+ def validate(self):
+ self.so_dn_required()
+ self.validate_proj_cust()
+ sales_com_obj = get_obj('Sales Common')
+ sales_com_obj.check_stop_sales_order(self)
+ sales_com_obj.check_active_sales_items(self)
+ sales_com_obj.check_conversion_rate(self)
+ sales_com_obj.validate_max_discount(self, 'entries') #verify whether rate is not greater than tolerance
+ sales_com_obj.get_allocated_sum(self) # this is to verify that the allocated % of sales persons is 100%
+ sales_com_obj.validate_fiscal_year(self.doc.fiscal_year,self.doc.posting_date,'Posting Date')
+ self.validate_customer()
+ self.validate_customer_account()
+ self.validate_debit_acc()
+ self.validate_fixed_asset_account()
+ self.add_remarks()
+ if cint(self.doc.is_pos):
+ self.validate_pos()
+ self.validate_write_off_account()
+ if cint(self.doc.update_stock):
+ sl = get_obj('Stock Ledger')
+ sl.validate_serial_no(self, 'entries')
+ sl.validate_serial_no(self, 'packing_details')
+ self.validate_item_code()
+ self.update_current_stock()
+ self.validate_delivery_note()
+ self.set_in_words()
+ if not self.doc.is_opening:
+ self.doc.is_opening = 'No'
+ self.set_aging_date()
+ self.clear_advances()
+ self.set_against_income_account()
+ self.validate_c_form()
+
+ def on_submit(self):
+ if cint(self.doc.is_pos) == 1:
+ if cint(self.doc.update_stock) == 1:
+ sl_obj = get_obj("Stock Ledger")
+ sl_obj.validate_serial_no_warehouse(self, 'entries')
+ sl_obj.validate_serial_no_warehouse(self, 'packing_details')
+
+ sl_obj.update_serial_record(self, 'entries', is_submit = 1, is_incoming = 0)
+ sl_obj.update_serial_record(self, 'packing_details', is_submit = 1, is_incoming = 0)
+
+ self.update_stock_ledger(update_stock=1)
+ else:
+ # Check for Approving Authority
+ if not self.doc.recurring_id:
+ get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, self.doc.company, self.doc.grand_total, self)
+
+ self.check_prev_docstatus()
+ get_obj("Sales Common").update_prevdoc_detail(1,self)
+
+ # this sequence because outstanding may get -ve
+ self.make_gl_entries()
+
+ if not cint(self.doc.is_pos) == 1:
+ self.update_against_document_in_jv()
+
+ self.update_c_form()
+
+ self.convert_to_recurring()
+
+
+ def on_cancel(self):
+ if cint(self.doc.is_pos) == 1:
+ if cint(self.doc.update_stock) == 1:
+ sl = get_obj('Stock Ledger')
+ sl.update_serial_record(self, 'entries', is_submit = 0, is_incoming = 0)
+ sl.update_serial_record(self, 'packing_details', is_submit = 0, is_incoming = 0)
+
+ self.update_stock_ledger(update_stock = -1)
+
+ sales_com_obj = get_obj(dt = 'Sales Common')
+ sales_com_obj.check_stop_sales_order(self)
+ self.check_next_docstatus()
+ sales_com_obj.update_prevdoc_detail(0, self)
+
+ self.make_gl_entries(is_cancel=1)
+
+ def on_update_after_submit(self):
+ self.convert_into_recurring()
def set_pos_fields(self):
@@ -428,40 +509,6 @@ class DocType(TransactionBase):
d.projected_qty = bin and flt(bin[0]['projected_qty']) or 0
- def validate(self):
- self.so_dn_required()
- self.validate_proj_cust()
- sales_com_obj = get_obj('Sales Common')
- sales_com_obj.check_stop_sales_order(self)
- sales_com_obj.check_active_sales_items(self)
- sales_com_obj.check_conversion_rate(self)
- sales_com_obj.validate_max_discount(self, 'entries') #verify whether rate is not greater than tolerance
- sales_com_obj.get_allocated_sum(self) # this is to verify that the allocated % of sales persons is 100%
- sales_com_obj.validate_fiscal_year(self.doc.fiscal_year,self.doc.posting_date,'Posting Date')
- self.validate_customer()
- self.validate_customer_account()
- self.validate_debit_acc()
- self.validate_fixed_asset_account()
- self.add_remarks()
- if cint(self.doc.is_pos):
- self.validate_pos()
- self.validate_write_off_account()
- if cint(self.doc.update_stock):
- sl = get_obj('Stock Ledger')
- sl.validate_serial_no(self, 'entries')
- sl.validate_serial_no(self, 'packing_details')
- self.validate_item_code()
- self.update_current_stock()
- self.validate_delivery_note()
- self.set_in_words()
- if not self.doc.is_opening:
- self.doc.is_opening = 'No'
- self.set_aging_date()
- self.clear_advances()
- self.set_against_income_account()
- self.validate_c_form()
-
-
def get_warehouse(self):
w = webnotes.conn.sql("select warehouse from `tabPOS Setting` where ifnull(user,'') = '%s' and company = '%s'" % (session['user'], self.doc.company))
w = w and w[0][0] or ''
@@ -598,80 +645,13 @@ class DocType(TransactionBase):
if submit_jv:
msgprint("Journal Voucher : " + cstr(submit_jv[0][0]) + " has been created against " + cstr(self.doc.doctype) + ". So " + cstr(self.doc.doctype) + " cannot be Cancelled.")
raise Exception, "Validation Error."
-
-
- def on_submit(self):
- if cint(self.doc.is_pos) == 1:
- if cint(self.doc.update_stock) == 1:
- sl_obj = get_obj("Stock Ledger")
- sl_obj.validate_serial_no_warehouse(self, 'entries')
- sl_obj.validate_serial_no_warehouse(self, 'packing_details')
-
- sl_obj.update_serial_record(self, 'entries', is_submit = 1, is_incoming = 0)
- sl_obj.update_serial_record(self, 'packing_details', is_submit = 1, is_incoming = 0)
-
- self.update_stock_ledger(update_stock=1)
- else:
- # Check for Approving Authority
- if not self.doc.recurring_id:
- get_obj('Authorization Control').validate_approving_authority(self.doc.doctype, self.doc.company, self.doc.grand_total, self)
-
- self.check_prev_docstatus()
- get_obj("Sales Common").update_prevdoc_detail(1,self)
-
- # this sequence because outstanding may get -ve
- self.make_gl_entries()
-
- if not cint(self.doc.is_pos) == 1:
- self.update_against_document_in_jv()
-
- self.update_c_form()
-
-
- def on_cancel(self):
- if cint(self.doc.is_pos) == 1:
- if cint(self.doc.update_stock) == 1:
- sl = get_obj('Stock Ledger')
- sl.update_serial_record(self, 'entries', is_submit = 0, is_incoming = 0)
- sl.update_serial_record(self, 'packing_details', is_submit = 0, is_incoming = 0)
-
- self.update_stock_ledger(update_stock = -1)
-
- sales_com_obj = get_obj(dt = 'Sales Common')
- sales_com_obj.check_stop_sales_order(self)
- self.check_next_docstatus()
- sales_com_obj.update_prevdoc_detail(0, self)
-
- self.make_gl_entries(is_cancel=1)
-
- def set_default_recurring_values(self):
- from webnotes.utils import cstr
-
- owner_email = self.doc.owner
- if owner_email.lower() == 'administrator':
- owner_email = cstr(webnotes.conn.get_value("Profile", "Administrator", "email"))
-
- ret = {
- 'repeat_on_day_of_month' : getdate(self.doc.posting_date).day,
- 'notification_email_address' : ', '.join([owner_email, cstr(self.doc.contact_email)]),
- }
- return ret
-
- def validate_notification_email_id(self):
- if self.doc.notification_email_address:
- from webnotes.utils import validate_email_add
- for add in self.doc.notification_email_address.replace('\n', '').replace(' ', '').split(","):
- if add and not validate_email_add(add):
- msgprint("%s is not a valid email address" % add, raise_exception=1)
- else:
- msgprint("Notification Email Addresses not specified for recurring invoice",
- raise_exception=1)
-
-
- def on_update_after_submit(self):
- self.convert_into_recurring()
-
-
+
+ @property
+ def meta(self):
+ if not hasattr(self, "_meta"):
+ self._meta = webnotes.get_doctype(self.doc.doctype)
+ return self._meta
+
def convert_into_recurring(self):
if self.doc.convert_into_recurring_invoice:
self.validate_notification_email_id()
@@ -685,6 +665,53 @@ class DocType(TransactionBase):
webnotes.conn.set(self.doc, 'recurring_id', make_autoname('RECINV/.#####'))
elif self.doc.recurring_id:
webnotes.conn.sql("""update `tabSales Invoice` set convert_into_recurring_invoice = 0 where recurring_id = %s""", self.doc.recurring_id)
+
+ def validate_notification_email_id(self):
+
+ if self.doc.notification_email_address:
+ email_list = filter(None, [cstr(email).strip() for email in
+ self.doc.notification_email_address.replace("\n", "").split(",")])
+
+ from webnotes.utils import validate_email_add
+ for email in email_list:
+ if not validate_email_add(email):
+ msgprint("%s is not a valid email address" % add, raise_exception=1)
+
+ else:
+ msgprint(
+
+ _("Notification Email Addresses not specified for recurring invoice",
+ raise_exception=1)
+
+
+
+ for add in self.doc.notification_email_address.replace('\n', '').replace(' ', '').split(","):
+ if add and not validate_email_add(add):
+ msgprint("%s is not a valid email address" % add, raise_exception=1)
+ else:
+ msgprint("Notification Email Addresses not specified for recurring invoice",
+ raise_exception=1)
+
+
+
+
+
+ # def set_default_recurring_values(self):
+ # from webnotes.utils import cstr
+ #
+ # owner_email = self.doc.owner
+ # if owner_email.lower() == 'administrator':
+ # owner_email = cstr(webnotes.conn.get_value("Profile", "Administrator", "email"))
+ #
+ # ret = {
+ # 'repeat_on_day_of_month' : getdate(self.doc.posting_date).day,
+ # 'notification_email_address' : ', '.join([owner_email, cstr(self.doc.contact_email)]),
+ # }
+ # return ret
+ #
+
+
+
def set_next_date(self):
""" Set next date on which auto invoice will be created"""
@@ -709,3 +736,193 @@ class DocType(TransactionBase):
webnotes.conn.set(self.doc, 'next_date', next_date)
+
+def manage_recurring_invoices():
+ """
+ Create recurring invoices on specific date by copying the original one
+ and notify the concerned people
+ """
+ rv = webnotes.conn.sql("""select name, recurring_id from `tabSales Invoice` \
+ where ifnull(convert_into_recurring_invoice, 0) = 1 and next_date = %s \
+ and next_date <= ifnull(end_date, '2199-12-31') and docstatus=1""", nowdate())
+
+
+ exception_list = []
+ for d in rv:
+ if not webnotes.conn.sql("""select name from `tabSales Invoice` \
+ where posting_date = %s and recurring_id = %s and docstatus=1""", (nowdate(), d[1])):
+ try:
+ prev_rv = get_obj('Sales Invoice', d[0], with_children=1)
+ new_rv = create_new_invoice(prev_rv)
+
+ send_notification(new_rv)
+ webnotes.conn.commit()
+ except Exception, e:
+ webnotes.conn.rollback()
+
+ webnotes.conn.begin()
+ webnotes.conn.sql("update `tabSales Invoice` set \
+ convert_into_recurring_invoice = 0 where name = %s", d[0])
+ notify_errors(d[0], prev_rv.doc.owner)
+ webnotes.conn.commit()
+
+ exception_list.append(e)
+ finally:
+ webnotes.conn.begin()
+
+ if exception_list:
+ exception_message = "\n\n".join([cstr(d) for d in exception_list])
+ raise Exception, exception_message
+
+
+def notify_errors(inv, owner):
+ import webnotes
+ import website
+
+ exception_msg = """
+ Dear User,
+
+ An error occured while creating recurring invoice from %s (at %s).
+
+ May be there are some invalid email ids mentioned in the invoice.
+
+ To stop sending repetitive error notifications from the system, we have unchecked
+ "Convert into Recurring" field in the invoice %s.
+
+
+ Please correct the invoice and make the invoice recurring again.
+
+ It is necessary to take this action today itself for the above mentioned recurring invoice \
+ 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.
+
+ Regards,
+ Administrator
+
+ """ % (inv, website.get_site_address(), inv)
+ subj = "[Urgent] Error while creating recurring invoice from %s" % inv
+
+ from webnotes.profile import get_system_managers
+ recipients = get_system_managers()
+ owner_email = webnotes.conn.get_value("Profile", owner, "email")
+ if not owner_email in recipients:
+ recipients.append(owner_email)
+
+ assign_task_to_owner(inv, exception_msg, recipients)
+ sendmail(recipients, subject=subj, msg = exception_msg)
+
+
+
+def assign_task_to_owner(inv, msg, users):
+ for d in users:
+ if d.lower() == 'administrator':
+ d = webnotes.conn.sql("select ifnull(email_id, '') \
+ from `tabProfile` where name = 'Administrator'")[0][0]
+ from webnotes.widgets.form import assign_to
+ args = {
+ 'assign_to' : d,
+ 'doctype' : 'Sales Invoice',
+ 'name' : inv,
+ 'description' : msg,
+ 'priority' : 'Urgent'
+ }
+ assign_to.add(args)
+
+
+def create_new_invoice(prev_rv):
+ # clone rv
+ new_rv = clone(prev_rv)
+
+ mdict = {'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6, 'Yearly': 12}
+ mcount = mdict[prev_rv.doc.recurring_type]
+
+ # update new rv
+
+ 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.invoice_period_from_date = get_next_date(new_rv.doc.invoice_period_from_date, mcount)
+ new_rv.doc.invoice_period_to_date = get_next_date(new_rv.doc.invoice_period_to_date, mcount)
+ new_rv.doc.owner = prev_rv.doc.owner
+ new_rv.doc.save()
+
+ # submit and after submit
+ new_rv.submit()
+ new_rv.update_after_submit()
+
+ return new_rv
+
+def get_next_date(dt, mcount):
+ import datetime
+ m = getdate(dt).month + mcount
+ y = getdate(dt).year
+ d = getdate(dt).day
+ if m > 12:
+ m, y = m-12, y+1
+ try:
+ next_month_date = datetime.date(y, m, d)
+ except:
+ import calendar
+ last_day = calendar.monthrange(y, m)[1]
+ next_month_date = datetime.date(y, m, last_day)
+ return next_month_date.strftime("%Y-%m-%d")
+
+
+def send_notification(new_rv):
+ """Notify concerned persons about recurring invoice generation"""
+ subject = "Invoice : " + new_rv.doc.name
+
+ com = new_rv.doc.company # webnotes.conn.get_value('Control Panel', '', 'letter_head')
+
+ hd = '''%s
+ Invoice: %s
+
+
+ Customer %s %s |
+ Invoice Date : %s Invoice Period : %s to %s Due Date : %s |
+
+
+ ''' % (com, new_rv.doc.name, new_rv.doc.customer_name, new_rv.doc.address_display, getdate(new_rv.doc.posting_date).strftime("%d-%m-%Y"), \
+ getdate(new_rv.doc.invoice_period_from_date).strftime("%d-%m-%Y"), getdate(new_rv.doc.invoice_period_to_date).strftime("%d-%m-%Y"),\
+ getdate(new_rv.doc.due_date).strftime("%d-%m-%Y"))
+
+
+ tbl = '''
+
+ Item |
+ Description |
+ Qty |
+ Rate |
+ Amount |
+
+ '''
+ for d in getlist(new_rv.doclist, 'entries'):
+ tbl += '' + d.item_code +' | ' + d.description+' | ' + cstr(d.qty) +' | ' + cstr(d.basic_rate) +' | ' + cstr(d.amount) +' |
'
+ tbl += '
'
+
+ totals ='''
+
+ |
+
+
+
+ Net Total: | %s |
+
+ Total Tax: | %s |
+
+ Grand Total: | %s |
+
+ In Words: | %s |
+
+
+ |
+
+ Terms and Conditions: |
+ %s |
+
+ ''' % (new_rv.doc.net_total, new_rv.doc.other_charges_total,new_rv.doc.grand_total, new_rv.doc.in_words,new_rv.doc.terms)
+
+
+ msg = hd + tbl + totals
+ recipients = new_rv.doc.notification_email_address.replace('\n', '').replace(' ', '').split(",")
+ sendmail(recipients, subject=subject, msg = msg)
diff --git a/accounts/doctype/sales_invoice/sales_invoice.txt b/accounts/doctype/sales_invoice/sales_invoice.txt
index 4790bc6367..2b968c61a1 100644
--- a/accounts/doctype/sales_invoice/sales_invoice.txt
+++ b/accounts/doctype/sales_invoice/sales_invoice.txt
@@ -2,12 +2,13 @@
{
"owner": "Administrator",
"docstatus": 0,
- "creation": "2012-10-10 10:52:22",
+ "creation": "2012-09-10 12:22:26",
"modified_by": "Administrator",
- "modified": "2012-09-07 11:56:59"
+ "modified": "2012-11-30 12:29:56"
},
{
"is_submittable": 1,
+ "autoname": "naming_series:",
"allow_attach": 1,
"default_print_format": "Standard",
"search_fields": "posting_date, due_date, debit_to, fiscal_year, grand_total, outstanding_amount",
@@ -34,6 +35,15 @@
"name": "Sales Invoice",
"doctype": "DocType"
},
+ {
+ "print_hide": 1,
+ "oldfieldtype": "Section Break",
+ "doctype": "DocField",
+ "label": "Basic Info",
+ "fieldname": "basic_info",
+ "fieldtype": "Section Break",
+ "permlevel": 0
+ },
{
"print_hide": 0,
"oldfieldtype": "Column Break",
@@ -217,9 +227,9 @@
"permlevel": 0
},
{
- "allow_on_submit": 1,
"oldfieldtype": "Table",
"colour": "White:FFF",
+ "allow_on_submit": 1,
"doctype": "DocField",
"label": "Entries",
"oldfieldname": "entries",
@@ -428,9 +438,9 @@
"permlevel": 0
},
{
- "allow_on_submit": 1,
"oldfieldtype": "Table",
"colour": "White:FFF",
+ "allow_on_submit": 1,
"doctype": "DocField",
"label": "Taxes and Charges1",
"oldfieldname": "other_charges",
@@ -1174,6 +1184,7 @@
},
{
"print_hide": 1,
+ "depends_on": "eval:doc.docstatus<2",
"colour": "White:FFF",
"doctype": "DocField",
"label": "Recurring Invoice",
@@ -1193,7 +1204,7 @@
"print_hide": 1,
"description": "Check if recurring invoice, uncheck to stop recurring or put proper End Date",
"no_copy": 1,
- "depends_on": "eval:doc.docstatus==1",
+ "depends_on": "eval:doc.docstatus<2",
"colour": "White:FFF",
"allow_on_submit": 1,
"doctype": "DocField",
@@ -1205,23 +1216,24 @@
},
{
"print_hide": 1,
- "allow_on_submit": 1,
"description": "Select the period when the invoice will be generated automatically",
"no_copy": 1,
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
+ "colour": "White:FFF",
+ "allow_on_submit": 1,
"doctype": "DocField",
"label": "Recurring Type",
- "options": "Monthly\nQuarterly\nHalf-yearly\nYearly",
+ "permlevel": 0,
"fieldname": "recurring_type",
"fieldtype": "Select",
- "permlevel": 0
+ "options": "Monthly\nQuarterly\nHalf-yearly\nYearly"
},
{
"print_hide": 1,
- "allow_on_submit": 1,
"description": "The day of the month on which auto invoice will be generated e.g. 05, 28 etc ",
"no_copy": 1,
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
+ "allow_on_submit": 1,
"doctype": "DocField",
"label": "Repeat on Day of Month",
"fieldname": "repeat_on_day_of_month",
@@ -1230,11 +1242,11 @@
},
{
"print_hide": 1,
- "allow_on_submit": 1,
"description": "Start date of the invoice period",
"no_copy": 1,
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
"colour": "White:FFF",
+ "allow_on_submit": 1,
"doctype": "DocField",
"label": "Invoice Period From Date",
"fieldname": "invoice_period_from_date",
@@ -1243,10 +1255,10 @@
},
{
"print_hide": 1,
- "allow_on_submit": 1,
"description": "End date of the invoice period",
"no_copy": 1,
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
+ "allow_on_submit": 1,
"doctype": "DocField",
"label": "Invoice Period To Date",
"fieldname": "invoice_period_to_date",
@@ -1264,10 +1276,10 @@
},
{
"print_hide": 1,
- "allow_on_submit": 1,
"description": "Enter email id separated by commas, invoice will be mailed automatically on particular date",
"no_copy": 1,
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
+ "allow_on_submit": 1,
"doctype": "DocField",
"label": "Notification Email Address",
"fieldname": "notification_email_address",
@@ -1276,9 +1288,10 @@
},
{
"print_hide": 1,
- "description": "The unique id for tracking all recurring invoices ",
+ "description": "The unique id for tracking all recurring invoices.\u00a0It is generated on submit.",
"no_copy": 1,
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
+ "colour": "White:FFF",
"doctype": "DocField",
"label": "Recurring Id",
"fieldname": "recurring_id",
@@ -1287,9 +1300,10 @@
},
{
"print_hide": 1,
- "description": "The date on which next invoice will be generated ",
+ "description": "The date on which next invoice will be generated. It is generated on submit.\n",
"no_copy": 1,
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
+ "colour": "White:FFF",
"doctype": "DocField",
"label": "Next Date",
"fieldname": "next_date",
@@ -1298,10 +1312,10 @@
},
{
"print_hide": 1,
- "allow_on_submit": 1,
"description": "The date on which recurring invoice will be stop",
"no_copy": 1,
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
+ "allow_on_submit": 1,
"doctype": "DocField",
"label": "End Date",
"fieldname": "end_date",