From 0c87abb2a908888e534390e38465db886a88c574 Mon Sep 17 00:00:00 2001 From: Lois Rilo Date: Fri, 7 Feb 2020 11:52:18 +0100 Subject: [PATCH 01/20] [11.0][ADD] purchase_representative --- purchase_representative/README.rst | 95 ++++ purchase_representative/__init__.py | 2 + purchase_representative/__manifest__.py | 22 + purchase_representative/hooks.py | 41 ++ purchase_representative/models/__init__.py | 2 + .../models/procurement_rule.py | 28 ++ .../models/purchase_order.py | 15 + .../readme/CONTRIBUTORS.rst | 1 + .../readme/DESCRIPTION.rst | 7 + purchase_representative/readme/ROADMAP.rst | 5 + purchase_representative/readme/USAGE.rst | 3 + .../static/description/icon.png | Bin 0 -> 9455 bytes .../static/description/index.html | 441 ++++++++++++++++++ .../views/purchase_order_view.xml | 41 ++ 14 files changed, 703 insertions(+) create mode 100644 purchase_representative/README.rst create mode 100644 purchase_representative/__init__.py create mode 100644 purchase_representative/__manifest__.py create mode 100644 purchase_representative/hooks.py create mode 100644 purchase_representative/models/__init__.py create mode 100644 purchase_representative/models/procurement_rule.py create mode 100644 purchase_representative/models/purchase_order.py create mode 100644 purchase_representative/readme/CONTRIBUTORS.rst create mode 100644 purchase_representative/readme/DESCRIPTION.rst create mode 100644 purchase_representative/readme/ROADMAP.rst create mode 100644 purchase_representative/readme/USAGE.rst create mode 100644 purchase_representative/static/description/icon.png create mode 100644 purchase_representative/static/description/index.html create mode 100644 purchase_representative/views/purchase_order_view.xml diff --git a/purchase_representative/README.rst b/purchase_representative/README.rst new file mode 100644 index 00000000000..383ceed2c72 --- /dev/null +++ b/purchase_representative/README.rst @@ -0,0 +1,95 @@ +======================= +Purchase Representative +======================= + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! 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-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fpurchase--workflow-lightgray.png?logo=github + :target: https://github.com/OCA/purchase-workflow/tree/11.0/purchase_representative + :alt: OCA/purchase-workflow +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/purchase-workflow-11-0/purchase-workflow-11-0-purchase_representative + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/142/11.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module adds the field *Purchase Representative* to Purchase +Orders. This field is present in Standard Odoo v12. The user specified will +be the contact person for the purchase order. + +Additionally, it defaults it to the user doing a procurement to overcome the +known flaw of Odoo (until v13) which changes the user in the transaction when +using `sudo`. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +Just set the *Purchase Representative* in the Purchase Order header. +Then when sending the RFQ/PO to the vendor the Purchase Representative will be +the contact person (email from and reply to). + +Known issues / Roadmap +====================== + +Migration notes: + +* The field `user_id` is out-of-the-box in v12. +* In v13 the user doing the transaction is respected. Check if emails are + also sent to the correct user. + +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 +~~~~~~~ + +* ForgeFlow + +Contributors +~~~~~~~~~~~~ + +* Lois Rilo + +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/purchase-workflow `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/purchase_representative/__init__.py b/purchase_representative/__init__.py new file mode 100644 index 00000000000..1a9a001cf76 --- /dev/null +++ b/purchase_representative/__init__.py @@ -0,0 +1,2 @@ +from . import models +from .hooks import post_init_hook, uninstall_hook diff --git a/purchase_representative/__manifest__.py b/purchase_representative/__manifest__.py new file mode 100644 index 00000000000..a38c63f2046 --- /dev/null +++ b/purchase_representative/__manifest__.py @@ -0,0 +1,22 @@ +# Copyright 2020 ForgeFlow S.L. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Purchase Representative", + "summary": "Purchase Representatives will be the point of contact for " + "RFQ's and PO's", + "version": "11.0.1.0.0", + "category": "Purchases", + "website": "https://github.com/OCA/purchase-workflow", + "author": "ForgeFlow, Odoo Community Association (OCA)", + "license": "AGPL-3", + "application": False, + "installable": True, + "depends": [ + "purchase", + ], + "data": [ + "views/purchase_order_view.xml", + ], + "post_init_hook": "post_init_hook", + "uninstall_hook": "uninstall_hook", +} diff --git a/purchase_representative/hooks.py b/purchase_representative/hooks.py new file mode 100644 index 00000000000..309c7a5f410 --- /dev/null +++ b/purchase_representative/hooks.py @@ -0,0 +1,41 @@ +# Copyright 2020 ForgeFlow S.L. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.tools import pycompat + +import logging +_logger = logging.getLogger(__name__) + + +def post_init_hook(cr, registry): + """email from in templates will be `user_id` now.""" + _logger.info("Update RFQ/PO email templates") + cr.execute(""" + SELECT id, email_from + FROM mail_template + WHERE model = 'purchase.order'; + """) + for template_id, email_from in cr.fetchall(): + new_mail_from = pycompat.to_text(email_from.replace("create_uid", "user_id")) + cr.execute(""" + UPDATE mail_template + SET email_from = %s + WHERE id = %s; + """, (new_mail_from, template_id)) + + +def uninstall_hook(cr, registry): + """set back email from to create_uid""" + _logger.info("Update RFQ/PO email templates") + cr.execute(""" + SELECT id, email_from + FROM mail_template + WHERE model = 'purchase.order'; + """) + for template_id, email_from in cr.fetchall(): + new_mail_from = pycompat.to_text(email_from.replace("user_id", "create_uid")) + cr.execute(""" + UPDATE mail_template + SET email_from = %s + WHERE id = %s; + """, (new_mail_from, template_id)) diff --git a/purchase_representative/models/__init__.py b/purchase_representative/models/__init__.py new file mode 100644 index 00000000000..54c2499c86f --- /dev/null +++ b/purchase_representative/models/__init__.py @@ -0,0 +1,2 @@ +from . import purchase_order +from . import procurement_rule diff --git a/purchase_representative/models/procurement_rule.py b/purchase_representative/models/procurement_rule.py new file mode 100644 index 00000000000..c7d307934b7 --- /dev/null +++ b/purchase_representative/models/procurement_rule.py @@ -0,0 +1,28 @@ +# Copyright 2020 ForgeFlow S.L. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, models + + +class ProcurementRule(models.Model): + _inherit = "procurement.rule" + + @api.multi + def _run_buy( + self, product_id, product_qty, product_uom, + location_id, name, origin, values + ): + values["propagate_create_uid"] = self.env.uid + return super()._run_buy( + product_id, product_qty, product_uom, location_id, name, + origin, values) + + def _prepare_purchase_order(self, product_id, product_qty, product_uom, + origin, values, partner): + vals = super()._prepare_purchase_order( + product_id, product_qty, product_uom, origin, values, partner) + if values.get("propagate_create_uid"): + vals.update({ + "user_id": values.get("propagate_create_uid"), + }) + return vals diff --git a/purchase_representative/models/purchase_order.py b/purchase_representative/models/purchase_order.py new file mode 100644 index 00000000000..0fb0d8cdd61 --- /dev/null +++ b/purchase_representative/models/purchase_order.py @@ -0,0 +1,15 @@ +# Copyright 2020 ForgeFlow S.L. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class PurchaseOrder(models.Model): + _inherit = "purchase.order" + + user_id = fields.Many2one( + comodel_name='res.users', + string='Purchase Representative', + track_visibility='onchange', + default=lambda self: self.env.user, + ) diff --git a/purchase_representative/readme/CONTRIBUTORS.rst b/purchase_representative/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000000..77dfbe89e97 --- /dev/null +++ b/purchase_representative/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Lois Rilo diff --git a/purchase_representative/readme/DESCRIPTION.rst b/purchase_representative/readme/DESCRIPTION.rst new file mode 100644 index 00000000000..1daf9e25b3e --- /dev/null +++ b/purchase_representative/readme/DESCRIPTION.rst @@ -0,0 +1,7 @@ +This module adds the field *Purchase Representative* to Purchase +Orders. This field is present in Standard Odoo v12. The user specified will +be the contact person for the purchase order. + +Additionally, it defaults it to the user doing a procurement to overcome the +known flaw of Odoo (until v13) which changes the user in the transaction when +using `sudo`. diff --git a/purchase_representative/readme/ROADMAP.rst b/purchase_representative/readme/ROADMAP.rst new file mode 100644 index 00000000000..1d379845a7a --- /dev/null +++ b/purchase_representative/readme/ROADMAP.rst @@ -0,0 +1,5 @@ +Migration notes: + +* The field `user_id` is out-of-the-box in v12. +* In v13 the user doing the transaction is respected. Check if emails are + also sent to the correct user. diff --git a/purchase_representative/readme/USAGE.rst b/purchase_representative/readme/USAGE.rst new file mode 100644 index 00000000000..113754c83bd --- /dev/null +++ b/purchase_representative/readme/USAGE.rst @@ -0,0 +1,3 @@ +Just set the *Purchase Representative* in the Purchase Order header. +Then when sending the RFQ/PO to the vendor the Purchase Representative will be +the contact person (email from and reply to). diff --git a/purchase_representative/static/description/icon.png b/purchase_representative/static/description/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0328b516c4980e8e44cdb63fd945757ddd132d GIT binary patch literal 9455 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 z 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 Xviia!U7SGha1wx#SCgwmn*{w2TRX*I literal 0 HcmV?d00001 diff --git a/purchase_representative/static/description/index.html b/purchase_representative/static/description/index.html new file mode 100644 index 00000000000..45f3a1f471a --- /dev/null +++ b/purchase_representative/static/description/index.html @@ -0,0 +1,441 @@ + + + + + + +Purchase Representative + + + +
+

