[FIX] crm: fixed on_change_user that was crashing because
[odoo/odoo.git] / addons / fleet / fleet.py
index c496277..7c5e014 100644 (file)
 # -*- coding: utf-8 -*-
-from itertools import chain
-from osv import osv, fields
+##############################################################################
+#
+#    OpenERP, Open Source Management Solution
+#    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
+#
+#    This program is free software: you can redistribute it and/or modify
+#    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.
+#
+#    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
+#    GNU Affero General Public License for more details.
+#
+#    You should have received a copy of the GNU Affero General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+##############################################################################
+
+from openerp.osv import fields, osv
 import time
 import datetime
-import tools
-from osv.orm import except_orm
-from tools.translate import _
+from openerp import tools
+from openerp.osv.orm import except_orm
+from openerp.tools.translate import _
 from dateutil.relativedelta import relativedelta
-############################
-############################
-#Vehicle.cost class
-############################
-############################
+
+def str_to_datetime(strdate):
+    return datetime.datetime.strptime(strdate, tools.DEFAULT_SERVER_DATE_FORMAT)
 
 class fleet_vehicle_cost(osv.Model):
     _name = 'fleet.vehicle.cost'
-    _description = 'Cost of vehicle'
+    _description = 'Cost related to a vehicle'
     _order = 'date desc, vehicle_id asc'
 
-    def name_get(self, cr, uid, ids, context=None):
-        if context is None:
-            context = {}
-        if not ids:
-            return []
-        reads = self.browse(cr, uid, ids, context=context)
-        res = []
-        for record in reads:
-            if record.vehicle_id.license_plate:
-                name = record.vehicle_id.license_plate
-            if record.cost_subtype.name:
-                name = name + ' / '+ record.cost_subtype.name
-            if record.date:
-                name = name + ' / '+ record.date
-            res.append((record.id, name))
+    def _get_odometer(self, cr, uid, ids, odometer_id, arg, context):
+        res = dict.fromkeys(ids, False)
+        for record in self.browse(cr,uid,ids,context=context):
+            if record.odometer_id:
+                res[record.id] = record.odometer_id.value
         return res
 
-    def year_get(self, cr, uid, ids, context=None):
-        if context is None:
-            context = {}
-        if not ids:
-            return []
-        reads = self.browse(cr, uid, ids, context=context)
-        res = []
-        for record in reads:
-            res.append((record.id, str(record.date[:4])))
-        return res
+    def _set_odometer(self, cr, uid, id, name, value, args=None, context=None):
+        if not value:
+            raise except_orm(_('Operation not allowed!'), _('Emptying the odometer value of a vehicle is not allowed.'))
+        date = self.browse(cr, uid, id, context=context).date
+        if not(date):
+            date = fields.date.context_today(self, cr, uid, context=context)
+        vehicle_id = self.browse(cr, uid, id, context=context).vehicle_id
+        data = {'value': value, 'date': date, 'vehicle_id': vehicle_id.id}
+        odometer_id = self.pool.get('fleet.vehicle.odometer').create(cr, uid, data, context=context)
+        return self.write(cr, uid, id, {'odometer_id': odometer_id}, context=context)
 
     def _year_get_fnc(self, cr, uid, ids, name, unknow_none, context=None):
-        res = self.year_get(cr, uid, ids, context=context)
-        return dict(res)
+        res = {}
+        for record in self.browse(cr, uid, ids, context=context):
+            if (record.date):
+                res[record.id] = str(time.strptime(record.date, tools.DEFAULT_SERVER_DATE_FORMAT).tm_year)
+            else:
+                res[record.id] = _('Unknown')
+        return res
 
     def _cost_name_get_fnc(self, cr, uid, ids, name, unknow_none, context=None):
-        res = self.name_get(cr, uid, ids, context=context)
-        return dict(res)
+        res = {}
+        for record in self.browse(cr, uid, ids, context=context):
+            name = record.vehicle_id.name
+            if record.cost_subtype_id.name:
+                name += ' / '+ record.cost_subtype_id.name
+            if record.date:
+                name += ' / '+ record.date
+            res[record.id] = name
+        return res
 
     _columns = {
-        'name' : fields.function(_cost_name_get_fnc, type="char", string='Name', store=True),
-        #'name' : fields.char('Name',size=32),
-        'vehicle_id': fields.many2one('fleet.vehicle', 'Vehicle', required=True, help='Vehicle concerned by this fuel log'),
-        'cost_subtype': fields.many2one('fleet.service.type', 'Type', required=False, help='Cost type purchased with this cost'),
+        'name': fields.function(_cost_name_get_fnc, type="char", string='Name', store=True),
+        'vehicle_id': fields.many2one('fleet.vehicle', 'Vehicle', required=True, help='Vehicle concerned by this log'),
+        'cost_subtype_id': fields.many2one('fleet.service.type', 'Type', help='Cost type purchased with this cost'),
         'amount': fields.float('Total Price'),
-        'cost_type' : fields.selection([('contract', 'Contract'),('services','Services'),('fuel','Fuel'),('other','Other')], 'Category of the cost', help='For internal purpose only',required=True),
-        'parent_id': fields.many2one('fleet.vehicle.cost', 'Parent', required=False, help='Parent cost to this current cost'),
-        'cost_ids' : fields.one2many('fleet.vehicle.cost', 'parent_id', 'Included Services'),
-
+        'cost_type': fields.selection([('contract', 'Contract'), ('services','Services'), ('fuel','Fuel'), ('other','Other')], 'Category of the cost', help='For internal purpose only', required=True),
+        'parent_id': fields.many2one('fleet.vehicle.cost', 'Parent', help='Parent cost to this current cost'),
+        'cost_ids': fields.one2many('fleet.vehicle.cost', 'parent_id', 'Included Services'),
+        'odometer_id': fields.many2one('fleet.vehicle.odometer', 'Odometer', help='Odometer measure of the vehicle at the moment of this log'),
+        'odometer': fields.function(_get_odometer, fnct_inv=_set_odometer, type='float', string='Odometer Value', help='Odometer measure of the vehicle at the moment of this log'),
+        'odometer_unit': fields.related('vehicle_id', 'odometer_unit', type="char", string="Unit", readonly=True),
         'date' :fields.date('Date',help='Date when the cost has been executed'),
-
-        'contract_id' : fields.many2one('fleet.vehicle.log.contract', 'Contract', required=False, help='Contract attached to this cost'),
-        'auto_generated' : fields.boolean('automatically generated',readonly=True,required=True),
-
-        'year' : fields.function(_year_get_fnc, type="char", string='Year', store=True),
+        'contract_id': fields.many2one('fleet.vehicle.log.contract', 'Contract', help='Contract attached to this cost'),
+        'auto_generated': fields.boolean('Automatically Generated', readonly=True, required=True),
+        'year': fields.function(_year_get_fnc, type="char", string='Year', store=True),
     }
 
     _defaults ={
-        'parent_id':None,
-        'auto_generated' : False,
-        'cost_type' : 'other',
+        'cost_type': 'other',
     }
 
-    
-
     def create(self, cr, uid, data, context=None):
+        #make sure that the data are consistent with values of parent and contract records given
         if 'parent_id' in data and data['parent_id']:
             parent = self.browse(cr, uid, data['parent_id'], context=context)
             data['vehicle_id'] = parent.vehicle_id.id
@@ -89,18 +104,14 @@ class fleet_vehicle_cost(osv.Model):
         if 'contract_id' in data and data['contract_id']:
             contract = self.pool.get('fleet.vehicle.log.contract').browse(cr, uid, data['contract_id'], context=context)
             data['vehicle_id'] = contract.vehicle_id.id
-            data['cost_subtype'] = contract.cost_subtype.id
+            data['cost_subtype_id'] = contract.cost_subtype_id.id
             data['cost_type'] = contract.cost_type
-        if not('cost_type' in data and data['cost_type']):
-            data['cost_type'] = 'other'
-        cost_id = super(fleet_vehicle_cost, self).create(cr, uid, data, context=context)
-        return cost_id
+        if 'odometer' in data and not data['odometer']:
+            #if received value for odometer is 0, then remove it from the data as it would result to the creation of a
+            #odometer log with 0, which is to be avoided
+            del(data['odometer'])
+        return super(fleet_vehicle_cost, self).create(cr, uid, data, context=context)
 
-############################
-############################
-#Vehicle.tag class
-############################
-############################
 
 class fleet_vehicle_tag(osv.Model):
     _name = 'fleet.vehicle.tag'
@@ -108,79 +119,51 @@ class fleet_vehicle_tag(osv.Model):
         'name': fields.char('Name', required=True, translate=True),
     }
 
-############################
-############################
-#Vehicle.state class
-############################
-############################
-
 class fleet_vehicle_state(osv.Model):
     _name = 'fleet.vehicle.state'
+    _order = 'sequence asc'
     _columns = {
         'name': fields.char('Name', required=True),
-        'sequence': fields.integer('Order',help="Used to order the note stages")
+        'sequence': fields.integer('Sequence', help="Used to order the note stages")
     }
-    _order = 'sequence asc'
-    _sql_constraints = [('fleet_state_name_unique','unique(name)','State name already exists')]
-
+    _sql_constraints = [('fleet_state_name_unique','unique(name)', 'State name already exists')]
 
-############################
-############################
-#Vehicle.model class
-############################
-############################
 
 class fleet_vehicle_model(osv.Model):
 
-    def name_get(self, cr, uid, ids, context=None):
-        if context is None:
-            context = {}
-        if not ids:
-            return []
-        reads = self.browse(cr, uid, ids, context=context)
-        res = []
-        for record in reads:
+    def _model_name_get_fnc(self, cr, uid, ids, field_name, arg, context=None):
+        res = {}
+        for record in self.browse(cr, uid, ids, context=context):
             name = record.modelname
-            if record.brand.name:
-                name = record.brand.name+' / '+name
-            res.append((record.id, name))
+            if record.brand_id.name:
+                name = record.brand_id.name + ' / ' + name
+            res[record.id] = name
         return res
 
-    def _model_name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None):
-        res = self.name_get(cr, uid, ids, context=context)
-        return dict(res)
-
     def on_change_brand(self, cr, uid, ids, model_id, context=None):
-
         if not model_id:
