You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							744 lines
						
					
					
						
							35 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							744 lines
						
					
					
						
							35 KiB
						
					
					
				| # -*- coding: utf-8 -*- | |
| ############################################################################# | |
| # | |
| #    Cybrosys Technologies Pvt. Ltd. | |
| # | |
| #    Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) | |
| #    Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) | |
| # | |
| #    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 <http://www.gnu.org/licenses/>. | |
| # | |
| ############################################################################# | |
| from datetime import datetime, date, timedelta | |
| from odoo import api, fields, models, _ | |
| from odoo.exceptions import UserError, ValidationError | |
| 
 | |
| 
 | |
| class CarRentalContract(models.Model): | |
|     _name = 'car.rental.contract' | |
|     _inherit = 'mail.thread' | |
|     _description = 'Fleet Rental Management' | |
| 
 | |
|     image = fields.Binary(related='vehicle_id.image_128', | |
|                           string="Image of Vehicle") | |
|     reserved_fleet_id = fields.Many2one('rental.fleet.reserved', | |
|                                         invisible=True, | |
|                                         copy=False) | |
|     name = fields.Char(string="Name", | |
|                        default="Draft Contract", | |
|                        readonly=True, | |
|                        copy=False) | |
|     customer_id = fields.Many2one('res.partner', | |
|                                   required=True, | |
|                                   string='Customer', | |
|                                   help="Customer") | |
|     vehicle_id = fields.Many2one('fleet.vehicle', | |
|                                  string="Vehicle", | |
|                                  required=True, | |
|                                  help="Vehicle") | |
|     car_brand = fields.Many2one('fleet.vehicle.model.brand', | |
|                                 string="Fleet Brand", | |
|                                 size=50, | |
|                                 related='vehicle_id.model_id.brand_id', | |
|                                 store=True, | |
|                                 readonly=True) | |
|     car_color = fields.Char(string="Fleet Color", | |
|                             size=50, | |
|                             related='vehicle_id.color', | |
|                             store=True, | |
|                             copy=False, | |
|                             default='#FFFFFF', | |
|                             readonly=True) | |
|     cost = fields.Float(string="Rent Cost", | |
|                         help="This fields is to determine the cost of rent", | |
|                         required=True) | |
|     rent_start_date = fields.Date(string="Rent Start Date", | |
|                                   required=True, | |
|                                   default=str(date.today()), | |
|                                   help="Start date of contract", | |
|                                   track_visibility='onchange') | |
|     start_time = fields.Char(string="Start By", | |
|                              help="Enter the contract starting hour") | |
|     end_time = fields.Char(string="End By", | |
|                            help="Enter the contract Ending hour") | |
|     rent_by_hour = fields.Boolean(string="Rent By Hour", | |
|                                   help="Enable to start contract on " | |
|                                        "hour basis") | |
|     rent_end_date = fields.Date(string="Rent End Date", | |
|                                 required=True, | |
|                                 help="End date of contract", | |
|                                 track_visibility='onchange') | |
|     state = fields.Selection( | |
|         [('draft', 'Draft'), ('reserved', 'Reserved'), ('running', 'Running'), | |
|          ('cancel', 'Cancel'), | |
|          ('checking', 'Checking'), ('invoice', 'Invoice'), ('done', 'Done')], | |
|         string="State", default="draft", | |
|         copy=False, track_visibility='onchange') | |
|     notes = fields.Text(string="Details & Notes") | |
|     cost_generated = fields.Float(string='Recurring Cost', | |
|                                   help="Costs paid at regular intervals, depending on the cost frequency") | |
|     cost_frequency = fields.Selection( | |
|         [('no', 'No'), ('daily', 'Daily'), ('weekly', 'Weekly'), | |
|          ('monthly', 'Monthly'), | |
|          ('yearly', 'Yearly')], string="Recurring Cost Frequency", | |
|         help='Frequency of the recurring cost', required=True) | |
|     journal_type = fields.Many2one('account.journal', 'Journal', | |
|                                    default=lambda self: self.env[ | |
|                                        'account.journal'].search( | |
|                                        [('id', '=', 1)])) | |
|     account_type = fields.Many2one('account.account', 'Account', | |
|                                    default=lambda self: self.env[ | |
|                                        'account.account'].search( | |
|                                        [('id', '=', 17)])) | |
|     recurring_line = fields.One2many('fleet.rental.line', 'rental_number', | |
|                                      readonly=True, help="Recurring Invoices", | |
|                                      copy=False) | |
|     first_payment = fields.Float(string='First Payment', | |
|                                  help="Transaction/Office/Contract charge " | |
|                                       "amount, must paid by customer side " | |
|                                       "other " | |
|                                       "than recurrent payments", | |
|                                  track_visibility='onchange', | |
|                                  required=True) | |
|     first_payment_inv = fields.Many2one('account.move', copy=False) | |
|     first_invoice_created = fields.Boolean(string="First Invoice Created", | |
|                                            invisible=True, copy=False) | |
|     attachment_ids = fields.Many2many('ir.attachment', | |
|                                       'car_rent_checklist_ir_attachments_rel', | |
|                                       'rental_id', 'attachment_id', | |
|                                       string="Attachments", | |
|                                       help="Images of the vehicle before " | |
|                                            "contract/any attachments") | |
|     checklist_line = fields.One2many('car.rental.checklist', | |
|                                      'checklist_number', string="Checklist", | |
|                                      help="Facilities/Accessories, That should" | |
|                                           " verify when closing the contract.") | |
|     total = fields.Float(string="Total (Accessories/Tools)", readonly=True, | |
|                          copy=False) | |
|     tools_missing_cost = fields.Float(string="Missing Cost", readonly=True, | |
|                                       copy=False, | |
|                                       help='This is the total amount of ' | |
|                                            'missing tools/accessories') | |
|     damage_cost = fields.Float(string="Damage Cost / Balance Amount", | |
|                                copy=False) | |
|     damage_cost_sub = fields.Float(string="Damage Cost / Balance Amount", | |
|                                    readonly=True, | |
|                                    copy=False) | |
|     total_cost = fields.Float(string="Total", readonly=True, copy=False) | |
|     invoice_count = fields.Integer(compute='_invoice_count', | |
|                                    string='# Invoice', copy=False) | |
|     check_verify = fields.Boolean(compute='check_action_verify', copy=False) | |
|     sales_person = fields.Many2one('res.users', string='Sales Person', | |
|                                    default=lambda self: self.env.uid, | |
|                                    track_visibility='always') | |
|     read_only = fields.Boolean(string="Read Only", help="To make field read " | |
|                                                         "only") | |
|     company_id = fields.Many2one('res.company', string='Company', | |
|                                  default=lambda self: self.env.company, | |
|                                  help="Company this record owns") | |
| 
 | |