Purchase Representative

+ + +

Beta License: AGPL-3 OCA/purchase-workflow Translate me on Weblate Try me on Runbot

+

This module adds the field Purchase Representative to Purchase +Orders. This field is present in Standard Odoo v12. The user specified will +be the contact person for the purchase order.

+

Additionally, it defaults it to the user doing a procurement to overcome the +known flaw of Odoo (until v13) which changes the user in the transaction when +using sudo.

+

Table of contents

+ +
+

Usage

+

Just set the Purchase Representative in the Purchase Order header. +Then when sending the RFQ/PO to the vendor the Purchase Representative will be +the contact person (email from and reply to).

+
+
+

Known issues / Roadmap

+

Migration notes:

+
    +
  • The field user_id is out-of-the-box in v12.
  • +
  • In v13 the user doing the transaction is respected. Check if emails are +also sent to the correct user.
  • +
+
+
+

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

+
    +
  • ForgeFlow
  • +
+
+ +
+

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/purchase-workflow project on GitHub.

+

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

+
+
+
+ + diff --git a/purchase_representative/views/purchase_order_view.xml b/purchase_representative/views/purchase_order_view.xml new file mode 100644 index 00000000000..4a33857ee66 --- /dev/null +++ b/purchase_representative/views/purchase_order_view.xml @@ -0,0 +1,41 @@ + + + + + + + purchase.order.form - test + purchase.order + + + + + + + + + + purchase.order.form - test + purchase.order + + + + + + + + + + purchase.order.select - purchase_tier_validation + purchase.order + + + + + + + + + + From 5139221ada0dc46cc5ecd6c793307299cfefce6a Mon Sep 17 00:00:00 2001 From: oca-travis Date: Tue, 18 Feb 2020 15:04:42 +0000 Subject: [PATCH 02/20] [UPD] Update purchase_representative.pot --- .../i18n/purchase_representative.pot | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 purchase_representative/i18n/purchase_representative.pot diff --git a/purchase_representative/i18n/purchase_representative.pot b/purchase_representative/i18n/purchase_representative.pot new file mode 100644 index 00000000000..562dabb926a --- /dev/null +++ b/purchase_representative/i18n/purchase_representative.pot @@ -0,0 +1,35 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * purchase_representative +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.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_representative +#: model:ir.ui.view,arch_db:purchase_representative.view_purchase_order_filter +msgid "My Purchases" +msgstr "" + +#. module: purchase_representative +#: model:ir.model,name:purchase_representative.model_procurement_rule +msgid "Procurement Rule" +msgstr "" + +#. module: purchase_representative +#: model:ir.model,name:purchase_representative.model_purchase_order +msgid "Purchase Order" +msgstr "" + +#. module: purchase_representative +#: model:ir.model.fields,field_description:purchase_representative.field_purchase_order_user_id +msgid "Purchase Representative" +msgstr "" + From 6cd96d46cf64c179549c78d785ea9e1943a8dad8 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Tue, 18 Feb 2020 15:23:43 +0000 Subject: [PATCH 03/20] [UPD] README.rst --- purchase_representative/static/description/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/purchase_representative/static/description/index.html b/purchase_representative/static/description/index.html index 45f3a1f471a..e5ed5048874 100644 --- a/purchase_representative/static/description/index.html +++ b/purchase_representative/static/description/index.html @@ -3,7 +3,7 @@ - + Purchase Representative -
-

