[IMP] Unify

This commit is contained in:
QS5ELkMu
2018-12-21 00:10:35 +01:00
parent d041f64ade
commit 775736b25d
7 changed files with 180 additions and 200 deletions

View File

@@ -960,7 +960,9 @@ class HotelReservation(models.Model):
master_reservation = self.parent_reservation or self
splitted_reservs = self.env['hotel.reservation'].search([
'|',
('splitted', '=', True),
('id', '=', master_reservation.id),
('folio_id', '=', self.folio_id.id),
'|',
('parent_reservation', '=', master_reservation.id),
@@ -1006,14 +1008,7 @@ class HotelReservation(models.Model):
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
parent_res = record.parent_reservation or record
vals.update({
'splitted': True,
'price_total': tprice[1],
@@ -1022,83 +1017,85 @@ class HotelReservation(models.Model):
'discount': parent_res.discount,
'reservation_line_ids': reservation_lines[1],
})
reservation_copy = self.env['hotel.reservation'].create(vals)
reservation_copy = self.env['hotel.reservation'].with_context({
'ignore_avail_restrictions': True}).create(vals)
if not reservation_copy:
raise ValidationError(_("Unexpected error copying record. \
Can't split reservation!"))
record.write({
'checkout': new_start_date_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
'price_total': tprice[0],
'splitted': True,
'reservation_line_ids': reservation_lines[0],
})
return True
@api.multi
def unify(self):
# FIXME Remove product inheritance
pass
# self.ensure_one()
# if not self.splitted:
# raise ValidationError(_("This reservation can't be unified"))
#
# master_reservation = self.parent_reservation or self
# self_is_master = (master_reservation == self)
#
# splitted_reservs = self.env['hotel.reservation'].search([
# ('splitted', '=', True),
# ('folio_id', '=', self.folio_id.id),
# '|',
# ('parent_reservation', '=', master_reservation.id),
# ('id', '=', master_reservation.id)
# ])
#
# rooms_products = splitted_reservs.mapped('product_id.id')
# if len(rooms_products) > 1 or \
# (len(rooms_products) == 1
# and master_reservation.product_id.id != rooms_products[0]):
# raise ValidationError(_("This reservation can't be unified: They \
# all need to be in the same room"))
#
# # Search checkout
# last_checkout = splitted_reservs[0].checkout
# for reserv in splitted_reservs:
# if last_checkout < reserv.checkout:
# last_checkout = reserv.checkout
#
# # Agrupate reservation lines
# reservation_line_ids = splitted_reservs.mapped('reservation_line_ids')
# reservation_line_ids.sorted(key=lambda r: r.date)
# rlines = [(5, False, False)]
# tprice = 0.0
# for rline in reservation_line_ids:
# rlines.append((0, False, {
# 'date': rline.date,
# 'price': rline.price,
# }))
# tprice += rline.price
#
# # Unify
# folio = self.folio_id # FIX: To Allow Unify confirm reservations
# state = folio.state # FIX
# folio.state = 'draft' # FIX
# osplitted_reservs = splitted_reservs - master_reservation
# osplitted_reservs.sudo().unlink()
# folio.state = state # FIX
#
# # FIXME: Two writes because checkout regenerate reservation lines
# master_reservation.write({
# 'checkout': last_checkout,
# 'splitted': False,
# })
# master_reservation.write({
# 'reservation_line_ids': rlines,
# 'price_unit': tprice,
# })
# if not self_is_master:
# return {'type': 'ir.actions.act_window_close'}
# return True
#
# '''
# Created this because "copy()" function create a new record
# and collide with date restrictions.
# This function generate a usable dictionary with reservation values
# for copy purposes.
# '''
def unify(self, reserv_ids=None):
self.ensure_one()
if not self.splitted:
raise ValidationError(_("This reservation can't be unified"))
master_reservation = self.parent_reservation or self
splitted_reservs = self.env['hotel.reservation'].search([
('splitted', '=', True),
('folio_id', '=', self.folio_id.id),
'|',
('parent_reservation', '=', master_reservation.id),
('id', '=', master_reservation.id)
])
self.unify_books(splitted_reservs)
self_is_master = (master_reservation == self)
if not self_is_master:
return {'type': 'ir.actions.act_window_close'}
@api.model
def unify_ids(self, reserv_ids):
splitted_reservs = self.env[self._name].browse(reserv_ids)
self.unify_books(splitted_reservs)
@api.model
def unify_books(self, splitted_reservs):
master_reservation = splitted_reservs[0].parent_reservation or splitted_reservs[0]
room_type_ids = splitted_reservs.mapped('room_type_id.id')
if len(room_type_ids) > 1 or \
(len(room_type_ids) == 1
and master_reservation.room_type_id.id != room_type_ids[0]):
raise ValidationError(_("This reservation can't be unified: They \
all need to be in the same room"))
# Search checkout
last_checkout = splitted_reservs[0].checkout
for reserv in splitted_reservs:
if last_checkout < reserv.checkout:
last_checkout = reserv.checkout
# Agrupate reservation lines
reservation_line_ids = splitted_reservs.mapped('reservation_line_ids')
reservation_line_ids.sorted(key=lambda r: r.date)
rlines = [(5, False, False)]
tprice = 0.0
for rline in reservation_line_ids:
rlines.append((0, False, {
'date': rline.date,
'price': rline.price,
}))
tprice += rline.price
# Unify
osplitted_reservs = splitted_reservs - master_reservation
osplitted_reservs.sudo().unlink()
master_reservation.write({
'checkout': last_checkout,
'splitted': False,
'reservation_line_ids': rlines,
'price_total': tprice,
})
return True
@api.multi
def open_master(self):

View File

@@ -434,8 +434,9 @@ class HotelReservation(models.Model):
'closure_reason_id' in vals or 'out_service_description' in vals or \
'reservation_type' in vals or \
'reserve_color' in vals or \
'reserve_color_text' in vals or 'product_id' in vals or \
'parent_reservation' in vals or 'overbooking' in vals:
'reserve_color_text' in vals or 'price_total' in vals or \
'parent_reservation' in vals or 'overbooking' in vals or \
'room_type_id' in vals:
for record in self:
record.send_bus_notification(
'write',

View File

@@ -18,7 +18,6 @@ var PMSCalendarController = AbstractController.extend({
custom_events: _.extend({}, AbstractController.prototype.custom_events, {
onLoadViewFilters: '_onLoadViewFilters',
onUpdateButtonsCounter: '_onUpdateButtonsCounter',
onSwapReservations: '_onSwapReservations',
onViewAttached: '_onViewAttached',
onApplyFilters: '_onApplyFilters',
}),
@@ -72,6 +71,25 @@ var PMSCalendarController = AbstractController.extend({
});
},
swapReservations: function (fromIds, toIds, detail, refFromReservDiv, refToReservDiv) {
var self = this;
return this.model.swap_reservations(fromIds, toIds).then(function(results){
var allReservs = detail.inReservs.concat(detail.outReservs);
for (var nreserv of allReservs) {
self.renderer.$el.find(nreserv._html).stop(true);
}
}).fail(function(err, errev){
for (var nreserv of detail.inReservs) {
self.renderer.$el.find(nreserv._html).animate({'top': refFromReservDiv.style.top}, 'fast');
}
for (var nreserv of detail.outReservs) {
self.renderer.$el.find(nreserv._html).animate({'top': refToReservDiv.style.top}, 'fast');
}
self._multi_calendar.swap_reservations(detail.outReservs, detail.inReservs);
});
},
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
@@ -114,11 +132,7 @@ var PMSCalendarController = AbstractController.extend({
var reservs = [];
for (var r of results['reservations']) {
var nreserv = new HReservation(self._generate_reservation_obj_values(r));
nreserv.addUserData({
'folio_id': r['folio_id'],
'parent_reservation': r['parent_reservation']
});
var nreserv = self._create_reservation_obj(r);
reservs.push(nreserv);
}
@@ -219,11 +233,7 @@ var PMSCalendarController = AbstractController.extend({
this.model.get_calendar_data(oparams).then(function(results){
var reservs = [];
for (var r of results['reservations']) {
var nreserv = new HReservation(self._generate_reservation_obj_values(r));
nreserv.addUserData({
'folio_id': r['folio_id'],
'parent_reservation': r['parent_reservation']
});
var nreserv = self._create_reservation_obj(r);
reservs.push(nreserv);
}
@@ -378,8 +388,7 @@ var PMSCalendarController = AbstractController.extend({
});
});
this._multi_calendar.on_calendar('hcalOnUnifyReservations', function(ev){
console.log("TO UNIFY");
console.log(ev.detail.toUnify);
self.model.unify_reservations(_.map(ev.detail.toUnify, 'id'));
});
this._multi_calendar.on_calendar('hcalOnSwapReservations', function(ev){
var qdict = {};
@@ -404,13 +413,7 @@ var PMSCalendarController = AbstractController.extend({
for (var nreserv of ev.detail.outReservs) {
$(nreserv._html).animate({'top': refFromReservDiv.style.top});
}
self.trigger_up('onSwapReservations', {
'fromIds': fromIds,
'toIds': toIds,
'detail': ev.detail,
'refFromReservDiv': refFromReservDiv,
'refToReservDiv': refToReservDiv
});
self.swapReservations(fromIds, toIds, ev.detail, refFromReservDiv, refToReservDiv);
} else {
var qdict = {};
var dialog = new Dialog(self, {
@@ -597,28 +600,53 @@ var PMSCalendarController = AbstractController.extend({
}.bind(this));
},
_create_reservation_obj: function(json_reserv) {
var nreserv = new HReservation({
'id': json_reserv['id'],
'room_id': json_reserv['room_id'],
'title': json_reserv['name'],
'adults': json_reserv['adults'],
'childrens': json_reserv['childrens'],
'startDate': HotelCalendar.toMoment(json_reserv['checkin'], HotelConstants.ODOO_DATETIME_MOMENT_FORMAT),
'endDate': HotelCalendar.toMoment(json_reserv['checkout'], HotelConstants.ODOO_DATETIME_MOMENT_FORMAT),
'color': json_reserv['bgcolor'],
'colorText': json_reserv['color'],
'splitted': json_reserv['splitted'] || false,
'readOnly': json_reserv['read_only'] || false,
'fixDays': json_reserv['fix_days'] || false,
'fixRooms': json_reserv['fix_room'],
'unusedZone': false,
'linkedId': false,
'overbooking': json_reserv['overbooking'],
'cancelled': json_reserv['state'] === 'cancelled'
});
nreserv.addUserData({
'folio_id': json_reserv['folio_id'],
'parent_reservation': json_reserv['parent_reservation'],
'realDates': [
HotelCalendar.toMoment(json_reserv['real_dates'][0], HotelConstants.ODOO_DATETIME_MOMENT_FORMAT),
HotelCalendar.toMoment(json_reserv['real_dates'][1], HotelConstants.ODOO_DATETIME_MOMENT_FORMAT)
]
});
return nreserv;
},
_generate_reservation_tooltip_dict: function(tp) {
return {
'name': tp['name'],
'phone': tp['phone'],
'arrival_hour': HotelCalendar.toMomentUTC(tp['checkin'], HotelConstants.ODOO_DATETIME_MOMENT_FORMAT).local().format('HH:mm'),
'num_split': tp['num_split'],
'amount_total': Number(tp['amount_total']).toLocaleString(),
'reservation_type': tp['type'],
'out_service_description': tp['out_service_description']
};
},
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
_onSwapReservations: function (ev) {
var self = this;
return this.model.swap_reservations(ev.data.fromIds, ev.data.toIds).then(function(results){
var allReservs = ev.data.detail.inReservs.concat(ev.data.detail.outReservs);
for (var nreserv of allReservs) {
self.renderer.$el.find(nreserv._html).stop(true);
}
}).fail(function(err, errev){
for (var nreserv of ev.data.detail.inReservs) {
self.renderer.$el.find(nreserv._html).animate({'top': refFromReservDiv.style.top}, 'fast');
}
for (var nreserv of ev.detail.outReservs) {
self.renderer.$el.find(nreserv._html).animate({'top': refToReservDiv.style.top}, 'fast');
}
self._multi_calendar.swap_reservations(ev.data.detail.outReservs, ev.data.detail.inReservs);
});
},
_onViewAttached: function (ev) {
this._multi_calendar.recalculate_reservation_positions();
},
@@ -651,29 +679,6 @@ var PMSCalendarController = AbstractController.extend({
});
},
_generate_reservation_obj_values: function(reserv) {
return {
'id': reserv['id'],
'room_id': reserv['room_id'],
'title': reserv['name'],
'adults': reserv['adults'],
'childrens': reserv['childrens'],
'startDate': HotelCalendar.toMomentUTC(reserv['checkin'], HotelConstants.ODOO_DATETIME_MOMENT_FORMAT),
'endDate': HotelCalendar.toMomentUTC(reserv['checkout'], HotelConstants.ODOO_DATETIME_MOMENT_FORMAT),
'color': reserv['bgcolor'],
'colorText': reserv['color'],
'splitted': reserv['splitted'] || false,
'readOnly': reserv['read_only'] || false,
'fixDays': reserv['fix_days'] || false,
'fixRooms': reserv['fix_room'],
'unusedZone': false,
'linkedId': false,
'overbooking': reserv['overbooking'],
'cancelled': reserv['state'] === 'cancelled',
'realDates': reserv['real_dates']
}
},
_onBusNotification: function(notifications) {
var need_reload_pricelists = false;
var need_update_counters = false;
@@ -707,11 +712,7 @@ var PMSCalendarController = AbstractController.extend({
nreservs = _.reject(nreservs, function(item){ return item.id == reserv['id']; });
} else {
nreservs = _.reject(nreservs, {'id': reserv['id']}); // Only like last changes
var nreserv = new HReservation(this._generate_reservation_obj_values(reserv));
nreserv.addUserData({
'folio_id': reserv['folio_id'],
'parent_reservation': reserv['parent_reservation'],
});
var nreserv = this._create_reservation_obj(reserv);
this._multi_calendar._reserv_tooltips[reserv['id']] = notif[1]['tooltip'];
nreservs.push(nreserv);
}
@@ -757,18 +758,6 @@ var PMSCalendarController = AbstractController.extend({
this._multi_calendar.get_active_calendar().setDomain(HotelCalendar.DOMAIN.ROOMS, domain);
},
_generate_reservation_tooltip_dict: function(tp) {
return {
'name': tp['name'],
'phone': tp['phone'],
'arrival_hour': HotelCalendar.toMomentUTC(tp['checkin'], HotelConstants.ODOO_DATETIME_MOMENT_FORMAT).local().format('HH:mm'),
'num_split': tp['num_split'],
'amount_total': Number(tp['amount_total']).toLocaleString(),
'reservation_type': tp['type'],
'out_service_description': tp['out_service_description']
};
},
_on_change_filter_date: function(isStartDate) {
isStartDate = isStartDate || false;
var $dateTimePickerBegin = this.renderer.$el.find('#pms-menu #date_begin');
@@ -867,6 +856,9 @@ var PMSCalendarController = AbstractController.extend({
$types.trigger('change');
},
//--------------------------------------------------------------------------
// Helpers
//--------------------------------------------------------------------------
_find_bootstrap_environment: function() {
var envs = ['xs', 'sm', 'md', 'lg'];

View File

@@ -134,13 +134,22 @@ return AbstractModel.extend({
split_reservation: function(id, nights) {
return this._rpc({
model: 'hotel.reservation',
model: this.modelName,
method: 'split',
args: [[id], nights],
context: Session.user_context,
})
},
unify_reservations: function(reserv_ids) {
return this._rpc({
model: this.modelName,
method: 'unify_ids',
args: [reserv_ids],
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

@@ -24,11 +24,6 @@ var HotelCalendarView = AbstractRenderer.extend({
searchable: false,
searchview_hidden: true,
// Custom Options
_reserv_tooltips: {},
_days_tooltips: [],
_last_dates: [false, false],
/** VIEW METHODS **/
init: function(parent, state, params) {
@@ -230,24 +225,6 @@ var HotelCalendarView = AbstractRenderer.extend({
}.bind(this));
},
toggle_pms_search: function() {
var $pms_search = this.$el.find('#pms-menu');
if ($pms_search.position().top < 0)
{
var $navbar = $('.navbar');
var toPos = $navbar.height() + parseInt($navbar.css('border-top-width'), 10) + parseInt($navbar.css('border-bottom-width'), 10);
$pms_search.animate({
'top': `${toPos}px`,
'opacity': 1.0,
}, 'fast');
} else {
$pms_search.animate({
'top': `-${$pms_search.height()}px`,
'opacity': 0.0,
}, 'slow');
}
},
_generate_search_domain: function(tsearch) {
var domain = [];
domain.push('|', '|', '|', '|',

View File

@@ -110,7 +110,10 @@ odoo.define('hotel_calendar.MultiCalendar', function(require) {
remove_reservation: function(reserv_id) {
this._dataset['reservations'] = _.reject(this._dataset['reservations'], {id: reserv_id});
for (var calendar of this._calendars) {
calendar.removeReservation(reserv_id);
var reserv = calendar.getReservation(reserv_id);
if (reserv) {
calendar.removeReservation(reserv);
}
}
},

View File

@@ -136,8 +136,7 @@ HotelCalendar.prototype = {
this._updateView(!fullUpdate, callback);
},
getOptions: function(/*String?*/key) {+
console.log(this.options);
getOptions: function(/*String?*/key) {
if (typeof key !== 'undefined') {
return this.options[key];
}
@@ -1769,7 +1768,13 @@ HotelCalendar.prototype = {
if (reserv.splitted) {
reserv._html.classList.add('hcal-reservation-splitted');
var magicNumber = Math.floor(Math.abs(Math.sin((reserv.getUserData('parent_reservation') || reserv.id))) * 100000);
// 1. Use reservation ID as seed
// 2. Use sinusiudal function
// 3. Only use positive values (This decrease longitude, increase frequency)
// 4. Use the first 5 decimals to make the integer value
// 5. Get integer value (Bitwise tilde method)
// TODO: Improve pseudo-random number generator
var magicNumber = ~~(Math.abs(Math.sin((reserv.getUserData('parent_reservation') || reserv.id))) * 100000);
var bbColor = this._intToRgb(magicNumber);
reserv._html.style.borderColor = `rgb(${bbColor[0]},${bbColor[1]},${bbColor[2]})`;
} else {
@@ -1787,23 +1792,19 @@ HotelCalendar.prototype = {
reserv._html.style.height = `${divHeight}px`;
reserv._html.style.lineHeight = `${divHeight+fontHeight/2.0}px`;
reserv._html.style.fontSize = `${fontHeight}px`;
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`;
reserv._html.style.width = `${(boundsEnd.left-boundsInit.left)+boundsEnd.width}px`;
if (reserv._drawModes[0] === 'soft-start') {
clearBorderLeft(reserv._html);
reserv._html.style.borderLeftWidth = '3px';
reserv._html.style.borderLeftStyle = 'double';
} else if (reserv.splitted && reserv.startDate.isSame(reserv.getUserData('realDates')[0], 'day')) {
reserv._html.style.borderLeftWidth = '0';
}
if (reserv._drawModes[1] === 'soft-end') {
clearBorderRight(reserv._html);
reserv._html.style.borderRightWidth = '3px';
reserv._html.style.borderRightStyle = 'double';
} else if (reserv.splitted && reserv.endDate.isSame(reserv.getUserData('realDates')[1], 'day')) {
reserv._html.style.borderRightWidth = '0';
}
}
},