@ -0,0 +1,46 @@ |
|||||
|
.. 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. |
||||
|
|
||||
|
Configuration |
||||
|
============= |
||||
|
* No additional configurations needed |
||||
|
|
||||
|
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: (V17) Afra K, Contact: odoo@cybrosys.com |
||||
|
|
||||
|
Contacts |
||||
|
-------- |
||||
|
* Mail Contact : odoo@cybrosys.com |
||||
|
* Website : https://cybrosys.com |
||||
|
|
||||
|
Bug Tracker |
||||
|
----------- |
||||
|
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. |
||||
|
|
||||
|
Maintainer |
||||
|
========== |
||||
|
.. image:: https://cybrosys.com/images/logo.png |
||||
|
:target: https://cybrosys.com |
||||
|
|
||||
|
This module is maintained by Cybrosys Technologies. |
||||
|
|
||||
|
For support and more information, please visit `Our Website <https://cybrosys.com/>`__ |
||||
|
|
||||
|
Further information |
||||
|
=================== |
||||
|
HTML Description: `<static/description/index.html>`__ |
@ -0,0 +1,22 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Cybrosys Techno Solutions(<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,61 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Cybrosys Techno Solutions(<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': '17.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_demo'], |
||||
|
'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', |
||||
|
'one_page_checkout/static/src/js/payment_demo.js' |
||||
|
], |
||||
|
}, |
||||
|
'license': 'AGPL-3', |
||||
|
'installable': True, |
||||
|
'auto_install': False, |
||||
|
'application': False, |
||||
|
} |
@ -0,0 +1,23 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Cybrosys Techno Solutions(<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,56 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Cybrosys Techno Solutions(<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_saleorder(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,137 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
############################################################################# |
||||
|
# |
||||
|
# Cybrosys Technologies Pvt. Ltd. |
||||
|
# |
||||
|
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
||||
|
# Author: Cybrosys Techno Solutions(<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 |
||||
|
""" |
||||
|
post.update({'partner_id': -1}) |
||||
|
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'), |
||||
|
'deliveries': order._get_delivery_methods().sudo(), |
||||
|
'delivery_action_id': request.env.ref( |
||||
|
'delivery.action_delivery_carrier_form' |
||||
|
).id, |
||||
|
'sale_order_id': order.id |
||||
|
|
||||
|
}) |
||||
|
if render_values['errors']: |
||||
|
render_values.pop('providers', '') |
||||
|
render_values.pop('tokens', '') |
||||
|
request.session['sale_last_order_id'] = order.id |
||||
|
return request.render("website_sale.payment", render_values) |
@ -0,0 +1,7 @@ |
|||||
|
## Module <one_page_checkout> |
||||
|
|
||||
|
#### 10.07.2024 |
||||
|
#### Version 17.0.1.0.0 |
||||
|
#### ADD |
||||
|
|
||||
|
- Initial Commit for One Page Checkout |
After Width: | Height: | Size: 36 KiB |
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.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 673 B |
After Width: | Height: | Size: 11 KiB |
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: 80 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: 3.2 KiB |
After Width: | Height: | Size: 589 B |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 565 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 967 B |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 912 KiB |
After Width: | Height: | Size: 228 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 85 KiB |
After Width: | Height: | Size: 81 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 67 KiB |
After Width: | Height: | Size: 77 KiB |
After Width: | Height: | Size: 85 KiB |
After Width: | Height: | Size: 88 KiB |
After Width: | Height: | Size: 237 KiB |
After Width: | Height: | Size: 108 KiB |
After Width: | Height: | Size: 138 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 80 KiB |
After Width: | Height: | Size: 12 KiB |
@ -0,0 +1,655 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html lang="en"> |
||||
|
<head> |
||||
|
<meta charset="UTF-8"> |
||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
||||
|
<title>Odoo App 3 Index</title> |
||||
|
<!-- Bootstrap CSS --> |
||||
|
<link rel="stylesheet" |
||||
|
href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css" |
||||
|
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" |
||||
|
crossorigin="anonymous"> |
||||
|
<link rel="stylesheet" |
||||
|
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css"> |
||||
|
<link rel="preconnect" href="https://fonts.googleapis.com"> |
||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> |
||||
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" |
||||
|
rel="stylesheet"> |
||||
|
</head> |
||||
|
<body> |
||||
|
<section> |
||||
|
<div class="container" |
||||
|
style="font-family: 'Inter', sans-serif !important;background-color: #fff !important;"> |
||||
|
<div class="row"> |
||||
|
<div class="col-sm-12 col-md-12 col-lg-12 d-flex justify-content-between flex-wrap align-items-sm-center" |
||||
|
style="border-bottom:1px solid rgba(0, 0, 0, 0.22)"> |
||||
|
<div class="my-3"> |
||||
|
<img src="assets/misc/Cybrosys R.png" |
||||
|
style="width:auto !important; height:40px !important"> |
||||
|
</div> |
||||
|
<div class="my-3 d-flex align-items-center"> |
||||
|
<div class="text-center" |
||||
|
style="background-color:#017E84 !important;font-size: 0.8rem !important; color:#fff !important; font-weight:500 !important; padding:4px !important; margin:0 3px !important; border-radius:50px !important; min-width: 120px !important;"> |
||||
|
Community |
||||
|
</div> |
||||
|
<div class="text-center" |
||||
|
style="background-color:#875A7B !important; color:#fff !important;font-size: 0.8rem !important; font-weight:500 !important; padding:4px !important; margin:0 3px !important; border-radius:50px !important;min-width: 120px !important;"> |
||||
|
Enterprise |
||||
|
</div> |
||||
|
<div class="text-center" |
||||
|
style="background-color:#7C7BAD !important; color:#fff !important;font-size: 0.8rem !important; font-weight:500 !important; padding:4px !important; margin:0 3px !important; border-radius:50px !important; min-width: 120px !important;"> |
||||
|
Odoo.sh |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="row"> |
||||
|
<div class="col-sm-12 col-md-12 col-lg-12 text-center d-flex align-items-center flex-column" |
||||
|
style="margin: 80px 0px !important;"> |
||||
|
<h1 style="font-size: 2.8rem;font-weight: 700; color: |
||||
|
#1A202C;"> |
||||
|
One Page Checkout</h1> |
||||
|
<p class="my-3 mb-4" |
||||
|
style="max-width: 80%; font-weight: 400 !important; line-height: 32px; color: #718096;"> |
||||
|
This Module simplifies ecommerce checkout by condensing it into a single, user-friendly page. |
||||
|
</p> |
||||
|
<div style="width: 80%; margin-top: 3rem;"> |
||||
|
<img src="assets/screenshots/hero.gif" |
||||
|
class="img-responsive" width="100%" height="auto"> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="container mt-5 mb-5"> |
||||
|
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center mt-4"> |
||||
|
<p class="m-0" |
||||
|
style="font-weight: 600; font-size: 24px; color:#714b67 !important"> |
||||
|
Key Highlights |
||||
|
</p> |
||||
|
</div> |
||||
|
<div class="row py-4"> |
||||
|
<div class="col-md-6 col-sm-12 p-3"> |
||||
|
<div class="d-flex h-100" style="padding: 30px;border-radius: 12px; |
||||
|
background: #FFF; |
||||
|
box-shadow: 1px 2px 3px 0px rgba(0, 0, 0, 0.25); "> |
||||
|
<div style="width: 36px; height: 36px; border-radius: 50%; background: #714B67; |
||||
|
display: flex; justify-content: center; align-items: center; |
||||
|
margin-right: 10px; flex-shrink: 0;"> |
||||
|
<i class="fa-solid fa-star " |
||||
|
style="color: #fff;font-size:14px;"></i> |
||||
|
</div> |
||||
|
<div> |
||||
|
<p style="color: #1A202C;font-weight: 600; |
||||
|
font-size: 1.2rem; margin-bottom: 2px;"> |
||||
|
Simplifies the ecommerce checkout process into single step. </p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-md-6 col-sm-12 p-3"> |
||||
|
<div class="d-flex h-100" style="padding: 30px;border-radius: 12px; |
||||
|
background: #FFF; |
||||
|
box-shadow: 1px 2px 3px 0px rgba(0, 0, 0, 0.25); "> |
||||
|
<div style="width: 36px; height: 36px; border-radius: 50%; background: #714B67; |
||||
|
display: flex; justify-content: center; align-items: center; |
||||
|
margin-right: 10px; flex-shrink: 0;"> |
||||
|
<i class="fa-solid fa-star " |
||||
|
style="color: #fff;font-size:14px;"></i> |
||||
|
</div> |
||||
|
<div> |
||||
|
<p style="color: #1A202C;font-weight: 600; |
||||
|
font-size: 1.2rem; margin-bottom: 2px;"> |
||||
|
Create a new address and select existing address.</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="container rounded"> |
||||
|
<ul class="nav nav-tabs d-flex" |
||||
|
style="width: fit-content;margin: 0 auto;gap: 1rem;"> |
||||
|
<li class="col text-center py-2 text-nowrap " |
||||
|
style="color: #fff; background-color: #714B67;border-radius: 6px 6px 0px 0px;"> |
||||
|
<a |
||||
|
class="active show" data-toggle="tab" href="#tab1" |
||||
|
style="color: #fff;font-weight: 500; background-color: #714B67; text-decoration: none;"> |
||||
|
<i class="fa-regular fa-image pr-2" |
||||
|
style="color: #fff;"></i> |
||||
|
Screenshots</a></li> |
||||
|
<li class="col text-center py-2 text-nowrap " |
||||
|
style="color: #fff; background-color: #714B67;border-radius: 6px 6px 0px 0px;"> |
||||
|
<a |
||||
|
data-toggle="tab" href="#tab2" |
||||
|
style="color: #fff;font-weight: 500; text-decoration: none;"><i |
||||
|
class="fa-solid fa-star pr-2" |
||||
|
style="color: #fff;"></i>Features</a></li> |
||||
|
<li class="col text-center py-2 text-nowrap " |
||||
|
style="color: #fff; background-color: #714B67;border-radius: 6px 6px 0px 0px;"> |
||||
|
<a |
||||
|
data-toggle="tab" href="#tab3" |
||||
|
style="color: #fff;font-weight: 500; text-decoration: none; background-color: #714B67;"><i |
||||
|
class="fa-solid fa-book-open pr-2" |
||||
|
style="color: #fff;"></i>Released Notes</a></li> |
||||
|
</ul> |
||||
|
<div class="tab-content" |
||||
|
style="background-color: rgba(121, 113, 119, 0.04);"> |
||||
|
<div id="tab1" class="tab-pane fade in active show"> |
||||
|
<div class="col-lg-12 py-2" |
||||
|
style="padding: 1rem 4rem !important;"> |
||||
|
<div |
||||
|
style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"> |
||||
|
<div class="row justify-content-center p-3 w-100 m-0"> |
||||
|
<img src="assets/screenshots/image1.png" |
||||
|
class="img-responsive" width="100%" |
||||
|
height="auto"> |
||||
|
</div> |
||||
|
<div class="px-3"> |
||||
|
<h4 class="mt-2" |
||||
|
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important"> |
||||
|
Checking out with Login User.</h4> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-lg-12 py-2" |
||||
|
style="padding: 1rem 4rem !important;"> |
||||
|
<div |
||||
|
style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"> |
||||
|
<div class="row justify-content-center p-3 w-100 m-0"> |
||||
|
<img src="assets/screenshots/image2.png" |
||||
|
class="img-responsive" width="100%" |
||||
|
height="auto"> |
||||
|
</div> |
||||
|
<div class="px-3"> |
||||
|
<h4 class="mt-2" |
||||
|
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important"> |
||||
|
Checking out with Public User.</h4> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-lg-12 py-2" |
||||
|
style="padding: 1rem 4rem !important;"> |
||||
|
<div |
||||
|
style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"> |
||||
|
<div class="row justify-content-center p-3 w-100 m-0"> |
||||
|
<img src="assets/screenshots/image3.png" |
||||
|
class="img-responsive" width="100%" |
||||
|
height="auto"> |
||||
|
</div> |
||||
|
<div class="px-3"> |
||||
|
<h4 class="mt-2" |
||||
|
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important"> |
||||
|
Form validation for Public User.</h4> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div id="tab2" class="tab-pane fade"> |
||||
|
<div class="col-mg-12" style="padding: 1rem 4rem;"> |
||||
|
<ul style="list-style: none; padding: 1rem 0;font-weight: 500;"> |
||||
|
<li class="py-3" |
||||
|
style="font-weight: 500;background-color: #fff; border-radius: 4px; padding: 1rem; margin-bottom: 1rem; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"> |
||||
|
<span style="margin-right: 12px;"><img |
||||
|
src="assets/misc/star (1) 2.svg" |
||||
|
alt="" |
||||
|
width="16px"></span>Support in Community, Enterprise & Odoo.sh. |
||||
|
</li> |
||||
|
<li class="py-3" |
||||
|
style="font-weight: 500;background-color: #fff; border-radius: 4px; padding: 1rem; margin-bottom: 1rem; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"> |
||||
|
<span style="margin-right: 12px;"><img |
||||
|
src="assets/misc/star (1) 2.svg" |
||||
|
alt="" |
||||
|
width="16px"></span>Select any delivery method. |
||||
|
</li> |
||||
|
<li class="py-3" |
||||
|
style="font-weight: 500;background-color: #fff; border-radius: 4px; padding: 1rem; margin-bottom: 1rem; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"> |
||||
|
<span style="margin-right: 12px;"><img |
||||
|
src="assets/misc/star (1) 2.svg" |
||||
|
alt="" |
||||
|
width="16px"></span>Create a new address and select existing address. |
||||
|
</li> |
||||
|
<li class="py-3" |
||||
|
style="font-weight: 500;background-color: #fff; border-radius: 4px; padding: 1rem; margin-bottom: 1rem; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"> |
||||
|
<span style="margin-right: 12px;"><img |
||||
|
src="assets/misc/star (1) 2.svg" |
||||
|
alt="" |
||||
|
width="16px"></span>Apply your promo-codes. |
||||
|
</li> |
||||
|
<li class="py-3" |
||||
|
style="font-weight: 500;background-color: #fff; border-radius: 4px; padding: 1rem; margin-bottom: 1rem; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"> |
||||
|
<span style="margin-right: 12px;"><img |
||||
|
src="assets/misc/star (1) 2.svg" |
||||
|
alt="" |
||||
|
width="16px"></span>Inline validation for public users. |
||||
|
</li> |
||||
|
|
||||
|
</ul> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div id="tab3" class="tab-pane fade"> |
||||
|
<div class="col-mg-12 active" style="padding: 1rem 4rem;"> |
||||
|
<div class="py-3" |
||||
|
style="font-weight: 500;background-color: #fff; border-radius: 4px; padding: 1rem; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);"> |
||||
|
<div class="d-flex mb-3" |
||||
|
style="font-size: 0.8rem; font-weight: 500;"><span>Version |
||||
|
17.0.1.0.0</span><span |
||||
|
class="px-2">|</span><span |
||||
|
style="color: #714B67;font-weight: 600;">Released on:25th Jan 2024</span> |
||||
|
</div> |
||||
|
<p class="m-0" |
||||
|
style=" color:#718096!important; font-size:1rem !important;line-height: 28px;"> |
||||
|
Initial commit for One Page Checkout </p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="container mt-5"> |
||||
|
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center mt-5"> |
||||
|
<p class="m-0" |
||||
|
style="font-weight: 600; font-size: 24px; color:#000 !important"> |
||||
|
Related Products</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div id="myCarousel" class="carousel slide py-3" data-ride="carousel"> |
||||
|
<div class="carousel-inner"> |
||||
|
<div class="carousel-item active"> |
||||
|
<div class="row p-4"> |
||||
|
<div class="col"> |
||||
|
<div class="p-3"> |
||||
|
<a href="https://apps.odoo.com/apps/modules/17.0/base_accounting_kit/" style="color: #000; text-decoration: none;"> |
||||
|
<div style="border:1px solid #CBCBCB !important;border-radius: 4px;"> |
||||
|
<div style="width: 300px; "> |
||||
|
<img src="assets/modules/1.gif" alt="" width="100%" height="auto"> |
||||
|
|
||||
|
</div> |
||||
|
<p class="text-center pt-2 text-black font-weight-bold">Odoo 17 Full Accounting Kit</p> |
||||
|
</div> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col"> |
||||
|
<div class="p-3"> |
||||
|
<a href="https://apps.odoo.com/apps/modules/17.0/invoice_format_editor/" style="color: #000; text-decoration: none;"> |
||||
|
<div style="border:1px solid #CBCBCB !important;border-radius: 4px;"> |
||||
|
<div style="width: 300px; "> |
||||
|
<img src="assets/modules/2.png" alt="" width="100%" height="auto"> |
||||
|
|
||||
|
</div> |
||||
|
<p class="text-center pt-2 text-black font-weight-bold">Invoice Format Editor</p> |
||||
|
</div> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col"> |
||||
|
<div class="p-3"> |
||||
|
<a href="https://apps.odoo.com/apps/modules/17.0/inventory_barcode_scanning/" style="color: #000; text-decoration: none;"> |
||||
|
<div style="border:1px solid #CBCBCB !important;border-radius: 4px;"> |
||||
|
<div style="width: 300px; "> |
||||
|
<img src="assets/modules/3.png" alt="" width="100%" height="auto"> |
||||
|
|
||||
|
</div> |
||||
|
<p class="text-center pt-2 text-black font-weight-bold">Barcode scanning in Inventory</p> |
||||
|
</div> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="carousel-item"> |
||||
|
<div class="row p-4"> |
||||
|
<div class="col"> |
||||
|
<div class="p-3"> |
||||
|
<a href="https://apps.odoo.com/apps/modules/17.0/whatsapp_redirect/" style="color: #000; text-decoration: none;"> |
||||
|
<div style="border:1px solid #CBCBCB !important;border-radius: 4px;"> |
||||
|
<div style="width: 300px; "> |
||||
|
<img src="assets/modules/4.jpg" alt="" width="100%" height="auto"> |
||||
|
|
||||
|
</div> |
||||
|
<p class="text-center pt-2 text-black font-weight-bold">Send Whatsapp Message</p> |
||||
|
</div> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col"> |
||||
|
<div class="p-3"> |
||||
|
<a href="https://apps.odoo.com/apps/modules/17.0/base_account_budget/" style="color: #000; text-decoration: none;"> |
||||
|
<div style="border:1px solid #CBCBCB !important;border-radius: 4px;"> |
||||
|
<div style="width: 300px;"> |
||||
|
<img src="assets/modules/5.jpg" alt="" width="100%" height="auto"> |
||||
|
|
||||
|
</div> |
||||
|
<p class="text-center pt-2 text-black font-weight-bold">Budget Management</p> |
||||
|
</div> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col"> |
||||
|
<div class="p-3"> |
||||
|
<a href="https://apps.odoo.com/apps/modules/17.0/product_barcode/" style="color: #000; text-decoration: none;"> |
||||
|
<div style="border:1px solid #CBCBCB !important;border-radius: 4px;"> |
||||
|
<div style="width: 300px;"> |
||||
|
<img src="assets/modules/6.png" alt="" width="100%" height="auto"> |
||||
|
</div> |
||||
|
<p class="text-center pt-2 text-black font-weight-bold">Product Barcode Generator</p> |
||||
|
</div> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<a class="carousel-control-prev" href="#myCarousel" 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="#myCarousel" 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 class="container mt-5"> |
||||
|
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center mt-4"> |
||||
|
<p class="m-0" |
||||
|
style="font-weight: 600; font-size: 24px; color:#000 !important"> |
||||
|
Our Services</p> |
||||
|
|
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="container my-5"> |
||||
|
<div class="row py-3"> |
||||
|
<div class="col-md-4 col-sm-6 px-4 py-4"> |
||||
|
<div |
||||
|
style="background-color: #fff; padding: 25px; text-align: center; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px; position: relative;border-radius: 4px;"> |
||||
|
<div style="position: absolute; top: 0%; left: 50%; transform: translate(-50%, -50%);"> |
||||
|
<div style="background-color:#13EA36 ; border-radius: 50%; padding: 15px; width: 68px; |
||||
|
height: 68px; display: inline-block; box-shadow:0px 4px 4px rgba(0, 0, 0, 0.25);"> |
||||
|
<img src="assets/icons/cogs.png" |
||||
|
alt="service-icon" width="38px" |
||||
|
height="auto"> |
||||
|
</div> |
||||
|
</div> |
||||
|
<p style="margin-top: 20px; font-weight: bold;">Odoo |
||||
|
Customization</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-md-4 col-sm-6 px-4 py-4"> |
||||
|
<div |
||||
|
style="background-color: #fff; padding: 25px; text-align: center; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px; position: relative;border-radius: 4px;"> |
||||
|
<div style="position: absolute; top: 0%; left: 50%; transform: translate(-50%, -50%);"> |
||||
|
<div style="background-color:#DBC711; border-radius: 50%; padding: 15px; width: 68px; |
||||
|
height: 68px; display: inline-block; box-shadow:0px 4px 4px rgba(0, 0, 0, 0.25);"> |
||||
|
<img src="assets/icons/wrench.png" |
||||
|
alt="service-icon" width="38px" |
||||
|
height="auto"> |
||||
|
</div> |
||||
|
</div> |
||||
|
<p style="margin-top: 20px; font-weight: bold;">Odoo |
||||
|
Implementation</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-md-4 col-sm-6 px-4 py-4"> |
||||
|
<div |
||||
|
style="background-color: #fff; padding: 25px; text-align: center; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px; position: relative; border-radius: 4px;"> |
||||
|
<div style="position: absolute; top: 0%; left: 50%; transform: translate(-50%, -50%);"> |
||||
|
<div style="background-color:#FF6B6B ; border-radius: 50%; padding: 15px; width: 68px; |
||||
|
height: 68px; display: inline-block; box-shadow:0px 4px 4px rgba(0, 0, 0, 0.25);"> |
||||
|
<img src="assets/icons/lifebuoy.png" |
||||
|
alt="service-icon" width="38px" |
||||
|
height="auto"> |
||||
|
</div> |
||||
|
</div> |
||||
|
<p style="margin-top: 20px; font-weight: bold;">Odoo |
||||
|
Support</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-md-4 col-sm-6 px-4 py-4"> |
||||
|
<div |
||||
|
style="background-color: #fff; padding: 25px; text-align: center; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px; position: relative; border-radius: 4px;"> |
||||
|
<div style="position: absolute; top: 0%; left: 50%; transform: translate(-50%, -50%);"> |
||||
|
<div style="background-color:#FFA801 ; border-radius: 50%; padding: 15px; width: 68px; |
||||
|
height: 68px; display: inline-block; box-shadow:0px 4px 4px rgba(0, 0, 0, 0.25);"> |
||||
|
<img src="assets/icons/user.png" |
||||
|
alt="service-icon" width="38px" |
||||
|
height="auto"> |
||||
|
</div> |
||||
|
</div> |
||||
|
<p style="margin-top: 20px; font-weight: bold;">Hire |
||||
|
Odoo Developer</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-md-4 col-sm-6 px-4 py-4"> |
||||
|
<div |
||||
|
style="background-color: #fff; padding: 25px; text-align: center; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px; position: relative; border-radius: 4px;"> |
||||
|
|
||||
|
<div style="position: absolute; top: 0%; left: 50%; transform: translate(-50%, -50%);"> |
||||
|
<div style="background-color:#54A0FF; border-radius: 50%; padding: 15px; width: 68px; |
||||
|
height: 68px; display: inline-block; box-shadow:0px 4px 4px rgba(0, 0, 0, 0.25);"> |
||||
|
<img src="assets/icons/puzzle.png" |
||||
|
alt="service-icon" width="38px" |
||||
|
height="auto"> |
||||
|
</div> |
||||
|
</div> |
||||
|
<p style="margin-top: 20px; font-weight: bold;">Odoo |
||||
|
Integration</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-md-4 col-sm-6 px-4 py-4"> |
||||
|
<div |
||||
|
style="background-color: #fff; padding: 25px; text-align: center; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px; position: relative;border-radius: 4px;"> |
||||
|
<div style="position: absolute; top: 0%; left: 50%; transform: translate(-50%, -50%);"> |
||||
|
<div style="background-color:#6D7680 ; border-radius: 50%; padding: 15px; width: 68px; |
||||
|
height: 68px; display: inline-block; box-shadow:0px 4px 4px rgba(0, 0, 0, 0.25);"> |
||||
|
<img src="assets/icons/update.png" |
||||
|
alt="service-icon" width="38px" |
||||
|
height="auto"> |
||||
|
</div> |
||||
|
</div> |
||||
|
<p style="margin-top: 20px; font-weight: bold;">Odoo |
||||
|
Migration</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-md-4 col-sm-6 px-4 py-4"> |
||||
|
<div |
||||
|
style="background-color: #fff; padding: 25px; text-align: center; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px; position: relative;border-radius: 4px;"> |
||||
|
<div style="position: absolute; top: 0%; left: 50%; transform: translate(-50%, -50%);"> |
||||
|
<div style="background-color:#786FA6 ; border-radius: 50%; padding: 15px; width: 68px; |
||||
|
height: 68px; display: inline-block; box-shadow:0px 4px 4px rgba(0, 0, 0, 0.25);"> |
||||
|
<img src="assets/icons/consultation.png" |
||||
|
alt="service-icon" width="38px" |
||||
|
height="auto"> |
||||
|
</div> |
||||
|
</div> |
||||
|
<p style="margin-top: 20px; font-weight: bold;">Odoo |
||||
|
Consultancy</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-md-4 col-sm-6 px-4 py-4"> |
||||
|
<div |
||||
|
style="background-color: #fff; padding: 25px; text-align: center; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px;position: relative;border-radius: 4px;"> |
||||
|
<div style="position: absolute; top: 0%; left: 50%; transform: translate(-50%, -50%);"> |
||||
|
<div style="background-color:#F8A5C2 ; border-radius: 50%; padding: 15px; width: 68px; |
||||
|
height: 68px; display: inline-block; box-shadow:0px 4px 4px rgba(0, 0, 0, 0.25);"> |
||||
|
<img src="assets/icons/training.png" |
||||
|
alt="service-icon" width="38px" |
||||
|
height="auto"> |
||||
|
</div> |
||||
|
</div> |
||||
|
<p style="margin-top: 20px; font-weight: bold;">Odoo |
||||
|
Implementation</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-md-4 col-sm-6 px-4 py-4"> |
||||
|
<div |
||||
|
style="background-color: #fff; padding: 25px; text-align: center; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px; position: relative;border-radius: 4px;"> |
||||
|
<div style="position: absolute; top: 0%; left: 50%; transform: translate(-50%, -50%);"> |
||||
|
<div style="background-color:#E6BE26; border-radius: 50%; padding: 15px; width: 68px; |
||||
|
height: 68px; display: inline-block; box-shadow:0px 4px 4px rgba(0, 0, 0, 0.25);"> |
||||
|
<img src="assets/icons/license.png" |
||||
|
alt="service-icon" width="38px" |
||||
|
height="auto"> |
||||
|
</div> |
||||
|
</div> |
||||
|
<p style="margin-top: 20px; font-weight: bold;">Odoo |
||||
|
Licensing Consultancy</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="container mt-5"> |
||||
|
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center mt-4"> |
||||
|
<p class="m-0" |
||||
|
style="font-weight: 600; font-size: 24px; color:#000 !important"> |
||||
|
Our Industries</p> |
||||
|
|
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="container"> |
||||
|
<div class="row my-5 py-4"> |
||||
|
<div class="col-md-3 col-sm-6 p-0"> |
||||
|
<div class="d-flex flex-column h-100 " |
||||
|
style="border-right: 1px solid rgb(209, 209, 209); border-bottom: 1px solid rgb(209, 209, 209); padding: 30px; box-shadow: 6px 0 10px rgba(228, 227, 227, 0.373);"> |
||||
|
<img src="assets/icons/trading-black.png" width="42px" |
||||
|
height="auto" alt=""> |
||||
|
<p style="color: #714B67;font-weight: 600; margin-top: 10px; |
||||
|
font-size: 1.2rem; margin-bottom: 2px;">Trading</p> |
||||
|
<p>Easily procure and sell your products</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-md-3 col-sm-6 p-0"> |
||||
|
<div class="d-flex flex-column h-100" |
||||
|
style="border-right: 1px solid rgb(209, 209, 209);border-bottom: 1px solid rgb(209, 209, 209); padding: 30px;"> |
||||
|
<img src="assets/icons/pos-black.png" width="42px" |
||||
|
height="auto" alt=""> |
||||
|
<p style="color: #714B67;font-weight: 600; margin-top: 10px; |
||||
|
font-size: 1.2rem; margin-bottom: 2px;">POS</p> |
||||
|
<p>Easy configuration and convivial experience</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-md-3 col-sm-6 p-0"> |
||||
|
<div class="d-flex flex-column h-100" |
||||
|
style="border-right: 1px solid rgb(209, 209, 209);border-bottom: 1px solid rgba(0, 0, 0, 0.2); padding: 30px; box-shadow: 0 5px 10px rgba(228, 227, 227, 0.373)"> |
||||
|
<img src="assets/icons/education-black.png" width="42px" |
||||
|
height="auto" alt=""> |
||||
|
<p style="color: #714B67;font-weight: 600; margin-top: 10px; |
||||
|
font-size: 1.2rem; margin-bottom: 2px;"> |
||||
|
Education</p> |
||||
|
<p>A platform for educational management</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-md-3 col-sm-6 p-0"> |
||||
|
<div class="d-flex flex-column h-100" |
||||
|
style="border-bottom: 1px solid rgb(209, 209, 209); padding: 30px; "> |
||||
|
<img src="assets/icons/manufacturing-black.png" |
||||
|
width="42px" height="auto" alt=""> |
||||
|
<p style="color: #714B67;font-weight: 600; margin-top: 10px; |
||||
|
font-size: 1.2rem; margin-bottom: 2px;"> |
||||
|
Manufacturing</p> |
||||
|
<p>Plan, track and schedule your operations</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-md-3 col-sm-6 p-0"> |
||||
|
<div class="d-flex flex-column h-100" |
||||
|
style="border-right: 1px solid rgb(209, 209, 209); padding: 30px;"> |
||||
|
<img src="assets/icons/ecom-black.png" width="42px" |
||||
|
height="auto" alt=""> |
||||
|
<p style="color: #714B67;font-weight: 600; margin-top: 10px; |
||||
|
font-size: 1.2rem; margin-bottom: 2px;">E-commerce & |
||||
|
Website</p> |
||||
|
<p>Mobile friendly, awe-inspiring product pages</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-md-3 col-sm-6 p-0"> |
||||
|
<div class="d-flex flex-column h-100" |
||||
|
style="border-right: 1px solid rgb(209, 209, 209); padding: 30px;box-shadow: 0 -5px 10px rgba(228, 227, 227, 0.373);"> |
||||
|
<img src="assets/icons/service-black.png" width="42px" |
||||
|
height="auto" alt=""> |
||||
|
<p style="color: #714B67;font-weight: 600; margin-top: 10px; |
||||
|
font-size: 1.2rem; margin-bottom: 2px;">Service |
||||
|
Management</p> |
||||
|
<p>Keep track of services and invoice</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-md-3 col-sm-6 p-0"> |
||||
|
<div class="d-flex flex-column h-100" |
||||
|
style="border-right: 1px solid rgb(209, 209, 209); padding: 30px; "> |
||||
|
<img src="assets/icons/restaurant-black.png" |
||||
|
width="42px" height="auto" alt=""> |
||||
|
<p style="color: #714B67;font-weight: 600; margin-top: 10px; |
||||
|
font-size: 1.2rem; margin-bottom: 2px;"> |
||||
|
Restaurant</p> |
||||
|
<p>Run your bar or restaurant methodically</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-md-3 col-sm-6 p-0"> |
||||
|
<div class="d-flex flex-column h-100" |
||||
|
style=" padding: 30px;box-shadow: -5px 0 10px rgba(228, 227, 227, 0.373);"> |
||||
|
<img src="assets/icons/hotel-black.png" width="42px" |
||||
|
height="auto" alt=""> |
||||
|
<p style="color: #714B67;font-weight: 600; margin-top: 10px; |
||||
|
font-size: 1.2rem; margin-bottom: 2px;">Hotel |
||||
|
Management</p> |
||||
|
<p>An all-inclusive hotel management application</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="container mt-5"> |
||||
|
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center mt-5"> |
||||
|
<p class="m-0" |
||||
|
style="font-weight: 600; font-size: 24px; color:#000 !important"> |
||||
|
Support</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="container my-5"> |
||||
|
<div class="row" style="background-color: #FFFAFE;"> |
||||
|
<div class="col-md-6 pb-4 d-flex align-items-center justify-content-center" |
||||
|
style="border-right: 1px solid #D9D9D9;"> |
||||
|
<div style="padding: 30px;"> |
||||
|
<div class="d-flex align-items-center"> |
||||
|
<img src="assets/misc/support (1) 1.svg" alt="" |
||||
|
width="60px" style="margin-right: 12px;"> |
||||
|
<div style="padding: 0px 8px;"> |
||||
|
<span |
||||
|
style="color: #714B67;font-size: 24px;font-weight: 600;padding-bottom: 1rem;">Need |
||||
|
Help?</span> |
||||
|
<p class="m-0" style="color:#718096;">Got |
||||
|
questions or need help? Get in touch.</p> |
||||
|
<div style="font-weight: 400;"><span><img |
||||
|
src="assets/misc/support-email.svg" |
||||
|
alt="" |
||||
|
width="18px" |
||||
|
style="filter: invert(1);margin-right: 0.8rem;"></span>odoo@cybrosys.com |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="col-md-6 pb-4 d-flex align-items-center justify-content-center"> |
||||
|
<div style="padding: 30px;"> |
||||
|
<div class="d-flex align-items-center"> |
||||
|
<img src="assets/misc/whatsapp 1.svg" alt="" |
||||
|
width="60px" style="margin-right: 12px;"> |
||||
|
<div> |
||||
|
<span style="color: #714B67;font-size: 24px;font-weight: 600;">WhatsApp</span> |
||||
|
<p class="m-0" style="color:#718096;">Say hi to |
||||
|
us on WhatsApp!</p> |
||||
|
<div style="font-weight: 400; font-size: 16px;"><span><img |
||||
|
src="assets/misc/phone.svg" |
||||
|
alt="" width="14px" |
||||
|
style="filter: invert(1); margin-right: 0.8rem;"></span>+91 |
||||
|
99456767686 |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</section> |
||||
|
<!-- Optional JavaScript --> |
||||
|
<!-- jQuery first, then Popper.js, then Bootstrap JS --> |
||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> |
||||
|
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script> |
||||
|
</body> |
||||
|
</html> |
@ -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,24 @@ |
|||||
|
/** @odoo-module **/ |
||||
|
import { _t } from '@web/core/l10n/translation'; |
||||
|
import { Component } from '@odoo/owl'; |
||||
|
import PaymentForm from '@payment/js/payment_form'; |
||||
|
|
||||
|
|
||||
|
PaymentForm.include({ |
||||
|
events: Object.assign({}, PaymentForm.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) { |
||||
|
this.$el('#extra_info_form').submit() |
||||
|
}, |
||||
|
}); |
||||
|
|
@ -0,0 +1,16 @@ |
|||||
|
/** @odoo-module **/ |
||||
|
|
||||
|
import publicWidget from "@web/legacy/js/public/public_widget"; |
||||
|
import { jsonrpc } from "@web/core/network/rpc_service"; |
||||
|
publicWidget.registry.determine_checkout = publicWidget.Widget.extend({ |
||||
|
selector: '#wrap', |
||||
|
init() { |
||||
|
this._super(...arguments); |
||||
|
this.rpc = this.bindService("rpc"); |
||||
|
}, |
||||
|
willStart: function () { |
||||
|
var self = this; |
||||
|
this.$el.find('#o_demo_express_checkout_container_6').css('display', 'none') |
||||
|
return this._super(...arguments); |
||||
|
}, |
||||
|
}); |
@ -0,0 +1,215 @@ |
|||||
|
/** @odoo-module **/ |
||||
|
|
||||
|
import wSaleUtils from "@website_sale/js/website_sale_utils"; |
||||
|
import VariantMixin from "@website_sale/js/sale_variant_mixin"; |
||||
|
import publicWidget from '@web/legacy/js/public/public_widget'; |
||||
|
import { cartHandlerMixin } from '@website_sale/js/website_sale_utils'; |
||||
|
import { WebsiteSale } from '@website_sale/js/website_sale'; |
||||
|
import { _t } from "@web/core/l10n/translation"; |
||||
|
|
||||
|
publicWidget.registry.OnePageCheckoutWebsiteSale = publicWidget.Widget.extend( |
||||
|
VariantMixin, cartHandlerMixin, { |
||||
|
selector: '.single_pg_checkout_layout', |
||||
|
events: Object.assign({}, 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; |
||||
|
this.rpc = this.bindService("rpc"); |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 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 () { |
||||
|
var self = this |
||||
|
if (!this.$el.find("#country_id").val()) { |
||||
|
return; |
||||
|
} |
||||
|
return this.rpc("/shop/country_infos/" + $("#country_id").val(), { |
||||
|
mode: this.$el.find("#country_id").attr('mode'), |
||||
|
}).then(function (data) { |
||||
|
// placeholder phone_code
|
||||
|
self.$el.find("input[name='phone']").attr('placeholder', data.phone_code !== 0 ? '+'+ data.phone_code : ''); |
||||
|
|
||||
|
// populate states and display
|
||||
|
var selectStates = self.$el.find("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(''); |
||||
|
data.states.forEach((x) => { |
||||
|
var opt = self.$el.find('<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 (data.fields.indexOf("zip") > data.fields.indexOf("city")){ |
||||
|
self.$el.find(".div_zip").before(self.$el.find(".div_city")); |
||||
|
} else { |
||||
|
self.$el.find(".div_zip").after(self.$el.find(".div_city")); |
||||
|
} |
||||
|
var all_fields = ["street", "zip", "city", "country_name"]; // "state_code"];
|
||||
|
all_fields.forEach((field) => { |
||||
|
self.$el.find(".checkout_autoformat .div_" + field.split('_')[0]).toggle(data.fields.indexOf(field)>=0); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
if (self.$el.find("label[for='zip']").length) { |
||||
|
self.$el.find("label[for='zip']").toggleClass('label-optional', !data.zip_required); |
||||
|
self.$el.find("label[for='zip']").get(0).toggleAttribute('required', !!data.zip_required); |
||||
|
} |
||||
|
if (self.$el.find("label[for='zip']").length) { |
||||
|
self.$el.find("label[for='state_id']").toggleClass('label-optional', !data.state_required); |
||||
|
self.$el.find("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 (this.$(ev.currentTarget).is('#products_grid .a-submit') && !forceSubmit) { |
||||
|
return; |
||||
|
} |
||||
|
var $aSubmit = this.$(ev.currentTarget); |
||||
|
if (!ev.isDefaultPrevented() && !$aSubmit.is(".disabled")) { |
||||
|
ev.preventDefault(); |
||||
|
$aSubmit.closest('form').submit(); |
||||
|
} |
||||
|
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) { |
||||
|
this.$el.find(".show_coupon").hide(); |
||||
|
this.$el.find('.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 = this.$(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 = this.$el.find('.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 = this.$el.find('.all_shipping').find('.card.border.border-primary'); |
||||
|
$old.find('.btn-ship').toggle(); |
||||
|
$old.addClass('js_change_shipping'); |
||||
|
$old.removeClass('border border-primary'); |
||||
|
|
||||
|
var $new = this.$(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 = this.$(ev.currentTarget).parent('div.one_kanban').find('form.d-none'); |
||||
|
this.$.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(); |
||||
|
this.$(ev.currentTarget).closest('div.one_kanban').find('form.d-none').attr('action', '/shop/address').submit(); |
||||
|
} |
||||
|
}); |
||||
|
return { |
||||
|
OnePageCheckoutWebsiteSale: publicWidget.registry.OnePageCheckoutWebsiteSale, |
||||
|
OnePageCheckoutWebsiteSaleCart: publicWidget.registry.OnePageCheckoutWebsiteSaleCart, |
||||
|
}; |
@ -0,0 +1,148 @@ |
|||||
|
/** @odoo-module **/ |
||||
|
|
||||
|
import publicWidget from "@web/legacy/js/public/public_widget"; |
||||
|
import { _t } from "@web/core/l10n/translation"; |
||||
|
import { renderToElement } from "@web/core/utils/render"; |
||||
|
import { KeepLast } from "@web/core/utils/concurrency"; |
||||
|
import { Component } from "@odoo/owl"; |
||||
|
import '@website_sale/js/website_sale_delivery'; |
||||
|
|
||||
|
publicWidget.registry.websiteSaleDelivery.include({ |
||||
|
_getCurrentLocation: async function () { |
||||
|
const data = await this.rpc("/shop/access_point/get"); |
||||
|
const carriers = this.$el.find('.o_delivery_carrier_select') |
||||
|
for (let carrier of carriers) { |
||||
|
const deliveryType = this.$el.find('input[type="radio"]').attr("delivery_type"); |
||||
|
const deliveryName = this.$el.find('.o_delivery_carrier_select label').text(); |
||||
|
const showLoc = this.$el.find(".o_show_pickup_locations"); |
||||
|
if (!showLoc) { |
||||
|
continue; |
||||
|
} |
||||
|
const orderLoc = this.$el.find(".o_order_location"); |
||||
|
if (data[deliveryType + '_access_point'] && data.delivery_name == deliveryName) { |
||||
|
this.$el.find(".o_order_location_name").text = data.name |
||||
|
this.$el.find(".o_order_location_address").text = data[deliveryType + '_access_point'] |
||||
|
orderLoc.parent().removeClass('new-parent-class'); |
||||
|
showLoc.addClass("d-none"); |
||||
|
break; |
||||
|
} else { |
||||
|
orderLoc.parent().addClass("d-none"); |
||||
|
showLoc.removeClass("d-none"); |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* @private |
||||
|
* @param {jQuery} $carrierInput |
||||
|
*/ |
||||
|
_showLoading: function (carrierInput) { |
||||
|
const priceTag = this.$el.find('.o_wsale_delivery_badge_price') |
||||
|
while (priceTag.firstChild) { |
||||
|
priceTag.removeChild(priceTag.lastChild); |
||||
|
} |
||||
|
const loadingCircle = priceTag.append(document.createElement('span')); |
||||
|
loadingCircle.addClass("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 |
||||
|
*/ |
||||
|
_getCarrierRateShipment: async function(carrierInput) { |
||||
|
const result = await this.rpc('/shop/carrier_rate_shipment', { |
||||
|
'carrier_id': carrierInput.value, |
||||
|
}); |
||||
|
}, |
||||
|
_handleCarrierUpdateResult: async function (carrierInput) { |
||||
|
//---updating carrier input function
|
||||
|
const result = await this.rpc('/shop/update_carrier', { |
||||
|
'carrier_id': carrierInput.value, |
||||
|
}) |
||||
|
this.result = result; |
||||
|
result.status = true |
||||
|
this._handleCarrierUpdateResultBadge(result); |
||||
|
if (carrierInput.checked) { |
||||
|
var amountDelivery = this.$el.find('#order_delivery .monetary_field'); |
||||
|
var amountUntaxed = this.$el.find('#order_total_untaxed .monetary_field'); |
||||
|
var amountTax = this.$el.find('#order_total_taxes .monetary_field'); |
||||
|
var amountTotal = this.$el.find('#order_total .monetary_field, #amount_total_summary.monetary_field'); |
||||
|
if(amountDelivery){ |
||||
|
amountDelivery.html = result.new_amount_delivery; |
||||
|
} |
||||
|
if(amountUntaxed){ |
||||
|
amountUntaxed.html = result.new_amount_untaxed; |
||||
|
} |
||||
|
if(amountTax){ |
||||
|
amountTax.html = result.new_amount_tax; |
||||
|
} |
||||
|
amountTotal.each(function() { |
||||
|
this.html = result.new_amount_total; |
||||
|
}); |
||||
|
if (result.new_amount_total_raw !== undefined) { |
||||
|
this._updateShippingCost(result.new_amount_total_raw); |
||||
|
// reload page only when amount_total switches between zero and not zero
|
||||
|
const hasPaymentMethod = this.$el.find( |
||||
|
"div[name='o_website_sale_free_cart']" |
||||
|
) === null; |
||||
|
const shouldDisplayPaymentMethod = result.new_amount_total_raw !== 0; |
||||
|
} |
||||
|
this._updateShippingCost(result.new_amount_delivery); |
||||
|
} |
||||
|
this._enableButton(result.status); |
||||
|
let currentId = result.carrier_id |
||||
|
const showLocations = this.$el.find(".o_show_pickup_locations"); |
||||
|
for (const showLoc of showLocations) { |
||||
|
const currentCarrierId = showLoc.closest("li").find("input")[0].value; |
||||
|
if (currentCarrierId == currentId) { |
||||
|
this._specificDropperDisplay(showLoc); |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
}, |
||||
|
|
||||
|
_onCarrierClick: async function (ev) { |
||||
|
//----on carrier click
|
||||
|
const radio = this.$el.find('.o_delivery_carrier_select')[0].firstElementChild |
||||
|
if (radio.checked && !this._shouldDisplayPickupLocations(ev) && !this.forceClickCarrier) { |
||||
|
return; |
||||
|
} |
||||
|
this.forceClickCarrier = false; |
||||
|
this._disablePayButton(); |
||||
|
this._showLoading(radio); |
||||
|
radio.checked = true; |
||||
|
await this._onClickShowLocations(ev); |
||||
|
await this._handleCarrierUpdateResult(radio); |
||||
|
this._disablePayButtonNoPickupPoint(ev); |
||||
|
}, |
||||
|
/** |
||||
|
* 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. |
||||
|
*/ |
||||
|
_enableButton(status){ |
||||
|
//----enabling payment button
|
||||
|
var PayButton = this.$el.find('[name="o_payment_submit_button"]'); |
||||
|
PayButton.removeAttr('disabled'); |
||||
|
}, |
||||
|
/** |
||||
|
* 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 = this.$el.find('select[name="country_id"]:not(.o_provider_restricted), select[name="state_id"]:not(.o_provider_restricted)'); |
||||
|
var $providerRestricted = this.$el.find('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,93 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<!-- Template for the address column --> |
||||
|
<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,262 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<!-- Template for the address form --> |
||||
|
<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="submit " 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,74 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<!-- Template for the extra info --> |
||||
|
<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,77 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||
|
<odoo> |
||||
|
<!-- Template for the payment --> |
||||
|
<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 class="mb24">Choose a |
||||
|
delivery method |
||||
|
</h3> |
||||
|
<div |
||||
|
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.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="payment_methods_sudo or tokens_sudo" |
||||
|
id="payment_method" |
||||
|
class="mt-4"> |
||||
|
<t t-call="payment.form"/> |
||||
|
</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,66 @@ |
|||||
|
<?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="//t[@t-call='website_sale.checkout_layout']" position="replace"> |
||||
|
<t t-call="website_sale.checkout_layout"> |
||||
|
<div class="single_pg_checkout_layout"> |
||||
|
<div class='col-auto'> |
||||
|
<!-- 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> |
||||
|
</div> |
||||
|
|
||||
|
<div class='col-12'> |
||||
|
<div class="col-12"> |
||||
|
<!-- 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"/> |
||||
|
<!-- This calls the cart_summary and extra_info templates for the left column. --> |
||||
|
<div class="row"> |
||||
|
<t t-call="one_page_checkout.extra_info"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="row"> |
||||
|
<!-- This calls the address column template for the middle column. --> |
||||
|
<div class="col-12"> |
||||
|
<t t-call="one_page_checkout.address_column"/> |
||||
|
</div> |
||||
|
</div> |
||||
|
</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> |
||||
|
</div> |
||||
|
</div> |
||||
|
</t> |
||||
|
</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_checkout" |
||||
|
inherit_id="website_sale.checkout"> |
||||
|
<!-- This XPath expression finds the "redirect_url" element and |
||||
|
replaces it with a new value. --> |
||||
|
<xpath expr="//t[@t-set='redirect']" position="replace"> |
||||
|
<!-- This sets the "redirect_url" variable to the new URL for |
||||
|
the one-page checkout. --> |
||||
|
<t t-set="redirect" t-value="'/shop/checkout?express=1'"/> |
||||
|
</xpath> |
||||
|
</template> |
||||
|
</odoo> |