Merge branch 'develop' of github.com:webnotes/erpnext into reports
This commit is contained in:
commit
8b7da55617
@ -7,11 +7,9 @@ import webnotes
|
|||||||
from webnotes.utils import cstr, flt
|
from webnotes.utils import cstr, flt
|
||||||
from webnotes.model.utils import getlist
|
from webnotes.model.utils import getlist
|
||||||
from webnotes import msgprint, _
|
from webnotes import msgprint, _
|
||||||
|
|
||||||
from buying.utils import get_last_purchase_details
|
from buying.utils import get_last_purchase_details
|
||||||
|
|
||||||
|
|
||||||
from controllers.buying_controller import BuyingController
|
from controllers.buying_controller import BuyingController
|
||||||
|
|
||||||
class DocType(BuyingController):
|
class DocType(BuyingController):
|
||||||
def __init__(self, doc, doclist=None):
|
def __init__(self, doc, doclist=None):
|
||||||
self.doc = doc
|
self.doc = doc
|
||||||
@ -38,13 +36,13 @@ class DocType(BuyingController):
|
|||||||
if flt(d.conversion_factor):
|
if flt(d.conversion_factor):
|
||||||
last_purchase_rate = flt(d.purchase_rate) / flt(d.conversion_factor)
|
last_purchase_rate = flt(d.purchase_rate) / flt(d.conversion_factor)
|
||||||
else:
|
else:
|
||||||
msgprint(_("Row ") + cstr(d.idx) + ": " +
|
webnotes.throw(_("Row ") + cstr(d.idx) + ": " +
|
||||||
_("UOM Conversion Factor is mandatory"), raise_exception=1)
|
_("UOM Conversion Factor is mandatory"))
|
||||||
|
|
||||||
# update last purchsae rate
|
# update last purchsae rate
|
||||||
if last_purchase_rate:
|
if last_purchase_rate:
|
||||||
webnotes.conn.sql("update `tabItem` set last_purchase_rate = %s where name = %s",
|
webnotes.conn.sql("""update `tabItem` set last_purchase_rate = %s where name = %s""",
|
||||||
(flt(last_purchase_rate),d.item_code))
|
(flt(last_purchase_rate), d.item_code))
|
||||||
|
|
||||||
def get_last_purchase_rate(self, obj):
|
def get_last_purchase_rate(self, obj):
|
||||||
"""get last purchase rates for all items"""
|
"""get last purchase rates for all items"""
|
||||||
@ -76,11 +74,11 @@ class DocType(BuyingController):
|
|||||||
for d in getlist( obj.doclist, obj.fname):
|
for d in getlist( obj.doclist, obj.fname):
|
||||||
# validation for valid qty
|
# validation for valid qty
|
||||||
if flt(d.qty) < 0 or (d.parenttype != 'Purchase Receipt' and not flt(d.qty)):
|
if flt(d.qty) < 0 or (d.parenttype != 'Purchase Receipt' and not flt(d.qty)):
|
||||||
msgprint("Please enter valid qty for item %s" % cstr(d.item_code))
|
webnotes.throw("Please enter valid qty for item %s" % cstr(d.item_code))
|
||||||
raise Exception
|
|
||||||
|
|
||||||
# udpate with latest quantities
|
# udpate with latest quantities
|
||||||
bin = webnotes.conn.sql("select projected_qty from `tabBin` where item_code = %s and warehouse = %s", (d.item_code, d.warehouse), as_dict = 1)
|
bin = webnotes.conn.sql("""select projected_qty from `tabBin` where
|
||||||
|
item_code = %s and warehouse = %s""", (d.item_code, d.warehouse), as_dict=1)
|
||||||
|
|
||||||
f_lst ={'projected_qty': bin and flt(bin[0]['projected_qty']) or 0, 'ordered_qty': 0, 'received_qty' : 0}
|
f_lst ={'projected_qty': bin and flt(bin[0]['projected_qty']) or 0, 'ordered_qty': 0, 'received_qty' : 0}
|
||||||
if d.doctype == 'Purchase Receipt Item':
|
if d.doctype == 'Purchase Receipt Item':
|
||||||
@ -89,48 +87,50 @@ class DocType(BuyingController):
|
|||||||
if d.fields.has_key(x):
|
if d.fields.has_key(x):
|
||||||
d.fields[x] = f_lst[x]
|
d.fields[x] = f_lst[x]
|
||||||
|
|
||||||
item = webnotes.conn.sql("select is_stock_item, is_purchase_item, is_sub_contracted_item, end_of_life from tabItem where name=%s",
|
item = webnotes.conn.sql("""select is_stock_item, is_purchase_item,
|
||||||
d.item_code)
|
is_sub_contracted_item, end_of_life from `tabItem` where name=%s""", d.item_code)
|
||||||
if not item:
|
if not item:
|
||||||
msgprint("Item %s does not exist in Item Master." % cstr(d.item_code), raise_exception=True)
|
webnotes.throw("Item %s does not exist in Item Master." % cstr(d.item_code))
|
||||||
|
|
||||||
from stock.utils import validate_end_of_life
|
from stock.utils import validate_end_of_life
|
||||||
validate_end_of_life(d.item_code, item[0][3])
|
validate_end_of_life(d.item_code, item[0][3])
|
||||||
|
|
||||||
# validate stock item
|
# validate stock item
|
||||||
if item[0][0]=='Yes' and d.qty and not d.warehouse:
|
if item[0][0]=='Yes' and d.qty and not d.warehouse:
|
||||||
msgprint("Warehouse is mandatory for %s, since it is a stock item" %
|
webnotes.throw("Warehouse is mandatory for %s, since it is a stock item" % d.item_code)
|
||||||
d.item_code, raise_exception=1)
|
|
||||||
|
|
||||||
# validate purchase item
|
# validate purchase item
|
||||||
if item[0][1] != 'Yes' and item[0][2] != 'Yes':
|
if item[0][1] != 'Yes' and item[0][2] != 'Yes':
|
||||||
msgprint("Item %s is not a purchase item or sub-contracted item. Please check" % (d.item_code), raise_exception=True)
|
webnotes.throw("Item %s is not a purchase item or sub-contracted item. Please check" % (d.item_code))
|
||||||
|
|
||||||
# list criteria that should not repeat if item is stock item
|
# list criteria that should not repeat if item is stock item
|
||||||
e = [d.schedule_date, d.item_code, d.description, d.warehouse, d.uom, d.fields.has_key('prevdoc_docname') and d.prevdoc_docname or '', d.fields.has_key('prevdoc_detail_docname') and d.prevdoc_detail_docname or '', d.fields.has_key('batch_no') and d.batch_no or '']
|
e = [d.schedule_date, d.item_code, d.description, d.warehouse, d.uom,
|
||||||
|
d.fields.has_key('prevdoc_docname') and d.prevdoc_docname or d.fields.has_key('sales_order_no') and d.sales_order_no or '',
|
||||||
|
d.fields.has_key('prevdoc_detail_docname') and d.prevdoc_detail_docname or '',
|
||||||
|
d.fields.has_key('batch_no') and d.batch_no or '']
|
||||||
|
|
||||||
# if is not stock item
|
# if is not stock item
|
||||||
f = [d.schedule_date, d.item_code, d.description]
|
f = [d.schedule_date, d.item_code, d.description]
|
||||||
|
|
||||||
ch = webnotes.conn.sql("select is_stock_item from `tabItem` where name = '%s'"%d.item_code)
|
ch = webnotes.conn.sql("""select is_stock_item from `tabItem` where name = %s""", d.item_code)
|
||||||
|
|
||||||
if ch and ch[0][0] == 'Yes':
|
if ch and ch[0][0] == 'Yes':
|
||||||
# check for same items
|
# check for same items
|
||||||
if e in check_list:
|
if e in check_list:
|
||||||
msgprint("""Item %s has been entered more than once with same description, schedule date, warehouse and uom.\n
|
webnotes.throw("""Item %s has been entered more than once with same description, schedule date, warehouse and uom.\n
|
||||||
Please change any of the field value to enter the item twice""" % d.item_code, raise_exception = 1)
|
Please change any of the field value to enter the item twice""" % d.item_code)
|
||||||
else:
|
else:
|
||||||
check_list.append(e)
|
check_list.append(e)
|
||||||
|
|
||||||
elif ch and ch[0][0] == 'No':
|
elif ch and ch[0][0] == 'No':
|
||||||
# check for same items
|
# check for same items
|
||||||
if f in chk_dupl_itm:
|
if f in chk_dupl_itm:
|
||||||
msgprint("""Item %s has been entered more than once with same description, schedule date.\n
|
webnotes.throw("""Item %s has been entered more than once with same description, schedule date.\n
|
||||||
Please change any of the field value to enter the item twice.""" % d.item_code, raise_exception = 1)
|
Please change any of the field value to enter the item twice.""" % d.item_code)
|
||||||
else:
|
else:
|
||||||
chk_dupl_itm.append(f)
|
chk_dupl_itm.append(f)
|
||||||
|
|
||||||
def get_qty(self,curr_doctype,ref_tab_fname,ref_tab_dn,ref_doc_tname, transaction, curr_parent_name):
|
def get_qty(self, curr_doctype, ref_tab_fname, ref_tab_dn, ref_doc_tname, transaction, curr_parent_name):
|
||||||
# Get total Quantities of current doctype (eg. PR) except for qty of this transaction
|
# Get total Quantities of current doctype (eg. PR) except for qty of this transaction
|
||||||
#------------------------------
|
#------------------------------
|
||||||
# please check as UOM changes from Material Request - Purchase Order ,so doing following else uom should be same .
|
# please check as UOM changes from Material Request - Purchase Order ,so doing following else uom should be same .
|
||||||
@ -138,35 +138,37 @@ class DocType(BuyingController):
|
|||||||
# but if in Material Request uom KG it can change in PO
|
# but if in Material Request uom KG it can change in PO
|
||||||
|
|
||||||
get_qty = (transaction == 'Material Request - Purchase Order') and 'qty * conversion_factor' or 'qty'
|
get_qty = (transaction == 'Material Request - Purchase Order') and 'qty * conversion_factor' or 'qty'
|
||||||
qty = webnotes.conn.sql("select sum(%s) from `tab%s` where %s = '%s' and docstatus = 1 and parent != '%s'"% ( get_qty, curr_doctype, ref_tab_fname, ref_tab_dn, curr_parent_name))
|
qty = webnotes.conn.sql("""select sum(%s) from `tab%s` where %s = %s and
|
||||||
|
docstatus = 1 and parent != %s""" % (get_qty, curr_doctype, ref_tab_fname, '%s', '%s'),
|
||||||
|
(ref_tab_dn, curr_parent_name))
|
||||||
qty = qty and flt(qty[0][0]) or 0
|
qty = qty and flt(qty[0][0]) or 0
|
||||||
|
|
||||||
# get total qty of ref doctype
|
# get total qty of ref doctype
|
||||||
#--------------------
|
#--------------------
|
||||||
max_qty = webnotes.conn.sql("select qty from `tab%s` where name = '%s' and docstatus = 1"% (ref_doc_tname, ref_tab_dn))
|
max_qty = webnotes.conn.sql("""select qty from `tab%s` where name = %s
|
||||||
|
and docstatus = 1""" % (ref_doc_tname, '%s'), ref_tab_dn)
|
||||||
max_qty = max_qty and flt(max_qty[0][0]) or 0
|
max_qty = max_qty and flt(max_qty[0][0]) or 0
|
||||||
|
|
||||||
return cstr(qty)+'~~~'+cstr(max_qty)
|
return cstr(qty)+'~~~'+cstr(max_qty)
|
||||||
|
|
||||||
def check_for_stopped_status(self, doctype, docname):
|
def check_for_stopped_status(self, doctype, docname):
|
||||||
stopped = webnotes.conn.sql("select name from `tab%s` where name = '%s' and status = 'Stopped'" %
|
stopped = webnotes.conn.sql("""select name from `tab%s` where name = %s and
|
||||||
( doctype, docname))
|
status = 'Stopped'""" % (doctype, '%s'), docname)
|
||||||
if stopped:
|
if stopped:
|
||||||
msgprint("One cannot do any transaction against %s : %s, it's status is 'Stopped'" %
|
webnotes.throw("One cannot do any transaction against %s : %s, it's status is 'Stopped'" %
|
||||||
( doctype, docname), raise_exception=1)
|
(doctype, docname))
|
||||||
|
|
||||||
def check_docstatus(self, check, doctype, docname , detail_doctype = ''):
|
def check_docstatus(self, check, doctype, docname, detail_doctype = ''):
|
||||||
if check == 'Next':
|
if check == 'Next':
|
||||||
submitted = webnotes.conn.sql("""select t1.name from `tab%s` t1,`tab%s` t2
|
submitted = webnotes.conn.sql("""select t1.name from `tab%s` t1,`tab%s` t2
|
||||||
where t1.name = t2.parent and t2.prevdoc_docname = %s and t1.docstatus = 1"""
|
where t1.name = t2.parent and t2.prevdoc_docname = %s and t1.docstatus = 1"""
|
||||||
% (doctype, detail_doctype, '%s'), docname)
|
% (doctype, detail_doctype, '%s'), docname)
|
||||||
if submitted:
|
if submitted:
|
||||||
msgprint(cstr(doctype) + ": " + cstr(submitted[0][0])
|
webnotes.throw(cstr(doctype) + ": " + cstr(submitted[0][0])
|
||||||
+ _(" has already been submitted."), raise_exception=1)
|
+ _("has already been submitted."))
|
||||||
|
|
||||||
if check == 'Previous':
|
if check == 'Previous':
|
||||||
submitted = webnotes.conn.sql("""select name from `tab%s`
|
submitted = webnotes.conn.sql("""select name from `tab%s`
|
||||||
where docstatus = 1 and name = %s"""% (doctype, '%s'), docname)
|
where docstatus = 1 and name = %s""" % (doctype, '%s'), docname)
|
||||||
if not submitted:
|
if not submitted:
|
||||||
msgprint(cstr(doctype) + ": " + cstr(submitted[0][0])
|
webnotes.throw(cstr(doctype) + ": " + cstr(submitted[0][0]) + _("not submitted"))
|
||||||
+ _(" not submitted"), raise_exception=1)
|
|
||||||
|
@ -9,7 +9,6 @@ from webnotes.model.bean import getlist
|
|||||||
from webnotes.model.code import get_obj
|
from webnotes.model.code import get_obj
|
||||||
from webnotes import msgprint, _
|
from webnotes import msgprint, _
|
||||||
|
|
||||||
|
|
||||||
class DocType:
|
class DocType:
|
||||||
def __init__(self, doc, doclist=[]):
|
def __init__(self, doc, doclist=[]):
|
||||||
self.doc = doc
|
self.doc = doc
|
||||||
@ -47,7 +46,7 @@ class DocType:
|
|||||||
|
|
||||||
def validate_company(self):
|
def validate_company(self):
|
||||||
if not self.doc.company:
|
if not self.doc.company:
|
||||||
msgprint("Please enter Company", raise_exception=1)
|
webnotes.throw(_("Please enter Company"))
|
||||||
|
|
||||||
def get_open_sales_orders(self):
|
def get_open_sales_orders(self):
|
||||||
""" Pull sales orders which are pending to deliver based on criteria selected"""
|
""" Pull sales orders which are pending to deliver based on criteria selected"""
|
||||||
@ -106,7 +105,7 @@ class DocType:
|
|||||||
def get_items(self):
|
def get_items(self):
|
||||||
so_list = filter(None, [d.sales_order for d in getlist(self.doclist, 'pp_so_details')])
|
so_list = filter(None, [d.sales_order for d in getlist(self.doclist, 'pp_so_details')])
|
||||||
if not so_list:
|
if not so_list:
|
||||||
msgprint("Please enter sales order in the above table")
|
msgprint(_("Please enter sales order in the above table"))
|
||||||
return []
|
return []
|
||||||
|
|
||||||
items = webnotes.conn.sql("""select distinct parent, item_code, reserved_warehouse,
|
items = webnotes.conn.sql("""select distinct parent, item_code, reserved_warehouse,
|
||||||
@ -155,21 +154,21 @@ class DocType:
|
|||||||
for d in getlist(self.doclist, 'pp_details'):
|
for d in getlist(self.doclist, 'pp_details'):
|
||||||
self.validate_bom_no(d)
|
self.validate_bom_no(d)
|
||||||
if not flt(d.planned_qty):
|
if not flt(d.planned_qty):
|
||||||
msgprint("Please Enter Planned Qty for item: %s at row no: %s" %
|
webnotes.throw("Please Enter Planned Qty for item: %s at row no: %s" %
|
||||||
(d.item_code, d.idx), raise_exception=1)
|
(d.item_code, d.idx))
|
||||||
|
|
||||||
def validate_bom_no(self, d):
|
def validate_bom_no(self, d):
|
||||||
if not d.bom_no:
|
if not d.bom_no:
|
||||||
msgprint("Please enter bom no for item: %s at row no: %s" %
|
webnotes.throw("Please enter bom no for item: %s at row no: %s" %
|
||||||
(d.item_code, d.idx), raise_exception=1)
|
(d.item_code, d.idx))
|
||||||
else:
|
else:
|
||||||
bom = webnotes.conn.sql("""select name from `tabBOM` where name = %s and item = %s
|
bom = webnotes.conn.sql("""select name from `tabBOM` where name = %s and item = %s
|
||||||
and docstatus = 1 and is_active = 1""",
|
and docstatus = 1 and is_active = 1""",
|
||||||
(d.bom_no, d.item_code), as_dict = 1)
|
(d.bom_no, d.item_code), as_dict = 1)
|
||||||
if not bom:
|
if not bom:
|
||||||
msgprint("""Incorrect BOM No: %s entered for item: %s at row no: %s
|
webnotes.throw("""Incorrect BOM No: %s entered for item: %s at row no: %s
|
||||||
May be BOM is inactive or for other item or does not exists in the system""" %
|
May be BOM is inactive or for other item or does not exists in the system""" %
|
||||||
(d.bom_no, d.item_doce, d.idx), raise_exception=1)
|
(d.bom_no, d.item_doce, d.idx))
|
||||||
|
|
||||||
def raise_production_order(self):
|
def raise_production_order(self):
|
||||||
"""It will raise production order (Draft) for all distinct FG items"""
|
"""It will raise production order (Draft) for all distinct FG items"""
|
||||||
@ -183,16 +182,20 @@ class DocType:
|
|||||||
if pro:
|
if pro:
|
||||||
pro = ["""<a href="#Form/Production Order/%s" target="_blank">%s</a>""" % \
|
pro = ["""<a href="#Form/Production Order/%s" target="_blank">%s</a>""" % \
|
||||||
(p, p) for p in pro]
|
(p, p) for p in pro]
|
||||||
msgprint("Production Order(s) created:\n\n" + '\n'.join(pro))
|
msgprint(_("Production Order(s) created:\n\n") + '\n'.join(pro))
|
||||||
else :
|
else :
|
||||||
msgprint("No Production Order created.")
|
msgprint(_("No Production Order created."))
|
||||||
|
|
||||||
|
|
||||||
def get_distinct_items_and_boms(self):
|
def get_distinct_items_and_boms(self):
|
||||||
""" Club similar BOM and item for processing"""
|
""" Club similar BOM and item for processing
|
||||||
|
bom_dict {
|
||||||
|
bom_no: ['sales_order', 'qty']
|
||||||
|
}
|
||||||
|
"""
|
||||||
item_dict, bom_dict = {}, {}
|
item_dict, bom_dict = {}, {}
|
||||||
for d in self.doclist.get({"parentfield": "pp_details"}):
|
for d in self.doclist.get({"parentfield": "pp_details"}):
|
||||||
bom_dict[d.bom_no] = bom_dict.get(d.bom_no, 0) + flt(d.planned_qty)
|
bom_dict.setdefault(d.bom_no, []).append([d.sales_order, flt(d.planned_qty)])
|
||||||
item_dict[(d.item_code, d.sales_order, d.warehouse)] = {
|
item_dict[(d.item_code, d.sales_order, d.warehouse)] = {
|
||||||
"production_item" : d.item_code,
|
"production_item" : d.item_code,
|
||||||
"sales_order" : d.sales_order,
|
"sales_order" : d.sales_order,
|
||||||
@ -241,46 +244,58 @@ class DocType:
|
|||||||
"item_code": [qty_required, description, stock_uom, min_order_qty]
|
"item_code": [qty_required, description, stock_uom, min_order_qty]
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
for bom in bom_dict:
|
bom_wise_item_details = {}
|
||||||
|
item_list = []
|
||||||
|
|
||||||
|
for bom, so_wise_qty in bom_dict.items():
|
||||||
if self.doc.use_multi_level_bom:
|
if self.doc.use_multi_level_bom:
|
||||||
# get all raw materials with sub assembly childs
|
# get all raw materials with sub assembly childs
|
||||||
fl_bom_items = webnotes.conn.sql("""select fb.item_code,
|
for d in webnotes.conn.sql("""select fb.item_code,
|
||||||
ifnull(sum(fb.qty_consumed_per_unit), 0)*%s as qty,
|
ifnull(sum(fb.qty_consumed_per_unit), 0) as qty,
|
||||||
fb.description, fb.stock_uom, it.min_order_qty
|
fb.description, fb.stock_uom, it.min_order_qty
|
||||||
from `tabBOM Explosion Item` fb,`tabItem` it
|
from `tabBOM Explosion Item` fb,`tabItem` it
|
||||||
where it.name = fb.item_code and ifnull(it.is_pro_applicable, 'No') = 'No'
|
where it.name = fb.item_code and ifnull(it.is_pro_applicable, 'No') = 'No'
|
||||||
and ifnull(it.is_sub_contracted_item, 'No') = 'No'
|
and ifnull(it.is_sub_contracted_item, 'No') = 'No'
|
||||||
and fb.docstatus<2 and fb.parent=%s
|
and fb.docstatus<2 and fb.parent=%s
|
||||||
group by item_code, stock_uom""", (flt(bom_dict[bom]), bom))
|
group by item_code, stock_uom""", bom, as_dict=1):
|
||||||
|
bom_wise_item_details.setdefault(d.item_code, d)
|
||||||
else:
|
else:
|
||||||
# Get all raw materials considering SA items as raw materials,
|
# Get all raw materials considering SA items as raw materials,
|
||||||
# so no childs of SA items
|
# so no childs of SA items
|
||||||
fl_bom_items = webnotes.conn.sql("""select bom_item.item_code,
|
for d in webnotes.conn.sql("""select bom_item.item_code,
|
||||||
ifnull(sum(bom_item.qty_consumed_per_unit), 0) * %s,
|
ifnull(sum(bom_item.qty_consumed_per_unit), 0) as qty,
|
||||||
bom_item.description, bom_item.stock_uom, item.min_order_qty
|
bom_item.description, bom_item.stock_uom, item.min_order_qty
|
||||||
from `tabBOM Item` bom_item, tabItem item
|
from `tabBOM Item` bom_item, tabItem item
|
||||||
where bom_item.parent = %s and bom_item.docstatus < 2
|
where bom_item.parent = %s and bom_item.docstatus < 2
|
||||||
and bom_item.item_code = item.name
|
and bom_item.item_code = item.name
|
||||||
group by item_code""", (flt(bom_dict[bom]), bom))
|
group by item_code""", bom, as_dict=1):
|
||||||
self.make_items_dict(fl_bom_items)
|
bom_wise_item_details.setdefault(d.item_code, d)
|
||||||
|
|
||||||
|
for item, item_details in bom_wise_item_details.items():
|
||||||
|
for so_qty in so_wise_qty:
|
||||||
|
item_list.append([item, flt(item_details.qty) * so_qty[1], item_details.description,
|
||||||
|
item_details.stock_uom, item_details.min_order_qty, so_qty[0]])
|
||||||
|
|
||||||
|
self.make_items_dict(item_list)
|
||||||
|
|
||||||
def make_items_dict(self, item_list):
|
def make_items_dict(self, item_list):
|
||||||
for i in item_list:
|
for i in item_list:
|
||||||
self.item_dict[i[0]] = [(flt(self.item_dict.get(i[0], [0])[0]) + flt(i[1])),
|
self.item_dict.setdefault(i[0], []).append([flt(i[1]), i[2], i[3], i[4], i[5]])
|
||||||
i[2], i[3], i[4]]
|
|
||||||
|
|
||||||
|
|
||||||
def get_csv(self):
|
def get_csv(self):
|
||||||
item_list = [['Item Code', 'Description', 'Stock UOM', 'Required Qty', 'Warehouse',
|
item_list = [['Item Code', 'Description', 'Stock UOM', 'Required Qty', 'Warehouse',
|
||||||
'Quantity Requested for Purchase', 'Ordered Qty', 'Actual Qty']]
|
'Quantity Requested for Purchase', 'Ordered Qty', 'Actual Qty']]
|
||||||
for d in self.item_dict:
|
for item in self.item_dict:
|
||||||
item_list.append([d, self.item_dict[d][1], self.item_dict[d][2], self.item_dict[d][0]])
|
total_qty = sum([flt(d[0]) for d in self.item_dict[item]])
|
||||||
item_qty= webnotes.conn.sql("""select warehouse, indented_qty, ordered_qty, actual_qty
|
for item_details in self.item_dict[item]:
|
||||||
from `tabBin` where item_code = %s""", d)
|
item_list.append([item, item_details[1], item_details[2], item_details[0]])
|
||||||
|
item_qty = webnotes.conn.sql("""select warehouse, indented_qty, ordered_qty, actual_qty
|
||||||
|
from `tabBin` where item_code = %s""", item, as_dict=1)
|
||||||
i_qty, o_qty, a_qty = 0, 0, 0
|
i_qty, o_qty, a_qty = 0, 0, 0
|
||||||
for w in item_qty:
|
for w in item_qty:
|
||||||
i_qty, o_qty, a_qty = i_qty + flt(w[1]), o_qty + flt(w[2]), a_qty + flt(w[3])
|
i_qty, o_qty, a_qty = i_qty + flt(w.indented_qty), o_qty + flt(w.ordered_qty), a_qty + flt(w.actual_qty)
|
||||||
item_list.append(['', '', '', '', w[0], flt(w[1]), flt(w[2]), flt(w[3])])
|
item_list.append(['', '', '', '', w.warehouse, flt(w.indented_qty),
|
||||||
|
flt(w.ordered_qty), flt(w.actual_qty)])
|
||||||
if item_qty:
|
if item_qty:
|
||||||
item_list.append(['', '', '', '', 'Total', i_qty, o_qty, a_qty])
|
item_list.append(['', '', '', '', 'Total', i_qty, o_qty, a_qty])
|
||||||
|
|
||||||
@ -293,31 +308,49 @@ class DocType:
|
|||||||
"""
|
"""
|
||||||
self.validate_data()
|
self.validate_data()
|
||||||
if not self.doc.purchase_request_for_warehouse:
|
if not self.doc.purchase_request_for_warehouse:
|
||||||
webnotes.msgprint("Please enter Warehouse for which Material Request will be raised",
|
webnotes.throw(_("Please enter Warehouse for which Material Request will be raised"))
|
||||||
raise_exception=1)
|
|
||||||
|
|
||||||
bom_dict = self.get_distinct_items_and_boms()[0]
|
bom_dict = self.get_distinct_items_and_boms()[0]
|
||||||
self.get_raw_materials(bom_dict)
|
self.get_raw_materials(bom_dict)
|
||||||
|
|
||||||
if not self.item_dict:
|
if self.item_dict:
|
||||||
return
|
self.insert_purchase_request()
|
||||||
|
|
||||||
|
def get_requested_items(self):
|
||||||
item_projected_qty = self.get_projected_qty()
|
item_projected_qty = self.get_projected_qty()
|
||||||
|
|
||||||
from accounts.utils import get_fiscal_year
|
|
||||||
fiscal_year = get_fiscal_year(nowdate())[0]
|
|
||||||
|
|
||||||
items_to_be_requested = webnotes._dict()
|
items_to_be_requested = webnotes._dict()
|
||||||
for item in self.item_dict:
|
|
||||||
if flt(self.item_dict[item][0]) > item_projected_qty.get(item, 0):
|
|
||||||
# shortage
|
|
||||||
requested_qty = flt(self.item_dict[item][0]) - item_projected_qty.get(item, 0)
|
|
||||||
# comsider minimum order qty
|
|
||||||
requested_qty = requested_qty > flt(self.item_dict[item][3]) and \
|
|
||||||
requested_qty or flt(self.item_dict[item][3])
|
|
||||||
items_to_be_requested[item] = requested_qty
|
|
||||||
|
|
||||||
self.insert_purchase_request(items_to_be_requested, fiscal_year)
|
for item, so_item_qty in self.item_dict.items():
|
||||||
|
requested_qty = 0
|
||||||
|
total_qty = sum([flt(d[0]) for d in so_item_qty])
|
||||||
|
if total_qty > item_projected_qty.get(item, 0):
|
||||||
|
# shortage
|
||||||
|
requested_qty = total_qty - item_projected_qty.get(item, 0)
|
||||||
|
# consider minimum order qty
|
||||||
|
requested_qty = requested_qty > flt(so_item_qty[0][3]) and \
|
||||||
|
requested_qty or flt(so_item_qty[0][3])
|
||||||
|
|
||||||
|
# distribute requested qty SO wise
|
||||||
|
for item_details in so_item_qty:
|
||||||
|
if requested_qty:
|
||||||
|
sales_order = item_details[4] or "No Sales Order"
|
||||||
|
if requested_qty <= item_details[0]:
|
||||||
|
adjusted_qty = requested_qty
|
||||||
|
else:
|
||||||
|
adjusted_qty = item_details[0]
|
||||||
|
|
||||||
|
items_to_be_requested.setdefault(item, {}).setdefault(sales_order, 0)
|
||||||
|
items_to_be_requested[item][sales_order] += adjusted_qty
|
||||||
|
requested_qty -= adjusted_qty
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
# requested qty >= total so qty, due to minimum order qty
|
||||||
|
if requested_qty:
|
||||||
|
items_to_be_requested.setdefault(item, {}).setdefault("No Sales Order", 0)
|
||||||
|
items_to_be_requested[item]["No Sales Order"] += requested_qty
|
||||||
|
|
||||||
|
return items_to_be_requested
|
||||||
|
|
||||||
def get_projected_qty(self):
|
def get_projected_qty(self):
|
||||||
items = self.item_dict.keys()
|
items = self.item_dict.keys()
|
||||||
@ -327,13 +360,17 @@ class DocType:
|
|||||||
|
|
||||||
return dict(item_projected_qty)
|
return dict(item_projected_qty)
|
||||||
|
|
||||||
def insert_purchase_request(self, items_to_be_requested, fiscal_year):
|
def insert_purchase_request(self):
|
||||||
|
items_to_be_requested = self.get_requested_items()
|
||||||
|
|
||||||
|
from accounts.utils import get_fiscal_year
|
||||||
|
fiscal_year = get_fiscal_year(nowdate())[0]
|
||||||
|
|
||||||
purchase_request_list = []
|
purchase_request_list = []
|
||||||
if items_to_be_requested:
|
if items_to_be_requested:
|
||||||
for item in items_to_be_requested:
|
for item in items_to_be_requested:
|
||||||
item_wrapper = webnotes.bean("Item", item)
|
item_wrapper = webnotes.bean("Item", item)
|
||||||
pr_doclist = [
|
pr_doclist = [{
|
||||||
{
|
|
||||||
"doctype": "Material Request",
|
"doctype": "Material Request",
|
||||||
"__islocal": 1,
|
"__islocal": 1,
|
||||||
"naming_series": "IDT",
|
"naming_series": "IDT",
|
||||||
@ -343,8 +380,9 @@ class DocType:
|
|||||||
"fiscal_year": fiscal_year,
|
"fiscal_year": fiscal_year,
|
||||||
"requested_by": webnotes.session.user,
|
"requested_by": webnotes.session.user,
|
||||||
"material_request_type": "Purchase"
|
"material_request_type": "Purchase"
|
||||||
},
|
}]
|
||||||
{
|
for sales_order, requested_qty in items_to_be_requested[item].items():
|
||||||
|
pr_doclist.append({
|
||||||
"doctype": "Material Request Item",
|
"doctype": "Material Request Item",
|
||||||
"__islocal": 1,
|
"__islocal": 1,
|
||||||
"parentfield": "indent_details",
|
"parentfield": "indent_details",
|
||||||
@ -354,11 +392,12 @@ class DocType:
|
|||||||
"uom": item_wrapper.doc.stock_uom,
|
"uom": item_wrapper.doc.stock_uom,
|
||||||
"item_group": item_wrapper.doc.item_group,
|
"item_group": item_wrapper.doc.item_group,
|
||||||
"brand": item_wrapper.doc.brand,
|
"brand": item_wrapper.doc.brand,
|
||||||
"qty": items_to_be_requested[item],
|
"qty": requested_qty,
|
||||||
"schedule_date": add_days(nowdate(), cint(item_wrapper.doc.lead_time_days)),
|
"schedule_date": add_days(nowdate(), cint(item_wrapper.doc.lead_time_days)),
|
||||||
"warehouse": self.doc.purchase_request_for_warehouse
|
"warehouse": self.doc.purchase_request_for_warehouse,
|
||||||
}
|
"sales_order_no": sales_order if sales_order!="No Sales Order" else None
|
||||||
]
|
})
|
||||||
|
|
||||||
pr_wrapper = webnotes.bean(pr_doclist)
|
pr_wrapper = webnotes.bean(pr_doclist)
|
||||||
pr_wrapper.ignore_permissions = 1
|
pr_wrapper.ignore_permissions = 1
|
||||||
pr_wrapper.submit()
|
pr_wrapper.submit()
|
||||||
@ -367,7 +406,7 @@ class DocType:
|
|||||||
if purchase_request_list:
|
if purchase_request_list:
|
||||||
pur_req = ["""<a href="#Form/Material Request/%s" target="_blank">%s</a>""" % \
|
pur_req = ["""<a href="#Form/Material Request/%s" target="_blank">%s</a>""" % \
|
||||||
(p, p) for p in purchase_request_list]
|
(p, p) for p in purchase_request_list]
|
||||||
webnotes.msgprint("Material Request(s) created: \n%s" %
|
msgprint("Material Request(s) created: \n%s" %
|
||||||
"\n".join(pur_req))
|
"\n".join(pur_req))
|
||||||
else:
|
else:
|
||||||
webnotes.msgprint("Nothing to request")
|
msgprint(_("Nothing to request"))
|
23
patches/1311/p07_scheduler_errors_digest.py
Normal file
23
patches/1311/p07_scheduler_errors_digest.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import webnotes
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
from webnotes.profile import get_system_managers
|
||||||
|
system_managers = get_system_managers(only_name=True)
|
||||||
|
if not system_managers:
|
||||||
|
return
|
||||||
|
|
||||||
|
# scheduler errors digest
|
||||||
|
edigest = webnotes.new_bean("Email Digest")
|
||||||
|
edigest.doc.fields.update({
|
||||||
|
"name": "Scheduler Errors",
|
||||||
|
"company": webnotes.conn.get_default("company"),
|
||||||
|
"frequency": "Daily",
|
||||||
|
"enabled": 1,
|
||||||
|
"recipient_list": "\n".join(system_managers),
|
||||||
|
"scheduler_errors": 1
|
||||||
|
})
|
||||||
|
edigest.insert()
|
11
patches/1311/p08_email_digest_recipients.py
Normal file
11
patches/1311/p08_email_digest_recipients.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||||
|
# License: GNU General Public License v3. See license.txt
|
||||||
|
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
import webnotes
|
||||||
|
|
||||||
|
def execute():
|
||||||
|
from webnotes.utils import extract_email_id
|
||||||
|
for name, recipients in webnotes.conn.sql("""select name, recipient_list from `tabEmail Digest`"""):
|
||||||
|
recipients = "\n".join([extract_email_id(r) for r in recipients.split("\n")])
|
||||||
|
webnotes.conn.set_value("Email Digest", name, "recipient_list", recipients)
|
@ -259,4 +259,6 @@ patch_list = [
|
|||||||
"patches.1312.p01_delete_old_stock_reports",
|
"patches.1312.p01_delete_old_stock_reports",
|
||||||
"execute:webnotes.delete_doc('Report', 'Payment Collection With Ageing')",
|
"execute:webnotes.delete_doc('Report', 'Payment Collection With Ageing')",
|
||||||
"execute:webnotes.delete_doc('Report', 'Payment Made With Ageing')",
|
"execute:webnotes.delete_doc('Report', 'Payment Made With Ageing')",
|
||||||
|
"patches.1311.p07_scheduler_errors_digest",
|
||||||
|
"patches.1311.p08_email_digest_recipients",
|
||||||
]
|
]
|
@ -70,8 +70,10 @@ cur_frm.cscript.addremove_recipients = function(doc, dt, dn) {
|
|||||||
check.checked = 1;
|
check.checked = 1;
|
||||||
add_or_update = 'Update';
|
add_or_update = 'Update';
|
||||||
}
|
}
|
||||||
|
var fullname = wn.user.full_name(v.name);
|
||||||
|
if(fullname !== v.name) v.name = fullname + " <" + v.name + ">";
|
||||||
if(v.enabled==0) {
|
if(v.enabled==0) {
|
||||||
v.name = "<span style='color: red'>" + v.name + " (disabled user)</span>"
|
v.name = repl("<span style='color: red'> %(name)s (disabled user)</span>", {name: v.name});
|
||||||
}
|
}
|
||||||
var profile = $a($td(tab, i+1, 1), 'span', '', '', v.name);
|
var profile = $a($td(tab, i+1, 1), 'span', '', '', v.name);
|
||||||
//profile.onclick = function() { check.checked = !check.checked; }
|
//profile.onclick = function() { check.checked = !check.checked; }
|
||||||
|
@ -19,16 +19,16 @@ content_sequence = [
|
|||||||
["Selling", ["new_leads", "new_enquiries", "new_quotations", "new_sales_orders"]],
|
["Selling", ["new_leads", "new_enquiries", "new_quotations", "new_sales_orders"]],
|
||||||
["Stock", ["new_delivery_notes", "new_purchase_receipts", "new_stock_entries"]],
|
["Stock", ["new_delivery_notes", "new_purchase_receipts", "new_stock_entries"]],
|
||||||
["Support", ["new_communications", "new_support_tickets", "open_tickets"]],
|
["Support", ["new_communications", "new_support_tickets", "open_tickets"]],
|
||||||
["Projects", ["new_projects"]]
|
["Projects", ["new_projects"]],
|
||||||
|
["System", ["scheduler_errors"]],
|
||||||
]
|
]
|
||||||
|
|
||||||
user_specific_content = ["calendar_events", "todo_list"]
|
user_specific_content = ["calendar_events", "todo_list"]
|
||||||
|
|
||||||
digest_template = """\
|
digest_template = """<style>p.ed-indent { margin-right: 17px; }</style>
|
||||||
<style>p.ed-indent { margin-right: 17px; }</style>
|
<h2>%(name)s</h2>
|
||||||
<h2>%(digest)s</h2>
|
|
||||||
<p style='color: grey'>%(date)s</p>
|
|
||||||
<h4>%(company)s</h4>
|
<h4>%(company)s</h4>
|
||||||
|
<p style='color: grey'>%(date)s</p>
|
||||||
<hr>
|
<hr>
|
||||||
%(with_value)s
|
%(with_value)s
|
||||||
%(no_value)s
|
%(no_value)s
|
||||||
@ -53,10 +53,10 @@ class DocType(DocListController):
|
|||||||
|
|
||||||
def get_profiles(self):
|
def get_profiles(self):
|
||||||
"""get list of profiles"""
|
"""get list of profiles"""
|
||||||
import webnotes
|
|
||||||
profile_list = webnotes.conn.sql("""
|
profile_list = webnotes.conn.sql("""
|
||||||
select name, enabled from tabProfile
|
select name, enabled from tabProfile
|
||||||
where docstatus=0 and name not in ('Administrator', 'Guest')
|
where docstatus=0 and name not in ('Administrator', 'Guest')
|
||||||
|
and user_type = "System User"
|
||||||
order by enabled desc, name asc""", as_dict=1)
|
order by enabled desc, name asc""", as_dict=1)
|
||||||
|
|
||||||
if self.doc.recipient_list:
|
if self.doc.recipient_list:
|
||||||
@ -81,7 +81,9 @@ class DocType(DocListController):
|
|||||||
msg_for_this_receipient = self.get_msg_html(self.get_user_specific_content(user_id) + \
|
msg_for_this_receipient = self.get_msg_html(self.get_user_specific_content(user_id) + \
|
||||||
common_msg)
|
common_msg)
|
||||||
from webnotes.utils.email_lib import sendmail
|
from webnotes.utils.email_lib import sendmail
|
||||||
sendmail(recipients=user_id, subject="[ERPNext] " + (self.doc.frequency + " Digest"),
|
sendmail(recipients=user_id,
|
||||||
|
subject="[ERPNext] [{frequency} Digest] {name}".format(
|
||||||
|
frequency=self.doc.frequency, name=self.doc.name),
|
||||||
msg=msg_for_this_receipient)
|
msg=msg_for_this_receipient)
|
||||||
|
|
||||||
def get_digest_msg(self):
|
def get_digest_msg(self):
|
||||||
@ -123,7 +125,7 @@ class DocType(DocListController):
|
|||||||
if with_value:
|
if with_value:
|
||||||
with_value = "\n".join(with_value)
|
with_value = "\n".join(with_value)
|
||||||
else:
|
else:
|
||||||
with_value = "<p>There were no updates in the items selected for this digest.</p>"
|
with_value = "<p>There were no updates in the items selected for this digest.</p><hr>"
|
||||||
|
|
||||||
# seperate out no value items
|
# seperate out no value items
|
||||||
no_value = [o[1] for o in out if not o[0]]
|
no_value = [o[1] for o in out if not o[0]]
|
||||||
@ -138,7 +140,8 @@ class DocType(DocListController):
|
|||||||
"date": date,
|
"date": date,
|
||||||
"company": self.doc.company,
|
"company": self.doc.company,
|
||||||
"with_value": with_value,
|
"with_value": with_value,
|
||||||
"no_value": no_value or ""
|
"no_value": no_value or "",
|
||||||
|
"name": self.doc.name
|
||||||
}
|
}
|
||||||
|
|
||||||
return msg
|
return msg
|
||||||
@ -453,6 +456,10 @@ class DocType(DocListController):
|
|||||||
else:
|
else:
|
||||||
return 0, "No Open Tickets!"
|
return 0, "No Open Tickets!"
|
||||||
|
|
||||||
|
def get_scheduler_errors(self):
|
||||||
|
import webnotes.utils.scheduler
|
||||||
|
return webnotes.utils.scheduler.get_error_report(self.from_date, self.to_date)
|
||||||
|
|
||||||
def onload(self):
|
def onload(self):
|
||||||
self.get_next_sending()
|
self.get_next_sending()
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
{
|
{
|
||||||
"creation": "2013-02-21 14:15:31",
|
"creation": "2013-02-21 14:15:31",
|
||||||
"docstatus": 0,
|
"docstatus": 0,
|
||||||
"modified": "2013-07-05 14:36:13",
|
"modified": "2013-12-16 12:37:43",
|
||||||
"modified_by": "Administrator",
|
"modified_by": "Administrator",
|
||||||
"owner": "Administrator"
|
"owner": "Administrator"
|
||||||
},
|
},
|
||||||
@ -100,11 +100,10 @@
|
|||||||
"label": "Add/Remove Recipients"
|
"label": "Add/Remove Recipients"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "Check all the items below that you want to send in this digest.",
|
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"fieldname": "select_digest_content",
|
"fieldname": "accounts",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"label": "Select Digest Content"
|
"label": "Accounts"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
@ -178,7 +177,7 @@
|
|||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"fieldname": "section_break_20",
|
"fieldname": "section_break_20",
|
||||||
"fieldtype": "Section Break",
|
"fieldtype": "Section Break",
|
||||||
"options": "Simple"
|
"label": "Buying & Selling"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
@ -234,6 +233,12 @@
|
|||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "New Sales Orders"
|
"label": "New Sales Orders"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"doctype": "DocField",
|
||||||
|
"fieldname": "section_break_34",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Inventory & Support"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"fieldname": "stock_module",
|
"fieldname": "stock_module",
|
||||||
@ -258,12 +263,6 @@
|
|||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "New Stock Entries"
|
"label": "New Stock Entries"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"doctype": "DocField",
|
|
||||||
"fieldname": "section_break_34",
|
|
||||||
"fieldtype": "Section Break",
|
|
||||||
"options": "Simple"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"fieldname": "support_module",
|
"fieldname": "support_module",
|
||||||
@ -288,6 +287,12 @@
|
|||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "New Communications"
|
"label": "New Communications"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"doctype": "DocField",
|
||||||
|
"fieldname": "section_break_40",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "Projects & System"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"fieldname": "projects_module",
|
"fieldname": "projects_module",
|
||||||
@ -302,7 +307,25 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"doctype": "DocField",
|
"doctype": "DocField",
|
||||||
"fieldname": "utilities_module",
|
"fieldname": "core_module",
|
||||||
|
"fieldtype": "Column Break",
|
||||||
|
"label": "System"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doctype": "DocField",
|
||||||
|
"fieldname": "scheduler_errors",
|
||||||
|
"fieldtype": "Check",
|
||||||
|
"label": "Scheduler Failed Events"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doctype": "DocField",
|
||||||
|
"fieldname": "user_specific",
|
||||||
|
"fieldtype": "Section Break",
|
||||||
|
"label": "User Specific"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doctype": "DocField",
|
||||||
|
"fieldname": "general",
|
||||||
"fieldtype": "Column Break",
|
"fieldtype": "Column Break",
|
||||||
"label": "General"
|
"label": "General"
|
||||||
},
|
},
|
||||||
@ -318,6 +341,12 @@
|
|||||||
"fieldtype": "Check",
|
"fieldtype": "Check",
|
||||||
"label": "To Do List"
|
"label": "To Do List"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"doctype": "DocField",
|
||||||
|
"fieldname": "stub",
|
||||||
|
"fieldtype": "Column Break",
|
||||||
|
"label": "Stub"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cancel": 1,
|
"cancel": 1,
|
||||||
"create": 1,
|
"create": 1,
|
||||||
|
@ -233,8 +233,9 @@ items = [
|
|||||||
"route": "Report/Scheduler Log", "type": "Link", "icon": "icon-exclamation-sign" },
|
"route": "Report/Scheduler Log", "type": "Link", "icon": "icon-exclamation-sign" },
|
||||||
]
|
]
|
||||||
|
|
||||||
@webnotes.whitelist(allow_roles=["System Manager"])
|
@webnotes.whitelist()
|
||||||
def get():
|
def get():
|
||||||
|
webnotes.only_for("System Manager")
|
||||||
for item in items:
|
for item in items:
|
||||||
if item.get("type")=="Section":
|
if item.get("type")=="Section":
|
||||||
continue
|
continue
|
||||||
|
@ -171,7 +171,7 @@ def create_feed_and_todo():
|
|||||||
|
|
||||||
def create_email_digest():
|
def create_email_digest():
|
||||||
from webnotes.profile import get_system_managers
|
from webnotes.profile import get_system_managers
|
||||||
system_managers = get_system_managers()
|
system_managers = get_system_managers(only_name=True)
|
||||||
if not system_managers:
|
if not system_managers:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -186,10 +186,23 @@ def create_email_digest():
|
|||||||
})
|
})
|
||||||
|
|
||||||
for fieldname in edigest.meta.get_fieldnames({"fieldtype": "Check"}):
|
for fieldname in edigest.meta.get_fieldnames({"fieldtype": "Check"}):
|
||||||
|
if fieldname != "scheduler_errors":
|
||||||
edigest.doc.fields[fieldname] = 1
|
edigest.doc.fields[fieldname] = 1
|
||||||
|
|
||||||
edigest.insert()
|
edigest.insert()
|
||||||
|
|
||||||
|
# scheduler errors digest
|
||||||
|
edigest = webnotes.new_bean("Email Digest")
|
||||||
|
edigest.doc.fields.update({
|
||||||
|
"name": "Scheduler Errors",
|
||||||
|
"company": webnotes.conn.get_default("company"),
|
||||||
|
"frequency": "Daily",
|
||||||
|
"recipient_list": "\n".join(system_managers),
|
||||||
|
"scheduler_errors": 1,
|
||||||
|
"enabled": 1
|
||||||
|
})
|
||||||
|
edigest.insert()
|
||||||
|
|
||||||
def get_fy_details(fy_start_date, fy_end_date):
|
def get_fy_details(fy_start_date, fy_end_date):
|
||||||
start_year = getdate(fy_start_date).year
|
start_year = getdate(fy_start_date).year
|
||||||
if start_year == getdate(fy_end_date).year:
|
if start_year == getdate(fy_end_date).year:
|
||||||
|
@ -14,3 +14,4 @@ def on_method(bean, method):
|
|||||||
|
|
||||||
if bean.doc.doctype=="Stock Entry" and method in ("on_submit", "on_cancel"):
|
if bean.doc.doctype=="Stock Entry" and method in ("on_submit", "on_cancel"):
|
||||||
update_completed_qty(bean.controller, method)
|
update_completed_qty(bean.controller, method)
|
||||||
|
|
@ -34,10 +34,6 @@ def execute_daily():
|
|||||||
from core.doctype.notification_count.notification_count import delete_notification_count_for
|
from core.doctype.notification_count.notification_count import delete_notification_count_for
|
||||||
delete_notification_count_for("Event")
|
delete_notification_count_for("Event")
|
||||||
|
|
||||||
# email digest
|
|
||||||
from setup.doctype.email_digest.email_digest import send
|
|
||||||
run_fn(send)
|
|
||||||
|
|
||||||
# run recurring invoices
|
# run recurring invoices
|
||||||
from accounts.doctype.sales_invoice.sales_invoice import manage_recurring_invoices
|
from accounts.doctype.sales_invoice.sales_invoice import manage_recurring_invoices
|
||||||
run_fn(manage_recurring_invoices)
|
run_fn(manage_recurring_invoices)
|
||||||
@ -54,8 +50,9 @@ def execute_daily():
|
|||||||
from stock.utils import reorder_item
|
from stock.utils import reorder_item
|
||||||
run_fn(reorder_item)
|
run_fn(reorder_item)
|
||||||
|
|
||||||
# scheduler error
|
# email digest
|
||||||
scheduler.report_errors()
|
from setup.doctype.email_digest.email_digest import send
|
||||||
|
run_fn(send)
|
||||||
|
|
||||||
def execute_weekly():
|
def execute_weekly():
|
||||||
from setup.doctype.backup_manager.backup_manager import take_backups_weekly
|
from setup.doctype.backup_manager.backup_manager import take_backups_weekly
|
||||||
|
@ -37,20 +37,25 @@ class DocType(BuyingController):
|
|||||||
|
|
||||||
for so_no in so_items.keys():
|
for so_no in so_items.keys():
|
||||||
for item in so_items[so_no].keys():
|
for item in so_items[so_no].keys():
|
||||||
already_indented = webnotes.conn.sql("select sum(qty) from `tabMaterial Request Item` where item_code = '%s' and sales_order_no = '%s' and docstatus = 1 and parent != '%s'" % (item, so_no, self.doc.name))
|
already_indented = webnotes.conn.sql("""select sum(qty) from `tabMaterial Request Item`
|
||||||
|
where item_code = %s and sales_order_no = %s and
|
||||||
|
docstatus = 1 and parent != %s""", (item, so_no, self.doc.name))
|
||||||
already_indented = already_indented and flt(already_indented[0][0]) or 0
|
already_indented = already_indented and flt(already_indented[0][0]) or 0
|
||||||
|
|
||||||
actual_so_qty = webnotes.conn.sql("select sum(qty) from `tabSales Order Item` where parent = '%s' and item_code = '%s' and docstatus = 1 group by parent" % (so_no, item))
|
actual_so_qty = webnotes.conn.sql("""select sum(qty) from `tabSales Order Item`
|
||||||
|
where parent = %s and item_code = %s and docstatus = 1
|
||||||
|
group by parent""", (so_no, item))
|
||||||
actual_so_qty = actual_so_qty and flt(actual_so_qty[0][0]) or 0
|
actual_so_qty = actual_so_qty and flt(actual_so_qty[0][0]) or 0
|
||||||
|
|
||||||
if flt(so_items[so_no][item]) + already_indented > actual_so_qty:
|
if actual_so_qty and (flt(so_items[so_no][item]) + already_indented > actual_so_qty):
|
||||||
msgprint("You can raise indent of maximum qty: %s for item: %s against sales order: %s\n Anyway, you can add more qty in new row for the same item." % (actual_so_qty - already_indented, item, so_no), raise_exception=1)
|
webnotes.throw("You can raise indent of maximum qty: %s for item: %s against sales order: %s\
|
||||||
|
\n Anyway, you can add more qty in new row for the same item."
|
||||||
|
% (actual_so_qty - already_indented, item, so_no))
|
||||||
|
|
||||||
def validate_schedule_date(self):
|
def validate_schedule_date(self):
|
||||||
for d in getlist(self.doclist, 'indent_details'):
|
for d in getlist(self.doclist, 'indent_details'):
|
||||||
if d.schedule_date < self.doc.transaction_date:
|
if d.schedule_date < self.doc.transaction_date:
|
||||||
msgprint("Expected Date cannot be before Material Request Date")
|
webnotes.throw(_("Expected Date cannot be before Material Request Date"))
|
||||||
raise Exception
|
|
||||||
|
|
||||||
# Validate
|
# Validate
|
||||||
# ---------------------
|
# ---------------------
|
||||||
@ -80,8 +85,8 @@ class DocType(BuyingController):
|
|||||||
for d in getlist(self.doclist, 'indent_details'):
|
for d in getlist(self.doclist, 'indent_details'):
|
||||||
if webnotes.conn.get_value("Item", d.item_code, "is_stock_item") == "Yes":
|
if webnotes.conn.get_value("Item", d.item_code, "is_stock_item") == "Yes":
|
||||||
if not d.warehouse:
|
if not d.warehouse:
|
||||||
msgprint("Please Enter Warehouse for Item %s as it is stock item"
|
webnotes.throw("Please Enter Warehouse for Item %s as it is stock item"
|
||||||
% cstr(d.item_code), raise_exception=1)
|
% cstr(d.item_code))
|
||||||
|
|
||||||
qty =flt(d.qty)
|
qty =flt(d.qty)
|
||||||
if is_stopped:
|
if is_stopped:
|
||||||
@ -96,16 +101,17 @@ class DocType(BuyingController):
|
|||||||
update_bin(args)
|
update_bin(args)
|
||||||
|
|
||||||
def on_submit(self):
|
def on_submit(self):
|
||||||
webnotes.conn.set(self.doc,'status','Submitted')
|
webnotes.conn.set(self.doc, 'status', 'Submitted')
|
||||||
self.update_bin(is_submit = 1, is_stopped = 0)
|
self.update_bin(is_submit = 1, is_stopped = 0)
|
||||||
|
|
||||||
def check_modified_date(self):
|
def check_modified_date(self):
|
||||||
mod_db = webnotes.conn.sql("select modified from `tabMaterial Request` where name = '%s'" % self.doc.name)
|
mod_db = webnotes.conn.sql("""select modified from `tabMaterial Request` where name = %s""",
|
||||||
date_diff = webnotes.conn.sql("select TIMEDIFF('%s', '%s')" % ( mod_db[0][0],cstr(self.doc.modified)))
|
self.doc.name)
|
||||||
|
date_diff = webnotes.conn.sql("""select TIMEDIFF('%s', '%s')"""
|
||||||
|
% (mod_db[0][0], cstr(self.doc.modified)))
|
||||||
|
|
||||||
if date_diff and date_diff[0][0]:
|
if date_diff and date_diff[0][0]:
|
||||||
msgprint(cstr(self.doc.doctype) +" => "+ cstr(self.doc.name) +" has been modified. Please Refresh. ")
|
webnotes.throw(cstr(self.doc.doctype) + " => " + cstr(self.doc.name) + " has been modified. Please Refresh.")
|
||||||
raise Exception
|
|
||||||
|
|
||||||
def update_status(self, status):
|
def update_status(self, status):
|
||||||
self.check_modified_date()
|
self.check_modified_date()
|
||||||
@ -113,10 +119,10 @@ class DocType(BuyingController):
|
|||||||
self.update_bin(is_submit = (status == 'Submitted') and 1 or 0, is_stopped = 1)
|
self.update_bin(is_submit = (status == 'Submitted') and 1 or 0, is_stopped = 1)
|
||||||
|
|
||||||
# Step 2:=> Set status
|
# Step 2:=> Set status
|
||||||
webnotes.conn.set(self.doc,'status',cstr(status))
|
webnotes.conn.set(self.doc, 'status', cstr(status))
|
||||||
|
|
||||||
# Step 3:=> Acknowledge User
|
# Step 3:=> Acknowledge User
|
||||||
msgprint(self.doc.doctype + ": " + self.doc.name + " has been %s." % ((status == 'Submitted') and 'Unstopped' or cstr(status)) )
|
msgprint(self.doc.doctype + ": " + self.doc.name + " has been %s." % ((status == 'Submitted') and 'Unstopped' or cstr(status)))
|
||||||
|
|
||||||
|
|
||||||
def on_cancel(self):
|
def on_cancel(self):
|
||||||
@ -177,9 +183,9 @@ def update_completed_qty(controller, caller_method):
|
|||||||
mr_doctype = webnotes.get_doctype("Material Request")
|
mr_doctype = webnotes.get_doctype("Material Request")
|
||||||
|
|
||||||
if mr_obj.doc.status in ["Stopped", "Cancelled"]:
|
if mr_obj.doc.status in ["Stopped", "Cancelled"]:
|
||||||
msgprint(_("Material Request") + ": %s, " % mr_obj.doc.name
|
webnotes.throw(_("Material Request") + ": %s, " % mr_obj.doc.name
|
||||||
+ _(mr_doctype.get_label("status")) + " = %s. " % _(mr_obj.doc.status)
|
+ _(mr_doctype.get_label("status")) + " = %s. " % _(mr_obj.doc.status)
|
||||||
+ _("Cannot continue."), raise_exception=webnotes.InvalidStatusError)
|
+ _("Cannot continue."), exc=webnotes.InvalidStatusError)
|
||||||
|
|
||||||
_update_requested_qty(controller, mr_obj, mr_items)
|
_update_requested_qty(controller, mr_obj, mr_items)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user