diff --git a/hotel_management_odoo/README.rst b/hotel_management_odoo/README.rst new file mode 100755 index 000000000..1d4f94c3f --- /dev/null +++ b/hotel_management_odoo/README.rst @@ -0,0 +1,46 @@ +.. image:: https://img.shields.io/badge/license-LGPL--3-green.svg + :target: https://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 + +Hotel Management +================ + A complete Hotel Management System that cover all areas of hotel services. + +Configuration +============= +* No additional configurations needed + +License +------- +General Public License, Version 3 (LGPL v3). +https://www.gnu.org/licenses/lgpl-3.0-standalone.html + +Company +------- +* `Cybrosys Techno Solutions `__ + +Credits +------- +* Developer:(V17) Vishnu KP, Contact: odoo@cybrosys.com + +Contacts +-------- +* Mail Contact : odoo@cybrosys.com +* Website : https://cybrosys.com + +Bug Tracker +----------- +Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. + +Maintainer +========== +.. image:: https://cybrosys.com/images/logo.png + :target: https://cybrosys.com + +This module is maintained by Cybrosys Technologies. + +For support and more information, please visit `Our Website `__ + +Further information +=================== +HTML Description: ``__ diff --git a/hotel_management_odoo/__init__.py b/hotel_management_odoo/__init__.py new file mode 100644 index 000000000..2f4ec11f1 --- /dev/null +++ b/hotel_management_odoo/__init__.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from . import controllers +from . import models +from . import wizard diff --git a/hotel_management_odoo/__manifest__.py b/hotel_management_odoo/__manifest__.py new file mode 100644 index 000000000..59e6fc34d --- /dev/null +++ b/hotel_management_odoo/__manifest__.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +{ + 'name': 'Hotel Management', + 'version': '17.0.1.0.0', + 'category': 'Industries', + 'summary': """A complete Hotel Management System that cover all areas of + Hotel services""" , + 'description': """The module helps you to manage rooms, amenities, + services, food, events and vehicles. End Users can book rooms and reserve + foods from hotel.""", + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'website': 'https://www.cybrosys.com', + 'depends': ['account', 'event', 'fleet', 'lunch'], + 'data': [ + 'security/hotel_management_odoo_groups.xml', + 'security/hotel_management_odoo_security.xml', + 'security/ir.model.access.csv', + 'data/ir_data_sequence.xml', + 'views/account_move_views.xml', + 'views/hotel_menu_views.xml', + 'views/hotel_amenity_views.xml', + 'views/hotel_service_views.xml', + 'views/hotel_floor_views.xml', + 'views/hotel_room_views.xml', + 'views/lunch_product_views.xml', + 'views/fleet_vehicle_model_views.xml', + 'views/room_booking_views.xml', + 'views/maintenance_team_views.xml', + 'views/maintenance_request_views.xml', + 'views/cleaning_team_views.xml', + 'views/cleaning_request_views.xml', + 'views/food_booking_line_views.xml', + 'views/dashboard_view.xml', + 'wizard/room_booking_detail_views.xml', + 'wizard/sale_order_detail_views.xml', + 'views/reporting_views.xml', + 'report/room_booking_reports.xml', + 'report/sale_order_reports.xml', + ], + 'assets': { + 'web.assets_backend': [ + 'hotel_management_odoo/static/src/js/action_manager.js', + 'hotel_management_odoo/static/src/css/dashboard.css', + 'hotel_management_odoo/static/src/js/dashboard_action.js', + 'hotel_management_odoo/static/src/xml/dashboard_templates.xml', + ], + }, + 'images': ['static/description/banner.jpg'], + 'license': 'LGPL-3', + 'installable': True, + 'auto_install': False, + 'application': True, +} diff --git a/hotel_management_odoo/controllers/__init__.py b/hotel_management_odoo/controllers/__init__.py new file mode 100644 index 000000000..de8d0a5be --- /dev/null +++ b/hotel_management_odoo/controllers/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from . import hotel_management_odoo diff --git a/hotel_management_odoo/controllers/hotel_management_odoo.py b/hotel_management_odoo/controllers/hotel_management_odoo.py new file mode 100644 index 000000000..c0b57b597 --- /dev/null +++ b/hotel_management_odoo/controllers/hotel_management_odoo.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +import json +from odoo import http +from odoo.http import content_disposition, request +from odoo.tools import html_escape + + +class XLSXReportController(http.Controller): + """Controller for XlsX report""" + + @http.route('/xlsx_reports', type='http', auth='user', + methods=['POST'], csrf=False) + def get_room_booking_report_xlsx(self, model, options, output_format, + report_name): + """Function for generating xlsx report""" + report_obj = request.env[model].sudo() + 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) + response.set_cookie('fileToken', 'dummy token') + return response + except Exception as e: + s_error = http.serialize_exception(e) + error = { + 'code': 200, + 'message': 'Odoo Server Error', + 'data': s_error + } + return request.make_response(html_escape(json.dumps(error))) diff --git a/hotel_management_odoo/data/ir_data_sequence.xml b/hotel_management_odoo/data/ir_data_sequence.xml new file mode 100644 index 000000000..9d5f51fd5 --- /dev/null +++ b/hotel_management_odoo/data/ir_data_sequence.xml @@ -0,0 +1,26 @@ + + + + + + Hotel Folio + room.booking + BOOKING/ + 5 + + + + Cleaning Request + cleaning.request + CLEANING/ + 4 + + + + Maintenance Request + maintenance.request + MNTC/ + 5 + + + diff --git a/hotel_management_odoo/doc/RELEASE_NOTES.md b/hotel_management_odoo/doc/RELEASE_NOTES.md new file mode 100644 index 000000000..094620355 --- /dev/null +++ b/hotel_management_odoo/doc/RELEASE_NOTES.md @@ -0,0 +1,6 @@ +## Module + +#### 15.01.2024 +#### Version 17.0.1.0.0 +#### ADD +- Initial commit for Hotel Management diff --git a/hotel_management_odoo/models/__init__.py b/hotel_management_odoo/models/__init__.py new file mode 100644 index 000000000..dbb0a8cc4 --- /dev/null +++ b/hotel_management_odoo/models/__init__.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from . import account_move +from . import account_move_line +from . import cleaning_request +from . import cleaning_team +from . import event_booking_line +from . import fleet_booking_line +from . import fleet_vehicle_model +from . import food_booking_line +from . import hotel_amenity +from . import hotel_floor +from . import hotel_room +from . import hotel_service +from . import maintenance_request +from . import maintenance_team +from . import room_booking +from . import room_booking_line +from . import service_booking_line diff --git a/hotel_management_odoo/models/account_move.py b/hotel_management_odoo/models/account_move.py new file mode 100644 index 000000000..9277da5ac --- /dev/null +++ b/hotel_management_odoo/models/account_move.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import fields, models + + +class AccountMove(models.Model): + """Inherited account. move for adding hotel booking reference field to + invoicing model.""" + _inherit = "account.move" + + hotel_booking_id = fields.Many2one('room.booking', + string="Booking Reference", + readonly=True, help="Choose the Booking" + "Reference") diff --git a/hotel_management_odoo/models/account_move_line.py b/hotel_management_odoo/models/account_move_line.py new file mode 100644 index 000000000..9055f1478 --- /dev/null +++ b/hotel_management_odoo/models/account_move_line.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import fields, models + + +class AccountMoveLine(models.Model): + """Adding Product Type field to Account Move Line model.""" + _inherit = "account.move.line" + + product_type = fields.Selection([('room', 'Room'), ('food', 'Food'), + ('event', 'Event'), + ('service', 'Service'), + ('fleet', 'Fleet')], + string="Product Type", + help="Choose the product type") diff --git a/hotel_management_odoo/models/cleaning_request.py b/hotel_management_odoo/models/cleaning_request.py new file mode 100644 index 000000000..8e07fa7be --- /dev/null +++ b/hotel_management_odoo/models/cleaning_request.py @@ -0,0 +1,131 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import api, fields, models, _ +from odoo.exceptions import ValidationError + + +class CleaningRequest(models.Model): + """Class for creating and assigning Cleaning Request""" + _name = "cleaning.request" + _inherit = ["mail.thread", "mail.activity.mixin"] + _rec_name = "sequence" + _description = "Cleaning Request" + + sequence = fields.Char(string="Sequence", readonly=True, default='New', + copy=False, tracking=True, + help="Sequence for identifying the request") + state = fields.Selection([('draft', 'Draft'), + ('assign', 'Assigned'), + ('ongoing', 'Cleaning'), + ('support', 'Waiting For Support'), + ('done', 'Completed')], + string="State", + default='draft', help="State of cleaning request") + cleaning_type = fields.Selection(selection=[('room', 'Room'), + ('hotel', 'Hotel'), + ('vehicle', 'Vehicle')], + required=True, tracking=True, + string="Cleaning Type", + help="Choose what is to be cleaned") + room_id = fields.Many2one('hotel.room', string="Room", + help="Choose the room") + hotel = fields.Char(string="Hotel", help="Cleaning request space in hotel") + vehicle_id = fields.Many2one('fleet.vehicle.model', + string="Vehicle", + help="Cleaning request from vehicle") + support_team_ids = fields.Many2many('res.users', + string="Support Team", + help="Support team members") + support_reason = fields.Char(string='Support', help="Support Reason") + description = fields.Char(string="Description", + help="Description about the cleaning") + team_id = fields.Many2one('cleaning.team', string="Team", + required=True, + tracking=True, + help="Choose the team") + head_id = fields.Many2one('res.users', string="Head", + related='team_id.team_head_id', + help="Head of cleaning team") + assigned_id = fields.Many2one('res.users', string="Assigned To", + help="The team member to whom the request is" + "Assigned To") + domain_partner_ids = fields.Many2many('res.partner', + string="Domain Partner", + help="Choose the Domain Partner") + + @api.model + def create(self, vals_list): + """Sequence Generation""" + if vals_list.get('sequence', 'New') == 'New': + vals_list['sequence'] = self.env['ir.sequence'].next_by_code( + 'cleaning.request') + return super().create(vals_list) + + @api.onchange('team_id') + def _onchange_team_id(self): + """Function for updating the domain partner ids""" + self.update( + {'domain_partner_ids': self.team_id.member_ids.ids}) + + def action_assign_cleaning(self): + """Button action for updating the state to assign""" + self.update({'state': 'assign'}) + + def action_start_cleaning(self): + """Button action for updating the state to ongoing""" + self.write({'state': 'ongoing'}) + + def action_done_cleaning(self): + """Button action for updating the state to done""" + self.write({'state': 'done'}) + + def action_assign_support(self): + """Button action for updating the state to support""" + if self.support_reason: + self.write({'state': 'support'}) + else: + raise ValidationError(_('Please enter the reason')) + + def action_assign_assign_support(self): + """Button action for updating the state to ongoing""" + if self.support_team_ids: + self.write({'state': 'ongoing'}) + else: + raise ValidationError(_('Please choose a support')) + + def action_maintain_request(self): + """Button action for creating the maintenance request""" + self.env['maintenance.request'].sudo().create({ + 'date': fields.Date.today(), + 'state': 'draft', + 'type': self.cleaning_type, + 'vehicle_maintenance_id': self.vehicle_id.id + }) + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'type': 'success', + 'message': "Maintenance Request Sent Successfully", + 'next': {'type': 'ir.actions.act_window_close'}, + } + } diff --git a/hotel_management_odoo/models/cleaning_team.py b/hotel_management_odoo/models/cleaning_team.py new file mode 100644 index 000000000..4401d2a40 --- /dev/null +++ b/hotel_management_odoo/models/cleaning_team.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import fields, models + + +class CleaningTeam(models.Model): + """ Model for creating Cleaning team and assigns Cleaning requests to + each team""" + _name = "cleaning.team" + _description = "Cleaning Team" + + name = fields.Char(string="Team Name", help="Name of the Team") + team_head_id = fields.Many2one('res.users', string="Team Head", + help="Choose the Team Head", + domain=lambda self: [ + ('groups_id', 'in', self.env.ref( + 'hotel_management_odoo.' + 'cleaning_team_group_head').id)]) + member_ids = fields.Many2many('res.users', string="Member", + domain=lambda self: [ + ('groups_id', 'in', self.env.ref( + 'hotel_management_odoo.' + 'cleaning_team_group_user').id)], + help="Team Members") diff --git a/hotel_management_odoo/models/event_booking_line.py b/hotel_management_odoo/models/event_booking_line.py new file mode 100644 index 000000000..2ddf9fc53 --- /dev/null +++ b/hotel_management_odoo/models/event_booking_line.py @@ -0,0 +1,113 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import api, fields, models + + +class EventBookingLine(models.Model): + """Model that handles the event booking form""" + _name = "event.booking.line" + _description = "Hotel Event Line" + _rec_name = 'event_id' + + booking_id = fields.Many2one("room.booking", string="Booking", + help="Choose room booking reference", + ondelete="cascade") + event_id = fields.Many2one('event.event', string="Event", + help="Choose the Event") + ticket_id = fields.Many2one('product.product', string="Ticket", + help="Choose the Ticket Type", + domain=[('detailed_type', '=', 'event')]) + description = fields.Char(string='Description', help="Detailed " + "description of the " + "event", + related='event_id.display_name') + uom_qty = fields.Float(string="Quantity", default=1, + help="The quantity converted into the UoM used by " + "the product") + uom_id = fields.Many2one('uom.uom', readonly=True, + string="Unit of Measure", + related='ticket_id.uom_id', help="This will set " + "the unit of" + " measure used") + price_unit = fields.Float(related='ticket_id.lst_price', string='Price', + digits='Product Price', + help="The selling price of the selected ticket.") + tax_ids = fields.Many2many('account.tax', + 'hotel_event_order_line_taxes_rel', + 'event_id', + 'tax_id', related='ticket_id.taxes_id', + string='Taxes', + help="Default taxes used when selling the event" + "tickets.", + domain=[('type_tax_use', '=', 'sale')]) + currency_id = fields.Many2one( + related='booking_id.pricelist_id.currency_id', string='Currency', + help='The currency used', store=True, precompute=True) + price_subtotal = fields.Float(string="Subtotal", + compute='_compute_price_subtotal', + help="Total Price Excluding Tax", store=True) + price_tax = fields.Float(string="Total Tax", + compute='_compute_price_subtotal', + help="Tax Amount", store=True) + price_total = fields.Float(string="Total", + compute='_compute_price_subtotal', + help="Total Price Including Tax", store=True) + state = fields.Selection(related='booking_id.state', + string="Order Status", + help="State of Room Booking", copy=False) + + @api.depends('uom_qty', 'price_unit', 'tax_ids') + def _compute_price_subtotal(self): + """Compute the amounts of the Event booking line.""" + for line in self: + tax_results = self.env['account.tax']._compute_taxes( + [line._convert_to_tax_base_line_dict()]) + totals = list(tax_results['totals'].values())[0] + amount_untaxed = totals['amount_untaxed'] + amount_tax = totals['amount_tax'] + line.update({ + 'price_subtotal': amount_untaxed, + 'price_tax': amount_tax, + 'price_total': amount_untaxed + amount_tax, + }) + if self.env.context.get('import_file', + False) and not self.env.user. \ + user_has_groups('account.group_account_manager'): + line.tax_id.invalidate_recordset( + ['invoice_repartition_line_ids']) + + def _convert_to_tax_base_line_dict(self): + """ Convert the current record to a dictionary in order to use the + generic taxes computation method + defined on account.tax. + :return: A python dictionary. + """ + self.ensure_one() + return self.env['account.tax']._convert_to_tax_base_line_dict( + self, + partner=self.booking_id.partner_id, + currency=self.currency_id, + taxes=self.tax_ids, + price_unit=self.price_unit, + quantity=self.uom_qty, + price_subtotal=self.price_subtotal, + ) diff --git a/hotel_management_odoo/models/fleet_booking_line.py b/hotel_management_odoo/models/fleet_booking_line.py new file mode 100644 index 000000000..ddabd4c05 --- /dev/null +++ b/hotel_management_odoo/models/fleet_booking_line.py @@ -0,0 +1,124 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import api, fields, models, tools + + +class FleetBookingLine(models.Model): + """Model that handles the fleet booking""" + _name = "fleet.booking.line" + _description = "Hotel Fleet Line" + _rec_name = 'fleet_id' + + @tools.ormcache() + def _get_default_uom_id(self): + """Method for getting the default uom id""" + return self.env.ref('uom.product_uom_km') + + booking_id = fields.Many2one("room.booking", string="Booking", + ondelete="cascade", + help="Shows the room Booking") + fleet_id = fields.Many2one('fleet.vehicle.model', + string="Vehicle", + help='Indicates the Vehicle') + description = fields.Char(string='Description', + related='fleet_id.display_name', + help="Description of Vehicle") + uom_qty = fields.Float(string="Total KM", default=1, + help="The quantity converted into the UoM used by " + "the product") + uom_id = fields.Many2one('uom.uom', readonly=True, + string="Unit of Measure", + default=_get_default_uom_id, help="This will set " + "the unit of" + " measure used") + price_unit = fields.Float(string='Rent/KM', + related='fleet_id.price_per_km', + digits='Product Price', + help="The rent/km of the selected fleet.") + tax_ids = fields.Many2many('account.tax', + 'hotel_fleet_order_line_taxes_rel', + 'fleet_id', + 'tax_id', string='Taxes', + help="Default taxes used when renting the fleet" + "models.", + domain=[('type_tax_use', '=', 'sale')]) + currency_id = fields.Many2one( + related='booking_id.pricelist_id.currency_id', + string="Currency", help='The currency used') + price_subtotal = fields.Float(string="Subtotal", + compute='_compute_price_subtotal', + help="Total price excluding tax", + store=True) + price_tax = fields.Float(string="Total Tax", + compute='_compute_price_subtotal', + help="Total tax amount", + store=True) + price_total = fields.Float(string="Total", + compute='_compute_price_subtotal', + help="Total Price Including Tax", + store=True) + state = fields.Selection(related='booking_id.state', + string="Order Status", + help=" Status of the Order", + copy=False) + + @api.depends('uom_qty', 'price_unit', 'tax_ids') + def _compute_price_subtotal(self): + """Compute the amounts of the room booking line.""" + for line in self: + tax_results = self.env['account.tax']._compute_taxes( + [line._convert_to_tax_base_line_dict()]) + totals = list(tax_results['totals'].values())[0] + amount_untaxed = totals['amount_untaxed'] + amount_tax = totals['amount_tax'] + line.update({ + 'price_subtotal': amount_untaxed, + 'price_tax': amount_tax, + 'price_total': amount_untaxed + amount_tax, + }) + if self.env.context.get('import_file', + False) and not self.env.user. \ + user_has_groups('account.group_account_manager'): + line.tax_id.invalidate_recordset( + ['invoice_repartition_line_ids']) + + def _convert_to_tax_base_line_dict(self): + """ Convert the current record to a dictionary in order to use the + generic taxes computation method + defined on account.tax. + :return: A python dictionary. + """ + self.ensure_one() + return self.env['account.tax']._convert_to_tax_base_line_dict( + self, + partner=self.booking_id.partner_id, + currency=self.currency_id, + taxes=self.tax_ids, + price_unit=self.price_unit, + quantity=self.uom_qty, + price_subtotal=self.price_subtotal, + ) + + def search_available_vehicle(self): + """Returns list of booked vehicles""" + return (self.env['fleet.vehicle.model'].search( + [('id', 'in', self.search([]).mapped('fleet_id').ids)]).ids) diff --git a/hotel_management_odoo/models/fleet_vehicle_model.py b/hotel_management_odoo/models/fleet_vehicle_model.py new file mode 100644 index 000000000..478634b48 --- /dev/null +++ b/hotel_management_odoo/models/fleet_vehicle_model.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import fields, models, tools + + +class FleetVehicleModel(models.Model): + """Inherits Fleet Model for Booking vehicles for hotel Customers""" + _inherit = 'fleet.vehicle.model' + + @tools.ormcache() + def _set_default_uom_id(self): + """Method for getting the default uom id""" + return self.env.ref('uom.product_uom_km') + + price_per_km = fields.Float(string="Price/KM", default=1.0, + help="Rent for Vehicle") + uom_id = fields.Many2one('uom.uom', + string='Reference Uom', + help="UOM of the product", + default=_set_default_uom_id, required=True) diff --git a/hotel_management_odoo/models/food_booking_line.py b/hotel_management_odoo/models/food_booking_line.py new file mode 100644 index 000000000..7ba9c9a96 --- /dev/null +++ b/hotel_management_odoo/models/food_booking_line.py @@ -0,0 +1,120 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import api, fields, models, tools + + +class FoodBookingLine(models.Model): + """Model that handles the food booking""" + _name = "food.booking.line" + _description = "Hotel Food Line" + _rec_name = 'food_id' + + @tools.ormcache() + def _get_default_uom_id(self): + """Method for getting the default uom id""" + return self.env.ref('uom.product_uom_unit') + + booking_id = fields.Many2one("room.booking", string="Booking", + help="Shows the room Booking", + ondelete="cascade") + food_id = fields.Many2one('lunch.product', string="Product", + help="Indicates the Food Product") + description = fields.Char(string='Description', + help="Description of Food Product", + related='food_id.display_name') + uom_qty = fields.Float(string="Qty", default=1, + help="The quantity converted into the UoM used by " + "the product") + uom_id = fields.Many2one('uom.uom', readonly=True, + string="Unit of Measure", + default=_get_default_uom_id, help="This will set " + "the unit of" + " measure used") + price_unit = fields.Float(related='food_id.price', string='Price', + digits='Product Price', + help="The price of the selected food item.") + tax_ids = fields.Many2many('account.tax', + 'hotel_food_order_line_taxes_rel', + 'food_id', 'tax_id', + string='Taxes', + help="Default taxes used when selling the food" + " products.", + domain=[('type_tax_use', '=', 'sale')]) + currency_id = fields.Many2one(related='booking_id.pricelist_id.currency_id' + , string="Currency", + help='The currency used') + price_subtotal = fields.Float(string="Subtotal", + compute='_compute_price_subtotal', + help="Total Price Excluding Tax", + store=True) + price_tax = fields.Float(string="Total Tax", + compute='_compute_price_subtotal', + help="Tax Amount", + store=True) + price_total = fields.Float(string="Total", + compute='_compute_price_subtotal', + help="Total Price Including Tax", + store=True) + state = fields.Selection(related='booking_id.state', + string="Order Status", + help=" Status of the Order", + copy=False) + + @api.depends('uom_qty', 'price_unit', 'tax_ids') + def _compute_price_subtotal(self): + """Compute the amounts of the room booking line.""" + for line in self: + tax_results = self.env['account.tax']._compute_taxes( + [line._convert_to_tax_base_line_dict()]) + totals = list(tax_results['totals'].values())[0] + amount_untaxed = totals['amount_untaxed'] + amount_tax = totals['amount_tax'] + line.update({ + 'price_subtotal': amount_untaxed, + 'price_tax': amount_tax, + 'price_total': amount_untaxed + amount_tax, + }) + if self.env.context.get('import_file', + False) and not self.env.user. \ + user_has_groups('account.group_account_manager'): + line.tax_id.invalidate_recordset( + ['invoice_repartition_line_ids']) + + def _convert_to_tax_base_line_dict(self): + """ Convert the current record to a dictionary in order to use the + generic taxes computation method + defined on account.tax. + :return: A python dictionary.""" + self.ensure_one() + return self.env['account.tax']._convert_to_tax_base_line_dict( + self, + partner=self.booking_id.partner_id, + currency=self.currency_id, + taxes=self.tax_ids, + price_unit=self.price_unit, + quantity=self.uom_qty, + price_subtotal=self.price_subtotal, ) + + def search_food_orders(self): + """Returns list of food orders""" + return (self.search([]).filtered(lambda r: r.booking_id.state not in [ + 'check_out', 'cancel', 'done']).ids) diff --git a/hotel_management_odoo/models/hotel_amenity.py b/hotel_management_odoo/models/hotel_amenity.py new file mode 100644 index 000000000..32e44fc57 --- /dev/null +++ b/hotel_management_odoo/models/hotel_amenity.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import fields, models + + +class HotelAmenity(models.Model): + """Model that handles all amenities of the hotel""" + _name = 'hotel.amenity' + _description = "Hotel Amenity" + _inherit = 'mail.thread' + _order = 'id desc' + + name = fields.Char(string='Name', help="Name of the amenity") + icon = fields.Image(string="Icon", required=True, + help="Image of the amenity") + description = fields.Html(string="About", + help="Specify the amenity description") diff --git a/hotel_management_odoo/models/hotel_floor.py b/hotel_management_odoo/models/hotel_floor.py new file mode 100644 index 000000000..5d9f85912 --- /dev/null +++ b/hotel_management_odoo/models/hotel_floor.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import fields, models + + +class HotelFloor(models.Model): + """Model that holds the Hotel Floors.""" + _name = "hotel.floor" + _description = "Floor" + _order = 'id desc' + + name = fields.Char(string="Name", help="Name of the floor", required=True) + user_id = fields.Many2one('res.users', string='Manager', + help="Manager of the Floor", + required=True) diff --git a/hotel_management_odoo/models/hotel_room.py b/hotel_management_odoo/models/hotel_room.py new file mode 100644 index 000000000..853ceb489 --- /dev/null +++ b/hotel_management_odoo/models/hotel_room.py @@ -0,0 +1,104 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import api, fields, models, tools, _ +from odoo.exceptions import ValidationError + + +class HotelRoom(models.Model): + """Model that holds all details regarding hotel room""" + _name = 'hotel.room' + _description = 'Rooms' + _inherit = ['mail.thread', 'mail.activity.mixin'] + + @tools.ormcache() + def _get_default_uom_id(self): + """Method for getting the default uom id""" + return self.env.ref('uom.product_uom_unit') + + name = fields.Char(string='Name', help="Name of the Room", index='trigram', + required=True, translate=True) + status = fields.Selection([("available", "Available"), + ("reserved", "Reserved"), + ("occupied", "Occupied")], + default="available", string="Status", + help="Status of The Room", + tracking=True) + is_room_avail = fields.Boolean(default=True, string="Available", + help="Check if the room is available") + list_price = fields.Float(string='Rent', digits='Product Price', + help="The rent of the room.") + uom_id = fields.Many2one('uom.uom', string='Unit of Measure', + default=_get_default_uom_id, required=True, + help="Default unit of measure used for all stock" + " operations.") + room_image = fields.Image(string="Room Image", max_width=1920, + max_height=1920, help='Image of the room') + taxes_ids = fields.Many2many('account.tax', + 'hotel_room_taxes_rel', + 'room_id', 'tax_id', + help="Default taxes used when selling the" + " room.", string='Customer Taxes', + domain=[('type_tax_use', '=', 'sale')], + default=lambda self: self.env.company. + account_sale_tax_id) + room_amenities_ids = fields.Many2many("hotel.amenity", + string="Room Amenities", + help="List of room amenities.") + floor_id = fields.Many2one('hotel.floor', string='Floor', + help="Automatically selects the Floor", + tracking=True) + user_id = fields.Many2one('res.users', string="User", + related='floor_id.user_id', + help="Automatically selects the manager", + tracking=True) + room_type = fields.Selection([('single', 'Single'), + ('double', 'Double'), + ('dormitory', 'Dormitory')], + required=True, string="Room Type", + help="Automatically selects the Room Type", + tracking=True, + default="single") + num_person = fields.Integer(string='Number Of Persons', + required=True, + help="Automatically chooses the No. of Persons", + tracking=True) + description = fields.Html(string='Description', help="Add description", + translate=True) + + @api.constrains("num_person") + def _check_capacity(self): + """Check capacity function""" + for room in self: + if room.num_person <= 0: + raise ValidationError(_("Room capacity must be more than 0")) + + @api.onchange("room_type") + def _onchange_room_type(self): + """Based on selected room type, number of person will be updated. + ---------------------------------------- + @param self: object pointer""" + if self.room_type == "single": + self.num_person = 1 + elif self.room_type == "double": + self.num_person = 2 + else: + self.num_person = 4 diff --git a/hotel_management_odoo/models/hotel_service.py b/hotel_management_odoo/models/hotel_service.py new file mode 100644 index 000000000..23ed3833c --- /dev/null +++ b/hotel_management_odoo/models/hotel_service.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import fields, models + + +class HotelService(models.Model): + """Model that holds the all hotel services""" + _name = 'hotel.service' + _description = "Hotel Service" + _inherit = 'mail.thread' + _order = 'id desc' + + name = fields.Char(string="Service", help="Name of the service", + required=True) + unit_price = fields.Float(string="Price", help="Price of the service", + default=0.0) + taxes_ids = fields.Many2many('account.tax', + 'hotel_service_taxes_rel', + 'service_id', 'tax_id', + string='Customer Taxes', + help="Default taxes used when selling the" + " service product.", + domain=[('type_tax_use', '=', 'sale')], + default=lambda self: + self.env.company.account_sale_tax_id) diff --git a/hotel_management_odoo/models/maintenance_request.py b/hotel_management_odoo/models/maintenance_request.py new file mode 100644 index 000000000..e742fc085 --- /dev/null +++ b/hotel_management_odoo/models/maintenance_request.py @@ -0,0 +1,152 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import api, fields, models, _ +from odoo.exceptions import ValidationError + + +class MaintenanceRequest(models.Model): + """Model that handles the maintenance requests""" + + _name = 'maintenance.request' + _inherit = ['mail.thread', 'mail.activity.mixin'] + _rec_name = 'sequence' + _description = "Maintenance Request" + + sequence = fields.Char(readonly=True, string="Sequence", copy=False, + default='New', help='Sequence number for' + ' identifying maintenance' + ' request') + date = fields.Date(string="Date", help="Date of maintenance request", + default=fields.Date.today) + state = fields.Selection(selection=[('draft', 'Draft'), + ('team_leader_approve', + 'Waiting For User Assign'), + ('pending', 'Waiting For User To ' + 'Accept'), + ('ongoing', 'Ongoing'), + ('support', 'Waiting For Support'), + ('done', 'Done'), + ('verify', 'Pending For Verify'), + ('cancel', 'Canceled')], + default='draft', string="State", + help="State of maintenance request", + tracking=True) + team_id = fields.Many2one('maintenance.team', + string='Maintenance Team', + help="Team for which this request is assigned", + tracking=True) + team_head_id = fields.Many2one('res.users', + related='team_id.user_id', + string='Team Leader', + help="Head of the maintenance team") + assigned_user_id = fields.Many2one('res.users', + string='Assigned User', + tracking=True, + help="User to whom the request is " + "assigned") + type = fields.Selection(selection=[('room', 'Room'), + ('vehicle', 'Vehicle'), + ('hotel', 'Hotel'), + ('cleaning', 'Cleaning')], string="Type", + help="The type for which the request is creating", + tracking=True) + room_maintenance_ids = fields.Many2many('hotel.room', + string="Room Maintenance", + help="Choose Room Maintenance") + hotel_maintenance = fields.Char(string='Hotel Maintenance', + help="This is the Hotel Maintenance") + cleaning_maintenance = fields.Char(string='Cleaning Maintenance', + help="This is the Cleaning Maintenance") + vehicle_maintenance_id = fields.Many2one('fleet.vehicle.model', + string="Vehicle", + help="Choose Vehicle") + support_team_ids = fields.Many2many('res.users', + string="Support Team", + help="Choose Support Team") + support_reason = fields.Char(string='Support', + help="Reason for adding Support") + remarks = fields.Char(string='Remarks', help="Add Remarks") + domain_partner_ids = fields.Many2many('res.partner', + string="Partner", + help="For filtering Users") + + @api.model + def create(self, vals_list): + """Sequence Generation""" + if vals_list.get('sequence', 'New') == 'New': + vals_list['sequence'] = self.env['ir.sequence'].next_by_code( + 'maintenance.request') + return super().create(vals_list) + + @api.onchange('team_id') + def _onchange_team_id(self): + """Function for filtering the maintenance team user""" + self.update({ + 'domain_partner_ids': self.team_id.member_ids.ids + }) + + def action_assign_team(self): + """Button action for changing the state to team_leader_approve""" + if self.team_id: + self.state = 'team_leader_approve' + else: + raise ValidationError( + _("Please assign a Team")) + + def action_assign_user(self): + """Button action for changing the state to pending""" + if self.assigned_user_id: + self.state = 'pending' + else: + raise ValidationError( + _("Please assign a User")) + + def action_start(self): + """Button action for changing the state to ongoing""" + self.state = 'ongoing' + + def action_support(self): + """Button action for changing the state to support""" + if self.support_reason: + self.state = 'support' + else: + raise ValidationError(_('Please enter the reason')) + + def action_complete(self): + """Button action for changing the state to verify""" + if self.remarks: + self.state = 'verify' + else: + raise ValidationError(_('Please Add remark')) + + def action_assign_support(self): + """Button action for changing the state to ongoing""" + if self.support_team_ids: + self.state = 'ongoing' + else: + raise ValidationError(_('Please choose support')) + + def action_verify(self): + """Button action for changing the state to done""" + self.state = 'done' + if self.vehicle_maintenance_id: + self.vehicle_maintenance_id.status = 'available' diff --git a/hotel_management_odoo/models/maintenance_team.py b/hotel_management_odoo/models/maintenance_team.py new file mode 100644 index 000000000..220017ddd --- /dev/null +++ b/hotel_management_odoo/models/maintenance_team.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import fields, models + + +class MaintenanceTeam(models.Model): + """Model that handles the maintenance team """ + _name = "maintenance.team" + _description = "Maintenance Team" + + name = fields.Char(string='Maintenance Team', + help='Name of the maintenance team') + user_id = fields.Many2one('res.users', string='Team Leader', + help="Leader of Team", + domain=lambda self: [ + ('groups_id', 'in', self.env.ref( + 'hotel_management_odoo.' + 'maintenance_team_group_' + 'leader').id)]) + member_ids = fields.Many2many('res.users', string='Members', + help="Members of the Team", + domain=lambda self: [ + ('groups_id', 'in', self.env.ref( + 'hotel_management_odoo.' + 'maintenance_' + 'team_group_user').id)]) diff --git a/hotel_management_odoo/models/room_booking.py b/hotel_management_odoo/models/room_booking.py new file mode 100644 index 000000000..529aa9e44 --- /dev/null +++ b/hotel_management_odoo/models/room_booking.py @@ -0,0 +1,738 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from datetime import datetime, timedelta +from odoo import api, fields, models, _ +from odoo.exceptions import ValidationError +from odoo.tools.safe_eval import pytz + + +class RoomBooking(models.Model): + """Model that handles the hotel room booking and all operations related + to booking""" + _name = "room.booking" + _description = "Hotel Room Reservation" + _inherit = ['mail.thread', 'mail.activity.mixin'] + + name = fields.Char(string="Folio Number", readonly=True, index=True, + default="New", help="Name of Folio") + company_id = fields.Many2one('res.company', string="Company", + help="Choose the Company", + required=True, index=True, + default=lambda self: self.env.company) + partner_id = fields.Many2one('res.partner', string="Customer", + help="Customers of hotel", + required=True, index=True, tracking=1, + domain="[('type', '!=', 'private')," + " ('company_id', 'in', " + "(False, company_id))]") + date_order = fields.Datetime(string="Order Date", + required=True, copy=False, + help="Creation date of draft/sent orders," + " Confirmation date of confirmed orders", + default=fields.Datetime.now) + is_checkin = fields.Boolean(default=False, string="Is Checkin", + help="sets to True if the room is occupied") + maintenance_request_sent = fields.Boolean(default=False, + string="Maintenance Request sent" + "or Not", + help="sets to True if the " + "maintenance request send " + "once") + checkin_date = fields.Datetime(string="Check In", + help="Date of Checkin", + default=fields.Datetime.now()) + checkout_date = fields.Datetime(string="Check Out", + help="Date of Checkout", + default=fields.Datetime.now() + timedelta( + hours=23, minutes=59, seconds=59)) + hotel_policy = fields.Selection([("prepaid", "On Booking"), + ("manual", "On Check In"), + ("picking", "On Checkout"), + ], + default="manual", string="Hotel Policy", + help="Hotel policy for payment that " + "either the guest has to pay at " + "booking time, check-in " + "or check-out time.", tracking=True) + duration = fields.Integer(string="Duration in Days", + help="Number of days which will automatically " + "count from the check-in and check-out " + "date.", ) + invoice_button_visible = fields.Boolean(string='Invoice Button Display', + help="Invoice button will be " + "visible if this button is " + "True") + invoice_status = fields.Selection( + selection=[('no_invoice', 'Nothing To Invoice'), + ('to_invoice', 'To Invoice'), + ('invoiced', 'Invoiced'), + ], string="Invoice Status", + help="Status of the Invoice", + default='no_invoice', tracking=True) + hotel_invoice_id = fields.Many2one("account.move", + string="Invoice", + help="Indicates the invoice", + copy=False) + duration_visible = fields.Float(string="Duration", + help="A dummy field for Duration") + need_service = fields.Boolean(default=False, string="Need Service", + help="Check if a Service to be added with" + " the Booking") + need_fleet = fields.Boolean(default=False, string="Need Vehicle", + help="Check if a Fleet to be" + " added with the Booking") + need_food = fields.Boolean(default=False, string="Need Food", + help="Check if a Food to be added with" + " the Booking") + need_event = fields.Boolean(default=False, string="Need Event", + help="Check if a Event to be added with" + " the Booking") + service_line_ids = fields.One2many("service.booking.line", + "booking_id", + string="Service", + help="Hotel services details provided to" + "Customer and it will included in " + "the main Invoice.") + event_line_ids = fields.One2many("event.booking.line", + 'booking_id', + string="Event", + help="Hotel event reservation detail.") + vehicle_line_ids = fields.One2many("fleet.booking.line", + "booking_id", + string="Vehicle", + help="Hotel fleet reservation detail.") + room_line_ids = fields.One2many("room.booking.line", + "booking_id", string="Room", + help="Hotel room reservation detail.") + food_order_line_ids = fields.One2many("food.booking.line", + "booking_id", + string='Food', + help="Food details provided" + " to Customer and" + " it will included in the " + "main invoice.", ) + state = fields.Selection(selection=[('draft', 'Draft'), + ('reserved', 'Reserved'), + ('check_in', 'Check In'), + ('check_out', 'Check Out'), + ('cancel', 'Cancelled'), + ('done', 'Done')], string='State', + help="State of the Booking", + default='draft', tracking=True) + user_id = fields.Many2one(comodel_name='res.partner', + string="Invoice Address", + compute='_compute_user_id', + help="Sets the User automatically", + required=True, + domain="['|', ('company_id', '=', False), " + "('company_id', '='," + " company_id)]") + pricelist_id = fields.Many2one(comodel_name='product.pricelist', + string="Pricelist", + compute='_compute_pricelist_id', + store=True, readonly=False, + required=True, + tracking=1, + help="If you change the pricelist," + " only newly added lines" + " will be affected.") + currency_id = fields.Many2one( + string="Currency", help="This is the Currency used", + related='pricelist_id.currency_id', + depends=['pricelist_id.currency_id'], + ) + invoice_count = fields.Integer(compute='_compute_invoice_count', + string="Invoice " + "Count", + help="The number of invoices created") + account_move = fields.Integer(string='Invoice Id', + help="Id of the invoice created") + amount_untaxed = fields.Monetary(string="Total Untaxed Amount", + help="This indicates the total untaxed " + "amount", store=True, + compute='_compute_amount_untaxed', + tracking=5) + amount_tax = fields.Monetary(string="Taxes", help="Total Tax Amount", + store=True, compute='_compute_amount_untaxed') + amount_total = fields.Monetary(string="Total", store=True, + help="The total Amount including Tax", + compute='_compute_amount_untaxed', + tracking=4) + amount_untaxed_room = fields.Monetary(string="Room Untaxed", + help="Untaxed Amount for Room", + compute='_compute_amount_untaxed', + tracking=5) + amount_untaxed_food = fields.Monetary(string="Food Untaxed", + help="Untaxed Amount for Food", + compute='_compute_amount_untaxed', + tracking=5) + amount_untaxed_event = fields.Monetary(string="Event Untaxed", + help="Untaxed Amount for Event", + compute='_compute_amount_untaxed', + tracking=5) + amount_untaxed_service = fields.Monetary( + string="Service Untaxed", help="Untaxed Amount for Service", + compute='_compute_amount_untaxed', tracking=5) + amount_untaxed_fleet = fields.Monetary(string="Amount Untaxed", + help="Untaxed amount for Fleet", + compute='_compute_amount_untaxed', + tracking=5) + amount_taxed_room = fields.Monetary(string="Rom Tax", help="Tax for Room", + compute='_compute_amount_untaxed', + tracking=5) + amount_taxed_food = fields.Monetary(string="Food Tax", help="Tax for Food", + compute='_compute_amount_untaxed', + tracking=5) + amount_taxed_event = fields.Monetary(string="Event Tax", + help="Tax for Event", + compute='_compute_amount_untaxed', + tracking=5) + amount_taxed_service = fields.Monetary(string="Service Tax", + compute='_compute_amount_untaxed', + help="Tax for Service", tracking=5) + amount_taxed_fleet = fields.Monetary(string="Fleet Tax", + compute='_compute_amount_untaxed', + help="Tax for Fleet", tracking=5) + amount_total_room = fields.Monetary(string="Total Amount for Room", + compute='_compute_amount_untaxed', + help="This is the Total Amount for " + "Room", tracking=5) + amount_total_food = fields.Monetary(string="Total Amount for Food", + compute='_compute_amount_untaxed', + help="This is the Total Amount for " + "Food", tracking=5) + amount_total_event = fields.Monetary(string="Total Amount for Event", + compute='_compute_amount_untaxed', + help="This is the Total Amount for " + "Event", tracking=5) + amount_total_service = fields.Monetary(string="Total Amount for Service", + compute='_compute_amount_untaxed', + help="This is the Total Amount for " + "Service", tracking=5) + amount_total_fleet = fields.Monetary(string="Total Amount for Fleet", + compute='_compute_amount_untaxed', + help="This is the Total Amount for " + "Fleet", tracking=5) + + @api.model + def create(self, vals_list): + """Sequence Generation""" + if vals_list.get('name', 'New') == 'New': + vals_list['name'] = self.env['ir.sequence'].next_by_code( + 'room.booking') + return super().create(vals_list) + + @api.depends('partner_id') + def _compute_user_id(self): + """Computes the User id""" + for order in self: + order.user_id = \ + order.partner_id.address_get(['invoice'])[ + 'invoice'] if order.partner_id else False + + def _compute_invoice_count(self): + """Compute the invoice count""" + for record in self: + record.invoice_count = self.env['account.move'].search_count( + [('ref', '=', self.name)]) + + @api.depends('partner_id') + def _compute_pricelist_id(self): + """Computes PriceList""" + for order in self: + if not order.partner_id: + order.pricelist_id = False + continue + order = order.with_company(order.company_id) + order.pricelist_id = order.partner_id.property_product_pricelist + + @api.depends('room_line_ids.price_subtotal', 'room_line_ids.price_tax', + 'room_line_ids.price_total', + 'food_order_line_ids.price_subtotal', + 'food_order_line_ids.price_tax', + 'food_order_line_ids.price_total', + 'service_line_ids.price_subtotal', + 'service_line_ids.price_tax', 'service_line_ids.price_total', + 'vehicle_line_ids.price_subtotal', + 'vehicle_line_ids.price_tax', 'vehicle_line_ids.price_total', + 'event_line_ids.price_subtotal', 'event_line_ids.price_tax', + 'event_line_ids.price_total', + ) + def _compute_amount_untaxed(self, flag=False): + """Compute the total amounts of the Sale Order""" + amount_untaxed_room = 0.0 + amount_untaxed_food = 0.0 + amount_untaxed_fleet = 0.0 + amount_untaxed_event = 0.0 + amount_untaxed_service = 0.0 + amount_taxed_room = 0.0 + amount_taxed_food = 0.0 + amount_taxed_fleet = 0.0 + amount_taxed_event = 0.0 + amount_taxed_service = 0.0 + amount_total_room = 0.0 + amount_total_food = 0.0 + amount_total_fleet = 0.0 + amount_total_event = 0.0 + amount_total_service = 0.0 + room_lines = self.room_line_ids + food_lines = self.food_order_line_ids + service_lines = self.service_line_ids + fleet_lines = self.vehicle_line_ids + event_lines = self.event_line_ids + booking_list = [] + account_move_line = self.env['account.move.line'].search_read( + domain=[('ref', '=', self.name), + ('display_type', '!=', 'payment_term')], + fields=['name', 'quantity', 'price_unit', 'product_type'], ) + for rec in account_move_line: + del rec['id'] + if room_lines: + amount_untaxed_room += sum(room_lines.mapped('price_subtotal')) + amount_taxed_room += sum(room_lines.mapped('price_tax')) + amount_total_room += sum(room_lines.mapped('price_total')) + for room in room_lines: + booking_dict = {'name': room.room_id.name, + 'quantity': room.uom_qty, + 'price_unit': room.price_unit, + 'product_type': 'room'} + if booking_dict not in account_move_line: + if not account_move_line: + booking_list.append(booking_dict) + else: + for rec in account_move_line: + if rec['product_type'] == 'room': + if booking_dict['name'] == rec['name'] and \ + booking_dict['price_unit'] == rec[ + 'price_unit'] and booking_dict['quantity']\ + != rec['quantity']: + booking_list.append( + {'name': room.room_id.name, + "quantity": booking_dict[ + 'quantity'] - rec[ + 'quantity'], + "price_unit": room.price_unit, + "product_type": 'room'}) + else: + booking_list.append(booking_dict) + if flag: + room.booking_line_visible = True + if food_lines: + for food in food_lines: + booking_list.append(self.create_list(food)) + amount_untaxed_food += sum(food_lines.mapped('price_subtotal')) + amount_taxed_food += sum(food_lines.mapped('price_tax')) + amount_total_food += sum(food_lines.mapped('price_total')) + if service_lines: + for service in service_lines: + booking_list.append(self.create_list(service)) + amount_untaxed_service += sum( + service_lines.mapped('price_subtotal')) + amount_taxed_service += sum(service_lines.mapped('price_tax')) + amount_total_service += sum(service_lines.mapped('price_total')) + if fleet_lines: + for fleet in fleet_lines: + booking_list.append(self.create_list(fleet)) + amount_untaxed_fleet += sum(fleet_lines.mapped('price_subtotal')) + amount_taxed_fleet += sum(fleet_lines.mapped('price_tax')) + amount_total_fleet += sum(fleet_lines.mapped('price_total')) + if event_lines: + for event in event_lines: + booking_list.append(self.create_list(event)) + amount_untaxed_event += sum(event_lines.mapped('price_subtotal')) + amount_taxed_event += sum(event_lines.mapped('price_tax')) + amount_total_event += sum(event_lines.mapped('price_total')) + for rec in self: + rec.amount_untaxed = amount_untaxed_food + amount_untaxed_room + \ + amount_untaxed_fleet + \ + amount_untaxed_event + amount_untaxed_service + rec.amount_untaxed_food = amount_untaxed_food + rec.amount_untaxed_room = amount_untaxed_room + rec.amount_untaxed_fleet = amount_untaxed_fleet + rec.amount_untaxed_event = amount_untaxed_event + rec.amount_untaxed_service = amount_untaxed_service + rec.amount_tax = (amount_taxed_food + amount_taxed_room + + amount_taxed_fleet + + amount_taxed_event + amount_taxed_service) + rec.amount_taxed_food = amount_taxed_food + rec.amount_taxed_room = amount_taxed_room + rec.amount_taxed_fleet = amount_taxed_fleet + rec.amount_taxed_event = amount_taxed_event + rec.amount_taxed_service = amount_taxed_service + rec.amount_total = (amount_total_food + amount_total_room + + amount_total_fleet + amount_total_event + + amount_total_service) + rec.amount_total_food = amount_total_food + rec.amount_total_room = amount_total_room + rec.amount_total_fleet = amount_total_fleet + rec.amount_total_event = amount_total_event + rec.amount_total_service = amount_total_service + return booking_list + + @api.onchange('need_food') + def _onchange_need_food(self): + """Unlink Food Booking Line if Need Food is false""" + if not self.need_food and self.food_order_line_ids: + for food in self.food_order_line_ids: + food.unlink() + + @api.onchange('need_service') + def _onchange_need_service(self): + """Unlink Service Booking Line if Need Service is False""" + if not self.need_service and self.service_line_ids: + for serv in self.service_line_ids: + serv.unlink() + + @api.onchange('need_fleet') + def _onchange_need_fleet(self): + """Unlink Fleet Booking Line if Need Fleet is False""" + if not self.need_fleet: + if self.vehicle_line_ids: + for fleet in self.vehicle_line_ids: + fleet.unlink() + + @api.onchange('need_event') + def _onchange_need_event(self): + """Unlink Event Booking Line if Need Event is False""" + if not self.need_event: + if self.event_line_ids: + for event in self.event_line_ids: + event.unlink() + + @api.onchange('food_order_line_ids', 'room_line_ids', + 'service_line_ids', 'vehicle_line_ids', 'event_line_ids') + def _onchange_room_line_ids(self): + """Invokes the Compute amounts function""" + self._compute_amount_untaxed() + self.invoice_button_visible = False + + @api.constrains("room_line_ids") + def _check_duplicate_folio_room_line(self): + """ + This method is used to validate the room_lines. + ------------------------------------------------ + @param self: object pointer + @return: raise warning depending on the validation + """ + for record in self: + # Create a set of unique ids + ids = set() + for line in record.room_line_ids: + if line.room_id.id in ids: + raise ValidationError( + _( + """Room Entry Duplicates Found!, """ + """You Cannot Book "%s" Room More Than Once!""" + ) + % line.room_id.name + ) + ids.add(line.room_id.id) + + def create_list(self, line_ids): + """Returns a Dictionary containing the Booking line Values""" + account_move_line = self.env['account.move.line'].search_read( + domain=[('ref', '=', self.name), + ('display_type', '!=', 'payment_term')], + fields=['name', 'quantity', 'price_unit', 'product_type'], ) + for rec in account_move_line: + del rec['id'] + booking_dict = {} + for line in line_ids: + name = "" + product_type = "" + if line_ids._name == 'food.booking.line': + name = line.food_id.name + product_type = 'food' + elif line_ids._name == 'fleet.booking.line': + name = line.fleet_id.name + product_type = 'fleet' + elif line_ids._name == 'service.booking.line': + name = line.service_id.name + product_type = 'service' + elif line_ids._name == 'event.booking.line': + name = line.event_id.name + product_type = 'event' + booking_dict = {'name': name, + 'quantity': line.uom_qty, + 'price_unit': line.price_unit, + 'product_type': product_type} + return booking_dict + + def action_reserve(self): + """Button Reserve Function""" + if self.state == 'reserved': + message = _("Room Already Reserved.") + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'type': 'warning', + 'message': message, + 'next': {'type': 'ir.actions.act_window_close'}, + } + } + if self.room_line_ids: + for room in self.room_line_ids: + room.room_id.write({ + 'status': 'reserved', + }) + room.room_id.is_room_avail = False + self.write({"state": "reserved"}) + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'type': 'success', + 'message': "Rooms reserved Successfully!", + 'next': {'type': 'ir.actions.act_window_close'}, + } + } + raise ValidationError(_("Please Enter Room Details")) + + def action_cancel(self): + """ + @param self: object pointer + """ + if self.room_line_ids: + for room in self.room_line_ids: + room.room_id.write({ + 'status': 'available', + }) + room.room_id.is_room_avail = True + self.write({"state": "cancel"}) + + def action_maintenance_request(self): + """ + Function that handles the maintenance request + """ + room_list = [] + for rec in self.room_line_ids.room_id.ids: + room_list.append(rec) + if room_list: + room_id = self.env['hotel.room'].search([ + ('id', 'in', room_list)]) + self.env['maintenance.request'].sudo().create({ + 'date': fields.Date.today(), + 'state': 'draft', + 'type': 'room', + 'room_maintenance_ids': room_id.ids, + }) + self.maintenance_request_sent = True + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'type': 'success', + 'message': "Maintenance Request Sent Successfully", + 'next': {'type': 'ir.actions.act_window_close'}, + } + } + raise ValidationError(_("Please Enter Room Details")) + + def action_done(self): + """Button action_confirm function""" + for rec in self.env['account.move'].search( + [('ref', '=', self.name)]): + if rec.payment_state != 'not_paid': + self.write({"state": "done"}) + self.is_checkin = False + if self.room_line_ids: + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'type': 'success', + 'message': "Booking Checked Out Successfully!", + 'next': {'type': 'ir.actions.act_window_close'}, + } + } + raise ValidationError(_('Your Invoice is Due for Payment.')) + self.write({"state": "done"}) + + def action_checkout(self): + """Button action_heck_out function""" + self.write({"state": "check_out"}) + for room in self.room_line_ids: + room.room_id.write({ + 'status': 'available', + 'is_room_avail': True + }) + room.write({'checkout_date': datetime.today()}) + + def action_invoice(self): + """Method for creating invoice""" + if not self.room_line_ids: + raise ValidationError(_("Please Enter Room Details")) + booking_list = self._compute_amount_untaxed(True) + if booking_list: + account_move = self.env["account.move"].create([{ + 'move_type': 'out_invoice', + 'invoice_date': fields.Date.today(), + 'partner_id': self.partner_id.id, + 'ref': self.name, + }]) + for rec in booking_list: + account_move.invoice_line_ids.create([{ + 'name': rec['name'], + 'quantity': rec['quantity'], + 'price_unit': rec['price_unit'], + 'move_id': account_move.id, + 'price_subtotal': rec['quantity'] * rec['price_unit'], + 'product_type': rec['product_type'], + }]) + self.write({'invoice_status': "invoiced"}) + self.invoice_button_visible = True + return { + 'type': 'ir.actions.act_window', + 'name': 'Invoices', + 'view_mode': 'form', + 'view_type': 'form', + 'res_model': 'account.move', + 'view_id': self.env.ref('account.view_move_form').id, + 'res_id': account_move.id, + 'context': "{'create': False}" + } + + def action_view_invoices(self): + """Method for Returning invoice View""" + return { + 'type': 'ir.actions.act_window', + 'name': 'Invoices', + 'view_mode': 'tree,form', + 'view_type': 'tree,form', + 'res_model': 'account.move', + 'domain': [('ref', '=', self.name)], + 'context': "{'create': False}" + } + + def action_checkin(self): + """ + @param self: object pointer + """ + if not self.room_line_ids: + raise ValidationError(_("Please Enter Room Details")) + else: + for room in self.room_line_ids: + room.room_id.write({ + 'status': 'occupied', + }) + room.room_id.is_room_avail = False + self.write({"state": "check_in"}) + return { + 'type': 'ir.actions.client', + 'tag': 'display_notification', + 'params': { + 'type': 'success', + 'message': "Booking Checked In Successfully!", + 'next': {'type': 'ir.actions.act_window_close'}, + } + } + + def get_details(self): + """ Returns different counts for displaying in dashboard""" + today = datetime.today() + tz_name = self.env.user.tz + today_utc = pytz.timezone('UTC').localize(today, + is_dst=False) + context_today = today_utc.astimezone(pytz.timezone(tz_name)) + total_room = self.env['hotel.room'].search_count([]) + check_in = self.env['room.booking'].search_count( + [('state', '=', 'check_in')]) + available_room = self.env['hotel.room'].search( + [('status', '=', 'available')]) + reservation = self.env['room.booking'].search_count( + [('state', '=', 'reserved')]) + check_outs = self.env['room.booking'].search([]) + check_out = 0 + staff = 0 + for rec in check_outs: + for room in rec.room_line_ids: + if room.checkout_date.date() == context_today.date(): + check_out += 1 + """staff""" + staff = self.env['res.users'].search_count( + [('groups_id', 'in', + [self.env.ref('hotel_management_odoo.hotel_group_admin').id, + self.env.ref( + 'hotel_management_odoo.cleaning_team_group_head').id, + self.env.ref( + 'hotel_management_odoo.cleaning_team_group_user').id, + self.env.ref( + 'hotel_management_odoo.hotel_group_reception').id, + self.env.ref( + 'hotel_management_odoo.maintenance_team_group_leader').id, + self.env.ref( + 'hotel_management_odoo.maintenance_team_group_user').id + ])]) + total_vehicle = self.env['fleet.vehicle.model'].search_count([]) + available_vehicle = total_vehicle - self.env[ + 'fleet.booking.line'].search_count( + [('state', '=', 'check_in')]) + total_event = self.env['event.event'].search_count([]) + pending_event = self.env['event.event'].search([]) + pending_events = 0 + today_events = 0 + for pending in pending_event: + if pending.date_end >= fields.datetime.now(): + pending_events += 1 + if pending.date_end.date() == fields.date.today(): + today_events += 1 + food_items = self.env['lunch.product'].search_count([]) + food_order = len(self.env['food.booking.line'].search([]).filtered( + lambda r: r.booking_id.state not in ['check_out', 'cancel', + 'done'])) + """total Revenue""" + total_revenue = 0 + today_revenue = 0 + pending_payment = 0 + for rec in self.env['account.move'].search( + [('payment_state', '=', 'paid')]): + if rec.ref: + if 'BOOKING' in rec.ref: + total_revenue += rec.amount_total + if rec.date == fields.date.today(): + today_revenue += rec.amount_total + for rec in self.env['account.move'].search( + [('payment_state', '=', 'not_paid')]): + if rec.ref: + if 'BOOKING' in rec.ref: + pending_payment += rec.amount_total + return { + 'total_room': total_room, + 'available_room': len(available_room), + 'staff': staff, + 'check_in': check_in, + 'reservation': reservation, + 'check_out': check_out, + 'total_vehicle': total_vehicle, + 'available_vehicle': available_vehicle, + 'total_event': total_event, + 'today_events': today_events, + 'pending_events': pending_events, + 'food_items': food_items, + 'food_order': food_order, + 'total_revenue': round(total_revenue, 2), + 'today_revenue': round(today_revenue, 2), + 'pending_payment': round(pending_payment, 2), + 'currency_symbol': self.env.user.company_id.currency_id.symbol, + 'currency_position': self.env.user.company_id.currency_id.position + } diff --git a/hotel_management_odoo/models/room_booking_line.py b/hotel_management_odoo/models/room_booking_line.py new file mode 100644 index 000000000..f06fdaab8 --- /dev/null +++ b/hotel_management_odoo/models/room_booking_line.py @@ -0,0 +1,143 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import api, fields, models, tools, _ +from odoo.exceptions import ValidationError + + +class RoomBookingLine(models.Model): + """Model that handles the room booking form""" + _name = "room.booking.line" + _description = "Hotel Folio Line" + _rec_name = 'room_id' + + @tools.ormcache() + def _set_default_uom_id(self): + return self.env.ref('uom.product_uom_day') + + booking_id = fields.Many2one("room.booking", string="Booking", + help="Indicates the Room", + ondelete="cascade") + checkin_date = fields.Datetime(string="Check In", + help="You can choose the date," + " Otherwise sets to current Date", + required=True) + checkout_date = fields.Datetime(string="Check Out", + help="You can choose the date," + " Otherwise sets to current Date", + required=True) + room_id = fields.Many2one('hotel.room', string="Room", + domain=[('status', '=', 'available')], + help="Indicates the Room", + required=True) + uom_qty = fields.Float(string="Duration", + help="The quantity converted into the UoM used by " + "the product", readonly=True) + uom_id = fields.Many2one('uom.uom', + default=_set_default_uom_id, + string="Unit of Measure", + help="This will set the unit of measure used", + readonly=True) + price_unit = fields.Float(related='room_id.list_price', string='Rent', + digits='Product Price', + help="The rent price of the selected room.") + tax_ids = fields.Many2many('account.tax', + 'hotel_room_order_line_taxes_rel', + 'room_id', 'tax_id', + related='room_id.taxes_ids', + string='Taxes', + help="Default taxes used when selling the room." + , domain=[('type_tax_use', '=', 'sale')]) + currency_id = fields.Many2one(string='Currency', + related='booking_id.pricelist_id.currency_id' + , help='The currency used') + price_subtotal = fields.Float(string="Subtotal", + compute='_compute_price_subtotal', + help="Total Price excluding Tax", + store=True) + price_tax = fields.Float(string="Total Tax", + compute='_compute_price_subtotal', + help="Tax Amount", + store=True) + price_total = fields.Float(string="Total", + compute='_compute_price_subtotal', + help="Total Price including Tax", + store=True) + state = fields.Selection(related='booking_id.state', + string="Order Status", + help=" Status of the Order", + copy=False) + booking_line_visible = fields.Boolean(default=False, + string="Booking Line Visible", + help="If True, then Booking Line " + "will be visible") + + @api.onchange("checkin_date", "checkout_date") + def _onchange_checkin_date(self): + """When you change checkin_date or checkout_date it will check + and update the qty of hotel service line + ----------------------------------------------------------------- + @param self: object pointer""" + if self.checkout_date < self.checkin_date: + raise ValidationError( + _("Checkout must be greater or equal checkin date")) + if self.checkin_date and self.checkout_date: + diffdate = self.checkout_date - self.checkin_date + qty = diffdate.days + if diffdate.total_seconds() > 0: + qty = qty + 1 + self.uom_qty = qty + + @api.depends('uom_qty', 'price_unit', 'tax_ids') + def _compute_price_subtotal(self): + """Compute the amounts of the room booking line.""" + for line in self: + tax_results = self.env['account.tax']._compute_taxes( + [line._convert_to_tax_base_line_dict()]) + totals = list(tax_results['totals'].values())[0] + amount_untaxed = totals['amount_untaxed'] + amount_tax = totals['amount_tax'] + line.update({ + 'price_subtotal': amount_untaxed, + 'price_tax': amount_tax, + 'price_total': amount_untaxed + amount_tax, + }) + if self.env.context.get('import_file', + False) and not self.env.user. \ + user_has_groups('account.group_account_manager'): + line.tax_id.invalidate_recordset( + ['invoice_repartition_line_ids']) + + def _convert_to_tax_base_line_dict(self): + """ Convert the current record to a dictionary in order to use the + generic taxes computation method + defined on account.tax. + :return: A python dictionary.""" + self.ensure_one() + return self.env['account.tax']._convert_to_tax_base_line_dict( + self, + partner=self.booking_id.partner_id, + currency=self.currency_id, + taxes=self.tax_ids, + price_unit=self.price_unit, + quantity=self.uom_qty, + price_subtotal=self.price_subtotal, + ) diff --git a/hotel_management_odoo/models/service_booking_line.py b/hotel_management_odoo/models/service_booking_line.py new file mode 100644 index 000000000..fd645cb8a --- /dev/null +++ b/hotel_management_odoo/models/service_booking_line.py @@ -0,0 +1,117 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from odoo import api, fields, models, tools + + +class ServiceBookingLine(models.Model): + """Model that handles the service booking form""" + _name = "service.booking.line" + _description = "Hotel service Line" + + @tools.ormcache() + def _get_default_uom_id(self): + """Returns default product uom unit""" + return self.env.ref('uom.product_uom_unit') + + booking_id = fields.Many2one("room.booking", string="Booking", + help="Indicates the Room Booking", + ondelete="cascade") + service_id = fields.Many2one('hotel.service', string="Service", + help="Indicates the Service") + description = fields.Char(string='Description', related='service_id.name', + help="Description of the Service") + uom_qty = fields.Float(string="Qty", default=1.0, + help="The quantity converted into the UoM used by " + "the product") + uom_id = fields.Many2one('uom.uom', readonly=True, + string="Unit of Measure", + help="This will set the unit of measure used", + default=_get_default_uom_id) + price_unit = fields.Float(string='Price', related='service_id.unit_price', + digits='Product Price', + help="The price of the selected service.") + tax_ids = fields.Many2many('account.tax', + 'hotel_service_order_line_taxes_rel', + 'service_id', 'tax_id', + related='service_id.taxes_ids', string='Taxes', + help="Default taxes used when selling the " + "services.", + domain=[('type_tax_use', '=', 'sale')]) + currency_id = fields.Many2one(string='Currency', + related='booking_id.pricelist_id.currency_id', + help='The currency used') + price_subtotal = fields.Float(string="Subtotal", + compute='_compute_price_subtotal', + help="Total Price Excluding Tax", + store=True) + price_tax = fields.Float(string="Total Tax", + compute='_compute_price_subtotal', + help="Tax Amount", + store=True) + price_total = fields.Float(string="Total", + compute='_compute_price_subtotal', + help="Total Price Including Tax", + store=True) + state = fields.Selection(related='booking_id.state', + string="Order Status", + help=" Status of the Order", + copy=False) + booking_line_visible = fields.Boolean(default=False, + string="Booking Line Visible", + help="If true, Booking line will be" + " visible") + + @api.depends('uom_qty', 'price_unit', 'tax_ids') + def _compute_price_subtotal(self): + """Compute the amounts of the room booking line.""" + for line in self: + tax_results = self.env['account.tax']._compute_taxes( + [line._convert_to_tax_base_line_dict()]) + totals = list(tax_results['totals'].values())[0] + amount_untaxed = totals['amount_untaxed'] + amount_tax = totals['amount_tax'] + line.update({ + 'price_subtotal': amount_untaxed, + 'price_tax': amount_tax, + 'price_total': amount_untaxed + amount_tax, + }) + if self.env.context.get('import_file', + False) and not self.env.user. \ + user_has_groups('account.group_account_manager'): + line.tax_id.invalidate_recordset( + ['invoice_repartition_line_ids']) + + def _convert_to_tax_base_line_dict(self): + """ Convert the current record to a dictionary in order to use the + generic taxes computation method + defined on account.tax. + :return: A python dictionary.""" + self.ensure_one() + return self.env['account.tax']._convert_to_tax_base_line_dict( + self, + partner=self.booking_id.partner_id, + currency=self.currency_id, + taxes=self.tax_ids, + price_unit=self.price_unit, + quantity=self.uom_qty, + price_subtotal=self.price_subtotal, + ) diff --git a/hotel_management_odoo/report/room_booking_reports.xml b/hotel_management_odoo/report/room_booking_reports.xml new file mode 100644 index 000000000..9f5c7d18a --- /dev/null +++ b/hotel_management_odoo/report/room_booking_reports.xml @@ -0,0 +1,60 @@ + + + + + Room Booking Order + room.booking + qweb-pdf + hotel_management_odoo.report_room_booking + hotel_management_odoo.report_room_booking + + report + + + + diff --git a/hotel_management_odoo/report/sale_order_reports.xml b/hotel_management_odoo/report/sale_order_reports.xml new file mode 100644 index 000000000..48ba3f885 --- /dev/null +++ b/hotel_management_odoo/report/sale_order_reports.xml @@ -0,0 +1,61 @@ + + + + + Sale Order + room.booking + qweb-pdf + hotel_management_odoo.report_sale_order + hotel_management_odoo.report_sale_order + + report + + + + diff --git a/hotel_management_odoo/security/hotel_management_odoo_groups.xml b/hotel_management_odoo/security/hotel_management_odoo_groups.xml new file mode 100644 index 000000000..b1d55d31b --- /dev/null +++ b/hotel_management_odoo/security/hotel_management_odoo_groups.xml @@ -0,0 +1,53 @@ + + + + + Hotel Management + Hotel Access Groups + 20 + + + + Maintenance Team User + + + + + Maintenance Team Leader + + + + + + Receptionist + + + + + Cleaning Team User + + + + + Cleaning Team Head + + + + + + Admin + + + + diff --git a/hotel_management_odoo/security/hotel_management_odoo_security.xml b/hotel_management_odoo/security/hotel_management_odoo_security.xml new file mode 100644 index 000000000..1ee6c3bce --- /dev/null +++ b/hotel_management_odoo/security/hotel_management_odoo_security.xml @@ -0,0 +1,67 @@ + + + + + Record Rule for Maintenance team leader + + + [('team_head_id', '=', user.id)] + + + + + + + + Record Rule for Maintenance User + + + [('assigned_user_id', '=', user.id)] + + + + + + + + Record Rule for hotel Admin + + + [(1,'=',1)] + + + + + + + + Cleaning Head Record Rule + + + [('team_id.team_head_id.id', '=', user.id)] + + + + + Cleaning User Record Rule + + + [('assigned_id.id', '=', user.id)] + + + + Cleaning Admin Record Rule + + + [(1, '=', 1)] + + diff --git a/hotel_management_odoo/security/ir.model.access.csv b/hotel_management_odoo/security/ir.model.access.csv new file mode 100644 index 000000000..7ac9c04ef --- /dev/null +++ b/hotel_management_odoo/security/ir.model.access.csv @@ -0,0 +1,21 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_hotel_amenity_user,access.hotel.amenity.user,model_hotel_amenity,base.group_user,1,1,1,1 +access_hotel_service_user,access.hotel.service.user,model_hotel_service,base.group_user,1,1,1,1 +access_hotel_floor_user,access.hotel.floor.user,model_hotel_floor,base.group_user,1,1,1,1 +access_hotel_room_user,access.hotel.room.user,model_hotel_room,base.group_user,1,1,1,1 +access_room_booking_user,access.room.booking.user,model_room_booking,base.group_user,1,1,1,1 +access_room_booking_line_user,access.room.booking.line.user,model_room_booking_line,base.group_user,1,1,1,1 +access_food_booking_line_user,access.food.booking.line.user,model_food_booking_line,base.group_user,1,1,1,1 +access_service_booking_line_user,access.service.booking.line.user,model_service_booking_line,base.group_user,1,1,1,1 +access_fleet_booking_line_user,access.fleet.booking.line.user,model_fleet_booking_line,base.group_user,1,1,1,1 +access_event_booking_line_user,access.event.booking.line.user,model_event_booking_line,base.group_user,1,1,1,1 +access_room_booking_detail_user,access.room.booking.detail.user,model_room_booking_detail,base.group_user,1,1,1,1 +access_sale_order_detail_user,access.sale.order.detail.user,model_sale_order_detail,base.group_user,1,1,1,1 +access_maintenance_team_maintenance_team_group_leader,access.maintenance.team.maintenance_team_group_leader,model_maintenance_team,hotel_management_odoo.maintenance_team_group_leader,1,1,1,1 +access_maintenance_request_hotel_group_admin,access.maintenance.request.hotel_group_admin,model_maintenance_request,hotel_management_odoo.hotel_group_admin,1,1,1,1 +access_maintenance_request_maintenance_team_group_leader,access.maintenance.request.maintenance_team_group_leader,model_maintenance_request,hotel_management_odoo.maintenance_team_group_leader,1,1,1,1 +access_maintenance_request_maintenance_team_group_user,access.maintenance.request.maintenance_team_group_user,model_maintenance_request,hotel_management_odoo.maintenance_team_group_user,1,1,1,1 +access_cleaning_team_cleaning_team_group_head,access.cleaning.team.cleaning_team_group_head,model_cleaning_team,hotel_management_odoo.cleaning_team_group_head,1,1,1,1 +access_cleaning_request_hotel_group_admin,access.cleaning.request.hotel_group_admin,model_cleaning_request,hotel_management_odoo.hotel_group_admin,1,1,1,1 +access_cleaning_request_cleaning_team_group_head,access.cleaning.request.cleaning_team_group_head,model_cleaning_request,hotel_management_odoo.cleaning_team_group_head,1,1,1,1 +access_cleaning_request_cleaning_team_group_user,access.cleaning.request.cleaning_team_group_user,model_cleaning_request,hotel_management_odoo.cleaning_team_group_user,1,1,1,1 diff --git a/hotel_management_odoo/static/description/assets/icons/capture (1).png b/hotel_management_odoo/static/description/assets/icons/capture (1).png new file mode 100644 index 000000000..8824deafc Binary files /dev/null and b/hotel_management_odoo/static/description/assets/icons/capture (1).png differ diff --git a/hotel_management_odoo/static/description/assets/icons/check.png b/hotel_management_odoo/static/description/assets/icons/check.png new file mode 100644 index 000000000..c8e85f51d Binary files /dev/null and b/hotel_management_odoo/static/description/assets/icons/check.png differ diff --git a/hotel_management_odoo/static/description/assets/icons/chevron.png b/hotel_management_odoo/static/description/assets/icons/chevron.png new file mode 100644 index 000000000..2089293d6 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/icons/chevron.png differ diff --git a/hotel_management_odoo/static/description/assets/icons/cogs.png b/hotel_management_odoo/static/description/assets/icons/cogs.png new file mode 100644 index 000000000..95d0bad62 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/icons/cogs.png differ diff --git a/hotel_management_odoo/static/description/assets/icons/consultation.png b/hotel_management_odoo/static/description/assets/icons/consultation.png new file mode 100644 index 000000000..8319d4baa Binary files /dev/null and b/hotel_management_odoo/static/description/assets/icons/consultation.png differ diff --git a/hotel_management_odoo/static/description/assets/icons/ecom-black.png b/hotel_management_odoo/static/description/assets/icons/ecom-black.png new file mode 100644 index 000000000..a9385ff13 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/icons/ecom-black.png differ diff --git a/hotel_management_odoo/static/description/assets/icons/education-black.png b/hotel_management_odoo/static/description/assets/icons/education-black.png new file mode 100644 index 000000000..3eb09b27b Binary files /dev/null and b/hotel_management_odoo/static/description/assets/icons/education-black.png differ diff --git a/hotel_management_odoo/static/description/assets/icons/hotel-black.png b/hotel_management_odoo/static/description/assets/icons/hotel-black.png new file mode 100644 index 000000000..130f613be Binary files /dev/null and b/hotel_management_odoo/static/description/assets/icons/hotel-black.png differ diff --git a/hotel_management_odoo/static/description/assets/icons/img.png b/hotel_management_odoo/static/description/assets/icons/img.png new file mode 100644 index 000000000..70197f477 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/icons/img.png differ diff --git a/hotel_management_odoo/static/description/assets/icons/license.png b/hotel_management_odoo/static/description/assets/icons/license.png new file mode 100644 index 000000000..a5869797e Binary files /dev/null and b/hotel_management_odoo/static/description/assets/icons/license.png differ diff --git a/hotel_management_odoo/static/description/assets/icons/lifebuoy.png b/hotel_management_odoo/static/description/assets/icons/lifebuoy.png new file mode 100644 index 000000000..658d56ccc Binary files /dev/null and b/hotel_management_odoo/static/description/assets/icons/lifebuoy.png differ diff --git a/hotel_management_odoo/static/description/assets/icons/manufacturing-black.png b/hotel_management_odoo/static/description/assets/icons/manufacturing-black.png new file mode 100644 index 000000000..697eb0e9f Binary files /dev/null and b/hotel_management_odoo/static/description/assets/icons/manufacturing-black.png differ diff --git a/hotel_management_odoo/static/description/assets/icons/photo-capture.png b/hotel_management_odoo/static/description/assets/icons/photo-capture.png new file mode 100644 index 000000000..06c111758 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/icons/photo-capture.png differ diff --git a/hotel_management_odoo/static/description/assets/icons/pos-black.png b/hotel_management_odoo/static/description/assets/icons/pos-black.png new file mode 100644 index 000000000..97c0f90c1 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/icons/pos-black.png differ diff --git a/hotel_management_odoo/static/description/assets/icons/puzzle.png b/hotel_management_odoo/static/description/assets/icons/puzzle.png new file mode 100644 index 000000000..65cf854e7 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/icons/puzzle.png differ diff --git a/hotel_management_odoo/static/description/assets/icons/restaurant-black.png b/hotel_management_odoo/static/description/assets/icons/restaurant-black.png new file mode 100644 index 000000000..4a35eb939 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/icons/restaurant-black.png differ diff --git a/hotel_management_odoo/static/description/assets/icons/service-black.png b/hotel_management_odoo/static/description/assets/icons/service-black.png new file mode 100644 index 000000000..301ab51cb Binary files /dev/null and b/hotel_management_odoo/static/description/assets/icons/service-black.png differ diff --git a/hotel_management_odoo/static/description/assets/icons/trading-black.png b/hotel_management_odoo/static/description/assets/icons/trading-black.png new file mode 100644 index 000000000..9398ba2f1 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/icons/trading-black.png differ diff --git a/hotel_management_odoo/static/description/assets/icons/training.png b/hotel_management_odoo/static/description/assets/icons/training.png new file mode 100644 index 000000000..884ca024d Binary files /dev/null and b/hotel_management_odoo/static/description/assets/icons/training.png differ diff --git a/hotel_management_odoo/static/description/assets/icons/update.png b/hotel_management_odoo/static/description/assets/icons/update.png new file mode 100644 index 000000000..ecbc5a01a Binary files /dev/null and b/hotel_management_odoo/static/description/assets/icons/update.png differ diff --git a/hotel_management_odoo/static/description/assets/icons/user.png b/hotel_management_odoo/static/description/assets/icons/user.png new file mode 100644 index 000000000..6ffb23d9f Binary files /dev/null and b/hotel_management_odoo/static/description/assets/icons/user.png differ diff --git a/hotel_management_odoo/static/description/assets/icons/wrench.png b/hotel_management_odoo/static/description/assets/icons/wrench.png new file mode 100644 index 000000000..6c04dea0f Binary files /dev/null and b/hotel_management_odoo/static/description/assets/icons/wrench.png differ diff --git a/hotel_management_odoo/static/description/assets/misc/Cybrosys R.png b/hotel_management_odoo/static/description/assets/misc/Cybrosys R.png new file mode 100644 index 000000000..da4058087 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/misc/Cybrosys R.png differ diff --git a/hotel_management_odoo/static/description/assets/misc/categories.png b/hotel_management_odoo/static/description/assets/misc/categories.png new file mode 100644 index 000000000..bedf1e0b1 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/misc/categories.png differ diff --git a/hotel_management_odoo/static/description/assets/misc/check-box.png b/hotel_management_odoo/static/description/assets/misc/check-box.png new file mode 100644 index 000000000..42caf24b9 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/misc/check-box.png differ diff --git a/hotel_management_odoo/static/description/assets/misc/compass.png b/hotel_management_odoo/static/description/assets/misc/compass.png new file mode 100644 index 000000000..d5fed8faa Binary files /dev/null and b/hotel_management_odoo/static/description/assets/misc/compass.png differ diff --git a/hotel_management_odoo/static/description/assets/misc/corporate.png b/hotel_management_odoo/static/description/assets/misc/corporate.png new file mode 100644 index 000000000..2eb13edbf Binary files /dev/null and b/hotel_management_odoo/static/description/assets/misc/corporate.png differ diff --git a/hotel_management_odoo/static/description/assets/misc/customer-support.png b/hotel_management_odoo/static/description/assets/misc/customer-support.png new file mode 100644 index 000000000..79efc72ed Binary files /dev/null and b/hotel_management_odoo/static/description/assets/misc/customer-support.png differ diff --git a/hotel_management_odoo/static/description/assets/misc/cybrosys-logo.png b/hotel_management_odoo/static/description/assets/misc/cybrosys-logo.png new file mode 100644 index 000000000..cc3cc0ccf Binary files /dev/null and b/hotel_management_odoo/static/description/assets/misc/cybrosys-logo.png differ diff --git a/hotel_management_odoo/static/description/assets/misc/email.svg b/hotel_management_odoo/static/description/assets/misc/email.svg new file mode 100644 index 000000000..15291cdc3 --- /dev/null +++ b/hotel_management_odoo/static/description/assets/misc/email.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hotel_management_odoo/static/description/assets/misc/features.png b/hotel_management_odoo/static/description/assets/misc/features.png new file mode 100644 index 000000000..b41769f77 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/misc/features.png differ diff --git a/hotel_management_odoo/static/description/assets/misc/logo.png b/hotel_management_odoo/static/description/assets/misc/logo.png new file mode 100644 index 000000000..478462d3e Binary files /dev/null and b/hotel_management_odoo/static/description/assets/misc/logo.png differ diff --git a/hotel_management_odoo/static/description/assets/misc/phone.svg b/hotel_management_odoo/static/description/assets/misc/phone.svg new file mode 100644 index 000000000..b7bd7f251 --- /dev/null +++ b/hotel_management_odoo/static/description/assets/misc/phone.svg @@ -0,0 +1,3 @@ + + + diff --git a/hotel_management_odoo/static/description/assets/misc/pictures.png b/hotel_management_odoo/static/description/assets/misc/pictures.png new file mode 100644 index 000000000..56d255fe9 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/misc/pictures.png differ diff --git a/hotel_management_odoo/static/description/assets/misc/pie-chart.png b/hotel_management_odoo/static/description/assets/misc/pie-chart.png new file mode 100644 index 000000000..426e05244 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/misc/pie-chart.png differ diff --git a/hotel_management_odoo/static/description/assets/misc/right-arrow.png b/hotel_management_odoo/static/description/assets/misc/right-arrow.png new file mode 100644 index 000000000..730984a06 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/misc/right-arrow.png differ diff --git a/hotel_management_odoo/static/description/assets/misc/star (1) 2.svg b/hotel_management_odoo/static/description/assets/misc/star (1) 2.svg new file mode 100644 index 000000000..5ae9f507a --- /dev/null +++ b/hotel_management_odoo/static/description/assets/misc/star (1) 2.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/hotel_management_odoo/static/description/assets/misc/star.png b/hotel_management_odoo/static/description/assets/misc/star.png new file mode 100644 index 000000000..2eb9ab29f Binary files /dev/null and b/hotel_management_odoo/static/description/assets/misc/star.png differ diff --git a/hotel_management_odoo/static/description/assets/misc/support (1) 1.svg b/hotel_management_odoo/static/description/assets/misc/support (1) 1.svg new file mode 100644 index 000000000..7d37a8f30 --- /dev/null +++ b/hotel_management_odoo/static/description/assets/misc/support (1) 1.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/hotel_management_odoo/static/description/assets/misc/support-email.svg b/hotel_management_odoo/static/description/assets/misc/support-email.svg new file mode 100644 index 000000000..eb70370d6 --- /dev/null +++ b/hotel_management_odoo/static/description/assets/misc/support-email.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/hotel_management_odoo/static/description/assets/misc/support.png b/hotel_management_odoo/static/description/assets/misc/support.png new file mode 100644 index 000000000..4f18b8b82 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/misc/support.png differ diff --git a/hotel_management_odoo/static/description/assets/misc/tick-mark.svg b/hotel_management_odoo/static/description/assets/misc/tick-mark.svg new file mode 100644 index 000000000..2dbb40187 --- /dev/null +++ b/hotel_management_odoo/static/description/assets/misc/tick-mark.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/hotel_management_odoo/static/description/assets/misc/whatsapp 1.svg b/hotel_management_odoo/static/description/assets/misc/whatsapp 1.svg new file mode 100644 index 000000000..0bfaf8fc6 --- /dev/null +++ b/hotel_management_odoo/static/description/assets/misc/whatsapp 1.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/hotel_management_odoo/static/description/assets/misc/whatsapp.png b/hotel_management_odoo/static/description/assets/misc/whatsapp.png new file mode 100644 index 000000000..d513a5356 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/misc/whatsapp.png differ diff --git a/hotel_management_odoo/static/description/assets/misc/whatsapp.svg b/hotel_management_odoo/static/description/assets/misc/whatsapp.svg new file mode 100644 index 000000000..b618aea1d --- /dev/null +++ b/hotel_management_odoo/static/description/assets/misc/whatsapp.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hotel_management_odoo/static/description/assets/modules/1.png b/hotel_management_odoo/static/description/assets/modules/1.png new file mode 100644 index 000000000..2c8fbb83f Binary files /dev/null and b/hotel_management_odoo/static/description/assets/modules/1.png differ diff --git a/hotel_management_odoo/static/description/assets/modules/2.png b/hotel_management_odoo/static/description/assets/modules/2.png new file mode 100644 index 000000000..17ba4d75f Binary files /dev/null and b/hotel_management_odoo/static/description/assets/modules/2.png differ diff --git a/hotel_management_odoo/static/description/assets/modules/3.png b/hotel_management_odoo/static/description/assets/modules/3.png new file mode 100644 index 000000000..a29119785 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/modules/3.png differ diff --git a/hotel_management_odoo/static/description/assets/modules/4.png b/hotel_management_odoo/static/description/assets/modules/4.png new file mode 100644 index 000000000..3add135c3 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/modules/4.png differ diff --git a/hotel_management_odoo/static/description/assets/modules/5.png b/hotel_management_odoo/static/description/assets/modules/5.png new file mode 100644 index 000000000..31ed46762 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/modules/5.png differ diff --git a/hotel_management_odoo/static/description/assets/modules/6.gif b/hotel_management_odoo/static/description/assets/modules/6.gif new file mode 100644 index 000000000..0b7368dc0 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/modules/6.gif differ diff --git a/hotel_management_odoo/static/description/assets/screenshots/configuration.png b/hotel_management_odoo/static/description/assets/screenshots/configuration.png new file mode 100644 index 000000000..9b1435b45 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/screenshots/configuration.png differ diff --git a/hotel_management_odoo/static/description/assets/screenshots/db.png b/hotel_management_odoo/static/description/assets/screenshots/db.png new file mode 100644 index 000000000..004c24338 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/screenshots/db.png differ diff --git a/hotel_management_odoo/static/description/assets/screenshots/hero.gif b/hotel_management_odoo/static/description/assets/screenshots/hero.gif new file mode 100644 index 000000000..488574580 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/screenshots/hero.gif differ diff --git a/hotel_management_odoo/static/description/assets/screenshots/maintains_req.png b/hotel_management_odoo/static/description/assets/screenshots/maintains_req.png new file mode 100644 index 000000000..949c3589c Binary files /dev/null and b/hotel_management_odoo/static/description/assets/screenshots/maintains_req.png differ diff --git a/hotel_management_odoo/static/description/assets/screenshots/maintains_team.png b/hotel_management_odoo/static/description/assets/screenshots/maintains_team.png new file mode 100644 index 000000000..bbaf37381 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/screenshots/maintains_team.png differ diff --git a/hotel_management_odoo/static/description/assets/screenshots/manufactures.png b/hotel_management_odoo/static/description/assets/screenshots/manufactures.png new file mode 100644 index 000000000..0b9937461 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/screenshots/manufactures.png differ diff --git a/hotel_management_odoo/static/description/assets/screenshots/product.png b/hotel_management_odoo/static/description/assets/screenshots/product.png new file mode 100644 index 000000000..4cdab821a Binary files /dev/null and b/hotel_management_odoo/static/description/assets/screenshots/product.png differ diff --git a/hotel_management_odoo/static/description/assets/screenshots/rbfp.png b/hotel_management_odoo/static/description/assets/screenshots/rbfp.png new file mode 100644 index 000000000..72da4c8b1 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/screenshots/rbfp.png differ diff --git a/hotel_management_odoo/static/description/assets/screenshots/reports.png b/hotel_management_odoo/static/description/assets/screenshots/reports.png new file mode 100644 index 000000000..3405bdbe8 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/screenshots/reports.png differ diff --git a/hotel_management_odoo/static/description/assets/screenshots/res1.png b/hotel_management_odoo/static/description/assets/screenshots/res1.png new file mode 100644 index 000000000..2a6c2d14c Binary files /dev/null and b/hotel_management_odoo/static/description/assets/screenshots/res1.png differ diff --git a/hotel_management_odoo/static/description/assets/screenshots/resfp.png b/hotel_management_odoo/static/description/assets/screenshots/resfp.png new file mode 100644 index 000000000..32eaf3a46 Binary files /dev/null and b/hotel_management_odoo/static/description/assets/screenshots/resfp.png differ diff --git a/hotel_management_odoo/static/description/assets/screenshots/sale_order_report.png b/hotel_management_odoo/static/description/assets/screenshots/sale_order_report.png new file mode 100644 index 000000000..3f72aeadf Binary files /dev/null and b/hotel_management_odoo/static/description/assets/screenshots/sale_order_report.png differ diff --git a/hotel_management_odoo/static/description/assets/screenshots/user_page.png b/hotel_management_odoo/static/description/assets/screenshots/user_page.png new file mode 100644 index 000000000..2dffd3a7a Binary files /dev/null and b/hotel_management_odoo/static/description/assets/screenshots/user_page.png differ diff --git a/hotel_management_odoo/static/description/assets/screenshots/vendor.png b/hotel_management_odoo/static/description/assets/screenshots/vendor.png new file mode 100644 index 000000000..3fbfbfe3a Binary files /dev/null and b/hotel_management_odoo/static/description/assets/screenshots/vendor.png differ diff --git a/hotel_management_odoo/static/description/banner.jpg b/hotel_management_odoo/static/description/banner.jpg new file mode 100644 index 000000000..d92c3d803 Binary files /dev/null and b/hotel_management_odoo/static/description/banner.jpg differ diff --git a/hotel_management_odoo/static/description/icon.png b/hotel_management_odoo/static/description/icon.png new file mode 100644 index 000000000..8796f70a1 Binary files /dev/null and b/hotel_management_odoo/static/description/icon.png differ diff --git a/hotel_management_odoo/static/description/index.html b/hotel_management_odoo/static/description/index.html new file mode 100644 index 000000000..c210610d5 --- /dev/null +++ b/hotel_management_odoo/static/description/index.html @@ -0,0 +1,825 @@ + + + + + + + Odoo App 3 Index + + + + + + + + +
+
+
+
+
+ +
+
+
+ Community +
+
+ Enterprise +
+
+
+
+
+
+

+ Hotel Management

+

+ A Complete Hotel Management System that Cover All Areas of + Hotel + Services +

+
+ +
+
+
+
+
+

+ Key Highlights +

+
+
+
+
+
+ +
+
+

+ Odoo 17 Community & Enterprise Edition + Support.

+

Hotel Management in Odoo 17 Community & + Enterprise Edition. +

+
+
+
+
+
+
+ +
+
+

+ Room Reservation

+

Reserve Hotel Rooms based on requirement of Room Capacity and Room Type +

+
+
+
+
+
+
+ +
+
+

+ Service, Food & Vehicle Management

+

+ Order Service, Food and vehicle as per need +

+
+
+
+
+
+
+ +
+
+

+ Event Management.

+

Book Slots for your favorite Event +

+
+
+
+
+
+
+ +
+
+

+ Maintenance Management

+

Request for Maintenance work as per need +

+
+
+
+
+
+
+ + +
+
+
+
+
+ +
+
+

+ User Configuration

+
+ In the user Form Page there is Some fields to give the access Permission
+
+
+
+
+
+
+ +
+
+

+ Dashboard

+
+
+
+
+
+
+
+
+ +
+
+

+ User access Level

+
+ Can Set up the User access Level in user form page
+
+
+
+
+
+
+ +
+
+

+ Room booking form page

+
+ User-friendly Room booking form page, easy to use
+
+
+
+
+
+
+ +
+
+

+ Room booking Tree view

+
+ User can easily manage the list of records
+
+
+
+
+
+
+ +
+
+

+ Vendor section

+
+ Can Set up the vendor from here.
+
+
+
+
+
+
+ +
+
+

+ Report

+
+ Can Print out the sale order reports.
+
+
+
+
+
+
+ +
+
+

+ Different Report types

+
+ Can Download XLSX and PDF report.
+
+
+
+
+
+
+ +
+
+

+ Product section

+
+ Can Manage Product from the Product model
+
+
+
+
+
+
+ +
+
+

+ Manufactures section

+
+ Can Manage Manufactures from the Manufactures model
+
+
+
+
+
+
+ +
+
+

+ Room maintaining team section

+
+ Can Manage Room maintaining team from here.
+
+
+
+
+
+
+ +
+
+

+ Maintain request section

+
+ Can Manage Maintain request with the Maintain request model
+
+
+
+
+
+
+ +
+
+

+ Configuration menu

+
+ Can configure Room , services , floor etc. with the Configuration model
+
+
+
+
+
+
+ +
+
+

+ Maintain request section

+
+ Can Manage Maintain request with the Maintain request model
+
+
+
+
+ +
+
+
    +
  • + Reserve Hotel Rooms based on requirement of Room Capacity and Room Type +
  • +
  • + Book Slots for your favorite Event +
  • +
  • + Request for Maintenance work as per need +
  • +
  • + Order Service, Food and vehicle as per need +
  • +
  • + Can Set up the User access Level +
  • +
  • + Can Download XLSX and PDF reports +
  • + +
