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