[FIX]fix renew contract method
[odoo/odoo.git] / addons / fleet / fleet.py
1 # -*- coding: utf-8 -*-
2 from itertools import chain
3 from osv import osv, fields
4 import time
5 import datetime
6 import tools
7 from osv.orm import except_orm
8 from tools.translate import _
9 from dateutil.relativedelta import relativedelta
10 ############################
11 ############################
12 #Vehicle.cost class
13 ############################
14 ############################
15
16 class fleet_vehicle_cost(osv.Model):
17     _name = 'fleet.vehicle.cost'
18     _description = 'Cost of vehicle'
19     _order = 'date desc, vehicle_id asc'
20
21     def name_get(self, cr, uid, ids, context=None):
22         if context is None:
23             context = {}
24         if not ids:
25             return []
26         reads = self.browse(cr, uid, ids, context=context)
27         res = []
28         for record in reads:
29             if record.vehicle_id.license_plate:
30                 name = record.vehicle_id.license_plate
31             if record.cost_subtype.name:
32                 name = name + ' / '+ record.cost_subtype.name
33             if record.date:
34                 name = name + ' / '+ record.date
35             res.append((record.id, name))
36         return res
37
38     def _cost_name_get_fnc(self, cr, uid, ids, name, unknow_none, context=None):
39         res = self.name_get(cr, uid, ids, context=context)
40         return dict(res)
41
42     _columns = {
43         'name' : fields.function(_cost_name_get_fnc, type="char", string='Name', store=True),
44         #'name' : fields.char('Name',size=32),
45         'vehicle_id': fields.many2one('fleet.vehicle', 'Vehicle', required=True, help='Vehicle concerned by this fuel log'),
46         'cost_subtype': fields.many2one('fleet.service.type', 'Type', required=False, help='Cost type purchased with this cost'),
47         'amount': fields.float('Total Price'),
48         'cost_type' : fields.selection([('contract', 'Contract'),('services','Services'),('fuel','Fuel'),('other','Other')], 'Category of the cost', help='For internal purpose only',required=True),
49         'parent_id': fields.many2one('fleet.vehicle.cost', 'Parent', required=False, help='Parent cost to this current cost'),
50         'cost_ids' : fields.one2many('fleet.vehicle.cost', 'parent_id', 'Included Services'),
51
52         'date' :fields.date('Date',help='Date when the cost has been executed'),
53
54         'contract_id' : fields.many2one('fleet.vehicle.log.contract', 'Contract', required=False, help='Contract attached to this cost'),
55         'auto_generated' : fields.boolean('automatically generated',readonly=True,required=True)
56     }
57
58     _defaults ={
59         'parent_id':None,
60         'auto_generated' : False,
61         'cost_type' : 'other',
62     }
63
64     
65
66     def create(self, cr, uid, data, context=None):
67         if 'parent_id' in data and data['parent_id']:
68             parent = self.browse(cr, uid, data['parent_id'], context=context)
69             data['vehicle_id'] = parent.vehicle_id.id
70             data['date'] = parent.date
71             data['cost_type'] = parent.cost_type
72         if 'contract_id' in data and data['contract_id']:
73             contract = self.pool.get('fleet.vehicle.log.contract').browse(cr, uid, data['contract_id'], context=context)
74             data['vehicle_id'] = contract.vehicle_id.id
75             data['cost_subtype'] = contract.cost_subtype.id
76             data['cost_type'] = contract.cost_type
77         if not('cost_type' in data and data['cost_type']):
78             data['cost_type'] = 'other'
79         cost_id = super(fleet_vehicle_cost, self).create(cr, uid, data, context=context)
80         return cost_id
81
82 ############################
83 ############################
84 #Vehicle.tag class
85 ############################
86 ############################
87
88 class fleet_vehicle_tag(osv.Model):
89     _name = 'fleet.vehicle.tag'
90     _columns = {
91         'name': fields.char('Name', required=True, translate=True),
92     }
93
94 ############################
95 ############################
96 #Vehicle.state class
97 ############################
98 ############################
99
100 class fleet_vehicle_state(osv.Model):
101     _name = 'fleet.vehicle.state'
102     _columns = {
103         'name': fields.char('Name', required=True),
104         'sequence': fields.integer('Order',help="Used to order the note stages")
105     }
106     _order = 'sequence asc'
107     _sql_constraints = [('fleet_state_name_unique','unique(name)','State name already exists')]
108
109
110 ############################
111 ############################
112 #Vehicle.model class
113 ############################
114 ############################
115
116 class fleet_vehicle_model(osv.Model):
117
118     def name_get(self, cr, uid, ids, context=None):
119         if context is None:
120             context = {}
121         if not ids:
122             return []
123         reads = self.browse(cr, uid, ids, context=context)
124         res = []
125         for record in reads:
126             name = record.modelname
127             if record.brand.name:
128                 name = record.brand.name+' / '+name
129             res.append((record.id, name))
130         return res
131
132     def _model_name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None):
133         res = self.name_get(cr, uid, ids, context=context)
134         return dict(res)
135
136     def on_change_brand(self, cr, uid, ids, model_id, context=None):
137
138         if not model_id:
139             return {}
140
141         brand = self.pool.get('fleet.vehicle.model.brand').browse(cr, uid, model_id, context=context)
142
143         return {
144             'value' : {
145                 'image' : brand.image,
146             }
147         }
148
149     _name = 'fleet.vehicle.model'
150     _description = 'Model of a vehicle'
151
152     _columns = {
153         'name' : fields.function(_model_name_get_fnc, type="char", string='Name', store=True),
154         'modelname' : fields.char('Model name', size=32, required=True), 
155         'brand' : fields.many2one('fleet.vehicle.model.brand', 'Model Brand', required=True, help='Brand of the vehicle'),
156         'vendors': fields.many2many('res.partner','fleet_vehicle_model_vendors','model_id', 'partner_id',string='Vendors',required=False),
157         'image': fields.related('brand','image',type="binary",string="Logo",store=False),
158         'image_medium': fields.related('brand','image_medium',type="binary",string="Logo",store=False),
159         'image_small': fields.related('brand','image_small',type="binary",string="Logo",store=False),
160     }
161
162 ############################
163 ############################
164 #Vehicle.brand class
165 ############################
166 ############################
167
168 class fleet_vehicle_model_brand(osv.Model):
169     _name = 'fleet.vehicle.model.brand'
170     _description = 'Brand model of the vehicle'
171
172     _order = 'name asc'
173
174     def _get_image(self, cr, uid, ids, name, args, context=None):
175         result = dict.fromkeys(ids, False)
176         for obj in self.browse(cr, uid, ids, context=context):
177             result[obj.id] = tools.image_get_resized_images(obj.image)
178         return result
179     
180     def _set_image(self, cr, uid, id, name, value, args, context=None):
181         return self.write(cr, uid, [id], {'image': tools.image_resize_image_big(value)}, context=context)
182
183     _columns = {
184         'name' : fields.char('Brand Name',size=32, required=True),
185
186         'image': fields.binary("Logo",
187             help="This field holds the image used as logo for the brand, limited to 1024x1024px."),
188         'image_medium': fields.function(_get_image, fnct_inv=_set_image,
189             string="Medium-sized photo", type="binary", multi="_get_image",
190             store = {
191                 'fleet.vehicle.model.brand': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
192             },
193             help="Medium-sized logo of the brand. It is automatically "\
194                  "resized as a 128x128px image, with aspect ratio preserved. "\
195                  "Use this field in form views or some kanban views."),
196         'image_small': fields.function(_get_image, fnct_inv=_set_image,
197             string="Smal-sized photo", type="binary", multi="_get_image",
198             store = {
199                 'fleet.vehicle.model.brand': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10),
200             },
201             help="Small-sized photo of the brand. It is automatically "\
202                  "resized as a 64x64px image, with aspect ratio preserved. "\
203                  "Use this field anywhere a small image is required."),
204     }
205
206 ############################
207 ############################
208 #Vehicle class
209 ############################
210 ############################
211
212
213 class fleet_vehicle(osv.Model):
214
215     _inherit = 'mail.thread'
216
217     def name_get(self, cr, uid, ids, context=None):
218         if context is None:
219             context = {}
220         if not ids:
221             return []
222         reads = self.browse(cr, uid, ids, context=context)
223         res = []
224         for record in reads:
225             if record.license_plate:
226                 name = record.license_plate
227             if record.model_id.modelname:
228                 name = record.model_id.modelname + ' / ' + name
229             if record.model_id.brand.name:
230                 name = record.model_id.brand.name+' / '+ name
231             res.append((record.id, name))
232         return res
233
234     def _vehicle_name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None):
235         res = self.name_get(cr, uid, ids, context=context)
236         return dict(res)
237
238     def act_show_log_services(self, cr, uid, ids, context=None):
239         """ This opens log view to view and add new log for this vehicle
240             @return: the service log view
241         """
242         res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid ,'fleet','fleet_vehicle_log_services_act', context)
243         res['context'] = {
244             'default_vehicle_id': ids[0]
245         }
246         res['domain']=[('vehicle_id','=', ids[0])]
247         return res
248
249     def act_show_log_contract(self, cr, uid, ids, context=None):
250         """ This opens log view to view and add new log for this vehicle
251             @return: the contract log view
252         """
253         res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid ,'fleet','fleet_vehicle_log_contract_act', context)
254         res['context'] = {
255             'default_vehicle_id': ids[0]
256         }
257         res['domain']=[('vehicle_id','=', ids[0])]
258         return res
259
260     def act_show_log_fuel(self, cr, uid, ids, context=None):
261         """ This opens log view to view and add new log for this vehicle
262             @return: the fuel log view
263         """
264         res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid ,'fleet','fleet_vehicle_log_fuel_act', context)
265         res['context'] = {
266             'default_vehicle_id': ids[0]
267         }
268         res['domain']=[('vehicle_id','=', ids[0])]
269         return res
270
271     def act_show_log_cost(self, cr, uid, ids, context=None):
272         """ This opens log view to view and add new log for this vehicle
273             @return: the costs log view
274         """
275         res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid ,'fleet','fleet_vehicle_costs_act', context)
276         res['context'] = {
277             'default_vehicle_id': ids[0],
278             'search_default_parent_false' : True
279         }
280         res['domain']=[('vehicle_id','=', ids[0])]
281         return res
282
283     def act_show_log_odometer(self, cr, uid, ids, context=None):
284         """ This opens log view to view and add new log for this vehicle
285             @return: the odometer log view
286         """
287         res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid ,'fleet','fleet_vehicle_odometer_act', context)
288         res['context'] = {
289             'default_vehicle_id': ids[0]
290         }
291         res['domain']=[('vehicle_id','=', ids[0])]
292         return res
293
294     def _get_odometer(self, cr, uid, ids, odometer_id, arg, context):
295         res = dict.fromkeys(ids, False)
296         for record in self.browse(cr,uid,ids,context=context):    
297             ids = self.pool.get('fleet.vehicle.odometer').search(cr,uid,[('vehicle_id','=',record.id)],limit=1, order='value desc')
298             if len(ids) > 0:
299                 res[record.id] = str(self.pool.get('fleet.vehicle.odometer').browse(cr,uid,ids[0],context=context).value)
300             else:
301                 res[record.id] = str(0)
302         return res
303
304     def _set_odometer(self, cr, uid, id, name, value, args=None, context=None):
305         if value:
306             try:
307                 value = float(value)
308             except ValueError:
309                 #_logger.exception(value+' is not a correct odometer value. Please, fill a float for this field')
310                 raise except_orm(_('Error!'), value+' is not a correct odometer value. Please, fill a float for this field')
311             
312             date = time.strftime('%Y-%m-%d')
313             data = {'value' : value,'date' : date,'vehicle_id' : id}
314             odometer_id = self.pool.get('fleet.vehicle.odometer').create(cr, uid, data, context=context)
315             return value
316         self.write(cr, uid, id, {'odometer_id': ''})
317         return False  
318
319     def str_to_date(self,strdate):
320         return datetime.datetime(int(strdate[:4]),int(strdate[5:7]),int(strdate[8:]))
321
322     def get_overdue_contract_reminder_fnc(self,cr,uid,ids,context=None):
323         if context is None:
324             context={}
325         if not ids:
326             return dict([])
327         reads = self.browse(cr,uid,ids,context=context)
328         res=[]
329         
330         for record in reads:
331             overdue=0
332             if (record.log_contracts):
333                 for element in record.log_contracts:
334                     if (element.state=='open' and element.expiration_date):
335                         current_date_str=time.strftime('%Y-%m-%d')
336                         due_time_str=element.expiration_date
337                             #due_time_str=element.browse()
338                         current_date=self.str_to_date(current_date_str)
339                         due_time=self.str_to_date(due_time_str)
340              
341                         diff_time=int((due_time-current_date).days)
342                         if diff_time<0:
343                             overdue = overdue +1;
344                 res.append((record.id,overdue))
345             else:
346                 res.append((record.id,0))
347
348         return dict(res)
349
350     def get_overdue_contract_reminder(self,cr,uid,ids,prop,unknow_none,context=None):
351         res = self.get_overdue_contract_reminder_fnc(cr, uid, ids, context=context)
352         return res
353
354     def get_next_contract_reminder_fnc(self,cr,uid,ids,context=None):
355         if context is None:
356             context={}
357         if not ids:
358             return dict([])
359         reads = self.browse(cr,uid,ids,context=context)
360         res=[]
361
362         for record in reads:
363             due_soon=0
364             if (record.log_contracts):
365                 for element in record.log_contracts:
366                     if (element.state=='open' and element.expiration_date):
367                         current_date_str=time.strftime('%Y-%m-%d')
368                         due_time_str=element.expiration_date
369                             #due_time_str=element.browse()
370                         current_date=self.str_to_date(current_date_str)
371                         due_time=self.str_to_date(due_time_str)
372              
373                         diff_time=int((due_time-current_date).days)
374                         if diff_time<15 and diff_time>=0:
375                             due_soon = due_soon +1;
376                 res.append((record.id,due_soon))
377             else:
378                 res.append((record.id,0))
379         
380         return dict(res)
381
382     def _search_get_overdue_contract_reminder(self, cr, uid, obj, name, args, context):
383         res = []
384         for field, operator, value in args:
385             #assert field == name
386             vehicle_ids = self.search(cr, uid, [])
387             renew_ids = self.get_overdue_contract_reminder_fnc(cr,uid,vehicle_ids,context=context)
388             res_ids = []
389             for renew_key,renew_value in renew_ids.items():
390                 if eval(str(renew_value) + " " + str(operator) + " " + str(value)):
391                     res_ids.append(renew_key)
392             res.append(('id', 'in', res_ids))      
393         return res
394     
395     def _search_contract_renewal_due_soon(self, cr, uid, obj, name, args, context):
396         res = []
397         for field, operator, value in args:
398             #assert field == name
399             vehicle_ids = self.search(cr, uid, [])
400             renew_ids = self.get_next_contract_reminder_fnc(cr,uid,vehicle_ids,context=context)
401             res_ids = []
402             for renew_key,renew_value in renew_ids.items():
403                 if eval(str(renew_value) + " " + str(operator) + " " + str(value)):
404                     res_ids.append(renew_key)
405             res.append(('id', 'in', res_ids))      
406         return res
407
408     def get_next_contract_reminder(self, cr, uid, ids, prop, unknow_none, context=None):
409         res = self.get_next_contract_reminder_fnc(cr, uid, ids, context=context)
410         return res
411
412     def get_contract_renewal_names(self,cr,uid,ids,function_name,args,context=None):
413         if not ids:
414             return dict([])
415         reads = self.browse(cr,uid,ids,context=context)
416         res=[]
417         for record in reads:
418             if (record.log_contracts):
419                 ids = self.pool.get('fleet.vehicle.log.contract').search(cr,uid,[('vehicle_id','=',record.id),('state','=','open')],limit=1,order='expiration_date asc')
420                 if len(ids) > 0:
421                     res.append((record.id,self.pool.get('fleet.vehicle.log.contract').browse(cr,uid,ids[0],context=context).cost_subtype.name))
422             else:
423                 res.append((record.id,''))
424         return dict(res)
425
426     def get_total_contract_reminder(self,cr,uid,ids,prop,unknow_none,context=None):
427         if context is None:
428             context={}
429         if not ids:
430             return dict([])
431         reads = self.browse(cr,uid,ids,context=context)
432         res=[]
433
434         for record in reads:
435             due_soon=0
436             if (record.log_contracts):
437                 for element in record.log_contracts:
438                     if (element.state=='open' and element.expiration_date):
439                         current_date_str=time.strftime('%Y-%m-%d')
440                         due_time_str=element.expiration_date
441
442                         current_date=self.str_to_date(current_date_str)
443                         due_time=self.str_to_date(due_time_str)
444              
445                         diff_time=int((due_time-current_date).days)
446                         if diff_time<15:
447                             due_soon = due_soon +1;
448                 if due_soon>0:
449                     due_soon=due_soon-1
450                 res.append((record.id,due_soon))
451             else:
452                 res.append((record.id,0))
453         
454         return dict(res)
455
456     def run_scheduler(self,cr,uid,context=None):
457         ids = self.pool.get('fleet.vehicle').search(cr, uid, [], offset=0, limit=None, order=None,context=None, count=False)
458         nexts = self.get_next_contract_reminder_fnc(cr,uid,ids,context=context)
459         overdues = self.get_overdue_contract_reminder_fnc(cr,uid,ids,context=context)
460         for key,value in nexts.items():
461             if value > 0 and overdues[key] > 0:
462                 self.message_post(cr, uid, [key], body=str(value) + ' contract(s) has to be renewed soon and '+str(overdues[key])+' contract(s) is (are) overdued', context=context)
463             elif value > 0:
464                 self.message_post(cr, uid, [key], body=str(value) + ' contract(s) has to be renewed soon!', context=context)
465             elif overdues[key] > 0 : 
466                 self.message_post(cr, uid, [key], body=str(overdues[key]) + ' contract(s) is(are) overdued!', context=context)
467         return True
468
469     def _get_default_state(self, cr, uid, context):
470         try:
471             model, model_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'fleet', 'vehicle_state_active')
472         except ValueError:
473             model_id = False
474         return model_id
475
476     _name = 'fleet.vehicle'
477     _description = 'Fleet Vehicle'
478     #_order = 'contract_renewal_overdue desc, contract_renewal_due_soon desc'
479     _order= 'license_plate asc'
480     _columns = {
481         'name' : fields.function(_vehicle_name_get_fnc, type="char", string='Name', store=True),
482
483         'company_id': fields.many2one('res.company', 'Company'),
484         'license_plate' : fields.char('License Plate', size=32, required=True, help='License plate number of the vehicle (ie: plate number for a car)'),
485         'vin_sn' : fields.char('Chassis Number', size=32, required=False, help='Unique number written on the vehicle motor (VIN/SN number)'),
486         'driver' : fields.many2one('res.partner', 'Driver',required=False, help='Driver of the vehicle'),
487         'model_id' : fields.many2one('fleet.vehicle.model', 'Model', required=True, help='Model of the vehicle'),
488         'log_fuel' : fields.one2many('fleet.vehicle.log.fuel','vehicle_id', 'Fuel Logs'),
489         'log_services' : fields.one2many('fleet.vehicle.log.services','vehicle_id', 'Services Logs'),
490         'log_contracts' : fields.one2many('fleet.vehicle.log.contract','vehicle_id', 'Contracts'),
491         'acquisition_date' : fields.date('Acquisition Date', required=False, help='Date when the vehicle has been bought'),
492         'color' : fields.char('Color',size=32, help='Color of the vehicle'),
493         'state': fields.many2one('fleet.vehicle.state', 'State', help='Current state of the vehicle',ondelete="set null"),
494         'location' : fields.char('Location',size=32, help='Location of the vehicle (garage, ...)'),
495         'seats' : fields.integer('Seats Number', help='Number of seats of the vehicle'),
496         'doors' : fields.integer('Doors Number', help='Number of doors of the vehicle'),
497         'tag_ids' :fields.many2many('fleet.vehicle.tag','fleet_vehicle_vehicle_tag_rel','vehicle_tag_id','tag_id','Tags'),
498
499         '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'),
500         'odometer_unit': fields.selection([('kilometers', 'Kilometers'),('miles','Miles')], 'Odometer Unit', help='Unit of the odometer ',required=True),
501
502         'transmission' : fields.selection([('manual', 'Manual'),('automatic','Automatic')], 'Transmission', help='Transmission Used by the vehicle',required=False),
503         'fuel_type' : fields.selection([('gasoline', 'Gasoline'),('diesel','Diesel'),('electric','Electric'),('hybrid','Hybrid')], 'Fuel Type', help='Fuel Used by the vehicle',required=False),
504         'horsepower' : fields.integer('Horsepower',required=False),
505         'horsepower_tax': fields.float('Horsepower Taxation'),
506         'power' : fields.integer('Power (kW)',required=False,help='Power in kW of the vehicle'),
507         'co2' : fields.float('CO2 Emissions',required=False,help='CO2 emissions of the vehicle'),
508
509         'image': fields.related('model_id','image',type="binary",string="Logo",store=False),
510         'image_medium': fields.related('model_id','image_medium',type="binary",string="Logo",store=False),
511         'image_small': fields.related('model_id','image_small',type="binary",string="Logo",store=False),
512
513         '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),
514         'contract_renewal_overdue' : fields.function(get_overdue_contract_reminder,fnct_search=_search_get_overdue_contract_reminder,type="integer",string='Contracts Overdued',store=False),
515         'contract_renewal_name' : fields.function(get_contract_renewal_names,type="text",string='Name of contract to renew soon',store=False),
516         'contract_renewal_total' : fields.function(get_total_contract_reminder,type="integer",string='Total of contracts due or overdue minus one',store=False),
517
518         'car_value': fields.float('Car Value', help='Value of the bought vehicle'),
519         #'leasing_value': fields.float('Leasing value',help='Value of the leasing(Monthly, usually'),
520         }
521
522     _defaults = {
523         'doors' : 5,
524         'odometer_unit' : 'kilometers',
525         'state' : _get_default_state,
526     }
527
528     def copy(self, cr, uid, id, default=None, context=None):
529         if not default:
530             default = {}
531
532         default.update({
533         #    'name': self.pool.get('ir.sequence').get(cr, uid, 'stock.orderpoint') or '',
534             #'log_ids':[],
535             'log_fuel':[],
536             'log_contracts':[],
537             'log_services':[],
538             'tag_ids':[],
539             'vin_sn':'',
540         })
541         return super(fleet_vehicle, self).copy(cr, uid, id, default, context=context)
542
543     def on_change_model(self, cr, uid, ids, model_id, context=None):
544
545         if not model_id:
546             return {}
547
548         model = self.pool.get('fleet.vehicle.model').browse(cr, uid, model_id, context=context)
549
550         return {
551             'value' : {
552                 'image' : model.image,
553             }
554         }
555     def create(self, cr, uid, data, context=None):
556         vehicle_id = super(fleet_vehicle, self).create(cr, uid, data, context=context)
557         try:
558             vehicle = self.browse(cr, uid, vehicle_id, context=context)
559             self.message_post(cr, uid, [vehicle_id], body='Vehicle %s has been added to the fleet!' % (vehicle.license_plate), context=context)
560         except:
561             pass # group deleted: do not push a message
562         return vehicle_id
563
564     def write(self, cr, uid, ids, vals, context=None):
565         changes = []
566         if 'driver' in vals:
567             value = self.pool.get('res.partner').browse(cr,uid,vals['driver'],context=context).name
568             olddriver = self.browse(cr, uid, ids, context)[0].driver
569             if olddriver:
570                 olddriver = olddriver.name
571             else:
572                 olddriver = 'None'
573             changes.append('Driver: from \'' + olddriver + '\' to \'' + value+'\'')
574         if 'state' in vals:
575             value = self.pool.get('fleet.vehicle.state').browse(cr,uid,vals['state'],context=context).name
576             oldstate = self.browse(cr, uid, ids, context)[0].state
577             if oldstate:
578                 oldstate=oldstate.name
579             else:
580                 oldstate = 'None'
581             changes.append('State: from \'' + oldstate + '\' to \'' + value+'\'')
582         if 'license_plate' in vals:
583             old_license_plate = self.browse(cr, uid, ids, context)[0].license_plate
584             if not old_license_plate:
585                 old_license_plate = 'None'
586             changes.append('License Plate: from \'' + old_license_plate + '\' to \'' + vals['license_plate']+'\'')   
587        
588         vehicle_id = super(fleet_vehicle,self).write(cr, uid, ids, vals, context)
589
590         try:
591             if len(changes) > 0:
592                 self.message_post(cr, uid, [self.browse(cr, uid, ids, context)[0].id], body=", ".join(changes), context=context)
593         except Exception as e:
594             print e
595             pass
596         return vehicle_id
597
598 ############################
599 ############################
600 #Vehicle.odometer class
601 ############################
602 ############################
603
604 class fleet_vehicle_odometer(osv.Model):
605     _name='fleet.vehicle.odometer'
606     _description='Odometer log for a vehicle'
607
608     _order='date desc'
609
610     def name_get(self, cr, uid, ids, context=None):
611         if context is None:
612             context = {}
613         if not ids:
614             return []
615         reads = self.browse(cr, uid, ids, context=context)
616         res = []
617         for record in reads:
618             if record.vehicle_id.name:
619                 name = str(record.vehicle_id.name)
620             if record.date:
621                 name = name+ ' / '+ str(record.date)
622             res.append((record.id, name))
623         return res
624
625     def _vehicle_log_name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None):
626         res = self.name_get(cr, uid, ids, context=context)
627         return dict(res)
628     def on_change_vehicle(self, cr, uid, ids, vehicle_id, context=None):
629
630         if not vehicle_id:
631             return {}
632
633         odometer_unit = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context).odometer_unit
634
635         return {
636             'value' : {
637                 'unit' : odometer_unit,
638             }
639         }
640
641     _columns = {
642         'name' : fields.function(_vehicle_log_name_get_fnc, type="char", string='Name', store=True),
643
644         'date' : fields.date('Date'),
645         'value' : fields.float('Odometer Value',group_operator="max"),
646         'vehicle_id' : fields.many2one('fleet.vehicle', 'Vehicle', required=True),
647         'unit': fields.related('vehicle_id','odometer_unit',type="char",string="Unit",store=False, readonly=True),
648         
649     }
650     _defaults = {
651         'date' : time.strftime('%Y-%m-%d')
652     }
653
654 ############################
655 ############################
656 #Vehicle.log classes
657 ############################
658 ############################
659
660
661 ############################
662 ############################
663 #Vehicle.log.fuel class
664 ############################
665 ############################
666
667
668 class fleet_vehicle_log_fuel(osv.Model):
669
670     #_inherits = {'fleet.vehicle.odometer': 'odometer_id'}
671     _inherits = {'fleet.vehicle.cost': 'cost_id'}
672
673     def on_change_vehicle(self, cr, uid, ids, vehicle_id, context=None):
674
675         if not vehicle_id:
676             return {}
677
678         odometer_unit = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context).odometer_unit
679
680         return {
681             'value' : {
682                 'odometer_unit' : odometer_unit,
683             }
684         }
685
686     def on_change_liter(self, cr, uid, ids, liter, price_per_liter, amount, context=None):
687
688         if liter > 0 and price_per_liter > 0:
689             return {'value' : {'amount' : float(liter) * float(price_per_liter),}}
690         elif liter > 0 and amount > 0:
691             return {'value' : {'price_per_liter' : float(amount) / float(liter),}}
692         elif price_per_liter > 0 and amount > 0:
693             return {'value' : {'liter' : float(amount) / float(price_per_liter),}}
694         else :
695             return {}
696
697     def on_change_price_per_liter(self, cr, uid, ids, liter, price_per_liter, amount, context=None):
698
699         liter = float(liter);
700         price_per_liter = float(price_per_liter);
701         if price_per_liter > 0 and liter > 0:
702             return {'value' : {'amount' : float(liter) * float(price_per_liter),}}
703         elif price_per_liter > 0 and amount > 0:
704             return {'value' : {'liter' : float(amount) / float(price_per_liter),}}
705         elif liter > 0 and amount > 0:
706             return {'value' : {'price_per_liter' : float(amount) / float(liter),}}
707         else :
708             return {}
709
710     def on_change_amount(self, cr, uid, ids, liter, price_per_liter, amount, context=None):
711
712         if amount > 0 and liter > 0:
713             return {'value' : {'price_per_liter' : float(amount) / float(liter),}}
714         elif amount > 0 and price_per_liter > 0:
715             return {'value' : {'liter' : float(amount) / float(price_per_liter),}}
716         elif liter > 0 and price_per_liter > 0:
717             return {'value' : {'amount' : float(liter) * float(price_per_liter),}}
718         else :
719             return {}
720         
721     def _get_odometer(self, cr, uid, ids, odometer_id, arg, context):
722         res = dict.fromkeys(ids, False)
723         for record in self.browse(cr,uid,ids,context=context):
724             if record.odometer_id:
725                 res[record.id] = record.odometer_id.value
726         return res
727
728     def _set_odometer(self, cr, uid, id, name, value, args=None, context=None):
729         if value:
730             try:
731                 value = float(value)
732             except ValueError:
733                 #_logger.exception(value+' is not a correct odometer value. Please, fill a float for this field')
734                 raise except_orm(_('Error!'), value+' is not a correct odometer value. Please, fill a float for this field')
735                
736             date = self.browse(cr, uid, id, context=context).date
737             if not(date):
738                 date = time.strftime('%Y-%m-%d')
739             vehicle_id = self.browse(cr, uid, id, context=context).vehicle_id
740             data = {'value' : value,'date' : date,'vehicle_id' : vehicle_id.id}
741             odometer_id = self.pool.get('fleet.vehicle.odometer').create(cr, uid, data, context=context)
742             self.write(cr, uid, id, {'odometer_id': odometer_id})
743             return value
744         self.write(cr, uid, id, {'odometer_id': ''})
745         return False
746
747     def _get_default_service_type(self, cr, uid, context):
748         try:
749             model, model_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'fleet', 'type_service_refueling')
750         except ValueError:
751             model_id = False
752         return model_id
753
754     _name = 'fleet.vehicle.log.fuel'
755
756     _columns = {
757         #'name' : fields.char('Name',size=64),
758         'liter' : fields.float('Liter'),
759         'price_per_liter' : fields.float('Price Per Liter'),
760         'purchaser_id' : fields.many2one('res.partner', 'Purchaser',domain="['|',('customer','=',True),('employee','=',True)]"),
761         'inv_ref' : fields.char('Invoice Reference', size=64),
762         'vendor_id' : fields.many2one('res.partner', 'Supplier', domain="[('supplier','=',True)]"),
763         'notes' : fields.text('Notes'),
764         'odometer_id' : fields.many2one('fleet.vehicle.odometer', 'Odometer', required=False, help='Odometer measure of the vehicle at the moment of this log'),
765         'odometer' : fields.function(_get_odometer,fnct_inv=_set_odometer,type='char',string='Odometer',store=False),
766         'odometer_unit': fields.related('vehicle_id','odometer_unit',type="char",string="Unit",store=False, readonly=True),
767         'cost_amount': fields.related('cost_id','amount',type="float",string="Amount",store=True, readonly=True),
768     }
769     _defaults = {
770         'purchaser_id': lambda self, cr, uid, ctx: uid,
771         'date' : time.strftime('%Y-%m-%d'),
772         'cost_subtype': _get_default_service_type,
773     }
774     def create(self, cr, uid, data, context=None):
775         data['cost_type'] = 'fuel'
776         cost_id = super(fleet_vehicle_log_fuel, self).create(cr, uid, data, context=context)
777         return cost_id
778
779 ############################
780 ############################
781 #Vehicle.log.service class
782 ############################
783 ############################
784
785
786 class fleet_vehicle_log_services(osv.Model):
787
788     _inherits = {'fleet.vehicle.cost': 'cost_id'}
789
790     def on_change_vehicle(self, cr, uid, ids, vehicle_id, context=None):
791
792         if not vehicle_id:
793             return {}
794
795         odometer_unit = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context).odometer_unit
796
797         return {
798             'value' : {
799                 'odometer_unit' : odometer_unit,
800             }
801         }
802
803     def _get_odometer(self, cr, uid, ids, odometer_id, arg, context):
804         res = dict.fromkeys(ids, False)
805         for record in self.browse(cr,uid,ids,context=context):
806             if record.odometer_id:
807                 res[record.id] = record.odometer_id.value
808         return res
809
810     def _set_odometer(self, cr, uid, id, name, value, args=None, context=None):
811         if value:
812             try:
813                 value = float(value)
814             except ValueError:
815                 #_logger.exception(value+' is not a correct odometer value. Please, fill a float for this field')
816                 raise except_orm(_('Error!'), value+' is not a correct odometer value. Please, fill a float for this field')
817                
818             date = self.browse(cr, uid, id, context=context).date
819             if not(date):
820                 date = time.strftime('%Y-%m-%d')
821             vehicle_id = self.browse(cr, uid, id, context=context).vehicle_id
822             data = {'value' : value,'date' : date,'vehicle_id' : vehicle_id.id}
823             odometer_id = self.pool.get('fleet.vehicle.odometer').create(cr, uid, data, context=context)
824             self.write(cr, uid, id, {'odometer_id': odometer_id})
825             return value
826         self.write(cr, uid, id, {'odometer_id': ''})
827         return False
828
829     def _get_default_service_type(self, cr, uid, context):
830         try:
831             model, model_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'fleet', 'type_service_service_8')
832         except ValueError:
833             model_id = False
834         return model_id
835
836     _name = 'fleet.vehicle.log.services'
837     _columns = {
838
839         #'name' : fields.char('Name',size=64),
840
841         'purchaser_id' : fields.many2one('res.partner', 'Purchaser',domain="['|',('customer','=',True),('employee','=',True)]"),
842         'inv_ref' : fields.char('Invoice Reference', size=64),
843         'vendor_id' :fields.many2one('res.partner', 'Supplier', domain="[('supplier','=',True)]"),
844         'notes' : fields.text('Notes'),
845
846         'odometer_id' : fields.many2one('fleet.vehicle.odometer', 'Odometer', required=False, help='Odometer measure of the vehicle at the moment of this log'),
847         'odometer' : fields.function(_get_odometer,fnct_inv=_set_odometer,type='char',string='Odometer Value',store=False),
848         'odometer_unit': fields.related('vehicle_id','odometer_unit',type="char",string="Unit",store=False, readonly=True),
849         'cost_amount': fields.related('cost_id','amount',type="float",string="Amount",store=True, readonly=True),
850     }
851     _defaults = {
852         'purchaser_id': lambda self, cr, uid, ctx: uid,
853         'date' : time.strftime('%Y-%m-%d'),
854         'cost_subtype' : _get_default_service_type
855     }
856     def create(self, cr, uid, data, context=None):
857         data['cost_type'] = 'services'
858         cost_id = super(fleet_vehicle_log_services, self).create(cr, uid, data, context=context)
859         return cost_id
860
861 ############################
862 ############################
863 #Vehicle.service.type class
864 ############################
865 ############################
866
867 class fleet_service_type(osv.Model):
868     _name = 'fleet.service.type'
869     _columns = {
870         'name': fields.char('Name', required=True, translate=True),
871         'category': fields.selection([('contract', 'Contract'), ('service', 'Service'),('both', 'Both')], 'Category',required=True, help='Choose wheter the service refer to contracts, vehicle services or both'),
872     }
873     #_defaults = {
874     #    'category': 'both'
875     #}
876
877 ############################
878 ############################
879 #Vehicle.log.contract class
880 ############################
881 ############################
882
883 class fleet_vehicle_log_contract(osv.Model):
884
885     _inherits = {'fleet.vehicle.cost': 'cost_id'}
886
887     def run_scheduler(self,cr,uid,context=None):
888
889         d = datetime.date.today()
890         #d = datetime.datetime(2012, 12, 01)
891
892         contract_ids = self.pool.get('fleet.vehicle.log.contract').search(cr, uid, [('state','=','open')], offset=0, limit=None, order=None,context=None, count=False)
893         deltas = {'yearly' : relativedelta(years=+1),'monthly' : relativedelta(months=+1),'weekly' : relativedelta(weeks=+1),'daily' : relativedelta(days=+1)}
894         for contract in self.pool.get('fleet.vehicle.log.contract').browse(cr,uid,contract_ids,context=context):
895             if not contract.start_date or contract.cost_frequency == 'no':
896                 break;
897             if contract.generated_cost_ids != []:
898                 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)
899                 last_cost_date = self.pool.get('fleet.vehicle.cost').browse(cr,uid,last_cost_id[0],context=None).date
900                 found = True
901             else : 
902                 found = False
903                 last_cost_date = contract.start_date
904             startdate = datetime.datetime.strptime(last_cost_date,'%Y-%m-%d').date() 
905             if found:
906                 startdate += deltas.get(contract.cost_frequency)
907             while (startdate < d) & (startdate < datetime.datetime.strptime(contract.expiration_date,'%Y-%m-%d').date()):
908                 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}
909                 print data
910                 cost_id = self.pool.get('fleet.vehicle.cost').create(cr, uid, data, context=context)
911                 startdate += deltas.get(contract.cost_frequency)
912         return True
913     
914     def name_get(self, cr, uid, ids, context=None):
915         if context is None:
916             context = {} 
917         if not ids:
918             return []
919         reads = self.browse(cr, uid, ids, context=context)
920         res = []
921         for record in reads:
922             if record.vehicle_id.name:
923                 name = str(record.vehicle_id.name)
924             if record.cost_subtype.name:
925                 name = name+ ' / '+ str(record.cost_subtype.name)
926             if record.date:
927                 name = name+ ' / '+ record.date
928             res.append((record.id, name))
929         return res
930
931     def _vehicle_contract_name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None):
932         res = self.name_get(cr, uid, ids, context=context)
933         return dict(res)
934
935     def _get_odometer(self, cr, uid, ids, odometer_id, arg, context):
936         res = dict.fromkeys(ids, False)
937         for record in self.browse(cr,uid,ids,context=context):
938             if record.odometer_id:
939                 res[record.id] = record.odometer_id.value
940         return res
941
942     def _set_odometer(self, cr, uid, id, name, value, args=None, context=None):
943         if value:
944             try:
945                 value = float(value)
946             except ValueError:
947                 #_logger.exception(value+' is not a correct odometer value. Please, fill a float for this field')
948                 raise except_orm(_('Error!'), value+' is not a correct odometer value. Please, fill a float for this field')
949                
950             date = self.browse(cr, uid, id, context=context).date
951             if not(date):
952                 date = time.strftime('%Y-%m-%d')
953             vehicle_id = self.browse(cr, uid, id, context=context).vehicle_id
954             data = {'value' : value,'date' : date,'vehicle_id' : vehicle_id.id}
955             odometer_id = self.pool.get('fleet.vehicle.odometer').create(cr, uid, data, context=context)
956             self.write(cr, uid, id, {'odometer_id': odometer_id})
957             return value
958         self.write(cr, uid, id, {'odometer_id': ''})
959         return False
960
961     def on_change_vehicle(self, cr, uid, ids, vehicle_id, context=None):
962
963         if not vehicle_id:
964             return {}
965
966         odometer_unit = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context).odometer_unit
967
968         return {
969             'value' : {
970                 'odometer_unit' : odometer_unit,
971             }
972         }
973
974     def compute_next_year_date(self, strdate):
975         oneyear=datetime.timedelta(days=365)
976         curdate = self.str_to_date(strdate)
977         nextyear=curdate+oneyear#int(strdate[:4])+1
978         return str(nextyear)#+strdate[4:]
979
980     def on_change_start_date(self, cr, uid, ids, strdate, enddate, context=None):
981         
982         if (strdate):
983            
984             return {'value' : {'expiration_date' : self.compute_next_year_date(strdate),}}
985         else:
986             return {}
987
988     def str_to_date(self,strdate):
989         return datetime.datetime(int(strdate[:4]),int(strdate[5:7]),int(strdate[8:]))
990
991     def get_warning_date(self,cr,uid,ids,prop,unknow_none,context=None):
992         if context is None:
993             context={}
994         if not ids:
995             return dict([])
996         reads = self.browse(cr,uid,ids,context=context)
997         res=[]
998         for record in reads:
999             #if (record.reminder==True):
1000             if (record.expiration_date and record.state=='open'):
1001                 today=self.str_to_date(time.strftime('%Y-%m-%d'))
1002                 renew_date = self.str_to_date(record.expiration_date)
1003                 diff_time=int((renew_date-today).days)
1004                 if (diff_time<=0):
1005                     res.append((record.id,0))
1006                 else:
1007                     res.append((record.id,diff_time))
1008             else:
1009                 res.append((record.id,-1))
1010             #else:
1011             #    res.append((record.id,-1))
1012         return dict(res)
1013
1014     def act_renew_contract(self,cr,uid,ids,context=None):
1015         
1016         
1017         contracts = self.browse(cr,uid,ids,context=context)
1018         res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid ,'fleet','act_renew_contract', context)
1019         for element in contracts:
1020             temp = []
1021             temp.append(('default_vehicle_id',element.vehicle_id.id))
1022             temp.append(('default_cost_subtype',element.cost_subtype.id))
1023             temp.append(('default_amount',element.amount))
1024             temp.append(('default_odometer_id',element.odometer_id.id))
1025             temp.append(('default_odometer_unit',element.odometer_unit))
1026             temp.append(('default_insurer_id',element.insurer_id.id))
1027             cost_temp = []
1028             for costs in element.cost_ids:
1029                 cost_temp.append(costs.id)
1030             temp.append(('default_cost_ids',cost_temp))
1031             temp.append(('default_date',time.strftime('%Y-%m-%d')))
1032             temp.append(('default_start_date',str(self.str_to_date(element.expiration_date)+datetime.timedelta(days=1))))
1033             temp.append(('default_purchaser_id',element.purchaser_id.id))
1034             temp.append(('default_ins_ref',element.ins_ref))
1035             #temp.append(('default_state','open'))
1036             temp.append(('default_notes',element.notes))
1037             temp.append(('default_cost_frequency',element.cost_frequency))
1038             generated_cost = []
1039             for gen_cost in element.generated_cost_ids:
1040                 generated_cost.append(gen_cost.id)
1041             temp.append(('default_generated_cost_ids',generated_cost))
1042             temp.append(('default_parent_id',element.parent_id.id))
1043             temp.append(('default_cost_type',element.cost_type))
1044             temp.append(('default_cost_subtype',element.cost_subtype.id))
1045
1046             #compute end date
1047             startdate = self.str_to_date(element.start_date)
1048             enddate = self.str_to_date(element.expiration_date)
1049             diffdate = (enddate-startdate)
1050             newenddate = enddate+diffdate
1051             temp.append(('default_expiration_date',str(newenddate)))
1052
1053         
1054         #data = self.read(cr, uid, ids, ['vehicle_id', 'cost_subtype', 'amount', 'odometer_id', 'odometer_unit', 'insurer_id', 'cost_ids', 'expiration_date', \
1055         #                                        'date', 'start_date', 'purchaser_id', 'ins_ref' ,'notes','cost_frequency', 'generated_cost'])
1056         
1057         
1058         res['context'] = dict(temp)
1059         #return super(fleet_vehicle_log_contract, self).copy(cr, uid, ids, default={}, context=None)
1060         return res
1061
1062     def _get_default_contract_type(self, cr, uid, context):
1063         try:
1064             model, model_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'fleet', 'type_contract_leasing')
1065         except ValueError:
1066             model_id = False
1067         return model_id
1068
1069     _name = 'fleet.vehicle.log.contract'
1070     _order='state,expiration_date'
1071     _columns = {
1072         'name' : fields.function(_vehicle_contract_name_get_fnc, type="text", string='Name', store=True),
1073
1074         'start_date' : fields.date('Contract Start Date', required=False, help='Date when the coverage of the contract begins'),
1075         '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)'),
1076         'warning_date' : fields.function(get_warning_date,type='integer',string='Warning Date',store=False),
1077
1078         'insurer_id' :fields.many2one('res.partner', 'Supplier', domain="[('supplier','=',True)]"),
1079         'purchaser_id' : fields.many2one('res.partner', 'Contractor',domain="['|',('customer','=',True),('employee','=',True)]",help='Person to which the contract is signed for'),
1080         'ins_ref' : fields.char('Contract Reference', size=64),
1081         'state' : fields.selection([('open', 'In Progress'), ('closed', 'Terminated')], 'Status', readonly=True, help='Choose wheter the contract is still valid or not'),
1082         #'reminder' : fields.boolean('Renewal Reminder', help="Warn the user a few days before the expiration date of this contract"),
1083         'notes' : fields.text('Terms and Conditions', help='Write here all supplementary informations relative to this contract'),
1084         'odometer_id' : fields.many2one('fleet.vehicle.odometer', 'Odometer', required=False, help='Odometer measure of the vehicle at the moment of this log'),
1085         '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'),
1086         'odometer_unit': fields.related('vehicle_id','odometer_unit',type="char",string="Unit",store=False, readonly=True),
1087         'cost_amount': fields.related('cost_id','amount',type="float",string="Amount",store=True, readonly=True),
1088         '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"),
1089         '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),
1090         'generated_cost_ids' : fields.one2many('fleet.vehicle.cost', 'contract_id', 'Generated Costs',ondelete='cascade'),
1091     }
1092     _defaults = {
1093         'purchaser_id': lambda self, cr, uid, ctx: uid,
1094         'date' : time.strftime('%Y-%m-%d'),
1095         'start_date' : time.strftime('%Y-%m-%d'),
1096         'state':'open',
1097         'expiration_date' : lambda self,cr,uid,ctx: self.compute_next_year_date(time.strftime('%Y-%m-%d')),
1098         'cost_frequency' : 'no',
1099         'cost_subtype' : _get_default_contract_type,
1100     }
1101
1102     def copy(self, cr, uid, id, default=None, context=None):
1103         default = default or {}
1104         current_object = self.browse(cr,uid,id,context)
1105         default['date'] = time.strftime('%Y-%m-%d')
1106         default['start_date'] = time.strftime('%Y-%m-%d')
1107         default['expiration_date'] = self.compute_next_year_date(time.strftime('%Y-%m-%d'))
1108         #default['name'] = current_object.name
1109         default['ins_ref'] = ''
1110         default['state'] = 'open'
1111         default['notes'] = ''
1112         default['date'] = time.strftime('%Y-%m-%d')
1113
1114         #default['odometer'] = current_object.odometer
1115         #default['odometer_unit'] = current_object.odometer_unit
1116         return super(fleet_vehicle_log_contract, self).copy(cr, uid, id, default, context=context)
1117
1118     def contract_close(self, cr, uid, ids, *args):
1119         self.write(cr, uid, ids, {'state': 'closed'})
1120         return True
1121
1122     def contract_open(self, cr, uid, ids, *args):
1123         self.write(cr, uid, ids, {'state': 'open'})
1124         return True
1125     def create(self, cr, uid, data, context=None):
1126         data['cost_type'] = 'contract'
1127         cost_id = super(fleet_vehicle_log_contract, self).create(cr, uid, data, context=context)
1128         return cost_id
1129
1130
1131 ############################
1132 ############################
1133 #Vehicle.log.contract.state class
1134 ############################
1135 ############################
1136
1137 class fleet_contract_state(osv.Model):
1138     _name = 'fleet.contract.state'
1139     _columns = {
1140         'name':fields.char('Contract Status',size=32),
1141     }