Browse Source

May 16: [ADD] Initital Commit 'website_product_reservation'

pull/317/head
RisvanaCybro 12 months ago
parent
commit
a3f5e9b3fb
  1. 48
      website_product_reservation/README.rst
  2. 23
      website_product_reservation/__init__.py
  3. 51
      website_product_reservation/__manifest__.py
  4. 23
      website_product_reservation/controllers/__init__.py
  5. 97
      website_product_reservation/controllers/portal.py
  6. 114
      website_product_reservation/controllers/website_product_reservation.py
  7. 10
      website_product_reservation/data/website_menu.xml
  8. 6
      website_product_reservation/doc/RELEASE_NOTES.md
  9. 24
      website_product_reservation/models/__init__.py
  10. 29
      website_product_reservation/models/product_template.py
  11. 83
      website_product_reservation/models/sale_order.py
  12. 155
      website_product_reservation/models/sale_order_line.py
  13. BIN
      website_product_reservation/static/description/assets/icons/check.png
  14. BIN
      website_product_reservation/static/description/assets/icons/chevron.png
  15. BIN
      website_product_reservation/static/description/assets/icons/cogs.png
  16. BIN
      website_product_reservation/static/description/assets/icons/consultation.png
  17. BIN
      website_product_reservation/static/description/assets/icons/ecom-black.png
  18. BIN
      website_product_reservation/static/description/assets/icons/education-black.png
  19. BIN
      website_product_reservation/static/description/assets/icons/hotel-black.png
  20. BIN
      website_product_reservation/static/description/assets/icons/license.png
  21. BIN
      website_product_reservation/static/description/assets/icons/lifebuoy.png
  22. BIN
      website_product_reservation/static/description/assets/icons/manufacturing-black.png
  23. BIN
      website_product_reservation/static/description/assets/icons/pos-black.png
  24. BIN
      website_product_reservation/static/description/assets/icons/puzzle.png
  25. BIN
      website_product_reservation/static/description/assets/icons/restaurant-black.png
  26. BIN
      website_product_reservation/static/description/assets/icons/service-black.png
  27. BIN
      website_product_reservation/static/description/assets/icons/trading-black.png
  28. BIN
      website_product_reservation/static/description/assets/icons/training.png
  29. BIN
      website_product_reservation/static/description/assets/icons/update.png
  30. BIN
      website_product_reservation/static/description/assets/icons/user.png
  31. BIN
      website_product_reservation/static/description/assets/icons/wrench.png
  32. BIN
      website_product_reservation/static/description/assets/misc/categories.png
  33. BIN
      website_product_reservation/static/description/assets/misc/check-box.png
  34. BIN
      website_product_reservation/static/description/assets/misc/compass.png
  35. BIN
      website_product_reservation/static/description/assets/misc/corporate.png
  36. BIN
      website_product_reservation/static/description/assets/misc/customer-support.png
  37. BIN
      website_product_reservation/static/description/assets/misc/cybrosys-logo.png
  38. BIN
      website_product_reservation/static/description/assets/misc/features.png
  39. BIN
      website_product_reservation/static/description/assets/misc/logo.png
  40. BIN
      website_product_reservation/static/description/assets/misc/pictures.png
  41. BIN
      website_product_reservation/static/description/assets/misc/pie-chart.png
  42. BIN
      website_product_reservation/static/description/assets/misc/right-arrow.png
  43. BIN
      website_product_reservation/static/description/assets/misc/star.png
  44. BIN
      website_product_reservation/static/description/assets/misc/support.png
  45. BIN
      website_product_reservation/static/description/assets/misc/whatsapp.png
  46. BIN
      website_product_reservation/static/description/assets/modules/1.jpg
  47. BIN
      website_product_reservation/static/description/assets/modules/2.jpg
  48. BIN
      website_product_reservation/static/description/assets/modules/3.jpg
  49. BIN
      website_product_reservation/static/description/assets/modules/4.jpg
  50. BIN
      website_product_reservation/static/description/assets/modules/5.jpg
  51. BIN
      website_product_reservation/static/description/assets/modules/6.jpg
  52. BIN
      website_product_reservation/static/description/assets/screenshots/1.png
  53. BIN
      website_product_reservation/static/description/assets/screenshots/2.png
  54. BIN
      website_product_reservation/static/description/assets/screenshots/3.png
  55. BIN
      website_product_reservation/static/description/assets/screenshots/4.png
  56. BIN
      website_product_reservation/static/description/assets/screenshots/5.png
  57. BIN
      website_product_reservation/static/description/assets/screenshots/6.png
  58. BIN
      website_product_reservation/static/description/assets/screenshots/hero.gif
  59. BIN
      website_product_reservation/static/description/banner.jpg
  60. BIN
      website_product_reservation/static/description/icon.png
  61. 737
      website_product_reservation/static/description/index.html
  62. 9
      website_product_reservation/static/src/img/bag.svg
  63. 230
      website_product_reservation/views/portal_templates.xml
  64. 19
      website_product_reservation/views/product_template_views.xml
  65. 31
      website_product_reservation/views/res_cofig_settings_views.xml
  66. 37
      website_product_reservation/views/sale_order_views.xml
  67. 175
      website_product_reservation/views/website_templates.xml

48
website_product_reservation/README.rst

