Browse Source

Feb 21 [ADD] : Initial Commit 'vehicle_subscription'

pull/267/merge
AjmalCybro 1 year ago
parent
commit
5afc92f060
  1. 46
      vehicle_subscription/README.rst
  2. 24
      vehicle_subscription/__init__.py
  3. 71
      vehicle_subscription/__manifest__.py
  4. 23
      vehicle_subscription/controllers/__init__.py
  5. 392
      vehicle_subscription/controllers/vehicle_subscription.py
  6. 63
      vehicle_subscription/controllers/website_portal.py
  7. 14
      vehicle_subscription/data/ir_cron_data.xml
  8. 76
      vehicle_subscription/data/mail_data.xml
  9. 13
      vehicle_subscription/data/product_template_data.xml
  10. 12
      vehicle_subscription/data/website_menu_data.xml
  11. 6
      vehicle_subscription/doc/RELEASE_NOTES.md
  12. 29
      vehicle_subscription/models/__init__.py
  13. 32
      vehicle_subscription/models/account_move.py
  14. 262
      vehicle_subscription/models/cancellation_request.py
  15. 377
      vehicle_subscription/models/fleet_subscription.py
  16. 69
      vehicle_subscription/models/fleet_vehicle.py
  17. 34
      vehicle_subscription/models/fleet_vehicle_model.py
  18. 46
      vehicle_subscription/models/insurance_type.py
  19. 92
      vehicle_subscription/models/subscription_request.py
  20. 47
      vehicle_subscription/models/vehicle_insurance.py
  21. 8
      vehicle_subscription/security/ir.model.access.csv
  22. 17
      vehicle_subscription/security/vehicle_subscription_groups.xml
  23. BIN
      vehicle_subscription/static/description/assets/icons/check.png
  24. BIN
      vehicle_subscription/static/description/assets/icons/chevron.png
  25. BIN
      vehicle_subscription/static/description/assets/icons/cogs.png
  26. BIN
      vehicle_subscription/static/description/assets/icons/consultation.png
  27. BIN
      vehicle_subscription/static/description/assets/icons/ecom-black.png
  28. BIN
      vehicle_subscription/static/description/assets/icons/education-black.png
  29. BIN
      vehicle_subscription/static/description/assets/icons/hotel-black.png
  30. BIN
      vehicle_subscription/static/description/assets/icons/license.png
  31. BIN
      vehicle_subscription/static/description/assets/icons/lifebuoy.png
  32. BIN
      vehicle_subscription/static/description/assets/icons/manufacturing-black.png
  33. BIN
      vehicle_subscription/static/description/assets/icons/pos-black.png
  34. BIN
      vehicle_subscription/static/description/assets/icons/puzzle.png
  35. BIN
      vehicle_subscription/static/description/assets/icons/restaurant-black.png
  36. BIN
      vehicle_subscription/static/description/assets/icons/service-black.png
  37. BIN
      vehicle_subscription/static/description/assets/icons/trading-black.png
  38. BIN
      vehicle_subscription/static/description/assets/icons/training.png
  39. BIN
      vehicle_subscription/static/description/assets/icons/update.png
  40. BIN
      vehicle_subscription/static/description/assets/icons/user.png
  41. BIN
      vehicle_subscription/static/description/assets/icons/wrench.png
  42. BIN
      vehicle_subscription/static/description/assets/misc/categories.png
  43. BIN
      vehicle_subscription/static/description/assets/misc/check-box.png
  44. BIN
      vehicle_subscription/static/description/assets/misc/compass.png
  45. BIN
      vehicle_subscription/static/description/assets/misc/corporate.png
  46. BIN
      vehicle_subscription/static/description/assets/misc/customer-support.png
  47. BIN
      vehicle_subscription/static/description/assets/misc/cybrosys-logo.png
  48. BIN
      vehicle_subscription/static/description/assets/misc/features.png
  49. BIN
      vehicle_subscription/static/description/assets/misc/logo.png
  50. BIN
      vehicle_subscription/static/description/assets/misc/pictures.png
  51. BIN
      vehicle_subscription/static/description/assets/misc/pie-chart.png
  52. BIN
      vehicle_subscription/static/description/assets/misc/right-arrow.png
  53. BIN
      vehicle_subscription/static/description/assets/misc/star.png
  54. BIN
      vehicle_subscription/static/description/assets/misc/support.png
  55. BIN
      vehicle_subscription/static/description/assets/misc/whatsapp.png
  56. BIN
      vehicle_subscription/static/description/assets/misc/white-arrow.png
  57. BIN
      vehicle_subscription/static/description/assets/modules/1.png
  58. BIN
      vehicle_subscription/static/description/assets/modules/2.png
  59. BIN
      vehicle_subscription/static/description/assets/modules/3.png
  60. BIN
      vehicle_subscription/static/description/assets/modules/4.png
  61. BIN
      vehicle_subscription/static/description/assets/modules/5.png
  62. BIN
      vehicle_subscription/static/description/assets/modules/6.png
  63. BIN
      vehicle_subscription/static/description/assets/screenshots/hero.gif
  64. BIN
      vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_01.png
  65. BIN
      vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_02.png
  66. BIN
      vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_03.png
  67. BIN
      vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_04.png
  68. BIN
      vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_05.png
  69. BIN
      vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_06.png
  70. BIN
      vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_07.png
  71. BIN
      vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_08.png
  72. BIN
      vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_09.png
  73. BIN
      vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_10.png
  74. BIN
      vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_11.png
  75. BIN
      vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_12.png
  76. BIN
      vehicle_subscription/static/description/banner.png
  77. BIN
      vehicle_subscription/static/description/icon.png
  78. 631
      vehicle_subscription/static/description/index.html
  79. 31
      vehicle_subscription/static/src/js/change_subscription_form.js
  80. 19
      vehicle_subscription/static/src/js/change_subscription_request.js
  81. 31
      vehicle_subscription/static/src/js/subscription_cancellation.js
  82. 94
      vehicle_subscription/static/src/js/vehicle_booking.js
  83. 78
      vehicle_subscription/static/src/js/vehicle_subscription_success.js
  84. 44
      vehicle_subscription/static/src/js/website_subscription.js
  85. 14
      vehicle_subscription/views/account_move_views.xml
  86. 46
      vehicle_subscription/views/cancellation_request_views.xml
  87. 309
      vehicle_subscription/views/change_vehicle_subscription_template.xml
  88. 114
      vehicle_subscription/views/fleet_subscription_views.xml
  89. 42
      vehicle_subscription/views/fleet_vehicle_model_views.xml
  90. 44
      vehicle_subscription/views/insurance_type_views.xml
  91. 254
      vehicle_subscription/views/online_subscription_template.xml
  92. 110
      vehicle_subscription/views/online_vehicle_cancellation_template.xml
  93. 197
      vehicle_subscription/views/online_vehicle_template.xml
  94. 103
      vehicle_subscription/views/subscription_form_success_template.xml
  95. 45
      vehicle_subscription/views/subscription_request_views.xml
  96. 37
      vehicle_subscription/views/vehicle_insurance_views.xml
  97. 122
      vehicle_subscription/views/website_portal_subscription_template.xml
  98. 22
      vehicle_subscription/wizard/__init__.py
  99. 54
      vehicle_subscription/wizard/change_subscription.py
  100. 29
      vehicle_subscription/wizard/change_subscription_views.xml

46
vehicle_subscription/README.rst