|     def action_run(self): | |
|         """ | |
|             Set the state of the object to 'running'. | |
|         """ | |
|         self.state = 'running' | |
| 
 | |
|     @api.depends('checklist_line.checklist_active') | |
|     def check_action_verify(self): | |
|         """ | |
|             Update the 'check_verify' field based on the value of | |
|             'checklist_active' in 'checklist_line'. | |
|         """ | |
|         flag = 0 | |
|         for each in self: | |
|             for i in each.checklist_line: | |
|                 if i.checklist_active: | |
|                     continue | |
|                 else: | |
|                     flag = 1 | |
|             if flag == 1: | |
|                 each.check_verify = False | |
|             else: | |
|                 each.check_verify = True | |
| 
 | |
|     @api.constrains('rent_start_date', 'rent_end_date') | |
|     def validate_dates(self): | |
|         """ | |
|             Check the validity of the 'rent_start_date' and 'rent_end_date' | |
|             fields. | |
|             Raise a warning if 'rent_end_date' is earlier than | |
|             'rent_start_date'. | |
|         """ | |
|         if self.rent_end_date < self.rent_start_date: | |
|             raise UserError("Please select the valid end date.") | |
| 
 | |
|     def set_to_done(self): | |
|         """ | |
|             Set the state of the object to 'done' based on certain conditions related to invoices. | |
|             Raise a UserError if certain invoices are pending or the total cost is zero. | |
|         """ | |
|         invoice_ids = self.env['account.move'].search( | |
|             [('fleet_rent_id', '=', self.id)]) | |
|         if any(each.payment_state != 'paid' for each in | |
|                invoice_ids): | |
|             raise UserError("Some Invoices are pending") | |
|         else: | |
|             self.state = 'done' | |
| 
 | |
