From 87578177ac4bc19c1fd7fb1155e3793fb5866d66 Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Thu, 25 Feb 2016 11:27:29 +0100 Subject: [PATCH] [FIX] mrp: Cost calculation of finished product when real price should work in real-time too For that, we needed to inverse the processing of the moves of the production order (first consumed, then produced instead of the opposite) as that way we know the price to put on the produced moves based on what was consumed before. --- addons/mrp/mrp.py | 79 ++++++++++++++++++++++------------------------- 1 file changed, 37 insertions(+), 42 deletions(-) diff --git a/addons/mrp/mrp.py b/addons/mrp/mrp.py index 235b57c4110..fdf1b92c468 100644 --- a/addons/mrp/mrp.py +++ b/addons/mrp/mrp.py @@ -811,23 +811,6 @@ class mrp_production(osv.osv): """ for production in self.browse(cr, uid, ids): total_cost = self._costs_generate(cr, uid, production) - if production.product_id.cost_method == 'real': - for consumed_move in production.move_lines2: - for consumed_quant in consumed_move.quant_ids: - total_cost += consumed_quant.inventory_value - - from_uom = production.product_uom - to_uom = production.product_id.uom_id - quant_cost = total_cost / self.pool['product.uom']._compute_qty_obj(cr, uid, from_uom, production.product_qty, to_uom) - self._apply_cost_from_production(cr, uid, production, quant_cost, context=context) - - def _apply_cost_from_production(self, cr, uid, production, quant_cost, context=None): - """Update the quant value based on computed production cost""" - for produced_product in production.move_created_ids2: - if produced_product.product_id == production.product_id: - # only the produced product - # should only have one quant at the end of the production - self.pool['stock.quant'].write(cr, SUPERUSER_ID, produced_product.quant_ids.ids, {'cost': quant_cost}, context=context) def action_production_end(self, cr, uid, ids, context=None): """ Changes production state to Finish and writes finished date. @@ -967,6 +950,12 @@ class mrp_production(osv.osv): consume_lines.append({'product_id': prod, 'product_qty': qty, 'lot_id': lot}) return consume_lines + def _calculate_total_cost(self, cr, uid, total_consume_moves, context=None): + total_cost = 0 + for consumed_move in self.pool['stock.move'].browse(cr, uid, total_consume_moves, context=context): + total_cost += sum([x.inventory_value for x in consumed_move.quant_ids if x.qty > 0]) + return total_cost + def action_produce(self, cr, uid, production_id, production_qty, production_mode, wiz=False, context=None): """ To produce final product based on production mode (consume/consume&produce). If Production mode is consume, all stock move lines of raw materials will be done/consumed. @@ -986,35 +975,11 @@ class mrp_production(osv.osv): main_production_move = False if production_mode == 'consume_produce': - # To produce remaining qty of final product - produced_products = {} - for produced_product in production.move_created_ids2: - if produced_product.scrapped: - continue - if not produced_products.get(produced_product.product_id.id, False): - produced_products[produced_product.product_id.id] = 0 - produced_products[produced_product.product_id.id] += produced_product.product_qty for produce_product in production.move_created_ids: - subproduct_factor = self._get_subproduct_factor(cr, uid, production.id, produce_product.id, context=context) - lot_id = False - if wiz: - lot_id = wiz.lot_id.id - qty = min(subproduct_factor * production_qty_uom, produce_product.product_qty) #Needed when producing more than maximum quantity - new_moves = stock_mov_obj.action_consume(cr, uid, [produce_product.id], qty, - location_id=produce_product.location_id.id, restrict_lot_id=lot_id, context=context) - stock_mov_obj.write(cr, uid, new_moves, {'production_id': production_id}, context=context) - remaining_qty = subproduct_factor * production_qty_uom - qty - if not float_is_zero(remaining_qty, precision_digits=precision): - # In case you need to make more than planned - #consumed more in wizard than previously planned - extra_move_id = stock_mov_obj.copy(cr, uid, produce_product.id, default={'product_uom_qty': remaining_qty, - 'production_id': production_id}, context=context) - stock_mov_obj.action_confirm(cr, uid, [extra_move_id], context=context) - stock_mov_obj.action_done(cr, uid, [extra_move_id], context=context) - if produce_product.product_id.id == production.product_id.id: main_production_move = produce_product.id + total_consume_moves = [] if production_mode in ['consume', 'consume_produce']: if wiz: consume_lines = [] @@ -1034,6 +999,7 @@ class mrp_production(osv.osv): consumed_qty = min(remaining_qty, raw_material_line.product_qty) stock_mov_obj.action_consume(cr, uid, [raw_material_line.id], consumed_qty, raw_material_line.location_id.id, restrict_lot_id=consume['lot_id'], consumed_for=main_production_move, context=context) + total_consume_moves.append(raw_material_line.id) remaining_qty -= consumed_qty if not float_is_zero(remaining_qty, precision_digits=precision): #consumed more in wizard than previously planned @@ -1042,6 +1008,35 @@ class mrp_production(osv.osv): stock_mov_obj.write(cr, uid, [extra_move_id], {'restrict_lot_id': consume['lot_id'], 'consumed_for': main_production_move}, context=context) stock_mov_obj.action_done(cr, uid, [extra_move_id], context=context) + total_consume_moves.append(extra_move_id) + + if production_mode == 'consume_produce': + price_unit = 0 + for produce_product in production.move_created_ids: + is_main_product = (produce_product.product_id.id == production.product_id.id) and production.product_id.cost_method=='real' + if is_main_product: + total_cost = self._calculate_total_cost(cr, uid, total_consume_moves, context=context) + price_unit = total_cost / production_qty_uom + subproduct_factor = self._get_subproduct_factor(cr, uid, production.id, produce_product.id, context=context) + lot_id = False + if wiz: + lot_id = wiz.lot_id.id + qty = min(subproduct_factor * production_qty_uom, produce_product.product_qty) #Needed when producing more than maximum quantity + if is_main_product: + stock_mov_obj.write(cr, uid, [produce_product.id], {'price_unit': price_unit}, context=context) + new_moves = stock_mov_obj.action_consume(cr, uid, [produce_product.id], qty, + location_id=produce_product.location_id.id, restrict_lot_id=lot_id, context=context) + stock_mov_obj.write(cr, uid, new_moves, {'production_id': production_id}, context=context) + remaining_qty = subproduct_factor * production_qty_uom - qty + if not float_is_zero(remaining_qty, precision_digits=precision): + # In case you need to make more than planned + #consumed more in wizard than previously planned + extra_move_id = stock_mov_obj.copy(cr, uid, produce_product.id, default={'product_uom_qty': remaining_qty, + 'production_id': production_id}, context=context) + if is_main_product: + stock_mov_obj.write(cr, uid, [extra_move_id], {'price_unit': price_unit}, context=context) + stock_mov_obj.action_confirm(cr, uid, [extra_move_id], context=context) + stock_mov_obj.action_done(cr, uid, [extra_move_id], context=context) self.message_post(cr, uid, production_id, body=_("%s produced") % self._description, context=context)