@ -0,0 +1,48 @@
.. 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
Website Product Reservation
===========================
This module helps you to reserve products from the website.
Configuration
=============
* No additional configurations needed
Company
-------
* `Cybrosys Techno Solutions <https://cybrosys.com/>`__
License
-------
Gnu Affero General Public License, Version 3 (AGPL v3).
(https://www.gnu.org/licenses/agpl-3.0-standalone.html)
Credits
-------
* Developers : (V16) Muhsina V,
(V17) Fathima Mazlin AM,
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>`__

23
website_product_reservation/__init__.py

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Fathima Mazlin AM (odoo@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 <http://www.gnu.org/licenses/>.
#
#############################################################################
from . import controllers
from . import models

51
website_product_reservation/__manifest__.py

@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Fathima Mazlin AM (odoo@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 <http://www.gnu.org/licenses/>.
#
#############################################################################
{
'name': 'Website Product Reservation',
'version': '17.0.1.0.0',
'category': 'Website',
'summary': 'Enable product reservation functionality on your website',
'description': "This module extends the website functionality by enabling "
"product reservation. Allow your customers to reserve "
"products directly from your website, and manage these "
"reservations seamlessly within the Odoo environment. "
"Enhance the shopping experience by providing a reservation"
" feature for in-demand products.",
'author': 'Cybrosys Techno Solutions',
'company': 'Cybrosys Techno Solutions',
'maintainer': 'Cybrosys Techno Solutions',
'website': 'https://www.cybrosys.com',
'depends': ['website_sale', 'stock'],
'data': [
'data/website_menu.xml',
'views/product_template_views.xml',
'views/res_cofig_settings_views.xml',
'views/sale_order_views.xml',
'views/website_templates.xml',
'views/portal_templates.xml',
],
'images': ['static/description/banner.png'],
'license': 'AGPL-3',
'installable': True,
'auto_install': False,
'application': False,
}

23
website_product_reservation/controllers/__init__.py

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Fathima Mazlin AM (odoo@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 <http://www.gnu.org/licenses/>.
#
#############################################################################
from . import portal
from . import website_product_reservation

97
website_product_reservation/controllers/portal.py

@ -0,0 +1,97 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Fathima Mazlin AM (odoo@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 <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import http
from odoo.http import request
from odoo.addons.portal.controllers import portal
class ReservationCustomerPortal(portal.CustomerPortal):
def _get_reservation_domain(self):
"""It returns the login person"""
return [('partner_id', '=', request.env.user.partner_id.id)]
@http.route('/my/reservation/requests',
type='http', auth='user', website=True)
def portal_my_reservation_orders(self):
"""List out the reservation Order"""
domain = self._get_reservation_domain()
domain.append(('is_reservation_order', '=', 'True'))
values = {
'reservation_request': request.env['sale.order'].sudo().search(
domain),
}
return request.render(
"website_product_reservation.portal_my_reservation_requests_tree",
values)
@http.route(['/my/reservation/requests/form/<int:reservation_id>'],
type='http',
auth="user", website=True)
def get_my_reservation_request_form(self, reservation_id):
"""Form view of reservation from website"""
return request.render(
"website_product_reservation.portal_my_reservation_requests_form",
{'record_reservation_requests': request.env[
'sale.order'].sudo().browse(reservation_id)})
@http.route(['/my/reservation/requests/form/id=<int:reservation_id>'],
type='http',
auth="user", website=True)
def get_my_reservation_request_form_cancel(self, reservation_id):
""" Cancel the reservation from website"""
cancel = request.env[
'sale.order'].sudo().browse(reservation_id)
cancel.action_cancel_reservation()
return request.render(
"website_product_reservation.portal_my_reservation_requests_form",
{'record_reservation_requests': request.env[
'sale.order'].sudo().browse(reservation_id)})
@http.route(['/my/reservation/requests/form/confirm=<int:reservation_id>'],
type='http',
auth="user", website=True)
def get_my_reservation_request_form_confirm(self, reservation_id):
"""Confirm the reservation from website"""
confirm = request.env[
'sale.order'].sudo().browse(reservation_id)
confirm.action_make_draft()
confirm.action_confirm()
return request.render(
"website_product_reservation.portal_my_reservation_requests_form",
{'record_reservation_requests': request.env[
'sale.order'].sudo().browse(reservation_id)})
class Return(portal.CustomerPortal):
"""This will take the count of total courier requests"""
def _prepare_home_portal_values(self, counters):
"""This will return the certificates count"""
values = super(Return, self)._prepare_home_portal_values(counters)
values.update({
'reservation_count': request.env[
'sale.order'].sudo().search_count(
[('partner_id', '=', request.env.user.partner_id.id),
('is_reservation_order', '=', 'True')])
})
return values

114
website_product_reservation/controllers/website_product_reservation.py

@ -0,0 +1,114 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Fathima Mazlin AM (odoo@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 <http://www.gnu.org/licenses/>.
#
#############################################################################
import json
from odoo import http
from odoo.http import request
from odoo.addons.website_sale.controllers.main import WebsiteSale
class WebsiteSaleReservation(WebsiteSale):
"""Custom controller for handling reservation-related functionality on
the website."""
@http.route(
["/reservation", "/reservation/page/<int:page>"],
type="http",
auth="public",
website=True,
)
def reservation(self, page=1, **kw):
"""Display a page with products available for reservation.
:param page: Page number for pagination.
:param kw: Additional keyword arguments.
:return: HTTP response rendering the reservation page."""
domain = [("reserve_products", "=", True), ("website_published", "=", True)]
product_obj = request.env["product.template"]
product_count = product_obj.search_count(domain)
pager = request.website.pager(
url="/reservation", total=product_count, page=page, step=12
)
products = product_obj.search(domain, limit=12, offset=pager["offset"])
values = {
"products": products,
"page_name": "Reserve Products",
"pager": pager,
"default_url": "/reservation",
}
self.clear_cart()
return request.render("website_product_reservation.reservation_page", values)
@http.route(
["/reservation/reserve"],
type="http",
auth="public",
methods=["POST"],
website=True,
csrf=False,
)
def reservation_update(self, product_id, add_qty=1, set_qty=0, **kw):
"""Update the reservation order based on user input.
:param product_id: ID of the product being reserved.
:param add_qty: Quantity to add to the reservation.
:param set_qty: Quantity to set for the reservation.
:param kw: Additional keyword arguments.
:return: HTTP response redirecting to the shopping cart."""
product_custom_attribute_values = None
if kw.get("product_custom_attribute_values"):
product_custom_attribute_values = json.loads(
kw.get("product_custom_attribute_values")
)
request.website.sale_get_order(force_create=1)._cart_update(
product_id=int(product_id),
add_qty=float(add_qty),
set_qty=float(set_qty),
product_custom_attribute_values=product_custom_attribute_values,
)
if kw.get("type_name") == "Reservation":
request.website.sale_get_order().is_reservation_order = True
return request.redirect("/shop/cart")
@http.route(
["/reservation/confirm_reserve_order"], type="http", auth="public", website=True
)
def confirm_reserve_order(self, **post):
"""Confirm and finalize the reservation order.
:param post: POST data from the request.
:return: HTTP response rendering the confirmation or error page."""
order = request.website.sale_get_order()
is_reservation = all(
order.website_order_line.mapped("product_id").mapped("reserve_products")
)
if is_reservation:
order.state = "reserve"
request.website.sale_reset()
for line in order.order_line.filtered(
lambda line: line.product_id.type == "product"
):
line.sudo().create_reservation_stock()
self.clear_cart()
return request.render(
"website_product_reservation.reservation_thankyou", {"order": order}
)
else:
return request.render(
"website_product_reservation.not_allowed_to_reserve_page", {}
)

10
website_product_reservation/data/website_menu.xml

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Define a menu item for the "Reservation" section on the website -->
<record id="menu_reservation" model="website.menu">
<field name="name">Reservation</field>
<field name="url">/reservation</field>
<field name="parent_id" ref="website.main_menu"/>
<field name="sequence">55</field>
</record>
</odoo>

6
website_product_reservation/doc/RELEASE_NOTES.md

@ -0,0 +1,6 @@
## Module <website_product_reservation>
#### 25.04.2024
#### Version 17.0.1.0.0
##### ADD
- Initial Commit for Website Product Reservation

24
website_product_reservation/models/__init__.py

@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Fathima Mazlin AM (odoo@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 <http://www.gnu.org/licenses/>.
#
#############################################################################
from . import product_template
from . import sale_order
from . import sale_order_line

29
website_product_reservation/models/product_template.py

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Fathima Mazlin AM(odoo@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 <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import fields, models
class ProductTemplate(models.Model):
_inherit = "product.template"
reserve_products = fields.Boolean(string='Reserve Products',
help="enable to reserve this product")

83
website_product_reservation/models/sale_order.py

@ -0,0 +1,83 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Fathima Mazlin AM (odoo@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 <http://www.gnu.org/licenses/>.
#
#############################################################################
from odoo import fields, models
class SaleOrder(models.Model):
""" This class extends the 'sale.order' model in Odoo.
It adds a new state ('reserve') and introduces a boolean field
('is_reservation_order') to identify reservation orders.
Methods:
- action_make_draft: Sets the order state to 'draft' and cancels
reservation stock for product lines.
- action_cancel_reservation: Cancels reservation stock for product
lines and sets the order state to 'cancel'."""
_inherit = 'sale.order'
state = fields.Selection(selection_add=[('reserve', 'Reserve')],
string='Order State',
help='The state of the sale order')
is_reservation_order = fields.Boolean(string='Reservation Order',
help='Check if the order is a '
'reservation order')
def action_make_draft(self):
""" Action method to set the order state to 'draft' and cancel
reservation stock for product lines."""
self.state = 'draft'
for line in self.order_line.filtered(
lambda line: line.product_id.type == 'product'):
line.cancel_reservation_stock(line.picking_id)
def action_cancel_reservation(self):
""" Action method to cancel reservation stock for product lines and set
the order state to 'cancel'."""
for line in self.order_line.filtered(
lambda line: line.product_id.type == 'product'):
line.cancel_reservation_stock(line.picking_id)
self.state = 'cancel'
class Company(models.Model):
""" This class extends the 'res.company' model in Odoo.
It adds a new field ('destination_location_id') to store the destination
location."""
_inherit = 'res.company'
destination_location_id = fields.Many2one(
'stock.location',
string='Destination Location',
help='The destination location for products.')
class AccountConfig(models.TransientModel):
""" This class extends the 'res.config.settings' model in Odoo.
It adds a related field ('destination_location_id') to configure the
destination location."""
_inherit = "res.config.settings"
destination_location_id = fields.Many2one(
'stock.location',
string='Destination Location',
related='company_id.destination_location_id',
readonly=False,
help='The destination location for products.')

155
website_product_reservation/models/sale_order_line.py

@ -0,0 +1,155 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>)
# Author: Fathima Mazlin AM (odoo@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 <http://www.gnu.org/licenses/>.
#
#############################################################################
from datetime import datetime
from odoo import fields, models
from odoo.tools import float_round
class SaleOrderLine(models.Model):
""" This class extends the 'sale.order.line' model in Odoo.
It adds functionality related to reservation stock for sale order lines."""
_inherit = 'sale.order.line'
picking_id = fields.Many2one('stock.picking', string='Picking',
help='The associated picking for the order '
'line')
def create_reservation_stock(self):
""" Create reservation stock for the product line."""
picking_obj = self.env['stock.picking']
destination_location_id = self.env.user.company_id.destination_location_id
if not destination_location_id:
destination_location_id = self.env['stock.location'].search(
[('usage', '=', 'internal'),
('company_id', '=', self.env.user.company_id.id)], limit=1)
warehouse_id = self.order_id.warehouse_id
location_id = warehouse_id.lot_stock_id
if self._context.get('product_id'):
product_id = self._context.get('product_id')
product_uom = product_id.uom_id
else:
product_id = self.product_id
product_uom = self.product_uom
if self._context.get('new_qty'):
product_uom_qty = self._context.get('new_qty')
else:
product_uom_qty = self.product_uom_qty
move_lines = []
move_lines.append((0, 0, {
'name': product_id.name,
'product_id': product_id.id,
'product_uom_qty': product_uom_qty,
'quantity': product_uom_qty,
'product_uom': product_uom.id,
'location_id': location_id and location_id.id,
'location_dest_id': destination_location_id and destination_location_id.id,
}))
values = {
'partner_id': self.order_id.partner_id.id,
'location_id': location_id and location_id.id,
'location_dest_id': destination_location_id and destination_location_id.id,
'scheduled_date': datetime.now(),
'date_done': datetime.now(),
'origin': self.order_id.name,
'owner_id': self.order_id.partner_id.id,
'picking_type_id': self.env.ref('stock.picking_type_out').id,
'move_ids_without_package': move_lines,
}
picking = picking_obj.sudo().create(values)
picking.sudo().action_confirm()
picking.sudo().action_assign()
picking.sudo().button_validate()
sms = self.env['confirm.stock.sms'].sudo().search([])
for rec in sms:
for pick in rec.pick_ids:
if pick.id == picking.id:
rec.send_sms()
picking.sudo().button_validate()
self.write({
'picking_id': picking.id
})
def cancel_reservation_stock(self, picking_ids):
""" Cancel reservation stock for the given picking IDs."""
product_return_moves = []
for picking in picking_ids:
if picking.products_availability_state == "late":
return picking.action_cancel()
else:
for move in picking.move_ids:
if move.move_dest_ids:
quantity = move.product_qty - sum(
move.sudo().filtered(
lambda m: m.state in [
'partially_available', 'assigned',
'done']).mapped('move_line_ids').mapped(
'qty_done'))
else:
quantity = move.product_qty
quantity = float_round(quantity,
precision_rounding=move.product_uom.rounding)
product_return_moves.append((0, 0, {
'product_id': move.product_id.id,
'quantity': quantity,
'move_id': move.id,
'uom_id': move.product_id.uom_id.id,
'to_refund': True,
}))
location_id = picking.location_id.id
if picking.picking_type_id.return_picking_type_id\
.default_location_dest_id.return_location:
location_id = picking.picking_type_id\
.return_picking_type_id.default_location_dest_id.id
stock_return = self.env['stock.return.picking'].sudo().create({
'product_return_moves': product_return_moves,
'picking_id': picking.id,
'original_location_id': picking.location_id.id,
'parent_location_id': picking.picking_type_id.warehouse_id and picking.picking_type_id.warehouse_id.view_location_id.id or picking.location_id.location_id.id,
'location_id': location_id
})
if stock_return:
new_picking_id, pick_type_id = stock_return.sudo()._create_returns()
new_picking = self.env['stock.picking'].sudo().browse(
new_picking_id)
if new_picking.mapped('move_line_ids').filtered(
lambda move: move.state in ['confirmed',
'waiting']):
new_picking.sudo().action_confirm()
new_picking.sudo().action_assign()
# new_picking.sudo().action_set_quantities_to_reservation()
new_picking.sudo().button_validate()
else:
new_picking.sudo().action_confirm()
new_picking.sudo().action_assign()
# new_picking.sudo().action_set_quantities_to_reservation()
new_picking.sudo().button_validate()
def unlink(self):
""" Override unlink method to cancel reservation stock when deleting
product lines in draft reservation orders."""
for line in self:
order_id = line.order_id
if order_id.state == 'draft' and order_id.type_name == 'Reservation':
if line.picking_id:
line.sudo().cancel_reservation_stock(line.picking_id)
return super(SaleOrderLine, self).unlink()

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 967 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
website_product_reservation/static/description/assets/modules/1.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

BIN
website_product_reservation/static/description/assets/modules/2.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

BIN
website_product_reservation/static/description/assets/modules/3.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

BIN
website_product_reservation/static/description/assets/modules/4.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

BIN
website_product_reservation/static/description/assets/modules/5.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

BIN
website_product_reservation/static/description/assets/modules/6.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
website_product_reservation/static/description/assets/screenshots/1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

BIN
website_product_reservation/static/description/assets/screenshots/2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

BIN
website_product_reservation/static/description/assets/screenshots/3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

BIN
website_product_reservation/static/description/assets/screenshots/4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
website_product_reservation/static/description/assets/screenshots/5.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
website_product_reservation/static/description/assets/screenshots/6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

BIN
website_product_reservation/static/description/banner.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

BIN
website_product_reservation/static/description/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

737
website_product_reservation/static/description/index.html

@ -0,0 +1,737 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Website Product Reservation</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous">
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap"
rel="stylesheet">
</head>
<body>
<section>
<div class="container"
style="font-family: 'Inter', sans-serif !important;background-color: #fff !important;">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12 d-flex justify-content-between flex-wrap align-items-sm-center"
style="border-bottom:1px solid rgba(0, 0, 0, 0.22)">
<div class="my-3">
<img src="assets/misc/logo.png"
style="width:auto !important; height:40px !important">
</div>
<div class="my-3 d-flex align-items-center">
<div class="text-center"
style="background-color:#017E84 !important;font-size: 0.8rem !important; color:#fff !important; font-weight:500 !important; padding:4px !important; margin:0 3px !important; border-radius:50px !important; min-width: 120px !important;">
Community
</div>
<div class="text-center"
style="background-color:#875A7B !important; color:#fff !important;font-size: 0.8rem !important; font-weight:500 !important; padding:4px !important; margin:0 3px !important; border-radius:50px !important;min-width: 120px !important;">
Enterprise
</div>
<div class="text-center"
style="background-color:#7C7BAD !important; color:#fff !important;font-size: 0.8rem !important; font-weight:500 !important; padding:4px !important; margin:0 3px !important; border-radius:50px !important; min-width: 120px !important;">
Odoo.sh
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12 text-center d-flex align-items-center flex-column"
style="margin: 80px 0px !important;">
<h1 style="font-size: 2.8rem;font-weight: 700; color:
#1A202C;">
Website Product Reservation</h1>
<p class="my-3 mb-4"
style="max-width: 80%; font-weight: 400 !important; line-height: 32px; color: #718096;">
Reserve The Products From the Website
</p>
<div style="width: 80%; margin-top: 3rem;">
<img src="assets/screenshots/hero.gif"
class="img-responsive" width="100%" height="auto">
</div>
</div>
</div>
<div class="container mt-5 mb-5">
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center mt-4">
<p class="m-0"
style="font-weight: 600; font-size: 24px; color:#714b67 !important">
Key Highlights
</p>
</div>
<div class="row py-4">
<div class="col-md-6 col-sm-12 p-3">
<div class="d-flex h-100" style="padding: 30px;border-radius: 12px;
background: #FFF;
box-shadow: 1px 2px 3px 0px rgba(0, 0, 0, 0.25); ">
<div style="width: 36px; height: 36px; border-radius: 50%; background: #714B67;
display: flex; justify-content: center; align-items: center;
margin-right: 10px; flex-shrink: 0;">
<i class="fa-solid fa-star "
style="color: #fff;font-size:14px;"></i>
</div>
<div>
<p style="color: #1A202C;font-weight: 600;
font-size: 1.2rem; margin-bottom: 2px;">
Users can reserve the product directly from the website.
</p>
</div>
</div>
</div>
<div class="col-md-6 col-sm-12 p-3">
<div class="d-flex h-100" style="padding: 30px;border-radius: 12px;
background: #FFF;
box-shadow: 1px 2px 3px 0px rgba(0, 0, 0, 0.25); ">
<div style="width: 36px; height: 36px; border-radius: 50%; background: #714B67;
display: flex; justify-content: center; align-items: center;
margin-right: 10px; flex-shrink: 0;">
<i class="fa-solid fa-star "
style="color: #fff;font-size:14px;"></i>
</div>
<div>
<p style="color: #1A202C;font-weight: 600;
font-size: 1.2rem; margin-bottom: 2px;">
A corresponding reservation order is created.</p>
</div>
</div>
</div><div class="col-md-6 col-sm-12 p-3">
<div class="d-flex h-100" style="padding: 30px;border-radius: 12px;
background: #FFF;
box-shadow: 1px 2px 3px 0px rgba(0, 0, 0, 0.25); ">
<div style="width: 36px; height: 36px; border-radius: 50%; background: #714B67;
display: flex; justify-content: center; align-items: center;
margin-right: 10px; flex-shrink: 0;">
<i class="fa-solid fa-star "
style="color: #fff;font-size:14px;"></i>
</div>
<div>
<p style="color: #1A202C;font-weight: 600;
font-size: 1.2rem; margin-bottom: 2px;">
By enabling the 'Reserve Products' checkbox
inside the product, the item can be reserved.</p>
</div>
</div>
</div>
</div>
</div>
<div class="container rounded">
<ul class="nav nav-tabs d-flex"
style="width: fit-content;margin: 0 auto;gap: 1rem;">
<li class="col text-center py-2 text-nowrap "
style="color: #fff; background-color: #714B67;border-radius: 6px 6px 0px 0px;">
<a
class="active show" data-toggle="tab" href="#tab1"
style="color: #fff;font-weight: 500; background-color: #714B67; text-decoration: none;">
<i class="fa-regular fa-image pr-2"
style="color: #fff;"></i>
Screenshots</a></li>
<li class="col text-center py-2 text-nowrap "
style="color: #fff; background-color: #714B67;border-radius: 6px 6px 0px 0px;">
<a
data-toggle="tab" href="#tab2"
style="color: #fff;font-weight: 500; text-decoration: none;"><i
class="fa-solid fa-star pr-2"
style="color: #fff;"></i>Features</a></li>
<li class="col text-center py-2 text-nowrap "
style="color: #fff; background-color: #714B67;border-radius: 6px 6px 0px 0px;">
<a
data-toggle="tab" href="#tab3"
style="color: #fff;font-weight: 500; text-decoration: none; background-color: #714B67;"><i
class="fa-solid fa-book-open pr-2"
style="color: #fff;"></i>Released Notes</a></li>
</ul>
<div class="tab-content"
style="background-color: rgba(121, 113, 119, 0.04);">
<div id="tab1" class="tab-pane fade in active show">
<div class="col-lg-12 py-2"
style="padding: 1rem 4rem !important;">
<div
style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
<div class="row justify-content-center p-3 w-100 m-0">
<img src="assets/screenshots/1.png"
class="img-responsive" width="100%"
height="auto">
</div>
<div class="px-3">
<h4 class="mt-2"
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
Enable Reserve Products.
</h4>
</div>
</div>
</div>
<div class="col-lg-12 py-2"
style="padding: 1rem 4rem !important;">
<div
style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
<div class="row justify-content-center p-3 w-100 m-0">
<img src="assets/screenshots/2.png"
class="img-responsive" width="100%"
height="auto">
</div>
<div class="px-3">
<h4 class="mt-2"
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
Reserve Products</h4>
</div>
</div>
</div>
<div class="col-lg-12 py-2"
style="padding: 1rem 4rem !important;">
<div
style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
<div class="row justify-content-center p-3 w-100 m-0">
<img src="assets/screenshots/3.png"
class="img-responsive" width="100%"
height="auto">
</div>
<div class="px-3">
<h4 class="mt-2"
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
Create Reservation Order.</h4>
</div>
</div>
</div>
<div class="col-lg-12 py-2"
style="padding: 1rem 4rem !important;">
<div
style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
<div class="row justify-content-center p-3 w-100 m-0">
<img src="assets/screenshots/4.png"
class="img-responsive" width="100%"
height="auto">
</div>
<div class="px-3">
<h4 class="mt-2"
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
Here, the order is created.</h4>
</div>
</div>
</div>
<div class="col-lg-12 py-2"
style="padding: 1rem 4rem !important;">
<div
style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
<div class="row justify-content-center p-3 w-100 m-0">
<img src="assets/screenshots/5.png"
class="img-responsive" width="100%"
height="auto">
</div>
<div class="px-3">
<h4 class="mt-2"
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
You can view these reservation orders
under the 'eCommerce' menu on the website.</h4>
</div>
</div>
</div>
<div class="col-lg-12 py-2"
style="padding: 1rem 4rem !important;">
<div
style="border: 1px solid #d8d6d6; border-radius: 4px; background: #fff; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
<div class="row justify-content-center p-3 w-100 m-0">
<img src="assets/screenshots/6.png"
class="img-responsive" width="100%"
height="auto">
</div>
<div class="px-3">
<h4 class="mt-2"
style=" font-weight:600 !important; color:#282F33 !important; font-size:1.3rem !important">
The created order is in the 'Reserve' state. You can either
cancel it or generate a quotation from the reservation order.</h4>
</div>
</div>
</div>
</div>
<div id="tab2" class="tab-pane fade">
<div class="col-mg-12" style="padding: 1rem 4rem;">
<ul style="list-style: none; padding: 1rem 0;font-weight: 500;">
<li class="py-3"
style="font-weight: 500;background-color: #fff; border-radius: 4px; padding: 1rem; margin-bottom: 1rem; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
<span style="margin-right: 12px;"><img
src="assets/misc/star (1) 2.svg"
alt=""
width="16px"></span>Users can reserve the product directly from the website.
</li><li class="py-3"
style="font-weight: 500;background-color: #fff; border-radius: 4px; padding: 1rem; margin-bottom: 1rem; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
<span style="margin-right: 12px;"><img
src="assets/misc/star (1) 2.svg"
alt=""
width="16px"></span>A corresponding reservation order is created.
</li><li class="py-3"
style="font-weight: 500;background-color: #fff; border-radius: 4px; padding: 1rem; margin-bottom: 1rem; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
<span style="margin-right: 12px;"><img
src="assets/misc/star (1) 2.svg"
alt=""
width="16px"></span>By enabling the 'Reserve Products' checkbox
inside the product, the item can be reserved.
</li>
</ul>
</div>
</div>
<div id="tab3" class="tab-pane fade">
<div class="col-mg-12 active" style="padding: 1rem 4rem;">
<div class="py-3"
style="font-weight: 500;background-color: #fff; border-radius: 4px; padding: 1rem; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">
<div class="d-flex mb-3"
style="font-size: 0.8rem; font-weight: 500;"><span>Version
17.0.1.0.0</span><span
class="px-2">|</span><span
style="color: #714B67;font-weight: 600;">Released on:25 March 2024</span>
</div>
<p class="m-0"
style=" color:#718096!important; font-size:1rem !important;line-height: 28px;">
Initial commit for Textile Management</p>
</div>
</div>
</div>
</div>
</div>
<div class="container mt-5">
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center mt-5">
<p class="m-0"
style="font-weight: 600; font-size: 24px; color:#000 !important">
Related Products</p>
</div>
</div>
<div id="myCarousel" class="carousel slide py-3" data-ride="carousel">
<div class="carousel-inner">
<div class="carousel-item active">
<div class="row p-4">
<div class="col">
<div class="p-3">
<a href="https://apps.odoo.com/apps/modules/17.0/website_product_publish/"
style="color: #000; text-decoration: none;">
<div style="border:1px solid #CBCBCB !important;border-radius: 4px;">
<div style="width: 300px; ">
<img src="assets/modules/1.jpg"
alt="" width="100%"
height="auto">
</div>
<p class="text-center pt-2 text-black font-weight-bold">
Quick Product Publish/Unpublish</p>
</div>
</a>
</div>
</div>
<div class="col">
<div class="p-3">
<a href="https://apps.odoo.com/apps/modules/17.0/odoo_icecat_connector/"
style="color: #000; text-decoration: none;">
<div style="border:1px solid #CBCBCB !important;border-radius: 4px;">
<div style="width: 300px; ">
<img src="assets/modules/2.jpg"
alt="" width="100%"
height="auto">
</div>
<p class="text-center pt-2 text-black font-weight-bold">
Odoo Icecat Connector</p>
</div>
</a>
</div>
</div>
<div class="col">
<div class="p-3">
<a href="https://apps.odoo.com/apps/modules/17.0/shopping_through_agent/"
style="color: #000; text-decoration: none;">
<div style="border:1px solid #CBCBCB !important;border-radius: 4px;">
<div style="width: 300px; ">
<img src="assets/modules/3.jpg"
alt="" width="100%"
height="auto">
</div>
<p class="text-center pt-2 text-black font-weight-bold">
Shopping Through Agent</p>
</div>
</a>
</div>
</div>
</div>
</div>
<div class="carousel-item">
<div class="row p-4">
<div class="col">
<div class="p-3">
<a href="https://apps.odoo.com/apps/modules/17.0/website_upload_files/"
style="color: #000; text-decoration: none;">
<div style="border:1px solid #CBCBCB !important;border-radius: 4px;">
<div style="width: 300px; ">
<img src="assets/modules/4.jpg"
alt="" width="100%"
height="auto">
</div>
<p class="text-center pt-2 text-black font-weight-bold">
Multiple Attachments In eCommerce Order</p>
</div>
</a>
</div>
</div>
<div class="col">
<div class="p-3">
<a href="https://apps.odoo.com/apps/modules/17.0/website_multi_variant/"
style="color: #000; text-decoration: none;">
<div style="border:1px solid #CBCBCB !important;border-radius: 4px;">
<div style="width: 300px;">
<img src="assets/modules/5.jpg"
alt="" width="100%"
height="auto">
</div>
<p class="text-center pt-2 text-black font-weight-bold">
Website Multi Variant Add to Cart</p>
</div>
</a>
</div>
</div>
<div class="col">
<div class="p-3">
<a href="https://apps.odoo.com/apps/modules/17.0/website_pdf_preview_snippet/"
style="color: #000; text-decoration: none;">
<div style="border:1px solid #CBCBCB !important;border-radius: 4px;">
<div style="width: 300px;">
<img src="assets/modules/6.jpg"
alt="" width="100%"
height="auto">
</div>
<p class="text-center pt-2 text-black font-weight-bold">
Website PDF Preview Snippet</p>
</div>
</a>
</div>
</div>
</div>
</div>
</div>
<a class="carousel-control-prev" href="#myCarousel"
data-slide="prev" style="width: 35px; color: #000;">
<span class="carousel-control-prev-icon">
<i class="fa fa-chevron-left"
style="font-size: 24px;"></i>
</span>
</a>
<a class="carousel-control-next" href="#myCarousel"
data-slide="next" style="width: 35px; color: #000;">
<span class="carousel-control-next-icon">
<i class="fa fa-chevron-right"
style="font-size: 24px;"></i>
</span>
</a>
</div>
<div class="container mt-5">
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center mt-4">
<p class="m-0"
style="font-weight: 600; font-size: 24px; color:#000 !important">
Our Services</p>
</div>
</div>
<div class="container my-5">
<div class="row py-3">
<div class="col-md-4 col-sm-6 px-4 py-4">
<div
style="background-color: #fff; padding: 25px; text-align: center; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px; position: relative;border-radius: 4px;">
<div style="position: absolute; top: 0%; left: 50%; transform: translate(-50%, -50%);">
<div style="background-color:#13EA36 ; border-radius: 50%; padding: 15px; width: 68px;
height: 68px; display: inline-block; box-shadow:0px 4px 4px rgba(0, 0, 0, 0.25);">
<img src="assets/icons/cogs.png"
alt="service-icon" width="38px"
height="auto">
</div>
</div>
<p style="margin-top: 20px; font-weight: bold;">Odoo
Customization</p>
</div>
</div>
<div class="col-md-4 col-sm-6 px-4 py-4">
<div
style="background-color: #fff; padding: 25px; text-align: center; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px; position: relative;border-radius: 4px;">
<div style="position: absolute; top: 0%; left: 50%; transform: translate(-50%, -50%);">
<div style="background-color:#DBC711; border-radius: 50%; padding: 15px; width: 68px;
height: 68px; display: inline-block; box-shadow:0px 4px 4px rgba(0, 0, 0, 0.25);">
<img src="assets/icons/wrench.png"
alt="service-icon" width="38px"
height="auto">
</div>
</div>
<p style="margin-top: 20px; font-weight: bold;">Odoo
Implementation</p>
</div>
</div>
<div class="col-md-4 col-sm-6 px-4 py-4">
<div
style="background-color: #fff; padding: 25px; text-align: center; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px; position: relative; border-radius: 4px;">
<div style="position: absolute; top: 0%; left: 50%; transform: translate(-50%, -50%);">
<div style="background-color:#FF6B6B ; border-radius: 50%; padding: 15px; width: 68px;
height: 68px; display: inline-block; box-shadow:0px 4px 4px rgba(0, 0, 0, 0.25);">
<img src="assets/icons/lifebuoy.png"
alt="service-icon" width="38px"
height="auto">
</div>
</div>
<p style="margin-top: 20px; font-weight: bold;">Odoo
Support</p>
</div>
</div>
<div class="col-md-4 col-sm-6 px-4 py-4">
<div
style="background-color: #fff; padding: 25px; text-align: center; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px; position: relative; border-radius: 4px;">
<div style="position: absolute; top: 0%; left: 50%; transform: translate(-50%, -50%);">
<div style="background-color:#FFA801 ; border-radius: 50%; padding: 15px; width: 68px;
height: 68px; display: inline-block; box-shadow:0px 4px 4px rgba(0, 0, 0, 0.25);">
<img src="assets/icons/user.png"
alt="service-icon" width="38px"
height="auto">
</div>
</div>
<p style="margin-top: 20px; font-weight: bold;">Hire
Odoo Developer</p>
</div>
</div>
<div class="col-md-4 col-sm-6 px-4 py-4">
<div
style="background-color: #fff; padding: 25px; text-align: center; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px; position: relative; border-radius: 4px;">
<div style="position: absolute; top: 0%; left: 50%; transform: translate(-50%, -50%);">
<div style="background-color:#54A0FF; border-radius: 50%; padding: 15px; width: 68px;
height: 68px; display: inline-block; box-shadow:0px 4px 4px rgba(0, 0, 0, 0.25);">
<img src="assets/icons/puzzle.png"
alt="service-icon" width="38px"
height="auto">
</div>
</div>
<p style="margin-top: 20px; font-weight: bold;">Odoo
Integration</p>
</div>
</div>
<div class="col-md-4 col-sm-6 px-4 py-4">
<div
style="background-color: #fff; padding: 25px; text-align: center; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px; position: relative;border-radius: 4px;">
<div style="position: absolute; top: 0%; left: 50%; transform: translate(-50%, -50%);">
<div style="background-color:#6D7680 ; border-radius: 50%; padding: 15px; width: 68px;
height: 68px; display: inline-block; box-shadow:0px 4px 4px rgba(0, 0, 0, 0.25);">
<img src="assets/icons/update.png"
alt="service-icon" width="38px"
height="auto">
</div>
</div>
<p style="margin-top: 20px; font-weight: bold;">Odoo
Migration</p>
</div>
</div>
<div class="col-md-4 col-sm-6 px-4 py-4">
<div
style="background-color: #fff; padding: 25px; text-align: center; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px; position: relative;border-radius: 4px;">
<div style="position: absolute; top: 0%; left: 50%; transform: translate(-50%, -50%);">
<div style="background-color:#786FA6 ; border-radius: 50%; padding: 15px; width: 68px;
height: 68px; display: inline-block; box-shadow:0px 4px 4px rgba(0, 0, 0, 0.25);">
<img src="assets/icons/consultation.png"
alt="service-icon" width="38px"
height="auto">
</div>
</div>
<p style="margin-top: 20px; font-weight: bold;">Odoo
Consultancy</p>
</div>
</div>
<div class="col-md-4 col-sm-6 px-4 py-4">
<div
style="background-color: #fff; padding: 25px; text-align: center; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px;position: relative;border-radius: 4px;">
<div style="position: absolute; top: 0%; left: 50%; transform: translate(-50%, -50%);">
<div style="background-color:#F8A5C2 ; border-radius: 50%; padding: 15px; width: 68px;
height: 68px; display: inline-block; box-shadow:0px 4px 4px rgba(0, 0, 0, 0.25);">
<img src="assets/icons/training.png"
alt="service-icon" width="38px"
height="auto">
</div>
</div>
<p style="margin-top: 20px; font-weight: bold;">Odoo
Implementation</p>
</div>
</div>
<div class="col-md-4 col-sm-6 px-4 py-4">
<div
style="background-color: #fff; padding: 25px; text-align: center; box-shadow: rgba(0, 0, 0, 0.1) 0px 1px 3px 0px, rgba(0, 0, 0, 0.06) 0px 1px 2px 0px; position: relative;border-radius: 4px;">
<div style="position: absolute; top: 0%; left: 50%; transform: translate(-50%, -50%);">
<div style="background-color:#E6BE26; border-radius: 50%; padding: 15px; width: 68px;
height: 68px; display: inline-block; box-shadow:0px 4px 4px rgba(0, 0, 0, 0.25);">
<img src="assets/icons/license.png"
alt="service-icon" width="38px"
height="auto">
</div>
</div>
<p style="margin-top: 20px; font-weight: bold;">Odoo
Licensing Consultancy</p>
</div>
</div>
</div>
</div>
<div class="container mt-5">
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center mt-4">
<p class="m-0"
style="font-weight: 600; font-size: 24px; color:#000 !important">
Our Industries</p>
</div>
</div>
<div class="container">
<div class="row my-5 py-4">
<div class="col-md-3 col-sm-6 p-0">
<div class="d-flex flex-column h-100 "
style="border-right: 1px solid rgb(209, 209, 209); border-bottom: 1px solid rgb(209, 209, 209); padding: 30px; box-shadow: 6px 0 10px rgba(228, 227, 227, 0.373);">
<img src="assets/icons/trading-black.png" width="42px"
height="auto" alt="">
<p style="color: #714B67;font-weight: 600; margin-top: 10px;
font-size: 1.2rem; margin-bottom: 2px;">Trading</p>
<p>Easily procure and sell your products</p>
</div>
</div>
<div class="col-md-3 col-sm-6 p-0">
<div class="d-flex flex-column h-100"
style="border-right: 1px solid rgb(209, 209, 209);border-bottom: 1px solid rgb(209, 209, 209); padding: 30px;">
<img src="assets/icons/pos-black.png" width="42px"
height="auto" alt="">
<p style="color: #714B67;font-weight: 600; margin-top: 10px;
font-size: 1.2rem; margin-bottom: 2px;">POS</p>
<p>Easy configuration and convivial experience</p>
</div>
</div>
<div class="col-md-3 col-sm-6 p-0">
<div class="d-flex flex-column h-100"
style="border-right: 1px solid rgb(209, 209, 209);border-bottom: 1px solid rgba(0, 0, 0, 0.2); padding: 30px; box-shadow: 0 5px 10px rgba(228, 227, 227, 0.373)">
<img src="assets/icons/education-black.png"
width="42px" height="auto" alt="">
<p style="color: #714B67;font-weight: 600; margin-top: 10px;
font-size: 1.2rem; margin-bottom: 2px;">
Education</p>
<p>A platform for educational management</p>
</div>
</div>
<div class="col-md-3 col-sm-6 p-0">
<div class="d-flex flex-column h-100"
style="border-bottom: 1px solid rgb(209, 209, 209); padding: 30px; ">
<img src="assets/icons/manufacturing-black.png"
width="42px" height="auto" alt="">
<p style="color: #714B67;font-weight: 600; margin-top: 10px;
font-size: 1.2rem; margin-bottom: 2px;">
Manufacturing</p>
<p>Plan, track and schedule your operations</p>
</div>
</div>
<div class="col-md-3 col-sm-6 p-0">
<div class="d-flex flex-column h-100"
style="border-right: 1px solid rgb(209, 209, 209); padding: 30px;">
<img src="assets/icons/ecom-black.png" width="42px"
height="auto" alt="">
<p style="color: #714B67;font-weight: 600; margin-top: 10px;
font-size: 1.2rem; margin-bottom: 2px;">E-commerce
& Website</p>
<p>Mobile friendly, awe-inspiring product pages</p>
</div>
</div>
<div class="col-md-3 col-sm-6 p-0">
<div class="d-flex flex-column h-100"
style="border-right: 1px solid rgb(209, 209, 209); padding: 30px;box-shadow: 0 -5px 10px rgba(228, 227, 227, 0.373);">
<img src="assets/icons/service-black.png" width="42px"
height="auto" alt="">
<p style="color: #714B67;font-weight: 600; margin-top: 10px;
font-size: 1.2rem; margin-bottom: 2px;">Service
Management</p>
<p>Keep track of services and invoice</p>
</div>
</div>
<div class="col-md-3 col-sm-6 p-0">
<div class="d-flex flex-column h-100"
style="border-right: 1px solid rgb(209, 209, 209); padding: 30px; ">
<img src="assets/icons/restaurant-black.png"
width="42px" height="auto" alt="">
<p style="color: #714B67;font-weight: 600; margin-top: 10px;
font-size: 1.2rem; margin-bottom: 2px;">
Restaurant</p>
<p>Run your bar or restaurant methodically</p>
</div>
</div>
<div class="col-md-3 col-sm-6 p-0">
<div class="d-flex flex-column h-100"
style=" padding: 30px;box-shadow: -5px 0 10px rgba(228, 227, 227, 0.373);">
<img src="assets/icons/hotel-black.png" width="42px"
height="auto" alt="">
<p style="color: #714B67;font-weight: 600; margin-top: 10px;
font-size: 1.2rem; margin-bottom: 2px;">Hotel
Management</p>
<p>An all-inclusive hotel management application</p>
</div>
</div>
</div>
</div>
<div class="container mt-5">
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center mt-5">
<p class="m-0"
style="font-weight: 600; font-size: 24px; color:#000 !important">
Support</p>
</div>
</div>
<div class="container my-5">
<div class="row" style="background-color: #FFFAFE;">
<div class="col-md-6 pb-4 d-flex align-items-center justify-content-center"
style="border-right: 1px solid #D9D9D9;">
<div style="padding: 30px;">
<div class="d-flex align-items-center">
<img src="assets/misc/support (1) 1.svg" alt=""
width="60px" style="margin-right: 12px;">
<div style="padding: 0px 8px;">
<span
style="color: #714B67;font-size: 24px;font-weight: 600;padding-bottom: 1rem;">Need
Help?</span>
<p class="m-0" style="color:#718096;">Got
questions or need help? Get in touch.</p>
<div style="font-weight: 400;"><span><img
src="assets/misc/support-email.svg"
alt=""
width="18px"
style="filter: invert(1);margin-right: 0.8rem;"></span>odoo@cybrosys.com
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6 pb-4 d-flex align-items-center justify-content-center">
<div style="padding: 30px;">
<div class="d-flex align-items-center">
<img src="assets/misc/whatsapp 1.svg" alt=""
width="60px" style="margin-right: 12px;">
<div>
<span style="color: #714B67;font-size: 24px;font-weight: 600;">WhatsApp</span>
<p class="m-0" style="color:#718096;">Say hi to
us on WhatsApp!</p>
<div style="font-weight: 400; font-size: 16px;"><span><img
src="assets/misc/phone.svg"
alt="" width="14px"
style="filter: invert(1); margin-right: 0.8rem;"></span>+91
99456767686
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</body>
</html>

9
website_product_reservation/static/src/img/bag.svg

@ -0,0 +1,9 @@
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M26.2233 2.70896C27.6214 1.90182 28.931 1.79727 29.9196 2.35586L29.921 2.35668C30.906 2.92274 31.4769 4.09983 31.4815 5.7074L31.4967 11.0667C31.4971 11.1929 31.395 11.2955 31.2688 11.2959C31.1425 11.2962 31.0399 11.1942 31.0396 11.068L31.0244 5.7087C31.0201 4.2002 30.4888 3.21066 29.694 2.75345C28.8949 2.30233 27.7656 2.34642 26.4519 3.10486C25.1387 3.86303 23.9468 5.16282 23.0753 6.67008C22.204 8.18154 21.6785 9.85639 21.6809 11.3659C21.6809 11.3659 21.6809 11.366 21.6809 11.3659L21.6961 16.725C21.6965 16.8513 21.5944 16.9539 21.4682 16.9543C21.3419 16.9546 21.2393 16.8526 21.239 16.7263L21.2238 11.3668C21.2211 9.75775 21.7785 8.00421 22.6794 6.44156L22.6796 6.44132C23.5805 4.88301 24.8244 3.51663 26.2233 2.70896Z" fill="#374874"/>
<path d="M37.7926 2.67932L42.0505 38.2168L11.6401 55.7743L15.6829 15.4444L37.7926 2.67932Z" fill="#C1DBF6"/>
<path d="M21.9496 61.7654L11.6401 55.7743L15.6829 15.4443H24.8303L25.9924 21.4355L21.9496 61.7654Z" fill="#FBDBD0"/>
<path d="M48.1021 32.7335L37.7926 26.7423V2.67932L39.2776 6.88008L48.1021 8.67052V32.7335Z" fill="#FBDBD0"/>
<path d="M48.1021 8.67053L52.36 44.208L21.9496 61.7655L25.9924 21.4356L48.1021 8.67053Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M36.9149 8.14731C38.3129 7.34017 39.6226 7.23562 40.6111 7.79422L40.6126 7.79503C41.5976 8.36109 42.1685 9.53818 42.173 11.1458L42.1882 16.505C42.1886 16.6313 42.0865 16.7339 41.9603 16.7342C41.8341 16.7346 41.7314 16.6326 41.7311 16.5063L41.7159 11.1471C41.7116 9.63855 41.1804 8.64901 40.3855 8.19181C39.5864 7.74068 38.4571 7.78477 37.1434 8.54321C35.8303 9.30138 34.6383 10.6012 33.7669 12.1084C32.8955 13.6199 32.37 15.2947 32.3724 16.8043C32.3724 16.8042 32.3724 16.8043 32.3724 16.8043L32.3876 22.1634C32.388 22.2896 32.2859 22.3923 32.1597 22.3926C32.0335 22.393 31.9309 22.2909 31.9305 22.1647L31.9153 16.8052C31.9127 15.1961 32.47 13.4426 33.3709 11.8799L33.3711 11.8797C34.272 10.3214 35.516 8.95498 36.9149 8.14731Z" fill="#374874"/>
<path d="M37.7926 2.6793L39.2776 6.88008L48.1021 8.67048L52.36 44.208L21.9496 61.7654L11.6401 55.7742L15.6829 15.4443L37.7926 2.6793ZM37.7927 1.76501C37.634 1.76501 37.4761 1.80632 37.3355 1.88751L15.2258 14.6525C14.971 14.7996 14.8025 15.0604 14.7732 15.3531L10.7304 55.683C10.6946 56.0398 10.8707 56.3846 11.1807 56.5647L21.4902 62.5559C21.6322 62.6384 21.7909 62.6797 21.9496 62.6797C22.1075 62.6797 22.2653 62.6388 22.4068 62.5572L52.8172 44.9998C53.134 44.8168 53.3113 44.4626 53.2678 44.0992L49.0099 8.56172C48.963 8.1702 48.6704 7.85285 48.2839 7.77445L39.967 6.08707L38.6546 2.37457C38.5641 2.11839 38.3642 1.91576 38.1093 1.82161C38.0068 1.78378 37.8995 1.76501 37.7927 1.76501Z" fill="#374874"/>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

230
website_product_reservation/views/portal_templates.xml

@ -0,0 +1,230 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="website_product_reservation" name="product_reservation"
inherit_id="portal.portal_my_home"
customize_show="True"
priority="32">
<xpath expr="//div[hasclass('o_portal_docs')]" position="inside">
<t t-call="portal.portal_docs_entry">
<t t-set="icon" t-value="'/website_product_reservation/static/src/img/bag.svg'"/>
<t t-set="title">Reservation</t>
<t t-set="url" t-value="'/my/reservation/requests'"/>
<t t-set="text">Check all the Reservation</t>
<t t-set="placeholder_count" t-value="'reservation_count'"/>
</t>
</xpath>
</template>
<template id="portal_my_reservation_requests_tree">
<t t-call="portal.portal_layout">
<div class="groupby_courier">
<t t-set="breadcrumbs_searchbar" t-value="True"/>
<t t-call="portal.portal_searchbar">
<h8 style="margin-left: -1250px;color: darkslategray;">/ My
Reservation Order
</h8>
</t>
<t
t-call="website_product_reservation.portal_my_reservation_search"/>
</div>
</t>
</template>
<template id="portal_my_reservation_search">
<div id="search_courier_requests_group" class="search_courier_requests">
<t t-if="not reservation_request">
<h5>There are currently no Reservation requests for your
account.
</h5>
</t>
<t t-if="reservation_request" t-call="portal.portal_table">
<thead>
<tr class="active">
<th>Reservation Order #</th>
<th class="text-right">Order date</th>
<th class="text-right">Total</th>
</tr>
</thead>
<t t-foreach="reservation_request" t-as="reservation">
<tr>
<td id="my_selector">
<a class="my_reservation_request_link"
t-attf-data-id="{{reservation.id}}"
t-attf-href="/my/reservation/requests/form/{{reservation.id}}">
<t t-esc="reservation.name"/>
</a>
</td>
<td class="text-right">
<span t-field="reservation.create_date"/>
</td>
<td class="text-right">
<span t-field="reservation.amount_total"/>
</td>
</tr>
</t>
</t>
</div>
</template>
<template id="portal_my_reservation_requests_form"
name="Reservation Request Form">
<t t-call="portal.portal_layout">
<t t-set="breadcrumbs_searchbar" t-value="True"/>
<t t-call="portal.portal_searchbar">
<a href="/my/reservation/requests">
<h8 style="margin-left: -1231px;color: darkslategray;"
class="breadcrumb-item active">/ My Reservation
Order
</h8>
</a>
<h8 style="margin-left: -1064px;color: darkgray;">/ Reservation
Order
<t t-esc="record_reservation_requests['name']"/>
</h8>
</t>
<!-- Slidebar-->
<div class="row mt16 o_portal_sale_sidebar">
<t t-call="portal.portal_record_sidebar">
<t t-set="classes" t-value="'col-lg-auto d-print-none'"/>
<t t-set="title">
<h4 class="mb-0">
<t t-esc="record_reservation_requests['name']"/>
</h4>
</t>
<t t-set="entries">
<ul class="list-group list-group-flush flex-wrap flex-row flex-lg-column">
<li class="list-group-item d-grid align-content-start">
<div class="small mb-1">
<strong class="text-muted">Your Contact
</strong>
</div>
<div class="row flex-nowrap">
<div class="col flex-grow-0 pe-2">
<img class="rounded-circle mr4 float-start o_portal_contact_img"
t-att-src="image_data_uri(record_reservation_requests['partner_id'].avatar_1024)"
alt="Contact" style="width: 150px"/>
</div>
<div class="col ps-0"
style="min-width: 150px">
<span
t-esc="record_reservation_requests['partner_id']"
t-options='{"widget": "contact", "fields": ["name", "phone"], "no_marker": True}'/>
</div>
</div>
</li>
</ul>
</t>
</t>
<div id="reservation_requests_call_page_details"
class="col-12 col-lg justify-content-end">
<div t-attf-class="card #{'pb-5' if report_type == 'html' else ''}"
id="cer_portal_doc_content">
<div class="card pb-5" style="padding: 1rem 1rem;">
<div class="container">
<h4 class="mb-0" style="margin-left:15px;">
<br/>
<b>
<span><strong>Reservation
Order : </strong> <t
t-esc="record_reservation_requests['name']"/></span>
<span
t-if="record_reservation_requests['state'] == 'reserve'">
<a
t-att-href="'/my/reservation/requests/form/id=%s' % (record_reservation_requests.id)">
<button type="button"
t-att-id="record_reservation_requests.id"
class="btn btn-primary">
<i class="fa fa-caret-left">
</i>
Cancel
</button>
</a>
</span>
<span
t-if="record_reservation_requests['state'] == 'reserve'">
<a
t-att-href="'/my/reservation/requests/form/confirm=%s' % (record_reservation_requests.id)">
<button type="button"
t-att-id="record_reservation_requests.id"
class="btn btn-primary">
<i class="fa fa-caret-left">
</i>
Create A Sale
</button>
</a>
</span>
</b>
</h4>
<hr style="width:100%"/>
</div>
<!-- Page Content-->
<table class="table-responsive">
<tr>
<th>Reserve Date : <t
t-esc="record_reservation_requests['date_order']"/></th>
</tr>
<tr>
<th>Expiration Date: <t
t-esc="record_reservation_requests['validity_date']"/></th>
</tr>
<tr>
<th>Status:
<t
t-esc="{'draft': 'Quotation','sent':'Quotation sent','reserve': 'Reserved', 'sale': 'Sale Order', 'cancel': 'Cancelled'} [record_reservation_requests['state']]"/>
</th>
</tr>
</table>
<br/>
<table class="table table-sm o_main_table">
<thead>
<tr>
<th>Product</th>
<th>Quantity</th>
<th>Unit Price</th>
<th>Taxes</th>
<th>Sub Total</th>
</tr>
</thead>
<tbody>
<t
t-foreach="record_reservation_requests['order_line']"
t-as="line">
<tr>
<td>
<t
t-esc="line.product_id.name"/>
</td>
<td>
<t
t-esc="line.product_uom_qty"/>
</td>
<td>
<t t-esc="line.price_unit"/>
</td><td>
<t t-esc="line.tax_id.name"/>
</td>
<td>
<t t-esc="line.price_subtotal"/>
</td>
</tr>
</t>
</tbody>
</table>
<div>
<div class="col-sm-7 col-md-6 ms-auto">
<table class="table table-sm">
<tr class="border-black o_total">
<th>Total</th>
<td class="text-end">
<t
t-esc="record_reservation_requests['amount_total']"/>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</t>
</template>
</odoo>

19
website_product_reservation/views/product_template_views.xml

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Product Form View Inherited -->
<record id="product_template_form_view" model="ir.ui.view">
<field name="name">product.template.view.form.inherit.website.product.reservation</field>
<field name="model">product.template</field>
<field name="inherit_id"
ref="product.product_template_form_view"/>
<field name="arch" type="xml">
<xpath expr="//sheet/div[@name='options']"
position="inside">
<span class="d-inline-block">
<field name="reserve_products"/>
<label for="reserve_products"/>
</span>
</xpath>
</field>
</record>
</odoo>

31
website_product_reservation/views/res_cofig_settings_views.xml

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!-- Override the res_config_settings_view_form view to add a new field -->
<record id="res_config_settings_view_form" model="ir.ui.view">
<field name="name">res.config.settings.inherit.website.product.reservation</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="stock.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//setting[@id='warning_info']" position="after">
<div class="col-12 col-lg-6 o_setting_box" id="warning_info">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<label for="destination_location_id"
string="Desination Location"/>
<div class="text-muted">
select destination location to reserve stock.
</div>
<div class="content-group">
<div class="mt16">
<!-- Field widget for the new field -->
<field name="destination_location_id"
class="o_light_label"
widget="selection"/>
</div>
</div>
</div>
</div>
</xpath>
</field>
</record>
</odoo>

37
website_product_reservation/views/sale_order_views.xml

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<!-- Customization of the sale.order form view -->
<record id="view_order_form" model="ir.ui.view">
<field name="name">sale.order.view.form.inherit.website.product.reservation</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="model">sale.order</field>
<field name="arch" type="xml">
<!-- Adding buttons for custom actions inside the form header -->
<xpath expr="//form/header" position="inside">
<!-- Button to create a quotation -->
<button name="action_make_draft" string="Create Quotation"
type="object" class="oe_highlight"
invisible="state != 'reserve'"/>
<!-- Button to cancel reservation -->
<button name="action_cancel_reservation" string="Cancel Reservation" type="object" invisible="state != 'reserve'"/>
</xpath>
</field>
</record>
<!-- Action for viewing reservation orders -->
<record id="action_view_reservation_orders" model="ir.actions.act_window">
<field name="name">Reservation Orders</field>
<field name="res_model">sale.order</field>
<field name="view_mode">tree,kanban,form,activity</field>
<field name="domain">[('state', '=', 'reserve'), ('website_id', '!=', False)]</field>
<field name="context" eval="{'show_sale': True, 'create': False}"/>
<field name="help" type="html">
<p class="o_view_nocontent_empty_folder">
There is no reservation order from the website yet
</p>
</field>
</record>
<!-- Menu item for the Reservation Orders -->
<menuitem id="menu_orders_reservation_orders" name="Reservation Orders"
action="action_view_reservation_orders"
parent="website_sale.menu_orders"/>
</odoo>

175
website_product_reservation/views/website_templates.xml

@ -0,0 +1,175 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Template for Reservation -->
<template id="reservation_page" name="Reservation">
<t t-call="website.layout">
<!-- Main structure for the reservation page -->
<div id="wrap" class="js_sale o_wsale_products_page">
<div class="oe_structure oe_empty oe_structure_not_nearest"
id="oe_structure_website_sale_products_1"/>
<div class="container oe_website_sale pt-2">
<h3 style="text-align: center;">
Reserve Products
</h3>
<!-- Product display section -->
<div class="row">
<t t-foreach="products" t-as="product">
<div class="col-md-3"
style="border: 1px solid rgba(100, 100, 100, 0.2);padding: 0 15px 10px 32px;">
<div class="card-body p-1 oe_product_image">
<input type="hidden" name="csrf_token"
t-att-value="request.csrf_token()"/>
<a t-att-href="product_href"
class="d-block h-100"
itemprop="url">
<t t-set="image_holder"
t-value="product._get_image_holder()"/>
<span t-field="image_holder.image_1920"
t-options="{'widget': 'image', 'preview_image': 'image_1920'}"
class="d-flex h-100 justify-content-center align-items-center"/>
</a>
</div>
<!-- Product details section -->
<div class="product details product-item-details">
<h6 class="o_wsale_products_item_title mb-2">
<a class="product-item-link"
t-attf-href="/shop/product/#{slug(product)}">
<span t-field="product.name"/>
</a>
</h6>
<!-- Reservation button -->
<div class="actions-primary"
style="text-align: center;">
<form t-attf-action="/reservation/reserve?type_name=Reservation"
method="post">
<input name="product_id"
t-att-value="product.product_variant_ids[0].id"
type="hidden"/>
<input type="hidden"
name="csrf_token"
t-att-value="request.csrf_token()"/>
<!-- Reservation button -->
<button type="submit"
title="Add to Reserve Cart"
class="btn btn-primary"
onclick="submit();"
style="background-color: #337ab7 !important; border: 1px solid white !important;">
<span>Reserve</span>
</button>
</form>
</div>
<a href="#"
class="action actions-secondary"
title="Compare"
aria-label="Compare"
role="button"
style="visibility: visible;
position: static;
opacity: 1;
height: 40px;
line-height: 40px;
top: 0;
width: 40px;
border: 0;
background-color: #e6e6e6;
color: #000; display: none;">
<i class="fa fa-signal"
aria-hidden="true"/>
<span>Compare</span>
</a>
</div>
</div>
</t>
<t t-if="not products">
<div class="text-center text-muted oe_product">
<h3 class="css_editable_display">No reserve product
defined.
</h3>
<p groups="sales_team.group_sale_manager">Click
<i>
'New'
</i> in the top-right corner to create your first
product.
</p>
</div>
</t>
</div>
</div>
</div>
<div class="products_pager o_portal_pager d-flex justify-content-center pt-5 pb-3">
<t t-call="website.pager"/>
</div>
</t>
</template>
<!-- Inherited Template to Add Reservation Link -->
<template id="inherit_product_reservation"
inherit_id="website_sale.product">
<xpath expr="//form" position="inside">
<t t-if="product.reserve_products and product.website_published">
<a href="/reservation" id="reservation_page" role="button">
RESERVE THIS PRODUCT
</a>
</t>
</xpath>
</template>
<!-- Template for Reserve From Cart -->
<template id="reserve_from_cart" inherit_id="website_sale.checkout_layout">
<xpath expr="//t[@t-call='website_sale.navigation_buttons']"
position="after">
<br/>
<div t-if="website_sale_order and website_sale_order.is_reservation_order">
<a class="btn btn-primary float-end" role="button"
href="/reservation/confirm_reserve_order">
<span>Reserve</span>
<span class="fa fa-chevron-right"/>
</a>
</div>
</xpath>
</template>
<!-- Template for Reserve Thankyou -->
<template id="reservation_thankyou" name="Reservation Thank You">
<t t-call="website.layout">
<div id="wrap">
<div class="oe_structure"/>
<div class="container">
<h1>Thank you!
<span>Order
<em t-field="order.name"/>
Reserved
</span>
</h1>
<div class="row">
<div class="col-md-12">
<div class="alert alert-success">
Thanks for your reservation request. Your
reservation has been confirmed.
</div>
</div>
</div>
</div>
<div class="oe_structure"/></div>
</t>
</template>
<!-- Template for Not Allowed Page-->
<template id="not_allowed_to_reserve_page" name="not_allowed_popup">
<t t-call="website.layout">
<div id="wrap">
<div class="oe_structure"/>
<div class="container">
<h1 class="modal-title">Reservation Not
Allowed
</h1>
<div class="row">
<div class="col-md-12">
<p>You cannot reserve this Order
</p>
</div>
<a href="/shop/cart">Back to Cart</a>
</div>
</div>
</div>
</t>
</template>
</odoo>
Loading…
Cancel
Save