diff options
| author | Baris Kocak <bko@odoo.com> | 2017-06-26 17:34:16 +0200 |
|---|---|---|
| committer | Christophe Monniez <moc@odoo.com> | 2017-08-07 14:05:16 +0200 |
| commit | bbcebcc12360eb7edca75ccb65180a954fcd6120 (patch) | |
| tree | 3c56e3a2d19c5010a6dadfbdf8899454d81416c5 /addons | |
| parent | b79c2a773c2b5a6d7beaf5db41bc1287a4b6e5a4 (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.xml | 2 | ||||
| -rw-r--r-- | addons/fleet/models/fleet_vehicle.py | 19 | ||||
| -rw-r--r-- | addons/fleet/models/fleet_vehicle_cost.py | 55 | ||||
| -rw-r--r-- | addons/fleet/views/fleet_vehicle_cost_views.xml | 19 | ||||
| -rw-r--r-- | addons/fleet/views/fleet_vehicle_model_views.xml | 4 | ||||
| -rw-r--r-- | addons/fleet/views/fleet_vehicle_views.xml | 56 |
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> |
