Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 122 additions & 0 deletions sale_product_matrix_secondary_unit/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
================================
Secondary unit in product matrix
================================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:34455330ff1ccd5b50ea1363108cddf7ace04951394d5702f2aadc9c3d9ee471
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |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%2Fproduct--attribute-lightgray.png?logo=github
:target: https://github.com/OCA/product-attribute/tree/17.0/sale_product_matrix_secondary_unit
:alt: OCA/product-attribute
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/product-attribute-17-0/product-attribute-17-0-sale_product_matrix_secondary_unit
: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/product-attribute&target_branch=17.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

With this module we'll be able to set the secondary units in the product
matrix for a quick quotation for those products using this kind of
configurator.

**Table of contents**

.. contents::
:local:

Configuration
=============

To configure this module, you need to:

- Go to a product with variants or create one.
- In the *Attributes and variants* tab, *Sales Variant Selection*
section, select **Order grid entry**.
- In the *General information* tab, *Secondary unit of measure* section,
add one or several secondary units.
- You can also set a default **Sale secondary unit**.

Usage
=====

To use this module, you need to:

1. Go to a sales order and add the configured product.
2. The matrix dialog will show up and there you'll be able to select the
available secondary units.
3. If a default sale secondary unit is set, it will selected in the
dialog already.

Known issues / Roadmap
======================

- When could have several lines from the same template with different
secondary units. In that case, the use of the matrix is discarded to
avoid missmatching values. From that moment, the products are forced
to be configured with the regular product configurator.
- The client side is roughly implemented right now. Probably we'll fix
some of the most obvious bugs but our roadmap is headed to v17 with
the Owl webclient.

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/product-attribute/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 <https://github.com/OCA/product-attribute/issues/new?body=module:%20sale_product_matrix_secondary_unit%0Aversion:%2017.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

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

Credits
=======

Authors
-------

* Tecnativa

Contributors
------------

