[IMP] Split Reservations

This commit is contained in:
QS5ELkMu
2018-12-15 01:30:52 +01:00
parent 78e9e62cb1
commit 62f92758f6
8 changed files with 186 additions and 92 deletions

View File

@@ -421,7 +421,7 @@ class HotelReservation(models.Model):
@api.model
def _autoassign(self, values):
res = {}
checkin = values.get('checkin')
checkin = values.get('checkin')
checkout = values.get('checkout')
room_type = values.get('room_type_id')
if checkin and checkout and room_type:
@@ -475,21 +475,22 @@ class HotelReservation(models.Model):
'checkin': checkin or self.checkin,
'checkout': checkout or self.checkout,
'folio_id': self.folio_id.id,
# 'product_id': self.product_id.id,
'parent_reservation': self.parent_reservation.id,
'state': self.state,
'overbooking': self.overbooking,
'reselling': self.reselling,
'price_unit': self.price_unit,
'price_total': self.price_total,
'price_tax': self.price_tax,
'price_subtotal': self.price_subtotal,
'splitted': self.splitted,
# 'room_type_id': self.room_type_id.id,
'room_type_id': self.room_type_id.id,
'room_id': self.room_id.id,
}
@api.constrains('adults')
def _check_adults(self):
for record in self:
extra_bed = record.service_ids.filtered(
extra_bed = record.service_ids.filtered(
lambda r: r.product_id.is_extra_bed == True)
if record.adults > record.room_id.get_capacity(len(extra_bed)):
raise ValidationError(
@@ -629,7 +630,7 @@ class HotelReservation(models.Model):
days=self.nights,
per_person=product.per_person,
persons=self.adults,
old_line_days=False))
old_line_days=False))
board_services.append((0, False, vals))
other_services = self.service_ids.filtered(lambda r: r.is_board_service == False)
self.update({'service_ids': [(6, 0, other_services.ids)] + board_services})
@@ -974,6 +975,59 @@ class HotelReservation(models.Model):
first_checkin = reserv.checkin
return (first_checkin, last_checkout)
@api.multi
def split(self, nights):
for record in self:
date_start_dt = fields.Date.from_string(record.checkin)
date_end_dt = fields.Date.from_string(record.checkout)
date_diff = abs((date_end_dt - date_start_dt).days)
new_start_date_dt = date_start_dt + \
timedelta(days=date_diff-nights)
if nights >= date_diff or nights < 1:
raise ValidationError(_("Invalid Nights! Max is \
'%d'") % (date_diff-1))
vals = record.generate_copy_values(
new_start_date_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
date_end_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
)
# Days Price
reservation_lines = [[], []]
tprice = [0.0, 0.0]
for rline in record.reservation_line_ids:
rline_dt = fields.Date.from_string(rline.date)
if rline_dt >= new_start_date_dt:
reservation_lines[1].append((0, False, {
'date': rline.date,
'price': rline.price
}))
tprice[1] += rline.price
reservation_lines[0].append((2, rline.id, False))
else:
tprice[0] += rline.price
record.write({
'checkout': new_start_date_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
'price_total': tprice[0],
'splitted': True,
'reservation_line_ids': reservation_lines[0],
})
parent_res = record.parent_reservation or \
record
vals.update({
'splitted': True,
'price_total': tprice[1],
'parent_reservation': parent_res.id,
'room_type_id': parent_res.room_type_id.id,
'discount': parent_res.discount,
'reservation_line_ids': reservation_lines[1],
})
reservation_copy = self.env['hotel.reservation'].create(vals)
if not reservation_copy:
raise ValidationError(_("Unexpected error copying record. \
Can't split reservation!"))
return True
@api.multi
def unify(self):
# FIXME Remove product inheritance

View File