|     def _invoice_count(self): | |
|         """ | |
|             Calculate the count of invoices related to the current object. | |
|             Update the 'invoice_count' field accordingly. | |
|         """ | |
|         self.invoice_count = self.env['account.move'].search_count( | |
|             [('fleet_rent_id', '=', self.id)]) | |
| 
 | |
|     @api.constrains('state') | |
|     def state_changer(self): | |
|         """ | |
|             Handle state transitions and update the 'state_id' of the | |
|             associated vehicle based on the value of the 'state' field. | |
|         """ | |
|         if self.state == "running": | |
|             state_id = self.env.ref('fleet_rental.vehicle_state_rent').id | |
|             self.vehicle_id.write({'state_id': state_id}) | |
|         elif self.state == "cancel": | |
|             state_id = self.env.ref('fleet_rental.vehicle_state_active').id | |
|             self.vehicle_id.write({'state_id': state_id}) | |
|         elif self.state == "invoice": | |
|             self.rent_end_date = fields.Date.today() | |
|             state_id = self.env.ref('fleet_rental.vehicle_state_active').id | |
|             self.vehicle_id.write({'state_id': state_id}) | |
| 
 | |
|     @api.constrains('checklist_line', 'damage_cost') | |
|     def total_updater(self): | |
|         """ | |
|            Update various fields related to totals based on the values in | |
|            'checklist_line', 'damage_cost', and other relevant fields. | |
|        """ | |
|         total = 0.0 | |
|         tools_missing_cost = 0.0 | |
|         for records in self.checklist_line: | |
|             total += records.price | |
|             if not records.checklist_active: | |
|                 tools_missing_cost += records.price | |
|         self.total = total | |
|         self.tools_missing_cost = tools_missing_cost | |
|         self.damage_cost_sub = self.damage_cost | |
|         self.total_cost = tools_missing_cost + self.damage_cost | |
| 
 | |
|     def fleet_scheduler1(self, rent_date): | |
|         """ | |
|             Perform actions related to fleet scheduling, including creating | |
|             invoices, managing recurring data, and sending email notifications. | |
|         """ | |
|         inv_obj = self.env['account.move'] | |
|         recurring_obj = self.env['fleet.rental.line'] | |
|         supplier = self.customer_id | |
|         product_id = self.env['product.product'].browse( | |
|             self.env.ref('fleet_rental.fleet_service_product').id) | |
|         if product_id.property_account_income_id.id: | |
|             income_account = product_id.property_account_income_id | |
|         elif product_id.categ_id.property_account_income_categ_id.id: | |
|             income_account = product_id.categ_id.property_account_income_categ_id | |
|         else: | |
|             raise UserError( | |
|                 _('Please define income account for this product: "%s" (id:%d).') % ( | |
|                     product_id.name, | |
|                     product_id.id)) | |
|         inv_data = { | |
|             'ref': supplier.name, | |
|             'partner_id': supplier.id, | |
|             'journal_id': self.journal_type.id, | |
|             'invoice_origin': self.name, | |
|             'fleet_rent_id': self.id, | |
|             'invoice_payment_term_id': None, | |
|             'invoice_date_due': self.rent_end_date, | |
|             'move_type': 'out_invoice', | |
|             'invoice_line_ids': [(0, 0, { | |
|                 'account_id': income_account.id, | |
|                 'price_unit': self.cost_generated, | |
|                 'quantity': 1, | |
|                 'product_id': product_id.id, | |
|             })] | |
|         } | |
|         inv_id = inv_obj.create(inv_data) | |
| 
 | |
