From d32f141f40763f2d28b5889121752d3f28acccbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 18 Jun 2018 21:49:37 +0200 Subject: [PATCH] Set output cost in done transition This ensure that all the costs are applied instead of using only the cost of the input moves. issue7479 review45601002 --- CHANGELOG | 2 ++ production.py | 63 ++++++++++++++++++----------------- tests/scenario_production.rst | 1 + 3 files changed, 36 insertions(+), 30 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 15fbc76a03..857dfa2ae8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Set output cost in done transition + Version 4.8.0 - 2018-04-23 * Bug fixes (see mercurial logs for details) diff --git a/production.py b/production.py index 5585114d15..4e67842d33 100644 --- a/production.py +++ b/production.py @@ -305,10 +305,8 @@ class Production(Workflow, ModelSQL, ModelView): def explode_bom(self): pool = Pool() Uom = pool.get('product.uom') - Move = pool.get('stock.move') if not (self.bom and self.product and self.uom): return - self.cost = Decimal(0) if self.warehouse: storage_location = self.warehouse.storage_location @@ -326,14 +324,8 @@ class Production(Workflow, ModelSQL, ModelView): inputs.append(move) quantity = Uom.compute_qty(input_.uom, quantity, input_.product.default_uom, round=False) - self.cost += (Decimal(str(quantity)) * - input_.product.cost_price) self.inputs = inputs - digits = self.__class__.cost.digits - self.cost = self.cost.quantize(Decimal(str(10 ** -digits[1]))) - digits = Move.unit_price.digits - digit = Decimal(str(10 ** -digits[1])) outputs = [] for output in self.bom.outputs: quantity = output.compute_quantity(factor) @@ -341,9 +333,6 @@ class Production(Workflow, ModelSQL, ModelView): self.company, output, quantity) if move: move.unit_price = Decimal(0) - if output.product == move.product and quantity: - move.unit_price = Decimal( - self.cost / Decimal(str(quantity))).quantize(digit) outputs.append(move) self.outputs = outputs @@ -425,9 +414,6 @@ class Production(Workflow, ModelSQL, ModelView): return cost def set_moves(self): - pool = Pool() - Move = pool.get('stock.move') - storage_location = self.warehouse.storage_location location = self.location company = self.company @@ -444,7 +430,6 @@ class Production(Workflow, ModelSQL, ModelView): return factor = self.bom.compute_factor(self.product, self.quantity, self.uom) - cost = Decimal(0) for input_ in self.bom.inputs: quantity = input_.compute_quantity(factor) product = input_.product @@ -453,13 +438,7 @@ class Production(Workflow, ModelSQL, ModelView): if move: move.production_input = self move.save() - cost += (Decimal(str(move.internal_quantity)) * - product.cost_price) - digits = self.__class__.cost.digits - cost = cost.quantize(Decimal(str(10 ** -digits[1]))) - digits = Move.unit_price.digits - digit = Decimal(str(10 ** -digits[1])) for output in self.bom.outputs: quantity = output.compute_quantity(factor) product = output.product @@ -467,27 +446,50 @@ class Production(Workflow, ModelSQL, ModelView): product, output.uom, quantity) if move: move.production_output = self - if product == self.product: - move.unit_price = Decimal( - cost / Decimal(str(quantity))).quantize(digit) - else: - move.unit_price = Decimal(0) + move.unit_price = Decimal(0) move.save() self._set_move_planned_date() + @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)) + for output in production.outputs: + if output.product == production.product: + output.unit_price = Uom.compute_price( + production.uom, unit_price, output.uom).quantize(digit) + moves.append(output) + Move.save(moves) + @classmethod def validate(cls, productions): super(Production, cls).validate(productions) for production in productions: production.check_cost() + @property + def output_cost(self): + cost_price = Decimal(0) + for output in self.outputs: + cost_price += (Decimal(str(output.quantity)) * output.unit_price) + return cost_price + def check_cost(self): if self.state != 'done': return - cost_price = Decimal(0) - for output in self.outputs: - cost_price += (Decimal(str(output.quantity)) - * output.unit_price) + cost_price = self.output_cost if not self.company.currency.is_zero(self.cost - cost_price): self.raise_user_error('uneven_costs', { 'production': self.rec_name, @@ -595,6 +597,7 @@ class Production(Workflow, ModelSQL, ModelView): pool = Pool() Move = pool.get('stock.move') Date = pool.get('ir.date') + cls.set_cost(productions) Move.do([m for p in productions for m in p.outputs]) cls.write([p for p in productions if not p.effective_date], { 'effective_date': Date.today(), diff --git a/tests/scenario_production.rst b/tests/scenario_production.rst index bde6fa8057..70ab2582ee 100644 --- a/tests/scenario_production.rst +++ b/tests/scenario_production.rst @@ -137,6 +137,7 @@ Make a production:: >>> output, = production.outputs >>> output.quantity == 2 True + >>> production.save() >>> production.cost Decimal('25.0000') >>> production.click('wait')