2009-10-20 10:52:23 +00:00
# -*- coding: utf-8 -*-
2006-12-07 13:41:40 +00:00
##############################################################################
2010-06-15 13:27:22 +00:00
#
2009-11-27 07:23:48 +00:00
# OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
2006-12-07 13:41:40 +00:00
#
2008-11-03 18:27:16 +00:00
# This program is free software: you can redistribute it and/or modify
2009-11-27 07:23:48 +00:00
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
2006-12-07 13:41:40 +00:00
#
2008-11-03 18:27:16 +00:00
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2009-11-27 07:23:48 +00:00
# GNU Affero General Public License for more details.
2006-12-07 13:41:40 +00:00
#
2009-11-27 07:23:48 +00:00
# You should have received a copy of the GNU Affero General Public License
2010-06-15 13:27:22 +00:00
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2006-12-07 13:41:40 +00:00
#
##############################################################################
2012-12-10 15:27:23 +00:00
2011-10-05 00:24:16 +00:00
import re
2006-12-07 13:41:40 +00:00
import time
2012-12-17 14:30:29 +00:00
from openerp import tools
2012-12-10 15:27:23 +00:00
from openerp . osv import fields , osv
from openerp . tools import float_round , float_is_zero , float_compare
from openerp . tools . translate import _
2006-12-07 13:41:40 +00:00
2011-10-05 00:24:16 +00:00
CURRENCY_DISPLAY_PATTERN = re . compile ( r ' ( \ w+) \ s*(?: \ ((.*) \ ))? ' )
2006-12-07 13:41:40 +00:00
class res_currency ( osv . osv ) :
2010-09-06 11:17:51 +00:00
def _current_rate ( self , cr , uid , ids , name , arg , context = None ) :
if context is None :
context = { }
res = { }
2008-07-22 14:24:36 +00:00
if ' date ' in context :
2010-09-06 11:17:51 +00:00
date = context [ ' date ' ]
2008-07-22 14:24:36 +00:00
else :
2010-09-06 11:17:51 +00:00
date = time . strftime ( ' % Y- % m- %d ' )
date = date or time . strftime ( ' % Y- % m- %d ' )
2011-08-30 14:09:36 +00:00
# Convert False values to None ...
currency_rate_type = context . get ( ' currency_rate_type_id ' ) or None
# ... and use 'is NULL' instead of '= some-id'.
2011-08-30 13:20:35 +00:00
operator = ' = ' if currency_rate_type else ' is '
2008-07-22 14:24:36 +00:00
for id in ids :
2011-08-27 22:53:30 +00:00
cr . execute ( " SELECT currency_id, rate FROM res_currency_rate WHERE currency_id = %s AND name <= %s AND currency_rate_type_id " + operator + " %s ORDER BY name desc LIMIT 1 " , ( id , date , currency_rate_type ) )
2008-07-22 14:24:36 +00:00
if cr . rowcount :
2010-09-06 11:17:51 +00:00
id , rate = cr . fetchall ( ) [ 0 ]
res [ id ] = rate
2008-07-22 14:24:36 +00:00
else :
2010-09-06 11:17:51 +00:00
res [ id ] = 0
2008-07-22 14:24:36 +00:00
return res
_name = " res.currency "
_description = " Currency "
_columns = {
2011-02-21 10:15:49 +00:00
# Note: 'code' column was removed as of v6.0, the 'name' should now hold the ISO code.
' name ' : fields . char ( ' Currency ' , size = 32 , required = True , help = " Currency Code (ISO 4217) " ) ,
2012-07-23 11:32:40 +00:00
' symbol ' : fields . char ( ' Symbol ' , size = 4 , help = " Currency sign, to be used when printing amounts. " ) ,
2012-01-04 13:30:27 +00:00
' rate ' : fields . function ( _current_rate , string = ' Current Rate ' , digits = ( 12 , 6 ) ,
2011-04-19 13:11:54 +00:00
help = ' The rate of the currency to the currency of rate 1. ' ) ,
2008-07-22 14:24:36 +00:00
' rate_ids ' : fields . one2many ( ' res.currency.rate ' , ' currency_id ' , ' Rates ' ) ,
' accuracy ' : fields . integer ( ' Computational Accuracy ' ) ,
2011-04-19 13:11:54 +00:00
' rounding ' : fields . float ( ' Rounding Factor ' , digits = ( 12 , 6 ) ) ,
2008-07-22 14:24:36 +00:00
' active ' : fields . boolean ( ' Active ' ) ,
2009-11-10 12:46:31 +00:00
' company_id ' : fields . many2one ( ' res.company ' , ' Company ' ) ,
' date ' : fields . date ( ' Date ' ) ,
2011-09-13 04:38:09 +00:00
' base ' : fields . boolean ( ' Base ' ) ,
2012-04-23 10:23:13 +00:00
' position ' : fields . selection ( [ ( ' after ' , ' After Amount ' ) , ( ' before ' , ' Before Amount ' ) ] , ' Symbol Position ' , help = " Determines where the currency symbol should be placed after or before the amount. " )
2008-07-22 14:24:36 +00:00
}
_defaults = {
2012-11-02 09:47:05 +00:00
' active ' : 1 ,
2011-09-21 23:21:50 +00:00
' position ' : ' after ' ,
2011-10-05 00:29:56 +00:00
' rounding ' : 0.01 ,
' accuracy ' : 4 ,
2008-07-22 14:24:36 +00:00
}
2011-07-26 13:21:37 +00:00
_sql_constraints = [
2011-09-19 14:48:21 +00:00
# this constraint does not cover all cases due to SQL NULL handling for company_id,
# so it is complemented with a unique index (see below). The constraint and index
# share the same prefix so that IntegrityError triggered by the index will be caught
# and reported to the user with the constraint's error message.
( ' unique_name_company_id ' , ' unique (name, company_id) ' , ' The currency code must be unique per company! ' ) ,
2011-07-26 13:21:37 +00:00
]
2010-11-18 11:11:54 +00:00
_order = " name "
2006-12-07 13:41:40 +00:00
2011-09-19 14:48:21 +00:00
def init ( self , cr ) :
# CONSTRAINT/UNIQUE INDEX on (name,company_id)
# /!\ The unique constraint 'unique_name_company_id' is not sufficient, because SQL92
# only support field names in constraint definitions, and we need a function here:
# we need to special-case company_id to treat all NULL company_id as equal, otherwise
# we would allow duplicate "global" currencies (all having company_id == NULL)
cr . execute ( """ SELECT indexname FROM pg_indexes WHERE indexname = ' res_currency_unique_name_company_id_idx ' """ )
if not cr . fetchone ( ) :
cr . execute ( """ CREATE UNIQUE INDEX res_currency_unique_name_company_id_idx
ON res_currency
( name , ( COALESCE ( company_id , - 1 ) ) ) """ )
2009-11-10 12:46:31 +00:00
def read ( self , cr , user , ids , fields = None , context = None , load = ' _classic_read ' ) :
2011-08-16 10:35:31 +00:00
res = super ( res_currency , self ) . read ( cr , user , ids , fields , context , load )
2011-08-30 12:55:21 +00:00
currency_rate_obj = self . pool . get ( ' res.currency.rate ' )
2012-08-22 09:54:33 +00:00
values = res
2012-12-14 12:38:03 +00:00
if not isinstance ( values , list ) :
2012-08-22 09:54:33 +00:00
values = [ values ]
for r in values :
2009-11-10 12:46:31 +00:00
if r . __contains__ ( ' rate_ids ' ) :
rates = r [ ' rate_ids ' ]
if rates :
2011-07-15 05:55:41 +00:00
currency_date = currency_rate_obj . read ( cr , user , rates [ 0 ] , [ ' name ' ] ) [ ' name ' ]
2010-09-06 11:17:51 +00:00
r [ ' date ' ] = currency_date
2009-11-10 12:46:31 +00:00
return res
2011-10-05 00:24:16 +00:00
def name_search ( self , cr , user , name = ' ' , args = None , operator = ' ilike ' , context = None , limit = 100 ) :
if not args :
args = [ ]
2011-10-11 16:34:35 +00:00
results = super ( res_currency , self ) \
. name_search ( cr , user , name , args , operator = operator , context = context , limit = limit )
if not results :
2011-10-05 00:24:16 +00:00
name_match = CURRENCY_DISPLAY_PATTERN . match ( name )
2011-10-11 16:34:35 +00:00
if name_match :
results = super ( res_currency , self ) \
. name_search ( cr , user , name_match . group ( 1 ) , args , operator = operator , context = context , limit = limit )
return results
2011-10-05 00:24:16 +00:00
2011-06-28 09:56:15 +00:00
def name_get ( self , cr , uid , ids , context = None ) :
2011-07-04 11:37:58 +00:00
if not ids :
2011-06-28 09:56:15 +00:00
return [ ]
if isinstance ( ids , ( int , long ) ) :
ids = [ ids ]
2011-07-04 11:22:06 +00:00
reads = self . read ( cr , uid , ids , [ ' name ' , ' symbol ' ] , context = context , load = ' _classic_write ' )
2012-11-24 17:54:33 +00:00
return [ ( x [ ' id ' ] , tools . ustr ( x [ ' name ' ] ) ) for x in reads ]
2011-06-28 09:56:15 +00:00
2008-07-22 14:24:36 +00:00
def round ( self , cr , uid , currency , amount ) :
2011-11-14 16:36:17 +00:00
""" Return ``amount`` rounded according to ``currency`` ' s
2011-11-14 18:23:10 +00:00
rounding rules .
2011-11-14 16:36:17 +00:00
: param browse_record currency : currency for which we are rounding
: param float amount : the amount to round
: return : rounded float
"""
return float_round ( amount , precision_rounding = currency . rounding )
def compare_amounts ( self , cr , uid , currency , amount1 , amount2 ) :
2011-11-14 18:23:10 +00:00
""" Compare ``amount1`` and ``amount2`` after rounding them according to the
given currency ' s precision..
An amount is considered lower / greater than another amount if their rounded
value is different . This is not the same as having a non - zero difference !
2011-11-14 16:36:17 +00:00
2011-11-14 18:23:10 +00:00
For example 1.432 and 1.431 are equal at 2 digits precision ,
so this method would return 0.
However 0.006 and 0.002 are considered different ( returns 1 ) because
they respectively round to 0.01 and 0.0 , even though
0.006 - 0.002 = 0.004 which would be considered zero at 2 digits precision .
2011-11-14 16:36:17 +00:00
: param browse_record currency : currency for which we are rounding
: param float amount1 : first amount to compare
: param float amount2 : second amount to compare
: return : ( resp . ) - 1 , 0 or 1 , if ` ` amount1 ` ` is ( resp . ) lower than ,
equal to , or greater than ` ` amount2 ` ` , according to
` ` currency ` ` ' s rounding.
"""
return float_compare ( amount1 , amount2 , precision_rounding = currency . rounding )
2006-12-27 16:20:27 +00:00
2008-07-22 14:24:36 +00:00
def is_zero ( self , cr , uid , currency , amount ) :
2011-11-14 16:36:17 +00:00
""" Returns true if ``amount`` is small enough to be treated as
zero according to ` ` currency ` ` ' s rounding rules.
2011-11-14 18:23:10 +00:00
Warning : ` ` is_zero ( amount1 - amount2 ) ` ` is not always equivalent to
` ` compare_amounts ( amount1 , amount2 ) == 0 ` ` , as the former will round after
computing the difference , while the latter will round before , giving
different results for e . g . 0.006 and 0.002 at 2 digits precision .
2011-11-14 16:36:17 +00:00
: param browse_record currency : currency for which we are rounding
: param float amount : amount to compare with currency ' s zero
"""
return float_is_zero ( amount , precision_rounding = currency . rounding )
2007-07-30 13:35:11 +00:00
2010-12-22 16:10:45 +00:00
def _get_conversion_rate ( self , cr , uid , from_currency , to_currency , context = None ) :
2010-09-06 11:17:51 +00:00
if context is None :
context = { }
2011-08-25 11:56:45 +00:00
ctx = context . copy ( )
2011-08-30 13:20:35 +00:00
ctx . update ( { ' currency_rate_type_id ' : ctx . get ( ' currency_rate_type_from ' ) } )
2011-08-27 22:53:30 +00:00
from_currency = self . browse ( cr , uid , from_currency . id , context = ctx )
2011-08-25 11:56:45 +00:00
2011-08-30 13:20:35 +00:00
ctx . update ( { ' currency_rate_type_id ' : ctx . get ( ' currency_rate_type_to ' ) } )
2011-08-27 22:53:30 +00:00
to_currency = self . browse ( cr , uid , to_currency . id , context = ctx )
2011-08-25 11:56:45 +00:00
2011-08-27 22:53:30 +00:00
if from_currency . rate == 0 or to_currency . rate == 0 :
2008-07-22 14:24:36 +00:00
date = context . get ( ' date ' , time . strftime ( ' % Y- % m- %d ' ) )
2011-08-27 22:53:30 +00:00
if from_currency . rate == 0 :
2010-11-19 05:06:26 +00:00
currency_symbol = from_currency . symbol
2008-07-22 14:24:36 +00:00
else :
2010-11-19 05:06:26 +00:00
currency_symbol = to_currency . symbol
2008-07-22 14:24:36 +00:00
raise osv . except_osv ( _ ( ' Error ' ) , _ ( ' No rate found \n ' \
' for the currency: %s \n ' \
2010-11-19 05:06:26 +00:00
' at the date: %s ' ) % ( currency_symbol , date ) )
2010-12-22 16:10:45 +00:00
return to_currency . rate / from_currency . rate
2011-08-19 11:07:19 +00:00
def compute ( self , cr , uid , from_currency_id , to_currency_id , from_amount ,
round = True , currency_rate_type_from = False , currency_rate_type_to = False , context = None ) :
2011-08-24 09:10:22 +00:00
if not context :
context = { }
2010-12-22 16:10:45 +00:00
if not from_currency_id :
from_currency_id = to_currency_id
if not to_currency_id :
to_currency_id = from_currency_id
xc = self . browse ( cr , uid , [ from_currency_id , to_currency_id ] , context = context )
from_currency = ( xc [ 0 ] . id == from_currency_id and xc [ 0 ] ) or xc [ 1 ]
to_currency = ( xc [ 0 ] . id == to_currency_id and xc [ 0 ] ) or xc [ 1 ]
2011-08-30 12:07:27 +00:00
if ( to_currency_id == from_currency_id ) and ( currency_rate_type_from == currency_rate_type_to ) :
2008-07-22 14:24:36 +00:00
if round :
return self . round ( cr , uid , to_currency , from_amount )
else :
return from_amount
else :
2011-08-25 11:56:45 +00:00
context . update ( { ' currency_rate_type_from ' : currency_rate_type_from , ' currency_rate_type_to ' : currency_rate_type_to } )
2010-12-22 16:10:45 +00:00
rate = self . _get_conversion_rate ( cr , uid , from_currency , to_currency , context = context )
2008-07-22 14:24:36 +00:00
if round :
2008-10-23 17:45:49 +00:00
return self . round ( cr , uid , to_currency , from_amount * rate )
2008-07-22 14:24:36 +00:00
else :
2012-12-14 12:38:03 +00:00
return from_amount * rate
2008-10-23 17:45:49 +00:00
2006-12-07 13:41:40 +00:00
res_currency ( )
2011-07-14 09:27:37 +00:00
class res_currency_rate_type ( osv . osv ) :
_name = " res.currency.rate.type "
2011-09-09 04:54:51 +00:00
_description = " Currency Rate Type "
2011-07-14 09:27:37 +00:00
_columns = {
2011-08-27 22:53:30 +00:00
' name ' : fields . char ( ' Name ' , size = 64 , required = True , translate = True ) ,
2011-07-14 09:27:37 +00:00
}
res_currency_rate_type ( )
2006-12-19 13:49:50 +00:00
class res_currency_rate ( osv . osv ) :
2008-07-22 14:24:36 +00:00
_name = " res.currency.rate "
_description = " Currency Rate "
2011-08-27 22:53:30 +00:00
2008-07-22 14:24:36 +00:00
_columns = {
' name ' : fields . date ( ' Date ' , required = True , select = True ) ,
2012-02-08 22:40:31 +00:00
' rate ' : fields . float ( ' Rate ' , digits = ( 12 , 6 ) , help = ' The rate of the currency to the currency of rate 1 ' ) ,
2008-07-22 14:24:36 +00:00
' currency_id ' : fields . many2one ( ' res.currency ' , ' Currency ' , readonly = True ) ,
2011-08-30 12:07:27 +00:00
' currency_rate_type_id ' : fields . many2one ( ' res.currency.rate.type ' , ' Currency Rate Type ' , help = " Allow you to define your own currency rate types, like ' Average ' or ' Year to Date ' . Leave empty if you simply want to use the normal ' spot ' rate type " ) ,
2008-07-22 14:24:36 +00:00
}
_defaults = {
' name ' : lambda * a : time . strftime ( ' % Y- % m- %d ' ) ,
}
_order = " name desc "
2011-07-14 09:27:37 +00:00
2006-12-19 13:49:50 +00:00
res_currency_rate ( )
2008-07-23 15:01:27 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: