From 384860c79e4b33a6e891f4f65ae7596888f1b087 Mon Sep 17 00:00:00 2001
From: AjmalCybro
Date: Wed, 8 Jan 2025 16:29:59 +0530
Subject: [PATCH] Jan 01 [ADD] : Initial Commit 'venue_booking_management'
---
venue_booking_management/README.rst | 57 +
venue_booking_management/__init__.py | 25 +
venue_booking_management/__manifest__.py | 77 +
.../controllers/__init__.py | 23 +
.../controllers/portal.py | 260 +
.../controllers/venue_booking_management.py | 93 +
.../data/confirmation_email_template_data.xml | 30 +
.../data/venue_type_data.xml | 60 +
venue_booking_management/doc/RELEASE_NOTES.md | 7 +
venue_booking_management/models/__init__.py | 33 +
venue_booking_management/models/amenities.py | 32 +
.../models/res_config_settings.py | 35 +
venue_booking_management/models/venue.py | 119 +
.../models/venue_booking.py | 556 +
venue_booking_management/models/venue_type.py | 33 +
venue_booking_management/report/__init__.py | 23 +
.../report/form_venue_booking_report.py | 78 +
.../report/venue_booking_report.py | 73 +
.../report/venue_booking_report_templates.xml | 186 +
.../report/venue_booking_report_views.xml | 106 +
.../report/venue_booking_reports.xml | 13 +
.../security/ir.model.access.csv | 10 +
.../venue_booking_management_groups.xml | 21 +
.../security/venue_booking_secruity.xml | 20 +
.../description/assets/gif_screenshot.zip | Bin 0 -> 1066784 bytes
.../assets/gif_screenshot/venue_1.png | Bin 0 -> 88407 bytes
.../assets/gif_screenshot/venue_11.png | Bin 0 -> 37139 bytes
.../assets/gif_screenshot/venue_12.png | Bin 0 -> 92957 bytes
.../assets/gif_screenshot/venue_13.png | Bin 0 -> 87111 bytes
.../assets/gif_screenshot/venue_26.png | Bin 0 -> 110386 bytes
.../assets/gif_screenshot/venue_4.png | Bin 0 -> 229759 bytes
.../assets/gif_screenshot/venue_47.png | Bin 0 -> 180856 bytes
.../assets/gif_screenshot/venue_5.png | Bin 0 -> 109232 bytes
.../assets/gif_screenshot/venue_53.png | Bin 0 -> 86386 bytes
.../assets/gif_screenshot/venue_8.png | Bin 0 -> 70761 bytes
.../assets/gif_screenshot/venue_9.png | Bin 0 -> 35929 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
.../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
.../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/categories.png | Bin 0 -> 1532 bytes
.../description/assets/misc/check-box.png | Bin 0 -> 1118 bytes
.../description/assets/misc/compass.png | Bin 0 -> 1931 bytes
.../description/assets/misc/corporate.png | Bin 0 -> 1177 bytes
.../assets/misc/customer-support.png | Bin 0 -> 2136 bytes
.../description/assets/misc/cybrosys-logo.png | Bin 0 -> 4496 bytes
.../description/assets/misc/features.png | Bin 0 -> 589 bytes
.../static/description/assets/misc/logo.png | Bin 0 -> 3452 bytes
.../description/assets/misc/pictures.png | Bin 0 -> 1692 bytes
.../description/assets/misc/pie-chart.png | Bin 0 -> 2338 bytes
.../description/assets/misc/right-arrow.png | Bin 0 -> 967 bytes
.../static/description/assets/misc/star.png | Bin 0 -> 1642 bytes
.../description/assets/misc/support.png | Bin 0 -> 3892 bytes
.../description/assets/misc/whatsapp.png | Bin 0 -> 5097 bytes
.../modules/delivery_date_ecommerce.png | Bin 0 -> 58204 bytes
.../modules/openai_website_product_media.png | Bin 0 -> 83603 bytes
.../modules/product_brand_ecommerce.png | Bin 0 -> 59694 bytes
.../assets/modules/website_multi_variant.png | Bin 0 -> 60412 bytes
.../assets/modules/website_repeat_sale.png | Bin 0 -> 56902 bytes
.../wishlist_product_website_backend.png | Bin 0 -> 60727 bytes
.../static/description/assets/screenshots.zip | Bin 0 -> 3790653 bytes
.../assets/screenshots/dashboard.png | Bin 0 -> 78194 bytes
.../description/assets/screenshots/hero.gif | Bin 0 -> 248431 bytes
.../assets/screenshots/venue_1.png | Bin 0 -> 88407 bytes
.../assets/screenshots/venue_10.png | Bin 0 -> 101567 bytes
.../assets/screenshots/venue_11.png | Bin 0 -> 37139 bytes
.../assets/screenshots/venue_12.png | Bin 0 -> 92957 bytes
.../assets/screenshots/venue_13.png | Bin 0 -> 87111 bytes
.../assets/screenshots/venue_14.png | Bin 0 -> 111266 bytes
.../assets/screenshots/venue_15.png | Bin 0 -> 103795 bytes
.../assets/screenshots/venue_16.png | Bin 0 -> 112075 bytes
.../assets/screenshots/venue_17.png | Bin 0 -> 116714 bytes
.../assets/screenshots/venue_18.png | Bin 0 -> 113260 bytes
.../assets/screenshots/venue_2.png | Bin 0 -> 136700 bytes
.../assets/screenshots/venue_20.png | Bin 0 -> 100339 bytes
.../assets/screenshots/venue_21.png | Bin 0 -> 108557 bytes
.../assets/screenshots/venue_22.png | Bin 0 -> 127136 bytes
.../assets/screenshots/venue_23.png | Bin 0 -> 92644 bytes
.../assets/screenshots/venue_24.png | Bin 0 -> 98088 bytes
.../assets/screenshots/venue_25.png | Bin 0 -> 129690 bytes
.../assets/screenshots/venue_26.png | Bin 0 -> 110386 bytes
.../assets/screenshots/venue_27.png | Bin 0 -> 54227 bytes
.../assets/screenshots/venue_28.png | Bin 0 -> 68802 bytes
.../assets/screenshots/venue_29.png | Bin 0 -> 61503 bytes
.../assets/screenshots/venue_3.png | Bin 0 -> 84775 bytes
.../assets/screenshots/venue_30.png | Bin 0 -> 50348 bytes
.../assets/screenshots/venue_31.png | Bin 0 -> 50882 bytes
.../assets/screenshots/venue_32.png | Bin 0 -> 71940 bytes
.../assets/screenshots/venue_33.png | Bin 0 -> 87549 bytes
.../assets/screenshots/venue_36.png | Bin 0 -> 51098 bytes
.../assets/screenshots/venue_39.png | Bin 0 -> 56215 bytes
.../assets/screenshots/venue_4.png | Bin 0 -> 229759 bytes
.../assets/screenshots/venue_40.png | Bin 0 -> 85027 bytes
.../assets/screenshots/venue_41.png | Bin 0 -> 106156 bytes
.../assets/screenshots/venue_45.png | Bin 0 -> 48765 bytes
.../assets/screenshots/venue_47.png | Bin 0 -> 180856 bytes
.../assets/screenshots/venue_48.png | Bin 0 -> 154771 bytes
.../assets/screenshots/venue_49.png | Bin 0 -> 101325 bytes
.../assets/screenshots/venue_5.png | Bin 0 -> 109232 bytes
.../assets/screenshots/venue_50.png | Bin 0 -> 48897 bytes
.../assets/screenshots/venue_51.png | Bin 0 -> 62039 bytes
.../assets/screenshots/venue_52.png | Bin 0 -> 42855 bytes
.../assets/screenshots/venue_53.png | Bin 0 -> 86386 bytes
.../assets/screenshots/venue_54.png | Bin 0 -> 96356 bytes
.../assets/screenshots/venue_6.png | Bin 0 -> 54802 bytes
.../assets/screenshots/venue_7.png | Bin 0 -> 44264 bytes
.../assets/screenshots/venue_8.png | Bin 0 -> 70761 bytes
.../assets/screenshots/venue_9.png | Bin 0 -> 35929 bytes
.../static/description/banner.png | Bin 0 -> 49524 bytes
.../static/description/icon.png | Bin 0 -> 8159 bytes
.../static/description/index.html | 993 +
.../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 | 115 +
.../static/src/css/website_page.css | 90 +
.../static/src/js/action_manager.js | 20 +
.../static/src/js/dashboard_action.js | 336 +
.../static/src/js/lib/chart_bundle.js | 19287 ++++++++++++++++
.../static/src/js/website_venue_booking.js | 73 +
.../static/src/scss/venue_booking.scss | 237 +
.../static/src/xml/dashboard_templates.xml | 262 +
.../views/amenities_views.xml | 52 +
.../views/dashboard_views.xml | 79 +
.../views/res_config_settings_views.xml | 52 +
.../views/res_partner_views.xml | 8 +
.../views/venue_booking_views.xml | 282 +
.../views/venue_type_views.xml | 51 +
.../views/venue_views.xml | 119 +
.../views/website_portal_templates.xml | 178 +
.../views/website_venue_booking_templates.xml | 133 +
venue_booking_management/wizards/__init__.py | 23 +
.../wizards/check_venue_availability.py | 88 +
.../check_venue_availability_views.xml | 50 +
.../wizards/venue_booking_analysis.py | 202 +
.../wizards/venue_booking_analysis_views.xml | 49 +
158 files changed, 24749 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_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_reports.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/gif_screenshot.zip
create mode 100644 venue_booking_management/static/description/assets/gif_screenshot/venue_1.png
create mode 100644 venue_booking_management/static/description/assets/gif_screenshot/venue_11.png
create mode 100644 venue_booking_management/static/description/assets/gif_screenshot/venue_12.png
create mode 100644 venue_booking_management/static/description/assets/gif_screenshot/venue_13.png
create mode 100644 venue_booking_management/static/description/assets/gif_screenshot/venue_26.png
create mode 100644 venue_booking_management/static/description/assets/gif_screenshot/venue_4.png
create mode 100644 venue_booking_management/static/description/assets/gif_screenshot/venue_47.png
create mode 100644 venue_booking_management/static/description/assets/gif_screenshot/venue_5.png
create mode 100644 venue_booking_management/static/description/assets/gif_screenshot/venue_53.png
create mode 100644 venue_booking_management/static/description/assets/gif_screenshot/venue_8.png
create mode 100644 venue_booking_management/static/description/assets/gif_screenshot/venue_9.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/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/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/categories.png
create mode 100644 venue_booking_management/static/description/assets/misc/check-box.png
create mode 100644 venue_booking_management/static/description/assets/misc/compass.png
create mode 100644 venue_booking_management/static/description/assets/misc/corporate.png
create mode 100644 venue_booking_management/static/description/assets/misc/customer-support.png
create mode 100644 venue_booking_management/static/description/assets/misc/cybrosys-logo.png
create mode 100644 venue_booking_management/static/description/assets/misc/features.png
create mode 100644 venue_booking_management/static/description/assets/misc/logo.png
create mode 100644 venue_booking_management/static/description/assets/misc/pictures.png
create mode 100644 venue_booking_management/static/description/assets/misc/pie-chart.png
create mode 100644 venue_booking_management/static/description/assets/misc/right-arrow.png
create mode 100644 venue_booking_management/static/description/assets/misc/star.png
create mode 100644 venue_booking_management/static/description/assets/misc/support.png
create mode 100644 venue_booking_management/static/description/assets/misc/whatsapp.png
create mode 100644 venue_booking_management/static/description/assets/modules/delivery_date_ecommerce.png
create mode 100644 venue_booking_management/static/description/assets/modules/openai_website_product_media.png
create mode 100644 venue_booking_management/static/description/assets/modules/product_brand_ecommerce.png
create mode 100644 venue_booking_management/static/description/assets/modules/website_multi_variant.png
create mode 100644 venue_booking_management/static/description/assets/modules/website_repeat_sale.png
create mode 100644 venue_booking_management/static/description/assets/modules/wishlist_product_website_backend.png
create mode 100644 venue_booking_management/static/description/assets/screenshots.zip
create mode 100644 venue_booking_management/static/description/assets/screenshots/dashboard.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/hero.gif
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_1.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_10.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_11.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_12.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_13.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_14.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_15.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_16.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_17.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_18.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_2.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_20.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_21.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_22.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_23.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_24.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_25.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_26.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_27.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_28.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_29.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_3.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_30.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_31.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_32.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_33.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_36.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_39.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_4.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_40.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_41.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_45.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_47.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_48.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_49.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_5.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_50.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_51.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_52.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_53.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_54.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_6.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_7.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_8.png
create mode 100644 venue_booking_management/static/description/assets/screenshots/venue_9.png
create mode 100644 venue_booking_management/static/description/banner.png
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/lib/chart_bundle.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..c68532cf5
--- /dev/null
+++ b/venue_booking_management/README.rst
@@ -0,0 +1,57 @@
+.. image:: https://img.shields.io/badge/licence-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
+-------
+* Developers :(V15) Fathima Mazlin AM,
+ (V16) Risvana AR,
+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..bab8b9d93
--- /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: 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 .
+#
+###############################################################################
+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..24ed8bd71
--- /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: 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 .
+#
+###############################################################################
+{
+ 'name': 'Venue / Event Booking Management',
+ 'version': '15.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": "Industry",
+ 'author': 'Cybrosys Techno Solutions',
+ 'company': 'Cybrosys Techno Solutions',
+ 'maintainer': 'Cybrosys Techno Solutions',
+ 'website': "https://www.cybrosys.com",
+ 'depends': ['base', 'account', 'website', ],
+ '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_reports.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': [
+ 'venue_booking_management/static/src/css/venue_dashboard.css',
+ 'venue_booking_management/static/src/scss/venue_booking.scss',
+ 'venue_booking_management/static/src/js/action_manager.js',
+ 'venue_booking_management/static/src/js/lib/chart_bundle.js',
+ 'venue_booking_management/static/src/js/dashboard_action.js',
+ ],
+ 'web.assets_qweb': [
+ 'venue_booking_management/static/src/xml/dashboard_templates.xml',
+ ],
+ },
+ 'images': ['static/description/banner.png'],
+ '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..8e38f0ecc
--- /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: 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 .
+#
+###############################################################################
+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..808332070
--- /dev/null
+++ b/venue_booking_management/controllers/portal.py
@@ -0,0 +1,260 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# 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 .
+#
+###############################################################################
+from collections import OrderedDict
+from datetime import timedelta
+from odoo import fields,http, _
+from odoo.http import request
+from odoo.osv import expression
+from odoo.osv.expression import OR
+from odoo.addons.portal.controllers import portal
+from odoo.addons.portal.controllers.portal import CustomerPortal, pager as portal_pager
+
+
+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..08adddb98
--- /dev/null
+++ b/venue_booking_management/controllers/venue_booking_management.py
@@ -0,0 +1,93 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# 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 .
+#
+###############################################################################
+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
+from odoo.exceptions import UserError
+
+
+class XLSXReportController(http.Controller):
+ """Controller Class for xlsx report"""
+ @http.route('/venue_xlsx_reports', type='http', auth='user', methods=['POST'],
+ csrf=False)
+ 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'),
+ 'state_id': int(post.get('state')),
+ 'country_id': int(post.get('country')),
+ 'city': (post.get('city')),
+ })
+ 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')
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..1ae419e1b
--- /dev/null
+++ b/venue_booking_management/doc/RELEASE_NOTES.md
@@ -0,0 +1,7 @@
+## Module
+
+#### 16.09.2024
+#### Version 15.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..52bc82409
--- /dev/null
+++ b/venue_booking_management/models/__init__.py
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# 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 .
+#
+###############################################################################
+from . import amenities
+from . import res_config_settings
+from . import venue
+from . import venue_type
+from . import venue_booking
+
+
+
+
+
+
+
diff --git a/venue_booking_management/models/amenities.py b/venue_booking_management/models/amenities.py
new file mode 100644
index 000000000..9dff1bde1
--- /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: 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 .
+#
+###############################################################################
+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..e1a424fec
--- /dev/null
+++ b/venue_booking_management/models/res_config_settings.py
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# 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 .
+#
+###############################################################################
+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', default=False,
+ config_parameter='venue_booking_management.is_extra',
+ help="Enable, if extra charge want to add")
+ extra_amount = fields.Float(
+ string='Extra Amount', help='Enter extra amount/KM',
+ config_parameter='venue_booking_management.extra_amount')
diff --git a/venue_booking_management/models/venue.py b/venue_booking_management/models/venue.py
new file mode 100644
index 000000000..50acb9d2b
--- /dev/null
+++ b/venue_booking_management/models/venue.py
@@ -0,0 +1,119 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# 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 .
+#
+###############################################################################
+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")
+ image = fields.Binary("Image", attachment=True,
+ help="This field holds the image used as "
+ "image for the event, limited to 1080x720px.")
+ venue_type_id = fields.Many2one('venue.type', 'Venue Type',
+ 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"""
+ for rec in self:
+ rec.price_subtotal = sum(
+ item.sub_total for item in rec.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_count([
+ ('venue_id', '=', records.id)])
+ records.venue_count = 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')
+
+
+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="Sub Total", 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_booking.py b/venue_booking_management/models/venue_booking.py
new file mode 100644
index 000000000..8921345e8
--- /dev/null
+++ b/venue_booking_management/models/venue_booking.py
@@ -0,0 +1,556 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# 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 .
+#
+###############################################################################
+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', 'Venue Type',
+ related='venue_id.venue_type_id',
+ readonly=True,
+ help='Used to choose the type of the'
+ ' particular venue')
+ image = fields.Binary("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')
+
+ @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"""
+ date = values['date']
+ partner_name = self.env['res.partner'].browse(
+ values['partner_id']).name
+ values['name'] = '%s- %s' % (partner_name, 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.constrains('start_date', 'end_date')
+ def constrains_dates(self):
+ for rec in self:
+ start_date = rec.start_date
+ end_date = rec.end_date
+ if start_date >= end_date:
+ raise UserError(_('Start date must be less than End date'))
+
+ def get_booking_dates(self, start_date, end_date, venue_id):
+ """Checking dates while Booking the Venues based on the changes
+ of the Dates"""
+ result = 0
+ date_result = 0
+ venue = self.env['venue'].browse(venue_id)
+ if start_date >= end_date:
+ date_result = 1
+ else:
+ date_result = 0
+ if date_result == 0:
+ booking = self.env['venue.booking'].sudo().search(
+ [('venue_id', '=', venue.id),
+ ('start_date', '<', end_date),
+ ('end_date', '>', start_date),
+ ])
+ if booking:
+ result = 1
+ else:
+ result = 0
+ data = {
+ 'result': result,
+ "date_result": date_result,
+ }
+ return data
+
+ @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', 'is_additional_charge', 'booking_type')
+ 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.is_additional_charge:
+ if rec.venue_id.additional_charge_day != 0.0:
+ total += rec.venue_id.additional_charge_day
+ 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')
+ total += float(amount)
+ elif rec.booking_type == 'hour':
+ total += (rec.booking_charge_per_hour * (
+ rec.days_difference * 24))
+ if rec.is_additional_charge:
+ if rec.venue_id.additional_charge_hour != 0.0:
+ total += rec.venue_id.additional_charge_hour
+ 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')
+ total += float(amount)
+ rec.total = total + rec.booking_charge
+
+ 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})
+
+ 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':
+ if self.is_additional_charge:
+ total = self.booking_charge_per_day + self.venue_id.\
+ additional_charge_day
+ else:
+ total = self.booking_charge_per_day
+ elif self.booking_type == 'hour':
+ if self.is_additional_charge:
+ total = (self.booking_charge_per_hour * (self.days_difference *
+ 24)) + \
+ self.venue_id.additional_charge_hour
+ else:
+ total = (self.booking_charge_per_hour * (self.days_difference *
+ 24))
+ 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 date_trunc('year', now()) AND now()'''
+ elif option == 'month':
+ create_date = '''create_date BETWEEN date_trunc('month', now()) AND now()'''
+ elif option == 'week':
+ create_date = '''create_date between date_trunc('week', now()) and now()'''
+ elif option == 'day':
+ create_date = '''create_date BETWEEN date_trunc('day', now()) 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,
+ }
+
+
+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_type.py b/venue_booking_management/models/venue_type.py
new file mode 100644
index 000000000..184cfd142
--- /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: 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 .
+#
+###############################################################################
+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("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..aa0ce73de
--- /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: 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 .
+#
+###############################################################################
+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..aff574625
--- /dev/null
+++ b/venue_booking_management/report/form_venue_booking_report.py
@@ -0,0 +1,78 @@
+# -*- coding: utf-8 -*-
+###############################################################################
+#
+# Cybrosys Technologies Pvt. Ltd.
+#
+# Copyright (C) 2024-TODAY Cybrosys Technologies()
+# 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 .
+#
+###############################################################################
+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..cb5cbc77d
--- /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: 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 .
+#
+###############################################################################
+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('Booking Reference', readonly=True,
+ help="Booking Reference field for the Reporting")
+ date = fields.Datetime('Booking Date', readonly=True,
+ help="Booking Date field for the Reporting")
+ partner_id = fields.Many2one('res.partner',
+ 'Customer', readonly=True,
+ help="Partner ID field for the Reporting")
+ total = fields.Float('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..bd6b94f29
--- /dev/null
+++ b/venue_booking_management/report/venue_booking_report_views.xml
@@ -0,0 +1,106 @@
+
+
+
+
+ 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_reports.xml b/venue_booking_management/report/venue_booking_reports.xml
new file mode 100644
index 000000000..350d97cff
--- /dev/null
+++ b/venue_booking_management/report/venue_booking_reports.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ 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..4439b61cd
--- /dev/null
+++ b/venue_booking_management/security/venue_booking_management_groups.xml
@@ -0,0 +1,21 @@
+
+
+
+ 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..fadc8ff3b
--- /dev/null
+++ b/venue_booking_management/security/venue_booking_secruity.xml
@@ -0,0 +1,20 @@
+
+
+
+
+ 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/gif_screenshot.zip b/venue_booking_management/static/description/assets/gif_screenshot.zip
new file mode 100644
index 0000000000000000000000000000000000000000..4c815c90269766cb1d372b5310f4c416218eff3f
GIT binary patch
literal 1066784
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