@@ -18,60 +18,5 @@ class SplitReservationWizard(models.TransientModel):
reservation_id = self.env['hotel.reservation'].browse(
self.env.context.get('active_id'))
if reservation_id:
date_start_dt = fields.Date.from_string(reservation_id.checkin)
date_end_dt = fields.Date.from_string(reservation_id.checkout)
date_diff = abs((date_end_dt - date_start_dt).days)
for record in self:
new_start_date_dt = date_start_dt + \
timedelta(days=date_diff-record.nights)
if record.nights >= date_diff or record.nights < 1:
raise ValidationError(_("Invalid Nights! Max is \
'%d'") % (date_diff-1))
vals = reservation_id.generate_copy_values(
new_start_date_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
date_end_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
)
# Days Price
reservation_lines = [[], []]
tprice = [0.0, 0.0]
for rline in reservation_id.reservation_lines:
rline_dt = fields.Date.from_string(rline.date)
if rline_dt >= new_start_date_dt:
reservation_lines[1].append((0, False, {
'date': rline.date,
'price': rline.price
}))
tprice[1] += rline.price
reservation_lines[0].append((2, rline.id, False))
else:
tprice[0] += rline.price
reservation_id.write({
'checkout': new_start_date_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
'price_unit': tprice[0],
'splitted': True,
})
reservation_id.reservation_lines = reservation_lines[0]
parent_res = reservation_id.parent_reservation or \
reservation_id
vals.update({
'splitted': True,
'price_unit': tprice[1],
'parent_reservation': parent_res.id,
'room_type_id': parent_res.room_type_id.id,
'discount': parent_res.discount,
})
reservation_copy = self.env['hotel.reservation'].create(vals)
if not reservation_copy:
raise ValidationError(_("Unexpected error copying record. \
Can't split reservation!"))
reservation_copy.reservation_lines = reservation_lines[1]
# return {
# 'type': 'ir.actions.act_window',
# 'res_model': 'hotel.folio',
# 'views': [[False, "form"]],
# 'target': 'new',
# 'res_id': reservation_id.folio_id.id,
# }
reservation_id.split(self.nights)
return True

View File

