diff --git a/hotel/__manifest__.py b/hotel/__manifest__.py
index 98c2551c5..ba6a25e45 100644
--- a/hotel/__manifest__.py
+++ b/hotel/__manifest__.py
@@ -50,6 +50,7 @@
'views/hotel_board_service_views.xml',
'views/hotel_checkin_partner_views.xml',
'views/hotel_room_type_availability_views.xml',
+ 'views/hotel_board_service_room_type_views.xml',
'data/cron_jobs.xml',
'data/records.xml',
'data/email_template_cancel.xml',
diff --git a/hotel/data/hotel_demo.xml b/hotel/data/hotel_demo.xml
index ee34db3c8..042b7d0b9 100644
--- a/hotel/data/hotel_demo.xml
+++ b/hotel/data/hotel_demo.xml
@@ -235,24 +235,90 @@
BreakFast
-
- 0
+
+ fixed
Half Board
-
- 10
+
+ fixed
FullBoard
-
- 10
+
+ fixed
+
+
+
+
+
+
+
+
+
+ fixed
+
+
+
+
+
+ fixed
+
+
+
+
+
+
+ fixed
+
+
+
+
+
+
+
+ fixed
+
+
+
+
+
+ fixed
@@ -280,7 +346,7 @@
'checkout': (DateTime.today() + timedelta(days=2)).strftime('%Y-%m-%d'),
'adults': 2,
'state': 'confirm',
- 'board_service_id': ref('hotel_board_service_1'),
+ 'board_service_room_id': ref('hotel_board_service_room_1'),
})]"/>
@@ -292,7 +358,7 @@
'checkin': (DateTime.today() + timedelta(days=2)).strftime('%Y-%m-%d'),
'checkout': (DateTime.today() + timedelta(days=4)).strftime('%Y-%m-%d'),
'adults': 3,
- 'board_service_id': ref('hotel_board_service_2'),
+ 'board_service_room_id': ref('hotel_board_service_room_3'),
})]"/>
@@ -329,7 +395,6 @@
'checkout': (DateTime.today() + timedelta(days=4)).strftime('%Y-%m-%d'),
'adults': 1,
'state': 'confirm',
- 'board_service_id': ref('hotel_board_service_1'),
})]"/>
diff --git a/hotel/models/__init__.py b/hotel/models/__init__.py
index 29689f309..c68f79c5b 100644
--- a/hotel/models/__init__.py
+++ b/hotel/models/__init__.py
@@ -29,3 +29,5 @@ from . import hotel_room_type_class
from . import hotel_room_closure_reason
from . import hotel_service_line
from . import hotel_board_service
+from . import hotel_board_service_room_type_line
+from . import hotel_board_service_line
diff --git a/hotel/models/hotel_board_service.py b/hotel/models/hotel_board_service.py
index 4fcff0aa4..e9fa26b15 100644
--- a/hotel/models/hotel_board_service.py
+++ b/hotel/models/hotel_board_service.py
@@ -1,6 +1,7 @@
# Copyright 2017 Dario Lodeiros
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-from odoo import models, fields
+from odoo import api, models, fields
+from odoo.addons import decimal_precision as dp
class HotelBoardService(models.Model):
@@ -8,8 +9,23 @@ class HotelBoardService(models.Model):
_description = "Board Services"
name = fields.Char('Board Name', size=64, required=True, index=True)
- service_ids = fields.Many2many(comodel_name='product.product',
- relation='hotel_board_services_reservation',
- column1='board_id',
- column2='service_id')
- sequence = fields.Integer('Sequence')
+ board_service_line_ids = fields.One2many('hotel.board.service.line',
+ 'hotel_board_service_id')
+ price_type = fields.Selection([
+ ('fixed','Fixed'),
+ ('percent','Percent')], string='Type', default='fixed', required=True)
+ hotel_board_service_room_type_ids = fields.One2many(
+ 'hotel.board.service.room.type', 'hotel_board_service_id')
+ amount = fields.Float('Amount',
+ digits=dp.get_precision('Product Price'),
+ compute='_compute_board_amount',
+ store=True)
+
+ @api.depends('board_service_line_ids.amount')
+ def _compute_board_amount(self):
+ for record in self:
+ total = 0
+ for service in record.board_service_line_ids:
+ total += service.amount
+ record.update({'amount': total})
+
diff --git a/hotel/models/hotel_board_service_line.py b/hotel/models/hotel_board_service_line.py
new file mode 100644
index 000000000..8475f57cc
--- /dev/null
+++ b/hotel/models/hotel_board_service_line.py
@@ -0,0 +1,29 @@
+# Copyright 2017 Dario Lodeiros
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+from odoo import api, fields, models, _
+from odoo.addons import decimal_precision as dp
+from odoo.exceptions import UserError
+
+
+class HotelBoardServiceLine(models.Model):
+ _name = 'hotel.board.service.line'
+ _description = 'Services on Board Service included'
+
+ def _get_default_price(self):
+ if self.product_id:
+ return self.product_id.list_price
+
+ hotel_board_service_id = fields.Many2one(
+ 'hotel.board.service', 'Board Service', ondelete='cascade', required=True)
+ product_id = fields.Many2one(
+ 'product.product', 'Product', required=True)
+ amount = fields.Float('Amount',
+ digits=dp.get_precision('Product Price'), default=_get_default_price)
+
+ @api.onchange('product_id')
+ def onchange_product_id(self):
+ if self.product_id:
+ self.update({'amount': self.product_id.list_price})
+
+
+
diff --git a/hotel/models/hotel_board_service_room_type.py b/hotel/models/hotel_board_service_room_type.py
index ec9111d22..ae09426dc 100644
--- a/hotel/models/hotel_board_service_room_type.py
+++ b/hotel/models/hotel_board_service_room_type.py
@@ -12,6 +12,17 @@ class HotelBoardServiceRoomType(models.Model):
_log_access = False
_description = 'Board Service included in Room'
+ @api.multi
+ def name_get(self):
+ result = []
+ for res in self:
+ if res.pricelist_id:
+ name = u'%s (%s)' % (res.hotel_board_service_id.name, res.pricelist_id.name)
+ else:
+ name = u'%s (%s)' % (res.hotel_board_service_id.name, _('Generic'))
+ result.append((res.id, name))
+ return result
+
hotel_board_service_id = fields.Many2one(
'hotel.board.service', 'Board Service', index=True, ondelete='cascade', required=True)
hotel_room_type_id = fields.Many2one(
@@ -21,7 +32,11 @@ class HotelBoardServiceRoomType(models.Model):
price_type = fields.Selection([
('fixed','Fixed'),
('percent','Percent')], string='Type', default='fixed', required=True)
- amount = fields.Float('Amount', digits=dp.get_precision('Product Price'), default=0.0)
+ amount = fields.Float('Amount',
+ digits=dp.get_precision('Product Price'),
+ compute='_compute_board_amount',
+ store=True)
+ board_service_line_ids = fields.One2many('hotel.board.service.room.type.line', 'hotel_board_service_room_type_id')
@api.model_cr
def init(self):
@@ -29,6 +44,52 @@ class HotelBoardServiceRoomType(models.Model):
if not self._cr.fetchone():
self._cr.execute('CREATE INDEX hotel_board_service_id_hotel_room_type_id_pricelist_id ON hotel_board_service_room_type_rel (hotel_board_service_id, hotel_room_type_id, pricelist_id)')
+ @api.model
+ def create(self, vals):
+ if 'hotel_board_service_id' in vals:
+ vals.update(
+ self.prepare_board_service_room_lines(vals['hotel_board_service_id'])
+ )
+ return super(HotelBoardServiceRoomType, self).create(vals)
+
+ @api.multi
+ def write(self, vals):
+ if 'hotel_board_service_id' in vals:
+ vals.update(
+ self.prepare_board_service_room_lines(vals['hotel_board_service_id'])
+ )
+ return super(HotelBoardServiceRoomType, self).write(vals)
+
+ @api.multi
+ def open_board_lines_form(self):
+ action = self.env.ref('hotel.action_hotel_board_service_room_type_view').read()[0]
+ action['views'] = [(self.env.ref('hotel.hotel_board_service_room_type_form').id, 'form')]
+ action['res_id'] = self.id
+ action['target'] = 'new'
+ return action
+
+ @api.depends('board_service_line_ids.amount')
+ def _compute_board_amount(self):
+ for record in self:
+ total = 0
+ for service in record.board_service_line_ids:
+ total += service.amount
+ record.update({'amount': total})
+
+ @api.model
+ def prepare_board_service_room_lines(self, board_service_id):
+ """
+ Prepare line to price products config
+ """
+ cmds=[(5,0,0)]
+ board_service = self.env['hotel.board.service'].browse(board_service_id)
+ for line in board_service.board_service_line_ids:
+ cmds.append((0, False, {
+ 'product_id': line.product_id.id,
+ 'amount': line.amount
+ }))
+ return {'board_service_line_ids': cmds}
+
@api.constrains('pricelist_id')
def constrains_pricelist_id(self):
for record in self:
diff --git a/hotel/models/hotel_board_service_room_type_line.py b/hotel/models/hotel_board_service_room_type_line.py
new file mode 100644
index 000000000..8896c0644
--- /dev/null
+++ b/hotel/models/hotel_board_service_room_type_line.py
@@ -0,0 +1,21 @@
+# Copyright 2017 Dario Lodeiros
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+from odoo import api, fields, models, _
+from odoo.addons import decimal_precision as dp
+from odoo.exceptions import UserError
+
+
+class HotelBoardServiceRoomTypeLine(models.Model):
+ _name = 'hotel.board.service.room.type.line'
+ _description = 'Services on Board Service included in Room'
+
+ #TODO def default_amount "amount of service"
+
+ hotel_board_service_room_type_id = fields.Many2one(
+ 'hotel.board.service.room.type', 'Board Service Room', ondelete='cascade', required=True)
+ product_id = fields.Many2one(
+ 'product.product', 'Product', required=True, readonly=True)
+ amount = fields.Float('Amount', digits=dp.get_precision('Product Price'), default=0.0)
+
+
+
diff --git a/hotel/models/hotel_reservation.py b/hotel/models/hotel_reservation.py
index be1bcf201..d00a04909 100644
--- a/hotel/models/hotel_reservation.py
+++ b/hotel/models/hotel_reservation.py
@@ -4,6 +4,7 @@
import logging
import time
from datetime import timedelta
+from lxml import etree
from odoo.exceptions import UserError, ValidationError
from odoo.tools import (
misc,
@@ -133,7 +134,8 @@ class HotelReservation(models.Model):
track_visibility='onchange')
reservation_type = fields.Selection(related='folio_id.reservation_type',
default=lambda *a: 'normal')
- board_service_id = fields.Many2one('hotel.board.service', string='Board Service')
+ board_service_room_id = fields.Many2one('hotel.board.service.room.type',
+ string='Board Service')
cancelled_reason = fields.Selection([
('late', 'Late'),
('intime', 'In time'),
@@ -290,12 +292,12 @@ class HotelReservation(models.Model):
vals.update({
'last_updated_res': fields.Datetime.now(),
})
- if 'board_service_id' in vals:
+ if 'board_service_room_id' in vals:
board_services = []
- board = self.env['hotel.board.service'].browse(vals['board_service_id'])
- for product in board.service_ids:
+ board = self.env['hotel.board.service.room.type'].browse(vals['board_service_room_id'])
+ for line in board.board_service_line_ids:
board_services.append((0, False, {
- 'product_id': product.id,
+ 'product_id': line.product_id.id,
'is_board_service': True,
'folio_id': vals.get('folio_id'),
}))
@@ -330,10 +332,10 @@ class HotelReservation(models.Model):
if self.compute_board_services(vals):
record.service_ids.filtered(lambda r: r.is_board_service == True).unlink()
board_services = []
- board = self.env['hotel.board.service'].browse(vals['board_service_id'])
- for product in board.service_ids:
+ board = self.env['hotel.board.service.room.type'].browse(vals['board_service_room_id'])
+ for line in board.board_service_line_ids:
board_services.append((0, False, {
- 'product_id': product.id,
+ 'product_id': line.product_id.id,
'is_board_service': True,
'folio_id': record.folio_id.id or vals.get('folio_id')
}))
@@ -369,10 +371,10 @@ class HotelReservation(models.Model):
@api.multi
def compute_board_services(self, vals):
"""
- We must compute service_ids when we hace a board_service_id without
+ We must compute service_ids when we have a board_service_id without
service_ids associated to reservation
"""
- if 'board_service_id' in vals:
+ if 'board_service_room_id' in vals:
if 'service_ids' in vals:
for service in vals['service_ids']:
if 'is_board_service' in service[2] and \
@@ -402,7 +404,7 @@ class HotelReservation(models.Model):
""" Deduce missing required fields from the onchange """
res = {}
onchange_fields = ['room_id', 'reservation_type',
- 'currency_id', 'name', 'board_service_id']
+ 'currency_id', 'name', 'board_service_room_id']
if values.get('room_type_id'):
line = self.new(values)
if any(f not in values for f in onchange_fields):
@@ -610,11 +612,12 @@ class HotelReservation(models.Model):
]
return {'domain': {'room_id': domain_rooms}}
- @api.onchange('board_service_id')
+ @api.onchange('board_service_room_id')
def onchange_board_service(self):
- if self.board_service_id:
+ if self.board_service_room_id:
board_services = []
- for product in self.board_service_id.service_ids:
+ for line in self.board_service_room_id.board_service_line_ids:
+ product = line.product_id
if product.per_day:
vals = {
'product_id': product.id,
diff --git a/hotel/models/hotel_service.py b/hotel/models/hotel_service.py
index 459dcded3..e0f38c16c 100644
--- a/hotel/models/hotel_service.py
+++ b/hotel/models/hotel_service.py
@@ -153,7 +153,7 @@ class HotelService(models.Model):
def _compute_tax_ids(self):
for record in self:
# If company_id is set, always filter taxes by the company
- folio = self.folio_id or self.env.context.get('default_folio_id')
+ folio = record.folio_id or self.env.context.get('default_folio_id')
record.tax_id = record.product_id.taxes_id.filtered(lambda r: not record.company_id or r.company_id == folio.company_id)
@api.multi
@@ -184,12 +184,12 @@ class HotelService(models.Model):
if record.per_day and record.ser_room_line:
product = record.product_id
reservation = record.ser_room_line
- vals.update(self.prepare_service_lines(
+ vals.update(record.prepare_service_lines(
dfrom=reservation.checkin,
days=reservation.nights,
per_person=product.per_person,
persons=reservation.adults,
- old_line_days=self.service_line_ids))
+ old_line_days=record.service_line_ids))
if record.product_id.daily_limit > 0:
for day in record.service_line_ids:
day.no_free_resources()
@@ -202,21 +202,33 @@ class HotelService(models.Model):
@api.multi
def _compute_price_unit(self):
- """
- Compute tax and price unit
- """
+ self.ensure_one()
folio = self.folio_id or self.env.context.get('default_folio_id')
- product = self.product_id.with_context(
- lang=folio.partner_id.lang,
- partner=folio.partner_id.id,
- quantity=self.product_qty,
- date=folio.date_order,
- pricelist=folio.pricelist_id.id,
- uom=self.product_id.uom_id.id,
- fiscal_position=False
- )
- return self.env['account.tax']._fix_tax_included_price_company(self._get_display_price(product), product.taxes_id, self.tax_ids, folio.company_id)
-
+ reservation = self.ser_room_line or self.env.context.get('ser_room_line')
+ if folio or reservation:
+ partner = folio.partner_id if folio else reservation.partner_id
+ pricelist = folio.pricelist_id if folio else reservation.pricelist_id
+ if reservation and self.is_board_service:
+ board_room_type = reservation.board_service_room_id
+ if board_room_type.price_type == 'fixed':
+ return self.env['hotel.board.service.room.type.line'].search([
+ ('hotel_board_service_room_type_id', '=', board_room_type.id),
+ ('product_id','=',self.product_id.id)]).amount
+ else:
+ return (reservation.price_total * self.env['hotel.board.service.room.type.line'].search([
+ ('hotel_board_service_room_type_id', '=', board_room_type.id),
+ ('product_id','=',self.product_id.id)]).amount) / 100
+ else:
+ product = self.product_id.with_context(
+ lang=partner.lang,
+ partner=partner.id,
+ quantity=self.product_qty,
+ date=folio.date_order or fields.Date.today(),
+ pricelist=pricelist.id,
+ uom=self.product_id.uom_id.id,
+ fiscal_position=False
+ )
+ return self.env['account.tax']._fix_tax_included_price_company(self._get_display_price(product), product.taxes_id, self.tax_ids, folio.company_id)
@api.model
def prepare_service_lines(self, **kwargs):
@@ -251,9 +263,12 @@ class HotelService(models.Model):
"""
for record in self:
folio = record.folio_id or self.env.context.get('default_folio_id')
+ reservation = record.ser_room_line or self.env.context.get('ser_room_line')
+ currency = folio.currency_id if folio else reservation.currency_id
product = record.product_id
price = record.price_unit * (1 - (record.discount or 0.0) * 0.01)
- taxes = record.tax_ids.compute_all(price, folio.currency_id, record.product_qty, product=product)
+ taxes = record.tax_ids.compute_all(price, currency, record.product_qty, product=product)
+
record.update({
'price_tax': sum(t.get('amount', 0.0) for t in taxes.get('taxes', [])),
'price_total': taxes['total_included'],
diff --git a/hotel/security/ir.model.access.csv b/hotel/security/ir.model.access.csv
index 7484025a9..3d41900d3 100644
--- a/hotel/security/ir.model.access.csv
+++ b/hotel/security/ir.model.access.csv
@@ -17,3 +17,5 @@ access_hotel_reservation,access_hotel_reservation,model_hotel_reservation,base.g
access_hotel_folio,access_hotel_folio,model_hotel_folio,base.group_user,1,0,0,0
access_hotel_room_type,access_hotel_room_type,model_hotel_room_type,base.group_user,1,0,0,0
access_hotel_board_service_room_type,access_hotel_board_service_room_type,model_hotel_board_service_room_type,base.group_user,1,0,0,0
+access_hotel_board_service_room_type_line,access_hotel_board_service_room_type_line,model_hotel_board_service_room_type_line,base.group_user,1,0,0,0
+access_hotel_board_service_line,access_hotel_board_service_line,model_hotel_board_service_line,base.group_user,1,0,0,0
diff --git a/hotel/views/hotel_board_service_room_type_views.xml b/hotel/views/hotel_board_service_room_type_views.xml
new file mode 100644
index 000000000..b260b933e
--- /dev/null
+++ b/hotel/views/hotel_board_service_room_type_views.xml
@@ -0,0 +1,30 @@
+
+
+
+
+ hotel.board.service.room.type.form
+ hotel.board.service.room.type
+
+
+
+
+
+
+ Hotel Board Service
+ hotel.board.service.room.type
+ form
+ form
+
+
+
diff --git a/hotel/views/hotel_board_service_views.xml b/hotel/views/hotel_board_service_views.xml
index 0dbc15fba..35faeee72 100644
--- a/hotel/views/hotel_board_service_views.xml
+++ b/hotel/views/hotel_board_service_views.xml
@@ -3,20 +3,20 @@
-
+
hotel.board.service.form
hotel.board.service
-
@@ -28,7 +28,7 @@
-
+
diff --git a/hotel/views/hotel_folio_views.xml b/hotel/views/hotel_folio_views.xml
index 91de623b4..71d5cdc71 100644
--- a/hotel/views/hotel_folio_views.xml
+++ b/hotel/views/hotel_folio_views.xml
@@ -298,7 +298,9 @@
-
+
diff --git a/hotel/views/hotel_reservation_views.xml b/hotel/views/hotel_reservation_views.xml
index 4791dcbe9..e8990fd1e 100644
--- a/hotel/views/hotel_reservation_views.xml
+++ b/hotel/views/hotel_reservation_views.xml
@@ -191,7 +191,10 @@
-
+
+
@@ -237,11 +240,16 @@
-
+
-
+
+
diff --git a/hotel/views/hotel_room_type_views.xml b/hotel/views/hotel_room_type_views.xml
index 7816a72a8..61294b3b5 100644
--- a/hotel/views/hotel_room_type_views.xml
+++ b/hotel/views/hotel_room_type_views.xml
@@ -46,6 +46,9 @@
+