[FIX]Resolve conflict in demo
[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'),
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             changes.append('Driver: from \'' + self.browse(cr, uid, ids, context)[0].driver.name + '\' to \'' + value+'\'')
454         if 'state' in vals:
455             value = self.pool.get('fleet.vehicle.state').browse(cr,uid,vals['state'],context=context).name
456             changes.append('State: from \'' + self.browse(cr, uid, ids, context)[0].state.name + '\' to \'' + value+'\'')
457         if 'license_plate' in vals:
458             changes.append('License Plate: from \'' + self.browse(cr, uid, ids, context)[0].license_plate + '\' to \'' + vals['license_plate']+'\'')   
459        
460         vehicle_id = super(fleet_vehicle,self).write(cr, uid, ids, vals, context)
461
462         try:
463             if len(changes) > 0:
464                 self.message_post(cr, uid, [self.browse(cr, uid, ids, context)[0].id], body=", ".join(changes), context=context)
465         except Exception as e:
466             print e
467             pass
468         return vehicle_id
469
470 ############################
471 ############################
472 #Vehicle.odometer class
473 ############################
474 ############################
475
476 class fleet_vehicle_odometer(osv.Model):
477     _name='fleet.vehicle.odometer'
478     _description='Odometer log for a vehicle'
479
480     _order='date desc'
481
482     def name_get(self, cr, uid, ids, context=None):
483         if context is None:
484             context = {}
485         if not ids:
486             return []
487         reads = self.browse(cr, uid, ids, context=context)
488         res = []
489         for record in reads:
490             if record.vehicle_id.name:
491                 name = str(record.vehicle_id.name)
492             if record.date:
493                 name = name+ ' / '+ str(record.date)
494             res.append((record.id, name))
495         return res
496
497     def _vehicle_log_name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None):
498         res = self.name_get(cr, uid, ids, context=context)
499         return dict(res)
500     def on_change_vehicle(self, cr, uid, ids, vehicle_id, context=None):
501
502         if not vehicle_id:
503             return {}
504
505         odometer_unit = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context).odometer_unit
506
507         return {
508             'value' : {
509                 'unit' : odometer_unit,
510             }
511         }
512
513     _columns = {
514         'name' : fields.function(_vehicle_log_name_get_fnc, type="char", string='Name', store=True),
515
516         'date' : fields.date('Purchase Date'),
517         'value' : fields.float('Odometer Value',group_operator="max"),
518         'vehicle_id' : fields.many2one('fleet.vehicle', 'Vehicle', required=True),
519         'unit': fields.related('vehicle_id','odometer_unit',type="char",string="Unit",store=False, readonly=True),
520         
521     }
522     _defaults = {
523         'date' : time.strftime('%Y-%m-%d')
524     }
525
526 ############################
527 ############################
528 #Vehicle.log classes
529 ############################
530 ############################
531
532
533 ############################
534 ############################
535 #Vehicle.log.fuel class
536 ############################
537 ############################
538
539
540 class fleet_vehicle_log_fuel(osv.Model):
541
542     #_inherits = {'fleet.vehicle.odometer': 'odometer_id'}
543     _inherits = {'fleet.vehicle.cost': 'cost_id'}
544
545     def on_change_vehicle(self, cr, uid, ids, vehicle_id, context=None):
546
547         if not vehicle_id:
548             return {}
549
550         odometer_unit = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context).odometer_unit
551
552         return {
553             'value' : {
554                 'odometer_unit' : odometer_unit,
555             }
556         }
557
558     def on_change_liter(self, cr, uid, ids, liter, price_per_liter, amount, context=None):
559
560         if liter > 0 and price_per_liter > 0:
561             return {'value' : {'amount' : float(liter) * float(price_per_liter),}}
562         elif liter > 0 and amount > 0:
563             return {'value' : {'price_per_liter' : float(amount) / float(liter),}}
564         elif price_per_liter > 0 and amount > 0:
565             return {'value' : {'liter' : float(amount) / float(price_per_liter),}}
566         else :
567             return {}
568
569     def on_change_price_per_liter(self, cr, uid, ids, liter, price_per_liter, amount, context=None):
570
571         liter = float(liter);
572         price_per_liter = float(price_per_liter);
573         if price_per_liter > 0 and liter > 0:
574             return {'value' : {'amount' : float(liter) * float(price_per_liter),}}
575         elif price_per_liter > 0 and amount > 0:
576             return {'value' : {'liter' : float(amount) / float(price_per_liter),}}
577         elif liter > 0 and amount > 0:
578             return {'value' : {'price_per_liter' : float(amount) / float(liter),}}
579         else :
580             return {}
581
582     def on_change_amount(self, cr, uid, ids, liter, price_per_liter, amount, context=None):
583
584         if amount > 0 and liter > 0:
585             return {'value' : {'price_per_liter' : float(amount) / float(liter),}}
586         elif amount > 0 and price_per_liter > 0:
587             return {'value' : {'liter' : float(amount) / float(price_per_liter),}}
588         elif liter > 0 and price_per_liter > 0:
589             return {'value' : {'amount' : float(liter) * float(price_per_liter),}}
590         else :
591             return {}
592         
593     def _get_odometer(self, cr, uid, ids, odometer_id, arg, context):
594         res = dict.fromkeys(ids, False)
595         for record in self.browse(cr,uid,ids,context=context):
596             if record.odometer_id:
597                 res[record.id] = record.odometer_id.value
598         return res
599
600     def _set_odometer(self, cr, uid, id, name, value, args=None, context=None):
601         if value:
602             try:
603                 value = float(value)
604             except ValueError:
605                 #_logger.exception(value+' is not a correct odometer value. Please, fill a float for this field')
606                 raise except_orm(_('Error!'), value+' is not a correct odometer value. Please, fill a float for this field')
607                
608             date = self.browse(cr, uid, id, context=context).date
609             if not(date):
610                 date = time.strftime('%Y-%m-%d')
611             vehicle_id = self.browse(cr, uid, id, context=context).vehicle_id
612             data = {'value' : value,'date' : date,'vehicle_id' : vehicle_id.id}
613             odometer_id = self.pool.get('fleet.vehicle.odometer').create(cr, uid, data, context=context)
614             self.write(cr, uid, id, {'odometer_id': odometer_id})
615             return value
616         self.write(cr, uid, id, {'odometer_id': ''})
617         return False
618
619     def _get_default_service_type(self, cr, uid, context):
620         model, model_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'fleet', 'type_service_refueling')
621         return model_id
622
623     _name = 'fleet.vehicle.log.fuel'
624
625     _columns = {
626         #'name' : fields.char('Name',size=64),
627         'liter' : fields.float('Liter'),
628         'price_per_liter' : fields.float('Price Per Liter'),
629         'purchaser_id' : fields.many2one('res.partner', 'Purchaser',domain="['|',('customer','=',True),('employee','=',True)]"),
630         'inv_ref' : fields.char('Invoice Reference', size=64),
631         'vendor_id' : fields.many2one('res.partner', 'Supplier', domain="[('supplier','=',True)]"),
632         'notes' : fields.text('Notes'),
633         'odometer_id' : fields.many2one('fleet.vehicle.odometer', 'Odometer', required=False, help='Odometer measure of the vehicle at the moment of this log'),
634         'odometer' : fields.function(_get_odometer,fnct_inv=_set_odometer,type='char',string='Odometer',store=False),
635         'odometer_unit': fields.related('vehicle_id','odometer_unit',type="char",string="Unit",store=False, readonly=True),
636         'amount': fields.related('cost_id','amount',type="float",string="Amount",store=True, readonly=True),
637     }
638     _defaults = {
639         'purchaser_id': lambda self, cr, uid, ctx: uid,
640         'date' : time.strftime('%Y-%m-%d'),
641         'cost_type': _get_default_service_type,
642     }
643
644 ############################
645 ############################
646 #Vehicle.log.service class
647 ############################
648 ############################
649
650
651 class fleet_vehicle_log_services(osv.Model):
652
653     _inherits = {'fleet.vehicle.cost': 'cost_id'}
654
655     def on_change_vehicle(self, cr, uid, ids, vehicle_id, context=None):
656
657         if not vehicle_id:
658             return {}
659
660         odometer_unit = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context).odometer_unit
661
662         return {
663             'value' : {
664                 'odometer_unit' : odometer_unit,
665             }
666         }
667
668     def _get_odometer(self, cr, uid, ids, odometer_id, arg, context):
669         res = dict.fromkeys(ids, False)
670         for record in self.browse(cr,uid,ids,context=context):
671             if record.odometer_id:
672                 res[record.id] = record.odometer_id.value
673         return res
674
675     def _set_odometer(self, cr, uid, id, name, value, args=None, context=None):
676         if value:
677             try:
678                 value = float(value)
679             except ValueError:
680                 #_logger.exception(value+' is not a correct odometer value. Please, fill a float for this field')
681                 raise except_orm(_('Error!'), value+' is not a correct odometer value. Please, fill a float for this field')
682                
683             date = self.browse(cr, uid, id, context=context).date
684             if not(date):
685                 date = time.strftime('%Y-%m-%d')
686             vehicle_id = self.browse(cr, uid, id, context=context).vehicle_id
687             data = {'value' : value,'date' : date,'vehicle_id' : vehicle_id.id}
688             odometer_id = self.pool.get('fleet.vehicle.odometer').create(cr, uid, data, context=context)
689             self.write(cr, uid, id, {'odometer_id': odometer_id})
690             return value
691         self.write(cr, uid, id, {'odometer_id': ''})
692         return False
693
694     _name = 'fleet.vehicle.log.services'
695     _columns = {
696
697         #'name' : fields.char('Name',size=64),
698
699         'purchaser_id' : fields.many2one('res.partner', 'Purchaser',domain="['|',('customer','=',True),('employee','=',True)]"),
700         'inv_ref' : fields.char('Invoice Reference', size=64),
701         'vendor_id' :fields.many2one('res.partner', 'Supplier', domain="[('supplier','=',True)]"),
702         'notes' : fields.text('Notes'),
703
704         'odometer_id' : fields.many2one('fleet.vehicle.odometer', 'Odometer', required=False, help='Odometer measure of the vehicle at the moment of this log'),
705         'odometer' : fields.function(_get_odometer,fnct_inv=_set_odometer,type='char',string='Odometer Value',store=False),
706         'odometer_unit': fields.related('vehicle_id','odometer_unit',type="char",string="Unit",store=False, readonly=True),
707         'amount': fields.related('cost_id','amount',type="float",string="Amount",store=True, readonly=True),
708     }
709     _defaults = {
710         'purchaser_id': lambda self, cr, uid, ctx: uid,
711         'date' : time.strftime('%Y-%m-%d'),
712     }
713
714 ############################
715 ############################
716 #Vehicle.service.type class
717 ############################
718 ############################
719
720 class fleet_service_type(osv.Model):
721     _name = 'fleet.service.type'
722     _columns = {
723         'name': fields.char('Name', required=True, translate=True),
724         'category': fields.selection([('contract', 'Contract'), ('service', 'Service'),('both', 'Both')], 'Category',required=True, help='Choose wheter the service refer to contracts, vehicle services or both'),
725     }
726     #_defaults = {
727     #    'category': 'both'
728     #}
729
730 ############################
731 ############################
732 #Vehicle.log.contract class
733 ############################
734 ############################
735
736 class fleet_vehicle_log_contract(osv.Model):
737
738     _inherits = {'fleet.vehicle.cost': 'cost_id'}
739     
740     def name_get(self, cr, uid, ids, context=None):
741         if context is None:
742             context = {}
743         if not ids:
744             return []
745         reads = self.browse(cr, uid, ids, context=context)
746         res = []
747         for record in reads:
748             if record.vehicle_id.name:
749                 name = str(record.vehicle_id.name)
750             if record.cost_type.name:
751                 name = name+ ' / '+ str(record.cost_type.name)
752             res.append((record.id, name))
753         return res
754
755     def _vehicle_contract_name_get_fnc(self, cr, uid, ids, prop, unknow_none, context=None):
756         res = self.name_get(cr, uid, ids, context=context)
757         return dict(res)
758
759     def _get_odometer(self, cr, uid, ids, odometer_id, arg, context):
760         res = dict.fromkeys(ids, False)
761         for record in self.browse(cr,uid,ids,context=context):
762             if record.odometer_id:
763                 res[record.id] = record.odometer_id.value
764         return res
765
766     def _set_odometer(self, cr, uid, id, name, value, args=None, context=None):
767         if value:
768             try:
769                 value = float(value)
770             except ValueError:
771                 #_logger.exception(value+' is not a correct odometer value. Please, fill a float for this field')
772                 raise except_orm(_('Error!'), value+' is not a correct odometer value. Please, fill a float for this field')
773                
774             date = self.browse(cr, uid, id, context=context).date
775             if not(date):
776                 date = time.strftime('%Y-%m-%d')
777             vehicle_id = self.browse(cr, uid, id, context=context).vehicle_id
778             data = {'value' : value,'date' : date,'vehicle_id' : vehicle_id.id}
779             odometer_id = self.pool.get('fleet.vehicle.odometer').create(cr, uid, data, context=context)
780             self.write(cr, uid, id, {'odometer_id': odometer_id})
781             return value
782         self.write(cr, uid, id, {'odometer_id': ''})
783         return False
784
785     def on_change_vehicle(self, cr, uid, ids, vehicle_id, context=None):
786
787         if not vehicle_id:
788             return {}
789
790         odometer_unit = self.pool.get('fleet.vehicle').browse(cr, uid, vehicle_id, context=context).odometer_unit
791
792         return {
793             'value' : {
794                 'odometer_unit' : odometer_unit,
795             }
796         }
797
798     def compute_next_year_date(self, strdate):
799         oneyear=datetime.timedelta(days=365)
800         curdate = self.str_to_date(strdate)
801         nextyear=curdate+oneyear#int(strdate[:4])+1
802         return str(nextyear)#+strdate[4:]
803
804     def on_change_start_date(self, cr, uid, ids, strdate, context=None):
805         if (strdate):
806            
807             return {'value' : {'expiration_date' : self.compute_next_year_date(strdate),}}
808         else:
809             return {}
810
811     def str_to_date(self,strdate):
812         return datetime.datetime(int(strdate[:4]),int(strdate[5:7]),int(strdate[8:]))
813
814     def get_warning_date(self,cr,uid,ids,prop,unknow_none,context=None):
815         if context is None:
816             context={}
817         if not ids:
818             return dict([])
819         reads = self.browse(cr,uid,ids,context=context)
820         res=[]
821         for record in reads:
822             #if (record.reminder==True):
823             if (record.expiration_date and record.state=='open'):
824                 today=self.str_to_date(time.strftime('%Y-%m-%d'))
825                 renew_date = self.str_to_date(record.expiration_date)
826                 diff_time=int((renew_date-today).days)
827                 if (diff_time<=0):
828                     res.append((record.id,0))
829                 else:
830                     res.append((record.id,diff_time))
831             else:
832                 res.append((record.id,-1))
833             #else:
834             #    res.append((record.id,-1))
835         return dict(res)
836
837     _name = 'fleet.vehicle.log.contract'
838     _order='state,expiration_date'
839     _columns = {
840         'name' : fields.function(_vehicle_contract_name_get_fnc, type="text", string='Name', store=True),
841         #'name' : fields.char('Name',size=64),
842
843         #'cost_type': fields.many2one('fleet.service.type', 'Service type', required=False, help='Service type purchased with this cost', domain="[('category','=','contract')]"),
844
845         'start_date' : fields.date('Start Date', required=False, help='Date when the coverage of the contract begins'),
846         'expiration_date' : fields.date('Expiration Date', required=False, help='Date when the coverage of the contract expirates (by default, one year after begin date)'),
847         'warning_date' : fields.function(get_warning_date,type='integer',string='Warning Date',store=False),
848
849         'insurer_id' :fields.many2one('res.partner', 'Insurer', domain="[('supplier','=',True)]"),
850         'purchaser_id' : fields.many2one('res.partner', 'Contractor',domain="['|',('customer','=',True),('employee','=',True)]",help='Person to which the contract is signed for'),
851         'ins_ref' : fields.char('Contract Reference', size=64),
852         'state' : fields.selection([('open', 'In Progress'), ('closed', 'Terminated')], 'Status', readonly=True, help='Choose wheter the contract is still valid or not'),
853         #'reminder' : fields.boolean('Renewal Reminder', help="Warn the user a few days before the expiration date of this contract"),
854         'notes' : fields.text('Terms and Conditions', help='Write here all supplementary informations relative to this contract'),
855         'odometer_id' : fields.many2one('fleet.vehicle.odometer', 'Odometer', required=False, help='Odometer measure of the vehicle at the moment of this log'),
856         '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'),
857         'odometer_unit': fields.related('vehicle_id','odometer_unit',type="char",string="Unit",store=False, readonly=True),
858     }
859     _defaults = {
860         'purchaser_id': lambda self, cr, uid, ctx: uid,
861         'date' : time.strftime('%Y-%m-%d'),
862         'start_date' : time.strftime('%Y-%m-%d'),
863         'state':'open',
864         #'expiration_date' : self.compute_next_year_date(time.strftime('%Y-%m-%d')),
865     
866     }
867
868     def copy(self, cr, uid, id, default=None, context=None):
869         default = default or {}
870         current_object = self.browse(cr,uid,id,context)
871         default['start_date'] = time.strftime('%Y-%m-%d')
872         default['expiration_date'] = self.compute_next_year_date(time.strftime('%Y-%m-%d'))
873         #default['name'] = current_object.name
874         default['ins_ref'] = ''
875         default['state'] = 'open'
876         default['notes'] = ''
877         default['date'] = time.strftime('%Y-%m-%d')
878
879         #default['odometer'] = current_object.odometer
880         #default['odometer_unit'] = current_object.odometer_unit
881         return super(fleet_vehicle_log_contract, self).copy(cr, uid, id, default, context=context)
882
883     def contract_close(self, cr, uid, ids, *args):
884         self.write(cr, uid, ids, {'state': 'closed'})
885         return True
886
887     def contract_open(self, cr, uid, ids, *args):
888         self.write(cr, uid, ids, {'state': 'open'})
889         return True
890
891
892 ############################
893 ############################
894 #Vehicle.log.contract.state class
895 ############################
896 ############################
897
898 class fleet_contract_state(osv.Model):
899     _name = 'fleet.contract.state'
900     _columns = {
901         'name':fields.char('Contract Status',size=32),
902     }