@ -0,0 +1,46 @@
.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg
:target: http://www.gnu.org/licenses/AGPL-3.0-standalone.html
:alt: License: AGPL-3
Vehicle Subscription Management
===============================
This module helps you to Subscribe,Cancel and Change subscription through website as well as backend.
Configuration
=============
* No additional configurations needed
Company
-------
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__
Credits
-------
* Developers: (v16) Rahna Rasheed, Contact: odoo@cybrosys.com
License
-------
GNU AFFERO GENERAL PUBLIC LICENSE v3.0 (AGPL-3)
(https://www.gnu.org/licenses/agpl-3.0-standalone.html)
Contacts
--------
* Mail Contact : odoo@cybrosys.com
* Website : https://cybrosys.com
Bug Tracker
-----------
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported.
Maintainer
==========
.. image:: https://cybrosys.com/images/logo.png
:target: https://cybrosys.com
This module is maintained by Cybrosys Technologies.
For support and more information, please visit `Our Website <https://cybrosys.com/>`__
Further information
===================
HTML Description: `<static/description/index.html>`__

24
vehicle_subscription/__init__.py

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Rahna Rasheed (<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 . import controllers
from . import models
from . import wizard

71
vehicle_subscription/__manifest__.py

@ -0,0 +1,71 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Rahna Rasheed (<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/>.
#
#############################################################################
{
'name': 'Vehicle Subscription Management',
'version': "16.0.1.0.0",
'category': 'Fleet',
'summary': """Vehicle Subscription Management From Website""",
'description': """Vehicle Subscription Management From Website""",
'author': 'Cybrosys Techno Solutions',
'company': 'Cybrosys Techno Solutions',
'maintainer': 'Cybrosys Techno Solutions',
'website': 'https://www.cybrosys.com',
'depends': ['mail', 'contacts', 'fleet', 'account', 'sale', 'website',
'portal', ],
'data': [
'security/vehicle_subscription_groups.xml',
'security/ir.model.access.csv',
'data/ir_cron_data.xml',
'data/product_template_data.xml',
'data/website_menu_data.xml',
'data/mail_data.xml',
'views/website_portal_subscription_template.xml',
'views/fleet_vehicle_model_views.xml',
'views/fleet_subscription_views.xml',
'views/vehicle_insurance_views.xml',
'views/subscription_request_views.xml',
'views/insurance_type_views.xml',
'views/online_subscription_template.xml',
'views/online_vehicle_template.xml',
'views/account_move_views.xml',
'views/subscription_form_success_template.xml',
'views/online_vehicle_cancellation_template.xml',
'views/cancellation_request_views.xml',
'views/change_vehicle_subscription_template.xml',
'wizard/change_subscription_views.xml',
],
'assets': {
'web.assets_frontend': [
'vehicle_subscription/static/src/js/website_subscription.js',
'vehicle_subscription/static/src/js/vehicle_booking.js',
'vehicle_subscription/static/src/js/subscription_cancellation.js',
'vehicle_subscription/static/src/js/change_subscription_form.js',
'vehicle_subscription/static/src/js/vehicle_subscription_success.js',
'vehicle_subscription/static/src/js/change_subscription_request.js',
],
},
'images': ['static/description/banner.png'],
'license': 'AGPL-3',
'installable': True,
'auto_install': False,
'application': False,
}

23
vehicle_subscription/controllers/__init__.py

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Rahna Rasheed (<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 . import vehicle_subscription
from . import website_portal

392
vehicle_subscription/controllers/vehicle_subscription.py

@ -0,0 +1,392 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Rahna Rasheed (<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, timedelta
from odoo import http
from odoo.http import request
class OnlineSubscription(http.Controller):
"""Online Vehicle subscription through website"""
@http.route(['/online/subscription/city'], type='json', auth="public",
website=True)
def get_city(self, **kwargs):
"""Calling this function using ajax rpc in order to get city
based on state """
state = int(kwargs.get('state'))
vehicle = request.env['fleet.vehicle'].sudo().search(
[('states_id', '=', state)])
states = [city.location for city in vehicle]
return [*set(states)]
@http.route('/online/subscription', auth='public', website=True)
def subscription_form(self):
"""This function will return vehicle with which state is not null"""
vehicle_id = request.env['fleet.vehicle'].sudo().search(
[('states_id', '!=', False)])
insurance_type = request.env['insurance.type'].sudo().search([])
vals = {
'states': vehicle_id.states_id,
'cities': [rec.location for rec in vehicle_id],
'insurance_type': insurance_type,
}
return http.request.render('vehicle_subscription.subscription_form',
vals)
@http.route('/online/subscription/next', auth='public', website=True)
def vehicle_form(self, **kw):
"""Redirect to corresponding templates according to the
data provided by user in form page """
if kw.get('start_date'):
states = kw.get('state')
city = kw.get('city')
start_date = kw.get('start_date')
end_date = kw.get('end_date')
insurance = kw.get('insurance_type')
start = datetime.strptime(start_date, '%Y-%m-%d').date()
end = datetime.strptime(end_date, '%Y-%m-%d').date()
seats = kw.get('seating_capacity')
insurance_amount = request.env['vehicle.insurance'].sudo().browse(
int(insurance)).insurance_amount
insurance_type = request.env['vehicle.insurance'].sudo().search(
[('insurance_type_id.id', '=', insurance),
('start_date', '<=', start), ('end_date', '>=', end)])
vehicle_ids = insurance_type.vehicle_id
subscribed_vehicle_id = (request.env['fleet.subscription'].sudo().
search(
[('state', '=', 'subscribed')]).vehicle_id)
vehicle = request.env['fleet.vehicle'].sudo().search(
[('id', 'in', vehicle_ids.ids), ('states_id', '=', int(states)),
('location', '=', city),
('seats', '=', int(seats))])
vehicle_id = vehicle.filtered(
lambda v: v.id not in subscribed_vehicle_id.ids)
if vehicle_id:
for rec in vehicle_id:
rec.write({
'insurance': insurance,
'start': start,
'end': end,
})
data = {
'vehicles': vehicle_id,
'amount': insurance_amount,
'customers': request.env.user.partner_id.name,
}
return http.request.render('vehicle_subscription.vehicle_form',
data)
else:
return http.request.render(
'vehicle_subscription.subscription_vehicle_missing')
else:
return http.request.render('vehicle_subscription.vehicle_form')
@http.route(['/online/subscription/book'], type='json', auth="public",
website=True)
def get_vehicle(self, **kwargs):
"""Ajax RPC handler for booking vehicle subscription and
creating corresponding invoices in the backend."""
extra_km = kwargs.get('extra_km')
product_template_id = (request.env.ref(
'vehicle_subscription.product_template_vehicle_subscription_form').
id)
product_id = request.env['product.product'].sudo().search(
[('product_tmpl_id', '=', product_template_id)])
vehicle = int(kwargs.get('vehicle'))
customer = kwargs.get('customer')
checked = int(kwargs.get('checked'))
invoice_type = int(kwargs.get('invoice'))
vehicle_id = request.env['fleet.vehicle'].sudo().browse(int(vehicle))
customer_id = request.env['res.partner'].sudo().search(
[('name', '=', customer)])
if extra_km == '':
km = 0
else:
km = extra_km
subscribe = request.env['fleet.subscription'].sudo().create({
'vehicle_id': vehicle_id.id,
'customer_id': customer_id.id,
'insurance_type_id': vehicle_id.insurance,
'start_date': vehicle_id.start,
'end_date': vehicle_id.end,
'extra_km': km,
'fuel': 'without_fuel' if checked == False else 'with_fuel'
})
subscribe.action_invoice()
subscribe.sale_id.action_confirm()
if invoice_type:
subscribe.sale_id._create_invoices().action_post()
subscribe.invoice_ids.is_subscription = True
subscribe.sale_id.invoice_ids.is_subscription = True
else:
subscribe.sale_id.invoice_status = 'invoiced'
total_price = subscribe.sale_id.order_line.price_unit
duration = vehicle_id.duration
per_day = total_price / duration
start_date = vehicle_id.start
end_date = vehicle_id.end
next_invoice_day = start_date
while next_invoice_day <= end_date:
next_invoice_day = next_invoice_day + timedelta(days=30)
if next_invoice_day <= end_date:
durations = (next_invoice_day - start_date).days
generate_invoice = request.env[
'account.move'].sudo().create({
'move_type': 'out_invoice',
'partner_id': customer_id.id,
'invoice_date': next_invoice_day,
'invoice_origin': subscribe.sale_id.name,
'invoice_line_ids': [(0, 0, {
'product_id': product_id.id,
'name': vehicle_id.name,
'price_unit': per_day * durations,
})]
})
generate_invoice.is_subscription = True
generate_invoice.action_post()
subscribe.sale_id.invoice_ids = [(4, generate_invoice.id)]
subscribe.invoice_ids = [(4, generate_invoice.id)]
else:
next_invoice_day = end_date
durations = (next_invoice_day - start_date).days
generate_invoice = request.env[
'account.move'].sudo().create({
'move_type': 'out_invoice',
'partner_id': customer_id.id,
'invoice_date': next_invoice_day,
'invoice_line_ids': [(0, 0, {
'product_id': product_id.id,
'name': vehicle_id.name,
'price_unit': per_day * durations,
})]
})
generate_invoice.is_subscription = True
generate_invoice.action_post()
subscribe.sale_id.invoice_ids = [(4, generate_invoice.id)]
subscribe.invoice_ids = [(4, generate_invoice.id)]
break
start_date = start_date + timedelta(days=30)
values = {
'subscription_id': subscribe.id
}
return values
@http.route(['/next/vehicle', '/next/vehicle/<int:subscription_id>'],
auth='public', website=True, type='http')
def subscription_create(self):
"""Return template for successful subscription"""
current_vehicle = request.env['fleet.subscription'].sudo().search([
('customer_id', '=', request.env.user.partner_id.id),
('state', '=', 'subscribed'),
], order='write_date desc', limit=1)
context = {
'vehicle_name': current_vehicle.vehicle_id.name,
'customer_name': request.env.user.partner_id.name,
}
return request.render('vehicle_subscription.subscription_form_success',
context)
@http.route(['/online/subscription/with/fuel'], type='json', auth="public",
website=True)
def get_with_fuel(self, **kwargs):
"""Calculate price for vehicle according to fuel type """
vehicle = int(kwargs.get('vehicle'))
km = kwargs.get('extra_km')
vehicle = request.env['fleet.vehicle'].sudo().browse(vehicle)
vehicle.write({
'extra_km': km,
})
insurance_amount = vehicle.insurance
amount = request.env['vehicle.insurance'].sudo() \
.browse(int(insurance_amount)).insurance_amount
if float(km) > vehicle.free_km:
new_price = (((vehicle.extra_km / vehicle.mileage) *
vehicle.fuel_rate) +
(vehicle.duration * vehicle.subscription_price) +
amount)
else:
if float(km) <= vehicle.free_km:
new_price = ((vehicle.duration * vehicle.subscription_price) +
amount)
return str(new_price)
@http.route(['/online/subscription/without/fuel'], type='json',
auth="public",
website=True)
def get_without_fuel(self, **kwargs):
"""Calculate price for vehicle according to fuel type """
vehicle = int(kwargs.get('vehicle'))
km = kwargs.get('extra_km')
vehicle = request.env['fleet.vehicle'].sudo().browse(vehicle)
insurance_amount = vehicle.insurance
amount = request.env['vehicle.insurance'].sudo() \
.browse(int(insurance_amount)).insurance_amount
vehicle.write({
'extra_km': km,
})
if float(km) > vehicle.free_km:
new_price = (((vehicle.duration * vehicle.subscription_price) +
amount) + (vehicle.charge_km * vehicle.extra_km))
else:
new_price = (vehicle.duration * vehicle.subscription_price) + amount
return str(new_price)
@http.route('/online/subscription/cancel', auth='public', website=True)
def cancellation_form(self):
"""Cancel subscription form through website"""
customer_id = request.env['res.partner'].sudo().search(
[('name', '=', request.env.user.partner_id.name)])
vehicle_id = request.env['fleet.subscription'].sudo().search(
[('customer_id', '=', customer_id.id),
('state', '=', 'subscribed')])
vals = {
'customers': customer_id.name,
'vehicles': vehicle_id,
}
return http.request.render(
'vehicle_subscription.subscription_cancellation_form', vals)
@http.route('/online/choose/vehicle', type='json', auth="public",
website=True)
def choose_vehicle(self, **kwargs):
"""Only display vehicle of selected customer in website"""
customer = kwargs.get('customer_id')
customer_id = request.env['res.partner'].sudo().search(
[('name', '=', customer)])
vehicle_id = request.env['fleet.subscription'].sudo().search(
[('state', '=', 'subscribed'),
('customer_id', '=', customer_id.id)]).mapped('vehicle_id')
if vehicle_id:
vehicle = [(rec.id, rec.name) for rec in vehicle_id]
return [*set(vehicle)]
@http.route('/online/cancellation/click', auth='public', type='http',
website=True)
def cancellation_click_form(self, **kwargs):
"""Proceed with cancellation button click"""
customer = kwargs.get('customer')
vehicle = int(kwargs.get('vehicle'))
reason = kwargs.get('reason')
customer_id = request.env['res.partner'].sudo().search(
[('name', '=', customer)])
vehicle_id = request.env['fleet.vehicle'].sudo().browse(vehicle)
cancel_request = request.env['cancellation.request'].sudo().create({
'customer_id': customer_id.id,
'vehicle_id': vehicle_id.id,
'reason': reason,
})
values = {
'customer': customer,
'vehicle': vehicle_id.name,
}
cancel_request.state = 'to_approve'
return request.render('vehicle_subscription.booking_cancellation',
values)
@http.route('/online/subscription/change', auth='public', website=True)
def subscription_change_form(self):
"""Rendered response for the 'vehicle_subscription.
subscription_change_form' template,
containing the available vehicles and the current customer's name."""
vehicle = request.env['fleet.vehicle'].sudo().search(
[('states_id', '!=', False)])
customer = request.env.user.partner_id.name
customer_id = request.env['res.partner'].sudo().search(
[('name', '=', customer)])
vals = {
'vehicles': vehicle,
'customers': customer_id.name,
}
return http.request.render(
'vehicle_subscription.subscription_change_form', vals)
@http.route('/online/subscription/change/vehicle', auth='public',
type='http', website=True)
def change_click_form(self, **kwargs):
""" Rendered response based on the conditions:
- If the 'customer' parameter exists, render the
'vehicle_subscription.subscription_change_button' template
with the provided data.
- If the 'customer' parameter does not exist, render the
'vehicle_subscription.subscription_change_boolean_false'
template."""
if kwargs.get('customer'):
customer = kwargs.get('customer')
vehicle = int(kwargs.get('vehicle'))
reason = kwargs.get('reason')
checkbox = kwargs.get('checkbox_model')
customer_id = request.env['res.partner'].sudo(). \
search([('name', '=', customer)])
vehicle_id = request.env['fleet.vehicle'].sudo().browse(vehicle)
new_vehicle_id = request.env['fleet.vehicle'].sudo() \
.search([('model_id', '=', vehicle_id.model_id.id)])
if checkbox == 'on':
values = {
'customer_name': customer_id.name,
'vehicle_name': vehicle_id.name,
'vehicles': [rec for rec in new_vehicle_id],
'reason': reason,
}
return request.render(
'vehicle_subscription.subscription_change_button', values)
else:
return request.render(
'vehicle_subscription.subscription_change_boolean_false')
else:
return request.render(
'vehicle_subscription.subscription_change_button')
@http.route('/online/subscription/change/button', auth='public',
type='http', website=True)
def click_form(self, **kwargs):
"""Rendered response for the
'vehicle_subscription.change_subscription' template. """
customer = kwargs.get('customer')
reason = kwargs.get('reason')
current_vehicle = kwargs.get('vehicle')
vehicle_id = int(kwargs.get('new_vehicle'))
current_vehicle_id = request.env['fleet.vehicle'].sudo() \
.search([('name', '=', current_vehicle)])
customer_id = request.env['res.partner'].sudo() \
.search([('name', '=', customer)])
vehicle = request.env['fleet.vehicle'].sudo().browse(vehicle_id)
change_subscription = request.env['subscription.request'] \
.sudo().create({
'current_vehicle': current_vehicle_id.id,
'new_vehicle_id': vehicle.id,
'reason_to_change': reason,
'customer_id': customer_id.id,
})
change_subscription.state = 'to_approve'
return request.render('vehicle_subscription.change_subscription')
@http.route('/online/proceed/cancellation', auth='public', type='http',
website=True)
def proceed_cancellation(self):
"""Proceed with cancellation in change subscription """
return request.redirect('/online/subscription/cancel')
@http.route(['/web/signup/user'], type='http', auth="user",
website=True)
def redirect_login(self):
"""Used to redirect on clicking signup page"""
return request.redirect('/online/subscription')

63
vehicle_subscription/controllers/website_portal.py

@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Rahna Rasheed (<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 odoo import http
from odoo.http import request
from odoo.addons.portal.controllers.portal import CustomerPortal, \
pager as portal_pager
class PortalAccount(CustomerPortal):
"""PortalAccount for subscription"""
@http.route(['/my/subscription/invoice'], type='http', auth="user",
website=True)
def portal_my_subscription_order(self, page=1, date_begin=None,
date_end=None, sortby=None, filterby=None):
"""Rendered response for the '
vehicle_subscription.portal_my_invoices_subscription' template,
containing the subscription invoices."""
partner = request.env.user.partner_id
values = self._prepare_my_invoices_values(page, date_begin, date_end,
sortby, filterby)
pager = portal_pager(**values['pager'])
domain = [
('invoice_line_ids.product_id', 'like', 'Vehicle Subscription'),
('partner_id', '=', partner.id)
]
values.update({
'invoices': request.env['account.move'].sudo().search(domain),
'pager': pager,
})
return request.render(
"vehicle_subscription.portal_my_invoices_subscription", values)
def _prepare_home_portal_values(self, counters):
"""Prepare the values for the home portal page."""
values = super()._prepare_home_portal_values(counters)
partner = request.env.user.partner_id
if 'subscription_count' in counters:
values['subscription_count'] = request.env['account.move'].sudo() \
.search_count(
[(
'invoice_line_ids.product_id', 'like', 'Vehicle Subscription'),
('partner_id', '=', partner.id)])
return values

14
vehicle_subscription/data/ir_cron_data.xml

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--Cron action for checking expiration-->
<record id="ir_cron_expiry_date_action" model="ir.cron">
<field name="name">Subscription Expired</field>
<field name="model_id" ref="model_fleet_subscription"/>
<field name="state">code</field>
<field name="code">model._onchange_end_date()</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field name="active" eval="True"/>
</record>
</odoo>

76
vehicle_subscription/data/mail_data.xml

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--Cron action for checking expiration-->
<record id="ir_cron_expiry_date_action" model="ir.cron">
<field name="name">Subscription Expired</field>
<field name="model_id" ref="model_fleet_subscription"/>
<field name="state">code</field>
<field name="code">model._onchange_end_date()</field>
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field name="active" eval="True"/>
</record>
<!--Subscription cancellation mail template-->
<record id="cancellation_request_mail" model="mail.template">
<field name="name">Vehicle Cancellation</field>
<field name="model_id"
ref="vehicle_subscription.model_cancellation_request"/>
<field name="subject">Subscription Cancellation</field>
<field name="body_html" type="html">
<div style="margin: 0px; padding: 0px;">
<p>
Dear
<br/>
Sorry....you need to pay amount till date inorder to cancel
subscription.Your invoice is attached
below
<br/>
</p>
Regards,
<br/>
<t t-out="user.name"/>
</div>
</field>
</record>
<!-- Mail template for refund in subscription cancellation -->
<record id="cancellation_request_refund_mail" model="mail.template">
<field name="name">Vehicle Cancellation</field>
<field name="model_id"
ref="vehicle_subscription.model_cancellation_request"/>
<field name="subject">Subscription Cancellation</field>
<field name="body_html" type="html">
<div style="margin: 0px; padding: 0px;">
<p>
Dear
<br/>
The amount should be refunded immediately.
<br/>
</p>
Regards,
<br/>
<t t-out="user.name"/>
</div>
</field>
</record>
<!-- Mail template for approval of subscription cancellation -->
<record id="cancellation_approved" model="mail.template">
<field name="name">Vehicle Cancellation</field>
<field name="model_id"
ref="vehicle_subscription.model_cancellation_request"/>
<field name="subject">Subscription Cancellation</field>
<field name="body_html" type="html">
<div style="margin: 0px; padding: 0px;">
<p>
Dear
<br/>
Your request for subscription cancellation is approved
<br/>
</p>
Regards,
<br/>
<t t-out="user.name"/>
</div>
</field>
</record>
</odoo>

13
vehicle_subscription/data/product_template_data.xml

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!--Created vehicle subscription as a service product-->
<record id="product_template_vehicle_subscription_form"
model="product.template">
<field name="name">Vehicle Subscription</field>
<field name="detailed_type">service</field>
<field name="invoice_policy">order</field>
<field name="sequence" type="int">55</field>
</record>
</data>
</odoo>

12
vehicle_subscription/data/website_menu_data.xml

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!--Subscription form in website -->
<data noupdate="1">
<record id="menu_subscription_form" model="website.menu">
<field name="name">Subscription Form</field>
<field name="url">/online/subscription</field>
<field name="parent_id" ref="website.main_menu"/>
<field name="sequence" type="int">55</field>
</record>
</data>
</odoo>

6
vehicle_subscription/doc/RELEASE_NOTES.md

@ -0,0 +1,6 @@
## Module <vehicle_subscription>
#### 15.02.2024
#### Version 16.0.1.0.0
#### ADD
Initial Commit Vehicle Subscription Management

29
vehicle_subscription/models/__init__.py

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Rahna Rasheed (<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 . import account_move
from . import cancellation_request
from . import fleet_subscription
from . import fleet_vehicle
from . import fleet_vehicle_model
from . import insurance_type
from . import subscription_request
from . import vehicle_insurance

32
vehicle_subscription/models/account_move.py

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Rahna Rasheed (<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 odoo import fields, models
class AccountMove(models.Model):
"""Inherited account.move to add a field """
_inherit = 'account.move'
is_subscription = fields.Boolean(string="Subscribe",
help="This field will be set true for "
"invoice corresponding to vehicle "
"subscription")

262
vehicle_subscription/models/cancellation_request.py

@ -0,0 +1,262 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Rahna Rasheed (<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/>.
#
#############################################################################
import base64
from odoo import fields, models
class CancellationRequest(models.Model):
"""Created new model to add new fields and function"""
_name = "cancellation.request"
_description = "Cancellation Request"
_inherit = "mail.thread"
_rec_name = 'vehicle_id'
vehicle_id = fields.Many2one('fleet.vehicle',
string="Vehicle", help="Choose vehicle "
"inorder to cancel "
"subscription")
date = fields.Date(string="Cancellation Date", default=fields.Date.today(),
help="Date for cancellation of vehicle")
customer_id = fields.Many2one('res.partner', string="Customer",
help="Choose Customer for the cancellation "
"of vehicle")
reason = fields.Char(string="Cancellation Reason", help="Describe the "
"reason for "
"cancellation")
state = fields.Selection(selection=[('draft', 'Draft'),
('to_approve', 'To Approve'),
('approved', 'Approved')],
string='State', default='draft',
help="States of cancellation subscription")
def action_request(self):
"""Change state to to_approve"""
self.write({'state': 'to_approve'})
def action_approve(self):
"""Handle cancellation approval by manager.
This method handles the approval process for a cancellation
request in a vehicle subscription system.
It updates the cancellation state, generates invoices or refunds
based on the payment status, and sends notifications to the customer."""
self.write({'state': 'approved'})
subscription = self.env['fleet.subscription'].search(
[('vehicle_id', '=', self.vehicle_id.id),
('customer_id', '=', self.customer_id.id)])
invoice = subscription.sale_id.invoice_ids
multy_invoice = subscription.invoice_ids.ids
product_template_id = self.env.ref(
'vehicle_subscription.product_template_vehicle_subscription_form').id
product_id = self.env['product.product'].search(
[('product_tmpl_id', '=', product_template_id)])
per_day_price = subscription.sale_id.amount_untaxed / subscription.duration
invoice_duration = (self.date - subscription.start_date).days
email_template = self.env.ref(
'vehicle_subscription.cancellation_request_mail')
template_approved = self.env.ref(
'vehicle_subscription.cancellation_approved')
refund_approved = self.env.ref(
'vehicle_subscription.cancellation_request_refund_mail')
uptodate_price = round(per_day_price * invoice_duration, 2)
paid_amount = self.env['account.move'].search(
[('id', 'in', subscription.invoice_ids.ids),
('payment_state', 'in', ['paid', 'partial'])]) \
.mapped('amount_untaxed_signed')
if paid_amount:
if sum(paid_amount) == uptodate_price:
subscription.state = 'cancel'
email_values = {
'email_to': self.customer_id.email,
'email_from': self.env.user.email,
}
template_approved.send_mail(self.id, email_values=email_values,
force_send=True)
elif sum(paid_amount) < uptodate_price:
if len(invoice) == 1 or len(multy_invoice) == 1:
invoice.button_cancel()
generate_invoice = self.env['account.move'].sudo().create({
'move_type': 'out_invoice',
'partner_id': self.customer_id.id,
'invoice_date': self.date,
'invoice_line_ids': [(0, 0, {
'product_id': product_id.id,
'name': self.vehicle_id.name,
'price_unit':
(per_day_price * invoice_duration) - sum(
paid_amount),
})]
})
generate_invoice.action_post()
data_record = base64.b64encode(
self.env['ir.actions.report'].sudo()._render_qweb_pdf(
"account.account_invoices",
generate_invoice.ids)[0])
ir_values = {
'name': 'Invoice',
'type': 'binary',
'datas': data_record,
'store_fname': 'invoice.pdf',
'mimetype': 'application/pdf',
'res_model': 'account.move',
'res_id': generate_invoice.id,
}
invoice_report_attachment_id = self.env[
'ir.attachment'].sudo().create(
ir_values)
email_values = {
'email_to': self.customer_id.email,
'email_from': self.env.user.email,
'attachment_ids': [
(4, invoice_report_attachment_id.id, None)]
}
email_template.send_mail(self.id, email_values=email_values,
force_send=True)
email_template.attachment_ids = [(5, 0, 0)]
subscription.invoice_ids = [(4, generate_invoice.id)]
subscription.sale_id.write({
'invoice_ids': [(4, generate_invoice.id)]
})
else:
for invoice_id in multy_invoice:
invoice = self.env['account.move'].browse(invoice_id)
invoice.button_cancel()
generate_invoice = self.env['account.move'].sudo().create({
'move_type': 'out_invoice',
'partner_id': self.customer_id.id,
'invoice_date': self.date,
'invoice_line_ids': [(0, 0, {
'product_id': product_id.id,
'name': self.vehicle_id.name,
'price_unit':
(per_day_price * invoice_duration) - sum(
paid_amount),
})]
})
generate_invoice.action_post()
data_record = base64.b64encode(
self.env['ir.actions.report'].sudo()._render_qweb_pdf(
"account.account_invoices",
generate_invoice.ids)[0])
ir_values = {
'name': 'Invoice',
'type': 'binary',
'datas': data_record,
'store_fname': 'invoice.pdf',
'mimetype': 'application/pdf',
'res_model': 'account.move',
'res_id': generate_invoice.id,
}
invoice_report_attachment_id = self.env[
'ir.attachment'].sudo().create(
ir_values)
email_values = {
'email_to': self.customer_id.email,
'email_from': self.env.user.email,
'attachment_ids': [
(4, invoice_report_attachment_id.id, None)]
}
email_template.send_mail(self.id, email_values=email_values,
force_send=True)
email_template.attachment_ids = [(5, 0, 0)]
subscription.invoice_ids = [(4, generate_invoice.id)]
subscription.sale_id.write({
'invoice_ids': [(4, generate_invoice.id)]
})
else:
generate_refund = self.env['account.move'].sudo().create({
'move_type': 'out_refund',
'invoice_date': fields.Date.today(),
'partner_id': self.customer_id.id,
'invoice_line_ids': [(0, 0, {
'product_id': product_id.id,
'name': self.vehicle_id.name,
'price_unit': (sum(paid_amount) - uptodate_price)
})]
})
generate_refund.action_post()
subscription.refund_id = generate_refund
data_record = base64.b64encode(
self.env['ir.actions.report'].sudo()._render_qweb_pdf(
"account.account_invoices",
generate_refund.ids)[0])
ir_values = {
'name': 'Invoice',
'type': 'binary',
'datas': data_record,
'store_fname': 'invoice.pdf',
'mimetype': 'application/pdf',
'res_model': 'account.move',
'res_id': generate_refund.id,
}
invoice_report_attachment_id = self.env[
'ir.attachment'].sudo().create(
ir_values)
email_values = {
'email_to': self.customer_id.email,
'email_from': self.env.user.email,
'attachment_ids': [
(4, invoice_report_attachment_id.id, None)]
}
refund_approved.send_mail(self.id, email_values=email_values,
force_send=True)
refund_approved.attachment_ids = [(5, 0, 0)]
else:
invoice.button_cancel()
generate_invoice = self.env['account.move'].sudo().create({
'move_type': 'out_invoice',
'partner_id': self.customer_id.id,
'invoice_date': self.date,
'invoice_line_ids': [(0, 0, {
'product_id': product_id.id,
'name': self.vehicle_id.name,
'price_unit': per_day_price * invoice_duration,
})]
})
generate_invoice.action_post()
data_record = base64.b64encode(
self.env['ir.actions.report'].sudo()._render_qweb_pdf(
"account.account_invoices",
generate_invoice.ids)[0])
ir_values = {
'name': 'Invoice',
'type': 'binary',
'datas': data_record,
'store_fname': 'invoice.pdf',
'mimetype': 'application/pdf',
'res_model': 'account.move',
'res_id': generate_invoice.id,
}
invoice_report_attachment_id = self.env[
'ir.attachment'].sudo().create(
ir_values)
email_values = {
'email_to': self.customer_id.email,
'email_from': self.env.user.email,
'attachment_ids': [(4, invoice_report_attachment_id.id, None)]
}
email_template.send_mail(self.id, email_values=email_values,
force_send=True)
email_template.attachment_ids = [(5, 0, 0)]
subscription.invoice_ids = [(4, generate_invoice.id)]
subscription.sale_id.write({
'invoice_ids': [(4, generate_invoice.id)]
})

377
vehicle_subscription/models/fleet_subscription.py

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

69
vehicle_subscription/models/fleet_vehicle.py

@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Rahna Rasheed (<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
from odoo import api, fields, models
class FleetVehicle(models.Model):
"""Inherited model to add fields and functions"""
_inherit = 'fleet.vehicle'
free_km = fields.Float(string="Free KM", required=True, default=1500,
help="Set free km for each vehicle")
subscription_price = fields.Float(string="Subscription price per day",
help='Price of vehicle per day',
required=True, default=12)
states_id = fields.Many2one("res.country.state", string='State',
help="Help you choose the state")
countries_id = fields.Many2one('res.country', string='Country',
help="help you to choose country")
insurance = fields.Char(string="Insurance",
help="Helps you to set Insurance")
start = fields.Date(string="Start Date",
help="Helps you to choose start date")
end = fields.Date(string="End Date", help="Helps you to choose end date")
duration = fields.Integer(string="Duration", compute='_compute_duration')
fuel = fields.Selection(selection=[('with_fuel', 'With Fuel'),
('without_fuel', 'Without Fuel')],
string="Fuel Choice", default='without_fuel',
help="Help you to choose the type of fuel")
fuel_rate = fields.Integer(String="Rate", default=300, help="Rate of fuel")
charge_km = fields.Integer(string="Charge in km", default=12,
help="Rate per kilometer")
extra_km = fields.Float(string="Extra KMS", default=1500,
help="As per customer he/she can choose extra km")
mileage = fields.Float(related='model_id.mileage', string='Mileage',
help="Helps to set mileage of vehicle")
@api.depends('start', 'end')
def _compute_duration(self):
"""Compute duration of days based on start and end date"""
for record in self:
if record.start and record.end:
start = record.start.strftime("%Y-%m-%d")
end = record.end.strftime("%Y-%m-%d")
start_datetime = datetime.strptime(start, "%Y-%m-%d")
end_datetime = datetime.strptime(end, "%Y-%m-%d")
delta = end_datetime - start_datetime
record.duration = delta.days
else:
record.duration = 0

34
vehicle_subscription/models/fleet_vehicle_model.py

@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Rahna Rasheed (<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 odoo import fields, models
class FleetVehicleModel(models.Model):
"""Inherited fleet.vehicle.model to add fields"""
_inherit = 'fleet.vehicle.model'
mileage = fields.Float(string="Mileage", required=True,
default=12, help="Helps you to set mileage for "
"vehicle")
seats = fields.Integer(string='Seats Number', required=True,
default=4, helps="Helps you to choose seating "
"capacity")

46
vehicle_subscription/models/insurance_type.py

@ -0,0 +1,46 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Rahna Rasheed (<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 odoo import fields, models
class InsuranceType(models.Model):
"""New model insurance type to add fields"""
_name = "insurance.type"
_description = "Insurance type"
_inherit = "mail.thread"
name = fields.Char(string="Insurance Name",
help="This field is used to set name for insurance")
coverage_ids = fields.One2many('insurance.coverage', 'coverage_id',
string="Coverage",
help="Helps you to give details of coverage")
class InsuranceCoverageType(models.Model):
"""One2many field for insurance type"""
_name = 'insurance.coverage'
_description = "Insurance Coverage"
description = fields.Char(string="Description", help="Detail of coverage")
coverage_price = fields.Float(string="Price", help="Rate of insurance")
coverage_id = fields.Many2one('insurance.type',
help="Can choose insurance type")

92
vehicle_subscription/models/subscription_request.py

@ -0,0 +1,92 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Rahna Rasheed (<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 odoo import api, fields, models
class SubscriptionRequest(models.Model):
"""New model subscription.request"""
_name = "subscription.request"
_description = "Subscription Request"
_inherit = "mail.thread"
_rec_name = "new_vehicle_id"
customer_id = fields.Many2one('res.partner', string="Customer",
help="Choose the customer for subscription "
"request")
sale_id = fields.Many2one('sale.order', string='sale', readonly=True,
help="Helps you to store sale order")
refund_id = fields.Many2one('account.move', string='Refund', readonly=True)
current_vehicle_id = fields.Many2one('fleet.vehicle',
string="Current Vehicle",
help="Currently using vehicle of "
"customer will be set")
new_vehicle_id = fields.Many2one('fleet.vehicle', string="New Vehicle"
, domain="[('id', 'in', vehicle_ids)]",
help="Can choose different vehicle "
"with same model")
vehicle_ids = fields.Many2many('fleet.vehicle',
compute='_compute_vehicle_ids',
help="Compute and can choose vehicle with "
"satisfying domain ")
reason_to_change = fields.Char(string="Reason",
help="Reason for changing vehicle")
state = fields.Selection(
selection=[('to_approve', 'To Approve'),
('approved', 'Approved'),
], string='State', default='to_approve',
help="States of subscription")
@api.depends('current_vehicle_id')
def _compute_vehicle_ids(self):
"""This method searches for vehicles with the same model and brand
as the current vehicle, excluding the current vehicle itself.
The vehicle IDs are updated accordingly, and the state
is set to 'to_approve'."""
self.vehicle_ids = False
model_id = self.env['fleet.vehicle'].search(
[('model_id', '=', self.current_vehicle_id.model_id.id),
('model_id.brand_id', '=',
self.current_vehicle_id.model_id.brand_id.id),
('id', '!=', self.current_vehicle_id.id)])
for record in model_id:
self.vehicle_ids = [(4, record.id)]
self.write({'state': 'to_approve'})
def action_approve(self):
""" Process the approval of the subscription request."""
subscription = self.env['fleet.subscription'].search(
[('vehicle_id', '=', self.current_vehicle_id.id),
('state', '=', 'subscribed')])
subscription.update({
'vehicle_id': self.new_vehicle_id,
'invisible_sub': True,
})
self.write({'state': 'approved'})
sale_order = subscription.sale_id
if sale_order.order_line:
sale_order.order_line[0].name = self.new_vehicle_id.name
invoice_ids = subscription.invoice_ids
for rec in invoice_ids:
if rec.invoice_line_ids:
rec.invoice_line_ids[0].name = self.new_vehicle_id.name
subscription.write({'sale_id': sale_order.id})
subscription.write({'invoice_ids': invoice_ids.ids})

47
vehicle_subscription/models/vehicle_insurance.py

@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Rahna Rasheed (<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 odoo import fields, models
class VehicleInsurance(models.Model):
"""New model vehicle .insurance"""
_name = "vehicle.insurance"
_description = "Vehicle Insurance"
_inherit = "mail.thread"
_rec_name = "insurance_type_id"
vehicle_id = fields.Many2one('fleet.vehicle', string="Vehicle",
help="Help you to choose vehicle")
start_date = fields.Date(string="Start Date", help="Insurance start date")
end_date = fields.Date(string="End Date", help="Insurance end date")
insurance_type_id = fields.Many2one('insurance.type',
string='Insurance Type',
help="Choose insurance type")
insurance_amount = fields.Float(string="Amount",
compute="_compute_insurance_amount",
help="Calculate insurance amount")
def _compute_insurance_amount(self):
"""Function used to compute insurance amount"""
for rec in self:
rec.insurance_amount = sum(rec.insurance_type_id.coverage_ids.
mapped('coverage_price'))

8
vehicle_subscription/security/ir.model.access.csv

@ -0,0 +1,8 @@
id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
access_fleet_subscription,access.fleet.subscription,model_fleet_subscription,base.group_user,1,1,1,1
access_vehicle_insurance,access.vehicle.insurance,model_vehicle_insurance,base.group_user,1,1,1,1
access_subscription_request,access.subscription.request,model_subscription_request,base.group_user,1,1,1,1
access_change_subscription,access.change.subscription,model_change_subscription,base.group_user,1,1,1,1
access_insurance_type,access.insurance.type,model_insurance_type,base.group_user,1,1,1,1
access_insurance_coverage,access.insurance.coverage,model_insurance_coverage,base.group_user,1,1,1,1
access_cancellation_request,access.cancellation.request,model_cancellation_request,base.group_user,1,1,1,1
1 id name model_id/id group_id/id perm_read perm_write perm_create perm_unlink
2 access_fleet_subscription access.fleet.subscription model_fleet_subscription base.group_user 1 1 1 1
3 access_vehicle_insurance access.vehicle.insurance model_vehicle_insurance base.group_user 1 1 1 1
4 access_subscription_request access.subscription.request model_subscription_request base.group_user 1 1 1 1
5 access_change_subscription access.change.subscription model_change_subscription base.group_user 1 1 1 1
6 access_insurance_type access.insurance.type model_insurance_type base.group_user 1 1 1 1
7 access_insurance_coverage access.insurance.coverage model_insurance_coverage base.group_user 1 1 1 1
8 access_cancellation_request access.cancellation.request model_cancellation_request base.group_user 1 1 1 1

17
vehicle_subscription/security/vehicle_subscription_groups.xml

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--User access levels for Fleet module-->
<record id="module_vehicle_subscription" model="ir.module.category">
<field name="name">Vehicle Subscription</field>
<field name="description">User access levels for Fleet module</field>
<field name="sequence">10</field>
</record>
<record id="vehicle_subscription_group_user" model="res.groups">
<field name="name">User</field>
<field name="category_id" ref="module_vehicle_subscription"/>
</record>
<record id="vehicle_subscription_group_manager" model="res.groups">
<field name="name">Manager</field>
<field name="category_id" ref="module_vehicle_subscription"/>
</record>
</odoo>

BIN
vehicle_subscription/static/description/assets/icons/check.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
vehicle_subscription/static/description/assets/icons/chevron.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

BIN
vehicle_subscription/static/description/assets/icons/cogs.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
vehicle_subscription/static/description/assets/icons/consultation.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
vehicle_subscription/static/description/assets/icons/ecom-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

BIN
vehicle_subscription/static/description/assets/icons/education-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

BIN
vehicle_subscription/static/description/assets/icons/hotel-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

BIN
vehicle_subscription/static/description/assets/icons/license.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
vehicle_subscription/static/description/assets/icons/lifebuoy.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
vehicle_subscription/static/description/assets/icons/manufacturing-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

BIN
vehicle_subscription/static/description/assets/icons/pos-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

BIN
vehicle_subscription/static/description/assets/icons/puzzle.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

BIN
vehicle_subscription/static/description/assets/icons/restaurant-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

BIN
vehicle_subscription/static/description/assets/icons/service-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

BIN
vehicle_subscription/static/description/assets/icons/trading-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

BIN
vehicle_subscription/static/description/assets/icons/training.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

BIN
vehicle_subscription/static/description/assets/icons/update.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
vehicle_subscription/static/description/assets/icons/user.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

BIN
vehicle_subscription/static/description/assets/icons/wrench.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
vehicle_subscription/static/description/assets/misc/categories.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
vehicle_subscription/static/description/assets/misc/check-box.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
vehicle_subscription/static/description/assets/misc/compass.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
vehicle_subscription/static/description/assets/misc/corporate.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
vehicle_subscription/static/description/assets/misc/customer-support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
vehicle_subscription/static/description/assets/misc/cybrosys-logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
vehicle_subscription/static/description/assets/misc/features.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

BIN
vehicle_subscription/static/description/assets/misc/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
vehicle_subscription/static/description/assets/misc/pictures.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
vehicle_subscription/static/description/assets/misc/pie-chart.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
vehicle_subscription/static/description/assets/misc/right-arrow.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 967 B

BIN
vehicle_subscription/static/description/assets/misc/star.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
vehicle_subscription/static/description/assets/misc/support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
vehicle_subscription/static/description/assets/misc/whatsapp.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
vehicle_subscription/static/description/assets/misc/white-arrow.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 B

BIN
vehicle_subscription/static/description/assets/modules/1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
vehicle_subscription/static/description/assets/modules/2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

BIN
vehicle_subscription/static/description/assets/modules/3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
vehicle_subscription/static/description/assets/modules/4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
vehicle_subscription/static/description/assets/modules/5.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

BIN
vehicle_subscription/static/description/assets/modules/6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
vehicle_subscription/static/description/assets/screenshots/hero.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 KiB

BIN
vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_01.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_02.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

BIN
vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_03.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_04.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

BIN
vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_05.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

BIN
vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_06.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

BIN
vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_07.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

BIN
vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_08.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

BIN
vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_09.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

BIN
vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_10.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

BIN
vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_11.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

BIN
vehicle_subscription/static/description/assets/screenshots/vehicle_subscription_12.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

BIN
vehicle_subscription/static/description/banner.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

BIN
vehicle_subscription/static/description/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

631
vehicle_subscription/static/description/index.html

@ -0,0 +1,631 @@
<div style="background-color: #714B67; height: 810px; width: 100%; padding: 15px; position: relative;">
<!-- TITLE BAR -->
<div class="d-flex align-items-center justify-content-between"
style="border-bottom: 1px solid #875A7B; padding: 15px; display: flex; justify-content: space-between; align-items: center;">
<img src="assets/misc/cybrosys-logo.png" width="42" height="42" style="width: 42px; height: 42px;"/>
<div>
<div
style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Community
</div>
<div
style="color: #875A7B; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Enterprise
</div>
<div
style="color: #017E84; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Odoo.sh
</div>
</div>
</div>
<!-- END OF TITLE BAR -->
<div class="container">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12">
<!-- APP HERO -->
<h1 style="color: #FFFFFF; font-weight: bolder; font-size: 50px; text-align: center; margin-top: 50px;">
Vehicle Subscription Management</h1>
<p style="color:#FFFFFF; padding: 8px 15px; text-align: center; font-size: 24px;">Vehicle Subscription Management From Website</p>
<!-- END OF APP HERO -->
<img src="assets/screenshots/hero.gif" class="img-responsive"
style="width: 100%; margin-left: auto; margin-right: auto;"/>
</div>
</div>
</div>
</div>
<!-- NAVIGATION SECTION -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px; margin-top: 300px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/compass.png"/>
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Explore This
Module</h2>
</div>
<div class="row my-4" style="font-family: 'Montserrat', sans-serif;">
<div class="col-sm-12 col-md-6 my-3">
<a href="#overview">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Overview</span>
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">Learn
more about this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#features">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Features</span>
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View
features of this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#screenshots">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Screenshots</span>
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View
screenshots for this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
</div>
<!-- END OF NAVIGATION SECTION -->
<!-- OVERVIEW SECTION -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="overview">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pie-chart.png"/>
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Overview
</h2>
</div>
<div class="row" style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 py-4">
This module helps you to Subscribe,Cancel and Change subscription through website as well as backend.
</div>
</div>
<!-- END OF OVERVIEW SECTION -->
<!-- FEATURES SECTION -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="features">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/features.png"/>
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Features
</h2>
</div>
<div class="row" style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 col-md-6">
<div class="d-flex align-items-center" style="margin-top: 40px; margin-bottom: 40px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Community &amp;
Enterprise Support.</span>
</div>
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Subscription of vehicle</span>
</div>
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Cancellation of subscription</span>
</div>
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Option to switch subscription</span>
</div>
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Payment option Monthly and Full Payment from website</span>
</div>
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Down Payment </span>
</div>
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Option to choose vehicle based on Location</span>
</div>
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Can decide Insurance type</span>
</div>
</div>
</div>
<!-- END OF FEATURES SECTION -->
<!-- SCREENSHOTS SECTION -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="screenshots">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pictures.png"/>
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Screenshots
</h2>
</div>
<div class="row">
<div class="col-sm-12">
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Vehicle Subscription
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Go to Website ->
Subscription Form ->
Choose Location , Insurance and duration of subscription.</p>
<img src="assets/screenshots/vehicle_subscription_01.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Choose Vehicle
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Book vehicle from
listed vehicle user can change default km choose fuel type ,choose payment type. </p>
<img src="assets/screenshots/vehicle_subscription_02.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Subscription Order
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Go to Fleet
-> Under Fleet Menu ->In Subscription submenu -> Subscription Order get created </p>
<img src="assets/screenshots/vehicle_subscription_04.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Subscription order in
Portal view.
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Go to My Account ->
Subscription Order -> User can see their invoices so that they can pay change and cancel subscription
from invoice</p>
<img src="assets/screenshots/vehicle_subscription_05.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Cancel subscription
</h3>
<img src="assets/screenshots/vehicle_subscription_06.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Cancellation form
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Specify the Reason </p>
<img src="assets/screenshots/vehicle_subscription_07.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Cancel Request
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">By submitting the
cancellation form cancel request will be generated in backend.</p>
<img src="assets/screenshots/vehicle_subscription_08.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Switch Subscription
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">From portal , user have
option to Change Subscription.</p>
<img src="assets/screenshots/vehicle_subscription_09.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Change Subscription
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">User need to choose
whether he or she needs to change for same model vehicle or different model and need to specify the
reason.</p>
<img src="assets/screenshots/vehicle_subscription_10.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Switch Subscription
to new vehicle
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">If user chosen same
model, then user will redirect to the different form where user can choose vehicle of same model .</p>
<img src="assets/screenshots/vehicle_subscription_11.png" class="img-thumbnail">
</div>
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Switch Request
</h3>
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;">Go to Fleet ->
Configuration -> Change Subscription -> Request for switching subscription will be generated</p>
<img src="assets/screenshots/vehicle_subscription_12.png" class="img-thumbnail">
</div>
</div>
</div>
<!-- END OF SCREENSHOTS SECTION -->
<!-- RELATED PRODUCTS -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/categories.png"/>
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Related
Products
</h2>
</div>
<div class="row">
<div class="col-sm-12">
<div id="demo1" class="row carousel slide" data-ride="carousel">
<!-- The slideshow -->
<div class="carousel-inner" style="padding: 30px;">
<div class="carousel-item" style="min-height: 198.656px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/dynamic_accounts_report/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block" style="border-radius: 0px;"
src="assets/modules/1.png">
</div>
</a>
</div>
</div>
<div class="carousel-item active" style="min-height: 198.656px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/pos_product_creation//" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block" style="border-radius: 0px;"
src="assets/modules/2.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/pos_mrp_order/#" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block" style="border-radius: 0px;"
src="assets/modules/3.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/product_barcode/#overview" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block" style="border-radius: 0px;"
src="assets/modules/4.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/hr_organizational_chart/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block" style="border-radius: 0px;"
src="assets/modules/5.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/timesheets_by_employee/" target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block" style="border-radius: 0px;"
src="assets/modules/6.png">
</div>
</a>
</div>
</div>
</div>
<!-- Left and right controls -->
<a class="carousel-control-prev" href="#demo1" data-slide="prev" style="width:35px; color:#000"> <span
class="carousel-control-prev-icon"><i class="fa fa-chevron-left" style="font-size:24px"></i></span>
</a> <a class="carousel-control-next" href="#demo1" data-slide="next" style="width:35px; color:#000">
<span class="carousel-control-next-icon"><i class="fa fa-chevron-right" style="font-size:24px"></i></span>
</a>
</div>
</div>
</div>
<!-- END OF RELATED PRODUCTS -->
<!-- OUR SERVICES -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/star.png"/>
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Our Services
</h2>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #1dd1a1 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/cogs.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Customization</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ff6b6b !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/wrench.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6462CD !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/lifebuoy.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Support</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ffa801 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/user.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Hire
Odoo
Developer</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #54a0ff !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/puzzle.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Integration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6d7680 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/update.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Migration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #786fa6 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/consultation.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Consultancy</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #f8a5c2 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/training.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #e6be26 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/license.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Licensing Consultancy</h6>
</div>
</div>
</div>
<!--END OF OUR SERVICES -->
<!-- OUR INDUSTRIES -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/corporate.png"/>
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Our
Industries
</h2>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/trading-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Trading
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easily procure
and
sell your products</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/pos-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
POS
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easy
configuration
and convivial experience</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/education-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Education
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
A platform for
educational management</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/manufacturing-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Manufacturing
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Plan, track and
schedule your operations</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/ecom-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
E-commerce &amp; Website
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Mobile
friendly,
awe-inspiring product pages</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/service-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Service Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Keep track of
services and invoice</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/restaurant-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Restaurant
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Run your bar or
restaurant methodically</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/hotel-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Hotel Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
An
all-inclusive
hotel management application</p>
</div>
</div>
</div>
</div>
<!-- END OF OUR INDUSTRIES -->
<!-- SUPPORT -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/customer-support.png"/>
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Support
</h2>
</div>
<div class="container mt-5">
<div class="row">
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4 d-flex justify-content-center align-items-center"
style="background-color: #714B67; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/support.png" height="48" width="48" style="width: 42px; height: 42px;"/>
</div>
<div>
<h4>Need Help?</h4>
<p style="line-height: 100%;">Got questions or need help? Get in touch.</p>
<a href="mailto:odoo@cybrosys.com">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">
odoo@cybrosys.com</p>
</a>
</div>
</div>
</div>
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4 d-flex justify-content-center align-items-center"
style="background-color: #2AC44D; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/whatsapp.png" height="52" width="52" style="width: 52px; height: 52px;"/>
</div>
<div>
<h4>WhatsApp</h4>
<p style="line-height: 100%;">Say hi to us on WhatsApp!</p>
<a href="https://api.whatsapp.com/send?phone=918606827707">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">+91 86068
27707</p>
</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 my-5 d-flex justify-content-center align-items-center">
<img src="assets/misc/logo.png" width="144" height="31"
style="width:144px; height: 31px; margin-top: 40px;"/>
</div>
</div>
</div>
<!-- END OF SUPPORT -->

31
vehicle_subscription/static/src/js/change_subscription_form.js

@ -0,0 +1,31 @@
odoo.define('vehicle_subscription.subscription_change', function (require) {
"use strict";
var publicWidget = require('web.public.widget');
const ajax = require('web.ajax');
publicWidget.registry.Change = publicWidget.Widget.extend({
selector: '.change_sub_vehicle',
start: function() {
this._super.apply(this, arguments);
this._onChangeCustomer(); // Call the function initially
},
//On the onchange function customer is passed to controller
_onChangeCustomer: async function(ev){
var self=this;
var customer_id = this.$('input[name="customer"]')[0].value
await ajax.jsonRpc('/online/choose/vehicle', "call", {
'customer_id': customer_id,
})
.then(function(result) {
const select = self.$el.find('#vehicle_change')[0];
const options = Array.from(select.options);
options.forEach((option) => {
option.remove();
});
result.forEach((item) => {
let newOption = new Option(item[1], item[0]);
select.add(newOption, undefined);
});
});
},
})
})

19
vehicle_subscription/static/src/js/change_subscription_request.js

@ -0,0 +1,19 @@
odoo.define('vehicle_subscription.subscription_submit_request', function (require) {
"use strict";
var publicWidget = require('web.public.widget');
const ajax = require('web.ajax');
//To getitem to get vehicle.
$(function() {
if (localStorage.getItem('current_vehicle')) {
$('#current_vehicle').val(localStorage.getItem('current_vehicle'));
}
});
publicWidget.registry.Request = publicWidget.Widget.extend({
selector: '.submit_boolean_on',
start: function() {
var self = this;//setitem to store the element.
var current_vehicle = self.$('#current_vehicle').val();
localStorage.setItem('current_vehicle', current_vehicle);
}
})
})

31
vehicle_subscription/static/src/js/subscription_cancellation.js

@ -0,0 +1,31 @@
odoo.define('vehicle_subscription.subscription_cancellation', function (require) {
"use strict";
var publicWidget = require('web.public.widget');
const ajax = require('web.ajax');
publicWidget.registry.Cancellation = publicWidget.Widget.extend({
selector: '.cancel_sub',
start: function() {
this._super.apply(this, arguments);
this._onChangeCustomer(); // Call the function initially
},
//On the onchange function customer is passed to controller
_onChangeCustomer: async function(ev){
var self=this;
var customer_id = this.$('input[name="customer"]')[0].value
await ajax.jsonRpc('/online/choose/vehicle', "call", {
'customer_id': customer_id,
})
.then(function(result) {
const select = self.$el.find('#vehicle_cancellation')[0];
const options = Array.from(select.options);
options.forEach((option) => {
option.remove();
});
result.forEach((item) => {
let newOption = new Option(item[1], item[0]);
select.add(newOption, undefined);
});
});
}
})
})

94
vehicle_subscription/static/src/js/vehicle_booking.js

@ -0,0 +1,94 @@
odoo.define('vehicle_subscription.book', function (require) {
"use strict";
var publicWidget = require('web.public.widget');
const ajax = require('web.ajax');
publicWidget.registry.book = publicWidget.Widget.extend({
selector: '#book_my_vehicle',
events: {
'click .redirect_back_with_data':'_onClickBack',
'click .book_now':'_onClickBook',
'click #with_fuel':'_onClickWithFuel',
'click #without_fuel':'_onClickWithoutFuel',
'change #extra_km':'_onChangeExtraKm',
'click #full_subscription':'_onClickFullPayment',
'click #monthly_subscription':'_onClickMonthlyPayment',
},
_onClickBook: async function(ev){ //Click function to book subscription
var checked=this.$('#checkbox_for_fuel')[0].checked
var invoice_checked=this.$('#checkbox_for_invoice_type')[0].checked
var customer_id = this.$('input[name="customer"]')[0].value
var km = this.$('#extra_km')[0].value
var vehicle_id = ev.currentTarget.firstChild.nextSibling.defaultValue
await ajax.jsonRpc('/online/subscription/book', "call", {
'vehicle': vehicle_id,
'customer':customer_id,
'checked':checked,
'invoice':invoice_checked,
'extra_km':km,
}).then(function(result) {
window.location.href="/next/vehicle/" +result.subscription_id;
});
},
_onClickWithFuel: async function(ev){ //Click function to set price
this.$('#checkbox_for_fuel')[0].checked = true
var km = this.$('#extra_km')[0].value
var table = this.$('#vehicle_booking_table')[0];
for (var i = 1, row; row = table.rows[i]; i++) {
for (var j = 1, col; col = row.cells[j]; j++) {
var current_price = row.cells[2].innerText
var vehicle_id = row.cells[1].getAttribute('value')
await ajax.jsonRpc('/online/subscription/with/fuel', "call", {
'vehicle': vehicle_id,
'price':current_price,
'extra_km': km,
})
.then(function(result) {
row.cells[2].innerText = result
})
}
}
},
_onClickWithoutFuel: async function(ev){//Click function to set price without fuel
this.$('#checkbox_for_fuel')[0].checked = true
var km = this.$('#extra_km')[0].value
var table = this.$('#vehicle_booking_table')[0];
for (var i = 1, row; row = table.rows[i]; i++) {
for (var j = 1, col; col = row.cells[j]; j++) {
var current_price = row.cells[2].innerText
var vehicle_id = row.cells[1].getAttribute('value')
await ajax.jsonRpc('/online/subscription/without/fuel', "call", {
'vehicle': vehicle_id,
'price':current_price,
'extra_km':km,
})
.then(function(result) {
row.cells[2].innerText = result
})
}
}
},
_onChangeExtraKm: async function(ev){ //Change function to set price using extra km
var km = ev.currentTarget.value
var table = this.$('#vehicle_booking_table')[0];
for (var i = 1, row; row = table.rows[i]; i++) {
for (var j = 1, col; col = row.cells[j]; j++) {
await ajax.jsonRpc('/online/subscription/with/fuel', "call", {
'extra_km': km,
})
.then(function(result){
row.cells[1].innerText = result
})
}
}
},
_onClickFullPayment:function(ev){//Click function
this.$('#checkbox_for_invoice_type')[0].checked = true
},
_onClickMonthlyPayment:function(ev){//Click function
this.$('#checkbox_for_invoice_type')[0].checked = true
},
_onClickBack:function(ev){//Click function for previous page
window.history.back();
}
})
})

78
vehicle_subscription/static/src/js/vehicle_subscription_success.js

@ -0,0 +1,78 @@
odoo.define('vehicle_subscription.form_page', function (require) {
"use strict";
var publicWidget = require('web.public.widget');
publicWidget.registry.form_page = publicWidget.Widget.extend({
selector: '#subscription_form_page',
events: {
'click .redirect_back_with_data':'_onClickBack',
},
_onClickBack:function(ev){ //Previous page
window.history.back();
}
})
})
odoo.define('vehicle_subscription.missing_page', function (require) {
"use strict";
var publicWidget = require('web.public.widget');
publicWidget.registry.missing_page = publicWidget.Widget.extend({
selector: '#subscription_missing_page',
events: {
'click .redirect_back_with_data':'_onClickBack',
},
_onClickBack:function(ev){ //Previous page
window.history.back();
}
})
})
odoo.define('vehicle_subscription.cancellation_page', function (require) {
"use strict";
var publicWidget = require('web.public.widget');
publicWidget.registry.cancellation_page = publicWidget.Widget.extend({
selector: '#subscription_cancellation_page',
events: {
'click .redirect_back_with_data':'_onClickBack',
},
_onClickBack:function(ev){ //Previous page
window.history.back();
}
})
})
odoo.define('vehicle_subscription.boolean_false', function (require) {
"use strict";
var publicWidget = require('web.public.widget');
publicWidget.registry.boolean_false = publicWidget.Widget.extend({
selector: '#boolean_false',
events: {
'click .redirect_back_with_data':'_onClickBack',
},
_onClickBack:function(ev){ //Previous page
window.history.back();
}
})
})
odoo.define('vehicle_subscription.boolean_true', function (require) {
"use strict";
var publicWidget = require('web.public.widget');
publicWidget.registry.boolean_true = publicWidget.Widget.extend({
selector: '#boolean_true',
events: {
'click .redirect_back_with_data':'_onClickBack',
},
_onClickBack:function(ev){ //Previous page
window.history.back();
}
})
})
odoo.define('vehicle_subscription.change_subscription_on', function (require) {
"use strict";
var publicWidget = require('web.public.widget');
publicWidget.registry.change_subscription_on = publicWidget.Widget.extend({
selector: '#change_subscription_on',
events: {
'click .redirect_back_with_data':'_onClickBack',
},
_onClickBack:function(ev){ //Previous page
window.history.back();
}
})
})

44
vehicle_subscription/static/src/js/website_subscription.js

@ -0,0 +1,44 @@
odoo.define('vehicle_subscription.subscription', function (require) {
"use strict";
var publicWidget = require('web.public.widget');
const Dialog = require('web.Dialog');
const ajax = require('web.ajax');
publicWidget.registry.Location = publicWidget.Widget.extend({
selector: '#whole_sub',
events: {
'click #location_id': '_onLocationClick',
'change #state_id':'_onStateChange',
'click #dismiss':'_onCloseClick',
},
_onLocationClick: function (ev) { //function that opens modal
var location = this.$('#location_temp')[0];
location.style.display='block';
},
_onStateChange:function(ev){ // On the change of state ,city gets changed
var self=this;
var state_id = ev.currentTarget.value
ajax.jsonRpc('/online/subscription/city', "call", {
'state': state_id,
})
.then(function(result) {
const select = self.$el.find('#city_id')[0];
const options = Array.from(select.options);
options.forEach((option) => {
option.remove();
});
result.forEach((item) => {
let newOption = new Option(item, item);
select.add(newOption, undefined);
});
});
},
// Click function of close button state and city is appended in location field.
_onCloseClick: function(ev){
var location = this.$('#location_temp')[0];
var city=this.$('#city_id')[0].value
var state=this.$("#state_id option:selected").data('state-name');
this.$('#location_id')[0].value = state +','+ city
location.style.display='none';
},
})
})

14
vehicle_subscription/views/account_move_views.xml

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--Used to add field in account.move-->
<record id="view_move_form" model="ir.ui.view">
<field name="name">account.move.view.form.inherited.vehicle.subscription</field>
<field name="model">account.move</field>
<field name="inherit_id" ref="account.view_move_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='company_id']" position="before">
<field name="is_subscription" invisible="1"/>
</xpath>
</field>
</record>
</odoo>

46
vehicle_subscription/views/cancellation_request_views.xml

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--Action of cancellation request-->
<record id="cancellation_request_action" model="ir.actions.act_window">
<field name="name">Cancellation Request</field>
<field name="res_model">cancellation.request</field>
<field name="view_mode">tree,form</field>
</record>
<!-- Form view of the cancellation request-->
<record id="cancellation_request_view_form" model="ir.ui.view">
<field name="name">cancellation.request.view.form</field>
<field name="model">cancellation.request</field>
<field name="arch" type="xml">
<form string="Channel">
<header>
<field name="state" widget="statusbar"/>
<button name="action_request" class="oe_highlight"
states="draft" string="Request"
type="object"/>
<button name="action_approve" class="oe_highlight"
states="to_approve" string="Approve"
type="object"
groups="vehicle_subscription.vehicle_subscription_group_manager"/>
</header>
<sheet>
<group>
<field name="customer_id"/>
<field name="vehicle_id"/>
<field name="date"/>
<field name="reason"/>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="message_ids"/>
</div>
</form>
</field>
</record>
<!--Menu item of cancellation-->
<menuitem id="cancellation_request_menu_action"
name="Cancellation Request"
parent="fleet.fleet_configuration"
action="cancellation_request_action"
sequence="7"/>
</odoo>

309
vehicle_subscription/views/change_vehicle_subscription_template.xml

@ -0,0 +1,309 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--Template for change subscription-->
<template id="subscription_change_form" name="Vehicle Form">
<t t-call="website.layout">
<div id="wrap" class="oe_structure oe_empty change_sub_vehicle">
<section class="s_website_form" id="change_my_vehicle"
data-vcss="001" data-snippet="s_website_form">
<div class="container">
<br/>
<h1 style="text-align: center;">Change Subscription
</h1>
<br/>
<form action="/online/subscription/change/vehicle"
method="post" enctype="multipart/form-data"
class="o_mark_required" data-mark="*"
data-model_name="" data-success-page=""
style="width: 50%;margin: 0 auto;padding: 40px;background: white;border-radius: 6px;box-shadow: 0 3px 10px rgb(0 0 0 /0.2);margin-bottom:60px">
<input type="hidden" name="csrf_token"
t-att-value="request.csrf_token()"/>
<div class="s_website_form_rows row s_col_no_bgcolor">
<div class="form-group col-12 s_website_form_field s_website_form_required"
data-type="char" data-name="Field">
<div class="row s_col_no_resize s_col_no_bgcolor"
style="display:none">
<label class="col-form-label col-sm-auto s_website_form_label"
style="width: 200px"
for="studio1">
<span class="s_website_form_label_content">
Name
</span>
<span class="s_website_form_mark">
*
</span>
</label>
<div class="col-sm">
<div class="col-sm">
<input class="form-control s_website_form_input"
name='customer'
type="text"
t-att-value="customers"/>
</div>
</div>
</div>
<br/>
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto s_website_form_label"
style="width: 200px"
for="studio1">
<span class="s_website_form_label_content">
Vehicle
</span>
<span class="s_website_form_mark">
*
</span>
</label>
<div class="col-sm">
<select id="vehicle_change"
type="text"
class="form-control s_website_form_input"
name="vehicle"
required="1">
<option t-att-value=""/>
<t t-foreach="vehicles or []"
t-as="vehicle">
<option t-att-value="vehicle.id"
required="1">
<t t-esc="vehicle.name"/>
</option>
</t>
</select>
</div>
</div>
</div>
</div>
<br/>
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto s_website_form_label"
style="width: 200px" for="studio1">
<span class="s_website_form_label_content">
Change vehicle to same model
</span>
<span class="s_website_form_mark">*</span>
</label>
<div class="col-sm">
<input type="checkbox"
name="checkbox_model"
class="form-check-input"
id="checkbox_vehicle_change"/>
</div>
</div>
<br/>
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto s_website_form_label"
style="width: 200px" for="studio1">
<span class="s_website_form_label_content">
Reason for changing vehicle
</span>
<span class="s_website_form_mark">*</span>
</label>
<div class="col-sm">
<input id="reason" type="text"
class="form-control s_website_form_input"
name="reason" required="1"
placeholder="Reason for change subscription"/>
</div>
</div>
<br/>
<br/>
<div class="form-group col-12 s_website_form_submit"
data-name="change Button"
style="margin-bottom: 40px;">
<div style="width: 200px;"
class="s_website_form_label"/>
<button type="submit" id="cancel"
class="btn btn-primary"
style="float: right;">Change
</button>
</div>
</form>
</div>
</section>
</div>
</t>
</template>
<!-- < On clicking change button if boolean is enabled >-->
<template id="subscription_change_button" name="Vehicle Form">
<t t-call="website.layout">
<div id="wrap" class="oe_structure oe_empty submit_boolean_on ">
<section class="s_website_form" id="boolean_true"
data-vcss="001" data-snippet="s_website_form">
<div class="btn btn-primary redirect_back_with_data"
style="background:none; border:none;">
<span style="font-size:18px; color:#000; background-image:url('https://cdn-icons-png.flaticon.com/512/2985/2985162.png');width: 63px;
height: 63px;display: block;background-size: 60%;margin-top: 23px;background-position: center;background-repeat: no-repeat;"/>
</div>
<div class="container">
<br/>
<h1 style="text-align: center;">Choose New vehicle</h1>
<br/>
<form action="/online/subscription/change/button"
method="post" enctype="multipart/form-data"
class="o_mark_required" data-mark="*"
data-model_name="" data-success-page=""
style="width: 50%;margin: 0 auto;padding: 30px;background: white;box-shadow: 0 3px 10px rgb(0 0 0 /0.2);margin-bottom: 40px;">
<input type="hidden" name="csrf_token"
t-att-value="request.csrf_token()"/>
<div class="s_website_form_rows row s_col_no_bgcolor"
style="display:none">
<div class="form-group col-12 s_website_form_field s_website_form_required"
data-type="char" data-name="Field">
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto s_website_form_label"
style="width: 200px"
for="studio1">
<span class="s_website_form_label_content">
Customer
</span>
<span class="s_website_form_mark">
*
</span>
</label>
<div class="col-sm">
<input class="form-control s_website_form_input"
name='customer' type="text"
t-att-value="customer_name"/>
</div>
</div>
</div>
</div>
<div class="s_website_form_rows row s_col_no_bgcolor">
<div class="form-group col-12 s_website_form_field s_website_form_required"
data-type="char" data-name="Field">
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto s_website_form_label"
style="width: 200px"
for="studio1">
<span class="s_website_form_label_content">
Reason
</span>
<span class="s_website_form_mark">
*
</span>
</label>
<div class="col-sm">
<input class="form-control s_website_form_input"
name='reason' type="text"
t-att-value="reason"/>
</div>
</div>
</div>
</div>
<br/>
<div class="s_website_form_rows row s_col_no_bgcolor">
<div class="form-group col-12 s_website_form_field s_website_form_required"
data-type="char" data-name="Field">
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto s_website_form_label"
style="width: 200px"
for="studio1">
<span class="s_website_form_label_content">
Current Vehicle
</span>
<span class="s_website_form_mark">
*
</span>
</label>
<div class="col-sm">
<input class="form-control s_website_form_input"
name='vehicle'
id="current_vehicle"
type="text"
t-att-value="vehicle_name"/>
</div>
</div>
</div>
</div>
<br/>
<div class="s_website_form_rows row s_col_no_bgcolor">
<div class="form-group col-12 s_website_form_field s_website_form_required"
data-type="char" data-name="Field">
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto s_website_form_label"
style="width: 200px"
for="studio1">
<span class="s_website_form_label_content">
New Vehicle
</span>
<span class="s_website_form_mark">
*
</span>
</label>
<div class="col-sm">
<select id="choose_vehicle"
type="text"
class="form-control s_website_form_input"
name="new_vehicle"
required="1">
<option t-att-value=""/>
<t t-foreach="vehicles or []"
t-as="vehicle">
<option t-att-value="vehicle.id"
required="1">
<t t-esc="vehicle.name"/>
</option>
</t>
</select>
</div>
</div>
</div>
</div>
<br/>
<br/>
<div class="form-group col-12 s_website_form_submit"
data-name="change Button"
style="margin-bottom: 40px;">
<div style="width: 200px;"
class="s_website_form_label"/>
<button type="submit" id="submit_request"
class="btn btn-primary"
style="float: right;">Submit
</button>
</div>
</form>
</div>
</section>
</div>
</t>
</template>
<!--< on clicking change button if boolean is not enabled >-->
<template id="subscription_change_boolean_false" name="Vehicle Form">
<t t-call="website.layout">
<div id="wrap" class="oe_structure oe_empty ">
<section class="s_website_form" id="boolean_false"
data-vcss="001" data-snippet="s_website_form"
style="width: 80%;margin: 0 auto;">
<div class="btn btn-primary redirect_back_with_data"
style="background:none; border:none;">
<span style="font-size:18px; color:#000; background-image:url('https://cdn-icons-png.flaticon.com/512/2985/2985162.png');width: 63px;
height: 63px;display: block;background-size: 60%;margin-top: 23px;background-position: center;background-repeat: no-repeat;"/>
</div>
<div class="container"
style="align-items: center; display: flex;flex-direction: column;}">
<br/>
<h5>You need to cancel subscription inorder to change
to different model
</h5>
<br/>
<form action="/online/proceed/cancellation"
method="post" enctype="multipart/form-data"
class="o_mark_required" data-mark="*"
data-model_name="" data-success-page="">
<input type="hidden" name="csrf_token"
t-att-value="request.csrf_token()"/>
<div class="form-group col-12 s_website_form_submit"
data-name="change Button">
<div class="s_website_form_label"/>
<button type="submit" id="proceed_cancel"
class="btn btn-primary">Proceed with
Cancellation
</button>
</div>
</form>
</div>
</section>
</div>
</t>
</template>
</odoo>

114
vehicle_subscription/views/fleet_subscription_views.xml

@ -0,0 +1,114 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--Action of fleet.subscription-->
<record id="fleet_subscription_action" model="ir.actions.act_window">
<field name="name">Subscription</field>
<field name="res_model">fleet.subscription</field>
<field name="view_mode">tree,form</field>
</record>
<!-- Form view of the fleet subscription-->
<record id="fleet_subscription_view_form" model="ir.ui.view">
<field name="name">fleet.subscription.view.form</field>
<field name="model">fleet.subscription</field>
<field name="arch" type="xml">
<form string="Channel">
<header>
<button name="action_invoice" class="oe_highlight"
state="draft" string="Create Order"
type="object"
attrs="{'invisible': [('state', '!=', 'draft')]}"/>
<button name="action_request" class="oe_highlight"
string="Change subscription"
type="object"
attrs="{'invisible': ['|',('state', '!=', 'subscribed'),'&amp;',('invisible_sub','=',True),('state','=','subscribed')]}"/>
<button name="action_cancel" class="oe_highlight"
state="draft" string="Cancel subscription"
type="object"
attrs="{'invisible': [('state', '!=', 'subscribed')]}"/>
<field name="state" widget="statusbar"
options="{'clickable': '1'}"/>
</header>
<sheet>
<div>
<div name="button_box" position="inside">
<button class="oe_stat_button" type="object"
name="action_get_car_insurance" icon="fa-car"
attrs="{'invisible': [('insurance_type_id', '=', False)]}"
string="Insurance">
</button>
<button class="oe_stat_button" type="object"
name="action_get_sale"
attrs="{ 'invisible': [('state', '=', 'draft')] }">
<field string="Sale Order" name="sale"
widget="statinfo"/>
</button>
<button class="oe_stat_button" type="object"
name="action_get_invoice"
attrs="{ 'invisible': [('state', '=', 'draft')]}">
<field string="Invoice" name="invoice"
widget="statinfo"/>
</button>
<button class="oe_stat_button" type="object"
name="action_get_refund"
attrs="{ 'invisible': [('refund', '=', 0), ('state', '!=', 'cancel')]}">
<field string="Refund" name="refund"
widget="statinfo"/>
</button>
</div>
</div>
<group col="2">
<group>
<field name="vehicle_id"/>
<field name="vehicle_ids" widget="many2many_tags"
invisible="True"/>
<field name="customer_id"/>
<field name="insurance_type_id"/>
<field name="seating_capacity"/>
<field name="price"/>
<field name="sale_id" invisible="True"/>
<field name="extra_price"/>
<field name="invoice_ids" widget="many2many_tags"
invisible="True"/>
<field name="invisible_sub" invisible="True"/>
</group>
<group>
<field name="start_date"/>
<field name="end_date"/>
<field name="cancellation_date"
attrs="{ 'invisible': [('state', '!=', 'cancel')] }"/>
<field name="city"/>
<field name="state_id"/>
<field name="country_id"/>
</group>
</group>
<notebook>
<page string="Features">
<group string="Add Extra Features">
<field name="fuel"/>
<field name="fuel_type"
attrs="{ 'invisible': [('fuel', '!=', 'with_fuel')] }"/>
<field name="mileage"
attrs="{ 'invisible': [('fuel', '!=', 'with_fuel')] }"/>
<field name="fuel_rate"
attrs="{ 'invisible': [('fuel', '!=', 'with_fuel')] }"/>
<field name="charge_km"/>
<field name="default_km"/>
<field name="extra_km"/>
</group>
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="message_ids"/>
</div>
</form>
</field>
</record>
<!--Menu item of vehicle subscription-->
<menuitem id="vehicle_subscription_menu_action"
name="Subscription"
action="fleet_subscription_action"
parent="fleet.fleet_vehicles"
/>
</odoo>

42
vehicle_subscription/views/fleet_vehicle_model_views.xml

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--Used to add field in fleet.vehicle.model-->
<record id="fleet_vehicle_model_view_form" model="ir.ui.view">
<field name="name">
fleet.vehicle.model.view.form.inherited.vehicle.subscription
</field>
<field name="model">fleet.vehicle.model</field>
<field name="inherit_id" ref="fleet.fleet_vehicle_model_view_form"/>
<field name="arch" type="xml">
<xpath expr="//group/field[@name='default_fuel_type']"
position="after">
<field name="mileage"/>
</xpath>
</field>
</record>
<!--Add fields in fleet.vehicle-->
<record id="fleet_vehicle_view_form" model="ir.ui.view">
<field name="name">
fleet.vehicle.view.form.inherited.vehicle.subscription
</field>
<field name="model">fleet.vehicle</field>
<field name="inherit_id" ref="fleet.fleet_vehicle_view_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='horsepower_tax']" position='after'>
<field name="free_km" invisible="1"/>
<field name="subscription_price" invisible="1"/>
<field name="states_id"/>
<field name="countries_id"/>
<field name="insurance" invisible="1"/>
<field name="end" invisible="1"/>
<field name="start" invisible="1"/>
<field name="duration" invisible="1"/>
<field name="fuel" invisible="1"/>
<field name="fuel_rate" invisible="1"/>
<field name="charge_km" invisible="1"/>
<field name="extra_km" invisible="1"/>
<field name="mileage" invisible="1"/>
</xpath>
</field>
</record>
</odoo>

44
vehicle_subscription/views/insurance_type_views.xml

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--Action of insurance.type-->
<record id="insurance_type_action" model="ir.actions.act_window">
<field name="name">Insurance Type</field>
<field name="res_model">insurance.type</field>
<field name="view_mode">tree,form</field>
</record>
<!-- Form view of the insurance type-->
<record id="insurance_type_view_form" model="ir.ui.view">
<field name="name">insurance.type.view.form</field>
<field name="model">insurance.type</field>
<field name="arch" type="xml">
<form string="Channel">
<sheet>
<group>
<field name="name"/>
</group>
<notebook>
<page string="Coverages">
<field name="coverage_ids">
<tree editable="bottom">
<field name="description"/>
<field name="coverage_price"/>
</tree>
</field>
</page>
</notebook>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="message_ids"/>
</div>
</form>
</field>
</record>
<!--Menu item of insurance type-->
<menuitem id="insurance_type_menu_action"
name="Insurance Type"
parent="fleet.fleet_configuration"
action="insurance_type_action"
groups="vehicle_subscription.vehicle_subscription_group_manager"
sequence="8"/>
</odoo>

254
vehicle_subscription/views/online_subscription_template.xml

@ -0,0 +1,254 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--Template for Subscription-->
<template id="subscription_form" name="Subscription Form">
<t t-call="website.layout">
<div class="image_website_form" style="background-image: linear-gradient(to bottom, rgb(255 255 255 / 43%), rgb(0 0 0 / 50%)), url('https://cdn.pixabay.com/photo/2017/01/31/17/44/highway-2025863_960_720.jpg');
background-size: cover;background-position: center;">
<div class="online_vehicle_main_form"
style="max-width: 1320px; margin: 0px auto;width: 100%;">
<div id="wrap" class="oe_structure oe_empty"
style="display: flex; justify-content: flex-end;align-items: center;">
<section class="s_website_form" data-vcss="001"
data-snippet="s_website_form"
style="padding: 50px 0px;">
<div class="container"
style="padding: 30px 50px;border-radius: 6px;background-color: #fffafa75;box-shadow: 0 3px 10px rgb(255 255 255 / 17%);">
<br/>
<h1 style="text-align: center;">Subscription
</h1>
<br/>
<form action="/online/subscription/next"
method="post"
enctype="multipart/form-data"
class="o_mark_required" data-mark="*"
data-model_name="" data-success-page="">
<input type="hidden" name="csrf_token"
t-att-value="request.csrf_token()"/>
<div class="s_website_form_rows row s_col_no_bgcolor"
id="whole_sub">
<div class="form-group col-12 s_website_form_field s_website_form_required"
data-type="char"
data-name="Field">
<div class="form-group col-12 s_website_form_field s_website_form_required"
data-type="char"
data-name="Field">
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto s_website_form_label"
style="width: 200px"
for="studio1">
<span class="s_website_form_label_content">
Location
</span>
<span class="s_website_form_mark">
*
</span>
</label>
<div id="location_temp"
style="display:none">
<div class="location_modal_container"
style="position: fixed;left: 0;height: 100%;width: 100%;background: rgba(0,0,0,0.2);top: 0;display: flex;align-items: center;justify-content: center;">
<div class="modal-dialog">
<div class="modal-content"
style="width: 400px;">
<div class="modal-header"
style="justify-content: center;">
<h4 class="modal-title">
Choose
Location
</h4>
</div>
<div class="modal-body">
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto s_website_form_label"
for="studio1">
<span class="s_website_form_label_content">
State
</span>
<span class="s_website_form_mark">
*
</span>
</label>
<div class="col-sm">
<select id="state_id"
type="text"
class="form-control s_website_form_input"
name="state"
required="1">
<option t-att-value=""/>
<t t-foreach="states or []"
t-as="state">
<option t-att-value="state.id"
t-att-data-state-name="state.name">
<t t-esc="state.name"/>
</option>
</t>
</select>
</div>
</div>
<br/>
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto s_website_form_label"
for="studio1">
<span class="s_website_form_label_content">
City
</span>
<span class="s_website_form_mark">
*
</span>
</label>
<div class="col-sm">
<select id="city_id"
type="text"
class="form-control s_website_form_input"
name="city"
required="1">
<option t-att-value=""/>
<t t-foreach="cities or []"
t-as="city">
<option t-att-value="">
<t t-esc="city"/>
</option>
</t>
</select>
</div>
</div>
<br/>
</div>
<div class="modal-footer">
<button type="button"
style="background: black;color: white;"
class="btn btn-default"
id="dismiss"
data-dismiss="modal">
Close
</button>
</div>
</div>
</div>
</div>
</div>
<div class="col-sm"
id="col-sm-location">
<input id="location_id"
type="text"
class="form-control s_website_form_input"
data-toggle="modal"
data-target="#location_temp">
</input>
</div>
</div>
</div>
<br/>
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto s_website_form_label"
style="width: 200px"
for="studio1">
<span class="s_website_form_label_content">
Start Date
</span>
<span class="s_website_form_mark">
*
</span>
</label>
<div class="col-sm">
<input id="start_date"
type="Date"
class="form-control s_website_form_input"
name="start_date"
required="1"/>
</div>
</div>
<br/>
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto s_website_form_label"
style="width: 200px"
for="studio1">
<span class="s_website_form_label_content">
End Date
</span>
<span class="s_website_form_mark">
*
</span>
</label>
<div class="col-sm">
<input id="end_date"
type="Date"
class="form-control s_website_form_input"
name="end_date"
required="1"/>
</div>
</div>
<br/>
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto s_website_form_label"
style="width: 200px"
for="studio1">
<span class="s_website_form_label_content">
Insurance Type
</span>
<span class="s_website_form_mark">
*
</span>
</label>
<div class="col-sm">
<select id="insurance_type"
type="text"
class="form-control s_website_form_input"
name="insurance_type"
required="1">
<option t-att-value=""/>
<t t-foreach="insurance_type or []"
t-as="type">
<option t-att-value="type.id">
<t t-esc="type.name"/>
</option>
</t>
</select>
</div>
</div>
<br/>
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto s_website_form_label"
style="width: 200px"
for="studio1">
<span class="s_website_form_label_content">
Seating Capacity
</span>
<span class="s_website_form_mark">
*
</span>
</label>
<div class="col-sm">
<input id="seating_capacity"
type="text"
class="form-control s_website_form_input"
name="seating_capacity"
required="1"/>
</div>
</div>
<br/>
<br/>
<div class="form-group col-12 s_website_form_submit"
data-name="Next Button">
<div style="width: 200px;"
class="s_website_form_label"/>
<button type="submit" id="next"
class="btn btn-primary"
style="width: 100%;">
Next
</button>
</div>
</div>
</div>
<br/>
<br/>
</form>
</div>
</section>
</div>
</div>
</div>
</t>
</template>
</odoo>

110
vehicle_subscription/views/online_vehicle_cancellation_template.xml

@ -0,0 +1,110 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--Template for subscription cancellation-->
<template id="subscription_cancellation_form" name="Vehicle Form">
<t t-call="website.layout">
<div id="wrap" class="oe_structure oe_empty cancel_sub">
<section class="s_website_form" id="book_my_vehicle"
data-vcss="001" data-snippet="s_website_form">
<div class="container">
<br/>
<h1 style="text-align: center;">Choose Vehicle</h1>
<br/>
<form action="/online/cancellation/click" method="post"
enctype="multipart/form-data"
class="o_mark_required" data-mark="*"
data-model_name="" data-success-page=""
style="width: 50%;margin: 0 auto;padding: 30px 58px;border-radius: 6px;padding: 40px 60px;background: white;box-shadow: 0 3px 10px rgb(0 0 0 /0.2);">
<input type="hidden" name="csrf_token"
t-att-value="request.csrf_token()"/>
<div class="s_website_form_rows row s_col_no_bgcolor">
<div class="form-group col-12 s_website_form_field s_website_form_required"
data-type="char" data-name="Field">
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto s_website_form_label"
style="width: 125px"
for="studio1">
<span class="s_website_form_label_content">
Name
</span>
<span class="s_website_form_mark">
*
</span>
</label>
<div class="col-sm">
<div class="col-sm">
<input class="form-control s_website_form_input"
id="customer_name"
name='customer'
type="text"
t-att-value="customers"/>
</div>
<br/>
<br/>
</div>
</div>
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto s_website_form_label"
style="width: 125px"
for="studio1">
<span class="s_website_form_label_content">
Vehicle
</span>
<span class="s_website_form_mark">
*
</span>
</label>
<div class="col-sm">
<select id="vehicle_cancellation"
type="text"
class="form-control s_website_form_input"
name="vehicle"
required="1">
<option t-att-value=""/>
<t t-foreach="vehicles or []"
t-as="vehicle">
<option t-att-value="vehicle.id"
required="1">
<t t-esc="vehicle.vehicle_id.name"/>
</option>
</t>
</select>
</div>
</div>
</div>
</div>
<br/>
<br/>
<div class="row s_col_no_resize s_col_no_bgcolor">
<label class="col-form-label col-sm-auto s_website_form_label"
style="width: 125px" for="studio1">
<span class="s_website_form_label_content">
Reason
</span>
<span class="s_website_form_mark">*</span>
</label>
<div class="col-sm">
<input id="reason" type="text"
class="form-control s_website_form_input"
name="reason" required="1"
placeholder="Reason for cancellation"/>
</div>
</div>
<br/>
<div class="form-group col-12 s_website_form_submit"
data-name="cancel Button"
style="margin-bottom: 30px">
<div style="width: 200px;"
class="s_website_form_label"/>
<button type="submit" id="cancel"
class="btn btn-primary"
style="float: right;">Cancel
</button>
</div>
</form>
</div>
</section>
</div>
</t>
</template>
</odoo>

197
vehicle_subscription/views/online_vehicle_template.xml

@ -0,0 +1,197 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--Booking page of subscription-->
<template id="vehicle_form" name="Vehicle Form">
<t t-call="website.layout">
<div id="wrap" class="oe_structure oe_empty">
<section class="s_website_form" id="book_my_vehicle"
data-vcss="001" data-snippet="s_website_form">
<div class="container">
<div class="btn btn-primary redirect_back_with_data"
style="background:none; border:none;">
<span style="font-size:18px; color:#000; background-image:url('https://cdn-icons-png.flaticon.com/512/2985/2985162.png');width: 63px;
height: 63px;display: block;background-size: 60%;margin-top: 23px;background-position: center;background-repeat: no-repeat;"/>
</div>
<br/>
<h1 style="text-align: center;">Choose Vehicle</h1>
<br/>
<input type="hidden" name="csrf_token"
t-att-value="request.csrf_token()"/>
<div class="s_website_form_rows row s_col_no_bgcolor">
<div class="form-group col-12 s_website_form_field s_website_form_required"
data-type="char" data-name="Field">
<div class="row s_col_no_resize s_col_no_bgcolor"
style="display:none">
<label class="col-form-label col-sm-auto s_website_form_label"
style="width: 200px" for="studio1">
<span class="s_website_form_label_content">
Name
</span>
<span class="s_website_form_mark">*
</span>
</label>
<div class="col-sm">
<input class="form-control s_website_form_input"
name='customer' type="text"
t-att-value="customers"/>
</div>
</div>
<div class="row s_col_no_resize s_col_no_bgcolor">
<div class="vehicle_table_scroll" style=
"overflow-y: scroll;">
<div class="col-sm"
style="display: flex;justify-content: center;">
<div class="col-lg-8 col-md-6 subscription_book"
style="height: 40vh;over-flow-y: scroll;">
<table style="width:100%;border-collapse: separate;border-spacing: 0 20px;"
id="vehicle_booking_table">
<thead> <!-- Add the table header section -->
<tr style="background-color: #ececec45;-webkit-box-shadow: 0px 0px 6px #0000001f;">
<th style="padding: 10px 0px 10px 50px;">
Image
</th>
<th>Name</th>
<th>Price</th>
<th>Free km</th>
<th/>
</tr>
</thead>
<t t-foreach="vehicles or []"
t-as="vehicle">
<div class="veh_table_row">
<tr style="background-color: #ececec45;-webkit-box-shadow: 0px 0px 6px #0000001f;">
<td id="vehicle_img"
style="padding: 0px 20px;">
<img t-attf-src="/web/image/fleet.vehicle/{{ vehicle.id }}/image_128"
style="width: 100px; height: 100px; object-fit: contain;"
alt="Vehicle image"/>
</td>
<td id="vehicle_fuel"
t-att-data-vehicleid="vehicle.id"
t-att-value="vehicle.id">
<t t-esc="vehicle.name"/>
</td>
<td>
<span id="vehicle_price">
<t t-esc="(vehicle.duration * vehicle.subscription_price)+amount"/>
</span>
</td>
<td>
<span id="vehicle_free_km">
<t t-esc="vehicle.free_km"/>
</span>
</td>
<td>
<div class="form-group col-12 s_website_form_submit "
data-name="submit Button"
t-attf-id="'%s'% vehicle.id">
<button id="book_now_button"
t-if="not request.env.user.sudo().has_group('base.group_public')"
class="btn btn-primary book_now">
Book
Now
<input type="hidden"
t-att-value="vehicle.id"/> <!-- getting vehicle id in js . -->
</button>
<a href="/web/signup/user"
t-if="request.env.user.sudo().has_group('base.group_public')"
class="btn btn-primary book_now">
Book
Now
<input type="hidden"
t-att-value="vehicle.id"/> <!-- getting vehicle id in js . -->
</a>
</div>
</td>
</tr>
</div>
</t>
</table>
</div>
</div>
</div>
</div>
<br/>
<br/>
<div class="extra_charge_info"
style="width: 60%;margin: 0 auto;">
<div class="form-group col-12 s_website_form_submit"
style="margin-bottom: 30px;">
<tr style="height:10%">
<div class="col-sm"
style="display: flex;justify-content: center;align-items: center;">
<span style="font-weight: 650;margin-right: 20px;">
Extra KMs
</span>
<input id="extra_km"
type="text"
class="form-control s_website_form_input"
name="extra_kms"
style="width: 30%;"/>
</div>
</tr>
</div>
<div class="fuel_choice_and_invoice_type"
style="display: flex;align-items: center;justify-content: space-around;">
<table>
<input type="checkbox"
class="form-check-input"
id="checkbox_for_fuel"
style="display:none;"/>
<span style="font-weight: 700;">
Fuel choice
<td>
<div class="form-group col-12 s_website_form_submit"
id="with_fuel">
<div class="btn btn-primary">
With Fuel
</div>
</div>
</td>
<td>
<div class="form-group col-12 s_website_form_submit"
id="without_fuel">
<div class="btn btn-primary">
Without Fuel
</div>
</div>
</td>
</span>
</table>
<table>
<input type="checkbox"
class="form-check-input"
id="checkbox_for_invoice_type"
style="display:none;"/>
<span style="font-weight: 700;">
Invoice Type
<td>
<div class="form-group col-12 s_website_form_submit"
id="full_subscription">
<div class="btn btn-primary">
Full Payment
</div>
</div>
</td>
<td>
<div class="form-group col-12 s_website_form_submit"
id="monthly_subscription">
<div class="btn btn-primary">
Monthly Payment
</div>
</div>
</td>
</span>
</table>
</div>
</div>
</div>
</div>
<br/>
<br/>
</div>
</section>
</div>
</t>
</template>
</odoo>

103
vehicle_subscription/views/subscription_form_success_template.xml

@ -0,0 +1,103 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--Template for confirmation of subscription-->
<template id="subscription_form_success">
<t t-call="website.layout">
<section id="subscription_form_page">
<div class="btn btn-primary redirect_back_with_data"
style="background:none; border:none;">
<span style="font-size:18px; color:#000; background-image:url('https://cdn-icons-png.flaticon.com/512/2985/2985162.png');width: 63px;
height: 63px;display: block;background-size: 60%;margin-top: 23px;background-position: center;background-repeat: no-repeat;"/>
</div>
<div id="wrap">
<div class="container"
style="height: 50vh;display: flex;align-items: center;">
<div class="col-md-12">
<div class="alert alert-success"
style="text-align: center;width: 50%;margin: 0 auto;">
Dear<t t-esc="customer_name"/>, Your
Subscription for
<t t-esc="vehicle_name"/>
vehicle has confirmed.
</div>
</div>
</div>
</div>
</section>
</t>
</template>
<!-- This template get loaded when vehicle is not found. -->
<template id="subscription_vehicle_missing">
<t t-call="website.layout">
<section id="subscription_missing_page">
<div class="btn btn-primary redirect_back_with_data"
style="background:none; border:none;">
<span style="font-size:18px; color:#000; background-image:url('https://cdn-icons-png.flaticon.com/512/2985/2985162.png');width: 63px;
height: 63px;display: block;background-size: 60%;margin-top: 23px;background-position: center;background-repeat: no-repeat;"/>
</div>
<div id="wrap">
<div class="container"
style="height: 50vh;display: flex;align-items: center;">
<div class="col-md-12">
<div class="alert alert-success"
style="text-align: center;width: 50%;margin: 0 auto;">
Sorry Vehicles not found
</div>
</div>
</div>
</div>
</section>
</t>
</template>
<!--Template for cancellation of vehicle-->
<template id="booking_cancellation">
<t t-call="website.layout">
<section id="subscription_cancellation_page">
<div class="btn btn-primary redirect_back_with_data"
style="background:none; border:none;">
<span style="font-size:18px; color:#000; background-image:url('https://cdn-icons-png.flaticon.com/512/2985/2985162.png');width: 63px;
height: 63px;display: block;background-size: 60%;margin-top: 23px;background-position: center;background-repeat: no-repeat;"/>
</div>
<div id="wrap">
<div class="container"
style="height: 50vh;display: flex;align-items: center;">
<div class="col-md-12">
<div class="alert alert-success"
style="text-align: center;width: 50%;margin: 0 auto;">
Dear
<t t-esc="customer"/>
Cancellation for the
<t t-esc="vehicle"/>
has been Processing.Will get back soon.
</div>
</div>
</div>
</div>
</section>
</t>
</template>
<!--Template for request in vehicle change-->
<template id="change_subscription">
<t t-call="website.layout">
<div id="wrap">
<section id="change_subscription_on">
<div class="btn btn-primary redirect_back_with_data"
style="background:none; border:none;">
<span style="font-size:18px; color:#000; background-image:url('https://cdn-icons-png.flaticon.com/512/2985/2985162.png');width: 63px;
height: 63px;display: block;background-size: 60%;margin-top: 23px;background-position: center;background-repeat: no-repeat;"/>
</div>
<div class="container"
style="height: 50vh;display: flex;align-items: center;">
<div class="col-md-12">
<div class="alert alert-success"
style="text-align: center;width: 50%;margin: 0 auto;">
Request for changing vehicle has been
Processing.Will get back soon.
</div>
</div>
</div>
</section>
</div>
</t>
</template>
</odoo>

45
vehicle_subscription/views/subscription_request_views.xml

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--Action of subscription.request-->
<record id="subscription_request_action" model="ir.actions.act_window">
<field name="name">Subscription Request</field>
<field name="res_model">subscription.request</field>
<field name="view_mode">tree,form</field>
</record>
<!-- Form view of the model subscription request-->
<record id="subscription_request_view_form" model="ir.ui.view">
<field name="name">subscription.request.view.form</field>
<field name="model">subscription.request</field>
<field name="arch" type="xml">
<form string="Channel">
<header>
<field name="state" widget="statusbar"
options="{'clickable': '1'}"/>
<button name="action_approve" class="oe_highlight"
states="to_approve" string="Approve"
type="object"
groups="vehicle_subscription.vehicle_subscription_group_manager"/>
</header>
<sheet>
<group>
<field name="current_vehicle_id"/>
<field name="vehicle_ids" widget="many2many_tags"
invisible="True"/>
<field name="new_vehicle_id"/>
<field name="reason_to_change"/>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="message_ids"/>
</div>
</form>
</field>
</record>
<!--Menu item of change subscription-->
<menuitem id="subscription_request_menu_action"
name="Change Subscription"
parent="fleet.fleet_configuration"
action="subscription_request_action"
sequence="7"/>
</odoo>

37
vehicle_subscription/views/vehicle_insurance_views.xml

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--Action of vehicle insurance-->
<record id="vehicle_insurance_action" model="ir.actions.act_window">
<field name="name">Insurance</field>
<field name="res_model">vehicle.insurance</field>
<field name="view_mode">tree,form</field>
</record>
<!-- Form view of the vehicle insurance-->
<record id="vehicle_insurance_view_form" model="ir.ui.view">
<field name="name">vehicle.insurance.view.form</field>
<field name="model">vehicle.insurance</field>
<field name="arch" type="xml">
<form string="Channel">
<sheet>
<group>
<field name="vehicle_id"/>
<field name="start_date"/>
<field name="end_date"/>
<field name="insurance_type_id"/>
<field name="insurance_amount"/>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids"/>
<field name="message_ids"/>
</div>
</form>
</field>
</record>
<!--Menu item of insurance-->
<menuitem id="vehicle_insurance_menu_action"
name="Insurance"
action="vehicle_insurance_action"
parent="fleet.fleet_vehicles"
sequence="7"/>
</odoo>

122
vehicle_subscription/views/website_portal_subscription_template.xml

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!--Website view for invoice in subscription-->
<template id="portal_my_home_subscribe" name="Subscription Order"
customize_show="True"
inherit_id="portal.portal_my_home" priority="1">
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
<t t-call="portal.portal_docs_entry">
<t t-set="title">Subscription Order</t>
<t t-set="url" t-value="'/my/subscription/invoice'"/>
<t t-set="placeholder_count" t-value="'subscription_count'"/>
</t>
</xpath>
</template>
<!-- Portal view of the invoice-->
<template id="portal_my_invoices_subscription"
name="My Invoices and Payments">
<t t-call="portal.portal_layout">
<t t-set="breadcrumbs_searchbar" t-value="True"/>
<t t-if="not invoices">
<p>There are currently no invoices and payments for your
account.
</p>
</t>
<t t-if="invoices" t-call="portal.portal_table">
<thead>
<tr class="active">
<th>Invoice #</th>
<th>Invoice Date</th>
<th class='d-none d-md-table-cell'>Due Date</th>
<th class="text-center">Status</th>
<th class="text-end">Amount Due</th>
</tr>
</thead>
<tbody>
<t t-foreach="invoices" t-as="invoice">
<tr>
<td>
<a t-att-href="invoice.get_portal_url()"
t-att-title="invoice.name">
<t t-esc="invoice.name"
t-if="invoice.name != '/'"/>
<em t-else="">Draft Invoice</em>
</a>
</td>
<td>
<span t-field="invoice.invoice_date"/>
</td>
<td class='d-none d-md-table-cell'>
<span t-field="invoice.invoice_date_due"/>
</td>
<td class="tx_status text-center">
<t t-if="invoice.state == 'posted' and invoice.payment_state not in ('in_payment', 'paid', 'reversed')">
<span class="badge rounded-pill text-bg-info">
<i class="fa fa-fw fa-clock-o"
aria-label="Opened" title="Opened"
role="img"/>
<span class="d-none d-md-inline">
Waiting for Payment
</span>
</span>
</t>
<t t-if="invoice.state == 'posted' and invoice.payment_state in ('paid', 'in_payment')">
<span class="badge rounded-pill text-bg-success">
<i class="fa fa-fw fa-check"
aria-label="Paid" title="Paid"
role="img"/>
<span class="d-none d-md-inline">Paid
</span>
</span>
</t>
<t t-if="invoice.state == 'posted' and invoice.payment_state == 'reversed'">
<span class="badge rounded-pill text-bg-success">
<i class="fa fa-fw fa-check"
aria-label="Reversed"
title="Reversed"
role="img"/>
<span class="d-none d-md-inline">
Reversed
</span>
</span>
</t>
<t t-if="invoice.state == 'cancel'">
<span class="badge rounded-pill text-bg-warning">
<i class="fa fa-fw fa-remove"
aria-label="Cancelled"
title="Cancelled"
role="img"/>
<span class="d-none d-md-inline">
Cancelled
</span>
</span>
</t>
</td>
<td class="text-end">
<span t-esc="-invoice.amount_residual if invoice.move_type == 'out_refund' else invoice.amount_residual"
t-options='{"widget": "monetary", "display_currency": invoice.currency_id}'/>
</td>
</tr>
</t>
</tbody>
</t>
</t>
</template>
<!--Template for subscription cancel and change-->
<template id="subscription_order_portal_id"
name="subscription_order_portal"
inherit_id="account.portal_invoice_page">
<xpath expr="//div[hasclass('o_download_pdf')]" position="after">
<t t-if="invoice.is_subscription">
<a href="/online/subscription/cancel" id="my_link"
class="btn btn-secondary btn-block o_download_btn">
Subscription Cancel
</a>
<a href="/online/subscription/change" id="my_link_data"
class="btn btn-secondary btn-block o_download_btn">
Subscription Change
</a>
</t>
</xpath>
</template>
</odoo>

22
vehicle_subscription/wizard/__init__.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Rahna Rasheed (<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 . import change_subscription

54
vehicle_subscription/wizard/change_subscription.py

@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Rahna Rasheed (<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 odoo import fields, models, _
from odoo.exceptions import ValidationError
class VehicleChange(models.TransientModel):
"""Transient Model for switching subscription"""
_name = "change.subscription"
_description = "Change Subscription"
_rec_name = "vehicle"
vehicle = fields.Selection(
[('same', 'Same Vehicle'), ('different', 'Different Vehicle')],
default='same', string='Vehicle',
help="Helps you to choose type of vehicle")
def action_change_subscription(self):
"""Proceed with changing subscription"""
if self.vehicle == 'different':
raise ValidationError(_(
"Inorder to change subscription"
" to different vehicle you need to"
" cancel the current subscription plan"))
else:
active_id = self._context.get('active_id')
subscription = self.env['fleet.subscription'].browse(active_id)
return {
'type': 'ir.actions.act_window',
'view_mode': 'form',
'res_model': 'subscription.request',
'target': 'new',
'context': {
'default_current_vehicle_id': subscription.vehicle_id.id}
}

29
vehicle_subscription/wizard/change_subscription_views.xml

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<!--View of change subscription-->
<record id="change_subscription_view" model="ir.ui.view">
<field name="name">change.subscription.view</field>
<field name="model">change.subscription</field>
<field name="arch" type="xml">
<form string="Channel">
<group class="oe_title">
<field name="vehicle" widget="radio"/>
</group>
<footer>
<button name="action_change_subscription" string="Ok"
type="object" class="oe_highlight"/>
<button string="Cancel" class="btn-secondary"
special="cancel"/>
</footer>
</form>
</field>
</record>
<!-- Action for the model change.subscription-->
<record id="change_subscription_action" model="ir.actions.act_window">
<field name="type">ir.actions.act_window</field>
<field name="res_model">change.subscription</field>
<field name="view_mode">form</field>
<field name="view_id" ref="change_subscription_view_form"/>
<field name="target">new</field>
</record>
</odoo>
Loading…
Cancel
Save