@ -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 <https://cybrosys.com/>`__ |
|||
|
|||
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 <https://cybrosys.com/>`__ |
|||
|
|||
Further information |
|||
=================== |
|||
HTML Description: `<static/description/index.html>`__ |
@ -0,0 +1,25 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Fathima Mazlin AM (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from . import controllers |
|||
from . import models |
|||
from . import report |
|||
from . import wizards |
@ -0,0 +1,77 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Fathima Mazlin AM (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
{ |
|||
'name': '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, |
|||
} |
@ -0,0 +1,23 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Fathima Mazlin AM (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from . import portal |
|||
from . import venue_booking_management |
@ -0,0 +1,260 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Fathima Mazlin AM (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from 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/<int: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/<int:record>'], 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'}) |
@ -0,0 +1,93 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Fathima Mazlin AM (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
import json |
|||
from odoo import 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') |
@ -0,0 +1,30 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
<!-- Email to notify the Customer to Confirm the Venue Booking --> |
|||
<record id="mail_template_notify_venue_booking" model="mail.template"> |
|||
<field name="name">Confirmed Venue Booking</field> |
|||
<field name="subject">Venue booking: Received the Venue Booking for |
|||
{{ object.venue_id.name }} |
|||
</field> |
|||
<field name="model_id" |
|||
ref="venue_booking_management.model_venue_booking"/> |
|||
<field name="email_from">{{ (object.env.user.login) }} |
|||
</field> |
|||
<field name="body_html"> |
|||
<![CDATA[ |
|||
<p> |
|||
Dear customer <t t-out="object.partner_id.name"/>,<br/><br/> |
|||
We have received a booking for the venue |
|||
<strong><t t-out="object.venue_id.name"/></strong>. Please proceed |
|||
with necessary actions. |
|||
<br/><br/> |
|||
Thank You |
|||
</p> |
|||
]]> |
|||
</field> |
|||
<field name="lang">{{ object.partner_id.lang or '' }}</field> |
|||
<field name="auto_delete" eval="False"/> |
|||
</record> |
|||
</data> |
|||
</odoo> |
@ -0,0 +1,60 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
<!-- Venue Types Records--> |
|||
<record id="venue_type1" model="venue.type"> |
|||
<field name="name">Conference centers</field> |
|||
<field name="image" type="base64" |
|||
file="venue_booking_management/static/img/venue_type1.jpeg"/> |
|||
</record> |
|||
<record id="venue_type2" model="venue.type"> |
|||
<field name="name">Meeting Room</field> |
|||
<field name="image" type="base64" |
|||
file="venue_booking_management/static/img/venue_type2.jpeg"/> |
|||
</record> |
|||
<record id="venue_type3" model="venue.type"> |
|||
<field name="name">Convention centers</field> |
|||
<field name="image" type="base64" |
|||
file="venue_booking_management/static/img/venue_type3.jpeg"/> |
|||
</record> |
|||
<record id="venue_type4" model="venue.type"> |
|||
<field name="name">Social clubs and lounges</field> |
|||
<field name="image" type="base64" |
|||
file="venue_booking_management/static/img/venue_type4.jpeg"/> |
|||
</record> |
|||
<record id="venue_type5" model="venue.type"> |
|||
<field name="name">Mini Conference centers</field> |
|||
<field name="image" type="base64" |
|||
file="venue_booking_management/static/img/venue_type5.jpeg"/> |
|||
</record> |
|||
<record id="venue_type6" model="venue.type"> |
|||
<field name="name">Stadiums</field> |
|||
<field name="image" type="base64" |
|||
file="venue_booking_management/static/img/venue_type6.jpeg"/> |
|||
</record> |
|||
<record id="venue_type7" model="venue.type"> |
|||
<field name="name">Community centers</field> |
|||
<field name="image" type="base64" |
|||
file="venue_booking_management/static/img/venue_type7.jpeg"/> |
|||
</record> |
|||
<record id="venue_type8" model="venue.type"> |
|||
<field name="name">Resorts</field> |
|||
<field name="image" type="base64" |
|||
file="venue_booking_management/static/img/venue_type8.jpeg"/> |
|||
</record> |
|||
<record id="venue_type9" model="venue.type"> |
|||
<field name="name">Auditorium</field> |
|||
<field name="image" type="base64" |
|||
file="venue_booking_management/static/img/venue_type9.jpeg"/> |
|||
</record> |
|||
<!-- Sequence Number Generation for Venue Booking--> |
|||
<record id="sequence_venue_booking" model="ir.sequence"> |
|||
<field name="name">Venue Booking</field> |
|||
<field name="code">venue.booking.sequence</field> |
|||
<field name="suffix">%(day)s/%(month)s/%(year)s</field> |
|||
<field name="prefix">VENUE-</field> |
|||
<field name="number_increment">1</field> |
|||
<field name="padding">3</field> |
|||
</record> |
|||
</data> |
|||
</odoo> |
@ -0,0 +1,7 @@ |
|||
## Module <venue_booking_management> |
|||
|
|||
#### 16.09.2024 |
|||
#### Version 15.0.1.0.0 |
|||
#### ADD |
|||
|
|||
- Initial Commit for Venue / Event Booking Management |
@ -0,0 +1,33 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Fathima Mazlin AM (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from . import amenities |
|||
from . import res_config_settings |
|||
from . import venue |
|||
from . import venue_type |
|||
from . import venue_booking |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
@ -0,0 +1,32 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Fathima Mazlin AM (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class 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") |
@ -0,0 +1,35 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Fathima Mazlin AM (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class 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') |
@ -0,0 +1,119 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Fathima Mazlin AM (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from odoo import 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 |
@ -0,0 +1,556 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Fathima Mazlin AM (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from odoo import 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 |
@ -0,0 +1,33 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Fathima Mazlin AM (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class 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.") |
@ -0,0 +1,23 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Fathima Mazlin AM (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from . import form_venue_booking_report |
|||
from . import venue_booking_report |
@ -0,0 +1,78 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Fathima Mazlin AM (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
import 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, |
|||
} |
@ -0,0 +1,73 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Fathima Mazlin AM (odoo@cybrosys.com) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from odoo import fields, models, 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,)) |
@ -0,0 +1,186 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<!-- Template used to create form for the booking report--> |
|||
<template id="report_venue_booking"> |
|||
<t t-call="web.html_container"> |
|||
<t t-call="web.external_layout"> |
|||
<div class="page"> |
|||
<div class="oe_structure"/> |
|||
<div class="row"> |
|||
<div class="col-md-12" style="text-align: center;"> |
|||
<h2> |
|||
<span>Venue/Event Booking Report</span> |
|||
</h2> |
|||
</div> |
|||
</div> |
|||
<br/> |
|||
<br/> |
|||
<div> |
|||
<span>Date:</span> |
|||
<span t-esc="today_date"/> |
|||
</div> |
|||
<br/> |
|||
<t t-if="doc_ids"> |
|||
<div> |
|||
<span t-if="doc_ids['start_date']"> |
|||
<b>From:</b> |
|||
<span style="margin-left:3px;margin-right:17px;margin-bottom:3px" |
|||
t-esc="doc_ids['start_date']"/> |
|||
</span> |
|||
<span t-if="doc_ids['end_date']"> |
|||
<b>To:</b> |
|||
<span style="margin-left:3px;margin-right:17px;margin-bottom:3px" |
|||
t-esc="doc_ids['end_date']"/> |
|||
</span> |
|||
<br/> |
|||
<br/> |
|||
<span t-if="doc_ids['partner_id']"> |
|||
<b>Customer:</b> |
|||
<span style="margin-left:3px;margin-bottom:3px" |
|||
t-esc="doc_ids['partner_id'].name"/> |
|||
</span> |
|||
<br/> |
|||
<br/> |
|||
<span t-if="doc_ids['venue_id']"> |
|||
<b>Venue:</b> |
|||
<span style="margin-left:3px;margin-bottom:3px" |
|||
t-esc="doc_ids['venue_id'].name"/> |
|||
</span> |
|||
</div> |
|||
<div class="row"> |
|||
<div class="col-md-12"> |
|||
<table class="table table-sm"> |
|||
<thead> |
|||
<tr> |
|||
<th>Sl.no</th> |
|||
<th>Ref.No</th> |
|||
<th>Venue</th> |
|||
<th>Booking Type</th> |
|||
<th>Customer</th> |
|||
<th>Start Date</th> |
|||
<th>End Date</th> |
|||
<th>State</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
<t t-foreach="doc_ids" t-as="l"> |
|||
<tr> |
|||
<td> |
|||
<t t-esc="l_index + 1"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="l['ref']"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="l['venue_id'].name"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="{'hour': 'Hour', 'day': 'Day'} |
|||
[l['booking_type']]"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="l['partner_id'].name"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="l['start_date']"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="l['end_date']"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="{'draft': 'Draft', 'confirm': 'Confirm', 'invoice': 'Invoiced', 'cancel': 'Cancelled', 'close': 'Closed'} |
|||
[l['state']]"/> |
|||
</td> |
|||
</tr> |
|||
</t> |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
<t t-if="docs2"> |
|||
<div> |
|||
<span t-if="docs2['start_date']"> |
|||
<b>From:</b> |
|||
<span style="margin-left:3px;margin-right:17px;margin-bottom:3px" |
|||
t-esc="docs2['start_date']"/> |
|||
</span> |
|||
<span t-if="docs2['end_date']"> |
|||
<b>To:</b> |
|||
<span style="margin-left:3px;margin-right:17px;margin-bottom:3px" |
|||
t-esc="docs2['end_date']"/> |
|||
</span> |
|||
<br/> |
|||
<br/> |
|||
<span t-if="docs2['partner_id']"> |
|||
<b>Customer:</b> |
|||
<span style="margin-left:3px;margin-bottom:3px" |
|||
t-esc="docs2['partner_id'][1]"/> |
|||
</span> |
|||
<br/> |
|||
<br/> |
|||
<span t-if="docs2['venue_id']"> |
|||
<b>Venue:</b> |
|||
<span style="margin-left:3px;margin-bottom:3px" |
|||
t-esc="docs2['venue_id'][1]"/> |
|||
</span> |
|||
</div> |
|||
<br/> |
|||
<br/> |
|||
<div class="row"> |
|||
<div class="col-md-12"> |
|||
<table class="table table-sm"> |
|||
<thead> |
|||
<tr> |
|||
<th>Sl.no</th> |
|||
<th>Ref.No</th> |
|||
<th>Venue</th> |
|||
<th>Booking Type</th> |
|||
<th>Customer</th> |
|||
<th>Start Date</th> |
|||
<th>End Date</th> |
|||
<th>State</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
<t t-foreach="docs" t-as="l"> |
|||
<tr> |
|||
<td> |
|||
<t t-esc="l_index + 1"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="l['ref']"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="l['venue']"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="{'hour': 'Hour', 'day': 'Day'} |
|||
[l['booking_type']]"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="l['name']"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="l['start_date']"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="l['end_date']"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="{'draft': 'Draft', 'confirm': 'Confirm', 'invoice': 'Invoiced', 'cancel': 'Cancelled', 'close': 'Closed'} |
|||
[l['state']]"/> |
|||
</td> |
|||
</tr> |
|||
</t> |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
<div class="oe_structure"/> |
|||
</div> |
|||
</t> |
|||
</t> |
|||
</template> |
|||
</odoo> |
@ -0,0 +1,106 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<!--Pivot view for the Report--> |
|||
<record id="venue_booking_report_view_pivot" model="ir.ui.view"> |
|||
<field name="name">venue.booking.report.view.pivot</field> |
|||
<field name="model">venue.booking.report</field> |
|||
<field name="arch" type="xml"> |
|||
<pivot string="Venue Booking Analysis" sample="1"> |
|||
<field name="partner_id" type="col"/> |
|||
<field name="date" interval="month" type="row"/> |
|||
<field name="total" type="measure"/> |
|||
<field name="partner_id" type="measure"/> |
|||
</pivot> |
|||
</field> |
|||
</record> |
|||
<!--Graph view for the report--> |
|||
<record id="venue_booking_report_view_graph" model="ir.ui.view"> |
|||
<field name="name">venue.booking.report.view.graph</field> |
|||
<field name="model">venue.booking.report</field> |
|||
<field name="arch" type="xml"> |
|||
<graph string="Venue Booking Analysis" type="line" sample="1"> |
|||
<field name="date" interval="day"/> |
|||
<field name="total" type="measure"/> |
|||
<field name="partner_id" type="measure"/> |
|||
</graph> |
|||
</field> |
|||
</record> |
|||
<!--Tree view for the booking Report--> |
|||
<record id="venue_booking_report_view_tree" model="ir.ui.view"> |
|||
<field name="name">venue.booking.report.view.tree</field> |
|||
<field name="model">venue.booking.report</field> |
|||
<field name="arch" type="xml"> |
|||
<tree string="Venue Booking Analysis"> |
|||
<field name="date" widget="date"/> |
|||
<field name="partner_id" optional="hide"/> |
|||
<field name="total" optional="hide" sum="Sum of Total"/> |
|||
<field name="state" optional="hide"/> |
|||
</tree> |
|||
</field> |
|||
</record> |
|||
<!--Search view for the Booking Report--> |
|||
<record id="venue_booking_report_view_search" model="ir.ui.view"> |
|||
<field name="name">venue.booking.report.view.search</field> |
|||
<field name="model">venue.booking.report</field> |
|||
<field name="arch" type="xml"> |
|||
<search string="Venue Booking Analysis"> |
|||
<field name="date"/> |
|||
<filter string="Date" name="year" invisible="1" date="date" |
|||
default_period="this_year"/> |
|||
<filter string="Enquiry" name="Enquiry" |
|||
domain="[('state','in', ('draft'))]"/> |
|||
<filter string="Confirmed Booking" name="Confirmed Booking" |
|||
domain="[('state','not in',('draft', 'cancel', 'close'))]"/> |
|||
<separator/> |
|||
<filter name="filter_date" date="date" |
|||
default_period="this_month"/> |
|||
<filter name="filter_order_date" invisible="1" |
|||
string="Order Date: Last 365 Days" |
|||
domain="[('date', '>=', (datetime.datetime.combine(context_today() + relativedelta(days=-365), datetime.time(0,0,0))).strftime('%Y-%m-%d %H:%M:%S'))]"/> |
|||
<separator/> |
|||
<field name="partner_id"/> |
|||
<group expand="1" string="Group By"> |
|||
<filter string="Customer" name="Customer" |
|||
context="{'group_by':'partner_id'}"/> |
|||
<filter string="Status" name="status" |
|||
context="{'group_by':'state'}"/> |
|||
<separator/> |
|||
<filter string="Order Date" name="date" |
|||
context="{'group_by':'date'}" |
|||
invisible="context.get('sale_report_view_hide_date')"/> |
|||
<filter string="Order Date" name="group_by_date_day" |
|||
context="{'group_by':'date:day'}" |
|||
invisible="not context.get('sale_report_view_hide_date')"/> |
|||
</group> |
|||
</search> |
|||
</field> |
|||
</record> |
|||
<!-- Action record for the Report--> |
|||
<record id="venue_booking_report_action" model="ir.actions.act_window"> |
|||
<field name="name">Venue Booking Analysis</field> |
|||
<field name="res_model">venue.booking.report</field> |
|||
<field name="view_mode">graph,pivot</field> |
|||
<field name="search_view_id" ref="venue_booking_report_view_search"/> |
|||
<field name="context">{'group_by_no_leaf':1,'group_by':[], 'search_default_filter_order_date': 1}</field> |
|||
<field name="help">This report performs analysis on your Venue Booking. |
|||
</field> |
|||
</record> |
|||
|
|||
<record id="report_all_venue_booking_action" model="ir.actions.act_window"> |
|||
<field name="name">Venue Booking Analysis</field> |
|||
<field name="res_model">venue.booking.report</field> |
|||
<field name="view_mode">pivot</field> |
|||
</record> |
|||
<!--MenuItems for the Reports--> |
|||
<menuitem id="venue_booking_menu_report" |
|||
name="Reporting" action="venue_booking_report_action" |
|||
parent="venue_booking_menu_root" |
|||
groups="venue_booking_management.venue_booking_management_group_venue_manager" |
|||
sequence="40"/> |
|||
<menuitem id="venue_booking_menu_report_sub_menu" |
|||
name="Venue Booking Analysis" |
|||
action="venue_booking_report_action" |
|||
parent="venue_booking_menu_report" |
|||
groups="venue_booking_management.venue_booking_management_group_venue_manager" |
|||
sequence="10"/> |
|||
</odoo> |
@ -0,0 +1,13 @@ |
|||
<?xml version="1.0" encoding="utf-8" ?> |
|||
<odoo> |
|||
<!-- Generate the Booking report as pdf Format--> |
|||
<record id="action_venue_booking_management_report" model="ir.actions.report"> |
|||
<field name="name">Venue Booking</field> |
|||
<field name="model">venue.booking</field> |
|||
<field name="report_type">qweb-pdf</field> |
|||
<field name="report_name">venue_booking_management.report_venue_booking</field> |
|||
<field name="report_file">venue_booking_management.report_venue_booking</field> |
|||
<field name="binding_model_id" ref="model_venue_booking"/> |
|||
<field name="binding_type">report</field> |
|||
</record> |
|||
</odoo> |
|
@ -0,0 +1,21 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<record model="ir.module.category" id="module_venue_booking_management"> |
|||
<field name="name">Venue Booking Management</field> |
|||
<field name="description">Category for Venue Booking Management</field> |
|||
</record> |
|||
<!--Group For User--> |
|||
<record id="venue_booking_management_group_venue_user" model="res.groups"> |
|||
<field name="name">User</field> |
|||
<field name="category_id" ref="module_venue_booking_management"/> |
|||
</record> |
|||
<!--Group For Manager--> |
|||
<record id="venue_booking_management_group_venue_manager" |
|||
model="res.groups"> |
|||
<field name="name">Manager</field> |
|||
<field name="category_id" ref="module_venue_booking_management"/> |
|||
<field name="implied_ids" |
|||
eval="[(4, ref('venue_booking_management_group_venue_user'))]"/> |
|||
<field name="users" eval="[(4, ref('base.user_root')), (4, ref('base.user_admin'))]"/> |
|||
</record> |
|||
</odoo> |
@ -0,0 +1,20 @@ |
|||
<?xml version="1.0" encoding="utf-8" ?> |
|||
<odoo> |
|||
<!--XML for viewing created records of logged user--> |
|||
<record id="venue_booking_rule_space_user" model="ir.rule"> |
|||
<field name="name">View Own Docs</field> |
|||
<field ref="model_venue_booking" name="model_id"/> |
|||
<field name="domain_force">['|',('user_id', '=', user.id),('create_uid', '=', user.id)] |
|||
</field> |
|||
<field name="groups" |
|||
eval="[(4, ref('venue_booking_management.venue_booking_management_group_venue_user'))]"/> |
|||
</record> |
|||
<!--XML for viewing all the records of all the users--> |
|||
<record id="venue_booking_rule_space_manager" model="ir.rule"> |
|||
<field name="name">View All Docs</field> |
|||
<field ref="model_venue_booking" name="model_id"/> |
|||
<field name="domain_force">[(1, '=', 1)]</field> |
|||
<field name="groups" |
|||
eval="[(4, ref('venue_booking_management.venue_booking_management_group_venue_manager'))]"/> |
|||
</record> |
|||
</odoo> |
After Width: | Height: | Size: 86 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 91 KiB |
After Width: | Height: | Size: 85 KiB |
After Width: | Height: | Size: 108 KiB |
After Width: | Height: | Size: 224 KiB |
After Width: | Height: | Size: 177 KiB |
After Width: | Height: | Size: 107 KiB |
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 69 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 310 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 576 B |
After Width: | Height: | Size: 733 B |
After Width: | Height: | Size: 911 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 673 B |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 653 B |
After Width: | Height: | Size: 905 B |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 427 B |
After Width: | Height: | Size: 627 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 988 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 4.4 KiB |
After Width: | Height: | Size: 589 B |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 967 B |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 57 KiB |
After Width: | Height: | Size: 82 KiB |
After Width: | Height: | Size: 58 KiB |
After Width: | Height: | Size: 59 KiB |
After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 59 KiB |
After Width: | Height: | Size: 76 KiB |
After Width: | Height: | Size: 243 KiB |
After Width: | Height: | Size: 86 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 91 KiB |
After Width: | Height: | Size: 85 KiB |
After Width: | Height: | Size: 109 KiB |
After Width: | Height: | Size: 101 KiB |
After Width: | Height: | Size: 109 KiB |
After Width: | Height: | Size: 114 KiB |
After Width: | Height: | Size: 111 KiB |
After Width: | Height: | Size: 134 KiB |
After Width: | Height: | Size: 98 KiB |
After Width: | Height: | Size: 106 KiB |
After Width: | Height: | Size: 124 KiB |
After Width: | Height: | Size: 90 KiB |
After Width: | Height: | Size: 96 KiB |
After Width: | Height: | Size: 127 KiB |
After Width: | Height: | Size: 108 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 67 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 83 KiB |