|         recurring_data = { | |
|             'name': self.vehicle_id.name, | |
|             'date_today': rent_date, | |
|             'account_info': income_account.name, | |
|             'rental_number': self.id, | |
|             'recurring_amount': self.cost_generated, | |
|             'invoice_number': inv_id.id, | |
|             'invoice_ref': inv_id.id, | |
|         } | |
|         recurring_obj.create(recurring_data) | |
|         mail_content = _( | |
|             '<h3>Reminder Recurrent Payment!</h3><br/>Hi %s, <br/> This is to remind you that the ' | |
|             'recurrent payment for the ' | |
|             'rental contract has to be done.' | |
|             'Please make the payment at the earliest.' | |
|             '<br/><br/>' | |
|             'Please find the details below:<br/><br/>' | |
|             '<table><tr><td>Contract Ref<td/><td> %s<td/><tr/>' | |
|             '<tr/><tr><td>Amount <td/><td> %s<td/><tr/>' | |
|             '<tr/><tr><td>Due Date <td/><td> %s<td/><tr/>' | |
|             '<tr/><tr><td>Responsible Person <td/><td> %s, %s<td/><tr/><table/>') % \ | |
|                        (self.customer_id.name, self.name, inv_id.amount_total, | |
|                         inv_id.invoice_date_due, | |
|                         inv_id.user_id.name, | |
|                         inv_id.user_id.phone) | |
|         main_content = { | |
|             'subject': "Reminder Recurrent Payment!", | |
|             'author_id': self.env.user.partner_id.id, | |
|             'body_html': mail_content, | |
|             'email_to': self.customer_id.email, | |
|         } | |
|         self.env['mail.mail'].create(main_content).send() | |
| 
 | |
|     @api.model | |
|     def fleet_scheduler(self): | |
|         """ | |
|             Perform fleet scheduling operations, including creating invoices, | |
|             managing recurring data, and sending email notifications. | |
|         """ | |
|         inv_obj = self.env['account.move'] | |
|         recurring_obj = self.env['fleet.rental.line'] | |
|         today = date.today() | |
|         for records in self.search([]): | |
|             start_date = datetime.strptime(str(records.rent_start_date), | |
|                                            '%Y-%m-%d').date() | |
|             end_date = datetime.strptime(str(records.rent_end_date), | |
|                                          '%Y-%m-%d').date() | |
|             if end_date >= date.today(): | |
|                 temp = 0 | |
|                 if records.cost_frequency == 'daily': | |
|                     temp = 1 | |
|                 elif records.cost_frequency == 'weekly': | |
|                     week_days = (date.today() - start_date).days | |
|                     if week_days % 7 == 0 and week_days != 0: | |
|                         temp = 1 | |
|                 elif records.cost_frequency == 'monthly': | |
|                     if start_date.day == date.today().day and start_date != date.today(): | |
|                         temp = 1 | |
|                 elif records.cost_frequency == 'yearly': | |
|                     if start_date.day == date.today().day and start_date.month == date.today().month and \ | |
|                             start_date != date.today(): | |
|                         temp = 1 | |
|                 if temp == 1 and records.cost_frequency != "no" and records.state == "running": | |
|                     supplier = records.customer_id | |
|                     product_id = self.env['product.product'].browse( | |
|                         self.env.ref('fleet_rental.fleet_service_product').id) | |
|                     if product_id.property_account_income_id.id: | |
|                         income_account = product_id.property_account_income_id | |
|                     elif product_id.categ_id.property_account_income_categ_id.id: | |
|                         income_account = product_id.categ_id.property_account_income_categ_id | |
|                     else: | |
|                         raise UserError( | |
|                             _('Please define income account for this product: "%s" (id:%d).') % ( | |
|                                 product_id.name, | |
|                                 product_id.id)) | |
|                     inv_data = { | |
|                         'ref': supplier.name, | |
|                         'partner_id': supplier.id, | |
|                         'currency_id': records.account_type.company_id.currency_id.id, | |
|                         'journal_id': records.journal_type.id, | |
|                         'invoice_origin': records.name, | |
|                         'fleet_rent_id': records.id, | |
|                         'invoice_date': today, | |
|                         'company_id': records.account_type.company_id.id, | |
|                         'invoice_payment_term_id': None, | |
|                         'invoice_date_due': records.rent_end_date, | |
|                         'move_type': 'out_invoice', | |
|                         'invoice_line_ids': [(0, 0, { | |
|                             'account_id': income_account.id, | |
|                             'price_unit': records.cost_generated, | |
|                             'quantity': 1, | |
|                             'product_id': product_id.id, | |
|                         })] | |
|                     } | |
|                     inv_id = inv_obj.create(inv_data) | |
|                     recurring_data = { | |
|                         'name': records.vehicle_id.name, | |
|                         'date_today': today, | |
|                         'account_info': income_account.name, | |
|                         'rental_number': records.id, | |
|                         'recurring_amount': records.cost_generated, | |
|                         'invoice_number': inv_id.id, | |
|                         'invoice_ref': inv_id.id, | |
|                     } | |
|                     recurring_obj.create(recurring_data) | |
| 
 | |
