Skip to content
Closed
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
8 changes: 7 additions & 1 deletion sale_ux/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
##############################################################################
{
"name": "Sale UX",
"version": "19.0.1.1.0",
"version": "19.0.1.2.0",
"category": "Sales",
"sequence": 14,
"summary": "",
Expand All @@ -45,9 +45,15 @@
"views/res_partner_view.xml",
"views/res_config_settings_views.xml",
"views/account_fiscal_position_views.xml",
"views/product_template_views.xml",
"data/ir_config_parameter_data.xml",
"data/ir_cron.xml",
],
"assets": {
"web.assets_backend": [
"sale_ux/static/src/js/sale_product_field.js",
],
},
"demo": [],
"installable": True,
"auto_install": False,
Expand Down
1 change: 1 addition & 0 deletions sale_ux/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from . import analytic_account
from . import res_config_settings
from . import product_product
from . import product_template
from . import account_fiscal_position
from . import res_partner
from . import crm_team
25 changes: 25 additions & 0 deletions sale_ux/models/product_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
##############################################################################
# For copyright and license notices, see __manifest__.py file in module root
# directory
##############################################################################
import logging

from odoo import fields, models

_logger = logging.getLogger(__name__)


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

only_packagings = fields.Boolean(
default=False,
help="Indicates that this product is only used as packaging and does not use units.",
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

El texto de ayuda "Indicates that this product is only used as packaging and does not use units" es confuso. El campo no indica que el producto "es un packaging", sino que restringe las UoM disponibles a solo las definidas en los packagings del producto.

Sugerencia de mejora:

help="When enabled, only UoMs defined in product packagings will be available for selection in sale orders."
Suggested change
help="Indicates that this product is only used as packaging and does not use units.",
help="When enabled, only UoMs defined in product packagings will be available for selection in sale orders.",

Copilot uses AI. Check for mistakes.
)

def _get_available_uoms(self):
self.ensure_one()
res = super()._get_available_uoms()
if self.only_packagings:
return self.uom_ids
return res
8 changes: 8 additions & 0 deletions sale_ux/models/sale_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,3 +297,11 @@ def write(self, vals):
)
)
return super().write(vals)

def _get_product_catalog_order_data(self, products, **kwargs):
"""Override to use packaging UoM when only_packagings is set"""
res = super()._get_product_catalog_order_data(products, **kwargs)
for product in products:
if product.product_tmpl_id.only_packagings and product.uom_ids:
res[product.id]["uomDisplayName"] = product.uom_ids[0].display_name
return res
27 changes: 27 additions & 0 deletions sale_ux/models/sale_order_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,30 @@ def _compute_discount(self):
and not (x.order_id.pricelist_id and x.pricelist_item_id._show_discount())
)
super(SaleOrderLine, self - lines)._compute_discount()

def _compute_product_uom_id(self):
"""Override to respect only_packagings configuration"""
for line in self:
if line.product_id.product_tmpl_id.only_packagings and line.product_id.uom_ids:
if line.product_uom_id and line.product_uom_id in line.product_id.uom_ids:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sería necesario este if con el continue?
Creo que pondría solo "line.product_uom_id = line.product_id.uom_ids[0]"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fran ! ese if con el continue evaluo el caso donde el usuario elige manualmente la uom. Entonces si se vuelve a ejecutar el compute no fuerza la uom

continue
line.product_uom_id = line.product_id.uom_ids[0]
else:
super()._compute_product_uom_id()

@api.depends("product_template_id.only_packagings")
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

El decorador @api.depends debería depender de product_id.product_tmpl_id.only_packagings en lugar de product_template_id.only_packagings, ya que en la línea 69 se accede al producto a través de line.product_id y luego a product.product_tmpl_id. Esto asegura que el cálculo se active cuando cambie el campo correcto.

Suggested change
@api.depends("product_template_id.only_packagings")
@api.depends("product_id.product_tmpl_id.only_packagings")

Copilot uses AI. Check for mistakes.
def _compute_allowed_uom_ids(self):
lines = self.filtered(lambda x: x.product_id.product_tmpl_id.only_packagings)
for line in lines:
line.allowed_uom_ids = line.product_id.uom_ids
super(SaleOrderLine, self - lines)._compute_allowed_uom_ids()

def _get_product_catalog_lines_data(self, **kwargs):
res = super()._get_product_catalog_lines_data(**kwargs)
if (
len(self) == 1
and self.product_id.product_tmpl_id.only_packagings
and self.product_uom_id in self.product_id.uom_ids
):
res["uomDisplayName"] = self.product_uom_id.display_name
return res
26 changes: 26 additions & 0 deletions sale_ux/static/src/js/sale_product_field.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/** @odoo-module **/

import { SaleOrderLineProductField } from '@sale/js/sale_product_field';
import { patch } from '@web/core/utils/patch';

patch(SaleOrderLineProductField. prototype, {
/**
* Override to set first packaging as default UoM when only_packagings is True
*/
async _openProductConfigurator(edit = false, selectedComboItems = []) {
const saleOrderLine = this.props.record.data;
if (saleOrderLine.product_template_id && !edit) {
const productTemplate = await this.orm.read(
'product.template',
[saleOrderLine.product_template_id.id],
['only_packagings', 'uom_ids']
);
if (productTemplate[0].only_packagings && productTemplate[0].uom_ids.length > 0) {
await this.props.record.update({
product_uom_id: { id: productTemplate[0].uom_ids[0] }
});
}
}
return super._openProductConfigurator(edit, selectedComboItems);
},
});
14 changes: 14 additions & 0 deletions sale_ux/views/product_template_views.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0"?>
<odoo>
<record id="product_template_form_view" model="ir.ui.view">
<field name="name">sale_ux.product.form</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_form_view"/>
<field name="priority">30</field>
<field name="arch" type="xml">
<field name="uom_ids" position="after">
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

La vista asume que existe un campo uom_ids en product.template para poder posicionar el nuevo campo only_packagings después de él. Sin embargo, en Odoo estándar no existe este campo por defecto.

Verifica que:

  1. Otro módulo esté agregando el campo uom_ids a product.template, o
  2. El campo de referencia correcto sea otro (por ejemplo, packaging_ids)

Si uom_ids no existe, el xpath fallará y la vista no se cargará correctamente.

Suggested change
<field name="uom_ids" position="after">
<field name="packaging_ids" position="after">

Copilot uses AI. Check for mistakes.
<field name="only_packagings"/>
</field>
</field>
</record>
</odoo>