mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-03 04:09:11 +00:00
fix: maintain FIFO queue even if outgoing_rate is not found (#30560)
This commit is contained in:
@@ -60,9 +60,9 @@ class TestFIFOValuation(unittest.TestCase):
|
|||||||
self.queue.remove_stock(1, 5)
|
self.queue.remove_stock(1, 5)
|
||||||
self.assertEqual(self.queue, [[-1, 5]])
|
self.assertEqual(self.queue, [[-1, 5]])
|
||||||
|
|
||||||
# XXX
|
self.queue.remove_stock(1)
|
||||||
self.queue.remove_stock(1, 10)
|
|
||||||
self.assertTotalQty(-2)
|
self.assertTotalQty(-2)
|
||||||
|
self.assertEqual(self.queue, [[-2, 5]])
|
||||||
|
|
||||||
self.queue.add_stock(2, 10)
|
self.queue.add_stock(2, 10)
|
||||||
self.assertTotalQty(0)
|
self.assertTotalQty(0)
|
||||||
@@ -93,7 +93,7 @@ class TestFIFOValuation(unittest.TestCase):
|
|||||||
self.queue.remove_stock(3, 20)
|
self.queue.remove_stock(3, 20)
|
||||||
self.assertEqual(self.queue, [[1, 10], [5, 20]])
|
self.assertEqual(self.queue, [[1, 10], [5, 20]])
|
||||||
|
|
||||||
def test_collapsing_of_queue(self):
|
def test_queue_with_unknown_rate(self):
|
||||||
self.queue.add_stock(1, 1)
|
self.queue.add_stock(1, 1)
|
||||||
self.queue.add_stock(1, 2)
|
self.queue.add_stock(1, 2)
|
||||||
self.queue.add_stock(1, 3)
|
self.queue.add_stock(1, 3)
|
||||||
@@ -102,8 +102,7 @@ class TestFIFOValuation(unittest.TestCase):
|
|||||||
self.assertTotalValue(10)
|
self.assertTotalValue(10)
|
||||||
|
|
||||||
self.queue.remove_stock(3, 1)
|
self.queue.remove_stock(3, 1)
|
||||||
# XXX
|
self.assertEqual(self.queue, [[1, 4]])
|
||||||
self.assertEqual(self.queue, [[1, 7]])
|
|
||||||
|
|
||||||
def test_rounding_off(self):
|
def test_rounding_off(self):
|
||||||
self.queue.add_stock(1.0, 1.0)
|
self.queue.add_stock(1.0, 1.0)
|
||||||
@@ -172,6 +171,32 @@ class TestFIFOValuation(unittest.TestCase):
|
|||||||
self.assertTotalQty(total_qty)
|
self.assertTotalQty(total_qty)
|
||||||
self.assertTotalValue(total_value)
|
self.assertTotalValue(total_value)
|
||||||
|
|
||||||
|
@given(stock_queue_generator, st.floats(min_value=0.1, max_value=1e6))
|
||||||
|
def test_fifo_qty_value_nonneg_hypothesis_with_outgoing_rate(self, stock_queue, outgoing_rate):
|
||||||
|
self.queue = FIFOValuation([])
|
||||||
|
total_qty = 0.0
|
||||||
|
total_value = 0.0
|
||||||
|
|
||||||
|
for qty, rate in stock_queue:
|
||||||
|
# don't allow negative stock
|
||||||
|
if qty == 0 or total_qty + qty < 0 or abs(qty) < 0.1:
|
||||||
|
continue
|
||||||
|
if qty > 0:
|
||||||
|
self.queue.add_stock(qty, rate)
|
||||||
|
total_qty += qty
|
||||||
|
total_value += qty * rate
|
||||||
|
else:
|
||||||
|
qty = abs(qty)
|
||||||
|
consumed = self.queue.remove_stock(qty, outgoing_rate)
|
||||||
|
self.assertAlmostEqual(
|
||||||
|
qty, sum(q for q, _ in consumed), msg=f"incorrect consumption {consumed}"
|
||||||
|
)
|
||||||
|
total_qty -= qty
|
||||||
|
total_value -= sum(q * r for q, r in consumed)
|
||||||
|
self.assertTotalQty(total_qty)
|
||||||
|
self.assertTotalValue(total_value)
|
||||||
|
self.assertGreaterEqual(total_value, 0)
|
||||||
|
|
||||||
|
|
||||||
class TestLIFOValuation(unittest.TestCase):
|
class TestLIFOValuation(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|||||||
@@ -60,9 +60,7 @@ class FIFOValuation(BinWiseValuation):
|
|||||||
|
|
||||||
# specifying the attributes to save resources
|
# specifying the attributes to save resources
|
||||||
# ref: https://docs.python.org/3/reference/datamodel.html#slots
|
# ref: https://docs.python.org/3/reference/datamodel.html#slots
|
||||||
__slots__ = [
|
__slots__ = ["queue"]
|
||||||
"queue",
|
|
||||||
]
|
|
||||||
|
|
||||||
def __init__(self, state: Optional[List[StockBin]]):
|
def __init__(self, state: Optional[List[StockBin]]):
|
||||||
self.queue: List[StockBin] = state if state is not None else []
|
self.queue: List[StockBin] = state if state is not None else []
|
||||||
@@ -123,15 +121,9 @@ class FIFOValuation(BinWiseValuation):
|
|||||||
index = idx
|
index = idx
|
||||||
break
|
break
|
||||||
|
|
||||||
# If no entry found with outgoing rate, collapse queue
|
# If no entry found with outgoing rate, consume as per FIFO
|
||||||
if index is None: # nosemgrep
|
if index is None: # nosemgrep
|
||||||
new_stock_value = sum(d[QTY] * d[RATE] for d in self.queue) - qty * outgoing_rate
|
index = 0
|
||||||
new_stock_qty = sum(d[QTY] for d in self.queue) - qty
|
|
||||||
self.queue = [
|
|
||||||
[new_stock_qty, new_stock_value / new_stock_qty if new_stock_qty > 0 else outgoing_rate]
|
|
||||||
]
|
|
||||||
consumed_bins.append([qty, outgoing_rate])
|
|
||||||
break
|
|
||||||
else:
|
else:
|
||||||
index = 0
|
index = 0
|
||||||
|
|
||||||
@@ -172,9 +164,7 @@ class LIFOValuation(BinWiseValuation):
|
|||||||
|
|
||||||
# specifying the attributes to save resources
|
# specifying the attributes to save resources
|
||||||
# ref: https://docs.python.org/3/reference/datamodel.html#slots
|
# ref: https://docs.python.org/3/reference/datamodel.html#slots
|
||||||
__slots__ = [
|
__slots__ = ["stack"]
|
||||||
"stack",
|
|
||||||
]
|
|
||||||
|
|
||||||
def __init__(self, state: Optional[List[StockBin]]):
|
def __init__(self, state: Optional[List[StockBin]]):
|
||||||
self.stack: List[StockBin] = state if state is not None else []
|
self.stack: List[StockBin] = state if state is not None else []
|
||||||
|
|||||||
Reference in New Issue
Block a user