diff --git a/product_secondary_unit/README.rst b/product_secondary_unit/README.rst index efc6bfa2aaa..37223f7fee9 100644 --- a/product_secondary_unit/README.rst +++ b/product_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 - ====================== Product Secondary Unit ====================== @@ -17,7 +13,7 @@ Product Secondary Unit .. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png :target: https://odoo-community.org/page/development-status :alt: Production/Stable -.. |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%2Fproduct--attribute-lightgray.png?logo=github @@ -40,6 +36,48 @@ other units with their conversion factor. .. contents:: :local: +Configuration +============= + +To configure this module, go to **Settings** and locate the **Units of +Measure** section. + +Secondary Unit Price Display +---------------------------- + +Configure how unit prices and quantities are shown in reports when +secondary units are used. + +- **Sales**: Select the display policy for sales order and customer + invoice reports and portal views. +- **Purchase**: Select the display policy for purchase order and vendor + bill reports and portal views. + +Available options: + +- **Primary Unit Price Only**: Show only the primary unit price. +- **Prioritize Secondary Unit Price**: Show the secondary unit price + when available, otherwise fall back to the primary unit price. +- **Both Primary and Secondary Unit Prices**: Show both primary and + secondary unit prices. + +Hide Secondary Qty Column +------------------------- + +Hide the separate **Second Qty** column in reports. + +- When enabled, the **Second Qty** column is hidden in reports. The + secondary quantity can still be shown in the main **Qty** column + depending on the selected price display policy above. +- Apply the setting per document type: + + - **Sales** + - **Purchase** + +These settings are intended to be used by dependency modules (for +example, ``purchase_order_secondary_unit`` and +``account_move_secondary_unit``). + Usage ===== @@ -70,11 +108,15 @@ Authors Contributors ------------ -- Carlos Dauden -- Sergio Teruel -- Kitti Upariphutthiphong -- Pimolnat Suntian -- Alan Ramos +- Carlos Dauden +- Sergio Teruel +- Kitti Upariphutthiphong +- Pimolnat Suntian +- Alan Ramos +- `Quartile `__: + + - Yoshi Tashiro + - Aung Ko Ko Lin Maintainers ----------- diff --git a/product_secondary_unit/__manifest__.py b/product_secondary_unit/__manifest__.py index 7c024e14b57..1ea02c3ba36 100644 --- a/product_secondary_unit/__manifest__.py +++ b/product_secondary_unit/__manifest__.py @@ -12,6 +12,11 @@ "application": False, "installable": True, "depends": ["product"], - "data": ["security/ir.model.access.csv", "views/product_views.xml"], + "data": [ + "security/product_secondary_unit_groups.xml", + "security/ir.model.access.csv", + "views/product_views.xml", + "views/res_config_settings_views.xml", + ], "maintainers": ["sergio-teruel"], } diff --git a/product_secondary_unit/models/__init__.py b/product_secondary_unit/models/__init__.py index 0f06812747f..da1809c334c 100644 --- a/product_secondary_unit/models/__init__.py +++ b/product_secondary_unit/models/__init__.py @@ -3,3 +3,5 @@ from . import product_second_unit from . import product_secondary_unit_mixin from . import product_template +from . import res_company +from . import res_config_settings diff --git a/product_secondary_unit/models/product_secondary_unit_mixin.py b/product_secondary_unit/models/product_secondary_unit_mixin.py index 7129d152ce5..2128db8bc49 100644 --- a/product_secondary_unit/models/product_secondary_unit_mixin.py +++ b/product_secondary_unit/models/product_secondary_unit_mixin.py @@ -149,3 +149,56 @@ def default_get(self, fields_list): ): defaults["secondary_uom_qty"] = 1.0 return defaults + + def _get_secondary_uom_report_type(self): + """Return 'sale', 'purchase', or None.""" + self.ensure_one() + if self._name == "sale.order.line" or ( + self._name == "account.move.line" + and self.move_id.is_sale_document(include_receipts=True) + ): + return "sale" + if self._name == "purchase.order.line" or ( + self._name == "account.move.line" + and self.move_id.is_purchase_document(include_receipts=True) + ): + return "purchase" + return None + + def _get_secondary_uom_hide_col(self): + """Return whether secondary UoM column should be hidden on reports.""" + self.ensure_one() + if not self.secondary_uom_id: + return True + report_type = self._get_secondary_uom_report_type() + if report_type == "purchase": + return self.company_id.hide_secondary_uom_column_purchase + if report_type == "sale": + return self.company_id.hide_secondary_uom_column_sale + return True + + def get_secondary_uom_display_mode(self): + """Return display mode for secondary UoM price on reports.""" + self.ensure_one() + if not self.secondary_uom_id: + return "primary" + report_type = self._get_secondary_uom_report_type() + if report_type == "purchase": + return self.company_id.secondary_uom_price_display_purchase + if report_type == "sale": + return self.company_id.secondary_uom_price_display_sale + return "primary" + + def report_show_price_uom(self, uom_source=None): + """Return True if UoM should be shown in price column. + + UoM is shown when the line displays multiple UoMs. + """ + self.ensure_one() + if not self.secondary_uom_id: + return False + hide_col = self._get_secondary_uom_hide_col() + display_mode = self.get_secondary_uom_display_mode() + if uom_source == "primary_uom" and display_mode == "secondary": + return False + return not hide_col or display_mode == "both" diff --git a/product_secondary_unit/models/res_company.py b/product_secondary_unit/models/res_company.py new file mode 100644 index 00000000000..a9a8d46e5f1 --- /dev/null +++ b/product_secondary_unit/models/res_company.py @@ -0,0 +1,51 @@ +# Copyright 2026 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + +PRICE_DISPLAY_SELECTION = [ + ("primary", "Primary Unit Price Only"), + ("secondary", "Prioritize Secondary Unit Price"), + ("both", "Both Primary and Secondary Unit Prices"), +] + + +class ResCompany(models.Model): + _inherit = "res.company" + + secondary_uom_price_display_sale = fields.Selection( + selection=PRICE_DISPLAY_SELECTION, + string="Secondary Unit Price Display (Sales)", + default="primary", + required=True, + ) + secondary_uom_price_display_purchase = fields.Selection( + selection=PRICE_DISPLAY_SELECTION, + string="Secondary Unit Price Display (Purchase)", + default="primary", + required=True, + ) + # Added for supporting the existing report presentation. We can drop this together + # with the second qty column in reports if the community agrees with it. + hide_secondary_uom_column_sale = fields.Boolean( + string="Hide Secondary UoM Column (Sales)", + default=False, + ) + hide_secondary_uom_column_purchase = fields.Boolean( + string="Hide Secondary UoM Column (Purchase)", + default=False, + ) + + def hide_secondary_uom_column(self, record): + """Return whether to hide the 'Second Qty' column for this document type.""" + if record._name == "sale.order" or ( + record._name == "account.move" + and record.is_sale_document(include_receipts=True) + ): + return self.hide_secondary_uom_column_sale + if record._name == "purchase.order" or ( + record._name == "account.move" + and record.is_purchase_document(include_receipts=True) + ): + return self.hide_secondary_uom_column_purchase + return True diff --git a/product_secondary_unit/models/res_config_settings.py b/product_secondary_unit/models/res_config_settings.py new file mode 100644 index 00000000000..7b5cf51570f --- /dev/null +++ b/product_secondary_unit/models/res_config_settings.py @@ -0,0 +1,25 @@ +# Copyright 2026 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = "res.config.settings" + + secondary_uom_price_display_sale = fields.Selection( + related="company_id.secondary_uom_price_display_sale", + readonly=False, + ) + secondary_uom_price_display_purchase = fields.Selection( + related="company_id.secondary_uom_price_display_purchase", + readonly=False, + ) + hide_secondary_uom_column_sale = fields.Boolean( + related="company_id.hide_secondary_uom_column_sale", + readonly=False, + ) + hide_secondary_uom_column_purchase = fields.Boolean( + related="company_id.hide_secondary_uom_column_purchase", + readonly=False, + ) diff --git a/product_secondary_unit/readme/CONFIGURE.md b/product_secondary_unit/readme/CONFIGURE.md new file mode 100644 index 00000000000..ba55653dbee --- /dev/null +++ b/product_secondary_unit/readme/CONFIGURE.md @@ -0,0 +1,34 @@ +To configure this module, go to **Settings** and locate the **Units of Measure** +section. + +## Secondary Unit Price Display + +Configure how unit prices and quantities are shown in reports when secondary units are +used. + +- **Sales**: Select the display policy for sales order and customer invoice reports and + portal views. +- **Purchase**: Select the display policy for purchase order and vendor bill reports and + portal views. + +Available options: + +- **Primary Unit Price Only**: Show only the primary unit price. +- **Prioritize Secondary Unit Price**: Show the secondary unit price when available, + otherwise fall back to the primary unit price. +- **Both Primary and Secondary Unit Prices**: Show both primary and secondary unit + prices. + +## Hide Secondary Qty Column + +Hide the separate **Second Qty** column in reports. + +- When enabled, the **Second Qty** column is hidden in reports. The secondary quantity + can still be shown in the main **Qty** column depending on the selected price display + policy above. +- Apply the setting per document type: + - **Sales** + - **Purchase** + +These settings are intended to be used by dependency modules (for example, +`purchase_order_secondary_unit` and `account_move_secondary_unit`). \ No newline at end of file diff --git a/product_secondary_unit/readme/CONTRIBUTORS.md b/product_secondary_unit/readme/CONTRIBUTORS.md index b9e4cd3c0b9..cd22f16ac6b 100644 --- a/product_secondary_unit/readme/CONTRIBUTORS.md +++ b/product_secondary_unit/readme/CONTRIBUTORS.md @@ -3,3 +3,6 @@ - Kitti Upariphutthiphong \<\> - Pimolnat Suntian \<\> - Alan Ramos \<\> +- [Quartile](https://www.quartile.co): + - Yoshi Tashiro + - Aung Ko Ko Lin diff --git a/product_secondary_unit/security/product_secondary_unit_groups.xml b/product_secondary_unit/security/product_secondary_unit_groups.xml new file mode 100644 index 00000000000..7df6e1fca38 --- /dev/null +++ b/product_secondary_unit/security/product_secondary_unit_groups.xml @@ -0,0 +1,11 @@ + + + + Sale Secondary Unit + + + + Purchase Secondary Unit + + + diff --git a/product_secondary_unit/static/description/index.html b/product_secondary_unit/static/description/index.html index 5f2e4e06282..8c2fc7c1d3d 100644 --- a/product_secondary_unit/static/description/index.html +++ b/product_secondary_unit/static/description/index.html @@ -3,7 +3,7 @@ -README.rst +Product Secondary Unit -
+
+

