mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
[ADD] Shared Rooms
This commit is contained in:
@@ -8,6 +8,7 @@ from . import hotel_floor
|
||||
from . import hotel_folio
|
||||
from . import hotel_reservation
|
||||
from . import hotel_room
|
||||
from . import hotel_shared_room
|
||||
from . import hotel_amenity
|
||||
from . import hotel_amenity_type
|
||||
from . import hotel_room_type
|
||||
|
||||
@@ -99,7 +99,8 @@ class HotelFolio(models.Model):
|
||||
default=lambda self: _('New'))
|
||||
client_order_ref = fields.Char(string='Customer Reference', copy=False)
|
||||
partner_id = fields.Many2one('res.partner',
|
||||
track_visibility='onchange')
|
||||
track_visibility='onchange',
|
||||
ondelete='restrict',)
|
||||
|
||||
room_lines = fields.One2many('hotel.reservation', 'folio_id',
|
||||
readonly=False,
|
||||
@@ -107,19 +108,20 @@ class HotelFolio(models.Model):
|
||||
help="Hotel room reservation detail.",)
|
||||
|
||||
service_ids = fields.One2many('hotel.service', 'folio_id',
|
||||
readonly=False,
|
||||
states={'done': [('readonly', True)]},
|
||||
help="Hotel services detail provide to "
|
||||
"customer and it will include in "
|
||||
"main Invoice.")
|
||||
readonly=False,
|
||||
states={'done': [('readonly', True)]},
|
||||
help="Hotel services detail provide to "
|
||||
"customer and it will include in "
|
||||
"main Invoice.")
|
||||
company_id = fields.Many2one('res.company', 'Company', default=lambda self: self.env['res.company']._company_default_get('hotel.folio'))
|
||||
analytic_account_id = fields.Many2one('account.analytic.account', 'Analytic Account', readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, help="The analytic account related to a folio.", copy=False)
|
||||
currency_id = fields.Many2one('res.currency', related='pricelist_id.currency_id',
|
||||
string='Currency', readonly=True, required=True)
|
||||
string='Currency', readonly=True, required=True, ondelete='restrict',)
|
||||
|
||||
pricelist_id = fields.Many2one('product.pricelist',
|
||||
string='Pricelist',
|
||||
required=True,
|
||||
ondelete='restrict',
|
||||
states={'draft': [('readonly', False)],
|
||||
'sent': [('readonly', False)]},
|
||||
help="Pricelist for current folio.")
|
||||
@@ -136,10 +138,11 @@ class HotelFolio(models.Model):
|
||||
('agency', 'Agencia'),
|
||||
('operator', 'Tour operador'),
|
||||
('virtualdoor', 'Virtual Door'),], 'Sales Channel', default='door')
|
||||
user_id = fields.Many2one('res.users', string='Salesperson', index=True,
|
||||
user_id = fields.Many2one('res.users', string='Salesperson', index=True, ondelete='restrict',
|
||||
track_visibility='onchange', default=lambda self: self.env.user)
|
||||
tour_operator_id = fields.Many2one('res.partner',
|
||||
'Tour Operator',
|
||||
ondelete='restrict',
|
||||
domain=[('is_tour_operator', '=', True)])
|
||||
date_order = fields.Datetime(
|
||||
string='Order Date',
|
||||
@@ -245,12 +248,14 @@ class HotelFolio(models.Model):
|
||||
help='Margin in days to create a notice if a payment \
|
||||
advance has not been recorded')
|
||||
segmentation_ids = fields.Many2many('res.partner.category',
|
||||
string='Segmentation')
|
||||
string='Segmentation',
|
||||
ondelete='restrict')
|
||||
client_order_ref = fields.Char(string='Customer Reference', copy=False)
|
||||
note = fields.Text('Terms and conditions')
|
||||
sequence = fields.Integer(string='Sequence', default=10)
|
||||
team_id = fields.Many2one('crm.team',
|
||||
'Sales Channel',
|
||||
ondelete='restrict',
|
||||
change_default=True,
|
||||
default=_get_default_team,
|
||||
oldname='section_id')
|
||||
|
||||
@@ -171,7 +171,7 @@ class HotelReservation(models.Model):
|
||||
name = fields.Text('Reservation Description', required=True)
|
||||
sequence = fields.Integer(string='Sequence', default=10)
|
||||
|
||||
room_id = fields.Many2one('hotel.room', string='Room')
|
||||
room_id = fields.Many2one('hotel.room', string='Room', ondelete='restrict')
|
||||
|
||||
reservation_no = fields.Char('Reservation No', size=64, readonly=True)
|
||||
adults = fields.Integer('Adults', size=64, readonly=False,
|
||||
@@ -316,8 +316,9 @@ class HotelReservation(models.Model):
|
||||
], string='Invoice Status', compute='_compute_invoice_status',
|
||||
store=True, readonly=True, default='no')
|
||||
tax_ids = fields.Many2many('account.tax',
|
||||
string='Taxes',
|
||||
domain=['|', ('active', '=', False), ('active', '=', True)])
|
||||
string='Taxes',
|
||||
ondelete='restrict',
|
||||
domain=['|', ('active', '=', False), ('active', '=', True)])
|
||||
qty_to_invoice = fields.Float(
|
||||
compute='_get_to_invoice_qty', string='To Invoice', store=True, readonly=True,
|
||||
digits=dp.get_precision('Product Unit of Measure'))
|
||||
|
||||
@@ -17,16 +17,16 @@ class HotelRoom(models.Model):
|
||||
active = fields.Boolean('Active', default=True)
|
||||
sequence = fields.Integer('Sequence', default=0)
|
||||
room_type_id = fields.Many2one('hotel.room.type', 'Hotel Room Type',
|
||||
required=True,
|
||||
ondelete='restrict')
|
||||
required=True,
|
||||
ondelete='restrict')
|
||||
floor_id = fields.Many2one('hotel.floor', 'Ubication',
|
||||
help='At which floor the room is located.')
|
||||
max_adult = fields.Integer('Max Adult')
|
||||
max_child = fields.Integer('Max Child')
|
||||
capacity = fields.Integer('Capacity')
|
||||
# FIXME not used
|
||||
to_be_cleaned = fields.Boolean('To be Cleaned', default=False)
|
||||
shared_room = fields.Boolean('Shared Room', default=False)
|
||||
shared_room_id = fields.Many2one('hotel.shared.room', 'Shared Room',
|
||||
default=False)
|
||||
description_sale = fields.Text(
|
||||
'Sale Description', translate=True,
|
||||
help="A description of the Product that you want to communicate to "
|
||||
@@ -36,11 +36,36 @@ class HotelRoom(models.Model):
|
||||
default='0',
|
||||
required=True)
|
||||
|
||||
@api.constrains('room_type_id')
|
||||
def _constrain_shared_room_type(self):
|
||||
for record in self:
|
||||
if record.shared_room_id:
|
||||
if not record.room_type_id.shared_room:
|
||||
raise ValidationError(_('We cant save normal rooms \
|
||||
in a shared room type'))
|
||||
else:
|
||||
if record.room_type_id.shared_room:
|
||||
raise ValidationError(_('We cant save shared rooms \
|
||||
in a normal room type'))
|
||||
|
||||
@api.constrains('shared_room_id')
|
||||
def _constrain_shared_room(self):
|
||||
for record in self:
|
||||
if record.shared_room_id:
|
||||
if not record.capacity > 1:
|
||||
raise ValidationError(_('We cant save normal rooms \
|
||||
in a shared room type'))
|
||||
|
||||
@api.constrains('capacity')
|
||||
def _check_capacity(self):
|
||||
if self.capacity < 1:
|
||||
raise ValidationError(_("Room capacity can't be less than one"))
|
||||
for record in self:
|
||||
if record.shared_room_id and record.capacity != 1:
|
||||
raise ValidationError(_("A Bed only can has capacity one"))
|
||||
if record.capacity < 1:
|
||||
raise ValidationError(_("Room capacity can't be less than one"))
|
||||
|
||||
@api.multi
|
||||
def get_capacity(self, extra_bed=0):
|
||||
return self.capacity + extra_bed
|
||||
if not self.shared_room_id:
|
||||
return self.capacity + extra_bed
|
||||
return self.capacity
|
||||
|
||||
@@ -34,6 +34,8 @@ class HotelRoomType(models.Model):
|
||||
active = fields.Boolean('Active', default=True,
|
||||
help="The active field allows you to hide the \
|
||||
category without removing it.")
|
||||
shared_room = fields.Boolean('Shared Room', default=False,
|
||||
help="This room type is reservation by beds")
|
||||
# Used for ordering
|
||||
sequence = fields.Integer('Sequence', default=0)
|
||||
|
||||
@@ -47,7 +49,7 @@ class HotelRoomType(models.Model):
|
||||
_sql_constraints = [('code_unique', 'unique(code_type)',
|
||||
'Room Type Code must be unique!')]
|
||||
|
||||
@api.depends('room_ids')
|
||||
@api.depends('room_ids', 'room_ids.active')
|
||||
def _compute_total_rooms(self):
|
||||
for record in self:
|
||||
record.total_rooms_count = len(record.room_ids)
|
||||
@@ -107,6 +109,18 @@ class HotelRoomType(models.Model):
|
||||
})
|
||||
return super().create(vals)
|
||||
|
||||
@api.constrains('shared_room', 'room_ids')
|
||||
def _constrain_shared_room(self):
|
||||
for record in self:
|
||||
if record.shared_room:
|
||||
if any(not room.shared_room_id for room in record.room_ids):
|
||||
raise ValidationError(_('We cant save normal rooms \
|
||||
in a shared room type'))
|
||||
else:
|
||||
if any(room.shared_room_id for room in record.room_ids):
|
||||
raise ValidationError(_('We cant save shared rooms \
|
||||
in a normal room type'))
|
||||
|
||||
@api.multi
|
||||
def unlink(self):
|
||||
for record in self:
|
||||
|
||||
@@ -115,7 +115,8 @@ class HotelService(models.Model):
|
||||
|
||||
name = fields.Char('Service description', required=True)
|
||||
sequence = fields.Integer(string='Sequence', default=10)
|
||||
product_id = fields.Many2one('product.product', 'Service', required=True)
|
||||
product_id = fields.Many2one('product.product', 'Service',
|
||||
ondelete='restrict', required=True)
|
||||
folio_id = fields.Many2one('hotel.folio', 'Folio',
|
||||
ondelete='cascade',
|
||||
default=_default_folio_id)
|
||||
@@ -132,10 +133,11 @@ class HotelService(models.Model):
|
||||
product_image = fields.Binary('Product Image', related="product_id.image", store=False, related_sudo=True)
|
||||
company_id = fields.Many2one(related='folio_id.company_id', string='Company', store=True, readonly=True)
|
||||
invoice_status = fields.Selection([
|
||||
('invoiced', 'Fully Invoiced'),
|
||||
('to invoice', 'To Invoice'),
|
||||
('no', 'Nothing to Invoice')
|
||||
], string='Invoice Status', compute='_compute_invoice_status', store=True, readonly=True, default='no')
|
||||
('invoiced', 'Fully Invoiced'),
|
||||
('to invoice', 'To Invoice'),
|
||||
('no', 'Nothing to Invoice')
|
||||
], string='Invoice Status', compute='_compute_invoice_status',
|
||||
store=True, readonly=True, default='no')
|
||||
channel_type = fields.Selection([
|
||||
('door', 'Door'),
|
||||
('mail', 'Mail'),
|
||||
|
||||
101
hotel/models/hotel_shared_room.py
Normal file
101
hotel/models/hotel_shared_room.py
Normal file
@@ -0,0 +1,101 @@
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# Copyright 2018 Pablo Quesada
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class HotelSharedRoom(models.Model):
|
||||
_name = 'hotel.shared.room'
|
||||
_description = 'Hotel Shared Room'
|
||||
_order = "room_type_id, name"
|
||||
|
||||
name = fields.Char('Room Name', required=True)
|
||||
active = fields.Boolean('Active', default=True)
|
||||
room_type_id = fields.Many2one(
|
||||
'hotel.room.type', 'Hotel Room Type',
|
||||
required=True, ondelete='restrict',
|
||||
domain=[('shared_room', '=', True)]
|
||||
)
|
||||
floor_id = fields.Many2one('hotel.floor', 'Ubication',
|
||||
help='At which floor the room is located.',
|
||||
ondelete='restrict',)
|
||||
sequence = fields.Integer('Sequence', required=True)
|
||||
beds = fields.Integer('Beds')
|
||||
bed_ids = fields.One2many('hotel.room',
|
||||
'shared_room_id',
|
||||
readonly=True,
|
||||
ondelete='restrict',)
|
||||
description_sale = fields.Text(
|
||||
'Sale Description', translate=True,
|
||||
help="A description of the Product that you want to communicate to "
|
||||
" your customers. This description will be copied to every Sales "
|
||||
" Order, Delivery Order and Customer Invoice/Credit Note")
|
||||
|
||||
@api.constrains('beds')
|
||||
def _constrain_beds(self):
|
||||
self.ensure_one()
|
||||
if self.beds < 1:
|
||||
raise ValidationError(_("Room beds can't be less than one"))
|
||||
if len(self.bed_ids) > self.beds:
|
||||
raise ValidationError(_(
|
||||
"If you want to eliminate beds in the \
|
||||
room you must deactivate the beds from your form"))
|
||||
beds = []
|
||||
inactive_beds = self.env['hotel.room'].search([
|
||||
('active', '=', False),
|
||||
('shared_room_id', '=', self.id)
|
||||
])
|
||||
for i in range(len(self.bed_ids), self.beds):
|
||||
if inactive_beds:
|
||||
bed = inactive_beds[0]
|
||||
bed.update({'active': True})
|
||||
inactive_beds -= bed
|
||||
continue
|
||||
name = u'%s (%s)' % (self.name, i)
|
||||
bed_vals = {
|
||||
'name': name,
|
||||
'max_adult': 1,
|
||||
'max_child': 0,
|
||||
'capacity': 1,
|
||||
'room_type_id': self.room_type_id.id,
|
||||
'sequence': self.sequence,
|
||||
'floor_id': self.floor_id.id if self.floor_id else False,
|
||||
'shared_room_id': self.id,
|
||||
}
|
||||
beds.append((0, False, bed_vals))
|
||||
if beds:
|
||||
self.update({
|
||||
'bed_ids': beds
|
||||
})
|
||||
|
||||
@api.constrains('active')
|
||||
def _constrain_active(self):
|
||||
self.bed_ids.write({
|
||||
'active': self.active,
|
||||
})
|
||||
|
||||
@api.constrains('room_type_id')
|
||||
def _constrain_room_type_id(self):
|
||||
self.bed_ids.write({
|
||||
'room_type_id': self.room_type_id.id,
|
||||
})
|
||||
|
||||
@api.constrains('floor_id')
|
||||
def _constrain_floor_id(self):
|
||||
self.bed_ids.write({
|
||||
'floor_id': self.floor_id.id,
|
||||
})
|
||||
|
||||
@api.constrains('sequence')
|
||||
def _constrain_sequence(self):
|
||||
self.bed_ids.write({
|
||||
'sequence': self.sequence,
|
||||
})
|
||||
|
||||
@api.constrains('descrition_sale')
|
||||
def _constrain_descrition_sale(self):
|
||||
self.bed_ids.write({
|
||||
'description_sale': self.descrition_sale,
|
||||
})
|
||||
Reference in New Issue
Block a user