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