From aea22d969dc836501f9836696607de4a62a83310 Mon Sep 17 00:00:00 2001 From: Sergey Krylov Date: Wed, 19 Feb 2025 14:24:32 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9D=D0=B0=D1=87=D0=B0=D0=BB=D1=8C=D0=BD?= =?UTF-8?q?=D0=BE=D0=B5=20=D0=BD=D0=B0=D0=BF=D0=BE=D0=BB=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __init__.py | 4 ++ __manifest__.py | 13 ++++ i18n/purchase_requisition_sale.pot | 21 ++++++ i18n/ru.po | 23 +++++++ tests/__init__.py | 4 ++ tests/test_purchase_requisition_sale.py | 64 +++++++++++++++++++ wizard/__init__.py | 4 ++ ...purchase_requisition_create_alternative.py | 16 +++++ 8 files changed, 149 insertions(+) create mode 100644 __init__.py create mode 100644 __manifest__.py create mode 100644 i18n/purchase_requisition_sale.pot create mode 100644 i18n/ru.po create mode 100644 tests/__init__.py create mode 100644 tests/test_purchase_requisition_sale.py create mode 100644 wizard/__init__.py create mode 100644 wizard/purchase_requisition_create_alternative.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..260776f --- /dev/null +++ b/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import wizard diff --git a/__manifest__.py b/__manifest__.py new file mode 100644 index 0000000..71c1723 --- /dev/null +++ b/__manifest__.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +{ + 'name': 'Purchase Requisition Sale', + 'description': "Bridge module for Purchase requisition and Sales. Used to properly create purchase requisitions for subcontracted services", + 'version': '1.0', + 'category': 'Inventory/Purchase', + 'sequence': 70, + 'depends': ['purchase_requisition', 'sale_purchase'], + 'auto_install': True, + 'license': 'LGPL-3', +} diff --git a/i18n/purchase_requisition_sale.pot b/i18n/purchase_requisition_sale.pot new file mode 100644 index 0000000..56b0ab7 --- /dev/null +++ b/i18n/purchase_requisition_sale.pot @@ -0,0 +1,21 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * purchase_requisition_sale +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-10-26 21:55+0000\n" +"PO-Revision-Date: 2023-10-26 21:55+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: purchase_requisition_sale +#: model:ir.model,name:purchase_requisition_sale.model_purchase_requisition_create_alternative +msgid "Wizard to preset values for alternative PO" +msgstr "" diff --git a/i18n/ru.po b/i18n/ru.po new file mode 100644 index 0000000..5f136bb --- /dev/null +++ b/i18n/ru.po @@ -0,0 +1,23 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * purchase_requisition_sale +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 17.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-10-26 21:55+0000\n" +"PO-Revision-Date: 2024-01-30 15:14+0400\n" +"Last-Translator: \n" +"Language-Team: Russian (https://app.transifex.com/odoo/teams/41243/ru/)\n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n" + +#. module: purchase_requisition_sale +#: model:ir.model,name:purchase_requisition_sale.model_purchase_requisition_create_alternative +msgid "Wizard to preset values for alternative PO" +msgstr "Мастер предварительной установки значений для альтернативных PO" diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..0c5024f --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import test_purchase_requisition_sale diff --git a/tests/test_purchase_requisition_sale.py b/tests/test_purchase_requisition_sale.py new file mode 100644 index 0000000..7d7d841 --- /dev/null +++ b/tests/test_purchase_requisition_sale.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.tests.common import TransactionCase +from odoo.tests import Form +from odoo import Command + + +class TestPurchaseRequisitionSale(TransactionCase): + + @classmethod + def setUpClass(cls): + super().setUpClass() + + cls.client = cls.env['res.partner'].create({'name': 'Client'}) + cls.vendor_1 = cls.env['res.partner'].create({'name': 'Vendor 1'}) + cls.vendor_2 = cls.env['res.partner'].create({'name': 'Vendor 2'}) + + cls.sub_service = cls.env['product.product'].create({ + 'name': 'Subcontracted service', + 'categ_id': cls.env.ref('product.product_category_all').id, + 'type': 'service', + 'seller_ids': [Command.create({ + 'partner_id': cls.vendor_1.id, + 'price': 10.0, + 'delay': 0, + })], + 'service_to_purchase': True, + }) + + def test_01_purchase_requisition_services(self): + """ Create an alternative RFQ for a RFQ automatically genrated from a sale order containing a service that + has the "service_to_purchase" activated. + """ + # Create a Sale Order for the subcontracted service + sale_order = self.env['sale.order'].create({ + 'partner_id': self.client.id, + 'order_line': [ + Command.create({ + 'product_id': self.sub_service.id, + 'product_uom_qty': 5, + }) + ] + }) + sale_order.action_confirm() + self.assertEqual(sale_order.purchase_order_count, 1, "A RFQ should be created, since `service_to_purchase` has been activated for this product") + purchase_order = sale_order._get_purchase_orders() + self.assertEqual(len(purchase_order), 1, "There should be only one Purchase Order linked to this Sale Order") + + # Create an alternative RFQ for another vendor + action = purchase_order.action_create_alternative() + alt_po_wizard = Form(self.env['purchase.requisition.create.alternative'].with_context(**action['context'])) + alt_po_wizard.partner_id = self.vendor_2 + alt_po_wizard.copy_products = True + alt_po_wizard = alt_po_wizard.save() + alt_po_wizard.action_create_alternative() + self.assertEqual(len(purchase_order.alternative_po_ids), 2, "Base PO should be linked with the alternative PO") + + # Check if newly created PO is correctly linked to the base Sale Order + alt_po = purchase_order.alternative_po_ids.filtered(lambda po: po.id != purchase_order.id) + linked_so = alt_po._get_sale_orders() + self.assertEqual(len(linked_so), 1, "The Sale Order from the original Purchase Order should be linked") + self.assertEqual(linked_so.id, sale_order.id, "The Sale Order linked to the alternative PO must be the same as the original one") + self.assertEqual(sale_order.purchase_order_count, 2, "Both the original PO and the alternative one should be there") diff --git a/wizard/__init__.py b/wizard/__init__.py new file mode 100644 index 0000000..d631661 --- /dev/null +++ b/wizard/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import purchase_requisition_create_alternative diff --git a/wizard/purchase_requisition_create_alternative.py b/wizard/purchase_requisition_create_alternative.py new file mode 100644 index 0000000..e6a69db --- /dev/null +++ b/wizard/purchase_requisition_create_alternative.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, models + + +class PurchaseRequisitionCreateAlternative(models.TransientModel): + _inherit = 'purchase.requisition.create.alternative' + + @api.model + def _get_alternative_line_value(self, order_line): + res_line = super()._get_alternative_line_value(order_line) + if order_line.sale_line_id: + res_line['sale_line_id'] = order_line.sale_line_id.id + + return res_line