Compare commits
No commits in common. "19.0" and "main" have entirely different histories.
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
'name': 'Product UOM Change',
|
'name': 'Product UOM Change',
|
||||||
'version': '19.0.1.0.0',
|
'version': '18.0.1.0.0',
|
||||||
'summary': 'Allow changing Product UOM even if stock moves exist',
|
'summary': 'Allow changing Product UOM even if stock moves exist',
|
||||||
'description': """
|
'description': """
|
||||||
This module adds a wizard to allow changing the Unit of Measure (UOM) of a product
|
This module adds a wizard to allow changing the Unit of Measure (UOM) of a product
|
||||||
|
|||||||
@ -7,66 +7,23 @@ class ProductUomChangeWizard(models.TransientModel):
|
|||||||
|
|
||||||
product_tmpl_id = fields.Many2one('product.template', string='Product', required=True, readonly=True)
|
product_tmpl_id = fields.Many2one('product.template', string='Product', required=True, readonly=True)
|
||||||
current_uom_id = fields.Many2one('uom.uom', related='product_tmpl_id.uom_id', string='Current UOM', readonly=True)
|
current_uom_id = fields.Many2one('uom.uom', related='product_tmpl_id.uom_id', string='Current UOM', readonly=True)
|
||||||
allowed_uom_ids = fields.Many2many('uom.uom', string='Allowed UOMs', compute='_compute_allowed_uom_ids')
|
uom_category_id = fields.Many2one('uom.category', related='product_tmpl_id.uom_id.category_id', readonly=True)
|
||||||
new_uom_id = fields.Many2one('uom.uom', string='New UOM', required=True)
|
new_uom_id = fields.Many2one('uom.uom', string='New UOM', required=True)
|
||||||
new_uom_po_id = fields.Many2one('uom.uom', string='New Purchase UOM')
|
new_uom_po_id = fields.Many2one('uom.uom', string='New Purchase UOM')
|
||||||
|
|
||||||
@api.depends('product_tmpl_id.uom_id')
|
|
||||||
def _compute_allowed_uom_ids(self):
|
|
||||||
for record in self:
|
|
||||||
if record.product_tmpl_id.uom_id:
|
|
||||||
# Find all UOMs that share the same root reference as the current UOM
|
|
||||||
# uom.uom model now uses _has_common_reference logic, but simpler to search by root category if possible.
|
|
||||||
# Since category_id is gone, we can group by root UoM if that concept exists, or rely on _has_common_reference.
|
|
||||||
# However, for a domain, we need a list of IDs.
|
|
||||||
# We can iterate all UOMs and check _has_common_reference, OR traverse up to the root and back down.
|
|
||||||
# Looking at uom_uom.py: _order = 'sequence, relative_uom_id, id'.
|
|
||||||
# fields: relative_uom_id (Reference Unit), related_uom_ids (Related UoMs).
|
|
||||||
# To get all in "category", we need to find the root.
|
|
||||||
|
|
||||||
# Let's traverse up to find the root.
|
|
||||||
uom = record.product_tmpl_id.uom_id
|
|
||||||
while uom.relative_uom_id:
|
|
||||||
uom = uom.relative_uom_id
|
|
||||||
|
|
||||||
# uom is now the root. Now find all descendants.
|
|
||||||
# A recursive search or using parent_path would be ideal if available/indexed.
|
|
||||||
# uom.uom has parent_path.
|
|
||||||
# parent_path structure: "root_id/child_id/..."
|
|
||||||
# So all UOMs in same category start with same root_id in parent_path.
|
|
||||||
root_id = uom.id
|
|
||||||
domain = [('parent_path', '=like', f'{root_id}/%')]
|
|
||||||
# Also include the root itself if it doesn't match the like pattern (which it usually doesn't as it is just "id/")
|
|
||||||
# Wait, parent_path is updated by standard valid Parent/Child implementation.
|
|
||||||
# Actually, simpler: search for uoms where root is the same.
|
|
||||||
# But we don't have a stored 'root_id'.
|
|
||||||
# Let's use the fact that we have the root uom 'uom'.
|
|
||||||
# We can search for all uoms that have this root as ancestor?
|
|
||||||
# Actually, standard Odoo usually just does `uom.search([])` and filters in python if the set is small,
|
|
||||||
# but UOMs can be many.
|
|
||||||
# Let's look at uom_uom.py again.
|
|
||||||
# It has `_has_common_reference`.
|
|
||||||
|
|
||||||
# A safer approach for now: Get all UOMs and filter. UOM table is usually small < 100.
|
|
||||||
all_uoms = self.env['uom.uom'].search([])
|
|
||||||
allowed = all_uoms.filtered(lambda u: u._has_common_reference(record.product_tmpl_id.uom_id))
|
|
||||||
record.allowed_uom_ids = allowed
|
|
||||||
else:
|
|
||||||
record.allowed_uom_ids = False
|
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def default_get(self, fields):
|
def default_get(self, fields):
|
||||||
res = super(ProductUomChangeWizard, self).default_get(fields)
|
res = super(ProductUomChangeWizard, self).default_get(fields)
|
||||||
if self.env.context.get('active_model') == 'product.template' and self.env.context.get('active_id'):
|
if self._context.get('active_model') == 'product.template' and self._context.get('active_id'):
|
||||||
res['product_tmpl_id'] = self.env.context['active_id']
|
res['product_tmpl_id'] = self._context['active_id']
|
||||||
elif self.env.context.get('active_model') == 'product.product' and self.env.context.get('active_id'):
|
elif self._context.get('active_model') == 'product.product' and self._context.get('active_id'):
|
||||||
product = self.env['product.product'].browse(self.env.context['active_id'])
|
product = self.env['product.product'].browse(self._context['active_id'])
|
||||||
res['product_tmpl_id'] = product.product_tmpl_id.id
|
res['product_tmpl_id'] = product.product_tmpl_id.id
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def action_change_uom(self):
|
def action_change_uom(self):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
if not self.new_uom_id._has_common_reference(self.product_tmpl_id.uom_id):
|
if self.new_uom_id.category_id != self.product_tmpl_id.uom_id.category_id:
|
||||||
raise UserError(_("New UOM must be in the same category as the current UOM."))
|
raise UserError(_("New UOM must be in the same category as the current UOM."))
|
||||||
|
|
||||||
# Update UOM via SQL to bypass the constraint check in product.template write
|
# Update UOM via SQL to bypass the constraint check in product.template write
|
||||||
@ -74,7 +31,7 @@ class ProductUomChangeWizard(models.TransientModel):
|
|||||||
|
|
||||||
# Also update Purchase UOM if specified
|
# Also update Purchase UOM if specified
|
||||||
if self.new_uom_po_id:
|
if self.new_uom_po_id:
|
||||||
if not self.new_uom_po_id._has_common_reference(self.product_tmpl_id.uom_po_id):
|
if self.new_uom_po_id.category_id != self.product_tmpl_id.uom_po_id.category_id:
|
||||||
raise UserError(_("New Purchase UOM must be in the same category as the current Purchase UOM."))
|
raise UserError(_("New Purchase UOM must be in the same category as the current Purchase UOM."))
|
||||||
self.env.cr.execute("UPDATE product_template SET uom_po_id = %s WHERE id = %s", (self.new_uom_po_id.id, self.product_tmpl_id.id))
|
self.env.cr.execute("UPDATE product_template SET uom_po_id = %s WHERE id = %s", (self.new_uom_po_id.id, self.product_tmpl_id.id))
|
||||||
|
|
||||||
|
|||||||
@ -8,9 +8,9 @@
|
|||||||
<group>
|
<group>
|
||||||
<field name="product_tmpl_id"/>
|
<field name="product_tmpl_id"/>
|
||||||
<field name="current_uom_id"/>
|
<field name="current_uom_id"/>
|
||||||
<field name="allowed_uom_ids" invisible="1"/>
|
<field name="uom_category_id" invisible="1"/>
|
||||||
<field name="new_uom_id" domain="[('id', 'in', allowed_uom_ids), ('id', '!=', current_uom_id)]"/>
|
<field name="new_uom_id" domain="[('category_id', '=', uom_category_id), ('id', '!=', current_uom_id)]"/>
|
||||||
<field name="new_uom_po_id" domain="[('id', 'in', allowed_uom_ids)]"/>
|
<field name="new_uom_po_id" domain="[('category_id', '=', uom_category_id)]"/>
|
||||||
</group>
|
</group>
|
||||||
<footer>
|
<footer>
|
||||||
<button name="action_change_uom" string="Change UOM" type="object" class="btn-primary" data-hotkey="q"/>
|
<button name="action_change_uom" string="Change UOM" type="object" class="btn-primary" data-hotkey="q"/>
|
||||||
@ -27,6 +27,6 @@
|
|||||||
<field name="target">new</field>
|
<field name="target">new</field>
|
||||||
<field name="binding_model_id" ref="product.model_product_template"/>
|
<field name="binding_model_id" ref="product.model_product_template"/>
|
||||||
<field name="binding_view_types">form</field>
|
<field name="binding_view_types">form</field>
|
||||||
<field name="group_ids" eval="[(4, ref('base.group_system'))]"/>
|
<field name="groups_id" eval="[(4, ref('base.group_system'))]"/>
|
||||||
</record>
|
</record>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user