diff --git a/purchase_request_operating_unit/README.rst b/purchase_request_operating_unit/README.rst new file mode 100644 index 0000000000..1f1d0fd449 --- /dev/null +++ b/purchase_request_operating_unit/README.rst @@ -0,0 +1,95 @@ +=================================== +Operating Unit in Purchase Requests +=================================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Foperating--unit-lightgray.png?logo=github + :target: https://github.com/OCA/operating-unit/tree/16.0/purchase_request_operating_unit + :alt: OCA/operating-unit +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/operating-unit-16-0/operating-unit-16-0-purchase_request_operating_unit + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/webui/builds.html?repo=OCA/operating-unit&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module introduces the following features: + +* Adds the Operating Unit (OU) to the Purchase Request. + +* The user’s default Operating Unit (OU) is proposed at the time of creating the Purchase Request. + +* Security rules are defined to ensure that users can only see the Purchase Request of that Operating Units in which they are allowed access to. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +Follow these steps: + +#. Create or use an existing Operating Unit (OU) in Settings -> + Users & Configuration -> Operating Unit. +#. Change the configuration of the Users. In Application Accesses, put an User + as Request manager and another one as Request User. +#. Create a Purchase Request Order. By default, if there is no Approver, any + Manager with the same OU can accept the PO. If you specify an Approver, he + must be in the same Operating Unit as the Purchase Request. + +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 `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Eficent +* SerpentCS + +Contributors +~~~~~~~~~~~~ + +* Jordi Ballester Alomar +* Serpent Consulting Services Pvt. Ltd. +* Saran Lim. + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +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. + +This module is part of the `OCA/operating-unit `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/purchase_request_operating_unit/__init__.py b/purchase_request_operating_unit/__init__.py new file mode 100644 index 0000000000..6081d63bec --- /dev/null +++ b/purchase_request_operating_unit/__init__.py @@ -0,0 +1,4 @@ +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from . import model +from . import wizard diff --git a/purchase_request_operating_unit/__manifest__.py b/purchase_request_operating_unit/__manifest__.py new file mode 100644 index 0000000000..02ec3f436d --- /dev/null +++ b/purchase_request_operating_unit/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright 2016-19 ForgeFlow S.L. +# Copyright 2016-19 Serpent Consulting Services Pvt. Ltd. +# () +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +{ + "name": "Operating Unit in Purchase Requests", + "version": "16.0.1.0.0", + "author": "Eficent, SerpentCS, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/operating-unit", + "license": "LGPL-3", + "category": "Purchase Management", + "depends": ["purchase_request", "purchase_operating_unit", "stock_operating_unit"], + "data": [ + "security/purchase_security.xml", + "view/purchase_request_view.xml", + "wizard/purchase_request_line_make_purchase_order_view.xml", + ], + "installable": True, +} diff --git a/purchase_request_operating_unit/i18n/fr.po b/purchase_request_operating_unit/i18n/fr.po new file mode 100644 index 0000000000..c57b6b6d87 --- /dev/null +++ b/purchase_request_operating_unit/i18n/fr.po @@ -0,0 +1,99 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * purchase_request_operating_unit +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2022-06-28 11:05+0000\n" +"Last-Translator: Khalid Hazam \n" +"Language-Team: none\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: purchase_request_operating_unit +#: code:addons/purchase_request_operating_unit/model/purchase_request.py:0 +#, python-format +msgid "" +"Configuration error. The Purchase Request and the Warehouse of picking type " +"must belong to the same Operating Unit." +msgstr "" + +#. module: purchase_request_operating_unit +#: code:addons/purchase_request_operating_unit/model/purchase_request.py:0 +#, fuzzy, python-format +msgid "Configuration error. The approver has not the indicated Operating Unit" +msgstr "" +"Erreur de configuration. L’approbateur n'a pas l'unité opérationnelle " +"indiquée" + +#. module: purchase_request_operating_unit +#: code:addons/purchase_request_operating_unit/wizard/purchase_request_line_make_purchase_order.py:0 +#, fuzzy, python-format +msgid "" +"Could not process !You have to select linesfrom the same operating unit." +msgstr "" +"Impossible de traiter ! Vous devez sélectionner les lignes de la même unité " +"opérationnelle." + +#. module: purchase_request_operating_unit +#: model:ir.model.fields,field_description:purchase_request_operating_unit.field_purchase_request__operating_unit_id +#: model:ir.model.fields,field_description:purchase_request_operating_unit.field_purchase_request_line__operating_unit_id +#: model:ir.model.fields,field_description:purchase_request_operating_unit.field_purchase_request_line_make_purchase_order__operating_unit_id +#: model_terms:ir.ui.view,arch_db:purchase_request_operating_unit.purchase_request_line_search +#: model_terms:ir.ui.view,arch_db:purchase_request_operating_unit.view_purchase_request_search +msgid "Operating Unit" +msgstr "Unité opérationnelle" + +#. module: purchase_request_operating_unit +#: model:ir.model,name:purchase_request_operating_unit.model_purchase_request +msgid "Purchase Request" +msgstr "Demande d'achat" + +#. module: purchase_request_operating_unit +#: model:ir.model,name:purchase_request_operating_unit.model_purchase_request_line +msgid "Purchase Request Line" +msgstr "Ligne de la demande d'achat" + +#. module: purchase_request_operating_unit +#: model:ir.model,name:purchase_request_operating_unit.model_purchase_request_line_make_purchase_order +#, fuzzy +msgid "Purchase Request Line Make Purchase Order" +msgstr "Ligne de demande d'achat fait Bon de commande" + +#. module: purchase_request_operating_unit +#: model:ir.model,name:purchase_request_operating_unit.model_stock_rule +msgid "Stock Rule" +msgstr "" + +#. module: purchase_request_operating_unit +#: code:addons/purchase_request_operating_unit/model/purchase_request.py:0 +#, python-format +msgid "" +"The Company in the Purchase Request and in the Operating Unit must bethe " +"same." +msgstr "" +"La société sur la demande d'achat et sur l'unité opérationnelle doit être la " +"même." + +#, python-format +#~ msgid "" +#~ "Configuration error. The Purchase Request and theWarehouse of picking " +#~ "type must belong to the same Operating Unit." +#~ msgstr "" +#~ "Erreur de configuration. La demande d'achat et l'entrepôt de prélèvement " +#~ "doivent appartenir à la même unité opérationnelle." + +#~ msgid "Display Name" +#~ msgstr "Nom affiché" + +#~ msgid "ID" +#~ msgstr "ID" + +#~ msgid "Last Modified on" +#~ msgstr "Dernière modification le" diff --git a/purchase_request_operating_unit/i18n/pt.po b/purchase_request_operating_unit/i18n/pt.po new file mode 100644 index 0000000000..fce60a9bc1 --- /dev/null +++ b/purchase_request_operating_unit/i18n/pt.po @@ -0,0 +1,75 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * purchase_request_operating_unit +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-02-29 15:13+0000\n" +"Last-Translator: Pedro Castro Silva \n" +"Language-Team: none\n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 3.10\n" + +#. module: purchase_request_operating_unit +#: code:addons/purchase_request_operating_unit/model/purchase_request.py:0 +#, python-format +msgid "" +"Configuration error. The Purchase Request and the Warehouse of picking type " +"must belong to the same Operating Unit." +msgstr "" + +#. module: purchase_request_operating_unit +#: code:addons/purchase_request_operating_unit/model/purchase_request.py:0 +#, python-format +msgid "Configuration error. The approver has not the indicated Operating Unit" +msgstr "" + +#. module: purchase_request_operating_unit +#: code:addons/purchase_request_operating_unit/wizard/purchase_request_line_make_purchase_order.py:0 +#, python-format +msgid "" +"Could not process !You have to select linesfrom the same operating unit." +msgstr "" + +#. module: purchase_request_operating_unit +#: model:ir.model.fields,field_description:purchase_request_operating_unit.field_purchase_request__operating_unit_id +#: model:ir.model.fields,field_description:purchase_request_operating_unit.field_purchase_request_line__operating_unit_id +#: model:ir.model.fields,field_description:purchase_request_operating_unit.field_purchase_request_line_make_purchase_order__operating_unit_id +#: model_terms:ir.ui.view,arch_db:purchase_request_operating_unit.purchase_request_line_search +#: model_terms:ir.ui.view,arch_db:purchase_request_operating_unit.view_purchase_request_search +msgid "Operating Unit" +msgstr "Unidade Operacional" + +#. module: purchase_request_operating_unit +#: model:ir.model,name:purchase_request_operating_unit.model_purchase_request +msgid "Purchase Request" +msgstr "" + +#. module: purchase_request_operating_unit +#: model:ir.model,name:purchase_request_operating_unit.model_purchase_request_line +msgid "Purchase Request Line" +msgstr "" + +#. module: purchase_request_operating_unit +#: model:ir.model,name:purchase_request_operating_unit.model_purchase_request_line_make_purchase_order +msgid "Purchase Request Line Make Purchase Order" +msgstr "" + +#. module: purchase_request_operating_unit +#: model:ir.model,name:purchase_request_operating_unit.model_stock_rule +msgid "Stock Rule" +msgstr "" + +#. module: purchase_request_operating_unit +#: code:addons/purchase_request_operating_unit/model/purchase_request.py:0 +#, python-format +msgid "" +"The Company in the Purchase Request and in the Operating Unit must bethe " +"same." +msgstr "" diff --git a/purchase_request_operating_unit/i18n/purchase_request_operating_unit.pot b/purchase_request_operating_unit/i18n/purchase_request_operating_unit.pot new file mode 100644 index 0000000000..652bfc835b --- /dev/null +++ b/purchase_request_operating_unit/i18n/purchase_request_operating_unit.pot @@ -0,0 +1,72 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * purchase_request_operating_unit +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 15.0\n" +"Report-Msgid-Bugs-To: \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: purchase_request_operating_unit +#: code:addons/purchase_request_operating_unit/model/purchase_request.py:0 +#, python-format +msgid "" +"Configuration error. The Purchase Request and the Warehouse of picking type " +"must belong to the same Operating Unit." +msgstr "" + +#. module: purchase_request_operating_unit +#: code:addons/purchase_request_operating_unit/model/purchase_request.py:0 +#, python-format +msgid "Configuration error. The approver has not the indicated Operating Unit" +msgstr "" + +#. module: purchase_request_operating_unit +#: code:addons/purchase_request_operating_unit/wizard/purchase_request_line_make_purchase_order.py:0 +#, python-format +msgid "" +"Could not process !You have to select linesfrom the same operating unit." +msgstr "" + +#. module: purchase_request_operating_unit +#: model:ir.model.fields,field_description:purchase_request_operating_unit.field_purchase_request__operating_unit_id +#: model:ir.model.fields,field_description:purchase_request_operating_unit.field_purchase_request_line__operating_unit_id +#: model:ir.model.fields,field_description:purchase_request_operating_unit.field_purchase_request_line_make_purchase_order__operating_unit_id +#: model_terms:ir.ui.view,arch_db:purchase_request_operating_unit.purchase_request_line_search +#: model_terms:ir.ui.view,arch_db:purchase_request_operating_unit.view_purchase_request_search +msgid "Operating Unit" +msgstr "" + +#. module: purchase_request_operating_unit +#: model:ir.model,name:purchase_request_operating_unit.model_purchase_request +msgid "Purchase Request" +msgstr "" + +#. module: purchase_request_operating_unit +#: model:ir.model,name:purchase_request_operating_unit.model_purchase_request_line +msgid "Purchase Request Line" +msgstr "" + +#. module: purchase_request_operating_unit +#: model:ir.model,name:purchase_request_operating_unit.model_purchase_request_line_make_purchase_order +msgid "Purchase Request Line Make Purchase Order" +msgstr "" + +#. module: purchase_request_operating_unit +#: model:ir.model,name:purchase_request_operating_unit.model_stock_rule +msgid "Stock Rule" +msgstr "" + +#. module: purchase_request_operating_unit +#: code:addons/purchase_request_operating_unit/model/purchase_request.py:0 +#, python-format +msgid "" +"The Company in the Purchase Request and in the Operating Unit must bethe " +"same." +msgstr "" diff --git a/purchase_request_operating_unit/model/__init__.py b/purchase_request_operating_unit/model/__init__.py new file mode 100644 index 0000000000..8e771c09a4 --- /dev/null +++ b/purchase_request_operating_unit/model/__init__.py @@ -0,0 +1,4 @@ +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from . import purchase_request +from . import stock_rule diff --git a/purchase_request_operating_unit/model/purchase_request.py b/purchase_request_operating_unit/model/purchase_request.py new file mode 100644 index 0000000000..debecd7175 --- /dev/null +++ b/purchase_request_operating_unit/model/purchase_request.py @@ -0,0 +1,86 @@ +# Copyright 2016-19 ForgeFlow S.L. +# Copyright 2016-19 Serpent Consulting Services Pvt. Ltd. +# () +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class PurchaseRequest(models.Model): + _inherit = "purchase.request" + + operating_unit_id = fields.Many2one( + "operating.unit", + string="Operating Unit", + states={ + "to_approve": [("readonly", True)], + "approved": [("readonly", True)], + "done": [("readonly", True)], + }, + default=lambda self: self.env["res.users"].operating_unit_default_get( + self._uid + ), + ) + + @api.constrains("operating_unit_id", "company_id") + def _check_company_operating_unit(self): + for rec in self: + if ( + rec.company_id + and rec.operating_unit_id + and rec.company_id != rec.operating_unit_id.company_id + ): + raise ValidationError( + _( + "The Company in the Purchase Request " + "and in the Operating Unit must be" + "the same." + ) + ) + + @api.constrains("operating_unit_id", "picking_type_id") + def _check_warehouse_operating_unit(self): + for rec in self: + picking_type = rec.picking_type_id + if picking_type: + if ( + picking_type.warehouse_id + and picking_type.warehouse_id.operating_unit_id + and rec.operating_unit_id + and picking_type.warehouse_id.operating_unit_id + != rec.operating_unit_id + ): + raise ValidationError( + _( + "Configuration error. The Purchase Request and the " + "Warehouse of picking type must belong to the same " + "Operating Unit." + ) + ) + + @api.constrains("operating_unit_id") + def _check_approver_operating_unit(self): + for rec in self: + if ( + rec.assigned_to + and rec.operating_unit_id + and rec.operating_unit_id not in rec.assigned_to.operating_unit_ids + ): + raise ValidationError( + _( + "Configuration error. The approver has not " + "the indicated Operating Unit" + ) + ) + + +class PurchaseRequestLine(models.Model): + _inherit = "purchase.request.line" + + operating_unit_id = fields.Many2one( + "operating.unit", + related="request_id.operating_unit_id", + string="Operating Unit", + store=True, + ) diff --git a/purchase_request_operating_unit/model/stock_rule.py b/purchase_request_operating_unit/model/stock_rule.py new file mode 100644 index 0000000000..f0b59d782c --- /dev/null +++ b/purchase_request_operating_unit/model/stock_rule.py @@ -0,0 +1,15 @@ +# Copyright 2023 ForgeFlow, S.L. +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0) + +from odoo import api, models + + +class StockRule(models.Model): + _inherit = "stock.rule" + + @api.model + def _prepare_purchase_request(self, origin, values): + res = super(StockRule, self)._prepare_purchase_request(origin, values) + if self.warehouse_id.operating_unit_id: + res.update({"operating_unit_id": self.warehouse_id.operating_unit_id.id}) + return res diff --git a/purchase_request_operating_unit/readme/CONTRIBUTORS.rst b/purchase_request_operating_unit/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..6251500b42 --- /dev/null +++ b/purchase_request_operating_unit/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* Jordi Ballester Alomar +* Serpent Consulting Services Pvt. Ltd. +* Saran Lim. diff --git a/purchase_request_operating_unit/readme/DESCRIPTION.rst b/purchase_request_operating_unit/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..b24fb80c0a --- /dev/null +++ b/purchase_request_operating_unit/readme/DESCRIPTION.rst @@ -0,0 +1,7 @@ +This module introduces the following features: + +* Adds the Operating Unit (OU) to the Purchase Request. + +* The user’s default Operating Unit (OU) is proposed at the time of creating the Purchase Request. + +* Security rules are defined to ensure that users can only see the Purchase Request of that Operating Units in which they are allowed access to. diff --git a/purchase_request_operating_unit/readme/USAGE.rst b/purchase_request_operating_unit/readme/USAGE.rst new file mode 100644 index 0000000000..48e96938bc --- /dev/null +++ b/purchase_request_operating_unit/readme/USAGE.rst @@ -0,0 +1,9 @@ +Follow these steps: + +#. Create or use an existing Operating Unit (OU) in Settings -> + Users & Configuration -> Operating Unit. +#. Change the configuration of the Users. In Application Accesses, put an User + as Request manager and another one as Request User. +#. Create a Purchase Request Order. By default, if there is no Approver, any + Manager with the same OU can accept the PO. If you specify an Approver, he + must be in the same Operating Unit as the Purchase Request. diff --git a/purchase_request_operating_unit/security/purchase_security.xml b/purchase_request_operating_unit/security/purchase_security.xml new file mode 100644 index 0000000000..6d58eaff66 --- /dev/null +++ b/purchase_request_operating_unit/security/purchase_security.xml @@ -0,0 +1,30 @@ + + + + + + + + + + ['|',('operating_unit_id','=',False), + ('operating_unit_id','in',[g.id for g in user.operating_unit_ids])] + Purchase Requests from allowed operating units + + + + + + + + + ['|',('request_id.operating_unit_id','=',False), + ('request_id.operating_unit_id','in',[g.id for g in user.operating_unit_ids])] + Purchase Requests lines from allowed operating units + + + + + + + diff --git a/purchase_request_operating_unit/static/description/icon.png b/purchase_request_operating_unit/static/description/icon.png new file mode 100644 index 0000000000..3a0328b516 Binary files /dev/null and b/purchase_request_operating_unit/static/description/icon.png differ diff --git a/purchase_request_operating_unit/static/description/index.html b/purchase_request_operating_unit/static/description/index.html new file mode 100644 index 0000000000..ca52e62972 --- /dev/null +++ b/purchase_request_operating_unit/static/description/index.html @@ -0,0 +1,441 @@ + + + + + + +Operating Unit in Purchase Requests + + + +
+

