From 6cd4a217ec0bc79d12816cef3a76666c7abe1d1a Mon Sep 17 00:00:00 2001 From: QS5ELkMu Date: Tue, 13 Nov 2018 03:12:31 +0100 Subject: [PATCH] [IMP] Refactor & Export pricelist values (#63) --- .../components/exporter.py | 119 +--------------- hotel_channel_connector/controllers/main.py | 96 ++++++------- .../models/channel_backend/common.py | 13 ++ .../models/channel_ota_info/common.py | 2 +- .../models/channel_ota_info/importer.py | 8 +- .../models/hotel_room_type/common.py | 6 +- .../models/hotel_room_type/importer.py | 16 +-- .../hotel_room_type_availability/common.py | 9 +- .../hotel_room_type_availability/exporter.py | 17 +-- .../hotel_room_type_availability/importer.py | 9 +- .../hotel_room_type_restriction/common.py | 8 +- .../hotel_room_type_restriction/importer.py | 4 +- .../common.py | 4 +- .../exporter.py | 20 +-- .../importer.py | 5 +- .../models/product_pricelist/common.py | 8 +- .../models/product_pricelist/importer.py | 7 +- .../models/product_pricelist_item/common.py | 11 +- .../models/product_pricelist_item/exporter.py | 128 ++++++------------ .../models/product_pricelist_item/importer.py | 9 +- .../views/channel_connector_backend_views.xml | 29 ++-- 21 files changed, 176 insertions(+), 352 deletions(-) diff --git a/hotel_channel_connector/components/exporter.py b/hotel_channel_connector/components/exporter.py index b60e00181..f06757a92 100644 --- a/hotel_channel_connector/components/exporter.py +++ b/hotel_channel_connector/components/exporter.py @@ -1,127 +1,10 @@ # Copyright 2018 Alexandre Díaz # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -import logging -import psycopg2 -from contextlib import contextmanager -from odoo.addons.connector.exception import (IDMissingInBackend, - RetryableJobError) from odoo.addons.component.core import AbstractComponent -from odoo.tools import ( - DEFAULT_SERVER_DATE_FORMAT, - DEFAULT_SERVER_DATETIME_FORMAT) -from .backend_adapter import DEFAULT_WUBOOK_DATE_FORMAT -from odoo import api, fields -_logger = logging.getLogger(__name__) + class HotelChannelConnectorExporter(AbstractComponent): _name = 'hotel.channel.exporter' _inherit = ['base.exporter', 'base.hotel.channel.connector'] _usage = 'channel.exporter' - - @api.model - def push_changes(self): - return self.push_availability() and self.push_priceplans() and \ - self.push_restrictions() - - @api.model - def push_priceplans(self): - unpushed = self.env['product.pricelist.item'].search([ - ('wpushed', '=', False), - ('date_start', '>=', fields.Datetime.now().strftime( - DEFAULT_SERVER_DATE_FORMAT)) - ], order="date_start ASC") - if any(unpushed): - date_start = fields.Date.from_string(unpushed[0].date_start) - date_end = fields.Date.from_string(unpushed[-1].date_start) - days_diff = (date_start - date_end).days + 1 - - prices = {} - pricelist_ids = self.env['product.pricelist'].search([ - ('wpid', '!=', False), - ('active', '=', True) - ]) - for pr in pricelist_ids: - prices.update({pr.wpid: {}}) - unpushed_pl = self.env['product.pricelist.item'].search( - [('wpushed', '=', False), ('pricelist_id', '=', pr.id)]) - product_tmpl_ids = unpushed_pl.mapped('product_tmpl_id') - for pt_id in product_tmpl_ids: - room_type = self.env['hotel.room.type'].search([ - ('product_id.product_tmpl_id', '=', pt_id.id) - ], limit=1) - if room_type: - prices[pr.wpid].update({room_type.wrid: []}) - for i in range(0, days_diff): - prod = room_type.product_id.with_context({ - 'quantity': 1, - 'pricelist': pr.id, - 'date': (date_start + timedelta(days=i)). - strftime(DEFAULT_SERVER_DATE_FORMAT), - }) - prices[pr.wpid][room_type.wrid].append(prod.price) - _logger.info("UPDATING PRICES IN WUBOOK...") - _logger.info(prices) - for k_pk, v_pk in prices.iteritems(): - if any(v_pk): - self.backend_adapter.update_plan_prices(k_pk, date_start.strftime( - DEFAULT_SERVER_DATE_FORMAT), v_pk) - - unpushed.with_context({ - 'wubook_action': False}).write({'wpushed': True}) - return True - - @api.model - def push_restrictions(self): - room_type_rest_obj = self.env['hotel.room.type.restriction'] - rest_item_obj = self.env['hotel.room.type.restriction.item'] - unpushed = rest_item_obj.search([ - ('wpushed', '=', False), - ('date_start', '>=', fields.Datetime.now().strftime( - DEFAULT_SERVER_DATE_FORMAT)) - ], order="date_start ASC") - if any(unpushed): - date_start = fields.Date.from_string(unpushed[0].date_start) - date_end = fields.Date.from_string(unpushed[-1].date_start) - days_diff = (date_start - date_end) + 1 - restrictions = {} - restriction_plan_ids = room_type_rest_obj.search([ - ('wpid', '!=', False), - ('active', '=', True) - ]) - for rp in restriction_plan_ids: - restrictions.update({rp.wpid: {}}) - unpushed_rp = rest_item_obj.search([ - ('wpushed', '=', False), - ('restriction_id', '=', rp.id) - ]) - room_type_ids = unpushed_rp.mapped('room_type_id') - for room_type in room_type_ids: - restrictions[rp.wpid].update({room_type.wrid: []}) - for i in range(0, days_diff): - ndate_dt = date_start + timedelta(days=i) - restr = room_type.get_restrictions( - ndate_dt.strftime(DEFAULT_SERVER_DATE_FORMAT)) - if restr: - restrictions[rp.wpid][room_type.wrid].append({ - 'min_stay': restr.min_stay or 0, - 'min_stay_arrival': restr.min_stay_arrival or 0, - 'max_stay': restr.max_stay or 0, - 'max_stay_arrival': restr.max_stay_arrival or 0, - 'closed': restr.closed and 1 or 0, - 'closed_arrival': restr.closed_arrival and 1 or 0, - 'closed_departure': restr.closed_departure and 1 or 0, - }) - else: - restrictions[rp.wpid][room_type.wrid].append({}) - _logger.info("UPDATING RESTRICTIONS IN WUBOOK...") - _logger.info(restrictions) - for k_res, v_res in restrictions.iteritems(): - if any(v_res): - self.backend_adapter.update_rplan_values( - int(k_res), - date_start.strftime(DEFAULT_SERVER_DATE_FORMAT), - v_res) - unpushed.with_context({ - 'wubook_action': False}).write({'wpushed': True}) - return True diff --git a/hotel_channel_connector/controllers/main.py b/hotel_channel_connector/controllers/main.py index af9da9840..840f20143 100644 --- a/hotel_channel_connector/controllers/main.py +++ b/hotel_channel_connector/controllers/main.py @@ -2,9 +2,15 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). import logging +from datetime import datetime from openerp import http, _ from openerp.http import request from openerp.exceptions import ValidationError +from odoo.addons.hotel_channel_connector.components.backend_adapter import ( + DEFAULT_WUBOOK_DATE_FORMAT) +from odoo.tools import ( + DEFAULT_SERVER_DATE_FORMAT, + DEFAULT_SERVER_DATETIME_FORMAT) _logger = logging.getLogger(__name__) @@ -14,14 +20,6 @@ class website_wubook(http.Controller): type='http', cors="*", auth="public", methods=['POST'], website=True, csrf=False) def wubook_push_reservations(self, security_token, **kwargs): - # Check Security Token - hotel_security_token = request.env['ir.default'].sudo().get( - 'wubook.config.settings', 'wubook_push_security_token') - if security_token != hotel_security_token: - # _logger.info("Invalid Tokens: '%s' != '%s'" % - # (security_token, hotel_security_token)) - raise ValidationError(_('Invalid Security Token!')) - rcode = kwargs.get('rcode') lcode = kwargs.get('lcode') @@ -31,35 +29,27 @@ class website_wubook(http.Controller): # WuBook Check if rcode == '2000' and lcode == '1000': - return request.make_response( - '200 OK', [('Content-Type', 'text/plain')]) + return request.make_response('200 OK', [('Content-Type', 'text/plain')]) - # Poor Security Check - wlcode = request.env['ir.default'].sudo().get( - 'wubook.config.settings', 'wubook_lcode') - if lcode != wlcode: - raise ValidationError(_("Error! lcode doesn't match!")) + # Get Backend + backend = request.env['channel.backend'].search([ + ('security_token', '=', security_token), + ('lcode', '=', lcode), + ]) + if not backend: + raise ValidationError(_("Can't found a backend!")) _logger.info(_("[WUBOOK->ODOO] Importing Booking...")) # Create Reservation request.env['wubook'].sudo().fetch_booking(lcode, rcode) - return request.make_response('200 OK', - [('Content-Type', 'text/plain')]) + return request.make_response('200 OK', [('Content-Type', 'text/plain')]) # Called when modify room values (Delay: ~5mins) @http.route(['/wubook/push/rooms/'], type='http', cors="*", auth="public", methods=['POST'], website=True, csrf=False) def wubook_push_rooms(self, security_token, **kwargs): - # Check Security Token - hotel_security_token = request.env['ir.default'].sudo().get( - 'wubook.config.settings', 'wubook_push_security_token') - if security_token != hotel_security_token: - # _logger.info("Invalid Tokens: '%s' != '%s'" % - # (security_token, hotel_security_token)) - raise ValidationError(_('Invalid Security Token!')) - lcode = kwargs.get('lcode') dfrom = kwargs.get('dfrom') dto = kwargs.get('dto') @@ -68,36 +58,32 @@ class website_wubook(http.Controller): if not lcode or not dfrom or not dto: raise ValidationError(_('Invalid Input Parameters!')) - # Poor Security Check - wlcode = request.env['ir.default'].sudo().get( - 'wubook.config.settings', 'wubook_lcode') - if lcode != wlcode: - raise ValidationError(_("Error! lcode doesn't match!")) + # Get Backend + backend = request.env['channel.backend'].search([ + ('security_token', '=', security_token), + ('lcode', '=', lcode), + ]) + if not backend: + raise ValidationError(_("Can't found a backend!")) - _logger.info(_("[WUBOOK->ODOO] Updating values...")) - wubook_obj = request.env['wubook'].sudo().with_context({ - 'init_connection': False + odoo_dfrom = datetime.strptime( + dfrom, + DEFAULT_WUBOOK_DATE_FORMAT).strftime(DEFAULT_SERVER_DATE_FORMAT) + odoo_dto = datetime.strptime( + dto, + DEFAULT_WUBOOK_DATE_FORMAT).strftime(DEFAULT_SERVER_DATE_FORMAT) + backend.write({ + 'avail_from': odoo_dfrom, + 'avail_to': odoo_dto, + 'restriction_id': False, + 'restriction_from': odoo_dfrom, + 'restriction_to': odoo_dto, + 'pricelist_id': False, + 'pricelist_from': odoo_dfrom, + 'pricelist_to': odoo_dto, }) - if wubook_obj.init_connection(): - wubook_obj.fetch_rooms_values(dfrom, dto) + backend.import_availability() + backend.import_restriction() + backend.import_pricelist() - default_restr_id = request.env['ir.default'].sudo().get( - 'res.config.settings', 'default_restriction_id') - if default_restr_id: - room_type_restr_obj = request.env['hotel.room.type.restriction'] - restr_id = room_type_restr_obj.sudo().browse(int(default_restr_id)) - if restr_id and restr_id.wpid and restr_id.wpid != '0': - wubook_obj.fetch_rplan_restrictions(dfrom, dto, - rpid=restr_id.wpid) - - default_pricelist_id = request.env['ir.default'].sudo().get( - 'res.config.settings', 'default_pricelist_id') - if default_pricelist_id: - pricelist_id = request.env['product.pricelist'].sudo().browse( - int(default_pricelist_id)) - if pricelist_id and pricelist_id.wpid: - wubook_obj.fetch_plan_prices(pricelist_id.wpid, dfrom, dto) - wubook_obj.close_connection() - - return request.make_response('200 OK', - [('Content-Type', 'text/plain')]) + return request.make_response('200 OK', [('Content-Type', 'text/plain')]) diff --git a/hotel_channel_connector/models/channel_backend/common.py b/hotel_channel_connector/models/channel_backend/common.py index c4d8e7ab2..56771db3a 100644 --- a/hotel_channel_connector/models/channel_backend/common.py +++ b/hotel_channel_connector/models/channel_backend/common.py @@ -126,6 +126,19 @@ class ChannelBackend(models.Model): channel_product_pricelist_item_obj.import_pricelist_values(backend) return True + @api.multi + def push_pricelist(self): + channel_product_pricelist_item_obj = self.env['channel.product.pricelist.item'] + for backend in self: + channel_product_pricelist_item_obj.push_pricelist(backend) + return True + + @api.multi + def push_changes(self): + self.push_availability() + self.push_restriction() + self.push_pricelist() + @contextmanager @api.multi def work_on(self, model_name, **kwargs): diff --git a/hotel_channel_connector/models/channel_ota_info/common.py b/hotel_channel_connector/models/channel_ota_info/common.py index f6308cbec..b66bafdd5 100644 --- a/hotel_channel_connector/models/channel_ota_info/common.py +++ b/hotel_channel_connector/models/channel_ota_info/common.py @@ -26,7 +26,7 @@ class ChannelOtaInfo(models.Model): self.create_issue( backend=backend.id, section='room', - internal_message=_("Can't import ota info from WuBook"), + internal_message=str(err), channel_message=err.data['message']) class HotelRoomTypeAdapter(Component): diff --git a/hotel_channel_connector/models/channel_ota_info/importer.py b/hotel_channel_connector/models/channel_ota_info/importer.py index e236ace26..8d16bc650 100644 --- a/hotel_channel_connector/models/channel_ota_info/importer.py +++ b/hotel_channel_connector/models/channel_ota_info/importer.py @@ -35,9 +35,13 @@ class ChannelOtaInfoImporter(Component): ('ota_id', '=', ota_id) ], limit=1) if ota_info_bind: - ota_info_bind.write(map_record.values()) + ota_info_bind.with_context({ + 'connector_no_export': True, + }).write(map_record.values()) else: - ota_info_bind.create(map_record.values(for_create=True)) + ota_info_bind.with_context({ + 'connector_no_export': True, + }).create(map_record.values(for_create=True)) count = count + 1 return count diff --git a/hotel_channel_connector/models/hotel_room_type/common.py b/hotel_channel_connector/models/hotel_room_type/common.py index e6cbcbf3f..a145dd5b7 100644 --- a/hotel_channel_connector/models/hotel_room_type/common.py +++ b/hotel_channel_connector/models/hotel_room_type/common.py @@ -73,7 +73,7 @@ class ChannelHotelRoomType(models.Model): self.create_issue( backend=self.backend_id.id, section='room', - internal_message=_("Can't create room in WuBook"), + internal_message=str(err), channel_message=err.data['message']) @job(default_channel='root.channel') @@ -90,7 +90,7 @@ class ChannelHotelRoomType(models.Model): self.create_issue( backend=self.backend_id.id, section='room', - internal_message=_("Can't modify rooms in WuBook"), + internal_message=str(err), channel_message=err.data['message']) @job(default_channel='root.channel') @@ -107,7 +107,7 @@ class ChannelHotelRoomType(models.Model): self.create_issue( backend=self.backend_id.id, section='room', - internal_message=_("Can't delete room in WuBook"), + internal_message=str(err), channel_message=err.data['message']) class HotelRoomType(models.Model): diff --git a/hotel_channel_connector/models/hotel_room_type/importer.py b/hotel_channel_connector/models/hotel_room_type/importer.py index c972a3080..5ef4d27dc 100644 --- a/hotel_channel_connector/models/hotel_room_type/importer.py +++ b/hotel_channel_connector/models/hotel_room_type/importer.py @@ -2,7 +2,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). import logging -from datetime import timedelta +from datetime import datetime, timedelta from odoo.exceptions import ValidationError from odoo.addons.component.core import Component from odoo.addons.connector.components.mapper import mapping @@ -34,9 +34,9 @@ class HotelRoomTypeImporter(Component): ('external_id', '=', room['id']) ], limit=1) if room_bind: - room_bind.with_context({'wubook_action': False}).write(map_record.values()) + room_bind.with_context({'connector_no_export':True}).write(map_record.values()) else: - room_bind = channel_room_type_obj.with_context({'wubook_action': False}).create( + room_bind = channel_room_type_obj.with_context({'connector_no_export':True}).create( map_record.values(for_create=True)) return count @@ -44,7 +44,7 @@ class HotelRoomTypeImporter(Component): def fetch_rooms_values(self, dfrom, dto, rooms=False, set_max_avail=False): # Sanitize Dates - now_dt = fields.Datetime.now() + now_dt = datetime.now() dfrom_dt = fields.Date.from_string(dfrom) dto_dt = fields.Date.from_string(dto) if dto_dt < now_dt: @@ -77,11 +77,11 @@ class HotelRoomTypeImporter(Component): ], limit=1) if channel_room_type_avail: channel_room_type_avail.with_context({ - 'wubook_action': False, + 'connector_no_export': True, }).write(map_record.values()) else: channel_room_type_avail_obj.with_context({ - 'wubook_action': False, + 'connector_no_export': True, 'mail_create_nosubscribe': True, }).create(map_record.values(for_create=True)) @@ -102,11 +102,11 @@ class HotelRoomTypeImporter(Component): ]) if room_type_restr: room_type_restr.with_context({ - 'wubook_action': False, + 'connector_no_export': True, }).write(map_record.values()) else: channel_room_type_restr_item_obj.with_context({ - 'wubook_action': False, + 'connector_no_export': True, }).create(map_record.values(for_create=True)) @api.model 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 e98b765ed..6f3a835bc 100644 --- a/hotel_channel_connector/models/hotel_room_type_availability/common.py +++ b/hotel_channel_connector/models/hotel_room_type_availability/common.py @@ -54,7 +54,7 @@ class ChannelHotelRoomTypeAvailability(models.Model): self.create_issue( backend=backend.id, section='avail', - internal_message=_("Can't update availability in WuBook"), + internal_message=str(err), channel_message=err.data['message']) @job(default_channel='root.channel') @@ -63,12 +63,13 @@ class ChannelHotelRoomTypeAvailability(models.Model): with backend.work_on(self._name) as work: importer = work.component(usage='hotel.room.type.availability.importer') try: - return importer.get_availability(backend.avail_from, backend.avail_to) + return importer.import_availability_values(backend.avail_from, + backend.avail_to) except ChannelConnectorError as err: self.create_issue( backend=backend.id, section='avail', - internal_message=_("Can't import availability from WuBook"), + internal_message=str(err), channel_message=err.data['message']) @job(default_channel='root.channel') @@ -82,7 +83,7 @@ class ChannelHotelRoomTypeAvailability(models.Model): self.create_issue( backend=backend.id, section='avail', - internal_message=_("Can't update availability in WuBook"), + internal_message=str(err), channel_message=err.data['message']) class HotelRoomTypeAvailability(models.Model): diff --git a/hotel_channel_connector/models/hotel_room_type_availability/exporter.py b/hotel_channel_connector/models/hotel_room_type_availability/exporter.py index 3c5cfae81..511ef4af6 100644 --- a/hotel_channel_connector/models/hotel_room_type_availability/exporter.py +++ b/hotel_channel_connector/models/hotel_room_type_availability/exporter.py @@ -15,21 +15,6 @@ class HotelRoomTypeAvailabilityExporter(Component): _apply_on = ['channel.hotel.room.type.availability'] _usage = 'hotel.room.type.availability.exporter' - @api.model - def update_availability(self, binding): - if any(binding.room_type_id.channel_bind_ids): - sday_dt = fields.Date.from_string(binding.date) - # FIXME: Supossed that only exists one channel connector per record - binding.channel_pushed = True - return self.backend_adapter.update_availability({ - 'id': binding.room_type_id.channel_bind_ids[0].channel_room_id, - 'days': [{ - 'date': sday_dt.strftime(DEFAULT_WUBOOK_DATE_FORMAT), - 'avail': binding.avail, - 'no_ota': binding.no_ota, - }], - }) - def push_availability(self): channel_room_type_avail_ids = self.env['channel.hotel.room.type.availability'].search([ ('channel_pushed', '=', False), @@ -56,7 +41,7 @@ class HotelRoomTypeAvailabilityExporter(Component): # 'booked': room_type_avail.booked and 1 or 0, }) avails.append({'id': room_type.channel_bind_ids[0].channel_room_id, 'days': days}) - _logger.info("UPDATING AVAILABILITY IN WUBOOK...") + _logger.info("==[ODOO->CHANNEL]==== AVAILABILITY ==") _logger.info(avails) if any(avails): self.backend_adapter.update_availability(avails) diff --git a/hotel_channel_connector/models/hotel_room_type_availability/importer.py b/hotel_channel_connector/models/hotel_room_type_availability/importer.py index 7651ed9bc..d45195147 100644 --- a/hotel_channel_connector/models/hotel_room_type_availability/importer.py +++ b/hotel_channel_connector/models/hotel_room_type_availability/importer.py @@ -18,7 +18,7 @@ class HotelRoomTypeAvailabilityImporter(Component): _usage = 'hotel.room.type.availability.importer' @api.model - def get_availability(self, date_from, date_to): + def import_availability_values(self, date_from, date_to): now_dt = date.today() dfrom_dt = fields.Date.from_string(date_from) dto_dt = fields.Date.from_string(date_to) @@ -30,6 +30,9 @@ class HotelRoomTypeAvailabilityImporter(Component): return True results = self.backend_adapter.fetch_rooms_values(date_from, date_to) + _logger.info("==[CHANNEL->ODOO]==== AVAILABILITY (%s - %s) ==", + date_from, date_to) + _logger.info(results) channel_room_type_avail_obj = self.env['channel.hotel.room.type.availability'] channel_room_type_obj = self.env['channel.hotel.room.type'] @@ -55,11 +58,11 @@ class HotelRoomTypeAvailabilityImporter(Component): ], limit=1) if room_type_avail_bind: room_type_avail_bind.with_context({ - 'wubook_action': False + 'connector_no_export': True, }).write(map_record.values()) else: room_type_avail_bind = channel_room_type_avail_obj.with_context({ - 'wubook_action': False + 'connector_no_export': True, }).create(map_record.values(for_create=True)) iter_day += timedelta(days=1) return count diff --git a/hotel_channel_connector/models/hotel_room_type_restriction/common.py b/hotel_channel_connector/models/hotel_room_type_restriction/common.py index fef19def4..31e0bd708 100644 --- a/hotel_channel_connector/models/hotel_room_type_restriction/common.py +++ b/hotel_channel_connector/models/hotel_room_type_restriction/common.py @@ -35,7 +35,7 @@ class ChannelHotelRoomTypeRestriction(models.Model): self.create_issue( backend=self.backend_id.id, section='restriction', - internal_message=_("Can't create restriction plan in WuBook"), + internal_message=str(err), channel_message=err.data['message']) @job(default_channel='root.channel') @@ -52,7 +52,7 @@ class ChannelHotelRoomTypeRestriction(models.Model): self.create_issue( backend=self.backend_id.id, section='restriction', - internal_message=_("Can't modify restriction plan in WuBook"), + internal_message=str(err), channel_message=err.data['message']) @job(default_channel='root.channel') @@ -69,7 +69,7 @@ class ChannelHotelRoomTypeRestriction(models.Model): self.create_issue( backend=self.backend_id.id, section='restriction', - internal_message=_("Can't delete restriction plan in WuBook"), + internal_message=str(err), channel_message=err.data['message']) @job(default_channel='root.channel') @@ -83,7 +83,7 @@ class ChannelHotelRoomTypeRestriction(models.Model): self.create_issue( backend=backend.id, section='restriction', - internal_message=_("Can't fetch restriction plans from wubook"), + internal_message=str(err), channel_message=err.data['message']) class HotelRoomTypeRestriction(models.Model): diff --git a/hotel_channel_connector/models/hotel_room_type_restriction/importer.py b/hotel_channel_connector/models/hotel_room_type_restriction/importer.py index 48b5d3f4f..aa044a101 100644 --- a/hotel_channel_connector/models/hotel_room_type_restriction/importer.py +++ b/hotel_channel_connector/models/hotel_room_type_restriction/importer.py @@ -29,11 +29,11 @@ class HotelRoomTypeRestrictionImporter(Component): ], limit=1) if not plan_bind: channel_restriction_obj.with_context({ - 'wubook_action': False, + 'connector_no_export': True, 'rules': plan.get('rules'), }).create(plan_record.values(for_create=True)) else: - plan_bind.with_context({'wubook_action': False}).write( + plan_bind.with_context({'connector_no_export':True}).write( plan_record.values()) count = count + 1 return count diff --git a/hotel_channel_connector/models/hotel_room_type_restriction_item/common.py b/hotel_channel_connector/models/hotel_room_type_restriction_item/common.py index c57c8db29..a6e0b1447 100644 --- a/hotel_channel_connector/models/hotel_room_type_restriction_item/common.py +++ b/hotel_channel_connector/models/hotel_room_type_restriction_item/common.py @@ -35,7 +35,7 @@ class ChannelHotelRoomTypeRestrictionItem(models.Model): self.create_issue( backend=backend.id, section='restriction', - internal_message=_("Can't fetch plan restrictions from wubook"), + internal_message=str(err), channel_message=err.data['message'], channel_object_id=backend.restriction_id, dfrom=backend.restriction_from, dto=backend.restriction_to) @@ -51,7 +51,7 @@ class ChannelHotelRoomTypeRestrictionItem(models.Model): self.create_issue( backend=backend.id, section='restriction', - internal_message=_("Can't update restrictions in WuBook"), + internal_message=str(err), channel_message=err.data['message']) class HotelRoomTypeRestrictionItem(models.Model): diff --git a/hotel_channel_connector/models/hotel_room_type_restriction_item/exporter.py b/hotel_channel_connector/models/hotel_room_type_restriction_item/exporter.py index ac44d4c58..5d588f0ee 100644 --- a/hotel_channel_connector/models/hotel_room_type_restriction_item/exporter.py +++ b/hotel_channel_connector/models/hotel_room_type_restriction_item/exporter.py @@ -17,24 +17,6 @@ class HotelRoomTypeRestrictionItemExporter(Component): _apply_on = ['channel.hotel.room.type.restriction.item'] _usage = 'hotel.room.type.restriction.item.exporter' - @api.model - def update_restriction(self, binding): - if any(binding.restriction_id.channel_bind_ids): - # FIXME: Supossed that only exists one channel connector per record - binding.channel_pushed = True - return self.backend_adapter.update_rplan_values( - binding.restriction_id.channel_bind_ids[0].external_id, - binding.date, - { - 'min_stay': binding.min_stay or 0, - 'min_stay_arrival': binding.min_stay_arrival or 0, - 'max_stay': binding.max_stay or 0, - 'max_stay_arrival': binding.max_stay_arrival or 0, - 'closed': binding.closed and 1 or 0, - 'closed_arrival': binding.closed_arrival and 1 or 0, - 'closed_departure': binding.closed_departure and 1 or 0, - }) - @api.model def push_restriction(self): channel_room_type_rest_obj = self.env['channel.hotel.room.type.restriction'] @@ -80,7 +62,7 @@ class HotelRoomTypeRestrictionItemExporter(Component): }) else: restrictions[rp.external_id][room_type_external_id].append({}) - _logger.info("==[ODOO->CHANNEL]==== UPDATING RESTRICTIONS ==") + _logger.info("==[ODOO->CHANNEL]==== RESTRICTIONS ==") _logger.info(restrictions) for k_res, v_res in restrictions.items(): if any(v_res): diff --git a/hotel_channel_connector/models/hotel_room_type_restriction_item/importer.py b/hotel_channel_connector/models/hotel_room_type_restriction_item/importer.py index 378f69993..649ba7f06 100644 --- a/hotel_channel_connector/models/hotel_room_type_restriction_item/importer.py +++ b/hotel_channel_connector/models/hotel_room_type_restriction_item/importer.py @@ -57,10 +57,11 @@ class HotelRoomTypeRestrictionImporter(Component): }) if channel_restriction_item: channel_restriction_item.with_context({ - 'wubook_action': False}).write(map_record.values()) + 'connector_no_export': True + }).write(map_record.values()) else: channel_restriction_item_obj.with_context({ - 'wubook_action': False + 'connector_no_export': True }).create(map_record.values(for_create=True)) @api.model diff --git a/hotel_channel_connector/models/product_pricelist/common.py b/hotel_channel_connector/models/product_pricelist/common.py index 9f45630da..d207b0e5f 100644 --- a/hotel_channel_connector/models/product_pricelist/common.py +++ b/hotel_channel_connector/models/product_pricelist/common.py @@ -34,7 +34,7 @@ class ChannelProductPricelist(models.Model): self.create_issue( backend=self.backend_id.id, section='restriction', - internal_message=_("Can't create pricelist plan in WuBook"), + internal_message=str(err), channel_message=err.data['message']) @job(default_channel='root.channel') @@ -51,7 +51,7 @@ class ChannelProductPricelist(models.Model): self.create_issue( backend=self.backend_id.id, section='restriction', - internal_message=_("Can't modify pricelist plan in WuBook"), + internal_message=str(err), channel_message=err.data['message']) @job(default_channel='root.channel') @@ -68,7 +68,7 @@ class ChannelProductPricelist(models.Model): self.create_issue( backend=self.backend_id.id, section='restriction', - internal_message=_("Can't delete pricelist plan in WuBook"), + internal_message=str(err), channel_message=err.data['message']) @job(default_channel='root.channel') @@ -82,7 +82,7 @@ class ChannelProductPricelist(models.Model): self.create_issue( backend=backend.id, section='pricelist', - internal_message=_("Can't get pricing plans from wubook"), + internal_message=str(err), channel_message=err.data['message']) class ProductPricelist(models.Model): diff --git a/hotel_channel_connector/models/product_pricelist/importer.py b/hotel_channel_connector/models/product_pricelist/importer.py index c99add698..dde6aaea0 100644 --- a/hotel_channel_connector/models/product_pricelist/importer.py +++ b/hotel_channel_connector/models/product_pricelist/importer.py @@ -34,9 +34,12 @@ class ProductPricelistImporter(Component): ], limit=1) if not plan_bind: channel_product_listprice_obj.with_context({ - 'wubook_action': False}).create(plan_record.values(for_create=True)) + 'connector_no_export': True, + }).create(plan_record.values(for_create=True)) else: - channel_product_listprice_obj.write(plan_record.values()) + channel_product_listprice_obj.with_context({ + 'connector_no_export': True, + }).write(plan_record.values()) count = count + 1 return count diff --git a/hotel_channel_connector/models/product_pricelist_item/common.py b/hotel_channel_connector/models/product_pricelist_item/common.py index 03457d231..cd58fd412 100644 --- a/hotel_channel_connector/models/product_pricelist_item/common.py +++ b/hotel_channel_connector/models/product_pricelist_item/common.py @@ -39,7 +39,7 @@ class ChannelProductPricelistItem(models.Model): self.create_issue( backend=backend.id, section='pricelist', - internal_message="Can't fetch plan prices from wubook!", + internal_message=str(err), channel_message=err.data['message'], channel_object_id=backend.pricelist_id.external_id, dfrom=backend.pricelist_from, @@ -51,7 +51,14 @@ class ChannelProductPricelistItem(models.Model): def push_pricelist(self, backend): with backend.work_on(self._name) as work: exporter = work.component(usage='product.pricelist.item.exporter') - return exporter.push_pricelist() + try: + return exporter.push_pricelist() + except ChannelConnectorError as err: + self.create_issue( + backend=backend.id, + section='pricelist', + internal_message=str(err), + channel_message=err.data['message']) class ProductPricelistItem(models.Model): _inherit = 'product.pricelist.item' diff --git a/hotel_channel_connector/models/product_pricelist_item/exporter.py b/hotel_channel_connector/models/product_pricelist_item/exporter.py index 1498a354b..c062acabd 100644 --- a/hotel_channel_connector/models/product_pricelist_item/exporter.py +++ b/hotel_channel_connector/models/product_pricelist_item/exporter.py @@ -2,7 +2,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). import logging -from datetime import timedelta +from datetime import datetime, timedelta from odoo.addons.component.core import Component from odoo.addons.hotel_channel_connector.components.backend_adapter import ( DEFAULT_WUBOOK_DATE_FORMAT) @@ -17,90 +17,50 @@ class ProductPricelistItemExporter(Component): _usage = 'product.pricelist.item.exporter' @api.model - def update_restriction(self, binding): - if any(binding.restriction_id.channel_bind_ids): - try: - # FIXME: Supossed that only exists one channel connector per record - binding.channel_pushed = True - return self.backend_adapter.update_rplan_values( - binding.restriction_id.channel_bind_ids[0].external_id, - binding.date, - { - 'min_stay': binding.min_stay or 0, - 'min_stay_arrival': binding.min_stay_arrival or 0, - 'max_stay': binding.max_stay or 0, - 'max_stay_arrival': binding.max_stay_arrival or 0, - 'closed': binding.closed and 1 or 0, - 'closed_arrival': binding.closed_arrival and 1 or 0, - 'closed_departure': binding.closed_departure and 1 or 0, - }) - except ChannelConnectorError as err: - self.create_issue( - backend=self.backend_adapter.id, - section='restriction', - internal_message=_("Can't update restriction in WuBook"), - channel_message=err.data['message']) - - @api.model - def push_restriction(self): - channel_room_type_rest_obj = self.env['channel.hotel.room.type.restriction'] - channel_rest_item_obj = self.env['channel.hotel.room.type.restriction.item'] - unpushed = channel_rest_item_obj.search([ + def push_pricelist(self): + channel_product_pricelist_item_obj = self.env['channel.product.pricelist.item'] + channel_product_pricelist_obj = self.env['channel.product.pricelist'] + channel_room_type_obj = self.env['channel.hotel.room.type'] + channel_unpushed = channel_product_pricelist_item_obj.search([ ('channel_pushed', '=', False), - ('date', '>=', fields.Date.today()) - ], order="date ASC") - if any(unpushed): - date_start = fields.Date.from_string(unpushed[0].date) - date_end = fields.Date.from_string(unpushed[-1].date) - days_diff = (date_end-date_start).days + 1 - restrictions = {} - channel_restr_plan_ids = channel_room_type_rest_obj.search([]) - for rp in channel_restr_plan_ids: - restrictions.update({rp.external_id: {}}) - unpushed_rp = channel_rest_item_obj.search([ - ('channel_pushed', '=', False), - ('restriction_id', '=', rp.odoo_id.id) - ]) - room_type_ids = unpushed_rp.mapped('room_type_id') - for room_type in room_type_ids: - if any(room_type.channel_bind_ids): - # FIXME: Supossed that only exists one channel connector per record - room_type_external_id = room_type.channel_bind_ids[0].external_id - restrictions[rp.external_id].update({ - room_type_external_id: [], - }) + ('date_start', '>=', datetime.now().strftime( + DEFAULT_SERVER_DATE_FORMAT)) + ], order="date_start ASC") + if any(channel_unpushed): + date_start = fields.Date.from_string(channel_unpushed[0].date_start) + date_end = fields.Date.from_string(channel_unpushed[-1].date_start) + days_diff = (date_start - date_end).days + 1 + + prices = {} + pricelist_ids = channel_product_pricelist_obj.search([ + ('external_id', '!=', False), + ('active', '=', True) + ]) + for pr in pricelist_ids: + prices.update({pr.external_id: {}}) + unpushed_pl = channel_product_pricelist_item_obj.search( + [('channel_pushed', '=', False), ('pricelist_id', '=', pr.id)]) + product_tmpl_ids = unpushed_pl.mapped('product_tmpl_id') + for pt_id in product_tmpl_ids: + channel_room_type = channel_room_type_obj.search([ + ('product_id.product_tmpl_id', '=', pt_id.id) + ], limit=1) + if channel_room_type: + prices[pr.external_id].update({channel_room_type.external_id: []}) for i in range(0, days_diff): - ndate_dt = date_start + timedelta(days=i) - restr = room_type.get_restrictions( - ndate_dt.strftime(DEFAULT_SERVER_DATE_FORMAT), - rp.odoo_id.id) - if restr: - restrictions[rp.external_id][room_type_external_id].append({ - 'min_stay': restr.min_stay or 0, - 'min_stay_arrival': restr.min_stay_arrival or 0, - 'max_stay': restr.max_stay or 0, - 'max_stay_arrival': restr.max_stay_arrival or 0, - 'closed': restr.closed and 1 or 0, - 'closed_arrival': restr.closed_arrival and 1 or 0, - 'closed_departure': restr.closed_departure and 1 or 0, + prod = channel_room_type.product_id.with_context({ + 'quantity': 1, + 'pricelist': pr.id, + 'date': (date_start + timedelta(days=i)). + strftime(DEFAULT_SERVER_DATE_FORMAT), }) - else: - restrictions[rp.external_id][room_type_external_id].append({}) - _logger.info("==[ODOO->CHANNEL]==== UPDATING RESTRICTIONS ==") - _logger.info(restrictions) - for k_res, v_res in restrictions.items(): - if any(v_res): - try: - self.backend_adapter.update_rplan_values( - int(k_res), - date_start.strftime(DEFAULT_SERVER_DATE_FORMAT), - v_res) - except ChannelConnectorError as err: - self.create_issue( - backend=self.backend_adapter.id, - section='restriction', - internal_message=_("Can't update restrictions in WuBook"), - channel_message=err.data['message']) - unpushed.with_context({ - 'wubook_action': False}).write({'channel_pushed': True}) + prices[pr.external_id][channel_room_type.external_id].append(prod.price) + _logger.info("==[ODOO->CHANNEL]==== PRICELISTS ==") + _logger.info(prices) + for k_pk, v_pk in prices.items(): + if any(v_pk): + self.backend_adapter.update_plan_prices(k_pk, date_start.strftime( + DEFAULT_SERVER_DATE_FORMAT), v_pk) + + channel_unpushed.write({'channel_pushed': True}) return True diff --git a/hotel_channel_connector/models/product_pricelist_item/importer.py b/hotel_channel_connector/models/product_pricelist_item/importer.py index bb7bb30b7..491cebfb0 100644 --- a/hotel_channel_connector/models/product_pricelist_item/importer.py +++ b/hotel_channel_connector/models/product_pricelist_item/importer.py @@ -20,6 +20,9 @@ class ProductPricelistItemImporter(Component): @api.model def _generate_pricelist_items(self, channel_plan_id, date_from, date_to, plan_prices): + _logger.info("==[CHANNEL->ODOO]==== PRICELISTS [%d] (%s - %s) ==", + int(channel_plan_id), date_from, date_to) + _logger.info(plan_prices) channel_hotel_room_type_obj = self.env['channel.hotel.room.type'] pricelist_bind = self.env['channel.product.pricelist'].search([ ('external_id', '=', channel_plan_id) @@ -58,10 +61,12 @@ class ProductPricelistItemImporter(Component): ], limit=1) if pricelist_item: pricelist_item.with_context({ - 'wubook_action': False}).write(map_record.values()) + 'connector_no_export': True, + }).write(map_record.values()) else: channel_pricelist_item_obj.with_context({ - 'wubook_action': False}).create(map_record.values(for_create=True)) + 'connector_no_export': True, + }).create(map_record.values(for_create=True)) return True @api.model diff --git a/hotel_channel_connector/views/channel_connector_backend_views.xml b/hotel_channel_connector/views/channel_connector_backend_views.xml index 34438bec7..18ccbb9a5 100644 --- a/hotel_channel_connector/views/channel_connector_backend_views.xml +++ b/hotel_channel_connector/views/channel_connector_backend_views.xml @@ -41,24 +41,6 @@ -

- By clicking on the buttons, - you will initiate the synchronizations - with Channel. - Note that the import or exports - won't be done directly, - they will create 'Jobs' - executed as soon as possible. -

-

- Once imported, - some types of records, - like the reservations, - need a manual review. - You will find the list - of the new records to review - in the menu 'Connectors > Checkpoint'. -

- + +