diff --git a/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js b/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js
index 7865ebb12..25e0ff8e6 100644
--- a/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js
+++ b/hotel_calendar/static/src/js/views/calendar/hotel_calendar_controller.js
@@ -107,6 +107,7 @@ var PMSCalendarController = AbstractController.extend({
hcal_dates[0].format(HotelConstants.ODOO_DATETIME_MOMENT_FORMAT),
hcal_dates[1].format(HotelConstants.ODOO_DATETIME_MOMENT_FORMAT)
];
+
this.model.get_calendar_data(oparams).then(function(results){
self._multi_calendar._days_tooltips = results['events'];
self._multi_calendar._reserv_tooltips = results['tooltips'];
diff --git a/hotel_calendar/static/src/js/views/calendar/hotel_calendar_model.js b/hotel_calendar/static/src/js/views/calendar/hotel_calendar_model.js
index a236e01ff..2a54a3a35 100644
--- a/hotel_calendar/static/src/js/views/calendar/hotel_calendar_model.js
+++ b/hotel_calendar/static/src/js/views/calendar/hotel_calendar_model.js
@@ -20,15 +20,6 @@ return AbstractModel.extend({
this.modelManagementName = 'hotel.calendar.management'
},
- save_pricelist: function(params) {
- return this._rpc({
- model: this.modelManagementName,
- method: 'save_changes',
- args: params,
- context: Session.user_context,
- });
- },
-
swap_reservations: function(fromIds, toIds) {
return this._rpc({
model: this.modelName,
@@ -39,11 +30,23 @@ return AbstractModel.extend({
},
get_calendar_data: function(oparams) {
+ var dialog = bootbox.dialog({
+ message: '
Downloading Calendar Data...
',
+ onEscape: false,
+ closeButton: false,
+ size: 'small',
+ backdrop: false,
+ });
return this._rpc({
model: this.modelName,
method: 'get_hcalendar_all_data',
args: oparams,
context: Session.user_context,
+ }, {
+ success: function() {
+ dialog.modal('hide');
+ },
+ shadow: true,
});
},
@@ -151,13 +154,15 @@ return AbstractModel.extend({
},
save_changes: function(params) {
- params.splice(0, 0, false); // FIXME: ID=False because first parameter its an integer
+ //params.splice(0, 0, false); // FIXME: ID=False because first parameter its an integer
+ //console.log(params);
return this._rpc({
model: 'hotel.calendar.management',
method: 'save_changes',
args: params,
- context: Session.user_context,
+ //context: Session.user_context,
})
}
});
+
});
diff --git a/hotel_calendar/static/src/lib/hcalendar/js/hcalendar.js b/hotel_calendar/static/src/lib/hcalendar/js/hcalendar.js
index 216236c97..af67a4071 100644
--- a/hotel_calendar/static/src/lib/hcalendar/js/hcalendar.js
+++ b/hotel_calendar/static/src/lib/hcalendar/js/hcalendar.js
@@ -89,6 +89,19 @@ function HotelCalendar(/*String*/querySelector, /*Dictionary*/options, /*List*/p
this._domains = {}; // Store domains for filter rooms & reservations
this._divideDivs = false;
+ // Support
+ var self = this;
+ this._supportsPassive = false;
+ try {
+ var opts = Object.defineProperty({}, 'passive', {
+ get: function() {
+ self._supportsPassive = true;
+ }
+ });
+ window.addEventListener("testPassive", null, opts);
+ window.removeEventListener("testPassive", null, opts);
+ } catch (e) {}
+
// Calculate Capacities
this._roomCapacityTotal = 0;
this._roomCapacities = {};
@@ -233,6 +246,12 @@ HotelCalendar.prototype = {
}
},
+ _updateOffsets: function() {
+ this._etableOffset = this.loopedOffsetOptimized(this.etable);
+ this._eOffset = this.loopedOffsetOptimized(this.e);
+ this._edivrOffset = this.loopedOffsetOptimized(this.edivr);
+ },
+
//==== DOMAINS
setDomain: function(/*Int*/section, /*Array*/domain) {
if (this._domains[section] !== domain) {
@@ -507,19 +526,16 @@ HotelCalendar.prototype = {
var numBeds = +limits.right.dataset.hcalBedNum - +limits.left.dataset.hcalBedNum;
var ndate = reservation.startDate.clone().local();
for (var i=0; i 0)
- humantext += `Min. Stay: ${restr[0]}\n`;
- if (restr[1] > 0)
- humantext += `Min. Stay Arrival: ${restr[1]}\n`;
- if (restr[2] > 0)
- humantext += `Max. Stay: ${restr[2]}\n`;
- if (restr[3] > 0)
- humantext += `Max. Stay Arrival: ${restr[3]}\n`;
- if (restr[4])
- humantext += `Closed: ${restr[4]}\n`;
- if (restr[5])
- humantext += `Closed Arrival: ${restr[5]}\n`;
- if (restr[6])
- humantext += `Closed Departure: ${restr[6]}`;
- cell.title = humantext;
- }
- else {
- cell.classList.remove('hcal-restriction-room-day');
- cell.title = '';
- }
+ var date = this.options.startDate.clone().startOf('day');
+ for (var i=0; i<=this.options.days; ++i) {
+ var dd = date.add(1, 'd');
+ var date_str = dd.format(HotelCalendar.DATE_FORMAT_SHORT_);
+ if (date_str in this._restrictions[room.price[1]]) {
+ var restr = this._restrictions[room.price[1]][date_str];
+ if (restr) {
+ var cell = this.getMainCell(dd, room.type, room.number);
+ if (cell) {
+ if (restr[0] || restr[1] || restr[2] || restr[3] || restr[4] || restr[5] || restr[6]) {
+ cell.classList.add('hcal-restriction-room-day');
+ var humantext = "Restrictions:\n";
+ if (restr[0] > 0)
+ humantext += `Min. Stay: ${restr[0]}\n`;
+ if (restr[1] > 0)
+ humantext += `Min. Stay Arrival: ${restr[1]}\n`;
+ if (restr[2] > 0)
+ humantext += `Max. Stay: ${restr[2]}\n`;
+ if (restr[3] > 0)
+ humantext += `Max. Stay Arrival: ${restr[3]}\n`;
+ if (restr[4])
+ humantext += `Closed: ${restr[4]}\n`;
+ if (restr[5])
+ humantext += `Closed Arrival: ${restr[5]}\n`;
+ if (restr[6])
+ humantext += `Closed Departure: ${restr[6]}`;
+ cell.title = humantext;
+ }
+ else {
+ cell.classList.remove('hcal-restriction-room-day');
+ cell.title = '';
}
}
}
@@ -853,7 +856,7 @@ HotelCalendar.prototype = {
if (!day) { return false; }
var num_rooms = this._roomCapacities[room_type];
- num_rooms -= _.reduce(this.getDayRoomTypeReservations(day, room_type), function(memo, r){ return memo + (r.room && r.room.shared)?r.getTotalPersons(false):1; }, 0);
+ num_rooms -= _.reduce(this.getDayRoomTypeReservations(day, room_type), function(memo, r){ return memo + ((r.room && r.room.shared)?r.getTotalPersons(false):1); }, 0);
return num_rooms;
},
@@ -866,17 +869,6 @@ HotelCalendar.prototype = {
return num_rooms;
},
- calcReservationOccupation: function(/*String,MomentObject*/day, /*String*/room_type) {
- var day = HotelCalendar.toMoment(day);
- if (!day) {
- return false;
- }
-
- var reservs = this.getReservationsByDay(day, true);
- return Math.round(reservs.length/_.filter(this.options.rooms, function(item){ return !item.overbooking && !item.cancelled; }).length*100.0);
- },
-
-
/** PRIVATE MEMBERS **/
//==== MAIN FUNCTIONS
@@ -961,6 +953,7 @@ HotelCalendar.prototype = {
observer.observe(this.edivr, { childList: true });
this._updateView();
+ //_.defer(function(self){ self._updateView(); }, this);
this._tableCreated = true;
return true;
@@ -1184,8 +1177,7 @@ HotelCalendar.prototype = {
var cheight = 0.0;
for (var i=0; i mainBounds.bottom) {
+ var eOffset = this._eOffset;
+ var bounds = this.loopedOffsetOptimized(reserv._html);
+ if (bounds.top > mainBounds.height) {
var warnDiv = this.e.querySelector(`div.hcal-warn-ob-indicator[data-hcal-reservation-obj-id='${reserv.id}']`);
if (!warnDiv) {
var warnDiv = document.createElement("DIV");
@@ -1461,10 +1433,10 @@ HotelCalendar.prototype = {
warnDiv.dataset.hcalReservationObjId = reserv.id;
this.e.appendChild(warnDiv);
var warnComputedStyle = window.getComputedStyle(warnDiv, null);
- warnDiv.style.top = `${mainBounds.bottom - eOffset.top - parseInt(warnComputedStyle.getPropertyValue("height"), 10)}px`;
+ warnDiv.style.top = `${mainBounds.height - eOffset.top - parseInt(warnComputedStyle.getPropertyValue("height"), 10)}px`;
warnDiv.style.left = `${(bounds.left + (bounds.right - bounds.left)/2.0 - parseInt(warnComputedStyle.getPropertyValue("width"), 10)/2.0) - mainBounds.left}px`;
}
- } else if (bounds.bottom < mainBounds.top) {
+ } else if (bounds.height < mainBounds.top) {
var warnDiv = this.e.querySelector(`div.hcal-warn-ob-indicator[data-hcal-reservation-obj-id='${reserv.id}']`);
if (!warnDiv) {
var warnDiv = document.createElement("DIV");
@@ -1629,14 +1601,14 @@ HotelCalendar.prototype = {
},
_updateScroll: function(/*HTMLObject*/reservationDiv) {
- var reservBounds = reservationDiv.getBoundingClientRect();
- var mainBounds = this.edivr.getBoundingClientRect();
- var eOffset = this.e.getBoundingClientRect();
- var bottom = mainBounds.bottom - eOffset.top;
+ var reservBounds = this.loopedOffsetOptimized(reservationDiv);
+ var mainBounds = this._edivrOffset;
+ var eOffset = this._eOffset;
+ var bottom = mainBounds.height - eOffset.top;
var top = mainBounds.top + eOffset.top;
var offset = 10.0;
var scrollDisp = 10.0;
- if (reservBounds.bottom >= bottom-offset) {
+ if (reservBounds.height >= bottom-offset) {
this.edivr.scrollBy(0, scrollDisp);
}
else if (reservBounds.top <= top+offset) {
@@ -1733,10 +1705,9 @@ HotelCalendar.prototype = {
}
if (!noRefresh) {
- var boundsInit = reserv._limits.left.getBoundingClientRect();
- var boundsEnd = reserv._limits.right.getBoundingClientRect();
- var etableOffset = this.etable.getBoundingClientRect();
- var divHeight = (boundsEnd.bottom-etableOffset.top-4)-(boundsInit.top-etableOffset.top);
+ var boundsInit = this.loopedOffsetOptimized(reserv._limits.left);
+ var boundsEnd = this.loopedOffsetOptimized(reserv._limits.right);
+ var divHeight = (boundsEnd.top+boundsEnd.height)-boundsInit.top-4;
var has_changed = false;
var reservStyles = {
@@ -1744,8 +1715,8 @@ HotelCalendar.prototype = {
color: reserv.colorText,
lineHeight: `${divHeight}px`,
fontSize: '12px',
- top: `${boundsInit.top-etableOffset.top+2}px`,
- left: `${boundsInit.left-etableOffset.left+2}px`,
+ top: `${boundsInit.top-this._etableOffset.top+2}px`,
+ left: `${boundsInit.left-this._etableOffset.left+2}px`,
width: `${(boundsEnd.left-boundsInit.left)+boundsEnd.width-4}px`,
height: `${divHeight}px`,
borderLeftWidth: '',
@@ -1758,7 +1729,7 @@ HotelCalendar.prototype = {
has_changed = true;
reservStyles.borderLeftWidth = '3px';
reservStyles.borderLeftStyle = 'double';
- reservStyles.left = `${boundsInit.left-etableOffset.left}px`;
+ reservStyles.left = `${boundsInit.left-this._etableOffset.left}px`;
reservStyles.width = `${(boundsEnd.left-boundsInit.left)+boundsEnd.width-2}px`;
} else if (reserv.splitted && reserv.startDate.isSame(reserv.getUserData('realDates')[0], 'day')) {
has_changed = true;
@@ -1774,7 +1745,7 @@ HotelCalendar.prototype = {
} else if (reserv.splitted && reserv.endDate.isSame(reserv.getUserData('realDates')[1], 'day')) {
has_changed = true;
reservStyles.borderRightWidth = '0';
- reservStyles.left = `${boundsInit.left-etableOffset.left-1}px`;
+ reservStyles.left = `${boundsInit.left-this._etableOffset.left-1}px`;
reservStyles.width = `${(boundsEnd.left-boundsInit.left)+boundsEnd.width-1}px`;
}
@@ -1791,7 +1762,7 @@ HotelCalendar.prototype = {
reservStyles.borderColor = `rgb(${bbColor[0]},${bbColor[1]},${bbColor[2]})`;
if (!has_changed) {
- reservStyles.left = `${boundsInit.left-etableOffset.left-1}px`;
+ reservStyles.left = `${boundsInit.left-this._etableOffset.left-1}px`;
reservStyles.width = `${(boundsEnd.left-boundsInit.left)+boundsEnd.width+2}px`;
}
} else {
@@ -1953,7 +1924,7 @@ HotelCalendar.prototype = {
var $this = this;
reservDivs = reservDivs || this.e.querySelectorAll('div.hcal-reservation');
for (var rdiv of reservDivs) {
- var bounds = rdiv.getBoundingClientRect();
+ var bounds = this.loopedOffsetOptimized(rdiv);
rdiv.addEventListener('mousemove', function(ev){
var posAction = $this._getRerservationPositionAction(this, ev.layerX, ev.layerY);
this.style.cursor = (posAction == HotelCalendar.ACTION.MOVE_LEFT || posAction == HotelCalendar.ACTION.MOVE_RIGHT)?'col-resize':'pointer';
@@ -2059,8 +2030,8 @@ HotelCalendar.prototype = {
}
}
};
- rdiv.addEventListener('mousedown', _funcEvent, false);
- rdiv.addEventListener('touchstart', _funcEvent, false);
+ rdiv.addEventListener('mousedown', _funcEvent, this._supportsPassive ? { passive: true } : false);
+ rdiv.addEventListener('touchstart', _funcEvent, this._supportsPassive ? { passive: true } : false);
rdiv.addEventListener('click', function(ev){
$this._dispatchEvent(
'hcalOnClickReservation',
@@ -2103,7 +2074,7 @@ HotelCalendar.prototype = {
},
_getRerservationPositionAction: function(/*HTMLObject*/elm, /*Int*/posX, /*Int*/posY) {
- var bounds = elm.getBoundingClientRect();
+ var bounds = this.loopedOffsetOptimized(elm);
if (posX <= 5) { return HotelCalendar.ACTION.MOVE_LEFT; }
else if (posX >= bounds.width-10) { return HotelCalendar.ACTION.MOVE_RIGHT; }
return HotelCalendar.ACTION.MOVE_ALL;
@@ -2155,9 +2126,9 @@ HotelCalendar.prototype = {
return;
}
var cells = [
- this.edtable.querySelectorAll('td.hcal-cell-detail-room-free-type-group-item-day'),
- this.edtable.querySelectorAll('td.hcal-cell-detail-room-free-total-group-item-day'),
- this.edtable.querySelectorAll('td.hcal-cell-detail-room-perc-occup-group-item-day')
+ this.edtable.querySelectorAll('.hcal-cell-detail-room-free-type-group-item-day'),
+ this.edtable.querySelectorAll('.hcal-cell-detail-room-free-total-group-item-day'),
+ this.edtable.querySelectorAll('.hcal-cell-detail-room-perc-occup-group-item-day')
];
for (var cell of cells[0]) {
@@ -2194,6 +2165,34 @@ HotelCalendar.prototype = {
},
//==== PRICELIST
+ getPricelist: function(onlyNew) {
+ var data = {};
+
+ var key = this._pricelist_id;
+ var pricelist = this._pricelist[key];
+ for (var listitem of pricelist) {
+ for (var i=0; i<=this.options.days; ++i) {
+ var dd = this.options.startDate.clone().local().startOf('day').add(i,'d').utc();
+ var dd_local = dd.clone().local();
+
+ var input = this.edtable.querySelector(`#${this._sanitizeId(`INPUT_PRICE_${key}_${listitem.room}_${dd_local.format(HotelCalendar.DATE_FORMAT_SHORT_)}`)}`);
+ if (input.value !== input.dataset.orgValue) {
+ var value = input.value;
+ var orgValue = input.dataset.orgValue;
+ var parentCell = this.edtable.querySelector(`#${input.dataset.hcalParentCell}`);
+ var parentRow = this.edtable.querySelector(`#${parentCell.dataset.hcalParentRow}`);
+ if (!(parentRow.dataset.hcalRoomTypeId in data)) { data[parentRow.dataset.hcalRoomTypeId] = []; }
+ data[parentRow.dataset.hcalRoomTypeId].push({
+ 'date': HotelCalendar.toMoment(parentCell.dataset.hcalDate).format('YYYY-MM-DD'),
+ 'price': value
+ });
+ }
+ }
+ }
+
+ return data;
+ },
+
setPricelist: function(/*List*/pricelist) {
this._pricelist = pricelist;
this._updatePriceList();
@@ -2285,9 +2284,7 @@ HotelCalendar.prototype = {
},
getDateDiffDays: function(/*MomentObject*/start, /*MomentObject*/end) {
- var end_date = end.clone().startOf('day');
- var start_date = start.clone().startOf('day');
- return end_date.diff(start_date, 'days');
+ return end.diff(start, 'days');
},
getDateLimits: function(/*List HReservationObject*/reservs, /*Bool?*/noCheckouts) {
@@ -2604,25 +2601,26 @@ HotelCalendar.prototype = {
$('', {class: 'hcal-reservation-divide-r', css: defStyle}).appendTo(this.edivr)
];
var diff = this.getDateDiffDays(this._splitReservation.startDate, date_cell);
- var etableOffset = this.etable.getBoundingClientRect();
- var boundsCell = ev.target.getBoundingClientRect();
- var beginCell = this._splitReservation._limits.left.getBoundingClientRect();
- var endCell = this._splitReservation._limits.right.getBoundingClientRect();
+ var boundsCell = false;
+ var beginCell = this.loopedOffsetOptimized(this._splitReservation._limits.left);
+ var endCell = this.loopedOffsetOptimized(this._splitReservation._limits.right);
this._splitDate = date_cell.clone();
if (date_cell.isSame(this._splitReservation.endDate.clone().subtract(1, 'd'), 'day')) {
this._splitDate.subtract(1, 'd');
var tcell = this.getCell(this._splitDate, this._splitReservation.room, 0);
if (tcell) {
- boundsCell = tcell.getBoundingClientRect();
+ boundsCell = this.loopedOffsetOptimized(tcell);
} else {
boundsCell = false;
this._splitReservation = false;
this._splitDate = false;
}
+ } else {
+ boundsCell = this.loopedOffsetOptimized(ev.target);
}
if (boundsCell) {
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.left = `${(boundsCell.left-this._etableOffset.left)+boundsCell.width}px`;
this._divideDivs[1][0].style.width = `${(endCell.left-boundsCell.left)}px`;
}
} else {
@@ -2749,10 +2747,41 @@ HotelCalendar.prototype = {
onMainResize: function(/*EventObject*/ev) {
_.defer(function(){
+ this._updateOffsets();
this._updateReservations();
}.bind(this));
},
+ //=== OPTIMIZED OFFSET
+ // Method from https://jsperf.com/offset-vs-getboundingclientrect/7
+ loopedOffsetOptimized: function (elem) {
+ var offsetLeft = elem.offsetLeft
+ , offsetTop = elem.offsetTop
+ , offsetWidth = elem.offsetWidth
+ , offsetHeight = elem.offsetHeight
+ , lastElem = elem;
+
+ while (elem = elem.offsetParent) {
+ if (elem === document.body) { //from my observation, document.body always has scrollLeft/scrollTop == 0
+ break;
+ }
+ offsetLeft += elem.offsetLeft;
+ offsetTop += elem.offsetTop;
+ lastElem = elem;
+ }
+ // if (lastElem && lastElem.style.position === 'fixed') { //slow - http://jsperf.com/offset-vs-getboundingclientrect/6
+ // //if(lastElem !== document.body) { //faster but does gives false positive in Firefox
+ // offsetLeft += window.pageXOffset || document.documentElement.scrollLeft;
+ // offsetTop += window.pageYOffset || document.documentElement.scrollTop;
+ // }
+ return {
+ left: offsetLeft,
+ top: offsetTop,
+ width: offsetWidth,
+ height: offsetHeight,
+ };
+ },
+
//==== COLOR FUNCTIONS (RANGE: 0.0|1.0)
_intToRgb: function(/*Int*/RGBint) {
return [(RGBint >> 16) & 255, (RGBint >> 8) & 255, RGBint & 255];