+
+
+
+
+
+
Version + 17.0.1.0.0|Released on:15th Jan 2024 +
+

+ Odoo 17 Hotel Management.

+
+
+
+
+
+
+
+

Related Products

+
+
+ +
+
+

Our Services

+ +
+
+
+
+
+
+
+
+ service-icon +
+
+

Odoo Customization

+
+
+
+
+
+
+ service-icon +
+
+

Odoo Implementation

+
+
+
+
+
+
+ service-icon +
+
+

Odoo Support

+
+
+
+
+
+
+ service-icon +
+
+

Hire Odoo Developer

+
+
+
+
+ +
+
+ service-icon +
+
+

Odoo Integration

+
+
+
+
+
+
+ service-icon +
+
+

Odoo Migration

+
+
+
+
+
+
+ service-icon +
+
+

Odoo Consultancy

+
+
+
+
+
+
+ service-icon +
+
+

Odoo Implementation

+
+
+
+
+
+
+ service-icon +
+
+

Odoo Licensing Consultancy

+
+
+
+
+
+
+

Our Industries

+ +
+
+
+
+
+
+ +

Trading

+

Easily procure and sell your products

+
+
+
+
+ +

POS

+

Easy configuration and convivial experience

+
+
+
+
+ +

Education

+

A platform for educational management

