[FIX] stock: allow change of reference unit of measure

closes odoo/odoo#57485

Related: odoo/enterprise#17365
Signed-off-by: Arnold Moyaux <amoyaux@users.noreply.github.com>
This commit is contained in:
JF Aubert
2021-04-14 13:14:10 +00:00
committed by Arnold Moyaux
parent eaf5d86fe7
commit 6f182eeeab
7 changed files with 138 additions and 40 deletions
+11
View File
@@ -23,4 +23,15 @@
</field>
</record>
<record id="product_uom_categ_form_view" model="ir.ui.view">
<field name="name">uom.category.form</field>
<field name="model">uom.category</field>
<field name="inherit_id" ref="uom.product_uom_categ_form_view"/>
<field name="arch" type="xml">
<field name="rounding" position="after">
<field name="l10n_ar_afip_code"/>
</field>
</field>
</record>
</odoo>
+11
View File
@@ -10,4 +10,15 @@
</xpath>
</field>
</record>
<record id="product_uom_categ_form_view_inherit_l10n_in" model="ir.ui.view">
<field name="name">uom.category.form</field>
<field name="model">uom.category</field>
<field name="inherit_id" ref="uom.product_uom_categ_form_view"/>
<field name="arch" type="xml">
<field name="category_id" position="after">
<field name="l10n_in_code"/>
</field>
</field>
</record>
</odoo>
+1 -1
View File
@@ -44,7 +44,7 @@
<menuitem
action="uom.product_uom_form_action" id="menu_purchase_uom_form_action"
parent="purchase.menu_unit_of_measure_in_config_purchase" sequence="5" groups="uom.group_uom"/>
parent="purchase.menu_unit_of_measure_in_config_purchase" sequence="5" groups="base.group_no_one"/>
<menuitem
action="uom.product_uom_categ_form_action" id="menu_purchase_uom_categ_form_action"
+3 -3
View File
@@ -95,9 +95,9 @@
<menuitem action="product_template_action" id="menu_product_template_action" parent="product_menu_catalog" sequence="1" active="False"/>
<menuitem id="prod_config_main" name="Products" parent="menu_sale_config" sequence="5"/>
<menuitem id="menu_products" action="product.product_normal_action_sell" parent="product_menu_catalog" groups="product.group_product_variant" sequence="2" active="False"/>
<menuitem id="next_id_16" name="Units of Measure" parent="sale.prod_config_main" sequence="6" groups="uom.group_uom" active="False"/>
<menuitem action="uom.product_uom_form_action" id="menu_product_uom_form_action" parent="sale.prod_config_main" sequence="7" groups="uom.group_uom" active="False"/>
<menuitem action="uom.product_uom_categ_form_action" id="menu_product_uom_categ_form_action" parent="sale.prod_config_main" sequence="8" groups="uom.group_uom" active="False"/>
<menuitem id="next_id_16" name="Units of Measure" parent="menu_sale_config" sequence="6" groups="uom.group_uom" active="False"/>
<menuitem action="uom.product_uom_form_action" id="menu_product_uom_form_action" parent="next_id_16" sequence="7" groups="base.group_no_one" active="False"/>
<menuitem action="uom.product_uom_categ_form_action" id="menu_product_uom_categ_form_action" parent="next_id_16" sequence="8" active="False"/>
<menuitem id="menu_product_pricelist_main" name="Pricelists" parent="product_menu_catalog" action="product.product_pricelist_action2" groups="product.group_product_pricelist" sequence="3" active="False"/>
<record id="sale_order_view_activity" model="ir.ui.view">
+1 -1
View File
@@ -36,7 +36,7 @@
<menuitem id="menu_stock_uom_form_action" action="uom.product_uom_form_action"
name="UoM"
parent="product_uom_menu" sequence="35"/>
parent="product_uom_menu" sequence="35" groups="base.group_no_one"/>
<menuitem id="menu_stock_inventory_control" name="Products" parent="menu_stock_root" sequence="4"/>
+80 -33
View File
@@ -13,11 +13,42 @@ class UoMCategory(models.Model):
name = fields.Char('Unit of Measure Category', required=True, translate=True)
uom_ids = fields.One2many('uom.uom', 'category_id')
reference_uom_id = fields.Many2one('uom.uom', "Reference UoM", store=False, help="Dummy field to keep track of reference uom change")
@api.onchange('uom_ids')
def _onchange_uom_ids(self):
if len(self.uom_ids) == 1:
self.uom_ids[0].uom_type = 'reference'
self.uom_ids[0].factor = 1
else:
reference_count = sum(uom.uom_type == 'reference' for uom in self.uom_ids)
if reference_count == 0 and self._origin.id:
return {
'warning': {
'title': _('Warning!'),
'message': _("UoM category %s should have a reference unit of measure.") % self.name
}
}
if self.reference_uom_id:
new_reference = self.uom_ids.filtered(lambda o: o.uom_type == 'reference' and o._origin.id != self.reference_uom_id.id)
else:
new_reference = self.uom_ids.filtered(lambda o: o.uom_type == 'reference' and o._origin.uom_type != 'reference')
if new_reference:
other_uoms = self.uom_ids - new_reference
for uom in other_uoms:
uom.factor = uom._origin.factor / (new_reference._origin.factor or 1)
if uom.factor > 1:
uom.uom_type = 'smaller'
else:
uom.uom_type = 'bigger'
self.reference_uom_id = new_reference._origin.id
class UoM(models.Model):
_name = 'uom.uom'
_description = 'Product Unit of Measure'
_order = "name"
_order = "factor DESC, id"
def _unprotected_uom_xml_ids(self):
return [
@@ -46,6 +77,8 @@ class UoM(models.Model):
('reference', 'Reference Unit of Measure for this category'),
('smaller', 'Smaller than the reference Unit of Measure')], 'Type',
default='reference', required=True)
ratio = fields.Float('Combined Ratio', compute='_compute_ratio', inverse='_set_ratio', store=False)
color = fields.Integer('Color', compute='_compute_color')
_sql_constraints = [
('factor_gt_zero', 'CHECK (factor!=0)', 'The conversion ratio for a unit of measure cannot be 0!'),
@@ -53,11 +86,48 @@ class UoM(models.Model):
('factor_reference_is_one', "CHECK((uom_type = 'reference' AND factor = 1.0) OR (uom_type != 'reference'))", "The reference unit must have a conversion factor equal to 1.")
]
def _check_category_reference_uniqueness(self):
for category in self.category_id:
if not category.uom_ids:
continue
reference_count = sum(
uom.uom_type == 'reference' for uom in category.uom_ids)
if reference_count > 1:
raise ValidationError(_("UoM category %s should only have one reference unit of measure.") % category.name)
elif reference_count == 0:
raise ValidationError(_("UoM category %s should have a reference unit of measure.") % category.name)
@api.depends('factor')
def _compute_factor_inv(self):
for uom in self:
uom.factor_inv = uom.factor and (1.0 / uom.factor) or 0.0
@api.depends('uom_type', 'factor')
def _compute_ratio(self):
for uom in self:
if uom.uom_type == 'reference':
uom.ratio = 1
elif uom.uom_type == 'bigger':
uom.ratio = uom.factor_inv
else:
uom.ratio = uom.factor
def _set_ratio(self):
if self.uom_type == 'reference':
self.factor = 1
elif self.uom_type == 'bigger':
self.factor = 1 / self.ratio
else:
self.factor = self.ratio
@api.depends('uom_type')
def _compute_color(self):
for uom in self:
if uom.uom_type == 'reference':
uom.color = 7
else:
uom.color = 0
@api.onchange('uom_type')
def _onchange_uom_type(self):
if self.uom_type == 'reference':
@@ -80,49 +150,26 @@ class UoM(models.Model):
}
}
@api.constrains('category_id', 'uom_type', 'active')
def _check_category_reference_uniqueness(self):
""" Force the existence of only one UoM reference per category
NOTE: this is a constraint on the all table. This might not be a good practice, but this is
not possible to do it in SQL directly.
"""
category_ids = self.mapped('category_id').ids
self.env['uom.uom'].flush(['category_id', 'uom_type', 'active'])
self._cr.execute("""
SELECT C.id AS category_id, count(U.id) AS uom_count
FROM uom_category C
LEFT JOIN uom_uom U ON C.id = U.category_id AND uom_type = 'reference' AND U.active = 't'
WHERE C.id IN %s
GROUP BY C.id
""", (tuple(category_ids),))
for uom_data in self._cr.dictfetchall():
if uom_data['uom_count'] == 0:
raise ValidationError(_("UoM category %s should have a reference unit of measure. If you just created a new category, please record the 'reference' unit first.") % (self.env['uom.category'].browse(uom_data['category_id']).name,))
if uom_data['uom_count'] > 1:
raise ValidationError(_("UoM category %s should only have one reference unit of measure.") % (self.env['uom.category'].browse(uom_data['category_id']).name,))
@api.constrains('category_id')
def _validate_uom_category(self):
for uom in self:
reference_uoms = self.env['uom.uom'].search([
('category_id', '=', uom.category_id.id),
('uom_type', '=', 'reference')])
if len(reference_uoms) > 1:
raise ValidationError(_("UoM category %s should only have one reference unit of measure.") % (self.category_id.name))
@api.model_create_multi
def create(self, vals_list):
for values in vals_list:
if 'factor_inv' in values:
factor_inv = values.pop('factor_inv')
values['factor'] = factor_inv and (1.0 / factor_inv) or 0.0
return super(UoM, self).create(vals_list)
res = super(UoM, self).create(vals_list)
res._check_category_reference_uniqueness()
return res
def write(self, values):
if 'factor_inv' in values:
factor_inv = values.pop('factor_inv')
values['factor'] = factor_inv and (1.0 / factor_inv) or 0.0
return super(UoM, self).write(values)
res = super(UoM, self).write(values)
if ('uom_type' not in values or values['uom_type'] != 'reference') and\
not self.env.context.get('allow_to_change_reference'):
self._check_category_reference_uniqueness()
return res
@api.ondelete(at_uninstall=False)
def _unlink_except_master_data(self):
+31 -2
View File
@@ -22,7 +22,7 @@
<group name="uom_details">
<field name="name"/>
<field name="category_id"/>
<field name="uom_type"/>
<field name="uom_type" readonly="1"/>
<label for="factor"
attrs="{'invisible':[('uom_type','!=','smaller')]}"/>
<div attrs="{'invisible':[('uom_type','!=','smaller')]}" class="o_row">
@@ -93,7 +93,23 @@
<sheet>
<group>
<field name="name"/>
<field name="reference_uom_id" invisible="1"/>
</group>
<notebook>
<page string="Units of Measure" name="uom_lines">
<field name="uom_ids" force_save="1" context="{'default_uom_type': 'smaller', 'default_category_id': id}">
<tree editable="bottom">
<field name="name" decoration-bf="uom_type == 'reference'"/>
<field name="uom_type" decoration-bf="uom_type == 'reference'"/>
<field name="factor" invisible="1"/>
<field name="factor_inv" invisible="1"/>
<field name="ratio" string="Ratio" attrs="{'readonly': [('uom_type', '=', 'reference')]}" digits="[42,5]"/>
<field name="active"/>
<field name="rounding" digits="[42, 5]"/>
</tree>
</field>
</page>
</notebook>
</sheet>
</form>
</field>
@@ -103,17 +119,30 @@
<field name="name">uom.category.tree</field>
<field name="model">uom.category</field>
<field name="arch" type="xml">
<tree string="Units of Measure categories" editable="bottom">
<tree string="Units of Measure categories">
<field name="name"/>
<field name="uom_ids" widget="many2many_tags" options="{'color_field': 'color'}"/>
</tree>
</field>
</record>
<record id="uom_categ_view_search" model="ir.ui.view">
<field name="name">uom.category.view.search</field>
<field name="model">uom.category</field>
<field name="arch" type="xml">
<search string="Search UoM Category">
<field name="name"/>
<field name="uom_ids"/>
</search>
</field>
</record>
<record id="product_uom_categ_form_action" model="ir.actions.act_window">
<field name="name">Units of Measure Categories</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">uom.category</field>
<field name="view_mode">tree,form</field>
<field name="context">{'allow_to_change_reference': 1}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Add a new unit of measure category