fixes to bin for reposting future entires

This commit is contained in:
Rushabh Mehta
2011-11-08 12:06:02 +05:30
parent efd222b6ac
commit d77cb27bd2
7 changed files with 55 additions and 75 deletions

View File

@@ -345,7 +345,7 @@ def execute(patch_no):
for b in bin: for b in bin:
bobj = get_obj('Bin',b[0]) bobj = get_obj('Bin',b[0])
prev_sle = bobj.get_prev_sle(posting_date = '2011-09-01', posting_time = '01:00') prev_sle = bobj.get_prev_sle(posting_date = '2011-09-01', posting_time = '01:00')
bobj.update_item_valuation(posting_date = '2011-09-01', posting_time = '01:00', prev_sle = prev_sle) bobj.update_entries_after(posting_date = '2011-09-01', posting_time = '01:00', prev_sle = prev_sle)
elif patch_no == 368: elif patch_no == 368:
from webnotes.utils import nestedset from webnotes.utils import nestedset
t = [ t = [

View File

@@ -1,18 +1,11 @@
# Please edit this list and import only required elements # Please edit this list and import only required elements
import webnotes import webnotes
from webnotes.utils import add_days, add_months, add_years, cint, cstr, date_diff, default_fields, flt, fmt_money, formatdate, generate_hash, getTraceback, get_defaults, get_first_day, get_last_day, getdate, has_common, month_name, now, nowdate, replace_newlines, sendmail, set_default, str_esc_quote, user_format, validate_email_add from webnotes.utils import cint, cstr, flt
from webnotes.model import db_exists from webnotes.model.code import get_obj
from webnotes.model.doc import Document, addchild, removechild, getchildren, make_autoname, SuperDocType from webnotes import msgprint
from webnotes.model.doclist import getlist, copy_doclist
from webnotes.model.code import get_obj, get_server_obj, run_server_obj, updatedb, check_syntax
from webnotes import session, form, is_testing, msgprint, errprint
set = webnotes.conn.set
sql = webnotes.conn.sql sql = webnotes.conn.sql
get_value = webnotes.conn.get_value
in_transaction = webnotes.conn.in_transaction
convert_to_lists = webnotes.conn.convert_to_lists
# ----------------------------------------------------------------------------------------- # -----------------------------------------------------------------------------------------
@@ -45,13 +38,7 @@ class DocType:
if serial_no: if serial_no:
self.check_qty_with_serial_no() self.check_qty_with_serial_no()
prev_sle = self.get_prev_sle(dt, posting_time, sle_id) self.update_entries_after(dt, posting_time)
cqty = flt(prev_sle.get('bin_aqat', 0))
# Block if actual qty becomes negative
if (flt(cqty) + flt(actual_qty)) < 0 and flt(actual_qty) < 0 and is_cancelled == 'No':
msgprint('Not enough quantity (requested: %s, current: %s) for Item <b>%s</b> in Warehouse <b>%s</b> as on %s %s' % (flt(actual_qty), flt(cqty), self.doc.item_code, self.doc.warehouse, dt, posting_time), raise_exception = 1)
self.update_item_valuation(sle_id, dt, posting_time, serial_no, prev_sle)
def check_qty_with_serial_no(self): def check_qty_with_serial_no(self):
""" """
@@ -81,33 +68,22 @@ class DocType:
""", (self.doc.item_code, self.doc.warehouse), as_dict=1) """, (self.doc.item_code, self.doc.warehouse), as_dict=1)
return sle and sle[0] or None return sle and sle[0] or None
# -------------------------------- def get_prev_sle(self, posting_date = '0000-00-00', posting_time = '00:00'):
# get previous stock ledger entry """get previous stock ledger entry"""
# -------------------------------- # get the last sle before the current time-bucket, so that all values
# are reposted from the current time-bucket onwards.
def get_prev_sle(self, posting_date, posting_time, sle_id = ''): # this is necessary because at the time of cancellation, there may be
# this function will only be called for a live entry # entries between the cancelled entries in the same time-bucket
# for which the "name" will be the latest (even for the same timestamp)
# and even for a back-dated entry
# hence there cannot be any "backdated entries" with a name greater than the
# current one
# if there are multiple entries on this timestamp, then the last one will be with
# the last "name"
# else, the last entry will be the highest name at the previous timestamp
# hence, the double sort on timestamp and name should be sufficient condition
# to get the last sle
sle = sql(""" sle = sql("""
select * from `tabStock Ledger Entry` select * from `tabStock Ledger Entry`
where item_code = %s where item_code = %s
and warehouse = %s and warehouse = %s
and name != %s
and ifnull(is_cancelled, 'No') = 'No' and ifnull(is_cancelled, 'No') = 'No'
and timestamp(posting_date, posting_time) <= timestamp(%s, %s) and timestamp(posting_date, posting_time) < timestamp(%s, %s)
order by timestamp(posting_date, posting_time) desc, name desc order by timestamp(posting_date, posting_time) desc, name desc
limit 1 limit 1
""", (self.doc.item_code, self.doc.warehouse, sle_id, posting_date, posting_time), as_dict=1) """, (self.doc.item_code, self.doc.warehouse, posting_date, posting_time), as_dict=1)
return sle and sle[0] or {} return sle and sle[0] or {}
@@ -121,11 +97,13 @@ class DocType:
diff = cqty + s['actual_qty'] diff = cqty + s['actual_qty']
if diff < 0 and (abs(diff) > 0.0001) and s['is_cancelled'] != 'Yes': if diff < 0 and (abs(diff) > 0.0001) and s['is_cancelled'] != 'Yes':
msgprint(""" msgprint("""
Negative stock error:
Cannot complete this transaction because stock will Cannot complete this transaction because stock will
become negative (%s) in future transaction for Item become negative (%s) for Item <b>%s</b> in Warehouse
<b>%s</b> in Warehouse <b>%s</b> on <b>%s %s</b>""" % \ <b>%s</b> on <b>%s %s</b> in Transaction %s %s""" % \
(str(diff), self.doc.item_code, self.doc.warehouse, (str(diff), self.doc.item_code, self.doc.warehouse,
s['posting_date'], s['posting_time']), raise_exception=1) s['posting_date'], s['posting_time'], s['voucher_type'], s['voucher_no']), \
raise_exception=1)
# ------------------------------------ # ------------------------------------
# get serialized inventory values # get serialized inventory values
@@ -222,11 +200,14 @@ class DocType:
stock_val = sum([flt(d[0])*flt(d[1]) for d in self.fcfs_bal]) stock_val = sum([flt(d[0])*flt(d[1]) for d in self.fcfs_bal])
return stock_val return stock_val
# ---------------------- def update_entries_after(self, posting_date, posting_time):
# update item valuation """update item valution from the give stock ledger entry (sle)
# ---------------------- onwards."""
def update_item_valuation(self, sle_id=None, posting_date=None, posting_time=None, serial_no=None, prev_sle=None):
# no sle given, start from the first one (for repost) # Get prev sle
prev_sle = self.get_prev_sle(posting_date, posting_time)
# if no prev sle, start from the first one (for repost)
if not prev_sle: if not prev_sle:
cqty, cval, val_rate, self.fcfs_bal = 0, 0, 0, [] cqty, cval, val_rate, self.fcfs_bal = 0, 0, 0, []
@@ -237,11 +218,11 @@ class DocType:
val_rate = flt(prev_sle.get('valuation_rate', 0)) val_rate = flt(prev_sle.get('valuation_rate', 0))
self.fcfs_bal = eval(prev_sle.get('fcfs_stack', '[]') or '[]') self.fcfs_bal = eval(prev_sle.get('fcfs_stack', '[]') or '[]')
val_method = get_obj('Valuation Control').get_valuation_method(self.doc.item_code) # get valuation method # get valuation method
val_method = get_obj('Valuation Control').get_valuation_method(self.doc.item_code)
# recalculate the balances for all stock ledger entries # recalculate the balances for all stock ledger entries
# after this one (so that the corrected balance will reflect # after the prev sle
# correctly in all entries after this one)
sll = sql(""" sll = sql("""
select * select *
from `tabStock Ledger Entry` from `tabStock Ledger Entry`
@@ -250,30 +231,32 @@ class DocType:
and ifnull(is_cancelled, 'No') = 'No' and ifnull(is_cancelled, 'No') = 'No'
and timestamp(posting_date, posting_time) > timestamp(%s, %s) and timestamp(posting_date, posting_time) > timestamp(%s, %s)
order by timestamp(posting_date, posting_time) asc, name asc""", \ order by timestamp(posting_date, posting_time) asc, name asc""", \
(self.doc.item_code, self.doc.warehouse, posting_date, posting_time), as_dict = 1) (self.doc.item_code, self.doc.warehouse, \
prev_sle.get('posting_date','0000-00-00'), prev_sle.get('posting_time', '00:00')), as_dict = 1)
# if in live entry - update the values of the current sle for sle in sll:
if sle_id:
sll = sql("select * from `tabStock Ledger Entry` where name=%s and ifnull(is_cancelled, 'No') = 'No'", sle_id, as_dict=1) + sll
for s in sll:
# block if stock level goes negative on any date # block if stock level goes negative on any date
self.validate_negative_stock(cqty, s) self.validate_negative_stock(cqty, sle)
stock_val, in_rate = 0, s['incoming_rate'] # IN stock_val, in_rate = 0, sle['incoming_rate'] # IN
serial_nos = s["serial_no"] and ("'"+"', '".join(cstr(s["serial_no"]).split('\n')) + "'") or '' serial_nos = sle["serial_no"] and ("'"+"', '".join(cstr(sle["serial_no"]).split('\n')) \
+ "'") or ''
# Get valuation rate # Get valuation rate
val_rate, stock_val = self.get_valuation_rate(val_method, serial_nos, val_rate, in_rate, stock_val, cqty, s) val_rate, stock_val = self.get_valuation_rate(val_method, serial_nos, \
val_rate, in_rate, stock_val, cqty, s)
# Qty upto the sle # Qty upto the sle
cqty += s['actual_qty'] cqty += sle['actual_qty']
# Stock Value upto the sle # Stock Value upto the sle
stock_val = self.get_stock_value(val_method, cqty, stock_val, serial_nos) stock_val = self.get_stock_value(val_method, cqty, stock_val, serial_nos)
# update current sle --> will it be good to update incoming rate in sle for outgoing stock entry?????
# update current sle --> will it be good to update incoming rate in sle
# for outgoing stock entry?????
sql("""update `tabStock Ledger Entry` sql("""update `tabStock Ledger Entry`
set bin_aqat=%s, valuation_rate=%s, fcfs_stack=%s, stock_value=%s set bin_aqat=%s, valuation_rate=%s, fcfs_stack=%s, stock_value=%s
where name=%s""", (cqty, flt(val_rate), cstr(self.fcfs_bal), stock_val, s['name'])) where name=%s""", (cqty, flt(val_rate), cstr(self.fcfs_bal), stock_val, sle['name']))
# update the bin # update the bin
if sll: if sll:

