diff --git a/mrp_production_real_cost/README.rst b/mrp_production_real_cost/README.rst index 1575ef3b4..e1c6c98bd 100644 --- a/mrp_production_real_cost/README.rst +++ b/mrp_production_real_cost/README.rst @@ -1,11 +1,85 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +================================== Real costs in manufacturing orders ================================== This module allows to manage the control of Manufacturing Orders actual costs, -by creating analytic lines as defined in the MO (from *mrp_project_link*). +by creating analytic lines as defined in the MO (from *mrp_project*). It also updates product standard price when a manufacturing orders is finished according this formula: (Product stock * Product standard price + Production real cost) / (Product stock + Final product quantity) + +Installation +============ + +This module depends on the module *product_variant_cost_price*, that is +available in: + +https://github.com/OCA/product-variant + +Usage +===== + +Operating with a manufacture order, analytic entries adding costs will be +created when: + +* Some raw material is consumed. +* A work order is finished or paused. + +Also, thanks to *project_timesheet* modules, users time is also translated to +costs in the linked analytic account. + + + +.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas + :alt: Try me on Runbot + :target: https://runbot.odoo-community.org/runbot/129/8.0 + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues +`_. In case of trouble, please +check there if your issue has already been reported. If you spotted it first, +help us smashing it by providing a detailed and welcomed `feedback +`_. + +Credits +======= + +Contributors +------------ + +* Pedro M. Baeza +* Ana Juaristi +* Ainara Galdona + +Images +------ + +* Original Odoo MRP icon +* Thanks to https://openclipart.org/detail/224801/black-and-white-calculator + +Maintainer +---------- + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +This module is maintained by the OCA. + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +To contribute to this module, please visit https://odoo-community.org. \ No newline at end of file diff --git a/mrp_production_real_cost/__init__.py b/mrp_production_real_cost/__init__.py index ecfcca241..a72b54a4a 100644 --- a/mrp_production_real_cost/__init__.py +++ b/mrp_production_real_cost/__init__.py @@ -1,20 +1,6 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see http://www.gnu.org/licenses/. -# -############################################################################## +# -*- coding: utf-8 -*- +# © 2014-2015 Avanzosc +# © 2014-2015 Pedro M. Baeza +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html from . import models -from . import wizard diff --git a/mrp_production_real_cost/__openerp__.py b/mrp_production_real_cost/__openerp__.py index c09892453..2fa957fbd 100644 --- a/mrp_production_real_cost/__openerp__.py +++ b/mrp_production_real_cost/__openerp__.py @@ -1,40 +1,32 @@ # -*- coding: utf-8 -*- -############################################################################## -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see http://www.gnu.org/licenses/. -# -############################################################################## +# © 2014-2015 Avanzosc +# © 2014-2015 Antiun Ingeniería +# © 2014-2015 Pedro M. Baeza +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html { - "name": "MRP real costs", - "version": "8.0.1.0.1", - "depends": ["analytic", - "project_timesheet", - "mrp_project_link", - "mrp_operations_time_control", - "stock_account", - "product_variant_cost", - "mrp_production_project_estimated_cost"], - "author": "OdooMRP team," - "AvanzOSC," - "Serv. Tecnol. Avanzados - Pedro M. Baeza", - "category": "MRP", + "name": "Real costs in manufacturing orders", + "version": "8.0.1.0.0", + "depends": [ + "project_timesheet", + "mrp_project", + "mrp_operations_extension", + "mrp_operations_time_control", + "stock_account", + "product_variant_cost_price", + ], + "author": "OdooMRP team, " + "AvanzOSC, " + "Serv. Tecnol. Avanzados - Pedro M. Baeza, " + "Antiun Ingeniería S.L., " + "Odoo Community Association (OCA)", + "category": "Manufacturing", 'data': [ "data/analytic_journal_data.xml", "views/mrp_production_view.xml", - "views/res_config_view.xml" - ], + ], + 'demo': [ + 'demo/mrp_production_demo.xml', + ], 'installable': True, - 'auto_install': False, } diff --git a/mrp_production_real_cost/demo/mrp_production_demo.xml b/mrp_production_real_cost/demo/mrp_production_demo.xml new file mode 100644 index 000000000..bfaea931c --- /dev/null +++ b/mrp_production_real_cost/demo/mrp_production_demo.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/mrp_production_real_cost/i18n/en_US.po b/mrp_production_real_cost/i18n/en_US.po deleted file mode 100644 index 543c75b96..000000000 --- a/mrp_production_real_cost/i18n/en_US.po +++ /dev/null @@ -1,79 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * mrp_production_real_costs -# -# Translators: -msgid "" -msgstr "" -"Project-Id-Version: odoomrp-wip (8.0)\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-10-07 10:44+0000\n" -"PO-Revision-Date: 2015-10-04 00:01+0000\n" -"Last-Translator: OCA Transbot \n" -"Language-Team: English (United States) (http://www.transifex.com/oca/odoomrp-wip-8-0/language/en_US/)\n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: \n" -"Language: en_US\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" - -#. module: mrp_production_real_costs -#: field:mrp.production,percentage_difference:0 -msgid "% difference" -msgstr "" - -#. module: mrp_production_real_costs -#: model:ir.model,name:mrp_production_real_costs.model_mrp_bom -msgid "Bill of Material" -msgstr "" - -#. module: mrp_production_real_costs -#: model:ir.model,name:mrp_production_real_costs.model_mrp_production -msgid "Manufacturing Order" -msgstr "" - -#. module: mrp_production_real_costs -#: view:mrp.production:mrp_production_real_costs.mrp_production_form_view_real_costs -msgid "Manufacturing costs" -msgstr "" - -#. module: mrp_production_real_costs -#: field:mrp.production.workcenter.line,post_cost:0 -msgid "Post-Operation Cost" -msgstr "" - -#. module: mrp_production_real_costs -#: field:mrp.production.workcenter.line,pre_cost:0 -msgid "Pre-Operation Cost" -msgstr "" - -#. module: mrp_production_real_costs -#: model:ir.model,name:mrp_production_real_costs.model_project_task_work -msgid "Project Task Work" -msgstr "" - -#. module: mrp_production_real_costs -#: model:ir.model,name:mrp_production_real_costs.model_stock_move -msgid "Stock Move" -msgstr "" - -#. module: mrp_production_real_costs -#: field:mrp.production,real_cost:0 -msgid "Total Real Cost" -msgstr "" - -#. module: mrp_production_real_costs -#: field:mrp.production,unit_real_cost:0 -msgid "Unit Real Cost" -msgstr "" - -#. module: mrp_production_real_costs -#: model:ir.model,name:mrp_production_real_costs.model_mrp_production_workcenter_line -msgid "Work Order" -msgstr "Work Order" - -#. module: mrp_production_real_costs -#: code:addons/mrp_production_real_costs/models/mrp_production.py:92 -#, python-format -msgid "You must define one Analytic Account for this MO: %s" -msgstr "" diff --git a/mrp_production_real_cost/i18n/mrp_production_real_costs.pot b/mrp_production_real_cost/i18n/mrp_production_real_costs.pot deleted file mode 100644 index 69ecdc8cb..000000000 --- a/mrp_production_real_cost/i18n/mrp_production_real_costs.pot +++ /dev/null @@ -1,38 +0,0 @@ -# Translation of Odoo Server. -# This file contains the translation of the following modules: -# * mrp_production_real_costs -# -msgid "" -msgstr "" -"Project-Id-Version: Odoo Server 8.0\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2014-11-11 15:06+0000\n" -"PO-Revision-Date: 2014-11-11 16:09+0100\n" -"Last-Translator: \n" -"Language-Team: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: \n" - -#. module: mrp_production_real_costs -#: model:ir.model,name:mrp_production_real_costs.model_project_task_work -msgid "Project Task Work" -msgstr "" - -#. module: mrp_production_real_costs -#: model:ir.model,name:mrp_production_real_costs.model_stock_move -msgid "Stock Move" -msgstr "" - -#. module: mrp_production_real_costs -#: model:ir.model,name:mrp_production_real_costs.model_mrp_production_workcenter_line -msgid "Work Order" -msgstr "" - -#. module: mrp_production_real_costs -#: code:addons/mrp_production_real_costs/models/mrp_production_workcenter_line.py:59 -#, python-format -msgid "You must define a general account for this Workcenter: [%s] %s" -msgstr "" - diff --git a/mrp_production_real_cost/models/__init__.py b/mrp_production_real_cost/models/__init__.py index 95f9cbed8..770634caa 100644 --- a/mrp_production_real_cost/models/__init__.py +++ b/mrp_production_real_cost/models/__init__.py @@ -1,23 +1,9 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see http://www.gnu.org/licenses/. -# -############################################################################## +# -*- coding: utf-8 -*- +# © 2014-2015 Avanzosc +# © 2014-2015 Pedro M. Baeza +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html -from . import stock_move -from . import mrp_production_workcenter_line -from . import mrp_production from . import mrp_bom -from . import mrp_config +from . import mrp_production +from . import mrp_production_workcenter_line +from . import stock_move diff --git a/mrp_production_real_cost/models/mrp_bom.py b/mrp_production_real_cost/models/mrp_bom.py index 8499f49cc..753e003e8 100644 --- a/mrp_production_real_cost/models/mrp_bom.py +++ b/mrp_production_real_cost/models/mrp_bom.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- -############################################################################## -# For copyright and license notices, see __openerp__.py file in root directory -############################################################################## +# © 2014-2015 Avanzosc +# © 2014-2015 Pedro M. Baeza +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + from openerp import models, api @@ -14,7 +15,7 @@ class MrpBom(models.Model): wc_use, level=level, factor=factor) wc = wc_use.workcenter_id res['pre_cost'] = ( - res.get('time_start', 0.0) * wc.pre_op_product.cost_price) + res.get('time_start', 0.0) * wc.pre_op_product.standard_price) res['post_cost'] = ( - res.get('time_stop', 0.0) * wc.post_op_product.cost_price) + res.get('time_stop', 0.0) * wc.post_op_product.standard_price) return res diff --git a/mrp_production_real_cost/models/mrp_config.py b/mrp_production_real_cost/models/mrp_config.py deleted file mode 100644 index 5c3d89efe..000000000 --- a/mrp_production_real_cost/models/mrp_config.py +++ /dev/null @@ -1,43 +0,0 @@ -# -*- 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 7c5f13994..49b5f4e0c 100644 --- a/mrp_production_real_cost/models/mrp_production.py +++ b/mrp_production_real_cost/models/mrp_production.py @@ -1,96 +1,40 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see http://www.gnu.org/licenses/. -# -############################################################################## +# -*- coding: utf-8 -*- +# © 2014-2015 Avanzosc +# © 2014-2015 Pedro M. Baeza +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html -from openerp import models, fields, api, exceptions, _ +from openerp import api, fields, models class MrpProduction(models.Model): - _inherit = 'mrp.production' @api.multi - def calc_mrp_real_cost(self): - self.ensure_one() - return sum([-line.amount for line in - self.analytic_line_ids.filtered(lambda l: l.amount < 0)]) - - @api.one @api.depends('analytic_line_ids', 'analytic_line_ids.amount', 'product_qty') - def get_real_cost(self): - self.real_cost = self.calc_mrp_real_cost() - self.unit_real_cost = self.real_cost / self.product_qty + def _compute_real_cost(self): + for production in self: + cost_lines = production.analytic_line_ids.filtered( + lambda l: l.amount < 0) + production.real_cost = -sum(cost_lines.mapped('amount')) + production.unit_real_cost = ( + production.real_cost / production.product_qty) - @api.one - @api.depends('avg_cost', 'real_cost') - def get_percentage_difference(self): - self.percentage_difference = 0 - if self.avg_cost and self.real_cost: - self.percentage_difference = (self.real_cost * 100 / self.avg_cost) - - real_cost = fields.Float("Total Real Cost", compute="get_real_cost", - store=True) - unit_real_cost = fields.Float("Unit Real Cost", compute="get_real_cost", - store=True) - percentage_difference = fields.Float( - "% difference", compute="get_percentage_difference", store=True) + analytic_line_ids = fields.One2many( + comodel_name="account.analytic.line", inverse_name="mrp_production_id", + string="Cost Lines") + real_cost = fields.Float( + "Total Real Cost", compute="_compute_real_cost", store=True) + unit_real_cost = fields.Float( + "Unit Real Cost", compute="_compute_real_cost", store=True) @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') - 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), - ('workorder', '=', 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() + self.mapped('move_created_ids2').filtered( + lambda l: l.state == 'done').product_price_update_production_done() 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, @@ -110,16 +54,11 @@ class MrpProduction(models.Model): """ analytic_line_obj = self.env['account.analytic.line'] property_obj = self.env['ir.property'] - if not general_account: - general_account = ( - product.property_account_expense or - product.categ_id.property_account_expense_categ or - property_obj.get('property_account_expense_categ', - 'product.category')) - if not production.analytic_account_id: - raise exceptions.Warning( - _('You must define one Analytic Account for this MO: %s') % - (production.name)) + general_account = ( + general_account or product.property_account_expense or + product.categ_id.property_account_expense_categ or + property_obj.get('property_account_expense_categ', + 'product.category')) return { 'name': name, 'mrp_production_id': production.id, diff --git a/mrp_production_real_cost/models/mrp_production_workcenter_line.py b/mrp_production_real_cost/models/mrp_production_workcenter_line.py index 81da71591..8a60546c8 100644 --- a/mrp_production_real_cost/models/mrp_production_workcenter_line.py +++ b/mrp_production_real_cost/models/mrp_production_workcenter_line.py @@ -1,37 +1,17 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see http://www.gnu.org/licenses/. -# -############################################################################## +# -*- coding: utf-8 -*- +# © 2014-2015 Avanzosc +# © 2014-2015 Pedro M. Baeza +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html -from openerp import models, api, fields +from openerp import api, fields, models class MrpProductionWorkcenterLine(models.Model): _inherit = 'mrp.production.workcenter.line' - @api.one - def _get_prepost_cost(self): - wc = self.workcenter_id - self.pre_cost = self.time_start * wc.pre_op_product.cost_price - self.post_cost = self.time_stop * wc.post_op_product.cost_price - - pre_cost = fields.Float('Pre-Operation Cost', default=_get_prepost_cost) - post_cost = fields.Float('Post-Operation Cost', - default=_get_prepost_cost) + pre_cost = fields.Float('Pre-Operation Cost') + post_cost = fields.Float('Post-Operation Cost') @api.multi def _create_analytic_line(self): @@ -82,14 +62,14 @@ class MrpProductionWorkcenterLine(models.Model): name = ((production.name or '') + '-' + (self.routing_wc_line.operation.code or '') + '-PRE-' + (product.default_code or '')) - price = -(self.pre_cost) + price = -self.pre_cost qty = self.time_start elif cost_type == 'post': product = workcenter.post_op_product name = ((production.name or '') + '-' + (self.routing_wc_line.operation.code or '') + '-POST-' + (product.default_code or '')) - price = -(self.post_cost) + price = -self.post_cost qty = self.time_stop if price: analytic_vals = production._prepare_real_cost_analytic_line( @@ -98,10 +78,17 @@ class MrpProductionWorkcenterLine(models.Model): qty=qty, amount=price) task = task_obj.search([('mrp_production_id', '=', production.id), ('workorder', '=', False)]) - analytic_vals['task_id'] = task and task[0].id or False + analytic_vals['task_id'] = task[:1].id analytic_vals['product_uom_id'] = hour_uom.id analytic_line_obj.create(analytic_vals) + @api.multi + def action_start_working(self): + result = super(MrpProductionWorkcenterLine, + self).action_start_working() + self._create_pre_post_cost_lines(cost_type='pre') + return result + @api.multi def action_pause(self): result = super(MrpProductionWorkcenterLine, self).action_pause() @@ -112,6 +99,5 @@ class MrpProductionWorkcenterLine(models.Model): def action_done(self): result = super(MrpProductionWorkcenterLine, self).action_done() self._create_analytic_line() - self._create_pre_post_cost_lines(cost_type='pre') self._create_pre_post_cost_lines(cost_type='post') return result diff --git a/mrp_production_real_cost/models/stock_move.py b/mrp_production_real_cost/models/stock_move.py index de519174a..67259cbd2 100644 --- a/mrp_production_real_cost/models/stock_move.py +++ b/mrp_production_real_cost/models/stock_move.py @@ -1,26 +1,12 @@ -# -*- encoding: utf-8 -*- -############################################################################## -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published -# by the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see http://www.gnu.org/licenses/. -# -############################################################################## +# -*- coding: utf-8 -*- +# © 2014-2015 Avanzosc +# © 2014-2015 Pedro M. Baeza +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html -from openerp import models, api +from openerp import api, models class StockMove(models.Model): - _inherit = 'stock.move' @api.multi @@ -28,10 +14,9 @@ class StockMove(models.Model): 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 (not record.raw_material_production_id or not - record.product_id.cost_price): - continue + records = self.filtered(lambda x: (x.raw_material_production_id and + x.product_id.standard_price)) + for record in records: journal_id = self.env.ref('mrp.analytic_journal_materials', False) production = record.raw_material_production_id name = ((production.name or '') + '-' + @@ -40,7 +25,8 @@ class StockMove(models.Model): 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))) + amount=(-record.product_id.standard_price * + record.product_qty))) task = task_obj.search([('mrp_production_id', '=', production.id), ('workorder', '=', False)]) analytic_vals['task_id'] = task and task[0].id or False @@ -49,33 +35,32 @@ class StockMove(models.Model): @api.multi def product_price_update_production_done(self): - for move in self: - if (not move.production_id or move.product_id.cost_method != - 'average'): - continue - prod_total_cost = move.production_id.calc_mrp_real_cost() + records = self.filtered( + lambda x: (x.production_id and + x.product_id.cost_method == 'average')) + for move in records: + prod_total_cost = move.production_id.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 + amount_unit = product.standard_price + tmpl_available = product.product_tmpl_id.qty_available + tmpl_price = product.product_tmpl_id.standard_price if move.state == 'done': product_avail -= move.product_qty - template_avail -= move.product_qty - new_cost_price = ( + tmpl_available -= move.product_qty + new_product_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}) + new_tmpl_price = ((tmpl_price * tmpl_available + prod_total_cost) / + ((tmpl_available > 0.0 and tmpl_available or + 0.0) + move.product_qty)) + product.sudo().standard_price = new_product_price + product.sudo().product_tmpl_id.standard_price = new_tmpl_price @api.model def get_price_unit(self, move): if move.production_id: - return move.production_id.calc_mrp_real_cost() / move.product_qty + return move.production_id.real_cost / move.product_qty else: return super(StockMove, self).get_price_unit(move) diff --git a/mrp_production_real_cost/static/description/icon.png b/mrp_production_real_cost/static/description/icon.png new file mode 100644 index 000000000..7c1450374 Binary files /dev/null and b/mrp_production_real_cost/static/description/icon.png differ diff --git a/mrp_production_real_cost/static/description/icon.svg b/mrp_production_real_cost/static/description/icon.svg new file mode 100644 index 000000000..7e3b32308 --- /dev/null +++ b/mrp_production_real_cost/static/description/icon.svg @@ -0,0 +1,297 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mrp_production_real_cost/tests/__init__.py b/mrp_production_real_cost/tests/__init__.py new file mode 100644 index 000000000..63eef852e --- /dev/null +++ b/mrp_production_real_cost/tests/__init__.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +# © 2015 Pedro M. Baeza +# © 2015 Antiun Ingeniería +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from . import test_mrp_production_real_cost diff --git a/mrp_production_real_cost/tests/test_mrp_production_real_cost.py b/mrp_production_real_cost/tests/test_mrp_production_real_cost.py new file mode 100644 index 000000000..2b0bea051 --- /dev/null +++ b/mrp_production_real_cost/tests/test_mrp_production_real_cost.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +# © 2015 Pedro M. Baeza +# © 2015 Antiun Ingeniería +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from openerp.tests import common +import time + + +class TestMrpProductionRealCost(common.TransactionCase): + def setUp(self): + super(TestMrpProductionRealCost, self).setUp() + self.production = self.env.ref( + 'mrp_operations_extension.mrp_production_opeext') + self.production.signal_workflow('button_confirm') + self.production.force_production() + + def test_flow(self): + line = self.production.workcenter_lines[1] + line.pre_cost = 10 + line.post_cost = 20 + line.signal_workflow('button_start_working') + self.assertEqual(len(self.production.analytic_line_ids), 1) + time.sleep(1) + line.signal_workflow('button_pause') + self.assertEqual(len(self.production.analytic_line_ids), 2) + line.signal_workflow('button_resume') + time.sleep(1) + line.signal_workflow('button_done') + self.assertEqual(len(self.production.analytic_line_ids), 4) + self.production.analytic_line_ids[:1].amount = -10 + self.assertTrue(self.production.real_cost) + + def test_produce(self): + # Set an impossible price to see if it changes + initial_price = 999999999 + self.production.product_id.standard_price = initial_price + self.production.product_id.cost_method = 'average' + self.production.action_produce( + self.production.id, self.production.product_qty, 'consume_produce') + self.assertEqual(len(self.production.analytic_line_ids), 4) + self.assertNotEqual( + initial_price, self.production.product_id.standard_price) diff --git a/mrp_production_real_cost/views/mrp_production_view.xml b/mrp_production_real_cost/views/mrp_production_view.xml index f6c9397a1..94be0262f 100644 --- a/mrp_production_real_cost/views/mrp_production_view.xml +++ b/mrp_production_real_cost/views/mrp_production_view.xml @@ -42,7 +42,6 @@ - diff --git a/mrp_production_real_cost/views/res_config_view.xml b/mrp_production_real_cost/views/res_config_view.xml deleted file mode 100644 index f3e3f75fc..000000000 --- a/mrp_production_real_cost/views/res_config_view.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - 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 deleted file mode 100644 index 92d4c4468..000000000 --- a/mrp_production_real_cost/wizard/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -# -*- 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 deleted file mode 100644 index ad2ebddba..000000000 --- a/mrp_production_real_cost/wizard/mrp_product_produce.py +++ /dev/null @@ -1,20 +0,0 @@ -# -*- 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 diff --git a/mrp_project/tests/test_mrp_project.py b/mrp_project/tests/test_mrp_project.py index cbc070785..431716bf1 100644 --- a/mrp_project/tests/test_mrp_project.py +++ b/mrp_project/tests/test_mrp_project.py @@ -71,6 +71,9 @@ class TestMrpProject(common.TransactionCase): def test_button_end_work(self): work = self.env['project.task.work'].create( {'task_id': self.task.id, + 'name': 'Test', + 'user_id': self.env.uid, + 'hours': 0, 'date': fields.Datetime.now()}) time.sleep(1) work.button_end_work() diff --git a/oca_dependencies.txt b/oca_dependencies.txt index 8e9d3e0ce..3ca90d77a 100644 --- a/oca_dependencies.txt +++ b/oca_dependencies.txt @@ -2,3 +2,5 @@ # Add a repository url and branch if you need a forked version product-attribute account-analytic +product-variant +