- Tecnativa (https://www.tecnativa.com)

- David Vidal

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.

.. |maintainer-carlos-lopez-tecnativa| image:: https://github.com/carlos-lopez-tecnativa.png?size=40px
:target: https://github.com/carlos-lopez-tecnativa
:alt: carlos-lopez-tecnativa

Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:

|maintainer-carlos-lopez-tecnativa|

This module is part of the `OCA/product-attribute <https://github.com/OCA/product-attribute/tree/17.0/sale_product_matrix_secondary_unit>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
1 change: 1 addition & 0 deletions sale_product_matrix_secondary_unit/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
29 changes: 29 additions & 0 deletions sale_product_matrix_secondary_unit/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Copyright 2024 Tecnativa - David Vidal
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
"name": "Secondary unit in product matrix",
"version": "17.0.1.0.0",
"author": "Tecnativa, Odoo Community Association (OCA)",
"license": "AGPL-3",
"website": "https://github.com/OCA/product-attribute",
"category": "Sales Management",
"maintainers": ["carlos-lopez-tecnativa"],
"depends": [
"sale_management",
"sale_product_matrix",
"sale_order_secondary_unit",
],
"data": [
"views/sale_order_views.xml",
],
"assets": {
"web.assets_backend": [
"sale_product_matrix_secondary_unit/static/src/js/sale_product_field.esm.js",
"sale_product_matrix_secondary_unit/static/src/js/product_matrix_dialog.esm.js",
"sale_product_matrix_secondary_unit/static/src/xml/**/*",
],
"web.assets_tests": [
"sale_product_matrix_secondary_unit/static/tests/tours/**/*",
],
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * sale_product_matrix_secondary_unit
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 15.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: sale_product_matrix_secondary_unit
#. openerp-web
#: code:addons/sale_product_matrix_secondary_unit/static/src/xml/product_matrix.xml:0
#, python-format
msgid "(main unit of measure)"
msgstr ""

#. module: sale_product_matrix_secondary_unit
#. openerp-web
#: code:addons/sale_product_matrix_secondary_unit/static/src/js/section_and_note_widget.js:0
#, python-format
msgid "Choose Product Variants"
msgstr ""

#. module: sale_product_matrix_secondary_unit
#. openerp-web
#: code:addons/sale_product_matrix_secondary_unit/static/src/js/section_and_note_widget.js:0
#, python-format
msgid "Close"
msgstr ""

#. module: sale_product_matrix_secondary_unit
#. openerp-web
#: code:addons/sale_product_matrix_secondary_unit/static/src/js/section_and_note_widget.js:0
#, python-format
msgid "Confirm"
msgstr ""

#. module: sale_product_matrix_secondary_unit
#: model:ir.model.fields,field_description:sale_product_matrix_secondary_unit.field_sale_order_line__force_product_configurator
msgid "Force Product Configurator"
msgstr ""

#. module: sale_product_matrix_secondary_unit
#: model:ir.model,name:sale_product_matrix_secondary_unit.model_product_template
msgid "Product Template"
msgstr ""

#. module: sale_product_matrix_secondary_unit
#: model:ir.model,name:sale_product_matrix_secondary_unit.model_sale_order
msgid "Sales Order"
msgstr ""

#. module: sale_product_matrix_secondary_unit
#: model:ir.model,name:sale_product_matrix_secondary_unit.model_sale_order_line
msgid "Sales Order Line"
msgstr ""

#. module: sale_product_matrix_secondary_unit
#. openerp-web
#: code:addons/sale_product_matrix_secondary_unit/static/src/xml/product_matrix.xml:0
#, python-format
msgid "Secondary Unit"
msgstr ""

#. module: sale_product_matrix_secondary_unit
#. openerp-web
#: code:addons/sale_product_matrix_secondary_unit/static/src/xml/product_matrix.xml:0
#, python-format
msgid "Secondary unit"
msgstr ""
2 changes: 2 additions & 0 deletions sale_product_matrix_secondary_unit/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import product_template
from . import sale_order
21 changes: 21 additions & 0 deletions sale_product_matrix_secondary_unit/models/product_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright 2024 Tecnativa - David Vidal
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import models


class ProductTemplate(models.Model):
_inherit = "product.template"

def _get_template_matrix(self, **kwargs):
matrix = super()._get_template_matrix(**kwargs)
# The default secondary unit
if self.sale_secondary_uom_id:
matrix["secondary_unit_id"] = self.sale_secondary_uom_id.id
# Optional secondary units
if self.secondary_uom_ids:
matrix["secondary_units"] = [
{"name": f"{su.name} {su.factor} {su.sudo().uom_id.name}", "id": su.id}
for su in self.secondary_uom_ids
]
matrix["uom_name"] = self.uom_id.name
return matrix
121 changes: 121 additions & 0 deletions sale_product_matrix_secondary_unit/models/sale_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Copyright 2024 Tecnativa - David Vidal
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
import json

from odoo import api, fields, models


class SaleOrder(models.Model):
_inherit = "sale.order"

def _get_matrix(self, product_template):
order_lines = self.order_line.filtered(
lambda line: line.product_id
and line.product_template_id == product_template
)
# Check if the secondary_uom_id is the same across all the order lines
is_same_secondary_uom = all(
x.secondary_uom_id == order_lines[0].secondary_uom_id for x in order_lines
)
# TODO: Improve this case handling
if not is_same_secondary_uom:
matrix = super()._get_matrix(product_template)
matrix.pop("secondary_units", None)
return matrix
# Whether true or false...
matrix = super(
SaleOrder,
self.with_context(
get_matrix_secondary_unit_id=order_lines.secondary_uom_id
),
)._get_matrix(product_template)
# There could be a default secondary in unit in which case we'll set it directly
# TODO: We should be able to flag the lines as already set by the matrix somehow
# so if there's no secondary unit selected it doesn't default to that default
# secondary unit every time.
matrix["secondary_unit_id"] = order_lines.secondary_uom_id.id or (
not order_lines and matrix.get("secondary_unit_id")
)
return matrix

@api.onchange("grid")
def _apply_grid(self):
if not self.grid or not self.grid_update:
return super()._apply_grid()
grid = json.loads(self.grid)
if "secondary_unit" not in grid:
return super()._apply_grid()
# In case that only the secondary unit is changed we need to set it manually
secondary_unit = self.env["product.secondary.unit"].browse(
grid["secondary_unit"]
)
if not grid.get("changed"):
lines = self.order_line.filtered(
lambda x, grid_template=self.grid_product_tmpl_id: grid_template
== x.product_template_id
)
lines.secondary_uom_id = secondary_unit
res = super()._apply_grid()
Attrib = self.env["product.template.attribute.value"]
dirty_cells = grid["changes"]
product_template = self.env["product.template"].browse(
grid["product_template_id"]
)
for cell in dirty_cells:
combination = Attrib.browse(cell["ptav_ids"])
no_variant_attr_values = (
combination - combination._without_no_variant_attributes()
)
# create or find product variant from combination
product = product_template._create_product_variant(combination)
order_lines = self.order_line.filtered(
lambda line,
product=product,
no_variant_attr_values=no_variant_attr_values: line.product_id.id
== product.id
and line.product_no_variant_attribute_value_ids.ids
== no_variant_attr_values.ids
)
order_lines.secondary_uom_id = secondary_unit
order_lines.secondary_uom_qty = cell["qty"]
order_lines._compute_helper_target_field_qty()
return res


class SaleOrderLine(models.Model):
_inherit = "sale.order.line"

force_product_configurator = fields.Boolean(
compute="_compute_force_product_configurator"
)

@api.depends("secondary_uom_id")
def _compute_force_product_configurator(self):
"""Checks if there are matrix products with the same template and different
secondary unit for every order"""
self.force_product_configurator = False
for order in self.order_id:
product_templates = order.order_line.product_template_id.filtered(
lambda x: x.product_add_mode == "matrix"
)
for product_template in product_templates:
order_lines = order.order_line.filtered(
lambda x, product_template=product_template: x.product_template_id
== product_template
)
if not all(
x.secondary_uom_id == order_lines[0].secondary_uom_id
for x in order_lines
):
self.force_product_configurator = True

def mapped(self, func):
# HACK: Use secondary_uom_qty when needed to avoid reparsing the matrix
if (
self.env.context.get("get_matrix_secondary_unit_id")
and func
and isinstance(func, str)
and func == "product_uom_qty"
):
func = "secondary_uom_qty"
return super().mapped(func)
3 changes: 3 additions & 0 deletions sale_product_matrix_secondary_unit/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[build-system]
requires = ["whool"]
build-backend = "whool.buildapi"
8 changes: 8 additions & 0 deletions sale_product_matrix_secondary_unit/readme/CONFIGURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
To configure this module, you need to:

- Go to a product with variants or create one.
- In the *Attributes and variants* tab, *Sales Variant Selection* section, select
**Order grid entry**.
- In the *General information* tab, *Secondary unit of measure* section, add one or
several secondary units.
- You can also set a default **Sale secondary unit**.
2 changes: 2 additions & 0 deletions sale_product_matrix_secondary_unit/readme/CONTRIBUTORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* Tecnativa (https://www.tecnativa.com)
* David Vidal
2 changes: 2 additions & 0 deletions sale_product_matrix_secondary_unit/readme/DESCRIPTION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
With this module we'll be able to set the secondary units in the product matrix for
a quick quotation for those products using this kind of configurator.
Loading