From 034eeac76133c4fde57de11e67daed660152b384 Mon Sep 17 00:00:00 2001 From: agaldona Date: Fri, 9 Oct 2015 11:39:43 +0200 Subject: [PATCH] [IMP] mrp_production_project_estimated_cost: Cost load in positive. [IMP] mrp_production_real_costs: The quant's cost will be loaded every Consume or Produce action and when ends a MO. New configurable check to load final product cost in analytic or not Closes #1001 #1010 --- mrp_production_real_cost/__init__.py | 1 + mrp_production_real_cost/__openerp__.py | 3 +- mrp_production_real_cost/models/__init__.py | 1 + mrp_production_real_cost/models/mrp_config.py | 43 +++++++ .../models/mrp_production.py | 31 ++++- mrp_production_real_cost/models/stock_move.py | 111 ++++++------------ .../views/res_config_view.xml | 18 +++ mrp_production_real_cost/wizard/__init__.py | 6 + .../wizard/mrp_product_produce.py | 20 ++++ 9 files changed, 160 insertions(+), 74 deletions(-) create mode 100644 mrp_production_real_cost/models/mrp_config.py create mode 100644 mrp_production_real_cost/views/res_config_view.xml create mode 100644 mrp_production_real_cost/wizard/__init__.py create mode 100644 mrp_production_real_cost/wizard/mrp_product_produce.py diff --git a/mrp_production_real_cost/__init__.py b/mrp_production_real_cost/__init__.py index 324fad228..ecfcca241 100644 --- a/mrp_production_real_cost/__init__.py +++ b/mrp_production_real_cost/__init__.py @@ -17,3 +17,4 @@ ############################################################################## from . import models +from . import wizard diff --git a/mrp_production_real_cost/__openerp__.py b/mrp_production_real_cost/__openerp__.py index d5cfaf6aa..8c64469a0 100644 --- a/mrp_production_real_cost/__openerp__.py +++ b/mrp_production_real_cost/__openerp__.py @@ -32,7 +32,8 @@ "category": "MRP", 'data': [ "data/analytic_journal_data.xml", - "views/mrp_production_view.xml" + "views/mrp_production_view.xml", + "views/res_config_view.xml" ], 'installable': True, 'auto_install': False, diff --git a/mrp_production_real_cost/models/__init__.py b/mrp_production_real_cost/models/__init__.py index e81c2bb0a..e87caf4c2 100644 --- a/mrp_production_real_cost/models/__init__.py +++ b/mrp_production_real_cost/models/__init__.py @@ -21,3 +21,4 @@ from . import mrp_production_workcenter_line from . import project_task_work from . import mrp_production from . import mrp_bom +from . import mrp_config diff --git a/mrp_production_real_cost/models/mrp_config.py b/mrp_production_real_cost/models/mrp_config.py new file mode 100644 index 000000000..5c3d89efe --- /dev/null +++ b/mrp_production_real_cost/models/mrp_config.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# (c) 2015 Ainara Galdona - AvanzOSC +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from openerp import api, fields, models + + +class MrpConfigSettings(models.TransientModel): + _inherit = 'mrp.config.settings' + + final_product_analytic_cost = fields.Boolean( + string='Load final product analytic cost', + help='This will allow you to define if those BoM passed back to draft' + ' are still activated or not') + + def _get_parameter(self, key, default=False): + param_obj = self.env['ir.config_parameter'] + rec = param_obj.search([('key', '=', key)]) + return rec or default + + def _write_or_create_param(self, key, value): + param_obj = self.env['ir.config_parameter'] + rec = self._get_parameter(key) + if rec: + if not value: + rec.unlink() + else: + rec.value = value + elif value: + param_obj.create({'key': key, 'value': value}) + + @api.multi + def get_default_parameters(self): + def get_value(key, default=''): + rec = self._get_parameter(key) + return rec and rec.value or default + return {'final_product_analytic_cost': get_value('final.product.cost', + False)} + + @api.multi + def set_parameters(self): + self._write_or_create_param('final.product.cost', + self.final_product_analytic_cost) diff --git a/mrp_production_real_cost/models/mrp_production.py b/mrp_production_real_cost/models/mrp_production.py index a15b906eb..42067aef2 100644 --- a/mrp_production_real_cost/models/mrp_production.py +++ b/mrp_production_real_cost/models/mrp_production.py @@ -52,16 +52,45 @@ class MrpProduction(models.Model): @api.multi def action_production_end(self): + task_obj = self.env['project.task'] + analytic_line_obj = self.env['account.analytic.line'] res = super(MrpProduction, self).action_production_end() for record in self: mrp_cost = record.calc_mrp_real_cost() done_lines = record.move_created_ids2.filtered(lambda l: l.state == 'done') - done_lines.create_produce_cost_line(mrp_cost) + create_cost = self.env['mrp.config.settings']._get_parameter( + 'final.product.cost') + if create_cost and create_cost.value and mrp_cost > 0.0: + journal_id = self.env.ref('mrp.analytic_journal_materials', + False) + qty = sum([l.product_qty for l in done_lines]) + name = ('Final product - ' + (record.name or '') + + '-' + (record.product_id.default_code or '')) + vals = record._prepare_real_cost_analytic_line( + journal_id, name, record, record.product_id, qty=qty, + amount=mrp_cost) + task = task_obj.search([('mrp_production_id', '=', record.id), + ('wk_order', '=', False)]) + vals['task_id'] = task and task[0].id or False + analytic_line_obj.create(vals) record.real_cost = mrp_cost done_lines.product_price_update_production_done() + # Reload produced quants cost to consider all production costs. + # Material, machine and manual costs. + self.load_final_quant_cost() return res + @api.multi + def load_final_quant_cost(self): + for production in self: + mrp_cost = production.calc_mrp_real_cost() + done_lines = production.move_created_ids2.filtered( + lambda l: l.state == 'done') + total_qty = sum([l.product_qty for l in done_lines]) + quants = done_lines.mapped('quant_ids') + quants.write({'cost': mrp_cost / total_qty}) + @api.model def _prepare_real_cost_analytic_line( self, journal, name, production, product, general_account=None, diff --git a/mrp_production_real_cost/models/stock_move.py b/mrp_production_real_cost/models/stock_move.py index 9c47221a7..bca465fce 100644 --- a/mrp_production_real_cost/models/stock_move.py +++ b/mrp_production_real_cost/models/stock_move.py @@ -24,86 +24,53 @@ class StockMove(models.Model): _inherit = 'stock.move' @api.multi - def create_produce_cost_line(self, amount): + def action_done(self): task_obj = self.env['project.task'] analytic_line_obj = self.env['account.analytic.line'] + result = super(StockMove, self).action_done() for record in self: - if amount > 0.0: - if record.production_id: - product = record.product_id - production = record.production_id - journal_id = self.env.ref( - 'mrp.analytic_journal_materials', False) - name = ('Final product - ' + (production.name or '') + - '-' + (product.default_code or '')) - vals = production._prepare_real_cost_analytic_line( - journal_id, name, production, product, - qty=record.product_qty, amount=amount) - task = task_obj.search( - [('mrp_production_id', '=', production.id), - ('wk_order', '=', False)]) - vals['task_id'] = task and task[0].id or False - analytic_line_obj.create(vals) - - @api.multi - def action_consume(self, product_qty, location_id=False, - restrict_lot_id=False, restrict_partner_id=False, - consumed_for=False): - task_obj = self.env['project.task'] - analytic_line_obj = self.env['account.analytic.line'] - result = super(StockMove, self).action_consume( - product_qty, location_id=location_id, - restrict_lot_id=restrict_lot_id, - restrict_partner_id=restrict_partner_id, consumed_for=consumed_for) - for record in self: - price = record.product_id.cost_price - if price > 0.0: - if record.raw_material_production_id: - product = record.product_id - journal_id = self.env.ref( - 'mrp.analytic_journal_materials', False) - production = record.raw_material_production_id - name = ( - (production.name or '') + '-' + - (record.work_order.routing_wc_line.operation.code or - '') + '-' + (product.default_code or '')) - analytic_vals = ( - production._prepare_real_cost_analytic_line( - journal_id, name, production, product, - workorder=record.work_order, - qty=record.product_qty, - amount=(-price * record.product_qty))) - task = task_obj.search( - [('mrp_production_id', '=', production.id), - ('wk_order', '=', False)]) - analytic_vals['task_id'] = task and task[0].id or False - analytic_line_obj.create(analytic_vals) + if (not record.raw_material_production_id or not + record.product_id.cost_price): + continue + journal_id = self.env.ref('mrp.analytic_journal_materials', False) + production = record.raw_material_production_id + name = ((production.name or '') + '-' + + (record.work_order.routing_wc_line.operation.code or '') + + '-' + (record.product_id.default_code or '')) + analytic_vals = (production._prepare_real_cost_analytic_line( + journal_id, name, production, record.product_id, + workorder=record.work_order, qty=record.product_qty, + amount=(-record.product_id.cost_price * record.product_qty))) + task = task_obj.search([('mrp_production_id', '=', production.id), + ('wk_order', '=', False)]) + analytic_vals['task_id'] = task and task[0].id or False + analytic_line_obj.create(analytic_vals) return result @api.multi def product_price_update_production_done(self): for move in self: - if (move.production_id) and (move.product_id.cost_method == - 'average'): - prod_total_cost = move.production_id.calc_mrp_real_cost() - product = move.product_id - product_avail = product.qty_available - amount_unit = product.cost_price - template_avail = product.product_tmpl_id.qty_available - template_price = product.standard_price - if move.state == 'done': - product_avail -= move.product_qty - template_avail -= move.product_qty - new_cost_price = ((amount_unit * product_avail + - prod_total_cost) / - ((product_avail >= 0.0 and product_avail or - 0.0) + move.product_qty)) - new_std_price = ((template_price * template_avail + - prod_total_cost) / - ((template_avail >= 0.0 and template_avail or - 0.0) + move.product_qty)) - product.sudo().write({'cost_price': new_cost_price, - 'standard_price': new_std_price}) + if (not move.production_id or move.product_id.cost_method != + 'average'): + continue + prod_total_cost = move.production_id.calc_mrp_real_cost() + product = move.product_id + product_avail = product.qty_available + amount_unit = product.cost_price + template_avail = product.product_tmpl_id.qty_available + template_price = product.standard_price + if move.state == 'done': + product_avail -= move.product_qty + template_avail -= move.product_qty + new_cost_price = ((amount_unit * product_avail + prod_total_cost) / + ((product_avail >= 0.0 and product_avail or 0.0) + + move.product_qty)) + new_std_price = ((template_price * template_avail + + prod_total_cost) / + ((template_avail >= 0.0 and template_avail or + 0.0) + move.product_qty)) + product.sudo().write({'cost_price': new_cost_price, + 'standard_price': new_std_price}) @api.model def get_price_unit(self, move): diff --git a/mrp_production_real_cost/views/res_config_view.xml b/mrp_production_real_cost/views/res_config_view.xml new file mode 100644 index 000000000..f3e3f75fc --- /dev/null +++ b/mrp_production_real_cost/views/res_config_view.xml @@ -0,0 +1,18 @@ + + + + + mrp.config.settings.costs + mrp.config.settings + + + +
+ +
+
+
+
+
+
diff --git a/mrp_production_real_cost/wizard/__init__.py b/mrp_production_real_cost/wizard/__init__.py new file mode 100644 index 000000000..92d4c4468 --- /dev/null +++ b/mrp_production_real_cost/wizard/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +############################################################################## +# For copyright and license notices, see __openerp__.py file in root directory +############################################################################## + +from . import mrp_product_produce diff --git a/mrp_production_real_cost/wizard/mrp_product_produce.py b/mrp_production_real_cost/wizard/mrp_product_produce.py new file mode 100644 index 000000000..ad2ebddba --- /dev/null +++ b/mrp_production_real_cost/wizard/mrp_product_produce.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +############################################################################## +# For copyright and license notices, see __openerp__.py file in root directory +############################################################################## +from openerp import models, api + + +class MrpProductProduce(models.TransientModel): + + _inherit = 'mrp.product.produce' + + # Reload produced quants cost every consume or produce action in a MO. + @api.multi + def do_produce(self): + res = super(MrpProductProduce, self).do_produce() + production_obj = self.env['mrp.production'] + production_id = self.env.context.get('active_id', False) + production = production_obj.browse(production_id) + production.load_final_quant_cost() + return res