Operating Unit in Purchase Requests

+ + +

Beta License: LGPL-3 OCA/operating-unit Translate me on Weblate Try me on Runboat

+

This module introduces the following features:

+
    +
  • Adds the Operating Unit (OU) to the Purchase Request.
  • +
  • The user’s default Operating Unit (OU) is proposed at the time of creating the Purchase Request.
  • +
  • Security rules are defined to ensure that users can only see the Purchase Request of that Operating Units in which they are allowed access to.
  • +
+

Table of contents

+ +
+

Usage

+

Follow these steps:

+
    +
  1. Create or use an existing Operating Unit (OU) in Settings -> +Users & Configuration -> Operating Unit.
  2. +
  3. Change the configuration of the Users. In Application Accesses, put an User +as Request manager and another one as Request User.
  4. +
  5. Create a Purchase Request Order. By default, if there is no Approver, any +Manager with the same OU can accept the PO. If you specify an Approver, he +must be in the same Operating Unit as the Purchase Request.
  6. +
+
+
+

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.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Eficent
  • +
  • SerpentCS
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

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.

+

This module is part of the OCA/operating-unit project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/purchase_request_operating_unit/test-requirements.txt b/purchase_request_operating_unit/test-requirements.txt new file mode 100644 index 0000000000..60c9138394 --- /dev/null +++ b/purchase_request_operating_unit/test-requirements.txt @@ -0,0 +1 @@ +odoo-addon-purchase_operating_unit @ git+https://github.com/OCA/operating-unit@refs/pull/443/head#subdirectory=setup/purchase_operating_unit diff --git a/purchase_request_operating_unit/tests/__init__.py b/purchase_request_operating_unit/tests/__init__.py new file mode 100644 index 0000000000..5c730c69af --- /dev/null +++ b/purchase_request_operating_unit/tests/__init__.py @@ -0,0 +1,4 @@ +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from . import test_purchase_request_operating_unit +from . import test_purchase_request_to_rfq_operating_unit diff --git a/purchase_request_operating_unit/tests/test_purchase_request_operating_unit.py b/purchase_request_operating_unit/tests/test_purchase_request_operating_unit.py new file mode 100644 index 0000000000..5eb8d89439 --- /dev/null +++ b/purchase_request_operating_unit/tests/test_purchase_request_operating_unit.py @@ -0,0 +1,108 @@ +# Copyright 2016-19 ForgeFlow S.L. +# Copyright 2016-19 Serpent Consulting Services Pvt. Ltd. +# () +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from odoo.exceptions import ValidationError +from odoo.tests.common import Form, TransactionCase + + +class TestPurchaseRequestOperatingUnit(TransactionCase): + def setUp(self): + super().setUp() + # Models + self.res_users_model = self.env["res.users"] + self.purchase_request = self.env["purchase.request"] + self.purchase_request_line = self.env["purchase.request.line"] + # Company + self.company = self.env.ref("base.main_company") + self.company2 = self.env["res.company"].create({"name": "Test Company"}) + # Main Operating Unit + self.ou1 = self.env.ref("operating_unit.main_operating_unit") + # B2C Operating Unit + self.b2c = self.env.ref("operating_unit.b2c_operating_unit") + # Product + self.product1 = self.env.ref("product.product_product_7") + self.product_uom = self.env.ref("uom.product_uom_unit") + # User + self.user_root = self.env.ref("base.user_root") + # Groups + self.grp_pr_mngr = self.env.ref( + "purchase_request.group_purchase_request_manager" + ) + # Picking Type + b2c_wh = self.env.ref("stock_operating_unit.stock_warehouse_b2c") + self.b2c_type_in = b2c_wh.in_type_id + self.picking_type = self.env.ref("stock.picking_type_in") + + # Creates Users and Purchase request + self.user1 = self._create_user("user_1", [], self.company, [self.ou1]) + self.user2 = self._create_user( + "user_2", self.grp_pr_mngr, self.company, [self.b2c] + ) + self.request1 = self._create_purchase_request(self.ou1) + self._purchase_line(self.request1) + self.request2 = self._create_purchase_request(self.b2c, self.b2c_type_in.id) + self._purchase_line(self.request2) + + def _create_user(self, login, groups, company, operating_units, context=None): + """Create a user.""" + group_ids = [group.id for group in groups] + user = self.res_users_model.create( + { + "name": "Test Purchase Request User", + "login": login, + "password": "demo", + "email": "example@yourcompany.com", + "company_id": company.id, + "company_ids": [(4, company.id)], + "operating_unit_ids": [(4, ou.id) for ou in operating_units], + "groups_id": [(6, 0, group_ids)], + } + ) + return user + + def _purchase_line(self, request): + line = self.purchase_request_line.create( + { + "request_id": request.id, + "product_id": self.product1.id, + "product_uom_id": self.product_uom.id, + "product_qty": 5.0, + } + ) + return line + + def _create_purchase_request(self, operating_unit, picking_type_id=False): + purchase_request = self.purchase_request.create( + { + "assigned_to": self.user_root.id, + "picking_type_id": picking_type_id or self.picking_type.id, + "operating_unit_id": operating_unit.id, + } + ) + return purchase_request + + def test_purchase_request(self): + record = self.purchase_request.with_user(self.user2.id).search( + [("id", "=", self.request1.id), ("operating_unit_id", "=", self.ou1.id)] + ) + self.assertEqual( + record.ids, [], "User 2 should not have access to OU %s" % self.ou1.name + ) + + # Check company in OU and operating unit must be equal + with self.assertRaises(ValidationError): + with Form(self.request1) as pr: + pr.company_id = self.company2 + + # Check OU in picking type and operating unit must be equal + with self.assertRaises(ValidationError): + with Form(self.request1) as pr: + pr.picking_type_id = self.b2c_type_in + + # Check OU in assigned_to and operating unit must be equal + with self.assertRaises(ValidationError): + with Form(self.request1) as pr: + pr.assigned_to = self.user2 + pr.operating_unit_id = self.ou1 diff --git a/purchase_request_operating_unit/tests/test_purchase_request_to_rfq_operating_unit.py b/purchase_request_operating_unit/tests/test_purchase_request_to_rfq_operating_unit.py new file mode 100644 index 0000000000..d55d605923 --- /dev/null +++ b/purchase_request_operating_unit/tests/test_purchase_request_to_rfq_operating_unit.py @@ -0,0 +1,53 @@ +# Copyright 2016-19 ForgeFlow S.L. +# Copyright 2016-19 Serpent Consulting Services Pvt. Ltd. +# () +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from odoo import SUPERUSER_ID +from odoo.tests import common + + +class TestPurchaseRequestToRfq(common.TransactionCase): + def setUp(self): + super().setUp() + self.purchase_request = self.env["purchase.request"] + self.purchase_request_line = self.env["purchase.request.line"] + self.wiz = self.env["purchase.request.line.make.purchase.order"] + self.purchase_order = self.env["purchase.order"] + # Main Operating Unit + self.ou1 = self.env.ref("operating_unit.main_operating_unit") + # Products + self.product1 = self.env.ref("product.product_product_9") + self._create_purchase_request() + + def _create_purchase_request(self): + vals = { + "picking_type_id": self.env.ref("stock.picking_type_in").id, + "requested_by": SUPERUSER_ID, + "operating_unit_id": self.ou1.id, + } + purchase_request = self.purchase_request.create(vals) + vals = { + "request_id": purchase_request.id, + "product_id": self.product1.id, + "product_uom_id": self.env.ref("uom.product_uom_unit").id, + "product_qty": 5.0, + } + self.purchase_request_line = self.purchase_request_line.create(vals) + purchase_request.button_to_approve() + purchase_request.button_approved() + + def test_purchase_request_to_purchase_requisition(self): + vals = {"supplier_id": self.env.ref("base.res_partner_12").id} + wiz_id = self.wiz.with_context( + active_model="purchase.request.line", + active_ids=[self.purchase_request_line.id], + active_id=self.purchase_request_line.id, + ).create(vals) + wiz_id.make_purchase_order() + purchase_id = self.purchase_request_line.purchase_lines.order_id + self.assertEqual( + purchase_id.operating_unit_id, + self.purchase_request_line.operating_unit_id, + "Should have the same Operating Unit", + ) diff --git a/purchase_request_operating_unit/view/purchase_request_view.xml b/purchase_request_operating_unit/view/purchase_request_view.xml new file mode 100644 index 0000000000..2090b4ed41 --- /dev/null +++ b/purchase_request_operating_unit/view/purchase_request_view.xml @@ -0,0 +1,112 @@ + + + + + + + + + purchase.request.tree + purchase.request + + + + + + + + + purchase.request.form + purchase.request + + + + + + + + + {'operating_unit_id': operating_unit_id} + + + + + + purchase.request.list.select + purchase.request + + + + + + + + + + + + purchase.request.line.tree + purchase.request.line + + + + + + + + + purchase.request.line.form + purchase.request.line + + + + + + + + + purchase.request.line.search + purchase.request.line + + + + + + + + + + + diff --git a/purchase_request_operating_unit/wizard/__init__.py b/purchase_request_operating_unit/wizard/__init__.py new file mode 100644 index 0000000000..5869ceb5a3 --- /dev/null +++ b/purchase_request_operating_unit/wizard/__init__.py @@ -0,0 +1,3 @@ +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from . import purchase_request_line_make_purchase_order diff --git a/purchase_request_operating_unit/wizard/purchase_request_line_make_purchase_order.py b/purchase_request_operating_unit/wizard/purchase_request_line_make_purchase_order.py new file mode 100644 index 0000000000..f7d01b31f9 --- /dev/null +++ b/purchase_request_operating_unit/wizard/purchase_request_line_make_purchase_order.py @@ -0,0 +1,61 @@ +# Copyright 2016-19 ForgeFlow S.L. +# Copyright 2016-19 Serpent Consulting Services Pvt. Ltd. +# () +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class PurchaseRequestLineMakePurchaseOrder(models.TransientModel): + _inherit = "purchase.request.line.make.purchase.order" + + operating_unit_id = fields.Many2one( + "operating.unit", + string="Operating Unit", + readonly=True, + ) + + @api.model + def default_get(self, fields): + res = super().default_get(fields) + operating_unit_id = False + active_model = self.env.context.get("active_model", False) + active_ids = self.env.context.get("active_ids", False) + _model = { + "purchase.request.line": "", + "purchase.request": "line_ids", + } + request_lines = ( + self.env[active_model].browse(active_ids).mapped(_model[active_model]) + ) + for line in request_lines: + line_operating_unit_id = ( + line.request_id.operating_unit_id + and line.request_id.operating_unit_id.id + or False + ) + if operating_unit_id and line_operating_unit_id != operating_unit_id: + raise ValidationError( + _( + "Could not process !" + "You have to select lines" + "from the same operating unit." + ) + ) + else: + operating_unit_id = line_operating_unit_id + res["operating_unit_id"] = operating_unit_id + return res + + @api.model + def _prepare_purchase_order( + self, picking_type, group_id, company, currency, origin + ): + data = super()._prepare_purchase_order( + picking_type, group_id, company, currency, origin + ) + if self.operating_unit_id: + data["requesting_operating_unit_id"] = self.operating_unit_id.id + data["operating_unit_id"] = self.operating_unit_id.id + return data diff --git a/purchase_request_operating_unit/wizard/purchase_request_line_make_purchase_order_view.xml b/purchase_request_operating_unit/wizard/purchase_request_line_make_purchase_order_view.xml new file mode 100644 index 0000000000..7effe4dd37 --- /dev/null +++ b/purchase_request_operating_unit/wizard/purchase_request_line_make_purchase_order_view.xml @@ -0,0 +1,35 @@ + + + + + + + + + Purchase Request Line Make Purchase Order + purchase.request.line.make.purchase.order + + form + + + + + + + ['&', ('partner_id', '=', supplier_id), '|', ('operating_unit_id', '=', False), ('operating_unit_id', '=', operating_unit_id)] + + + + diff --git a/setup/purchase_request_operating_unit/odoo/addons/purchase_request_operating_unit b/setup/purchase_request_operating_unit/odoo/addons/purchase_request_operating_unit new file mode 120000 index 0000000000..d252cd6e74 --- /dev/null +++ b/setup/purchase_request_operating_unit/odoo/addons/purchase_request_operating_unit @@ -0,0 +1 @@ +../../../../purchase_request_operating_unit \ No newline at end of file diff --git a/setup/purchase_request_operating_unit/setup.py b/setup/purchase_request_operating_unit/setup.py new file mode 100644 index 0000000000..28c57bb640 --- /dev/null +++ b/setup/purchase_request_operating_unit/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)