mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
[WIP][11.0] hotel channel connector
This commit is contained in:
@@ -1,9 +1,8 @@
|
|||||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
import xmlrpclib
|
import xmlrpc.client
|
||||||
from odoo import _
|
import logging
|
||||||
from odoo.exceptions import ValidationError
|
|
||||||
from odoo.addons.component.core import AbstractComponent
|
from odoo.addons.component.core import AbstractComponent
|
||||||
from odoo.addons.queue_job.exception import RetryableJobError
|
from odoo.addons.queue_job.exception import RetryableJobError
|
||||||
from odoo.tools import (
|
from odoo.tools import (
|
||||||
@@ -11,7 +10,9 @@ from odoo.tools import (
|
|||||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
from odoo.addons.payment.models.payment_acquirer import _partner_split_name
|
from odoo.addons.payment.models.payment_acquirer import _partner_split_name
|
||||||
from odoo.addons.hotel import date_utils
|
from odoo.addons.hotel import date_utils
|
||||||
from odoo import fields
|
from odoo.addons.hotel_channel_connector.components.core import ChannelConnectorError
|
||||||
|
from odoo import fields, _
|
||||||
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# GLOBAL VARS
|
# GLOBAL VARS
|
||||||
DEFAULT_WUBOOK_DATE_FORMAT = "%d/%m/%Y"
|
DEFAULT_WUBOOK_DATE_FORMAT = "%d/%m/%Y"
|
||||||
@@ -63,9 +64,11 @@ class WuBookServer(object):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def server(self):
|
def server(self):
|
||||||
if self._server is None and self._login_data.is_valid():
|
if not self._login_data.is_valid():
|
||||||
|
raise ChannelConnectorError("Invalid Channel Parameters!")
|
||||||
|
if self._server is None:
|
||||||
try:
|
try:
|
||||||
self._server = xmlrpclib.Server(self._login_data.address)
|
self._server = xmlrpc.client.ServerProxy(self._login_data.address)
|
||||||
res, tok = self._server.acquire_token(
|
res, tok = self._server.acquire_token(
|
||||||
self._login_data.user,
|
self._login_data.user,
|
||||||
self._login_data.passwd,
|
self._login_data.passwd,
|
||||||
@@ -183,7 +186,7 @@ class HotelChannelInterfaceAdapter(AbstractComponent):
|
|||||||
channel_server = getattr(self.work, 'channel_api')
|
channel_server = getattr(self.work, 'channel_api')
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise AttributeError(
|
raise AttributeError(
|
||||||
'You must provide a hotel_channel_server attribute with a '
|
'You must provide a channel_api attribute with a '
|
||||||
'WuBookServer instance to be able to use the '
|
'WuBookServer instance to be able to use the '
|
||||||
'Backend Adapter.'
|
'Backend Adapter.'
|
||||||
)
|
)
|
||||||
@@ -192,14 +195,14 @@ class HotelChannelInterfaceAdapter(AbstractComponent):
|
|||||||
@property
|
@property
|
||||||
def _session_info(self):
|
def _session_info(self):
|
||||||
try:
|
try:
|
||||||
channel_server = getattr(self.work, 'hotel_channel_server')
|
channel_server = getattr(self.work, 'channel_api')
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
raise AttributeError(
|
raise AttributeError(
|
||||||
'You must provide a hotel_channel_server attribute with a '
|
'You must provide a channel_api attribute with a '
|
||||||
'WuBookServer instance to be able to use the '
|
'WuBookServer instance to be able to use the '
|
||||||
'Backend Adapter.'
|
'Backend Adapter.'
|
||||||
)
|
)
|
||||||
return (channel_server.session_token, channel_server.lcode)
|
return (channel_server.session_token, channel_server._login_data.lcode)
|
||||||
|
|
||||||
class WuBookAdapter(AbstractComponent):
|
class WuBookAdapter(AbstractComponent):
|
||||||
_name = 'wubook.adapter'
|
_name = 'wubook.adapter'
|
||||||
@@ -220,7 +223,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
# rtype=('name' in vals and vals['name'] and 3) or 1
|
# rtype=('name' in vals and vals['name'] and 3) or 1
|
||||||
)
|
)
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't create room in WuBook"), {
|
raise ChannelConnectorError("Can't create room in WuBook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
})
|
})
|
||||||
return results
|
return results
|
||||||
@@ -239,7 +242,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
# rtype=('name' in vals and vals['name'] and 3) or 1
|
# rtype=('name' in vals and vals['name'] and 3) or 1
|
||||||
)
|
)
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't modify room in WuBook"), {
|
raise ChannelConnectorError("Can't modify room in WuBook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
'channel_id': channel_room_id,
|
'channel_id': channel_room_id,
|
||||||
})
|
})
|
||||||
@@ -251,7 +254,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
self._session_info[1],
|
self._session_info[1],
|
||||||
channel_room_id)
|
channel_room_id)
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't delete room in WuBook"), {
|
raise ChannelConnectorError("Can't delete room in WuBook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
'channel_id': channel_room_id,
|
'channel_id': channel_room_id,
|
||||||
})
|
})
|
||||||
@@ -263,7 +266,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
self._session_info[1],
|
self._session_info[1],
|
||||||
channel_room_id)
|
channel_room_id)
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't fetch room values from WuBook"), {
|
raise ChannelConnectorError("Can't fetch room values from WuBook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
'channel_id': channel_room_id,
|
'channel_id': channel_room_id,
|
||||||
})
|
})
|
||||||
@@ -277,7 +280,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
date_utils.get_datetime(date_to).strftime(DEFAULT_WUBOOK_DATE_FORMAT),
|
date_utils.get_datetime(date_to).strftime(DEFAULT_WUBOOK_DATE_FORMAT),
|
||||||
rooms)
|
rooms)
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't fetch rooms values from WuBook"), {
|
raise ChannelConnectorError("Can't fetch rooms values from WuBook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
})
|
})
|
||||||
return results
|
return results
|
||||||
@@ -288,7 +291,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
self._session_info[1],
|
self._session_info[1],
|
||||||
rooms_avail)
|
rooms_avail)
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't update rooms availability in WuBook"), {
|
raise ChannelConnectorError("Can't update rooms availability in WuBook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
})
|
})
|
||||||
return results
|
return results
|
||||||
@@ -296,7 +299,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
def corporate_fetch(self):
|
def corporate_fetch(self):
|
||||||
rcode, results = self._server.corporate_fetchable_properties(self.TOKEN)
|
rcode, results = self._server.corporate_fetchable_properties(self.TOKEN)
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't call 'corporate_fetch' from WuBook"), {
|
raise ChannelConnectorError("Can't call 'corporate_fetch' from WuBook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
})
|
})
|
||||||
return results
|
return results
|
||||||
@@ -326,7 +329,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
customer,
|
customer,
|
||||||
adults+children)
|
adults+children)
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't create reservations in wubook"), {
|
raise ChannelConnectorError("Can't create reservations in wubook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
'date_from': checkin,
|
'date_from': checkin,
|
||||||
'date_to': checkout,
|
'date_to': checkout,
|
||||||
@@ -340,7 +343,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
channel_reservation_id,
|
channel_reservation_id,
|
||||||
reason)
|
reason)
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't cancel reservation in WuBook"), {
|
raise ChannelConnectorError("Can't cancel reservation in WuBook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
'channel_reservation_id': channel_reservation_id,
|
'channel_reservation_id': channel_reservation_id,
|
||||||
})
|
})
|
||||||
@@ -353,7 +356,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
1,
|
1,
|
||||||
0)
|
0)
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't process reservations from wubook"), {
|
raise ChannelConnectorError("Can't process reservations from wubook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
})
|
})
|
||||||
return results
|
return results
|
||||||
@@ -364,7 +367,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
self._session_info[1],
|
self._session_info[1],
|
||||||
channel_reservation_id)
|
channel_reservation_id)
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't process reservation from wubook"), {
|
raise ChannelConnectorError("Can't process reservation from wubook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
})
|
})
|
||||||
return results
|
return results
|
||||||
@@ -379,7 +382,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
self._session_info[1],
|
self._session_info[1],
|
||||||
channel_reservation_ids)
|
channel_reservation_ids)
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't mark as readed a reservation in wubook"), {
|
raise ChannelConnectorError("Can't mark as readed a reservation in wubook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
'channel_reservation_ids': str(channel_reservation_ids),
|
'channel_reservation_ids': str(channel_reservation_ids),
|
||||||
})
|
})
|
||||||
@@ -393,7 +396,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
name,
|
name,
|
||||||
daily)
|
daily)
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't add pricing plan to wubook"), {
|
raise ChannelConnectorError("Can't add pricing plan to wubook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
})
|
})
|
||||||
return results
|
return results
|
||||||
@@ -404,7 +407,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
self._session_info[1],
|
self._session_info[1],
|
||||||
channel_plan_id)
|
channel_plan_id)
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't delete pricing plan from wubook"), {
|
raise ChannelConnectorError("Can't delete pricing plan from wubook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
'channel_plan_id': channel_plan_id,
|
'channel_plan_id': channel_plan_id,
|
||||||
})
|
})
|
||||||
@@ -417,7 +420,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
channel_plan_id,
|
channel_plan_id,
|
||||||
new_name)
|
new_name)
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't update pricing plan name in wubook"), {
|
raise ChannelConnectorError("Can't update pricing plan name in wubook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
'channel_plan_id': channel_plan_id,
|
'channel_plan_id': channel_plan_id,
|
||||||
})
|
})
|
||||||
@@ -431,7 +434,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
date_utils.get_datetime(date_from).strftime(DEFAULT_WUBOOK_DATE_FORMAT),
|
date_utils.get_datetime(date_from).strftime(DEFAULT_WUBOOK_DATE_FORMAT),
|
||||||
prices)
|
prices)
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't update pricing plan in wubook"), {
|
raise ChannelConnectorError("Can't update pricing plan in wubook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
'channel_plan_id': channel_plan_id,
|
'channel_plan_id': channel_plan_id,
|
||||||
'date_from': date_from,
|
'date_from': date_from,
|
||||||
@@ -445,7 +448,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
channel_plan_id,
|
channel_plan_id,
|
||||||
periods)
|
periods)
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't update pricing plan period in wubook"), {
|
raise ChannelConnectorError("Can't update pricing plan period in wubook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
'channel_plan_id': channel_plan_id,
|
'channel_plan_id': channel_plan_id,
|
||||||
})
|
})
|
||||||
@@ -456,7 +459,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
self._session_info[0],
|
self._session_info[0],
|
||||||
self._session_info[1])
|
self._session_info[1])
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't get pricing plans from wubook"), {
|
raise ChannelConnectorError("Can't get pricing plans from wubook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
})
|
})
|
||||||
return results
|
return results
|
||||||
@@ -470,7 +473,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
date_utils(date_to).strftime(DEFAULT_WUBOOK_DATE_FORMAT),
|
date_utils(date_to).strftime(DEFAULT_WUBOOK_DATE_FORMAT),
|
||||||
rooms or [])
|
rooms or [])
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't get pricing plans from wubook"), {
|
raise ChannelConnectorError("Can't get pricing plans from wubook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
'channel_plan_id': channel_plan_id,
|
'channel_plan_id': channel_plan_id,
|
||||||
'date_from': date_from,
|
'date_from': date_from,
|
||||||
@@ -484,7 +487,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
self._session_info[0],
|
self._session_info[0],
|
||||||
self._session_info[1])
|
self._session_info[1])
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't fetch restriction plans from wubook"), {
|
raise ChannelConnectorError("Can't fetch restriction plans from wubook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
})
|
})
|
||||||
return results
|
return results
|
||||||
@@ -497,7 +500,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
date_utils(date_to).strftime(DEFAULT_WUBOOK_DATE_FORMAT),
|
date_utils(date_to).strftime(DEFAULT_WUBOOK_DATE_FORMAT),
|
||||||
channel_restriction_plan_id)
|
channel_restriction_plan_id)
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't fetch restriction plans from wubook"), {
|
raise ChannelConnectorError("Can't fetch restriction plans from wubook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
'channel_restriction_plan_id': channel_restriction_plan_id,
|
'channel_restriction_plan_id': channel_restriction_plan_id,
|
||||||
'date_from': date_from,
|
'date_from': date_from,
|
||||||
@@ -513,7 +516,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
date_utils(date_from).strftime(DEFAULT_WUBOOK_DATE_FORMAT),
|
date_utils(date_from).strftime(DEFAULT_WUBOOK_DATE_FORMAT),
|
||||||
values)
|
values)
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't update plan restrictions on wubook"), {
|
raise ChannelConnectorError("Can't update plan restrictions on wubook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
'channel_restriction_plan_id': channel_restriction_plan_id,
|
'channel_restriction_plan_id': channel_restriction_plan_id,
|
||||||
'date_from': date_from,
|
'date_from': date_from,
|
||||||
@@ -527,7 +530,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
name,
|
name,
|
||||||
compact and 1 or 0)
|
compact and 1 or 0)
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't create plan restriction in wubook"), {
|
raise ChannelConnectorError("Can't create plan restriction in wubook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
})
|
})
|
||||||
return results
|
return results
|
||||||
@@ -539,7 +542,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
channel_restriction_plan_id,
|
channel_restriction_plan_id,
|
||||||
new_name)
|
new_name)
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't rename plan restriction in wubook"), {
|
raise ChannelConnectorError("Can't rename plan restriction in wubook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
'channel_restriction_plan_id': channel_restriction_plan_id,
|
'channel_restriction_plan_id': channel_restriction_plan_id,
|
||||||
})
|
})
|
||||||
@@ -551,7 +554,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
self._session_info[1],
|
self._session_info[1],
|
||||||
channel_restriction_plan_id)
|
channel_restriction_plan_id)
|
||||||
if rcode != 0:
|
if rcode != 0:
|
||||||
raise ValidationError(_("Can't delete plan restriction on wubook"), {
|
raise ChannelConnectorError("Can't delete plan restriction on wubook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
'channel_restriction_plan_id': channel_restriction_plan_id,
|
'channel_restriction_plan_id': channel_restriction_plan_id,
|
||||||
})
|
})
|
||||||
@@ -560,7 +563,7 @@ class WuBookAdapter(AbstractComponent):
|
|||||||
def get_channels_info(self):
|
def get_channels_info(self):
|
||||||
results = self._server.get_channels_info(self._session_info[0])
|
results = self._server.get_channels_info(self._session_info[0])
|
||||||
if not any(results):
|
if not any(results):
|
||||||
raise ValidationError(_("Can't import channels info from wubook"), {
|
raise ChannelConnectorError("Can't import channels info from wubook", {
|
||||||
'message': results,
|
'message': results,
|
||||||
})
|
})
|
||||||
return results
|
return results
|
||||||
|
|||||||
@@ -20,3 +20,8 @@ class BaseHotelChannelConnectorComponent(AbstractComponent):
|
|||||||
'date_start': dfrom,
|
'date_start': dfrom,
|
||||||
'date_end': dto,
|
'date_end': dto,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
class ChannelConnectorError(Exception):
|
||||||
|
def __init__(self, message, data):
|
||||||
|
super().__init__(message)
|
||||||
|
self.data = data
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import json
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from odoo.exceptions import ValidationError
|
from odoo.exceptions import ValidationError
|
||||||
from odoo.addons.component.core import AbstractComponent, Component
|
from odoo.addons.component.core import AbstractComponent, Component
|
||||||
|
from odoo.addons.hotel_channel_connector.components.core import ChannelConnectorError
|
||||||
from odoo.addons.hotel import date_utils
|
from odoo.addons.hotel import date_utils
|
||||||
from odoo import _
|
from odoo import _
|
||||||
from odoo.tools import (
|
from odoo.tools import (
|
||||||
@@ -130,7 +131,7 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _generate_booking_vals(self, broom, checkin_str, checkout_str,
|
def _generate_booking_vals(self, broom, checkin_str, checkout_str,
|
||||||
is_cancellation, wchannel_info, wstatus, crcode,
|
is_cancellation, channel_info, wstatus, crcode,
|
||||||
rcode, room_type, split_booking, dates_checkin,
|
rcode, room_type, split_booking, dates_checkin,
|
||||||
dates_checkout, book):
|
dates_checkout, book):
|
||||||
# Generate Reservation Day Lines
|
# Generate Reservation Day Lines
|
||||||
@@ -154,24 +155,27 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
persons = room_type.wcapacity
|
persons = room_type.wcapacity
|
||||||
if 'ancillary' in broom and 'guests' in broom['ancillary']:
|
if 'ancillary' in broom and 'guests' in broom['ancillary']:
|
||||||
persons = broom['ancillary']['guests']
|
persons = broom['ancillary']['guests']
|
||||||
|
|
||||||
vals = {
|
vals = {
|
||||||
'checkin': checkin_str,
|
'channel_reservation_id': rcode,
|
||||||
'checkout': checkout_str,
|
'ota_id': channel_info and channel_info.id,
|
||||||
'adults': persons,
|
'ota_reservation_id': crcode,
|
||||||
'children': book['children'],
|
'channel_raw_data': json.dumps(book),
|
||||||
'reservation_line_ids': reservation_line_ids,
|
|
||||||
'price_unit': tprice,
|
|
||||||
'to_assign': True,
|
|
||||||
'wrid': rcode,
|
|
||||||
'wchannel_id': wchannel_info and wchannel_info.id,
|
|
||||||
'wchannel_reservation_code': crcode,
|
|
||||||
'wstatus': wstatus,
|
'wstatus': wstatus,
|
||||||
'to_read': True,
|
'wmodified': book['was_modified'],
|
||||||
'state': is_cancellation and 'cancelled' or 'draft',
|
'odoo_id': [0, False, {
|
||||||
'room_type_id': room_type.id,
|
'checkin': checkin_str,
|
||||||
'splitted': split_booking,
|
'checkout': checkout_str,
|
||||||
'wbook_json': json.dumps(book),
|
'adults': persons,
|
||||||
'wmodified': book['was_modified']
|
'children': book['children'],
|
||||||
|
'reservation_line_ids': reservation_line_ids,
|
||||||
|
'price_unit': tprice,
|
||||||
|
'to_assign': True,
|
||||||
|
'to_read': True,
|
||||||
|
'state': is_cancellation and 'cancelled' or 'draft',
|
||||||
|
'room_type_id': room_type.id,
|
||||||
|
'splitted': split_booking,
|
||||||
|
}],
|
||||||
}
|
}
|
||||||
_logger.info("===== CONTRUCT RESERV")
|
_logger.info("===== CONTRUCT RESERV")
|
||||||
_logger.info(vals)
|
_logger.info(vals)
|
||||||
@@ -210,8 +214,10 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
tz_hotel = self.env['ir.default'].sudo().get(
|
tz_hotel = self.env['ir.default'].sudo().get(
|
||||||
'res.config.settings', 'tz_hotel')
|
'res.config.settings', 'tz_hotel')
|
||||||
res_partner_obj = self.env['res.partner']
|
res_partner_obj = self.env['res.partner']
|
||||||
|
channel_reserv_obj = self.env['channel.hotel.reservation']
|
||||||
hotel_reserv_obj = self.env['hotel.reservation']
|
hotel_reserv_obj = self.env['hotel.reservation']
|
||||||
hotel_folio_obj = self.env['hotel.folio']
|
hotel_folio_obj = self.env['hotel.folio']
|
||||||
|
channel_room_type_obj = self.env['channel.hotel.room.type']
|
||||||
hotel_room_type_obj = self.env['hotel.room.type']
|
hotel_room_type_obj = self.env['hotel.room.type']
|
||||||
# Space for store some data for construct folios
|
# Space for store some data for construct folios
|
||||||
processed_rids = []
|
processed_rids = []
|
||||||
@@ -231,10 +237,10 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
# (for example set a invalid new reservation and receive in
|
# (for example set a invalid new reservation and receive in
|
||||||
# the same transaction an cancellation)
|
# the same transaction an cancellation)
|
||||||
if crcode in failed_reservations:
|
if crcode in failed_reservations:
|
||||||
self.create_channel_connector_issue(
|
self.create_issue(
|
||||||
'reservation',
|
'reservation',
|
||||||
"Can't process a reservation that previusly failed!",
|
"Can't process a reservation that previusly failed!",
|
||||||
'', wid=book['reservation_code'])
|
'', channel_object_id=book['reservation_code'])
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Get dates for the reservation (GMT->UTC)
|
# Get dates for the reservation (GMT->UTC)
|
||||||
@@ -260,34 +266,37 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
# Search Folio. If exists.
|
# Search Folio. If exists.
|
||||||
folio_id = False
|
folio_id = False
|
||||||
if crcode != 'undefined':
|
if crcode != 'undefined':
|
||||||
reserv_folio = hotel_reserv_obj.search([
|
reserv_folio = channel_reserv_obj.search([
|
||||||
('wchannel_reservation_code', '=', crcode)
|
('ota_reservation_id', '=', crcode)
|
||||||
], limit=1)
|
], limit=1)
|
||||||
if reserv_folio:
|
if reserv_folio:
|
||||||
folio_id = reserv_folio.folio_id
|
folio_id = reserv_folio.odoo_id.folio_id
|
||||||
else:
|
else:
|
||||||
reserv_folio = hotel_reserv_obj.search([
|
reserv_folio = channel_reserv_obj.search([
|
||||||
('wrid', '=', rcode)
|
('channel_reservation_id', '=', rcode)
|
||||||
], limit=1)
|
], limit=1)
|
||||||
if reserv_folio:
|
if reserv_folio:
|
||||||
folio_id = reserv_folio.folio_id
|
folio_id = reserv_folio.odoo_id.folio_id
|
||||||
|
|
||||||
# Need update reservations?
|
# Need update reservations?
|
||||||
sreservs = hotel_reserv_obj.search([('wrid', '=', rcode)])
|
sreservs = channel_reserv_obj.search([('channel_reservation_id', '=', rcode)])
|
||||||
reservs = folio_id.room_lines if folio_id else sreservs
|
reservs = folio_id.room_lines if folio_id else sreservs.mapped(lambda x: x.odoo_id)
|
||||||
reservs_processed = False
|
reservs_processed = False
|
||||||
if any(reservs):
|
if any(reservs):
|
||||||
folio_id = reservs[0].folio_id
|
folio_id = reservs[0].folio_id
|
||||||
for reserv in reservs:
|
for reserv in reservs:
|
||||||
if reserv.wrid == rcode:
|
if reserv.channel_reservation_id == rcode:
|
||||||
reserv.with_context({'wubook_action': False}).write({
|
binding_id = reserv.channel_bind_ids[0]
|
||||||
|
binding_id.write({
|
||||||
|
'channel_raw_data': json.dumps(book),
|
||||||
'wstatus': str(book['status']),
|
'wstatus': str(book['status']),
|
||||||
'wstatus_reason': book.get('status_reason', ''),
|
'wstatus_reason': book.get('status_reason', ''),
|
||||||
|
})
|
||||||
|
reserv.with_context({'wubook_action': False}).write({
|
||||||
'to_read': True,
|
'to_read': True,
|
||||||
'to_assign': True,
|
'to_assign': True,
|
||||||
'price_unit': book['amount'],
|
'price_unit': book['amount'],
|
||||||
'wcustomer_notes': book['customer_notes'],
|
'customer_notes': book['customer_notes'],
|
||||||
'wbook_json': json.dumps(book),
|
|
||||||
})
|
})
|
||||||
if reserv.partner_id.unconfirmed:
|
if reserv.partner_id.unconfirmed:
|
||||||
reserv.partner_id.write(
|
reserv.partner_id.write(
|
||||||
@@ -321,22 +330,22 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
partner_id = res_partner_obj.create(self._generate_partner_vals(book))
|
partner_id = res_partner_obj.create(self._generate_partner_vals(book))
|
||||||
|
|
||||||
# Search Wubook Channel Info
|
# Search Wubook Channel Info
|
||||||
wchannel_info = self.env['wubook.channel.info'].search(
|
channel_info = self.env['hotel.channel.connector.ota.info'].search(
|
||||||
[('wid', '=', str(book['id_channel']))], limit=1)
|
[('ota_id', '=', str(book['id_channel']))], limit=1)
|
||||||
|
|
||||||
reservations = []
|
reservations = []
|
||||||
used_rooms = []
|
used_rooms = []
|
||||||
# Iterate booked rooms
|
# Iterate booked rooms
|
||||||
for broom in book['booked_rooms']:
|
for broom in book['booked_rooms']:
|
||||||
room_type = hotel_room_type_obj.search([
|
room_type = channel_room_type_obj.search([
|
||||||
('wrid', '=', broom['room_id'])
|
('channel_room_id', '=', broom['room_id'])
|
||||||
], limit=1)
|
], limit=1)
|
||||||
if not room_type:
|
if not room_type:
|
||||||
self.create_channel_connector_issue(
|
self.create_issue(
|
||||||
'reservation',
|
'reservation',
|
||||||
"Can't found any room type associated to '%s' \
|
"Can't found any room type associated to '%s' \
|
||||||
in this hotel" % book['rooms'],
|
in this hotel" % book['rooms'],
|
||||||
'', wid=book['reservation_code'])
|
'', channel_object_id=book['reservation_code'])
|
||||||
failed_reservations.append(crcode)
|
failed_reservations.append(crcode)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -355,26 +364,26 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
checkin_str,
|
checkin_str,
|
||||||
checkout_str,
|
checkout_str,
|
||||||
is_cancellation,
|
is_cancellation,
|
||||||
wchannel_info,
|
channel_info,
|
||||||
bstatus,
|
bstatus,
|
||||||
crcode,
|
crcode,
|
||||||
rcode,
|
rcode,
|
||||||
room_type,
|
room_type.odoo_id,
|
||||||
split_booking,
|
split_booking,
|
||||||
dates_checkin,
|
dates_checkin,
|
||||||
dates_checkout,
|
dates_checkout,
|
||||||
book,
|
book,
|
||||||
)
|
)
|
||||||
if vals['price_unit'] != book['amount']:
|
if vals['price_unit'] != book['amount']:
|
||||||
self.create_channel_connector_issue(
|
self.create_issue(
|
||||||
'reservation',
|
'reservation',
|
||||||
"Invalid reservation total price! %.2f != %.2f" % (vals['price_unit'], book['amount']),
|
"Invalid reservation total price! %.2f != %.2f" % (vals['price_unit'], book['amount']),
|
||||||
'', wid=book['reservation_code'])
|
'', channel_object_id=book['reservation_code'])
|
||||||
|
|
||||||
free_rooms = hotel_room_type_obj.check_availability_room(
|
free_rooms = room_type.odoo_id.check_availability_room(
|
||||||
checkin_str,
|
checkin_str,
|
||||||
checkout_str,
|
checkout_str,
|
||||||
room_type_id=room_type.id,
|
room_type_id=room_type.odoo_id.id,
|
||||||
notthis=used_rooms)
|
notthis=used_rooms)
|
||||||
if any(free_rooms):
|
if any(free_rooms):
|
||||||
vals.update({
|
vals.update({
|
||||||
@@ -412,11 +421,11 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
checkin_utc_dt,
|
checkin_utc_dt,
|
||||||
checkout_utc_dt,
|
checkout_utc_dt,
|
||||||
is_cancellation,
|
is_cancellation,
|
||||||
wchannel_info,
|
channel_info,
|
||||||
bstatus,
|
bstatus,
|
||||||
crcode,
|
crcode,
|
||||||
rcode,
|
rcode,
|
||||||
room_type,
|
room_type.odoo_id,
|
||||||
False,
|
False,
|
||||||
(checkin_utc_dt, False),
|
(checkin_utc_dt, False),
|
||||||
(checkout_utc_dt, False),
|
(checkout_utc_dt, False),
|
||||||
@@ -424,15 +433,15 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
)
|
)
|
||||||
vals.update({
|
vals.update({
|
||||||
'product_id':
|
'product_id':
|
||||||
room_type.room_ids[0].product_id.id,
|
room_type.odoo_id.room_ids[0].product_id.id,
|
||||||
'name': room_type.name,
|
'name': room_type.odoo_id.name,
|
||||||
'overbooking': True,
|
'overbooking': True,
|
||||||
})
|
})
|
||||||
reservations.append((0, False, vals))
|
reservations.append((0, False, vals))
|
||||||
self.create_channel_connector_issue(
|
self.create_issue(
|
||||||
'reservation',
|
'reservation',
|
||||||
"Reservation imported with overbooking state",
|
"Reservation imported with overbooking state",
|
||||||
'', wid=rcode)
|
'', channel_object_id=rcode)
|
||||||
dates_checkin = [False, False]
|
dates_checkin = [False, False]
|
||||||
dates_checkout = [False, False]
|
dates_checkout = [False, False]
|
||||||
split_booking = False
|
split_booking = False
|
||||||
@@ -448,10 +457,10 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
]
|
]
|
||||||
|
|
||||||
if split_booking:
|
if split_booking:
|
||||||
self.create_channel_connector_issue(
|
self.create_issue(
|
||||||
'reservation',
|
'reservation',
|
||||||
"Reservation Splitted",
|
"Reservation Splitted",
|
||||||
'', wid=rcode)
|
'', channel_object_id=rcode)
|
||||||
|
|
||||||
# Create Folio
|
# Create Folio
|
||||||
if not any(failed_reservations) and any(reservations):
|
if not any(failed_reservations) and any(reservations):
|
||||||
@@ -487,11 +496,11 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
creserv.parent_reservation = preserv.id
|
creserv.parent_reservation = preserv.id
|
||||||
|
|
||||||
processed_rids.append(rcode)
|
processed_rids.append(rcode)
|
||||||
except Exception as e_msg:
|
except ChannelConnectorError as err:
|
||||||
self.create_channel_connector_issue(
|
self.create_issue(
|
||||||
'reservation',
|
'reservation',
|
||||||
e_msg[0],
|
err.data['message'],
|
||||||
'', wid=rcode)
|
'', channel_object_id=rcode)
|
||||||
failed_reservations.append(crcode)
|
failed_reservations.append(crcode)
|
||||||
return (processed_rids, any(failed_reservations),
|
return (processed_rids, any(failed_reservations),
|
||||||
checkin_utc_dt, checkout_utc_dt)
|
checkin_utc_dt, checkout_utc_dt)
|
||||||
@@ -698,8 +707,8 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
room_type.with_context({'wubook_action': False}).write(vals)
|
room_type.with_context({'wubook_action': False}).write(vals)
|
||||||
else:
|
else:
|
||||||
room_type_obj.with_context({'wubook_action': False}).create(vals)
|
room_type_obj.with_context({'wubook_action': False}).create(vals)
|
||||||
except ValidationError:
|
except ChannelConnectorError as err:
|
||||||
self.create_issue('room', _("Can't import rooms from WuBook"), results)
|
self.create_issue('room', _("Can't import rooms from WuBook"), err.data['message'])
|
||||||
|
|
||||||
return count
|
return count
|
||||||
|
|
||||||
@@ -725,10 +734,10 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
dto_dt.strftime(DEFAULT_WUBOOK_DATE_FORMAT),
|
dto_dt.strftime(DEFAULT_WUBOOK_DATE_FORMAT),
|
||||||
rooms)
|
rooms)
|
||||||
self._generate_room_values(dfrom, dto, results,
|
self._generate_room_values(dfrom, dto, results,
|
||||||
set_max_avail=set_max_avail)
|
set_max_avail=set_max_avail)
|
||||||
except ValidationError:
|
except ChannelConnectorError as err:
|
||||||
self.create_issue('room', _("Can't fetch rooms values from WuBook"),
|
self.create_issue('room', _("Can't fetch rooms values from WuBook"),
|
||||||
results, dfrom=dfrom, dto=dto)
|
err.data['message'], dfrom=dfrom, dto=dto)
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -746,11 +755,11 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
self.backend_adapter.fetch_rooms_values(
|
self.backend_adapter.fetch_rooms_values(
|
||||||
checkin_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT),
|
checkin_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT),
|
||||||
checkout_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT))
|
checkout_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT))
|
||||||
except ValidationError:
|
except ChannelConnectorError as err:
|
||||||
self.create_channel_connector_issue(
|
self.create_issue(
|
||||||
'reservation',
|
'reservation',
|
||||||
_("Can't process reservations from wubook"),
|
_("Can't process reservations from wubook"),
|
||||||
results, channel_object_id=channel_reservation_id)
|
err.data['message'], channel_object_id=channel_reservation_id)
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -759,11 +768,11 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
try:
|
try:
|
||||||
results = self.backend_adapter.get_pricing_plans()
|
results = self.backend_adapter.get_pricing_plans()
|
||||||
count = self._generate_pricelists(results)
|
count = self._generate_pricelists(results)
|
||||||
except ValidationError:
|
except ChannelConnectorError as err:
|
||||||
self.create_issue(
|
self.create_issue(
|
||||||
'plan',
|
'plan',
|
||||||
_("Can't get pricing plans from wubook"),
|
_("Can't get pricing plans from wubook"),
|
||||||
results)
|
err.data['message'])
|
||||||
return 0
|
return 0
|
||||||
return count
|
return count
|
||||||
|
|
||||||
@@ -776,11 +785,11 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
date_to,
|
date_to,
|
||||||
rooms)
|
rooms)
|
||||||
self._generate_pricelist_items(channel_plan_id, date_from, date_to, results)
|
self._generate_pricelist_items(channel_plan_id, date_from, date_to, results)
|
||||||
except ValidationError:
|
except ChannelConnectorError as err:
|
||||||
self.create_issue(
|
self.create_issue(
|
||||||
'plan',
|
'plan',
|
||||||
_("Can't fetch plan prices from wubook"),
|
_("Can't fetch plan prices from wubook"),
|
||||||
results)
|
err.data['message'])
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -799,11 +808,12 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
date_to,
|
date_to,
|
||||||
rooms)
|
rooms)
|
||||||
self._generate_pricelist_items(channel_plan_id, date_from, date_to, results)
|
self._generate_pricelist_items(channel_plan_id, date_from, date_to, results)
|
||||||
except ValidationError:
|
except ChannelConnectorError as err:
|
||||||
self.create_issue(
|
self.create_issue(
|
||||||
'plan',
|
'plan',
|
||||||
"Can't fetch all plan prices from wubook!",
|
"Can't fetch all plan prices from wubook!",
|
||||||
results, wid=channel_plan_id, dfrom=date_from, dto=date_to)
|
err.data['message'],
|
||||||
|
channel_object_id=channel_plan_id, dfrom=date_from, dto=date_to)
|
||||||
return False
|
return False
|
||||||
return no_errors
|
return no_errors
|
||||||
|
|
||||||
@@ -812,11 +822,11 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
try:
|
try:
|
||||||
results = self.backend_adapter.rplan_rplans()
|
results = self.backend_adapter.rplan_rplans()
|
||||||
count = self._generate_restrictions(results)
|
count = self._generate_restrictions(results)
|
||||||
except ValidationError:
|
except ChannelConnectorError as err:
|
||||||
self.create_issue(
|
self.create_issue(
|
||||||
'rplan',
|
'rplan',
|
||||||
_("Can't fetch restriction plans from wubook"),
|
_("Can't fetch restriction plans from wubook"),
|
||||||
results)
|
err.data['message'])
|
||||||
return 0
|
return 0
|
||||||
return count
|
return count
|
||||||
|
|
||||||
@@ -829,12 +839,12 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
int(channel_restriction_plan_id))
|
int(channel_restriction_plan_id))
|
||||||
if any(results):
|
if any(results):
|
||||||
self._generate_restriction_items(results)
|
self._generate_restriction_items(results)
|
||||||
except ValidationError:
|
except ChannelConnectorError as err:
|
||||||
self.create_issue(
|
self.create_issue(
|
||||||
'rplan',
|
'rplan',
|
||||||
_("Can't fetch plan restrictions from wubook"),
|
_("Can't fetch plan restrictions from wubook"),
|
||||||
results,
|
err.data['message'],
|
||||||
wid=channel_restriction_plan_id,
|
channel_object_id=channel_restriction_plan_id,
|
||||||
dfrom=date_from, dto=date_to)
|
dfrom=date_from, dto=date_to)
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
@@ -844,10 +854,10 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
try:
|
try:
|
||||||
results = self.backend_adapter.get_channels_info()
|
results = self.backend_adapter.get_channels_info()
|
||||||
count = self._generate_wubook_channel_info(results)
|
count = self._generate_wubook_channel_info(results)
|
||||||
except ValidationError:
|
except ChannelConnectorError as err:
|
||||||
self.create_issue(
|
self.create_issue(
|
||||||
'channel',
|
'channel',
|
||||||
_("Can't import channels info from wubook"),
|
_("Can't import channels info from wubook"),
|
||||||
results)
|
err.data['message'])
|
||||||
return 0
|
return 0
|
||||||
return count
|
return count
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
from odoo.exceptions import ValidationError
|
from odoo.exceptions import ValidationError
|
||||||
from odoo.addons.component.core import Component
|
from odoo.addons.component.core import Component
|
||||||
|
from odoo.addons.hotel_channel_connector.components.core import ChannelConnectorError
|
||||||
from odoo import fields, api, _
|
from odoo import fields, api, _
|
||||||
from odoo.tools import (
|
from odoo.tools import (
|
||||||
DEFAULT_SERVER_DATE_FORMAT,
|
DEFAULT_SERVER_DATE_FORMAT,
|
||||||
@@ -34,10 +35,10 @@ class HotelReservationImporter(Component):
|
|||||||
self.backend_adapter.fetch_rooms_values(
|
self.backend_adapter.fetch_rooms_values(
|
||||||
checkin_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT),
|
checkin_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT),
|
||||||
checkout_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT))
|
checkout_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT))
|
||||||
except ValidationError:
|
except ChannelConnectorError as err:
|
||||||
self.create_issue(
|
self.create_issue(
|
||||||
'reservation',
|
'reservation',
|
||||||
_("Can't process reservations from wubook"),
|
_("Can't process reservations from wubook"),
|
||||||
results)
|
err.data['message'])
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -21,9 +21,10 @@
|
|||||||
<notebook>
|
<notebook>
|
||||||
<page string="API" name="api">
|
<page string="API" name="api">
|
||||||
<group colspan="4" col="4">
|
<group colspan="4" col="4">
|
||||||
<field name="version" colspan="4"/>
|
<field name="version" colspan="2"/>
|
||||||
<field name="server" colspan="2"/>
|
<field name="server" colspan="2"/>
|
||||||
<field name="lcode" colspan="2"/>
|
<field name="lcode" colspan="2"/>
|
||||||
|
<field name="pkey" colspan="2"/>
|
||||||
<field name="username" colspan="2"/>
|
<field name="username" colspan="2"/>
|
||||||
<field name="passwd" password="1" colspan="2"/>
|
<field name="passwd" password="1" colspan="2"/>
|
||||||
</group>
|
</group>
|
||||||
|
|||||||
Reference in New Issue
Block a user