2018-01-16 06:58:15 +01:00
# -*- coding: utf-8 -*-
2018-01-16 11:34:37 +01:00
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
2018-01-16 06:58:15 +01:00
2018-01-16 11:34:37 +01:00
from flectra import api , fields , tools , models , _
from flectra . exceptions import UserError
2018-01-16 06:58:15 +01:00
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