Browse Source

May 28: [ADD] Initital Commit 'one_page_checkout'

pull/254/merge
RisvanaCybro 11 months ago
parent
commit
898ad48e3a
  1. 50
      one_page_checkout/README.rst
  2. 22
      one_page_checkout/__init__.py
  3. 60
      one_page_checkout/__manifest__.py
  4. 23
      one_page_checkout/controllers/__init__.py
  5. 55
      one_page_checkout/controllers/website_form.py
  6. 136
      one_page_checkout/controllers/website_sale.py
  7. 6
      one_page_checkout/doc/RELEASE_NOTES.md
  8. BIN
      one_page_checkout/static/description/assets/icons/check.png
  9. BIN
      one_page_checkout/static/description/assets/icons/chevron.png
  10. BIN
      one_page_checkout/static/description/assets/icons/cogs.png
  11. BIN
      one_page_checkout/static/description/assets/icons/consultation.png
  12. BIN
      one_page_checkout/static/description/assets/icons/ecom-black.png
  13. BIN
      one_page_checkout/static/description/assets/icons/education-black.png
  14. BIN
      one_page_checkout/static/description/assets/icons/hotel-black.png
  15. BIN
      one_page_checkout/static/description/assets/icons/license.png
  16. BIN
      one_page_checkout/static/description/assets/icons/lifebuoy.png
  17. BIN
      one_page_checkout/static/description/assets/icons/manufacturing-black.png
  18. BIN
      one_page_checkout/static/description/assets/icons/pos-black.png
  19. BIN
      one_page_checkout/static/description/assets/icons/puzzle.png
  20. BIN
      one_page_checkout/static/description/assets/icons/restaurant-black.png
  21. BIN
      one_page_checkout/static/description/assets/icons/service-black.png
  22. BIN
      one_page_checkout/static/description/assets/icons/trading-black.png
  23. BIN
      one_page_checkout/static/description/assets/icons/training.png
  24. BIN
      one_page_checkout/static/description/assets/icons/update.png
  25. BIN
      one_page_checkout/static/description/assets/icons/user.png
  26. BIN
      one_page_checkout/static/description/assets/icons/wrench.png
  27. BIN
      one_page_checkout/static/description/assets/misc/categories.png
  28. BIN
      one_page_checkout/static/description/assets/misc/check-box.png
  29. BIN
      one_page_checkout/static/description/assets/misc/compass.png
  30. BIN
      one_page_checkout/static/description/assets/misc/corporate.png
  31. BIN
      one_page_checkout/static/description/assets/misc/customer-support.png
  32. BIN
      one_page_checkout/static/description/assets/misc/cybrosys-logo.png
  33. BIN
      one_page_checkout/static/description/assets/misc/features.png
  34. BIN
      one_page_checkout/static/description/assets/misc/logo.png
  35. BIN
      one_page_checkout/static/description/assets/misc/pictures.png
  36. BIN
      one_page_checkout/static/description/assets/misc/pie-chart.png
  37. BIN
      one_page_checkout/static/description/assets/misc/right-arrow.png
  38. BIN
      one_page_checkout/static/description/assets/misc/star.png
  39. BIN
      one_page_checkout/static/description/assets/misc/support.png
  40. BIN
      one_page_checkout/static/description/assets/misc/whatsapp.png
  41. BIN
      one_page_checkout/static/description/assets/modules/1.png
  42. BIN
      one_page_checkout/static/description/assets/modules/2.png
  43. BIN
      one_page_checkout/static/description/assets/modules/3.png
  44. BIN
      one_page_checkout/static/description/assets/modules/4.png
  45. BIN
      one_page_checkout/static/description/assets/modules/5.png
  46. BIN
      one_page_checkout/static/description/assets/modules/6.png
  47. BIN
      one_page_checkout/static/description/assets/screenshots/hero.gif
  48. BIN
      one_page_checkout/static/description/assets/screenshots/sc1.png
  49. BIN
      one_page_checkout/static/description/assets/screenshots/sc2.png
  50. BIN
      one_page_checkout/static/description/assets/screenshots/sc3.png
  51. BIN
      one_page_checkout/static/description/assets/screenshots/sc4.png
  52. BIN
      one_page_checkout/static/description/assets/screenshots/sc6.png
  53. BIN
      one_page_checkout/static/description/banner.jpg
  54. BIN
      one_page_checkout/static/description/icon.png
  55. 651
      one_page_checkout/static/description/index.html
  56. 40
      one_page_checkout/static/src/css/style.css
  57. 32
      one_page_checkout/static/src/js/checkout_form.js
  58. 228
      one_page_checkout/static/src/js/website_sale.js
  59. 138
      one_page_checkout/static/src/js/website_sale_delivery.js
  60. 91
      one_page_checkout/views/address_column_templates.xml
  61. 198
      one_page_checkout/views/address_form_templates.xml
  62. 73
      one_page_checkout/views/extra_info_templates.xml
  63. 81
      one_page_checkout/views/payment_templates.xml
  64. 48
      one_page_checkout/views/website_sale_templates.xml