+
+
+
+
+ +

Manufacturing

+

Plan, track and schedule your operations

+
+
+
+
+ +

E-commerce & Website

+

Mobile friendly, awe-inspiring product pages

+
+
+
+
+ +

Service Management

+

Keep track of services and invoice

+
+
+
+
+ +

Restaurant

+

Run your bar or restaurant methodically

+
+
+
+
+ +

Hotel Management

+

An all-inclusive hotel management application

+
+
+
+
+
+
+

Support

+
+
+
+
+
+
+
+ +
+ Need + Help? +

Got questions or need help? Get in touch.

+
odoo@cybrosys.com +
+
+
+
+
+
+
+
+ +
+ WhatsApp +

Say hi + to us on WhatsApp!

+
+91 + 99456767686 +
+
+
+
+
+
+
+
+
+ + + + + + diff --git a/hotel_management_odoo/static/src/css/dashboard.css b/hotel_management_odoo/static/src/css/dashboard.css new file mode 100644 index 000000000..2f3663c2a --- /dev/null +++ b/hotel_management_odoo/static/src/css/dashboard.css @@ -0,0 +1,32 @@ +.main-section{ + margin:25px; + padding:0px; + background: none; +} +.oh_dashboards { + padding: 0px !important; +} +.dash-card .card{ + text-align:center; + border:none; + margin:20px; +} +.dash-card .card:hover { + + transform: translateY(-2px) translateZ(0) !important; + box-shadow: 0 10px 10px 0 rgba(62, 57, 107, 0.12), 0 0 0 transparent !important; + +} +.dash-card .dash-count{ + font-size:35px; +} +.dash-card .dash-icon-1{ + width:100%; + font-size: 36px; + font-weight: 900; + margin-top:10px; +} +.dash-card .dash-head{ + font-weight: 300; + font-size: 18px; +} diff --git a/hotel_management_odoo/static/src/js/action_manager.js b/hotel_management_odoo/static/src/js/action_manager.js new file mode 100644 index 000000000..112f4f92d --- /dev/null +++ b/hotel_management_odoo/static/src/js/action_manager.js @@ -0,0 +1,23 @@ +/** @odoo-module **/ +import { registry } from "@web/core/registry"; +import { BlockUI } from "@web/core/ui/block_ui"; +import { download } from "@web/core/network/download"; +/** +XLSX Handler +This handler is responsible for generating XLSX reports. +It sends a request to the server to generate the report in XLSX format +and downloads the generated file. +@param {Object} action - The action object containing the report details. +@returns {Promise} - A promise that resolves when the report generation is complete. +*/ +registry.category("ir.actions.report handlers").add("xlsx", async function (action) { + if (action.report_type === 'xlsx') { + BlockUI; + await download({ + url: '/xlsx_reports', + data: action.data, + complete: () => unblockUI, + error: (error) => self.call('crash_manager', 'rpc_error', error), + }); + } +}); diff --git a/hotel_management_odoo/static/src/js/dashboard_action.js b/hotel_management_odoo/static/src/js/dashboard_action.js new file mode 100644 index 000000000..98454b338 --- /dev/null +++ b/hotel_management_odoo/static/src/js/dashboard_action.js @@ -0,0 +1,297 @@ +/** @odoo-module */ +import { registry} from '@web/core/registry'; +import { useService } from "@web/core/utils/hooks"; +const { Component, onWillStart, onMounted} = owl +import { jsonrpc } from "@web/core/network/rpc_service"; +import { Domain } from "@web/core/domain"; +import { _t } from "@web/core/l10n/translation"; +import {serializeDate,serializeDateTime,} from "@web/core/l10n/dates"; +const today = new Date(); +const day = today.getDate(); // Returns the day of the month (1-31) +const month = today.getMonth() + 1; // Returns the month (0-11); Adding 1 to match regular months (1-12) +const year = today.getFullYear(); // Returns the year (4 digits) +// Display the current date in a specific format (e.g., MM/DD/YYYY) +const formattedDate = `${year}-${month}-${day}`; +export class CustomDashBoard extends Component { + /** + * Setup method to initialize required services and register event handlers. + */ +setup() { +this.action = useService("action"); +this.orm = useService("orm"); +onWillStart(this.onWillStart); +onMounted(this.onMounted); +} +async onWillStart() { +await this.fetch_data(); +} +async onMounted() { +// Render other components after fetching data +// this.render_project_task(); +// this.render_top_employees_graph(); +// this.render_filter(); +} +fetch_data() { + var self = this; + //RPC call for retrieving data for displaying on dashboard tiles + var def1= jsonrpc('/web/dataset/call_kw/room.booking/get_details' + ,{ model:'room.booking', + method:'get_details', + args: [{}], + kwargs: {}, + }).then(function(result){ + document.getElementsByClassName("total_room").innerHTML=['total_room'] + self.total_room=result['total_room'] + self.available_room=result['available_room'] + self.staff=result['staff'] + self.check_in=result['check_in'] + self.reservation=result['reservation'] + self.check_out=result['check_out'] + self.total_vehicle=result['total_vehicle'] + self.available_vehicle=result['available_vehicle'] + self.total_event=result['total_event'] + self.today_events=result['today_events'] + self.pending_events=result['pending_events'] + self.food_items=result['food_items'] + self.food_order=result['food_order'] + if(result['currency_position']=='before'){ + self.total_revenue=result['currency_symbol']+" "+result['total_revenue'] + self.today_revenue=result['currency_symbol']+" "+result['today_revenue'] + self.pending_payment=result['currency_symbol']+" "+result['pending_payment'] + } + else{ + self.total_revenue=+result['total_revenue']+" "+result['currency_symbol'] + self.today_revenue=result['today_revenue']+" "+result['currency_symbol'] + self.pending_payment=result['pending_payment']+" "+result['currency_symbol'] + } + + }); + + return $.when(def1); + } + total_rooms(e){ + var self = this; + e.stopPropagation(); + e.preventDefault(); + var options={on_reverse_breadcrum:this.on_reverse_breadcrum,}; + console.log(this.action.doAction) + this.action.doAction({ + name: _t("Rooms"), + type:'ir.actions.act_window', + res_model:'hotel.room', + view_mode:'tree,form', + view_type:'form', + views:[[false,'list'],[false,'form']], + target:'current' + },options) + } + check_ins(e){ + var self = this; + e.stopPropagation(); + e.preventDefault(); + var options={on_reverse_breadcrum:this.on_reverse_breadcrum,}; + this.action.doAction({ + name: _t("Check-In"), + type:'ir.actions.act_window', + res_model:'room.booking', + view_mode:'tree,form', + view_type:'form', + views:[[false,'list'],[false,'form']], + domain: [['state', '=', 'check_in']], + target:'current' + },options) + } + // Total Events + view_total_events(e){ + var self = this; + e.stopPropagation(); + e.preventDefault(); + var options={on_reverse_breadcrum:this.on_reverse_breadcrum,}; + this.action.doAction({ + name: _t("Total Events"), + type:'ir.actions.act_window', + res_model:'event.event', + view_mode:'kanban,tree,form', + view_type:'form', + views:[[false,'kanban'],[false,'list'],[false,'form']], + domain: [], + target:'current' + },options) + } +// // Today's Events + fetch_today_events(e){ + var self = this; + e.stopPropagation(); + e.preventDefault(); + var options={on_reverse_breadcrum:this.on_reverse_breadcrum,}; + this.action.doAction({ + name: _t("Today's Events"), + type:'ir.actions.act_window', + res_model:'event.event', + view_mode:'kanban,tree,form', + view_type:'form', + views:[[false,'kanban'],[false,'list'],[false,'form']], + domain: [['date_end', '=', formattedDate]], + target:'current' + },options) + } +// // Pending Events + fetch_pending_events(e){ + var self = this; + e.stopPropagation(); + e.preventDefault(); + var options={on_reverse_breadcrum:this.on_reverse_breadcrum,}; + this.action.doAction({ + name: _t("Pending Events"), + type:'ir.actions.act_window', + res_model:'event.event', + view_mode:'kanban,tree,form', + view_type:'form', + views:[[false,'kanban'],[false,'list'],[false,'form']], + domain: [['date_end', '>=', formattedDate]], + target:'current' + },options) + } +// // Total staff + fetch_total_staff(e){ + var self = this; + e.stopPropagation(); + e.preventDefault(); + var options={on_reverse_breadcrum:this.on_reverse_breadcrum,}; + this.action.doAction({ + name: _t("Total Staffs"), + type:'ir.actions.act_window', + res_model:'res.users', + view_mode:'tree,form', + view_type:'form', + views:[[false,'list'],[false,'form']], + domain: [['groups_id.name', 'in',['Admin', + 'Cleaning Team User', + 'Cleaning Team Head', + 'Receptionist', + 'Maintenance Team User', + 'Maintenance Team Leader' + ]]], + target:'current' + },options) + } + // check-out + check_outs(e){ + var self = this; + var options={on_reverse_breadcrum:this.on_reverse_breadcrum,}; + this.action.doAction({ + name: _t("Today's Check-Out"), + type:'ir.actions.act_window', + res_model:'room.booking', + view_mode:'tree,form', + view_type:'form', + views:[[false,'list'],[false,'form']], + domain: [['room_line_ids.checkout_date', '=', formattedDate]], + target:'current' + },options) + } +// Available rooms + available_rooms(e){ + var self = this; + e.stopPropagation(); + e.preventDefault(); + var options={on_reverse_breadcrum:this.on_reverse_breadcrum,}; + this.action.doAction({ + name: _t("Available Room"), + type:'ir.actions.act_window', + res_model:'hotel.room', + view_mode:'tree,form', + view_type:'form', + views:[[false,'list'],[false,'form']], + domain: [['status', '=', 'available']], + target:'current' + },options) + } +// Reservations + reservations(e){ + var self = this; + e.stopPropagation(); + e.preventDefault(); + var options={on_reverse_breadcrum:this.on_reverse_breadcrum,}; + this.action.doAction({ + name: _t("Total Reservations"), + type:'ir.actions.act_window', + res_model:'room.booking', + view_mode:'tree,form', + view_type:'form', + views:[[false,'list'],[false,'form']], + domain: [['state', '=', 'reserved']], + target:'current' + },options) + } +// Food Items + fetch_food_item(e){ + var self = this; + e.stopPropagation(); + e.preventDefault(); + var options={on_reverse_breadcrum:this.on_reverse_breadcrum,}; + this.action.doAction({ + name: _t("Food Items"), + type:'ir.actions.act_window', + res_model:'lunch.product', + view_mode:'tree,form', + view_type:'form', + views:[[false,'list'],[false,'form']], + domain: [], + target:'current' + },options) + } +// food Orders + async fetch_food_order(e){ + var self = this; + const result = await this.orm.call('food.booking.line', 'search_food_orders',[{}],{}); + e.stopPropagation(); + e.preventDefault(); + var options={on_reverse_breadcrum:this.on_reverse_breadcrum,}; + this.action.doAction({ + name: _t("Food Orders"), + type:'ir.actions.act_window', + res_model:'food.booking.line', + view_mode:'tree,form', + view_type:'form', + views:[[false,'list'],[false,'form']], + domain: [['id','in', result]], + target:'current' + },options) + } +// total vehicle + fetch_total_vehicle(e){ + var self = this; + e.stopPropagation(); + e.preventDefault(); + var options={on_reverse_breadcrum:this.on_reverse_breadcrum,}; + this.action.doAction({name: _t("Total Vehicles"), + type:'ir.actions.act_window', + res_model:'fleet.vehicle.model', + view_mode:'tree,form', + view_type:'form', + views:[[false,'list'],[false,'form']], + target:'current' + },options) + } +// Available Vehicle + async fetch_available_vehicle(e){ + const result = await this.orm.call('fleet.booking.line', 'search_available_vehicle',[{}],{}); + var self = this; + var options={on_reverse_breadcrum:this.on_reverse_breadcrum,}; + e.stopPropagation(); + e.preventDefault(); + this.action.doAction({ + name: _t("Available Vehicle"), + type:'ir.actions.act_window', + res_model:'fleet.vehicle.model', + view_mode:'tree,form', + view_type:'form', + views:[[false,'list'],[false,'form']], + domain: [['id','not in', result]], + target:'current' + },options) + } +} +CustomDashBoard.template = "CustomDashBoard" +registry.category("actions").add("custom_dashboard_tags", CustomDashBoard) \ No newline at end of file diff --git a/hotel_management_odoo/static/src/xml/dashboard_templates.xml b/hotel_management_odoo/static/src/xml/dashboard_templates.xml new file mode 100644 index 000000000..c91dfeafa --- /dev/null +++ b/hotel_management_odoo/static/src/xml/dashboard_templates.xml @@ -0,0 +1,287 @@ + + + diff --git a/hotel_management_odoo/views/account_move_views.xml b/hotel_management_odoo/views/account_move_views.xml new file mode 100644 index 000000000..4736ce654 --- /dev/null +++ b/hotel_management_odoo/views/account_move_views.xml @@ -0,0 +1,16 @@ + + + + + + account.move.view.form.inherit.odoo.hotel.management + + account.move + + + + + + + + diff --git a/hotel_management_odoo/views/cleaning_request_views.xml b/hotel_management_odoo/views/cleaning_request_views.xml new file mode 100644 index 000000000..c95387926 --- /dev/null +++ b/hotel_management_odoo/views/cleaning_request_views.xml @@ -0,0 +1,118 @@ + + + + + cleaning.request.view.tree + cleaning.request + + + + + + + + + + + + cleaning.request.view.form + cleaning.request + +
+
+
+ +

