Skip to content

Commit

Permalink
[ADD] mrp_routing_workcenter_capacity: In MRP operations new fields c…
Browse files Browse the repository at this point in the history
…apacity, time before production, and time after production.
  • Loading branch information
alfredoavanzosc committed Jul 15, 2021
1 parent 8da8770 commit 66d57bc
Show file tree
Hide file tree
Showing 12 changed files with 397 additions and 1 deletion.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
language: python

python:
- "3.5"
- "3.6"

sudo: false
cache: pip
Expand Down
35 changes: 35 additions & 0 deletions mrp_routing_workcenter_capacity/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
.. 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

===============================
MRP Routing workcenter capacity
===============================

* In MRP operations new fields capacity, time before production, and time after
production.
* When calculating the "Expected Duration" of the OF work orders, it will take
the capacity defined in the operation, not the one defined in the Work
Center.
* The fields "Time before prod.", "Time after prod." defined in the operation
also participate in the calculation, if they are informed. If they are not
informed, those of the Work Center will be used.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues
<https://github.com/avanzosc/mrp-addons/issues>`_. In case of trouble,
please check there if your issue has already been reported. If you spotted
it first, help us smash it by providing detailed and welcomed feedback.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Contributors
------------

* Ana Juaristi <anajuaristi@avanzosc.es>
* Alfredo de la Fuente <alfredodelafuente@avanzosc.es>
1 change: 1 addition & 0 deletions mrp_routing_workcenter_capacity/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
16 changes: 16 additions & 0 deletions mrp_routing_workcenter_capacity/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright 2021 Alfredo de la Fuente - AvanzOSC
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
"name": "MRP Routing Workcenter Capacity",
"version": '14.0.1.0.0',
"author": "Avanzosc",
"license": "AGPL-3",
"category": "Manufacturing/Manufacturing",
"depends": [
"mrp",
],
"data": [
'views/mrp_routing_workcenter_views.xml'
],
"installable": True,
}
81 changes: 81 additions & 0 deletions mrp_routing_workcenter_capacity/i18n/es.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mrp_routing_workcenter_capacity
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-07-15 14:18+0000\n"
"PO-Revision-Date: 2021-07-15 14:18+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: mrp_routing_workcenter_capacity
#: model:ir.model.fields,field_description:mrp_routing_workcenter_capacity.field_mrp_routing_workcenter__capacity
msgid "Capacity"
msgstr "Capacidad"

#. module: mrp_routing_workcenter_capacity
#: model:ir.model.fields,field_description:mrp_routing_workcenter_capacity.field_mrp_routing_workcenter__display_name
#: model:ir.model.fields,field_description:mrp_routing_workcenter_capacity.field_mrp_workorder__display_name
msgid "Display Name"
msgstr "Nombre mostrado"

#. module: mrp_routing_workcenter_capacity
#: model:ir.model.fields,field_description:mrp_routing_workcenter_capacity.field_mrp_routing_workcenter__id
#: model:ir.model.fields,field_description:mrp_routing_workcenter_capacity.field_mrp_workorder__id
msgid "ID"
msgstr ""

#. module: mrp_routing_workcenter_capacity
#: model:ir.model.fields,field_description:mrp_routing_workcenter_capacity.field_mrp_routing_workcenter____last_update
#: model:ir.model.fields,field_description:mrp_routing_workcenter_capacity.field_mrp_workorder____last_update
msgid "Last Modified on"
msgstr "Última modificación el"

#. module: mrp_routing_workcenter_capacity
#: code:addons/mrp_routing_workcenter_capacity/models/mrp_routing_workcenter.py:0
#, python-format
msgid "The capacity must be strictly positive."
msgstr "La capacidad debe ser estrictamente positiva. "

#. module: mrp_routing_workcenter_capacity
#: model:ir.model.fields,field_description:mrp_routing_workcenter_capacity.field_mrp_routing_workcenter__time_stop
msgid "Time after prod."
msgstr "Tiempo después producción"

#. module: mrp_routing_workcenter_capacity
#: model:ir.model.fields,field_description:mrp_routing_workcenter_capacity.field_mrp_routing_workcenter__time_start
msgid "Time before prod."
msgstr "Tiempo antes producción"

#. module: mrp_routing_workcenter_capacity
#: model:ir.model.fields,help:mrp_routing_workcenter_capacity.field_mrp_routing_workcenter__time_stop
msgid "Time in minutes for the cleaning."
msgstr "Tiempo en minutos para la limpieza."

#. module: mrp_routing_workcenter_capacity
#: model:ir.model.fields,help:mrp_routing_workcenter_capacity.field_mrp_routing_workcenter__time_start
msgid "Time in minutes for the setup."
msgstr "Tiempo en minutos para la instalación."

#. module: mrp_routing_workcenter_capacity
#: model:ir.model,name:mrp_routing_workcenter_capacity.model_mrp_routing_workcenter
msgid "Work Center Usage"
msgstr "Utilización del centro de producción"

