From 24a03700052989994709f1a0a2958fb8207856e1 Mon Sep 17 00:00:00 2001
From: RisvanaCybro
Date: Thu, 25 Jan 2024 20:00:57 +0530
Subject: [PATCH] Jan 25 : [ADD] Initial Commit 'venue_booking_management'
---
venue_booking_management/README.rst | 55 +
venue_booking_management/__init__.py | 25 +
venue_booking_management/__manifest__.py | 77 +
.../controllers/__init__.py | 23 +
.../controllers/portal.py | 264 +++
.../controllers/venue_booking_management.py | 96 ++
.../data/confirmation_email_template_data.xml | 30 +
.../data/venue_type_data.xml | 60 +
venue_booking_management/doc/RELEASE_NOTES.md | 5 +
venue_booking_management/models/__init__.py | 28 +
venue_booking_management/models/amenities.py | 32 +
.../models/res_config_settings.py | 34 +
venue_booking_management/models/venue.py | 87 +
.../models/venue_booking.py | 489 ++++++
.../models/venue_booking_line.py | 65 +
.../models/venue_lines.py | 54 +
venue_booking_management/models/venue_type.py | 33 +
venue_booking_management/report/__init__.py | 23 +
.../report/form_venue_booking_report.py | 80 +
.../report/venue_booking_report.py | 73 +
.../report/venue_booking_report_templates.xml | 186 +++
.../report/venue_booking_report_views.xml | 108 ++
.../report/venue_booking_rerports.xml | 18 +
.../security/ir.model.access.csv | 10 +
.../venue_booking_management_groups.xml | 22 +
.../security/venue_booking_secruity.xml | 22 +
.../description/assets/icons/capture (1).png | Bin 0 -> 36623 bytes
.../static/description/assets/icons/check.png | Bin 0 -> 3676 bytes
.../description/assets/icons/chevron.png | Bin 0 -> 310 bytes
.../static/description/assets/icons/cogs.png | Bin 0 -> 1377 bytes
.../description/assets/icons/consultation.png | Bin 0 -> 1458 bytes
.../description/assets/icons/ecom-black.png | Bin 0 -> 576 bytes
.../assets/icons/education-black.png | Bin 0 -> 733 bytes
.../description/assets/icons/hotel-black.png | Bin 0 -> 911 bytes
.../static/description/assets/icons/img.png | Bin 0 -> 1173 bytes
.../description/assets/icons/license.png | Bin 0 -> 1095 bytes
.../description/assets/icons/lifebuoy.png | Bin 0 -> 1199 bytes
.../assets/icons/manufacturing-black.png | Bin 0 -> 673 bytes
.../assets/icons/photo-capture.png | Bin 0 -> 10898 bytes
.../description/assets/icons/pos-black.png | Bin 0 -> 878 bytes
.../description/assets/icons/puzzle.png | Bin 0 -> 653 bytes
.../assets/icons/restaurant-black.png | Bin 0 -> 905 bytes
.../assets/icons/service-black.png | Bin 0 -> 839 bytes
.../assets/icons/trading-black.png | Bin 0 -> 427 bytes
.../description/assets/icons/training.png | Bin 0 -> 627 bytes
.../description/assets/icons/update.png | Bin 0 -> 1225 bytes
.../static/description/assets/icons/user.png | Bin 0 -> 988 bytes
.../description/assets/icons/wrench.png | Bin 0 -> 1205 bytes
.../description/assets/misc/Cybrosys R.png | Bin 0 -> 82191 bytes
.../static/description/assets/misc/email.svg | 33 +
.../static/description/assets/misc/phone.svg | 3 +
.../description/assets/misc/star (1) 2.svg | 9 +
.../description/assets/misc/support (1) 1.svg | 9 +
.../description/assets/misc/support-email.svg | 6 +
.../description/assets/misc/tick-mark.svg | 17 +
.../description/assets/misc/whatsapp 1.svg | 9 +
.../description/assets/misc/whatsapp.svg | 33 +
.../static/description/assets/modules/1.png | Bin 0 -> 81144 bytes
.../static/description/assets/modules/2.jpg | Bin 0 -> 90339 bytes
.../static/description/assets/modules/3.gif | Bin 0 -> 934175 bytes
.../static/description/assets/modules/4.gif | Bin 0 -> 544786 bytes
.../static/description/assets/modules/5.jpg | Bin 0 -> 86680 bytes
.../static/description/assets/modules/6.jpg | Bin 0 -> 78127 bytes
.../description/assets/screenshots/1.png | Bin 0 -> 114384 bytes
.../description/assets/screenshots/10.png | Bin 0 -> 56524 bytes
.../description/assets/screenshots/11.png | Bin 0 -> 41803 bytes
.../description/assets/screenshots/12.png | Bin 0 -> 106747 bytes
.../description/assets/screenshots/13.png | Bin 0 -> 32931 bytes
.../description/assets/screenshots/14.png | Bin 0 -> 104587 bytes
.../description/assets/screenshots/15.png | Bin 0 -> 122674 bytes
.../description/assets/screenshots/16.png | Bin 0 -> 110352 bytes
.../description/assets/screenshots/17.png | Bin 0 -> 108587 bytes
.../description/assets/screenshots/18.png | Bin 0 -> 123958 bytes
.../description/assets/screenshots/19.png | Bin 0 -> 148120 bytes
.../description/assets/screenshots/2.png | Bin 0 -> 582418 bytes
.../description/assets/screenshots/20.png | Bin 0 -> 148908 bytes
.../description/assets/screenshots/21.png | Bin 0 -> 106459 bytes
.../description/assets/screenshots/22.png | Bin 0 -> 144409 bytes
.../description/assets/screenshots/23.png | Bin 0 -> 128271 bytes
.../description/assets/screenshots/24.png | Bin 0 -> 106387 bytes
.../description/assets/screenshots/25.png | Bin 0 -> 110871 bytes
.../description/assets/screenshots/26.png | Bin 0 -> 113457 bytes
.../description/assets/screenshots/27.png | Bin 0 -> 63927 bytes
.../description/assets/screenshots/28.png | Bin 0 -> 160791 bytes
.../description/assets/screenshots/29.png | Bin 0 -> 137687 bytes
.../description/assets/screenshots/3.png | Bin 0 -> 839824 bytes
.../description/assets/screenshots/30.png | Bin 0 -> 97663 bytes
.../description/assets/screenshots/31.png | Bin 0 -> 99309 bytes
.../description/assets/screenshots/32.png | Bin 0 -> 97826 bytes
.../description/assets/screenshots/33.png | Bin 0 -> 111132 bytes
.../description/assets/screenshots/34.png | Bin 0 -> 104355 bytes
.../description/assets/screenshots/35.png | Bin 0 -> 79817 bytes
.../description/assets/screenshots/36.png | Bin 0 -> 80157 bytes
.../description/assets/screenshots/37.png | Bin 0 -> 182194 bytes
.../description/assets/screenshots/38.png | Bin 0 -> 136392 bytes
.../description/assets/screenshots/39.png | Bin 0 -> 200197 bytes
.../description/assets/screenshots/4.png | Bin 0 -> 89858 bytes
.../description/assets/screenshots/40.png | Bin 0 -> 111750 bytes
.../description/assets/screenshots/41.png | Bin 0 -> 78788 bytes
.../description/assets/screenshots/42.png | Bin 0 -> 149391 bytes
.../description/assets/screenshots/43.png | Bin 0 -> 235995 bytes
.../description/assets/screenshots/44.png | Bin 0 -> 94992 bytes
.../description/assets/screenshots/5.png | Bin 0 -> 470432 bytes
.../description/assets/screenshots/6.png | Bin 0 -> 117968 bytes
.../description/assets/screenshots/7.png | Bin 0 -> 44955 bytes
.../description/assets/screenshots/8.png | Bin 0 -> 122119 bytes
.../description/assets/screenshots/9.png | Bin 0 -> 111641 bytes
.../description/assets/screenshots/hero.gif | Bin 0 -> 661354 bytes
.../static/description/banner.jpg | Bin 0 -> 96843 bytes
.../static/description/icon.png | Bin 0 -> 9512 bytes
.../static/description/index.html | 1470 +++++++++++++++++
.../static/img/venue_booking.jpeg | Bin 0 -> 8063 bytes
.../static/img/venue_type1.jpeg | Bin 0 -> 102970 bytes
.../static/img/venue_type2.jpeg | Bin 0 -> 71913 bytes
.../static/img/venue_type3.jpeg | Bin 0 -> 7830 bytes
.../static/img/venue_type4.jpeg | Bin 0 -> 9418 bytes
.../static/img/venue_type5.jpeg | Bin 0 -> 64498 bytes
.../static/img/venue_type6.jpeg | Bin 0 -> 100720 bytes
.../static/img/venue_type7.jpeg | Bin 0 -> 11390 bytes
.../static/img/venue_type8.jpeg | Bin 0 -> 5623 bytes
.../static/img/venue_type9.jpeg | Bin 0 -> 11586 bytes
.../static/src/css/venue_dashboard.css | 101 ++
.../static/src/css/website_page.css | 86 +
.../static/src/js/action_manager.js | 16 +
.../static/src/js/dashboard_action.js | 329 ++++
.../static/src/js/website_venue_booking.js | 99 ++
.../static/src/scss/venue_booking.scss | 237 +++
.../static/src/xml/dashboard_templates.xml | 272 +++
.../views/amenities_views.xml | 52 +
.../views/dashboard_views.xml | 23 +
.../views/res_config_settings_views.xml | 57 +
.../views/res_partner_views.xml | 29 +
.../views/venue_booking_views.xml | 301 ++++
.../views/venue_type_views.xml | 51 +
.../views/venue_views.xml | 180 ++
.../views/website_portal_templates.xml | 203 +++
.../views/website_venue_booking_templates.xml | 136 ++
venue_booking_management/wizards/__init__.py | 23 +
.../wizards/check_venue_availability.py | 88 +
.../check_venue_availability_views.xml | 50 +
.../wizards/venue_booking_analysis.py | 207 +++
.../wizards/venue_booking_analysis_views.xml | 49 +
142 files changed, 6177 insertions(+)
create mode 100644 venue_booking_management/README.rst
create mode 100644 venue_booking_management/__init__.py
create mode 100644 venue_booking_management/__manifest__.py
create mode 100644 venue_booking_management/controllers/__init__.py
create mode 100644 venue_booking_management/controllers/portal.py
create mode 100644 venue_booking_management/controllers/venue_booking_management.py
create mode 100644 venue_booking_management/data/confirmation_email_template_data.xml
create mode 100644 venue_booking_management/data/venue_type_data.xml
create mode 100644 venue_booking_management/doc/RELEASE_NOTES.md
create mode 100644 venue_booking_management/models/__init__.py
create mode 100644 venue_booking_management/models/amenities.py
create mode 100644 venue_booking_management/models/res_config_settings.py
create mode 100644 venue_booking_management/models/venue.py
create mode 100644 venue_booking_management/models/venue_booking.py
create mode 100644 venue_booking_management/models/venue_booking_line.py
create mode 100644 venue_booking_management/models/venue_lines.py
create mode 100644 venue_booking_management/models/venue_type.py
create mode 100644 venue_booking_management/report/__init__.py
create mode 100644 venue_booking_management/report/form_venue_booking_report.py
create mode 100644 venue_booking_management/report/venue_booking_report.py
create mode 100644 venue_booking_management/report/venue_booking_report_templates.xml
create mode 100644 venue_booking_management/report/venue_booking_report_views.xml
create mode 100644 venue_booking_management/report/venue_booking_rerports.xml
create mode 100644 venue_booking_management/security/ir.model.access.csv
create mode 100644 venue_booking_management/security/venue_booking_management_groups.xml
create mode 100644 venue_booking_management/security/venue_booking_secruity.xml
create mode 100644 venue_booking_management/static/description/assets/icons/capture (1).png
create mode 100644 venue_booking_management/static/description/assets/icons/check.png
create mode 100644 venue_booking_management/static/description/assets/icons/chevron.png
create mode 100644 venue_booking_management/static/description/assets/icons/cogs.png
create mode 100644 venue_booking_management/static/description/assets/icons/consultation.png
create mode 100644 venue_booking_management/static/description/assets/icons/ecom-black.png
create mode 100644 venue_booking_management/static/description/assets/icons/education-black.png
create mode 100644 venue_booking_management/static/description/assets/icons/hotel-black.png
create mode 100644 venue_booking_management/static/description/assets/icons/img.png
create mode 100644 venue_booking_management/static/description/assets/icons/license.png
create mode 100644 venue_booking_management/static/description/assets/icons/lifebuoy.png
create mode 100644 venue_booking_management/static/description/assets/icons/manufacturing-black.png
create mode 100644 venue_booking_management/static/description/assets/icons/photo-capture.png
create mode 100644 venue_booking_management/static/description/assets/icons/pos-black.png
create mode 100644 venue_booking_management/static/description/assets/icons/puzzle.png
create mode 100644 venue_booking_management/static/description/assets/icons/restaurant-black.png
create mode 100644 venue_booking_management/static/description/assets/icons/service-black.png
create mode 100644 venue_booking_management/static/description/assets/icons/trading-black.png
create mode 100644 venue_booking_management/static/description/assets/icons/training.png
create mode 100644 venue_booking_management/static/description/assets/icons/update.png
create mode 100644 venue_booking_management/static/description/assets/icons/user.png
create mode 100644 venue_booking_management/static/description/assets/icons/wrench.png
create mode 100644 venue_booking_management/static/description/assets/misc/Cybrosys R.png
create mode 100644 venue_booking_management/static/description/assets/misc/email.svg
create mode 100644 venue_booking_management/static/description/assets/misc/phone.svg
create mode 100644 venue_booking_management/static/description/assets/misc/star (1) 2.svg
create mode 100644 venue_booking_management/static/description/assets/misc/support (1) 1.svg
create mode 100644 venue_booking_management/static/description/assets/misc/support-email.svg
create mode 100644 venue_booking_management/static/description/assets/misc/tick-mark.svg
create mode 100644 venue_booking_management/static/description/assets/misc/whatsapp 1.svg
create mode 100644 venue_booking_management/static/description/assets/misc/whatsapp.svg
create mode 100644 venue_booking_management/static/description/assets/modules/1.png
create mode 100644 venue_booking_management/static/description/assets/modules/2.jpg
create mode 100644 venue_booking_management/static/description/assets/modules/3.gif
create mode 100644 venue_booking_management/static/description/assets/modules/4.gif
create mode 100644 venue_booking_management/static/description/assets/modules/5.jpg
create mode 100644 venue_booking_management/static/description/assets/modules/6.jpg
create mode 100644 venue_booking_management/static/description/assets/screenshots/1.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/10.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/11.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/12.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/13.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/14.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/15.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/16.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/17.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/18.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/19.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/2.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/20.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/21.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/22.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/23.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/24.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/25.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/26.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/27.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/28.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/29.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/3.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/30.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/31.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/32.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/33.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/34.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/35.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/36.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/37.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/38.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/39.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/4.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/40.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/41.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/42.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/43.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/44.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/5.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/6.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/7.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/8.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/9.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/hero.gif
create mode 100644 venue_booking_management/static/description/banner.jpg
create mode 100644 venue_booking_management/static/description/icon.png
create mode 100644 venue_booking_management/static/description/index.html
create mode 100644 venue_booking_management/static/img/venue_booking.jpeg
create mode 100644 venue_booking_management/static/img/venue_type1.jpeg
create mode 100644 venue_booking_management/static/img/venue_type2.jpeg
create mode 100644 venue_booking_management/static/img/venue_type3.jpeg
create mode 100644 venue_booking_management/static/img/venue_type4.jpeg
create mode 100644 venue_booking_management/static/img/venue_type5.jpeg
create mode 100644 venue_booking_management/static/img/venue_type6.jpeg
create mode 100644 venue_booking_management/static/img/venue_type7.jpeg
create mode 100644 venue_booking_management/static/img/venue_type8.jpeg
create mode 100644 venue_booking_management/static/img/venue_type9.jpeg
create mode 100644 venue_booking_management/static/src/css/venue_dashboard.css
create mode 100644 venue_booking_management/static/src/css/website_page.css
create mode 100644 venue_booking_management/static/src/js/action_manager.js
create mode 100644 venue_booking_management/static/src/js/dashboard_action.js
create mode 100644 venue_booking_management/static/src/js/website_venue_booking.js
create mode 100644 venue_booking_management/static/src/scss/venue_booking.scss
create mode 100644 venue_booking_management/static/src/xml/dashboard_templates.xml
create mode 100644 venue_booking_management/views/amenities_views.xml
create mode 100644 venue_booking_management/views/dashboard_views.xml
create mode 100644 venue_booking_management/views/res_config_settings_views.xml
create mode 100644 venue_booking_management/views/res_partner_views.xml
create mode 100644 venue_booking_management/views/venue_booking_views.xml
create mode 100644 venue_booking_management/views/venue_type_views.xml
create mode 100644 venue_booking_management/views/venue_views.xml
create mode 100644 venue_booking_management/views/website_portal_templates.xml
create mode 100644 venue_booking_management/views/website_venue_booking_templates.xml
create mode 100644 venue_booking_management/wizards/__init__.py
create mode 100644 venue_booking_management/wizards/check_venue_availability.py
create mode 100644 venue_booking_management/wizards/check_venue_availability_views.xml
create mode 100644 venue_booking_management/wizards/venue_booking_analysis.py
create mode 100644 venue_booking_management/wizards/venue_booking_analysis_views.xml
diff --git a/venue_booking_management/README.rst b/venue_booking_management/README.rst
new file mode 100644
index 000000000..739ab20a7
--- /dev/null
+++ b/venue_booking_management/README.rst
@@ -0,0 +1,55 @@
+.. 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
+
+Venue / Event Booking Management
+================================
+The 'Venue / Event Booking Management' is a core module which can manage any type of venue reservation.
+
+Features
+========
+* Venue Booking creation.
+* Allocate the Booking to different users.
+* Integrated with Accounting module.
+* Simple Workflow.
+* Attractive Design.
+
+Configuration
+=============
+* No additional configurations needed
+
+License
+-------
+Gnu Affero General Public License, v3.0 (AGPL v3).
+(https://www.gnu.org/licenses/agpl-3.0-standalone.html)
+
+Company
+-------
+* `Cybrosys Techno Solutions `__
+
+Credits
+-------
+* Developer : (V16) Risvana AR,
+ (V17) Farhana Jahan PT,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 `__
+
+Further information
+===================
+HTML Description: ``__
diff --git a/venue_booking_management/__init__.py b/venue_booking_management/__init__.py
new file mode 100644
index 000000000..822511fa5
--- /dev/null
+++ b/venue_booking_management/__init__.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (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 .
+#
+###############################################################################
+from . import controllers
+from . import models
+from . import report
+from . import wizards
diff --git a/venue_booking_management/__manifest__.py b/venue_booking_management/__manifest__.py
new file mode 100644
index 000000000..8e20ca6fc
--- /dev/null
+++ b/venue_booking_management/__manifest__.py
@@ -0,0 +1,77 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (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 .
+#
+###############################################################################
+{
+ 'name': 'Venue / Event Booking Management',
+ 'version': '17.0.1.0.0',
+ 'summary': 'Core Module for Managing Different Types of '
+ 'Venue/ Event Booking.',
+ 'description': 'Core Module for Managing Different Types of '
+ 'Venue/ Event Booking, Event Booking, Venue Booking, '
+ 'Space Booking, Booking, Event, Venue, Wedding, Birthday, '
+ 'Party, Hall Booking, Room Booking',
+ "category": "Account/Website",
+ 'author': 'Cybrosys Techno Solutions',
+ 'company': 'Cybrosys Techno Solutions',
+ 'maintainer': 'Cybrosys Techno Solutions',
+ 'depends': ['base', 'account', 'website'],
+ 'website': "https://www.cybrosys.com",
+ 'data': [
+ 'security/venue_booking_management_groups.xml',
+ 'security/ir.model.access.csv',
+ 'data/venue_type_data.xml',
+ 'data/confirmation_email_template_data.xml',
+ 'views/venue_booking_views.xml',
+ 'views/venue_type_views.xml',
+ 'views/amenities_views.xml',
+ 'views/venue_views.xml',
+ 'views/dashboard_views.xml',
+ 'views/res_partner_views.xml',
+ 'views/res_config_settings_views.xml',
+ 'wizards/check_venue_availability_views.xml',
+ 'report/venue_booking_report_views.xml',
+ 'report/venue_booking_report_templates.xml',
+ 'report/venue_booking_rerports.xml',
+ 'wizards/venue_booking_analysis_views.xml',
+ 'views/website_venue_booking_templates.xml',
+ 'views/website_portal_templates.xml',
+ ],
+ 'assets': {
+ 'web.assets_frontend': [
+ 'venue_booking_management/static/src/css/website_page.css',
+ 'venue_booking_management/static/src/js/website_venue_booking.js'
+ ],
+ 'web.assets_backend': [
+ 'https://fonts.googleapis.com/css2?family=Poppins:wght@400;600&display=swap',
+ 'venue_booking_management/static/src/css/venue_dashboard.css',
+ 'venue_booking_management/static/src/scss/venue_booking.scss',
+ 'venue_booking_management/static/src/xml/dashboard_templates.xml',
+ 'venue_booking_management/static/src/js/action_manager.js',
+ 'venue_booking_management/static/src/js/dashboard_action.js',
+ 'https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.0/chart.umd.min.js'
+ ]
+ },
+ 'images': ['static/description/banner.jpg'],
+ 'license': 'AGPL-3',
+ 'installable': True,
+ 'application': True,
+}
+
diff --git a/venue_booking_management/controllers/__init__.py b/venue_booking_management/controllers/__init__.py
new file mode 100644
index 000000000..372b63fe1
--- /dev/null
+++ b/venue_booking_management/controllers/__init__.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (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 .
+#
+###############################################################################
+from . import portal
+from . import venue_booking_management
diff --git a/venue_booking_management/controllers/portal.py b/venue_booking_management/controllers/portal.py
new file mode 100644
index 000000000..6bd02fe13
--- /dev/null
+++ b/venue_booking_management/controllers/portal.py
@@ -0,0 +1,264 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (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 .
+#
+###############################################################################
+from collections import OrderedDict
+from datetime import timedelta
+from odoo.addons.portal.controllers import portal
+from odoo.addons.portal.controllers.portal import CustomerPortal, \
+ pager as portal_pager
+from odoo import fields, http, _
+from odoo.http import request
+from odoo.osv import expression
+from odoo.osv.expression import OR
+
+
+class CustomerPortal(portal.CustomerPortal):
+ """Class for Venue booking portal that gives the record and
+ counts of the Bookings"""
+
+ def _prepare_home_portal_values(self, counters):
+ """ Function for finding the number of document """
+ values = super()._prepare_home_portal_values(counters)
+ uid = request.env.user.partner_id.id
+ venue_booking_count = request.env['venue.booking'].search_count(
+ [('partner_id', '=', uid)])
+ values.update({'venue_booking_count': venue_booking_count})
+ return values
+
+ @http.route(['/my/venue_booking', '/my/venue_booking/page/'],
+ type='http', auth='user',
+ website=True)
+ def create_venue_booking_management(self, page=1, date_begin=None,
+ date_end=None,
+ sortby=None, filterby=None,
+ search=None,
+ search_in='content', ):
+ """ Function to fetch booking records and pass to the portal template"""
+ uid = request.env.user.partner_id.id
+ venue_booking_management = request.env['venue.booking'].sudo().search(
+ [('partner_id', '=', uid)])
+ values = self._prepare_my_booking_values(page, date_begin, date_end,
+ sortby, filterby, search,
+ search_in)
+ # Pager
+ pager = portal_pager(**values['pager'])
+ venue = values['venue'](pager['offset'])
+ request.session['my_venue_booking_history'] = venue.ids[:100]
+ values.update({
+ 'venue_booking_management': venue_booking_management,
+ 'venues': venue,
+ 'pager': pager,
+ })
+ return request.render(
+ "venue_booking_management.portal_my_venue_booking_documents",
+ values)
+
+ def _prepare_my_booking_values(self, page, date_begin, date_end, sortby,
+ filterby, search, search_in,
+ domain=None, url="/my/venue_booking"):
+ """Add all event values to the portal. Which will return the
+ values event, page, pager, filter, sort, and search"""
+ values = self._prepare_portal_layout_values()
+ Venue = request.env['venue.booking']
+ domain = expression.AND([
+ domain or [],
+ self._get_booking_domain(),
+ ])
+ searchbar_sortings = self._get_venue_booking_searchbar_sortings()
+ # default sort by order
+ if not sortby:
+ sortby = 'date'
+ order = searchbar_sortings[sortby]['order']
+ searchbar_filters = self._get_venue_booking_searchbar_filters()
+ # default filter by value
+ if not filterby:
+ filterby = 'all'
+ domain += searchbar_filters[filterby]['domain']
+ searchbar_inputs = self._get_venue_booking_searchbar_inputs()
+ if search and search_in:
+ domain += self._get_venue_booking_search_domain(search_in, search)
+ if date_begin and date_end:
+ domain += [('create_date', '>', date_begin),
+ ('create_date', '<=', date_end)]
+ values.update({
+ 'date': date_begin,
+ 'venue': lambda pager_offset: self._get_grouped_venues(Venue,
+ domain,
+ order,
+ pager_offset),
+ 'page_name': 'venue_booking',
+ 'pager': {
+ "url": url,
+ "url_args": {'date_begin': date_begin, 'date_end': date_end,
+ 'sortby': sortby, 'search_in': search_in,
+ 'search': search},
+ "total": Venue.search_count(domain),
+ "page": page,
+ "step": self._items_per_page,
+ },
+ 'default_url': url,
+ 'searchbar_sortings': searchbar_sortings,
+ 'sortby': sortby,
+ 'searchbar_filters': OrderedDict(
+ sorted(searchbar_filters.items())),
+ 'filterby': filterby,
+ 'searchbar_inputs': searchbar_inputs,
+ 'search_in': search_in,
+ 'search': search,
+ })
+ return values
+
+ def _get_venue_page_view_values(self, venue, access_token, **kwargs):
+ """Get the page view values"""
+ values = {
+ 'venue': venue,
+ 'page_name': 'venue_booking',
+ }
+ return self._get_page_view_values(venue, access_token, values,
+ 'my_venue_booking_history', False,
+ **kwargs)
+
+ def _get_booking_domain(self):
+ """Returns the booking that are in stage 'cancel' and 'draft'"""
+ return [('state', 'not in', ('cancel', 'closed'))]
+
+ def _get_venue_booking_searchbar_sortings(self):
+ """Sort the booking based on the date and name"""
+ return {
+ 'date': {'label': _('Date'), 'order': 'create_date desc'},
+ 'name': {'label': _('Name'), 'order': 'name asc'},
+ }
+
+ def _get_venue_booking_searchbar_filters(self):
+ """Filter the events by All, Last month, This Month, Last Week,
+ This Week, Last Year, This Year, Today and This Quarter"""
+ today = fields.Date.today()
+ this_month_start = today.replace(day=1)
+ this_quarter_start = today.replace(day=1, month=((
+ today.month - 1) // 3) * 3 + 1)
+ this_week_start = today - timedelta(days=today.weekday())
+ this_year_start = today.replace(month=1, day=1)
+ return {
+ 'all': {'label': _('All'), 'domain': []},
+ 'last_month': {
+ 'label': _('Last Month'),
+ 'domain': [('create_date', '>=',
+ (this_month_start - timedelta(days=30)).strftime(
+ '%Y-%m-%d')),
+ ('create_date', '<=',
+ (this_month_start - timedelta(days=1)).strftime(
+ '%Y-%m-%d'))]
+ },
+ 'this_month': {
+ 'label': _('This Month'),
+ 'domain': [
+ (
+ 'create_date', '>=',
+ this_month_start.strftime('%Y-%m-%d')),
+ ('create_date', '<=', today.strftime('%Y-%m-%d'))]
+ },
+ 'last_week': {
+ 'label': _('Last Week'),
+ 'domain': [('create_date', '>=',
+ (this_week_start - timedelta(days=7)).strftime(
+ '%Y-%m-%d')),
+ ('create_date', '<=',
+ (this_week_start - timedelta(days=1)).strftime(
+ '%Y-%m-%d'))]
+ },
+ 'this_week': {
+ 'label': _('This Week'),
+ 'domain': [
+ (
+ 'create_date', '>=',
+ this_week_start.strftime('%Y-%m-%d')),
+ ('create_date', '<=', today.strftime('%Y-%m-%d'))]
+ },
+ 'last_year': {
+ 'label': _('Last Year'),
+ 'domain': [('create_date', '>=',
+ (this_year_start - timedelta(days=365)).strftime(
+ '%Y-%m-%d')),
+ ('create_date', '<=',
+ (this_year_start - timedelta(days=1)).strftime(
+ '%Y-%m-%d'))]
+ },
+ 'this_year': {
+ 'label': _('This Year'),
+ 'domain': [
+ (
+ 'create_date', '>=',
+ this_year_start.strftime('%Y-%m-%d')),
+ ('create_date', '<=', today.strftime('%Y-%m-%d'))]
+ },
+ 'today': {
+ 'label': _('Today'),
+ 'domain': [('create_date', '=', today.strftime('%Y-%m-%d'))]
+ },
+ 'this_quarter': {
+ 'label': _('This Quarter'),
+ 'domain': [
+ ('create_date', '>=',
+ this_quarter_start.strftime('%Y-%m-%d')),
+ ('create_date', '<=', today.strftime('%Y-%m-%d'))]
+ }
+ }
+
+ def _get_venue_booking_search_domain(self, search_in, search):
+ """Returns the events for the given search(If we have not entered
+ the full name which will also gives the output"""
+ search_domain = []
+ if search_in == 'all':
+ search_domain.append([('name', 'ilike',
+ f'{search}%')])
+ search_domain.append([('phone', 'ilike',
+ f'{search}%')])
+ if search_in in ('venue', 'all'):
+ search_domain.append([('venue_id', 'ilike',
+ f'{search}%')])
+ return OR(search_domain)
+
+ def _get_venue_booking_searchbar_inputs(self):
+ """Which will returns a dictionary of values by the search contents
+ as Search in All, in Content, Search in states, Search in Venues"""
+ values = {
+ 'all': {'input': 'all', 'label': _('Search in All'), 'order': 1},
+ 'venue': {'input': 'venue', 'label': _('Search in Venue'),
+ 'order': 2},
+ }
+ return dict(sorted(values.items(), key=lambda item: item[1]["order"]))
+
+ def _get_grouped_venues(self, Venue, domain, order, pager_offset, ):
+ """Returns the grouped venues for a given domain"""
+ venues = Venue.search(domain, order=order, limit=self._items_per_page,
+ offset=pager_offset)
+ return venues
+
+ @http.route(['/my/booking_data/'], type='http',
+ auth="user", website=True)
+ def portal_my_venue_booking(self, record):
+ """ Function to fetch data of selected visitors record and pass to
+ the portal template"""
+ booking_record = request.env['venue.booking'].sudo().browse(record)
+ return http.request.render(
+ 'venue_booking_management.booking_portal_form',
+ {'booking_record': booking_record,
+ 'page_name': 'venue_booking_management_record'})
diff --git a/venue_booking_management/controllers/venue_booking_management.py b/venue_booking_management/controllers/venue_booking_management.py
new file mode 100644
index 000000000..ad27d30c0
--- /dev/null
+++ b/venue_booking_management/controllers/venue_booking_management.py
@@ -0,0 +1,96 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (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 .
+#
+###############################################################################
+import json
+from odoo import fields, http
+from odoo.http import content_disposition, request
+from odoo.http import serialize_exception as _serialize_exception
+from odoo.tools import html_escape
+
+
+class XLSXReportController(http.Controller):
+ """Controller Class for xlsx report"""
+
+ @http.route('/venue_xlsx_reports', type='http', auth='user',
+ methods=['POST'])
+ def get_report_xlsx(self, model, options, output_format, report_name):
+ """Method for passing data to xlsx report"""
+ uid = request.session.uid
+ report_obj = request.env[model].with_user(uid)
+ options = json.loads(options)
+ try:
+ if output_format == 'xlsx':
+ response = request.make_response(
+ None,
+ headers=[('Content-Type', 'application/vnd.ms-excel'), (
+ 'Content-Disposition',
+ content_disposition(report_name + '.xlsx'))])
+ report_obj.get_xlsx_report(options, response)
+ return response
+ except Exception as err:
+ exception = _serialize_exception(err)
+ error = {
+ 'code': 200,
+ 'message': 'Odoo Server Error',
+ 'data': exception
+ }
+ return request.make_response(html_escape(json.dumps(error)))
+
+
+class VenueBookingController(http.Controller):
+ """Class to add Venue booking menu in website"""
+
+ @http.route('/venue/booking', type='http', auth='public', website=True)
+ def venue_booking(self):
+ """Function to render venue booking values to XML"""
+ venue_ids = request.env['venue'].sudo().search([])
+ state_ids = request.env['res.country.state'].sudo().search([])
+ country_ids = request.env['res.country'].sudo().search([])
+ return http.request.render(
+ 'venue_booking_management.venue_booking_page',
+ {'venue_ids': venue_ids,
+ 'state_ids': state_ids,
+ 'country_ids': country_ids})
+
+ @http.route('/booking/submit', type='http', auth='public', website=True)
+ def booking_success_page(self, **post):
+ """Function to create booking and return to success page"""
+ partner_id = request.env['res.partner'].sudo().create({
+ 'name': post.get('name'),
+ 'mobile': post.get('mobile_no'),
+ 'city': post.get('city'),
+ 'state_id': post.get('state'),
+ 'country_id': post.get('country')
+ })
+ venue_id = request.env['venue'].browse(int(post.get('venue_type')))
+ values = {
+ 'partner_id': partner_id.id,
+ 'venue_id': venue_id.id,
+ 'start_date': post.get('from_date'),
+ 'end_date': post.get('to_date'),
+ 'booking_type': post.get('booking_type'),
+ 'date': fields.Date.today()
+ }
+ booking_id = request.env['venue.booking'].sudo().create(values)
+ return request.render(
+ 'venue_booking_management.venue_booking_success_page',
+ {'partner_id': partner_id,
+ 'booking_id': booking_id})
diff --git a/venue_booking_management/data/confirmation_email_template_data.xml b/venue_booking_management/data/confirmation_email_template_data.xml
new file mode 100644
index 000000000..b24100844
--- /dev/null
+++ b/venue_booking_management/data/confirmation_email_template_data.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+ Confirmed Venue Booking
+ Venue booking: Received the Venue Booking for
+ {{ object.venue_id.name }}
+
+
+ {{ (object.env.user.login) }}
+
+
+
+ Dear customer ,
+ We have received a booking for the venue
+ . Please proceed
+ with necessary actions.
+
+ Thank You
+
+ ]]>
+
+ {{ object.partner_id.lang or '' }}
+
+
+
+
diff --git a/venue_booking_management/data/venue_type_data.xml b/venue_booking_management/data/venue_type_data.xml
new file mode 100644
index 000000000..2d5d10601
--- /dev/null
+++ b/venue_booking_management/data/venue_type_data.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+ Conference centers
+
+
+
+ Meeting Room
+
+
+
+ Convention centers
+
+
+
+ Social clubs and lounges
+
+
+
+ Mini Conference centers
+
+
+
+ Stadiums
+
+
+
+ Community centers
+
+
+
+ Resorts
+
+
+
+ Auditorium
+
+
+
+
+ Venue Booking
+ venue.booking.sequence
+ %(day)s/%(month)s/%(year)s
+ VENUE-
+ 1
+ 3
+
+
+
diff --git a/venue_booking_management/doc/RELEASE_NOTES.md b/venue_booking_management/doc/RELEASE_NOTES.md
new file mode 100644
index 000000000..68def998b
--- /dev/null
+++ b/venue_booking_management/doc/RELEASE_NOTES.md
@@ -0,0 +1,5 @@
+## Module
+#### 23.01.2024
+#### Version 17.0.1.0.0
+#### ADD
+- Initial Commit for Venue / Event Booking Management
diff --git a/venue_booking_management/models/__init__.py b/venue_booking_management/models/__init__.py
new file mode 100644
index 000000000..b649a37bf
--- /dev/null
+++ b/venue_booking_management/models/__init__.py
@@ -0,0 +1,28 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (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 .
+#
+###############################################################################
+from . import amenities
+from . import res_config_settings
+from . import venue
+from . import venue_booking
+from . import venue_booking_line
+from . import venue_lines
+from . import venue_type
diff --git a/venue_booking_management/models/amenities.py b/venue_booking_management/models/amenities.py
new file mode 100644
index 000000000..84a0bcd76
--- /dev/null
+++ b/venue_booking_management/models/amenities.py
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (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 FITNproduct_id.ESS 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 .
+#
+###############################################################################
+from odoo import fields, models
+
+
+class Amenities(models.Model):
+ """Model for managing the Amenities"""
+ _name = 'amenities'
+ _inherit = ['mail.thread', 'mail.activity.mixin']
+ _description = 'Amenities'
+
+ name = fields.Char(string="Name", help="Name of the Amenities")
+ amount = fields.Float(string='Amount', help="Amount of the Amenities")
diff --git a/venue_booking_management/models/res_config_settings.py b/venue_booking_management/models/res_config_settings.py
new file mode 100644
index 000000000..a8d7caf70
--- /dev/null
+++ b/venue_booking_management/models/res_config_settings.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+#############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions()
+#
+# You can modify it under the terms of the GNU LESSER
+# GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details.
+#
+# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE
+# (LGPL v3) along with this program.
+# If not, see .
+#
+#############################################################################
+from odoo import fields, models
+
+
+class ResConfigSettings(models.TransientModel):
+ """Inherit the model res.config.settings to add Additional fields"""
+ _inherit = 'res.config.settings'
+
+ is_extra = fields.Boolean(string='Apply Extra Amount',
+ config_parameter='venue_booking_management.is_extra',
+ help="Enable, if extra charge want to add")
+ extra_amount = fields.Float(string='Extra Amount',
+ config_parameter='venue_booking_management.extra_amount',
+ help='Enter extra amount/KM')
diff --git a/venue_booking_management/models/venue.py b/venue_booking_management/models/venue.py
new file mode 100644
index 000000000..f3ed22d64
--- /dev/null
+++ b/venue_booking_management/models/venue.py
@@ -0,0 +1,87 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (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 .
+#
+###############################################################################
+from odoo import api, fields, models
+
+
+class Venue(models.Model):
+ """Model for managing the Venue that used to add new fields and
+ functions to create the Venue"""
+ _name = 'venue'
+ _inherit = ['mail.thread', 'mail.activity.mixin']
+ _description = 'Venue'
+
+ name = fields.Char(string="Name", help="Name of the venue type",
+ required=True)
+ image = fields.Binary(string="Image", attachment=True,
+ related="venue_type_id.image",
+ help="This field holds the image used as "
+ "image for the event, limited to 1080x720px.")
+ venue_type_id = fields.Many2one('venue.type',
+ string='Venue Type', required=True,
+ help='Used to choose the type of the '
+ 'particular venue')
+ venue_location = fields.Char(string='Location', required=True,
+ help='The venue location for Booking')
+ capacity = fields.Integer(string='Capacity',
+ help='The capacity of the venue')
+ seating = fields.Integer(string='Seating', help='The Seating of the venue')
+ venue_charge_hour = fields.Float(string='Charge Per Hour',
+ help='The charge per hour of the venue')
+ venue_charge_day = fields.Float(string='Charge Per Day',
+ help='The charge per day of the venue')
+ additional_charge_hour = fields.Float(string=' Additional Charge Per Hour',
+ help='The charge per hour of the '
+ 'venue')
+ additional_charge_day = fields.Float(string='Additional Charge Per Day',
+ help='The charge per day of the venue')
+ venue_count = fields.Integer(string="# of Events",
+ compute='_compute_venue_count',
+ help='Compute field for calculate the '
+ 'venue count')
+ open_time = fields.Float(string=' Open Time', help='Open time of the venue')
+ closed_time = fields.Float(string=' Close Time',
+ help='Close time of the venue')
+ venue_line_ids = fields.One2many('venue.lines',
+ 'venue_id', string='Amenities',
+ help='Amenities for the venue')
+ price_subtotal = fields.Float(string='Total',
+ help='Total price of the venue',
+ compute='_compute_price_subtotal',
+ readonly=True, store=True)
+
+ @api.depends('venue_line_ids', 'venue_line_ids.sub_total')
+ def _compute_price_subtotal(self):
+ """Compute function for calculating the Amenities Price Subtotal"""
+ self.price_subtotal = sum(
+ item.sub_total for item in self.venue_line_ids)
+
+ def _compute_venue_count(self):
+ """Compute function for calculating the venue count"""
+ for records in self:
+ venues = self.env['venue.booking'].search([
+ ('venue_id', '=', records.id)])
+ records.venue_count = len(venues)
+
+ def get_venue_type_action(self):
+ """Get the venue type action for the venue bookings"""
+ return self._get_action(
+ 'venue_booking_management.venue_booking_action_view_kanban')
diff --git a/venue_booking_management/models/venue_booking.py b/venue_booking_management/models/venue_booking.py
new file mode 100644
index 000000000..ee1e34877
--- /dev/null
+++ b/venue_booking_management/models/venue_booking.py
@@ -0,0 +1,489 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (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 .
+#
+###############################################################################
+from markupsafe import Markup
+
+from odoo import api, fields, models, _
+from odoo.exceptions import UserError, ValidationError
+
+
+class VenueBooking(models.Model):
+ """Model for managing the Venue Booking"""
+ _name = 'venue.booking'
+ _inherit = ['mail.thread', 'mail.activity.mixin']
+ _description = 'Venue Reservation'
+
+ name = fields.Char(string="Name", help="Name of the venue type")
+ ref = fields.Char(string='Ref', readonly=True,
+ help="Name of the venue that created as sequencing")
+ venue_id = fields.Many2one('venue', string='Venue',
+ help="Venue for the Event", required=True)
+ venue_type_id = fields.Many2one('venue.type',
+ string='Venue Type',
+ related='venue_id.venue_type_id',
+ readonly=True,
+ help='Used to choose the type of the '
+ 'particular venue')
+ image = fields.Binary(string="Image", attachment=True,
+ related='venue_type_id.image',
+ help="This field holds the image used as "
+ "image for the event, limited to 1080x720px.")
+ partner_id = fields.Many2one('res.partner', string="Customer",
+ required=True,
+ help='Used to Choose the Booking Person')
+ date = fields.Date(string="Date", default=fields.Date.today, required=True,
+ help='Date field for booking the Venue')
+ currency_id = fields.Many2one('res.currency', readonly=True,
+ string='Currency',
+ default=lambda self:
+ self.env.user.company_id.currency_id,
+ help='Currency field for booking Venue')
+ start_date = fields.Datetime(string="Start Date",
+ default=lambda self: fields.datetime.now(),
+ required=True,
+ help='Venue Booking Start Date')
+ end_date = fields.Datetime(string="End Date", required=True,
+ help='Venue Booking End Date')
+ state = fields.Selection([('draft', 'Draft'),
+ ('confirm', 'Confirmed'),
+ ('invoice', 'Invoiced'),
+ ('close', 'Close'), ('cancel', 'Canceled')],
+ string="State", default="draft",
+ help="State of venue booking")
+ booking_type = fields.Selection([('day', 'Day'),
+ ('hour', 'Hours')], string='Booking Type',
+ default='day',
+ help='The selection field for Booking Type')
+ venue_booking_line_ids = fields.One2many('venue.booking.line',
+ 'venue_booking_id',
+ string="Venues",
+ help='Booking Line for the '
+ 'given venue')
+ note = fields.Text(string='Terms and Conditions',
+ help='The note field for Venue Booking')
+ pending_invoice = fields.Boolean(string="Invoice Pending",
+ compute='_compute_pending_invoice',
+ help='Find out is there any pending '
+ 'invoice')
+ total = fields.Monetary(string="Total Amount", store=True,
+ compute='_compute_total_amount',
+ help='Total amount for the Venue Booking')
+ booking_charge_per_day = fields.Float(string="Booking Charge Per Day",
+ related='venue_id.venue_charge_day',
+ help='Field for adding Booking '
+ 'Charge Per Day')
+ booking_charge_per_hour = fields.Float(string="Booking Charge Per Hour",
+ related='venue_id.venue_charge_hour',
+ help='Field for adding Booking '
+ 'Charge Per hour')
+ booking_charge = fields.Float(string="Venue Amenities Charge",
+ compute='_compute_booking_charge',
+ help='Compute the total Booking cost '
+ 'includes the amenities')
+ days_difference = fields.Integer(string='Days Difference',
+ compute='_compute_days_difference',
+ help='Number of Days to Booking the venue')
+ invoice_count = fields.Integer(string="Invoice Count",
+ compute='_compute_invoice_count',
+ help='Total invoice count')
+ is_additional_charge = fields.Boolean(string="Add Extra Charge?",
+ help='Add additional charge '
+ 'for the booking')
+ is_extra_check = fields.Boolean(string="Checks Additional Charges",
+ help='Checks additional charge '
+ 'is enabled on settings',
+ default=lambda self: self.env[
+ 'ir.config_parameter'].sudo().get_param(
+ 'venue_booking_management.is_extra'))
+ amenity_line_ids = fields.One2many('venue.booking.line',
+ 'venue_booking_id',
+ string="Included Amenities",
+ help='Booking Line for the given venue')
+
+ @api.constrains('venue_booking_line_ids')
+ def _check_venue_booking_line_ids(self):
+ """Check if the venue bookings line contains already taken amenities"""
+ amenities_list = []
+ name_list = []
+ if self.venue_id.venue_line_ids:
+ amenities = self.venue_id.venue_line_ids.mapped('amenities_id')
+ for line in self.venue_booking_line_ids:
+ if line.amenity_id in amenities:
+ amenities_list.append(line.amenity_id)
+ name_list.append(line.amenity_id.name)
+ if amenities_list:
+ names = ', '.join(name_list)
+ raise ValidationError(
+ _("Amenities %s are already Include in Your Venue Booking %s"
+ % (str(names), str(self.venue_id.name))))
+
+ @api.model
+ def create(self, values):
+ """Create method for sequencing and checking dates while Booking the
+ Venues"""
+ partner_name = self.env['res.partner'].browse(
+ values['partner_id']).name
+ if values['start_date'] >= values['end_date']:
+ raise UserError(_('Start date must be less than End date'))
+ values['name'] = '%s- %s' % (partner_name, values['date'])
+ values['ref'] = self.env['ir.sequence'].next_by_code(
+ 'venue.booking.sequence')
+ res = super().create(values)
+ return res
+
+ @api.onchange('start_date', 'end_date')
+ def _onchange_booking_dates(self):
+ """Checking dates while Booking the Venues based on the changes
+ of the Dates"""
+ if self.venue_id:
+ booking = self.env['venue.booking'].search(
+ [('start_date', '<', self.end_date),
+ ('end_date', '>', self.start_date),
+ ('venue_id', '=', self.venue_id.id)])
+ if booking:
+ raise ValidationError(
+ "Venue is not available for the selected time range.")
+
+ @api.depends('start_date', 'end_date')
+ def _compute_days_difference(self):
+ """Compute the difference between start and end dates for
+ Calculating the days"""
+ for record in self:
+ if record.start_date and record.end_date:
+ delta = record.end_date - record.start_date
+ record.days_difference = delta.days
+ else:
+ record.days_difference = 0
+
+ @api.depends('booking_charge', 'venue_id')
+ def _compute_booking_charge(self):
+ """Compute booking charge for the given venue with the Amenities"""
+ for rec in self:
+ rec.booking_charge = rec.venue_id.price_subtotal if rec.venue_id else 0.0
+
+ @api.depends('venue_booking_line_ids', 'venue_booking_line_ids.state')
+ def _compute_pending_invoice(self):
+ """Compute function for finding the pending Invoices"""
+ for pending in self:
+ pending.pending_invoice = any(
+ not line.is_invoiced and line.state == "done" for line in
+ pending.venue_booking_line_ids)
+
+ @api.depends('venue_booking_line_ids.sub_total', 'booking_charge_per_hour',
+ 'booking_charge_per_day')
+ def _compute_total_amount(self):
+ """Compute total amount of bookings with the Charge of the Particular
+ venue"""
+ total = sum(item.sub_total for item in self.venue_booking_line_ids)
+ for rec in self:
+ if rec.booking_type == 'day':
+ total += (rec.booking_charge_per_day * rec.days_difference)
+ if rec.venue_id.additional_charge_day != 0.0:
+ total += rec.venue_id.additional_charge_day
+ elif rec.booking_type == 'hour':
+ total += (rec.booking_charge_per_hour * rec.days_difference)
+ if rec.venue_id.additional_charge_hour != 0.0:
+ total += rec.venue_id.additional_charge_hour
+ rec.total = total + rec.booking_charge
+
+ @api.constrains('start_date', 'end_date', 'venue_id')
+ def check_date_overlap(self):
+ """Check the date overlap between the start and end dates"""
+ for booking in self:
+ overlapping_bookings = self.env['venue.booking'].search([
+ ('venue_id', '=', booking.venue_id.id),
+ ('start_date', '<', booking.end_date),
+ ('end_date', '>', booking.start_date),
+ ('id', '!=', booking.id), # Exclude the current record itself
+ ])
+ if overlapping_bookings:
+ raise ValidationError(
+ "Booking dates overlap with existing bookings.")
+
+ def action_booking_confirm(self):
+ """Button action to confirm"""
+ for booking in self:
+ bookings = self.env['venue.booking'].search([
+ ('venue_id', '=', booking.venue_id.id),
+ ('start_date', '<', booking.end_date),
+ ('end_date', '>', booking.start_date),
+ ('id', '!=', booking.id), # Exclude the current record itself
+ ])
+ if bookings:
+ raise ValidationError(
+ "Booking dates overlap with existing bookings.")
+ else:
+ self.state = "confirm"
+
+ def action_reset_to_draft(self):
+ """Button action to reset"""
+ self.state = "draft"
+
+ def action_send_confirmation_mail(self):
+ """Button action to send confirmation mail"""
+ template = self.env.ref(
+ 'venue_booking_management.mail_template_notify_venue_booking').sudo()
+ template.send_mail(self._origin.id, force_send=True,
+ email_values={
+ 'email_to': self.partner_id.email})
+ for rec in self:
+ body = Markup(
+ "%(greeting)s
%(content)s
%(conclude)s
") % {
+ 'greeting': _("Dear %s", rec.partner_id.name),
+ 'content': _(
+ "We have received a booking for the venue %s.Please proceed with necessary actions.",
+ rec.venue_id.name),
+ 'conclude': _('Thank You'),
+ }
+ rec.message_post(body=body)
+
+ def action_booking_invoice_create(self):
+ """Button action to create related invoice"""
+ invoice_id = self.env['account.move'].search(
+ [('invoice_origin', '=', self.ref), ('state', '=', 'draft')])
+ amenity_lists = []
+
+ def add_charge(name, price_unit, quantity=1):
+ amenity_lists.append({
+ 'name': name,
+ 'price_unit': price_unit,
+ 'quantity': quantity,
+ })
+
+ if self.booking_type == 'day':
+ total = self.booking_charge_per_day + self.venue_id.additional_charge_day
+ elif self.booking_type == 'hour':
+ total = self.booking_charge_per_hour + self.venue_id.additional_charge_hour
+ else:
+ total = 0
+ add_charge('Amenities charge', self.booking_charge)
+ add_charge('Booking Charges', total)
+ for rec in self.venue_booking_line_ids:
+ add_charge(rec.amenity_id.name, rec.amount, rec.quantity)
+ if self.is_additional_charge:
+ is_extra = self.env['ir.config_parameter'].sudo(). \
+ get_param('venue_booking_management.is_extra')
+ if is_extra:
+ amount = self.env['ir.config_parameter'].sudo(). \
+ get_param('venue_booking_management.extra_amount')
+ amenity_lists.append({
+ 'name': 'Extra charges',
+ 'price_unit': amount,
+ 'quantity': '1',
+ })
+ invoice_vals = {
+ 'move_type': 'out_invoice',
+ 'partner_id': self.partner_id.id,
+ 'invoice_origin': self.ref,
+ 'invoice_line_ids': [(0, 0, line) for line in amenity_lists],
+ }
+ if not invoice_id:
+ invoice = self.env['account.move'].create([invoice_vals])
+ self.state = "invoice"
+ return {
+ 'name': 'Invoice',
+ 'view_mode': 'form',
+ 'res_id': invoice.id,
+ 'res_model': 'account.move',
+ 'type': 'ir.actions.act_window',
+ 'target': 'current',
+ }
+ else:
+ # Unlink existing lines
+ invoice_id.invoice_line_ids.unlink()
+ invoice_id.write(
+ {'invoice_line_ids': [(0, 0, line) for line in amenity_lists]})
+ self.state = "invoice"
+ return {
+ 'name': 'Invoice',
+ 'view_mode': 'form',
+ 'res_id': invoice_id.id,
+ 'res_model': 'account.move',
+ 'type': 'ir.actions.act_window',
+ 'target': 'current',
+ }
+
+ def action_view_invoice(self):
+ """Smart button to view the Corresponding Invoices for the
+ Venue Booking"""
+ return {
+ 'type': 'ir.actions.act_window',
+ 'name': 'Invoice',
+ 'view_mode': 'tree,form',
+ 'res_model': 'account.move',
+ 'target': 'current',
+ 'domain': [('invoice_origin', '=', self.ref)],
+ 'context': {"create": False},
+ }
+
+ def _compute_invoice_count(self):
+ """Function to count invoice"""
+ for record in self:
+ record.invoice_count = self.env['account.move']. \
+ search_count([('invoice_origin', '=', self.ref)])
+
+ def action_booking_cancel(self):
+ """Button action to move the cancel state"""
+ self.state = "cancel"
+
+ def action_booking_close(self):
+ """Button action to close the records"""
+ if any(not line.is_invoiced for line in self.venue_booking_line_ids):
+ raise ValidationError(_('You can close The Booking only when all '
+ 'Procedure is Done and Invoiced'))
+ else:
+ self.state = "close"
+
+ @api.model
+ def get_total_booking(self):
+ """Function to get total booking, distance and invoice amount details"""
+ total_booking = self.env['venue.booking'].search_count([])
+ booking_ids = self.env['venue.booking'].search(
+ [('state', 'not in', ['draft', 'cancel', 'close'])])
+ invoice_ids = self.env['venue.booking']. \
+ search([('state', '=', 'invoice')]).mapped('total')
+ venue_ids = self.env['venue'].search_count([])
+ return {'total_booking': total_booking,
+ 'total_invoice': sum(invoice_ids),
+ 'total_amount': sum(booking_ids.mapped('total')),
+ 'total_venue': venue_ids}
+
+ @api.model
+ def get_top_venue(self):
+ """Function to return top venue and customer details query to js"""
+ self.env.cr.execute('''select fv.name,count(tb.name) from venue_booking as tb
+ inner join venue as fv on fv.id = tb.venue_id
+ group by fv.name order by count(tb.name) desc limit 10''')
+ venue = self.env.cr.dictfetchall()
+ self.env.cr.execute('''select pr.name,count(tb.name) from venue_booking as tb
+ inner join res_partner as pr on pr.id = tb.partner_id
+ group by pr.name order by count(tb.name) desc limit 10''')
+ customer = self.env.cr.dictfetchall()
+ self.env.cr.execute('''select tb.ref, pr.name, tb.date from
+ venue_booking as tb
+ inner join res_partner as pr on pr.id = tb.partner_id
+ where tb.date >= '%s' and tb.state = 'invoice'
+ order by tb.date''' % fields.date.today())
+ upcoming = self.env.cr.dictfetchall()
+ return {'venue': venue, 'customer': customer, 'upcoming': upcoming}
+
+ @api.model
+ def get_booking_analysis(self):
+ """Function to return customer details to js for graph view"""
+ self.env.cr.execute('''select pr.name,sum(tb.total) from venue_booking as tb
+ inner join res_partner as pr on pr.id = tb.partner_id
+ group by pr.name order by sum(tb.total)''')
+ booking = self.env.cr.dictfetchall()
+ count = []
+ customer = []
+ for record in booking:
+ customer.append(record.get('name'))
+ count.append(record.get('sum'))
+ value = {'name': customer, 'count': count}
+ return value
+
+ @api.model
+ def get_venue_analysis(self):
+ """Function to return truck details to js for graph view"""
+ self.env.cr.execute('''select fv.name,sum(tb.total) from venue_booking as tb
+ inner join venue as fv on fv.id = tb.venue_id
+ group by fv.name order by sum(tb.total)''')
+ booking = self.env.cr.dictfetchall()
+ count = []
+ customer = []
+ for record in booking:
+ customer.append(record.get('name'))
+ count.append(record.get('sum'))
+ return {'name': customer, 'count': count}
+
+ @api.model
+ def get_select_filter(self, option):
+ """Function to filter data on the bases of the year"""
+ if option == 'year':
+ create_date = '''create_date between (now() - interval '1 year') and now()'''
+ elif option == 'month':
+ create_date = '''create_date between (now() - interval '1 months') and now()'''
+ elif option == 'week':
+ create_date = '''create_date between (now() - interval '7 day') and now()'''
+ elif option == 'day':
+ create_date = '''create_date between (now() - interval '1 day') and now()'''
+ self.env.cr.execute('''select count(*) from venue_booking
+ where %s''' % create_date)
+ booking = self.env.cr.dictfetchall()
+ self.env.cr.execute('''select sum(total) from venue_booking
+ where %s''' % create_date)
+ amount = self.env.cr.dictfetchall()
+ self.env.cr.execute('''select sum(total) from venue_booking
+ where state = 'invoice' and %s''' % create_date)
+ invoice = self.env.cr.dictfetchall()
+ self.env.cr.execute('''select count(*) from venue
+ where %s''' % create_date)
+ venue_count = self.env.cr.dictfetchall()
+ self.env.cr.execute('''SELECT fv.name, COUNT(tb.name) AS name_count
+ FROM venue_booking AS tb
+ INNER JOIN venue AS fv ON fv.id = tb.venue_id
+ where tb.%s
+ GROUP BY fv.name
+ ORDER BY name_count DESC
+ LIMIT 10''' % create_date)
+ venue = self.env.cr.dictfetchall()
+ self.env.cr.execute('''SELECT pr.name, COUNT(tb.name) AS name_count
+ FROM venue_booking AS tb
+ INNER JOIN res_partner AS pr ON pr.id = tb.partner_id
+ where tb.%s
+ GROUP BY pr.name
+ ORDER BY name_count DESC
+ LIMIT 10''' % create_date)
+ customer = self.env.cr.dictfetchall()
+ self.env.cr.execute('''SELECT pr.name, COUNT(pr.name) AS count, SUM(tb.total) AS total_sum
+ FROM venue_booking AS tb
+ INNER JOIN res_partner AS pr ON pr.id = tb.partner_id
+ WHERE tb.%s
+ GROUP BY pr.name
+ ''' % create_date)
+ cust_invoice = self.env.cr.dictfetchall()
+ cust_invoice_name = []
+ cust_invoice_sum = []
+ cust_invoice_count = []
+ for record in cust_invoice:
+ cust_invoice_name.append(record.get('name'))
+ cust_invoice_count.append(record.get('count'))
+ cust_invoice_sum.append(record.get('sum'))
+ self.env.cr.execute('''SELECT fv.name, SUM(tb.total) AS total_sum
+ FROM venue_booking AS tb
+ INNER JOIN venue AS fv ON fv.id = tb.venue_id
+ where tb.%s
+ GROUP BY fv.name;
+ ''' % create_date)
+ truck_invoice = self.env.cr.dictfetchall()
+ truck_invoice_name = []
+ truck_invoice_sum = []
+ for record in truck_invoice:
+ truck_invoice_name.append(record.get('name'))
+ truck_invoice_sum.append(record.get('total_sum'))
+ return {'booking': booking, 'amount': amount,
+ 'invoice': invoice, 'venue': venue, 'venue_count': venue_count,
+ 'customer': customer,
+ 'cust_invoice_name': cust_invoice_name,
+ 'cust_invoice_count': cust_invoice_count, 'cust_invoice_sum':
+ cust_invoice_sum, 'truck_invoice_name': truck_invoice_name,
+ 'truck_invoice_sum': truck_invoice_sum,
+ }
diff --git a/venue_booking_management/models/venue_booking_line.py b/venue_booking_management/models/venue_booking_line.py
new file mode 100644
index 000000000..056616339
--- /dev/null
+++ b/venue_booking_management/models/venue_booking_line.py
@@ -0,0 +1,65 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (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 .
+#
+###############################################################################
+from odoo import api, fields, models
+
+
+class VenueBookingLine(models.Model):
+ """Model to manage the Venue Booking lines of the Venue Reservation"""
+ _name = 'venue.booking.line'
+ _description = "Venue Booking"
+
+ venue_booking_id = fields.Many2one('venue.booking',
+ string="Venue Booking",
+ help='The relation added for the venue '
+ 'Booking ')
+ state = fields.Selection([('done', 'Done'), ('pending', 'Pending')],
+ string="State", default="pending",
+ readonly=True,
+ help="The state of the venue Booking line")
+ currency_id = fields.Many2one('res.currency', readonly=True,
+ default=lambda self:
+ self.env.user.company_id.currency_id,
+ string="Currency",
+ help="The currency of the booking line")
+ is_invoiced = fields.Boolean(string="Invoiced", readonly=True,
+ help="The boolean value used for finding the "
+ "venue booking is invoiced or not")
+ venue_type_id = fields.Many2one('venue.type',
+ string="Related Venue Type",
+ related='venue_booking_id.venue_type_id',
+ help="The venue type of the booking line")
+ amenity_id = fields.Many2one('amenities', string='Amenities',
+ help='The relational field for the booking '
+ 'line with the amenities model')
+ quantity = fields.Float(string="Quantity", default=1,
+ help="Quantity of the Amenities")
+ amount = fields.Float(string="Amount", help="Amount of the Amenities",
+ related='amenity_id.amount')
+ sub_total = fields.Float(string="Sub Total",
+ compute="_compute_extra_sub_total",
+ readonly=True, help="Sub Total of the Values")
+
+ @api.depends('quantity', 'amount')
+ def _compute_extra_sub_total(self):
+ """Compute function for the Amenities"""
+ for booking in self:
+ booking.sub_total = booking.quantity * booking.amount
diff --git a/venue_booking_management/models/venue_lines.py b/venue_booking_management/models/venue_lines.py
new file mode 100644
index 000000000..a0812ce6f
--- /dev/null
+++ b/venue_booking_management/models/venue_lines.py
@@ -0,0 +1,54 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (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 .
+#
+###############################################################################
+from odoo import api, fields, models
+
+
+class VenueLines(models.Model):
+ """Model for managing the Venue lines"""
+ _name = 'venue.lines'
+ _description = 'Venue Lines'
+
+ venue_id = fields.Many2one('venue', string='Venue Lines',
+ help='The relational field for the venue model')
+ amenities_id = fields.Many2one('amenities', string='Amenities',
+ help='The field used to link the '
+ 'amenities model')
+ quantity = fields.Float(string="Quantity", default=1,
+ help="Quantity of the Amenities")
+ amount = fields.Float(string="Amount", help="Amount of the Amenities",
+ related='amenities_id.amount')
+ sub_total = fields.Float(string="Subtotal", compute="_compute_sub_total",
+ readonly=True, help="Sub Total of the Values")
+ currency_id = fields.Many2one('res.currency', readonly=True,
+ string='Currency',
+ default=lambda self:
+ self.env.user.company_id.currency_id,
+ help="Currency value of the Venue")
+ status = fields.Selection([('open', 'Open'), ('done', 'Done')],
+ string="Status", default='open',
+ help="Status of the Venue")
+
+ @api.depends('quantity', 'amount')
+ def _compute_sub_total(self):
+ """Compute the Sub Total of the Venue values"""
+ for item in self:
+ item.sub_total = item.quantity * item.amount
diff --git a/venue_booking_management/models/venue_type.py b/venue_booking_management/models/venue_type.py
new file mode 100644
index 000000000..8a594e319
--- /dev/null
+++ b/venue_booking_management/models/venue_type.py
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (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 .
+#
+###############################################################################
+from odoo import fields, models
+
+
+class VenueType(models.Model):
+ """Model for managing the Venue types"""
+ _name = 'venue.type'
+ _description = 'Venue Type'
+
+ name = fields.Char(string="Name", help="Name of the venue type")
+ image = fields.Binary(string="Image", attachment=True,
+ help="This field holds the image used as "
+ "image for the event, limited to 1080x720px.")
diff --git a/venue_booking_management/report/__init__.py b/venue_booking_management/report/__init__.py
new file mode 100644
index 000000000..3ffd37d69
--- /dev/null
+++ b/venue_booking_management/report/__init__.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (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 .
+#
+###############################################################################
+from . import form_venue_booking_report
+from . import venue_booking_report
diff --git a/venue_booking_management/report/form_venue_booking_report.py b/venue_booking_management/report/form_venue_booking_report.py
new file mode 100644
index 000000000..850fc65b6
--- /dev/null
+++ b/venue_booking_management/report/form_venue_booking_report.py
@@ -0,0 +1,80 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (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 .
+#
+###############################################################################
+import pytz
+
+from odoo import api, fields, models
+from odoo.exceptions import ValidationError
+
+
+class VenueBookingReport(models.AbstractModel):
+ """Class is used to print pdf report for the venue_booking module
+ form view"""
+ _name = 'report.venue_booking_management.report_venue_booking'
+
+ @api.model
+ def _get_report_values(self, docids, data=None):
+ """Function to return values for the report,
+ docids: it will provide the current id the model"""
+ current = fields.datetime.now().astimezone(
+ pytz.timezone(self.env.user.tz))
+ current = current.strftime("%d-%m-%Y %H:%M:%S")
+ if docids:
+ doc_ids = self.env['venue.booking'].sudo().browse(docids)
+ return {
+ 'doc_ids': doc_ids,
+ 'today_date': current,
+ }
+ else:
+ form_data = data['form']
+ # Initialize the SQL WHERE clause
+ where = '1=1'
+ # Check if the start_date is greater than end_date
+ if form_data['start_date'] and form_data['end_date'] and form_data[
+ 'start_date'] > form_data['end_date']:
+ raise ValidationError('Start Date must be less than End Date')
+ # Add conditions to the WHERE clause based on form data
+ if form_data["partner_id"]:
+ where += """ AND tb.partner_id = %s""" % \
+ form_data['partner_id'][0]
+ if form_data['start_date']:
+ where += """ AND tb.date >= '%s'""" % form_data['start_date']
+ if form_data['end_date']:
+ where += """ AND tb.date <= '%s'""" % form_data['end_date']
+ if form_data['venue_id']:
+ where += """ AND tb.venue_id = %s""" % form_data['venue_id'][0]
+ # Execute the SQL query with the WHERE clause
+ self.env.cr.execute("""
+ SELECT tb.ref, pr.name, fv.name as venue, tb.booking_type,
+ tb.date, tb.start_date, tb.end_date, tb.state
+ FROM venue_booking as tb
+ INNER JOIN res_partner as pr ON pr.id = tb.partner_id
+ INNER JOIN venue as fv ON fv.id = tb.venue_id
+ WHERE %s
+ """ % where)
+ # Fetch the query results
+ rec = self.env.cr.dictfetchall()
+ # Return the data for the report
+ return {
+ 'docs': rec,
+ 'docs2': form_data,
+ 'today_date': current,
+ }
diff --git a/venue_booking_management/report/venue_booking_report.py b/venue_booking_management/report/venue_booking_report.py
new file mode 100644
index 000000000..b061558a2
--- /dev/null
+++ b/venue_booking_management/report/venue_booking_report.py
@@ -0,0 +1,73 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# Author: Cybrosys Techno Solutions (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 .
+#
+###############################################################################
+from odoo import fields, models, tools
+
+
+class VenueBookingReport(models.Model):
+ _name = "venue.booking.report"
+ _description = "Venue Booking Analysis Report"
+ _auto = False
+ _rec_name = 'date'
+ _order = 'date desc'
+
+ name = fields.Char(string='Booking Reference', readonly=True,
+ help="Booking Reference field for the Reporting")
+ date = fields.Datetime(string='Booking Date', readonly=True,
+ help="Booking Date field for the Reporting")
+ partner_id = fields.Many2one('res.partner',
+ string='Customer', readonly=True,
+ help="Partner ID field for the Reporting")
+ total = fields.Float(string='Total', readonly=True,
+ help="Total amount for the Booking Values")
+ state = fields.Selection([
+ ('draft', 'Enquiry'),
+ ('confirm', 'Confirmed'),
+ ('invoice', 'Invoiced'),
+ ('close', 'Closed'),
+ ('cancel', 'Cancelled'),
+ ], string='Status', readonly=True,
+ help="The selection field for the Booking")
+
+ def init(self):
+ """Initialize the function to get the Booking Details"""
+ tools.drop_view_if_exists(self._cr, self._table)
+ self._cr.execute("""
+ CREATE OR REPLACE VIEW %s AS (
+ SELECT
+ vb.id as id,
+ vb.name as name,
+ vb.date as date,
+ vb.partner_id as partner_id,
+ vb.total as total,
+ vb.state as state
+ FROM venue_booking vb
+ WHERE vb.state IN ('confirm', 'invoice')
+ GROUP BY
+ vb.id,
+ vb.name,
+ vb.date,
+ vb.partner_id,
+ vb.total,
+ vb.state
+ ORDER BY vb.id
+ )
+ """ % (self._table,))
diff --git a/venue_booking_management/report/venue_booking_report_templates.xml b/venue_booking_management/report/venue_booking_report_templates.xml
new file mode 100644
index 000000000..0c4c6509d
--- /dev/null
+++ b/venue_booking_management/report/venue_booking_report_templates.xml
@@ -0,0 +1,186 @@
+
+
+
+
+
+
+
+
+
+
+
+ Venue/Event Booking Report
+
+
+
+
+
+
+ Date:
+
+
+
+
+
+
+ From:
+
+
+
+ To:
+
+
+
+
+
+ Customer:
+
+
+
+
+
+ Venue:
+
+
+
+
+
+
+
+
+ Sl.no |
+ Ref.No |
+ Venue |
+ Booking Type |
+ Customer |
+ Start Date |
+ End Date |
+ State |
+
+
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+ From:
+
+
+
+ To:
+
+
+
+
+
+ Customer:
+
+
+
+
+
+ Venue:
+
+
+
+
+
+
+
+
+
+
+ Sl.no |
+ Ref.No |
+ Venue |
+ Booking Type |
+ Customer |
+ Start Date |
+ End Date |
+ State |
+
+
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/venue_booking_management/report/venue_booking_report_views.xml b/venue_booking_management/report/venue_booking_report_views.xml
new file mode 100644
index 000000000..f58484296
--- /dev/null
+++ b/venue_booking_management/report/venue_booking_report_views.xml
@@ -0,0 +1,108 @@
+
+
+
+
+ venue.booking.report.view.pivot
+ venue.booking.report
+
+
+
+
+
+
+
+
+
+
+
+ venue.booking.report.view.graph
+ venue.booking.report
+
+
+
+
+
+
+
+
+
+
+ venue.booking.report.view.tree
+ venue.booking.report
+
+
+
+
+
+
+
+
+
+
+
+ venue.booking.report.view.search
+ venue.booking.report
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Venue Booking Analysis
+ venue.booking.report
+ graph,pivot
+
+ {'group_by_no_leaf':1,'group_by':[],
+ 'search_default_filter_order_date': 1}
+
+ This report performs analysis on your Venue
+ Booking.
+
+
+
+ Venue Booking Analysis
+ venue.booking.report
+ pivot
+
+
+
+
+
diff --git a/venue_booking_management/report/venue_booking_rerports.xml b/venue_booking_management/report/venue_booking_rerports.xml
new file mode 100644
index 000000000..3e8b8cba8
--- /dev/null
+++ b/venue_booking_management/report/venue_booking_rerports.xml
@@ -0,0 +1,18 @@
+
+
+
+
+ Venue Booking
+ venue.booking
+ qweb-pdf
+
+ venue_booking_management.report_venue_booking
+
+
+ venue_booking_management.report_venue_booking
+
+
+ report
+
+
diff --git a/venue_booking_management/security/ir.model.access.csv b/venue_booking_management/security/ir.model.access.csv
new file mode 100644
index 000000000..9fc24ff71
--- /dev/null
+++ b/venue_booking_management/security/ir.model.access.csv
@@ -0,0 +1,10 @@
+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
+access_venue_type_manager,access.venue.type.manager,model_venue_type,base.group_user,1,1,1,1
+access_venue_booking,access.venue.booking,model_venue_booking,base.group_user,1,1,1,1
+access_amenities,access.amenities,model_amenities,base.group_user,1,1,1,1
+access_venue,access.venue,model_venue,base.group_user,1,1,1,1
+access_venue_lines,access.venue.lines,model_venue_lines,base.group_user,1,1,1,1
+access_venue_booking_line,access.venue.booking.line,model_venue_booking_line,base.group_user,1,1,1,1
+access_check_venue_availability,access.check.venue.availability,model_check_venue_availability,base.group_user,1,1,1,1
+access_venue_booking_report,access.venue.booking.report,model_venue_booking_report,base.group_user,1,1,1,1
+access_venue_booking_analysis,access.venue.booking.analysis,model_venue_booking_analysis,base.group_user,1,1,1,1
diff --git a/venue_booking_management/security/venue_booking_management_groups.xml b/venue_booking_management/security/venue_booking_management_groups.xml
new file mode 100644
index 000000000..db391f355
--- /dev/null
+++ b/venue_booking_management/security/venue_booking_management_groups.xml
@@ -0,0 +1,22 @@
+
+
+
+ Venue Booking Management
+ Category for Venue Booking Management
+
+
+
+ User
+
+
+
+
+ Manager
+
+
+
+
+
diff --git a/venue_booking_management/security/venue_booking_secruity.xml b/venue_booking_management/security/venue_booking_secruity.xml
new file mode 100644
index 000000000..80211c1de
--- /dev/null
+++ b/venue_booking_management/security/venue_booking_secruity.xml
@@ -0,0 +1,22 @@
+
+
+
+
+ View Own Docs
+
+ ['|',('user_id', '=',
+ user.id),('create_uid',
+ '=', user.id)]
+
+
+
+
+
+ View All Docs
+
+ [(1, '=', 1)]
+
+
+
diff --git a/venue_booking_management/static/description/assets/icons/capture (1).png b/venue_booking_management/static/description/assets/icons/capture (1).png
new file mode 100644
index 0000000000000000000000000000000000000000..8824deafca0ae1d56fce83c80cc8ae543855dc68
GIT binary patch
literal 36623
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%0Au
z%R=EpfO{dHkP?j#k>1;E?4mg62PU6{5y_9<(3hwZ4v4dMjX!&+vWi7JuTNKBa~@5td