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 000000000..47a151bcf Binary files /dev/null and b/fleet_rental/static/description/images/screenshot-12.png differ 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;"/>