fixing recurring invoice

This commit is contained in:
Anand Doshi 2012-11-30 12:48:33 +05:30
parent c2fb039697
commit b2293c48e8
4 changed files with 377 additions and 328 deletions

View File

@ -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.
<b>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.</b>
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 = '''<div><h2>%s</h2></div>
<div><h3>Invoice: %s</h3></div>
<table cellspacing= "5" cellpadding="5" width = "100%%">
<tr>
<td width = "50%%"><b>Customer</b><br>%s<br>%s</td>
<td width = "50%%">Invoice Date : %s<br>Invoice Period : %s to %s <br>Due Date : %s</td>
</tr>
</table>
''' % (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 = '''<table border="1px solid #CCC" width="100%%" cellpadding="0px" cellspacing="0px">
<tr>
<td width = "15%%" bgcolor="#CCC" align="left"><b>Item</b></td>
<td width = "40%%" bgcolor="#CCC" align="left"><b>Description</b></td>
<td width = "15%%" bgcolor="#CCC" align="center"><b>Qty</b></td>
<td width = "15%%" bgcolor="#CCC" align="center"><b>Rate</b></td>
<td width = "15%%" bgcolor="#CCC" align="center"><b>Amount</b></td>
</tr>
'''
for d in getlist(new_rv.doclist, 'entries'):
tbl += '<tr><td>' + d.item_code +'</td><td>' + d.description+'</td><td>' + cstr(d.qty) +'</td><td>' + cstr(d.basic_rate) +'</td><td>' + cstr(d.amount) +'</td></tr>'
tbl += '</table>'
totals =''' <table cellspacing= "5" cellpadding="5" width = "100%%">
<tr>
<td width = "50%%"></td>
<td width = "50%%">
<table width = "100%%">
<tr>
<td width = "50%%">Net Total: </td><td>%s </td>
</tr><tr>
<td width = "50%%">Total Tax: </td><td>%s </td>
</tr><tr>
<td width = "50%%">Grand Total: </td><td>%s</td>
</tr><tr>
<td width = "50%%">In Words: </td><td>%s</td>
</tr>
</table>
</td>
</tr>
<tr><td>Terms and Conditions:</td></tr>
<tr><td>%s</td></tr>
</table>
''' % (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)

View File

@ -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');
}
}
}
}

View File

@ -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.
<b>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.</b>
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 = '''<div><h2>%s</h2></div>
<div><h3>Invoice: %s</h3></div>
<table cellspacing= "5" cellpadding="5" width = "100%%">
<tr>
<td width = "50%%"><b>Customer</b><br>%s<br>%s</td>
<td width = "50%%">Invoice Date : %s<br>Invoice Period : %s to %s <br>Due Date : %s</td>
</tr>
</table>
''' % (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 = '''<table border="1px solid #CCC" width="100%%" cellpadding="0px" cellspacing="0px">
<tr>
<td width = "15%%" bgcolor="#CCC" align="left"><b>Item</b></td>
<td width = "40%%" bgcolor="#CCC" align="left"><b>Description</b></td>
<td width = "15%%" bgcolor="#CCC" align="center"><b>Qty</b></td>
<td width = "15%%" bgcolor="#CCC" align="center"><b>Rate</b></td>
<td width = "15%%" bgcolor="#CCC" align="center"><b>Amount</b></td>
</tr>
'''
for d in getlist(new_rv.doclist, 'entries'):
tbl += '<tr><td>' + d.item_code +'</td><td>' + d.description+'</td><td>' + cstr(d.qty) +'</td><td>' + cstr(d.basic_rate) +'</td><td>' + cstr(d.amount) +'</td></tr>'
tbl += '</table>'
totals =''' <table cellspacing= "5" cellpadding="5" width = "100%%">
<tr>
<td width = "50%%"></td>
<td width = "50%%">
<table width = "100%%">
<tr>
<td width = "50%%">Net Total: </td><td>%s </td>
</tr><tr>
<td width = "50%%">Total Tax: </td><td>%s </td>
</tr><tr>
<td width = "50%%">Grand Total: </td><td>%s</td>
</tr><tr>
<td width = "50%%">In Words: </td><td>%s</td>
</tr>
</table>
</td>
</tr>
<tr><td>Terms and Conditions:</td></tr>
<tr><td>%s</td></tr>
</table>
''' % (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)

View File

@ -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",