View File

@@ -86,9 +86,9 @@ class DocType:
d.save() d.save()
sql("update `tabStock Ledger Entry` set incoming_rate = '%s' where voucher_detail_no = '%s'"%(flt(d.valuation_rate), d.name)) sql("update `tabStock Ledger Entry` set incoming_rate = '%s' where voucher_detail_no = '%s'"%(flt(d.valuation_rate), d.name))
bin_name = sql("select t1.name, t2.name, t2.posting_date, t2.posting_time from `tabBin` t1, `tabStock Ledger Entry` t2 where t2.voucher_detail_no = '%s' and t2.item_code = t1.item_code and t2.warehouse = t1.warehouse LIMIT 1"%(d.name)) bin_name = sql("select t1.name, t2.posting_date, t2.posting_time from `tabBin` t1, `tabStock Ledger Entry` t2 where t2.voucher_detail_no = '%s' and t2.item_code = t1.item_code and t2.warehouse = t1.warehouse LIMIT 1"%(d.name))
if bin_name and bin_name[0][0]: if bin_name and bin_name[0][0]:
obj = get_obj('Bin', bin_name[0][0]).update_item_valuation(bin_name[0][1], bin_name[0][2], bin_name[0][3]) obj = get_obj('Bin', bin_name[0][0]).update_entries_after(bin_name[0][1], bin_name[0][2])
# now distribute the taxes among the PRs # now distribute the taxes among the PRs
for lc in getlist(self.doclist, 'landed_cost_details'): for lc in getlist(self.doclist, 'landed_cost_details'):
@@ -140,11 +140,11 @@ class DocType:
d.valuation_rate = (flt(d.purchase_rate) + (flt(d.rm_supp_cost) / flt(d.qty)) + (flt(d.item_tax_amount)/flt(d.qty))) / flt(d.conversion_factor) d.valuation_rate = (flt(d.purchase_rate) + (flt(d.rm_supp_cost) / flt(d.qty)) + (flt(d.item_tax_amount)/flt(d.qty))) / flt(d.conversion_factor)
d.save() d.save()
sql("update `tabStock Ledger Entry` set incoming_rate = '%s' where voucher_detail_no = '%s'"%(flt(d.valuation_rate), d.name)) sql("update `tabStock Ledger Entry` set incoming_rate = '%s' where voucher_detail_no = '%s'"%(flt(d.valuation_rate), d.name))
bin_name = sql("select t1.name, t2.name, t2.posting_date, t2.posting_time from `tabBin` t1, `tabStock Ledger Entry` t2 where t2.voucher_detail_no = '%s' and t2.item_code = t1.item_code and t2.warehouse = t1.warehouse LIMIT 1"%(d.name)) bin_name = sql("select t1.name, t2.posting_date, t2.posting_time from `tabBin` t1, `tabStock Ledger Entry` t2 where t2.voucher_detail_no = '%s' and t2.item_code = t1.item_code and t2.warehouse = t1.warehouse LIMIT 1"%(d.name))
# update valuation of the item # update valuation of the item
if bin_name and bin_name[0][0]: if bin_name and bin_name[0][0]:
obj = get_obj('Bin', bin_name[0][0]).update_item_valuation(bin_name[0][1], bin_name[0][2], bin_name[0][3]) obj = get_obj('Bin', bin_name[0][0]).update_entries_after(bin_name[0][1], bin_name[0][2])
def add_deduct_taxes(self, ocd, oc, tax_amount, total_amount, total, prev_total, f=1): def add_deduct_taxes(self, ocd, oc, tax_amount, total_amount, total, prev_total, f=1):
ocd[oc].total_amount = flt(tax_amount.toFixed(2)) ocd[oc].total_amount = flt(tax_amount.toFixed(2))

