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
This commit is contained in:
Cédric Krier committed 2020-10-11 16:12:36 +02:00
1 parent b546cb8f90
commit 172ab5efdf
3 files changed
+50 -14

No files matched your search

+1
View File
@@ -1,3 +1,4 @@
* Keep cost of unused input products
* Use the shipment assign wizard for production
* Rename production state from cancel to cancelled
+34 -4
View File
@@ -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,7 +530,36 @@ class Production(ShipmentAssignMixin, Workflow, ModelSQL, ModelView):
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
@@ -541,7 +571,7 @@ class Production(ShipmentAssignMixin, Workflow, ModelSQL, ModelView):
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 @@ class Production(ShipmentAssignMixin, Workflow, ModelSQL, ModelView):
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)
+15 -10
View File
@@ -51,13 +51,13 @@ Create Bill of Material::
>>> 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 @@ Make a production::
>>> 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 @@ Launch cron task::
>>> 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