diff --git a/purchase_order_secondary_unit/README.rst b/purchase_order_secondary_unit/README.rst index bf295f67a03..ada37484a90 100644 --- a/purchase_order_secondary_unit/README.rst +++ b/purchase_order_secondary_unit/README.rst @@ -1,7 +1,3 @@ -.. image:: https://odoo-community.org/readme-banner-image - :target: https://odoo-community.org/get-involved?utm_source=readme - :alt: Odoo Community Association - ============================= Purchase Order Secondary Unit ============================= @@ -17,7 +13,7 @@ Purchase Order Secondary Unit .. |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/license-AGPL--3-blue.png +.. |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 @@ -35,11 +31,25 @@ Purchase Order Secondary Unit This module extends the functionality of purchase orders to allow buy products in secondary unit of distinct category. +Users can enter quantities and prices in secondary units on purchase +order lines. Vendor pricelist records are also extended to support +secondary unit pricing. + +Purchase reports and the Purchase Order portal are adjusted to display +quantities and prices in secondary units based on company configuration. + **Table of contents** .. contents:: :local: +Configuration +============= + +For configuration of displaying secondary unit information in purchase +reports and the Purchase Order portal, see the guidelines provided in +product_secondary_unit. + Usage ===== @@ -52,6 +62,24 @@ To use this module you need to: 5. Change secondary qty and secondary uom in line, and quantity (product_qty) will be changed (according to the conversion factor). +**Vendor Pricelist Integration** + +- When adding a vendor to a product's pricelist (via *Purchase tab > + Vendors*), the secondary unit of measure is automatically defaulted + from the product variant's purchase secondary UOM, or from the + product template if not set on the variant. +- When a new vendor pricelist record is created from purchase order + confirmation, the secondary UOM from the purchase order line is + automatically stored in the vendor pricelist entry. + +Known issues / Roadmap +====================== + +Updating existing vendor pricelist records from purchase order +confirmation does not currently support secondary UOM or secondary UOM +pricing. This is not included in the current scope and may be considered +in future improvements. + Bug Tracker =========== @@ -73,14 +101,17 @@ Authors Contributors ------------ -- `Tecnativa `__: +- `Tecnativa `__: + + - Sergio Teruel + - Ernesto Tejeda - - Sergio Teruel - - Ernesto Tejeda +- Nikul Chaudhary +- Pimolnat Suntian +- Miguel Ángel Gómez +- `Quartile `__: -- Nikul Chaudhary -- Pimolnat Suntian -- Miguel Ángel Gómez + - Yoshi Tashiro Maintainers ----------- diff --git a/purchase_order_secondary_unit/__manifest__.py b/purchase_order_secondary_unit/__manifest__.py index c7fd5dbb492..3dcc7386cf2 100644 --- a/purchase_order_secondary_unit/__manifest__.py +++ b/purchase_order_secondary_unit/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Purchase Order Secondary Unit", "summary": "Purchase product in a secondary unit", - "version": "18.0.1.0.1", + "version": "18.0.1.1.0", "development_status": "Beta", "category": "Purchase", "website": "https://github.com/OCA/purchase-workflow", @@ -15,6 +15,8 @@ "depends": ["purchase", "product_secondary_unit"], "data": [ "views/product_views.xml", + "views/product_supplierinfo_views.xml", + "views/purchase_order_portal_templates.xml", "views/purchase_order_views.xml", "reports/purchase_order_templates.xml", "reports/purchase_quotation_templates.xml", diff --git a/purchase_order_secondary_unit/migrations/18.0.1.1.0/pre-migrate.py b/purchase_order_secondary_unit/migrations/18.0.1.1.0/pre-migrate.py new file mode 100644 index 00000000000..cb6cf693891 --- /dev/null +++ b/purchase_order_secondary_unit/migrations/18.0.1.1.0/pre-migrate.py @@ -0,0 +1,17 @@ +# Copyright 2026 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.tools.sql import column_exists + + +def migrate(cr, version): + if not column_exists(cr, "purchase_order_line", "secondary_uom_price"): + cr.execute(""" + ALTER TABLE purchase_order_line + ADD COLUMN secondary_uom_price double precision; + + UPDATE purchase_order_line pol + SET secondary_uom_price = pol.price_unit * su.factor + FROM product_secondary_unit su + WHERE su.id = pol.secondary_uom_id; + """) diff --git a/purchase_order_secondary_unit/models/__init__.py b/purchase_order_secondary_unit/models/__init__.py index a90631ae040..f1f600bd030 100644 --- a/purchase_order_secondary_unit/models/__init__.py +++ b/purchase_order_secondary_unit/models/__init__.py @@ -1,4 +1,5 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from . import product_product +from . import product_supplierinfo from . import product_template from . import purchase_order diff --git a/purchase_order_secondary_unit/models/product_supplierinfo.py b/purchase_order_secondary_unit/models/product_supplierinfo.py new file mode 100644 index 00000000000..e5c3ad7e781 --- /dev/null +++ b/purchase_order_secondary_unit/models/product_supplierinfo.py @@ -0,0 +1,42 @@ +# Copyright 2026 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class ProductSupplierinfo(models.Model): + _inherit = "product.supplierinfo" + + secondary_uom_id = fields.Many2one( + comodel_name="product.secondary.unit", + string="Secondary Unit", + domain="[('product_tmpl_id', '=', product_tmpl_id)]", + ) + secondary_uom_price = fields.Float( + string="Secondary Price", + digits="Product Price", + compute="_compute_secondary_uom_price", + inverse="_inverse_secondary_uom_price", + store=True, + ) + + @api.depends("price", "secondary_uom_id", "secondary_uom_id.factor") + def _compute_secondary_uom_price(self): + for rec in self: + if rec.secondary_uom_id: + rec.secondary_uom_price = rec.price * rec.secondary_uom_id.factor + else: + rec.secondary_uom_price = 0.0 + + @api.onchange("secondary_uom_price") + def _inverse_secondary_uom_price(self): + for rec in self: + if rec.secondary_uom_id: + rec.price = rec.secondary_uom_price / rec.secondary_uom_id.factor + + @api.onchange("product_tmpl_id", "product_id") + def _onchange_product_id_secondary_uom(self): + self.secondary_uom_id = ( + self.product_id.purchase_secondary_uom_id + or self.product_tmpl_id.purchase_secondary_uom_id + ) diff --git a/purchase_order_secondary_unit/models/purchase_order.py b/purchase_order_secondary_unit/models/purchase_order.py index ada6a343b46..37cece5901e 100644 --- a/purchase_order_secondary_unit/models/purchase_order.py +++ b/purchase_order_secondary_unit/models/purchase_order.py @@ -3,6 +3,15 @@ from odoo import api, fields, models +class PurchaseOrder(models.Model): + _inherit = "purchase.order" + + def _prepare_supplier_info(self, partner, line, price, currency): + vals = super()._prepare_supplier_info(partner, line, price, currency) + vals["secondary_uom_id"] = line.secondary_uom_id.id + return vals + + class PurchaseOrderLine(models.Model): _inherit = ["purchase.order.line", "product.secondary.unit.mixin"] _name = "purchase.order.line" @@ -25,12 +34,34 @@ class PurchaseOrderLine(models.Model): product_packaging_id = fields.Many2one( compute="_compute_product_packaging_id", store=True, precompute=True ) + secondary_uom_price = fields.Float( + string="Secondary Price", + digits="Product Price", + aggregator="avg", + compute="_compute_secondary_uom_price", + inverse="_inverse_secondary_uom_price", + store=True, + ) @api.depends("secondary_uom_qty", "secondary_uom_id") def _compute_product_qty(self): self._compute_helper_target_field_qty() return super()._compute_product_qty() + @api.depends("price_unit", "secondary_uom_id", "secondary_uom_id.factor") + def _compute_secondary_uom_price(self): + for rec in self: + if rec.secondary_uom_id: + rec.secondary_uom_price = rec.price_unit * rec.secondary_uom_id.factor + else: + rec.secondary_uom_price = 0.0 + + @api.onchange("secondary_uom_price") + def _inverse_secondary_uom_price(self): + for rec in self: + if rec.secondary_uom_id: + rec.price_unit = rec.secondary_uom_price / rec.secondary_uom_id.factor + @api.onchange("product_uom") def onchange_product_uom_for_secondary(self): self._onchange_helper_product_uom_for_secondary() @@ -54,3 +85,12 @@ def onchange_product_id(self): if self.secondary_uom_id: self.secondary_uom_qty = 1.0 return res + + def _prepare_account_move_line(self, move=False): + # Set secondary UoM values only when account_move_secondary_unit is installed + # (i.e., the fields exist on account.move.line). + res = super()._prepare_account_move_line(move) + aml_fields = self.env["account.move.line"]._fields + if "secondary_uom_id" in aml_fields and self.secondary_uom_id: + res["secondary_uom_id"] = self.secondary_uom_id.id + return res diff --git a/purchase_order_secondary_unit/readme/CONFIGURE.md b/purchase_order_secondary_unit/readme/CONFIGURE.md new file mode 100644 index 00000000000..2ba195bf886 --- /dev/null +++ b/purchase_order_secondary_unit/readme/CONFIGURE.md @@ -0,0 +1,2 @@ +For configuration of displaying secondary unit information in purchase reports and +the Purchase Order portal, see the guidelines provided in product_secondary_unit. diff --git a/purchase_order_secondary_unit/readme/CONTRIBUTORS.md b/purchase_order_secondary_unit/readme/CONTRIBUTORS.md index 1d97b2c52aa..0eb9326cb63 100644 --- a/purchase_order_secondary_unit/readme/CONTRIBUTORS.md +++ b/purchase_order_secondary_unit/readme/CONTRIBUTORS.md @@ -4,3 +4,5 @@ - Nikul Chaudhary \<\> - Pimolnat Suntian \<\> - Miguel Ángel Gómez \<\> +- [Quartile](https://www.quartile.co): + - Yoshi Tashiro diff --git a/purchase_order_secondary_unit/readme/DESCRIPTION.md b/purchase_order_secondary_unit/readme/DESCRIPTION.md index f81706f581f..bade08f8ea0 100644 --- a/purchase_order_secondary_unit/readme/DESCRIPTION.md +++ b/purchase_order_secondary_unit/readme/DESCRIPTION.md @@ -1,2 +1,8 @@ This module extends the functionality of purchase orders to allow buy products in secondary unit of distinct category. + +Users can enter quantities and prices in secondary units on purchase order lines. Vendor +pricelist records are also extended to support secondary unit pricing. + +Purchase reports and the Purchase Order portal are adjusted to display quantities and prices +in secondary units based on company configuration. diff --git a/purchase_order_secondary_unit/readme/ROADMAP.md b/purchase_order_secondary_unit/readme/ROADMAP.md new file mode 100644 index 00000000000..03a36575c9e --- /dev/null +++ b/purchase_order_secondary_unit/readme/ROADMAP.md @@ -0,0 +1,3 @@ +Updating existing vendor pricelist records from purchase order confirmation does not +currently support secondary UOM or secondary UOM pricing. This is not included in the +current scope and may be considered in future improvements. diff --git a/purchase_order_secondary_unit/readme/USAGE.md b/purchase_order_secondary_unit/readme/USAGE.md index 3e7f0e0aed2..f87ccf9b3ae 100644 --- a/purchase_order_secondary_unit/readme/USAGE.md +++ b/purchase_order_secondary_unit/readme/USAGE.md @@ -6,3 +6,12 @@ To use this module you need to: 4. Go to *Purchase \> Quotation \> Create*. 5. Change secondary qty and secondary uom in line, and quantity (product_qty) will be changed (according to the conversion factor). + +**Vendor Pricelist Integration** + +- When adding a vendor to a product's pricelist (via *Purchase tab > Vendors*), the + secondary unit of measure is automatically defaulted from the product variant's + purchase secondary UOM, or from the product template if not set on the variant. +- When a new vendor pricelist record is created from purchase order confirmation, the + secondary UOM from the purchase order line is automatically stored in the vendor + pricelist entry. diff --git a/purchase_order_secondary_unit/reports/purchase_order_templates.xml b/purchase_order_secondary_unit/reports/purchase_order_templates.xml index b79d2fc3b3c..01b9b2340ec 100644 --- a/purchase_order_secondary_unit/reports/purchase_order_templates.xml +++ b/purchase_order_secondary_unit/reports/purchase_order_templates.xml @@ -6,16 +6,64 @@ > - + Second Qty - + + + + line.get_secondary_uom_display_mode() != 'secondary' + + + line.get_secondary_uom_display_mode() != 'secondary' + + + + + + + + + + + +
+ + ( + ) + +
+
+ + + line.get_secondary_uom_display_mode() != 'secondary' + + + + diff --git a/purchase_order_secondary_unit/reports/purchase_quotation_templates.xml b/purchase_order_secondary_unit/reports/purchase_quotation_templates.xml index ef64f13d1a1..1dbae6d6855 100644 --- a/purchase_order_secondary_unit/reports/purchase_quotation_templates.xml +++ b/purchase_order_secondary_unit/reports/purchase_quotation_templates.xml @@ -4,18 +4,57 @@ id="report_purchasequotation_document" inherit_id="purchase.report_purchasequotation_document" > - + - + Second Qty - + - + + + + order_line.get_secondary_uom_display_mode() != 'secondary' + + + order_line.get_secondary_uom_display_mode() != 'secondary' + + + + + + + + + + + +
+ + ( + ) + +
+
diff --git a/purchase_order_secondary_unit/static/description/index.html b/purchase_order_secondary_unit/static/description/index.html index a4e876f5df9..1f7c874044f 100644 --- a/purchase_order_secondary_unit/static/description/index.html +++ b/purchase_order_secondary_unit/static/description/index.html @@ -3,7 +3,7 @@ -README.rst +Purchase Order Secondary Unit -
+
+

