-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ Calendar colors
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hotel_channel_connector/__manifest__.py b/hotel_channel_connector/__manifest__.py
index 77b4d51f9..b478791b1 100644
--- a/hotel_channel_connector/__manifest__.py
+++ b/hotel_channel_connector/__manifest__.py
@@ -22,6 +22,7 @@
'wizard/wubook_import_plan_restrictions.xml',
'wizard/wubook_import_availability.xml',
'views/general.xml',
+ 'views/hotel_channel_connector_issue_views.xml',
'views/inherited_hotel_reservation_views.xml',
'views/inherited_hotel_room_type_views.xml',
'views/inherited_hotel_room_type_availability_views.xml',
@@ -32,11 +33,11 @@
'views/inherited_hotel_room_type_restriction_item_views.xml',
'views/inherited_res_partner_views.xml',
'views/channel_ota_info_views.xml',
- 'views/hotel_channel_connector_issue_views.xml',
'views/channel_hotel_reservation_views.xml',
'views/channel_hotel_room_type_views.xml',
'views/channel_hotel_room_type_availability_views.xml',
'views/channel_hotel_room_type_restriction_views.xml',
+ 'views/channel_hotel_room_type_restriction_item_views.xml',
'views/channel_product_pricelist_views.xml',
'views/channel_product_pricelist_item_views.xml',
'views/channel_connector_backend_views.xml',
diff --git a/hotel_channel_connector/components/backend_adapter.py b/hotel_channel_connector/components/backend_adapter.py
index 930b1dd92..07d2058ba 100644
--- a/hotel_channel_connector/components/backend_adapter.py
+++ b/hotel_channel_connector/components/backend_adapter.py
@@ -441,7 +441,7 @@ class WuBookAdapter(AbstractComponent):
return results
def update_plan_periods(self, channel_plan_id, periods):
- rcode, results = self.SERVER.update_plan_periods(
+ rcode, results = self._server.update_plan_periods(
self._session_info[0],
self._session_info[1],
channel_plan_id,
@@ -454,7 +454,7 @@ class WuBookAdapter(AbstractComponent):
return results
def get_pricing_plans(self):
- rcode, results = self.SERVER.get_pricing_plans(
+ rcode, results = self._server.get_pricing_plans(
self._session_info[0],
self._session_info[1])
if rcode != 0:
diff --git a/hotel_channel_connector/models/channel_backend/common.py b/hotel_channel_connector/models/channel_backend/common.py
index 1901bfb36..32feb4c9a 100644
--- a/hotel_channel_connector/models/channel_backend/common.py
+++ b/hotel_channel_connector/models/channel_backend/common.py
@@ -39,6 +39,11 @@ class ChannelBackend(models.Model):
restriction_id = fields.Many2one('channel.hotel.room.type.restriction',
'Channel Restriction')
+ pricelist_from = fields.Date('Pricelist From')
+ pricelist_to = fields.Date('Pricelist To')
+ pricelist_id = fields.Many2one('channel.product.pricelist',
+ 'Channel Product Pricelist')
+
issue_ids = fields.One2many('hotel.channel.connector.issue',
'backend_id',
string='Issues',
@@ -98,6 +103,20 @@ class ChannelBackend(models.Model):
channel_hotel_restr_item_obj.import_restriction_values(backend)
return True
+ @api.multi
+ def push_restriction(self):
+ channel_hotel_restr_item_obj = self.env['channel.hotel.room.type.restriction.item']
+ for backend in self:
+ channel_hotel_restr_item_obj.push_restriction(backend)
+ return True
+
+ @api.multi
+ def import_pricelist_plans(self):
+ channel_product_pricelist_obj = self.env['channel.product.pricelist']
+ for backend in self:
+ channel_product_pricelist_obj.import_price_plans(backend)
+ return True
+
@contextmanager
@api.multi
def work_on(self, model_name, **kwargs):
diff --git a/hotel_channel_connector/models/hotel_channel_connector_issue.py b/hotel_channel_connector/models/hotel_channel_connector_issue.py
index fba387289..e9cba78b0 100644
--- a/hotel_channel_connector/models/hotel_channel_connector_issue.py
+++ b/hotel_channel_connector/models/hotel_channel_connector_issue.py
@@ -11,6 +11,7 @@ class HotelChannelConnectorIssue(models.Model):
backend_id = fields.Many2one('channel.backend',
'Restriction Plan',
+ required=True,
ondelete='cascade',
index=True)
@@ -46,10 +47,9 @@ class HotelChannelConnectorIssue(models.Model):
reserv_ids.append(record.channel_object_id)
record.to_read = False
if any(reserv_ids):
- res = self.env['hotel.channel.connector'].mark_bookings(reserv_ids)
- if not res:
- raise ValidationError(
- ("Can't mark reservation as readed in Channel!"))
+ with self.backend_id.work_on('channel.hotel.reservation') as work:
+ exporter = work.component(usage='hotel.reservation.exporter')
+ return exporter.mark_bookings(reserv_ids)
@api.model
def _needaction_domain_get(self):
diff --git a/hotel_channel_connector/models/hotel_room_type/common.py b/hotel_channel_connector/models/hotel_room_type/common.py
index ca490e8dd..fb2a84ec7 100644
--- a/hotel_channel_connector/models/hotel_room_type/common.py
+++ b/hotel_channel_connector/models/hotel_room_type/common.py
@@ -101,9 +101,7 @@ class HotelRoomType(models.Model):
self._compute_capacity()
@api.multi
- def get_restrictions(self, date):
- restriction_plan_id = int(self.env['ir.default'].sudo().get(
- 'res.config.settings', 'parity_restrictions_id'))
+ def get_restrictions(self, date, restriction_plan_id):
self.ensure_one()
restriction = self.env['hotel.room.type.restriction.item'].search([
('date', '=', date),
@@ -141,7 +139,9 @@ class BindingHotelRoomTypeListener(Component):
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
def on_record_write(self, record, fields=None):
- if any(record.channel_bind_ids) and 'name' in fields or 'list_price' in fields:
+ if any(record.channel_bind_ids) and 'name' in fields or 'list_price' in fields or \
+ 'room_ids' in fields:
+ # FIXME: Supossed that only exists one channel connector per record
record.channel_bind_ids[0].modify_room()
# @skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
diff --git a/hotel_channel_connector/models/hotel_room_type/importer.py b/hotel_channel_connector/models/hotel_room_type/importer.py
index 9a471dcd3..185ea9acf 100644
--- a/hotel_channel_connector/models/hotel_room_type/importer.py
+++ b/hotel_channel_connector/models/hotel_room_type/importer.py
@@ -165,7 +165,7 @@ class HotelRoomTypeImportMapper(Component):
_apply_on = 'channel.hotel.room.type'
direct = [
- ('id', 'externa_id'),
+ ('id', 'external_id'),
('shortname', 'channel_short_code'),
('occupancy', 'ota_capacity'),
('price', 'list_price'),
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 7210008e6..9a4f78e87 100644
--- a/hotel_channel_connector/models/hotel_room_type_availability/common.py
+++ b/hotel_channel_connector/models/hotel_room_type_availability/common.py
@@ -164,14 +164,22 @@ class BindingHotelRoomTypeAvailabilityListener(Component):
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
def on_record_write(self, record, fields=None):
if 'avail' in fields:
- for binding in record.channel_bind_ids:
- binding.channel_pushed = False
+ record.channel_bind_ids.write({'channel_pushed': False})
class ChannelBindingHotelRoomTypeAvailabilityListener(Component):
_name = 'channel.binding.hotel.room.type.availability.listener'
_inherit = 'base.connector.listener'
_apply_on = ['channel.hotel.room.type.availability']
+ @skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
+ def on_record_create(self, record, fields=None):
+ record.channel_pushed = False
+
+ @skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
+ def on_record_write(self, record, fields=None):
+ if 'avail' in fields:
+ record.channel_pushed = False
+
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
def on_fix_channel_availability(self, record, fields=None):
- record.with_delay(priority=20).update_availability()
+ record.update_availability()
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 8eb17c2fc..589d7d27a 100644
--- a/hotel_channel_connector/models/hotel_room_type_availability/exporter.py
+++ b/hotel_channel_connector/models/hotel_room_type_availability/exporter.py
@@ -20,7 +20,7 @@ class HotelRoomTypeAvailabilityExporter(Component):
if any(binding.room_type_id.channel_bind_ids):
try:
sday_dt = fields.Date.from_string(binding.date)
- # Supossed that only exists one channel connector per record
+ # 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,
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 a328904bf..ac687dbca 100644
--- a/hotel_channel_connector/models/hotel_room_type_restriction/importer.py
+++ b/hotel_channel_connector/models/hotel_room_type_restriction/importer.py
@@ -35,15 +35,15 @@ class HotelRoomTypeRestrictionImporter(Component):
channel_restriction_obj.with_context({
'wubook_action': False,
'rules': plan.get('rules'),
- }).create(plan_record.values())
+ }).create(plan_record.values(for_create=True))
else:
plan_bind.with_context({'wubook_action': False}).write(
- plan_record.values(for_create=True))
+ plan_record.values())
count = count + 1
except ChannelConnectorError as err:
self.create_issue(
backend=self.backend_adapter.id,
- section='rplan',
+ section='restriction',
internal_message=_("Can't fetch restriction plans from wubook"),
channel_message=err.data['message'])
return count
diff --git a/hotel_channel_connector/models/hotel_room_type_restriction_item/__init__.py b/hotel_channel_connector/models/hotel_room_type_restriction_item/__init__.py
index 06e54858b..fe02f8e98 100644
--- a/hotel_channel_connector/models/hotel_room_type_restriction_item/__init__.py
+++ b/hotel_channel_connector/models/hotel_room_type_restriction_item/__init__.py
@@ -3,3 +3,4 @@
from . import common
from . import importer
+from . import exporter
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 c01c39197..5377b8cef 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
@@ -20,12 +20,6 @@ class ChannelHotelRoomTypeRestrictionItem(models.Model):
channel_pushed = fields.Boolean("Channel Pushed", readonly=True, default=False,
old_name='wpushed')
- @job(default_channel='root.channel')
- @api.multi
- def update_channel_pushed(self, status):
- self.ensure_one()
- self.channel_pushed = status
-
@job(default_channel='root.channel')
@api.model
def import_restriction_values(self, backend):
@@ -36,6 +30,13 @@ class ChannelHotelRoomTypeRestrictionItem(models.Model):
backend.restriction_to,
channel_restr_id=backend.restriction_id)
+ @job(default_channel='root.channel')
+ @api.model
+ def push_restriction(self, backend):
+ with backend.work_on(self._name) as work:
+ exporter = work.component(usage='hotel.room.type.restriction.item.exporter')
+ return exporter.push_restriction()
+
class HotelRoomTypeRestrictionItem(models.Model):
_inherit = 'hotel.room.type.restriction.item'
@@ -55,15 +56,34 @@ class HotelRoomTypeRestrictionItemAdapter(Component):
date_to,
channel_restriction_plan_id)
-class ChannelBindingHotelRoomTypeRestrictionItemListener(Component):
- _name = 'channel.binding.hotel.room.type.restriction.item.listener'
+class BindingHotelRoomTypeRestrictionItemListener(Component):
+ _name = 'binding.hotel.room.type.restriction.item.listener'
_inherit = 'base.connector.listener'
- _apply_on = ['channel.hotel.room.type.restriction']
-
- @skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
- def on_record_create(self, record, fields=None):
- return True
+ _apply_on = ['hotel.room.type.restriction.item']
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
def on_record_write(self, record, fields=None):
- return True
+ fields_to_check = ('min_stay', 'min_stay_arrival', 'max_stay', 'max_stay_arrival',
+ 'max_stay_arrival', 'closed', 'closed_departure', 'closed_arrival',
+ 'date')
+ fields_checked = [elm for elm in fields_to_check if elm in fields]
+ if any(fields_checked):
+ record.channel_bind_ids.write({'channel_pushed': False})
+
+class ChannelBindingHotelRoomTypeRestrictionItemListener(Component):
+ _name = 'channel.binding.hotel.room.type.restriction.item.listener'
+ _inherit = 'base.connector.listener'
+ _apply_on = ['channel.hotel.room.type.restriction.item']
+
+ @skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
+ def on_record_create(self, record, fields=None):
+ record.channel_pushed = False
+
+ @skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
+ def on_record_write(self, record, fields=None):
+ fields_to_check = ('min_stay', 'min_stay_arrival', 'max_stay', 'max_stay_arrival',
+ 'max_stay_arrival', 'closed', 'closed_departure', 'closed_arrival',
+ 'date')
+ fields_checked = [elm for elm in fields_to_check if elm in fields]
+ if any(fields_checked):
+ record.channel_pushed = False
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
new file mode 100644
index 000000000..b8788aaf1
--- /dev/null
+++ b/hotel_channel_connector/models/hotel_room_type_restriction_item/exporter.py
@@ -0,0 +1,107 @@
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+import logging
+from datetime import timedelta
+from odoo.addons.component.core import Component
+from odoo.addons.hotel_channel_connector.components.core import ChannelConnectorError
+from odoo.addons.hotel_channel_connector.components.backend_adapter import (
+ DEFAULT_WUBOOK_DATE_FORMAT)
+from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
+from odoo import fields, api, _
+_logger = logging.getLogger(__name__)
+
+class HotelRoomTypeRestrictionItemExporter(Component):
+ _name = 'channel.hotel.room.type.restriction.item.exporter'
+ _inherit = 'hotel.channel.exporter'
+ _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):
+ 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([
+ ('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: [],
+ })
+ 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,
+ })
+ 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})
+ return True
diff --git a/hotel_channel_connector/models/product_pricelist/__init__.py b/hotel_channel_connector/models/product_pricelist/__init__.py
index 257ab04fc..fe02f8e98 100644
--- a/hotel_channel_connector/models/product_pricelist/__init__.py
+++ b/hotel_channel_connector/models/product_pricelist/__init__.py
@@ -2,3 +2,5 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import common
+from . import importer
+from . import exporter
diff --git a/hotel_channel_connector/models/product_pricelist/common.py b/hotel_channel_connector/models/product_pricelist/common.py
index 3430fcc87..775bd698a 100644
--- a/hotel_channel_connector/models/product_pricelist/common.py
+++ b/hotel_channel_connector/models/product_pricelist/common.py
@@ -17,7 +17,6 @@ class ChannelProductPricelist(models.Model):
string='Pricelist',
required=True,
ondelete='cascade')
- channel_plan_id = fields.Char("Channel Plan ID", readonly=True, old_name='wpid')
is_daily_plan = fields.Boolean("Channel Daily Plan", default=True, old_name='wdaily_plan')
@job(default_channel='root.channel')
@@ -25,61 +24,37 @@ class ChannelProductPricelist(models.Model):
@api.multi
def create_plan(self):
self.ensure_one()
- if self._context.get('channel_action', True):
+ if not self.external_id:
with self.backend_id.work_on(self._name) as work:
- adapter = work.component(usage='backend.adapter')
- try:
- channel_plan_id = adapter.create_plan(self.name,
- self.is_daily_plan and 1 or 0)
- if channel_plan_id:
- self.channel_plan_id = channel_plan_id
- except ValidationError as e:
- self.create_issue(
- backend=self.backend_adapter.id,
- section='room',
- internal_message="Can't create plan on channel")
+ exporter = work.component(usage='product.pricelist.exporter')
+ exporter.create_plan(self)
@job(default_channel='root.channel')
@related_action(action='related_action_unwrap_binding')
@api.multi
def update_plan_name(self):
self.ensure_one()
- if self._context.get('channel_action', True):
+ if self.external_id:
with self.backend_id.work_on(self._name) as work:
- adapter = work.component(usage='backend.adapter')
- try:
- adapter.update_plan_name(
- self.channel_plan_id,
- self.name)
- except ValidationError as e:
- self.create_issue(
- backend=self.backend_adapter.id,
- section='room',
- internal_message="Can't update plan name on channel")
+ exporter = work.component(usage='product.pricelist.exporter')
+ exporter.rename_plan(self)
@job(default_channel='root.channel')
@related_action(action='related_action_unwrap_binding')
@api.multi
def delete_plan(self):
self.ensure_one()
- if self._context.get('channel_action', True) and self.channel_room_id:
+ if self.external_id:
with self.backend_id.work_on(self._name) as work:
- adapter = work.component(usage='backend.adapter')
- try:
- adapter.delete_plan(self.channel_plan_id)
- except ValidationError as e:
- self.create_issue(
- backend=self.backend_adapter.id,
- section='room',
- internal_message="Can't delete plan on channel")
+ exporter = work.component(usage='product.pricelist.exporter')
+ exporter.delete_plan(self)
@job(default_channel='root.channel')
- @api.multi
- def import_price_plans(self):
- if self._context.get('channel_action', True):
- with self.backend_id.work_on(self._name) as work:
- importer = work.component(usage='channel.importer')
- return importer.import_pricing_plans()
+ @api.model
+ def import_price_plans(self, backend):
+ with backend.work_on(self._name) as work:
+ importer = work.component(usage='product.pricelist.importer')
+ return importer.import_pricing_plans()
class ProductPricelist(models.Model):
_inherit = 'product.pricelist'
@@ -92,19 +67,47 @@ class ProductPricelist(models.Model):
@api.multi
@api.depends('name')
def name_get(self):
- self.ensure_one()
pricelist_obj = self.env['product.pricelist']
org_names = super(ProductPricelist, self).name_get()
names = []
for name in org_names:
priclist_id = pricelist_obj.browse(name[0])
if any(priclist_id.channel_bind_ids) and \
- priclist_id.channel_bind_ids[0].channel_plan_id:
- names.append((name[0], '%s (Channel)' % name[1]))
+ priclist_id.channel_bind_ids[0].external_id:
+ names.append((name[0], '%s (%s Backend)' % (
+ name[1],
+ priclist_id.channel_bind_ids[0].backend_id.name)))
else:
names.append((name[0], name[1]))
return names
+class ProductPricelistAdapter(Component):
+ _name = 'channel.product.pricelist.adapter'
+ _inherit = 'wubook.adapter'
+ _apply_on = 'channel.product.pricelist'
+
+ def get_pricing_plans(self):
+ return super(ProductPricelistAdapter, self).get_pricing_plans()
+
+ def create_plan(self, name):
+ return super(ProductPricelistAdapter, self).create_plan(name)
+
+ def delete_plan(self, external_id):
+ return super(ProductPricelistAdapter, self).delete_plan(external_id)
+
+ def rename_plan(self, external_id, new_name):
+ return super(ProductPricelistAdapter, self).rename_plan(external_id, new_name)
+
+class BindingProductPricelistListener(Component):
+ _name = 'binding.product.pricelist.listener'
+ _inherit = 'base.connector.listener'
+ _apply_on = ['product.pricelist']
+
+ @skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
+ def on_record_write(self, record, fields=None):
+ if any(record.channel_bind_ids) and 'name' in fields:
+ record.channel_bind_ids[0].update_plan_name()
+
class ChannelBindingProductPricelistListener(Component):
_name = 'channel.binding.product.pricelist.listener'
_inherit = 'base.connector.listener'
@@ -112,13 +115,13 @@ class ChannelBindingProductPricelistListener(Component):
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
def on_record_create(self, record, fields=None):
- record.with_delay(priority=20).create_plan()
+ record.create_plan()
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
def on_record_unlink(self, record, fields=None):
- record.with_delay(priority=20).delete_plan()
+ record.delete_plan()
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
def on_record_write(self, record, fields=None):
if 'name' in fields:
- record.with_delay(priority=20).update_plan_name()
+ record.update_plan_name()
diff --git a/hotel_channel_connector/models/product_pricelist/exporter.py b/hotel_channel_connector/models/product_pricelist/exporter.py
new file mode 100644
index 000000000..45b028d84
--- /dev/null
+++ b/hotel_channel_connector/models/product_pricelist/exporter.py
@@ -0,0 +1,52 @@
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+import logging
+from odoo.addons.component.core import Component
+from odoo.addons.hotel_channel_connector.components.core import ChannelConnectorError
+from odoo import api, _
+_logger = logging.getLogger(__name__)
+
+class ProductPricelistExporter(Component):
+ _name = 'channel.product.pricelist.exporter'
+ _inherit = 'hotel.channel.exporter'
+ _apply_on = ['channel.product.pricelist']
+ _usage = 'product.pricelist.exporter'
+
+ @api.model
+ def rename_plan(self, binding):
+ try:
+ return self.backend_adapter.rename_plan(
+ binding.external_id,
+ binding.name)
+ except ChannelConnectorError as err:
+ self.create_issue(
+ backend=self.backend_adapter.id,
+ section='restriction',
+ internal_message=_("Can't modify pricelist plan in WuBook"),
+ channel_message=err.data['message'])
+
+ @api.model
+ def delete_plan(self, binding):
+ try:
+ return self.backend_adapter.delete_plan(binding.external_id)
+ except ChannelConnectorError as err:
+ self.create_issue(
+ backend=self.backend_adapter.id,
+ section='restriction',
+ internal_message=_("Can't delete pricelist plan in WuBook"),
+ channel_message=err.data['message'])
+
+ @api.model
+ def create_plan(self, binding):
+ try:
+ external_id = self.backend_adapter.create_plan(binding.name)
+ binding.external_id = external_id
+ except ChannelConnectorError as err:
+ self.create_issue(
+ backend=self.backend_adapter.id,
+ section='restriction',
+ internal_message=_("Can't create pricelist plan in WuBook"),
+ channel_message=err.data['message'])
+ else:
+ self.binder.bind(external_id, binding)
diff --git a/hotel_channel_connector/models/product_pricelist/importer.py b/hotel_channel_connector/models/product_pricelist/importer.py
new file mode 100644
index 000000000..74dabe6e8
--- /dev/null
+++ b/hotel_channel_connector/models/product_pricelist/importer.py
@@ -0,0 +1,65 @@
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+import logging
+from datetime import datetime, timedelta
+from odoo.addons.component.core import Component
+from odoo.addons.hotel_channel_connector.components.core import ChannelConnectorError
+from odoo.addons.connector.components.mapper import mapping, only_create
+from odoo.addons.hotel_channel_connector.components.backend_adapter import (
+ DEFAULT_WUBOOK_DATE_FORMAT)
+from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
+from odoo import fields, api, _
+_logger = logging.getLogger(__name__)
+
+
+class ProductPricelistImporter(Component):
+ _name = 'channel.product.pricelist.importer'
+ _inherit = 'hotel.channel.importer'
+ _apply_on = ['channel.product.pricelist']
+ _usage = 'product.pricelist.importer'
+
+ @api.model
+ def import_pricing_plans(self):
+ channel_product_listprice_obj = self.env['channel.product.pricelist']
+ pricelist_mapper = self.component(usage='import.mapper',
+ model_name='channel.product.pricelist')
+ count = 0
+ try:
+ results = self.backend_adapter.get_pricing_plans()
+ for plan in results:
+ if 'vpid' in plan:
+ continue # FIXME: Ignore Virtual Plans
+ plan_record = pricelist_mapper.map_record(plan)
+ plan_bind = channel_product_listprice_obj.search([
+ ('external_id', '=', str(plan['id']))
+ ], limit=1)
+ if not plan_bind:
+ channel_product_listprice_obj.with_context({
+ 'wubook_action': False}).create(plan_record.values(for_create=True))
+ else:
+ channel_product_listprice_obj.write(plan_record.values())
+ count = count + 1
+ except ChannelConnectorError as err:
+ self.create_issue(
+ section='pricelist',
+ internal_message=_("Can't get pricing plans from wubook"),
+ channel_message=err.data['message'])
+ return 0
+ return count
+
+
+class ProductPricelistMapper(Component):
+ _name = 'channel.product.pricelist.import.mapper'
+ _inherit = 'channel.import.mapper'
+ _apply_on = 'channel.product.pricelist'
+
+ direct = [
+ ('id', 'external_id'),
+ ('name', 'name'),
+ ('daily', 'is_daily_plan'),
+ ]
+
+ @mapping
+ def backend_id(self, record):
+ return {'backend_id': self.backend_record.id}
diff --git a/hotel_channel_connector/views/channel_connector_backend_views.xml b/hotel_channel_connector/views/channel_connector_backend_views.xml
index 3e2dcb8c5..2b947a5d0 100644
--- a/hotel_channel_connector/views/channel_connector_backend_views.xml
+++ b/hotel_channel_connector/views/channel_connector_backend_views.xml
@@ -116,6 +116,15 @@
string="Import in background"/>