|                     mail_content = _( | |
|                         '<h3>Reminder Recurrent Payment!</h3><br/>Hi %s, <br/> This is to remind you that the ' | |
|                         'recurrent payment for the ' | |
|                         'rental contract has to be done.' | |
|                         'Please make the payment at the earliest.' | |
|                         '<br/><br/>' | |
|                         'Please find the details below:<br/><br/>' | |
|                         '<table><tr><td>Contract Ref<td/><td> %s<td/><tr/>' | |
|                         '<tr/><tr><td>Amount <td/><td> %s<td/><tr/>' | |
|                         '<tr/><tr><td>Due Date <td/><td> %s<td/><tr/>' | |
|                         '<tr/><tr><td>Responsible Person <td/><td> %s, %s<td/><tr/><table/>') % \ | |
|                                    (self.customer_id.name, self.name, | |
|                                     inv_id.amount_total, | |
|                                     inv_id.invoice_date_due, | |
|                                     inv_id.user_id.name, | |
|                                     inv_id.user_id.mobile) | |
|                     main_content = { | |
|                         'subject': "Reminder Recurrent Payment!", | |
|                         'author_id': self.env.user.partner_id.id, | |
|                         'body_html': mail_content, | |
|                         'email_to': self.customer_id.email, | |
|                     } | |
|                     self.env['mail.mail'].create(main_content).send() | |
|             else: | |
|                 if self.state == 'running': | |
|                     records.state = "checking" | |
| 
 | |
|     def action_verify(self): | |
|         """ | |
|             Verifies the damage cost or missing cost | |
|         """ | |
|         self.state = "invoice" | |
|         self.reserved_fleet_id.unlink() | |
|         self.rent_end_date = fields.Date.today() | |
|         self.vehicle_id.rental_check_availability = True | |
|         product_id = self.env['product.product'].browse( | |
|             self.env.ref('fleet_rental.fleet_service_product').id) | |
|         if product_id.property_account_income_id.id: | |
|             income_account = product_id.property_account_income_id | |
|         elif product_id.categ_id.property_account_income_categ_id.id: | |
|             income_account = product_id.categ_id.property_account_income_categ_id | |
|         else: | |
|             raise UserError( | |
|                 _('Please define income account for this product: "%s" (id:%d).') % ( | |
|                     product_id.name, | |
|                     product_id.id)) | |
|         if self.total_cost != 0: | |
|             supplier = self.customer_id | |
|             inv_data = { | |
|                 'ref': supplier.name, | |
|                 'move_type': 'out_invoice', | |
|                 'partner_id': supplier.id, | |
|                 'currency_id': self.account_type.company_id.currency_id.id, | |
|                 'journal_id': self.journal_type.id, | |
|                 'invoice_origin': self.name, | |
|                 'fleet_rent_id': self.id, | |
|                 'company_id': self.account_type.company_id.id, | |
|                 'invoice_date_due': self.rent_end_date, | |
|                 'invoice_line_ids': [(0, 0, { | |
|                     'name': "Damage/Tools missing cost", | |
|                     'account_id': income_account.id, | |
|                     'price_unit': self.total_cost, | |
|                     'quantity': 1, | |
|                     'product_id': product_id.id, | |
|                 })] | |
|             } | |
|             inv_id = self.env['account.move'].create(inv_data) | |
|             list_view_id = self.env.ref('account.view_move_form', False) | |
|             form_view_id = self.env.ref('account.view_move_tree', False) | |
|             result = { | |
|                 'name': 'Fleet Rental Invoices', | |
|                 'view_mode': 'form', | |
|                 'res_model': 'account.move', | |
|                 'type': 'ir.actions.act_window', | |
|                 'views': [(list_view_id.id, 'tree'), | |
|                           (form_view_id.id, 'form')], | |
|             } | |
|             if len(inv_id) > 1: | |
|                 result['domain'] = "[('id','in',%s)]" % inv_id.ids | |
|             else: | |
|                 result = {'type': 'ir.actions.act_window_close'} | |
|             return result | |
| 
 | |