Purchase Order Secondary Unit

- - -Odoo Community Association - -
-

Purchase Order Secondary Unit

-

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 extends the functionality of purchase orders to allow buy products in secondary unit of distinct category.

+

Users can enter quantities and prices in secondary units on purchase +order lines. Vendor pricelist records are also extended to support +secondary unit pricing.

+

Purchase reports and the Purchase Order portal are adjusted to display +quantities and prices in secondary units based on company configuration.

Table of contents

+
+

Configuration

+

For configuration of displaying secondary unit information in purchase +reports and the Purchase Order portal, see the guidelines provided in +product_secondary_unit.

+
-

Usage

+

Usage

To use this module you need to:

  1. Go to a Product > General Information tab.
  2. @@ -401,9 +409,26 @@

    Usage

  3. Change secondary qty and secondary uom in line, and quantity (product_qty) will be changed (according to the conversion factor).
+

Vendor Pricelist Integration

+
    +
  • When adding a vendor to a product’s pricelist (via Purchase tab > +Vendors), the secondary unit of measure is automatically defaulted +from the product variant’s purchase secondary UOM, or from the +product template if not set on the variant.
  • +
  • When a new vendor pricelist record is created from purchase order +confirmation, the secondary UOM from the purchase order line is +automatically stored in the vendor pricelist entry.
  • +