View File

@@ -131,18 +131,18 @@ class DocType:
update item valuation in previous date and also on post date if no qty diff update item valuation in previous date and also on post date if no qty diff
""" """
self.update_item_valuation_pre_date(d) self.update_entries_pre_date(d)
if not flt(d[self.label['qty']]) and not flt(d[self.label['actual_qty']]): if not flt(d[self.label['qty']]) and not flt(d[self.label['actual_qty']]):
# seems like a special condition when there is no actual quanitity but there is a rate, may be only for setting a rate! # seems like a special condition when there is no actual quanitity but there is a rate, may be only for setting a rate!
self.make_sl_entry(1,d,1) self.make_sl_entry(1,d,1)
self.make_sl_entry(1,d,-1) self.make_sl_entry(1,d,-1)
elif not qty_diff: elif not qty_diff:
self.update_item_valuation_post_date(d) self.update_entries_post_date(d)
# update valuation rate as csv file in all sle before reconciliation date # update valuation rate as csv file in all sle before reconciliation date
# ------------------------------------------------------------------------ # ------------------------------------------------------------------------
def update_item_valuation_pre_date(self, d): def update_entries_pre_date(self, d):
mar = flt(d[self.label['mar']]) mar = flt(d[self.label['mar']])
# previous sle # previous sle
@@ -168,15 +168,12 @@ class DocType:
# Update item valuation in all sle after the reconcliation date # Update item valuation in all sle after the reconcliation date
# --------------------------------------------------------- # ---------------------------------------------------------
def update_item_valuation_post_date(self, d): def update_entries_post_date(self, d):
bin = sql("select name from `tabBin` where item_code = '%s' and warehouse = '%s'" % (d[self.label['item_code']], d[self.label['warehouse']])) bin = sql("select name from `tabBin` where item_code = '%s' and warehouse = '%s'" % (d[self.label['item_code']], d[self.label['warehouse']]))
bin_obj = get_obj('Bin', bin[0][0]) bin_obj = get_obj('Bin', bin[0][0])
# prev sle
prev_sle = bin_obj.get_prev_sle(self.doc.reconciliation_date,self.doc.reconciliation_time)
# update valuation in sle posted after reconciliation datetime # update valuation in sle posted after reconciliation datetime
bin_obj.update_item_valuation(posting_date = self.doc.reconciliation_date, posting_time = self.doc.reconciliation_time, prev_sle = prev_sle) bin_obj.update_entries_after(posting_date = self.doc.reconciliation_date, posting_time = self.doc.reconciliation_time)
# -------------- # --------------
# make sl entry # make sl entry

