mirror of
https://github.com/NaN-tic/trytond-patches.git
synced 2023-12-14 06:03:03 +01:00
137 lines
5.4 KiB
Diff
137 lines
5.4 KiB
Diff
|
From a5edc544456d361175a4de1ed2fc12948cd67118 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 09:15:58 +0200
|
||
|
Subject: [PATCH] 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
|
||
|
---
|
||
|
production.py | 85 +++++++++++++++++++++++++++++++++++++++++++--------
|
||
|
1 file changed, 73 insertions(+), 12 deletions(-)
|
||
|
|
||
|
diff --git a/production.py b/production.py
|
||
|
index 2bd52d1..13ec112 100644
|
||
|
--- a/trytond/trytond/modules/production/production.py
|
||
|
+++ b/trytond/trytond/modules/production/production.py
|
||
|
@@ -1,7 +1,7 @@
|
||
|
# 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 decimal import Decimal
|
||
|
-
|
||
|
+from collections import defaultdict
|
||
|
from sql import Null
|
||
|
|
||
|
from trytond.i18n import gettext
|
||
|
@@ -21,6 +21,12 @@ BOM_CHANGES = ['bom', 'product', 'quantity', 'uom', 'warehouse', 'location',
|
||
|
'company', 'inputs', 'outputs']
|
||
|
|
||
|
|
||
|
+
|
||
|
+def round_price(value, rounding=None):
|
||
|
+ "Round price using the price digits"
|
||
|
+ return value.quantize(
|
||
|
+ Decimal(1) / 10 ** price_digits[1], rounding=rounding)
|
||
|
+
|
||
|
class Production(Workflow, ModelSQL, ModelView):
|
||
|
"Production"
|
||
|
__name__ = 'production'
|
||
|
@@ -461,26 +467,81 @@ class Production(Workflow, ModelSQL, ModelView):
|
||
|
productions.add(move.production_input)
|
||
|
Move.write(moves, {'production_cost_price_updated': False})
|
||
|
|
||
|
+ @property
|
||
|
+ def _list_price_context(self):
|
||
|
+ return {
|
||
|
+ 'company': self.company.id,
|
||
|
+ }
|
||
|
+
|
||
|
@classmethod
|
||
|
def set_cost(cls, productions):
|
||
|
pool = Pool()
|
||
|
Uom = pool.get('product.uom')
|
||
|
Move = pool.get('stock.move')
|
||
|
|
||
|
- digits = Move.unit_price.digits
|
||
|
- digit = Decimal(str(10 ** -digits[1]))
|
||
|
moves = []
|
||
|
for production in productions:
|
||
|
- if not production.quantity or not production.uom:
|
||
|
- continue
|
||
|
- if production.company.currency.is_zero(
|
||
|
- production.cost - production.output_cost):
|
||
|
- continue
|
||
|
- unit_price = production.cost / Decimal(str(production.quantity))
|
||
|
+ 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:
|
||
|
- if output.product == production.product:
|
||
|
- output.unit_price = Uom.compute_price(
|
||
|
- production.uom, unit_price, output.uom).quantize(digit)
|
||
|
+ 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))
|
||
|
+ * Uom.compute_price(
|
||
|
+ product.default_uom, list_price, output.uom))
|
||
|
+ prices[output] = product_price
|
||
|
+ sum_ += product_price
|
||
|
+
|
||
|
+ if not sum_ and production.product:
|
||
|
+ prices.clear()
|
||
|
+ for output in outputs:
|
||
|
+ if output.product == production.product:
|
||
|
+ quantity = Uom.compute_qty(
|
||
|
+ output.uom, output.quantity,
|
||
|
+ output.product.default_uom, round=False)
|
||
|
+ quantity = Decimal(str(quantity))
|
||
|
+ prices[output] = quantity
|
||
|
+ sum_ += quantity
|
||
|
+
|
||
|
+ for output in outputs:
|
||
|
+ if sum_:
|
||
|
+ ratio = prices.get(output, 0) / sum_
|
||
|
+ else:
|
||
|
+ ratio = Decimal(1) / len(outputs)
|
||
|
+ quantity = Decimal(str(output.quantity))
|
||
|
+ unit_price = round_price(cost * ratio / quantity)
|
||
|
+ if output.unit_price != unit_price:
|
||
|
+ output.unit_price = unit_price
|
||
|
moves.append(output)
|
||
|
Move.save(moves)
|
||
|
|
||
|
--
|
||
|
2.25.1
|