@ -0,0 +1,47 @@ |
|||||
|
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg |
||||
|
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html |
||||
|
:alt: License: AGPL-3 |
||||
|
|
||||
|
One Page Checkout |
||||
|
================= |
||||
|
* Condensed ecommerce checkout into a single page. |
||||
|
|
||||
|
Installation |
||||
|
============ |
||||
|
- https://www.odoo.com/documentation/16.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: (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) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Yassir Irfan(<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) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Yassir Irfan(<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': '16.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': ['base', 'website', 'website_sale', 'payment'], |
||||
|
'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': True, |
||||
|
} |
@ -0,0 +1,23 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Yassir Irfan(<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) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Yassir Irfan(<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,130 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Yassir Irfan(<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 |
||||
|
""" |
||||
|
return super(WebsiteSaleEcom, self).address(**post).qcontext |
||||
|
|
||||
|
@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 = 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_paymentsite 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({ |
||||
|
'account_on_checkout': address_values.get('account_on_checkout'), |
||||
|
'country_states': address_values.get('country_states', []), |
||||
|
'is_public_user': address_values.get('is_public_user'), |
||||
|
'only_services': address_values.get('only_services'), |
||||
|
'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'), |
||||
|
}) |
||||
|
if render_values['errors']: |
||||
|
render_values.pop('providers', '') |
||||
|
render_values.pop('tokens', '') |
||||
|
|
||||
|
return request.render("website_sale.payment", render_values) |
@ -0,0 +1,7 @@ |
|||||
|
## Module <one_page_checkout> |
||||
|
|
||||
|
#### 18.11.2023 |
||||
|
#### Version 16.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: 54 KiB |
After Width: | Height: | Size: 55 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 121 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 122 KiB |
After Width: | Height: | Size: 108 KiB |
After Width: | Height: | Size: 108 KiB |
After Width: | Height: | Size: 150 KiB |
After Width: | Height: | Size: 90 KiB |
After Width: | Height: | Size: 12 KiB |
@ -0,0 +1,646 @@ |
|||||
|
<div style="background-color: #714B67; height: 810px; width: 100%; padding: 15px; position: relative;"> |
||||
|
<!-- TITLE BAR --> |
||||
|
<div class="d-flex align-items-center justify-content-between" |
||||
|
style="border-bottom: 1px solid #875A7B; padding: 15px; display: flex; justify-content: space-between; align-items: center;"> |
||||
|
<img src="assets/misc/cybrosys-logo.png" width="42" height="42" |
||||
|
style="width: 42px; height: 42px;"/> |
||||
|
<div> |
||||
|
<div |
||||
|
style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;" |
||||
|
class="mr-2"> |
||||
|
<i class="fa fa-check mr-1"></i>Community |
||||
|
</div> |
||||
|
<div |
||||
|
style="color: #875A7B; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;" |
||||
|
class="mr-2"> |
||||
|
<i class="fa fa-check mr-1"></i>Enterprise |
||||
|
</div> |
||||
|
<div |
||||
|
style="color: #017E84; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;" |
||||
|
class="mr-2"> |
||||
|
<i class="fa fa-check mr-1"></i>Odoo.sh |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- END OF TITLE BAR --> |
||||
|
<div class="container"> |
||||
|
<div class="row"> |
||||
|
<div class="col-sm-12 col-md-12 col-lg-12"> |
||||
|
<!-- APP HERO --> |
||||
|
<h1 style="color: #FFFFFF; font-weight: bolder; font-size: 50px; text-align: center; margin-top: 50px;"> |
||||
|
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> |
||||
|
<!-- END OF APP HERO --> |
||||
|
<img src="assets/screenshots/hero.gif" class="img-responsive" |
||||
|
style="width: 100%; margin-left: auto; margin-right: auto;"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- NAVIGATION SECTION --> |
||||
|
<div class="d-flex align-items-center" |
||||
|
style="border-bottom: 2px solid #714B67; padding: 15px 0px; margin-top: 300px;"> |
||||
|
<div class="d-flex justify-content-center align-items-center mr-2" |
||||
|
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
||||
|
<img src="assets/misc/compass.png"/> |
||||
|
</div> |
||||
|
<h2 class="mt-2" |
||||
|
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
||||
|
Explore This |
||||
|
Module |
||||
|
</h2> |
||||
|
</div> |
||||
|
<div class="row my-4" style="font-family: 'Montserrat', sans-serif;"> |
||||
|
<div class="col-sm-12 col-md-6 my-3"> |
||||
|
<a href="#overview"> |
||||
|
<div class="d-flex justify-content-between align-items-center" |
||||
|
style="background-color: #f5f5f5; padding: 30px; width: 100%;"> |
||||
|
<div> |
||||
|
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Overview</span> |
||||
|
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">Learn |
||||
|
more about this |
||||
|
module</span> |
||||
|
</div> |
||||
|
<img src="assets/misc/right-arrow.png" width="36" height="36"/> |
||||
|
</div> |
||||
|
</a> |
||||
|
</div> |
||||
|
<div class="col-sm-12 col-md-6 my-3"> |
||||
|
<a href="#features"> |
||||
|
<div class="d-flex justify-content-between align-items-center" |
||||
|
style="background-color: #f5f5f5; padding: 30px; width: 100%;"> |
||||
|
<div> |
||||
|
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Features</span> |
||||
|
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View |
||||
|
features of this |
||||
|
module</span> |
||||
|
</div> |
||||
|
<img src="assets/misc/right-arrow.png" width="36" height="36"/> |
||||
|
</div> |
||||
|
</a> |
||||
|
</div> |
||||
|
<div class="col-sm-12 col-md-6 my-3"> |
||||
|
<a href="#screenshots"> |
||||
|
<div class="d-flex justify-content-between align-items-center" |
||||
|
style="background-color: #f5f5f5; padding: 30px; width: 100%;"> |
||||
|
<div> |
||||
|
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Screenshots</span> |
||||
|
<span style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View |
||||
|
screenshots for this |
||||
|
module</span> |
||||
|
</div> |
||||
|
<img src="assets/misc/right-arrow.png" width="36" height="36"/> |
||||
|
</div> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- END OF NAVIGATION SECTION --> |
||||
|
<!-- OVERVIEW SECTION --> |
||||
|
<div class="d-flex align-items-center" |
||||
|
style="border-bottom: 2px solid #714B67; padding: 15px 0px;" |
||||
|
id="overview"> |
||||
|
<div class="d-flex justify-content-center align-items-center mr-2" |
||||
|
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
||||
|
<img src="assets/misc/pie-chart.png"/> |
||||
|
</div> |
||||
|
<h2 class="mt-2" |
||||
|
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
||||
|
Overview |
||||
|
</h2> |
||||
|
</div> |
||||
|
<div class="row" |
||||
|
style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;"> |
||||
|
<div class="col-sm-12 py-4"> |
||||
|
This Module 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-start" |
||||
|
style="margin-top: 40px; margin-bottom: 40px"> |
||||
|
<img src="./assets/misc/check-box.png" class="mr-2"/> |
||||
|
<div> |
||||
|
<span style="display: block; 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> |
||||
|
<div class="d-flex align-items-start" |
||||
|
style="margin-top: 40px; margin-bottom: 40px"> |
||||
|
<img src="./assets/misc/check-box.png" class="mr-2"/> |
||||
|
<div> |
||||
|
<span style="display: block; font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> Create a new address and select existing address.</span> |
||||
|
<span style="display:block; font-family:'Montserrat', sans-serif; font-size:14px">Easily add a new address to your profile or select from existing addresses for a seamless and personalized checkout experience.</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-sm-12 col-md-6"> |
||||
|
<div class="d-flex align-items-start" |
||||
|
style="margin-top: 40px; margin-bottom: 40px"> |
||||
|
<img src="./assets/misc/check-box.png" class="mr-2"/> |
||||
|
<div> |
||||
|
<span style="display: block; font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> Apply your promo-codes.</span> |
||||
|
<span style="display:block; font-family:'Montserrat', sans-serif; font-size:14px">Enter your promo code to apply special discounts.</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="d-flex align-items-start" |
||||
|
style="margin-top: 40px; margin-bottom: 40px"> |
||||
|
<img src="./assets/misc/check-box.png" class="mr-2"/> |
||||
|
<div> |
||||
|
<span style="display: block; font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;"> Inline validation for public users.</span> |
||||
|
<span style="display:block; font-family:'Montserrat', sans-serif; font-size:14px">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> |
||||
|
</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> |
||||
|
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"></p> |
||||
|
<img src="./assets/screenshots/IU001.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.</h3> |
||||
|
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"></p> |
||||
|
<img src="./assets/screenshots/PU001.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 for Public User.</h3> |
||||
|
<p style="font-weight: 400; font-family: 'Montserrat', sans-serif; font-size: 14px;"></p> |
||||
|
<img src="./assets/screenshots/PU002.png" class="img-thumbnail"> |
||||
|
</div> |
||||
|
</div> |
||||
|
<!-- END OF SCREENSHOTS SECTION --> |
||||
|
<!-- RELATED PRODUCTS --> |
||||
|
<div class="d-flex align-items-center" |
||||
|
style="border-bottom: 2px solid #714B67; padding: 15px 0px;"> |
||||
|
<div class="d-flex justify-content-center align-items-center mr-2" |
||||
|
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;"> |
||||
|
<img src="./assets/misc/categories.png"/> |
||||
|
</div> |
||||
|
<h2 class="mt-2" |
||||
|
style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;"> |
||||
|
Related |
||||
|
Products |
||||
|
</h2> |
||||
|
</div> |
||||
|
<div class="row"> |
||||
|
<div class="col-sm-12"> |
||||
|
<div id="demo1" class="row carousel slide" data-ride="carousel"> |
||||
|
<!-- The slideshow --> |
||||
|
<div class="carousel-inner" style="padding: 30px;"> |
||||
|
<div class="carousel-item" style="min-height: 198.656px;"> |
||||
|
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" |
||||
|
style="float:left"> |
||||
|
<a href="https://apps.odoo.com/apps/modules/16.0/geoip_website_redirect/" |
||||
|
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/16.0/website_hide_variants/" |
||||
|
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 class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" |
||||
|
style="float:left"> |
||||
|
<a href="https://apps.odoo.com/apps/modules/16.0/odoo_website_helpdesk/" |
||||
|
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> |
||||
|
<div class="carousel-item active" |
||||
|
style="min-height: 198.656px;"> |
||||
|
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" |
||||
|
style="float:left"> |
||||
|
<a href="https://apps.odoo.com/apps/modules/16.0/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 class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" |
||||
|
style="float:left"> |
||||
|
<a href="https://apps.odoo.com/apps/modules/16.0/product_brand_ecommerce/" |
||||
|
target="_blank"> |
||||
|
<div style="border-radius:10px"> |
||||
|
<img class="img img-responsive center-block" |
||||
|
style="border-radius: 0px;" |
||||
|
src="./assets/modules/4.png"> |
||||
|
</div> |
||||
|
</a> |
||||
|
</div> |
||||
|
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" |
||||
|
style="float:left"> |
||||
|
<a href="https://apps.odoo.com/apps/modules/16.0/openai_website_product_media/" |
||||
|
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> |
||||
|
</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" |
||||
|
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" |
||||
|
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> |
||||
|
</div> |
||||
|
<!-- END OF SUPPORT --> |
@ -0,0 +1,38 @@ |
|||||
|
/* Column Responsive CSS for including three templates in a single page */ |
||||
|
.single_pg_checkout_layout{ |
||||
|
width:90%; |
||||
|
max-width:1400px; |
||||
|
margin: 0 auto; |
||||
|
} |
||||
|
.single_pg_checkout_layout .column { |
||||
|
float: left; |
||||
|
width: 33.33%; |
||||
|
} |
||||
|
.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: 1000px) { |
||||
|
.single_pg_checkout_layout .column { |
||||
|
width: 80%; |
||||
|
margin: 15px auto; |
||||
|
} |
||||
|
} |
||||
|
@media screen and (max-width: 750px) { |
||||
|
.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) { |
||||
|
// placeholder phone_code
|
||||
|
$("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; |
||||
|
} |
||||
|
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. |
||||
|
* 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,92 @@ |
|||||
|
<?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 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 is_public_user" |
||||
|
groups="account.group_delivery_invoice_address"> |
||||
|
<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,261 @@ |
|||||
|
<?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 t-if="is_public_user" |
||||
|
action="/shop/payment" method="post" |
||||
|
class="checkout_autoformat"> |
||||
|
<div class="row"> |
||||
|
<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> |
||||
|
<!-- Input fields for company name and VAT number if in B2B mode --> |
||||
|
<t t-if="website._display_partner_b2b_fields()"> |
||||
|
<div class="w-100"/> |
||||
|
<t t-set='vat_warning' |
||||
|
t-value="'vat' in checkout and checkout['vat'] and not can_edit_vat"/> |
||||
|
<t t-if="mode == ('new', 'billing') or (mode == ('edit', 'billing') and (can_edit_vat or 'vat' in checkout and checkout['vat']))"> |
||||
|
<div t-attf-class="mb-3 col-lg-6 mb-0"> |
||||
|
<label class="col-form-label fw-normal label-optional" |
||||
|
for="company_name"> |
||||
|
Company Name |
||||
|
</label> |
||||
|
<input type="text" |
||||
|
name="company_name" |
||||
|
t-attf-class="form-control" |
||||
|
t-att-value="'commercial_company_name' in checkout and checkout['commercial_company_name'] or 'company_name' in checkout and checkout['company_name']" |
||||
|
t-att-readonly="'1' if vat_warning else None"/> |
||||
|
<small t-if="vat_warning" |
||||
|
class="form-text text-muted d-block d-lg-none"> |
||||
|
Changing company |
||||
|
name is not allowed |
||||
|
once document(s) |
||||
|
have been issued |
||||
|
for your account. |
||||
|
Please contact us |
||||
|
directly for this |
||||
|
operation. |
||||
|
</small> |
||||
|
</div> |
||||
|
<div t-attf-class="mb-3 col-lg-6 div_vat mb-0"> |
||||
|
<label class="col-form-label fw-normal label-optional" |
||||
|
for="vat">TIN / |
||||
|
VAT |
||||
|
</label> |
||||
|
<input type="text" |
||||
|
name="vat" |
||||
|
t-attf-class="form-control" |
||||
|
t-att-value="'vat' in checkout and checkout['vat']" |
||||
|
t-att-readonly="'1' if vat_warning else None"/> |
||||
|
<small t-if="vat_warning" |
||||
|
class="form-text text-muted d-block d-lg-none"> |
||||
|
Changing VAT number |
||||
|
is not allowed once |
||||
|
document(s) have |
||||
|
been issued for |
||||
|
your account. |
||||
|
Please contact us |
||||
|
directly for this |
||||
|
operation. |
||||
|
</small> |
||||
|
</div> |
||||
|
<div t-if="vat_warning" |
||||
|
class="col-12 d-none d-lg-block mb-1"> |
||||
|
<small class="form-text text-muted"> |
||||
|
Changing company |
||||
|
name or VAT number |
||||
|
is not allowed once |
||||
|
document(s) have |
||||
|
been issued for |
||||
|
your account. |
||||
|
Please contact us |
||||
|
directly for this |
||||
|
operation. |
||||
|
</small> |
||||
|
</div> |
||||
|
</t> |
||||
|
</t> |
||||
|
<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"> |
||||
|
<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,82 @@ |
|||||
|
<?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="providers 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 t-if="not providers" 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> |
||||
|
</div> |
||||
|
</template> |
||||
|
</odoo> |
@ -0,0 +1,60 @@ |
|||||
|
<?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> |
||||
|
<!-- This template inherits from the website_sale.cart template and is |
||||
|
used for the one-page checkout cart feature. --> |
||||
|
<template id="one_page_checkout_cart" |
||||
|
inherit_id="website_sale.cart"> |
||||
|
<!-- This XPath expression finds the "redirect_url" element and |
||||
|
replaces it with a new value. --> |
||||
|
<xpath expr="//t[@t-set='redirect_url']" position="replace"> |
||||
|
<!-- This sets the "redirect_url" variable to the new URL for |
||||
|
the one-page checkout. --> |
||||
|
<t t-set="redirect_url" t-value="'/shop/checkout?express=1'"/> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
</odoo> |