# HG changeset patch # User Cédric Krier 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')