fleet_vehicle_log_contract.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. # -*- coding: utf-8 -*-
  2. # Part of Odoo. See LICENSE file for full copyright and licensing details.
  3. from dateutil.relativedelta import relativedelta
  4. from odoo import api, fields, models
  5. class FleetVehicleLogContract(models.Model):
  6. _inherit = ['mail.thread', 'mail.activity.mixin']
  7. _name = 'fleet.vehicle.log.contract'
  8. _description = 'Vehicle Contract'
  9. _order = 'state desc,expiration_date'
  10. def compute_next_year_date(self, strdate):
  11. oneyear = relativedelta(years=1)
  12. start_date = fields.Date.from_string(strdate)
  13. return fields.Date.to_string(start_date + oneyear)
  14. vehicle_id = fields.Many2one('fleet.vehicle', 'Vehicle', required=True, check_company=True)
  15. cost_subtype_id = fields.Many2one('fleet.service.type', 'Type', help='Cost type purchased with this cost', domain=[('category', '=', 'contract')])
  16. amount = fields.Monetary('Cost', tracking=True)
  17. date = fields.Date(help='Date when the cost has been executed')
  18. company_id = fields.Many2one('res.company', 'Company', default=lambda self: self.env.company)
  19. currency_id = fields.Many2one('res.currency', related='company_id.currency_id')
  20. name = fields.Char(string='Name', compute='_compute_contract_name', store=True, readonly=False)
  21. active = fields.Boolean(default=True)
  22. user_id = fields.Many2one('res.users', 'Responsible', default=lambda self: self.env.user, index=True)
  23. start_date = fields.Date(
  24. 'Contract Start Date', default=fields.Date.context_today,
  25. help='Date when the coverage of the contract begins')
  26. expiration_date = fields.Date(
  27. 'Contract Expiration Date', default=lambda self:
  28. self.compute_next_year_date(fields.Date.context_today(self)),
  29. help='Date when the coverage of the contract expirates (by default, one year after begin date)')
  30. days_left = fields.Integer(compute='_compute_days_left', string='Warning Date')
  31. expires_today = fields.Boolean(compute='_compute_days_left')
  32. insurer_id = fields.Many2one('res.partner', 'Vendor')
  33. purchaser_id = fields.Many2one(related='vehicle_id.driver_id', string='Driver')
  34. ins_ref = fields.Char('Reference', size=64, copy=False)
  35. state = fields.Selection(
  36. [('futur', 'Incoming'),
  37. ('open', 'In Progress'),
  38. ('expired', 'Expired'),
  39. ('closed', 'Closed')
  40. ], 'Status', default='open', readonly=True,
  41. help='Choose whether the contract is still valid or not',
  42. tracking=True,
  43. copy=False)
  44. notes = fields.Html('Terms and Conditions', copy=False)
  45. cost_generated = fields.Monetary('Recurring Cost', tracking=True)
  46. cost_frequency = fields.Selection([
  47. ('no', 'No'),
  48. ('daily', 'Daily'),
  49. ('weekly', 'Weekly'),
  50. ('monthly', 'Monthly'),
  51. ('yearly', 'Yearly')
  52. ], 'Recurring Cost Frequency', default='monthly', required=True)
  53. service_ids = fields.Many2many('fleet.service.type', string="Included Services")
  54. @api.depends('vehicle_id.name', 'cost_subtype_id')
  55. def _compute_contract_name(self):
  56. for record in self:
  57. name = record.vehicle_id.name
  58. if name and record.cost_subtype_id.name:
  59. name = record.cost_subtype_id.name + ' ' + name
  60. record.name = name
  61. @api.depends('expiration_date', 'state')
  62. def _compute_days_left(self):
  63. """return a dict with as value for each contract an integer
  64. if contract is in an open state and is overdue, return 0
  65. if contract is in a closed state, return -1
  66. otherwise return the number of days before the contract expires
  67. """
  68. today = fields.Date.from_string(fields.Date.today())
  69. for record in self:
  70. if record.expiration_date and record.state in ['open', 'expired']:
  71. renew_date = fields.Date.from_string(record.expiration_date)
  72. diff_time = (renew_date - today).days
  73. record.days_left = diff_time if diff_time > 0 else 0
  74. record.expires_today = diff_time == 0
  75. else:
  76. record.days_left = -1
  77. record.expires_today = False
  78. def write(self, vals):
  79. res = super(FleetVehicleLogContract, self).write(vals)
  80. if 'start_date' in vals or 'expiration_date' in vals:
  81. date_today = fields.Date.today()
  82. future_contracts, running_contracts, expired_contracts = self.env[self._name], self.env[self._name], self.env[self._name]
  83. for contract in self.filtered(lambda c: c.start_date and c.state != 'closed'):
  84. if date_today < contract.start_date:
  85. future_contracts |= contract
  86. elif not contract.expiration_date or contract.start_date <= date_today <= contract.expiration_date:
  87. running_contracts |= contract
  88. else:
  89. expired_contracts |= contract
  90. future_contracts.action_draft()
  91. running_contracts.action_open()
  92. expired_contracts.action_expire()
  93. if vals.get('expiration_date') or vals.get('user_id'):
  94. self.activity_reschedule(['fleet.mail_act_fleet_contract_to_renew'], date_deadline=vals.get('expiration_date'), new_user_id=vals.get('user_id'))
  95. return res
  96. def action_close(self):
  97. self.write({'state': 'closed'})
  98. def action_draft(self):
  99. self.write({'state': 'futur'})
  100. def action_open(self):
  101. self.write({'state': 'open'})
  102. def action_expire(self):
  103. self.write({'state': 'expired'})
  104. @api.model
  105. def scheduler_manage_contract_expiration(self):
  106. # This method is called by a cron task
  107. # It manages the state of a contract, possibly by posting a message on the vehicle concerned and updating its status
  108. params = self.env['ir.config_parameter'].sudo()
  109. delay_alert_contract = int(params.get_param('hr_fleet.delay_alert_contract', default=30))
  110. date_today = fields.Date.from_string(fields.Date.today())
  111. outdated_days = fields.Date.to_string(date_today + relativedelta(days=+delay_alert_contract))
  112. reminder_activity_type = self.env.ref('fleet.mail_act_fleet_contract_to_renew', raise_if_not_found=False) or self.env['mail.activity.type']
  113. nearly_expired_contracts = self.search([
  114. ('state', '=', 'open'),
  115. ('expiration_date', '<', outdated_days),
  116. ('user_id', '!=', False)
  117. ]
  118. ).filtered(
  119. lambda nec: reminder_activity_type not in nec.activity_ids.activity_type_id
  120. )
  121. for contract in nearly_expired_contracts:
  122. contract.activity_schedule(
  123. 'fleet.mail_act_fleet_contract_to_renew', contract.expiration_date,
  124. user_id=contract.user_id.id)
  125. expired_contracts = self.search([('state', 'not in', ['expired', 'closed']), ('expiration_date', '<',fields.Date.today() )])
  126. expired_contracts.write({'state': 'expired'})
  127. futur_contracts = self.search([('state', 'not in', ['futur', 'closed']), ('start_date', '>', fields.Date.today())])
  128. futur_contracts.write({'state': 'futur'})
  129. now_running_contracts = self.search([('state', '=', 'futur'), ('start_date', '<=', fields.Date.today())])
  130. now_running_contracts.write({'state': 'open'})
  131. def run_scheduler(self):
  132. self.scheduler_manage_contract_expiration()