Purchase Representative

+
+ + +Odoo Community Association + +
+

Purchase Representative

-

Beta License: AGPL-3 OCA/purchase-workflow Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/purchase-workflow Translate me on Weblate Try me on Runboat

This module makes the field Purchase Representative in Purchase Orders default to the user doing a procurement to overcome the known flaw of Odoo user in the transaction when using SUPERUSER_ID.

@@ -387,13 +392,13 @@

Purchase Representative

-

Usage

+

Usage

Just set the Purchase Representative in the Purchase Order header. Then when sending the RFQ/PO to the vendor the Purchase Representative will be the contact person (email from and reply to).

-

Bug Tracker

+

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 to smash it by providing a detailed and welcomed @@ -401,21 +406,21 @@

Bug Tracker

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

+
From 616db063d9e89e5b50b109df0ce0142d3fc0be99 Mon Sep 17 00:00:00 2001 From: mymage Date: Thu, 7 Aug 2025 11:05:11 +0000 Subject: [PATCH 18/20] Added translation using Weblate (Italian) --- purchase_representative/i18n/it.po | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 purchase_representative/i18n/it.po diff --git a/purchase_representative/i18n/it.po b/purchase_representative/i18n/it.po new file mode 100644 index 00000000000..466e732f4e1 --- /dev/null +++ b/purchase_representative/i18n/it.po @@ -0,0 +1,20 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * purchase_representative +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: it\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" + +#. module: purchase_representative +#: model:ir.model,name:purchase_representative.model_stock_rule +msgid "Stock Rule" +msgstr "" From 792a2cc94deb63869f30513ca6a343a0d581e025 Mon Sep 17 00:00:00 2001 From: mymage Date: Thu, 7 Aug 2025 12:06:07 +0000 Subject: [PATCH 19/20] Translated using Weblate (Italian) Currently translated at 100.0% (1 of 1 strings) Translation: purchase-workflow-18.0/purchase-workflow-18.0-purchase_representative Translate-URL: https://translation.odoo-community.org/projects/purchase-workflow-18-0/purchase-workflow-18-0-purchase_representative/it/ --- purchase_representative/i18n/it.po | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/purchase_representative/i18n/it.po b/purchase_representative/i18n/it.po index 466e732f4e1..a9a9ce34641 100644 --- a/purchase_representative/i18n/it.po +++ b/purchase_representative/i18n/it.po @@ -6,15 +6,17 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 18.0\n" "Report-Msgid-Bugs-To: \n" -"Last-Translator: Automatically generated\n" +"PO-Revision-Date: 2025-08-07 14:25+0000\n" +"Last-Translator: mymage \n" "Language-Team: none\n" "Language: it\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 5.10.4\n" #. module: purchase_representative #: model:ir.model,name:purchase_representative.model_stock_rule msgid "Stock Rule" -msgstr "" +msgstr "Regola di giacenza" From 64c531d1161baa8a357c503316252e1a195ad89a Mon Sep 17 00:00:00 2001 From: Bhavesh Heliconia Date: Thu, 30 Apr 2026 16:20:07 +0530 Subject: [PATCH 20/20] [MIG] purchase_representative: Migration to 19.0 --- purchase_representative/README.rst | 13 +++-- purchase_representative/__manifest__.py | 2 +- .../readme/CONTRIBUTORS.md | 2 + .../static/description/index.html | 10 +++- .../tests/test_purchase_representative.py | 55 +++++++++---------- 5 files changed, 44 insertions(+), 38 deletions(-) diff --git a/purchase_representative/README.rst b/purchase_representative/README.rst index e2e80f71143..98361681742 100644 --- a/purchase_representative/README.rst +++ b/purchase_representative/README.rst @@ -21,13 +21,13 @@ Purchase Representative :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html :alt: License: AGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fpurchase--workflow-lightgray.png?logo=github - :target: https://github.com/OCA/purchase-workflow/tree/18.0/purchase_representative + :target: https://github.com/OCA/purchase-workflow/tree/19.0/purchase_representative :alt: OCA/purchase-workflow .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png - :target: https://translation.odoo-community.org/projects/purchase-workflow-18-0/purchase-workflow-18-0-purchase_representative + :target: https://translation.odoo-community.org/projects/purchase-workflow-19-0/purchase-workflow-19-0-purchase_representative :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png - :target: https://runboat.odoo-community.org/builds?repo=OCA/purchase-workflow&target_branch=18.0 + :target: https://runboat.odoo-community.org/builds?repo=OCA/purchase-workflow&target_branch=19.0 :alt: Try me on Runboat |badge1| |badge2| |badge3| |badge4| |badge5| @@ -54,7 +54,7 @@ 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 to smash it by providing a detailed and welcomed -`feedback `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -70,6 +70,9 @@ Contributors ------------ - Lois Rilo +- `Heliconia Solutions Pvt. Ltd. `__ + + - Bhavesh Heliconia Maintainers ----------- @@ -84,6 +87,6 @@ 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/purchase-workflow `_ project on GitHub. +This module is part of the `OCA/purchase-workflow `_ project on GitHub. You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/purchase_representative/__manifest__.py b/purchase_representative/__manifest__.py index 686fe180046..da5e984345c 100644 --- a/purchase_representative/__manifest__.py +++ b/purchase_representative/__manifest__.py @@ -4,7 +4,7 @@ "name": "Purchase Representative", "summary": "Purchase Representatives will be the point of contact for " "RFQ's and PO's", - "version": "18.0.1.0.0", + "version": "19.0.1.0.0", "category": "Purchases", "website": "https://github.com/OCA/purchase-workflow", "author": "ForgeFlow, Odoo Community Association (OCA)", diff --git a/purchase_representative/readme/CONTRIBUTORS.md b/purchase_representative/readme/CONTRIBUTORS.md index d0d2ab838ba..53edefdf30e 100644 --- a/purchase_representative/readme/CONTRIBUTORS.md +++ b/purchase_representative/readme/CONTRIBUTORS.md @@ -1 +1,3 @@ - Lois Rilo \ +- [Heliconia Solutions Pvt. Ltd.](https://www.heliconia.io) + - Bhavesh Heliconia diff --git a/purchase_representative/static/description/index.html b/purchase_representative/static/description/index.html index 21b28efa9f5..e946689b72f 100644 --- a/purchase_representative/static/description/index.html +++ b/purchase_representative/static/description/index.html @@ -374,7 +374,7 @@