-            return {}
-
+            return {'value': {'image_medium': False}}
         brand = self.pool.get('fleet.vehicle.model.brand').browse(cr, uid, model_id, context=context)
-
         return {
-            'value' : {
-                'image' : brand.image,
+            'value': {
+                'image_medium': brand.image,
             }
         }
 
     _name = 'fleet.vehicle.model'
     _description = 'Model of a vehicle'
+    _order = 'name asc'
 
     _columns = {
-        'name' : fields.function(_model_name_get_fnc, type="char", string='Name', store=True),
-        'modelname' : fields.char('Model name', size=32, required=True), 
-        'brand' : fields.many2one('fleet.vehicle.model.brand', 'Model Brand', required=True, help='Brand of the vehicle'),
-        'vendors': fields.many2many('res.partner','fleet_vehicle_model_vendors','model_id', 'partner_id',string='Vendors',required=False),
-        'image': fields.related('brand','image',type="binary",string="Logo",store=False),
-        'image_medium': fields.related('brand','image_medium',type="binary",string="Logo",store=False),
-        'image_small': fields.related('brand','image_small',type="binary",string="Logo",store=False),
+        'name': fields.function(_model_name_get_fnc, type="char", string='Name', store=True),
+        'modelname': fields.char('Model name', size=32, required=True), 
+        'brand_id': fields.many2one('fleet.vehicle.model.brand', 'Model Brand', required=True, help='Brand of the vehicle'),
+        'vendors': fields.many2many('res.partner', 'fleet_vehicle_model_vendors', 'model_id', 'partner_id', string='Vendors'),
+        'image': fields.related('brand_id', 'image', type="binary", string="Logo"),
+        'image_medium': fields.related('brand_id', 'image_medium', type="binary", string="Logo"),
+        'image_small': fields.related('brand_id', 'image_small', type="binary", string="Logo"),
     }
 
-############################
-############################
-#Vehicle.brand class
-############################
-############################
 
 class fleet_vehicle_model_brand(osv.Model):
     _name = 'fleet.vehicle.model.brand'
@@ -193,13 +176,12 @@ class fleet_vehicle_model_brand(osv.Model):
         for obj in self.browse(cr, uid, ids, context=context):
             result[obj.id] = tools.image_get_resized_images(obj.image)
         return result
-    
+
     def _set_image(self, cr, uid, id, name, value, args, context=None):
         return self.write(cr, uid, [id], {'image': tools.image_resize_image_big(value)}, context=context)
 
     _columns = {
-        'name' : fields.char('Brand Name',size=32, required=True),
-
+        'name': fields.char('Brand Name', size=64, required=True),
         'image': fields.binary("Logo",
             help="This field holds the image used as logo for the brand, limited to 1024x1024px."),
         'image_medium': fields.function(_get_image, fnct_inv=_set_image,
@@ -220,271 +202,122 @@ class fleet_vehicle_model_brand(osv.Model):
                  "Use this field anywhere a small image is required."),
     }
 
-############################
-############################
-#Vehicle class
-############################
-############################
-
 
 class fleet_vehicle(osv.Model):
 
     _inherit = 'mail.thread'
 
-    def name_get(self, cr, uid, ids, context=None):
-        if context is None:
-            context = {}
-        if not ids:
-            return []
-        reads = self.browse(cr, uid, ids, context=context)
-        res = []
-        for record in reads:
-            if record.license_plate:
-                name = record.license_plate
-            if record.model_id.modelname:
-                name = record.model_id.modelname + ' / ' + name
-            if record.model_id.brand.name:
-                name = record.model_id.brand.name+' / '+ name
-            res.append((record.id, name))
-        return res
-
     def _vehicle_name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None):
-        res = self.name_get(cr, uid, ids, context=context)
-        return dict(res)
-
-    def act_show_log_services(self, cr, uid, ids, context=None):
-        """ This opens log view to view and add new log for this vehicle
-            @return: the service log view
-        """
-        res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid ,'fleet','fleet_vehicle_log_services_act', context)
-        res['context'] = {
-            'default_vehicle_id': ids[0]
-        }
-        res['domain']=[('vehicle_id','=', ids[0])]
-        return res
-
-    def act_show_log_contract(self, cr, uid, ids, context=None):
-        """ This opens log view to view and add new log for this vehicle
-            @return: the contract log view
-        """
-        res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid ,'fleet','fleet_vehicle_log_contract_act', context)
-        res['context'] = {
-            'default_vehicle_id': ids[0]
-        }
-        res['domain']=[('vehicle_id','=', ids[0])]
+        res = {}
+        for record in self.browse(cr, uid, ids, context=context):
+            res[record.id] = record.model_id.brand_id.name + '/' + record.model_id.modelname + ' / ' + record.license_plate
         return res
 
-    def act_show_log_fuel(self, cr, uid, ids, context=None):
-        """ This opens log view to view and add new log for this vehicle
-            @return: the fuel log view
-        """
-        res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid ,'fleet','fleet_vehicle_log_fuel_act', context)
-        res['context'] = {
-            'default_vehicle_id': ids[0]
-        }
-        res['domain']=[('vehicle_id','=', ids[0])]
-        return res
+    def return_action_to_open(self, cr, uid, ids, context=None):
+        """ This opens the xml view specified in xml_id for the current vehicle """
+        if context is None:
+            context = {}
+        if context.get('xml_id'):
+            res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid ,'fleet', context['xml_id'], context=context)
+            res['context'] = context
+            res['context'].update({'default_vehicle_id': ids[0]})
+            res['domain'] = [('vehicle_id','=', ids[0])]
+            return res
+        return False
 
     def act_show_log_cost(self, cr, uid, ids, context=None):