|     def action_confirm(self): | |
|         """ | |
|            Confirm the rental contract, check vehicle availability, update | |
|            state to "reserved," generate a sequence code, and send a | |
|            confirmation email. | |
|         """ | |
|         self.vehicle_id.rental_check_availability = False | |
|         check_availability = 0 | |
|         for each in self.vehicle_id.rental_reserved_time: | |
|             if each.date_from <= self.rent_start_date <= each.date_to: | |
|                 check_availability = 1 | |
|             elif self.rent_start_date < each.date_from: | |
|                 if each.date_from <= self.rent_end_date <= each.date_to: | |
|                     check_availability = 1 | |
|                 elif self.rent_end_date > each.date_to: | |
|                     check_availability = 1 | |
|                 else: | |
|                     check_availability = 0 | |
|             else: | |
|                 check_availability = 0 | |
|         if check_availability == 0: | |
|             reserved_id = self.vehicle_id.rental_reserved_time.create( | |
|                 {'customer_id': self.customer_id.id, | |
|                  'date_from': self.rent_start_date, | |
|                  'date_to': self.rent_end_date, | |
|                  'reserved_obj_id': self.vehicle_id.id | |
|                  }) | |
|             self.write({'reserved_fleet_id': reserved_id.id}) | |
|         else: | |
|             raise UserError( | |
|                 'Sorry This vehicle is already booked by another customer') | |
|         self.state = "reserved" | |
|         sequence_code = 'car.rental.sequence' | |
|         order_date = self.create_date | |
|         order_date = str(order_date)[0:10] | |
|         self.name = self.env['ir.sequence'] \ | |
|             .with_context(ir_sequence_date=order_date).next_by_code( | |
|             sequence_code) | |
|         mail_content = _( | |
|             '<h3>Order Confirmed!</h3><br/>Hi %s, <br/> This is to notify that your rental contract has ' | |
|             'been confirmed. <br/><br/>' | |
|             'Please find the details below:<br/><br/>' | |
|             '<table><tr><td>Reference Number<td/><td> %s<td/><tr/>' | |
|             '<tr><td>Time Range <td/><td> %s to %s <td/><tr/><tr><td>Vehicle <td/><td> %s<td/><tr/>' | |
|             '<tr><td>Point Of Contact<td/><td> %s , %s<td/><tr/><table/>') % \ | |
|                        (self.customer_id.name, self.name, self.rent_start_date, | |
|                         self.rent_end_date, | |
|                         self.vehicle_id.name, self.sales_person.name, | |
|                         self.sales_person.phone) | |
|         main_content = { | |
|             'subject': _('Confirmed: %s - %s') % | |
|                        (self.name, self.vehicle_id.name), | |
|             'author_id': self.env.user.partner_id.id, | |
|             'body_html': mail_content, | |
|             'email_to': self.customer_id.email, | |
|         } | |
|         self.env['mail.mail'].create(main_content).send() | |
| 
 | |
|     def action_cancel(self): | |
|         """ | |
|            Cancel the rental contract. | |
|            Update the state to "cancel" and delete the associated reserved | |
|            fleet ID if it exists. | |
|        """ | |
|         self.state = "cancel" | |
|         self.vehicle_id.rental_check_availability = True | |
|         if self.reserved_fleet_id: | |
|             self.reserved_fleet_id.unlink() | |
| 
 | |
|     def force_checking(self): | |
|         """ | |
|             Force the checking of payment status for associated invoices. | |
|             If all invoices are marked as paid, update the state to "checking." | |
|             Otherwise, raise a UserError indicating that some invoices are | |
|             pending. | |
|         """ | |
|         invoice_ids = self.env['account.move'].search( | |
|             [('fleet_rent_id', '=', self.id)]) | |
|         if any(each.payment_state != 'paid' for each in invoice_ids): | |
|             raise UserError("Some Invoices are pending") | |
|         else: | |
|             self.state = "checking" | |
| 
 | |