Purchase Representative

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! source digest: sha256:c3c1ec9335e5b0afa9656edfba111c93467e0e0334ac02b21f895b74fdfb8b3f !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> -

Beta License: AGPL-3 OCA/purchase-workflow Translate me on Weblate Try me on Runboat

+

Beta License: AGPL-3 OCA/purchase-workflow Translate me on Weblate Try me on Runboat

This module makes the field Purchase Representative in Purchase Orders default to the user doing a procurement to overcome the known flaw of Odoo user in the transaction when using SUPERUSER_ID.

@@ -402,7 +402,7 @@

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 to smash it by providing a detailed and welcomed -feedback.

+feedback.

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

@@ -417,6 +417,10 @@

Authors

Contributors

@@ -428,7 +432,7 @@

Maintainers

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/purchase-workflow project on GitHub.

+

This module is part of the OCA/purchase-workflow project on GitHub.

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

diff --git a/purchase_representative/tests/test_purchase_representative.py b/purchase_representative/tests/test_purchase_representative.py index 4337039b8b8..dad78468531 100644 --- a/purchase_representative/tests/test_purchase_representative.py +++ b/purchase_representative/tests/test_purchase_representative.py @@ -1,51 +1,47 @@ -from odoo import fields -from odoo.tests.common import TransactionCase +from odoo import Command, fields +from odoo.tests import new_test_user +from odoo.addons.base.tests.common import BaseCommon -class TestPurchaseRepresentative(TransactionCase): - def setUp(self): - super().setUp() - self.user_test = self.env["res.users"].create( - { - "email": "testuser@testuser.com", - "name": "Test User", - "login": "test_user", - "password": "test_user", - } - ) - self.partner = self.env["res.partner"].create( - { - "name": "Partner Test", - "supplier_rank": 1, - } + +class TestPurchaseRepresentative(BaseCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.user_test = new_test_user( + cls.env, + login="test_user", + groups="purchase.group_purchase_user", + name="Test User", + email="testuser@testuser.com", ) - self.product = self.env["product.product"].create( + cls.product = cls.env["product.product"].create( { "name": "Product Test", "is_storable": True, "route_ids": [ - (6, 0, [self.env.ref("purchase_stock.route_warehouse0_buy").id]) + Command.set([cls.env.ref("purchase_stock.route_warehouse0_buy").id]) ], "standard_price": 50.0, } ) - self.env["product.supplierinfo"].create( + cls.env["product.supplierinfo"].create( { - "partner_id": self.partner.id, - "product_tmpl_id": self.product.product_tmpl_id.id, + "partner_id": cls.partner.id, + "product_tmpl_id": cls.product.product_tmpl_id.id, "min_qty": 1.0, "price": 45.0, } ) - self.location = self.env.ref("stock.stock_location_stock") - self.picking_type = self.env.ref("stock.picking_type_in") + cls.location = cls.env.ref("stock.stock_location_stock") + cls.picking_type = cls.env.ref("stock.picking_type_in") def test_create_procurement(self): """Test that the user_id field is filled automatically""" - procurement = self.env["procurement.group"].Procurement( + procurement = self.env["stock.rule"].Procurement( self.product, 10, self.product.uom_id, @@ -60,9 +56,10 @@ def test_create_procurement(self): "procure_method": "make_to_order", }, ) - self.env["stock.rule"].with_user(self.user_test)._run_buy( - [(procurement, self.env["stock.rule"].search([], limit=1))] - ) + rule = self.env["stock.rule"].search([("action", "=", "buy")], limit=1) + if not rule: + rule = self.env["stock.rule"].search([], limit=1) + self.env["stock.rule"].with_user(self.user_test)._run_buy([(procurement, rule)]) purchase_orders = self.env["purchase.order"].search( [("origin", "=", "Test Origin")]