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