@ -0,0 +1,50 @@ |
|||
.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg |
|||
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html |
|||
:alt: License: AGPL-3 |
|||
|
|||
One Page Checkout |
|||
================= |
|||
* Condensed ecommerce checkout into a single page. |
|||
|
|||
Installation |
|||
============ |
|||
- https://www.odoo.com/documentation/15.0/administration/install.html |
|||
- Install our custom addon |
|||
|
|||
License |
|||
------- |
|||
AFFERO GENERAL PUBLIC LICENSE, Version 3 (AGPL v3). |
|||
(https://www.gnu.org/licenses/agpl-3.0-standalone.html) |
|||
|
|||
Company |
|||
------- |
|||
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__ |
|||
|
|||
Credits |
|||
------- |
|||
* Developer: |
|||
(V15) Jumana Haseen, |
|||
(V16) Yassir Irfan, |
|||
Contact: odoo@cybrosys.com |
|||
|
|||
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,22 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Jumana Haseen (<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 <https://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
from . import controllers |
@ -0,0 +1,60 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Jumana Haseen (<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 <https://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
{ |
|||
'name': 'One Page Checkout', |
|||
'version': '15.0.1.0.0', |
|||
'category': 'eCommerce', |
|||
'summary': """ |
|||
Simplifies ecommerce checkout by condensing it into a single, |
|||
user-friendly page. |
|||
""", |
|||
'description': """ |
|||
Condenses the entire ecommerce checkout process into a single, |
|||
user-friendly page, simplifying the steps and enhancing the user |
|||
experience. |
|||
""", |
|||
'author': 'Cybrosys Techno Solutions', |
|||
'company': 'Cybrosys Techno Solutions', |
|||
'maintainer': 'Cybrosys Techno Solutions', |
|||
'website': 'https://www.cybrosys.com', |
|||
'images': ['static/description/banner.jpg'], |
|||
'depends': ['website', 'website_sale'], |
|||
'data': [ |
|||
'views/address_column_templates.xml', |
|||
'views/address_form_templates.xml', |
|||
'views/extra_info_templates.xml', |
|||
'views/payment_templates.xml', |
|||
'views/website_sale_templates.xml', |
|||
], |
|||
'assets': { |
|||
'web.assets_frontend': [ |
|||
'one_page_checkout/static/src/css/style.css', |
|||
'one_page_checkout/static/src/js/website_sale.js', |
|||
'one_page_checkout/static/src/js/checkout_form.js', |
|||
'one_page_checkout/static/src/js/website_sale_delivery.js', |
|||
], |
|||
}, |
|||
'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: Jumana Haseen (<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 <https://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
from . import website_form |
|||
from . import website_sale |
@ -0,0 +1,55 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Jumana Haseen (<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 <https://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
from odoo import http |
|||
from odoo.http import request |
|||
from odoo.addons.website.controllers.form import WebsiteForm |
|||
|
|||
|
|||
class WebsiteSaleForm(WebsiteForm): |
|||
""" |
|||
Class representing a form for ecommerce checkout. |
|||
Inherits: |
|||
WebsiteForm: The base class for website forms, providing common |
|||
functionalities. |
|||
Usage: |
|||
1. Create an instance of `WebsiteSaleForm` and customize it as needed. |
|||
2. Use the instance to handle the checking out in your shop. |
|||
""" |
|||
@http.route('/website/form/shop.sale.order', type='http', auth="public", |
|||
methods=['POST'], website=True) |
|||
def website_form_sale_order(self, **kwargs): |
|||
""" |
|||
This function is called when the user submits the checkout form for a |
|||
sales order on the website. It first calls the parent method `website_ |
|||
form_sale_order` to handle the submission of the form and create the |
|||
sales order. Then, it retrieves the created sales order from the |
|||
website session and stores its ID in the user's session. Finally, |
|||
it redirects the user to the payment status page. |
|||
|
|||
:param kwargs: Optional keyword arguments. |
|||
:return: A redirect to the payment status page. |
|||
""" |
|||
super(WebsiteSaleForm, self).website_form_saleorder(**kwargs) |
|||
order = request.website.sale_get_order() |
|||
if request.session.get('sale_last_order_id') is None and order: |
|||
request.session['sale_last_order_id'] = order.id |
|||
return request.redirect('/payment/status') |
@ -0,0 +1,136 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: Jumana Haseen (<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 <https://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
from odoo import http |
|||
from odoo.http import request |
|||
from odoo.addons.website_sale.controllers.main import WebsiteSale |
|||
|
|||
|
|||
class WebsiteSaleEcom(WebsiteSale): |
|||
""" |
|||
Customized version of the website sale controller for e-commerce. |
|||
This class is a subclass of `WebsiteSale` and provides additional |
|||
customizations and overrides specific to e-commerce functionality on the |
|||
website. It extends the base functionality of `WebsiteSale` to cater to the |
|||
specific needs of an e-commerce website. |
|||
|
|||
Inherits: |
|||
WebsiteSale: The base class for the website sale controller. |
|||
Usage: |
|||
1. Create an instance of `WebsiteSaleEcom` and customize it as needed. |
|||
2. Use the instance to handle e-commerce functionality on your website. |
|||
""" |
|||
|
|||
def _get_address_values(self, **post): |
|||
""" |
|||
This method overrides the default `address()` method of the |
|||
`WebsiteSale` class to get additional context values related to the |
|||
customer's address. |
|||
|
|||
:param post: A dictionary containing the form data submitted by the |
|||
user. |
|||
:type post: dict |
|||
|
|||
:return: A dictionary containing the updated q-context values related |
|||
to the customer's address. |
|||
:rtype: dict |
|||
""" |
|||
result = super(WebsiteSaleEcom, self).address(**post).qcontext |
|||
return result |
|||
|
|||
@http.route(['/shop/address'], type='http', methods=['GET', 'POST'], |
|||
auth="public", website=True, sitemap=False) |
|||
def address(self, **kw): |
|||
""" |
|||
Renders the checkout address page for the current website sale order. |
|||
If the request is a POST, updates the current order's delivery and |
|||
invoice addresses with the provided data. |
|||
|
|||
If the current user is authenticated and the order's partner matches |
|||
the authenticated user's partner, redirects to the payment page. |
|||
|
|||
:return: An HTTP response with the rendered checkout address page or a |
|||
redirection to the login or payment page. |
|||
:rtype: werkzeug.wrappers.Response |
|||
""" |
|||
|
|||
res = super(WebsiteSaleEcom, self).address(**kw) |
|||
order = request.website.sale_get_order() |
|||
render_values = self._get_shop_payment_values(order, **kw) |
|||
render_values.update({ |
|||
'is_public_user': request.website.is_public_user(), |
|||
'is_address': False}) |
|||
request.render("website_sale.address", render_values) |
|||
order = res.qcontext.get('website_sale_order') |
|||
if order: |
|||
user = request.website.user_id.sudo() |
|||
if order.partner_id.id == user.partner_id.id: |
|||
return request.redirect('/shop/payment') |
|||
else: |
|||
return res |
|||
return res |
|||
|
|||
@http.route(['/shop/extra_info'], type='http', auth="public", website=True, |
|||
sitemap=False) |
|||
def extra_info(self): |
|||
""" |
|||
Overwrites the existing extra_info function. |
|||
Redirects the current request to the checkout payment page. |
|||
|
|||
:return: An HTTP response redirecting to the checkout payment page. |
|||
:rtype: werkzeug.wrappers.Response |
|||
""" |
|||
return request.redirect('/shop/payment') |
|||
|
|||
@http.route('/shop/payment', type='http', auth='public', website=True, |
|||
sitemap=False) |
|||
def shop_payment(self, **post): |
|||
""" |
|||
Overwrites the existing shop_payment function. |
|||
Removed the redirection if there is no address for user. |
|||
This page proposes several payment means based on available |
|||
payment.provider. State at this point : |
|||
|
|||
- a draft sales order with lines; otherwise, clean context / session |
|||
and back to the shop |
|||
- no transaction in context / session, or only a draft one, if the |
|||
customer did go to a 'payment.provider' webshop_payment site but |
|||
closed the tab without paying / canceling |
|||
""" |
|||
order = request.website.sale_get_order() |
|||
render_values = self._get_shop_payment_values(order, **post) |
|||
render_values['only_services'] = order and order.only_services or False |
|||
address_values = self._get_address_values(**post) |
|||
# Included /address values to the /payment and its template |
|||
render_values.update({ |
|||
'country_states': address_values.get('country_states', []), |
|||
'only_services': address_values.get('only_services', False), |
|||
'countries': address_values.get('countries', []), |
|||
'country': address_values.get('country', []), |
|||
'checkout': address_values.get('checkout', []), |
|||
'error': address_values.get('error', {}), |
|||
'mode': address_values.get('mode', 'shipping'), |
|||
'add': True if address_values.get('response_template') is None else False, |
|||
}) |
|||
if render_values['errors']: |
|||
render_values.pop('providers', '') |
|||
render_values.pop('tokens', '') |
|||
return request.render("website_sale.payment", render_values) |
@ -0,0 +1,6 @@ |
|||
## Module <one_page_checkout> |
|||
|
|||
#### 08.04.2024 |
|||
#### Version 15.0.1.0.0 |
|||
#### ADD |
|||
- Initial Commit for One Page Checkout |
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: 49 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 48 KiB |
After Width: | Height: | Size: 162 KiB |
After Width: | Height: | Size: 109 KiB |
After Width: | Height: | Size: 91 KiB |
After Width: | Height: | Size: 98 KiB |
After Width: | Height: | Size: 77 KiB |
After Width: | Height: | Size: 128 KiB |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 8.9 KiB |
@ -0,0 +1,651 @@ |
|||
<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: #da3ce8; 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: #e83cb2; font-size: 14px; f |
|||
ont-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;"> |
|||
One Page Checkout</h1> |
|||
<p style="color:#FFFFFF; padding: 8px 15px; text-align: center; font-size: 24px;"> |
|||
This Module simplifies ecommerce checkout by condensing it |
|||
into a single, |
|||
user-friendly page. |
|||
</p> |
|||
<img src="./assets/screenshots/hero.gif" |
|||
class="img-responsive" width="100%" height="auto"/> |
|||
|
|||
<!-- END OF APP HERO --> |
|||
</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 simplifies ecommerce checkout by condensing it into a |
|||
single, |
|||
user-friendly page. |
|||
</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;">Select any delivery method.</span> |
|||
<span style="display:block; font-family:'Montserrat', sans-serif; font-size:14px">Choose your preferred delivery method from a range |
|||
of options available for your orders.</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;">Create a new address and select existing address.</span> |
|||
<span style="font-family: 'Montserrat', sans-serif; |
|||
font-size: 18px; font-weight: bold;">Easily add a new address to your profile or select |
|||
from existing addresses for a seamless and personalized checkout experience.</span> |
|||
</div> |
|||
</div> |
|||
<div class="col-sm-12 col-md-6"> |
|||
<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;">Apply your promo-codes.</span> |
|||
<span style="font-family: 'Montserrat', sans-serif; |
|||
font-size: 18px; font-weight: bold;">Enter your promo code to apply special discounts.</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;">Inline validation for public users.</span> |
|||
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Enable inline form validation for public users, |
|||
ensuring that inputted data is instantly validated and errors |
|||
are highlighted for a smoother and error-free user experience.</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;"> |
|||
Checking out with Login User. |
|||
</h3> |
|||
<img src="assets/screenshots/sc1.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;"> |
|||
Form validation on checking out with Public User. |
|||
</h3> |
|||
<img src="assets/screenshots/sc2.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;"> |
|||
Checking out with Public User by adding required details. |
|||
</h3> |
|||
<img src="assets/screenshots/sc3.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;"> |
|||
Confirm it by clicking on confirm button and save the address |
|||
</h3> |
|||
<img src="assets/screenshots/sc4.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;"> |
|||
Payment done adding payment details and redirected to confirmation page |
|||
</h3> |
|||
<img src="assets/screenshots/sc6.png" class="img-thumbnail"> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END OF SCREENSHOTS SECTION --> |
|||
|
|||
<!-- RELATED PRODUCTS --> |
|||
<div class="d-flex align-items-center" |
|||
style="border-bottom: 2px solid #714B67; padding: 15px 0px;"> |
|||
<div class="d-flex justify-content-center align-items-center mr-2" |
|||
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
|||
<img src="assets/misc/categories.png"/> |
|||
</div> |
|||
<h2 class="mt-2" |
|||
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
|||
Related |
|||
Products |
|||
</h2> |
|||
</div> |
|||
<div class="row"> |
|||
<div class="col-sm-12"> |
|||
<div id="demo1" class="row carousel slide" data-ride="carousel"> |
|||
<!-- The slideshow --> |
|||
<div class="carousel-inner" style="padding: 30px;"> |
|||
<div class="carousel-item" style="min-height: 198.656px;"> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" |
|||
style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/15.0/woo_commerce/" |
|||
target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-radius: 0px;" |
|||
src="./assets/modules/1.png"> |
|||
</div> |
|||
</a> |
|||
</div> |
|||
<div 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/delivery_date_ecommerce/" |
|||
target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-radius: 0px;" |
|||
src="./assets/modules/2.png"></div> |
|||
</a> |
|||
</div> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" |
|||
style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/15.0/website_repeat_sale/" |
|||
target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-radius: 0px;" |
|||
src="./assets/modules/3.png"></div> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
<div class="carousel-item active" |
|||
style="min-height: 198.656px;"> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" |
|||
style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/15.0/geoip_website_redirect/" |
|||
target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-radius: 0px;" |
|||
src="./assets/modules/4.png"></div> |
|||
</a> |
|||
</div> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" |
|||
style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/15.0/product_brand_ecommerce/" |
|||
target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-radius: 0px;" |
|||
src="./assets/modules/5.png"></div> |
|||
</a> |
|||
</div> |
|||
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" |
|||
style="float:left"> |
|||
<a href="https://apps.odoo.com/apps/modules/15.0/table_reservation_on_website/" |
|||
target="_blank"> |
|||
<div style="border-radius:10px"> |
|||
<img class="img img-responsive center-block" |
|||
style="border-radius: 0px;" |
|||
src="./assets/modules/6.png"></div> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- Left and right controls --> |
|||
<a class="carousel-control-prev" href="#demo1" data-slide="prev" |
|||
style="width:35px; color:#000"> <span |
|||
class="carousel-control-prev-icon"><i |
|||
class="fa fa-chevron-left" |
|||
style="font-size:24px"></i></span> |
|||
</a> <a class="carousel-control-next" href="#demo1" |
|||
data-slide="next" style="width:35px; color:#000"> |
|||
<span class="carousel-control-next-icon"><i |
|||
class="fa fa-chevron-right" |
|||
style="font-size:24px"></i></span> |
|||
</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- END OF RELATED PRODUCTS --> |
|||
|
|||
<!-- OUR SERVICES --> |
|||
<div class="d-flex align-items-center" |
|||
style="border-bottom: 2px solid #714B67; padding: 15px 0px;"> |
|||
<div class="d-flex justify-content-center align-items-center mr-2" |
|||
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
|||
<img src="assets/misc/star.png"/> |
|||
</div> |
|||
<h2 class="mt-2" |
|||
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
|||
Our Services |
|||
</h2> |
|||
</div> |
|||
<div class="container my-5"> |
|||
<div class="row"> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #1dd1a1 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/cogs.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Customization</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #ff6b6b !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/wrench.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Implementation</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #6462CD !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/lifebuoy.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Support</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #ffa801 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/user.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Hire |
|||
Odoo |
|||
Developer</h6> |
|||
</div> |
|||
|
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #54a0ff !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/puzzle.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Integration</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #6d7680 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/update.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Migration</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #786fa6 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/consultation.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Consultancy</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #f8a5c2 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/training.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Implementation</h6> |
|||
</div> |
|||
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> |
|||
<div class="d-flex justify-content-center align-items-center mx-3 my-3" |
|||
style="background-color: #e6be26 !important; border-radius: 15px !important; height: 80px; width: 80px;"> |
|||
<img src="assets/icons/license.png" class="img-responsive" |
|||
height="48px" width="48px"> |
|||
</div> |
|||
<h6 class="text-center" |
|||
style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> |
|||
Odoo |
|||
Licensing Consultancy</h6> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- END OF OUR SERVICES --> |
|||
|
|||
<!-- OUR INDUSTRIES --> |
|||
<div class="d-flex align-items-center" |
|||
style="border-bottom: 2px solid #714B67; padding: 15px 0px;"> |
|||
<div class="d-flex justify-content-center align-items-center mr-2" |
|||
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
|||
<img src="assets/misc/corporate.png"/> |
|||
</div> |
|||
<h2 class="mt-2" |
|||
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
|||
Our |
|||
Industries |
|||
</h2> |
|||
</div> |
|||
<div class="container my-5"> |
|||
<div class="row"> |
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" |
|||
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="assets/icons/trading-black.png" |
|||
class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
Trading |
|||
</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
Easily procure |
|||
and |
|||
sell your products</p> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" |
|||
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="assets/icons/pos-black.png" |
|||
class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
POS |
|||
</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
Easy |
|||
configuration |
|||
and convivial experience</p> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" |
|||
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="assets/icons/education-black.png" |
|||
class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
Education |
|||
</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
A platform for |
|||
educational management</p> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" |
|||
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="assets/icons/manufacturing-black.png" |
|||
class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
Manufacturing |
|||
</h5> |
|||
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> |
|||
Plan, track and |
|||
schedule your operations</p> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-3"> |
|||
<div class="my-4 d-flex flex-column justify-content-center" |
|||
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;"> |
|||
<img src="assets/icons/ecom-black.png" |
|||
class="img-responsive mb-3" height="48px" width="48px"> |
|||
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> |
|||
E-commerce & 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,40 @@ |
|||
/* Column Responsive CSS for including three templates in a single page */ |
|||
.single_pg_checkout_layout{ |
|||
width:90%; |
|||
max-width:1400px; |
|||
margin:15px auto; |
|||
} |
|||
.single_pg_checkout_layout .column { |
|||
float: left; |
|||
width: 29.33%; |
|||
margin:15px auto; |
|||
|
|||
} |
|||
.block-ui{ |
|||
pointer-events:none; |
|||
opacity:0.5; |
|||
} |
|||
/* Clear floats after the columns */ |
|||
.single_pg_checkout_layout:after { |
|||
content: ""; |
|||
display: table; |
|||
clear: both; |
|||
} |
|||
@media screen and (max-width: 500px) { |
|||
.single_pg_checkout_layout .column { |
|||
width: 80%; |
|||
margin: 15px auto; |
|||
} |
|||
} |
|||
@media screen and (max-width: 500px) { |
|||
.single_pg_checkout_layout .column { |
|||
width: 90%; |
|||
margin: 15px auto; |
|||
} |
|||
} |
|||
@media screen and (max-width: 500px) { |
|||
.single_pg_checkout_layout .column { |
|||
width: 97%; |
|||
margin: 15px auto; |
|||
} |
|||
} |
@ -0,0 +1,32 @@ |
|||
odoo.define('one_page_checkout.checkout_form', require => { |
|||
'use strict'; |
|||
|
|||
const publicWidget = require('web.public.widget'); |
|||
const paymentFormMixin = require('payment.payment_form_mixin'); |
|||
/** |
|||
* OnePagePaymentForm widget. Enhances the payment form by adding a click |
|||
* event listener that submits the extra_info_form along with the payment form. |
|||
* |
|||
* @extends paymentFormMixin |
|||
*/ |
|||
publicWidget.registry.OnePagePaymentForm = publicWidget.Widget.extend(paymentFormMixin, { |
|||
selector: 'form[name="o_payment_checkout"]', |
|||
events: Object.assign({}, publicWidget.Widget.prototype.events, { |
|||
'click button[name="o_payment_submit_button"]': '_onClickPayment', |
|||
}), |
|||
init: function () { |
|||
this._super(...arguments); |
|||
}, |
|||
/** |
|||
* OnePagePaymentForm widget. Enhances the payment form by adding a click |
|||
* event listener that submits the extra_info_form along with the payment form. |
|||
* |
|||
* @extends paymentFormMixin |
|||
*/ |
|||
_onClickPayment: async function (ev) { |
|||
$('#extra_info_form').submit() |
|||
|
|||
}, |
|||
}); |
|||
return publicWidget.registry.OnePagePaymentForm; |
|||
}); |
@ -0,0 +1,228 @@ |
|||
odoo.define('one_page_checkout.website_sale', function (require) { |
|||
'use strict'; |
|||
|
|||
var core = require('web.core'); |
|||
var config = require('web.config'); |
|||
var publicWidget = require('web.public.widget'); |
|||
var VariantMixin = require('website_sale.VariantMixin'); |
|||
var wSaleUtils = require('website_sale.utils'); |
|||
const cartHandlerMixin = wSaleUtils.cartHandlerMixin; |
|||
require("web.zoomodoo"); |
|||
const dom = require('web.dom'); |
|||
|
|||
publicWidget.registry.OnePageCheckoutWebsiteSale = publicWidget.Widget.extend( |
|||
VariantMixin, cartHandlerMixin, { |
|||
selector: '.single_pg_checkout_layout', |
|||
events: _.extend({}, VariantMixin.events || {}, { |
|||
'click .a-submit': '_onClickSubmit', |
|||
'click .show_coupon': '_onClickShowCoupon', |
|||
'change select[name="country_id"]': '_onChangeCountry', |
|||
'click span[title="Details"]': '_onCartDetailClick', |
|||
}), |
|||
|
|||
/** |
|||
* Initializes the widget. |
|||
* Sets the `isWebsite` property to `true`. |
|||
*/ |
|||
init: function () { |
|||
this._super.apply(this, arguments); |
|||
this.isWebsite = true; |
|||
}, |
|||
|
|||
/** |
|||
* Starts the widget. |
|||
* Calls the super method and returns the resulting promise. |
|||
* @returns {Promise} A promise representing the start of the widget. |
|||
*/ |
|||
start() { |
|||
const def = this._super(...arguments); |
|||
return def; |
|||
}, |
|||
|
|||
/** |
|||
* Destroys the widget. |
|||
* Calls the super method and performs any necessary cleanup. |
|||
*/ |
|||
destroy() { |
|||
this._super.apply(this, arguments); |
|||
this._cleanupZoom(); |
|||
}, |
|||
/** |
|||
* Changes the country and updates the corresponding fields |
|||
based on the selected country. |
|||
*/ |
|||
_changeCountry: function () { |
|||
if (!$("#country_id").val()) { |
|||
return; |
|||
} |
|||
// Get country information via RPC call
|
|||
this._rpc({ |
|||
route: "/shop/country_infos/" + $("#country_id").val(), |
|||
params: { |
|||
mode: $("#country_id").attr('mode'), |
|||
}, |
|||
}).then(function (data) { |
|||
$("input[name='phone']").attr('placeholder', data.phone_code !== 0 ? '+'+ data.phone_code : ''); // populate states and display
|
|||
var selectStates = $("select[name='state_id']"); |
|||
// Dont reload state at first loading (done in qweb)
|
|||
if (selectStates.data('init')===0 || selectStates.find('option').length===1) { |
|||
if (data.states.length || data.state_required) { |
|||
selectStates.html(''); |
|||
_.each(data.states, function (x) { |
|||
var opt = $('<option>').text(x[1]) |
|||
.attr('value', x[0]) |
|||
.attr('data-code', x[2]); |
|||
selectStates.append(opt); |
|||
}); |
|||
selectStates.parent('div').show(); |
|||
} else { |
|||
selectStates.val('').parent('div').hide(); |
|||
} |
|||
selectStates.data('init', 0); |
|||
} else { |
|||
selectStates.data('init', 0); |
|||
} |
|||
// Manage fields order / visibility
|
|||
if (data.fields) { |
|||
if ($.inArray('zip', data.fields) > $.inArray('city', data.fields)){ |
|||
$(".div_zip").before($(".div_city")); |
|||
} else { |
|||
$(".div_zip").after($(".div_city")); |
|||
} |
|||
var all_fields = ["street", "zip", "city", "country_name"]; // "state_code"];
|
|||
_.each(all_fields, function (field) { |
|||
$(".checkout_autoformat .div_" + field.split('_')[0]).toggle($.inArray(field, data.fields)>=0); |
|||
}); |
|||
} |
|||
if ($("label[for='zip']").length) { |
|||
$("label[for='zip']").toggleClass('label-optional', !data.zip_required); |
|||
$("label[for='zip']").get(0).toggleAttribute('required', !!data.zip_required); |
|||
} |
|||
if ($("label[for='zip']").length) { |
|||
$("label[for='state_id']").toggleClass('label-optional', !data.state_required); |
|||
$("label[for='state_id']").get(0).toggleAttribute('required', !!data.state_required); |
|||
} |
|||
}); |
|||
}, |
|||
/** |
|||
* Handles the click event on submit buttons and performs the necessary actions. |
|||
* @param {Event} ev - The click event. |
|||
* @param {boolean} forceSubmit - Determines whether to force the submission |
|||
even if certain conditions are not met. |
|||
*/ |
|||
_onClickSubmit: function (ev, forceSubmit) { |
|||
if ($(ev.currentTarget).is('#products_grid .a-submit') && !forceSubmit) { |
|||
return; |
|||
} |
|||
// Hide the 'address_public_user' div
|
|||
var $aSubmit = $(ev.currentTarget); |
|||
if (!ev.isDefaultPrevented() && !$aSubmit.is(".disabled")) { |
|||
ev.preventDefault(); |
|||
$aSubmit.closest('form').submit(); |
|||
} |
|||
if ($aSubmit.hasClass('a-submit-disable')) { |
|||
$aSubmit.addClass("disabled"); |
|||
} |
|||
if ($aSubmit.hasClass('a-submit-loading')) { |
|||
var loading = '<span class="fa fa-cog fa-spin"/>'; |
|||
var fa_span = $aSubmit.find('span[class*="fa"]'); |
|||
if (fa_span.length) { |
|||
fa_span.replaceWith(loading); |
|||
} else { |
|||
$aSubmit.append(loading); |
|||
} |
|||
} |
|||
}, |
|||
/** |
|||
* Handles the click event to show the coupon form by hiding the |
|||
"show coupon" button and displaying the coupon form. |
|||
* @param {Event} ev - The click event. |
|||
*/ |
|||
_onClickShowCoupon: function (ev) { |
|||
$(".show_coupon").hide(); |
|||
$('.coupon_form').removeClass('d-none'); |
|||
}, |
|||
/** |
|||
* Handles the change event on the country field and triggers the country |
|||
change functionality. |
|||
* If the checkout_autoformat element is not present, the function does |
|||
nothing.one_page_checkout_cart |
|||
* This function internally calls the _changeCountry function. |
|||
* @param {Event} ev - The change event. |
|||
*/ |
|||
_onChangeCountry: function (ev) { |
|||
if (!this.$('.checkout_autoformat').length) { |
|||
return; |
|||
} |
|||
this._changeCountry(); |
|||
}, |
|||
/** |
|||
* Handles the click event on the cart detail element. |
|||
* Toggles the chevron icon and shows/hides the summary div accordingly. |
|||
* @param {Event} ev - The click event. |
|||
*/ |
|||
_onCartDetailClick: function(ev) { |
|||
var $elem = $(ev.currentTarget); |
|||
if ($elem.hasClass('fa-chevron-down')) { |
|||
$elem.removeClass('fa-chevron-down'); |
|||
$elem.addClass('fa-chevron-up'); |
|||
} else { |
|||
$elem.removeClass('fa-chevron-up'); |
|||
$elem.addClass('fa-chevron-down'); |
|||
} |
|||
var $summary_div = $('.toggle_summary_div'); |
|||
$summary_div.toggleClass('d-none'); |
|||
} |
|||
}); |
|||
/** |
|||
* This widget is used for the one-page checkout cart functionality. |
|||
* It adds events to change shipping and edit address. |
|||
*/ |
|||
publicWidget.registry.OnePageCheckoutWebsiteSaleCart = publicWidget.Widget.extend({ |
|||
selector: '.single_pg_checkout_layout .oe_cart', |
|||
events: { |
|||
'click .js_change_shipping': '_onClickChangeShipping', |
|||
'click .js_edit_address': '_onClickEditAddress', |
|||
}, |
|||
/** |
|||
* Handles the click event on the "Change Shipping" element. |
|||
* Updates the shipping options by toggling visibility and applying CSS classes. |
|||
* Performs a POST request to update the selected shipping option via AJAX. |
|||
* @param {Event} ev - The click event. |
|||
*/ |
|||
_onClickChangeShipping: function (ev) { |
|||
var $old = $('.all_shipping').find('.card.border.border-primary'); |
|||
$old.find('.btn-ship').toggle(); |
|||
$old.addClass('js_change_shipping'); |
|||
$old.removeClass('border border-primary'); |
|||
|
|||
var $new = $(ev.currentTarget).parent('div.one_kanban').find('.card'); |
|||
$new.find('.btn-ship').toggle(); |
|||
$new.removeClass('js_change_shipping'); |
|||
$new.addClass('border border-primary'); |
|||
|
|||
var $form = $(ev.currentTarget).parent('div.one_kanban').find('form.d-none'); |
|||
$.post($form.attr('action'), $form.serialize()+'&xhr=1'); |
|||
}, |
|||
/** |
|||
* Handles the click event on the "Edit Address" element. |
|||
* Prevents the default action of the click event. |
|||
* Updates the action attribute of the corresponding form and submits it. |
|||
* @param {Event} ev - The click event. |
|||
*/ |
|||
_onClickEditAddress: function (ev) { |
|||
ev.preventDefault(); |
|||
$(ev.currentTarget).closest('div.one_kanban').find('form.d-none').attr('action', '/shop/address').submit(); |
|||
} |
|||
}); |
|||
/** |
|||
* Returns an object with two properties representing publicWidget registries. |
|||
* - OnePageCheckoutWebsiteSale: Represents the publicWidget registry for the OnePageCheckoutWebsiteSale. |
|||
* - OnePageCheckoutWebsiteSaleCart: Represents the publicWidget registry for the OnePageCheckoutWebsiteSaleCart. |
|||
* @returns {Object} An object with publicWidget registries. |
|||
*/ |
|||
return { |
|||
OnePageCheckoutWebsiteSale: publicWidget.registry.OnePageCheckoutWebsiteSale, |
|||
OnePageCheckoutWebsiteSaleCart: publicWidget.registry.OnePageCheckoutWebsiteSaleCart, |
|||
}; |
|||
}); |
@ -0,0 +1,138 @@ |
|||
odoo.define('one_page_checkout.checkout', function (require) { |
|||
'use strict'; |
|||
|
|||
var core = require('web.core'); |
|||
var publicWidget = require('web.public.widget'); |
|||
|
|||
var _t = core._t; |
|||
var concurrency = require('web.concurrency'); |
|||
var dp = new concurrency.DropPrevious(); |
|||
|
|||
publicWidget.registry.OPCWebsiteSaleDelivery = publicWidget.Widget.extend({ |
|||
selector: '.single_pg_checkout_layout', |
|||
events: { |
|||
'change select[name="shipping_id"]': '_onSetAddress', |
|||
'click #delivery_carrier .o_delivery_carrier_select': '_onCarrierClick', |
|||
}, |
|||
/** |
|||
* @override |
|||
*/ |
|||
start: function () { |
|||
var self = this; |
|||
var $carriers = $('#delivery_carrier input[name="delivery_type"]'); |
|||
// Asynchronously retrieve every carrier price
|
|||
_.each($carriers, function (carrierInput, k) { |
|||
self._showLoading($(carrierInput)); |
|||
self._rpc({ |
|||
route: '/shop/carrier_rate_shipment', |
|||
params: { |
|||
'carrier_id': carrierInput.value, |
|||
}, |
|||
}).then(self._handleCarrierUpdateResultBadge.bind(self)); |
|||
}); |
|||
return this._super.apply(this, arguments); |
|||
}, |
|||
/** |
|||
* @private |
|||
* @param {jQuery} $carrierInput |
|||
*/ |
|||
_showLoading: function ($carrierInput) { |
|||
$carrierInput.siblings('.o_wsale_delivery_badge_price').empty(); |
|||
$carrierInput.siblings('.o_wsale_delivery_badge_price').append('<span class="fa fa-circle-o-notch fa-spin"/>'); |
|||
}, |
|||
/** |
|||
* Update the total cost according to the selected shipping method |
|||
* |
|||
* @private |
|||
* @param {float} amount : The new total amount of to be paid |
|||
*/ |
|||
_updateShippingCost: function(amount){ |
|||
core.bus.trigger('update_shipping_cost', amount); |
|||
}, |
|||
/** |
|||
* Handles the result of the carrier update and updates the relevant elements on the order summary. |
|||
* Updates the carrier badge, delivery amount, untaxed amount, tax amount, total amount, and shipping cost (if applicable). |
|||
* @param {Object} result - The result of the carrier update. |
|||
*/ |
|||
_handleCarrierUpdateResult: function (result) { |
|||
this._handleCarrierUpdateResultBadge(result); |
|||
var $amountDelivery = $('#order_delivery .monetary_field'); |
|||
var $amountUntaxed = $('#order_total_untaxed .monetary_field'); |
|||
var $amountTax = $('#order_total_taxes .monetary_field'); |
|||
var $amountTotal = $('#order_total .monetary_field, #amount_total_summary.monetary_field'); |
|||
|
|||
if (result.status === true) { |
|||
$amountDelivery.html(result.new_amount_delivery); |
|||
$amountUntaxed.html(result.new_amount_untaxed); |
|||
$amountTax.html(result.new_amount_tax); |
|||
$amountTotal.html(result.new_amount_total); |
|||
} else { |
|||
$amountDelivery.html(result.new_amount_delivery); |
|||
$amountUntaxed.html(result.new_amount_untaxed); |
|||
$amountTax.html(result.new_amount_tax); |
|||
$amountTotal.html(result.new_amount_total); |
|||
} |
|||
if (result.new_amount_total_raw !== undefined) { |
|||
this._updateShippingCost(result.new_amount_total_raw); |
|||
} |
|||
}, |
|||
/** |
|||
* Handles the result of the carrier update and updates the carrier badge accordingly. |
|||
* Updates the badge text and styling based on the result status and amount. |
|||
* @param {Object} result - The result of the carrier update. |
|||
*/ |
|||
_handleCarrierUpdateResultBadge: function (result) { |
|||
var $carrierBadge = $('#delivery_carrier input[name="delivery_type"][value=' + result.carrier_id + '] ~ .o_wsale_delivery_badge_price'); |
|||
|
|||
if (result.status === true) { |
|||
// If free delivery (`free_over` field), show 'Free', not '$0'
|
|||
if (result.is_free_delivery) { |
|||
$carrierBadge.text(_t('Free')); |
|||
} else { |
|||
$carrierBadge.html(result.new_amount_delivery); |
|||
} |
|||
$carrierBadge.removeClass('o_wsale_delivery_carrier_error'); |
|||
} else { |
|||
$carrierBadge.addClass('o_wsale_delivery_carrier_error'); |
|||
$carrierBadge.text(result.error_message); |
|||
} |
|||
}, |
|||
/** |
|||
* Handles the click event on a carrier element. |
|||
* Updates the selected carrier by sending an RPC request to update the carrier. |
|||
* Shows a loading indicator while the request is being processed. |
|||
* @param {Event} ev - The click event. |
|||
*/ |
|||
_onCarrierClick: function (ev) { |
|||
var $radio = $(ev.currentTarget).find('input[type="radio"]'); |
|||
this._showLoading($radio); |
|||
$radio.prop("checked", true); |
|||
dp.add(this._rpc({ |
|||
route: '/shop/update_carrier', |
|||
params: { |
|||
carrier_id: $radio.val(), |
|||
}, |
|||
})).then(this._handleCarrierUpdateResult.bind(this)); |
|||
}, |
|||
/** |
|||
* Handles the change event on the address selection element. |
|||
* Determines whether to show the available shipping countries for billing or all countries. |
|||
* Updates the visibility and disabled state of the country and state selection elements accordingly. |
|||
* @param {Event} ev - The change event. |
|||
*/ |
|||
_onSetAddress: function (ev) { |
|||
var value = $(ev.currentTarget).val(); |
|||
var $providerFree = $('select[name="country_id"]:not(.o_provider_restricted), select[name="state_id"]:not(.o_provider_restricted)'); |
|||
var $providerRestricted = $('select[name="country_id"].o_provider_restricted, select[name="state_id"].o_provider_restricted'); |
|||
if (value === 0) { |
|||
// Ship to the same address: only show shipping countries available for billing
|
|||
$providerFree.hide().attr('disabled', true); |
|||
$providerRestricted.show().attr('disabled', false).change(); |
|||
} else { |
|||
// Create a new address: show all countries available for billing
|
|||
$providerFree.show().attr('disabled', false).change(); |
|||
$providerRestricted.hide().attr('disabled', true); |
|||
} |
|||
}, |
|||
}); |
|||
}); |
@ -0,0 +1,91 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<template id="address_column" name="Address Column"> |
|||
<div class="col-12 col-xl order-xl-1 oe_cart"> |
|||
<div class="row" |
|||
t-if="not only_services and not request.website.is_public_user()"> |
|||
<div class="col-lg-12"> |
|||
<h3 class="o_page_header mt8"> |
|||
Billing Address |
|||
</h3> |
|||
</div> |
|||
<!-- Call the address_kanban template for the billing address --> |
|||
<div class="col-lg-12 one_kanban"> |
|||
<t t-call="website_sale.address_kanban"> |
|||
<t t-set='contact' |
|||
t-value="order.partner_id"/> |
|||
<t t-set='selected' t-value="1"/> |
|||
<t t-set='readonly' t-value="1"/> |
|||
<t t-set='allow_edit' t-value="1"/> |
|||
</t> |
|||
</div> |
|||
</div> |
|||
<!-- Display the shipping address header if the user is not a |
|||
public user and has permission to access the delivery/invoice address group --> |
|||
<t t-if="not only_services and not request.website.is_public_user()"> |
|||
<div class="row"> |
|||
<div class="col-lg-12"> |
|||
<h3 class="o_page_header mt16 mb4"> |
|||
Shipping Address |
|||
</h3> |
|||
</div> |
|||
</div> |
|||
<div class="col-lg-12 one_kanban"> |
|||
<t t-call="website_sale.address_kanban"> |
|||
<t t-set='contact' |
|||
t-value="order.partner_shipping_id"/> |
|||
<t t-set='selected' t-value="1"/> |
|||
<t t-set='readonly' t-value="1"/> |
|||
<t t-set='allow_edit' t-value="1"/> |
|||
</t> |
|||
</div> |
|||
<div class="row all_shipping"> |
|||
<div class="col-lg-12"> |
|||
<div class="row mt8"> |
|||
<!-- Display a button to add a new shipping address --> |
|||
<div class="col-md-12 col-lg-12 one_kanban"> |
|||
<form action="/shop/address" |
|||
method="post" |
|||
class=''> |
|||
<input type="hidden" |
|||
name="csrf_token" |
|||
t-att-value="request.csrf_token()" |
|||
t-nocache="The csrf token must always be up to date."/> |
|||
<a role="button" |
|||
href="#" |
|||
class='a-submit btn btn-secondary mb-2 btn-block'> |
|||
<i class="fa fa-plus-square"/> |
|||
<span> |
|||
Add an address |
|||
</span> |
|||
</a> |
|||
</form> |
|||
</div> |
|||
<!-- Loop over each shipping address and call |
|||
the address_kanban template for each address --> |
|||
<t t-foreach="shippings" |
|||
t-as="ship"> |
|||
<div class="col-md-12 col-lg-6 one_kanban mb-2"> |
|||
<t t-call="website_sale.address_kanban"> |
|||
<t t-set='contact' |
|||
t-value="ship"/> |
|||
<t t-set='selected' |
|||
t-value="order.partner_shipping_id==ship"/> |
|||
<t t-set='readonly' |
|||
t-value="bool(len(shippings)==1)"/> |
|||
<t t-set='edit_billing' |
|||
t-value="bool(ship==order.partner_id)"/> |
|||
<t t-set="allow_edit" |
|||
t-value="not order.partner_id or (ship.id in order.partner_id.child_ids.ids)"/> |
|||
</t> |
|||
</div> |
|||
</t> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
<!-- Call the one_page_checkout.address_form template --> |
|||
<t t-call="one_page_checkout.address_form"/> |
|||
</div> |
|||
</template> |
|||
</odoo> |
@ -0,0 +1,198 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<template id="address_form" name="Address Form"> |
|||
<div class="row"> |
|||
<!-- Form for public users to enter their payment information --> |
|||
<form id="address_form_id" t-if="request.website.is_public_user()" |
|||
action="/shop/payment" method="post" |
|||
class="checkout_autoformat"> |
|||
<div id='address_on_payment'> |
|||
<t t-call="website_sale.address_on_payment" t-set="address"/> |
|||
</div> |
|||
<div class="row" t-if="not add"> |
|||
<t t-set="error_message" t-value="error.get('error_message', False)"/> |
|||
<t t-if="error_message"> |
|||
<h5 class="text-danger" t-esc="error_message[0]"/> |
|||
</t> |
|||
<div t-attf-class="mb-3 col-lg-12 div_name"> |
|||
<label class="col-form-label" |
|||
for="name">Name |
|||
</label> |
|||
<input type="text" name="name" |
|||
t-attf-class="form-control #{'is-invalid' if error.get('name', '') != '' else 'valid'}" |
|||
t-att-value="'name' in checkout and checkout['name']"/> |
|||
</div> |
|||
<div class="w-100"/> |
|||
<div t-attf-class="mb-3 col-lg-6" |
|||
id="div_email"> |
|||
<label t-attf-class="col-form-label #{mode[1] == 'shipping' and 'label-optional' or ''}" |
|||
for="email">Email |
|||
</label> |
|||
<input type="email" |
|||
name="email" |
|||
t-attf-class="form-control #{'is-invalid' if error.get('email', '') != '' else 'valid'}" |
|||
t-att-value="'email' in checkout and checkout['email']"/> |
|||
</div> |
|||
<div t-attf-class="mb-3 col-lg-6" |
|||
id="div_phone"> |
|||
<label class="col-form-label" |
|||
for="phone">Phone |
|||
</label> |
|||
<input type="tel" name="phone" |
|||
t-attf-class="form-control #{'is-invalid' if error.get('name', '') != '' else 'valid'}" |
|||
t-att-value="'phone' in checkout and checkout['phone']"/> |
|||
</div> |
|||
<div class="w-100"/> |
|||
<div t-attf-class="mb-3 col-lg-12 div_street"> |
|||
<label class="col-form-label" |
|||
for="street">Street |
|||
<span class="d-none d-md-inline"> |
|||
and Number |
|||
</span> |
|||
</label> |
|||
<input type="text" |
|||
name="street" |
|||
t-attf-class="form-control #{'is-invalid' if error.get('street', '') != '' else 'valid'}" |
|||
t-att-value="'street' in checkout and checkout['street']"/> |
|||
</div> |
|||
<div t-attf-class="mb-3 col-lg-12 div_street2"> |
|||
<label class="col-form-label label-optional" |
|||
for="street2">Street 2 |
|||
</label> |
|||
<input type="text" |
|||
name="street2" |
|||
t-attf-class="form-control" |
|||
t-att-value="'street2' in checkout and checkout['street2']"/> |
|||
</div> |
|||
<div class="w-100"/> |
|||
<t t-set='zip_city' |
|||
t-value='country and [x for x in country.get_address_fields() if x in ["zip", "city"]] or ["city", "zip"]'/> |
|||
<t t-if="'zip' in zip_city and zip_city.index('zip') < zip_city.index('city')"> |
|||
<div t-attf-class="mb-3 col-md-4 div_zip"> |
|||
<label class="col-form-label label-optional" |
|||
for="zip">Zip Code |
|||
</label> |
|||
<input type="text" |
|||
name="zip" |
|||
t-attf-class="form-control" |
|||
t-att-value="'zip' in checkout and checkout['zip']"/> |
|||
</div> |
|||
</t> |
|||
<div t-attf-class="mb-3 col-md-8 div_city"> |
|||
<label class="col-form-label" |
|||
for="city">City |
|||
</label> |
|||
<input type="text" name="city" |
|||
t-attf-class="form-control #{'is-invalid' if error.get('city', '') != '' else 'valid'}" |
|||
t-att-value="'city' in checkout and checkout['city']"/> |
|||
</div> |
|||
<t t-if="'zip' in zip_city and zip_city.index('zip') > zip_city.index('city')"> |
|||
<div t-attf-class="mb-3 col-md-4 div_zip"> |
|||
<label class="col-form-label label-optional" |
|||
for="zip">Zip Code |
|||
</label> |
|||
<input type="text" |
|||
name="zip" |
|||
t-attf-class="form-control" |
|||
t-att-value="'zip' in checkout and checkout['zip']"/> |
|||
</div> |
|||
</t> |
|||
<div class="w-100"/> |
|||
<div t-attf-class="mb-3 and 'o_has_error' or ''} col-lg-6 div_country"> |
|||
<label class="col-form-label" |
|||
for="country_id">Country |
|||
</label> |
|||
<select id="country_id" |
|||
name="country_id" |
|||
t-attf-class="form-select" |
|||
t-att-mode="mode[1]"> |
|||
<option value=""> |
|||
Country... |
|||
</option> |
|||
<t t-foreach="countries" |
|||
t-as="c"> |
|||
<option t-att-value="c.id" |
|||
t-att-selected="c.id == (country and country.id or -1)"> |
|||
<t t-esc="c.name"/> |
|||
</option> |
|||
</t> |
|||
</select> |
|||
</div> |
|||
<div t-attf-class="mb-3 col-lg-6 div_state" |
|||
t-att-style="(not country or not country.state_ids) and 'display: none'"> |
|||
<label class="col-form-label" for="state_id"> |
|||
State / Province |
|||
</label> |
|||
<select name="state_id" t-attf-class="form-select" |
|||
data-init="1"> |
|||
<option value=""> |
|||
State / Province... |
|||
</option> |
|||
<t t-foreach="country_states" t-as="s"> |
|||
<option t-att-value="s.id" |
|||
t-att-selected="s.id == ('state_id' in checkout and country and checkout['state_id'] != '' and int(checkout['state_id']))"> |
|||
<t t-esc="s.name"/> |
|||
</option> |
|||
</t> |
|||
</select> |
|||
</div> |
|||
<div class="w-100"/> |
|||
<!-- Checkbox to choose whether to ship to the same address as billing --> |
|||
<t t-if="mode == ('new', 'billing') and not only_services"> |
|||
<div class="col-lg-12"> |
|||
<div class="checkbox"> |
|||
<label> |
|||
<input type="checkbox" |
|||
id='shipping_use_same' |
|||
class="mr8" |
|||
name='use_same' |
|||
value="1" |
|||
checked='checked'/> |
|||
Ship to the same |
|||
address |
|||
<span class='ship_to_other text-muted' |
|||
style="display: none"> |
|||
&nbsp;( |
|||
<i>Your |
|||
shipping |
|||
address |
|||
will be |
|||
requested |
|||
later) |
|||
</i> |
|||
</span> |
|||
</label> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
</div> |
|||
<input type="hidden" name="csrf_token" |
|||
t-att-value="request.csrf_token()" |
|||
t-nocache="The csrf token must always be up to date."/> |
|||
<input type="hidden" name="submitted" |
|||
value="1"/> |
|||
<input type="hidden" name="partner_id" |
|||
t-att-value="partner_id or '0'"/> |
|||
<input type="hidden" name="callback" |
|||
t-att-value="callback"/> |
|||
<input type="hidden" |
|||
name="field_required" |
|||
t-att-value="'phone,name'"/> |
|||
<!-- Navigation --> |
|||
<div class="d-flex justify-content-between" t-if="not add"> |
|||
<a role="button" |
|||
t-att-href="mode == ('new', 'billing') and '/shop/cart' or '/shop/checkout'" |
|||
class="btn btn-secondary mb32"> |
|||
<i class="fa fa-chevron-left"/> |
|||
<span>Back</span> |
|||
</a> |
|||
<a role="button" href="#" |
|||
class="btn btn-primary mb32 a-submit a-submit-disable a-submit-loading"> |
|||
<span>Confirm</span> |
|||
<i class="fa fa-chevron-right"/> |
|||
</a> |
|||
</div> |
|||
</form> |
|||
</div> |
|||
</template> |
|||
</odoo> |
@ -0,0 +1,73 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<template id="extra_info" name="Extra Info"> |
|||
<form action="/website/form/shop.sale.order" method="post" |
|||
id="extra_info_form" |
|||
enctype="multipart/form-data" |
|||
t-attf-class="o_mark_required s_website_form_no_recaptcha #{'block-ui' if website_sale_order.partner_id.active == False else ''}" |
|||
data-mark="*" data-force_action="shop.sale.order" |
|||
data-model_name="sale.order" data-success-mode="redirect" |
|||
data-success-page="/payment/status" hide-change-model="true"> |
|||
<!-- Create a hidden input field with name "csrf_token" and |
|||
value from request.csrf_token() --> |
|||
<input type="hidden" name="csrf_token" |
|||
t-att-value="request.csrf_token()"/> |
|||
<div class="s_website_form_rows row s_col_no_bgcolor"> |
|||
<!-- Create a form field for a text input with name "client_order_ref" --> |
|||
<div class="mb-0 py-2 col-12 s_website_form_field" |
|||
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="sale1"> |
|||
<span class="s_website_form_label_content"> |
|||
Your Reference |
|||
</span> |
|||
</label> |
|||
<!-- Create a text input field with id "sale1" and |
|||
class "form-control s_website_form_input" --> |
|||
<div class="col-sm"> |
|||
<input id="sale1" type="text" |
|||
class="form-control s_website_form_input" |
|||
name="client_order_ref"/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div class="mb-0 py-2 col-12 s_website_form_field s_website_form_custom" |
|||
data-type="text" 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="sale2"> |
|||
<span class="s_website_form_label_content">Give |
|||
us your feedback |
|||
</span> |
|||
</label> |
|||
<!-- Create a textarea input field with id "sale2" |
|||
and class "form-control s_website_form_input" --> |
|||
<div class="col-sm"> |
|||
<textarea id="sale2" |
|||
class="form-control s_website_form_input" |
|||
name="Give us your feedback"/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<!-- Create a form field for a binary input with name "a_document" --> |
|||
<div class="mb-0 py-2 col-12 s_website_form_field s_website_form_custom" |
|||
data-type="binary" 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="sale3"> |
|||
<span class="s_website_form_label_content"> |
|||
Upload a document |
|||
</span> |
|||
</label> |
|||
<div class="col-sm"> |
|||
<input id="sale3" type="file" |
|||
class="form-control s_website_form_input" |
|||
name="a_document"/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</form> |
|||
</template> |
|||
</odoo> |
@ -0,0 +1,81 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<template id="payment" name="Payment"> |
|||
<!--- Section for selecting the delivery method, which is |
|||
only shown if there is more than one delivery option available. --> |
|||
<div t-if="deliveries" id="delivery_carrier"> |
|||
<t t-set="delivery_nb" t-value="len(deliveries)"/> |
|||
<h3 t-if="delivery_nb > 1" class="mb24">Choose a |
|||
delivery method |
|||
</h3> |
|||
<div t-if="delivery_nb > 1" |
|||
class="card border-0" id="delivery_method"> |
|||
<ul class="list-group"> |
|||
<t t-foreach="deliveries" t-as="delivery"> |
|||
<li class="list-group-item o_delivery_carrier_select"> |
|||
<t t-call="website_sale_delivery.payment_delivery_methods"/> |
|||
</li> |
|||
</t> |
|||
</ul> |
|||
</div> |
|||
</div> |
|||
<!-- Section for selecting the payment method, which is shown |
|||
if there is a total amount to be paid. --> |
|||
<div class="col-12 col-xl order-xl-1 oe_cart"> |
|||
<div class="oe_structure clearfix mt-3" |
|||
id="oe_structure_website_sale_payment_1"/> |
|||
<t t-if="website_sale_order.amount_total" > |
|||
<div t-if="acquirers or tokens" |
|||
id="payment_method" class="mt-3"> |
|||
<h3 class="mb24">Pay with</h3> |
|||
<t t-call="payment.checkout"> |
|||
<t t-set="footer_template_id" |
|||
t-value="'website_sale.payment_footer'"/> |
|||
<t t-set="submit_button_label">Pay |
|||
Now |
|||
</t> |
|||
</t> |
|||
</div> |
|||
<!-- If there are payment providers available, the user is |
|||
presented with the option to choose a payment method. |
|||
Otherwise, a message is displayed saying that no suitable |
|||
payment option could be found. --> |
|||
<div t-else="" class="alert alert-warning"> |
|||
<strong>No suitable payment option could be |
|||
found. |
|||
</strong> |
|||
<br/> |
|||
If you believe that it is an error, please |
|||
contact the website administrator. |
|||
</div> |
|||
</t> |
|||
</div> |
|||
<div t-if="not acquirers" class="mt-2"> |
|||
<a role="button" class="btn-link" |
|||
groups="base.group_system" |
|||
t-attf-href="/web#action=#{payment_action_id}"> |
|||
<i class="fa fa-arrow-right"/> |
|||
Add payment providers |
|||
</a> |
|||
</div> |
|||
<div class="js_payment mt-3" |
|||
t-if="not website_sale_order.amount_total" |
|||
id="payment_method" |
|||
name="o_website_sale_free_cart"> |
|||
<form target="_self" |
|||
action="/shop/payment/validate" |
|||
method="post"> |
|||
<input type="hidden" name="csrf_token" |
|||
t-att-value="request.csrf_token()" |
|||
t-nocache="The csrf token must always be up to date."/> |
|||
<!-- If there is no amount to be paid (i.e., the cart is free), |
|||
a confirmation button is displayed instead of the payment methods section. --> |
|||
<t t-call="website_sale.payment_footer"> |
|||
<t t-set="submit_button_label">Confirm |
|||
Order |
|||
</t> |
|||
</t> |
|||
</form> |
|||
</div> |
|||
</template> |
|||
</odoo> |
@ -0,0 +1,48 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<!-- This template inherits from the website_sale.payment template and |
|||
is used for the one-page checkout payment step. --> |
|||
<template id="one_page_checkout_payment" inherit_id="website_sale.payment"> |
|||
<xpath expr="//div[@id='wrap']/div" position="replace"> |
|||
<div class="row single_pg_checkout_layout"> |
|||
<div class='col-12'> |
|||
<t t-call="website_sale.wizard_checkout"> |
|||
<!-- This sets the step to 20 if the partner is inactive, |
|||
or 40 if the partner is active. --> |
|||
<t t-if="website_sale_order.partner_id.active == False"> |
|||
<t t-set="step" t-value="20"/> |
|||
</t> |
|||
<t t-else=""> |
|||
<t t-set="step" t-value="40"/> |
|||
</t> |
|||
</t> |
|||
</div> |
|||
<!-- This displays any errors that occur during checkout. --> |
|||
<div class="col-12" t-if="errors"> |
|||
<t t-foreach="errors" t-as="error"> |
|||
<div class="alert alert-danger" t-if="error" role="alert"> |
|||
<h4> |
|||
<t t-esc="error[0]"/> |
|||
</h4> |
|||
<t t-esc="error[1]"/> |
|||
</div> |
|||
</t> |
|||
</div> |
|||
<!-- This calls the cart_summary and extra_info templates for the left column. --> |
|||
<div class="column"> |
|||
<t t-call="website_sale.cart_summary"/> |
|||
<t t-call="one_page_checkout.extra_info"/> |
|||
</div> |
|||
<!-- This calls the address column template for the middle column. --> |
|||
<div class="column"> |
|||
<t t-call="one_page_checkout.address_column"/> |
|||
</div> |
|||
<!-- This calls the payment template for the right column. |
|||
If the partner is inactive, it adds the "block-ui" class to the column. --> |
|||
<div t-attf-class="column #{'block-ui' if website_sale_order.partner_id.active == False else ''}"> |
|||
<t t-call="one_page_checkout.payment"/> |
|||
</div> |
|||
</div> |
|||
</xpath> |
|||
</template> |
|||
</odoo> |