@ -0,0 +1,45 @@ |
|||
.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg |
|||
:target: https://www.gnu.org/licenses/agpl-3.0-standalone.html |
|||
:alt: License: AGPL-3 |
|||
|
|||
Show Booking Management |
|||
======================= |
|||
A module for show booking management. Admin can manage shows and Users |
|||
can book shows easily through Website by selecting date, screen, time and seats. |
|||
|
|||
Configuration |
|||
============= |
|||
- No configuration needed |
|||
|
|||
License |
|||
======= |
|||
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 |
|||
------- |
|||
* Developer: (V17) Ashwin A, Contact: odoo@cybrosys.com |
|||
|
|||
Contacts |
|||
-------- |
|||
* Mail Contact : odoo@cybrosys.com |
|||
* Website : http://www.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 https://www.cybrosys.com |
|||
|
|||
Further information |
|||
=================== |
|||
HTML Description: `<static/description/index.html>`__ |
@ -0,0 +1,23 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
from . import controller |
|||
from . import models |
@ -0,0 +1,70 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
{ |
|||
'name': "Show Booking Management", |
|||
'version': '17.0.1.0.0', |
|||
'category': 'Services', |
|||
'summary': "Manage shows and book shows easily.", |
|||
'description': """A module for show booking management. Admin can manage shows |
|||
and Users can book shows easily through Website by selecting date, |
|||
screen, time and seats.""", |
|||
'author': "Cybrosys Techno Solutions", |
|||
'company': 'Cybrosys Techno Solutions', |
|||
'maintainer': 'Cybrosys Techno Solutions', |
|||
'website': "https://www.cybrosys.com", |
|||
'depends': ['stock', 'website_sale', 'account', 'portal'], |
|||
'data': [ |
|||
'security/show_booking_management_groups.xml', |
|||
'security/ir.model.access.csv', |
|||
'data/product_product_data.xml', |
|||
'data/report_paperformat_data.xml', |
|||
'data/mail_template_data.xml', |
|||
'data/ir_sequence_data.xml', |
|||
'data/website_menu_data.xml', |
|||
'views/movie_movie_views.xml', |
|||
'views/show_type_views.xml', |
|||
'views/cast_type_views.xml', |
|||
'views/movie_cast_views.xml', |
|||
'views/time_slots_views.xml', |
|||
'views/movie_screen_views.xml', |
|||
'views/movie_registration_views.xml', |
|||
'views/website_templates.xml', |
|||
'views/portal_template.xml', |
|||
'report/movie_registration_templates.xml', |
|||
], |
|||
'assets': { |
|||
'web.assets_backend': [ |
|||
'show_booking_management/static/src/js/time_widget.js', |
|||
'show_booking_management/static/src/xml/**/*.xml', |
|||
], |
|||
'web.assets_frontend': [ |
|||
'show_booking_management/static/src/js/bookShow.js', |
|||
'show_booking_management/static/src/js/selectSeat.js', |
|||
'show_booking_management/static/src/css/show_booking_management.css', |
|||
], |
|||
}, |
|||
'images': ['static/description/banner.jpg'], |
|||
'license': 'AGPL-3', |
|||
'installable': True, |
|||
'auto_install': False, |
|||
'application': True, |
|||
} |
@ -0,0 +1,24 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
from . import payment |
|||
from . import portal |
|||
from . import show_booking_management |
@ -0,0 +1,102 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
import base64 |
|||
import json |
|||
from io import BytesIO |
|||
import qrcode |
|||
from odoo import http |
|||
from odoo.http import request |
|||
from odoo.addons.payment.controllers.post_processing import PaymentPostProcessing |
|||
|
|||
|
|||
class PaymentPost(PaymentPostProcessing): |
|||
""" |
|||
Inherit the poll status method to handle payment status completion. |
|||
Creates movie registration and movie seats records if payment status is 'done'. |
|||
""" |
|||
@http.route() |
|||
def poll_status(self, **kwargs): |
|||
""" Inheriting the poll status and if the status of payment is done |
|||
it will create records movie registration and movie seats.""" |
|||
res = super(PaymentPost, self).poll_status(**kwargs) |
|||
movie_booking_data = request.session.get('movie_booking_data') |
|||
if movie_booking_data and res['state'] == 'done': |
|||
movie_booking_data = json.loads(movie_booking_data) |
|||
# Creating movie.registration record |
|||
movie_ticket = request.env['movie.registration'].create({ |
|||
'movie_id': movie_booking_data['movie_id'], |
|||
'screen_id': movie_booking_data['screen_id'], |
|||
'time_slot_id': movie_booking_data['time_slot_id'], |
|||
'date': movie_booking_data['booking_date'], |
|||
'no_of_tickets': len(movie_booking_data['selected_seats']), |
|||
'partner_id': request.env.user.partner_id.id, |
|||
'state': 'invoiced' |
|||
}) |
|||
# Creating QR code |
|||
qr_data = f"Ticket : {movie_ticket.name}\n" \ |
|||
f"Movie: {movie_ticket.movie_id.name}\n" \ |
|||
f"Date: {movie_ticket.date}\n" \ |
|||
f"Time: {movie_ticket.time_slot_id.name}\n" \ |
|||
f"Screen: {movie_ticket.screen_id.name}\n" \ |
|||
f"Seats: {', '.join(movie_booking_data['selected_seats'])}" |
|||
qr = qrcode.QRCode(version=1, box_size=10, border=5) |
|||
qr.add_data(qr_data) |
|||
qr.make(fit=True) |
|||
img = qr.make_image() |
|||
buffer = BytesIO() |
|||
img.save(buffer, format="PNG") |
|||
qr_image = base64.b64encode(buffer.getvalue()).decode() |
|||
movie_ticket.write({'qr_code': qr_image}) |
|||
|
|||
# Creating movie.seats records |
|||
for seat in movie_booking_data['selected_seats']: |
|||
request.env['movie.seats'].create({ |
|||
'screen_id': movie_booking_data['screen_id'], |
|||
'time_slot_id': movie_booking_data['time_slot_id'], |
|||
'movie_registration_id': movie_ticket.id, |
|||
'date': movie_booking_data['booking_date'], |
|||
'seat': seat, |
|||
'is_booked': True |
|||
}) |
|||
invoice = request.env['account.move'].browse( |
|||
movie_booking_data['invoice_id']) |
|||
invoice.movie_ticket_id = movie_ticket.id |
|||
movie_admin_users = request.env['res.users'].search([ |
|||
('groups_id', 'in', |
|||
request.env.ref('show_booking_management.show_booking_management_group_admin').id) |
|||
]) |
|||
template = request.env.ref( |
|||
'show_booking_management.email_template_movie_ticket') |
|||
attachment_id = request.env['ir.attachment'].create({ |
|||
'name': 'Movie_Ticket_QR_Code.png', |
|||
'type': 'binary', |
|||
'datas': qr_image, |
|||
'res_model': 'movie.registration', |
|||
'res_id': movie_ticket.id, |
|||
'mimetype': 'image/png' |
|||
}) |
|||
email_values = { |
|||
'email_from': movie_admin_users[0].email, |
|||
'attachment_ids': [(6, 0, [attachment_id.id])], |
|||
} |
|||
template.send_mail(movie_ticket.id, email_values=email_values, force_send=True) |
|||
return res |
@ -0,0 +1,33 @@ |
|||
from odoo import http |
|||
from odoo.http import request |
|||
from odoo.addons.portal.controllers.portal import CustomerPortal |
|||
|
|||
|
|||
class ShowPortal(CustomerPortal): |
|||
""" Prepare values for the home portal and retrieve shows based on user permissions.""" |
|||
def _prepare_home_portal_values(self, counters): |
|||
""" |
|||
Prepare values for the home portal and retrieve the count |
|||
of shows available based on user permissions. |
|||
""" |
|||
values = super()._prepare_home_portal_values(counters) |
|||
if 'shows_count' in counters: |
|||
shows_count = request.env['movie.registration'].search_count([]) |
|||
|
|||
values['shows_count'] = shows_count |
|||
return values |
|||
|
|||
@http.route('/my/shows', type='http', auth="user", website=True) |
|||
def my_subscription(self, **kw): |
|||
""" |
|||
Retrieve shows for the user based on permissions and render them on the portal. |
|||
""" |
|||
user = request.env.user |
|||
if user.has_group('base.group_system'): |
|||
shows = request.env['movie.registration'].sudo().search([]) |
|||
else: |
|||
shows = request.env['movie.registration'].sudo().search([('partner_id', '=', user.partner_id.id)]) |
|||
values = { |
|||
'shows': shows, |
|||
} |
|||
return request.render('show_booking_management.portal_my_shows', values) |
@ -0,0 +1,108 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
import json |
|||
from werkzeug.urls import url_encode |
|||
from odoo import http, fields |
|||
from odoo.http import request |
|||
|
|||
|
|||
class MovieShow(http.Controller): |
|||
""" This class defines the HTTP routes and movie shows. |
|||
It provides functionality to render the movie template for user |
|||
interaction.""" |
|||
@http.route(['/show'], type='http', auth="public", csrf=False, website=True) |
|||
def show_movies(self): |
|||
""" Function for rendering show page.""" |
|||
movies = request.env['movie.movie'].search([('state', '=', 'ongoing')]) |
|||
return http.request.render('show_booking_management.show_movie', |
|||
{'movies': movies}) |
|||
|
|||
@http.route(['/book_now/<int:movie_id>'], type='http', auth="public", |
|||
csrf=False, website=True) |
|||
def book_now(self, movie_id): |
|||
""" Function for rendering booking page while clicking the button book now.""" |
|||
movie = request.env['movie.movie'].browse(movie_id) |
|||
return http.request.render('show_booking_management.book_movie', |
|||
{'movie': movie}) |
|||
|
|||
@http.route('/movie/book_ticket', type='http', auth='public', website=True, |
|||
methods=['POST'], csrf=False) |
|||
def book_ticket(self, **kwargs): |
|||
""" Function for submitting the form and rendering the seat selection chart.""" |
|||
movie_id = request.env['movie.movie'].browse( |
|||
int(kwargs.get('movie_id'))) |
|||
screen_id = request.env['movie.screen'].browse( |
|||
int(kwargs.get('screen'))) |
|||
time_slot_id = request.env['time.slots'].browse( |
|||
int(kwargs.get('time_slots'))) |
|||
booked_seats = request.env['movie.seats'].search([ |
|||
('screen_id', '=', screen_id.id), |
|||
('time_slot_id', '=', int(kwargs.get('time_slots'))), |
|||
('date', '=', kwargs.get('show_date')), |
|||
('is_booked', '=', True) |
|||
]).mapped('seat') |
|||
|
|||
return http.request.render( |
|||
'show_booking_management.seat_selection_template', |
|||
{'screen': screen_id, 'movie': movie_id, |
|||
'time_slot_id': time_slot_id, 'booked_seats': booked_seats, |
|||
'booked_seats_count': len(booked_seats), |
|||
'available_seats_count': screen_id.total_seat_count - len(booked_seats), |
|||
'booking_date': kwargs.get('show_date')}) |
|||
|
|||
@http.route('/movie/confirm_booking', type='http', auth='public', |
|||
website=True, methods=['POST'], csrf=True) |
|||
def confirm_booking(self, **post): |
|||
""" Function for confirming the seats selection and creating invoice.""" |
|||
selected_seats = request.httprequest.form.getlist('selected_seats') |
|||
movie = request.env['movie.movie'].browse(int(post.get('movie_id'))) |
|||
product = request.env.ref('show_booking_management.product_1') |
|||
invoice = request.env['account.move'].sudo().create({ |
|||
'move_type': 'out_invoice', |
|||
'invoice_origin': 'Movie', |
|||
'partner_id': request.env.user.partner_id.id, |
|||
'invoice_date': fields.Date.today(), |
|||
'state': 'draft', |
|||
'invoice_line_ids': [(0, 0, { |
|||
'name': f"Ticket for {movie.name} on {post.get('booking_date')}", |
|||
'product_id': product.id, |
|||
'quantity': len(selected_seats), |
|||
'price_unit': movie.price, |
|||
})], |
|||
}) |
|||
if invoice: |
|||
invoice.sudo().action_post() |
|||
access_token = invoice._portal_ensure_token() |
|||
booking_data = { |
|||
'invoice_id': invoice.id, |
|||
'movie_id': int(post.get('movie_id')), |
|||
'screen_id': int(post.get('screen_id')), |
|||
'time_slot_id': int(post.get('time_slot_id')), |
|||
'booking_date': post.get('booking_date'), |
|||
'selected_seats': selected_seats, |
|||
} |
|||
request.session['movie_booking_data'] = json.dumps(booking_data) |
|||
params = { |
|||
'access_token': access_token, |
|||
'payment_method_id': post.get('payment_method_id'), |
|||
} |
|||
return request.redirect(f'/my/invoices/{invoice.id}?{url_encode(params)}') |
@ -0,0 +1,15 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
<!-- Movie Registration sequence --> |
|||
<record id="movie_registration_sequence" model="ir.sequence"> |
|||
<field name="name">Movie Registration</field> |
|||
<field name="code">movie.registration</field> |
|||
<field name="prefix">MV</field> |
|||
<field name="padding">5</field> |
|||
<field name="number_next">1</field> |
|||
<field name="number_increment">1</field> |
|||
<field name="company_id" eval="False"/> |
|||
</record> |
|||
</data> |
|||
</odoo> |
@ -0,0 +1,61 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<data> |
|||
<!-- Movie ticket email template --> |
|||
<record id="email_template_movie_ticket" model="mail.template"> |
|||
<field name="name">Movie Ticket Booking Confirmation</field> |
|||
<field name="model_id" ref="show_booking_management.model_movie_registration"/> |
|||
<field name="subject">Movie Ticket : {{object.movie_id.name}} On {{object.date}}</field> |
|||
<field name="email_to">{{object.partner_id.email}}</field> |
|||
<field name="body_html" type="html"> |
|||
<p>Your movie ticket booking for |
|||
<strong> |
|||
<t t-out="object.movie_id.name"/> |
|||
</strong> |
|||
has been confirmed. |
|||
</p> |
|||
<h3>Movie Ticket Details:</h3> |
|||
|
|||
<table style="border-collapse: collapse; width: 50%;"> |
|||
<tr> |
|||
<th style="border: 1px solid black; padding: 8px; text-align: left;">Movie</th> |
|||
<td style="border: 1px solid black; padding: 8px;"> |
|||
<strong><t t-out="object.movie_id.name"/></strong> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<th style="border: 1px solid black; padding: 8px; text-align: left;">Screen</th> |
|||
<td style="border: 1px solid black; padding: 8px;"> |
|||
<strong><t t-out="object.screen_id.name"/></strong> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<th style="border: 1px solid black; padding: 8px; text-align: left;">Time Slot</th> |
|||
<td style="border: 1px solid black; padding: 8px;"> |
|||
<strong><t t-out="object.time_slot_id.name"/></strong> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<th style="border: 1px solid black; padding: 8px; text-align: left;">Date</th> |
|||
<td style="border: 1px solid black; padding: 8px;"> |
|||
<strong><t t-out="object.date"/></strong> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<th style="border: 1px solid black; padding: 8px; text-align: left;">Number of Tickets</th> |
|||
<td style="border: 1px solid black; padding: 8px;"> |
|||
<strong><t t-out="object.no_of_tickets"/></strong> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<th style="border: 1px solid black; padding: 8px; text-align: left;">Seats</th> |
|||
<td style="border: 1px solid black; padding: 8px;"> |
|||
<strong><t t-out="', '.join(object.seat_ids.mapped('seat'))"/></strong> |
|||
</td> |
|||
</tr> |
|||
</table> |
|||
<p>Thank you for booking with us.</p> |
|||
</field> |
|||
</record> |
|||
</data> |
|||
</odoo> |
@ -0,0 +1,10 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<odoo> |
|||
<data> |
|||
<!-- Movie Ticket Service Product --> |
|||
<record id="product_1" model="product.product"> |
|||
<field name="name">Movie Ticket</field> |
|||
<field name="type">service</field> |
|||
</record> |
|||
</data> |
|||
</odoo> |
@ -0,0 +1,17 @@ |
|||
<odoo> |
|||
<data> |
|||
<!-- Movie ticket receipt paper format --> |
|||
<record id="paper_format_movie_ticket" model="report.paperformat"> |
|||
<field name="name">Movie Ticket Receipt</field> |
|||
<field name="default" eval="False"/> |
|||
<field name="format">custom</field> |
|||
<field name="page_height">200</field> |
|||
<field name="page_width">80</field> |
|||
<field name="orientation">Portrait</field> |
|||
<field name="margin_top">10</field> |
|||
<field name="margin_bottom">10</field> |
|||
<field name="margin_left">10</field> |
|||
<field name="margin_right">10</field> |
|||
</record> |
|||
</data> |
|||
</odoo> |
@ -0,0 +1,12 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
<!-- Show menu in Website --> |
|||
<record id="website_movie_show" model="website.menu"> |
|||
<field name="name">Show</field> |
|||
<field name="url">/show</field> |
|||
<field name="parent_id" ref="website.main_menu"/> |
|||
<field name="sequence" type="int">50</field> |
|||
</record> |
|||
</data> |
|||
</odoo> |
@ -0,0 +1,6 @@ |
|||
## Module <show_booking_management> |
|||
|
|||
#### 06.09.2024 |
|||
#### Version 17.0.1.0.0 |
|||
##### ADD |
|||
-Initial Commit for Show Booking Management |
@ -0,0 +1,30 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
from . import account_move |
|||
from . import cast_type |
|||
from . import movie_cast |
|||
from . import movie_movie |
|||
from . import movie_registration |
|||
from . import movie_screen |
|||
from . import movie_seats |
|||
from . import show_type |
|||
from . import time_slots |
@ -0,0 +1,33 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class AccountMove(models.Model): |
|||
""" |
|||
Add a Many2one field to link movie tickets with account moves. |
|||
""" |
|||
_inherit = 'account.move' |
|||
|
|||
movie_ticket_id = fields.Many2one('account.move', |
|||
string='Movie Ticket ID', |
|||
help='Movie ticket ID') |
@ -0,0 +1,32 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class CastType(models.Model): |
|||
""" |
|||
Defines a model for Cast Type. |
|||
""" |
|||
_name = 'cast.type' |
|||
_description = 'Cast Type' |
|||
|
|||
name = fields.Char(string='Cast Type', help='Mention the Cast type') |
@ -0,0 +1,34 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class MovieCast(models.Model): |
|||
""" |
|||
Movie Cast model for managing information about movie casts. |
|||
""" |
|||
_name = 'movie.cast' |
|||
_description = 'Movie Cast' |
|||
|
|||
name = fields.Char(string='Name', help='Name of the movie cast') |
|||
cast_id = fields.Many2one('cast.type', string='Cast Type', help='Id of the cast type') |
|||
cast_image = fields.Binary(String='Image', help='Image of the movie cast') |
@ -0,0 +1,157 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
from odoo import api, fields, models |
|||
from odoo.exceptions import ValidationError |
|||
|
|||
|
|||
class MovieMovie(models.Model): |
|||
""" |
|||
Model for managing movie details including name, duration, |
|||
release date, show type, language, poster, time slots, cast, |
|||
screens, price, overview, currency, and status. |
|||
""" |
|||
_name = 'movie.movie' |
|||
_description = 'Movie Movie' |
|||
|
|||
name = fields.Char(string='Name', help='Name of the Movie') |
|||
duration = fields.Float(string='Duration of the movie', |
|||
help='Duration of the Movie') |
|||
release_date = fields.Date(string='Release Date', |
|||
help='Release date of the Movie') |
|||
show_type_ids = fields.Many2many('show.type', |
|||
string='Show Type', |
|||
help='Show type of the movie') |
|||
movie_language_id = fields.Many2one('res.lang', |
|||
string='Movie Language', |
|||
help='Language of the movie') |
|||
movie_poster = fields.Binary(string='Movie Poster', help='Poster of the Movie') |
|||
available_time_slots_ids = fields.Many2many('time.slots', |
|||
string='Time Slots', |
|||
help='Time slots of the movie') |
|||
movie_cast_ids = fields.Many2many('movie.cast', |
|||
string='Movie Cast', |
|||
help='Mention the movie casts') |
|||
available_screens_ids = fields.Many2many('movie.screen', |
|||
string='Screens', |
|||
help='Mention the screens') |
|||
show_start_date = fields.Date(string='Show Start Date', |
|||
help='Mention the show start date') |
|||
show_end_date = fields.Date(string='Show End Date', |
|||
help='Mention the show end date') |
|||
price = fields.Monetary(currency_field='currency_id', string='Price', |
|||
help='Mention the ticket price') |
|||
about_movie = fields.Text(string='About Movie', help='Overview of the movie.') |
|||
currency_id = fields.Many2one('res.currency', |
|||
string='Currency', |
|||
help="Currency", |
|||
required=True, |
|||
default=lambda |
|||
self: self.env.user.company_id.currency_id) |
|||
state = fields.Selection([('draft', 'Draft'), |
|||
('ongoing', 'Ongoing'), |
|||
('cancel', 'Cancelled')], |
|||
string='Status', default='draft', |
|||
help='') |
|||
|
|||
@api.constrains('show_start_date', 'show_end_date', 'release_date') |
|||
def _check_show_start_date(self): |
|||
""" Function for validating show start date and end date """ |
|||
for record in self: |
|||
if (record.show_start_date and record.release_date and |
|||
record.show_start_date < record.release_date): |
|||
raise ValidationError( |
|||
'Show Start date must be on or after the Release Date') |
|||
if (record.show_end_date and record.show_end_date and |
|||
record.show_start_date > record.show_end_date): |
|||
raise ValidationError( |
|||
'Show End date must be on or after the Show Start date') |
|||
|
|||
@api.constrains('available_screens_ids', 'show_start_date', 'show_end_date') |
|||
def _check_screen_availability(self): |
|||
""" Function for checking the screen availability if the |
|||
screen is already booked for another movie it raises error""" |
|||
for record in self: |
|||
if record.show_start_date and record.show_end_date: |
|||
overlapping_movies = self.env['movie.movie'].search([ |
|||
('id', '!=', record.id), |
|||
('available_screens_ids', 'in', |
|||
record.available_screens_ids.ids), |
|||
('show_start_date', '<=', record.show_end_date), |
|||
('show_end_date', '>=', record.show_start_date), |
|||
]) |
|||
if overlapping_movies: |
|||
raise ValidationError( |
|||
'One or more of the selected screens are already booked ' |
|||
'for another movie during this period.') |
|||
|
|||
@api.model |
|||
def create(self, vals): |
|||
"""Supering create function to check screen availability""" |
|||
res = super(MovieMovie, self).create(vals) |
|||
res._check_screen_availability() |
|||
return res |
|||
|
|||
@api.model |
|||
def write(self, vals): |
|||
"""Supering create function to check screen availability""" |
|||
res = super(MovieMovie, self).write(vals) |
|||
self._check_screen_availability() |
|||
return res |
|||
|
|||
@api.model |
|||
def check_shows_on_date(self, date, selected_movie): |
|||
""" Function for searching the movies based on the date from js.""" |
|||
movie = self.search([('id', '=', selected_movie), |
|||
('show_start_date', '<=', date), |
|||
('show_end_date', '>=', date)]) |
|||
return bool(movie) |
|||
|
|||
def action_start_show(self): |
|||
""" Function for changing the state into ongoing.""" |
|||
for rec in self: |
|||
if fields.Date.today() >= rec.show_start_date: |
|||
self.write({'state': 'ongoing'}) |
|||
else: |
|||
raise ValidationError( |
|||
'Show Starts only based on the Show Start Date') |
|||
|
|||
def action_cancel_show(self): |
|||
""" Function for changing the state into cancel.""" |
|||
self.write({'state': 'cancel'}) |
|||
|
|||
@api.model |
|||
def update_seats(self, screen_id, time_slot_id, booking_date): |
|||
""" |
|||
Update the seats availability based on the screen, time slot, and booking date. |
|||
""" |
|||
booked_seats = self.env['movie.seats'].search([ |
|||
('screen_id', '=', int(screen_id)), |
|||
('time_slot_id', '=', int(time_slot_id)), |
|||
('date', '=', booking_date), |
|||
('is_booked', '=', True) |
|||
]).mapped('seat') |
|||
time_slot = self.env['time.slots'].browse(int(time_slot_id)).name |
|||
screen = self.env['movie.screen'].browse(int(screen_id)) |
|||
return {'booked_seats': booked_seats, |
|||
'time_slot': time_slot, |
|||
'booked_seats_count': len(booked_seats), |
|||
'available_seats_count': screen.total_seat_count - len(booked_seats)} |
@ -0,0 +1,213 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
from odoo import api, fields, models |
|||
from odoo.exceptions import ValidationError |
|||
|
|||
|
|||
class MovieRegistration(models.Model): |
|||
""" |
|||
Model for managing movie registrations including details like partner, |
|||
movie, date, time slot, screen, tickets, etc. |
|||
""" |
|||
_name = 'movie.registration' |
|||
_description = 'Movie Registration' |
|||
|
|||
name = fields.Char(required=True, copy=False, |
|||
default='New', readonly=True, |
|||
help='Name of the Movie Ticket') |
|||
partner_id = fields.Many2one('res.partner', string='Select Partner', |
|||
help='Mention the partner') |
|||
movie_id = fields.Many2one('movie.movie', string='Select Movie', |
|||
domain="[('id', 'in', available_movie_ids)]", |
|||
required=True, help='Mention the movie id') |
|||
movie_type = fields.Many2many('show.type', related='movie_id.show_type_ids', |
|||
help='Show type of the movie') |
|||
movie_lang = fields.Many2one('res.lang', string='Movie Langauge', |
|||
related='movie_id.movie_language_id', |
|||
help='Language of the movie') |
|||
date = fields.Date(string='Date', default=fields.Date.today(), |
|||
required=True, help='Mention the date for booking.') |
|||
time_slot_id = fields.Many2one('time.slots', |
|||
string='Select time slot', |
|||
domain="[('id', 'in', available_time_slot_ids)]", |
|||
required=True, help='Mention the time slots of the movie') |
|||
screen_id = fields.Many2one('movie.screen', string='Select Screen', |
|||
domain="[('id', 'in', available_screens_ids)]", |
|||
required=True, help='Mention the screen of the movie') |
|||
available_movie_ids = fields.Many2many('movie.movie', |
|||
string='Available movies', |
|||
help='Mention the available movies') |
|||
available_time_slot_ids = fields.Many2many('time.slots', |
|||
string='Available time slots', |
|||
compute='_compute_available_time_slot_ids', |
|||
help='Mention the available time slots') |
|||
available_screens_ids = fields.Many2many('movie.screen', |
|||
string='Available screens', |
|||
help='Mention the available screen') |
|||
movie_price = fields.Monetary(string='Movie Price', |
|||
related='movie_id.price', |
|||
help='Price of the movie ticket') |
|||
currency_id = fields.Many2one('res.currency', string='Currency', |
|||
help="Currency", |
|||
required=True, |
|||
default=lambda |
|||
self: self.env.user.company_id.currency_id) |
|||
no_of_tickets = fields.Integer(string='Number of tickets', default=1, |
|||
help='Mention the number of tickets') |
|||
movie_poster = fields.Binary(related='movie_id.movie_poster', |
|||
string='Movie poster', |
|||
help='Poster of the movie.') |
|||
movie_cast_ids = fields.Many2many(related='movie_id.movie_cast_ids', |
|||
string='Movie Cast', readonly=True, |
|||
help='Movie casts') |
|||
seat_ids = fields.One2many('movie.seats', 'movie_registration_id', |
|||
string="Seats", help='Mention the seat ids') |
|||
qr_code = fields.Binary(string='Qr Code', help='Qr code containing ticket details') |
|||
state = fields.Selection([('draft', 'Draft'), |
|||
('done', 'Done'), |
|||
('invoiced', 'Invoiced')], string='Status', |
|||
default='draft', help='Status of the movie registration') |
|||
|
|||
def action_submit(self): |
|||
""" Function for writing the state into done.""" |
|||
self.write({'state': 'done'}) |
|||
|
|||
def action_invoice(self): |
|||
""" Function for creating invoice.""" |
|||
product_id = self.env.ref('show_booking_management.product_1') |
|||
try: |
|||
move = self.env['account.move'].create([ |
|||
{ |
|||
'move_type': 'out_invoice', |
|||
'partner_id': self.partner_id.id, |
|||
'movie_ticket_id': self.id, |
|||
'date': self.date, |
|||
'invoice_date': fields.Date.today(), |
|||
'invoice_line_ids': [ |
|||
(0, 0, |
|||
{ |
|||
'product_id': product_id.id, |
|||
'name': product_id.name, |
|||
'quantity': self.no_of_tickets, |
|||
'price_unit': self.movie_id.price, |
|||
})], |
|||
}, ]) |
|||
self.write({'state': 'invoiced'}) |
|||
move.action_post() |
|||
return { |
|||
'name': 'Invoice', |
|||
'res_id': move.id, |
|||
'res_model': 'account.move', |
|||
'view_id': False, |
|||
'view_mode': 'form', |
|||
'type': 'ir.actions.act_window', |
|||
} |
|||
except: |
|||
raise ValidationError('Invoice Creation Failed!') |
|||
|
|||
@api.depends('movie_id') |
|||
def _compute_available_time_slot_ids(self): |
|||
""" Function for computing time slots and screens.""" |
|||
for record in self: |
|||
record.available_time_slot_ids = record.movie_id.available_time_slots_ids.ids |
|||
record.available_screens_ids = record.movie_id.available_screens_ids.ids |
|||
|
|||
@api.onchange('date') |
|||
def fetch_movies(self): |
|||
""" Function for validating date and fetching movies based on the date.""" |
|||
for record in self: |
|||
if record.date < fields.Date.today(): |
|||
raise ValidationError('The date must be greater than or equal to today\'s date.') |
|||
record.movie_id = None |
|||
record.available_movie_ids = None |
|||
movies_list = self.env['movie.movie'].search([ |
|||
('show_start_date', '<=', record.date), |
|||
('show_end_date', '>=', record.date), |
|||
]).ids |
|||
record.available_movie_ids = movies_list |
|||
|
|||
def check_seat_availability(self): |
|||
""" Function for checking seat availability""" |
|||
reserved_seats = sum(self.search([ |
|||
('date', '=', self.date), |
|||
('time_slot_id', '=', self.time_slot_id.id), |
|||
('screen_id', '=', self.screen_id.id), |
|||
('state', '=', 'invoiced') |
|||
]).mapped('no_of_tickets')) + self.no_of_tickets |
|||
if reserved_seats > self.screen_id.total_seat_count: |
|||
raise ValidationError('Selected screen is already full') |
|||
|
|||
@api.model |
|||
def create(self, vals): |
|||
"""Supering create function to check screen availability""" |
|||
if vals.get('name', 'New') == 'New': |
|||
vals['name'] = self.env['ir.sequence'].next_by_code( |
|||
'movie.registration') |
|||
res = super(MovieRegistration, self).create(vals) |
|||
res.check_seat_availability() |
|||
return res |
|||
|
|||
@api.constrains('no_of_tickets') |
|||
def check_seat(self): |
|||
""" Function for checking seat availability based on the number of tickets""" |
|||
self.check_seat_availability() |
|||
|
|||
@api.onchange('movie_id') |
|||
def set_values(self): |
|||
""" Function for resetting time slot and screen while changing movie.""" |
|||
for record in self: |
|||
record.update({'time_slot_id': None, 'screen_id': None}) |
|||
|
|||
def action_generate_ticket_pdf(self): |
|||
""" Function for downloading ticket pdf.""" |
|||
return self.env.ref( |
|||
'show_booking_management.action_report_movie_ticket').report_action(self) |
|||
|
|||
@api.model |
|||
def check_seat_available(self, date, time_slot_id, screen_id, ticket_count): |
|||
""" Function for updating the status of the seats availability based |
|||
on the movie time slot and screen selected""" |
|||
screen = self.env['movie.screen'].browse(int(screen_id)) |
|||
reserved_seats = sum(self.search([ |
|||
('date', '=', date), |
|||
('time_slot_id', '=', int(time_slot_id)), |
|||
('screen_id', '=', int(screen_id)), |
|||
('state', '=', 'invoiced') |
|||
]).mapped('no_of_tickets')) |
|||
if reserved_seats + int(ticket_count) > screen.total_seat_count: |
|||
return { |
|||
'Status': 'Failed', |
|||
'Error': f"The selected screen has only " |
|||
f"{screen.total_seat_count - reserved_seats} seats left!" |
|||
} |
|||
return {'Status': 'Success'} |
|||
|
|||
def action_open_invoices(self): |
|||
""" Function for viewing created invoices""" |
|||
return { |
|||
'name': 'Invoice', |
|||
'domain': [('movie_ticket_id', '=', self.id)], |
|||
'res_model': 'account.move', |
|||
'view_id': False, |
|||
'view_mode': 'tree,form', |
|||
'type': 'ir.actions.act_window', |
|||
} |
@ -0,0 +1,50 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
from odoo import api, fields, models |
|||
|
|||
|
|||
class MovieScreen(models.Model): |
|||
""" |
|||
Model for managing movie screens with details like name, total rows, |
|||
seats per row, and total seat count. |
|||
""" |
|||
_name = 'movie.screen' |
|||
_description = 'Movie Screen' |
|||
|
|||
name = fields.Char(string='Name of the screen', |
|||
help='Mention the name of the screen') |
|||
total_rows = fields.Integer(string='Number of total Rows', |
|||
help='Mention the number of total rows.') |
|||
no_of_seat_row = fields.Integer(string='Number of seat per row', |
|||
help='Mention the number of seats per row') |
|||
total_seat_count = fields.Integer(string='Total seats', |
|||
compute='_compute_total_seat_count', |
|||
help='Calculates the total seats') |
|||
|
|||
@api.constrains('total_rows', 'no_of_seat_row') |
|||
def _compute_total_seat_count(self): |
|||
""" Function for computing total seats in the screen.""" |
|||
for record in self: |
|||
if record.total_rows and record.no_of_seat_row: |
|||
record.total_seat_count = record.total_rows * record.no_of_seat_row |
|||
else: |
|||
record.total_seat_count = 0 |
@ -0,0 +1,41 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class MovieSeats(models.Model): |
|||
""" |
|||
Movie Seats model for managing seat bookings. |
|||
""" |
|||
_name = 'movie.seats' |
|||
_description = 'Movie Seats' |
|||
|
|||
screen_id = fields.Many2one('movie.screen', 'Screen', |
|||
required=True, help='Mention the screen id') |
|||
time_slot_id = fields.Many2one('time.slots', 'Time Slot', |
|||
required=True, help='Mention the time slot id') |
|||
movie_registration_id = fields.Many2one('movie.registration', |
|||
'Booking ID', required=True, |
|||
help='Mention the movie registration id') |
|||
date = fields.Date(string='Date', help='Mention the date', required=True) |
|||
seat = fields.Char(string='Seat', required=True, help='Mention the seats') |
|||
is_booked = fields.Boolean('Is booked', help='Check if is booked true') |
@ -0,0 +1,34 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
from odoo import fields, models |
|||
|
|||
|
|||
class ShowType(models.Model): |
|||
""" |
|||
Show Type model for managing different types of shows. |
|||
""" |
|||
_name = 'show.type' |
|||
_description = 'Show Type' |
|||
|
|||
name = fields.Char(string='Show Type', |
|||
required=True, |
|||
help='Name of the Show type') |
@ -0,0 +1,60 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################# |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: Cybrosys Techno Solutions(<https://www.cybrosys.com>) |
|||
# |
|||
# You can modify it under the terms of the GNU AFFERO |
|||
# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. |
|||
# |
|||
# This program is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE |
|||
# (AGPL v3) along with this program. |
|||
# If not, see <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################# |
|||
from datetime import datetime |
|||
from odoo import api, fields, models |
|||
from odoo.exceptions import ValidationError |
|||
|
|||
|
|||
class TimeSlots(models.Model): |
|||
""" |
|||
Time slots model for managing different time slots for show. |
|||
""" |
|||
_name = 'time.slots' |
|||
_description = 'Time Slots' |
|||
|
|||
name = fields.Char(string='Time Slot', default='New', |
|||
readonly=True, help='Mention the name of the Time slots') |
|||
movie_time = fields.Char(string='Movie Time', help='Mention the slot time') |
|||
|
|||
_sql_constraints = [ |
|||
('name_uniq', 'unique(name)', "Name should be unique") |
|||
] |
|||
|
|||
@api.model |
|||
def create(self, vals): |
|||
"""Supering create function to update name.""" |
|||
if vals['movie_time']: |
|||
vals['name'] = datetime.strptime(vals['movie_time'], "%H:%M").strftime("%I:%M %p") |
|||
vals['movie_time'] = vals['movie_time'].replace(":", ".") |
|||
else: |
|||
raise ValidationError('Please mention time!!') |
|||
return super().create(vals) |
|||
|
|||
@api.model |
|||
def write(self, vals): |
|||
"""Supering write function to update name.""" |
|||
if vals['movie_time']: |
|||
vals['name'] = datetime.strptime(vals['movie_time'], |
|||
"%H:%M").strftime("%I:%M %p") |
|||
vals['movie_time'] = vals['movie_time'].replace(":", ".") |
|||
res = super(TimeSlots, self).write(vals) |
|||
return res |
@ -0,0 +1,77 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<!-- Movie ticket report template --> |
|||
<template id="report_movie_ticket"> |
|||
<t t-call="web.basic_layout"> |
|||
<div class="page"> |
|||
<div class="oe_structure"/> |
|||
<div class="pos-receipt" style="width:80mm;padding:10px;font-size:10pt;"> |
|||
<t t-foreach="docs" t-as="doc"> |
|||
<div class="receipt-header" style="text-align: center;margin-bottom: 10px;"> |
|||
<h2>Movie Ticket</h2> |
|||
<h3><t t-esc="doc.name"/></h3> |
|||
</div> |
|||
<br/> |
|||
<div style="margin-top:10px;text-align: center;border-top: 1px solid #000;border-bottom: 1px solid #000;"> |
|||
<div class="receipt-center-align" style="text-align: center;padding: 5px;"> |
|||
<img t-attf-src="data:image/png;base64,#{doc.qr_code}" style="width:100px; height:100px;"/> |
|||
</div> |
|||
</div> |
|||
<div class="receipt-ticket-data" style="margin-top: 10px;"> |
|||
<div style="text-align: center;margin:10px;"> |
|||
<img t-attf-src="data:image/png;base64,#{doc.movie_id.movie_poster}" style="width:150px; height:200px;"/> |
|||
</div> |
|||
<table class="table table-hover" style="width:100%;margin-top: 10px;display: flex;"> |
|||
<tr style="display: flex;"> |
|||
<td style="padding: 5px;">Movie:</td> |
|||
<td style="padding: 5px;"><strong><t t-esc="doc.movie_id.name"/></strong></td> |
|||
</tr> |
|||
<tr> |
|||
<td style="padding: 5px;">Date:</td> |
|||
<td style="padding: 5px;"><strong><t t-esc="doc.date"/></strong></td> |
|||
</tr> |
|||
<tr> |
|||
<td style="padding: 5px;">Time:</td> |
|||
<td style="padding: 5px;"><strong><t t-esc="doc.time_slot_id.name"/></strong></td> |
|||
</tr> |
|||
<tr> |
|||
<td style="padding: 5px;">Screen:</td> |
|||
<td style="padding: 5px;"><strong><t t-esc="doc.screen_id.name"/></strong></td> |
|||
</tr> |
|||
<tr> |
|||
<td style="padding: 5px;">No of Tickets:</td> |
|||
<td style="padding: 5px;"><strong><t t-esc="doc.no_of_tickets"/></strong></td> |
|||
</tr> |
|||
<tr> |
|||
<td style="padding: 5px;">Seats:</td> |
|||
<td> |
|||
<t t-foreach="doc.seat_ids" t-as="seat"> |
|||
<span style="padding: 5px;background:#7ec4ed;border-radius: 10px;"><strong><t t-esc="seat.seat"/></strong></span> |
|||
</t> |
|||
</td> |
|||
</tr> |
|||
</table> |
|||
</div> |
|||
<div class="receipt-footer" style="margin-top:20px;text-align: center;"> |
|||
<div class="receipt-center-align" style="text-align: center;padding-top: 5px;"> |
|||
<strong>Enjoy Your Movie!</strong> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
</template> |
|||
<!-- Action report movie ticket --> |
|||
<record id="action_report_movie_ticket" model="ir.actions.report"> |
|||
<field name="name">Movie Ticket</field> |
|||
<field name="model">movie.registration</field> |
|||
<field name="report_type">qweb-pdf</field> |
|||
<field name="report_name">show_booking_management.report_movie_ticket</field> |
|||
<field name="report_file">show_booking_management.report_movie_ticket</field> |
|||
<field name="binding_model_id" |
|||
ref="show_booking_management.model_movie_registration"/> |
|||
<field name="paperformat_id" |
|||
ref="show_booking_management.paper_format_movie_ticket"/> |
|||
</record> |
|||
</odoo> |
|
@ -0,0 +1,8 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<!-- Group Movie Admin --> |
|||
<record id="show_booking_management_group_admin" model="res.groups"> |
|||
<field name="name">Show Booking Management Admin</field> |
|||
<field name="users" eval="[(4, ref('base.user_admin'))]"/> |
|||
</record> |
|||
</odoo> |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 628 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: 542 B |
After Width: | Height: | Size: 576 B |
After Width: | Height: | Size: 733 B |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 4.0 KiB |
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: 2.0 KiB |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 653 B |
After Width: | Height: | Size: 905 B |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 2.3 KiB |
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: 3.7 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 912 KiB |
After Width: | Height: | Size: 81 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 85 KiB |
After Width: | Height: | Size: 125 KiB |
After Width: | Height: | Size: 256 KiB |
After Width: | Height: | Size: 121 KiB |
After Width: | Height: | Size: 126 KiB |
After Width: | Height: | Size: 132 KiB |
After Width: | Height: | Size: 140 KiB |
After Width: | Height: | Size: 62 KiB |
After Width: | Height: | Size: 58 KiB |
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 193 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 51 KiB |
After Width: | Height: | Size: 38 KiB |
After Width: | Height: | Size: 49 KiB |
After Width: | Height: | Size: 185 KiB |
After Width: | Height: | Size: 99 KiB |
After Width: | Height: | Size: 196 KiB |
After Width: | Height: | Size: 389 KiB |
After Width: | Height: | Size: 880 KiB |
After Width: | Height: | Size: 90 KiB |
After Width: | Height: | Size: 4.3 KiB |
@ -0,0 +1,137 @@ |
|||
.movie_details{ |
|||
display: -webkit-box; |
|||
} |
|||
|
|||
.param{ |
|||
margin-left:10px; |
|||
} |
|||
|
|||
.sidebar{ |
|||
max-width:280px; |
|||
margin-left: 20px; |
|||
margin-right:20px; |
|||
margin-bottom:20px; |
|||
padding: 20px; |
|||
background-color: #c9e3fd; |
|||
border: 1px solid #ddd; |
|||
border-radius: 5px; |
|||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); |
|||
} |
|||
|
|||
.seating-chart-container { |
|||
position: relative; |
|||
display: ruby-text; |
|||
max-width: 100%; |
|||
overflow-x: auto; |
|||
user-select: none; |
|||
} |
|||
|
|||
.seating-chart { |
|||
flex-grow: 1; |
|||
overflow-x: auto; |
|||
} |
|||
|
|||
.seat-row { |
|||
display: flex; |
|||
align-items: center; |
|||
margin-bottom: 10px; |
|||
} |
|||
|
|||
.seat-row-inner { |
|||
display: flex; |
|||
gap: 10px; |
|||
margin-bottom: 10px; |
|||
} |
|||
|
|||
.seat-wrapper { |
|||
display: inline-block; |
|||
} |
|||
|
|||
.seat-label { |
|||
border-radius: 5px; |
|||
width: 30px; |
|||
height: 30px; |
|||
text-align: center; |
|||
line-height: 30px; |
|||
cursor: pointer; |
|||
background-color: #d3d3d3; |
|||
} |
|||
|
|||
.seat-checkbox { |
|||
display: none; |
|||
} |
|||
|
|||
.seat-checkbox:checked + .seat-label { |
|||
background-color: #28a745; |
|||
color: white; |
|||
} |
|||
|
|||
.seat-checkbox:disabled + .seat-label { |
|||
background-color: #dc3545; |
|||
color: white; |
|||
cursor: not-allowed; |
|||
} |
|||
|
|||
.screen{ |
|||
text-align: center; |
|||
background: darkseagreen; |
|||
padding: 10px; |
|||
margin-top: 5rem; |
|||
margin-bottom: 10px; |
|||
border-radius: 15px; |
|||
} |
|||
|
|||
.button-container { |
|||
position: absolute; |
|||
right: 25%; |
|||
} |
|||
|
|||
.seat-demo-booked{ |
|||
width: 30px; |
|||
height: 30px; |
|||
border-radius: 5px; |
|||
text-align: center; |
|||
line-height: 30px; |
|||
background-color: #dc3545; |
|||
color: white; |
|||
} |
|||
|
|||
.seat-demo-selected{ |
|||
width: 30px; |
|||
height: 30px; |
|||
border-radius: 5px; |
|||
text-align: center; |
|||
line-height: 30px; |
|||
background-color: #28a745; |
|||
color: white; |
|||
} |
|||
|
|||
.seat-demo-available{ |
|||
width: 30px; |
|||
height: 30px; |
|||
border-radius: 5px; |
|||
text-align: center; |
|||
line-height: 30px; |
|||
background-color: #d3d3d3; |
|||
} |
|||
|
|||
.card{ |
|||
min-width: 300px; |
|||
margin-right: 15px; |
|||
margin-top: 20px; |
|||
margin-bottom: 20px; |
|||
} |
|||
|
|||
.card-body{ |
|||
justify-content: center; |
|||
} |
|||
|
|||
.text{ |
|||
font-family: system-ui; |
|||
font-size: larger; |
|||
} |
|||
|
|||
.time-slot-btn { |
|||
margin: 5px; |
|||
cursor: pointer; |
|||
} |
After Width: | Height: | Size: 998 B |
@ -0,0 +1,51 @@ |
|||
/** @odoo-module **/ |
|||
import publicWidget from "@web/legacy/js/public/public_widget"; |
|||
import { jsonrpc } from "@web/core/network/rpc_service"; |
|||
|
|||
publicWidget.registry.bookShow = publicWidget.Widget.extend({ |
|||
/* Extending widget and creating book show */ |
|||
selector: '.book_show', |
|||
events: { |
|||
'change #choose_date' : 'CheckShows', |
|||
}, |
|||
CheckShows: function (ev) { |
|||
/* Function for validating date. */ |
|||
const selectedDate = new Date(ev.currentTarget.value); |
|||
const currentDate = new Date(); |
|||
selectedDate.setHours(0, 0, 0, 0); |
|||
currentDate.setHours(0, 0, 0, 0); |
|||
const movieId = this.$el.find('form')[0].dataset.movieId |
|||
this.$el.find('form')[0][4].value = '' |
|||
if (selectedDate < currentDate){ |
|||
ev.currentTarget.value = '' |
|||
this.$el.find('#error_box').text('Please select a date in the future!') |
|||
this.$el.find('#error_box').show() |
|||
} |
|||
else{ |
|||
this.$el.find('#error_box').hide() |
|||
this.checkShowsOnDate(ev, selectedDate, movieId); |
|||
} |
|||
}, |
|||
|
|||
checkShowsOnDate: function (ev, date, movieId) { |
|||
/* Function for checking shows on the selected date. */ |
|||
const formattedDate = new Date(date.getTime() - (date.getTimezoneOffset() * 60000)) |
|||
.toISOString().split('T')[0]; |
|||
return jsonrpc("/web/dataset/call_kw", { |
|||
model: 'movie.movie', |
|||
method: 'check_shows_on_date', |
|||
args: [formattedDate,movieId], |
|||
kwargs: {} |
|||
}).then((result) => { |
|||
if (!result){ |
|||
ev.currentTarget.value = '' |
|||
this.$el.find('#error_box').text('There is no shows on the selected date!!') |
|||
this.$el.find('#error_box').show() |
|||
this.$el.find('.tickets_section').hide() |
|||
} |
|||
else{ |
|||
this.$el.find('.tickets_section').show() |
|||
} |
|||
}) |
|||
}, |
|||
}); |
@ -0,0 +1,57 @@ |
|||
/** @odoo-module **/ |
|||
import publicWidget from "@web/legacy/js/public/public_widget"; |
|||
import { jsonrpc } from "@web/core/network/rpc_service"; |
|||
|
|||
publicWidget.registry.selectSeat = publicWidget.Widget.extend({ |
|||
/* Extending widget and creating selectSeat */ |
|||
selector: '.seat-selection', |
|||
events: { |
|||
'change .seat-checkbox': 'UpdateSeatCount', |
|||
'click .time-slot-btn': 'UpdateSeatChart', |
|||
}, |
|||
UpdateSeatCount: function (ev) { |
|||
/* Function for hiding and showing the |
|||
confirm button based on selecting seats. */ |
|||
var checked_seats = this.$el.find('.seat-checkbox:checked:not(:disabled)') |
|||
if (checked_seats.length > 0){ |
|||
this.$el.find('.button-container').show() |
|||
this.$el.find('.selected-seats').show() |
|||
this.$el.find('.seat-demo-selected')[0].innerText = checked_seats.length |
|||
}else{ |
|||
this.$el.find('.button-container').hide() |
|||
this.$el.find('.selected-seats').hide() |
|||
} |
|||
}, |
|||
UpdateSeatChart: function(ev){ |
|||
/* Function for updating the seat chart and side bar contents |
|||
based on the clicking the time slots */ |
|||
this.$el.find('.time-slot-btn').removeClass('active'); |
|||
ev.currentTarget.classList.add("active") |
|||
this.$el.find('.seat-demo-selected')[0].innerText = 0; |
|||
const screenId = this.$el.find('input[name="screen_id"]').val(); |
|||
const timeSlotId = ev.currentTarget.dataset.timeSlotId |
|||
const booking_date = this.$el.find('input[name="booking_date"]').val(); |
|||
this.$el.find('input[name="time_slot_id"]').val(timeSlotId); |
|||
jsonrpc("/web/dataset/call_kw", { |
|||
model: 'movie.movie', |
|||
method: 'update_seats', |
|||
args: [screenId,timeSlotId,booking_date], |
|||
kwargs: {} |
|||
}).then((result) => { |
|||
this.$el.siblings().find('.sidebar_timeslot')[0].innerText = result.time_slot; |
|||
this.$el.siblings().find('.seat-demo-booked')[0].innerText = result.booked_seats_count; |
|||
this.$el.siblings().find('.seat-demo-available')[0].innerText = result.available_seats_count; |
|||
var bookedSeats = result.booked_seats; |
|||
this.$el.find('.seat-checkbox').each(function() { |
|||
var seatId = this.value; |
|||
if (bookedSeats.includes(seatId)) { |
|||
this.checked = true; |
|||
this.disabled = true; |
|||
} else { |
|||
this.checked = false; |
|||
this.disabled = false; |
|||
} |
|||
}); |
|||
}) |
|||
}, |
|||
}) |
@ -0,0 +1,35 @@ |
|||
/** @odoo-module **/ |
|||
import { registry } from "@web/core/registry"; |
|||
import { useInputField } from "@web/views/fields/input_field_hook"; |
|||
const { Component, useRef } = owl; |
|||
/** |
|||
* We define this module for the function of creating a time picker widget |
|||
* |
|||
*/ |
|||
export class FieldTimePicker extends Component { |
|||
setup() { |
|||
this.input = useRef('input_time'); |
|||
useInputField({ getValue: () => this.props.record.data[this.props.name] || "", refName: "input_time" }); |
|||
} |
|||
|
|||
onBlur(){ |
|||
/** |
|||
* Handle the blur event for the timepicker input field. |
|||
* |
|||
* This function is responsible for handling the blur event on the timepicker input field. |
|||
* It checks if the close button is present in the timepicker, and if so, it adds a click event |
|||
* listener to it to handle the closing of the timepicker. |
|||
* |
|||
* @returns {void} |
|||
*/ |
|||
this.props.record.update({ [this.props.name] : this.input.el?.value}) |
|||
} |
|||
} |
|||
// Set the template for the FieldTimePicker component
|
|||
FieldTimePicker.template = 'FieldTimePicker'; |
|||
FieldTimePicker.supportedTypes = ["char"] |
|||
export const timepicker = { |
|||
component: FieldTimePicker |
|||
} |
|||
// Add the timepicker to the fields category
|
|||
registry.category("fields").add("timepicker_time", timepicker); |
@ -0,0 +1,9 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<templates xml:space="preserve"> |
|||
<t t-name="FieldTimePicker" owl="1"> |
|||
<!-- FieldTimePicker template to add input field --> |
|||
<div class="input-group timepicker-component"> |
|||
<input type="time" class="time-input" t-ref="input_time" t-on-blur="onBlur"/> |
|||
</div> |
|||
</t> |
|||
</templates> |
@ -0,0 +1,22 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<!-- Cast type tree view --> |
|||
<record id="cast_type_view_tree" model="ir.ui.view"> |
|||
<field name="name">cast.type.view.tree</field> |
|||
<field name="model">cast.type</field> |
|||
<field name="arch" type="xml"> |
|||
<tree editable="bottom"> |
|||
<field name="name" required="1"/> |
|||
</tree> |
|||
</field> |
|||
</record> |
|||
<!-- Action Cast Type --> |
|||
<record id="cast_type_action" model="ir.actions.act_window"> |
|||
<field name="name">Cast Type</field> |
|||
<field name="res_model">cast.type</field> |
|||
<field name="view_mode">tree</field> |
|||
</record> |
|||
<!-- MenuItem for cast type --> |
|||
<menuitem id="movie_cast_type" name="Cast Type" |
|||
parent="show_booking_management.movie_configuration" action="cast_type_action"/> |
|||
</odoo> |
@ -0,0 +1,45 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<!-- Movie Cast Form View --> |
|||
<record id="movie_cast_view_form" model="ir.ui.view"> |
|||
<field name="name">movie.cast.view.form</field> |
|||
<field name="model">movie.cast</field> |
|||
<field name="arch" type="xml"> |
|||
<form string="Movie Cast"> |
|||
<sheet> |
|||
<group> |
|||
<group> |
|||
<field name="name" required="1"/> |
|||
<field name="cast_id" required="1"/> |
|||
</group> |
|||
<group> |
|||
<field name="cast_image" widget='image' nolabel="1"/> |
|||
</group> |
|||
</group> |
|||
</sheet> |
|||
</form> |
|||
</field> |
|||
</record> |
|||
<!-- Movie Cast Tree View --> |
|||
<record id="movie_cast_view_tree" model="ir.ui.view"> |
|||
<field name="name">movie.cast.view.tree</field> |
|||
<field name="model">movie.cast</field> |
|||
<field name="arch" type="xml"> |
|||
<tree> |
|||
<field name="name"/> |
|||
<field name="cast_id"/> |
|||
<field name="cast_image" widget="image" options="{'size': [100, 100]}"/> |
|||
</tree> |
|||
</field> |
|||
</record> |
|||
<!-- Action Movie Cast --> |
|||
<record id="movie_cast_action" model="ir.actions.act_window"> |
|||
<field name="name">Show Cast</field> |
|||
<field name="res_model">movie.cast</field> |
|||
<field name="view_mode">tree,form</field> |
|||
</record> |
|||
<!-- MenuItem for movie cast --> |
|||
<menuitem id="movie_movie_cast" name="Show Cast" |
|||
parent="show_booking_management.movie_configuration" |
|||
action="movie_cast_action"/> |
|||
</odoo> |
@ -0,0 +1,158 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<!-- Movie Search View --> |
|||
<record id="movie_movie_view_search" model="ir.ui.view"> |
|||
<field name="name">movie.movie.view.search</field> |
|||
<field name="model">movie.movie</field> |
|||
<field name="arch" type="xml"> |
|||
<search string="Search Tips"> |
|||
<field name="name" string="Name"/> |
|||
<filter name="filter_movies_ongoing" string="Ongoing" domain="[('state','=','ongoing')]"/> |
|||
<filter name="filter_movies_draft" string="Draft" domain="[('state','=','draft')]"/> |
|||
<filter name="filter_movies_cancel" string="Cancelled" domain="[('state','=','cancel')]"/> |
|||
<group expand="0" string="Group By"> |
|||
<filter name="State" string="State" |
|||
context="{'group_by':'state'}"/> |
|||
<filter name="Language" string="Language" |
|||
context="{'group_by':'movie_language_id'}"/> |
|||
<filter name="Release Date" string="Release Date" |
|||
context="{'group_by':'release_date'}"/> |
|||
</group> |
|||
</search> |
|||
</field> |
|||
</record> |
|||
<!-- Movie Kanban View --> |
|||
<record id="movie_movie_view_kanban" model="ir.ui.view"> |
|||
<field name="name">movie.movie.view.kanban</field> |
|||
<field name="model">movie.movie</field> |
|||
<field name="arch" type="xml"> |
|||
<kanban sample="1"> |
|||
<field name="id"/> |
|||
<field name="movie_language_id"/> |
|||
<field name="movie_poster"/> |
|||
<field name="show_type_ids"/> |
|||
<field name="available_time_slots_ids"/> |
|||
<field name="price"/> |
|||
<templates> |
|||
<t t-name="kanban-box"> |
|||
<div class="oe_kanban_global_click"> |
|||
<div class="o_kanban_image"> |
|||
<img t-att-src="kanban_image('movie.movie', 'movie_poster', record.id.raw_value)" |
|||
alt="Movie Poster"/> |
|||
</div> |
|||
<div class="oe_kanban_details"> |
|||
<strong class="o_kanban_record_title"> |
|||
<field name="name"/> |
|||
</strong> |
|||
<ul> |
|||
<li> |
|||
<strong>Language: |
|||
<field name="movie_language_id"/> |
|||
</strong> |
|||
</li> |
|||
<li> |
|||
<strong>Price: |
|||
<field name="price"/> |
|||
</strong> |
|||
</li> |
|||
<li> |
|||
<strong>Show Type: |
|||
<field name="show_type_ids" widget="many2many_tags"/> |
|||
</strong> |
|||
</li> |
|||
<li> |
|||
<strong>Time Slots: |
|||
<field name="available_time_slots_ids" widget="many2many_tags"/> |
|||
</strong> |
|||
</li> |
|||
<li> |
|||
<strong>Screen: |
|||
<field name="available_screens_ids" widget="many2many_tags"/> |
|||
</strong> |
|||
</li> |
|||
</ul> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
</templates> |
|||
</kanban> |
|||
</field> |
|||
</record> |
|||
<!-- Movie Form View --> |
|||
<record id="movie_movie_view_form" model="ir.ui.view"> |
|||
<field name="name">movie.movie.view.form</field> |
|||
<field name="model">movie.movie</field> |
|||
<field name="arch" type="xml"> |
|||
<form string="Movie Movie"> |
|||
<header> |
|||
<button name="action_start_show" type="object" string="Start Show" |
|||
invisible="state not in ['draft']" class="btn-primary"/> |
|||
<button name="action_cancel_show" type="object" string="Cancel Show" |
|||
invisible="state not in ['ongoing']" class="btn-primary"/> |
|||
<field name="state" widget="statusbar"/> |
|||
</header> |
|||
<sheet> |
|||
<div class="oe_title"> |
|||
<h1> |
|||
<field name="name" required="1"/> |
|||
</h1> |
|||
</div> |
|||
<group> |
|||
<group> |
|||
<field name="duration" required="1"/> |
|||
<field name="release_date" required="1"/> |
|||
<field name="show_type_ids" |
|||
widget="many2many_tags" required="1"/> |
|||
<field name="movie_language_id"/> |
|||
<field name="available_time_slots_ids" |
|||
widget="many2many_tags" required="1"/> |
|||
<field name="available_screens_ids" |
|||
widget="many2many_tags" required="1"/> |
|||
<field name="show_start_date" required="1"/> |
|||
<field name="show_end_date" required="1"/> |
|||
<field name="price" required="1"/> |
|||
<field name="currency_id" invisible="1"/> |
|||
</group> |
|||
<group> |
|||
<field name="movie_poster" widget="image" options="{'size': [185, 280]}" required="1"/> |
|||
</group> |
|||
</group> |
|||
<notebook> |
|||
<page string="About"> |
|||
<field name="about_movie" placeholder="Overview of the movie"/> |
|||
</page> |
|||
<page string="Cast"> |
|||
<field name="movie_cast_ids"/> |
|||
</page> |
|||
</notebook> |
|||
</sheet> |
|||
</form> |
|||
</field> |
|||
</record> |
|||
<!-- Movie Tree View --> |
|||
<record id="movie_movie_view_tree" model="ir.ui.view"> |
|||
<field name="name">movie.movie.view.tree</field> |
|||
<field name="model">movie.movie</field> |
|||
<field name="arch" type="xml"> |
|||
<tree> |
|||
<field name="name"/> |
|||
</tree> |
|||
</field> |
|||
</record> |
|||
<!-- Action Movie --> |
|||
<record id="movie_movie_action" model="ir.actions.act_window"> |
|||
<field name="name">Shows</field> |
|||
<field name="res_model">movie.movie</field> |
|||
<field name="view_mode">kanban,form,tree</field> |
|||
</record> |
|||
<!-- MenuItem for movie, registration, configuration --> |
|||
<menuitem id="movie" name="Shows" sequence="1" |
|||
groups="show_booking_management.show_booking_management_group_admin" |
|||
web_icon="show_booking_management,static/description/icon.png"/> |
|||
<menuitem id="movie_ticket" name="Shows" parent="show_booking_management.movie" |
|||
action="movie_movie_action" sequence="1"/> |
|||
<menuitem id="movie_registration" name="Registration" |
|||
parent="show_booking_management.movie"/> |
|||
<menuitem id="movie_configuration" name="Configuration" |
|||
parent="show_booking_management.movie" sequence="5"/> |
|||
</odoo> |