+ +

+ + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + + cleaning.team.view.tree + cleaning.team + + + + + + + + + + Cleaning Request + cleaning.request + ir.actions.act_window + tree,form + {} + + + +
diff --git a/hotel_management_odoo/views/cleaning_team_views.xml b/hotel_management_odoo/views/cleaning_team_views.xml new file mode 100644 index 000000000..f06f7d8da --- /dev/null +++ b/hotel_management_odoo/views/cleaning_team_views.xml @@ -0,0 +1,77 @@ + + + + + cleaning.team.view.tree + cleaning.team + + + + + + + + + + cleaning.team.view.form + cleaning.team + +
+ + + + + + + + + + + + + + + + + + +
+
+
+ + + Cleaning Team + cleaning.team + ir.actions.act_window + tree,form + {} + + + + + +
diff --git a/hotel_management_odoo/views/dashboard_view.xml b/hotel_management_odoo/views/dashboard_view.xml new file mode 100644 index 000000000..d94d05589 --- /dev/null +++ b/hotel_management_odoo/views/dashboard_view.xml @@ -0,0 +1,13 @@ + + + + + Dashboard + custom_dashboard_tags + + + + diff --git a/hotel_management_odoo/views/fleet_vehicle_model_views.xml b/hotel_management_odoo/views/fleet_vehicle_model_views.xml new file mode 100644 index 000000000..08077b8d3 --- /dev/null +++ b/hotel_management_odoo/views/fleet_vehicle_model_views.xml @@ -0,0 +1,38 @@ + + + + + + fleet.vehicle.model.view.form.inherit.odoo.hotel.management + + fleet.vehicle.model + + + + + + + + + + + Vehicles + fleet.vehicle.model + tree,form + + + + Manufacturers + fleet.vehicle.model.brand + kanban,tree,form + + + + + + \ No newline at end of file diff --git a/hotel_management_odoo/views/food_booking_line_views.xml b/hotel_management_odoo/views/food_booking_line_views.xml new file mode 100644 index 000000000..637a14c91 --- /dev/null +++ b/hotel_management_odoo/views/food_booking_line_views.xml @@ -0,0 +1,47 @@ + + + + + food.booking.line.view.form + food.booking.line + +
+ +

