[ADD] Pricelist cancelled rules

This commit is contained in:
Dario Lodeiros
2019-03-23 15:51:24 +01:00
parent 8af44c43cf
commit e73be563d2
11 changed files with 230 additions and 29 deletions

View File

@@ -31,3 +31,4 @@ from . import hotel_board_service
from . import hotel_board_service_room_type_line
from . import hotel_board_service_line
from . import inherited_account_invoice_line
from . import hotel_cancelation_rule

View File

@@ -0,0 +1,30 @@
# Copyright 2017 Alexandre Díaz
# Copyright 2017 Dario Lodeiros
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import models, fields
class HotelCancelationRule(models.Model):
_name = 'hotel.cancelation.rule'
_description = 'Cancelation Rules'
name = fields.Char('Amenity Name', translate=True, required=True)
active = fields.Boolean('Active', default=True)
pricelist_ids = fields.One2many('product.pricelist',
'cancelation_rule_id',
'Pricelist that use this rule')
days_intime = fields.Integer(
'Days Late',
help='Maximum number of days for free cancellation before Checkin')
penalty_late = fields.Integer('% Penalty Late', defaul="100")
apply_on_late = fields.Selection([
('first', 'First Day'),
('all', 'All Days'),
('days', 'Specify days')], 'Late apply on', default='first')
days_late = fields.Integer('Late first days', default="2")
penalty_noshow = fields.Integer('% Penalty No Show', default="100")
apply_on_noshow = fields.Selection([
('first', 'First Day'),
('all', 'All Days'),
('days', 'Specify days')], 'No Show apply on', default='all')
days_noshow = fields.Integer('NoShow first days', default="2")

View File

