diff options
Diffstat (limited to 'addons/fleet/models/fleet_vehicle_cost.py')
| -rw-r--r-- | addons/fleet/models/fleet_vehicle_cost.py | 315 |
1 files changed, 60 insertions, 255 deletions
diff --git a/addons/fleet/models/fleet_vehicle_cost.py b/addons/fleet/models/fleet_vehicle_cost.py index 69c55dce09a..ab073a6a877 100644 --- a/addons/fleet/models/fleet_vehicle_cost.py +++ b/addons/fleet/models/fleet_vehicle_cost.py @@ -6,78 +6,8 @@ from odoo.exceptions import UserError from dateutil.relativedelta import relativedelta - -class FleetVehicleCost(models.Model): - _name = 'fleet.vehicle.cost' - _description = 'Cost related to a vehicle' - _order = 'date desc, vehicle_id asc' - - name = fields.Char(related='vehicle_id.name', string='Name', store=True, readonly=False) - vehicle_id = fields.Many2one('fleet.vehicle', 'Vehicle', required=True, help='Vehicle concerned by this log') - cost_subtype_id = fields.Many2one('fleet.service.type', 'Type', help='Cost type purchased with this cost') - amount = fields.Float('Total Price') - cost_type = fields.Selection([ - ('contract', 'Contract'), - ('services', 'Services'), - ('fuel', 'Fuel'), - ('other', 'Other') - ], 'Category of the cost', default="other", help='For internal purpose only', required=True) - parent_id = fields.Many2one('fleet.vehicle.cost', 'Parent', help='Parent cost to this current cost') - cost_ids = fields.One2many('fleet.vehicle.cost', 'parent_id', 'Included Services', copy=True) - odometer_id = fields.Many2one('fleet.vehicle.odometer', 'Odometer', help='Odometer measure of the vehicle at the moment of this log') - odometer = fields.Float(compute="_get_odometer", inverse='_set_odometer', string='Odometer Value', - help='Odometer measure of the vehicle at the moment of this log') - odometer_unit = fields.Selection(related='vehicle_id.odometer_unit', string="Unit", readonly=True) - date = fields.Date(help='Date when the cost has been executed') - contract_id = fields.Many2one('fleet.vehicle.log.contract', 'Contract', help='Contract attached to this cost') - auto_generated = fields.Boolean('Automatically Generated', readonly=True) - description = fields.Char("Cost Description") - company_id = fields.Many2one('res.company', 'Company', default=lambda self: self.env.company) - currency_id = fields.Many2one('res.currency', related='company_id.currency_id') - - def _get_odometer(self): - self.odometer = 0.0 - for record in self: - record.odometer = False - if record.odometer_id: - record.odometer = record.odometer_id.value - - def _set_odometer(self): - for record in self: - if not record.odometer: - raise UserError(_('Emptying the odometer value of a vehicle is not allowed.')) - odometer = self.env['fleet.vehicle.odometer'].create({ - 'value': record.odometer, - 'date': record.date or fields.Date.context_today(record), - 'vehicle_id': record.vehicle_id.id - }) - self.odometer_id = odometer - - @api.model_create_multi - def create(self, vals_list): - for data in vals_list: - # make sure that the data are consistent with values of parent and contract records given - if 'parent_id' in data and data['parent_id']: - parent = self.browse(data['parent_id']) - data['vehicle_id'] = parent.vehicle_id.id - data['date'] = parent.date - data['cost_type'] = parent.cost_type - if 'contract_id' in data and data['contract_id']: - contract = self.env['fleet.vehicle.log.contract'].browse(data['contract_id']) - data['vehicle_id'] = contract.vehicle_id.id - 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 - # odometer log with 0, which is to be avoided - del data['odometer'] - return super(FleetVehicleCost, self).create(vals_list) - - class FleetVehicleLogContract(models.Model): _inherit = ['mail.thread', 'mail.activity.mixin'] - _inherits = {'fleet.vehicle.cost': 'cost_id'} _name = 'fleet.vehicle.log.contract' _description = 'Contract information on a vehicle' _order = 'state desc,expiration_date' @@ -87,18 +17,13 @@ class FleetVehicleLogContract(models.Model): start_date = fields.Date.from_string(strdate) return fields.Date.to_string(start_date + oneyear) - @api.model - def default_get(self, default_fields): - res = super(FleetVehicleLogContract, self).default_get(default_fields) - contract = self.env.ref('fleet.type_contract_leasing', raise_if_not_found=False) - res.update({ - 'date': fields.Date.context_today(self), - 'cost_subtype_id': contract and contract.id or False, - 'cost_type': 'contract' - }) - return res - - name = fields.Text(compute='_compute_contract_name', store=True) + vehicle_id = fields.Many2one('fleet.vehicle', 'Vehicle', default=1, required=True, help='Vehicle concerned by this log') + cost_subtype_id = fields.Many2one('fleet.service.type', 'Type', help='Cost type purchased with this cost', domain=[('category', '=', 'contract')]) + amount = fields.Float('Cost') + date = fields.Date(help='Date when the cost has been executed') + company_id = fields.Many2one('res.company', 'Company', default=lambda self: self.env.company) + currency_id = fields.Many2one('res.currency', related='company_id.currency_id') + name = fields.Char(string='Name', compute='_compute_contract_name', store=True) active = fields.Boolean(default=True) user_id = fields.Many2one('res.users', 'Responsible', default=lambda self: self.env.user, index=True) start_date = fields.Date('Contract Start Date', default=fields.Date.context_today, @@ -108,13 +33,11 @@ class FleetVehicleLogContract(models.Model): 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') - purchaser_id = fields.Many2one('res.partner', 'Driver', default=lambda self: self.env.user.partner_id.id, - help='Person to which the contract is signed for') - ins_ref = fields.Char('Contract Reference', size=64, copy=False) + purchaser_id = fields.Many2one(related='vehicle_id.driver_id', string='Driver') + ins_ref = fields.Char('Reference', size=64, copy=False) state = fields.Selection([ ('futur', 'Incoming'), ('open', 'In Progress'), - ('diesoon', 'Expiring Soon'), ('expired', 'Expired'), ('closed', 'Closed') ], 'Status', default='open', readonly=True, @@ -122,34 +45,22 @@ class FleetVehicleLogContract(models.Model): tracking=True, 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', tracking=True, - 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") + cost_generated = fields.Float('Recurring Cost') cost_frequency = fields.Selection([ ('no', 'No'), ('daily', 'Daily'), ('weekly', 'Weekly'), ('monthly', 'Monthly'), ('yearly', 'Yearly') - ], 'Recurring Cost Frequency', default='no', help='Frequency of the recuring cost', required=True) - generated_cost_ids = fields.One2many('fleet.vehicle.cost', 'contract_id', 'Generated Costs') - sum_cost = fields.Float(compute='_compute_sum_cost', string='Indicative Costs Total') - cost_id = fields.Many2one('fleet.vehicle.cost', 'Cost', required=True, ondelete='cascade') - # we need to keep this field as a related with store=True because the graph view doesn't support - # (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, readonly=False) - odometer = fields.Float(string='Creation Contract Odometer', - help='Odometer measure of the vehicle at the moment of the contract creation') + ], 'Recurring Cost Frequency', default='monthly', help='Frequency of the recuring cost', required=True) + service_ids = fields.Many2many('fleet.service.type', string="Included Services") - @api.depends('vehicle_id', 'cost_subtype_id', 'date') + @api.depends('vehicle_id', 'cost_subtype_id') def _compute_contract_name(self): for record in self: name = record.vehicle_id.name if record.cost_subtype_id.name: - name += ' / ' + record.cost_subtype_id.name - if record.date: - name += ' / ' + str(record.date) + name = record.cost_subtype_id.name + ' ' + name record.name = name @api.depends('expiration_date', 'state') @@ -160,7 +71,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 in ['open', 'diesoon', 'expired']: + if record.expiration_date and record.state in ['open', 'expired']: today = fields.Date.from_string(fields.Date.today()) renew_date = fields.Date.from_string(record.expiration_date) diff_time = (renew_date - today).days @@ -168,16 +79,6 @@ class FleetVehicleLogContract(models.Model): else: record.days_left = -1 - @api.depends('cost_ids.amount') - def _compute_sum_cost(self): - for contract in self: - contract.sum_cost = sum(contract.cost_ids.mapped('amount')) - - @api.onchange('vehicle_id') - def _onchange_vehicle(self): - if self.vehicle_id: - self.odometer_unit = self.vehicle_id.odometer_unit - def write(self, vals): res = super(FleetVehicleLogContract, self).write(vals) if vals.get('expiration_date') or vals.get('user_id'): @@ -188,80 +89,14 @@ class FleetVehicleLogContract(models.Model): for record in self: record.state = 'closed' + def contract_draft(self): + for record in self: + record.state = 'futur' + def contract_open(self): for record in self: record.state = 'open' - def act_renew_contract(self): - assert len(self.ids) == 1, "This operation should only be done for 1 single contract at a time, as it it suppose to open a window as result" - for element in self: - # compute end date - startdate = fields.Date.from_string(element.start_date) - enddate = fields.Date.from_string(element.expiration_date) - diffdate = (enddate - startdate) - default = { - 'date': fields.Date.context_today(self), - 'start_date': fields.Date.to_string(fields.Date.from_string(element.expiration_date) + relativedelta(days=1)), - 'expiration_date': fields.Date.to_string(enddate + diffdate), - } - newid = element.copy(default).id - return { - 'name': _("Renew Contract"), - 'view_mode': 'form', - 'view_id': self.env.ref('fleet.fleet_vehicle_log_contract_view_form').id, - 'res_model': 'fleet.vehicle.log.contract', - 'type': 'ir.actions.act_window', - 'domain': '[]', - 'res_id': newid, - 'context': {'active_id': newid}, - } - - @api.model - def scheduler_manage_auto_costs(self): - # This method is called by a cron task - # It creates costs for contracts having the "recurring cost" field setted, depending on their frequency - # For example, if a contract has a reccuring cost of 200 with a weekly frequency, this method creates a cost of 200 on the - # first day of each week, from the date of the last recurring costs in the database to today - # If the contract has not yet any recurring costs in the database, the method generates the recurring costs from the start_date to today - # The created costs are associated to a contract thanks to the many2one field contract_id - # If the contract has no start_date, no cost will be created, even if the contract has recurring costs - VehicleCost = self.env['fleet.vehicle.cost'] - deltas = { - 'yearly': relativedelta(years=+1), - 'monthly': relativedelta(months=+1), - 'weekly': relativedelta(weeks=+1), - 'daily': relativedelta(days=+1) - } - contracts = self.env['fleet.vehicle.log.contract'].search([('state', '!=', 'closed')], offset=0, limit=None, order=None) - for contract in contracts: - if not contract.start_date or contract.cost_frequency == 'no': - continue - found = False - startdate = contract.start_date - if contract.generated_cost_ids: - last_autogenerated_cost = VehicleCost.search([ - ('contract_id', '=', contract.id), - ('auto_generated', '=', True) - ], offset=0, limit=1, order='date desc') - if last_autogenerated_cost: - found = True - startdate = last_autogenerated_cost.date - if found: - startdate += deltas.get(contract.cost_frequency) - today = fields.Date.context_today(self) - while (startdate <= today) & (startdate <= contract.expiration_date): - data = { - 'amount': contract.cost_generated, - 'date': fields.Date.context_today(self), - 'vehicle_id': contract.vehicle_id.id, - 'cost_subtype_id': contract.cost_subtype_id.id, - 'contract_id': contract.id, - 'auto_generated': True - } - self.env['fleet.vehicle.cost'].create(data) - startdate += deltas.get(contract.cost_frequency) - return True - @api.model def scheduler_manage_contract_expiration(self): # This method is called by a cron task @@ -272,7 +107,6 @@ class FleetVehicleLogContract(models.Model): outdated_days = fields.Date.to_string(date_today + relativedelta(days=+delay_alert_contract)) nearly_expired_contracts = self.search([('state', '=', 'open'), ('expiration_date', '<', outdated_days)]) - nearly_expired_contracts.write({'state': 'diesoon'}) for contract in nearly_expired_contracts.filtered(lambda contract: contract.user_id): contract.activity_schedule( 'fleet.mail_act_fleet_contract_to_renew', contract.expiration_date, @@ -288,67 +122,12 @@ class FleetVehicleLogContract(models.Model): now_running_contracts.write({'state': 'open'}) def run_scheduler(self): - self.scheduler_manage_auto_costs() self.scheduler_manage_contract_expiration() - -class FleetVehicleLogFuel(models.Model): - _name = 'fleet.vehicle.log.fuel' - _description = 'Fuel log for vehicles' - _inherits = {'fleet.vehicle.cost': 'cost_id'} - - @api.model - def default_get(self, default_fields): - res = super(FleetVehicleLogFuel, self).default_get(default_fields) - service = self.env.ref('fleet.type_service_refueling', raise_if_not_found=False) - res.update({ - 'date': fields.Date.context_today(self), - 'cost_subtype_id': service and service.id or False, - 'cost_type': 'fuel' - }) - return res - - liter = fields.Float() - price_per_liter = fields.Float() - purchaser_id = fields.Many2one('res.partner', 'Purchaser') - inv_ref = fields.Char('Invoice Reference', size=64) - vendor_id = fields.Many2one('res.partner', 'Vendor') - notes = fields.Text() - cost_id = fields.Many2one('fleet.vehicle.cost', 'Cost', required=True, ondelete='cascade') - # we need to keep this field as a related with store=True because the graph view doesn't support - # (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, readonly=False) - - @api.onchange('vehicle_id') - def _onchange_vehicle(self): - if self.vehicle_id: - self.odometer_unit = self.vehicle_id.odometer_unit - self.purchaser_id = self.vehicle_id.driver_id.id - - @api.onchange('liter', 'price_per_liter', 'amount') - def _onchange_liter_price_amount(self): - # need to cast in float because the value receveid from web client maybe an integer (Javascript and JSON do not - # make any difference between 3.0 and 3). This cause a problem if you encode, for example, 2 liters at 1.5 per - # liter => total is computed as 3.0, then trigger an onchange that recomputes price_per_liter as 3/2=1 (instead - # of 3.0/2=1.5) - # If there is no change in the result, we return an empty dict to prevent an infinite loop due to the 3 intertwine - # onchange. And in order to verify that there is no change in the result, we have to limit the precision of the - # computation to 2 decimal - liter = float(self.liter) - price_per_liter = float(self.price_per_liter) - amount = float(self.amount) - if liter > 0 and price_per_liter > 0 and round(liter * price_per_liter, 2) != amount: - self.amount = round(liter * price_per_liter, 2) - elif amount > 0 and liter > 0 and round(amount / liter, 2) != price_per_liter: - self.price_per_liter = round(amount / liter, 2) - elif amount > 0 and price_per_liter > 0 and round(amount / price_per_liter, 2) != liter: - self.liter = round(amount / price_per_liter, 2) - - class FleetVehicleLogServices(models.Model): _name = 'fleet.vehicle.log.services' - _inherits = {'fleet.vehicle.cost': 'cost_id'} + _inherit = ['mail.thread', 'mail.activity.mixin'] + _rec_name = 'service_type_id' _description = 'Services for vehicles' @api.model @@ -357,22 +136,48 @@ class FleetVehicleLogServices(models.Model): service = self.env.ref('fleet.type_service_service_8', raise_if_not_found=False) res.update({ 'date': fields.Date.context_today(self), - 'cost_subtype_id': service and service.id or False, - 'cost_type': 'services' + 'service_type_id': service.id if service else None, }) return res - purchaser_id = fields.Many2one('res.partner', 'Purchaser') - inv_ref = fields.Char('Invoice Reference') + vehicle_id = fields.Many2one('fleet.vehicle', 'Vehicle', default=1, required=True, help='Vehicle concerned by this log') + amount = fields.Float('Cost') + odometer_id = fields.Many2one('fleet.vehicle.odometer', 'Odometer', help='Odometer measure of the vehicle at the moment of this log') + odometer = fields.Float(compute="_get_odometer", inverse='_set_odometer', string='Odometer Value', + help='Odometer measure of the vehicle at the moment of this log') + odometer_unit = fields.Selection(related='vehicle_id.odometer_unit', string="Unit", readonly=True) + date = fields.Date(help='Date when the cost has been executed') + company_id = fields.Many2one('res.company', 'Company', default=lambda self: self.env.company) + currency_id = fields.Many2one('res.currency', related='company_id.currency_id') + purchaser_id = fields.Many2one(related='vehicle_id.driver_id', string="Driver") + inv_ref = fields.Char('Vendor Reference') vendor_id = fields.Many2one('res.partner', 'Vendor') - # we need to keep this field as a related with store=True because the graph view doesn't support - # (1) to address fields from inherited table and (2) fields that aren't stored in database - cost_amount = fields.Float(related='cost_id.amount', string='Amount', store=True, readonly=False) notes = fields.Text() - cost_id = fields.Many2one('fleet.vehicle.cost', 'Cost', required=True, ondelete='cascade') + service_type_id = fields.Many2one('fleet.service.type', 'Service Type', required=True) - @api.onchange('vehicle_id') - def _onchange_vehicle(self): - if self.vehicle_id: - self.odometer_unit = self.vehicle_id.odometer_unit - self.purchaser_id = self.vehicle_id.driver_id.id + def _get_odometer(self): + self.odometer = 0 + for record in self: + if record.odometer_id: + record.odometer = record.odometer_id.value + + def _set_odometer(self): + for record in self: + if not record.odometer: + raise UserError(_('Emptying the odometer value of a vehicle is not allowed.')) + odometer = self.env['fleet.vehicle.odometer'].create({ + 'value': record.odometer, + 'date': record.date or fields.Date.context_today(record), + 'vehicle_id': record.vehicle_id.id + }) + self.odometer_id = odometer + + @api.model_create_multi + def create(self, vals_list): + for data in vals_list: + 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 + # odometer log with 0, which is to be avoided + del data['odometer'] + return super(FleetVehicleLogServices, self).create(vals_list)
\ No newline at end of file |
