From d246c51fbe783d5135cb6e989d1ebe30f9ffa3e9 Mon Sep 17 00:00:00 2001 From: AjmalCybro Date: Sat, 7 Oct 2023 15:31:02 +0530 Subject: [PATCH] Oct 7 : [FIX] Bug Fixed 'fleet_rental' --- fleet_rental/README.rst | 5 +- fleet_rental/__init__.py | 3 +- fleet_rental/__manifest__.py | 11 +- fleet_rental/data/fleet_rental_data.xml | 2 - fleet_rental/doc/RELEASE_NOTES.md | 6 +- fleet_rental/models/__init__.py | 6 +- fleet_rental/models/car_rental.py | 314 +++++----- fleet_rental/models/fleet.py | 11 +- fleet_rental/models/res_config_settings.py | 35 ++ fleet_rental/reports/__init__.py | 2 +- fleet_rental/reports/rental_report.py | 2 +- fleet_rental/reports/rental_report.xml | 19 +- .../description/images/screenshot-12.png | Bin 0 -> 37500 bytes fleet_rental/static/description/index.html | 565 +++++++++++------- fleet_rental/views/car_rental_view.xml | 119 ++-- fleet_rental/views/checklist_view.xml | 17 +- .../views/res_config_settings_views.xml | 27 + 17 files changed, 692 insertions(+), 452 deletions(-) create mode 100755 fleet_rental/models/res_config_settings.py create mode 100644 fleet_rental/static/description/images/screenshot-12.png create mode 100755 fleet_rental/views/res_config_settings_views.xml diff --git a/fleet_rental/README.rst b/fleet_rental/README.rst index ecd62a4bf..87c2472d0 100755 --- a/fleet_rental/README.rst +++ b/fleet_rental/README.rst @@ -1,8 +1,11 @@ +.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg + :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + Fleet Rental Management v15 =========================== This module will helps you to give the vehicles for Rent. - Configuration ============= * No additional configurations needed diff --git a/fleet_rental/__init__.py b/fleet_rental/__init__.py index 8ecef343d..13b3ad01e 100755 --- a/fleet_rental/__init__.py +++ b/fleet_rental/__init__.py @@ -3,7 +3,7 @@ # # Cybrosys Technologies Pvt. Ltd. # -# Copyright (C) 2021-TODAY Cybrosys Technologies(). +# Copyright (C) 2023-TODAY Cybrosys Technologies(). # Author: Cybrosys Technogies @cybrosys(odoo@cybrosys.com) # # You can modify it under the terms of the GNU AFFERO @@ -19,6 +19,5 @@ # If not, see . # ############################################################################# - from . import models from . import reports diff --git a/fleet_rental/__manifest__.py b/fleet_rental/__manifest__.py index cc9e9ecf6..b477c0480 100755 --- a/fleet_rental/__manifest__.py +++ b/fleet_rental/__manifest__.py @@ -3,7 +3,7 @@ # # Cybrosys Technologies Pvt. Ltd. # -# Copyright (C) 2021-TODAY Cybrosys Technologies(). +# Copyright (C) 2023-TODAY Cybrosys Technologies(). # Author: Cybrosys Technogies @cybrosys(odoo@cybrosys.com) # # You can modify it under the terms of the GNU AFFERO @@ -22,28 +22,29 @@ { 'name': 'Fleet Rental Management', - 'version': '15.0.1.0.0', + 'version': '15.0.2.0.0', + 'category': "Industries", 'summary': """This module will helps you to give the vehicles for Rent.""", 'description': "Module Helps You To Manage Rental Contracts, Odoo13, Odoo 13, Fleet, Rental, Rent, Vehicle management", - 'category': "Industries", 'live_test_url': 'https://youtu.be/chN-n7nB3Ac', 'author': 'Cybrosys Techno Solutions', 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', 'website': "https://www.cybrosys.com", 'depends': ['base', 'account', 'fleet', 'mail'], 'data': [ 'data/fleet_rental_data.xml', 'security/rental_security.xml', 'security/ir.model.access.csv', + 'views/res_config_settings_views.xml', 'views/car_rental_view.xml', 'views/checklist_view.xml', 'views/car_tools_view.xml', 'reports/rental_report.xml' ], - 'demo': [ - ], 'images': ['static/description/banner.png'], 'license': 'AGPL-3', 'installable': True, 'application': True, + 'auto_install': False } diff --git a/fleet_rental/data/fleet_rental_data.xml b/fleet_rental/data/fleet_rental_data.xml index 1e999515e..35e364dd8 100755 --- a/fleet_rental/data/fleet_rental_data.xml +++ b/fleet_rental/data/fleet_rental_data.xml @@ -1,6 +1,5 @@ - Fleet Rental Service @@ -745,5 +744,4 @@ - \ No newline at end of file diff --git a/fleet_rental/doc/RELEASE_NOTES.md b/fleet_rental/doc/RELEASE_NOTES.md index 68147e9e7..9c2057c6d 100755 --- a/fleet_rental/doc/RELEASE_NOTES.md +++ b/fleet_rental/doc/RELEASE_NOTES.md @@ -3,8 +3,12 @@ #### 03.12.2020 #### Version 15.0.1.0.0 #### ADD -Initial Commit for Fleet Rental Management +- Initial Commit for Fleet Rental Management +#### 26.09.2023 +#### Version 15.0.2.0.0 +#### ADD +- Rental fleet Invoice product selection from Configuration Settings. diff --git a/fleet_rental/models/__init__.py b/fleet_rental/models/__init__.py index 21efa60d9..3ad4f5630 100755 --- a/fleet_rental/models/__init__.py +++ b/fleet_rental/models/__init__.py @@ -3,7 +3,7 @@ # # Cybrosys Technologies Pvt. Ltd. # -# Copyright (C) 2021-TODAY Cybrosys Technologies(). +# Copyright (C) 2023-TODAY Cybrosys Technologies(). # Author: Cybrosys Technogies @cybrosys(odoo@cybrosys.com) # # You can modify it under the terms of the GNU AFFERO @@ -19,8 +19,6 @@ # If not, see . # ############################################################################# - from . import car_rental from . import fleet - - +from . import res_config_settings diff --git a/fleet_rental/models/car_rental.py b/fleet_rental/models/car_rental.py index 6702ca27c..790231164 100755 --- a/fleet_rental/models/car_rental.py +++ b/fleet_rental/models/car_rental.py @@ -3,7 +3,7 @@ # # Cybrosys Technologies Pvt. Ltd. # -# Copyright (C) 2021-TODAY Cybrosys Technologies(). +# Copyright (C) 2023-TODAY Cybrosys Technologies(). # Author: Cybrosys Technogies @cybrosys(odoo@cybrosys.com) # # You can modify it under the terms of the GNU AFFERO @@ -22,7 +22,7 @@ from datetime import datetime, date, timedelta from odoo import models, fields, api, _ -from odoo.exceptions import UserError, Warning +from odoo.exceptions import UserError class CarRentalContract(models.Model): @@ -40,7 +40,8 @@ class CarRentalContract(models.Model): if str(each.date_from) <= str(self.rent_start_date) <= str(each.date_to): i.write({'rental_check_availability': False}) elif str(self.rent_start_date) < str(each.date_from): - if str(each.date_from) <= str(self.rent_end_date) <= str(each.date_to): + if str(each.date_from) <= str(self.rent_end_date) <= str( + each.date_to): i.write({'rental_check_availability': False}) elif str(self.rent_end_date) > str(each.date_to): i.write({'rental_check_availability': False}) @@ -50,37 +51,54 @@ class CarRentalContract(models.Model): i.write({'rental_check_availability': True}) image = fields.Binary(related='vehicle_id.image_128', string="Image of Vehicle") - reserved_fleet_id = fields.Many2one('rental.fleet.reserved', invisible=True, copy=False) + 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", + customer_id = fields.Many2one('res.partner', required=True, string='Customer', + help="Customer") + vehicle_id = fields.Many2one('fleet.vehicle', string="Vehicle", required=True, + help="Vehicle", readonly=True, states={'draft': [('readonly', False)]} ) - 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, + 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') - rent_end_date = fields.Date(string="Rent End Date", required=True, help="End date of contract", + 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') + 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", + [('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) + 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, default='no') journal_type = fields.Many2one('account.journal', 'Journal', - default=lambda self: self.env['account.journal'].search([('id', '=', 1)])) + 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", + 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 " @@ -88,11 +106,14 @@ class CarRentalContract(models.Model): 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', + 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", + checklist_line = fields.One2many('car.rental.checklist', 'checklist_number', + string="Checklist", help="Facilities/Accessories, That should verify when closing the contract.", states={'invoice': [('readonly', True)], 'done': [('readonly', True)], @@ -103,9 +124,11 @@ class CarRentalContract(models.Model): damage_cost = fields.Float(string="Damage Cost", copy=False) damage_cost_sub = fields.Float(string="Damage Cost", 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) + 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, + sales_person = fields.Many2one('res.users', string='Sales Person', + default=lambda self: self.env.uid, track_visibility='always') def action_run(self): @@ -128,10 +151,11 @@ class CarRentalContract(models.Model): @api.constrains('rent_start_date', 'rent_end_date') def validate_dates(self): if self.rent_end_date < self.rent_start_date: - raise Warning("Please select the valid end date.") + raise UserError("Please select the valid end date.") def set_to_done(self): - invoice_ids = self.env['account.move'].search([('invoice_origin', '=', self.name)]) + invoice_ids = self.env['account.move'].search( + [('invoice_origin', '=', self.name)]) f = 0 for each in invoice_ids: if each.payment_state != 'paid': @@ -143,7 +167,8 @@ class CarRentalContract(models.Model): raise UserError("Some Invoices are pending") def _invoice_count(self): - invoice_ids = self.env['account.move'].search([('invoice_origin', '=', self.name)]) + invoice_ids = self.env['account.move'].search( + [('invoice_origin', '=', self.name)]) self.invoice_count = len(invoice_ids) @api.constrains('state') @@ -181,24 +206,22 @@ class CarRentalContract(models.Model): supplier = self.customer_id inv_data = { 'ref': supplier.name, - # 'account_id': supplier.property_account_payable_id.id, 'partner_id': supplier.id, - # 'currency_id': self.account_type.company_id.currency_id.id, - # 'journal_id': self.journal_type.id, 'invoice_origin': self.name, - # 'company_id': self.account_type.company_id.id, 'invoice_date_due': self.rent_end_date, } inv_id = inv_obj.create(inv_data) - product_id = self.env['product.product'].search([("name", "=", "Fleet Rental Service")]) + product_id = self.env['product.product'].search( + [("name", "=", "Fleet Rental Service")]) 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)) + _('Please define income account for this product: "%s" (id:%d).') % ( + product_id.name, + product_id.id)) recurring_data = { 'name': self.vehicle_id.name, 'date_today': rent_date, @@ -229,7 +252,8 @@ class CarRentalContract(models.Model): 'Amount %s' 'Due Date %s' 'Responsible Person %s, %s') % \ - (self.customer_id.name, self.name, inv_id.amount_total, inv_id.invoice_date_due, + (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 = { @@ -247,7 +271,8 @@ class CarRentalContract(models.Model): 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() + 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 @@ -278,15 +303,17 @@ class CarRentalContract(models.Model): 'invoice_date_due': self.rent_end_date, } inv_id = inv_obj.create(inv_data) - product_id = self.env['product.product'].search([("name", "=", "Fleet Rental Service")]) + product_id = self.env['product.product'].search( + [("name", "=", "Fleet Rental Service")]) 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)) + _('Please define income account for this product: "%s" (id:%d).') % ( + product_id.name, + product_id.id)) recurring_data = { 'name': records.vehicle_id.name, 'date_today': today, @@ -318,7 +345,8 @@ class CarRentalContract(models.Model): '' '' '
Amount %s
Due Date %s
Responsible Person %s, %s
') % \ - (self.customer_id.name, self.name, inv_id.amount_total, inv_id.invoice_date_due, + (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 = { @@ -341,9 +369,7 @@ class CarRentalContract(models.Model): inv_line_obj = self.env['account.move.line'] supplier = self.customer_id inv_data = { - # 'name': supplier.name, 'ref': supplier.name, - # 'account_id': supplier.property_account_payable_id.id, 'partner_id': supplier.id, 'currency_id': self.account_type.company_id.currency_id.id, 'journal_id': self.journal_type.id, @@ -352,15 +378,17 @@ class CarRentalContract(models.Model): 'invoice_date_due': self.rent_end_date, } inv_id = inv_obj.create(inv_data) - product_id = self.env['product.product'].search([("name", "=", "Fleet Rental Service")]) + product_id = self.env['product.product'].search( + [("name", "=", "Fleet Rental Service")]) 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)) + _('Please define income account for this product: "%s" (id:%d).') % ( + product_id.name, + product_id.id)) inv_line_data = { 'name': "Damage/Tools missing cost", 'account_id': income_account.id, @@ -376,28 +404,14 @@ class CarRentalContract(models.Model): list_view_id = self.env.ref('account.view_move_form', False) form_view_id = self.env.ref('account.view_move_tree', False) result = { - # 'domain': "[('id', '=', " + str(inv_id) + ")]", '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')], } - # result = { - # # 'name': action.name, - # 'help': action.help, - # 'type': 'ir.actions.act_window', - # 'views': [[list_view_id, 'tree'], [form_view_id, 'form'], [False, 'graph'], [False, 'kanban'], - # [False, 'calendar'], [False, 'pivot']], - # 'target': action.target, - # 'context': action.context, - # 'res_model': 'account.move', - # } if len(inv_id) > 1: result['domain'] = "[('id','in',%s)]" % inv_id.ids - # elif len(inv_id) == 1: - # result['views'] = [(form_view_id.id, 'form')] - # result['res_id'] = inv_id.ids[0] else: result = {'type': 'ir.actions.act_window_close'} return result @@ -417,28 +431,32 @@ class CarRentalContract(models.Model): 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': self.vehicle_id.id - }) + 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': self.vehicle_id.id + }) self.write({'reserved_fleet_id': reserved_id.id}) else: - raise Warning('Sorry This vehicle is already booked by another customer') + 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 = _('