#. module: mrp_routing_workcenter_capacity
#: model:ir.model,name:mrp_routing_workcenter_capacity.model_mrp_workorder
msgid "Work Order"
msgstr "Orden de trabajo"

#. module: mrp_routing_workcenter_capacity
#: model_terms:ir.ui.view,arch_db:mrp_routing_workcenter_capacity.mrp_routing_workcenter_form_view
msgid "minutes"
msgstr "minutos"

Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * mrp_routing_workcenter_capacity
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-07-15 14:18+0000\n"
"PO-Revision-Date: 2021-07-15 14:18+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: mrp_routing_workcenter_capacity
#: model:ir.model.fields,field_description:mrp_routing_workcenter_capacity.field_mrp_routing_workcenter__capacity
msgid "Capacity"
msgstr ""

#. module: mrp_routing_workcenter_capacity
#: model:ir.model.fields,field_description:mrp_routing_workcenter_capacity.field_mrp_routing_workcenter__display_name
#: model:ir.model.fields,field_description:mrp_routing_workcenter_capacity.field_mrp_workorder__display_name
msgid "Display Name"
msgstr ""

#. module: mrp_routing_workcenter_capacity
#: model:ir.model.fields,field_description:mrp_routing_workcenter_capacity.field_mrp_routing_workcenter__id
#: model:ir.model.fields,field_description:mrp_routing_workcenter_capacity.field_mrp_workorder__id
msgid "ID"
msgstr ""

#. module: mrp_routing_workcenter_capacity
#: model:ir.model.fields,field_description:mrp_routing_workcenter_capacity.field_mrp_routing_workcenter____last_update
#: model:ir.model.fields,field_description:mrp_routing_workcenter_capacity.field_mrp_workorder____last_update
msgid "Last Modified on"
msgstr ""

#. module: mrp_routing_workcenter_capacity
#: code:addons/mrp_routing_workcenter_capacity/models/mrp_routing_workcenter.py:0
#, python-format
msgid "The capacity must be strictly positive."
msgstr ""

#. module: mrp_routing_workcenter_capacity
#: model:ir.model.fields,field_description:mrp_routing_workcenter_capacity.field_mrp_routing_workcenter__time_stop
msgid "Time after prod."
msgstr ""

#. module: mrp_routing_workcenter_capacity
#: model:ir.model.fields,field_description:mrp_routing_workcenter_capacity.field_mrp_routing_workcenter__time_start
msgid "Time before prod."
msgstr ""

#. module: mrp_routing_workcenter_capacity
#: model:ir.model.fields,help:mrp_routing_workcenter_capacity.field_mrp_routing_workcenter__time_stop
msgid "Time in minutes for the cleaning."
msgstr ""

#. module: mrp_routing_workcenter_capacity
#: model:ir.model.fields,help:mrp_routing_workcenter_capacity.field_mrp_routing_workcenter__time_start
msgid "Time in minutes for the setup."
msgstr ""

#. module: mrp_routing_workcenter_capacity
#: model:ir.model,name:mrp_routing_workcenter_capacity.model_mrp_routing_workcenter
msgid "Work Center Usage"
msgstr ""

#. module: mrp_routing_workcenter_capacity
#: model:ir.model,name:mrp_routing_workcenter_capacity.model_mrp_workorder
msgid "Work Order"
msgstr ""

#. module: mrp_routing_workcenter_capacity
#: model_terms:ir.ui.view,arch_db:mrp_routing_workcenter_capacity.mrp_routing_workcenter_form_view
msgid "minutes"
msgstr ""
2 changes: 2 additions & 0 deletions mrp_routing_workcenter_capacity/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import mrp_routing_workcenter
from . import mrp_workorder
49 changes: 49 additions & 0 deletions mrp_routing_workcenter_capacity/models/mrp_routing_workcenter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Copyright 2021 Alfredo de la fuente - AvanzOSC
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
from odoo import models, fields, api, exceptions, _


class MrpRoutingWorkcenter(models.Model):
_inherit = 'mrp.routing.workcenter'

capacity = fields.Float(
string='Capacity', default=1.0)
time_start = fields.Float(
string='Time before prod.', help="Time in minutes for the setup.")
time_stop = fields.Float(
string='Time after prod.', help="Time in minutes for the cleaning.")

@api.depends('time_cycle_manual', 'time_mode', 'workorder_ids')
def _compute_time_cycle(self):
result = super(MrpRoutingWorkcenter, self)._compute_time_cycle()
manual_ops = self.filtered(
lambda operation: operation.time_mode == 'manual')
for operation in manual_ops:
operation.time_cycle = operation.time_cycle_manual
operations = self - manual_ops
for operation in operations.filtered(lambda x: x.capacity):
data = self.env['mrp.workorder'].read_group(
[('operation_id', '=', operation.id),
('qty_produced', '>', 0),
('state', '=', 'done')
],
['operation_id', 'duration', 'qty_produced'],
['operation_id'], limit=operation.time_mode_batch)
count_data = dict(
(item['operation_id'][0],
(item['duration'],
item['qty_produced'])) for item in data)
if count_data.get(operation.id) and count_data[operation.id][1]:
operation.time_cycle = (
count_data[operation.id][0] /
count_data[operation.id][1]) * (operation.capacity or 1.0)
else:
operation.time_cycle = operation.time_cycle_manual
return result