|     def action_view_invoice(self): | |
|         """ | |
|             Display the associated invoices for the current record. | |
|             Construct the appropriate view configurations based on the number | |
|             of invoices found. | |
|         """ | |
|         inv_obj = self.env['account.move'].search( | |
|             [('fleet_rent_id', '=', self.id)]) | |
|         inv_ids = [] | |
|         for each in inv_obj: | |
|             inv_ids.append(each.id) | |
|         view_id = self.env.ref('account.view_move_form').id | |
|         if inv_ids: | |
|             if len(inv_ids) <= 1: | |
|                 value = { | |
|                     'view_type': 'form', | |
|                     'view_mode': 'form', | |
|                     'res_model': 'account.move', | |
|                     'view_id': view_id, | |
|                     'type': 'ir.actions.act_window', | |
|                     'name': _('Invoice'), | |
|                     'res_id': inv_ids and inv_ids[0] | |
|                 } | |
|             else: | |
|                 value = { | |
|                     'domain': [('fleet_rent_id', '=', self.id)], | |
|                     'view_type': 'form', | |
|                     'view_mode': 'tree,form', | |
|                     'res_model': 'account.move', | |
|                     'view_id': False, | |
|                     'type': 'ir.actions.act_window', | |
|                     'name': _('Invoice'), | |
|                 } | |
|             return value | |
| 
 | |
|     def action_invoice_create(self): | |
|         """ | |
|             Create an invoice for the rental contract. | |
|             Calculate the rental duration and iterate over each day to create | |
|             invoices. | |
|             Create the first payment invoice, add relevant invoice line data, | |
|             and send an email notification for the received payment. | |
|         """ | |
|         for each in self: | |
|             rent_date = self.rent_start_date | |
|             if each.cost_frequency != 'no' and rent_date < date.today(): | |
|                 rental_days = (date.today() - rent_date).days | |
|                 if each.cost_frequency == 'weekly': | |
|                     rental_days = int(rental_days / 7) | |
|                 if each.cost_frequency == 'monthly': | |
|                     rental_days = int(rental_days / 30) | |
|                 if each.cost_frequency == 'yearly': | |
|                     rental_days = int(rental_days / 365) | |
|                 for each1 in range(0, rental_days + 1): | |
|                     if rent_date > datetime.strptime(str(each.rent_end_date), | |
|                                                      "%Y-%m-%d").date(): | |
|                         break | |
|                     each.fleet_scheduler1(rent_date) | |
|                     if each.cost_frequency == 'daily': | |
|                         rent_date = rent_date + timedelta(days=1) | |
|                     if each.cost_frequency == 'weekly': | |
|                         rent_date = rent_date + timedelta(days=7) | |
|                     if each.cost_frequency == 'monthly': | |
|                         rent_date = rent_date + timedelta(days=30) | |
|                     if each.cost_frequency == 'yearly': | |
|                         rent_date = rent_date + timedelta(days=365) | |
|         self.first_invoice_created = True | |
|         inv_obj = self.env['account.move'] | |
|         supplier = self.customer_id | |
|         inv_data = { | |
|             'ref': supplier.name, | |
|             'move_type': 'out_invoice', | |
|             'partner_id': supplier.id, | |
|             'currency_id': self.account_type.company_id.currency_id.id, | |
|             'journal_id': self.journal_type.id, | |
|             'invoice_origin': self.name, | |
|             'fleet_rent_id': self.id, | |
|             'company_id': self.account_type.company_id.id, | |
|             'invoice_date_due': self.rent_end_date, | |
|             'is_first_invoice': True, | |
|         } | |
|         inv_id = inv_obj.create(inv_data) | |
|         self.first_payment_inv = inv_id.id | |
|         product_id = self.env['product.product'].browse( | |
|             self.env.ref('fleet_rental.fleet_service_product').id) | |
|         if product_id.property_account_income_id.id: | |
|             income_account = product_id.property_account_income_id.id | |
|         elif product_id.categ_id.property_account_income_categ_id.id: | |
|             income_account = product_id.categ_id.property_account_income_categ_id.id | |
|         else: | |
|             raise UserError( | |
|                 _('Please define income account for this product: "%s" (id:%d).') % ( | |
|                     product_id.name, | |
|                     product_id.id)) | |
| 
 | |
