refactored a recurring sales invoice

This commit is contained in:
Anand Doshi 2012-11-30 15:11:12 +05:30
parent f991fe3997
commit 420e1b42e2
3 changed files with 162 additions and 184 deletions

View File

@ -21,7 +21,7 @@ import webnotes
from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, 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, getchildren, make_autoname
from webnotes.model.wrapper import getlist, copy_doclist, clone
from webnotes.model.wrapper import getlist, copy_doclist
from webnotes.model.code import get_obj
from webnotes import session, form, msgprint, errprint
from webnotes.utils.email_lib import sendmail

View File

@ -19,6 +19,9 @@ from __future__ import unicode_literals
import webnotes
from webnotes.utils import add_days, add_months, add_years, cint, cstr,date_diff, default_fields, flt, fmt_money, formatdate,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 comma_and
from webnotes import _
from webnotes.model import db_exists
from webnotes.model.doc import Document, addchild, getchildren, make_autoname
from webnotes.model.wrapper import getlist, copy_doclist
@ -29,6 +32,8 @@ in_transaction = webnotes.conn.in_transaction
convert_to_lists = webnotes.conn.convert_to_lists
session = webnotes.session
month_map = {'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6, 'Yearly': 12}
# -----------------------------------------------------------------------------------------
from utilities.transaction_base import TransactionBase
@ -75,6 +80,7 @@ class DocType(TransactionBase):
self.clear_advances()
self.set_against_income_account()
self.validate_c_form()
self.validate_recurring_invoice()
def on_submit(self):
if cint(self.doc.is_pos) == 1:
@ -123,7 +129,8 @@ class DocType(TransactionBase):
self.make_gl_entries(is_cancel=1)
def on_update_after_submit(self):
self.convert_into_recurring()
self.validate_recurring_invoice()
self.convert_to_recurring()
def set_pos_fields(self):
"""Set retail related fields from pos settings"""
@ -651,22 +658,35 @@ class DocType(TransactionBase):
self._meta = webnotes.get_doctype(self.doc.doctype)
return self._meta
def convert_into_recurring(self):
def validate_recurring_invoice(self):
if self.doc.convert_into_recurring_invoice:
self.validate_notification_email_id()
if not self.doc.recurring_type:
msgprint("Please select recurring type", raise_exception=1)
elif not self.doc.invoice_period_from_date or not self.doc.invoice_period_to_date:
msgprint("Invoice period from date and to date is mandatory for recurring invoice", raise_exception=1)
self.set_next_date()
msgprint(_("Please select: ") + self.meta.get_label("recurring_type"),
raise_exception=1)
elif not (self.doc.invoice_period_from_date and \
self.doc.invoice_period_to_date):
msgprint(comma_and([self.meta.get_label("invoice_period_from_date"),
self.meta.get_label("invoice_period_to_date")])
+ _(": Mandatory for a Recurring Invoice."),
raise_exception=True)
def convert_to_recurring(self):
if self.doc.convert_into_recurring_invoice:
if not self.doc.recurring_id:
webnotes.conn.set(self.doc, 'recurring_id', make_autoname('RECINV/.#####'))
webnotes.conn.set(self.doc, "recurring_id",
make_autoname("RECINV/.#####"))
self.set_next_date()
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)
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(",")])
@ -674,98 +694,71 @@ class DocType(TransactionBase):
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",
msgprint(self.meta.get_label("notification_email_address") \
+ " - " + _("Invalid Email Address") + ": \"%s\"" % email,
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"""
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
msgprint("""Please enter 'Repeat on Day of Month' field value.
The day of the month on which auto invoice
will be generated e.g. 05, 28 etc.""", raise_exception=1)
import datetime
mcount = {'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6, 'Yearly': 12}
m = getdate(self.doc.posting_date).month + mcount[self.doc.recurring_type]
y = getdate(self.doc.posting_date).year
if m > 12:
m, y = m-12, 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")
next_date = get_next_date(self.doc.posting_date,
month_map[self.doc.recurring_type], cint(self.doc.repeat_on_day_of_month))
webnotes.conn.set(self.doc, 'next_date', next_date)
def get_next_date(dt, mcount, day=None):
import datetime
month = getdate(dt).month + mcount
year = getdate(dt).year
if not day:
day = getdate(dt).day
if month > 12:
month, year = m-12, y+1
try:
next_month_date = datetime.date(year, month, day)
except:
import calendar
last_day = calendar.monthrange(year, month)[1]
next_month_date = datetime.date(year, month, last_day)
return next_month_date.strftime("%Y-%m-%d")
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())
recurring_invoices = webnotes.conn.sql("""select name, recurring_id
from `tabSales Invoice` where ifnull(convert_into_recurring_invoice, 0)=1
and docstatus=1 and next_date=%s
and next_date <= ifnull(end_date, '2199-12-31')""", 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])):
for ref_invoice, recurring_id in recurring_invoices:
if not webnotes.conn.sql("""select name from `tabSales Invoice`
where posting_date=%s and recurring_id=%s and docstatus=1""",
(nowdate(), recurring_id)):
try:
prev_rv = get_obj('Sales Invoice', d[0], with_children=1)
new_rv = create_new_invoice(prev_rv)
send_notification(new_rv)
ref_wrapper = webnotes.model_wrapper('Sales Invoice', ref_invoice)
new_invoice_wrapper = make_new_invoice(ref_wrapper)
send_notification(new_invoice_wrapper)
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)
convert_into_recurring_invoice = 0 where name = %s", ref_invoice)
notify_errors(ref_invoice, ref_wrapper.doc.owner)
webnotes.conn.commit()
exception_list.append(e)
exception_list.append(webnotes.getTraceback())
finally:
webnotes.conn.begin()
@ -773,99 +766,33 @@ def manage_recurring_invoices():
exception_message = "\n\n".join([cstr(d) for d in exception_list])
raise Exception, exception_message
def make_new_invoice(ref_wrapper):
from webnotes.model.wrapper import clone
new_invoice = clone(ref_wrapper)
def notify_errors(inv, owner):
import webnotes
import website
mcount = month_map[ref_wrapper.doc.recurring_type]
exception_msg = """
Dear User,
today = nowdate()
An error occured while creating recurring invoice from %s (at %s).
new_invoice.doc.fields.update({
"posting_date": today,
"aging_date": today,
May be there are some invalid email ids mentioned in the invoice.
"due_date": add_days(today, cint(date_diff(ref_wrapper.doc.due_date,
ref_wrapper.doc.posting_date))),
To stop sending repetitive error notifications from the system, we have unchecked
"Convert into Recurring" field in the invoice %s.
"invoice_period_from_date": \
get_next_date(ref_wrapper.doc.invoice_period_from_date, mcount),
"invoice_period_to_date": \
get_next_date(ref_wrapper.doc.invoice_period_to_date, mcount),
Please correct the invoice and make the invoice recurring again.
"owner": ref_wrapper.doc.owner,
})
<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")
new_invoice.submit()
return new_invoice
def send_notification(new_rv):
"""Notify concerned persons about recurring invoice generation"""
@ -919,9 +846,60 @@ def send_notification(new_rv):
<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)
''' % (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)
sendmail(new_rv.doc.notification_email_address, subject=subject, msg = msg)
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:
from webnotes.widgets.form import assign_to
args = {
'assign_to' : d,
'doctype' : 'Sales Invoice',
'name' : inv,
'description' : msg,
'priority' : 'Urgent'
}
assign_to.add(args)

View File

@ -39,7 +39,7 @@ def execute_daily():
run_fn(send)
# run recurring invoices
from accounts.doctype.gl_control.gl_control import manage_recurring_invoices
from accounts.doctype.sales_invoice.sales_invoice import manage_recurring_invoices
run_fn(manage_recurring_invoices)
# send bulk emails