Product Secondary Unit

- - -Odoo Community Association - -
-

Product Secondary Unit

-

Production/Stable License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

+

Production/Stable License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

This module extends the functionality of product module to allow define other units with their conversion factor.

Table of contents

+
+

Configuration

+

To configure this module, go to Settings and locate the Units of +Measure section.

+
+

Secondary Unit Price Display

+

Configure how unit prices and quantities are shown in reports when +secondary units are used.

+
    +
  • Sales: Select the display policy for sales order and customer +invoice reports and portal views.
  • +
  • Purchase: Select the display policy for purchase order and vendor +bill reports and portal views.
  • +
+

Available options:

+
    +
  • Primary Unit Price Only: Show only the primary unit price.
  • +
  • Prioritize Secondary Unit Price: Show the secondary unit price +when available, otherwise fall back to the primary unit price.
  • +
  • Both Primary and Secondary Unit Prices: Show both primary and +secondary unit prices.
  • +
+
+
+

Hide Secondary Qty Column

+

Hide the separate Second Qty column in reports.

+
    +
  • When enabled, the Second Qty column is hidden in reports. The +secondary quantity can still be shown in the main Qty column +depending on the selected price display policy above.
  • +
  • Apply the setting per document type:
      +
    • Sales
    • +
    • Purchase
+

These settings are intended to be used by dependency modules (for +example, purchase_order_secondary_unit and +account_move_secondary_unit).

+
-

Usage

+

Usage

To use this module you need to:

  1. Go to a Product > General Information tab.
  2. @@ -400,7 +441,7 @@

    Usage

-

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 @@ -408,25 +449,30 @@

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 @@ -441,6 +487,5 @@

Maintainers

-
diff --git a/product_secondary_unit/views/res_config_settings_views.xml b/product_secondary_unit/views/res_config_settings_views.xml new file mode 100644 index 00000000000..d9670dcaf73 --- /dev/null +++ b/product_secondary_unit/views/res_config_settings_views.xml @@ -0,0 +1,74 @@ + + + + res.config.settings.view.form.inherit.secondary.unit + res.config.settings + + + + +
+
+
+
+
+ +
+ + + + + + +
+
+
+
+
+