trytond-patches/product_cost_fifo-Use-all-m...

190 lines
8.3 KiB
Diff

From eaae8d1ba4909042e276065d106c47e9117b2a13 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C3=80ngel=20=C3=80lvarez?= <angel@nan-tic.com>
Date: Thu, 8 Apr 2021 10:40:42 +0200
Subject: [PATCH] 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
product_cost_fifo: Keep last cost price when quantity is zero
When there is no quantity in stock, we keep the last cost price instead of
setting it to zero. This gives the same behavior between on move computation
and on product recomputation.
issue9443
---
product.py | 41 +++++++++++--------
...product_cost_fifo_recompute_cost_price.rst | 23 +++++++----
2 files changed, 38 insertions(+), 26 deletions(-)
diff --git a/product.py b/product.py
index 0c204bd..b7e25bb 100644
--- a/trytond/trytond/modules/product_cost_fifo/product.py
+++ b/trytond/trytond/modules/product_cost_fifo/product.py
@@ -30,7 +30,7 @@ class Product(metaclass=PoolMeta):
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:
@@ -134,11 +134,10 @@ class Product(metaclass=PoolMeta):
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(
@@ -149,12 +148,15 @@ class Product(metaclass=PoolMeta):
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 (cost_price / Decimal(str(consumed_qty))).quantize(
@@ -189,7 +191,7 @@ class Product(metaclass=PoolMeta):
- (fifo_cost_price * current_out_qty))
/ quantity)
else:
- cost_price = Decimal(0)
+ cost_price = current_cost_price
current_cost_price = cost_price.quantize(
Decimal(str(10.0 ** -digits[1])))
current_moves.clear()
@@ -201,12 +203,15 @@ class Product(metaclass=PoolMeta):
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)
@@ -215,7 +220,7 @@ class Product(metaclass=PoolMeta):
cost_price = unit_price
current_cost_price = cost_price.quantize(
Decimal(str(10.0 ** -digits[1])))
- else:
+ elif out_move(move):
current_out_qty += -qty
quantity += qty
diff --git a/tests/scenario_product_cost_fifo_recompute_cost_price.rst b/tests/scenario_product_cost_fifo_recompute_cost_price.rst
index f8b952f..ff76174 100644
--- 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 @@ Get stock locations::
>>> 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 @@ Create some moves::
... 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 @@ Create some moves::
... 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,12 @@ Recompute cost price::
>>> 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.9999')
+ Decimal('99.9998')
+
Recompute cost price from a date::
@@ -119,8 +126,8 @@ Recompute cost price from a date::
>>> 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.9999')
+ Decimal('99.9998')
--
2.25.1