# -*- coding: utf-8 -*- ############################################################################# # # Cybrosys Technologies Pvt. Ltd. # # Copyright (C) 2024-TODAY Cybrosys Technologies() # Author: Swaraj R () # # You can modify it under the terms of the GNU AFFERO # GENERAL PUBLIC LICENSE (AGPL v3), Version 3. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. # # You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE # (AGPL v3) along with this program. # If not, see . # ############################################################################# from datetime import datetime from odoo import api, fields, models, _ from odoo.exceptions import ValidationError class VehicleSubscription(models.Model): """Created new model to add new fields and function""" _name = "fleet.subscription" _description = "Fleet Subscription" _inherit = "mail.thread" _rec_name = 'vehicle_id' vehicle_id = fields.Many2one('fleet.vehicle', string="Vehicle", domain="[('id', 'in',vehicle_ids)]", required=True, help="This field help you to choose vehicle") vehicle_ids = fields.Many2many('fleet.vehicle', string="Vehicle", compute='_compute_vehicle_ids', help="Returns vehicle by satisfying " "the domain") model_id = fields.Many2one(related="vehicle_id.model_id", string='Model', help="This field help you to choose model " "of vehicle") price = fields.Float(string='Price', help="Compute field which results the price of " "vehicle") uptodate_price = fields.Float(compute="_compute_uptodate_price", string='Price', help="Compute field which results the price " "of vehicle until the date ") extra_price = fields.Float(string="Extra Price", help="Compute field which results the extra " "price of vehicle") start_date = fields.Date(string="Start Date", required=True, help="Start date of subscription") end_date = fields.Date(string="End Date", required=True, help="End date of subscription") cancellation_date = fields.Date(string="Cancellation Date", default=fields.Date.today(), help="Subscription cancellation date") duration = fields.Integer(string="Duration", compute='_compute_duration', help="Compute subscription duration") cancel_duration = fields.Integer(string="Duration", compute='_compute_cancel_duration', help="compute cancel duration") state = fields.Selection( selection=[('draft', 'Draft'), ('subscribed', 'Subscribed'), ('cancel', 'Cancelled'), ('expired', 'Expired') ], string='State', default='draft', help="States of subscription") street = fields.Char(string="Street", help="Choose the street") state_id = fields.Many2one("res.country.state", string='State', ondelete='restrict', domain="[('country_id', '=?', country_id)]", help="Choose the state") city = fields.Char(string="City", help="Choose the city") country_id = fields.Many2one('res.country', string='Country', ondelete='restrict', help="Choose the country") fuel = fields.Selection(selection=[('with_fuel', 'With Fuel'), ('without_fuel', 'Without Fuel')], string="Fuel Choice", default='without_fuel', help="Help you to choose the type of fuel") fuel_type = fields.Selection(string="Fuel Type", related="vehicle_id.model_id.default_fuel_type" , help="Fuel type will be given which is" " related to the model") fuel_rate = fields.Integer(string="Rate", default=300, help="Rate of fuel") charge_km = fields.Integer(string="Charge in km", default=12, help="Rate per kilometer") default_km = fields.Float(string="Default KMS", related='vehicle_id.free_km', help="Default km is set based on free km of " "vehicle which is given by authorised " "person") extra_km = fields.Float(string="Extra KMS", default=1, help="As per customer he/she can choose extra km") mileage = fields.Float(string='Mileage', related='vehicle_id.model_id.mileage', help="Helps to set mileage of vehicle") sale = fields.Integer(string="sale", compute='_compute_sale', help="Helps you to store count of sale") invoice = fields.Integer(string="Invoice", compute='_compute_invoice', help="Helps you to store count of invoice") invoice_ids = fields.Many2many('account.move', string='Invoices', help="Used to store ids of invoices") customer_id = fields.Many2one('res.partner', string="Customer", required=True, help="Helps you to choose customer") sale_id = fields.Many2one('sale.order', string='sale', readonly=True, help="Stores id of sale order") refund_id = fields.Many2one('account.move', string='Refund', readonly=True, help="Stores id of invoice which belongs " "to refund") insurance_type_id = fields.Many2one('vehicle.insurance', domain="[('vehicle_id', '='," "vehicle_id)]") refund = fields.Integer(compute='_compute_refund', help="Helps you to store count of refund") seating_capacity = fields.Integer(string='Seating Capacity', help="Seating capacity of vehicle can " "be set") is_invisible_sub = fields.Boolean(string="Approve Subscription", help="As subscription request get " "approved this will be enabled") def _get_vehicle_domain(self): """This method retrieves the vehicles that meet the following criteria""" insurance_ids = self.env['vehicle.insurance'].search([]).mapped( 'vehicle_id') domain = [] for record in insurance_ids: state = record.log_services.mapped('state') if 'done' in state and 'running' not in state and 'new' \ not in state and 'cancelled' not in state: if not self.search( [('vehicle_id', '=', record.id), ('state', '!=', 'subscribe')]): domain.append(record.id) return domain @api.onchange('vehicle_id') def _onchange_vehicle_id(self): """Function used to fill the seating capacity""" if self.vehicle_id: self.seating_capacity = self.vehicle_id.model_id.seats @api.onchange('seating_capacity') def _onchange_seating_capacity(self): """As the seating capacity changes vehicles are shown """ if self.seating_capacity != self.vehicle_id.model_id.seats: self.vehicle_id = False @api.onchange('default_km') def _onchange_default_km(self): """Charge per km is set as onchange of default_km""" if self.default_km <= self.vehicle_id.free_km: self.charge_km = 0 @api.depends('vehicle_id', 'seating_capacity') def _compute_vehicle_ids(self): """Compute the vehicle_IDS based on the vehicle and seating capacity.""" for rec in self: if not rec.vehicle_ids: domain = rec._get_vehicle_domain() if rec.seating_capacity: model_id = self.env['fleet.vehicle'].search( [('state_id', '=', 'registered'), ('model_id.seats', '=', rec.seating_capacity), ('id', 'in', domain)]) for record in model_id: self.vehicle_ids = [(4, record.id)] else: model_id = self.env['fleet.vehicle'].search( [('id', 'in', domain)]) for record in model_id: self.vehicle_ids = [(4, record.id)] @api.depends('start_date', 'end_date') def _compute_duration(self): """Compute duration based on start and end date""" for record in self: if record.end_date: if record.end_date < record.start_date: raise ValidationError(_( "End date should be greater than start date.")) if record.start_date and record.end_date: start = record.start_date.strftime("%Y-%m-%d") end = record.end_date.strftime("%Y-%m-%d") start_datetime = datetime.strptime(start, "%Y-%m-%d") end_datetime = datetime.strptime(end, "%Y-%m-%d") delta = end_datetime - start_datetime record.duration = delta.days else: record.duration = 0 @api.depends('start_date', 'cancellation_date') def _compute_cancel_duration(self): """Compute duration based on cancellation date""" for record in self: if record.start_date and record.cancellation_date: start = record.start_date.strftime("%Y-%m-%d") end = record.cancellation_date.strftime("%Y-%m-%d") start_datetime = datetime.strptime(start, "%Y-%m-%d") end_datetime = datetime.strptime(end, "%Y-%m-%d") delta = end_datetime - start_datetime record.cancel_duration = delta.days else: record.cancel_duration = 0 @api.depends('cancel_duration') def _compute_uptodate_price(self): """Compute price as per the cancellation date""" for rec in self: rec.uptodate_price = ( (rec.sale_id.order_line.price_unit / rec.duration) * ( (rec.cancellation_date - rec.start_date).days)) def action_get_car_insurance(self): """Get the action to view the car insurance associated with the subscription.""" self.ensure_one() return { 'type': 'ir.actions.act_window', 'name': 'Insurance', 'view_mode': 'form', 'res_model': 'vehicle.insurance', 'res_id': self.insurance_type_id.id, 'context': [('create', '=', False)] } def action_get_sale(self): """Get the action to view the sale associated with the subscription.""" return { 'type': 'ir.actions.act_window', 'name': 'Sale Order', 'view_mode': 'form', 'res_model': 'sale.order', 'res_id': self.sale_id.id, 'context': [('create', '=', False)] } def _compute_sale(self): """Used to calculate the sale count""" for record in self: record.sale = self.env['sale.order'].search_count( [('id', '=', self.sale_id.id)]) def action_get_refund(self): """Get the action to view the refund associated with the subscription.""" return { 'type': 'ir.actions.act_window', 'name': 'Refund', 'view_mode': 'form', 'res_id': self.refund_id.id, 'res_model': 'account.move', 'context': [('create', '=', False)] } def _compute_refund(self): """Used to calculate count of refund""" for record in self: record.refund = self.env['account.move'].search_count( [('id', '=', self.refund_id.id)]) def action_get_invoice(self): """Get the action to view the invoice associated with the subscription.""" invoice_ids = self.invoice_ids + self.sale_id.invoice_ids return { 'type': 'ir.actions.act_window', 'name': 'Sale Order', 'view_mode': 'tree,form', 'res_model': 'account.move', 'domain': [('id', 'in', invoice_ids.ids)], 'context': [('create', '=', False)] } def _compute_invoice(self): """Used to calculate invoice count""" for record in self: invoice_ids = record.invoice_ids + record.sale_id.invoice_ids record.invoice = self.env['account.move'].search_count( [('id', 'in', invoice_ids.ids)]) def action_invoice(self): """Used to generate invoice on clicking the button""" self.write({'state': 'subscribed'}) product_template_id = self.env.ref( 'vehicle_subscription.product_template_vehicle_subscription_form').id product_id = self.env['product.product'].search( [('product_tmpl_id', '=', product_template_id)]) sale_order_id = self.env['sale.order'].create({ 'partner_id': self.customer_id.id, }) line = self.env["sale.order.line"].create({ 'product_id': product_id.id, 'product_uom_qty': 1, 'price_unit': self.price, 'order_id': sale_order_id.id }) self.sale_id = sale_order_id def action_request(self): """Request for change subscription is generated """ return { 'type': 'ir.actions.act_window', 'view_mode': 'form', 'res_model': 'change.subscription', 'target': 'new', } def action_cancel(self): """Proceed with cancellation of subscription""" product_template_id = self.env.ref( 'vehicle_subscription.product_template_vehicle_subscription_form').id product_id = self.env['product.product'].search( [('product_tmpl_id', '=', product_template_id)]) invoice = self.env['account.move'].search( [('id', 'in', self.invoice_ids.ids), ('payment_state', 'in', ['paid', 'partial'])]).mapped( 'amount_untaxed_signed') invoiced_amount = sum(invoice) total_price = self.uptodate_price if invoiced_amount == total_price: self.write({'state': 'cancel'}) self.sale_id.action_done() elif invoiced_amount > total_price: self.write({'state': 'cancel'}) self.refund_id = self.env['account.move'].create({ 'move_type': 'out_refund', 'invoice_date': fields.Date.today(), 'partner_id': self.customer_id.id, 'invoice_line_ids': [(0, 0, { 'product_id': product_id.id, 'name': self.vehicle_id.name, 'price_unit': self.uptodate_price, })] }) else: return { 'type': 'ir.actions.client', 'tag': 'display_notification', 'params': { 'title': _('Warning'), 'message': 'you need to pay amount till date inorder to ' 'cancel subscription', 'sticky': True, } } @api.onchange('end_date') def _onchange_end_date(self): """Check expiry for subscription""" if self.end_date: if self.end_date < fields.Date.today(): self.write({'state': 'expired'}) self.sale_id.action_done()