odoo/addons/product/models/product_uom.py

119 lines
5.1 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, tools, models, _
from odoo.exceptions import UserError
class ProductUoMCategory(models.Model):
_name = 'product.uom.categ'
_description = 'Product UoM Categories'
name = fields.Char('Name', required=True, translate=True)
class ProductUoM(models.Model):
_name = 'product.uom'
_description = 'Product Unit of Measure'
_order = "name"
name = fields.Char('Unit of Measure', required=True, translate=True)
category_id = fields.Many2one(
'product.uom.categ', 'Category', required=True, ondelete='cascade',
help="Conversion between Units of Measure can only occur if they belong to the same category. The conversion will be made based on the ratios.")
factor = fields.Float(
'Ratio', default=1.0, digits=0, required=True, # force NUMERIC with unlimited precision
help='How much bigger or smaller this unit is compared to the reference Unit of Measure for this category: 1 * (reference unit) = ratio * (this unit)')
factor_inv = fields.Float(
'Bigger Ratio', compute='_compute_factor_inv', digits=0, # force NUMERIC with unlimited precision
readonly=True, required=True,
help='How many times this Unit of Measure is bigger than the reference Unit of Measure in this category: 1 * (this unit) = ratio * (reference unit)')
rounding = fields.Float(
'Rounding Precision', default=0.01, digits=0, required=True,
help="The computed quantity will be a multiple of this value. "
"Use 1.0 for a Unit of Measure that cannot be further split, such as a piece.")
active = fields.Boolean('Active', default=True, help="Uncheck the active field to disable a unit of measure without deleting it.")
uom_type = fields.Selection([
('bigger', 'Bigger than the reference Unit of Measure'),
('reference', 'Reference Unit of Measure for this category'),
('smaller', 'Smaller than the reference Unit of Measure')], 'Type',
default='reference', required=1)
_sql_constraints = [
('factor_gt_zero', 'CHECK (factor!=0)', _('The conversion ratio for a unit of measure cannot be 0!')),
('rounding_gt_zero', 'CHECK (rounding>0)', _('The rounding precision must be greater than 0!'))
]
@api.one
@api.depends('factor')
def _compute_factor_inv(self):
self.factor_inv = self.factor and (1.0 / self.factor) or 0.0
@api.onchange('uom_type')
def _onchange_uom_type(self):
if self.uom_type == 'reference':
self.factor = 1
@api.model
def create(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(ProductUoM, self).create(values)
@api.multi
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(ProductUoM, self).write(values)
@api.model
def name_create(self, name):
""" The UoM category and factor are required, so we'll have to add temporary values
for imported UoMs """
values = {
self._rec_name: name,
'factor': 1
}
# look for the category based on the english name, i.e. no context on purpose!
# TODO: should find a way to have it translated but not created until actually used
if not self._context.get('default_category_id'):
EnglishUoMCateg = self.env['product.uom.categ'].with_context({})
misc_category = EnglishUoMCateg.search([('name', '=', 'Unsorted/Imported Units')])
if misc_category:
values['category_id'] = misc_category.id
else:
values['category_id'] = EnglishUoMCateg.name_create('Unsorted/Imported Units')[0]
new_uom = self.create(values)
return new_uom.name_get()[0]
@api.multi
def _compute_quantity(self, qty, to_unit, round=True, rounding_method='UP'):
if not self:
return qty
self.ensure_one()
if self.category_id.id != to_unit.category_id.id:
if self._context.get('raise-exception', True):
raise UserError(_('Conversion from Product UoM %s to Default UoM %s is not possible as they both belong to different Category!.') % (self.name, to_unit.name))
else:
return qty
amount = qty / self.factor
if to_unit:
amount = amount * to_unit.factor
if round:
amount = tools.float_round(amount, precision_rounding=to_unit.rounding, rounding_method=rounding_method)
return amount
@api.multi
def _compute_price(self, price, to_unit):
self.ensure_one()
if not self or not price or not to_unit or self == to_unit:
return price
if self.category_id.id != to_unit.category_id.id:
return price
amount = price * self.factor
if to_unit:
amount = amount / to_unit.factor
return amount