+
+
+

Known issues / Roadmap

+

Updating existing vendor pricelist records from purchase order +confirmation does not currently support secondary UOM or secondary UOM +pricing. This is not included in the current scope and may be considered +in future improvements.

-

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 @@ -411,15 +436,15 @@

Bug Tracker

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

-

Credits

+

Credits

-

Authors

+

Authors

  • Tecnativa
-

Contributors

+

Contributors

-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association @@ -445,6 +474,5 @@

Maintainers

-
diff --git a/purchase_order_secondary_unit/tests/__init__.py b/purchase_order_secondary_unit/tests/__init__.py index 6df95cebd79..cee0507553b 100644 --- a/purchase_order_secondary_unit/tests/__init__.py +++ b/purchase_order_secondary_unit/tests/__init__.py @@ -1,2 +1,4 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from . import common +from . import test_product_supplierinfo_secondary_unit from . import test_purchase_order_secondary_unit diff --git a/purchase_order_secondary_unit/tests/common.py b/purchase_order_secondary_unit/tests/common.py new file mode 100644 index 00000000000..d536d59b67e --- /dev/null +++ b/purchase_order_secondary_unit/tests/common.py @@ -0,0 +1,33 @@ +# Copyright 2018 Tecnativa - Sergio Teruel +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import Command + +from odoo.addons.base.tests.common import BaseCommon + + +class TestPurchaseSecondaryUnitCommon(BaseCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env.user.groups_id = [Command.link(cls.env.ref("uom.group_uom").id)] + cls.product_uom_kg = cls.env.ref("uom.product_uom_kgm") + cls.product_uom_gram = cls.env.ref("uom.product_uom_gram") + cls.product_uom_unit = cls.env.ref("uom.product_uom_unit") + cls.product = cls.env["product.product"].create( + { + "name": "Test Product", + "uom_id": cls.product_uom_kg.id, + "uom_po_id": cls.product_uom_kg.id, + } + ) + cls.secondary_unit = cls.env["product.secondary.unit"].create( + { + "name": "unit-700", + "uom_id": cls.product_uom_unit.id, + "factor": 0.7, + "product_tmpl_id": cls.product.product_tmpl_id.id, + } + ) + cls.product.purchase_secondary_uom_id = cls.secondary_unit + cls.partner = cls.env["res.partner"].create({"name": "Test Vendor"}) diff --git a/purchase_order_secondary_unit/tests/test_product_supplierinfo_secondary_unit.py b/purchase_order_secondary_unit/tests/test_product_supplierinfo_secondary_unit.py new file mode 100644 index 00000000000..8fc9ef7921c --- /dev/null +++ b/purchase_order_secondary_unit/tests/test_product_supplierinfo_secondary_unit.py @@ -0,0 +1,76 @@ +# Copyright 2026 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.tests import Form, tagged + +from .common import TestPurchaseSecondaryUnitCommon + + +@tagged("-at_install", "post_install") +class TestProductSupplierinfoSecondaryUnit(TestPurchaseSecondaryUnitCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.supplierinfo = cls.env["product.supplierinfo"].create( + { + "partner_id": cls.partner.id, + "product_tmpl_id": cls.product.product_tmpl_id.id, + "price": 100.0, + } + ) + + def test_supplierinfo_secondary_uom_price_compute(self): + self.supplierinfo.secondary_uom_id = self.secondary_unit + # price = 100, factor = 0.7, secondary_uom_price = 70 + self.assertEqual(self.supplierinfo.secondary_uom_price, 70.0) + + def test_supplierinfo_secondary_uom_price_inverse(self): + self.supplierinfo.secondary_uom_id = self.secondary_unit + self.supplierinfo.secondary_uom_price = 140.0 + # secondary_uom_price = 140, factor = 0.7, price = 200 + self.assertEqual(self.supplierinfo.price, 200.0) + + def test_supplierinfo_no_secondary_unit(self): + self.supplierinfo.secondary_uom_id = False + self.assertEqual(self.supplierinfo.secondary_uom_price, 0.0) + + def test_supplierinfo_onchange_product_tmpl_id_secondary_uom(self): + self.product.product_tmpl_id.purchase_secondary_uom_id = self.secondary_unit + supplierinfo_form = Form( + self.env["product.supplierinfo"].with_context( + default_product_tmpl_id=self.product.product_tmpl_id.id + ) + ) + supplierinfo_form.partner_id = self.partner + self.assertEqual(supplierinfo_form.secondary_uom_id, self.secondary_unit) + + def test_supplierinfo_onchange_product_id_secondary_uom(self): + self.product.purchase_secondary_uom_id = self.secondary_unit + supplierinfo_form = Form( + self.env["product.supplierinfo"].with_context( + default_product_id=self.product.id, + default_product_tmpl_id=self.product.product_tmpl_id.id, + ) + ) + supplierinfo_form.partner_id = self.partner + self.assertEqual(supplierinfo_form.secondary_uom_id, self.secondary_unit) + + def test_supplierinfo_onchange_product_variant_takes_precedence(self): + secondary_unit_2 = self.env["product.secondary.unit"].create( + { + "name": "Pallet", + "uom_id": self.product_uom_unit.id, + "factor": 48.0, + "product_tmpl_id": self.product.product_tmpl_id.id, + } + ) + self.product.product_tmpl_id.purchase_secondary_uom_id = self.secondary_unit + self.product.purchase_secondary_uom_id = secondary_unit_2 + supplierinfo_form = Form( + self.env["product.supplierinfo"].with_context( + default_product_id=self.product.id, + default_product_tmpl_id=self.product.product_tmpl_id.id, + ) + ) + supplierinfo_form.partner_id = self.partner + self.assertEqual(supplierinfo_form.secondary_uom_id, secondary_unit_2) diff --git a/purchase_order_secondary_unit/tests/test_purchase_order_secondary_unit.py b/purchase_order_secondary_unit/tests/test_purchase_order_secondary_unit.py index 17c03215ff1..9ff99cfc2b8 100644 --- a/purchase_order_secondary_unit/tests/test_purchase_order_secondary_unit.py +++ b/purchase_order_secondary_unit/tests/test_purchase_order_secondary_unit.py @@ -3,34 +3,14 @@ from odoo import Command, fields from odoo.tests import Form, tagged -from odoo.addons.base.tests.common import BaseCommon +from .common import TestPurchaseSecondaryUnitCommon @tagged("-at_install", "post_install") -class TestPurchaseOrderSecondaryUnit(BaseCommon): +class TestPurchaseOrderSecondaryUnit(TestPurchaseSecondaryUnitCommon): @classmethod def setUpClass(cls): super().setUpClass() - # Active multiple units of measure security group for user - cls.env.user.groups_id = [(4, cls.env.ref("uom.group_uom").id)] - cls.product_uom_kg = cls.env.ref("uom.product_uom_kgm") - cls.product_uom_gram = cls.env.ref("uom.product_uom_gram") - cls.product_uom_unit = cls.env.ref("uom.product_uom_unit") - # Create a product - product_form = Form(cls.env["product.product"]) - product_form.name = "Test" - product_form.uom_id = cls.product_uom_kg - product_form.uom_po_id = cls.product_uom_kg - cls.product = product_form.save() - # Set a secondary unit on the template of the previously created product - with Form(cls.product.product_tmpl_id) as template_form: - with template_form.secondary_uom_ids.new() as secondary_uom_form: - secondary_uom_form.name = "unit-700" - secondary_uom_form.uom_id = cls.product_uom_unit - secondary_uom_form.factor = 0.7 - cls.secondary_unit = cls.product.product_tmpl_id.secondary_uom_ids - cls.product.purchase_secondary_uom_id = cls.secondary_unit.id - cls.partner = cls.env["res.partner"].create({"name": "test - partner"}) cls.purchase_order_obj = cls.env["purchase.order"] po_val = { "partner_id": cls.partner.id, @@ -76,3 +56,51 @@ def test_purchase_order_02(self): self.assertAlmostEqual(line_new.product_qty, 0.7, places=2) line_new.product_qty = 1 self.assertEqual(line_new.secondary_uom_qty, 1.43) + + def test_purchase_order_secondary_uom_price(self): + purchase_order = Form(self.order) + with purchase_order.order_line.edit(0) as line: + line.secondary_uom_id = self.secondary_unit + line.price_unit = 100.0 + # price_unit = 100, factor = 0.7, secondary_uom_price = 70 + self.assertEqual(line.secondary_uom_price, 70.0) + + def test_purchase_order_confirm_creates_supplierinfo_with_secondary_uom(self): + new_product = self.env["product.product"].create( + { + "name": "New Product", + "uom_id": self.product_uom_kg.id, + "uom_po_id": self.product_uom_kg.id, + } + ) + secondary_unit = self.env["product.secondary.unit"].create( + { + "name": "Case", + "uom_id": self.product_uom_unit.id, + "factor": 5.0, + "product_tmpl_id": new_product.product_tmpl_id.id, + } + ) + po = self.purchase_order_obj.create( + { + "partner_id": self.partner.id, + "order_line": [ + Command.create( + { + "product_id": new_product.id, + "product_qty": 10, + "product_uom": new_product.uom_id.id, + "price_unit": 50.0, + "secondary_uom_id": secondary_unit.id, + "secondary_uom_qty": 2.0, + } + ) + ], + } + ) + po.button_confirm() + # Check that supplierinfo was created with secondary_uom_id + supplierinfo = new_product.seller_ids + self.assertTrue(supplierinfo) + self.assertEqual(supplierinfo.partner_id, self.partner) + self.assertEqual(supplierinfo.secondary_uom_id, secondary_unit) diff --git a/purchase_order_secondary_unit/views/product_supplierinfo_views.xml b/purchase_order_secondary_unit/views/product_supplierinfo_views.xml new file mode 100644 index 00000000000..16bf9abb2b1 --- /dev/null +++ b/purchase_order_secondary_unit/views/product_supplierinfo_views.xml @@ -0,0 +1,51 @@ + + + + product.supplierinfo.form.view + product.supplierinfo + + + + + + + + + product.supplierinfo.list.view + product.supplierinfo + + + + + + + + + diff --git a/purchase_order_secondary_unit/views/purchase_order_portal_templates.xml b/purchase_order_secondary_unit/views/purchase_order_portal_templates.xml new file mode 100644 index 00000000000..8f2b5c910a6 --- /dev/null +++ b/purchase_order_secondary_unit/views/purchase_order_portal_templates.xml @@ -0,0 +1,95 @@ + + + + + diff --git a/purchase_order_secondary_unit/views/purchase_order_views.xml b/purchase_order_secondary_unit/views/purchase_order_views.xml index 087e71d7ae7..a949d2543a3 100644 --- a/purchase_order_secondary_unit/views/purchase_order_views.xml +++ b/purchase_order_secondary_unit/views/purchase_order_views.xml @@ -27,6 +27,11 @@ readonly="state in ['purchase','done', 'cancel']" required="secondary_uom_qty != 0.0" /> + +