@@ -16,7 +16,6 @@ var AbstractController = require('web.AbstractController'),
var PMSCalendarController = AbstractController.extend({
custom_events: _.extend({}, AbstractController.prototype.custom_events, {
onLoadCalendar: '_onLoadCalendar',
onLoadCalendarSettings: '_onLoadCalendarSettings',
onLoadViewFilters: '_onLoadViewFilters',
onUpdateButtonsCounter: '_onUpdateButtonsCounter',
@@ -42,12 +41,14 @@ var PMSCalendarController = AbstractController.extend({
var self = this;
this._multi_calendar.setElement(this.renderer.$el.find('#hcal_widget'));
this._multi_calendar.start();
this._multi_calendar.on('tab_changed', function(ev, active_index){
if (active_index) {
self._refresh_filters(active_index);
}
});
this._multi_calendar.reset();
this._multi_calendar.start();
this._assign_multi_calendar_events();
this._load_calendars();
this._assign_view_events();
@@ -167,6 +168,7 @@ var PMSCalendarController = AbstractController.extend({
var calendar = self._multi_calendar.get_calendar(calendar_index+1);
calendar.setDomain(HotelCalendar.DOMAIN.ROOMS, domain);
}
self._multi_calendar.set_active_calendar(self._multi_calendar._calendars.length-1);
});
},
@@ -302,7 +304,7 @@ var PMSCalendarController = AbstractController.extend({
this.renderer.$el.find('#pms-menu #btn_action_divide button').on('click', function(ev){
var active_calendar = self._multi_calendar.get_active_calendar();
var cur_mode = active_calendar.getSelectionMode();
active_calendar.setSelectionMode(cur_mode===HotelCalendar.MODE.DIVIDE?HotelCalendar.MODE.NONE:HotelCalendar.MODE.DIVIDE);
active_calendar.setSelectionMode(cur_mode===HotelCalendar.ACTION.DIVIDE?HotelCalendar.MODE.NONE:HotelCalendar.ACTION.DIVIDE);
});
this.renderer.$el.find('#pms-menu #btn_save_calendar_record').on('click', function(ev){
@@ -352,6 +354,9 @@ var PMSCalendarController = AbstractController.extend({
}).tooltip('show');
}
});
this._multi_calendar.on_calendar('hcalOnSplitReservation', function(ev){
self.model.split_reservation(ev.detail.obj_id, ev.detail.nights);
});
this._multi_calendar.on_calendar('hcalOnClickReservation', function(ev){
//var res_id = ev.detail.reservationObj.getUserData('folio_id');
$(ev.detail.reservationDiv).tooltip('hide');
@@ -522,7 +527,7 @@ var PMSCalendarController = AbstractController.extend({
});
this._multi_calendar.on_calendar('hcalOnChangeSelectionMode', function(ev){
var $led = this.renderer.$el.find('#pms-menu #btn_action_divide button .led');
if (ev.detail.newMode === HotelCalendar.MODE.DIVIDE) {
if (ev.detail.newMode === HotelCalendar.ACTION.DIVIDE) {
$led.removeClass('led-disabled').addClass('led-enabled');
} else {
$led.removeClass('led-enabled').addClass('led-disabled');
@@ -819,7 +824,7 @@ var PMSCalendarController = AbstractController.extend({
/* Divide Led */
var $led = this.renderer.$el.find('#pms-menu #btn_action_divide button .led');
if (active_calendar.getSelectionMode() === HotelCalendar.MODE.DIVIDE) {
if (active_calendar.getSelectionMode() === HotelCalendar.ACTION.DIVIDE) {
$led.removeClass('led-disabled').addClass('led-enabled');
} else {
$led.removeClass('led-enabled').addClass('led-disabled');

View File

@@ -132,6 +132,15 @@ return AbstractModel.extend({
});
},
split_reservation: function(id, nights) {
return this._rpc({
model: 'hotel.reservation',
method: 'split',
args: [[id], nights],
context: Session.user_context,
})
},
save_changes: function(params) {
params.splice(0, 0, false); // FIXME: ID=False because first parameter its an integer
return this._rpc({

View File

@@ -34,6 +34,24 @@ odoo.define('hotel_calendar.MultiCalendar', function(require) {
this.$el.on(event_name, callback.bind(this));
},
reset: function() {
for (var i in this._calendars) {
delete this._calendars[i];
}
for (var [$tab, $panel] of this._tabs) {
$tab.remove();
$panel.remove();
}
$('#multicalendar_tabs').remove();
$('#multicalendar_panels').remove();
this._calendars = [];
this._calendar_records = [];
this._tabs = [];
this._datasets = {};
this._active_index = -1;
this._events = {};
},
get_calendar: function(index) {
return this._calendars[index-1];
},
@@ -264,9 +282,11 @@ odoo.define('hotel_calendar.MultiCalendar', function(require) {
this.$el.empty();
this.$tabs = $('<ul/>', {
class: 'nav nav-tabs',
id: 'multicalendar_tabs'
}).appendTo(this.$el);
this.$tabs_content = $('<div/>', {
class: 'tab-content',
id: 'multicalendar_panels'
}).appendTo(this.$el);
// '+' Tab

View File

@@ -314,6 +314,7 @@
.hcal-reservation-splitted {
border-width: 1px 6px;
border-style: solid;
}
.hcal-reservation-invalid {
@@ -378,6 +379,28 @@
background-color: #99bdd5 !important;
}
.hcal-reservation-to-divide {
pointer-events: none;
}
.hcal-reservation-divide-l {
background-color: transparent !important;
border: 2px dashed black;
cursor: copy;
pointer-events: none;
border-color: black !important;
border-right-style: solid !important;
}
.hcal-reservation-divide-r {
background-color: transparent !important;
border: 2px dashed black;
cursor: copy;
pointer-events: none;
border-color: black !important;
border-left-style: solid !important;
}
.hcal-row-room-type-group-item {
text-align: center;
}

View File

@@ -163,15 +163,13 @@ HotelCalendar.prototype = {
setSelectionMode: function(/*Int*/mode) {
if (this._modeSwap === HotelCalendar.MODE.NONE) {
this._selectionMode = mode;
if (this._selectionMode === HotelCalendar.MODE.DIVIDE) {
if (this._selectionMode === HotelCalendar.ACTION.DIVIDE) {
for (var reserv of this._reservations) {
reserv._active = false;
this._updateDivReservation(reserv, true);
reserv._html.classList.add('hcal-reservation-to-divide');
}
} else {
for (var reserv of this._reservations) {
reserv._active = true;
this._updateDivReservation(reserv, true);
reserv._html.classList.remove('hcal-reservation-to-divide');
}
if (this._divideDivs) {
this._divideDivs[0].remove();
@@ -1741,9 +1739,11 @@ HotelCalendar.prototype = {
var clearBorderLeft = function(/*HTMLObject*/elm) {
elm.style.borderLeftWidth = '3px';
elm.style.borderLeftStyle = 'double';
};
var clearBorderRight = function(/*HTMLObject*/elm) {
elm.style.borderRightWidth = '3px';
elm.style.borderRightStyle = 'double';
};
reserv._html.style.left = `${boundsInit.left-etableOffset.left}px`;
@@ -2353,10 +2353,25 @@ HotelCalendar.prototype = {
},
_onCellMouseUp: function(ev) {
if (this._cellSelection.start &&
this._cellSelection.start.dataset.hcalParentRow === ev.target.dataset.hcalParentRow) {
if (this._selectionMode === HotelCalendar.ACTION.DIVIDE) {
if (this.reservationAction.reservation) {
var realEndDate = this.reservationAction.endDate.clone().subtract(1, 'd');
if (this.reservationAction.action === HotelCalendar.ACTION.DIVIDE && !this.reservationAction.date.isSame(realEndDate, 'day')) {
var diff = this.getDateDiffDays(this.reservationAction.date, realEndDate);
this._dispatchEvent('hcalOnSplitReservation', {
reservation: this.reservationAction.reservation,
obj_id: this.reservationAction.obj_id,
date: this.reservationAction.date,
nights: diff
})
this._reset_action_reservation();
this.setSelectionMode(HotelCalendar.ACTION.NONE);
}
}
}
else if (this._cellSelection.start &&
this._cellSelection.start.dataset.hcalParentRow === ev.target.dataset.hcalParentRow) {
this._cellSelection.end = ev.target;
this._dispatchEvent(
'hcalOnChangeSelection',
{
@@ -2367,9 +2382,21 @@ HotelCalendar.prototype = {
},
_onCellMouseDown: function(ev) {
this._cellSelection.start = this._cellSelection.current = ev.target;
this._cellSelection.end = false;
this._updateCellSelection();
if (this._selectionMode === HotelCalendar.ACTION.DIVIDE && this._splitReservation) {
this.reservationAction = {
reservation: this._splitReservation._html,
obj_id: this._splitReservation.id,
endDate: this._splitReservation.endDate,
action: this._selectionMode,
date: this._splitDate,
};
this._splitReservation = false;
this._splitDate = false;
} else {
this._cellSelection.start = this._cellSelection.current = ev.target;
this._cellSelection.end = false;
this._updateCellSelection();
}
},
_onCellMouseEnter: function(ev) {
@@ -2478,7 +2505,7 @@ HotelCalendar.prototype = {
}
}
}
} else if (this._selectionMode === HotelCalendar.MODE.DIVIDE) {
} else if (this._selectionMode === HotelCalendar.ACTION.DIVIDE) {
var parentRow = ev.target.parentNode.parentNode.parentNode.parentNode;
var room_id = parentRow.dataset.hcalRoomObjId;
var reservs = this.getReservationsByDay(date_cell, true, false, room_id);
@@ -2488,18 +2515,29 @@ HotelCalendar.prototype = {
this._divideDivs = false;
}
if (reservs.length) {
this._divideDivs = [$(reservs[0]._html).clone().text('').appendTo(this.edivr), $(reservs[0]._html).clone().text('').appendTo(this.edivr)];
var diff = this.getDateDiffDays(reservs[0].startDate, date_cell);
this._divideDivs[0].css('background-color', 'red');
this._divideDivs[1].css('background-color', 'blue');
this._splitReservation = reservs[0];
this._divideDivs = [$(this._splitReservation._html).clone().text('').appendTo(this.edivr), $(this._splitReservation._html).clone().text('').appendTo(this.edivr)];
var diff = this.getDateDiffDays(this._splitReservation.startDate, date_cell);
this._divideDivs[0].addClass('hcal-reservation-divide-l');
this._divideDivs[1].addClass('hcal-reservation-divide-r');
var etableOffset = this.etable.getBoundingClientRect();
var boundsCell = ev.target.getBoundingClientRect();
var beginCell = reservs[0]._limits.left.getBoundingClientRect();
var endCell = reservs[0]._limits.right.getBoundingClientRect();
this._divideDivs[0][0].style.width = `${(boundsCell.left-beginCell.left)+boundsCell.width}px`;
this._divideDivs[1][0].style.left = `${(boundsCell.left-etableOffset.left)+boundsCell.width}px`;
this._divideDivs[1][0].style.width = `${(endCell.left-boundsCell.left)}px`;
var beginCell = this._splitReservation._limits.left.getBoundingClientRect();
var endCell = this._splitReservation._limits.right.getBoundingClientRect();
var splitCell = boundsCell;
var splitDate = date_cell.clone();
this._splitDate = date_cell.clone();
if (date_cell.isSame(this._splitReservation.endDate.clone().subtract(1, 'd'), 'day')) {
splitDate.subtract(1, 'd');
splitCell = this.getCell(this._splitDate, this._splitReservation.room, 0);
}
this._divideDivs[0][0].style.width = `${(splitCell.left-beginCell.left)+splitCell.width}px`;
this._divideDivs[1][0].style.left = `${(splitCell.left-etableOffset.left)+splitCell.width}px`;
this._divideDivs[1][0].style.width = `${(endCell.left-splitCell.left)}px`;
} else {
this._splitReservation = false;
this._splitDate = false;
}
}
},
@@ -2701,8 +2739,8 @@ HotelCalendar.prototype = {
/** CONSTANTS **/
HotelCalendar.DOMAIN = { NONE: -1, RESERVATIONS: 0, ROOMS: 1 };
HotelCalendar.ACTION = { NONE: -1, MOVE_ALL: 0, MOVE_LEFT: 1, MOVE_RIGHT: 2, SWAP: 3 };
HotelCalendar.MODE = { NONE: -1, SWAP_FROM: 0, SWAP_TO: 1, DIVIDE: 2, UNIFY: 3 };
HotelCalendar.ACTION = { NONE: -1, MOVE_ALL: 0, MOVE_LEFT: 1, MOVE_RIGHT: 2, SWAP: 3, DIVIDE: 4, UNIFY: 5 };
HotelCalendar.MODE = { NONE: -1, SWAP_FROM: 0, SWAP_TO: 1 };
HotelCalendar.DATE_FORMAT_SHORT_ = 'DD/MM/YYYY';
HotelCalendar.DATE_FORMAT_LONG_ = HotelCalendar.DATE_FORMAT_SHORT_ + ' HH:mm:ss';
/** STATIC METHODS **/

View File

@@ -71,13 +71,13 @@ class HotelFolio(models.Model):
@api.depends('room_lines')
def _compute_has_cancelled_reservations_to_send(self):
super()._compute_has_cancelled_reservations_to_send()
hotel_reserv_obj = self.env['hotel.reservation']
channel_hotel_reserv_obj = self.env['channel.hotel.reservation']
for record in self:
splitted_reservation_ids = record.room_lines.filtered(lambda x: x.splitted)
has_to_send = False
for rline in splitted_reservation_ids:
master_reservation = rline.parent_reservation or rline
has_to_send = hotel_reserv_obj.search_count([
has_to_send = channel_hotel_reserv_obj.search_count([
('splitted', '=', True),
('folio_id', '=', self.id),
('to_send', '=', True),