+ +

+ + + + + + + + + + + + + +
+
+
+
+ + + food.booking.line.view.tree + food.booking.line + + + + + + + + + + + + + +
diff --git a/hotel_management_odoo/views/hotel_amenity_views.xml b/hotel_management_odoo/views/hotel_amenity_views.xml new file mode 100644 index 000000000..9f151f948 --- /dev/null +++ b/hotel_management_odoo/views/hotel_amenity_views.xml @@ -0,0 +1,52 @@ + + + + + hotel.amenity.view.tree + hotel.amenity + + + + + + + + + hotel.amenity.view.form + hotel.amenity + +
+ + + + + + + + + + + +
+ + +
+
+
+
+ + + Amenity + ir.actions.act_window + hotel.amenity + tree,form + {'default_detailed_type': 'service'} + + + +
diff --git a/hotel_management_odoo/views/hotel_detail_views.xml b/hotel_management_odoo/views/hotel_detail_views.xml new file mode 100644 index 000000000..da27ed7de --- /dev/null +++ b/hotel_management_odoo/views/hotel_detail_views.xml @@ -0,0 +1,43 @@ + + + + + hotel.details.view.tree + hotel.detail + + + + + + + + + + hotel.details.view.form + hotel.detail + +
+ + + + + + + +
+
+
+ + + Hotel Details + ir.actions.act_window + hotel.detail + tree,form + + + +
diff --git a/hotel_management_odoo/views/hotel_floor_views.xml b/hotel_management_odoo/views/hotel_floor_views.xml new file mode 100644 index 000000000..6c5b1dc96 --- /dev/null +++ b/hotel_management_odoo/views/hotel_floor_views.xml @@ -0,0 +1,27 @@ + + + + + hotel.floor.view.tree + hotel.floor + + + + + + + + + + Floors + ir.actions.act_window + hotel.floor + tree + + + + diff --git a/hotel_management_odoo/views/hotel_menu_views.xml b/hotel_management_odoo/views/hotel_menu_views.xml new file mode 100644 index 000000000..323b9e47e --- /dev/null +++ b/hotel_management_odoo/views/hotel_menu_views.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + diff --git a/hotel_management_odoo/views/hotel_room_views.xml b/hotel_management_odoo/views/hotel_room_views.xml new file mode 100644 index 000000000..dc5c014eb --- /dev/null +++ b/hotel_management_odoo/views/hotel_room_views.xml @@ -0,0 +1,95 @@ + + + + + hotel.room.view.tree + hotel.room + + + + + + + + + + + + + hotel.room.view.form + hotel.room + +
+
+ +
+ + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + + Rooms + ir.actions.act_window + hotel.room + tree,form + {'default_is_room_avail':True} + + + +
diff --git a/hotel_management_odoo/views/hotel_service_views.xml b/hotel_management_odoo/views/hotel_service_views.xml new file mode 100644 index 000000000..5492bcbfa --- /dev/null +++ b/hotel_management_odoo/views/hotel_service_views.xml @@ -0,0 +1,27 @@ + + + + + hotel.service.view.tree + hotel.service + + + + + + + + + + + Services + hotel.service + tree + + + + diff --git a/hotel_management_odoo/views/lunch_product_views.xml b/hotel_management_odoo/views/lunch_product_views.xml new file mode 100644 index 000000000..1ec6712af --- /dev/null +++ b/hotel_management_odoo/views/lunch_product_views.xml @@ -0,0 +1,27 @@ + + + + + Products + lunch.product + tree,kanban,form + + + + Vendors + lunch.supplier + kanban,tree,form + + + + + + diff --git a/hotel_management_odoo/views/maintenance_request_views.xml b/hotel_management_odoo/views/maintenance_request_views.xml new file mode 100644 index 000000000..a9908f77d --- /dev/null +++ b/hotel_management_odoo/views/maintenance_request_views.xml @@ -0,0 +1,108 @@ + + + + + maintenance.request.view.form + maintenance.request + +
+
+
+ +
+

