[IMP] mrp_production_real_cost: Tests + cleaning + adaptation to OCA

This commit is contained in:
Pedro M. Baeza
2015-12-10 14:51:17 +01:00
parent 06942b61b1
commit 86a455a0db
22 changed files with 557 additions and 441 deletions

View File

@@ -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
<https://github.com/OCA/manufacture/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
<https://github.com/OCA/
manufacture/issues/new?body=module:%20
mrp_production_real_cost%0Aversion:%20
8.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Credits
=======
Contributors
------------
* Pedro M. Baeza <pedro.baeza@serviciosbaeza.com>
* Ana Juaristi <ajuaristio@gmail.com>
* Ainara Galdona <agaldona@avanzosc.es>
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.

View File

@@ -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

View File

@@ -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,
}

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="1">
<record id="mrp.mrp_production_1" model="mrp.production">
<field name="project_id" ref="project.project_project_1"/>
<field name="analytic_account_id" search="[('name', 'ilike', '%jackson%')]"/>
</record>
<record id="mrp_operations.mrp_production_op1" model="mrp.production">
<field name="project_id" ref="project.project_project_1"/>
<field name="analytic_account_id" search="[('name', 'ilike', '%jackson%')]"/>
</record>
<record id="mrp_operations.mrp_production_mo1" model="mrp.production">
<field name="project_id" ref="project.project_project_1"/>
<field name="analytic_account_id" search="[('name', 'ilike', '%jackson%')]"/>
</record>
</data>
</openerp>

View File

@@ -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 <transbot@odoo-community.org>\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 ""

View File

@@ -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 ""

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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,

View File

@@ -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

View File

@@ -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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -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

View File

@@ -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)

View File

@@ -42,7 +42,6 @@
<field name="arch" type="xml">
<field name="product_uom" position="after">
<field name="real_cost" />
<field name="percentage_difference" />
</field>
</field>
</record>

View File

@@ -1,18 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="mrp_config_settings_costs">
<field name="name">mrp.config.settings.costs</field>
<field name="model">mrp.config.settings</field>
<field name="inherit_id" ref="mrp.view_mrp_config" />
<field name="arch" type="xml">
<xpath expr="//field[@name='module_mrp_repair']/.." position="after">
<div>
<field name="final_product_analytic_cost" class="oe_inline"/>
<label for="final_product_analytic_cost"/>
</div>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@@ -1,6 +0,0 @@
# -*- coding: utf-8 -*-
##############################################################################
# For copyright and license notices, see __openerp__.py file in root directory
##############################################################################
from . import mrp_product_produce

View File

@@ -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

View File

@@ -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()

View File

@@ -2,3 +2,5 @@
# Add a repository url and branch if you need a forked version
product-attribute
account-analytic
product-variant