summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorBaris Kocak <bko@odoo.com>2017-06-26 17:34:16 +0200
committerChristophe Monniez <moc@odoo.com>2017-08-07 14:05:16 +0200
commitbbcebcc12360eb7edca75ccb65180a954fcd6120 (patch)
tree3c56e3a2d19c5010a6dadfbdf8899454d81416c5 /addons
parentb79c2a773c2b5a6d7beaf5db41bc1287a4b6e5a4 (diff)
[IMP] fleet: Improve dashboard, vehicule form and contracts
Purpose: Improve fleet for a better usability Dashboard: - Replace 'leasing' button by a contract status icon in kanban tiles - Add a link to contract - Link to vehicule form when clicking on the tile Vehicle form: - Track contract status in a chatter - Add a model_year Contracts: - Imporve the states names - Split service types in two list views service/contracts - Execute a cron once a day to upgrade contract status - Add a new contract status is introduced 'Expiring Soon' to help spot contracts that will expire until 15 days with a filter. - Add a 'group by vehicle' to improve list usability Fuel logs view: Add an an odometer column
Diffstat (limited to 'addons')
-rw-r--r--addons/fleet/data/fleet_data.xml2
-rw-r--r--addons/fleet/models/fleet_vehicle.py19
-rw-r--r--addons/fleet/models/fleet_vehicle_cost.py55
-rw-r--r--addons/fleet/views/fleet_vehicle_cost_views.xml19
-rw-r--r--addons/fleet/views/fleet_vehicle_model_views.xml4
-rw-r--r--addons/fleet/views/fleet_vehicle_views.xml56
6 files changed, 101 insertions, 54 deletions
diff --git a/addons/fleet/data/fleet_data.xml b/addons/fleet/data/fleet_data.xml
index 3ba311c878e..bd7b51bf00e 100644
--- a/addons/fleet/data/fleet_data.xml
+++ b/addons/fleet/data/fleet_data.xml
@@ -380,7 +380,7 @@
<record id="type_contract_repairing" model="fleet.service.type">
<field name="name">Repairing</field>
- <field name="category">both</field>
+ <field name="category">service</field>
</record>
<record id="type_service_refueling" model="fleet.service.type">
diff --git a/addons/fleet/models/fleet_vehicle.py b/addons/fleet/models/fleet_vehicle.py
index face994b75e..fd9bffd1433 100644
--- a/addons/fleet/models/fleet_vehicle.py
+++ b/addons/fleet/models/fleet_vehicle.py
@@ -17,7 +17,7 @@ class FleetVehicle(models.Model):
return state and state.id or False
name = fields.Char(compute="_compute_vehicle_name", store=True)
- active = fields.Boolean(default=True)
+ active = fields.Boolean('Active', default=True, track_visibility="onchange")
company_id = fields.Many2one('res.company', 'Company')
license_plate = fields.Char(required=True, help='License plate number of the vehicle (i = plate number for a car)')
vin_sn = fields.Char('Chassis Number', help='Unique number written on the vehicle motor (VIN/SN number)', copy=False)
@@ -33,9 +33,11 @@ class FleetVehicle(models.Model):
odometer_count = fields.Integer(compute="_compute_count_all", string='Odometer')
acquisition_date = fields.Date('Immatriculation Date', required=False, help='Date when the vehicle has been immatriculated')
color = fields.Char(help='Color of the vehicle')
- state_id = fields.Many2one('fleet.vehicle.state', 'State', default=_get_default_state, help='Current state of the vehicle', ondelete="set null")
+ state_id = fields.Many2one('fleet.vehicle.state', 'State', default=_get_default_state,
+ help='Current state of the vehicle', ondelete="set null")
location = fields.Char(help='Location of the vehicle (garage, ...)')
seats = fields.Integer('Seats Number', help='Number of seats of the vehicle')
+ model_year = fields.Char('Model Year',help='Year of the model')
doors = fields.Integer('Doors Number', help='Number of doors of the vehicle', default=5)
tag_ids = fields.Many2many('fleet.vehicle.tag', 'fleet_vehicle_vehicle_tag_rel', 'vehicle_tag_id', 'tag_id', 'Tags', copy=False)
odometer = fields.Float(compute='_get_odometer', inverse='_set_odometer', string='Last Odometer',
@@ -103,7 +105,7 @@ class FleetVehicle(models.Model):
record.odometer_count = Odometer.search_count([('vehicle_id', '=', record.id)])
record.fuel_logs_count = LogFuel.search_count([('vehicle_id', '=', record.id)])
record.service_count = LogService.search_count([('vehicle_id', '=', record.id)])
- record.contract_count = LogContract.search_count([('vehicle_id', '=', record.id), ('state', '=', 'open')])
+ record.contract_count = LogContract.search_count([('vehicle_id', '=', record.id),('state','!=','closed')])
record.cost_count = Cost.search_count([('vehicle_id', '=', record.id), ('parent_id', '=', False)])
@api.depends('log_contracts')
@@ -114,7 +116,7 @@ class FleetVehicle(models.Model):
total = 0
name = ''
for element in record.log_contracts:
- if element.state in ('open', 'toclose') and element.expiration_date:
+ if element.state in ('open', 'expired') and element.expiration_date:
current_date_str = fields.Date.context_today(record)
due_time_str = element.expiration_date
current_date = fields.Date.from_string(current_date_str)
@@ -129,7 +131,7 @@ class FleetVehicle(models.Model):
if overdue or due_soon:
log_contract = self.env['fleet.vehicle.log.contract'].search([
('vehicle_id', '=', record.id),
- ('state', 'in', ('open', 'toclose'))
+ ('state', 'in', ('open', 'expired'))
], limit=1, order='expiration_date asc')
if log_contract:
# we display only the name of the oldest overdue/due soon contract
@@ -157,7 +159,7 @@ class FleetVehicle(models.Model):
WHERE contract.expiration_date IS NOT NULL
AND contract.expiration_date > %s
AND contract.expiration_date < %s
- AND contract.state IN ('open', 'toclose')
+ AND contract.state IN ('open', 'expired')
GROUP BY cost.vehicle_id""", (today, limit_date))
res_ids = [x[0] for x in self.env.cr.fetchall()]
res.append(('id', search_operator, res_ids))
@@ -177,7 +179,7 @@ class FleetVehicle(models.Model):
LEFT JOIN fleet_vehicle_log_contract contract ON contract.cost_id = cost.id
WHERE contract.expiration_date IS NOT NULL
AND contract.expiration_date < %s
- AND contract.state IN ('open', 'toclose')
+ AND contract.state IN ('open', 'expired')
GROUP BY cost.vehicle_id ''', (today,))
res_ids = [x[0] for x in self.env.cr.fetchall()]
res.append(('id', search_operator, res_ids))
@@ -307,6 +309,5 @@ class FleetServiceType(models.Model):
name = fields.Char(required=True, translate=True)
category = fields.Selection([
('contract', 'Contract'),
- ('service', 'Service'),
- ('both', 'Both')
+ ('service', 'Service')
], 'Category', required=True, help='Choose wheter the service refer to contracts, vehicle services or both')
diff --git a/addons/fleet/models/fleet_vehicle_cost.py b/addons/fleet/models/fleet_vehicle_cost.py
index 12c6a7d7f2e..2c347c09783 100644
--- a/addons/fleet/models/fleet_vehicle_cost.py
+++ b/addons/fleet/models/fleet_vehicle_cost.py
@@ -65,14 +65,15 @@ class FleetVehicleCost(models.Model):
data['cost_subtype_id'] = contract.cost_subtype_id.id
data['cost_type'] = contract.cost_type
if 'odometer' in data and not data['odometer']:
- # if received value for odometer is 0, then remove it from the data as it would result to the creation of a
+ # if received value for odometer is 0, then remove it from the
+ # data as it would result to the creation of a
# odometer log with 0, which is to be avoided
- del(data['odometer'])
+ del data['odometer']
return super(FleetVehicleCost, self).create(data)
class FleetVehicleLogContract(models.Model):
-
+ _inherit = ['mail.thread']
_inherits = {'fleet.vehicle.cost': 'cost_id'}
_name = 'fleet.vehicle.log.contract'
_description = 'Contract information on a vehicle'
@@ -96,8 +97,10 @@ class FleetVehicleLogContract(models.Model):
name = fields.Text(compute='_compute_contract_name', store=True)
active = fields.Boolean(default=True)
- start_date = fields.Date('Contract Start Date', default=fields.Date.context_today, help='Date when the coverage of the contract begins')
- expiration_date = fields.Date('Contract Expiration Date', default=lambda self: self.compute_next_year_date(fields.Date.context_today(self)),
+ start_date = fields.Date('Contract Start Date', default=fields.Date.context_today,
+ help='Date when the coverage of the contract begins')
+ expiration_date = fields.Date('Contract Expiration Date', default=lambda self:
+ self.compute_next_year_date(fields.Date.context_today(self)),
help='Date when the coverage of the contract expirates (by default, one year after begin date)')
days_left = fields.Integer(compute='_compute_days_left', string='Warning Date')
insurer_id = fields.Many2one('res.partner', 'Vendor')
@@ -105,15 +108,19 @@ class FleetVehicleLogContract(models.Model):
help='Person to which the contract is signed for')
ins_ref = fields.Char('Contract Reference', size=64, copy=False)
state = fields.Selection([
+ ('futur', 'Incoming'),
('open', 'In Progress'),
- ('toclose', 'To Close'),
- ('closed', 'Terminated')
- ], 'Status', default='open', readonly=True, help='Choose wheter the contract is still valid or not',
- copy=False)
+ ('expired', 'Expired'),
+ ('diesoon', 'Expiring Soon'),
+ ('closed', 'Closed')
+ ], 'Status', default='open', readonly=True,
+ help='Choose wheter the contract is still valid or not',
+ track_visibility="onchange",
+ copy=False)
notes = fields.Text('Terms and Conditions', help='Write here all supplementary information relative to this contract', copy=False)
- cost_generated = fields.Float('Recurring Cost Amount',
+ 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")
+ "If the cost frequency is set to unique, the cost will be logged at the start date")
cost_frequency = fields.Selection([
('no', 'No'),
('daily', 'Daily'),
@@ -128,7 +135,8 @@ class FleetVehicleLogContract(models.Model):
# (1) to address fields from inherited table
# (2) fields that aren't stored in database
cost_amount = fields.Float(related='cost_id.amount', string='Amount', store=True)
- odometer = fields.Float(string='Odometer at creation', help='Odometer measure of the vehicle at the moment of the contract creation')
+ odometer = fields.Float(string='Odometer at creation',
+ help='Odometer measure of the vehicle at the moment of the contract creation')
@api.depends('vehicle_id', 'cost_subtype_id', 'date')
def _compute_contract_name(self):
@@ -148,7 +156,7 @@ class FleetVehicleLogContract(models.Model):
otherwise return the number of days before the contract expires
"""
for record in self:
- if (record.expiration_date and (record.state == 'open' or record.state == 'toclose')):
+ if (record.expiration_date and (record.state == 'open' or record.state == 'expired')):
today = fields.Date.from_string(fields.Date.today())
renew_date = fields.Date.from_string(record.expiration_date)
diff_time = (renew_date - today).days
@@ -253,11 +261,11 @@ class FleetVehicleLogContract(models.Model):
def scheduler_manage_contract_expiration(self):
# This method is called by a cron task
# It manages the state of a contract, possibly by posting a message on the vehicle concerned and updating its status
- date_today = fields.Date.from_string(fields.Date.context_today(self))
- limit_date = fields.Date.to_string(date_today + relativedelta(days=+15))
- contracts = self.search([('state', '=', 'open'), ('expiration_date', '<', limit_date)])
+ date_today = fields.Date.from_string(fields.Date.today())
+ in_fifteen_days = fields.Date.to_string(date_today + relativedelta(days=+15))
+ nearly_expired_contracts = self.search([('state', '=', 'open'), ('expiration_date', '<', in_fifteen_days)])
res = {}
- for contract in contracts:
+ for contract in nearly_expired_contracts:
if contract.vehicle_id.id in res:
res[contract.vehicle_id.id] += 1
else:
@@ -265,8 +273,17 @@ class FleetVehicleLogContract(models.Model):
Vehicle = self.env['fleet.vehicle']
for vehicle, value in pycompat.items(res):
- Vehicle.browse(vehicle).message_post(body=_('%s contract(s) need(s) to be renewed and/or closed!') % value)
- return contracts.write({'state': 'toclose'})
+ Vehicle.browse(vehicle).message_post(body=_('%s contract(s) will expire soon and should be renewed and/or closed!') % value)
+ nearly_expired_contracts.write({'state': 'diesoon'})
+
+ expired_contracts = self.search([('state', '!=', 'expired'), ('expiration_date', '<',fields.Date.today() )])
+ expired_contracts.write({'state': 'expired'})
+
+ futur_contracts = self.search([('state', 'not in', ['futur', 'closed']), ('start_date', '>', fields.Date.today())])
+ futur_contracts.write({'state': 'futur'})
+
+ now_running_contracts = self.search([('state', '=', 'futur'), ('start_date', '<=', fields.Date.today())])
+ now_running_contracts.write({'state': 'open'})
@api.model
def run_scheduler(self):
diff --git a/addons/fleet/views/fleet_vehicle_cost_views.xml b/addons/fleet/views/fleet_vehicle_cost_views.xml
index 51dceaf016f..9b9d8b360b4 100644
--- a/addons/fleet/views/fleet_vehicle_cost_views.xml
+++ b/addons/fleet/views/fleet_vehicle_cost_views.xml
@@ -148,9 +148,8 @@
<field name="arch" type="xml">
<form string="Contract logs">
<header>
- <button modifiers="{'invisible': [['state', '=', 'closed']]}" name="contract_close" states="open" type="object" class="oe_highlight" string="Terminate Contract" groups="fleet.fleet_group_manager"/>
- <button modifiers="{'invisible': [['state', '=', 'closed']]}" name="contract_close" states="toclose" type="object" class="oe_highlight" string="Terminate Contract" groups="fleet.fleet_group_manager"/>
- <button modifiers="{'invisible': [['state', 'not in', ['closed']]]}" name="contract_open" states="closed" type="object" class="oe_highlight" string="Set Contract In Progress" groups="fleet.fleet_group_manager"/>
+ <button name="contract_close" states="open,expired,future" type="object" class="oe_highlight" string="Close Contract" groups="fleet.fleet_group_manager"/>
+ <button name="contract_open" states="closed" type="object" class="oe_highlight" string="Set Contract In Progress" groups="fleet.fleet_group_manager"/>
<button class="oe_highlight" name="act_renew_contract" type="object" string="Renew Contract" help="Create a new contract automatically with all the same informations except for the date that will start at the end of current contract" groups="fleet.fleet_group_manager"/>
<field name="state" widget="statusbar" />
</header>
@@ -225,6 +224,10 @@
<field name="notes" nolabel="1" placeholder="Write here all other information relative to this contract" />
</group>
</sheet>
+ <div class="oe_chatter">
+ <field name="message_follower_ids" widget="mail_followers"/>
+ <field name="message_ids" widget="mail_thread" options='{"thread_level": 1}'/>
+ </div>
</form>
</field>
</record>
@@ -238,7 +241,6 @@
view_type="form"
/>
-
<record id='fleet_vehicle_log_contract_view_tree' model='ir.ui.view'>
<field name="name">fleet.vehicle.log.contract.tree</field>
<field name="model">fleet.vehicle.log.contract</field>
@@ -278,6 +280,11 @@
<search string="Vehicles Contracts">
<filter string="Archived" name="inactive" domain="[('active','=',False)]"/>
<filter string="In Progress" name="open" domain="[('state', '=', 'open')]"/>
+ <filter string="Expired" name="expired" domain="[('state', '=', 'expired')]"/>
+ <filter string="Expiring Soon" name="expire_soon" domain="[('state', '=', 'diesoon')]"/>
+ <group expand="0" string="Group By">
+ <filter string="Vehicle" name="vehicle" context="{'group_by':'vehicle_id'}"/>
+ </group>
</search>
</field>
</record>
@@ -348,11 +355,11 @@
<tree string="Fuel Logs">
<field name="date" />
<field name="vehicle_id" />
- <field name="odometer" invisible="1"/>
- <field name="odometer_unit" invisible="1"/>
<field name="purchaser_id" />
<field name="inv_ref" invisible="1"/>
<field name="vendor_id" invisible="1"/>
+ <field name="odometer" />
+ <field name="odometer_unit" />
<field name="liter" />
<field name="price_per_liter" invisible="1"/>
<field name="amount" sum="Price"/>
diff --git a/addons/fleet/views/fleet_vehicle_model_views.xml b/addons/fleet/views/fleet_vehicle_model_views.xml
index 20d66fd232b..579fe921518 100644
--- a/addons/fleet/views/fleet_vehicle_model_views.xml
+++ b/addons/fleet/views/fleet_vehicle_model_views.xml
@@ -84,7 +84,7 @@
<menuitem name="Fleet" id="menu_root" sequence="115" groups="fleet_group_user" web_icon="fleet,static/description/icon.png"/>
<menuitem name="Configuration" parent="menu_root" id="fleet_configuration" sequence="100" groups="fleet_group_manager"/>
- <menuitem action="fleet_vehicle_model_action" parent="fleet_configuration" id="fleet_vehicle_model_menu"/>
+ <menuitem action="fleet_vehicle_model_action" parent="fleet_configuration" id="fleet_vehicle_model_menu" sequence="1"/>
<record id='fleet_vehicle_model_brand_view_tree' model='ir.ui.view'>
<field name="name">fleet.vehicle.model.brand.tree</field>
@@ -154,5 +154,5 @@
</field>
</record>
- <menuitem action="fleet_vehicle_model_brand_action" parent="fleet_configuration" id="fleet_vehicle_model_brand_menu"/>
+ <menuitem action="fleet_vehicle_model_brand_action" parent="fleet_configuration" id="fleet_vehicle_model_brand_menu" sequence="2"/>
</odoo>
diff --git a/addons/fleet/views/fleet_vehicle_views.xml b/addons/fleet/views/fleet_vehicle_views.xml
index 4355823971e..432d3a17eae 100644
--- a/addons/fleet/views/fleet_vehicle_views.xml
+++ b/addons/fleet/views/fleet_vehicle_views.xml
@@ -73,6 +73,7 @@
<field name="driver_id" />
<field name="location" />
<field name="vin_sn" />
+ <field name="model_year"/>
<field name="company_id" groups="base.group_multi_company"/>
</group>
<group >
@@ -175,6 +176,7 @@
<field name="contract_renewal_overdue" />
<field name="contract_renewal_name" />
<field name="contract_renewal_total" />
+ <field name="contract_count" />
<templates>
<t t-name="kanban-box">
@@ -197,14 +199,20 @@
<t t-if="record.location.raw_value"><field name="location"/></t>
</li>
</ul>
- <div class="o_kanban_button">
- <a t-if="record.contract_renewal_due_soon.raw_value and !record.contract_renewal_overdue.raw_value" data-type="object" data-name="return_action_to_open" href="#" class="oe_kanban_action btn btn-sm btn-warning" data-context='{"xml_id":"fleet_vehicle_log_contract_action"}'>
- <field name="contract_renewal_name"/> <t t-if="record.contract_renewal_total.raw_value > 0"> and <field name="contract_renewal_total" /> other(s)</t>
- </a>
- <a t-if="record.contract_renewal_overdue.raw_value" data-type="object" data-name="return_action_to_open" href="#" class="oe_kanban_action btn btn-sm btn-danger" data-context='{"xml_id":"fleet_vehicle_log_contract_action"}'>
- <field name="contract_renewal_name"/> <t t-if="record.contract_renewal_total.raw_value > 0"> and <field name="contract_renewal_total" /> other(s)</t>
- </a>
- </div>
+ </div>
+ <div class="o_kanban_button">
+ <a t-if="record.contract_count.raw_value>0" data-type="object"
+ data-name="return_action_to_open" href="#" class="oe_kanban_action oe_kanban_action_a"
+ data-context='{"xml_id":"fleet_vehicle_log_contract_action","search_default_open": 1}'>
+ <field name="contract_count"/>
+ Contract(s)
+ <span t-if="record.contract_renewal_due_soon.raw_value and !record.contract_renewal_overdue.raw_value"
+ class="fa fa-exclamation-triangle" t-att-style="'color:orange'">
+ </span>
+ <span t-if="record.contract_renewal_overdue.raw_value"
+ class="fa fa-exclamation-triangle" t-att-style="'color:red;'">
+ </span>
+ </a>
</div>
</div>
</t>
@@ -244,10 +252,8 @@
<sheet>
<group>
<field name="vehicle_id"/>
- <div>
- <field name="value" class="oe_inline"/>
- <field name="unit" class="oe_inline"/>
- </div>
+ <field name="value" class="oe_inline"/>
+ <field name="unit" class="oe_inline"/>
<field name="date" />
</group>
</sheet>
@@ -300,7 +306,7 @@
<field name="name">Vehicles Odometer</field>
<field name="res_model">fleet.vehicle.odometer</field>
<field name="view_type">form</field>
- <field name="view_mode">tree,graph</field>
+ <field name="view_mode">tree,form,graph</field>
<field name="context">{"search_default_groupby_vehicle" : True}</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
@@ -322,7 +328,7 @@
<field name="arch" type="xml">
<tree string="Service types" editable="top">
<field name="name" />
- <field name="category"/>
+ <field name="category" invisible="1"/>
</tree>
</field>
</record>
@@ -332,6 +338,8 @@
<field name="res_model">fleet.service.type</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
+ <field name="domain">[('category','=','service')]</field>
+ <field name="context">{'default_category':'service'}</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a new type of service.
@@ -340,17 +348,31 @@
</p>
</field>
</record>
+ <menuitem action="fleet_vehicle_service_types_action" parent="fleet_configuration" id="fleet_vehicle_service_types_menu" sequence="3"/>
+
+ <record id='fleet_vehicle_contract_types_action' model='ir.actions.act_window'>
+ <field name="name">Contract Types</field>
+ <field name="res_model">fleet.service.type</field>
+ <field name="view_type">form</field>
+ <field name="view_mode">tree,form</field>
+ <field name="domain">[('category','=','contract')]</field>
+ <field name="context">{'default_category':'contract'}</field>
+ <field name="help" type="html">
+ <p class="oe_view_nocontent_create">
+ Click to create a new type of contract.
+ </p>
+ </field>
+ </record>
+ <menuitem action="fleet_vehicle_contract_types_action" parent="fleet_configuration" id="fleet_vehicle_contract_types_menu" sequence="4"/>
- <menuitem action="fleet_vehicle_service_types_action" parent="fleet_configuration" id="fleet_vehicle_service_types_menu"/>
<record id='fleet_vehicle_state_view_tree' model='ir.ui.view'>
<field name="name">fleet.vehicle.state.tree</field>
<field name="model">fleet.vehicle.state</field>
<field name="arch" type="xml">
<tree string="State" editable="bottom">
- <field name="sequence" widget="handler"/>
+ <field name="sequence" widget="handle"/>
<field name="name" />
-
</tree>
</field>
</record>