@ -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: (V15) Swaraj R, 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>`__ |
@ -0,0 +1,24 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Swaraj R (<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 |
@ -0,0 +1,69 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Swaraj R (<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': "15.0.1.0.0", |
|||
'category': 'Industries', |
|||
'summary': """Vehicle Subscription Management From Website""", |
|||
'description': """A Vehicle Subscription Management system on a website |
|||
allows users to subscribe to vehicles on a flexible, recurring basis, |
|||
similar to how they might subscribe to streaming services""", |
|||
'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', |
|||
'report/cancellation_request.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/*.js', |
|||
], |
|||
}, |
|||
'images': ['static/description/banner.png'], |
|||
'license': 'AGPL-3', |
|||
'installable': True, |
|||
'auto_install': False, |
|||
'application': False, |
|||
} |
@ -0,0 +1,23 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Swaraj R (<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 |
@ -0,0 +1,442 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Swaraj R (<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.addons.base.models.ir_ui_view import keep_query |
|||
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, |
|||
type='http', method="POST") |
|||
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_type = request.env['vehicle.insurance'].sudo().search( |
|||
[('insurance_type_id.id', '=', int(insurance)), |
|||
('start_date', '<=', start), ('end_date', '>=', end)]) |
|||
insurance_amount = insurance_type[ |
|||
0].insurance_amount if insurance_type else 0 |
|||
for rec in insurance_type: |
|||
rec.vehicle_id.insurance = rec.id |
|||
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({ |
|||
'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)], limit=1) |
|||
if extra_km == '': |
|||
km = 0 |
|||
else: |
|||
km = int(extra_km) |
|||
subscribe = request.env['fleet.subscription'].sudo().create({ |
|||
'vehicle_id': vehicle_id.id, |
|||
'customer_id': request.env.user.partner_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 not checked else 'with_fuel' |
|||
}) |
|||
if checked: |
|||
subscribe.price = ( |
|||
((km / vehicle_id.mileage) * vehicle_id.fuel_rate) + |
|||
(vehicle_id.duration * vehicle_id.subscription_price) + |
|||
request.env['vehicle.insurance'].browse( |
|||
int(vehicle_id.insurance)).insurance_amount + ( |
|||
vehicle_id.charge_km * km)) |
|||
else: |
|||
subscribe.price = ( |
|||
((vehicle_id.duration * vehicle_id.subscription_price) + |
|||
request.env['vehicle.insurance'].browse( |
|||
int(vehicle_id.insurance)).insurance_amount) + ( |
|||
vehicle_id.charge_km * km)) |
|||
subscribe.sudo().action_invoice() |
|||
subscribe.sale_id.sudo().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 |
|||
subscribe.sale_id.invoice_ids.subscription_id = subscribe.id |
|||
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, |
|||
'subscription_id': subscribe.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, |
|||
'subscription_id': subscribe.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 |
|||
} |
|||
for each in subscribe.invoice_ids: |
|||
each.partner_id = customer_id.id |
|||
for each in subscribe.sale_id.invoice_ids: |
|||
each.partner_id = customer_id.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') if kwargs.get('extra_km') else '0' |
|||
vehicle = request.env['fleet.vehicle'].sudo().browse(vehicle) |
|||
vehicle.write({ |
|||
'extra_km': float(km), |
|||
}) |
|||
insurance_amount = vehicle.insurance |
|||
amount = request.env['vehicle.insurance'].sudo() \ |
|||
.browse(int(insurance_amount)).insurance_amount |
|||
new_price = (((vehicle.extra_km / vehicle.mileage) * |
|||
vehicle.fuel_rate) + |
|||
(vehicle.duration * vehicle.subscription_price) + |
|||
amount + (vehicle.charge_km * vehicle.extra_km)) |
|||
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') if kwargs.get('extra_km') else '0' |
|||
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': float(km), |
|||
}) |
|||
new_price = (((vehicle.duration * vehicle.subscription_price) + |
|||
amount) + (vehicle.charge_km * vehicle.extra_km)) |
|||
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.user.partner_id |
|||
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""" |
|||
if bool(kwargs): |
|||
vehicle = [] |
|||
customer = kwargs.get('customer_id') |
|||
customer_id = request.env['res.partner'].sudo().search( |
|||
[('name', '=', customer)], limit=1) |
|||
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""" |
|||
if bool(kwargs): |
|||
customer = kwargs.get('customer') |
|||
vehicle = int(kwargs.get('vehicle')) |
|||
reason = kwargs.get('reason') |
|||
customer_id = request.env['res.partner'].sudo().search( |
|||
[('name', '=', customer)], limit=1) |
|||
vehicle_id = request.env['fleet.vehicle'].sudo().browse(vehicle) |
|||
subscription = request.env['fleet.subscription'].search( |
|||
[('vehicle_id', '=', vehicle_id.id), ('state', '=', 'subscribed'), |
|||
('customer_id', '=', customer_id.id)], limit=1) |
|||
if request.env['cancellation.request'].sudo().search([ |
|||
('customer_id', '=', customer_id.id), |
|||
('vehicle_id', '=', vehicle_id.id), |
|||
('subscription_id', '=', subscription.id) |
|||
]): |
|||
return request.render('vehicle_subscription.booking_cancelled', |
|||
{'customer': customer, |
|||
'vehicle': vehicle_id.name}) |
|||
cancel_request = request.env['cancellation.request'].sudo().create({ |
|||
'customer_id': customer_id.id, |
|||
'vehicle_id': vehicle_id.id, |
|||
'reason': reason, |
|||
'subscription_id': subscription.id |
|||
}) |
|||
values = { |
|||
'customer': customer, |
|||
'vehicle': vehicle_id.name, |
|||
} |
|||
cancel_request.state = 'to_approve' |
|||
return request.render('vehicle_subscription.booking_cancellation', |
|||
values) |
|||
else: |
|||
return request.redirect("/online/subscription") |
|||
|
|||
@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 |
|||
vals = { |
|||
'vehicles': vehicle, |
|||
'customers': customer, |
|||
} |
|||
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 bool(kwargs): |
|||
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)], limit=1) |
|||
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') |
|||
else: |
|||
return request.redirect("/online/subscription") |
|||
|
|||
@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. """ |
|||
if bool(kwargs): |
|||
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)], limit=1) |
|||
vehicle = request.env['fleet.vehicle'].sudo().browse(vehicle_id) |
|||
subscription = request.env['fleet.subscription'].search( |
|||
[('vehicle_id', '=', current_vehicle_id.id), |
|||
('state', '=', 'subscribed'), |
|||
('customer_id', '=', customer_id.id)], limit=1) |
|||
if request.env['subscription.request'].sudo().search([ |
|||
('current_vehicle_id', '=', current_vehicle_id.id), |
|||
('customer_id', '=', customer_id.id), |
|||
('subscription_id', '=', subscription.id), |
|||
('state', '=', 'to_approve') |
|||
]): |
|||
return request.render('vehicle_subscription' |
|||
'.subscription_change_create_alert', |
|||
{'customer': customer_id.name, |
|||
'vehicle': current_vehicle_id.name}) |
|||
change_subscription = request.env['subscription.request'].sudo().create( |
|||
{ |
|||
'current_vehicle_id': current_vehicle_id.id, |
|||
'new_vehicle_id': vehicle.id, |
|||
'reason_to_change': reason, |
|||
'customer_id': customer_id.id, |
|||
'subscription_id': subscription.id |
|||
}) |
|||
change_subscription.state = 'to_approve' |
|||
return request.render('vehicle_subscription.change_subscription') |
|||
else: |
|||
return request.redirect("/online/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') |
@ -0,0 +1,133 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Swaraj R (<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 collections import OrderedDict |
|||
from odoo.osv import expression |
|||
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""" |
|||
|
|||
def _get_account_searchbar_sortings(self): |
|||
"""Website accounts search bar sorting options""" |
|||
return { |
|||
'date': {'label': _('Date'), 'order': 'invoice_date desc'}, |
|||
'duedate': {'label': _('Due Date'), |
|||
'order': 'invoice_date_due desc'}, |
|||
'name': {'label': _('Reference'), 'order': 'name desc'}, |
|||
'state': {'label': _('Status'), 'order': 'state'}, |
|||
} |
|||
|
|||
def _get_account_searchbar_filters(self): |
|||
"""Function get the search bar filters""" |
|||
return { |
|||
'all': {'label': _('All'), 'domain': []}, |
|||
'invoices': {'label': _('Invoices'), 'domain': [ |
|||
('move_type', 'in', ('out_invoice', 'out_refund'))]}, |
|||
'bills': {'label': _('Bills'), 'domain': [ |
|||
('move_type', 'in', ('in_invoice', 'in_refund'))]}, |
|||
} |
|||
|
|||
def _prepare_my_invoices_values(self, page, date_begin, date_end, sortby, |
|||
filterby, domain=None, url="/my/invoices"): |
|||
"""Function prepare the invoice value""" |
|||
values = self._prepare_portal_layout_values() |
|||
AccountInvoice = request.env['account.move'] |
|||
domain = expression.AND([ |
|||
domain or [], |
|||
self._get_invoices_domain(), |
|||
]) |
|||
searchbar_sortings = self._get_account_searchbar_sortings() |
|||
if not sortby: |
|||
sortby = 'date' |
|||
order = searchbar_sortings[sortby]['order'] |
|||
searchbar_filters = self._get_account_searchbar_filters() |
|||
if not filterby: |
|||
filterby = 'all' |
|||
domain += searchbar_filters[filterby]['domain'] |
|||
if date_begin and date_end: |
|||
domain += [('create_date', '>', date_begin), |
|||
('create_date', '<=', date_end)] |
|||
values.update({ |
|||
'date': date_begin, |
|||
'invoices': lambda pager_offset: AccountInvoice.search( |
|||
domain, |
|||
order=order, |
|||
limit=self._items_per_page, |
|||
offset=pager_offset), |
|||
'page_name': 'invoice', |
|||
'pager': { |
|||
"url": url, |
|||
"url_args": {'date_begin': date_begin, 'date_end': date_end, |
|||
'sortby': sortby}, |
|||
"total": AccountInvoice.search_count(domain), |
|||
"page": page, |
|||
"step": self._items_per_page, |
|||
}, |
|||
'default_url': url, |
|||
'searchbar_sortings': searchbar_sortings, |
|||
'sortby': sortby, |
|||
'searchbar_filters': OrderedDict(sorted(searchbar_filters.items())), |
|||
'filterby': filterby, |
|||
}) |
|||
return values |
|||
|
|||
@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), ('subscription_id', '!=', False) |
|||
] |
|||
values.update({ |
|||
'invoices': request.env['account.move'].sudo().search(domain), |
|||
'pager': pager, |
|||
'page_name': 'subscription_home' |
|||
}) |
|||
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), |
|||
('subscription_id', 'in', |
|||
request.env['fleet.subscription'].search([]).ids)]) |
|||
return values |
@ -0,0 +1,16 @@ |
|||
<?xml version="1.0" encoding="utf-8" ?> |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
<!--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> |
|||
</data> |
|||
</odoo> |
@ -0,0 +1,79 @@ |
|||
<?xml version="1.0" encoding="utf-8" ?> |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
<!--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> |
|||
</data> |
|||
</odoo> |
@ -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> |
@ -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> |
@ -0,0 +1,6 @@ |
|||
## Module <vehicle_subscription> |
|||
|
|||
#### 13.09.2024 |
|||
#### Version 15.0.1.0.0 |
|||
#### ADD |
|||
Initial Commit Vehicle Subscription Management |
@ -0,0 +1,29 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Swaraj R (<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 |
@ -0,0 +1,35 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Swaraj R (<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 field's """ |
|||
_inherit = 'account.move' |
|||
|
|||
is_subscription = fields.Boolean(string="Subscribe", |
|||
help="This field will be set true for " |
|||
"invoice corresponding to vehicle " |
|||
"subscription") |
|||
subscription_id = fields.Many2one('fleet.subscription', |
|||
help='Subscription Id of the invoice if ' |
|||
'any', string='Subscription Id') |
@ -0,0 +1,296 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Swaraj R (<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, _ |
|||
from odoo.exceptions import UserError |
|||
|
|||
|
|||
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', required=True, |
|||
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", required=True) |
|||
reason = fields.Char(string="Cancellation Reason", required=True, |
|||
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") |
|||
subscription_id = fields.Many2one('fleet.subscription', |
|||
string='Subscription Id', |
|||
help='Subscription related to this ' |
|||
'cancellation request') |
|||
|
|||
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.""" |
|||
subscription = self.env['fleet.subscription'].search( |
|||
[('vehicle_id', '=', self.vehicle_id.id), |
|||
('customer_id', '=', self.customer_id.id), |
|||
('state', '=', 'subscribed')], limit=1) |
|||
if subscription: |
|||
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 = self.vehicle_id.subscription_price |
|||
insurance_amount = self.subscription_id.insurance_type_id.insurance_amount |
|||
invoice_duration =1 if self.date - subscription.start_date == 0 else (self.date - subscription.start_date).days |
|||
template_approved = self.env.ref( |
|||
'vehicle_subscription.cancellation_approved') |
|||
if invoice_duration < 0: |
|||
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) |
|||
self.write({'state': 'approved'}) |
|||
invoice.button_cancel() |
|||
return |
|||
email_template = self.env.ref( |
|||
'vehicle_subscription.cancellation_request_mail') |
|||
refund_approved = self.env.ref( |
|||
'vehicle_subscription.cancellation_request_refund_mail') |
|||
uptodate_price = round(per_day_price * invoice_duration, 2) + insurance_amount |
|||
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) |
|||
self.write({'state': 'approved'}) |
|||
elif sum(paid_amount) < uptodate_price: |
|||
self.state = 'to_approve' |
|||
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': |
|||
round(per_day_price * invoice_duration, 2) + insurance_amount - sum(paid_amount), |
|||
})] |
|||
}) |
|||
generate_invoice.action_post() |
|||
data_record = base64.b64encode( |
|||
self.env.ref('vehicle_subscription' |
|||
'.cancellation_request_action_report')._render_qweb_pdf(res_ids=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: |
|||
self.state = 'to_approve' |
|||
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': |
|||
round(per_day_price * invoice_duration, 2) + insurance_amount - sum( |
|||
paid_amount), |
|||
})] |
|||
}) |
|||
generate_invoice.action_post() |
|||
data_record = base64.b64encode( |
|||
self.env.ref('vehicle_subscription' |
|||
'.cancellation_request_action_report')._render_qweb_pdf( |
|||
res_ids=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: |
|||
self.state = 'to_approve' |
|||
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.ref('vehicle_subscription' |
|||
'.cancellation_request_action_report')._render_qweb_pdf( |
|||
res_ids=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: |
|||
for invoice in subscription.invoice_ids: |
|||
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_origin': subscription.sale_id.name, |
|||
'invoice_line_ids': [(0, 0, { |
|||
'product_id': product_id.id, |
|||
'name': self.vehicle_id.name, |
|||
'price_unit': round(per_day_price * invoice_duration, 2) + insurance_amount, |
|||
})] |
|||
}) |
|||
generate_invoice.action_post() |
|||
data_record = base64.b64encode( |
|||
self.env.ref('vehicle_subscription' |
|||
'.cancellation_request_action_report')._render_qweb_pdf( |
|||
res_ids=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: |
|||
raise UserError(_(f"{self.customer_id.name} currently has no " |
|||
f"active" |
|||
f" Subscription for {self.vehicle_id.name}")) |
@ -0,0 +1,361 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Swaraj R (<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)]", |
|||
required=True, |
|||
help="This field help you to choose vehicle") |
|||
vehicle_ids = fields.Many2many('fleet.vehicle', string="Vehicle", |
|||
compute='_compute_vehicle_ids', |
|||
help="Returns vehicle by satisfying " |
|||
"the domain") |
|||
model_id = fields.Many2one(related="vehicle_id.model_id", string='Model', |
|||
help="This field help you to choose model " |
|||
"of vehicle") |
|||
price = fields.Float(string='Price', |
|||
help="Compute field which results the price of " |
|||
"vehicle") |
|||
uptodate_price = fields.Float(compute="_compute_uptodate_price", |
|||
string='Price', |
|||
help="Compute field which results the price " |
|||
"of vehicle until the date ") |
|||
extra_price = fields.Float(string="Extra Price", |
|||
help="Compute field which results the extra " |
|||
"price of vehicle") |
|||
start_date = fields.Date(string="Start Date", required=True, |
|||
help="Start date of subscription") |
|||
end_date = fields.Date(string="End Date", required=True, |
|||
help="End date of subscription") |
|||
cancellation_date = fields.Date(string="Cancellation Date", |
|||
default=fields.Date.today(), |
|||
help="Subscription cancellation date") |
|||
duration = fields.Integer(string="Duration", compute='_compute_duration', |
|||
help="Compute subscription duration") |
|||
cancel_duration = fields.Integer(string="Duration", |
|||
compute='_compute_cancel_duration', |
|||
help="compute cancel duration") |
|||
state = fields.Selection( |
|||
selection=[('draft', 'Draft'), ('subscribed', 'Subscribed'), |
|||
('cancel', 'Cancelled'), ('expired', 'Expired') |
|||
], string='State', default='draft', |
|||
help="States of subscription") |
|||
street = fields.Char(string="Street", help="Choose the street") |
|||
state_id = fields.Many2one("res.country.state", string='State', |
|||
ondelete='restrict', |
|||
domain="[('country_id', '=?', country_id)]", |
|||
help="Choose the state") |
|||
city = fields.Char(string="City", help="Choose the city") |
|||
country_id = fields.Many2one('res.country', string='Country', |
|||
ondelete='restrict', help="Choose the country") |
|||
fuel = fields.Selection(selection=[('with_fuel', 'With Fuel'), |
|||
('without_fuel', 'Without Fuel')], |
|||
string="Fuel Choice", default='without_fuel', |
|||
help="Help you to choose the type of fuel") |
|||
fuel_type = fields.Selection(string="Fuel Type", |
|||
related="vehicle_id.model_id.default_fuel_type" |
|||
, help="Fuel type will be given which is" |
|||
" related to the model") |
|||
fuel_rate = fields.Integer(string="Rate", default=300, help="Rate of fuel") |
|||
charge_km = fields.Integer(string="Charge in km", default=12, |
|||
help="Rate per kilometer") |
|||
default_km = fields.Float(string="Default KMS", |
|||
related='vehicle_id.free_km', |
|||
help="Default km is set based on free km of " |
|||
"vehicle which is given by authorised " |
|||
"person") |
|||
extra_km = fields.Float(string="Extra KMS", default=1, |
|||
help="As per customer he/she can choose extra km") |
|||
mileage = fields.Float(string='Mileage', |
|||
related='vehicle_id.model_id.mileage', |
|||
help="Helps to set mileage of vehicle") |
|||
sale = fields.Integer(string="sale", compute='_compute_sale', |
|||
help="Helps you to store count of sale") |
|||
invoice = fields.Integer(string="Invoice", compute='_compute_invoice', |
|||
help="Helps you to store count of invoice") |
|||
invoice_ids = fields.Many2many('account.move', string='Invoices', |
|||
help="Used to store ids of invoices") |
|||
customer_id = fields.Many2one('res.partner', string="Customer", |
|||
required=True, |
|||
help="Helps you to choose customer") |
|||
sale_id = fields.Many2one('sale.order', string='sale', readonly=True, |
|||
help="Stores id of sale order") |
|||
refund_id = fields.Many2one('account.move', string='Refund', readonly=True, |
|||
help="Stores id of invoice which belongs " |
|||
"to refund") |
|||
insurance_type_id = fields.Many2one('vehicle.insurance', |
|||
domain="[('vehicle_id', '='," |
|||
"vehicle_id)]") |
|||
refund = fields.Integer(compute='_compute_refund', |
|||
help="Helps you to store count of refund") |
|||
seating_capacity = fields.Integer(string='Seating Capacity', |
|||
help="Seating capacity of vehicle can " |
|||
"be set") |
|||
is_invisible_sub = fields.Boolean(string="Approve Subscription", |
|||
help="As subscription request get " |
|||
"approved this will be enabled") |
|||
|
|||
def _get_vehicle_domain(self): |
|||
"""This method retrieves the vehicles that meet the following |
|||
criteria""" |
|||
insurance_ids = self.env['vehicle.insurance'].search([]).mapped( |
|||
'vehicle_id') |
|||
domain = [] |
|||
for record in insurance_ids: |
|||
state = record.log_services.mapped('state') |
|||
if 'done' in state and 'running' not in state and 'new' \ |
|||
not in state and 'cancelled' not in state: |
|||
if not self.search( |
|||
[('vehicle_id', '=', record.id), |
|||
('state', '!=', 'subscribe')]): |
|||
domain.append(record.id) |
|||
return domain |
|||
|
|||
@api.onchange('vehicle_id') |
|||
def _onchange_vehicle_id(self): |
|||
"""Function used to fill the seating capacity""" |
|||
if self.vehicle_id: |
|||
self.seating_capacity = self.vehicle_id.model_id.seats |
|||
|
|||
@api.onchange('seating_capacity') |
|||
def _onchange_seating_capacity(self): |
|||
"""As the seating capacity changes vehicles are shown """ |
|||
if self.seating_capacity != self.vehicle_id.model_id.seats: |
|||
self.vehicle_id = False |
|||
|
|||
@api.onchange('default_km') |
|||
def _onchange_default_km(self): |
|||
"""Charge per km is set as onchange of default_km""" |
|||
if self.default_km <= self.vehicle_id.free_km: |
|||
self.charge_km = 0 |
|||
|
|||
@api.depends('vehicle_id', 'seating_capacity') |
|||
def _compute_vehicle_ids(self): |
|||
"""Compute the vehicle_IDS based on the vehicle and seating capacity.""" |
|||
for rec in self: |
|||
if not rec.vehicle_ids: |
|||
domain = rec._get_vehicle_domain() |
|||
if rec.seating_capacity: |
|||
model_id = self.env['fleet.vehicle'].search( |
|||
[('state_id', '=', 'registered'), |
|||
('model_id.seats', '=', rec.seating_capacity), |
|||
('id', 'in', domain)]) |
|||
for record in model_id: |
|||
self.vehicle_ids = [(4, record.id)] |
|||
else: |
|||
model_id = self.env['fleet.vehicle'].search( |
|||
[('id', 'in', domain)]) |
|||
for record in model_id: |
|||
self.vehicle_ids = [(4, record.id)] |
|||
|
|||
@api.depends('start_date', 'end_date') |
|||
def _compute_duration(self): |
|||
"""Compute duration based on start and end date""" |
|||
for record in self: |
|||
if record.end_date: |
|||
if record.end_date < record.start_date: |
|||
raise ValidationError(_( |
|||
"End date should be greater than start date.")) |
|||
if record.start_date and record.end_date: |
|||
start = record.start_date.strftime("%Y-%m-%d") |
|||
end = record.end_date.strftime("%Y-%m-%d") |
|||
start_datetime = datetime.strptime(start, "%Y-%m-%d") |
|||
end_datetime = datetime.strptime(end, "%Y-%m-%d") |
|||
delta = end_datetime - start_datetime |
|||
record.duration = delta.days |
|||
else: |
|||
record.duration = 0 |
|||
|
|||
@api.depends('start_date', 'cancellation_date') |
|||
def _compute_cancel_duration(self): |
|||
"""Compute duration based on cancellation date""" |
|||
for record in self: |
|||
if record.start_date and record.cancellation_date: |
|||
start = record.start_date.strftime("%Y-%m-%d") |
|||
end = record.cancellation_date.strftime("%Y-%m-%d") |
|||
start_datetime = datetime.strptime(start, "%Y-%m-%d") |
|||
end_datetime = datetime.strptime(end, "%Y-%m-%d") |
|||
delta = end_datetime - start_datetime |
|||
record.cancel_duration = delta.days |
|||
else: |
|||
record.cancel_duration = 0 |
|||
|
|||
@api.depends('cancel_duration') |
|||
def _compute_uptodate_price(self): |
|||
"""Compute price as per the cancellation date""" |
|||
for rec in self: |
|||
rec.uptodate_price = ( |
|||
(rec.sale_id.order_line.price_unit / rec.duration) * ( |
|||
(rec.cancellation_date - rec.start_date).days)) |
|||
|
|||
def action_get_car_insurance(self): |
|||
"""Get the action to view the car |
|||
insurance associated with the subscription.""" |
|||
self.ensure_one() |
|||
return { |
|||
'type': 'ir.actions.act_window', |
|||
'name': 'Insurance', |
|||
'view_mode': 'form', |
|||
'res_model': 'vehicle.insurance', |
|||
'res_id': self.insurance_type_id.id, |
|||
'context': [('create', '=', False)] |
|||
} |
|||
|
|||
def action_get_sale(self): |
|||
"""Get the action to view the sale |
|||
associated with the subscription.""" |
|||
return { |
|||
'type': 'ir.actions.act_window', |
|||
'name': 'Sale Order', |
|||
'view_mode': 'form', |
|||
'res_model': 'sale.order', |
|||
'res_id': self.sale_id.id, |
|||
'context': [('create', '=', False)] |
|||
} |
|||
|
|||
def _compute_sale(self): |
|||
"""Used to calculate the sale count""" |
|||
for record in self: |
|||
record.sale = self.env['sale.order'].search_count( |
|||
[('id', '=', self.sale_id.id)]) |
|||
|
|||
def action_get_refund(self): |
|||
"""Get the action to view the refund |
|||
associated with the subscription.""" |
|||
return { |
|||
'type': 'ir.actions.act_window', |
|||
'name': 'Refund', |
|||
'view_mode': 'form', |
|||
'res_id': self.refund_id.id, |
|||
'res_model': 'account.move', |
|||
'context': [('create', '=', False)] |
|||
} |
|||
|
|||
def _compute_refund(self): |
|||
"""Used to calculate count of refund""" |
|||
for record in self: |
|||
record.refund = self.env['account.move'].search_count( |
|||
[('id', '=', self.refund_id.id)]) |
|||
|
|||
def action_get_invoice(self): |
|||
"""Get the action to view the invoice |
|||
associated with the subscription.""" |
|||
invoice_ids = self.invoice_ids + self.sale_id.invoice_ids |
|||
return { |
|||
'type': 'ir.actions.act_window', |
|||
'name': 'Sale Order', |
|||
'view_mode': 'tree,form', |
|||
'res_model': 'account.move', |
|||
'domain': [('id', 'in', invoice_ids.ids)], |
|||
'context': [('create', '=', False)] |
|||
} |
|||
|
|||
def _compute_invoice(self): |
|||
"""Used to calculate invoice count""" |
|||
for record in self: |
|||
invoice_ids = record.invoice_ids + record.sale_id.invoice_ids |
|||
record.invoice = self.env['account.move'].search_count( |
|||
[('id', 'in', invoice_ids.ids)]) |
|||
|
|||
def action_invoice(self): |
|||
"""Used to generate invoice on clicking the button""" |
|||
self.write({'state': 'subscribed'}) |
|||
product_template_id = self.env.ref( |
|||
'vehicle_subscription.product_template_vehicle_subscription_form').id |
|||
product_id = self.env['product.product'].search( |
|||
[('product_tmpl_id', '=', product_template_id)]) |
|||
sale_order_id = self.env['sale.order'].create({ |
|||
'partner_id': self.customer_id.id, |
|||
}) |
|||
line = self.env["sale.order.line"].create({ |
|||
'product_id': product_id.id, |
|||
'product_uom_qty': 1, |
|||
'price_unit': self.price, |
|||
'order_id': sale_order_id.id |
|||
}) |
|||
self.sale_id = sale_order_id |
|||
|
|||
def action_request(self): |
|||
"""Request for change subscription is generated """ |
|||
return { |
|||
'type': 'ir.actions.act_window', |
|||
'view_mode': 'form', |
|||
'res_model': 'change.subscription', |
|||
'target': 'new', |
|||
} |
|||
|
|||
def action_cancel(self): |
|||
"""Proceed with cancellation of subscription""" |
|||
product_template_id = self.env.ref( |
|||
'vehicle_subscription.product_template_vehicle_subscription_form').id |
|||
product_id = self.env['product.product'].search( |
|||
[('product_tmpl_id', '=', product_template_id)]) |
|||
invoice = self.env['account.move'].search( |
|||
[('id', 'in', self.invoice_ids.ids), |
|||
('payment_state', 'in', ['paid', 'partial'])]).mapped( |
|||
'amount_untaxed_signed') |
|||
invoiced_amount = sum(invoice) |
|||
total_price = self.uptodate_price |
|||
if invoiced_amount == total_price: |
|||
self.write({'state': 'cancel'}) |
|||
self.sale_id.action_done() |
|||
elif invoiced_amount > total_price: |
|||
self.write({'state': 'cancel'}) |
|||
self.refund_id = self.env['account.move'].create({ |
|||
'move_type': 'out_refund', |
|||
'invoice_date': fields.Date.today(), |
|||
'partner_id': self.customer_id.id, |
|||
'invoice_line_ids': [(0, 0, { |
|||
'product_id': product_id.id, |
|||
'name': self.vehicle_id.name, |
|||
'price_unit': self.uptodate_price, |
|||
})] |
|||
}) |
|||
else: |
|||
return { |
|||
'type': 'ir.actions.client', |
|||
'tag': 'display_notification', |
|||
'params': { |
|||
'title': _('Warning'), |
|||
'message': 'you need to pay amount till date inorder to ' |
|||
'cancel subscription', |
|||
'sticky': True, |
|||
} |
|||
} |
|||
|
|||
@api.onchange('end_date') |
|||
def _onchange_end_date(self): |
|||
"""Check expiry for subscription""" |
|||
if self.end_date: |
|||
if self.end_date < fields.Date.today(): |
|||
self.write({'state': 'expired'}) |
|||
self.sale_id.action_done() |
@ -0,0 +1,69 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Swaraj R (<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 |
@ -0,0 +1,34 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Swaraj R (<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, help="Helps you to choose seating " |
|||
"capacity") |
@ -0,0 +1,46 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Swaraj R (<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", required=True, |
|||
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") |
@ -0,0 +1,80 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Swaraj R (<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 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", required=True, readonly=True) |
|||
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", |
|||
required=True, readonly=True, |
|||
help="Currently using vehicle of " |
|||
"customer will be set") |
|||
new_vehicle_id = fields.Many2one('fleet.vehicle', |
|||
string="New Vehicle", |
|||
readonly=True, |
|||
required=True, |
|||
help="Can choose different vehicle " |
|||
"with same model") |
|||
reason_to_change = fields.Char(string="Reason", required=True, |
|||
readonly=True, |
|||
help="Reason for changing vehicle") |
|||
subscription_id = fields.Many2one('fleet.subscription', |
|||
string='Subscription Id', |
|||
help='Subscription related to this ' |
|||
'cancellation request') |
|||
state = fields.Selection( |
|||
selection=[('to_approve', 'To Approve'), |
|||
('approved', 'Approved'), |
|||
], string='State', default='to_approve', |
|||
help="States of subscription") |
|||
|
|||
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, |
|||
'is_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}) |
@ -0,0 +1,47 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Swaraj R (<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')) |
@ -0,0 +1,13 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<!--Report Action for attachment in model cancellation request--> |
|||
<record id="cancellation_request_action_report" model="ir.actions.report"> |
|||
<field name="name">Fleet Vehicle Subscription Cancel</field> |
|||
<field name="model">cancellation.request</field> |
|||
<field name="report_type">qweb-pdf</field> |
|||
<field name="report_name">account.report_invoice_with_payments</field> |
|||
<field name="report_file">account.report_invoice_with_payments</field> |
|||
<field name="binding_model_id" ref="model_cancellation_request"/> |
|||
<field name="binding_type">report</field> |
|||
</record> |
|||
</odoo> |
|
@ -0,0 +1,18 @@ |
|||
<?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="implied_ids" eval="[(4, ref('vehicle_subscription_group_user'))]"/> |
|||
<field name="category_id" ref="module_vehicle_subscription"/> |
|||
</record> |
|||
</odoo> |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 310 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 576 B |
After Width: | Height: | Size: 733 B |
After Width: | Height: | Size: 911 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 673 B |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 653 B |
After Width: | Height: | Size: 905 B |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 427 B |
After Width: | Height: | Size: 627 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 988 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 589 B |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 967 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 322 B |
After Width: | Height: | Size: 59 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 58 KiB |
After Width: | Height: | Size: 1.1 MiB |
After Width: | Height: | Size: 141 KiB |
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 63 KiB |
After Width: | Height: | Size: 76 KiB |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 108 KiB |
After Width: | Height: | Size: 142 KiB |
After Width: | Height: | Size: 146 KiB |
After Width: | Height: | Size: 110 KiB |
After Width: | Height: | Size: 95 KiB |
After Width: | Height: | Size: 79 KiB |
After Width: | Height: | Size: 479 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 9.5 KiB |
@ -0,0 +1,637 @@ |
|||
<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 & |
|||
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/1.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/2.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/4.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/5.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/6.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/7.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/9.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/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;">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/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 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/12.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/14.png" class="img-thumbnail"> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END OF SCREENSHOTS SECTION --> |
|||
|
|||
<!-- SUGGESTED PRODUCTS --> |
|||
<div class="row"> |
|||
<div class="col-lg-12 d-flex flex-column justify-content-center" |
|||
style="text-align: center; padding: 2.5rem 1rem !important;"> |
|||
<h2 style="color: #212529 !important;">Suggested Products</h2> |
|||
<hr |
|||
style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;" /> |
|||
|
|||
<div id="demo1" class="row carousel slide" data-ride="carousel"> |
|||
<!-- The slideshow --> |
|||
<div class="carousel-inner"> |
|||
<div class="carousel-item active" style="min-height:0px"> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/15.0/export_stockinfo_xls/" target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-top-left-radius:10px; border-top-right-radius:10px" |
|||
src="./assets/modules/export_image.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/15.0/custom_gantt_view/" target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-top-left-radius:10px; border-top-right-radius:10px" |
|||
src="./assets/modules/gantt_image.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/15.0/sales_credit_limit/" target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-top-left-radius:10px; border-top-right-radius:10px" |
|||
src="./assets/modules/credit_image.png"> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
<div class="carousel-item" style="min-height:0px"> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/15.0/base_account_budget/" target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-top-left-radius:10px; border-top-right-radius:10px" |
|||
src="./assets/modules/budget_image.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/15.0/product_to_quotation/" target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-top-left-radius:10px; border-top-right-radius:10px" |
|||
src="./assets/modules/quotation_image.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/15.0/employee_documents_expiry/" |
|||
target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-top-left-radius:10px; border-top-right-radius:10px" |
|||
src="./assets/modules/employee_image.png"> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- Left and right controls --> |
|||
<a class="carousel-control-prev" href="#demo1" data-slide="prev" |
|||
style="left:-25px;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="right:-25px;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 SUGGESTED 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 & 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 --> |
@ -0,0 +1,14 @@ |
|||
/** @odoo-module **/ |
|||
|
|||
import publicWidget from 'web.public.widget'; |
|||
//Booking cancellation redirect to back page
|
|||
publicWidget.registry.cancellation_page = publicWidget.Widget.extend({ |
|||
selector: '#subscription_cancellation_page', |
|||
events: { |
|||
'click .redirect_back_with_data':'_onClickBack', |
|||
}, |
|||
//Previous page
|
|||
_onClickBack:function(ev){ |
|||
window.history.back(); |
|||
} |
|||
}) |
@ -0,0 +1,14 @@ |
|||
/** @odoo-module **/ |
|||
|
|||
import publicWidget from 'web.public.widget'; |
|||
//Change subscription redirect to back page
|
|||
publicWidget.registry.change_subscription_on = publicWidget.Widget.extend({ |
|||
selector: '#change_subscription_on', |
|||
events: { |
|||
'click .redirect_back_with_data':'_onClickBack', |
|||
}, |
|||
//Previous page
|
|||
_onClickBack:function(ev){ |
|||
window.history.back(); |
|||
} |
|||
}) |
@ -0,0 +1,31 @@ |
|||
/** @odoo-module **/ |
|||
|
|||
import publicWidget from 'web.public.widget'; |
|||
import ajax from 'web.ajax'; |
|||
//Public Widget Class for Change subscription
|
|||
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('#change_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); |
|||
}); |
|||
}); |
|||
}, |
|||
}) |
@ -0,0 +1,18 @@ |
|||
/** @odoo-module **/ |
|||
|
|||
import publicWidget from 'web.public.widget'; |
|||
import ajax from '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); |
|||
} |
|||
}) |
@ -0,0 +1,31 @@ |
|||
/** @odoo-module **/ |
|||
|
|||
import publicWidget from 'web.public.widget'; |
|||
import ajax from '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); |
|||
}); |
|||
}); |
|||
} |
|||
}) |
@ -0,0 +1,14 @@ |
|||
/** @odoo-module **/ |
|||
|
|||
import publicWidget from 'web.public.widget'; |
|||
//Redirect from subscription_change_boolean_false to Previous page
|
|||
publicWidget.registry.boolean_false = publicWidget.Widget.extend({ |
|||
selector: '#boolean_false', |
|||
events: { |
|||
'click .redirect_back_with_data':'_onClickBack', |
|||
}, |
|||
//Previous page
|
|||
_onClickBack:function(ev){ |
|||
window.history.back(); |
|||
} |
|||
}) |
@ -0,0 +1,14 @@ |
|||
/** @odoo-module **/ |
|||
|
|||
import publicWidget from 'web.public.widget'; |
|||
//Redirect from subscription_change_button to previous page
|
|||
publicWidget.registry.boolean_true = publicWidget.Widget.extend({ |
|||
selector: '#boolean_true', |
|||
events: { |
|||
'click .redirect_back_with_data':'_onClickBack', |
|||
}, |
|||
//Previous page
|
|||
_onClickBack:function(ev){ |
|||
window.history.back(); |
|||
} |
|||
}) |
@ -0,0 +1,14 @@ |
|||
/** @odoo-module **/ |
|||
|
|||
import publicWidget from 'web.public.widget'; |
|||
//Redirect from subscription_form_success to previous page
|
|||
publicWidget.registry.form_page = publicWidget.Widget.extend({ |
|||
selector: '#subscription_form_page', |
|||
events: { |
|||
'click .redirect_back_with_data':'_onClickBack', |
|||
}, |
|||
//Previous page
|
|||
_onClickBack:function(ev){ |
|||
window.history.back(); |
|||
} |
|||
}) |
@ -0,0 +1,14 @@ |
|||
/** @odoo-module **/ |
|||
|
|||
import publicWidget from 'web.public.widget'; |
|||
//Redirect from subscription_vehicle_missing to previous page
|
|||
publicWidget.registry.form_page = publicWidget.Widget.extend({ |
|||
selector: '#subscription_form_page', |
|||
events: { |
|||
'click .redirect_back_with_data':'_onClickBack', |
|||
}, |
|||
//Previous page
|
|||
_onClickBack:function(ev){ |
|||
window.history.back(); |
|||
} |
|||
}) |
@ -0,0 +1,115 @@ |
|||
/** @odoo-module **/ |
|||
|
|||
import publicWidget from 'web.public.widget'; |
|||
import ajax from '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', |
|||
}, |
|||
//Click function to book subscription
|
|||
_onClickBook: async function(ev){ |
|||
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; |
|||
}); |
|||
}, |
|||
//Click function to set price
|
|||
_onClickWithFuel: async function(ev){ |
|||
this.$('#with_fuel .btn').css('background-color', 'red'); |
|||
this.$('#without_fuel .btn').css('background-color', ''); |
|||
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 |
|||
}) |
|||
} |
|||
} |
|||
}, |
|||
//Click function to set price without fuel
|
|||
_onClickWithoutFuel: async function(ev){ |
|||
this.$('#without_fuel .btn').css('background-color', 'red'); |
|||
this.$('#with_fuel .btn').css('background-color', ''); |
|||
this.$('#checkbox_for_fuel')[0].checked = false |
|||
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 |
|||
}) |
|||
} |
|||
} |
|||
}, |
|||
//Change function to set price using extra km
|
|||
_onChangeExtraKm: async function(ev){ |
|||
this.$('#checkbox_for_fuel')[0].checked = true |
|||
this.$('#with_fuel .btn').css('background-color', 'red'); |
|||
this.$('#without_fuel .btn').css('background-color', ''); |
|||
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++) { |
|||
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 |
|||
}) |
|||
} |
|||
} |
|||
}, |
|||
//Click function
|
|||
_onClickFullPayment:function(ev){ |
|||
this.$('#checkbox_for_invoice_type')[0].checked = true |
|||
this.$('#full_subscription .btn').css('background-color', 'red'); |
|||
this.$('#monthly_subscription .btn').css('background-color', ''); |
|||
}, |
|||
//Click function
|
|||
_onClickMonthlyPayment:function(ev){ |
|||
this.$('#checkbox_for_invoice_type')[0].checked = true |
|||
this.$('#full_subscription .btn').css('background-color', ''); |
|||
this.$('#monthly_subscription .btn').css('background-color', 'red'); |
|||
}, |
|||
//Click function for previous page
|
|||
_onClickBack:function(ev){ |
|||
window.history.back(); |
|||
} |
|||
}) |
@ -0,0 +1,14 @@ |
|||
/** @odoo-module **/ |
|||
|
|||
import publicWidget from 'web.public.widget'; |
|||
//Vehicle Missing redirect to back page
|
|||
publicWidget.registry.subscription_missing_page = publicWidget.Widget.extend({ |
|||
selector: '#subscription_missing_page', |
|||
events: { |
|||
'click .redirect_back_with_data':'_onClickBack', |
|||
}, |
|||
//Previous page
|
|||
_onClickBack:function(ev){ |
|||
window.history.back(); |
|||
} |
|||
}) |
@ -0,0 +1,44 @@ |
|||
/** @odoo-module **/ |
|||
|
|||
import publicWidget from 'web.public.widget'; |
|||
import Dialog from 'web.Dialog'; |
|||
import ajax from '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').val(); |
|||
this.$('#location_id')[0].value = this.$('#state_id')[0].options[this.$('#state_id')[0].selectedIndex].text +','+ city |
|||
location.style.display='none'; |
|||
}, |
|||
}) |
@ -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='currency_id']" position="after"> |
|||
<field name="is_subscription" invisible="1"/> |
|||
</xpath> |
|||
</field> |
|||
</record> |
|||
</odoo> |
@ -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> |
@ -0,0 +1,304 @@ |
|||
<?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="vehicles_website_form" id="change_my_vehicle"> |
|||
<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="change_vehicle_change" |
|||
type="text" |
|||
class="form-control s_website_form_input" |
|||
name="vehicle" |
|||
required="1"> |
|||
<option value="">Choose</option> |
|||
<option t-foreach="vehicles" |
|||
t-as="vehicle" |
|||
t-att-value="vehicle.id" |
|||
required="1"> |
|||
<t t-esc="vehicle.name"/> |
|||
</option> |
|||
</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="vehicles_website_form" id="boolean_true"> |
|||
<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" |
|||
name='vehicle' |
|||
id="current_vehicle_name" |
|||
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 value="">Choose new or different of current vehicle</option> |
|||
<option t-foreach="vehicles" |
|||
t-as="vehicle" |
|||
t-att-value="vehicle.id" |
|||
required="1"> |
|||
<t t-esc="vehicle.name"/> |
|||
</option> |
|||
</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="vehicles_website_form" id="boolean_false" |
|||
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> |
@ -0,0 +1,117 @@ |
|||
<?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'),'&',('is_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"/> |
|||
</header> |
|||
<sheet> |
|||
<div> |
|||
<div class="oe_button_box" name="button_box"> |
|||
<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" |
|||
icon="fa-dollar" |
|||
attrs="{ 'invisible': [('state', '=', 'draft')] }"> |
|||
<field string="Sale Order" name="sale" |
|||
widget="statinfo"/> |
|||
</button> |
|||
<button class="oe_stat_button" type="object" |
|||
name="action_get_invoice" |
|||
icon="fa-pencil-square-o" |
|||
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="is_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> |
@ -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"/> |
|||
<field name="subscription_price"/> |
|||
<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"/> |
|||
<field name="charge_km" invisible="0"/> |
|||
<field name="extra_km" invisible="1"/> |
|||
<field name="mileage"/> |
|||
</xpath> |
|||
</field> |
|||
</record> |
|||
</odoo> |
@ -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> |
@ -0,0 +1,250 @@ |
|||
<?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="" 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="" data-vcss="001" |
|||
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;"> |
|||
</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" |
|||
style="margin-left: -3%;" |
|||
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="top: 13% !important; z-index: 100; 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 value=""/> |
|||
<option t-foreach="states" |
|||
t-as="state" |
|||
t-att-value="state.id"> |
|||
<t t-esc="state.name"/> |
|||
</option> |
|||
</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-foreach="cities" |
|||
t-as="city" |
|||
t-att-value="city"> |
|||
<t t-esc="city"/> |
|||
</option> |
|||
</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" |
|||
autocomplete="off" |
|||
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 value=""/> |
|||
<option t-foreach="insurance_type" |
|||
t-as="insurance" |
|||
t-att-value="insurance.id"> |
|||
<t t-esc="insurance.name"/> |
|||
</option> |
|||
</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 " |
|||
data-name="Next Button"> |
|||
<div style="width: 200px;" |
|||
class="s_website_form_label"/> |
|||
<button type="submit" id="" |
|||
class="btn btn-primary" |
|||
style="width: 100%;"> |
|||
Next |
|||
</button> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<br/> |
|||
<br/> |
|||
</form> |
|||
</div> |
|||
</section> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
</template> |
|||
</odoo> |
@ -0,0 +1,108 @@ |
|||
<?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="vehicle_s_website_form" id="book_my_vehicle"> |
|||
<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 value=""/> |
|||
<option t-foreach="vehicles" |
|||
t-as="each" |
|||
t-att-value="each.id" |
|||
required="1"> |
|||
<t t-esc="each.vehicle_id.name"/> |
|||
</option> |
|||
</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> |
@ -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="vehicles_website_form" id="book_my_vehicle"> |
|||
<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; width: 100%;"> |
|||
<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: 70%;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> |