* feat: Added valuation of quantity for each age group in stock ageing report (cherry picked from commit2f80c4dee5) * fix: Test case for ageing report (cherry picked from commit839b79ffd0) * fix: Fixed more test cases (cherry picked from commitf996f71d16) * fix: Fixed final test case (cherry picked from commit1f2d7da426) * test: Valuation of ageing stock (cherry picked from commitdbb572eec1) --------- Co-authored-by: Mihir Kandoi <kandoimihir@gmail.com>
This commit is contained in:
@@ -89,18 +89,22 @@ def get_average_age(fifo_queue: list, to_date: str) -> float:
|
|||||||
|
|
||||||
def get_range_age(filters: Filters, fifo_queue: list, to_date: str, item_dict: dict) -> list:
|
def get_range_age(filters: Filters, fifo_queue: list, to_date: str, item_dict: dict) -> list:
|
||||||
precision = cint(frappe.db.get_single_value("System Settings", "float_precision", cache=True))
|
precision = cint(frappe.db.get_single_value("System Settings", "float_precision", cache=True))
|
||||||
range_values = [0.0] * (len(filters.ranges) + 1)
|
range_values = [0.0] * ((len(filters.ranges) * 2) + 2)
|
||||||
|
|
||||||
for item in fifo_queue:
|
for item in fifo_queue:
|
||||||
age = flt(date_diff(to_date, item[1]))
|
age = flt(date_diff(to_date, item[1]))
|
||||||
qty = flt(item[0]) if not item_dict["has_serial_no"] else 1.0
|
qty = flt(item[0]) if not item_dict["has_serial_no"] else 1.0
|
||||||
|
stock_value = flt(item[2])
|
||||||
|
|
||||||
for i, age_limit in enumerate(filters.ranges):
|
for i, age_limit in enumerate(filters.ranges):
|
||||||
if age <= flt(age_limit):
|
if age <= flt(age_limit):
|
||||||
|
i *= 2
|
||||||
range_values[i] = flt(range_values[i] + qty, precision)
|
range_values[i] = flt(range_values[i] + qty, precision)
|
||||||
|
range_values[i + 1] = flt(range_values[i + 1] + stock_value, precision)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
range_values[-1] = flt(range_values[-1] + qty, precision)
|
range_values[-2] = flt(range_values[-2] + qty, precision)
|
||||||
|
range_values[-1] = flt(range_values[-1] + stock_value, precision)
|
||||||
|
|
||||||
return range_values
|
return range_values
|
||||||
|
|
||||||
@@ -199,6 +203,7 @@ def setup_ageing_columns(filters: Filters, range_columns: list):
|
|||||||
for i, label in enumerate(ranges):
|
for i, label in enumerate(ranges):
|
||||||
fieldname = "range" + str(i + 1)
|
fieldname = "range" + str(i + 1)
|
||||||
add_column(range_columns, label=_("Age ({0})").format(label), fieldname=fieldname)
|
add_column(range_columns, label=_("Age ({0})").format(label), fieldname=fieldname)
|
||||||
|
add_column(range_columns, label=_("Value ({0})").format(label), fieldname=fieldname + "value")
|
||||||
|
|
||||||
|
|
||||||
def add_column(range_columns: list, label: str, fieldname: str, fieldtype: str = "Float", width: int = 140):
|
def add_column(range_columns: list, label: str, fieldname: str, fieldtype: str = "Float", width: int = 140):
|
||||||
@@ -298,16 +303,22 @@ class FIFOSlots:
|
|||||||
# neutralize 0/negative stock by adding positive stock
|
# neutralize 0/negative stock by adding positive stock
|
||||||
fifo_queue[0][0] += flt(row.actual_qty)
|
fifo_queue[0][0] += flt(row.actual_qty)
|
||||||
fifo_queue[0][1] = row.posting_date
|
fifo_queue[0][1] = row.posting_date
|
||||||
|
fifo_queue[0][2] += flt(row.stock_value_difference)
|
||||||
else:
|
else:
|
||||||
fifo_queue.append([flt(row.actual_qty), row.posting_date])
|
fifo_queue.append(
|
||||||
|
[flt(row.actual_qty), row.posting_date, flt(row.stock_value_difference)]
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
valuation = row.stock_value_difference / row.actual_qty
|
||||||
for serial_no in serial_nos:
|
for serial_no in serial_nos:
|
||||||
if self.serial_no_batch_purchase_details.get(serial_no):
|
if self.serial_no_batch_purchase_details.get(serial_no):
|
||||||
fifo_queue.append([serial_no, self.serial_no_batch_purchase_details.get(serial_no)])
|
fifo_queue.append(
|
||||||
|
[serial_no, self.serial_no_batch_purchase_details.get(serial_no), valuation]
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
self.serial_no_batch_purchase_details.setdefault(serial_no, row.posting_date)
|
self.serial_no_batch_purchase_details.setdefault(serial_no, row.posting_date)
|
||||||
fifo_queue.append([serial_no, row.posting_date])
|
fifo_queue.append([serial_no, row.posting_date, valuation])
|
||||||
|
|
||||||
def __compute_outgoing_stock(self, row: dict, fifo_queue: list, transfer_key: tuple, serial_nos: list):
|
def __compute_outgoing_stock(self, row: dict, fifo_queue: list, transfer_key: tuple, serial_nos: list):
|
||||||
"Update FIFO Queue on outward stock."
|
"Update FIFO Queue on outward stock."
|
||||||
@@ -316,34 +327,44 @@ class FIFOSlots:
|
|||||||
return
|
return
|
||||||
|
|
||||||
qty_to_pop = abs(row.actual_qty)
|
qty_to_pop = abs(row.actual_qty)
|
||||||
|
stock_value = abs(row.stock_value_difference)
|
||||||
|
|
||||||
while qty_to_pop:
|
while qty_to_pop:
|
||||||
slot = fifo_queue[0] if fifo_queue else [0, None]
|
slot = fifo_queue[0] if fifo_queue else [0, None, 0]
|
||||||
if 0 < flt(slot[0]) <= qty_to_pop:
|
if 0 < flt(slot[0]) <= qty_to_pop:
|
||||||
# qty to pop >= slot qty
|
# qty to pop >= slot qty
|
||||||
# if +ve and not enough or exactly same balance in current slot, consume whole slot
|
# if +ve and not enough or exactly same balance in current slot, consume whole slot
|
||||||
qty_to_pop -= flt(slot[0])
|
qty_to_pop -= flt(slot[0])
|
||||||
|
stock_value -= flt(slot[2])
|
||||||
self.transferred_item_details[transfer_key].append(fifo_queue.pop(0))
|
self.transferred_item_details[transfer_key].append(fifo_queue.pop(0))
|
||||||
elif not fifo_queue:
|
elif not fifo_queue:
|
||||||
# negative stock, no balance but qty yet to consume
|
# negative stock, no balance but qty yet to consume
|
||||||
fifo_queue.append([-(qty_to_pop), row.posting_date])
|
fifo_queue.append([-(qty_to_pop), row.posting_date, -(stock_value)])
|
||||||
self.transferred_item_details[transfer_key].append([qty_to_pop, row.posting_date])
|
self.transferred_item_details[transfer_key].append(
|
||||||
|
[qty_to_pop, row.posting_date, stock_value]
|
||||||
|
)
|
||||||
qty_to_pop = 0
|
qty_to_pop = 0
|
||||||
|
stock_value = 0
|
||||||
else:
|
else:
|
||||||
# qty to pop < slot qty, ample balance
|
# qty to pop < slot qty, ample balance
|
||||||
# consume actual_qty from first slot
|
# consume actual_qty from first slot
|
||||||
slot[0] = flt(slot[0]) - qty_to_pop
|
slot[0] = flt(slot[0]) - qty_to_pop
|
||||||
self.transferred_item_details[transfer_key].append([qty_to_pop, slot[1]])
|
slot[2] = flt(slot[2]) - stock_value
|
||||||
|
self.transferred_item_details[transfer_key].append([qty_to_pop, slot[1], stock_value])
|
||||||
qty_to_pop = 0
|
qty_to_pop = 0
|
||||||
|
stock_value = 0
|
||||||
|
|
||||||
def __adjust_incoming_transfer_qty(self, transfer_data: dict, fifo_queue: list, row: dict):
|
def __adjust_incoming_transfer_qty(self, transfer_data: dict, fifo_queue: list, row: dict):
|
||||||
"Add previously removed stock back to FIFO Queue."
|
"Add previously removed stock back to FIFO Queue."
|
||||||
transfer_qty_to_pop = flt(row.actual_qty)
|
transfer_qty_to_pop = flt(row.actual_qty)
|
||||||
|
stock_value = flt(row.stock_value_difference)
|
||||||
|
|
||||||
def add_to_fifo_queue(slot):
|
def add_to_fifo_queue(slot):
|
||||||
if fifo_queue and flt(fifo_queue[0][0]) <= 0:
|
if fifo_queue and flt(fifo_queue[0][0]) <= 0:
|
||||||
# neutralize 0/negative stock by adding positive stock
|
# neutralize 0/negative stock by adding positive stock
|
||||||
fifo_queue[0][0] += flt(slot[0])
|
fifo_queue[0][0] += flt(slot[0])
|
||||||
fifo_queue[0][1] = slot[1]
|
fifo_queue[0][1] = slot[1]
|
||||||
|
fifo_queue[0][2] += flt(slot[2])
|
||||||
else:
|
else:
|
||||||
fifo_queue.append(slot)
|
fifo_queue.append(slot)
|
||||||
|
|
||||||
@@ -351,16 +372,20 @@ class FIFOSlots:
|
|||||||
if transfer_data and 0 < transfer_data[0][0] <= transfer_qty_to_pop:
|
if transfer_data and 0 < transfer_data[0][0] <= transfer_qty_to_pop:
|
||||||
# bucket qty is not enough, consume whole
|
# bucket qty is not enough, consume whole
|
||||||
transfer_qty_to_pop -= transfer_data[0][0]
|
transfer_qty_to_pop -= transfer_data[0][0]
|
||||||
|
stock_value -= transfer_data[0][2]
|
||||||
add_to_fifo_queue(transfer_data.pop(0))
|
add_to_fifo_queue(transfer_data.pop(0))
|
||||||
elif not transfer_data:
|
elif not transfer_data:
|
||||||
# transfer bucket is empty, extra incoming qty
|
# transfer bucket is empty, extra incoming qty
|
||||||
add_to_fifo_queue([transfer_qty_to_pop, row.posting_date])
|
add_to_fifo_queue([transfer_qty_to_pop, row.posting_date, stock_value])
|
||||||
transfer_qty_to_pop = 0
|
transfer_qty_to_pop = 0
|
||||||
|
stock_value = 0
|
||||||
else:
|
else:
|
||||||
# ample bucket qty to consume
|
# ample bucket qty to consume
|
||||||
transfer_data[0][0] -= transfer_qty_to_pop
|
transfer_data[0][0] -= transfer_qty_to_pop
|
||||||
add_to_fifo_queue([transfer_qty_to_pop, transfer_data[0][1]])
|
transfer_data[0][2] -= stock_value
|
||||||
|
add_to_fifo_queue([transfer_qty_to_pop, transfer_data[0][1], stock_value])
|
||||||
transfer_qty_to_pop = 0
|
transfer_qty_to_pop = 0
|
||||||
|
stock_value = 0
|
||||||
|
|
||||||
def __update_balances(self, row: dict, key: tuple | str):
|
def __update_balances(self, row: dict, key: tuple | str):
|
||||||
self.item_details[key]["qty_after_transaction"] = row.qty_after_transaction
|
self.item_details[key]["qty_after_transaction"] = row.qty_after_transaction
|
||||||
@@ -412,6 +437,7 @@ class FIFOSlots:
|
|||||||
item.stock_uom,
|
item.stock_uom,
|
||||||
item.has_serial_no,
|
item.has_serial_no,
|
||||||
sle.actual_qty,
|
sle.actual_qty,
|
||||||
|
sle.stock_value_difference,
|
||||||
sle.posting_date,
|
sle.posting_date,
|
||||||
sle.voucher_type,
|
sle.voucher_type,
|
||||||
sle.voucher_no,
|
sle.voucher_no,
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=30,
|
actual_qty=30,
|
||||||
qty_after_transaction=30,
|
qty_after_transaction=30,
|
||||||
|
stock_value_difference=30,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-01",
|
posting_date="2021-12-01",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -29,6 +30,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=20,
|
actual_qty=20,
|
||||||
qty_after_transaction=50,
|
qty_after_transaction=50,
|
||||||
|
stock_value_difference=20,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-02",
|
posting_date="2021-12-02",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -40,6 +42,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=(-10),
|
actual_qty=(-10),
|
||||||
qty_after_transaction=40,
|
qty_after_transaction=40,
|
||||||
|
stock_value_difference=(-10),
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-03",
|
posting_date="2021-12-03",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -57,6 +60,8 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
|
|
||||||
self.assertEqual(result["qty_after_transaction"], result["total_qty"])
|
self.assertEqual(result["qty_after_transaction"], result["total_qty"])
|
||||||
self.assertEqual(queue[0][0], 20.0)
|
self.assertEqual(queue[0][0], 20.0)
|
||||||
|
data = format_report_data(self.filters, slots, self.filters["to_date"])
|
||||||
|
self.assertEqual(data[0][8], 40.0) # valuating for stock value between age 0-30
|
||||||
|
|
||||||
def test_insufficient_balance(self):
|
def test_insufficient_balance(self):
|
||||||
"Reference: Case 3 in stock_ageing_fifo_logic.md (same wh)"
|
"Reference: Case 3 in stock_ageing_fifo_logic.md (same wh)"
|
||||||
@@ -65,6 +70,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=(-30),
|
actual_qty=(-30),
|
||||||
qty_after_transaction=(-30),
|
qty_after_transaction=(-30),
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-01",
|
posting_date="2021-12-01",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -76,6 +82,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=20,
|
actual_qty=20,
|
||||||
qty_after_transaction=(-10),
|
qty_after_transaction=(-10),
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-02",
|
posting_date="2021-12-02",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -87,6 +94,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=20,
|
actual_qty=20,
|
||||||
qty_after_transaction=10,
|
qty_after_transaction=10,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-03",
|
posting_date="2021-12-03",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -98,6 +106,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=10,
|
actual_qty=10,
|
||||||
qty_after_transaction=20,
|
qty_after_transaction=20,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-03",
|
posting_date="2021-12-03",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -126,6 +135,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=30,
|
actual_qty=30,
|
||||||
qty_after_transaction=30,
|
qty_after_transaction=30,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-01",
|
posting_date="2021-12-01",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -137,6 +147,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=0,
|
actual_qty=0,
|
||||||
qty_after_transaction=50,
|
qty_after_transaction=50,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-02",
|
posting_date="2021-12-02",
|
||||||
voucher_type="Stock Reconciliation",
|
voucher_type="Stock Reconciliation",
|
||||||
@@ -148,6 +159,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=(-10),
|
actual_qty=(-10),
|
||||||
qty_after_transaction=40,
|
qty_after_transaction=40,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-03",
|
posting_date="2021-12-03",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -178,6 +190,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=0,
|
actual_qty=0,
|
||||||
qty_after_transaction=1000,
|
qty_after_transaction=1000,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-01",
|
posting_date="2021-12-01",
|
||||||
voucher_type="Stock Reconciliation",
|
voucher_type="Stock Reconciliation",
|
||||||
@@ -189,6 +202,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=0,
|
actual_qty=0,
|
||||||
qty_after_transaction=400,
|
qty_after_transaction=400,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-02",
|
posting_date="2021-12-02",
|
||||||
voucher_type="Stock Reconciliation",
|
voucher_type="Stock Reconciliation",
|
||||||
@@ -200,6 +214,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=(-10),
|
actual_qty=(-10),
|
||||||
qty_after_transaction=390,
|
qty_after_transaction=390,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-03",
|
posting_date="2021-12-03",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -233,6 +248,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=0,
|
actual_qty=0,
|
||||||
qty_after_transaction=1000,
|
qty_after_transaction=1000,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-01",
|
posting_date="2021-12-01",
|
||||||
voucher_type="Stock Reconciliation",
|
voucher_type="Stock Reconciliation",
|
||||||
@@ -244,6 +260,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=0,
|
actual_qty=0,
|
||||||
qty_after_transaction=400,
|
qty_after_transaction=400,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 2",
|
warehouse="WH 2",
|
||||||
posting_date="2021-12-02",
|
posting_date="2021-12-02",
|
||||||
voucher_type="Stock Reconciliation",
|
voucher_type="Stock Reconciliation",
|
||||||
@@ -255,6 +272,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=(-10),
|
actual_qty=(-10),
|
||||||
qty_after_transaction=990,
|
qty_after_transaction=990,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-03",
|
posting_date="2021-12-03",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -301,6 +319,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=500,
|
actual_qty=500,
|
||||||
qty_after_transaction=500,
|
qty_after_transaction=500,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-03",
|
posting_date="2021-12-03",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -312,6 +331,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=(-50),
|
actual_qty=(-50),
|
||||||
qty_after_transaction=450,
|
qty_after_transaction=450,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-04",
|
posting_date="2021-12-04",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -323,6 +343,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=(-50),
|
actual_qty=(-50),
|
||||||
qty_after_transaction=400,
|
qty_after_transaction=400,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-04",
|
posting_date="2021-12-04",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -334,6 +355,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=100,
|
actual_qty=100,
|
||||||
qty_after_transaction=500,
|
qty_after_transaction=500,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-04",
|
posting_date="2021-12-04",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -370,6 +392,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=500,
|
actual_qty=500,
|
||||||
qty_after_transaction=500,
|
qty_after_transaction=500,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-03",
|
posting_date="2021-12-03",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -381,6 +404,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=(-100),
|
actual_qty=(-100),
|
||||||
qty_after_transaction=400,
|
qty_after_transaction=400,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-04",
|
posting_date="2021-12-04",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -392,6 +416,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=50,
|
actual_qty=50,
|
||||||
qty_after_transaction=450,
|
qty_after_transaction=450,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-04",
|
posting_date="2021-12-04",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -426,6 +451,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=20,
|
actual_qty=20,
|
||||||
qty_after_transaction=20,
|
qty_after_transaction=20,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-03",
|
posting_date="2021-12-03",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -437,6 +463,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=(-50),
|
actual_qty=(-50),
|
||||||
qty_after_transaction=(-30),
|
qty_after_transaction=(-30),
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-04",
|
posting_date="2021-12-04",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -448,6 +475,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=(-50),
|
actual_qty=(-50),
|
||||||
qty_after_transaction=(-80),
|
qty_after_transaction=(-80),
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-04",
|
posting_date="2021-12-04",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -459,6 +487,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=50,
|
actual_qty=50,
|
||||||
qty_after_transaction=(-30),
|
qty_after_transaction=(-30),
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-04",
|
posting_date="2021-12-04",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -496,6 +525,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=500,
|
actual_qty=500,
|
||||||
qty_after_transaction=500,
|
qty_after_transaction=500,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-03",
|
posting_date="2021-12-03",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -507,6 +537,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=(-50),
|
actual_qty=(-50),
|
||||||
qty_after_transaction=450,
|
qty_after_transaction=450,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-04",
|
posting_date="2021-12-04",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -518,6 +549,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=100,
|
actual_qty=100,
|
||||||
qty_after_transaction=550,
|
qty_after_transaction=550,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-04",
|
posting_date="2021-12-04",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -553,6 +585,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=20,
|
actual_qty=20,
|
||||||
qty_after_transaction=20,
|
qty_after_transaction=20,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-03",
|
posting_date="2021-12-03",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -564,6 +597,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=(-50),
|
actual_qty=(-50),
|
||||||
qty_after_transaction=(-30),
|
qty_after_transaction=(-30),
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-04",
|
posting_date="2021-12-04",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -575,6 +609,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=50,
|
actual_qty=50,
|
||||||
qty_after_transaction=20,
|
qty_after_transaction=20,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-04",
|
posting_date="2021-12-04",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -586,6 +621,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=50,
|
actual_qty=50,
|
||||||
qty_after_transaction=70,
|
qty_after_transaction=70,
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-04",
|
posting_date="2021-12-04",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -623,6 +659,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=(-50),
|
actual_qty=(-50),
|
||||||
qty_after_transaction=(-50),
|
qty_after_transaction=(-50),
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-01",
|
posting_date="2021-12-01",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -634,6 +671,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=(-50),
|
actual_qty=(-50),
|
||||||
qty_after_transaction=(-100),
|
qty_after_transaction=(-100),
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-01",
|
posting_date="2021-12-01",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -645,6 +683,7 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
name="Flask Item",
|
name="Flask Item",
|
||||||
actual_qty=30,
|
actual_qty=30,
|
||||||
qty_after_transaction=(-70),
|
qty_after_transaction=(-70),
|
||||||
|
stock_value_difference=0,
|
||||||
warehouse="WH 1",
|
warehouse="WH 1",
|
||||||
posting_date="2021-12-01",
|
posting_date="2021-12-01",
|
||||||
voucher_type="Stock Entry",
|
voucher_type="Stock Entry",
|
||||||
@@ -722,6 +761,113 @@ class TestStockAgeing(FrappeTestCase):
|
|||||||
self.assertEqual(bal_qty, 0.9)
|
self.assertEqual(bal_qty, 0.9)
|
||||||
self.assertEqual(bal_qty, range_qty_sum)
|
self.assertEqual(bal_qty, range_qty_sum)
|
||||||
|
|
||||||
|
def test_ageing_stock_valuation(self):
|
||||||
|
"Test stock valuation for each time bucket."
|
||||||
|
sle = [
|
||||||
|
frappe._dict(
|
||||||
|
name="Flask Item",
|
||||||
|
actual_qty=10,
|
||||||
|
qty_after_transaction=10,
|
||||||
|
stock_value_difference=10,
|
||||||
|
warehouse="WH 1",
|
||||||
|
posting_date="2021-12-01",
|
||||||
|
voucher_type="Stock Entry",
|
||||||
|
voucher_no="001",
|
||||||
|
has_serial_no=False,
|
||||||
|
serial_no=None,
|
||||||
|
),
|
||||||
|
frappe._dict(
|
||||||
|
name="Flask Item",
|
||||||
|
actual_qty=20,
|
||||||
|
qty_after_transaction=30,
|
||||||
|
stock_value_difference=20,
|
||||||
|
warehouse="WH 1",
|
||||||
|
posting_date="2021-12-02",
|
||||||
|
voucher_type="Stock Entry",
|
||||||
|
voucher_no="002",
|
||||||
|
has_serial_no=False,
|
||||||
|
serial_no=None,
|
||||||
|
),
|
||||||
|
frappe._dict(
|
||||||
|
name="Flask Item",
|
||||||
|
actual_qty=(-10),
|
||||||
|
qty_after_transaction=20,
|
||||||
|
stock_value_difference=(-10),
|
||||||
|
warehouse="WH 1",
|
||||||
|
posting_date="2021-12-03",
|
||||||
|
voucher_type="Stock Entry",
|
||||||
|
voucher_no="003",
|
||||||
|
has_serial_no=False,
|
||||||
|
serial_no=None,
|
||||||
|
),
|
||||||
|
frappe._dict(
|
||||||
|
name="Flask Item",
|
||||||
|
actual_qty=10,
|
||||||
|
qty_after_transaction=30,
|
||||||
|
stock_value_difference=20,
|
||||||
|
warehouse="WH 1",
|
||||||
|
posting_date="2022-01-01",
|
||||||
|
voucher_type="Stock Entry",
|
||||||
|
voucher_no="004",
|
||||||
|
has_serial_no=False,
|
||||||
|
serial_no=None,
|
||||||
|
),
|
||||||
|
frappe._dict(
|
||||||
|
name="Flask Item",
|
||||||
|
actual_qty=(-15),
|
||||||
|
qty_after_transaction=15,
|
||||||
|
stock_value_difference=(-15),
|
||||||
|
warehouse="WH 1",
|
||||||
|
posting_date="2022-01-02",
|
||||||
|
voucher_type="Stock Entry",
|
||||||
|
voucher_no="005",
|
||||||
|
has_serial_no=False,
|
||||||
|
serial_no=None,
|
||||||
|
),
|
||||||
|
frappe._dict(
|
||||||
|
name="Flask Item",
|
||||||
|
actual_qty=10,
|
||||||
|
qty_after_transaction=25,
|
||||||
|
stock_value_difference=5,
|
||||||
|
warehouse="WH 1",
|
||||||
|
posting_date="2022-02-01",
|
||||||
|
voucher_type="Stock Entry",
|
||||||
|
voucher_no="006",
|
||||||
|
has_serial_no=False,
|
||||||
|
serial_no=None,
|
||||||
|
),
|
||||||
|
frappe._dict(
|
||||||
|
name="Flask Item",
|
||||||
|
actual_qty=5,
|
||||||
|
qty_after_transaction=30,
|
||||||
|
stock_value_difference=2.5,
|
||||||
|
warehouse="WH 1",
|
||||||
|
posting_date="2022-02-02",
|
||||||
|
voucher_type="Stock Entry",
|
||||||
|
voucher_no="007",
|
||||||
|
has_serial_no=False,
|
||||||
|
serial_no=None,
|
||||||
|
),
|
||||||
|
frappe._dict(
|
||||||
|
name="Flask Item",
|
||||||
|
actual_qty=5,
|
||||||
|
qty_after_transaction=35,
|
||||||
|
stock_value_difference=15,
|
||||||
|
warehouse="WH 1",
|
||||||
|
posting_date="2022-03-01",
|
||||||
|
voucher_type="Stock Entry",
|
||||||
|
voucher_no="008",
|
||||||
|
has_serial_no=False,
|
||||||
|
serial_no=None,
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
slots = FIFOSlots(self.filters, sle).generate()
|
||||||
|
report_data = format_report_data(self.filters, slots, "2022-03-31")
|
||||||
|
range_values = report_data[0][7:15]
|
||||||
|
range_valuations = range_values[1::2]
|
||||||
|
self.assertEqual(range_valuations, [15, 7.5, 20, 5])
|
||||||
|
|
||||||
|
|
||||||
def generate_item_and_item_wh_wise_slots(filters, sle):
|
def generate_item_and_item_wh_wise_slots(filters, sle):
|
||||||
"Return results with and without 'show_warehouse_wise_stock'"
|
"Return results with and without 'show_warehouse_wise_stock'"
|
||||||
|
|||||||
Reference in New Issue
Block a user