|         if inv_id: | |
|             list_value = [(0, 0, { | |
|                 'name': self.vehicle_id.name, | |
|                 'price_unit': self.first_payment, | |
|                 'quantity': 1.0, | |
|                 'account_id': income_account, | |
|                 'product_id': product_id.id, | |
|                 'move_id': inv_id.id, | |
|             })] | |
|             inv_id.write({'invoice_line_ids': list_value}) | |
|         action = self.env.ref('account.action_move_out_invoice_type') | |
|         result = { | |
|             'name': action.name, | |
|             'type': 'ir.actions.act_window', | |
|             'views': [[False, 'form']], | |
|             'target': 'current', | |
|             'res_id': inv_id.id, | |
|             'res_model': 'account.move', | |
|         } | |
|         return result | |
| 
 | |
|     def action_extend_rent(self): | |
|         """ | |
|             Set the 'read_only' attribute to True, indicating that the rent | |
|             extension action is being performed and the corresponding fields | |
|             should be made read-only. | |
|  | |
|             This method is typically used in the context of extending a rental | |
|             agreement. | |
|         """ | |
|         self.read_only = True | |
| 
 | |
|     def action_confirm_extend_rent(self): | |
|         """ | |
|             Confirm the extension of a rental agreement and update the rental | |
|             reserved time for the associated vehicle. | |
|  | |
|             This method sets the 'date_to' field of the rental reserved time | |
|             for the vehicle to the specified 'rent_end_date', indicating the | |
|             extended rental period. After confirming the extension, the | |
|             'read_only' attribute is set to False to allow further | |
|             modifications. | |
|  | |
|             This method is typically called when a user confirms the extension | |
|             of a rental. | |
|         """ | |
|         self.vehicle_id.rental_reserved_time.write( | |
|             { | |
|                 'date_to': self.rent_end_date, | |
|             }) | |
|         self.read_only = False | |
| 
 | |
|     @api.constrains('start_time', 'end_time', 'rent_start_date', | |
|                     'rent_end_date') | |
|     def validate_time(self): | |
|         """ | |
|             Validate the time constraints for a rental agreement. | |
|  | |
|             This method is used as a constraint to ensure that the specified | |
|             start and end times are valid, especially when renting by the hour. | |
|             If renting by the hour, it checks whether the end time is greater | |
|             than the start time when the rental start and end | |
|             dates are the same. | |
|  | |
|             :raises ValidationError: If the time constraints are not met, a | |
|                                     validation error is raised with a relevant | |
|                                     error message. | |
|         """ | |
|         if self.rent_by_hour: | |
|             start_time = datetime.strptime(self.start_time, "%H:%M").time() | |
|             end_time = datetime.strptime(self.end_time, "%H:%M").time() | |
|             if (self.rent_end_date == self.rent_start_date and | |
|                     end_time <= start_time): | |
|                 raise ValidationError("Please choose a different end time") | |
| 
 | |
|     @api.constrains('rent_end_date') | |
|     def validate_on_read_only(self): | |
|         old_date = self.vehicle_id.rental_reserved_time.date_to | |
|         if self.read_only: | |
|             if self.rent_end_date <= old_date: | |
|                 raise ValidationError( | |
|                     f"Please choose a date greater that {old_date}") | |
| 
 | |
|     def action_discard_extend(self): | |
|         """ | |
|             Validate the 'rent_end_date' when the rental agreement is in | |
|             read-only mode. | |
|  | |
|             This constraint checks if the rental agreement is marked as | |
|             read-only, indicating that it has been extended or modified. If in | |
|             read-only mode, it compares the 'rent_end_date' with the existing | |
|             'date_to' value in the rental reserved time of the associated | |
|             vehicle. It ensures that the 'rent_end_date' is greater than the | |
|             existing date to maintain consistency. | |
|  | |
|             :raises ValidationError: If the 'rent_end_date' is not greater than | |
|                                     the existing 'date_to', a validation error | |
|                                     is raised with a relevant error message. | |
|         """ | |
|         self.read_only = False | |
|         self.rent_end_date = self.vehicle_id.rental_reserved_time.date_to
 | |
| 
 |