@ -0,0 +1,48 @@ |
|||
.. 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 <https://cybrosys.com/>`__ |
|||
|
|||
Credits |
|||
------- |
|||
* Developer:(V18) Adarsh K, |
|||
(V17) Vishnu K P |
|||
Contact: odoo@cybrosys.com |
|||
|
|||
Contacts |
|||
-------- |
|||
* Mail Contact : odoo@cybrosys.com |
|||
* Website : https://cybrosys.com |
|||
|
|||
Bug Tracker |
|||
----------- |
|||
Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. |
|||
|
|||
Maintainer |
|||
========== |
|||
.. image:: https://cybrosys.com/images/logo.png |
|||
:target: https://cybrosys.com |
|||
|
|||
This module is maintained by Cybrosys Technologies. |
|||
|
|||
For support and more information, please visit `Our Website <https://cybrosys.com/>`__ |
|||
|
|||
Further information |
|||
=================== |
|||
HTML Description: `<static/description/index.html>`__ |
@ -0,0 +1,24 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: ADARSH K (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 <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from . import controllers |
|||
from . import models |
|||
from . import wizard |
@ -0,0 +1,75 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: ADARSH K (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 <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
{ |
|||
'name': 'Hotel Management', |
|||
'version': '18.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, |
|||
} |
@ -0,0 +1,22 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: ADARSH K (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 <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
from . import hotel_management_odoo |
@ -0,0 +1,56 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: ADARSH K (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 <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
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))) |
@ -0,0 +1,26 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<data noupdate="1"> |
|||
<!-- Room Booking Sequence--> |
|||
<record id="seq_hotel_folio" model="ir.sequence"> |
|||
<field name="name">Hotel Folio</field> |
|||
<field name="code">room.booking</field> |
|||
<field name="prefix">BOOKING/</field> |
|||
<field name="padding">5</field> |
|||
</record> |
|||
<!-- Cleaning Request sequence--> |
|||
<record id="seq_cleaning" model="ir.sequence"> |
|||
<field name="name">Cleaning Request</field> |
|||
<field name="code">cleaning.request</field> |
|||
<field name="prefix">CLEANING/</field> |
|||
<field name="padding">4</field> |
|||
</record> |
|||
<!-- Maintenance Request Sequence--> |
|||
<record id="seq_maintenance" model="ir.sequence"> |
|||
<field name="name">Maintenance Request</field> |
|||
<field name="code">maintenance.request</field> |
|||
<field name="prefix">MNTC/</field> |
|||
<field name="padding">5</field> |
|||
</record> |
|||
</data> |
|||
</odoo> |
@ -0,0 +1,6 @@ |
|||
## Module <hotel_management_odoo> |
|||
|
|||
#### 11.08.2024 |
|||
#### Version 18.0.1.0.0 |
|||
#### ADD |
|||
- Initial commit for Hotel Management |
@ -0,0 +1,38 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: ADARSH K (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 <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
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 |
@ -0,0 +1,33 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: ADARSH K (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 <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
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") |
@ -0,0 +1,34 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: ADARSH K (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 <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
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") |
@ -0,0 +1,131 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: ADARSH K (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 <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
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'}, |
|||
} |
|||
} |
@ -0,0 +1,43 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: ADARSH K (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 <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
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") |
@ -0,0 +1,109 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: ADARSH K (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 <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
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=[('service_tracking', '=', '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 room booking line.""" |
|||
for line in self: |
|||
base_line = line._prepare_base_line_for_taxes_computation() |
|||
self.env['account.tax']._add_tax_details_in_base_line(base_line, self.env.company) |
|||
line.price_subtotal = base_line['tax_details']['total_excluded_currency'] |
|||
line.price_total = base_line['tax_details']['total_included_currency'] |
|||
line.price_tax = line.price_total - line.price_subtotal |
|||
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 _prepare_base_line_for_taxes_computation(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']._prepare_base_line_for_taxes_computation( |
|||
self, |
|||
**{ |
|||
'tax_ids': self.tax_ids, |
|||
'quantity': self.uom_qty, |
|||
'partner_id': self.booking_id.partner_id, |
|||
'currency_id': self.currency_id, |
|||
}, |
|||
) |
@ -0,0 +1,119 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: ADARSH K (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 <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
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: |
|||
base_line = line._prepare_base_line_for_taxes_computation() |
|||
self.env['account.tax']._add_tax_details_in_base_line(base_line, self.env.company) |
|||
line.price_subtotal = base_line['tax_details']['total_excluded_currency'] |
|||
line.price_total = base_line['tax_details']['total_included_currency'] |
|||
line.price_tax = line.price_total - line.price_subtotal |
|||
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 _prepare_base_line_for_taxes_computation(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']._prepare_base_line_for_taxes_computation( |
|||
self, |
|||
**{ |
|||
'tax_ids': self.tax_ids, |
|||
'quantity': self.uom_qty, |
|||
'partner_id': self.booking_id.partner_id, |
|||
'currency_id': self.currency_id, |
|||
}, |
|||
) |
|||
|
|||
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) |
@ -0,0 +1,39 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: ADARSH K (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 <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
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) |
@ -0,0 +1,117 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: ADARSH K (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 <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
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: |
|||
base_line = line._prepare_base_line_for_taxes_computation() |
|||
self.env['account.tax']._add_tax_details_in_base_line(base_line, self.env.company) |
|||
line.price_subtotal = base_line['tax_details']['total_excluded_currency'] |
|||
line.price_total = base_line['tax_details']['total_included_currency'] |
|||
line.price_tax = line.price_total - line.price_subtotal |
|||
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 _prepare_base_line_for_taxes_computation(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']._prepare_base_line_for_taxes_computation( |
|||
self, |
|||
**{ |
|||
'tax_ids': self.tax_ids, |
|||
'quantity': self.uom_qty, |
|||
'partner_id': self.booking_id.partner_id, |
|||
'currency_id': self.currency_id, |
|||
}, |
|||
) |
|||
|
|||
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) |
@ -0,0 +1,36 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: ADARSH K (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 <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
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") |
@ -0,0 +1,34 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: ADARSH K (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 <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
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) |
@ -0,0 +1,104 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: ADARSH K (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 <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
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 |
@ -0,0 +1,44 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: ADARSH K (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 <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
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) |
@ -0,0 +1,152 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: ADARSH K (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 <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
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' |
@ -0,0 +1,45 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: ADARSH K (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 <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
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)]) |
@ -0,0 +1,738 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: ADARSH K (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 <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
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': 'list,form', |
|||
'view_type': 'list,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 |
|||
} |
@ -0,0 +1,139 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: ADARSH K (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 <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
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: |
|||
base_line = line._prepare_base_line_for_taxes_computation() |
|||
self.env['account.tax']._add_tax_details_in_base_line(base_line, self.env.company) |
|||
line.price_subtotal = base_line['tax_details']['total_excluded_currency'] |
|||
line.price_total = base_line['tax_details']['total_included_currency'] |
|||
line.price_tax = line.price_total - line.price_subtotal |
|||
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 _prepare_base_line_for_taxes_computation(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']._prepare_base_line_for_taxes_computation( |
|||
self, |
|||
**{ |
|||
'tax_ids': self.tax_ids, |
|||
'quantity': self.uom_qty, |
|||
'partner_id': self.booking_id.partner_id, |
|||
'currency_id': self.currency_id, |
|||
}, |
|||
) |
@ -0,0 +1,113 @@ |
|||
# -*- coding: utf-8 -*- |
|||
############################################################################### |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# |
|||
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>) |
|||
# Author: ADARSH K (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 <http://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################### |
|||
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: |
|||
base_line = line._prepare_base_line_for_taxes_computation() |
|||
self.env['account.tax']._add_tax_details_in_base_line(base_line, self.env.company) |
|||
line.price_subtotal = base_line['tax_details']['total_excluded_currency'] |
|||
line.price_total = base_line['tax_details']['total_included_currency'] |
|||
line.price_tax = line.price_total - line.price_subtotal |
|||
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 _prepare_base_line_for_taxes_computation(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']._prepare_base_line_for_taxes_computation( |
|||
self, |
|||
**{ |
|||
'tax_ids': self.tax_ids, |
|||
'quantity': self.uom_qty, |
|||
'partner_id': self.booking_id.partner_id, |
|||
'currency_id': self.currency_id, |
|||
}, |
|||
) |
@ -0,0 +1,60 @@ |
|||
<?xml version = "1.0" encoding = "UTF-8" ?> |
|||
<odoo> |
|||
<!-- Room booking report action--> |
|||
<record id="action_report_room_booking" model="ir.actions.report"> |
|||
<field name="name">Room Booking Order</field> |
|||
<field name="model">room.booking</field> |
|||
<field name="report_type">qweb-pdf</field> |
|||
<field name="report_name">hotel_management_odoo.report_room_booking</field> |
|||
<field name="report_file">hotel_management_odoo.report_room_booking</field> |
|||
<field name="binding_model_id" ref="model_room_booking"/> |
|||
<field name="binding_type">report</field> |
|||
</record> |
|||
<!-- Room booking template--> |
|||
<template id="report_room_booking"> |
|||
<t t-call="web.html_container"> |
|||
<t t-call="web.external_layout"> |
|||
<div class="page"> |
|||
<h2>Room Booking</h2> |
|||
<br/> |
|||
<table class="table"> |
|||
<thead> |
|||
<tr> |
|||
<th>Sl No.</th> |
|||
<th>Guest Name</th> |
|||
<th>Room No.</th> |
|||
<th>Check-In</th> |
|||
<th>Check-Out</th> |
|||
<th>Reference No.</th> |
|||
</tr> |
|||
</thead> |
|||
<t t-set="i" t-value="0"/> |
|||
<t t-foreach="booking" t-as="line"> |
|||
<t t-set="i" t-value="i+1"/> |
|||
<tr> |
|||
<td> |
|||
<t t-esc="i"/> |
|||
</td> |
|||
<td> |
|||
<t t-esc="line['partner_id']"/> |
|||
</td> |
|||
<td> |
|||
<t t-esc="line['room']"/> |
|||
</td> |
|||
<td> |
|||
<t t-esc="line['checkin_date']"/> |
|||
</td> |
|||
<td> |
|||
<t t-esc="line['checkin_date']"/> |
|||
</td> |
|||
<td> |
|||
<t t-esc="line['name']"/> |
|||
</td> |
|||
</tr> |
|||
</t> |
|||
</table> |
|||
</div> |
|||
</t> |
|||
</t> |
|||
</template> |
|||
</odoo> |
@ -0,0 +1,61 @@ |
|||
<?xml version = "1.0" encoding = "UTF-8" ?> |
|||
<odoo> |
|||
<!-- Sale order report action--> |
|||
<record id="action_report_sale_order" model="ir.actions.report"> |
|||
<field name="name">Sale Order</field> |
|||
<field name="model">room.booking</field> |
|||
<field name="report_type">qweb-pdf</field> |
|||
<field name="report_name">hotel_management_odoo.report_sale_order</field> |
|||
<field name="report_file">hotel_management_odoo.report_sale_order</field> |
|||
<field name="binding_model_id" ref="model_room_booking"/> |
|||
<field name="binding_type">report</field> |
|||
</record> |
|||
<!-- Sale order report template--> |
|||
<template id="report_sale_order"> |
|||
<t t-call="web.html_container"> |
|||
<t t-call="web.external_layout"> |
|||
<div class="page"> |
|||
<div class="oe_structure"/> |
|||
<h2>Sale Order</h2> |
|||
<br/> |
|||
<table class="table"> |
|||
<thead> |
|||
<tr> |
|||
<th>Sl No.</th> |
|||
<th>Guest Name</th> |
|||
<th>Check-In</th> |
|||
<th>Check-Out</th> |
|||
<th>Reference No.</th> |
|||
<th>Amount Total</th> |
|||
</tr> |
|||
</thead> |
|||
<t t-set="i" t-value="0"/> |
|||
<t t-foreach="booking" t-as="line"> |
|||
<t t-set="i" t-value="i+1"/> |
|||
<tr> |
|||
<td> |
|||
<t t-esc="i"/> |
|||
</td> |
|||
<td> |
|||
<t t-esc="line['partner_id']"/> |
|||
</td> |
|||
<td> |
|||
<t t-esc="line['checkin_date']"/> |
|||
</td> |
|||
<td> |
|||
<t t-esc="line['checkin_date']"/> |
|||
</td> |
|||
<td> |
|||
<t t-esc="line['name']"/> |
|||
</td> |
|||
<td> |
|||
<t t-esc="line['amount_total']"/> |
|||
</td> |
|||
</tr> |
|||
</t> |
|||
</table> |
|||
</div> |
|||
</t> |
|||
</t> |
|||
</template> |
|||
</odoo> |
@ -0,0 +1,53 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<!-- Hotel Access Groups--> |
|||
<record id="module_category_hotel_management" model="ir.module.category"> |
|||
<field name="name">Hotel Management</field> |
|||
<field name="description">Hotel Access Groups</field> |
|||
<field name="sequence">20</field> |
|||
</record> |
|||
<!-- Maintenance Team User groups--> |
|||
<record id="maintenance_team_group_user" model="res.groups"> |
|||
<field name="name">Maintenance Team User</field> |
|||
<field name="category_id" |
|||
ref="hotel_management_odoo.module_category_hotel_management"/> |
|||
</record> |
|||
<!-- Maintenance Team Leader group--> |
|||
<record id="maintenance_team_group_leader" model="res.groups"> |
|||
<field name="name">Maintenance Team Leader</field> |
|||
<field name="category_id" |
|||
ref="hotel_management_odoo.module_category_hotel_management"/> |
|||
<field name="implied_ids" |
|||
eval="[(4, ref('hotel_management_odoo.maintenance_team_group_user'))]"/> |
|||
</record> |
|||
<!-- Reception groups--> |
|||
<record id="hotel_group_reception" model="res.groups"> |
|||
<field name="name">Receptionist</field> |
|||
<field name="category_id" |
|||
ref="hotel_management_odoo.module_category_hotel_management"/> |
|||
</record> |
|||
<!-- Cleaning Team User group--> |
|||
<record id="cleaning_team_group_user" model="res.groups"> |
|||
<field name="name">Cleaning Team User</field> |
|||
<field name="category_id" |
|||
ref="hotel_management_odoo.module_category_hotel_management"/> |
|||
</record> |
|||
<!-- Cleaning Team Head group--> |
|||
<record id="cleaning_team_group_head" model="res.groups"> |
|||
<field name="name">Cleaning Team Head</field> |
|||
<field name="category_id" |
|||
ref="hotel_management_odoo.module_category_hotel_management"/> |
|||
<field name="implied_ids" |
|||
eval="[(4, ref('hotel_management_odoo.cleaning_team_group_user'))]"/> |
|||
</record> |
|||
<!--Hotel Admin group--> |
|||
<record id="hotel_group_admin" model="res.groups"> |
|||
<field name="name">Admin</field> |
|||
<field name="category_id" |
|||
ref="hotel_management_odoo.module_category_hotel_management"/> |
|||
<field name="implied_ids" |
|||
eval="[(4, ref('hotel_management_odoo.maintenance_team_group_leader')), |
|||
(4, ref('hotel_management_odoo.cleaning_team_group_head')), |
|||
(4, ref('hotel_group_reception')), ]"/> |
|||
</record> |
|||
</odoo> |
@ -0,0 +1,67 @@ |
|||
<?xml version="1.0" encoding="UTF-8" ?> |
|||
<odoo> |
|||
<!-- MAINTENANCE RECORD RULE--> |
|||
<record id="maintenance_request_rule_leader" |
|||
model="ir.rule"> |
|||
<field name="name">Record Rule for Maintenance team leader</field> |
|||
<field ref="model_maintenance_request" name="model_id"/> |
|||
<field name="groups" |
|||
eval="[(4, ref('hotel_management_odoo.maintenance_team_group_leader'))]"/> |
|||
<field name="domain_force">[('team_head_id', '=', user.id)]</field> |
|||
<field name="perm_read" eval="True"/> |
|||
<field name="perm_write" eval="True"/> |
|||
<field name="perm_create" eval="True"/> |
|||
<field name="perm_unlink" eval="True"/> |
|||
</record> |
|||
<!-- Record Rule for Maintenance User--> |
|||
<record id="maintenance_request_rule_user" |
|||
model="ir.rule"> |
|||
<field name="name">Record Rule for Maintenance User</field> |
|||
<field ref="model_maintenance_request" name="model_id"/> |
|||
<field name="groups" |
|||
eval="[(4, ref('hotel_management_odoo.maintenance_team_group_user'))]"/> |
|||
<field name="domain_force">[('assigned_user_id', '=', user.id)]</field> |
|||
<field name="perm_read" eval="True"/> |
|||
<field name="perm_write" eval="True"/> |
|||
<field name="perm_create" eval="True"/> |
|||
<field name="perm_unlink" eval="True"/> |
|||
</record> |
|||
<!-- Record Rule for hotel Admin--> |
|||
<record id="maintenance_request_rule_admin" |
|||
model="ir.rule"> |
|||
<field name="name">Record Rule for hotel Admin</field> |
|||
<field ref="model_maintenance_request" name="model_id"/> |
|||
<field name="groups" |
|||
eval="[(4, ref('hotel_management_odoo.hotel_group_admin'))]"/> |
|||
<field name="domain_force">[(1,'=',1)]</field> |
|||
<field name="perm_read" eval="True"/> |
|||
<field name="perm_write" eval="True"/> |
|||
<field name="perm_create" eval="True"/> |
|||
<field name="perm_unlink" eval="True"/> |
|||
</record> |
|||
<!-- CLEANING HEAD RECORD RULE--> |
|||
<record id="cleaning_request_rule_head" model="ir.rule"> |
|||
<field name="name">Cleaning Head Record Rule</field> |
|||
<field name="model_id" ref="model_cleaning_request"/> |
|||
<field name="groups" |
|||
eval="[(4, ref('hotel_management_odoo.cleaning_team_group_head'))]"/> |
|||
<field name="domain_force">[('team_id.team_head_id.id', '=', user.id)] |
|||
</field> |
|||
</record> |
|||
<!-- CLEANING USER RECORD RULE--> |
|||
<record id="cleaning_request_rule_user" model="ir.rule"> |
|||
<field name="name">Cleaning User Record Rule</field> |
|||
<field name="model_id" ref="model_cleaning_request"/> |
|||
<field name="groups" |
|||
eval="[(4, ref('hotel_management_odoo.cleaning_team_group_user'))]"/> |
|||
<field name="domain_force">[('assigned_id.id', '=', user.id)]</field> |
|||
</record> |
|||
<!-- CLEANING ADMIN RECORD RULE--> |
|||
<record id="cleaning_request_rule_admin" model="ir.rule"> |
|||
<field name="name">Cleaning Admin Record Rule</field> |
|||
<field name="model_id" ref="model_cleaning_request"/> |
|||
<field name="groups" |
|||
eval="[(4, ref('hotel_management_odoo.hotel_group_admin'))]"/> |
|||
<field name="domain_force">[(1, '=', 1)]</field> |
|||
</record> |
|||
</odoo> |
|
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 628 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 210 KiB |
After Width: | Height: | Size: 209 KiB |
After Width: | Height: | Size: 109 KiB |
After Width: | Height: | Size: 495 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 624 B |
After Width: | Height: | Size: 136 KiB |
After Width: | Height: | Size: 214 KiB |
After Width: | Height: | Size: 36 KiB |
After Width: | Height: | Size: 3.6 KiB |
After Width: | Height: | Size: 310 B |
After Width: | Height: | Size: 929 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 542 B |
After Width: | Height: | Size: 576 B |
After Width: | Height: | Size: 733 B |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 4.0 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.9 MiB |
After Width: | Height: | Size: 2.2 KiB |
After Width: | Height: | Size: 911 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 600 B |
After Width: | Height: | Size: 673 B |
After Width: | Height: | Size: 2.0 KiB |
After Width: | Height: | Size: 462 B |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 926 B |
After Width: | Height: | Size: 9.0 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 7.0 KiB |
After Width: | Height: | Size: 878 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 653 B |
After Width: | Height: | Size: 800 B |
After Width: | Height: | Size: 905 B |
After Width: | Height: | Size: 189 KiB |
After Width: | Height: | Size: 4.3 KiB |
After Width: | Height: | Size: 839 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 5.9 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 3.8 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 427 B |
After Width: | Height: | Size: 627 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 988 B |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 5.0 KiB |
After Width: | Height: | Size: 875 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 767 KiB |
After Width: | Height: | Size: 138 KiB |