50
one_page_checkout/README.rst

@ -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>`__

22
one_page_checkout/__init__.py

@ -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

60
one_page_checkout/__manifest__.py

@ -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,
}

23
one_page_checkout/controllers/__init__.py

@ -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

55
one_page_checkout/controllers/website_form.py

@ -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')

136
one_page_checkout/controllers/website_sale.py

@ -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)

6
one_page_checkout/doc/RELEASE_NOTES.md

@ -0,0 +1,6 @@
## Module <one_page_checkout>
#### 08.04.2024
#### Version 15.0.1.0.0
#### ADD
- Initial Commit for One Page Checkout

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 967 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

BIN
one_page_checkout/static/description/assets/screenshots/sc1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

BIN
one_page_checkout/static/description/assets/screenshots/sc2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

BIN
one_page_checkout/static/description/assets/screenshots/sc3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

BIN
one_page_checkout/static/description/assets/screenshots/sc4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

BIN
one_page_checkout/static/description/assets/screenshots/sc6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

BIN
one_page_checkout/static/description/banner.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

BIN
one_page_checkout/static/description/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

651
one_page_checkout/static/description/index.html

@ -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 &amp; Website
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Mobile
friendly,
awe-inspiring product pages</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/service-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Service Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Keep track of
services and invoice</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/restaurant-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Restaurant
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Run your bar or
restaurant methodically</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/hotel-black.png"
class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Hotel Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
An
all-inclusive
hotel management application</p>
</div>
</div>
</div>
</div>
<!-- END OF OUR INDUSTRIES -->
<!-- SUPPORT -->
<div class="d-flex align-items-center"
style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/customer-support.png"/>
</div>
<h2 class="mt-2"
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">
Support
</h2>
</div>
<div class="container mt-5">
<div class="row">
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4 d-flex justify-content-center align-items-center"
style="background-color: #714B67; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/support.png" height="48" width="48"
style="width: 42px; height: 42px;"/>
</div>
<div>
<h4>Need Help?</h4>
<p style="line-height: 100%;">Got questions or need help?
Get in touch.</p>
<a href="mailto:odoo@cybrosys.com">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">
odoo@cybrosys.com</p>
</a>
</div>
</div>
</div>
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4 d-flex justify-content-center align-items-center"
style="background-color: #2AC44D; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/whatsapp.png" height="52" width="52"
style="width: 52px; height: 52px;"/>
</div>
<div>
<h4>WhatsApp</h4>
<p style="line-height: 100%;">Say hi to us on WhatsApp!</p>
<a href="https://api.whatsapp.com/send?phone=918606827707">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">
+91 86068
27707</p>
</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 my-5 d-flex justify-content-center align-items-center">
<img src="assets/misc/logo.png" width="144" height="31"
style="width:144px; height: 31px; margin-top: 40px;"/>
</div>
</div>
</div>
<!-- END OF SUPPORT -->

40
one_page_checkout/static/src/css/style.css

@ -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;
}
}

32
one_page_checkout/static/src/js/checkout_form.js

@ -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;
});

228
one_page_checkout/static/src/js/website_sale.js

@ -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,
};
});

138
one_page_checkout/static/src/js/website_sale_delivery.js

@ -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);
}
},
});
});

91
one_page_checkout/views/address_column_templates.xml

@ -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>

198
one_page_checkout/views/address_form_templates.xml

@ -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') &lt; 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') &gt; 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">
&amp;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>

73
one_page_checkout/views/extra_info_templates.xml

@ -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>

81
one_page_checkout/views/payment_templates.xml

@ -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 &gt; 1" class="mb24">Choose a
delivery method
</h3>
<div t-if="delivery_nb &gt; 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>

48
one_page_checkout/views/website_sale_templates.xml

@ -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>
Loading…
Cancel
Save