diff --git a/mrp_production_date_planned_finished/README.rst b/mrp_production_date_planned_finished/README.rst new file mode 100644 index 000000000..f86ee85e1 --- /dev/null +++ b/mrp_production_date_planned_finished/README.rst @@ -0,0 +1 @@ +TO BE GENERATED diff --git a/mrp_production_date_planned_finished/__init__.py b/mrp_production_date_planned_finished/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/mrp_production_date_planned_finished/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/mrp_production_date_planned_finished/__manifest__.py b/mrp_production_date_planned_finished/__manifest__.py new file mode 100644 index 000000000..67cedcfe9 --- /dev/null +++ b/mrp_production_date_planned_finished/__manifest__.py @@ -0,0 +1,16 @@ +# Copyright 2022 Camptocamp SA (https://www.camptocamp.com). +# @author Iván Todorovich +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "MRP Production Date Planned Finished", + "summary": "Allows to plan production from the desired finish date", + "version": "15.0.1.0.0", + "author": "Camptocamp, Odoo Community Association (OCA)", + "maintainers": ["ivantodorovich"], + "website": "https://github.com/OCA/manufacture", + "license": "AGPL-3", + "category": "Manufacturing", + "depends": ["mrp"], + "data": ["views/mrp_production.xml"], +} diff --git a/mrp_production_date_planned_finished/models/__init__.py b/mrp_production_date_planned_finished/models/__init__.py new file mode 100644 index 000000000..a9e5f13e4 --- /dev/null +++ b/mrp_production_date_planned_finished/models/__init__.py @@ -0,0 +1 @@ +from . import mrp_production diff --git a/mrp_production_date_planned_finished/models/mrp_production.py b/mrp_production_date_planned_finished/models/mrp_production.py new file mode 100644 index 000000000..81e50b309 --- /dev/null +++ b/mrp_production_date_planned_finished/models/mrp_production.py @@ -0,0 +1,26 @@ +# Copyright 2022 Camptocamp SA (https://www.camptocamp.com). +# @author Iván Todorovich +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from dateutil.relativedelta import relativedelta + +from odoo import api, models + + +class MrpProduction(models.Model): + _inherit = "mrp.production" + + @api.onchange("date_planned_finished") + def _onchange_date_planned_finished_set_date_planned_start(self): + if self.date_planned_finished and not self.is_planned: + date_planned_start = self.date_planned_finished + date_planned_start -= relativedelta(days=self.product_id.produce_delay) + date_planned_start -= relativedelta(days=self.company_id.manufacturing_lead) + if date_planned_start == self.date_planned_finished: + date_planned_start -= relativedelta(hours=1) + if self.date_planned_start != date_planned_start: + self.date_planned_start = date_planned_start + self.move_raw_ids = [ + (1, m.id, {"date": self.date_planned_start}) + for m in self.move_raw_ids + ] diff --git a/mrp_production_date_planned_finished/readme/CONTRIBUTORS.rst b/mrp_production_date_planned_finished/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..a1e0a8395 --- /dev/null +++ b/mrp_production_date_planned_finished/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* `Camptocamp `_ + + * Iván Todorovich diff --git a/mrp_production_date_planned_finished/readme/DESCRIPTION.rst b/mrp_production_date_planned_finished/readme/DESCRIPTION.rst new file mode 100644 index 000000000..0321a154e --- /dev/null +++ b/mrp_production_date_planned_finished/readme/DESCRIPTION.rst @@ -0,0 +1,5 @@ +Shows the Scheduled End Date on Manufacturing Orders, and allows to change the start +date from it, through an onchange. + +It's useful for companies wanting to plan their manufacturing orders from the target +finish date. Usually these companies have long manufacturing times (days or weeks). diff --git a/mrp_production_date_planned_finished/tests/__init__.py b/mrp_production_date_planned_finished/tests/__init__.py new file mode 100644 index 000000000..7a9da722a --- /dev/null +++ b/mrp_production_date_planned_finished/tests/__init__.py @@ -0,0 +1 @@ +from . import test_date_planned_finished diff --git a/mrp_production_date_planned_finished/tests/test_date_planned_finished.py b/mrp_production_date_planned_finished/tests/test_date_planned_finished.py new file mode 100644 index 000000000..a4c0e23b5 --- /dev/null +++ b/mrp_production_date_planned_finished/tests/test_date_planned_finished.py @@ -0,0 +1,51 @@ +# Copyright 2022 Camptocamp SA (https://www.camptocamp.com). +# @author Iván Todorovich +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from lxml import etree + +from odoo.tests import Form, TransactionCase + + +class TestDatePlannedFinished(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.company = cls.env.ref("base.main_company") + cls.company.manufacturing_lead = 1 + cls.product = cls.env.ref("mrp.product_product_computer_desk") + cls.product.produce_delay = 1 + cls.product_bom = cls.env.ref("mrp.mrp_bom_desk") + + def test_mrp_production_date_planned_finished_onchange(self): + """Test that date_planned_start is set when date_planned_finished is changed.""" + with Form(self.env["mrp.production"]) as mo: + mo.product_id = self.product + mo.bom_id = self.product_bom + mo.product_qty = 1 + mo.date_planned_finished = "2022-10-10 10:00:00" + self.assertEqual(mo.date_planned_start, "2022-10-08 10:00:00") + + def test_mrp_production_date_planned_finished_decoration(self): + """Test that the date_planned_finished field is decorated properly + + Its decoration has to exactly match the date_planned_start one. + As this might change if odoo updates their code, or during migrations, + this test case will track any mismatches and fail. + """ + res = self.env["mrp.production"].fields_view_get(view_type="form") + doc = etree.XML(res["arch"]) + date_planned_start = doc.xpath("//field[@name='date_planned_start']")[0] + date_planned_finished = doc.xpath("//field[@name='date_planned_finished']")[0] + decoration_attrs = [ + attr + for attr in date_planned_start.attrib.keys() + if attr.startswith("decoration-") + ] + for attr in decoration_attrs: + self.assertEqual( + date_planned_start.attrib[attr], + date_planned_finished.attrib[attr], + f"date_planned_finished decoration mismatch: {attr}", + ) diff --git a/mrp_production_date_planned_finished/views/mrp_production.xml b/mrp_production_date_planned_finished/views/mrp_production.xml new file mode 100644 index 000000000..caba4d0d3 --- /dev/null +++ b/mrp_production_date_planned_finished/views/mrp_production.xml @@ -0,0 +1,57 @@ + + + + + + mrp.production + + + + + + + + 1 + {"readonly": [("state", "in", ["close", "cancel"])]} + state not in ('done', 'cancel') and date_planned_start < now + state not in ('done', 'cancel') and date_planned_start < current_date + state not in ('done', 'cancel') and (date_planned_start < current_date or date_planned_start < now) + + + + + + mrp.production + + + + + + + + + diff --git a/setup/mrp_production_date_planned_finished/odoo/addons/mrp_production_date_planned_finished b/setup/mrp_production_date_planned_finished/odoo/addons/mrp_production_date_planned_finished new file mode 120000 index 000000000..e74edc27a --- /dev/null +++ b/setup/mrp_production_date_planned_finished/odoo/addons/mrp_production_date_planned_finished @@ -0,0 +1 @@ +../../../../mrp_production_date_planned_finished \ No newline at end of file diff --git a/setup/mrp_production_date_planned_finished/setup.py b/setup/mrp_production_date_planned_finished/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/mrp_production_date_planned_finished/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)