-        """ This opens log view to view and add new log for this vehicle
+        """ This opens log view to view and add new log for this vehicle, groupby default to only show effective costs
             @return: the costs log view
         """
-        res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid ,'fleet','fleet_vehicle_costs_act', context)
-        res['context'] = {
+        if context is None:
+            context = {}
+        res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid ,'fleet','fleet_vehicle_costs_act', context=context)
+        res['context'] = context
+        res['context'].update({
             'default_vehicle_id': ids[0],
-            'search_default_parent_false' : True
-        }
-        res['domain']=[('vehicle_id','=', ids[0])]
-        return res
-
-    def act_show_log_odometer(self, cr, uid, ids, context=None):
-        """ This opens log view to view and add new log for this vehicle
-            @return: the odometer log view
-        """
-        res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid ,'fleet','fleet_vehicle_odometer_act', context)
-        res['context'] = {
-            'default_vehicle_id': ids[0]
-        }
-        res['domain']=[('vehicle_id','=', ids[0])]
+            'search_default_parent_false': True
+        })
+        res['domain'] = [('vehicle_id','=', ids[0])]
         return res
 
     def _get_odometer(self, cr, uid, ids, odometer_id, arg, context):
-        res = dict.fromkeys(ids, False)
-        for record in self.browse(cr,uid,ids,context=context):    
-            ids = self.pool.get('fleet.vehicle.odometer').search(cr,uid,[('vehicle_id','=',record.id)],limit=1, order='value desc')
+        res = dict.fromkeys(ids, 0)
+        for record in self.browse(cr,uid,ids,context=context):
+            ids = self.pool.get('fleet.vehicle.odometer').search(cr, uid, [('vehicle_id', '=', record.id)], limit=1, order='value desc')
             if len(ids) > 0:
-                res[record.id] = str(self.pool.get('fleet.vehicle.odometer').browse(cr,uid,ids[0],context=context).value)
-            else:
-                res[record.id] = str(0)
+                res[record.id] = self.pool.get('fleet.vehicle.odometer').browse(cr, uid, ids[0], context=context).value
         return res
 
     def _set_odometer(self, cr, uid, id, name, value, args=None, context=None):
         if value:
-            try:
-                value = float(value)
-            except ValueError:
-                #_logger.exception(value+' is not a correct odometer value. Please, fill a float for this field')
-                raise except_orm(_('Error!'), value+' is not a correct odometer value. Please, fill a float for this field')
-            
-            date = time.strftime('%Y-%m-%d')
-            data = {'value' : value,'date' : date,'vehicle_id' : id}
-            odometer_id = self.pool.get('fleet.vehicle.odometer').create(cr, uid, data, context=context)
-            return value
-        self.write(cr, uid, id, {'odometer_id': ''})
-        return False  
-
-    def str_to_date(self,strdate):
-        return datetime.datetime(int(strdate[:4]),int(strdate[5:7]),int(strdate[8:]))
-
-    def get_overdue_contract_reminder_fnc(self,cr,uid,ids,context=None):
-        if context is None:
-            context={}
-        if not ids:
-            return dict([])
-        reads = self.browse(cr,uid,ids,context=context)
-        res=[]
-        
-        for record in reads:
-            overdue=0
-            if (record.log_contracts):
-                for element in record.log_contracts:
-                    if ((element.state=='open' or element.state=='toclose') and element.expiration_date):
-                        current_date_str=time.strftime('%Y-%m-%d')
-                        due_time_str=element.expiration_date
-                            #due_time_str=element.browse()
-                        current_date=self.str_to_date(current_date_str)
-                        due_time=self.str_to_date(due_time_str)
-             
-                        diff_time=int((due_time-current_date).days)
-                        if diff_time<0:
-                            overdue = overdue +1;
-                res.append((record.id,overdue))
-            else:
-                res.append((record.id,0))
-
-        return dict(res)
-
-    def get_overdue_contract_reminder(self,cr,uid,ids,prop,unknow_none,context=None):
-        res = self.get_overdue_contract_reminder_fnc(cr, uid, ids, context=context)
-        return res
-
-    def get_next_contract_reminder_fnc(self,cr,uid,ids,context=None):
-        if context is None:
-            context={}
-        if not ids:
-            return dict([])
-        reads = self.browse(cr,uid,ids,context=context)
-        res=[]
-
-        for record in reads:
-            due_soon=0
-            if (record.log_contracts):
-                for element in record.log_contracts:
-                    if ((element.state=='open' or element.state=='toclose') and element.expiration_date):
-                        current_date_str=time.strftime('%Y-%m-%d')
-                        due_time_str=element.expiration_date
-                            #due_time_str=element.browse()
-                        current_date=self.str_to_date(current_date_str)
-                        due_time=self.str_to_date(due_time_str)
-             
-                        diff_time=int((due_time-current_date).days)
-                        if diff_time<15 and diff_time>=0:
-                            due_soon = due_soon +1;
-                res.append((record.id,due_soon))
-            else:
-                res.append((record.id,0))
-        
-        return dict(res)
+            date = fields.date.context_today(self, cr, uid, context=context)
+            data = {'value': value, 'date': date, 'vehicle_id': id}
+            return self.pool.get('fleet.vehicle.odometer').create(cr, uid, data, context=context)
 
     def _search_get_overdue_contract_reminder(self, cr, uid, obj, name, args, context):
         res = []
         for field, operator, value in args:
-            #assert field == name
-            vehicle_ids = self.search(cr, uid, [])
-            renew_ids = self.get_overdue_contract_reminder_fnc(cr,uid,vehicle_ids,context=context)
-            res_ids = []
-            for renew_key,renew_value in renew_ids.items():
-                if eval(str(renew_value) + " " + str(operator) + " " + str(value)):
-                    res_ids.append(renew_key)
-            res.append(('id', 'in', res_ids))      
+            assert operator in ('=', '!=', '<>') and value in (True, False), 'Operation not supported'
+            if (operator == '=' and value == True) or (operator in ('<>', '!=') and value == False):
+                search_operator = 'in'
+            else:
+                search_operator = 'not in'
+            today = fields.date.context_today(self, cr, uid, context=context)
+            cr.execute('select cost.vehicle_id, count(contract.id) as contract_number FROM fleet_vehicle_cost cost left join fleet_vehicle_log_contract contract on contract.cost_id = cost.id WHERE contract.expiration_date is not null AND contract.expiration_date < %s AND contract.state IN (\'open\', \'toclose\') GROUP BY cost.vehicle_id', (today,))
+            res_ids = [x[0] for x in cr.fetchall()]
+            res.append(('id', search_operator, res_ids))
         return res
-    
+
     def _search_contract_renewal_due_soon(self, cr, uid, obj, name, args, context):
         res = []
         for field, operator, value in args:
-            #assert field == name
-            vehicle_ids = self.search(cr, uid, [])
-            renew_ids = self.get_next_contract_reminder_fnc(cr,uid,vehicle_ids,context=context)
-            res_ids = []
-            for renew_key,renew_value in renew_ids.items():
-                if eval(str(renew_value) + " " + str(operator) + " " + str(value)):
-                    res_ids.append(renew_key)
-            res.append(('id', 'in', res_ids))      
+            assert operator in ('=', '!=', '<>') and value in (True, False), 'Operation not supported'
+            if (operator == '=' and value == True) or (operator in ('<>', '!=') and value == False):
+                search_operator = 'in'
+            else:
+                search_operator = 'not in'
+            today = fields.date.context_today(self, cr, uid, context=context)
+            datetime_today = datetime.datetime.strptime(today, tools.DEFAULT_SERVER_DATE_FORMAT)
+            limit_date = str((datetime_today + relativedelta(days=+15)).strftime(tools.DEFAULT_SERVER_DATE_FORMAT))
+            cr.execute('select cost.vehicle_id, count(contract.id) as contract_number FROM fleet_vehicle_cost cost left join fleet_vehicle_log_contract contract on contract.cost_id = cost.id WHERE contract.expiration_date is not null AND contract.expiration_date > %s AND contract.expiration_date < %s AND contract.state IN (\'open\', \'toclose\') GROUP BY cost.vehicle_id', (today, limit_date))
+            res_ids = [x[0] for x in cr.fetchall()]
+            res.append(('id', search_operator, res_ids))
         return res
 
-    def get_next_contract_reminder(self, cr, uid, ids, prop, unknow_none, context=None):
-        res = self.get_next_contract_reminder_fnc(cr, uid, ids, context=context)
+    def _get_contract_reminder_fnc(self, cr, uid, ids, field_names, unknow_none, context=None):
+        res= {}
+        for record in self.browse(cr, uid, ids, context=context):
+            overdue = False
+            due_soon = False
+            total = 0
+            name = ''
+            for element in record.log_contracts:
+                if element.state in ('open', 'toclose') and element.expiration_date:
+                    current_date_str = fields.date.context_today(self, cr, uid, context=context)
+                    due_time_str = element.expiration_date
+                    current_date = str_to_datetime(current_date_str)
+                    due_time = str_to_datetime(due_time_str)
+                    diff_time = (due_time-current_date).days
+                    if diff_time < 0:
+                        overdue = True
+                        total += 1
+                    if diff_time < 15 and diff_time >= 0:
+                            due_soon = True;
+                            total += 1
+                    if overdue or due_soon:
+                        ids = self.pool.get('fleet.vehicle.log.contract').search(cr,uid,[('vehicle_id', '=', record.id), ('state', 'in', ('open', 'toclose'))], limit=1, order='expiration_date asc')
+                        if len(ids) > 0:
+                            #we display only the name of the oldest overdue/due soon contract
+                            name=(self.pool.get('fleet.vehicle.log.contract').browse(cr, uid, ids[0], context=context).cost_subtype_id.name)
+
+            res[record.id] = {
+                'contract_renewal_overdue': overdue,
+                'contract_renewal_due_soon': due_soon,
+                'contract_renewal_total': (total - 1), #we remove 1 from the real total for display purposes
+                'contract_renewal_name': name,
+            }
         return res
 
-    def get_contract_renewal_names(self,cr,uid,ids,function_name,args,context=None):
-        if not ids:
-            return dict([])
-        reads = self.browse(cr,uid,ids,context=context)
-        res=[]
-        for record in reads:
-            if (record.log_contracts):
-                ids = self.pool.get('fleet.vehicle.log.contract').search(cr,uid,[('vehicle_id','=',record.id),'|',('state','=','open'),('state','=','toclose')],limit=1,order='expiration_date asc')
-                if len(ids) > 0:
-                    res.append((record.id,self.pool.get('fleet.vehicle.log.contract').browse(cr,uid,ids[0],context=context).cost_subtype.name))
-            else:
-                res.append((record.id,''))
-        return dict(res)
-
-    def get_total_contract_reminder(self,cr,uid,ids,prop,unknow_none,context=None):
-        if context is None:
-            context={}
-        if not ids:
-            return dict([])
-        reads = self.browse(cr,uid,ids,context=context)
-        res=[]
-
-        for record in reads:
-            due_soon=0
-            if (record.log_contracts):
-                for element in record.log_contracts:
-                    if ((element.state=='open' or element.state=='toclose') and element.expiration_date):
-                        current_date_str=time.strftime('%Y-%m-%d')
-                        due_time_str=element.expiration_date
-
-                        current_date=self.str_to_date(current_date_str)
-                        due_time=self.str_to_date(due_time_str)
-             
-                        diff_time=int((due_time-current_date).days)
-                        if diff_time<15:
-                            due_soon = due_soon +1;
-                if due_soon>0:
-                    due_soon=due_soon-1
-                res.append((record.id,due_soon))
-            else:
-                res.append((record.id,0))
-        
-        return dict(res)
-
-    def run_scheduler(self,cr,uid,context=None):
-        ids = self.pool.get('fleet.vehicle.log.contract').search(cr, uid, ['&',('state','=','open'),('expiration_date','<',(datetime.date.today() + relativedelta(days=+15)).strftime('%Y-%m-%d'))], offset=0, limit=None, order=None,context=None, count=False)
-        res = {}
-        for contract in self.pool.get('fleet.vehicle.log.contract').browse(cr,uid,ids,context=context):
-            if contract.vehicle_id.id in res:
-                res[contract.vehicle_id.id] += 1
-            else :
-                res[contract.vehicle_id.id] = 1
-
-        for vehicle,value in res.items():
-            self.message_post(cr, uid, vehicle, body=str(value) + ' contract(s) need(s) to be renewed and/or closed!', context=context)
-
-        self.pool.get('fleet.vehicle.log.contract').write(cr,uid,ids,{'state' : 'toclose'},context=context)
-        return True
-
     def _get_default_state(self, cr, uid, context):
         try:
             model, model_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'fleet', 'vehicle_state_active')
@@ -493,64 +326,53 @@ class fleet_vehicle(osv.Model):
         return model_id
 
     _name = 'fleet.vehicle'
-    _description = 'Fleet Vehicle'
-    #_order = 'contract_renewal_overdue desc, contract_renewal_due_soon desc'
+    _description = 'Information on a vehicle'
     _order= 'license_plate asc'
     _columns = {
-        'name' : fields.function(_vehicle_name_get_fnc, type="char", string='Name', store=True),
-
+        'name': fields.function(_vehicle_name_get_fnc, type="char", string='Name', store=True),
         'company_id': fields.many2one('res.company', 'Company'),
-        'license_plate' : fields.char('License Plate', size=32, required=True, help='License plate number of the vehicle (ie: plate number for a car)'),
-        'vin_sn' : fields.char('Chassis Number', size=32, required=False, help='Unique number written on the vehicle motor (VIN/SN number)'),
-        'driver' : fields.many2one('res.partner', 'Driver',required=False, help='Driver of the vehicle'),
-        'model_id' : fields.many2one('fleet.vehicle.model', 'Model', required=True, help='Model of the vehicle'),
-        'log_fuel' : fields.one2many('fleet.vehicle.log.fuel','vehicle_id', 'Fuel Logs'),
-        'log_services' : fields.one2many('fleet.vehicle.log.services','vehicle_id', 'Services Logs'),
-        'log_contracts' : fields.one2many('fleet.vehicle.log.contract','vehicle_id', 'Contracts'),
-        'acquisition_date' : fields.date('Acquisition Date', required=False, help='Date when the vehicle has been bought'),
-        'color' : fields.char('Color',size=32, help='Color of the vehicle'),
-        'state': fields.many2one('fleet.vehicle.state', 'State', help='Current state of the vehicle',ondelete="set null"),
-        'location' : fields.char('Location',size=32, help='Location of the vehicle (garage, ...)'),
-        'seats' : fields.integer('Seats Number', help='Number of seats of the vehicle'),
-        'doors' : fields.integer('Doors Number', help='Number of doors of the vehicle'),
-        'tag_ids' :fields.many2many('fleet.vehicle.tag','fleet_vehicle_vehicle_tag_rel','vehicle_tag_id','tag_id','Tags'),
-
-        'odometer' : fields.function(_get_odometer,fnct_inv=_set_odometer,type='char',string='Odometer Value',store=False,help='Odometer measure of the vehicle at the moment of this log'),
+        'license_plate': fields.char('License Plate', size=32, required=True, help='License plate number of the vehicle (ie: plate number for a car)'),
+        'vin_sn': fields.char('Chassis Number', size=32, help='Unique number written on the vehicle motor (VIN/SN number)'),
+        'driver_id': fields.many2one('res.partner', 'Driver', help='Driver of the vehicle'),
+        'model_id': fields.many2one('fleet.vehicle.model', 'Model', required=True, help='Model of the vehicle'),
+        'log_fuel': fields.one2many('fleet.vehicle.log.fuel', 'vehicle_id', 'Fuel Logs'),
+        'log_services': fields.one2many('fleet.vehicle.log.services', 'vehicle_id', 'Services Logs'),
+        'log_contracts': fields.one2many('fleet.vehicle.log.contract', 'vehicle_id', 'Contracts'),
+        'acquisition_date': fields.date('Acquisition Date', required=False, help='Date when the vehicle has been bought'),
+        'color': fields.char('Color', size=32, help='Color of the vehicle'),
+        'state_id': fields.many2one('fleet.vehicle.state', 'State', help='Current state of the vehicle', ondelete="set null"),
+        'location': fields.char('Location', size=128, help='Location of the vehicle (garage, ...)'),
+        'seats': fields.integer('Seats Number', help='Number of seats of the vehicle'),
+        'doors': fields.integer('Doors Number', help='Number of doors of the vehicle'),
+        'tag_ids' :fields.many2many('fleet.vehicle.tag', 'fleet_vehicle_vehicle_tag_rel', 'vehicle_tag_id','tag_id', 'Tags'),
+        'odometer': fields.function(_get_odometer, fnct_inv=_set_odometer, type='float', string='Last Odometer', help='Odometer measure of the vehicle at the moment of this log'),
         'odometer_unit': fields.selection([('kilometers', 'Kilometers'),('miles','Miles')], 'Odometer Unit', help='Unit of the odometer ',required=True),
-
-        'transmission' : fields.selection([('manual', 'Manual'),('automatic','Automatic')], 'Transmission', help='Transmission Used by the vehicle',required=False),
-        'fuel_type' : fields.selection([('gasoline', 'Gasoline'),('diesel','Diesel'),('electric','Electric'),('hybrid','Hybrid')], 'Fuel Type', help='Fuel Used by the vehicle',required=False),
-        'horsepower' : fields.integer('Horsepower',required=False),
+        'transmission': fields.selection([('manual', 'Manual'), ('automatic', 'Automatic')], 'Transmission', help='Transmission Used by the vehicle'),
+        'fuel_type': fields.selection([('gasoline', 'Gasoline'), ('diesel', 'Diesel'), ('electric', 'Electric'), ('hybrid', 'Hybrid')], 'Fuel Type', help='Fuel Used by the vehicle'),
+        'horsepower': fields.integer('Horsepower'),
         'horsepower_tax': fields.float('Horsepower Taxation'),
-        'power' : fields.integer('Power (kW)',required=False,help='Power in kW of the vehicle'),
-        'co2' : fields.float('CO2 Emissions',required=False,help='CO2 emissions of the vehicle'),
-
-        'image': fields.related('model_id','image',type="binary",string="Logo",store=False),
-        'image_medium': fields.related('model_id','image_medium',type="binary",string="Logo",store=False),
-        'image_small': fields.related('model_id','image_small',type="binary",string="Logo",store=False),
-
-        'contract_renewal_due_soon' : fields.function(get_next_contract_reminder,fnct_search=_search_contract_renewal_due_soon,type="integer",string='Contracts to renew',store=False),
-        'contract_renewal_overdue' : fields.function(get_overdue_contract_reminder,fnct_search=_search_get_overdue_contract_reminder,type="integer",string='Contracts Overdued',store=False),
-        'contract_renewal_name' : fields.function(get_contract_renewal_names,type="text",string='Name of contract to renew soon',store=False),
-        'contract_renewal_total' : fields.function(get_total_contract_reminder,type="integer",string='Total of contracts due or overdue minus one',store=False),
-
+        'power': fields.integer('Power (kW)', help='Power in kW of the vehicle'),
+        'co2': fields.float('CO2 Emissions', help='CO2 emissions of the vehicle'),
+        'image': fields.related('model_id', 'image', type="binary", string="Logo"),
+        'image_medium': fields.related('model_id', 'image_medium', type="binary", string="Logo"),
+        'image_small': fields.related('model_id', 'image_small', type="binary", string="Logo"),
+        'contract_renewal_due_soon': fields.function(_get_contract_reminder_fnc, fnct_search=_search_contract_renewal_due_soon, type="boolean", string='Has Contracts to renew', multi='contract_info'),
+        'contract_renewal_overdue': fields.function(_get_contract_reminder_fnc, fnct_search=_search_get_overdue_contract_reminder, type="boolean", string='Has Contracts Overdued', multi='contract_info'),
+        'contract_renewal_name': fields.function(_get_contract_reminder_fnc, type="text", string='Name of contract to renew soon', multi='contract_info'),
+        'contract_renewal_total': fields.function(_get_contract_reminder_fnc, type="integer", string='Total of contracts due or overdue minus one', multi='contract_info'),
         'car_value': fields.float('Car Value', help='Value of the bought vehicle'),
-        #'leasing_value': fields.float('Leasing value',help='Value of the leasing(Monthly, usually'),
         }
 
     _defaults = {
-        'doors' : 5,
-        'odometer_unit' : 'kilometers',
-        'state' : _get_default_state,
+        'doors': 5,
+        'odometer_unit': 'kilometers',
+        'state_id': _get_default_state,
     }
 
     def copy(self, cr, uid, id, default=None, context=None):
         if not default:
             default = {}
-
         default.update({
-        #    'name': self.pool.get('ir.sequence').get(cr, uid, 'stock.orderpoint') or '',
-            #'log_ids':[],
             'log_fuel':[],
             'log_contracts':[],
             'log_services':[],
@@ -560,208 +382,161 @@ class fleet_vehicle(osv.Model):
         return super(fleet_vehicle, self).copy(cr, uid, id, default, context=context)
 
     def on_change_model(self, cr, uid, ids, model_id, context=None):
-
         if not model_id:
             return {}
-
         model = self.pool.get('fleet.vehicle.model').browse(cr, uid, model_id, context=context)
-
         return {
-            'value' : {
-                'image' : model.image,
+            'value': {
+                'image_medium': model.image,
             }
         }
+
     def create(self, cr, uid, data, context=None):
         vehicle_id = super(fleet_vehicle, self).create(cr, uid, data, context=context)
-        try:
-            vehicle = self.browse(cr, uid, vehicle_id, context=context)
-            self.message_post(cr, uid, [vehicle_id], body='Vehicle %s has been added to the fleet!' % (vehicle.license_plate), context=context)
-        except:
-            pass # group deleted: do not push a message
+        vehicle = self.browse(cr, uid, vehicle_id, context=context)
+        self.message_post(cr, uid, [vehicle_id], body=_('Vehicle %s has been added to the fleet!') % (vehicle.license_plate), context=context)
         return vehicle_id
 
     def write(self, cr, uid, ids, vals, context=None):
-        changes = []
-        if 'driver' in vals:
-            value = self.pool.get('res.partner').browse(cr,uid,vals['driver'],context=context).name
-            olddriver = self.browse(cr, uid, ids, context)[0].driver
-            if olddriver:
-                olddriver = olddriver.name
-            else:
-                olddriver = 'None'
-            changes.append('Driver: from \'' + olddriver + '\' to \'' + value+'\'')
-        if 'state' in vals:
-            value = self.pool.get('fleet.vehicle.state').browse(cr,uid,vals['state'],context=context).name
-            oldstate = self.browse(cr, uid, ids, context)[0].state
-            if oldstate:
-                oldstate=oldstate.name
-            else:
-                oldstate = 'None'
-            changes.append('State: from \'' + oldstate + '\' to \'' + value+'\'')
-        if 'license_plate' in vals:
-            old_license_plate = self.browse(cr, uid, ids, context)[0].license_plate
-            if not old_license_plate:
-                old_license_plate = 'None'
-            changes.append('License Plate: from \'' + old_license_plate + '\' to \'' + vals['license_plate']+'\'')   
-       
-        vehicle_id = super(fleet_vehicle,self).write(cr, uid, ids, vals, context)
+        """
+        This function write an entry in the openchatter whenever we change important information
+        on the vehicle like the model, the drive, the state of the vehicle or its license plate
+        """
+        for vehicle in self.browse(cr, uid, ids, context):
+            changes = []
+            if 'model_id' in vals and vehicle.model_id.id != vals['model_id']:
+                value = self.pool.get('fleet.vehicle.model').browse(cr,uid,vals['model_id'],context=context).name
+                oldmodel = vehicle.model_id.name or _('None')
+                changes.append(_("Model: from '%s' to '%s'") %(oldmodel, value))
+            if 'driver_id' in vals and vehicle.driver_id.id != vals['driver_id']:
+                value = self.pool.get('res.partner').browse(cr,uid,vals['driver_id'],context=context).name
+                olddriver = (vehicle.driver_id.name) or _('None')
+                changes.append(_("Driver: from '%s' to '%s'") %(olddriver, value))
+            if 'state_id' in vals and vehicle.state_id.id != vals['state_id']:
+                value = self.pool.get('fleet.vehicle.state').browse(cr,uid,vals['state_id'],context=context).name
+                oldstate = vehicle.state_id.name or _('None')
+                changes.append(_("State: from '%s' to '%s'") %(oldstate, value))
+            if 'license_plate' in vals and vehicle.license_plate != vals['license_plate']:
+                old_license_plate = vehicle.license_plate or _('None')
+                changes.append(_("License Plate: from '%s' to '%s'") %(old_license_plate, vals['license_plate']))
 
-        try:
             if len(changes) > 0:
-                self.message_post(cr, uid, [self.browse(cr, uid, ids, context)[0].id], body=", ".join(changes), context=context)
-        except Exception as e:
-            print e
-            pass
-        return vehicle_id
+                self.message_post(cr, uid, [vehicle.id], body=", ".join(changes), context=context)
+
+        vehicle_id = super(fleet_vehicle,self).write(cr, uid, ids, vals, context)
+        return True
 
-############################
-############################
-#Vehicle.odometer class
-############################
-############################
 
 class fleet_vehicle_odometer(osv.Model):
     _name='fleet.vehicle.odometer'
     _description='Odometer log for a vehicle'
-
     _order='date desc'
 
-    def name_get(self, cr, uid, ids, context=None):
-        if context is None:
-            context = {}
-        if not ids:
-            return []
-        reads = self.browse(cr, uid, ids, context=context)
-        res = []
-        for record in reads:
-            if record.vehicle_id.name:
-                name = str(record.vehicle_id.name)
+    def _vehicle_log_name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None):
+        res = {}
+        for record in self.browse(cr, uid, ids, context=context):
+            name = record.vehicle_id.name
             if record.date:
                 name = name+ ' / '+ str(record.date)
-            res.append((record.id, name))
+            res[record.id] = name
         return res
 
-    def _vehicle_log_name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None):
-        res = self.name_get(cr, uid, ids, context=context)
-        return dict(res)
     def on_change_vehicle(self, cr, uid, ids, vehicle_id, context=None):
-
         if not vehicle_id:
             return {}
-
         odometer_unit = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context).odometer_unit
-
         return {
-            'value' : {
-                'unit' : odometer_unit,
+            'value': {
+                'unit': odometer_unit,
             }
         }
 
     _columns = {
-        'name' : fields.function(_vehicle_log_name_get_fnc, type="char", string='Name', store=True),
-
-        'date' : fields.date('Date'),
-        'value' : fields.float('Odometer Value',group_operator="max"),
-        'vehicle_id' : fields.many2one('fleet.vehicle', 'Vehicle', required=True),
-        'unit': fields.related('vehicle_id','odometer_unit',type="char",string="Unit",store=False, readonly=True),
-        
+        'name': fields.function(_vehicle_log_name_get_fnc, type="char", string='Name', store=True),
+        'date': fields.date('Date'),
+        'value': fields.float('Odometer Value', group_operator="max"),
+        'vehicle_id': fields.many2one('fleet.vehicle', 'Vehicle', required=True),
+        'unit': fields.related('vehicle_id', 'odometer_unit', type="char", string="Unit", readonly=True),
     }
     _defaults = {
-        'date' : time.strftime('%Y-%m-%d')
+        'date': fields.date.context_today,
     }
 
-############################
-############################
-#Vehicle.log classes
-############################
-############################
-
-
-############################
-############################
-#Vehicle.log.fuel class
-############################
-############################
-
 
 class fleet_vehicle_log_fuel(osv.Model):
 
-    #_inherits = {'fleet.vehicle.odometer': 'odometer_id'}
-    _inherits = {'fleet.vehicle.cost': 'cost_id'}
-
     def on_change_vehicle(self, cr, uid, ids, vehicle_id, context=None):
-
         if not vehicle_id:
             return {}
-
-        odometer_unit = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context).odometer_unit
-
+        vehicle = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context)
+        odometer_unit = vehicle.odometer_unit
+        driver = vehicle.driver_id.id
         return {
-            'value' : {
-                'odometer_unit' : odometer_unit,
+            'value': {
+                'odometer_unit': odometer_unit,
+                'purchaser_id': driver,
             }
         }
 
     def on_change_liter(self, cr, uid, ids, liter, price_per_liter, amount, context=None):
-
-        if liter > 0 and price_per_liter > 0:
-            return {'value' : {'amount' : float(liter) * float(price_per_liter),}}
-        elif liter > 0 and amount > 0:
-            return {'value' : {'price_per_liter' : float(amount) / float(liter),}}
-        elif price_per_liter > 0 and amount > 0:
-            return {'value' : {'liter' : float(amount) / float(price_per_liter),}}
+        #need to cast in float because the value receveid from web client maybe an integer (Javascript and JSON do not
+        #make any difference between 3.0 and 3). This cause a problem if you encode, for example, 2 liters at 1.5 per
+        #liter => total is computed as 3.0, then trigger an onchange that recomputes price_per_liter as 3/2=1 (instead
+        #of 3.0/2=1.5)
+        #If there is no change in the result, we return an empty dict to prevent an infinite loop due to the 3 intertwine
+        #onchange. And in order to verify that there is no change in the result, we have to limit the precision of the 
+        #computation to 2 decimal
+        liter = float(liter)
+        price_per_liter = float(price_per_liter)
+        amount = float(amount)
+        if liter > 0 and price_per_liter > 0 and round(liter*price_per_liter,2) != amount:
+            return {'value' : {'amount' : round(liter * price_per_liter,2),}}
+        elif amount > 0 and liter > 0 and round(amount/liter,2) != price_per_liter:
+            return {'value' : {'price_per_liter' : round(amount / liter,2),}}
+        elif amount > 0 and price_per_liter > 0 and round(amount/price_per_liter,2) != liter:
+            return {'value' : {'liter' : round(amount / price_per_liter,2),}}
         else :
             return {}
 
     def on_change_price_per_liter(self, cr, uid, ids, liter, price_per_liter, amount, context=None):
-
-        liter = float(liter);
-        price_per_liter = float(price_per_liter);
-        if price_per_liter > 0 and liter > 0:
-            return {'value' : {'amount' : float(liter) * float(price_per_liter),}}
-        elif price_per_liter > 0 and amount > 0:
-            return {'value' : {'liter' : float(amount) / float(price_per_liter),}}
-        elif liter > 0 and amount > 0:
-            return {'value' : {'price_per_liter' : float(amount) / float(liter),}}
+        #need to cast in float because the value receveid from web client maybe an integer (Javascript and JSON do not
+        #make any difference between 3.0 and 3). This cause a problem if you encode, for example, 2 liters at 1.5 per
+        #liter => total is computed as 3.0, then trigger an onchange that recomputes price_per_liter as 3/2=1 (instead
+        #of 3.0/2=1.5)
+        #If there is no change in the result, we return an empty dict to prevent an infinite loop due to the 3 intertwine
+        #onchange. And in order to verify that there is no change in the result, we have to limit the precision of the 
+        #computation to 2 decimal
+        liter = float(liter)
+        price_per_liter = float(price_per_liter)
+        amount = float(amount)
+        if liter > 0 and price_per_liter > 0 and round(liter*price_per_liter,2) != amount:
+            return {'value' : {'amount' : round(liter * price_per_liter,2),}}
+        elif amount > 0 and price_per_liter > 0 and round(amount/price_per_liter,2) != liter:
+            return {'value' : {'liter' : round(amount / price_per_liter,2),}}
+        elif amount > 0 and liter > 0 and round(amount/liter,2) != price_per_liter:
+            return {'value' : {'price_per_liter' : round(amount / liter,2),}}
         else :
             return {}
 
     def on_change_amount(self, cr, uid, ids, liter, price_per_liter, amount, context=None):
-
-        if amount > 0 and liter > 0:
-            return {'value' : {'price_per_liter' : float(amount) / float(liter),}}
-        elif amount > 0 and price_per_liter > 0:
-            return {'value' : {'liter' : float(amount) / float(price_per_liter),}}
-        elif liter > 0 and price_per_liter > 0:
-            return {'value' : {'amount' : float(liter) * float(price_per_liter),}}
+        #need to cast in float because the value receveid from web client maybe an integer (Javascript and JSON do not
+        #make any difference between 3.0 and 3). This cause a problem if you encode, for example, 2 liters at 1.5 per
+        #liter => total is computed as 3.0, then trigger an onchange that recomputes price_per_liter as 3/2=1 (instead
+        #of 3.0/2=1.5)
+        #If there is no change in the result, we return an empty dict to prevent an infinite loop due to the 3 intertwine
+        #onchange. And in order to verify that there is no change in the result, we have to limit the precision of the 
+        #computation to 2 decimal
+        liter = float(liter)
+        price_per_liter = float(price_per_liter)
+        amount = float(amount)
+        if amount > 0 and liter > 0 and round(amount/liter,2) != price_per_liter:
+            return {'value': {'price_per_liter': round(amount / liter,2),}}
+        elif amount > 0 and price_per_liter > 0 and round(amount/price_per_liter,2) != liter:
+            return {'value': {'liter': round(amount / price_per_liter,2),}}
+        elif liter > 0 and price_per_liter > 0 and round(liter*price_per_liter,2) != amount:
+            return {'value': {'amount': round(liter * price_per_liter,2),}}
         else :
             return {}
-        
-    def _get_odometer(self, cr, uid, ids, odometer_id, arg, context):
-        res = dict.fromkeys(ids, False)
-        for record in self.browse(cr,uid,ids,context=context):
-            if record.odometer_id:
-                res[record.id] = record.odometer_id.value
-        return res
-
-    def _set_odometer(self, cr, uid, id, name, value, args=None, context=None):
-        if value:
-            try:
-                value = float(value)
-            except ValueError:
-                #_logger.exception(value+' is not a correct odometer value. Please, fill a float for this field')
-                raise except_orm(_('Error!'), value+' is not a correct odometer value. Please, fill a float for this field')
-               
-            date = self.browse(cr, uid, id, context=context).date
-            if not(date):
-                date = time.strftime('%Y-%m-%d')
-            vehicle_id = self.browse(cr, uid, id, context=context).vehicle_id
-            data = {'value' : value,'date' : date,'vehicle_id' : vehicle_id.id}
-            odometer_id = self.pool.get('fleet.vehicle.odometer').create(cr, uid, data, context=context)
-            self.write(cr, uid, id, {'odometer_id': odometer_id})
-            return value
-        self.write(cr, uid, id, {'odometer_id': ''})
-        return False
 
     def _get_default_service_type(self, cr, uid, context):
         try:
@@ -771,80 +546,40 @@ class fleet_vehicle_log_fuel(osv.Model):
         return model_id
 
     _name = 'fleet.vehicle.log.fuel'
+    _description = 'Fuel log for vehicles'
+    _inherits = {'fleet.vehicle.cost': 'cost_id'}
 
     _columns = {
-        #'name' : fields.char('Name',size=64),
-        'liter' : fields.float('Liter'),
-        'price_per_liter' : fields.float('Price Per Liter'),
-        'purchaser_id' : fields.many2one('res.partner', 'Purchaser',domain="['|',('customer','=',True),('employee','=',True)]"),
-        'inv_ref' : fields.char('Invoice Reference', size=64),
-        'vendor_id' : fields.many2one('res.partner', 'Supplier', domain="[('supplier','=',True)]"),
-        'notes' : fields.text('Notes'),
-        'odometer_id' : fields.many2one('fleet.vehicle.odometer', 'Odometer', required=False, help='Odometer measure of the vehicle at the moment of this log'),
-        'odometer' : fields.function(_get_odometer,fnct_inv=_set_odometer,type='char',string='Odometer',store=False),
-        'odometer_unit': fields.related('vehicle_id','odometer_unit',type="char",string="Unit",store=False, readonly=True),
-        'cost_amount': fields.related('cost_id','amount',type="float",string="Amount",store=True, readonly=True),
+        'liter': fields.float('Liter'),
+        'price_per_liter': fields.float('Price Per Liter'),
+        'purchaser_id': fields.many2one('res.partner', 'Purchaser', domain="['|',('customer','=',True),('employee','=',True)]"),
+        'inv_ref': fields.char('Invoice Reference', size=64),
+        'vendor_id': fields.many2one('res.partner', 'Supplier', domain="[('supplier','=',True)]"),
+        'notes': fields.text('Notes'),
+        'cost_amount': fields.related('cost_id', 'amount', string='Amount', type='float', store=True), #we need to keep this field as a related with store=True because the graph view doesn't support (1) to address fields from inherited table and (2) fields that aren't stored in database
     }
     _defaults = {
-        'purchaser_id': lambda self, cr, uid, ctx: uid,
-        'date' : time.strftime('%Y-%m-%d'),
-        'cost_subtype': _get_default_service_type,
+        'date': fields.date.context_today,
+        'cost_subtype_id': _get_default_service_type,
+        'cost_type': 'fuel',
     }
-    def create(self, cr, uid, data, context=None):
-        data['cost_type'] = 'fuel'
-        cost_id = super(fleet_vehicle_log_fuel, self).create(cr, uid, data, context=context)
-        return cost_id
-
-############################
-############################
-#Vehicle.log.service class
-############################
-############################
 
 
 class fleet_vehicle_log_services(osv.Model):
 
-    _inherits = {'fleet.vehicle.cost': 'cost_id'}
-
     def on_change_vehicle(self, cr, uid, ids, vehicle_id, context=None):
-
         if not vehicle_id:
             return {}
-
-        odometer_unit = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context).odometer_unit
-
+        vehicle = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context)
+        odometer_unit = vehicle.odometer_unit
+        driver = vehicle.driver_id.id
         return {
-            'value' : {
-                'odometer_unit' : odometer_unit,
+            'value': {
+                'odometer_unit': odometer_unit,
+                'purchaser_id': driver,
             }
         }
 
-    def _get_odometer(self, cr, uid, ids, odometer_id, arg, context):
-        res = dict.fromkeys(ids, False)
-        for record in self.browse(cr,uid,ids,context=context):
-            if record.odometer_id:
-                res[record.id] = record.odometer_id.value
-        return res
-
-    def _set_odometer(self, cr, uid, id, name, value, args=None, context=None):
-        if value:
-            try:
-                value = float(value)
-            except ValueError:
-                #_logger.exception(value+' is not a correct odometer value. Please, fill a float for this field')
-                raise except_orm(_('Error!'), value+' is not a correct odometer value. Please, fill a float for this field')
-               
-            date = self.browse(cr, uid, id, context=context).date
-            if not(date):
-                date = time.strftime('%Y-%m-%d')
-            vehicle_id = self.browse(cr, uid, id, context=context).vehicle_id
-            data = {'value' : value,'date' : date,'vehicle_id' : vehicle_id.id}
-            odometer_id = self.pool.get('fleet.vehicle.odometer').create(cr, uid, data, context=context)
-            self.write(cr, uid, id, {'odometer_id': odometer_id})
-            return value
-        self.write(cr, uid, id, {'odometer_id': ''})
-        return False
-
     def _get_default_service_type(self, cr, uid, context):
         try:
             model, model_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'fleet', 'type_service_service_8')
@@ -852,309 +587,248 @@ class fleet_vehicle_log_services(osv.Model):
             model_id = False
         return model_id
 
+    _inherits = {'fleet.vehicle.cost': 'cost_id'}
     _name = 'fleet.vehicle.log.services'
+    _description = 'Services for vehicles'
     _columns = {
-
-        #'name' : fields.char('Name',size=64),
-
-        'purchaser_id' : fields.many2one('res.partner', 'Purchaser',domain="['|',('customer','=',True),('employee','=',True)]"),
-        'inv_ref' : fields.char('Invoice Reference', size=64),
-        'vendor_id' :fields.many2one('res.partner', 'Supplier', domain="[('supplier','=',True)]"),
-        'notes' : fields.text('Notes'),
-
-        'odometer_id' : fields.many2one('fleet.vehicle.odometer', 'Odometer', required=False, help='Odometer measure of the vehicle at the moment of this log'),
-        'odometer' : fields.function(_get_odometer,fnct_inv=_set_odometer,type='char',string='Odometer Value',store=False),
-        'odometer_unit': fields.related('vehicle_id','odometer_unit',type="char",string="Unit",store=False, readonly=True),
-        'cost_amount': fields.related('cost_id','amount',type="float",string="Amount",store=True, readonly=True),
+        'purchaser_id': fields.many2one('res.partner', 'Purchaser', domain="['|',('customer','=',True),('employee','=',True)]"),
+        'inv_ref': fields.char('Invoice Reference', size=64),
+        'vendor_id': fields.many2one('res.partner', 'Supplier', domain="[('supplier','=',True)]"),
+        'cost_amount': fields.related('cost_id', 'amount', string='Amount', type='float', store=True), #we need to keep this field as a related with store=True because the graph view doesn't support (1) to address fields from inherited table and (2) fields that aren't stored in database
+        'notes': fields.text('Notes'),
     }
     _defaults = {
-        'purchaser_id': lambda self, cr, uid, ctx: uid,
-        'date' : time.strftime('%Y-%m-%d'),
-        'cost_subtype' : _get_default_service_type
+        'date': fields.date.context_today,
+        'cost_subtype_id': _get_default_service_type,
+        'cost_type': 'services'
     }
-    def create(self, cr, uid, data, context=None):
-        data['cost_type'] = 'services'
-        cost_id = super(fleet_vehicle_log_services, self).create(cr, uid, data, context=context)
-        return cost_id
 
-############################
-############################
-#Vehicle.service.type class
-############################
-############################
 
 class fleet_service_type(osv.Model):
     _name = 'fleet.service.type'
+    _description = 'Type of services available on a vehicle'
     _columns = {
         'name': fields.char('Name', required=True, translate=True),
-        'category': fields.selection([('contract', 'Contract'), ('service', 'Service'),('both', 'Both')], 'Category',required=True, help='Choose wheter the service refer to contracts, vehicle services or both'),
+        'category': fields.selection([('contract', 'Contract'), ('service', 'Service'), ('both', 'Both')], 'Category', required=True, help='Choose wheter the service refer to contracts, vehicle services or both'),
     }
-    #_defaults = {
-    #    'category': 'both'
-    #}
 
-############################
-############################
-#Vehicle.log.contract class
-############################
-############################
 
 class fleet_vehicle_log_contract(osv.Model):
 
-    _inherits = {'fleet.vehicle.cost': 'cost_id'}
-
-    def run_scheduler(self,cr,uid,context=None):
-
-        d = datetime.date.today()
-        #d = datetime.datetime(2012, 12, 01)
-
+    def scheduler_manage_auto_costs(self, cr, uid, context=None):
+        #This method is called by a cron task
+        #It creates costs for contracts having the "recurring cost" field setted, depending on their frequency
+        #For example, if a contract has a reccuring cost of 200 with a weekly frequency, this method creates a cost of 200 on the first day of each week, from the date of the last recurring costs in the database to today
+        #If the contract has not yet any recurring costs in the database, the method generates the recurring costs from the start_date to today
+        #The created costs are associated to a contract thanks to the many2one field contract_id
+        #If the contract has no start_date, no cost will be created, even if the contract has recurring costs
+        vehicle_cost_obj = self.pool.get('fleet.vehicle.cost')
+        d = datetime.datetime.strptime(fields.date.context_today(self, cr, uid, context=context), tools.DEFAULT_SERVER_DATE_FORMAT).date()
         contract_ids = self.pool.get('fleet.vehicle.log.contract').search(cr, uid, [('state','!=','closed')], offset=0, limit=None, order=None,context=None, count=False)
-        deltas = {'yearly' : relativedelta(years=+1),'monthly' : relativedelta(months=+1),'weekly' : relativedelta(weeks=+1),'daily' : relativedelta(days=+1)}
-        for contract in self.pool.get('fleet.vehicle.log.contract').browse(cr,uid,contract_ids,context=context):
+        deltas = {'yearly': relativedelta(years=+1), 'monthly': relativedelta(months=+1), 'weekly': relativedelta(weeks=+1), 'daily': relativedelta(days=+1)}
+        for contract in self.pool.get('fleet.vehicle.log.contract').browse(cr, uid, contract_ids, context=context):
             if not contract.start_date or contract.cost_frequency == 'no':
-                break;
-            if contract.generated_cost_ids != []:
-                last_cost_id = self.pool.get('fleet.vehicle.cost').search(cr, uid, ['&',('contract_id','=',contract.id),('auto_generated','=',True)], offset=0, limit=1, order='date desc',context=None, count=False)
-                last_cost_date = self.pool.get('fleet.vehicle.cost').browse(cr,uid,last_cost_id[0],context=None).date
-                found = True
-            else : 
-                found = False
-                last_cost_date = contract.start_date
-            startdate = datetime.datetime.strptime(last_cost_date,'%Y-%m-%d').date() 
+                continue
+            found = False
+            last_cost_date = contract.start_date
+            if contract.generated_cost_ids:
+                last_autogenerated_cost_id = vehicle_cost_obj.search(cr, uid, ['&', ('contract_id','=',contract.id), ('auto_generated','=',True)], offset=0, limit=1, order='date desc',context=context, count=False)
+                if last_autogenerated_cost_id:
+                    found = True
+                    last_cost_date = vehicle_cost_obj.browse(cr, uid, last_autogenerated_cost_id[0], context=context).date
+            startdate = datetime.datetime.strptime(last_cost_date, tools.DEFAULT_SERVER_DATE_FORMAT).date()
             if found:
                 startdate += deltas.get(contract.cost_frequency)
-            while (startdate < d) & (startdate < datetime.datetime.strptime(contract.expiration_date,'%Y-%m-%d').date()):
-                data = {'amount' : contract.cost_generated,'date' : startdate.strftime('%Y-%m-%d'),'vehicle_id' : contract.vehicle_id.id,'cost_subtype' : contract.cost_subtype.id,'contract_id' : contract.id,'auto_generated' : True}
-                print data
+            while (startdate <= d) & (startdate <= datetime.datetime.strptime(contract.expiration_date, tools.DEFAULT_SERVER_DATE_FORMAT).date()):
+                data = {
+                    'amount': contract.cost_generated,
+                    'date': startdate.strftime(tools.DEFAULT_SERVER_DATE_FORMAT),
+                    'vehicle_id': contract.vehicle_id.id,
+                    'cost_subtype_id': contract.cost_subtype_id.id,
+                    'contract_id': contract.id,
+                    'auto_generated': True
+                }
                 cost_id = self.pool.get('fleet.vehicle.cost').create(cr, uid, data, context=context)
                 startdate += deltas.get(contract.cost_frequency)
         return True
-    
-    def name_get(self, cr, uid, ids, context=None):
-        if context is None:
-            context = {} 
-        if not ids:
-            return []
-        reads = self.browse(cr, uid, ids, context=context)
-        res = []
-        for record in reads:
-            if record.vehicle_id.name:
-                name = str(record.vehicle_id.name)
-            if record.cost_subtype.name:
-                name = name+ ' / '+ str(record.cost_subtype.name)
-            if record.date:
-                name = name+ ' / '+ record.date
-            res.append((record.id, name))
-        return res
 
-    def _vehicle_contract_name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None):
-        res = self.name_get(cr, uid, ids, context=context)
-        return dict(res)
+    def scheduler_manage_contract_expiration(self, cr, uid, context=None):
+        #This method is called by a cron task
+        #It manages the state of a contract, possibly by posting a message on the vehicle concerned and updating its status
+        datetime_today = datetime.datetime.strptime(fields.date.context_today(self, cr, uid, context=context), tools.DEFAULT_SERVER_DATE_FORMAT)
+        limit_date = (datetime_today + relativedelta(days=+15)).strftime(tools.DEFAULT_SERVER_DATE_FORMAT)
+        ids = self.search(cr, uid, ['&', ('state', '=', 'open'), ('expiration_date', '<', limit_date)], offset=0, limit=None, order=None, context=context, count=False)
+        res = {}
+        for contract in self.browse(cr, uid, ids, context=context):
+            if contract.vehicle_id.id in res:
+                res[contract.vehicle_id.id] += 1
+            else:
+                res[contract.vehicle_id.id] = 1
 
-    def _get_odometer(self, cr, uid, ids, odometer_id, arg, context):
-        res = dict.fromkeys(ids, False)
-        for record in self.browse(cr,uid,ids,context=context):
-            if record.odometer_id:
-                res[record.id] = record.odometer_id.value
-        return res
+        for vehicle, value in res.items():
+            self.pool.get('fleet.vehicle').message_post(cr, uid, vehicle, body=_('%s contract(s) need(s) to be renewed and/or closed!') % (str(value)), context=context)
+        return self.write(cr, uid, ids, {'state': 'toclose'}, context=context)
 
-    def _set_odometer(self, cr, uid, id, name, value, args=None, context=None):
-        if value:
-            try:
-                value = float(value)
-            except ValueError:
-                #_logger.exception(value+' is not a correct odometer value. Please, fill a float for this field')
-                raise except_orm(_('Error!'), value+' is not a correct odometer value. Please, fill a float for this field')
-               
-            date = self.browse(cr, uid, id, context=context).date
-            if not(date):
-                date = time.strftime('%Y-%m-%d')
-            vehicle_id = self.browse(cr, uid, id, context=context).vehicle_id
-            data = {'value' : value,'date' : date,'vehicle_id' : vehicle_id.id}
-            odometer_id = self.pool.get('fleet.vehicle.odometer').create(cr, uid, data, context=context)
-            self.write(cr, uid, id, {'odometer_id': odometer_id})
-            return value
-        self.write(cr, uid, id, {'odometer_id': ''})
-        return False
+    def run_scheduler(self, cr, uid, context=None):
+        self.scheduler_manage_auto_costs(cr, uid, context=context)
+        self.scheduler_manage_contract_expiration(cr, uid, context=context)
+        return True
 
-    def on_change_vehicle(self, cr, uid, ids, vehicle_id, context=None):
+    def _vehicle_contract_name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None):
+        res = {}
+        for record in self.browse(cr, uid, ids, context=context):
+            name = record.vehicle_id.name
+            if record.cost_subtype_id.name:
+                name += ' / '+ record.cost_subtype_id.name
+            if record.date:
+                name += ' / '+ record.date
+            res[record.id] = name
+        return res
 
+    def on_change_vehicle(self, cr, uid, ids, vehicle_id, context=None):
         if not vehicle_id:
             return {}
-
         odometer_unit = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context).odometer_unit
-
         return {
-            'value' : {
-                'odometer_unit' : odometer_unit,
+            'value': {
+                'odometer_unit': odometer_unit,
             }
         }
 
     def compute_next_year_date(self, strdate):
-        oneyear=datetime.timedelta(days=365)
-        curdate = self.str_to_date(strdate)
-        nextyear=curdate+oneyear#int(strdate[:4])+1
-        return str(nextyear)#+strdate[4:]
+        oneyear = datetime.timedelta(days=365)
+        curdate = str_to_datetime(strdate)
+        return datetime.datetime.strftime(curdate + oneyear, tools.DEFAULT_SERVER_DATE_FORMAT)
 
     def on_change_start_date(self, cr, uid, ids, strdate, enddate, context=None):
-        
         if (strdate):
-           
-            return {'value' : {'expiration_date' : self.compute_next_year_date(strdate),}}
-        else:
-            return {}
-
-    def str_to_date(self,strdate):
-        return datetime.datetime(int(strdate[:4]),int(strdate[5:7]),int(strdate[8:]))
-
-    def get_warning_date(self,cr,uid,ids,prop,unknow_none,context=None):
-        if context is None:
-            context={}
-        if not ids:
-            return dict([])
-        reads = self.browse(cr,uid,ids,context=context)
-        res=[]
-        for record in reads:
-            #if (record.reminder==True):
-            if (record.expiration_date and (record.state=='open' or record.state=='toclose')):
-                today=self.str_to_date(time.strftime('%Y-%m-%d'))
-                renew_date = self.str_to_date(record.expiration_date)
-                diff_time=int((renew_date-today).days)
-                if (diff_time<=0):
-                    res.append((record.id,0))
-                else:
-                    res.append((record.id,diff_time))
+            return {'value': {'expiration_date': self.compute_next_year_date(strdate),}}
+        return {}
+
+    def get_days_left(self, cr, uid, ids, prop, unknow_none, context=None):
+        """return a dict with as value for each contract an integer
+        if contract is in an open state and is overdue, return 0
+        if contract is in a closed state, return -1
+        otherwise return the number of days before the contract expires
+        """
+        res = {}
+        for record in self.browse(cr, uid, ids, context=context):
+            if (record.expiration_date and (record.state == 'open' or record.state == 'toclose')):
+                today = str_to_datetime(time.strftime(tools.DEFAULT_SERVER_DATE_FORMAT))
+                renew_date = str_to_datetime(record.expiration_date)
+                diff_time = (renew_date-today).days
+                res[record.id] = diff_time > 0 and diff_time or 0
             else:
-                res.append((record.id,-1))
-            #else:
-            #    res.append((record.id,-1))
-        return dict(res)
-
-    def act_renew_contract(self,cr,uid,ids,context=None):
-        
-        
-        contracts = self.browse(cr,uid,ids,context=context)
-        res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid ,'fleet','act_renew_contract', context)
-        for element in contracts:
-            temp = []
-            temp.append(('default_vehicle_id',element.vehicle_id.id))
-            temp.append(('default_cost_subtype',element.cost_subtype.id))
-            temp.append(('default_amount',element.amount))
-            temp.append(('default_odometer_id',element.odometer_id.id))
-            temp.append(('default_odometer_unit',element.odometer_unit))
-            temp.append(('default_insurer_id',element.insurer_id.id))
-            cost_temp = []
-            for costs in element.cost_ids:
-                cost_temp.append(costs.id)
-            temp.append(('default_cost_ids',cost_temp))
-            temp.append(('default_date',time.strftime('%Y-%m-%d')))
-            temp.append(('default_start_date',str(self.str_to_date(element.expiration_date)+datetime.timedelta(days=1))))
-            temp.append(('default_purchaser_id',element.purchaser_id.id))
-            temp.append(('default_ins_ref',element.ins_ref))
-            #temp.append(('default_state','open'))
-            temp.append(('default_notes',element.notes))
-            temp.append(('default_cost_frequency',element.cost_frequency))
-            generated_cost = []
-            for gen_cost in element.generated_cost_ids:
-                generated_cost.append(gen_cost.id)
-            temp.append(('default_generated_cost_ids',generated_cost))
-            temp.append(('default_parent_id',element.parent_id.id))
-            temp.append(('default_cost_type',element.cost_type))
-            temp.append(('default_cost_subtype',element.cost_subtype.id))
+                res[record.id] = -1
+        return res
 
+    def act_renew_contract(self, cr, uid, ids, context=None):
+        assert len(ids) == 1, "This operation should only be done for 1 single contract at a time, as it it suppose to open a window as result"
+        for element in self.browse(cr, uid, ids, context=context):
             #compute end date
-            startdate = self.str_to_date(element.start_date)
-            enddate = self.str_to_date(element.expiration_date)
-            diffdate = (enddate-startdate)
-            newenddate = enddate+diffdate
-            temp.append(('default_expiration_date',str(newenddate)))
-
-        
-        #data = self.read(cr, uid, ids, ['vehicle_id', 'cost_subtype', 'amount', 'odometer_id', 'odometer_unit', 'insurer_id', 'cost_ids', 'expiration_date', \
-        #                                        'date', 'start_date', 'purchaser_id', 'ins_ref' ,'notes','cost_frequency', 'generated_cost'])
-        
-        
-        res['context'] = dict(temp)
-        #return super(fleet_vehicle_log_contract, self).copy(cr, uid, ids, default={}, context=None)
-        return res
+            startdate = str_to_datetime(element.start_date)
+            enddate = str_to_datetime(element.expiration_date)
+            diffdate = (enddate - startdate)
+            default = {
+                'date': fields.date.context_today(self, cr, uid, context=context),
+                'start_date': datetime.datetime.strftime(str_to_datetime(element.expiration_date) + datetime.timedelta(days=1), tools.DEFAULT_SERVER_DATE_FORMAT),
+                'expiration_date': datetime.datetime.strftime(enddate + diffdate, tools.DEFAULT_SERVER_DATE_FORMAT),
+            }
+            newid = super(fleet_vehicle_log_contract, self).copy(cr, uid, element.id, default, context=context)
+        mod, modid = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'fleet', 'fleet_vehicle_log_contract_form')
+        return {
+            'name':_("Renew Contract"),
+            'view_mode': 'form',
+            'view_id': modid,
+            'view_type': 'tree,form',
+            'res_model': 'fleet.vehicle.log.contract',
+            'type': 'ir.actions.act_window',
+            'nodestroy': True,
+            'domain': '[]',
+            'res_id': newid,
+            'context': {'active_id':newid}, 
+        }
 
-    def _get_default_contract_type(self, cr, uid, context):
+    def _get_default_contract_type(self, cr, uid, context=None):
         try:
             model, model_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'fleet', 'type_contract_leasing')
         except ValueError:
             model_id = False
         return model_id
 
+    def on_change_indic_cost(self, cr, uid, ids, cost_ids, context=None):
+        totalsum = 0.0
+        for element in cost_ids:
+            if element and len(element) == 3 and element[2] is not False:
+                totalsum += element[2].get('amount', 0.0)
+        return {
+            'value': {
+                'sum_cost': totalsum,
+            }
+        }
+
+    def _get_sum_cost(self, cr, uid, ids, field_name, arg, context=None):
+        res = {}
+        for contract in self.browse(cr, uid, ids, context=context):
+            totalsum = 0
+            for cost in contract.cost_ids:
+                totalsum += cost.amount
+            res[contract.id] = totalsum
+        return res
+
+    _inherits = {'fleet.vehicle.cost': 'cost_id'}
     _name = 'fleet.vehicle.log.contract'
-    _order='state,expiration_date'
+    _description = 'Contract information on a vehicle'
+    _order='state desc,expiration_date'
     _columns = {
-        'name' : fields.function(_vehicle_contract_name_get_fnc, type="text", string='Name', store=True),
-
-        'start_date' : fields.date('Contract Start Date', required=False, help='Date when the coverage of the contract begins'),
-        'expiration_date' : fields.date('Contract Expiration Date', required=False, help='Date when the coverage of the contract expirates (by default, one year after begin date)'),
-        'warning_date' : fields.function(get_warning_date,type='integer',string='Warning Date',store=False),
-
-        'insurer_id' :fields.many2one('res.partner', 'Supplier', domain="[('supplier','=',True)]"),
-        'purchaser_id' : fields.many2one('res.partner', 'Contractor',domain="['|',('customer','=',True),('employee','=',True)]",help='Person to which the contract is signed for'),
-        'ins_ref' : fields.char('Contract Reference', size=64),
-        'state' : fields.selection([('open', 'In Progress'),('toclose','To Close'), ('closed', 'Terminated')], 'Status', readonly=True, help='Choose wheter the contract is still valid or not'),
-        #'reminder' : fields.boolean('Renewal Reminder', help="Warn the user a few days before the expiration date of this contract"),
-        'notes' : fields.text('Terms and Conditions', help='Write here all supplementary informations relative to this contract'),
-        'odometer_id' : fields.many2one('fleet.vehicle.odometer', 'Odometer', required=False, help='Odometer measure of the vehicle at the moment of this log'),
-        'odometer' : fields.function(_get_odometer,fnct_inv=_set_odometer,type='char',string='Odometer Value',store=False,help='Odometer measure of the vehicle at the moment of this log'),
-        'odometer_unit': fields.related('vehicle_id','odometer_unit',type="char",string="Unit",store=False, readonly=True),
-        'cost_amount': fields.related('cost_id','amount',type="float",string="Amount",store=True, readonly=True),
-        'cost_generated': fields.float('Recurring Cost Amount',help="Costs paid at regular intervals, depending on the cost frequency. If the cost frequency is set to unique, the cost will be logged at the start date"),
-        'cost_frequency': fields.selection([('no','No'),('daily', 'Daily'),('weekly','Weekly'),('monthly','Monthly'),('yearly','Yearly')], 'Recurring Cost Frequency', help='Frequency of the recuring cost',required=True),
-        'generated_cost_ids' : fields.one2many('fleet.vehicle.cost', 'contract_id', 'Generated Costs',ondelete='cascade'),
+        'name': fields.function(_vehicle_contract_name_get_fnc, type="text", string='Name', store=True),
+        'start_date': fields.date('Contract Start Date', help='Date when the coverage of the contract begins'),
+        'expiration_date': fields.date('Contract Expiration Date', help='Date when the coverage of the contract expirates (by default, one year after begin date)'),
+        'days_left': fields.function(get_days_left, type='integer', string='Warning Date'),
+        'insurer_id' :fields.many2one('res.partner', 'Supplier'),
+        'purchaser_id': fields.many2one('res.partner', 'Contractor', help='Person to which the contract is signed for'),
+        'ins_ref': fields.char('Contract Reference', size=64),
+        'state': fields.selection([('open', 'In Progress'), ('toclose','To Close'), ('closed', 'Terminated')], 'Status', readonly=True, help='Choose wheter the contract is still valid or not'),
+        'notes': fields.text('Terms and Conditions', help='Write here all supplementary informations relative to this contract'),
+        'cost_generated': fields.float('Recurring Cost Amount', help="Costs paid at regular intervals, depending on the cost frequency. If the cost frequency is set to unique, the cost will be logged at the start date"),
+        'cost_frequency': fields.selection([('no','No'), ('daily', 'Daily'), ('weekly','Weekly'), ('monthly','Monthly'), ('yearly','Yearly')], 'Recurring Cost Frequency', help='Frequency of the recuring cost', required=True),
+        'generated_cost_ids': fields.one2many('fleet.vehicle.cost', 'contract_id', 'Generated Costs', ondelete='cascade'),
+        'sum_cost': fields.function(_get_sum_cost, type='float', string='Indicative Costs Total'),
+        'cost_amount': fields.related('cost_id', 'amount', string='Amount', type='float', store=True), #we need to keep this field as a related with store=True because the graph view doesn't support (1) to address fields from inherited table and (2) fields that aren't stored in database
     }
     _defaults = {
-        'purchaser_id': lambda self, cr, uid, ctx: uid,
-        'date' : time.strftime('%Y-%m-%d'),
-        'start_date' : time.strftime('%Y-%m-%d'),
+        'purchaser_id': lambda self, cr, uid, ctx: self.pool.get('res.users').browse(cr, uid, uid, context=ctx).partner_id.id or False,
+        'date': fields.date.context_today,
+        'start_date': fields.date.context_today,
         'state':'open',
-        'expiration_date' : lambda self,cr,uid,ctx: self.compute_next_year_date(time.strftime('%Y-%m-%d')),
-        'cost_frequency' : 'no',
-        'cost_subtype' : _get_default_contract_type,
+        'expiration_date': lambda self, cr, uid, ctx: self.compute_next_year_date(fields.date.context_today(self, cr, uid, context=ctx)),
+        'cost_frequency': 'no',
+        'cost_subtype_id': _get_default_contract_type,
+        'cost_type': 'contract',
     }
 
     def copy(self, cr, uid, id, default=None, context=None):
-        default = default or {}
-        current_object = self.browse(cr,uid,id,context)
-        default['date'] = time.strftime('%Y-%m-%d')
-        default['start_date'] = time.strftime('%Y-%m-%d')
-        default['expiration_date'] = self.compute_next_year_date(time.strftime('%Y-%m-%d'))
-        #default['name'] = current_object.name
+        if default is None:
+            default = {}
+        today = fields.date.context_today(self, cr, uid, context=context)
+        default['date'] = today
+        default['start_date'] = today
+        default['expiration_date'] = self.compute_next_year_date(today)
         default['ins_ref'] = ''
         default['state'] = 'open'
         default['notes'] = ''
-        default['date'] = time.strftime('%Y-%m-%d')
-
-        #default['odometer'] = current_object.odometer
-        #default['odometer_unit'] = current_object.odometer_unit
         return super(fleet_vehicle_log_contract, self).copy(cr, uid, id, default, context=context)
 
-    def contract_close(self, cr, uid, ids, *args):
-        self.write(cr, uid, ids, {'state': 'closed'})
-        return True
-
-    def contract_open(self, cr, uid, ids, *args):
-        self.write(cr, uid, ids, {'state': 'open'})
-        return True
-    def create(self, cr, uid, data, context=None):
-        data['cost_type'] = 'contract'
-        cost_id = super(fleet_vehicle_log_contract, self).create(cr, uid, data, context=context)
-        return cost_id
+    def contract_close(self, cr, uid, ids, context=None):
+        return self.write(cr, uid, ids, {'state': 'closed'}, context=context)
 
-
-############################
-############################
-#Vehicle.log.contract.state class
-############################
-############################
+    def contract_open(self, cr, uid, ids, context=None):
+        return self.write(cr, uid, ids, {'state': 'open'}, context=context)
 
 class fleet_contract_state(osv.Model):
     _name = 'fleet.contract.state'
+    _description = 'Contains the different possible status of a leasing contract'
+
     _columns = {
-        'name':fields.char('Contract Status',size=32),
-    }
\ No newline at end of file
+        'name':fields.char('Contract Status', size=64, required=True),
+    }