@@ -170,12 +170,15 @@ class HotelReservation(models.Model):
track_visibility='onchange',
help='Number of children there in guest list.')
to_assign = fields.Boolean('To Assign', track_visibility='onchange')
state = fields.Selection([('draft', 'Pre-reservation'), ('confirm', 'Pending Entry'),
('booking', 'On Board'), ('done', 'Out'),
('cancelled', 'Cancelled')],
'State', readonly=True,
default=lambda *a: 'draft',
track_visibility='onchange')
state = fields.Selection([
('draft', 'Pre-reservation'),
('confirm', 'Pending Entry'),
('booking', 'On Board'),
('done', 'Out'),
('cancelled', 'Cancelled')
], string='State', readonly=True,
default=lambda *a: 'draft', copy=False,
track_visibility='onchange')
reservation_type = fields.Selection(related='folio_id.reservation_type',
default=lambda *a: 'normal')
invoice_count = fields.Integer(related='folio_id.invoice_count')
@@ -635,6 +638,11 @@ class HotelReservation(models.Model):
write_vals.update({'room_type_id': self.room_id.room_type_id.id})
self.update(write_vals)
@api.onchange('cancelled_reason')
def onchange_cancelled_reason(self):
for record in self:
record._compute_cancelled_discount()
@api.onchange('partner_id')
def onchange_partner_id(self):
addr = self.partner_id.address_get(['invoice'])
@@ -815,6 +823,9 @@ class HotelReservation(models.Model):
else:
vals.update({'state': 'confirm'})
record.write(vals)
record.reservation_line_ids.update({
'cancel_discount': 0
})
if record.splitted:
master_reservation = record.parent_reservation or record
@@ -846,7 +857,9 @@ class HotelReservation(models.Model):
for record in self:
record.write({
'state': 'cancelled',
'cancelled_reason': record.compute_cancelation_reason()
})
record._compute_cancelled_discount()
if record.splitted:
master_reservation = record.parent_reservation or record
splitted_reservs = self.env['hotel.reservation'].search([
@@ -861,6 +874,25 @@ class HotelReservation(models.Model):
splitted_reservs.action_cancel()
record.folio_id.compute_amount()
@api.multi
def compute_cancelation_reason(self):
self.ensure_one()
pricelist = self.pricelist_id
if pricelist and pricelist.cancelation_rule_id:
tz_hotel = self.env['ir.default'].sudo().get(
'res.config.settings', 'tz_hotel')
today = fields.Date.context_today(self.with_context(
tz=tz_hotel))
days_diff = (fields.Date.from_string(self.real_checkin) -
fields.Date.from_string(today)).days
if days_diff < 0:
return 'noshow'
elif days_diff < pricelist.cancelation_rule_id.days_intime:
return 'late'
else:
return 'intime'
return False
@api.multi
def draft(self):
for record in self:
@@ -904,11 +936,17 @@ class HotelReservation(models.Model):
return True
return False
@api.depends('reservation_line_ids.discount')
@api.depends('reservation_line_ids.discount',
'reservation_line_ids.cancel_discount')
def _compute_discount(self):
for record in self:
record.discount = sum(line.price * ((line.discount or 0.0) * 0.01) \
for line in record.reservation_line_ids)
discount = 0
for line in record.reservation_line_ids:
first_discount = line.price * ((line.discount or 0.0) * 0.01)
price = line.price - first_discount
cancel_discount = price * ((line.cancel_discount or 0.0) * 0.01)
discount += first_discount + cancel_discount
record.discount = discount
@api.depends('reservation_line_ids.price', 'discount', 'tax_ids')
def _compute_amount_reservation(self):
@@ -927,6 +965,51 @@ class HotelReservation(models.Model):
'price_subtotal': taxes['total_excluded'],
})
@api.multi
def _compute_cancelled_discount(self):
self.ensure_one()
pricelist = self.pricelist_id
if self.state == 'cancelled':
if self.cancelled_reason and pricelist and pricelist.cancelation_rule_id:
date_start_dt = fields.Date.from_string(self.real_checkin or self.checkin)
date_end_dt = fields.Date.from_string(self.real_checkout or self.checkout)
days = abs((date_end_dt - date_start_dt).days)
rule = pricelist.cancelation_rule_id
if self.cancelled_reason == 'late':
discount = 100 - rule.penalty_late
if rule.apply_on_late == 'first':
days = 1
elif rule.apply_on_late == 'days':
days = rule.days_late
elif self.cancelled_reason == 'noshow':
discount = 100 - rule.penalty_noshow
if rule.apply_on_noshow == 'first':
days = 1
elif rule.apply_on_noshow == 'days':
days = rule.days_late - 1
elif self.cancelled_reason == 'intime':
discount = 100
checkin = self.real_checkin or self.checkin
dates = []
for i in range(0, days):
dates.append((fields.Date.from_string(checkin) + timedelta(days=i)).strftime(
DEFAULT_SERVER_DATE_FORMAT))
self.reservation_line_ids.filtered(lambda r: r.date in dates).update({
'cancel_discount': discount
})
self.reservation_line_ids.filtered(lambda r: r.date not in dates).update({
'cancel_discount': 100
})
else:
self.reservation_line_ids.update({
'cancel_discount': 0
})
else:
self.reservation_line_ids.update({
'cancel_discount': 0
})
@api.model
def prepare_reservation_lines(self, dfrom, days, pricelist_id, vals=False, update_old_prices=False):
total_price = 0.0
@@ -1164,7 +1247,6 @@ class HotelReservation(models.Model):
'price_total': tprice[1],
'parent_reservation': parent_res.id,
'room_type_id': parent_res.room_type_id.id,
'discount': parent_res.discount,
'state': parent_res.state,
'reservation_line_ids': reservation_lines[1],
'preconfirm': False,

View File

@@ -22,9 +22,13 @@ class HotelReservationLine(models.Model):
ondelete='cascade', required=True,
copy=False)
date = fields.Date('Date')
state = fields.Selection(related='reservation_id.state')
price = fields.Float(
string='Price',
digits=dp.get_precision('Product Price'))
cancel_discount = fields.Float(
string='Cancel Discount (%)',
digits=dp.get_precision('Discount'), default=0.0)
discount = fields.Float(
string='Discount (%)',
digits=dp.get_precision('Discount'), default=0.0)

View File

@@ -11,6 +11,9 @@ class ProductPricelist(models.Model):
pricelist_type = fields.Selection([
('daily', 'Daily Plan'),
], string='Pricelist Type', default='daily')
cancelation_rule_id = fields.Many2one(
'hotel.cancelation.rule',
string="Cancelation Policy")
@api.multi
@api.depends('name')