changeset b97f12a119f2 in modules/product_cost_fifo:default
details:
https://hg.tryton.org/modules/product_cost_fifo?cmd=changeset&node=b97f12a119f2
description:
Exclude quantity coming back from production the same day
This avoid to have a loop back that keeps the initial cost price of the
production in the history.
issue11265
review386101002
diffstat:
product.py | 29 ++-
tests/scenario_product_cost_fifo_recompute_cost_price_production.rst | 105
++++++++++
tests/test_product_cost_fifo.py | 5 +
3 files changed, 133 insertions(+), 6 deletions(-)
diffs (203 lines):
diff -r 356d29f8a922 -r b97f12a119f2 product.py
--- a/product.py Sat Dec 18 16:31:09 2021 +0100
+++ b/product.py Sun Mar 06 13:34:18 2022 +0100
@@ -139,6 +139,11 @@
def out_move(move):
return not in_move(move)
+ def production_move(move):
+ return (
+ move.from_location.type == 'production'
+ or move.to_location.type == 'production')
+
def compute_fifo_cost_price(quantity, date):
fifo_moves = self.get_fifo_move(float(quantity), date=date)
@@ -154,10 +159,13 @@
# in order to keep quantity positive where possible
# We do not re-browse because we expect only small changes
moves = sorted(moves, key=lambda m: (
- m.effective_date, out_move(m), m.id))
+ m.effective_date,
+ out_move(m) or (in_move(m) and production_move(m)),
+ m.id))
current_moves = []
current_out_qty = 0
current_cost_price = cost_price
+ qty_production = 0
for move in moves:
if (current_moves
and current_moves[-1].effective_date
@@ -188,6 +196,7 @@
current_cost_price = round_price(cost_price)
current_moves.clear()
current_out_qty = 0
+ qty_production = 0
current_moves.append(move)
cost_price = Revision.apply_up_to(
@@ -197,17 +206,23 @@
if out_move(move):
qty *= -1
if in_move(move):
+ in_qty = qty
+ if production_move(move) and qty_production < 0:
+ # Exclude quantity coming back from production
+ in_qty -= min(abs(qty_production), in_qty)
unit_price = move.get_cost_price(product_cost_price=cost_price)
- if quantity + qty > 0 and quantity >= 0:
+ if quantity + in_qty > 0 and quantity >= 0:
cost_price = (
- (cost_price * quantity) + (unit_price * qty)
- ) / (quantity + qty)
- elif qty > 0:
+ (cost_price * quantity) + (unit_price * in_qty)
+ ) / (quantity + in_qty)
+ elif in_qty > 0:
cost_price = unit_price
current_cost_price = round_price(cost_price)
elif out_move(move):
current_out_qty += -qty
quantity += qty
+ if production_move(move):
+ qty_production += qty
Move.write([
m for m in filter(in_move, current_moves)
@@ -224,11 +239,13 @@
m for m in out_moves
if m.cost_price != fifo_cost_price],
dict(cost_price=fifo_cost_price))
- if quantity:
+ if quantity > 0:
cost_price = (
((cost_price * (quantity + current_out_qty))
- (fifo_cost_price * current_out_qty))
/ quantity)
+ else:
+ cost_price = current_cost_price
for revision in revisions:
cost_price = revision.get_cost_price(cost_price)
return cost_price
diff -r 356d29f8a922 -r b97f12a119f2
tests/scenario_product_cost_fifo_recompute_cost_price_production.rst
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/scenario_product_cost_fifo_recompute_cost_price_production.rst
Sun Mar 06 13:34:18 2022 +0100
@@ -0,0 +1,105 @@
+=================================================
+Product Cost FIFO Recompute Cost Price Production
+=================================================
+
+Imports::
+
+ >>> import datetime as dt
+ >>> from decimal import Decimal
+
+ >>> from proteus import Model, Wizard
+ >>> from trytond.tests.tools import activate_modules
+ >>> from trytond.modules.company.tests.tools import (
+ ... create_company, get_company)
+
+ >>> today = dt.date.today()
+ >>> yesterday = today - dt.timedelta(days=1)
+
+Activate modules::
+
+ >>> config = activate_modules('product_cost_fifo')
+
+ >>> Location = Model.get('stock.location')
+ >>> ProductUom = Model.get('product.uom')
+ >>> ProductTemplate = Model.get('product.template')
+ >>> StockMove = Model.get('stock.move')
+
+Create company::
+
+ >>> _ = create_company()
+ >>> company = get_company()
+
+Create product::
+
+ >>> unit, = ProductUom.find([('name', '=', 'Unit')])
+
+ >>> template = ProductTemplate()
+ >>> template.name = 'Product'
+ >>> template.default_uom = unit
+ >>> template.type = 'goods'
+ >>> template.list_price = Decimal('50.0000')
+ >>> template.cost_price_method = 'fifo'
+ >>> product, = template.products
+ >>> product.cost_price = Decimal('40.0000')
+ >>> template.save()
+ >>> product, = template.products
+
+Get stock locations::
+
+ >>> supplier_loc, = Location.find([('code', '=', 'SUP')])
+ >>> storage_loc, = Location.find([('code', '=', 'STO')])
+ >>> production_loc = Location(name="Production", type='production')
+ >>> production_loc.save()
+
+Consume product for production and reverse some::
+
+ >>> StockMove(
+ ... product=product,
+ ... quantity=10,
+ ... from_location=storage_loc,
+ ... to_location=production_loc,
+ ... effective_date=today).click('do')
+ >>> StockMove(
+ ... product=product,
+ ... quantity=2,
+ ... from_location=production_loc,
+ ... to_location=storage_loc,
+ ... unit_price=Decimal('40.0000'),
+ ... effective_date=today).click('do')
+
+ >>> [m.cost_price for m in StockMove.find([])]
+ [Decimal('40.0000'), Decimal('40.0000')]
+
+Recompute cost price::
+
+ >>> recompute = Wizard('product.recompute_cost_price', [product])
+ >>> recompute.execute('recompute')
+
+ >>> [m.cost_price for m in StockMove.find([])]
+ [Decimal('0.0000'), Decimal('40.0000')]
+
+ >>> product.reload()
+ >>> product.cost_price
+ Decimal('0.0000')
+
+Receive product yesterday at new cost::
+
+ >>> StockMove(
+ ... product=product,
+ ... quantity=16,
+ ... from_location=supplier_loc,
+ ... to_location=storage_loc,
+ ... unit_price=Decimal('20.0000'),
+ ... effective_date=yesterday).click('do')
+
+Recompute cost price::
+
+ >>> recompute = Wizard('product.recompute_cost_price', [product])
+ >>> recompute.execute('recompute')
+
+ >>> [m.cost_price for m in StockMove.find([])]
+ [Decimal('20.0000'), Decimal('20.0000'), Decimal('20.0000')]
+
+ >>> product.reload()
+ >>> product.cost_price
+ Decimal('20.0000')
diff -r 356d29f8a922 -r b97f12a119f2 tests/test_product_cost_fifo.py
--- a/tests/test_product_cost_fifo.py Sat Dec 18 16:31:09 2021 +0100
+++ b/tests/test_product_cost_fifo.py Sun Mar 06 13:34:18 2022 +0100
@@ -37,4 +37,9 @@
tearDown=doctest_teardown, encoding='utf-8',
checker=doctest_checker,
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
+ suite.addTests(doctest.DocFileSuite(
+ 'scenario_product_cost_fifo_recompute_cost_price_production.rst',
+ tearDown=doctest_teardown, encoding='utf-8',
+ checker=doctest_checker,
+ optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
return suite