From b2293c48e8fa601becfec422e64473598c8f7d51 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Fri, 30 Nov 2012 12:48:33 +0530 Subject: [PATCH] fixing recurring invoice --- accounts/doctype/gl_control/gl_control.py | 191 -------- .../doctype/sales_invoice/sales_invoice.js | 35 +- .../doctype/sales_invoice/sales_invoice.py | 435 +++++++++++++----- .../doctype/sales_invoice/sales_invoice.txt | 44 +- 4 files changed, 377 insertions(+), 328 deletions(-) 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 = ''' - - - - - - - - ''' - for d in getlist(new_rv.doclist, 'entries'): - tbl += '' - tbl += '
ItemDescriptionQtyRateAmount
' + d.item_code +'' + d.description+'' + cstr(d.qty) +'' + cstr(d.basic_rate) +'' + cstr(d.amount) +'
' - - 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 = ''' + + + + + + + + ''' + for d in getlist(new_rv.doclist, 'entries'): + tbl += '' + tbl += '
ItemDescriptionQtyRateAmount
' + d.item_code +'' + d.description+'' + cstr(d.qty) +'' + cstr(d.basic_rate) +'' + cstr(d.amount) +'
' + + 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",