diff --git a/addons/l10n_ar/views/uom_uom_view.xml b/addons/l10n_ar/views/uom_uom_view.xml index 5a02b9318ca..218247e0712 100644 --- a/addons/l10n_ar/views/uom_uom_view.xml +++ b/addons/l10n_ar/views/uom_uom_view.xml @@ -23,4 +23,15 @@ + + uom.category.form + uom.category + + + + + + + + diff --git a/addons/l10n_in/views/uom_uom_views.xml b/addons/l10n_in/views/uom_uom_views.xml index 237ce736788..0e012a4b374 100644 --- a/addons/l10n_in/views/uom_uom_views.xml +++ b/addons/l10n_in/views/uom_uom_views.xml @@ -10,4 +10,15 @@ + + + uom.category.form + uom.category + + + + + + + diff --git a/addons/purchase/views/purchase_views.xml b/addons/purchase/views/purchase_views.xml index 35683066287..54757c71a01 100644 --- a/addons/purchase/views/purchase_views.xml +++ b/addons/purchase/views/purchase_views.xml @@ -44,7 +44,7 @@ + parent="purchase.menu_unit_of_measure_in_config_purchase" sequence="5" groups="base.group_no_one"/> - - - + + + diff --git a/addons/stock/views/stock_menu_views.xml b/addons/stock/views/stock_menu_views.xml index 6da09922ab3..3bfcad370eb 100644 --- a/addons/stock/views/stock_menu_views.xml +++ b/addons/stock/views/stock_menu_views.xml @@ -36,7 +36,7 @@ + parent="product_uom_menu" sequence="35" groups="base.group_no_one"/> diff --git a/addons/uom/models/uom_uom.py b/addons/uom/models/uom_uom.py index 2fa8267f498..7ffd1cfea7a 100644 --- a/addons/uom/models/uom_uom.py +++ b/addons/uom/models/uom_uom.py @@ -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): diff --git a/addons/uom/views/uom_uom_views.xml b/addons/uom/views/uom_uom_views.xml index 91a883c85b0..c8e39b68849 100644 --- a/addons/uom/views/uom_uom_views.xml +++ b/addons/uom/views/uom_uom_views.xml @@ -22,7 +22,7 @@ - +