|
|
|
|
@@ -17,9 +17,8 @@
|
|
|
|
|
from __future__ import unicode_literals
|
|
|
|
|
import webnotes
|
|
|
|
|
|
|
|
|
|
from webnotes.utils import add_days, cstr, flt
|
|
|
|
|
from webnotes.utils import cstr, flt
|
|
|
|
|
from webnotes.model.bean import getlist
|
|
|
|
|
from webnotes.model.code import get_obj
|
|
|
|
|
from webnotes import msgprint, _
|
|
|
|
|
|
|
|
|
|
from buying.utils import get_last_purchase_details
|
|
|
|
|
@@ -32,46 +31,11 @@ class DocType(BuyingController):
|
|
|
|
|
self.doc = doc
|
|
|
|
|
self.doclist = doclist
|
|
|
|
|
|
|
|
|
|
self.chk_tol_for_list = ['Material Request - Purchase Order', 'Purchase Order - Purchase Receipt', 'Purchase Order - Purchase Invoice']
|
|
|
|
|
|
|
|
|
|
self.update_qty = {
|
|
|
|
|
'Material Request - Purchase Order': 'ordered_qty',
|
|
|
|
|
'Purchase Order - Purchase Receipt': 'received_qty',
|
|
|
|
|
'Purchase Order - Purchase Invoice': 'billed_qty',
|
|
|
|
|
'Purchase Receipt - Purchase Invoice': 'billed_qty'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.update_percent_field = {
|
|
|
|
|
'Material Request - Purchase Order': 'per_ordered',
|
|
|
|
|
'Purchase Order - Purchase Receipt': 'per_received',
|
|
|
|
|
'Purchase Order - Purchase Invoice': 'per_billed',
|
|
|
|
|
'Purchase Receipt - Purchase Invoice': 'per_billed'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# used in validation for items and update_prevdoc_detail
|
|
|
|
|
self.doctype_dict = {
|
|
|
|
|
'Material Request': 'Material Request Item',
|
|
|
|
|
'Purchase Order': 'Purchase Order Item',
|
|
|
|
|
'Purchase Receipt': 'Purchase Receipt Item'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.next_dt_detail = {
|
|
|
|
|
'ordered_qty' : 'Purchase Order Item',
|
|
|
|
|
'billed_qty' : 'Purchase Invoice Item',
|
|
|
|
|
'received_qty': 'Purchase Receipt Item'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.msg = []
|
|
|
|
|
|
|
|
|
|
def is_item_table_empty(self, obj):
|
|
|
|
|
if not len(obj.doclist.get({"parentfield": obj.fname})):
|
|
|
|
|
msgprint(_("Hey there! You need to put at least one item in \
|
|
|
|
|
the item table."), raise_exception=True)
|
|
|
|
|
|
|
|
|
|
# Client Trigger functions
|
|
|
|
|
#------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
# Get Supplier Details
|
|
|
|
|
def get_supplier_details(self, name = ''):
|
|
|
|
|
details = sql("select supplier_name,address from `tabSupplier` where name = '%s' and docstatus != 2" %(name), as_dict = 1)
|
|
|
|
|
if details:
|
|
|
|
|
@@ -94,8 +58,6 @@ class DocType(BuyingController):
|
|
|
|
|
ret = { 'projected_qty' : bin and flt(bin[0]['projected_qty']) or 0 }
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
|
# --- Last Purchase Rate related methods ---
|
|
|
|
|
|
|
|
|
|
def update_last_purchase_rate(self, obj, is_submit):
|
|
|
|
|
"""updates last_purchase_rate in item table for each item"""
|
|
|
|
|
|
|
|
|
|
@@ -146,8 +108,6 @@ class DocType(BuyingController):
|
|
|
|
|
d.purchase_ref_rate = d.purchase_rate = d.import_ref_rate \
|
|
|
|
|
= d.import_rate = item_last_purchase_rate
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# validate for same items and validate is_stock_item , is_purchase_item also validate uom and conversion factor
|
|
|
|
|
def validate_for_items(self, obj):
|
|
|
|
|
check_list, chk_dupl_itm=[],[]
|
|
|
|
|
for d in getlist( obj.doclist, obj.fname):
|
|
|
|
|
@@ -159,7 +119,7 @@ class DocType(BuyingController):
|
|
|
|
|
# udpate with latest quantities
|
|
|
|
|
bin = 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, 'billed_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':
|
|
|
|
|
f_lst.pop('received_qty')
|
|
|
|
|
for x in f_lst :
|
|
|
|
|
@@ -206,36 +166,7 @@ class DocType(BuyingController):
|
|
|
|
|
Please change any of the field value to enter the item twice.""" % d.item_code, raise_exception = 1)
|
|
|
|
|
else:
|
|
|
|
|
chk_dupl_itm.append(f)
|
|
|
|
|
|
|
|
|
|
# Check for Stopped status
|
|
|
|
|
def check_for_stopped_status(self, doctype, docname):
|
|
|
|
|
stopped = sql("select name from `tab%s` where name = '%s' and status = 'Stopped'" %
|
|
|
|
|
( doctype, docname))
|
|
|
|
|
if stopped:
|
|
|
|
|
msgprint("One cannot do any transaction against %s : %s, it's status is 'Stopped'" %
|
|
|
|
|
( doctype, docname), raise_exception=1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Check Docstatus of Next DocType on Cancel AND of Previous DocType on Submit
|
|
|
|
|
def check_docstatus(self, check, doctype, docname , detail_doctype = ''):
|
|
|
|
|
|
|
|
|
|
if check == 'Next':
|
|
|
|
|
# Convention := doctype => Next Doctype, docname = current_docname , detail_doctype = Next Doctype Detail Table
|
|
|
|
|
|
|
|
|
|
submitted = 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" % ( doctype, detail_doctype, docname))
|
|
|
|
|
if submitted:
|
|
|
|
|
msgprint(cstr(doctype) + " : " + cstr(submitted[0][0]) + " has already been submitted !")
|
|
|
|
|
raise Exception
|
|
|
|
|
|
|
|
|
|
if check == 'Previous':
|
|
|
|
|
# Convention := doctype => Previous Doctype, docname = Previous Docname
|
|
|
|
|
submitted = sql("select name from `tab%s` where docstatus = 1 and name = '%s'" % (doctype, docname))
|
|
|
|
|
if not submitted:
|
|
|
|
|
msgprint(cstr(doctype) + " : " + cstr(submitted[0][0]) + " not submitted !")
|
|
|
|
|
raise Exception
|
|
|
|
|
|
|
|
|
|
# Update Ref Doc
|
|
|
|
|
# =======================================================
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
#------------------------------
|
|
|
|
|
@@ -252,112 +183,35 @@ class DocType(BuyingController):
|
|
|
|
|
max_qty = sql("select qty from `tab%s` where name = '%s' and docstatus = 1"% (ref_doc_tname, ref_tab_dn))
|
|
|
|
|
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):
|
|
|
|
|
stopped = sql("select name from `tab%s` where name = '%s' and status = 'Stopped'" %
|
|
|
|
|
( doctype, docname))
|
|
|
|
|
if stopped:
|
|
|
|
|
msgprint("One cannot do any transaction against %s : %s, it's status is 'Stopped'" %
|
|
|
|
|
( doctype, docname), raise_exception=1)
|
|
|
|
|
|
|
|
|
|
def check_docstatus(self, check, doctype, docname , detail_doctype = ''):
|
|
|
|
|
if check == 'Next':
|
|
|
|
|
submitted = 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"""
|
|
|
|
|
% (doctype, detail_doctype, '%s'), docname)
|
|
|
|
|
if submitted:
|
|
|
|
|
msgprint(cstr(doctype) + ": " + cstr(submitted[0][0])
|
|
|
|
|
+ _(" has already been submitted."), raise_exception=1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def update_refdoc_qty(self, curr_qty, curr_doctype, ref_dn, ref_dt, ref_tab_fname, ref_tab_dn, transaction, item_code, is_submit, curr_parent_doctype, curr_parent_name):
|
|
|
|
|
# Get Quantity
|
|
|
|
|
#------------------------------
|
|
|
|
|
curr_ref_qty = self.get_qty(curr_doctype,ref_tab_fname,ref_tab_dn,self.doctype_dict[ref_dt], transaction, curr_parent_name)
|
|
|
|
|
qty, max_qty, max_qty_plus_tol = flt(curr_ref_qty.split('~~~')[0]), flt(curr_ref_qty.split('~~~')[1]), flt(curr_ref_qty.split('~~~')[1])
|
|
|
|
|
|
|
|
|
|
# Qty above Tolerance should be allowed only once.
|
|
|
|
|
# But there is special case for Transaction 'Material Request-Purhcase Order' that there should be no restriction
|
|
|
|
|
# One can create any no. of PO against same Material Request!!!
|
|
|
|
|
if qty >= max_qty and is_submit and flt(curr_qty) > 0:
|
|
|
|
|
reason = (curr_parent_doctype == 'Purchase Order') and 'Ordered' or (curr_parent_doctype == 'Purchase Receipt') and 'Received' or (curr_parent_doctype == 'Purchase Invoice') and 'Billed'
|
|
|
|
|
msgprint("Error: Item Code : '%s' of '%s' is already %s." %(item_code,ref_dn,reason))
|
|
|
|
|
raise Exception
|
|
|
|
|
|
|
|
|
|
#check if tolerance added in item master
|
|
|
|
|
tolerance = flt(webnotes.conn.get_value('Item',item_code,'tolerance') or 0)
|
|
|
|
|
|
|
|
|
|
if not(tolerance):
|
|
|
|
|
tolerance = flt(webnotes.conn.get_value('Stock Settings',None,'tolerance') or 0)
|
|
|
|
|
|
|
|
|
|
if is_submit:
|
|
|
|
|
qty = qty + flt(curr_qty)
|
|
|
|
|
|
|
|
|
|
# Calculate max_qty_plus_tol i.e. max_qty with tolerance
|
|
|
|
|
#-----------------------------------------------------------------
|
|
|
|
|
if transaction in self.chk_tol_for_list:
|
|
|
|
|
max_qty_plus_tol = max_qty * (1 + (flt(tolerance)/ 100))
|
|
|
|
|
|
|
|
|
|
if max_qty_plus_tol < qty:
|
|
|
|
|
reason = (curr_parent_doctype == 'Purchase Order') and 'Ordered' or (curr_parent_doctype == 'Purchase Receipt') and 'Received' or (curr_parent_doctype == 'Purchase Invoice') and 'Billed'
|
|
|
|
|
msg = "error: Already %s Qty for %s is %s and \
|
|
|
|
|
maximum allowed Qty is %s [against %s: %s]" % \
|
|
|
|
|
(cstr(reason), item_code,
|
|
|
|
|
cstr(flt(qty) - flt(curr_qty)) , cstr(max_qty_plus_tol),
|
|
|
|
|
cstr(ref_dt), cstr(ref_dn))
|
|
|
|
|
msgprint(msg, raise_exception=1)
|
|
|
|
|
|
|
|
|
|
# Update qty
|
|
|
|
|
#------------------
|
|
|
|
|
sql("update `tab%s` set %s = '%s',modified = now() where name = '%s'" % (self.doctype_dict[ref_dt],self.update_qty[transaction] , flt(qty), ref_tab_dn))
|
|
|
|
|
|
|
|
|
|
def update_ref_doctype_dict(self, curr_qty, curr_doctype, ref_dn, ref_dt, ref_tab_fname, ref_tab_dn, transaction, item_code, is_submit, curr_parent_doctype, curr_parent_name):
|
|
|
|
|
# update qty
|
|
|
|
|
self.update_refdoc_qty( curr_qty, curr_doctype, ref_dn, ref_dt, ref_tab_fname, ref_tab_dn, transaction, item_code, is_submit, curr_parent_doctype, curr_parent_name)
|
|
|
|
|
|
|
|
|
|
# append distinct ref_dn in doctype_dict
|
|
|
|
|
if not self.ref_doctype_dict.has_key(ref_dn) and self.update_percent_field.has_key(transaction):
|
|
|
|
|
self.ref_doctype_dict[ref_dn] = [ ref_dt, self.doctype_dict[ref_dt],transaction]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# update prevdoc detail
|
|
|
|
|
# --------------------
|
|
|
|
|
def update_prevdoc_detail(self, obj, is_submit):
|
|
|
|
|
import math
|
|
|
|
|
self.ref_doctype_dict= {}
|
|
|
|
|
for d in getlist(obj.doclist, obj.fname):
|
|
|
|
|
|
|
|
|
|
if d.fields.has_key('prevdoc_docname') and d.prevdoc_docname:
|
|
|
|
|
transaction = cstr(d.prevdoc_doctype) + ' - ' + cstr(obj.doc.doctype)
|
|
|
|
|
curr_qty = (transaction == 'Material Request - Purchase Order') and flt(d.qty) * flt(d.conversion_factor) or flt(d.qty)
|
|
|
|
|
self.update_ref_doctype_dict( flt(curr_qty), d.doctype, d.prevdoc_docname, d.prevdoc_doctype, 'prevdoc_detail_docname', d.prevdoc_detail_docname, transaction, d.item_code, is_submit, obj.doc.doctype, obj.doc.name)
|
|
|
|
|
|
|
|
|
|
# for payable voucher
|
|
|
|
|
if d.fields.has_key('purchase_order') and d.purchase_order:
|
|
|
|
|
curr_qty = sql("select sum(qty) from `tabPurchase Invoice Item` where po_detail = '%s' and parent = '%s'" % (cstr(d.po_detail), cstr(obj.doc.name)))
|
|
|
|
|
curr_qty = curr_qty and flt(curr_qty[0][0]) or 0
|
|
|
|
|
self.update_ref_doctype_dict( curr_qty, d.doctype, d.purchase_order, 'Purchase Order', 'po_detail', d.po_detail, 'Purchase Order - ' + cstr(obj.doc.doctype), d.item_code, is_submit, obj.doc.doctype, obj.doc.name)
|
|
|
|
|
|
|
|
|
|
if d.fields.has_key('purchase_receipt') and d.purchase_receipt:
|
|
|
|
|
self.update_ref_doctype_dict( flt(d.qty), d.doctype, d.purchase_receipt, 'Purchase Receipt', 'pr_detail', d.pr_detail, 'Purchase Receipt - ' + cstr(obj.doc.doctype), d.item_code, is_submit, obj.doc.doctype, obj.doc.name)
|
|
|
|
|
|
|
|
|
|
for ref_dn in self.ref_doctype_dict:
|
|
|
|
|
# Calculate percentage
|
|
|
|
|
#----------------------
|
|
|
|
|
ref_doc_obj = get_obj(self.ref_doctype_dict[ref_dn][0],ref_dn,with_children = 1)
|
|
|
|
|
count = 0
|
|
|
|
|
percent = 0
|
|
|
|
|
for d in getlist(ref_doc_obj.doclist,ref_doc_obj.fname):
|
|
|
|
|
ref_qty = d.fields[self.update_qty[self.ref_doctype_dict[ref_dn][2]]]
|
|
|
|
|
if flt(d.qty) - flt(ref_qty) <= 0:
|
|
|
|
|
percent += 100
|
|
|
|
|
else:
|
|
|
|
|
percent += (flt(ref_qty)/flt(d.qty) * 100)
|
|
|
|
|
count += 1
|
|
|
|
|
percent_complete = math.floor(flt(percent)/ flt(count))
|
|
|
|
|
|
|
|
|
|
# update percent complete and modified
|
|
|
|
|
#-------------------------------------
|
|
|
|
|
sql("update `tab%s` set %s = '%s', modified = '%s' where name = '%s'" % (self.ref_doctype_dict[ref_dn][0], self.update_percent_field[self.ref_doctype_dict[ref_dn][2]], percent_complete, obj.doc.modified, ref_dn))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def validate_fiscal_year(self, fiscal_year, transaction_date, dn):
|
|
|
|
|
fy=sql("select year_start_date from `tabFiscal Year` where name='%s'"%fiscal_year)
|
|
|
|
|
ysd=fy and fy[0][0] or ""
|
|
|
|
|
yed=add_days(str(ysd),365)
|
|
|
|
|
if str(transaction_date) < str(ysd) or str(transaction_date) > str(yed):
|
|
|
|
|
msgprint("'%s' Not Within The Fiscal Year"%(dn))
|
|
|
|
|
raise Exception
|
|
|
|
|
if check == 'Previous':
|
|
|
|
|
submitted = sql("""select name from `tab%s`
|
|
|
|
|
where docstatus = 1 and name = %s"""% (doctype, '%s'), docname)
|
|
|
|
|
if not submitted:
|
|
|
|
|
msgprint(cstr(doctype) + ": " + cstr(submitted[0][0])
|
|
|
|
|
+ _(" not submitted"), raise_exception=1)
|
|
|
|
|
|
|
|
|
|
def get_rate(self, arg, obj):
|
|
|
|
|
arg = eval(arg)
|
|
|
|
|
rate = sql("select account_type, tax_rate from `tabAccount` where name = '%s'" %(arg['account_head']), as_dict=1)
|
|
|
|
|
rate = sql("select account_type, tax_rate from `tabAccount` where name = %s"
|
|
|
|
|
, (arg['account_head']), as_dict=1)
|
|
|
|
|
|
|
|
|
|
return {'rate': rate and (rate[0]['account_type'] == 'Tax' \
|
|
|
|
|
and not arg['charge_type'] == 'Actual') and flt(rate[0]['tax_rate']) or 0 }
|
|
|
|
|
@@ -365,5 +219,6 @@ class DocType(BuyingController):
|
|
|
|
|
def get_prevdoc_date(self, obj):
|
|
|
|
|
for d in getlist(obj.doclist, obj.fname):
|
|
|
|
|
if d.prevdoc_doctype and d.prevdoc_docname:
|
|
|
|
|
dt = sql("select transaction_date from `tab%s` where name = '%s'" % (d.prevdoc_doctype, d.prevdoc_docname))
|
|
|
|
|
dt = sql("select transaction_date from `tab%s` where name = %s"
|
|
|
|
|
% (d.prevdoc_doctype, '%s'), (d.prevdoc_docname))
|
|
|
|
|
d.prevdoc_date = dt and dt[0][0].strftime('%Y-%m-%d') or ''
|
|
|
|
|
|