changeset 36999d34ea12 in modules/production:default
details: 
https://hg.tryton.org/modules/production?cmd=changeset;node=36999d34ea12
description:
        Keep cost of unused input products

        We set the average cost price of the input products as the unit price 
of the
        output of the same product. This way the cost price computation for this
        product does not change.

        issue9637
        review316051002
diffstat:

 CHANGELOG                              |   1 +
 production.py                          |  38 ++++++++++++++++++++++++++++++---
 tests/scenario_production_set_cost.rst |  25 +++++++++++++--------
 3 files changed, 50 insertions(+), 14 deletions(-)

diffs (140 lines):

diff -r 5fa6035477e6 -r 36999d34ea12 CHANGELOG
--- a/CHANGELOG Fri Oct 09 19:09:05 2020 +0200
+++ b/CHANGELOG Sun Oct 11 16:12:36 2020 +0200
@@ -1,3 +1,4 @@
+* Keep cost of unused input products
 * Use the shipment assign wizard for production
 * Rename production state from cancel to cancelled
 
diff -r 5fa6035477e6 -r 36999d34ea12 production.py
--- a/production.py     Fri Oct 09 19:09:05 2020 +0200
+++ b/production.py     Sun Oct 11 16:12:36 2020 +0200
@@ -1,5 +1,6 @@
 # This file is part of Tryton.  The COPYRIGHT file at the top level of
 # this repository contains the full copyright notices and license terms.
+from collections import defaultdict
 from decimal import Decimal
 from itertools import chain
 
@@ -529,8 +530,37 @@
         for production in productions:
             sum_ = Decimal(0)
             prices = {}
+            cost = production.cost
+
+            input_quantities = defaultdict(Decimal)
+            input_costs = defaultdict(Decimal)
+            for input_ in production.inputs:
+                if input_.cost_price is not None:
+                    cost_price = input_.cost_price
+                else:
+                    cost_price = input_.product.cost_price
+                input_quantities[input_.product] += (
+                    Decimal(str(input_.internal_quantity)))
+                input_costs[input_.product] += (
+                    Decimal(str(input_.internal_quantity)) * cost_price)
+            outputs = []
             for output in production.outputs:
                 product = output.product
+                if input_quantities.get(output.product):
+                    cost_price = (
+                        input_costs[product] / input_quantities[product])
+                    unit_price = round_price(Uom.compute_price(
+                            product.default_uom, cost_price, output.uom))
+                    if output.unit_price != unit_price:
+                        output.unit_price = unit_price
+                        moves.append(output)
+                    cost -= min(
+                        unit_price * Decimal(str(output.quantity)), cost)
+                else:
+                    outputs.append(output)
+
+            for output in outputs:
+                product = output.product
                 with Transaction().set_context(production._list_price_context):
                     list_price = product.list_price_used
                 product_price = (Decimal(str(output.quantity))
@@ -541,7 +571,7 @@
 
             if not sum_ and production.product:
                 prices.clear()
-                for output in production.outputs:
+                for output in outputs:
                     if output.product == production.product:
                         quantity = Uom.compute_qty(
                             output.uom, output.quantity,
@@ -550,13 +580,13 @@
                         prices[output] = quantity
                         sum_ += quantity
 
-            for output in production.outputs:
+            for output in outputs:
                 if sum_:
                     ratio = prices.get(output, 0) / sum_
                 else:
-                    ratio = Decimal(1) / len(production.outputs)
+                    ratio = Decimal(1) / len(outputs)
                 quantity = Decimal(str(output.quantity))
-                unit_price = round_price(production.cost * ratio / quantity)
+                unit_price = round_price(cost * ratio / quantity)
                 if output.unit_price != unit_price:
                     output.unit_price = unit_price
                     moves.append(output)
diff -r 5fa6035477e6 -r 36999d34ea12 tests/scenario_production_set_cost.rst
--- a/tests/scenario_production_set_cost.rst    Fri Oct 09 19:09:05 2020 +0200
+++ b/tests/scenario_production_set_cost.rst    Sun Oct 11 16:12:36 2020 +0200
@@ -51,13 +51,13 @@
     >>> bom = BOM(name='product')
     >>> input = bom.inputs.new()
     >>> input.product = component
-    >>> input.quantity = 2
+    >>> input.quantity = 3
     >>> output = bom.outputs.new()
     >>> output.product = product
     >>> output.quantity = 1
     >>> bom.save()
 
-Make a production::
+Make a production with 2 unused component::
 
     >>> Production = Model.get('production')
     >>> production = Production()
@@ -67,15 +67,20 @@
     >>> production.click('wait')
     >>> production.click('assign_force')
     >>> production.click('run')
+    >>> output = production.outputs.new()
+    >>> output.product = component
+    >>> output.quantity = 2
+    >>> output.unit_price = Decimal(0)
+    >>> output.from_location = production.location
+    >>> output.to_location = production.warehouse.storage_location
     >>> production.click('done')
 
 Check output price::
 
     >>> production.cost
-    Decimal('20.0000')
-    >>> output, = production.outputs
-    >>> output.unit_price
-    Decimal('10.0000')
+    Decimal('30.0000')
+    >>> sorted([o.unit_price for o in production.outputs])
+    [Decimal('5.0000'), Decimal('10.0000')]
 
 
 Change cost of input::
@@ -97,9 +102,9 @@
     >>> cron_set_cost.companies.append(Company(company.id))
     >>> cron_set_cost.click('run_once')
 
-    >>> output.reload()
-    >>> output.unit_price
-    Decimal('12.0000')
-    >>> input.reload()
+    >>> production.reload()
+    >>> sorted([o.unit_price for o in production.outputs])
+    [Decimal('6.0000'), Decimal('12.0000')]
+    >>> input, = production.inputs
     >>> bool(input.production_cost_price_updated)
     False

Reply via email to