From 69b66b6d87212185fcef7965bd717683a4cf39d9 Mon Sep 17 00:00:00 2001 From: Dario Lodeiros Date: Thu, 28 Feb 2019 17:27:23 +0100 Subject: [PATCH] [WIP] Refresh Availability --- .../inherited_hotel_calendar_management.py | 4 +- .../models/hotel_reservation/common.py | 45 ++++++--- .../hotel_room_type_availability/common.py | 98 ++++++++++--------- 3 files changed, 86 insertions(+), 61 deletions(-) diff --git a/hotel_calendar_channel_connector/models/inherited_hotel_calendar_management.py b/hotel_calendar_channel_connector/models/inherited_hotel_calendar_management.py index 0d870814e..35cb84ef1 100644 --- a/hotel_calendar_channel_connector/models/inherited_hotel_calendar_management.py +++ b/hotel_calendar_channel_connector/models/inherited_hotel_calendar_management.py @@ -36,8 +36,8 @@ class HotelCalendarManagement(models.TransientModel): 'id': False, 'date': date, 'no_ota': False, - 'quota': -1, # FIXED: `avail and avail.max_quota or -1` returns -1 if quota = 0 - 'max_avail': -1, + 'quota': room_type.channel_bind_ids.default_quota, + 'max_avail': room_type.channel_bind_ids.default_max_avail, 'channel_avail': room_type.channel_bind_ids.default_availability } if avail: diff --git a/hotel_channel_connector/models/hotel_reservation/common.py b/hotel_channel_connector/models/hotel_reservation/common.py index 0d0090627..d1344c364 100644 --- a/hotel_channel_connector/models/hotel_reservation/common.py +++ b/hotel_channel_connector/models/hotel_reservation/common.py @@ -35,6 +35,13 @@ class ChannelHotelReservation(models.Model): channel_modified = fields.Boolean("Channel Modified", readonly=True, default=False, old_name='wmodified') + # Inherit binding constrain becouse two reservations can have + # the same external_id + _sql_constraints = [ + ('channel_uniq', 'unique(odoo_id, external_id)', + 'A binding already exists with the same Channel ID.'), + ] + @api.depends('channel_reservation_id', 'ota_id') def _is_from_ota(self): for record in self: @@ -42,9 +49,9 @@ class ChannelHotelReservation(models.Model): @job(default_channel='root.channel') @api.model - def refresh_availability(self, checkin, checkout, room_id): + def refresh_availability(self, checkin, checkout, backend_id, room_id): self.env['channel.hotel.room.type.availability'].refresh_availability( - checkin, checkout, room_id) + checkin, checkout, backend_id, room_id) @job(default_channel='root.channel') @api.model @@ -82,15 +89,24 @@ class ChannelHotelReservation(models.Model): older_vals = [] new_vals = [] for record in self: + backend_id = self.env['channel.hotel.room.type'].search([ + ('odoo_id', '=', record.room_id.room_type_id.id) + ]).backend_id.id older_vals.append({ 'checkin': record.checkin, 'checkout': record.checkout, - 'room_id': record.room_id, + 'backend_id': backend_id, + 'room_id': record.room_id.id, }) + new_backend_id = self.env['channel.hotel.room.type'].search([ + ('odoo_id', '=', self.env['hotel.room']. + browse(vals.get('room_id', record.room_id.id)). + room_type_id.id)]).backend_id.id new_vals.append({ 'checkin': vals.get('checkin', record.checkin), 'checkout': vals.get('checkout', record.checkout), - 'room_id': vals.get('room_id', record.room_id), + 'backend_id': new_backend_id, + 'room_id': vals.get('room_id', record.room_id.id), }) res = super(ChannelHotelReservation, self).write(vals) @@ -99,14 +115,16 @@ class ChannelHotelReservation(models.Model): for k_i, v_i in enumerate(older_vals): # FIX: 3rd parameters is backend_id, use room_id=v_i['room_id'] instead channel_room_type_avail_obj.refresh_availability( - v_i['checkin'], - v_i['checkout'], - v_i['room_id']) + checkin=v_i['checkin'], + checkout=v_i['checkout'], + backend_id=v_i['backend_id'], + room_id=v_i['room_id']) # FIX: 3rd parameters is backend_id, use room_id=new_vals[k_i]['room_id'] instead channel_room_type_avail_obj.refresh_availability( - new_vals[k_i]['checkin'], - new_vals[k_i]['checkout'], - new_vals[k_i]['room_id']) + checkin=new_vals[k_i]['checkin'], + checkout=new_vals[k_i]['checkout'], + backend_id=new_vals[k_i]['backend_id'], + room_id=new_vals[k_i]['room_id']) else: res = super(ChannelHotelReservation, self).write(vals) return res @@ -117,9 +135,13 @@ class ChannelHotelReservation(models.Model): for record in self: if record.is_from_ota and self._context.get('ota_limits', True): raise UserError(_("You can't delete OTA's reservations")) + backend_id = self.env['channel.hotel.room.type'].search([ + ('odoo_id', '=', record.room_id.room_type_id.id) + ]).backend_id.id vals.append({ 'checkin': record.checkin, 'checkout': record.checkout, + 'backend_id': backend_id, 'room_id': record.room_id.id, }) res = super(ChannelHotelReservation, self).unlink() @@ -130,9 +152,11 @@ class ChannelHotelReservation(models.Model): channel_room_type_avail_obj.refresh_availability( record['checkin'], record['checkout'], + record['backend_id'], record['room_id']) return res + class HotelReservation(models.Model): _inherit = 'hotel.reservation' @@ -244,7 +268,6 @@ class ChannelBindingHotelReservationListener(Component): _inherit = 'base.connector.listener' _apply_on = ['channel.hotel.reservation'] - @skip_if(lambda self, record, **kwargs: self.no_connector_export(record)) def on_record_create(self, record, fields=None): record.refresh_availability() diff --git a/hotel_channel_connector/models/hotel_room_type_availability/common.py b/hotel_channel_connector/models/hotel_room_type_availability/common.py index 51f2bdb37..e54aec04c 100644 --- a/hotel_channel_connector/models/hotel_room_type_availability/common.py +++ b/hotel_channel_connector/models/hotel_room_type_availability/common.py @@ -18,8 +18,10 @@ class HotelRoomTypeAvailability(models.Model): @api.model def _default_max_avail(self): - if self.room_type_id: - return self.room_type_id.total_rooms_count + room_type_id = self._context.get('room_type_id') + if room_type_id: + room_type_id = self.env['hotel.room_type'].browse(room_type_id) + return room_type_id.default_max_avail if room_type_id else -1 return -1 @api.model @@ -64,9 +66,6 @@ class HotelRoomTypeAvailability(models.Model): if record.quota > record.room_type_id.total_rooms_count: raise ValidationError(_("The quota assigned to the channel manager can't be greater " "than the total rooms count!")) - if (record.max_avail > record.quota) and (record.quota >= 0): - raise ValidationError(_("The maximum simultaneous availability can't be greater " - "than a given quota.")) if record.max_avail > record.room_type_id.total_rooms_count: raise ValidationError(_("The maximum simultaneous availability can't be greater " "than the total rooms count!")) @@ -122,12 +121,13 @@ class ChannelHotelRoomTypeAvailability(models.Model): room_type_id=False, from_channel=False): date_start = fields.Date.from_string(checkin) date_end = fields.Date.from_string(checkout) + if date_start == date_end: + date_end = date_start + timedelta(days=1) # Not count end day of the reservation date_diff = (date_end - date_start).days channel_room_type_obj = self.env['channel.hotel.room.type'] channel_room_type_avail_obj = self.env['channel.hotel.room.type.availability'] - if room_type_id: room_type_bind = channel_room_type_obj.search([('odoo_id', '=', room_type_id)]) else: @@ -152,43 +152,32 @@ class ChannelHotelRoomTypeAvailability(models.Model): room_type_avail_id = channel_room_type_avail_obj.search([ ('room_type_id', '=', room_type_bind.odoo_id.id), ('date', '=', ndate_str)], limit=1) - quota = room_type_bind.default_quota - if room_type_avail_id: - if room_type_avail_id.quota >= 0: - if from_channel and room_type_avail_id.quota > 0: - room_type_avail_id.update({ - 'quota': room_type_avail_id.quota - 1, - }) - quota = room_type_avail_id.quota - if room_type_avail_id.max_avail >= 0: - to_eval.append(room_type_avail_id.max_avail) - else: - if room_type_bind.default_max_avail >= 0: - to_eval.append(room_type_bind.default_max_avail) - if from_channel and quota > 0: - quota -= 1 - to_eval.append(quota) + quota = room_type_avail_id.quota if room_type_avail_id \ + else room_type_bind.default_quota + max_avail = room_type_avail_id.max_avail if room_type_avail_id \ + else room_type_bind.default_max_avail + + if from_channel and quota > 0: + quota -= 1 + # We ignore quota and max_avail if its value is -1 + if quota >= 0: + to_eval.append(quota) + if max_avail >= 0: + to_eval.append(max_avail) + # And finally, set the channel avail like the min set value avail = max(min(to_eval), 0) - _logger.info({ - 'real_avail': cavail, - 'default_avail': room_type_bind.default_availability, - 'quota': room_type_avail_id.quota, - 'max_avail': room_type_avail_id.max_avail, - }) - _logger.info({ - 'room_type_id': room_type_bind.odoo_id.id, - 'date': ndate_str, - 'channel_avail': avail, - }) + if room_type_avail_id: # CAVEAT: update channel.hotel.room.type.availability if needed + vals_avail = {} + if room_type_avail_id.quota != quota: + vals_avail.update({'quota': quota}) if room_type_avail_id.channel_avail != avail: - room_type_avail_id.write({'channel_avail': avail}) + vals_avail.update({'channel_avail': avail}) + if vals_avail: + room_type_avail_id.write(vals_avail) else: - quota = room_type_bind.default_quota - if from_channel and quota > 0: - quota -= 1 self.env['hotel.room.type.availability'].create({ 'room_type_id': room_type_bind.odoo_id.id, 'date': ndate_str, @@ -246,6 +235,8 @@ class BindingHotelRoomTypeAvailabilityListener(Component): 'channel.hotel.room.type.availability'] backends = self.env['channel.backend'].search([]) for backend in backends: + # REVIEW :: If you create directly channel_binding, this search + # return empty avail_bind = channel_room_type_avail_obj.search([ ('odoo_id', '=', record.id), ('backend_id', '=', backend.id), @@ -257,15 +248,16 @@ class BindingHotelRoomTypeAvailabilityListener(Component): 'channel_pushed': False, 'backend_id': backend.id, }) - _logger.info("==[on_record_create] :: hotel.room.type.availability==") - _logger.info(avail_bind) - avail_bind.refresh_availability( - record.date, - (datetime.strptime(record.date, DEFAULT_SERVER_DATE_FORMAT).date() + - timedelta(days=1)).strftime(DEFAULT_SERVER_DATE_FORMAT), - backend.id, - # room_type_id=record.room_type_id.channel_bind_ids.id, - room_type_id=record.room_type_id.id) + _logger.info("==[on_record_create] :: hotel.room.type.availability==") + _logger.info(avail_bind) + else: + avail_bind.refresh_availability( + record.date, + (datetime.strptime(record.date, DEFAULT_SERVER_DATE_FORMAT).date() + + timedelta(days=1)).strftime(DEFAULT_SERVER_DATE_FORMAT), + backend.id, + # room_type_id=record.room_type_id.channel_bind_ids.id, + room_type_id=record.room_type_id.id) class ChannelBindingHotelRoomTypeAvailabilityListener(Component): @@ -286,12 +278,22 @@ class ChannelBindingHotelRoomTypeAvailabilityListener(Component): record.channel_pushed = False record.push_availability(record.backend_id) + @skip_if(lambda self, record, **kwargs: self.no_connector_export(record)) + def on_record_create(self, record, fields=None): + if any(record.channel_bind_ids): + for binding in record.channel_bind_ids: + record.refresh_availability( + record.date, + record.date, + binding.backend_id.id, + room_type_id=record.room_type_id.id) + @skip_if(lambda self, record, **kwargs: self.no_connector_export(record)) def on_fix_channel_availability(self, record, fields=None): if any(record.channel_bind_ids): for binding in record.channel_bind_ids: record.refresh_availability( - record.checkin, - record.checkout, + record.date, + record.date, binding.backend_id.id, room_type_id=record.room_type_id.id)