View File

@@ -85,7 +85,7 @@ class DocType:
for w in wh: for w in wh:
bin = sql("select name from `tabBin` where item_code = '%s' and warehouse = '%s'" % (self.doc.item_code, w[0])) bin = sql("select name from `tabBin` where item_code = '%s' and warehouse = '%s'" % (self.doc.item_code, w[0]))
if bin and bin[0][0]: if bin and bin[0][0]:
get_obj("Bin", bin[0][0]).update_item_valuation(sle_id = '', posting_date = '', posting_time = '') get_obj("Bin", bin[0][0]).update_entries_after(posting_date = '', posting_time = '')
# acknowledge user # acknowledge user
msgprint("Item Valuation Updated Successfully.") msgprint("Item Valuation Updated Successfully.")

View File

@@ -68,7 +68,7 @@ class DocType:
bl = sql("select name from tabBin where warehouse=%s", self.doc.name) bl = sql("select name from tabBin where warehouse=%s", self.doc.name)
for b in bl: for b in bl:
bobj = get_obj('Bin',b[0]) bobj = get_obj('Bin',b[0])
bobj.update_item_valuation(posting_date = '2000-01-01', posting_time = '12:00') bobj.update_entries_after(posting_date = '2000-01-01', posting_time = '12:00')
sql("COMMIT") sql("COMMIT")
sql("START TRANSACTION") sql("START TRANSACTION")

View File

@@ -88,7 +88,7 @@ class DocType:
bin_act_qty = flt(bin_obj.doc.actual_qty) bin_act_qty = flt(bin_obj.doc.actual_qty)
try: try:
# udpate actual qty and item valuation # udpate actual qty and item valuation
bin_obj.update_item_valuation('', '2000-01-01', '00:00') bin_obj.update_entries_after('0000-00-00', '00:00')
# get bin qty # get bin qty
qty_dict = self.get_bin_qty(bin_obj.doc.warehouse, bin_obj.doc.item_code) qty_dict = self.get_bin_qty(bin_obj.doc.warehouse, bin_obj.doc.item_code)