+ +

+
+ + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + + Maintenance Request + ir.actions.act_window + maintenance.request + tree,form + + + +
diff --git a/hotel_management_odoo/views/maintenance_team_views.xml b/hotel_management_odoo/views/maintenance_team_views.xml new file mode 100644 index 000000000..a890dcba1 --- /dev/null +++ b/hotel_management_odoo/views/maintenance_team_views.xml @@ -0,0 +1,78 @@ + + + + + maintenance.team.view.form + maintenance.team + +
+ + + + + + + + + + + + + + + + + +
+
+ +
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+ + + maintenance.team.view.tree + maintenance.team + + + + + + + + + + Maintenance Team + maintenance.team + ir.actions.act_window + tree,form + + + + + +
diff --git a/hotel_management_odoo/views/reporting_views.xml b/hotel_management_odoo/views/reporting_views.xml new file mode 100644 index 000000000..66f91de78 --- /dev/null +++ b/hotel_management_odoo/views/reporting_views.xml @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/hotel_management_odoo/views/room_booking_views.xml b/hotel_management_odoo/views/room_booking_views.xml new file mode 100644 index 000000000..3df7ab57e --- /dev/null +++ b/hotel_management_odoo/views/room_booking_views.xml @@ -0,0 +1,333 @@ + + + + + room.booking.view.form + room.booking + +
+
+
+ +
+ +
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + room.booking.view.tree + room.booking + + + + + + + + + + + + Room Booking + ir.actions.act_window + room.booking + tree,form + + + + diff --git a/hotel_management_odoo/wizard/__init__.py b/hotel_management_odoo/wizard/__init__.py new file mode 100644 index 000000000..f88603766 --- /dev/null +++ b/hotel_management_odoo/wizard/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +from .import room_booking_detail +from .import sale_order_detail diff --git a/hotel_management_odoo/wizard/room_booking_detail.py b/hotel_management_odoo/wizard/room_booking_detail.py new file mode 100644 index 000000000..f9dd16bda --- /dev/null +++ b/hotel_management_odoo/wizard/room_booking_detail.py @@ -0,0 +1,150 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +import io +import json +from odoo import fields, models, _ +from odoo.exceptions import ValidationError +from odoo.tools import date_utils + +try: + from odoo.tools.misc import xlsxwriter +except ImportError: + import xlsxwriter + + +class RoomBookingWizard(models.TransientModel): + """Pdf Report for room Booking""" + + _name = "room.booking.detail" + _description = "Room Booking Details" + + checkin = fields.Date(help="Choose the Checkin Date", string="Checkin") + checkout = fields.Date(help="Choose the Checkout Date", string="Checkout") + room_id = fields.Many2one("hotel.room", string="Room", + help="Choose The Room") + + def action_room_booking_pdf(self): + """Button action_room_booking_pdf function""" + data = { + "booking": self.generate_data(), + } + return self.env.ref( + "hotel_management_odoo.action_report_room_booking" + ).report_action(self, data=data) + + def action_room_booking_excel(self): + """Button action for creating Room Booking Excel report""" + data = { + "booking": self.generate_data(), + } + return { + "type": "ir.actions.report", + "data": { + "model": "room.booking.detail", + "options": json.dumps(data, default=date_utils.json_default), + "output_format": "xlsx", + "report_name": "Excel Report", + }, + "report_type": "xlsx", + } + + def generate_data(self): + """Generate data to be printed in the report""" + domain = [] + room_list = [] + if self.checkin and self.checkout: + if self.checkin > self.checkout: + raise ValidationError( + _("Check-in date should be less than Check-out date") + ) + if self.checkin: + domain.append( + ("checkin_date", ">=", self.checkin), + ) + if self.checkout: + domain.append( + ("checkout_date", "<=", self.checkout), + ) + room_booking = self.env["room.booking"].search_read( + domain=domain, + fields=["partner_id", "name", "checkin_date", "checkout_date"], + ) + for rec in room_booking: + rooms = ( + self.env["room.booking"] + .browse(rec["id"]) + .room_line_ids.room_id.mapped("name") + ) + rec["partner_id"] = rec["partner_id"][1] + for room in rooms: + if self.room_id: + if self.room_id.name == room: + rec["room_id"] = room + room_list.append(rec) + else: + rec_copy = rec.copy() + rec_copy["room_id"] = room + room_list.append(rec_copy) + + return room_list + + def get_xlsx_report(self, data, response): + """Organizing xlsx report""" + output = io.BytesIO() + workbook = xlsxwriter.Workbook(output, {"in_memory": True}) + sheet = workbook.add_worksheet() + cell_format = workbook.add_format( + {"font_size": "14px", "bold": True, "align": "center", + "border": True} + ) + head = workbook.add_format( + {"align": "center", "bold": True, "font_size": "23px", + "border": True} + ) + body = workbook.add_format( + {"align": "left", "text_wrap": True, "border": True}) + sheet.merge_range("A1:F1", "Room Booking", head) + sheet.set_column("A2:F2", 18) + sheet.set_row(0, 30) + sheet.set_row(1, 20) + sheet.write("A2", "Sl No.", cell_format) + sheet.write("B2", "Guest Name", cell_format) + sheet.write("C2", "Room No.", cell_format) + sheet.write("D2", "Check In", cell_format) + sheet.write("E2", "Check Out", cell_format) + sheet.write("F2", "Reference No.", cell_format) + row = 2 + column = 0 + value = 1 + for i in data["booking"]: + sheet.write(row, column, value, body) + sheet.write(row, column + 1, i["partner_id"], body) + sheet.write(row, column + 2, i["room"], body) + sheet.write(row, column + 3, i["checkin_date"], body) + sheet.write(row, column + 4, i["checkout_date"], body) + sheet.write(row, column + 5, i["name"], body) + row = row + 1 + value = value + 1 + workbook.close() + output.seek(0) + response.stream.write(output.read()) + output.close() diff --git a/hotel_management_odoo/wizard/room_booking_detail_views.xml b/hotel_management_odoo/wizard/room_booking_detail_views.xml new file mode 100644 index 000000000..e8cdf2313 --- /dev/null +++ b/hotel_management_odoo/wizard/room_booking_detail_views.xml @@ -0,0 +1,42 @@ + + + + + room.booking.detail.view.form + room.booking.detail + +
+ + + + + +
+ + +
+ +
+
+ + + Room Booking Report + ir.actions.act_window + room.booking.detail + form + + new + +
diff --git a/hotel_management_odoo/wizard/sale_order_detail.py b/hotel_management_odoo/wizard/sale_order_detail.py new file mode 100644 index 000000000..2a1edee34 --- /dev/null +++ b/hotel_management_odoo/wizard/sale_order_detail.py @@ -0,0 +1,128 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies() +# Author: Vishnu K P (odoo@cybrosys.com) +# +# You can modify it under the terms of the GNU LESSER +# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. +# +# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE +# (LGPL v3) along with this program. +# If not, see . +# +############################################################################### +import io +import json +from odoo import fields, models, _ +from odoo.exceptions import ValidationError +from odoo.tools import date_utils + +try: + from odoo.tools.misc import xlsxwriter +except ImportError: + import xlsxwriter + + +class SaleOrderWizard(models.TransientModel): + """Pdf Report for Sale Order""" + _name = "sale.order.detail" + _description = "Room Booking Details" + + checkin = fields.Date(help="Choose the Checkin Date", string="Check In") + checkout = fields.Date(help="Choose the Checkout Date", string="Check Out") + + def action_sale_order_pdf(self): + """Button action for creating Sale Order Pdf Report""" + data = { + 'booking': self.generate_data(), + } + return self.env.ref( + 'hotel_management_odoo.action_report_sale_order').report_action( + self, data=data) + + def action_sale_order_excel(self): + """Button action for creating Sale Order Report""" + data = { + 'booking': self.generate_data(), + } + return { + 'type': 'ir.actions.report', + 'data': {'model': 'sale.order.detail', + 'options': json.dumps(data, + default=date_utils.json_default), + 'output_format': 'xlsx', + 'report_name': 'Excel Report', + }, + 'report_type': 'xlsx', + } + + def generate_data(self): + """Generate data to be printed in the report""" + domain = [] + if self.checkin and self.checkout: + if self.checkin > self.checkout: + raise ValidationError(_( + 'Check-in date should be less than Check-out date')) + if self.checkin: + domain.append(('checkin_date', '>=', self.checkin), ) + if self.checkout: + domain.append(('checkout_date', '<=', self.checkout), ) + room_booking = self.env['room.booking'].search_read(domain=domain, + fields=[ + 'partner_id', + 'name', + 'checkin_date', + 'checkout_date', + 'amount_total']) + for rec in room_booking: + rec['partner_id'] = rec['partner_id'][1] + return room_booking + + def get_xlsx_report(self, data, response): + """Organizing xlsx report""" + output = io.BytesIO() + workbook = xlsxwriter.Workbook(output, {'in_memory': True}) + sheet = workbook.add_worksheet() + cell_format = workbook.add_format( + {'font_size': '14px', 'bold': True, 'align': 'center', + 'border': True}) + head = workbook.add_format( + {'align': 'center', 'bold': True, 'font_size': '23px', + 'border': True}) + body = workbook.add_format( + {'align': 'left', 'text_wrap': True, 'border': True}) + sheet.merge_range('A1:F1', 'Sale Order', head) + sheet.set_column('A2:F2', 18) + sheet.set_row(0, 30) + sheet.set_row(1, 20) + sheet.write('A2', 'Sl No.', cell_format) + sheet.write('B2', 'Guest Name', cell_format) + sheet.write('C2', 'Check In', cell_format) + sheet.write('D2', 'Check Out', cell_format) + sheet.write('E2', 'Reference No.', cell_format) + sheet.write('F2', 'Total Amount', cell_format) + row = 2 + column = 0 + value = 1 + for i in data['booking']: + sheet.write(row, column, value, body) + sheet.write(row, column + 1, i['partner_id'], body) + sheet.write(row, column + 2, i['checkin_date'], body) + sheet.write(row, column + 3, i['checkout_date'], body) + sheet.write(row, column + 4, i['name'], body) + sheet.write(row, column + 5, "{:.2f}".format(i['amount_total']), + body) + row = row + 1 + value = value + 1 + workbook.close() + output.seek(0) + response.stream.write(output.read()) + output.close() diff --git a/hotel_management_odoo/wizard/sale_order_detail_views.xml b/hotel_management_odoo/wizard/sale_order_detail_views.xml new file mode 100644 index 000000000..139428ff8 --- /dev/null +++ b/hotel_management_odoo/wizard/sale_order_detail_views.xml @@ -0,0 +1,39 @@ + + + + + sale.order.detail.view.form + sale.order.detail + +
+ + + + +
+ + +
+ +
+
+ + + Sale Order Report + ir.actions.act_window + sale.order.detail + form + + new + +