fixes to valuation control
This commit is contained in:
parent
612efe843b
commit
09dba5cf1d
@ -1,81 +1,113 @@
|
|||||||
# Please edit this list and import only required elements
|
# Please edit this list and import only required elements
|
||||||
import webnotes
|
import webnotes, unittest
|
||||||
|
|
||||||
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 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.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
|
class TestValuationControl(unittest.TestCase):
|
||||||
sql = webnotes.conn.sql
|
def setUp(self):
|
||||||
get_value = webnotes.conn.get_value
|
webnotes.conn.begin()
|
||||||
in_transaction = webnotes.conn.in_transaction
|
|
||||||
convert_to_lists = webnotes.conn.convert_to_lists
|
def tearDown(self):
|
||||||
|
webnotes.conn.rollback()
|
||||||
|
|
||||||
|
def test_fifo_rate(self):
|
||||||
|
"""test fifo rate"""
|
||||||
|
fcfs_stack = [[40,500.0], [12,400.0]]
|
||||||
|
self.assertTrue(DocType(None, None).get_fifo_rate(fcfs_stack)==((40*500.0 + 12*400.0)/52.0))
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------------------
|
def test_serial_no_value(self):
|
||||||
|
"""test serial no value"""
|
||||||
|
from webnotes.model.doc import Document
|
||||||
|
|
||||||
|
Document(fielddata = {
|
||||||
|
'doctype': 'Item',
|
||||||
|
'docstatus': 0,
|
||||||
|
'name': 'it',
|
||||||
|
'item_name': 'it',
|
||||||
|
'item_code': 'it',
|
||||||
|
'item_group': 'Default',
|
||||||
|
'is_stock_item': 'Yes',
|
||||||
|
'has_serial_no': 'Yes',
|
||||||
|
'stock_uom': 'Nos',
|
||||||
|
'is_sales_item': 'Yes',
|
||||||
|
'is_purchase_item': 'Yes',
|
||||||
|
'is_service_item': 'No',
|
||||||
|
'is_sub_contracted_item': 'No',
|
||||||
|
'is_pro_applicable': 'Yes',
|
||||||
|
'is_manufactured_item': 'Yes'
|
||||||
|
}).save(1)
|
||||||
|
|
||||||
|
s1 = Document(fielddata= {
|
||||||
|
'doctype':'Serial No',
|
||||||
|
'serial_no':'s1',
|
||||||
|
'item_code':'it',
|
||||||
|
'purchase_rate': 100.0
|
||||||
|
})
|
||||||
|
s2 = Document(fielddata = s1.fields.copy())
|
||||||
|
s3 = Document(fielddata = s1.fields.copy())
|
||||||
|
s4 = Document(fielddata = s1.fields.copy())
|
||||||
|
s1.save(1)
|
||||||
|
s2.purchase_rate = 120.0
|
||||||
|
s2.serial_no = 's2'
|
||||||
|
s2.save(1)
|
||||||
|
s3.purchase_rate = 130.0
|
||||||
|
s3.serial_no = 's3'
|
||||||
|
s3.save(1)
|
||||||
|
s4.purchase_rate = 150.0
|
||||||
|
s4.serial_no = 's4'
|
||||||
|
s4.save(1)
|
||||||
|
|
||||||
|
r = DocType(None, None).get_serializable_inventory_rate('s1,s2,s3')
|
||||||
|
self.assertTrue(flt(r) - (100.0+120.0+130.0)/3 < 0.0001)
|
||||||
|
|
||||||
|
|
||||||
class DocType:
|
class DocType:
|
||||||
def __init__(self, d, dl):
|
def __init__(self, d, dl):
|
||||||
self.doc, self.doclist = d, dl
|
self.doc, self.doclist = d, dl
|
||||||
|
|
||||||
# Get FIFO Rate from Stack
|
def get_fifo_rate(self, fcfs_stack):
|
||||||
# -------------------------
|
"""get FIFO (average) Rate from Stack"""
|
||||||
def get_fifo_rate(self, fcfs_stack, qty):
|
if not fcfs_stack:
|
||||||
fcfs_val = 0
|
return 0.0
|
||||||
withdraw = flt(qty)
|
|
||||||
while withdraw:
|
total = sum(f[0] for f in fcfs_stack)
|
||||||
batch = fcfs_stack[0]
|
if not total:
|
||||||
if batch[0] <= withdraw:
|
return 0.0
|
||||||
# not enough or exactly same qty in current batch, clear batch
|
|
||||||
withdraw -= batch[0]
|
return sum(f[0] * f[1] for f in fcfs_stack) / total
|
||||||
fcfs_val += (flt(batch[0]) * flt(batch[1]))
|
|
||||||
fcfs_stack.pop(0)
|
|
||||||
else:
|
|
||||||
# all from current batch
|
|
||||||
fcfs_val += (flt(withdraw) * flt(batch[1]))
|
|
||||||
batch[0] -= withdraw
|
|
||||||
withdraw = 0
|
|
||||||
fcfs_rate = flt(fcfs_val) / flt(qty)
|
|
||||||
return fcfs_rate
|
|
||||||
|
|
||||||
# --------------------------------
|
|
||||||
# get serializable inventory rate
|
|
||||||
# --------------------------------
|
|
||||||
def get_serializable_inventory_rate(self, serial_no):
|
def get_serializable_inventory_rate(self, serial_no):
|
||||||
|
"""get average value of serial numbers"""
|
||||||
|
|
||||||
sr_nos = get_obj("Stock Ledger").get_sr_no_list(serial_no)
|
sr_nos = get_obj("Stock Ledger").get_sr_no_list(serial_no)
|
||||||
tot = 0
|
return webnotes.conn.sql("""select avg(ifnull(purchase_rate, 0))
|
||||||
for s in sr_nos:
|
from `tabSerial No` where name in ("%s")""" % '", "'.join(sr_nos))[0][0] or 0.0
|
||||||
serial_no = s.strip()
|
|
||||||
tot += flt(get_value('Serial No', serial_no, 'purchase_rate'))
|
|
||||||
return tot / len(sr_nos)
|
|
||||||
|
|
||||||
|
|
||||||
# ---------------------
|
|
||||||
# get valuation method
|
|
||||||
# ---------------------
|
|
||||||
def get_valuation_method(self, item_code):
|
def get_valuation_method(self, item_code):
|
||||||
|
"""get valuation method from item or default"""
|
||||||
val_method = webnotes.conn.get_value('Item', item_code, 'valuation_method')
|
val_method = webnotes.conn.get_value('Item', item_code, 'valuation_method')
|
||||||
if not val_method:
|
if not val_method:
|
||||||
|
from webnotes.utils import get_defaults
|
||||||
val_method = get_defaults().get('valuation_method', 'FIFO')
|
val_method = get_defaults().get('valuation_method', 'FIFO')
|
||||||
return val_method
|
return val_method
|
||||||
|
|
||||||
|
|
||||||
# Get Incoming Rate based on valuation method
|
|
||||||
# --------------------------------------------
|
|
||||||
def get_incoming_rate(self, posting_date, posting_time, item, warehouse, qty = 0, serial_no = ''):
|
def get_incoming_rate(self, posting_date, posting_time, item, warehouse, qty = 0, serial_no = ''):
|
||||||
|
"""Get Incoming Rate based on valuation method"""
|
||||||
in_rate = 0
|
in_rate = 0
|
||||||
val_method = self.get_valuation_method(item)
|
val_method = self.get_valuation_method(item)
|
||||||
bin_obj = get_obj('Warehouse',warehouse).get_bin(item)
|
bin_obj = get_obj('Warehouse',warehouse).get_bin(item)
|
||||||
if serial_no:
|
if serial_no:
|
||||||
in_rate = self.get_serializable_inventory_rate(serial_no)
|
in_rate = self.get_serializable_inventory_rate(serial_no)
|
||||||
elif val_method == 'FIFO':
|
elif val_method == 'FIFO':
|
||||||
in_rate = 0
|
# get rate based on the last item value?
|
||||||
if qty:
|
if qty:
|
||||||
prev_sle = bin_obj.get_prev_sle(posting_date, posting_time)
|
prev_sle = bin_obj.get_prev_sle(posting_date, posting_time)
|
||||||
fcfs_stack = eval(prev_sle.get('fcfs_stack', '[]') or '[]')
|
if not prev_sle:
|
||||||
|
return 0.0
|
||||||
|
fcfs_stack = eval(prev_sle.get('fcfs_stack', '[]'))
|
||||||
in_rate = fcfs_stack and self.get_fifo_rate(fcfs_stack, qty) or 0
|
in_rate = fcfs_stack and self.get_fifo_rate(fcfs_stack, qty) or 0
|
||||||
elif val_method == 'Moving Average':
|
elif val_method == 'Moving Average':
|
||||||
prev_sle = bin_obj.get_prev_sle(posting_date, posting_time)
|
prev_sle = bin_obj.get_prev_sle(posting_date, posting_time)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user