diff --git a/product_origin_char/README.rst b/product_origin_char/README.rst index 0cbdfa6..e8a0f90 100644 --- a/product_origin_char/README.rst +++ b/product_origin_char/README.rst @@ -19,8 +19,7 @@ Product Origin Text |badge1| |badge2| -This module replaces the structured country/state origin fields from ``product_origin`` -with a flexible free-text field that can be defined per supplier. +This module adds a simple free-text ``origin_text`` field to products. **Problem:** @@ -38,21 +37,18 @@ These free-form descriptions don't fit into structured country/state fields. **Solution:** -This module adds a translatable ``origin_text`` field to ``product.supplierinfo`` that: +This module adds a simple ``origin_text`` field to ``product.template`` that: * Allows free-form text to describe product origin -* Is stored per supplier (different suppliers may have different origin info) -* Is translatable (can be described differently in each language) -* Is automatically displayed on the product based on the main vendor - (from ``product_main_seller`` module) +* Is accessible from product variants via related field +* Works with any product workflow **Features:** -* Free-text ``Origin`` field in supplier info (Purchase tab of product) -* Computed ``Origin`` field in product form (shows main vendor's origin) -* Field is visible in product list view (optional column) -* Full translation support for multiple languages -* Compatible with existing supplier management workflows +* Free-text ``Origin`` field in product form +* Field visible in product list views (optional column) +* Variants share the same origin as their template +* Editable from both template and variant views **Table of contents** @@ -65,7 +61,6 @@ Installation This module depends on: * ``product`` - Base product management -* ``product_main_seller`` - To determine the main vendor for products To install: @@ -77,8 +72,8 @@ Configuration No configuration is needed. The module works automatically after installation. -The origin text displayed on a product is based on the **main vendor** as determined -by ``product_main_seller`` (the first supplier in the vendors list). +The origin field appears in the product form view (next to category) and can be +enabled as an optional column in list views. Usage ===== @@ -86,29 +81,21 @@ Usage **To add origin information to a product:** #. Go to a product form -#. Open the **Purchase** tab -#. In the **Vendors** section, select a supplier line -#. Fill in the **Origin** field with free-form text describing the origin - (e.g., "Valencia, Huerta de..., Spain") +#. Find the **Origin** field (near the product category) +#. Fill in the origin with free-form text + (e.g., "Valencia, Spain", "Local producer - Basque Country") #. Save the product -**To view origin information:** +**To view origin information in lists:** -* The **Origin** field will be automatically displayed on the product form - (below the **Main Vendor** field in the Purchase tab) -* The origin shown is from the **main vendor** (first supplier in the list) -* You can also add the Origin column to product list views +* In product list views, enable the optional "Origin" column +* The origin is shown for both product templates and variants -**To change the displayed origin:** +**Product variants:** -* Reorder the vendors list to change which is the main vendor -* The origin text will automatically update to show the new main vendor's origin - -**Multi-language support:** - -* The origin text is translatable -* Switch to another language and edit the supplier info to provide a translation -* Each language can have a different description of the origin +* All variants of a product template share the same origin +* Updating the origin on any variant updates the template +* This ensures consistency across all variants Bug Tracker =========== diff --git a/product_origin_char/README_DEV.md b/product_origin_char/README_DEV.md index 3ed005a..789407d 100644 --- a/product_origin_char/README_DEV.md +++ b/product_origin_char/README_DEV.md @@ -4,111 +4,88 @@ ### Architecture -This module extends the product origin information system to use free-text fields instead of structured country/state fields. +This module adds a simple free-text origin field to products. **Models:** -1. **product.supplierinfo** - Base model with the `origin_text` field - - Field: `origin_text` (Char, translate=True) +1. **product.template** - Base model with the `origin_text` field + - Field: `origin_text` (Char) - This is where the actual data is stored - - Each supplier can have a different origin text for the same product + - Editable directly on the product form -2. **product.template** - Computed field - - Field: `origin_text` (Char, computed, store=False) - - Computes from main vendor's supplierinfo - - Depends on: `main_seller_id`, `variant_seller_ids.origin_text` +2. **product.product** - Related field for variant access + - Field: `origin_text` (Char, related to `product_tmpl_id.origin_text`) + - `readonly=False` allows editing from variant views + - Changes propagate to the template -3. **product.product** - Computed field (variant level) - - Field: `origin_text` (Char, computed, store=False) - - Computes from main vendor's supplierinfo - - Depends on: `product_tmpl_id.main_seller_id`, `seller_ids.origin_text` +### Why This Architecture? -### Why Computed Fields Instead of Related? +The `origin_text` field is stored in `product.template` because: -The `origin_text` field in `product.template` and `product.product` cannot be a simple `related` field because: +- Origin typically applies to all variants of a product +- Simplifies data management (one source of truth) +- Avoids duplication across variants +- Standard Odoo pattern for product-level attributes -- `main_seller_id` is a `res.partner` record -- `origin_text` is stored in `product.supplierinfo` records -- We need to find the supplierinfo record where `partner_id == main_seller_id` +The related field in `product.product` with `readonly=False` allows: -This requires a computed field with custom logic to filter and find the correct supplierinfo record. +- Seamless access from variant views +- Editing from either template or variant forms +- Automatic synchronization between template and variants -### Translation Support +### Previous Architecture (Deprecated) -The `origin_text` field in `product.supplierinfo` uses `translate=True`, which means: +The previous version stored `origin_text` in `product.supplierinfo` with computed +fields in template/product. This was deprecated because: -- Each language can have a different value -- Translations are stored in Odoo's translation system -- When switching languages, the field shows the translated value -- If no translation exists, it falls back to the default language value - -### Store Strategy - -The computed fields in product template and product use `store=False` because: - -- The value should always reflect the current main vendor -- If the main vendor changes or its origin text is updated, the product's origin should update automatically -- No need to store redundant data -- Reduces database size and update complexity +- Supplierinfo records don't always exist when products are created +- Added unnecessary complexity with computed fields +- Required `product_main_seller` dependency +- Origin semantically belongs to the product, not the supplier relationship ### Dependencies -- **product** - Core product module -- **product_main_seller** - Provides `main_seller_id` computed field for products - -### Relationship to product_origin - -This module is a replacement/alternative to the OCA `product_origin` module: - -- `product_origin` provides structured fields (country_id, state_id) -- `product_origin_char` provides free-text field (origin_text) -- Both cannot be installed simultaneously without potential conflicts -- This module was created because suppliers use creative, non-standardized origin descriptions +- **product** - Core product module (only dependency) ### Performance Considerations -- Computed fields with `store=False` are calculated on-the-fly -- Performance is acceptable because the computation is simple (filter + get first) -- If performance becomes an issue, consider: - - Adding `store=True` with proper dependencies - - Adding database indexes on frequently searched fields - - Caching strategies +- Simple stored field with no computation overhead +- Related field access is efficient in Odoo ORM +- No additional queries needed for variant access ### Testing Strategy Tests cover: -1. **Basic field storage** - Create supplierinfo with origin_text -2. **Computed field** - Verify product shows main vendor's origin -3. **Main vendor change** - Verify origin updates when main vendor changes -4. **Translation** - Verify field is translatable (multilingual support) -5. **Empty cases** - Product without vendors, vendor without origin - -### Future Improvements - -Potential enhancements: - -- Add migration script from `product_origin` to convert country/state to text -- Add bulk update wizard to set origin for multiple products -- Add origin text to purchase order lines -- Add search/group by origin in product lists -- Add validation rules (max length, format checks) +1. **Basic field storage** - Set origin on template +2. **Related field access** - Verify variant sees template origin +3. **Write from variant** - Verify changes propagate to template +4. **Empty cases** - Products without origin +5. **Multiple products** - Independent origins +6. **Variants** - All variants share same origin ## Code Quality - Follows OCA guidelines - Black formatted (line length 88) -- isort sorted imports -- Passes flake8 and pylint checks -- Full test coverage -- Documented with docstrings -- Translatable strings handled correctly (no `_()` in field definitions) +- isort for imports +- Minimal dependencies (only `product`) + +## Migration from v1.x + +If upgrading from the previous supplier-based architecture: + +1. Data in `product.supplierinfo.origin_text` will need manual migration +2. Run migration script to copy main supplier origin to product template +3. Remove dependency on `product_main_seller` if no longer needed ## Version History -- **18.0.1.0.0** (2026-02-25) - Initial release +- **18.0.2.0.0** (2026-03-06) - Simplified architecture + - Field directly on product.template + - Related field in product.product + - Removed dependency on product_main_seller + +- **18.0.1.0.0** (2026-02-25) - Initial release (deprecated) - Free-text origin field per supplier - Automatic display based on main vendor - - Multi-language support - - Full test coverage - - OCA documentation structure diff --git a/product_origin_char/__manifest__.py b/product_origin_char/__manifest__.py index 5be4956..18c9a8b 100644 --- a/product_origin_char/__manifest__.py +++ b/product_origin_char/__manifest__.py @@ -3,19 +3,17 @@ { # noqa: B018 "name": "Product Origin Text", - "version": "18.0.1.0.0", + "version": "18.0.2.0.0", "category": "Product", - "summary": "Free text origin field per supplier", + "summary": "Free text origin field for products", "author": "Odoo Community Association (OCA), Criptomart", "maintainers": ["Criptomart"], "license": "AGPL-3", "website": "https://git.criptomart.net/criptomart/addons-cm", "depends": [ "product", - "product_main_seller", ], "data": [ - "views/product_supplierinfo_views.xml", "views/product_template_views.xml", ], } diff --git a/product_origin_char/models/__init__.py b/product_origin_char/models/__init__.py index e138082..481ccad 100644 --- a/product_origin_char/models/__init__.py +++ b/product_origin_char/models/__init__.py @@ -1,6 +1,5 @@ # Copyright 2026 Criptomart # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from . import product_supplierinfo # noqa: F401 from . import product_template # noqa: F401 from . import product_product # noqa: F401 diff --git a/product_origin_char/models/product_product.py b/product_origin_char/models/product_product.py index 1ec475b..dea55c5 100644 --- a/product_origin_char/models/product_product.py +++ b/product_origin_char/models/product_product.py @@ -1,7 +1,6 @@ # Copyright 2026 Criptomart # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import api from odoo import fields from odoo import models @@ -10,21 +9,6 @@ class ProductProduct(models.Model): _inherit = "product.product" origin_text = fields.Char( - string="Origin", - compute="_compute_origin_text", - store=False, - help="Origin text from main vendor's supplierinfo", + related="product_tmpl_id.origin_text", + readonly=False, ) - - @api.depends("product_tmpl_id.main_seller_id", "seller_ids.origin_text") - def _compute_origin_text(self): - for product in self: - if product.product_tmpl_id.main_seller_id: - # Find the supplierinfo record for the main seller - main_seller = product.product_tmpl_id.main_seller_id - seller = product.seller_ids.filtered( - lambda s, ms=main_seller: s.partner_id == ms - )[:1] - product.origin_text = seller.origin_text if seller else False - else: - product.origin_text = False diff --git a/product_origin_char/models/product_supplierinfo.py b/product_origin_char/models/product_supplierinfo.py deleted file mode 100644 index 1f87c7d..0000000 --- a/product_origin_char/models/product_supplierinfo.py +++ /dev/null @@ -1,15 +0,0 @@ -# Copyright 2026 Criptomart -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - -from odoo import fields -from odoo import models - - -class ProductSupplierinfo(models.Model): - _inherit = "product.supplierinfo" - - origin_text = fields.Char( - string="Origin", - translate=True, - help="Free text to describe product origin (country, region, producer, etc.)", - ) diff --git a/product_origin_char/models/product_template.py b/product_origin_char/models/product_template.py index 3386907..28876b4 100644 --- a/product_origin_char/models/product_template.py +++ b/product_origin_char/models/product_template.py @@ -1,7 +1,6 @@ # Copyright 2026 Criptomart # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -from odoo import api from odoo import fields from odoo import models @@ -11,20 +10,5 @@ class ProductTemplate(models.Model): origin_text = fields.Char( string="Origin", - compute="_compute_origin_text", - store=False, - help="Origin text from main vendor's supplierinfo", + help="Origin of the product.", ) - - @api.depends("main_seller_id", "variant_seller_ids.origin_text") - def _compute_origin_text(self): - for template in self: - if template.main_seller_id: - # Find the supplierinfo record for the main seller - main_seller = template.main_seller_id - seller = template.variant_seller_ids.filtered( - lambda s, ms=main_seller: s.partner_id == ms - )[:1] - template.origin_text = seller.origin_text if seller else False - else: - template.origin_text = False diff --git a/product_origin_char/readme/CONFIGURE.rst b/product_origin_char/readme/CONFIGURE.rst index 6c5dff4..53df9d6 100644 --- a/product_origin_char/readme/CONFIGURE.rst +++ b/product_origin_char/readme/CONFIGURE.rst @@ -1,4 +1,4 @@ No configuration is needed. The module works automatically after installation. -The origin text displayed on a product is based on the **main vendor** as determined -by ``product_main_seller`` (the first supplier in the vendors list). +The origin field appears in the product form view (next to category) and can be +enabled as an optional column in list views. diff --git a/product_origin_char/readme/DESCRIPTION.rst b/product_origin_char/readme/DESCRIPTION.rst index 39203bc..b65fe60 100644 --- a/product_origin_char/readme/DESCRIPTION.rst +++ b/product_origin_char/readme/DESCRIPTION.rst @@ -1,5 +1,4 @@ -This module replaces the structured country/state origin fields from ``product_origin`` -with a flexible free-text field that can be defined per supplier. +This module adds a simple free-text ``origin_text`` field to products. **Problem:** @@ -17,18 +16,15 @@ These free-form descriptions don't fit into structured country/state fields. **Solution:** -This module adds a translatable ``origin_text`` field to ``product.supplierinfo`` that: +This module adds a simple ``origin_text`` field to ``product.template`` that: * Allows free-form text to describe product origin -* Is stored per supplier (different suppliers may have different origin info) -* Is translatable (can be described differently in each language) -* Is automatically displayed on the product based on the main vendor - (from ``product_main_seller`` module) +* Is accessible from product variants via related field +* Works with any product workflow **Features:** -* Free-text ``Origin`` field in supplier info (Purchase tab of product) -* Computed ``Origin`` field in product form (shows main vendor's origin) -* Field is visible in product list view (optional column) -* Full translation support for multiple languages -* Compatible with existing supplier management workflows +* Free-text ``Origin`` field in product form +* Field visible in product list views (optional column) +* Variants share the same origin as their template +* Editable from both template and variant views diff --git a/product_origin_char/readme/INSTALL.rst b/product_origin_char/readme/INSTALL.rst index 621a392..48c1f0d 100644 --- a/product_origin_char/readme/INSTALL.rst +++ b/product_origin_char/readme/INSTALL.rst @@ -1,7 +1,6 @@ This module depends on: * ``product`` - Base product management -* ``product_main_seller`` - To determine the main vendor for products To install: diff --git a/product_origin_char/readme/USAGE.rst b/product_origin_char/readme/USAGE.rst index 60476ba..d0da105 100644 --- a/product_origin_char/readme/USAGE.rst +++ b/product_origin_char/readme/USAGE.rst @@ -1,26 +1,18 @@ **To add origin information to a product:** #. Go to a product form -#. Open the **Purchase** tab -#. In the **Vendors** section, select a supplier line -#. Fill in the **Origin** field with free-form text describing the origin - (e.g., "Valencia, Huerta de..., Spain") +#. Find the **Origin** field (near the product category) +#. Fill in the origin with free-form text + (e.g., "Valencia, Spain", "Local producer - Basque Country") #. Save the product -**To view origin information:** +**To view origin information in lists:** -* The **Origin** field will be automatically displayed on the product form - (below the **Main Vendor** field in the Purchase tab) -* The origin shown is from the **main vendor** (first supplier in the list) -* You can also add the Origin column to product list views +* In product list views, enable the optional "Origin" column +* The origin is shown for both product templates and variants -**To change the displayed origin:** +**Product variants:** -* Reorder the vendors list to change which is the main vendor -* The origin text will automatically update to show the new main vendor's origin - -**Multi-language support:** - -* The origin text is translatable -* Switch to another language and edit the supplier info to provide a translation -* Each language can have a different description of the origin +* All variants of a product template share the same origin +* Updating the origin on any variant updates the template +* This ensures consistency across all variants diff --git a/product_origin_char/static/description/LOGO_NEEDED.txt b/product_origin_char/static/description/LOGO_NEEDED.txt deleted file mode 100644 index 8a1fad3..0000000 --- a/product_origin_char/static/description/LOGO_NEEDED.txt +++ /dev/null @@ -1 +0,0 @@ -Logo placeholder - run install_logo.sh to add CriptoMart logo diff --git a/product_origin_char/tests/test_product_origin_char.py b/product_origin_char/tests/test_product_origin_char.py index 0d7a9df..7b58a6f 100644 --- a/product_origin_char/tests/test_product_origin_char.py +++ b/product_origin_char/tests/test_product_origin_char.py @@ -5,190 +5,71 @@ from odoo.tests.common import TransactionCase class TestProductOriginChar(TransactionCase): + """Test cases for product_origin_char module. + + This module adds a simple origin_text field to product.template + with a related field in product.product for variant access. + """ + @classmethod def setUpClass(cls): super().setUpClass() cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) - # Create test suppliers - cls.supplier_1 = cls.env["res.partner"].create( - { - "name": "Supplier 1", - "is_company": True, - } - ) - cls.supplier_2 = cls.env["res.partner"].create( - { - "name": "Supplier 2", - "is_company": True, - } - ) - - # Create test product - cls.product = cls.env["product.product"].create( + # Create test product template + cls.product_tmpl = cls.env["product.template"].create( { "name": "Test Product", "type": "consu", } ) + cls.product = cls.product_tmpl.product_variant_ids[0] - def test_01_origin_text_in_supplierinfo(self): - """Test that origin_text can be set in supplierinfo""" - supplierinfo = self.env["product.supplierinfo"].create( - { - "partner_id": self.supplier_1.id, - "product_tmpl_id": self.product.product_tmpl_id.id, - "origin_text": "Valencia, Spain", - } - ) - self.assertEqual(supplierinfo.origin_text, "Valencia, Spain") + def test_01_origin_text_in_template(self): + """Test that origin_text can be set in product.template""" + self.product_tmpl.origin_text = "Valencia, Spain" + self.assertEqual(self.product_tmpl.origin_text, "Valencia, Spain") - def test_02_origin_from_main_seller(self): - """Test that product shows origin from main seller""" - # Create supplierinfo for supplier 1 (will be main seller) - self.env["product.supplierinfo"].create( - { - "partner_id": self.supplier_1.id, - "product_tmpl_id": self.product.product_tmpl_id.id, - "sequence": 1, - "origin_text": "Valencia, Spain", - } - ) - - # Verify main seller is supplier 1 - self.product.product_tmpl_id.invalidate_recordset() - self.assertEqual(self.product.product_tmpl_id.main_seller_id, self.supplier_1) - - # Verify origin_text on product matches supplier 1's origin - self.product.invalidate_recordset() - self.assertEqual(self.product.origin_text, "Valencia, Spain") - self.assertEqual(self.product.product_tmpl_id.origin_text, "Valencia, Spain") - - def test_03_origin_updates_with_main_seller_change(self): - """Test that origin updates when main seller changes""" - # Create supplierinfo for both suppliers - supplier1_info = self.env["product.supplierinfo"].create( - { - "partner_id": self.supplier_1.id, - "product_tmpl_id": self.product.product_tmpl_id.id, - "sequence": 1, - "origin_text": "Valencia, Spain", - } - ) - supplier2_info = self.env["product.supplierinfo"].create( - { - "partner_id": self.supplier_2.id, - "product_tmpl_id": self.product.product_tmpl_id.id, - "sequence": 2, - "origin_text": "Aragón, Spain", - } - ) - - # Initially, main seller is supplier 1 - self.product.product_tmpl_id.invalidate_recordset() - self.assertEqual(self.product.product_tmpl_id.main_seller_id, self.supplier_1) - self.product.invalidate_recordset() - self.assertEqual(self.product.origin_text, "Valencia, Spain") - - # Change main seller by swapping sequences - supplier1_info.sequence = 2 - supplier2_info.sequence = 1 - - # Verify main seller is now supplier 2 - self.product.product_tmpl_id.invalidate_recordset() - self.assertEqual(self.product.product_tmpl_id.main_seller_id, self.supplier_2) - - # Verify origin_text updated to supplier 2's origin - self.product.invalidate_recordset() + def test_02_origin_text_in_product_related(self): + """Test that product.product has related access to origin_text""" + self.product_tmpl.origin_text = "Aragón, Spain" + # Variant should show template's origin via related field self.assertEqual(self.product.origin_text, "Aragón, Spain") - def test_04_empty_origin_without_supplier(self): - """Test that product without suppliers has no origin""" - # Create product without suppliers - product_no_supplier = self.env["product.product"].create( + def test_03_origin_text_write_from_variant(self): + """Test that origin_text can be written from variant (readonly=False)""" + self.product.origin_text = "Basque Country" + # Should update the template + self.assertEqual(self.product_tmpl.origin_text, "Basque Country") + + def test_04_empty_origin(self): + """Test that origin_text defaults to False/empty""" + new_product = self.env["product.product"].create( { - "name": "Product Without Supplier", + "name": "Product Without Origin", "type": "consu", } ) + self.assertFalse(new_product.origin_text) + self.assertFalse(new_product.product_tmpl_id.origin_text) - # Verify no main seller and no origin - self.assertFalse(product_no_supplier.product_tmpl_id.main_seller_id) - self.assertFalse(product_no_supplier.origin_text) - - def test_05_empty_origin_with_supplier_no_text(self): - """Test that supplier without origin_text shows False""" - # Create supplierinfo without origin_text - self.env["product.supplierinfo"].create( - { - "partner_id": self.supplier_1.id, - "product_tmpl_id": self.product.product_tmpl_id.id, - "sequence": 1, - # No origin_text set - } - ) - - # Verify main seller exists but origin is False - self.product.product_tmpl_id.invalidate_recordset() - self.assertEqual(self.product.product_tmpl_id.main_seller_id, self.supplier_1) - self.product.invalidate_recordset() - self.assertFalse(self.product.origin_text) - - def test_06_translation_support(self): - """Test that origin_text field is translatable""" - # Create supplierinfo with origin in default language - supplierinfo = self.env["product.supplierinfo"].create( - { - "partner_id": self.supplier_1.id, - "product_tmpl_id": self.product.product_tmpl_id.id, - "origin_text": "Valencia, Spain", - } - ) - - # Verify field has translate=True attribute - field = self.env["product.supplierinfo"]._fields["origin_text"] - self.assertTrue(field.translate) - - # Test that we can set translation (requires lang to be installed) - # This is a basic check - full translation testing would require - # installing multiple languages - self.assertEqual(supplierinfo.origin_text, "Valencia, Spain") - - def test_07_multiple_products_same_supplier(self): - """Test that different products can have different origins from same supplier""" - product2 = self.env["product.product"].create( + def test_05_multiple_products_independent_origins(self): + """Test that different products have independent origins""" + product2_tmpl = self.env["product.template"].create( { "name": "Test Product 2", "type": "consu", } ) - # Create supplierinfo for product 1 - self.env["product.supplierinfo"].create( - { - "partner_id": self.supplier_1.id, - "product_tmpl_id": self.product.product_tmpl_id.id, - "origin_text": "Valencia, Spain", - } - ) + self.product_tmpl.origin_text = "Valencia, Spain" + product2_tmpl.origin_text = "Aragón, Spain" - # Create supplierinfo for product 2 with same supplier but different origin - self.env["product.supplierinfo"].create( - { - "partner_id": self.supplier_1.id, - "product_tmpl_id": product2.product_tmpl_id.id, - "origin_text": "Aragón, Spain", - } - ) + self.assertEqual(self.product_tmpl.origin_text, "Valencia, Spain") + self.assertEqual(product2_tmpl.origin_text, "Aragón, Spain") - # Verify each product has its own origin - self.product.invalidate_recordset() - product2.invalidate_recordset() - self.assertEqual(self.product.origin_text, "Valencia, Spain") - self.assertEqual(product2.origin_text, "Aragón, Spain") - - def test_08_product_variant_level(self): - """Test that origin_text works at product variant level""" + def test_06_product_variants_share_origin(self): + """Test that all variants of a template share the same origin""" # Create product template with variants product_attr = self.env["product.attribute"].create({"name": "Color"}) attr_value_red = self.env["product.attribute.value"].create( @@ -217,17 +98,49 @@ class TestProductOriginChar(TransactionCase): } ) - # Create supplierinfo at template level - self.env["product.supplierinfo"].create( + # Set origin on template + product_tmpl.origin_text = "Test Origin" + + # Verify all variants show the same origin + for variant in product_tmpl.product_variant_ids: + self.assertEqual(variant.origin_text, "Test Origin") + + def test_07_origin_update_propagates_to_variants(self): + """Test that updating template origin updates all variants""" + # Create product with variants + product_attr = self.env["product.attribute"].create({"name": "Size"}) + attr_value_s = self.env["product.attribute.value"].create( + {"name": "S", "attribute_id": product_attr.id} + ) + attr_value_m = self.env["product.attribute.value"].create( + {"name": "M", "attribute_id": product_attr.id} + ) + + product_tmpl = self.env["product.template"].create( { - "partner_id": self.supplier_1.id, - "product_tmpl_id": product_tmpl.id, - "origin_text": "Test Origin", + "name": "Sized Product", + "type": "consu", + "origin_text": "Original Origin", + "attribute_line_ids": [ + ( + 0, + 0, + { + "attribute_id": product_attr.id, + "value_ids": [(6, 0, [attr_value_s.id, attr_value_m.id])], + }, + ) + ], } ) - # Verify all variants show the same origin (from template level) - product_tmpl.invalidate_recordset() + # Verify initial origin for variant in product_tmpl.product_variant_ids: - variant.invalidate_recordset() - self.assertEqual(variant.origin_text, "Test Origin") + self.assertEqual(variant.origin_text, "Original Origin") + + # Update origin on template + product_tmpl.origin_text = "Updated Origin" + + # Verify all variants show updated origin + for variant in product_tmpl.product_variant_ids: + self.assertEqual(variant.origin_text, "Updated Origin") diff --git a/product_origin_char/views/product_supplierinfo_views.xml b/product_origin_char/views/product_supplierinfo_views.xml deleted file mode 100644 index d881aa0..0000000 --- a/product_origin_char/views/product_supplierinfo_views.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - product.supplierinfo.form.origin.text - product.supplierinfo - - - - - - - - - - - product.supplierinfo.tree.origin.text - product.supplierinfo - - - - - - - - diff --git a/product_origin_char/views/product_template_views.xml b/product_origin_char/views/product_template_views.xml index 19d9db7..8e91092 100644 --- a/product_origin_char/views/product_template_views.xml +++ b/product_origin_char/views/product_template_views.xml @@ -8,13 +8,9 @@ product.template - - - + + + @@ -34,9 +30,9 @@ product.template.tree.origin.text product.template - + - +