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

+
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
+
+
+
+
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).
+
+
+
+
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.
+
+
+
+
+
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.
+
+
+
+
+
+
+
+
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.
+
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
+
+
+
+
+
+
+
Purchase Representative
-

+

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
-
+
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).
-
+
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 @@
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
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
-

+

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 @@
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.
@@ -428,7 +432,7 @@
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")]