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