196 lines
8.3 KiB
Diff
196 lines
8.3 KiB
Diff
|
# HG changeset patch
|
||
|
# User Cédric Krier <cedric.krier@b2ck.com>
|
||
|
Use all moves to compute FIFO
|
||
|
|
||
|
product_cost_fifo: Use all moves to compute FIFO
|
||
|
|
||
|
We must consider any incoming moves (ex: inventory) for the computation of the
|
||
|
FIFO otherwise the back computation to find first in moves does not pick enough
|
||
|
moves. As not all incoming moves have a unit price, we use the current cost
|
||
|
price as fallback.
|
||
|
Also in re-computation, the in or out move test should only rely on the storage
|
||
|
location usage in order to properly compute the average cost.
|
||
|
|
||
|
issue9274
|
||
|
|
||
|
review321471002
|
||
|
|
||
|
Index: move.py
|
||
|
===================================================================
|
||
|
--- a/trytond/trytond/modules/product_cost_fifo/move.py
|
||
|
+++ b/trytond/trytond/modules/product_cost_fifo/move.py
|
||
|
@@ -81,13 +81,15 @@
|
||
|
to_save = []
|
||
|
for move, move_qty in fifo_moves:
|
||
|
consumed_qty += move_qty
|
||
|
-
|
||
|
- with Transaction().set_context(date=move.effective_date):
|
||
|
- move_unit_price = Currency.compute(
|
||
|
- move.currency, move.unit_price,
|
||
|
- self.company.currency, round=False)
|
||
|
- move_unit_price = Uom.compute_price(move.uom, move_unit_price,
|
||
|
- move.product.default_uom)
|
||
|
+ if move.from_location.type in {'supplier', 'production'}:
|
||
|
+ with Transaction().set_context(date=move.effective_date):
|
||
|
+ move_unit_price = Currency.compute(
|
||
|
+ move.currency, move.unit_price,
|
||
|
+ self.company.currency, round=False)
|
||
|
+ move_unit_price = Uom.compute_price(
|
||
|
+ move.uom, move_unit_price, move.product.default_uom)
|
||
|
+ else:
|
||
|
+ move_unit_price = move.cost_price or 0
|
||
|
cost_price += move_unit_price * Decimal(str(move_qty))
|
||
|
|
||
|
move_qty = Uom.compute_qty(self.product.default_uom, move_qty,
|
||
|
Index: product.py
|
||
|
===================================================================
|
||
|
--- a/trytond/trytond/modules/product_cost_fifo/product.py
|
||
|
+++ b/trytond/trytond/modules/product_cost_fifo/product.py
|
||
|
@@ -31,7 +31,7 @@
|
||
|
domain = [
|
||
|
('product', '=', self.id),
|
||
|
self._domain_moves_cost(),
|
||
|
- ('from_location.type', 'in', ['supplier', 'production']),
|
||
|
+ ('from_location.type', '!=', 'storage'),
|
||
|
('to_location.type', '=', 'storage'),
|
||
|
]
|
||
|
if not date:
|
||
|
@@ -137,11 +137,10 @@
|
||
|
quantity = Decimal(str(quantity))
|
||
|
|
||
|
def in_move(move):
|
||
|
- return (move.from_location.type in ['supplier', 'production']
|
||
|
- or move.to_location.type == 'supplier')
|
||
|
+ return move.to_location.type == 'storage'
|
||
|
|
||
|
def out_move(move):
|
||
|
- return not in_move(move)
|
||
|
+ return move.from_location.type == 'storage'
|
||
|
|
||
|
def compute_fifo_cost_price(quantity, date):
|
||
|
fifo_moves = self.get_fifo_move(
|
||
|
@@ -152,12 +151,15 @@
|
||
|
consumed_qty = 0
|
||
|
for move, move_qty in fifo_moves:
|
||
|
consumed_qty += move_qty
|
||
|
- with Transaction().set_context(date=move.effective_date):
|
||
|
- unit_price = Currency.compute(
|
||
|
- move.currency, move.unit_price,
|
||
|
- move.company.currency, round=False)
|
||
|
- unit_price = Uom.compute_price(
|
||
|
- move.uom, unit_price, move.product.default_uom)
|
||
|
+ if move.from_location.type in {'supplier', 'production'}:
|
||
|
+ with Transaction().set_context(date=move.effective_date):
|
||
|
+ unit_price = Currency.compute(
|
||
|
+ move.currency, move.unit_price,
|
||
|
+ move.company.currency, round=False)
|
||
|
+ unit_price = Uom.compute_price(
|
||
|
+ move.uom, unit_price, move.product.default_uom)
|
||
|
+ else:
|
||
|
+ unit_price = move.cost_price or 0
|
||
|
cost_price += unit_price * Decimal(str(move_qty))
|
||
|
if consumed_qty:
|
||
|
return round_price(cost_price / Decimal(str(consumed_qty)))
|
||
|
@@ -204,12 +206,15 @@
|
||
|
if move.from_location.type == 'storage':
|
||
|
qty *= -1
|
||
|
if in_move(move):
|
||
|
- with Transaction().set_context(date=move.effective_date):
|
||
|
- unit_price = Currency.compute(
|
||
|
- move.currency, move.unit_price,
|
||
|
- move.company.currency, round=False)
|
||
|
- unit_price = Uom.compute_price(
|
||
|
- move.uom, unit_price, self.default_uom)
|
||
|
+ if move.from_location.type in {'supplier', 'production'}:
|
||
|
+ with Transaction().set_context(date=move.effective_date):
|
||
|
+ unit_price = Currency.compute(
|
||
|
+ move.currency, move.unit_price,
|
||
|
+ move.company.currency, round=False)
|
||
|
+ unit_price = Uom.compute_price(
|
||
|
+ move.uom, unit_price, self.default_uom)
|
||
|
+ else:
|
||
|
+ unit_price = cost_price
|
||
|
if quantity + qty > 0 and quantity >= 0:
|
||
|
cost_price = (
|
||
|
(cost_price * quantity) + (unit_price * qty)
|
||
|
@@ -217,7 +222,7 @@
|
||
|
elif qty > 0:
|
||
|
cost_price = unit_price
|
||
|
current_cost_price = round_price(cost_price)
|
||
|
- else:
|
||
|
+ elif out_move(move):
|
||
|
current_out_qty += -qty
|
||
|
quantity += qty
|
||
|
|
||
|
Index: tests/scenario_product_cost_fifo_recompute_cost_price.rst
|
||
|
===================================================================
|
||
|
--- a/trytond/trytond/modules/product_cost_fifo/tests/scenario_product_cost_fifo_recompute_cost_price.rst
|
||
|
+++ b/trytond/trytond/modules/product_cost_fifo/tests/scenario_product_cost_fifo_recompute_cost_price.rst
|
||
|
@@ -45,6 +45,7 @@
|
||
|
>>> supplier_loc, = Location.find([('code', '=', 'SUP')])
|
||
|
>>> storage_loc, = Location.find([('code', '=', 'STO')])
|
||
|
>>> customer_loc, = Location.find([('code', '=', 'CUS')])
|
||
|
+ >>> lost_found, = Location.find([('name', '=', "Lost and Found")])
|
||
|
|
||
|
Create some moves::
|
||
|
|
||
|
@@ -65,6 +66,12 @@
|
||
|
... effective_date=today - dt.timedelta(days=1)).click('do')
|
||
|
>>> StockMove(
|
||
|
... product=product,
|
||
|
+ ... quantity=1,
|
||
|
+ ... from_location=lost_found,
|
||
|
+ ... to_location=storage_loc,
|
||
|
+ ... effective_date=today - dt.timedelta(days=1)).click('do')
|
||
|
+ >>> StockMove(
|
||
|
+ ... product=product,
|
||
|
... quantity=2,
|
||
|
... from_location=storage_loc,
|
||
|
... to_location=customer_loc,
|
||
|
@@ -88,17 +95,16 @@
|
||
|
... product=product,
|
||
|
... quantity=1,
|
||
|
... from_location=storage_loc,
|
||
|
- ... to_location=customer_loc,
|
||
|
- ... unit_price=Decimal('300'),
|
||
|
+ ... to_location=lost_found,
|
||
|
... effective_date=today).click('do')
|
||
|
|
||
|
|
||
|
>>> [m.cost_price for m in StockMove.find([])]
|
||
|
- [Decimal('100.0000'), Decimal('110.0000'), Decimal('105.0000'), Decimal('110.0000'), Decimal('113.3333'), Decimal('100.0000')]
|
||
|
+ [Decimal('100.0000'), Decimal('116.6666'), Decimal('106.6666'), Decimal('110.0000'), Decimal('113.3333'), Decimal('113.3333'), Decimal('100.0000')]
|
||
|
|
||
|
>>> product.reload()
|
||
|
>>> product.cost_price
|
||
|
- Decimal('100.0000')
|
||
|
+ Decimal('99.9998')
|
||
|
|
||
|
Recompute cost price::
|
||
|
|
||
|
@@ -106,11 +112,11 @@
|
||
|
>>> recompute.execute('recompute')
|
||
|
|
||
|
>>> [m.cost_price for m in StockMove.find([])]
|
||
|
- [Decimal('106.6667'), Decimal('106.6667'), Decimal('105.0000'), Decimal('110.0000'), Decimal('113.3333'), Decimal('100.0000')]
|
||
|
+ [Decimal('111.1111'), Decimal('111.1111'), Decimal('106.6666'), Decimal('110.0000'), Decimal('113.3333'), Decimal('113.3333'), Decimal('100.0000')]
|
||
|
|
||
|
>>> product.reload()
|
||
|
>>> product.cost_price
|
||
|
- Decimal('99.9998')
|
||
|
+ Decimal('100.0000')
|
||
|
|
||
|
Recompute cost price from a date::
|
||
|
|
||
|
@@ -119,8 +125,8 @@
|
||
|
>>> recompute.execute('recompute')
|
||
|
|
||
|
>>> [m.cost_price for m in StockMove.find([])]
|
||
|
- [Decimal('106.6667'), Decimal('106.6667'), Decimal('105.0000'), Decimal('110.0000'), Decimal('113.3333'), Decimal('100.0000')]
|
||
|
+ [Decimal('111.1111'), Decimal('111.1111'), Decimal('106.6666'), Decimal('110.0000'), Decimal('113.3333'), Decimal('113.3333'), Decimal('100.0000')]
|
||
|
|
||
|
>>> product.reload()
|
||
|
>>> product.cost_price
|
||
|
- Decimal('99.9998')
|
||
|
+ Decimal('100.0000')
|