fixing recurring invoice
This commit is contained in:
parent
c2fb039697
commit
b2293c48e8
@ -397,194 +397,3 @@ class DocType:
|
|||||||
fy_obj = get_obj('Fiscal Year', fy[0])
|
fy_obj = get_obj('Fiscal Year', fy[0])
|
||||||
for a in set(ac_list):
|
for a in set(ac_list):
|
||||||
fy_obj.repost(a)
|
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)
|
|
||||||
|
@ -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_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);
|
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');
|
if(doc.customer) unhide_field('contact_section');
|
||||||
else hide_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);
|
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) {
|
cur_frm.cscript.on_submit = function(doc, cdt, cdn) {
|
||||||
var args = {
|
var args = {
|
||||||
type: 'Sales Invoice',
|
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.notify(doc, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_frm.cscript.invoice_period_from_date = function(doc, dt, dn) {
|
cur_frm.cscript.convert_into_recurring_invoice = function(doc, dt, dn) {
|
||||||
if(doc.invoice_period_from_date) {
|
// set default values for recurring invoices
|
||||||
var recurring_type_map = { 'Monthly': 1, 'Quarterly': 3, 'Half-yearly': 6, 'Yearly': 12 };
|
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) {
|
if(months) {
|
||||||
var to_date = wn.datetime.add_months(doc.invoice_period_from_date,
|
var to_date = wn.datetime.add_months(doc.invoice_period_from_date,
|
||||||
months);
|
months);
|
||||||
@ -525,4 +534,4 @@ cur_frm.cscript.invoice_period_from_date = function(doc, dt, dn) {
|
|||||||
refresh_field('invoice_period_to_date');
|
refresh_field('invoice_period_to_date');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,9 +40,90 @@ class DocType(TransactionBase):
|
|||||||
self.tname = 'Sales Invoice Item'
|
self.tname = 'Sales Invoice Item'
|
||||||
self.fname = 'entries'
|
self.fname = 'entries'
|
||||||
|
|
||||||
|
|
||||||
def autoname(self):
|
def autoname(self):
|
||||||
self.doc.name = make_autoname(self.doc.naming_series+ '.#####')
|
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):
|
def set_pos_fields(self):
|
||||||
@ -428,40 +509,6 @@ class DocType(TransactionBase):
|
|||||||
d.projected_qty = bin and flt(bin[0]['projected_qty']) or 0
|
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):
|
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 = 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 ''
|
w = w and w[0][0] or ''
|
||||||
@ -598,80 +645,13 @@ class DocType(TransactionBase):
|
|||||||
if submit_jv:
|
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.")
|
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."
|
raise Exception, "Validation Error."
|
||||||
|
|
||||||
|
@property
|
||||||
def on_submit(self):
|
def meta(self):
|
||||||
if cint(self.doc.is_pos) == 1:
|
if not hasattr(self, "_meta"):
|
||||||
if cint(self.doc.update_stock) == 1:
|
self._meta = webnotes.get_doctype(self.doc.doctype)
|
||||||
sl_obj = get_obj("Stock Ledger")
|
return self._meta
|
||||||
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()
|
|
||||||
|
|
||||||
|
|
||||||
def convert_into_recurring(self):
|
def convert_into_recurring(self):
|
||||||
if self.doc.convert_into_recurring_invoice:
|
if self.doc.convert_into_recurring_invoice:
|
||||||
self.validate_notification_email_id()
|
self.validate_notification_email_id()
|
||||||
@ -685,6 +665,53 @@ class DocType(TransactionBase):
|
|||||||
webnotes.conn.set(self.doc, 'recurring_id', make_autoname('RECINV/.#####'))
|
webnotes.conn.set(self.doc, 'recurring_id', make_autoname('RECINV/.#####'))
|
||||||
elif self.doc.recurring_id:
|
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(",")])
|
||||||
|
|
||||||
|
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):
|
def set_next_date(self):
|
||||||
""" Set next date on which auto invoice will be created"""
|
""" 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)
|
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)
|
||||||
|
@ -2,12 +2,13 @@
|
|||||||
{
|
{
|
||||||
"owner": "Administrator",
|
"owner": "Administrator",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"creation": "2012-10-10 10:52:22",
|
"creation": "2012-09-10 12:22:26",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"modified": "2012-09-07 11:56:59"
|
"modified": "2012-11-30 12:29:56"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"is_submittable": 1,
|
"is_submittable": 1,
|
||||||
|
"autoname": "naming_series:",
|
||||||
"allow_attach": 1,
|
"allow_attach": 1,
|
||||||
"default_print_format": "Standard",
|
"default_print_format": "Standard",
|
||||||
"search_fields": "posting_date, due_date, debit_to, fiscal_year, grand_total, outstanding_amount",
|
"search_fields": "posting_date, due_date, debit_to, fiscal_year, grand_total, outstanding_amount",
|
||||||
@ -34,6 +35,15 @@
|
|||||||
"name": "Sales Invoice",
|
"name": "Sales Invoice",
|
||||||
"doctype": "DocType"
|
"doctype": "DocType"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"print_hide": 1,
|
||||||
|
"oldfieldtype": "Section Break",
|
||||||
|
"doctype": "DocField",
|
||||||
|
"label": "Basic Info",
|
||||||
|
"fieldname": "basic_info",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"permlevel": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"print_hide": 0,
|
"print_hide": 0,
|
||||||
"oldfieldtype": "Column Break",
|
"oldfieldtype": "Column Break",
|
||||||
@ -217,9 +227,9 @@
|
|||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 1,
|
|
||||||
"oldfieldtype": "Table",
|
"oldfieldtype": "Table",
|
||||||
"colour": "White:FFF",
|
"colour": "White:FFF",
|
||||||
|
"allow_on_submit": 1,
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"label": "Entries",
|
"label": "Entries",
|
||||||
"oldfieldname": "entries",
|
"oldfieldname": "entries",
|
||||||
@ -428,9 +438,9 @@
|
|||||||
"permlevel": 0
|
"permlevel": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"allow_on_submit": 1,
|
|
||||||
"oldfieldtype": "Table",
|
"oldfieldtype": "Table",
|
||||||
"colour": "White:FFF",
|
"colour": "White:FFF",
|
||||||
|
"allow_on_submit": 1,
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"label": "Taxes and Charges1",
|
"label": "Taxes and Charges1",
|
||||||
"oldfieldname": "other_charges",
|
"oldfieldname": "other_charges",
|
||||||
@ -1174,6 +1184,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
|
"depends_on": "eval:doc.docstatus<2",
|
||||||
"colour": "White:FFF",
|
"colour": "White:FFF",
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"label": "Recurring Invoice",
|
"label": "Recurring Invoice",
|
||||||
@ -1193,7 +1204,7 @@
|
|||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"description": "Check if recurring invoice, uncheck to stop recurring or put proper End Date",
|
"description": "Check if recurring invoice, uncheck to stop recurring or put proper End Date",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"depends_on": "eval:doc.docstatus==1",
|
"depends_on": "eval:doc.docstatus<2",
|
||||||
"colour": "White:FFF",
|
"colour": "White:FFF",
|
||||||
"allow_on_submit": 1,
|
"allow_on_submit": 1,
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
@ -1205,23 +1216,24 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"allow_on_submit": 1,
|
|
||||||
"description": "Select the period when the invoice will be generated automatically",
|
"description": "Select the period when the invoice will be generated automatically",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
|
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
|
||||||
|
"colour": "White:FFF",
|
||||||
|
"allow_on_submit": 1,
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"label": "Recurring Type",
|
"label": "Recurring Type",
|
||||||
"options": "Monthly\nQuarterly\nHalf-yearly\nYearly",
|
"permlevel": 0,
|
||||||
"fieldname": "recurring_type",
|
"fieldname": "recurring_type",
|
||||||
"fieldtype": "Select",
|
"fieldtype": "Select",
|
||||||
"permlevel": 0
|
"options": "Monthly\nQuarterly\nHalf-yearly\nYearly"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"print_hide": 1,
|
"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 ",
|
"description": "The day of the month on which auto invoice will be generated e.g. 05, 28 etc ",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
|
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
|
||||||
|
"allow_on_submit": 1,
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"label": "Repeat on Day of Month",
|
"label": "Repeat on Day of Month",
|
||||||
"fieldname": "repeat_on_day_of_month",
|
"fieldname": "repeat_on_day_of_month",
|
||||||
@ -1230,11 +1242,11 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"allow_on_submit": 1,
|
|
||||||
"description": "Start date of the invoice period",
|
"description": "Start date of the invoice period",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
|
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
|
||||||
"colour": "White:FFF",
|
"colour": "White:FFF",
|
||||||
|
"allow_on_submit": 1,
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"label": "Invoice Period From Date",
|
"label": "Invoice Period From Date",
|
||||||
"fieldname": "invoice_period_from_date",
|
"fieldname": "invoice_period_from_date",
|
||||||
@ -1243,10 +1255,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"allow_on_submit": 1,
|
|
||||||
"description": "End date of the invoice period",
|
"description": "End date of the invoice period",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
|
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
|
||||||
|
"allow_on_submit": 1,
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"label": "Invoice Period To Date",
|
"label": "Invoice Period To Date",
|
||||||
"fieldname": "invoice_period_to_date",
|
"fieldname": "invoice_period_to_date",
|
||||||
@ -1264,10 +1276,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"allow_on_submit": 1,
|
|
||||||
"description": "Enter email id separated by commas, invoice will be mailed automatically on particular date",
|
"description": "Enter email id separated by commas, invoice will be mailed automatically on particular date",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
|
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
|
||||||
|
"allow_on_submit": 1,
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"label": "Notification Email Address",
|
"label": "Notification Email Address",
|
||||||
"fieldname": "notification_email_address",
|
"fieldname": "notification_email_address",
|
||||||
@ -1276,9 +1288,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"print_hide": 1,
|
"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,
|
"no_copy": 1,
|
||||||
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
|
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
|
||||||
|
"colour": "White:FFF",
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"label": "Recurring Id",
|
"label": "Recurring Id",
|
||||||
"fieldname": "recurring_id",
|
"fieldname": "recurring_id",
|
||||||
@ -1287,9 +1300,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"print_hide": 1,
|
"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,
|
"no_copy": 1,
|
||||||
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
|
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
|
||||||
|
"colour": "White:FFF",
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"label": "Next Date",
|
"label": "Next Date",
|
||||||
"fieldname": "next_date",
|
"fieldname": "next_date",
|
||||||
@ -1298,10 +1312,10 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"print_hide": 1,
|
"print_hide": 1,
|
||||||
"allow_on_submit": 1,
|
|
||||||
"description": "The date on which recurring invoice will be stop",
|
"description": "The date on which recurring invoice will be stop",
|
||||||
"no_copy": 1,
|
"no_copy": 1,
|
||||||
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
|
"depends_on": "eval:doc.convert_into_recurring_invoice==1",
|
||||||
|
"allow_on_submit": 1,
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"label": "End Date",
|
"label": "End Date",
|
||||||
"fieldname": "end_date",
|
"fieldname": "end_date",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user