@api.constrains('capacity')
def _check_capacity(self):
if any(routing_workcenter.capacity < 0.0
for routing_workcenter in self):
raise exceptions.UserError(
_('The capacity must be strictly positive.'))
40 changes: 40 additions & 0 deletions mrp_routing_workcenter_capacity/models/mrp_workorder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright 2021 Alfredo de la fuente - AvanzOSC
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
from odoo import models
from odoo.tools import float_round


class MrpWorkorder(models.Model):
_inherit = 'mrp.workorder'

def _get_duration_expected(self, alternative_workcenter=False, ratio=1):
self.ensure_one()
if not self.workcenter_id and not self.operation_id:
return super(MrpWorkorder, self)._get_duration_expected(
alternative_workcenter=alternative_workcenter, ratio=ratio)
qty_production = self.production_id.product_uom_id._compute_quantity(
self.qty_production, self.production_id.product_id.uom_id)
capacity = (
self.operation_id.capacity if self.operation_id.capacity else
self.workcenter_id.capacity)
cycle_number = float_round(qty_production / capacity,
precision_digits=0, rounding_method='UP')
if self.operation_id.time_start or self.operation_id.time_stop:
time_start = self.operation_id.time_start
time_stop = self.operation_id.time_stop
else:
time_start = self.workcenter_id.time_start
time_stop = self.workcenter_id.time_stop
if alternative_workcenter:
duration_expected_working = (
(self.duration_expected - time_start - time_stop) *
self.workcenter_id.time_efficiency / (100.0 * cycle_number))
if duration_expected_working < 0:
duration_expected_working = 0
return (alternative_workcenter.time_start +
alternative_workcenter.time_stop +
cycle_number * duration_expected_working * 100.0 /
alternative_workcenter.time_efficiency)
time_cycle = self.operation_id and self.operation_id.time_cycle or 60.0
return (time_start + time_stop + cycle_number * time_cycle * 100.0 /
self.workcenter_id.time_efficiency)
1 change: 1 addition & 0 deletions mrp_routing_workcenter_capacity/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_mrp_routing_workcenter_capacity
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Copyright 2021 Alfredo de la Fuente - AvanzOSC
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
from odoo.tests import common


class TestMrpRoutingWorkcenterCapacity(common.SavepointCase):

@classmethod
def setUpClass(cls):
super(TestMrpRoutingWorkcenterCapacity, cls).setUpClass()
cls.product = cls.env.ref('mrp.product_product_computer_desk_head')
cls.mrp_bom = cls.env['mrp.bom'].search(
[('product_tmpl_id', '=', cls.product.product_tmpl_id.id)])
cls.operation = cls.mrp_bom.operation_ids[0]
operation_vals = {
'capacity': 2,
'time_cycle_manual': 60}
cls.operation.write(operation_vals)
cls.workcenter = cls.operation.workcenter_id
production_vals = {
'product_id': cls.product.id,
'product_uom_id': cls.product.uom_id.id,
'bom_id': cls.mrp_bom.id,
'product_qty': 1}
cls.production = cls.env['mrp.production'].create(production_vals)
cls.production._onchange_workorder_ids()
cls.production._onchange_product_qty()

def test_mrp_routing_workcenter_capacity(self):
workorder = self.production.workorder_ids[0]
self.assertEqual(workorder.duration_expected, 60.0)
self.production.product_qty = 2
self.production._onchange_product_qty()
self.assertEqual(workorder.duration_expected, 60.0)
self.production.product_qty = 3
self.production._onchange_product_qty()
self.assertEqual(workorder.duration_expected, 120.0)
operation_vals = {'time_start': 10,
'time_stop': 10}
self.operation.write(operation_vals)
self.production._onchange_product_qty()
self.assertEqual(workorder.duration_expected, 140.0)
workcenter_vals = {'capacity': 1,
'time_start': 20,
'time_stop': 20}
self.workcenter.write(workcenter_vals)
result = workorder._get_duration_expected(
alternative_workcenter=self.workcenter, ratio=1)
self.assertEqual(result, 160.0)
operation_vals = {'time_mode': 'auto',
'time_cycle_manual': 30}
self.operation.write(operation_vals)
self.operation._compute_time_cycle()
self.assertEqual(self.operation.time_cycle, 30.0)
workorder_vals = {'workcenter_id': False,
'operation_id': False}
workorder.write(workorder_vals)
result = workorder._get_duration_expected()
self.assertEqual(result, 140.0)
Loading

0 comments on commit 66d57bc

Please sign in to comment.