Order Confirmed!


Hi %s,
This is to notify that your rental contract has ' - 'been confirmed.

' - 'Please find the details below:

' - '
' - '' - '
Reference Number %s
Time Range %s to %s
Vehicle %s
Point Of Contact %s , %s
') % \ - (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.mobile) + mail_content = _( + '

Order Confirmed!


Hi %s,
This is to notify that your rental contract has ' + 'been confirmed.

' + 'Please find the details below:

' + '
' + '' + '
Reference Number %s
Time Range %s to %s
Vehicle %s
Point Of Contact %s , %s
') % \ + (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.mobile) main_content = { 'subject': _('Confirmed: %s - %s') % (self.name, self.vehicle_id.name), @@ -482,7 +500,6 @@ class CarRentalContract(models.Model): 'view_id': False, 'type': 'ir.actions.act_window', 'name': _('Invoice'), - # 'res_id': inv_ids } return value @@ -497,7 +514,8 @@ class CarRentalContract(models.Model): if each.cost_frequency == 'monthly': rental_days = int(rental_days / 30) for each1 in range(0, rental_days + 1): - if rent_date > datetime.strptime(str(each.rent_end_date), "%Y-%m-%d").date(): + 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': @@ -507,76 +525,74 @@ class CarRentalContract(models.Model): if each.cost_frequency == 'monthly': rent_date = rent_date + timedelta(days=30) - if self.first_payment != 0: - self.first_invoice_created = True - inv_obj = self.env['account.move'] - inv_line_obj = self.env['account.move.line'] - supplier = self.customer_id - inv_data = { - # 'name': supplier.name, - 'ref': supplier.name, - 'move_type': 'out_invoice', - # 'account_id': supplier.property_account_payable_id.id, - 'partner_id': supplier.id, - 'currency_id': self.account_type.company_id.currency_id.id, - 'journal_id': self.journal_type.id, - 'invoice_origin': self.name, - 'company_id': self.account_type.company_id.id, - 'invoice_date_due': self.rent_end_date, - } - inv_id = inv_obj.create(inv_data) - self.first_payment_inv = inv_id.id - product_id = self.env['product.product'].search([("name", "=", "Fleet Rental Service")]) - 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}) - mail_content = _( - '

First Payment Received!


Hi %s,
This is to notify that your first payment has ' - 'been received.

' - 'Please find the details below:

' - '
' - '
Invoice Number %s
Date %s
Amount %s
') % ( - self.customer_id.name, inv_id.payment_reference, inv_id.invoice_date, inv_id.amount_total) - main_content = { - 'subject': _('Payment Received: %s') % inv_id.payment_reference, - '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() - imd = self.env['ir.model.data'] - action = self.env.ref('account.action_move_out_invoice_type') - - # action = imd._xmlid_lookup('account.action_move_out_invoice_type') - # action = imd._xmlid_to_res_id('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 - + self.first_invoice_created = True + inv_obj = self.env['account.move'] + inv_line_obj = self.env['account.move.line'] + 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, + 'company_id': self.account_type.company_id.id, + 'invoice_date_due': self.rent_end_date, + } + inv_id = inv_obj.create(inv_data) + self.first_payment_inv = inv_id.id + fleet_rental_product_id = int( + self.env['ir.config_parameter'].sudo().get_param( + 'fleet_service_product_id')) + product_id = self.env['product.template'].sudo().browse( + fleet_rental_product_id).product_variant_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 Warning("Please enter advance amount to make first payment") + 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}) + mail_content = _( + '

First Payment Received!


Hi %s,
This is to notify that your first payment has ' + 'been received.

' + 'Please find the details below:

' + '
' + '
Invoice Number %s
Date %s
Amount %s
') % ( + self.customer_id.name, inv_id.payment_reference, + inv_id.invoice_date, inv_id.amount_total) + main_content = { + 'subject': _('Payment Received: %s') % inv_id.payment_reference, + '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() + imd = self.env['ir.model.data'] + 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 class FleetRentalLine(models.Model): @@ -587,7 +603,8 @@ class FleetRentalLine(models.Model): account_info = fields.Char('Account') recurring_amount = fields.Float('Amount') rental_number = fields.Many2one('car.rental.contract', string='Rental Number') - payment_info = fields.Char(compute='paid_info', string='Payment Stage', default='draft') + payment_info = fields.Char(compute='paid_info', string='Payment Stage', + default='draft') invoice_number = fields.Integer(string='Invoice ID') invoice_ref = fields.Many2one('account.move', string='Invoice Ref') date_due = fields.Date(string='Due Date', related='invoice_ref.invoice_date_due') @@ -595,7 +612,8 @@ class FleetRentalLine(models.Model): def paid_info(self): for each in self: if self.env['account.move'].browse(each.invoice_number): - each.payment_info = self.env['account.move'].browse(each.invoice_number).state + each.payment_info = self.env['account.move'].browse( + each.invoice_number).state else: each.payment_info = 'Record Deleted' diff --git a/fleet_rental/models/fleet.py b/fleet_rental/models/fleet.py index 484ff43ee..92f13575a 100755 --- a/fleet_rental/models/fleet.py +++ b/fleet_rental/models/fleet.py @@ -3,7 +3,7 @@ # # Cybrosys Technologies Pvt. Ltd. # -# Copyright (C) 2021-TODAY Cybrosys Technologies(). +# Copyright (C) 2023-TODAY Cybrosys Technologies(). # Author: Cybrosys Technogies @cybrosys(odoo@cybrosys.com) # # You can modify it under the terms of the GNU AFFERO @@ -38,7 +38,8 @@ class EmployeeFleet(models.Model): rental_check_availability = fields.Boolean(default=True, copy=False) color = fields.Char(string='Color', default='#FFFFFF') - rental_reserved_time = fields.One2many('rental.fleet.reserved', 'reserved_obj', string='Reserved Time', readonly=1, + rental_reserved_time = fields.One2many('rental.fleet.reserved', 'reserved_obj', + string='Reserved Time', readonly=1, ondelete='cascade') fuel_type = fields.Selection([('gasoline', 'Gasoline'), ('diesel', 'Diesel'), @@ -47,5 +48,7 @@ class EmployeeFleet(models.Model): ('petrol', 'Petrol')], 'Fuel Type', help='Fuel Used by the vehicle') - _sql_constraints = [('vin_sn_unique', 'unique (vin_sn)', "Chassis Number already exists !"), - ('license_plate_unique', 'unique (license_plate)', "License plate already exists !")] + _sql_constraints = [ + ('vin_sn_unique', 'unique (vin_sn)', "Chassis Number already exists !"), + ('license_plate_unique', 'unique (license_plate)', + "License plate already exists !")] diff --git a/fleet_rental/models/res_config_settings.py b/fleet_rental/models/res_config_settings.py new file mode 100755 index 000000000..f39606cf7 --- /dev/null +++ b/fleet_rental/models/res_config_settings.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies(). +# Author: Cybrosys Technogies @cybrosys(odoo@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 . +# +############################################################################# +from odoo import api, fields, models + + +class ResConfigSettings(models.TransientModel): + """Inherit configuration settings""" + _inherit = 'res.config.settings' + + def _get_default_product(self): + return self.env.ref('fleet_rental.fleet_service_product').id + + fleet_service_product_id = fields.Many2one('product.template', + string="Product", + config_parameter='fleet_service_product_id', + default=_get_default_product) diff --git a/fleet_rental/reports/__init__.py b/fleet_rental/reports/__init__.py index 7dcd4f019..4f9a39c26 100755 --- a/fleet_rental/reports/__init__.py +++ b/fleet_rental/reports/__init__.py @@ -3,7 +3,7 @@ # # Cybrosys Technologies Pvt. Ltd. # -# Copyright (C) 2021-TODAY Cybrosys Technologies(). +# Copyright (C) 2023-TODAY Cybrosys Technologies(). # Author: Cybrosys Technogies @cybrosys(odoo@cybrosys.com) # # You can modify it under the terms of the GNU AFFERO diff --git a/fleet_rental/reports/rental_report.py b/fleet_rental/reports/rental_report.py index 3c28815ec..3f66ae17f 100755 --- a/fleet_rental/reports/rental_report.py +++ b/fleet_rental/reports/rental_report.py @@ -3,7 +3,7 @@ # # Cybrosys Technologies Pvt. Ltd. # -# Copyright (C) 2021-TODAY Cybrosys Technologies(). +# Copyright (C) 2023-TODAY Cybrosys Technologies(). # Author: Cybrosys Technogies @cybrosys(odoo@cybrosys.com) # # You can modify it under the terms of the GNU AFFERO diff --git a/fleet_rental/reports/rental_report.xml b/fleet_rental/reports/rental_report.xml index 5986c2ca1..7ffef207e 100755 --- a/fleet_rental/reports/rental_report.xml +++ b/fleet_rental/reports/rental_report.xml @@ -2,14 +2,15 @@ - + report.fleet.rental.pivot report.fleet.rental - - - - + + + + @@ -17,10 +18,14 @@ report.fleet.rental pivot {'group_by_no_leaf':1,'group_by':[]} - This report allows you to analyse the performance of your Fleet Rental. + This report allows you to analyse the performance of your + Fleet Rental. + - + \ No newline at end of file diff --git a/fleet_rental/static/description/images/screenshot-12.png b/fleet_rental/static/description/images/screenshot-12.png new file mode 100644 index 0000000000000000000000000000000000000000..47a151bcf58fe0f044e8104683821f437ee7f3e7 GIT binary patch literal 37500 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 YgYJjCq7OFn7mNL+f(D@cx%tQc55!+}4gdfE literal 0 HcmV?d00001 diff --git a/fleet_rental/static/description/index.html b/fleet_rental/static/description/index.html index 781ef9b51..7db08599d 100644 --- a/fleet_rental/static/description/index.html +++ b/fleet_rental/static/description/index.html @@ -1,17 +1,19 @@ -

+
+ style="border-bottom: 1px solid #d5d5d5;">
- +
+ style="background-color: #7C7BAD !important; color: #fff !important; font-weight: 600 !important; padding: 5px 15px 8px !important; margin: 0 5px !important;"> Community
+ style="background-color: #875A7B !important; color: #fff !important; font-weight: 600 !important; padding: 5px 15px 8px !important; margin: 0 5px !important;"> Enterprise
@@ -25,12 +27,15 @@
-

Fleet Rental Management

+ style="text-align: center; padding: 1rem !important;"> +

Fleet Rental Management +

- With this module you can give vehicles like car, van, bike, jeep etc. for rent. + style="color: #212529 !important; font-size: 1.5rem !important; letter-spacing: 1px !important;"> + With this module you can give vehicles like car, van, bike, jeep etc. + for rent.

@@ -40,15 +45,20 @@
+ style="text-align: center; padding: 2.5rem 1rem !important;">

Overview


-

- This module is an application for Vehicle Rental System which helps in managing the rental of - vehicles like car,van,bike, jeep etc. It manages fleet/vehicle property by extending the basic - fleet module of Odoo. Currently fleet module does not have any connection with accounting - module. But in this module, we integrate the module with accounting also. + style="border: 3px solid #AC1015 !important; background-color: #AC1015 !important; width: 80px !important; margin-bottom: 2rem !important;"/> +

+ This module is an application for Vehicle Rental System which helps in + managing the rental of + vehicles like car,van,bike, jeep etc. It manages fleet/vehicle + property by extending the basic + fleet module of Odoo. Currently fleet module does not have any + connection with accounting + module. But in this module, we integrate the module with accounting + also.

@@ -56,118 +66,134 @@
-
-

Key Features

+
+

Key + Features


+ style="border: 3px solid #AC1015 !important; background-color: #AC1015 !important; width: 80px !important; margin-bottom: 2rem !important;"/>
- + style="height: 60px !important; padding: 1rem 1.5rem !important; border-radius: 0 !important; margin: 1.5rem 0"> +

- Multiple Plans for Rental Contract(Days/Weeks/Months/Years). + Multiple Plans for Rental + Contract(Days/Weeks/Months/Years).

- + style="height: 60px !important; padding: 1rem 1.5rem !important; border-radius: 0 !important; margin: 1.5rem 0"> +

Integrated with Accounting Module.

- + style="height: 60px !important; padding: 1rem 1.5rem !important; border-radius: 0 !important; margin: 1.5rem 0"> +

Automatically Create Recurring Invoices.

- + style="height: 60px !important; padding: 1rem 1.5rem !important; border-radius: 0 !important; margin: 1.5rem 0"> +

- Sending email for confirmation, first payment and recurrent invoices. + Sending email for confirmation, first payment and + recurrent invoices.

- + style="height: 60px !important; padding: 1rem 1.5rem !important; border-radius: 0 !important; margin: 1.5rem 0"> +

Check List Facility.

- + style="height: 60px !important; padding: 1rem 1.5rem !important; border-radius: 0 !important; margin: 1.5rem 0"> +

Separate Tree view for Checklist.

- + style="height: 60px !important; padding: 1rem 1.5rem !important; border-radius: 0 !important; margin: 1.5rem 0"> +

Damage Checking Facility.

- + style="height: 60px !important; padding: 1rem 1.5rem !important; border-radius: 0 !important; margin: 1.5rem 0"> +

Billing Facility for Damages/Check Lists.

- + style="height: 60px !important; padding: 1rem 1.5rem !important; border-radius: 0 !important; margin: 1.5rem 0"> +

Contract Payment Validations.

- + style="height: 60px !important; padding: 1rem 1.5rem !important; border-radius: 0 !important; margin: 1.5rem 0"> +

Detailed Fleet Rental Analysis Report.

- + style="height: 60px !important; padding: 1rem 1.5rem !important; border-radius: 0 !important; margin: 1.5rem 0"> +

Access Rights From Multiple Level.

- + style="height: 60px !important; padding: 1rem 1.5rem !important; border-radius: 0 !important; margin: 1.5rem 0"> +

Flexible for further customization.

@@ -183,16 +209,19 @@
-
-

Screenshots

+
+

+ Screenshots


+ style="border: 3px solid #AC1015 !important; background-color: #AC1015 !important; width: 80px !important; margin-bottom: 2rem !important;"/> -
+

+ style="font-size: 2rem !important; font-weight: 800 !important; color: #ffffff !important; background-color: #AC1015 !important; padding: 1rem !important; width: 70px !important; height: 75px !important;"> 01

@@ -200,23 +229,27 @@ Fleet Rental -> Rental Management

- When you install the module, an extra menu named Rental Management is created under the - Fleet Menu. Also "Fleet" menu is replaced as "Fleet Rental". Here you can see different - color codes according to each state. This helps you in finding out contracts easily. + style="color: #212529 !important; font-size: 1.3rem !important; font-weight: 300 !important;"> + When you install the module, an extra menu named Rental + Management is created under the + Fleet Menu. Also "Fleet" menu is replaced as "Fleet Rental". + Here you can see different + color codes according to each state. This helps you in finding + out contracts easily.

- + style="margin-top: -15px !important; margin-top: 1rem !important; margin-bottom: 4rem !important;"> + -
+

+ style="font-size: 2rem !important; font-weight: 800 !important; color: #ffffff !important; background-color: #AC1015 !important; padding: 1rem !important; width: 70px !important; height: 75px !important;"> 02

@@ -224,25 +257,28 @@ Fleet Rental -> Rental Management -> Rental Contract

- This is the Rental Contract form. You can see the Recurring lines created according to + style="color: #212529 !important; font-size: 1.3rem !important; font-weight: 300 !important;"> + This is the Rental Contract form. You can see the Recurring + lines created according to the - Recurring cost.
And also you can see all the invoices related to this contract from + Recurring cost.
And also you can see all the invoices + related to this contract from the smart button "Invoices".

- + style="margin-top: -15px !important; margin-top: 1rem !important; margin-bottom: 4rem !important;"> + -
+

+ style="font-size: 2rem !important; font-weight: 800 !important; color: #ffffff !important; background-color: #AC1015 !important; padding: 1rem !important; width: 70px !important; height: 75px !important;"> 03

@@ -250,24 +286,30 @@ Checklist Tab in Rental Contract Form

- Here you can add the list of tools given with the vehicle. When the vehicle is returned - back, the checklist can be validated and helps you to identify the tools that are not - returned. The price of unreturned tools will be added to the missing tool cost. The - renter have to pay that amount and you can also add damage cost if any. Check the - damages by using the images of vehicle uploaded before the contract. + style="color: #212529 !important; font-size: 1.3rem !important; font-weight: 300 !important;"> + Here you can add the list of tools given with the vehicle. + When the vehicle is returned + back, the checklist can be validated and helps you to identify + the tools that are not + returned. The price of unreturned tools will be added to the + missing tool cost. The + renter have to pay that amount and you can also add damage + cost if any. Check the + damages by using the images of vehicle uploaded before the + contract.

- + style="margin-top: -15px !important; margin-top: 1rem !important; margin-bottom: 4rem !important;"> + -
+

+ style="font-size: 2rem !important; font-weight: 800 !important; color: #ffffff !important; background-color: #AC1015 !important; padding: 1rem !important; width: 70px !important; height: 75px !important;"> 04

@@ -275,104 +317,138 @@ Checklist Easy Access

- - You can also create invoice against the checklist from here. The checklists are those - which are in the checking state, that means the ones ready for checking the operation. - If there is any damage or any missing tool, then you can charge all that from customer. + style="color: #212529 !important; font-size: 1.3rem !important; font-weight: 300 !important;"> + + You can also create invoice against the checklist from here. + The checklists are those + which are in the checking state, that means the ones ready for + checking the operation. + If there is any damage or any missing tool, then you can + charge all that from customer.

+ style="margin-top: -15px !important; margin-top: 1rem !important; margin-bottom: 4rem !important;"> - + style="margin-top: -15px !important; margin-top: 1rem !important; margin-bottom: 4rem !important;"> + -
+

+ style="font-size: 2rem !important; font-weight: 800 !important; color: #ffffff !important; background-color: #AC1015 !important; padding: 1rem !important; width: 70px !important; height: 75px !important;"> 05

+
+

+ Fleet Rental Service Product +

+

+ + You can also select the Service product in Configuration Settings. +

+
+
+ + + + +
+
+

+ 06

+

Email Notifications

- The system will send email notification to notify the confirmation of contract. -
- Note: You should configure outgoing and incoming e-mail settings from + style="color: #212529 !important; font-size: 1.3rem !important; font-weight: 300 !important;"> + The system will send email notification to notify the + confirmation of contract. +
+ Note: You should configure outgoing and + incoming e-mail settings from your odoo for email service.

+ style="margin-top: -15px !important; margin-top: 1rem !important; margin-bottom: 4rem !important;">

The system will notify the first payment through email.

+ style="margin-top: -15px !important; margin-top: 1rem !important; margin-bottom: 4rem !important;">

The system will remind all recurrent invoices through email.

- + style="margin-top: -15px !important; margin-top: 1rem !important; margin-bottom: 4rem !important;"> + -
+

- 06

+ style="font-size: 2rem !important; font-weight: 800 !important; color: #ffffff !important; background-color: #AC1015 !important; padding: 1rem !important; width: 70px !important; height: 75px !important;"> + 07

Contract Payment Validations

- Here you can see you have 1 invoice and this contract is in 'Invoice' state. So you can - set this contract to done only if all the invoices are in 'paid' state. Otherwise it + style="color: #212529 !important; font-size: 1.3rem !important; font-weight: 300 !important;"> + Here you can see you have 1 invoice and this contract is in + 'Invoice' state. So you can + set this contract to done only if all the invoices are in + 'paid' state. Otherwise it will raise a warning as follow.

+ style="margin-top: -15px !important; margin-top: 1rem !important; margin-bottom: 4rem !important;"> - + style="margin-top: -15px !important; margin-top: 1rem !important; margin-bottom: 4rem !important;"> + -
+

- 07

+ style="font-size: 2rem !important; font-weight: 800 !important; color: #ffffff !important; background-color: #AC1015 !important; padding: 1rem !important; width: 70px !important; height: 75px !important;"> + 08

Fleet Rental Analysis Report

- You can also analyse all your fleet rentals from Fleet Rental -> Reports -> Fleet Rental + style="color: #212529 !important; font-size: 1.3rem !important; font-weight: 300 !important;"> + You can also analyse all your fleet rentals from Fleet Rental + -> Reports -> Fleet Rental Analysis.

- + style="margin-top: -15px !important; margin-top: 1rem !important; margin-bottom: 4rem !important;"> +
@@ -382,72 +458,80 @@
+ style="text-align: center; padding: 2.5rem 1rem !important;">

Suggested Products


+ style="border: 3px solid #AC1015 !important; background-color: #AC1015 !important; width: 80px !important; margin-bottom: 2rem !important;"/>