diff --git a/hotel_calendar/models/hotel_calendar_management.py b/hotel_calendar/models/hotel_calendar_management.py
index 4727c428e..33d9c2204 100644
--- a/hotel_calendar/models/hotel_calendar_management.py
+++ b/hotel_calendar/models/hotel_calendar_management.py
@@ -36,7 +36,7 @@ class HotelCalendarManagement(models.TransientModel):
@api.model
def _get_availability_values(self, avail, vroom):
- vroom_obj = self.env['hotel.virtual.room']
+ vroom_obj = self.env['hotel.room.type']
cavail = len(vroom_obj.check_availability_virtual_room(
avail['date'], avail['date'], virtual_room_id=vroom.id))
ravail = min(cavail, vroom.total_rooms_count, int(avail['avail']))
@@ -49,7 +49,7 @@ class HotelCalendarManagement(models.TransientModel):
@api.multi
def save_changes(self, pricelist_id, restriction_id, pricelist,
restrictions, availability):
- vroom_obj = self.env['hotel.virtual.room']
+ vroom_obj = self.env['hotel.room.type']
product_pricelist_item_obj = self.env['product.pricelist.item']
vroom_rest_item_obj = self.env['hotel.virtual.room.restriction.item']
vroom_avail_obj = self.env['hotel.virtual.room.availability']
@@ -140,7 +140,7 @@ class HotelCalendarManagement(models.TransientModel):
@api.model
def _hcalendar_pricelist_json_data(self, prices):
json_data = {}
- vroom_obj = self.env['hotel.virtual.room']
+ vroom_obj = self.env['hotel.room.type']
for rec in prices:
virtual_room_id = vroom_obj.search([
('product_id.product_tmpl_id', '=', rec.product_tmpl_id.id)
@@ -178,7 +178,7 @@ class HotelCalendarManagement(models.TransientModel):
def _hcalendar_availability_json_data(self, dfrom, dto):
date_start = date_utils.get_datetime(dfrom, hours=False)
date_diff = date_utils.date_diff(dfrom, dto, hours=False) + 1
- vrooms = self.env['hotel.virtual.room'].search([])
+ vrooms = self.env['hotel.room.type'].search([])
json_data = {}
for vroom in vrooms:
@@ -239,10 +239,10 @@ class HotelCalendarManagement(models.TransientModel):
@api.model
def _hcalendar_get_count_reservations_json_data(self, dfrom, dto):
- vrooms = self.env['hotel.virtual.room'].search([])
+ vrooms = self.env['hotel.room.type'].search([])
date_start = date_utils.get_datetime(dfrom, hours=False)
date_diff = date_utils.date_diff(dfrom, dto, hours=False) + 1
- hotel_vroom_obj = self.env['hotel.virtual.room']
+ hotel_vroom_obj = self.env['hotel.room.type']
vrooms = hotel_vroom_obj.search([])
json_data = {}
@@ -308,7 +308,7 @@ class HotelCalendarManagement(models.TransientModel):
})
if withRooms:
- room_ids = self.env['hotel.virtual.room'].search(
+ room_ids = self.env['hotel.room.type'].search(
[],
order='hcal_sequence ASC')
json_rooms = self._hcalendar_room_json_data(room_ids)
diff --git a/hotel_calendar/models/inherited_hotel_reservation.py b/hotel_calendar/models/inherited_hotel_reservation.py
index 8e654df19..9dcd7bd47 100644
--- a/hotel_calendar/models/inherited_hotel_reservation.py
+++ b/hotel_calendar/models/inherited_hotel_reservation.py
@@ -65,7 +65,7 @@ class HotelReservation(models.Model):
pricelist_id = int(pricelist_id)
json_rooms = []
room_type_obj = self.env['hotel.room.type']
- vroom_obj = self.env['hotel.virtual.room']
+ vroom_obj = self.env['hotel.room.type']
for room in rooms:
room_type = room_type_obj.search([
('cat_id', '=', room.categ_id.id)
@@ -138,7 +138,7 @@ class HotelReservation(models.Model):
date_diff = date_utils.date_diff(date_start, dto, hours=False) + 1
# Get Prices
json_rooms_prices = {pricelist_id: []}
- vrooms = self.env['hotel.virtual.room'].search(
+ vrooms = self.env['hotel.room.type'].search(
[],
order='hcal_sequence ASC')
vroom_pr_cached_obj = self.env['virtual.room.pricelist.cached']
@@ -178,7 +178,7 @@ class HotelReservation(models.Model):
date_diff = date_utils.date_diff(dfrom, dto, hours=False) + 1
# Get Prices
json_rooms_rests = {}
- vrooms = self.env['hotel.virtual.room'].search(
+ vrooms = self.env['hotel.room.type'].search(
[],
order='hcal_sequence ASC')
vroom_rest_obj = self.env['hotel.virtual.room.restriction.item']
diff --git a/hotel_calendar/models/inherited_hotel_virtual_room.py b/hotel_calendar/models/inherited_hotel_virtual_room.py
index 59508b000..815d6225d 100644
--- a/hotel_calendar/models/inherited_hotel_virtual_room.py
+++ b/hotel_calendar/models/inherited_hotel_virtual_room.py
@@ -4,7 +4,7 @@ from odoo import models, fields, api
class HotelVirtualRoom(models.Model):
- _inherit = 'hotel.virtual.room'
+ _inherit = 'hotel.room.type'
hcal_sequence = fields.Integer('Calendar Sequence', default=0)
diff --git a/hotel_calendar/models/inherited_ir_default.py b/hotel_calendar/models/inherited_ir_default.py
index 9ae372b97..f254607a3 100644
--- a/hotel_calendar/models/inherited_ir_default.py
+++ b/hotel_calendar/models/inherited_ir_default.py
@@ -18,7 +18,7 @@ class IrDefault(models.Model):
pricelist_items = self.env['product.pricelist.item'].search([
('pricelist_id', '=', pricelist_id)
])
- vroom_obj = self.env['hotel.virtual.room']
+ vroom_obj = self.env['hotel.room.type']
vroom_pr_cached_obj = self.env['virtual.room.pricelist.cached']
for pitem in pricelist_items:
date_start = pitem.date_start
diff --git a/hotel_calendar/models/inherited_product_pricelist.py b/hotel_calendar/models/inherited_product_pricelist.py
index 2a321cdb7..651d4d8cf 100644
--- a/hotel_calendar/models/inherited_product_pricelist.py
+++ b/hotel_calendar/models/inherited_product_pricelist.py
@@ -8,7 +8,7 @@ class ProductPricelist(models.Model):
@api.multi
def update_price(self, virtual_room_id, date, price):
- vroom = self.env['hotel.virtual.room'].browse(virtual_room_id)
+ vroom = self.env['hotel.room.type'].browse(virtual_room_id)
pritem_obj = self.env['product.pricelist.item']
for record in self:
plitem = pritem_obj.search([
diff --git a/hotel_calendar/models/inherited_product_pricelist_item.py b/hotel_calendar/models/inherited_product_pricelist_item.py
index 81f567b7d..309c6d55b 100644
--- a/hotel_calendar/models/inherited_product_pricelist_item.py
+++ b/hotel_calendar/models/inherited_product_pricelist_item.py
@@ -16,7 +16,7 @@ class ProductPricelistItem(models.Model):
pricelist_id = res.pricelist_id.id
product_tmpl_id = res.product_tmpl_id.id
date_start = res.date_start
- vroom = self.env['hotel.virtual.room'].search([
+ vroom = self.env['hotel.room.type'].search([
('product_id.product_tmpl_id', '=', product_tmpl_id)
], limit=1)
if pricelist_id == pricelist_parity_id and vroom:
@@ -59,7 +59,7 @@ class ProductPricelistItem(models.Model):
vroom_pr_cached_obj = self.env['virtual.room.pricelist.cached']
bus_calendar_obj = self.env['bus.hotel.calendar']
- vroom_obj = self.env['hotel.virtual.room']
+ vroom_obj = self.env['hotel.room.type']
if vals.get('fixed_price'):
for record in self:
pricelist_id = vals.get('pricelist_id') or \
@@ -113,7 +113,7 @@ class ProductPricelistItem(models.Model):
for record in self:
if record.pricelist_id.id != pricelist_parity_id:
continue
- vroom = self.env['hotel.virtual.room'].search([
+ vroom = self.env['hotel.room.type'].search([
('product_id.product_tmpl_id', '=', record.product_tmpl_id.id)
], limit=1)
unlink_vals.append({
diff --git a/hotel_calendar/models/virtual_room_pricelist_cached.py b/hotel_calendar/models/virtual_room_pricelist_cached.py
index 5d1395fd7..5ec8fd32d 100644
--- a/hotel_calendar/models/virtual_room_pricelist_cached.py
+++ b/hotel_calendar/models/virtual_room_pricelist_cached.py
@@ -11,7 +11,7 @@ class VirtualRoomPricelistCached(models.Model):
_name = 'virtual.room.pricelist.cached'
- virtual_room_id = fields.Many2one('hotel.virtual.room', 'Virtual Room',
+ virtual_room_id = fields.Many2one('hotel.room.type', 'Virtual Room',
required=True, track_visibility='always')
price = fields.Float('Price', default=0.0)
date = fields.Date('Date', required=True, track_visibility='always')
diff --git a/hotel_calendar/static/src/js/views/calendar/hotel_calendar_model.js b/hotel_calendar/static/src/js/views/calendar/hotel_calendar_model.js
index b1542c5e3..5f6297d73 100644
--- a/hotel_calendar/static/src/js/views/calendar/hotel_calendar_model.js
+++ b/hotel_calendar/static/src/js/views/calendar/hotel_calendar_model.js
@@ -82,7 +82,7 @@ return AbstractModel.extend({
},
get_vrooms: function() {
return this._rpc({
- model: 'hotel.virtual.room',
+ model: 'hotel.room.type',
method: 'search_read',
args: [false, ['id','name']],
context: Session.user_context,
diff --git a/hotel_calendar/views/inherited_hotel_virtual_room_views.xml b/hotel_calendar/views/inherited_hotel_virtual_room_views.xml
index 57505f6a0..2d12dc572 100644
--- a/hotel_calendar/views/inherited_hotel_virtual_room_views.xml
+++ b/hotel_calendar/views/inherited_hotel_virtual_room_views.xml
@@ -2,7 +2,7 @@
- hotel.virtual.room
+ hotel.room.type
diff --git a/hotel_calendar/wizard/wizard_reservation.py b/hotel_calendar/wizard/wizard_reservation.py
index 35c0ca159..08d791e00 100644
--- a/hotel_calendar/wizard/wizard_reservation.py
+++ b/hotel_calendar/wizard/wizard_reservation.py
@@ -226,7 +226,7 @@ class FolioWizard(models.TransientModel):
checkout_dt = date_utils.get_datetime(self.checkout, stz=tz)
# Reservation end day count as free day. Not check it
checkout_dt -= timedelta(days=1)
- virtual_room_ids = self.env['hotel.virtual.room'].search([])
+ virtual_room_ids = self.env['hotel.room.type'].search([])
virtual_rooms = []
for virtual in virtual_room_ids:
@@ -313,7 +313,7 @@ class VirtualRoomWizars(models.TransientModel):
def _get_default_checkout(self):
return self.folio_wizard_id.checkout
- virtual_room_id = fields.Many2one('hotel.virtual.room',
+ virtual_room_id = fields.Many2one('hotel.room.type',
string="Virtual Rooms")
rooms_num = fields.Integer('Number of Rooms')
max_rooms = fields.Integer('Max', compute="_compute_max")
@@ -459,7 +459,7 @@ class ReservationWizard(models.TransientModel):
help='Number of children there in guest list.')
checkin = fields.Datetime('Check In', required=True)
checkout = fields.Datetime('Check Out', required=True)
- virtual_room_id = fields.Many2one('hotel.virtual.room',
+ virtual_room_id = fields.Many2one('hotel.room.type',
string='Virtual Room Type',
required=True)
nights = fields.Integer('Nights', readonly=True)
diff --git a/hotel_calendar_channel_connector/__init__.py b/hotel_calendar_channel_connector/__init__.py
index 8f10572dd..572903d95 100644
--- a/hotel_calendar_channel_connector/__init__.py
+++ b/hotel_calendar_channel_connector/__init__.py
@@ -1,22 +1,3 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import models
diff --git a/hotel_calendar_channel_connector/models/__init__.py b/hotel_calendar_channel_connector/models/__init__.py
index 32e496b97..4cb563145 100644
--- a/hotel_calendar_channel_connector/models/__init__.py
+++ b/hotel_calendar_channel_connector/models/__init__.py
@@ -1,25 +1,6 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import inherited_hotel_reservation
from . import inherited_bus_hotel_calendar
-from . import inherited_wubook_issue
+from . import inherited_hotel_channel_connector_issue
from . import inherited_hotel_calendar_management
diff --git a/hotel_calendar_channel_connector/models/inherited_bus_hotel_calendar.py b/hotel_calendar_channel_connector/models/inherited_bus_hotel_calendar.py
index 1897d5ca2..f3bc09eac 100644
--- a/hotel_calendar_channel_connector/models/inherited_bus_hotel_calendar.py
+++ b/hotel_calendar_channel_connector/models/inherited_bus_hotel_calendar.py
@@ -1,24 +1,5 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from datetime import datetime
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
from openerp import models, api
diff --git a/hotel_calendar_channel_connector/models/inherited_hotel_calendar_management.py b/hotel_calendar_channel_connector/models/inherited_hotel_calendar_management.py
index 6b576872f..f20f26270 100644
--- a/hotel_calendar_channel_connector/models/inherited_hotel_calendar_management.py
+++ b/hotel_calendar_channel_connector/models/inherited_hotel_calendar_management.py
@@ -1,24 +1,5 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, api
diff --git a/hotel_calendar_channel_connector/models/inherited_hotel_channel_connector_issue.py b/hotel_calendar_channel_connector/models/inherited_hotel_channel_connector_issue.py
new file mode 100644
index 000000000..bbaa6d821
--- /dev/null
+++ b/hotel_calendar_channel_connector/models/inherited_hotel_channel_connector_issue.py
@@ -0,0 +1,18 @@
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+from openerp import models, fields, api, _
+
+
+class WuBookIssue(models.Model):
+ _inherit = 'hotel.channel.connector.issue'
+
+ @api.model
+ def create(self, vals):
+ issue_id = super(WuBookIssue, self).create(vals)
+ self.env['bus.hotel.calendar'].send_issue_notification(
+ 'warn',
+ _("Oops! Issue Reported!!"),
+ issue_id.id,
+ issue_id.section,
+ issue_id.message)
+ return issue_id
diff --git a/hotel_calendar_channel_connector/models/inherited_hotel_reservation.py b/hotel_calendar_channel_connector/models/inherited_hotel_reservation.py
index 0ae6e46dd..94856adb4 100644
--- a/hotel_calendar_channel_connector/models/inherited_hotel_reservation.py
+++ b/hotel_calendar_channel_connector/models/inherited_hotel_reservation.py
@@ -1,24 +1,5 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# 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 openerp import models, fields, api, _
@@ -118,5 +99,5 @@ class HotelReservation(models.Model):
def confirm(self):
for record in self:
if record.to_assign == True:
- record.write({'to_read': False, 'to_assign': False})
+ record.write({'to_read': False, 'to_assign': False})
return super(HotelReservation, self).confirm()
diff --git a/hotel_calendar_channel_connector/static/src/js/views/hotel_calendar_model.js b/hotel_calendar_channel_connector/static/src/js/views/hotel_calendar_model.js
index b1542c5e3..5f6297d73 100644
--- a/hotel_calendar_channel_connector/static/src/js/views/hotel_calendar_model.js
+++ b/hotel_calendar_channel_connector/static/src/js/views/hotel_calendar_model.js
@@ -82,7 +82,7 @@ return AbstractModel.extend({
},
get_vrooms: function() {
return this._rpc({
- model: 'hotel.virtual.room',
+ model: 'hotel.room.type',
method: 'search_read',
args: [false, ['id','name']],
context: Session.user_context,
diff --git a/hotel_calendar_channel_connector/tests/__init__.py b/hotel_calendar_channel_connector/tests/__init__.py
index 327f7e426..5c2388c95 100644
--- a/hotel_calendar_channel_connector/tests/__init__.py
+++ b/hotel_calendar_channel_connector/tests/__init__.py
@@ -1,23 +1,3 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import test_folio
diff --git a/hotel_calendar_channel_connector/tests/test_folio.py b/hotel_calendar_channel_connector/tests/test_folio.py
index 718141d45..824d9a05f 100644
--- a/hotel_calendar_channel_connector/tests/test_folio.py
+++ b/hotel_calendar_channel_connector/tests/test_folio.py
@@ -1,25 +1,5 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from datetime import timedelta
from odoo.addons.hotel_calendar.tests.common import TestHotelCalendar
from odoo.addons.hotel import date_utils
diff --git a/hotel_channel_connector/__init__.py b/hotel_channel_connector/__init__.py
index f33b38cae..88bc9d53e 100644
--- a/hotel_channel_connector/__init__.py
+++ b/hotel_channel_connector/__init__.py
@@ -1,25 +1,7 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+from openerp import models, fields, api, _
from . import controllers
from . import models
-from . import wubook
from . import wizard
+from . import components
diff --git a/hotel_channel_connector/__manifest__.py b/hotel_channel_connector/__manifest__.py
index d686144f7..816b607e8 100644
--- a/hotel_channel_connector/__manifest__.py
+++ b/hotel_channel_connector/__manifest__.py
@@ -1,33 +1,14 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
- 'name': 'Hotel WuBook Prototype',
+ 'name': 'Hotel Channel Connector',
'version': '1.0',
- 'author': "Alexandre Díaz (Aloxa Solucións S.L.) ",
+ 'author': "Alexandre Díaz ",
'website': 'https://www.eiqui.com',
- 'category': 'eiqui/hotel',
- 'summary': "Hotel WuBook",
- 'description': "Hotel WuBook Prototype",
+ 'category': 'hotel/connector',
+ 'summary': "Hotel Channel Connector Base",
+ 'description': "Hotel Channel Connector Base",
'depends': [
'hotel',
],
diff --git a/hotel_channel_connector/components/__init__.py b/hotel_channel_connector/components/__init__.py
new file mode 100644
index 000000000..8c217199f
--- /dev/null
+++ b/hotel_channel_connector/components/__init__.py
@@ -0,0 +1,7 @@
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+from . import backend_adapter
+from . import binder
+from . import core
+from . import exporter
+from . import importer
diff --git a/hotel_channel_connector/components/backend_adapter.py b/hotel_channel_connector/components/backend_adapter.py
new file mode 100644
index 000000000..a644a071d
--- /dev/null
+++ b/hotel_channel_connector/components/backend_adapter.py
@@ -0,0 +1,552 @@
+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 (
+ DEFAULT_SERVER_DATE_FORMAT,
+ DEFAULT_SERVER_DATETIME_FORMAT)
+from odoo.addons.payment.models.payment_acquirer import _partner_split_name
+from odoo.addons.hotel import date_utils
+
+# GLOBAL VARS
+DEFAULT_WUBOOK_DATE_FORMAT = "%d/%m/%Y"
+DEFAULT_WUBOOK_TIME_FORMAT = "%H:%M"
+DEFAULT_WUBOOK_DATETIME_FORMAT = "%s %s" % (DEFAULT_WUBOOK_DATE_FORMAT,
+ DEFAULT_WUBOOK_TIME_FORMAT)
+WUBOOK_STATUS_CONFIRMED = 1
+WUBOOK_STATUS_WAITING = 2
+WUBOOK_STATUS_REFUSED = 3
+WUBOOK_STATUS_ACCEPTED = 4
+WUBOOK_STATUS_CANCELLED = 5
+WUBOOK_STATUS_CANCELLED_PENALTY = 6
+
+WUBOOK_STATUS_GOOD = (
+ WUBOOK_STATUS_CONFIRMED,
+ WUBOOK_STATUS_WAITING,
+ WUBOOK_STATUS_ACCEPTED,
+)
+WUBOOK_STATUS_BAD = (
+ WUBOOK_STATUS_REFUSED,
+ WUBOOK_STATUS_CANCELLED,
+ WUBOOK_STATUS_CANCELLED_PENALTY,
+)
+
+class WuBookLogin(object):
+ def __init__(self, address, user, passwd, lcode, pkey):
+ self.address = address
+ self.user = user
+ self.passwd = passwd
+ self.lcode = lcode
+ self.pkey = pkey
+
+ def is_valid(self):
+ return self.address and self.user and self.passwd and self.lcode and self.pkey
+
+class WuBookServer(object):
+ def __init__(self, login_data):
+ self._server = None
+ self._token = None
+ self._login_data = login_data
+
+ @property
+ def server(self):
+ if self._server is None and self._login_data.is_valid():
+ try:
+ self._server = xmlrpclib.Server(self._login_data.address)
+ res, tok = self._server.acquire_token(
+ self._login_data.user,
+ self._login_data.passwd,
+ self._login_data.pkey)
+ if res == 0:
+ self._token = tok
+ else:
+ self._server = None
+ except Exception:
+ self._server = None
+ raise RetryableJobError("Can't connect with channel!")
+ return self._server
+
+ @property
+ def session_token(self):
+ return self._token
+
+ @property
+ def lcode(self):
+ return self._login_data.lcode
+
+ def close(self):
+ self._server.release_token(self._token)
+ self._token = None
+ self._server = None
+
+class HotelChannelInterfaceAdapter(AbstractComponent):
+ _name = 'hotel.channel.interface.adapter'
+ _inherit = ['base.backend.adapter', 'base.hotel.channel.connector']
+ _usage = 'backend.adapter'
+
+ def create_room(self, shortcode, name, capacity, price, availability):
+ raise NotImplementedError
+
+ def modify_room(self, channel_room_id, name, capacity, price, availability, scode):
+ raise NotImplementedError
+
+ def delete_room(self, channel_room_id):
+ raise NotImplementedError
+
+ def fetch_rooms(self, channel_room_id=0):
+ raise NotImplementedError
+
+ def fetch_rooms_values(self, date_from, date_to, rooms=False):
+ raise NotImplementedError
+
+ def update_availability(self, rooms_avail):
+ raise NotImplementedError
+
+ def corporate_fetch(self):
+ raise NotImplementedError
+
+ def create_reservation(self, channel_room_id, customer_name, email, city,
+ phone, address, country_code, checkin, checkout,
+ adults, children, notes=''):
+ raise NotImplementedError
+
+ def cancel_reservation(self, channel_reservation_id, reason=""):
+ raise NotImplementedError
+
+ def fetch_new_bookings(self):
+ raise NotImplementedError
+
+ def fetch_booking(self, channel_reservation_id):
+ raise NotImplementedError
+
+ def mark_bookings(self, channel_reservation_ids):
+ raise NotImplementedError
+
+ def create_plan(self, name, daily=1):
+ raise NotImplementedError
+
+ def delete_plan(self, channel_plan_id):
+ raise NotImplementedError
+
+ def update_plan_name(self, channel_plan_id, new_name):
+ raise NotImplementedError
+
+ def update_plan_prices(self, channel_plan_id, date_from, prices):
+ raise NotImplementedError
+
+ def update_plan_periods(self, channel_plan_id, periods):
+ raise NotImplementedError
+
+ def get_pricing_plans(self):
+ raise NotImplementedError
+
+ def fetch_plan_prices(self, channel_plan_id, date_from, date_to, rooms):
+ raise NotImplementedError
+
+ def rplan_rplans(self):
+ raise NotImplementedError
+
+ def wired_rplan_get_rplan_values(self, date_from, date_to, channel_restriction_plan_id):
+ raise NotImplementedError
+
+ def update_rplan_values(self, channel_restriction_plan_id, date_from, values):
+ raise NotImplementedError
+
+ def create_rplan(self, name, compact=False):
+ raise NotImplementedError
+
+ def rename_rplan(self, channel_restriction_plan_id, new_name):
+ raise NotImplementedError
+
+ def delete_rplan(self, channel_restriction_plan_id):
+ raise NotImplementedError
+
+ def get_channels_info(self):
+ raise NotImplementedError
+
+ @property
+ def _server(self):
+ try:
+ channel_server = getattr(self.work, 'hotel_channel_server')
+ except AttributeError:
+ raise AttributeError(
+ 'You must provide a hotel_channel_server attribute with a '
+ 'WuBookServer instance to be able to use the '
+ 'Backend Adapter.'
+ )
+ return channel_server.server
+
+ @property
+ def _session_info(self):
+ try:
+ channel_server = getattr(self.work, 'hotel_channel_server')
+ except AttributeError:
+ raise AttributeError(
+ 'You must provide a hotel_channel_server attribute with a '
+ 'WuBookServer instance to be able to use the '
+ 'Backend Adapter.'
+ )
+ return (channel_server.session_token, channel_server.lcode)
+
+class WuBookAdapter(AbstractComponent):
+ _name = 'wubook.adapter'
+ _inherit = 'hotel.channel.interface.adapter'
+
+ # === ROOMS
+ def create_room(self, shortcode, name, capacity, price, availability):
+ rcode, results = self._server.new_room(
+ self._session_info[0],
+ self._session_info[1],
+ 0,
+ name,
+ capacity,
+ price,
+ availability,
+ shortcode[:4],
+ 'nb' # TODO: Complete this part
+ # rtype=('name' in vals and vals['name'] and 3) or 1
+ )
+ if rcode != 0:
+ raise ValidationError(_("Can't create room in WuBook"), {
+ 'message': results,
+ })
+ return results
+
+ def modify_room(self, channel_room_id, name, capacity, price, availability, scode):
+ rcode, results = self._server.mod_room(
+ self._session_info[0],
+ self._session_info[1],
+ channel_room_id,
+ name,
+ capacity,
+ price,
+ availability,
+ scode,
+ 'nb'
+ # rtype=('name' in vals and vals['name'] and 3) or 1
+ )
+ if rcode != 0:
+ raise ValidationError(_("Can't modify room in WuBook"), {
+ 'message': results,
+ 'channel_id': channel_room_id,
+ })
+ return results
+
+ def delete_room(self, channel_room_id):
+ rcode, results = self._server.del_room(
+ self._session_info[0],
+ self._session_info[1],
+ channel_room_id)
+ if rcode != 0:
+ raise ValidationError(_("Can't delete room in WuBook"), {
+ 'message': results,
+ 'channel_id': channel_room_id,
+ })
+ return results
+
+ def fetch_rooms(self, channel_room_id=0):
+ rcode, results = self._server.fetch_rooms(
+ self._session_info[0],
+ self._session_info[1],
+ channel_room_id)
+ if rcode != 0:
+ raise ValidationError(_("Can't fetch room values from WuBook"), {
+ 'message': results,
+ 'channel_id': channel_room_id,
+ })
+ return results
+
+ def fetch_rooms_values(self, date_from, date_to, rooms=False):
+ rcode, results = self._server.fetch_rooms_values(
+ self._session_info[0],
+ self._session_info[1],
+ date_utils.get_datetime(date_from).strftime(DEFAULT_WUBOOK_DATE_FORMAT),
+ date_utils.get_datetime(date_to).strftime(DEFAULT_WUBOOK_DATE_FORMAT),
+ rooms)
+ if rcode != 0:
+ raise ValidationError(_("Can't fetch rooms values from WuBook"), {
+ 'message': results,
+ })
+ return results
+
+ def update_availability(self, rooms_avail):
+ rcode, results = self._server.update_sparse_avail(
+ self._session_info[0],
+ self._session_info[1],
+ rooms_avail)
+ if rcode != 0:
+ raise ValidationError(_("Can't update rooms availability in WuBook"), {
+ 'message': results,
+ })
+ return results
+
+ def corporate_fetch(self):
+ rcode, results = self._server.corporate_fetchable_properties(self.TOKEN)
+ if rcode != 0:
+ raise ValidationError(_("Can't call 'corporate_fetch' from WuBook"), {
+ 'message': results,
+ })
+ return results
+
+ # === RESERVATIONS
+ def create_reservation(self, channel_room_id, customer_name, email, city,
+ phone, address, country_code, checkin, checkout,
+ adults, children, notes=''):
+ customer_name = _partner_split_name(customer_name)
+ customer = {
+ 'lname': customer_name[0],
+ 'fname': customer_name[1],
+ 'email': email,
+ 'city': city,
+ 'phone': phone,
+ 'street': address,
+ 'country': country_code,
+ 'arrival_hour': date_utils.get_datetime(checkin).strftime("%H:%M"),
+ 'notes': notes
+ }
+ rcode, results = self._server.new_reservation(
+ self._session_info[0],
+ self._session_info[1],
+ date_utils.get_datetime(checkin).strftime(DEFAULT_WUBOOK_DATE_FORMAT),
+ date_utils.get_datetime(checkout).strftime(DEFAULT_WUBOOK_DATE_FORMAT),
+ {channel_room_id: [adults+children, 'nb']},
+ customer,
+ adults+children)
+ if rcode != 0:
+ raise ValidationError(_("Can't create reservations in wubook"), {
+ 'message': results,
+ 'date_from': checkin,
+ 'date_to': checkout,
+ })
+ return results
+
+ def cancel_reservation(self, channel_reservation_id, reason=""):
+ rcode, results = self._server.cancel_reservation(
+ self._session_info[0],
+ self._session_info[1],
+ channel_reservation_id,
+ reason)
+ if rcode != 0:
+ raise ValidationError(_("Can't cancel reservation in WuBook"), {
+ 'message': results,
+ 'channel_reservation_id': channel_reservation_id,
+ })
+ return results
+
+ def fetch_new_bookings(self):
+ rcode, results = self._server.fetch_new_bookings(
+ self._session_info[0],
+ self._session_info[1],
+ 1,
+ 0)
+ if rcode != 0:
+ raise ValidationError(_("Can't process reservations from wubook"), {
+ 'message': results,
+ })
+ return results
+
+ def fetch_booking(self, channel_reservation_id):
+ rcode, results = self.backend_adapter.fetch_booking(
+ self._session_info[0],
+ self._session_info[1],
+ channel_reservation_id)
+ if rcode != 0:
+ raise ValidationError(_("Can't process reservation from wubook"), {
+ 'message': results,
+ })
+ return results
+
+ def mark_bookings(self, channel_reservation_ids):
+ init_connection = self._context.get('init_connection', True)
+ if init_connection:
+ if not self.init_connection():
+ return False
+ rcode, results = self._server.mark_bookings(
+ self._session_info[0],
+ self._session_info[1],
+ channel_reservation_ids)
+ if rcode != 0:
+ raise ValidationError(_("Can't mark as readed a reservation in wubook"), {
+ 'message': results,
+ 'channel_reservation_ids': str(channel_reservation_ids),
+ })
+ return results
+
+ # === PRICE PLANS
+ def create_plan(self, name, daily=1):
+ rcode, results = self._server.add_pricing_plan(
+ self._session_info[0],
+ self._session_info[1],
+ name,
+ daily)
+ if rcode != 0:
+ raise ValidationError(_("Can't add pricing plan to wubook"), {
+ 'message': results,
+ })
+ return results
+
+ def delete_plan(self, channel_plan_id):
+ rcode, results = self._server.del_plan(
+ self._session_info[0],
+ self._session_info[1],
+ channel_plan_id)
+ if rcode != 0:
+ raise ValidationError(_("Can't delete pricing plan from wubook"), {
+ 'message': results,
+ 'channel_plan_id': channel_plan_id,
+ })
+ return results
+
+ def update_plan_name(self, channel_plan_id, new_name):
+ rcode, results = self._server.update_plan_name(
+ self._session_info[0],
+ self._session_info[1],
+ channel_plan_id,
+ new_name)
+ if rcode != 0:
+ raise ValidationError(_("Can't update pricing plan name in wubook"), {
+ 'message': results,
+ 'channel_plan_id': channel_plan_id,
+ })
+ return results
+
+ def update_plan_prices(self, channel_plan_id, date_from, prices):
+ rcode, results = self._server.update_plan_prices(
+ self._session_info[0],
+ self._session_info[1],
+ channel_plan_id,
+ date_utils.get_datetime(date_from).strftime(DEFAULT_WUBOOK_DATE_FORMAT),
+ prices)
+ if rcode != 0:
+ raise ValidationError(_("Can't update pricing plan in wubook"), {
+ 'message': results,
+ 'channel_plan_id': channel_plan_id,
+ 'date_from': date_from,
+ })
+ return results
+
+ def update_plan_periods(self, channel_plan_id, periods):
+ rcode, results = self.SERVER.update_plan_periods(
+ self._session_info[0],
+ self._session_info[1],
+ channel_plan_id,
+ periods)
+ if rcode != 0:
+ raise ValidationError(_("Can't update pricing plan period in wubook"), {
+ 'message': results,
+ 'channel_plan_id': channel_plan_id,
+ })
+ return results
+
+ def get_pricing_plans(self):
+ rcode, results = self.SERVER.get_pricing_plans(
+ self._session_info[0],
+ self._session_info[1])
+ if rcode != 0:
+ raise ValidationError(_("Can't get pricing plans from wubook"), {
+ 'message': results,
+ })
+ return results
+
+ def fetch_plan_prices(self, channel_plan_id, date_from, date_to, rooms):
+ rcode, results = self._server.fetch_plan_prices(
+ self._session_info[0],
+ self._session_info[1],
+ channel_plan_id,
+ date_utils(date_from).strftime(DEFAULT_WUBOOK_DATE_FORMAT),
+ date_utils(date_to).strftime(DEFAULT_WUBOOK_DATE_FORMAT),
+ rooms or [])
+ if rcode != 0:
+ raise ValidationError(_("Can't get pricing plans from wubook"), {
+ 'message': results,
+ 'channel_plan_id': channel_plan_id,
+ 'date_from': date_from,
+ 'date_to': date_to
+ })
+ return results
+
+ # === RESTRICTIONS
+ def rplan_rplans(self):
+ rcode, results = self._server.rplan_rplans(
+ self._session_info[0],
+ self._session_info[1])
+ if rcode != 0:
+ raise ValidationError(_("Can't fetch restriction plans from wubook"), {
+ 'message': results,
+ })
+ return results
+
+ def wired_rplan_get_rplan_values(self, date_from, date_to, channel_restriction_plan_id):
+ rcode, results = self._server.wired_rplan_get_rplan_values(
+ self._session_info[0],
+ self._session_info[1],
+ date_utils(date_from).strftime(DEFAULT_WUBOOK_DATE_FORMAT),
+ date_utils(date_to).strftime(DEFAULT_WUBOOK_DATE_FORMAT),
+ channel_restriction_plan_id)
+ if rcode != 0:
+ raise ValidationError(_("Can't fetch restriction plans from wubook"), {
+ 'message': results,
+ 'channel_restriction_plan_id': channel_restriction_plan_id,
+ 'date_from': date_from,
+ 'date_to': date_to,
+ })
+ return results
+
+ def update_rplan_values(self, channel_restriction_plan_id, date_from, values):
+ rcode, results = self._server.rplan_update_rplan_values(
+ self._session_info[0],
+ self._session_info[1],
+ channel_restriction_plan_id,
+ date_utils(date_from).strftime(DEFAULT_WUBOOK_DATE_FORMAT),
+ values)
+ if rcode != 0:
+ raise ValidationError(_("Can't update plan restrictions on wubook"), {
+ 'message': results,
+ 'channel_restriction_plan_id': channel_restriction_plan_id,
+ 'date_from': date_from,
+ })
+ return results
+
+ def create_rplan(self, name, compact=False):
+ rcode, results = self._server.rplan_add_rplan(
+ self._session_info[0],
+ self._session_info[1],
+ name,
+ compact and 1 or 0)
+ if rcode != 0:
+ raise ValidationError(_("Can't create plan restriction in wubook"), {
+ 'message': results,
+ })
+ return results
+
+ def rename_rplan(self, channel_restriction_plan_id, new_name):
+ rcode, results = self._server.rplan_rename_rplan(
+ self._session_info[0],
+ self._session_info[1],
+ channel_restriction_plan_id,
+ new_name)
+ if rcode != 0:
+ raise ValidationError(_("Can't rename plan restriction in wubook"), {
+ 'message': results,
+ 'channel_restriction_plan_id': channel_restriction_plan_id,
+ })
+ return results
+
+ def delete_rplan(self, channel_restriction_plan_id):
+ rcode, results = self._server.rplan_del_rplan(
+ self._session_info[0],
+ self._session_info[1],
+ channel_restriction_plan_id)
+ if rcode != 0:
+ raise ValidationError(_("Can't delete plan restriction on wubook"), {
+ 'message': results,
+ 'channel_restriction_plan_id': channel_restriction_plan_id,
+ })
+ return results
+
+ def get_channels_info(self):
+ results = self._server.get_channels_info(self._session_info[0])
+ if not any(results):
+ raise ValidationError(_("Can't import channels info from wubook"), {
+ 'message': results,
+ })
+ return results
diff --git a/hotel_channel_connector/components/binder.py b/hotel_channel_connector/components/binder.py
new file mode 100644
index 000000000..45dd234cd
--- /dev/null
+++ b/hotel_channel_connector/components/binder.py
@@ -0,0 +1,8 @@
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+from odoo.addons.component.core import Component
+
+class HotelConnectorModelBinder(Component):
+ _name = 'hotel.channel.connector.binder'
+ _inherit = ['base.binder', 'base.hotel.channel.connector']
+ _apply_on = []
diff --git a/hotel_channel_connector/components/core.py b/hotel_channel_connector/components/core.py
new file mode 100644
index 000000000..7cdea7605
--- /dev/null
+++ b/hotel_channel_connector/components/core.py
@@ -0,0 +1,19 @@
+from odoo.addons.component.core import AbstractComponent
+
+
+class BaseHotelChannelConnectorComponent(AbstractComponent):
+ _name = 'base.hotel.channel.connector'
+ _inherit = 'base.connector'
+ _collection = 'hotel.channel.backend'
+
+ @api.model
+ def create_issue(self, section, message, wmessage, wid=False,
+ dfrom=False, dto=False):
+ self.env['hotel.channel.connector.issue'].sudo().create({
+ 'section': section,
+ 'message': message,
+ 'wid': wid,
+ 'wmessage': wmessage,
+ 'date_start': dfrom and dfrom.strftime(DEFAULT_SERVER_DATE_FORMAT),
+ 'date_end': dto and dto.strftime(DEFAULT_SERVER_DATE_FORMAT),
+ })
diff --git a/hotel_channel_connector/components/exporter.py b/hotel_channel_connector/components/exporter.py
new file mode 100644
index 000000000..16080ec73
--- /dev/null
+++ b/hotel_channel_connector/components/exporter.py
@@ -0,0 +1,169 @@
+# 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 AbstractComponent
+from odoo.tools import (
+ DEFAULT_SERVER_DATE_FORMAT,
+ DEFAULT_SERVER_DATETIME_FORMAT)
+from .backend_adapter import DEFAULT_WUBOOK_DATE_FORMAT
+from odoo.addons.hotel import date_utils
+_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_availability(self):
+ vroom_avail_ids = self.env['hotel.virtual.room.availability'].search([
+ ('wpushed', '=', False),
+ ('date', '>=', date_utils.now(hours=False).strftime(
+ DEFAULT_SERVER_DATE_FORMAT))
+ ])
+
+ vrooms = vroom_avail_ids.mapped('virtual_room_id')
+ avails = []
+ for vroom in vrooms:
+ vroom_avails = vroom_avail_ids.filtered(
+ lambda x: x.virtual_room_id.id == vroom.id)
+ days = []
+ for vroom_avail in vroom_avails:
+ vroom_avail.with_context({
+ 'wubook_action': False}).write({'wpushed': True})
+ wavail = vroom_avail.avail
+ if wavail > vroom_avail.wmax_avail:
+ wavail = vroom_avail.wmax_avail
+ date_dt = date_utils.get_datetime(
+ vroom_avail.date,
+ dtformat=DEFAULT_SERVER_DATE_FORMAT)
+ days.append({
+ 'date': date_dt.strftime(DEFAULT_WUBOOK_DATE_FORMAT),
+ 'avail': wavail,
+ 'no_ota': vroom_avail.no_ota and 1 or 0,
+ # 'booked': vroom_avail.booked and 1 or 0,
+ })
+ avails.append({'id': vroom.wrid, 'days': days})
+ _logger.info("UPDATING AVAILABILITY IN WUBOOK...")
+ _logger.info(avails)
+ if any(avails):
+ self.backend_adapter.update_availability(avails)
+ return True
+
+ @api.model
+ def push_priceplans(self):
+ unpushed = self.env['product.pricelist.item'].search([
+ ('wpushed', '=', False),
+ ('date_start', '>=', date_utils.now(hours=False).strftime(
+ DEFAULT_SERVER_DATE_FORMAT))
+ ], order="date_start ASC")
+ if any(unpushed):
+ date_start = date_utils.get_datetime(
+ unpushed[0].date_start,
+ dtformat=DEFAULT_SERVER_DATE_FORMAT)
+ date_end = date_utils.get_datetime(
+ unpushed[-1].date_start,
+ dtformat=DEFAULT_SERVER_DATE_FORMAT)
+ days_diff = date_utils.date_diff(date_start, date_end, hours=False) + 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:
+ vroom = self.env['hotel.room.type'].search([
+ ('product_id.product_tmpl_id', '=', pt_id.id)
+ ], limit=1)
+ if vroom:
+ prices[pr.wpid].update({vroom.wrid: []})
+ for i in range(0, days_diff):
+ prod = vroom.product_id.with_context({
+ 'quantity': 1,
+ 'pricelist': pr.id,
+ 'date': (date_start + timedelta(days=i)).
+ strftime(DEFAULT_SERVER_DATE_FORMAT),
+ })
+ prices[pr.wpid][vroom.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):
+ vroom_rest_obj = self.env['hotel.virtual.room.restriction']
+ rest_item_obj = self.env['hotel.virtual.room.restriction.item']
+ unpushed = rest_item_obj.search([
+ ('wpushed', '=', False),
+ ('date_start', '>=', date_utils.now(hours=False).strftime(
+ DEFAULT_SERVER_DATE_FORMAT))
+ ], order="date_start ASC")
+ if any(unpushed):
+ date_start = date_utils.get_datetime(
+ unpushed[0].date_start,
+ dtformat=DEFAULT_SERVER_DATE_FORMAT)
+ date_end = date_utils.get_datetime(
+ unpushed[-1].date_start,
+ dtformat=DEFAULT_SERVER_DATE_FORMAT)
+ days_diff = date_utils.date_diff(
+ date_start,
+ date_end,
+ hours=False) + 1
+ restrictions = {}
+ restriction_plan_ids = vroom_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)
+ ])
+ virtual_room_ids = unpushed_rp.mapped('virtual_room_id')
+ for vroom in virtual_room_ids:
+ restrictions[rp.wpid].update({vroom.wrid: []})
+ for i in range(0, days_diff):
+ ndate_dt = date_start + timedelta(days=i)
+ restr = vroom.get_restrictions(
+ ndate_dt.strftime(DEFAULT_SERVER_DATE_FORMAT))
+ if restr:
+ restrictions[rp.wpid][vroom.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][vroom.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/components/importer.py b/hotel_channel_connector/components/importer.py
new file mode 100644
index 000000000..1e7832046
--- /dev/null
+++ b/hotel_channel_connector/components/importer.py
@@ -0,0 +1,871 @@
+# 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 AbstractComponent
+from odoo.tools import (
+ DEFAULT_SERVER_DATE_FORMAT,
+ DEFAULT_SERVER_DATETIME_FORMAT)
+from .backend_adapter import DEFAULT_WUBOOK_DATE_FORMAT
+_logger = logging.getLogger(__name__)
+
+class HotelChannelConnectorImporter(AbstractComponent):
+ _name = 'hotel.channel.importer'
+ _inherit = ['base.importer', 'base.hotel.channel.connector']
+ _usage = 'channel.importer'
+
+ @api.model
+ def _get_room_values_availability(self, vroom_id, date_str, day_vals, set_wmax_avail):
+ virtual_room_avail_obj = self.env['hotel.virtual.room.availability']
+ vroom_avail = virtual_room_avail_obj.search([
+ ('virtual_room_id', '=', vroom_id),
+ ('date', '=', date_str)
+ ], limit=1)
+ vals = {
+ 'no_ota': day_vals.get('no_ota'),
+ 'booked': day_vals.get('booked'),
+ 'avail': day_vals.get('avail', 0),
+ 'wpushed': True,
+ }
+ if set_wmax_avail:
+ vals.update({'wmax_avail': day_vals.get('avail', 0)})
+ if vroom_avail:
+ vroom_avail.with_context({
+ 'wubook_action': False,
+ }).write(vals)
+ else:
+ vals.update({
+ 'virtual_room_id': vroom_id,
+ 'date': date_str,
+ })
+ virtual_room_avail_obj.with_context({
+ 'wubook_action': False,
+ 'mail_create_nosubscribe': True,
+ }).create(vals)
+
+ @api.model
+ def _get_room_values_restrictions(self, restriction_plan_id, vroom_id, date_str, day_vals):
+ vroom_restr_item_obj = self.env['hotel.virtual.room.restriction.item']
+ vroom_restr = vroom_restr_item_obj.search([
+ ('virtual_room_id', '=', vroom_id),
+ ('applied_on', '=', '0_virtual_room'),
+ ('date_start', '=', date_str),
+ ('date_end', '=', date_str),
+ ('restriction_id', '=', restriction_plan_id),
+ ])
+ vals = {
+ 'min_stay': int(day_vals.get('min_stay', 0)),
+ 'min_stay_arrival': int(day_vals.get(
+ 'min_stay_arrival',
+ 0)),
+ 'max_stay': int(day_vals.get('max_stay', 0)),
+ 'max_stay_arrival': int(day_vals.get(
+ 'max_stay_arrival',
+ 0)),
+ 'closed': int(day_vals.get('closed', False)),
+ 'closed_departure': int(day_vals.get(
+ 'closed_departure',
+ False)),
+ 'closed_arrival': int(day_vals.get(
+ 'closed_arrival',
+ False)),
+ 'wpushed': True,
+ }
+ if vroom_restr:
+ vroom_restr.with_context({
+ 'wubook_action': False,
+ }).write(vals)
+ else:
+ vals.update({
+ 'restriction_id': restriction_plan_id,
+ 'virtual_room_id': vroom_id,
+ 'date_start': date_str,
+ 'date_end': date_str,
+ 'applied_on': '0_virtual_room',
+ })
+ vroom_restr_item_obj.with_context({
+ 'wubook_action': False,
+ }).create(vals)
+
+ @api.model
+ def _generate_room_values(self, dfrom, dto, values, set_wmax_avail=False):
+ virtual_room_restr_obj = self.env['hotel.virtual.room.restriction']
+ hotel_virtual_room_obj = self.env['hotel.room.type']
+ def_restr_plan = virtual_room_restr_obj.search([('wpid', '=', '0')])
+ _logger.info("==== ROOM VALUES (%s -- %s)", dfrom, dto)
+ _logger.info(values)
+ for k_rid, v_rid in values.iteritems():
+ vroom = hotel_virtual_room_obj.search([
+ ('wrid', '=', k_rid)
+ ], limit=1)
+ if vroom:
+ date_dt = date_utils.get_datetime(
+ dfrom,
+ dtformat=DEFAULT_WUBOOK_DATE_FORMAT)
+ for day_vals in v_rid:
+ date_str = date_dt.strftime(DEFAULT_SERVER_DATE_FORMAT)
+ self._get_room_values_availability(
+ vroom.id,
+ date_str,
+ day_vals,
+ set_wmax_avail)
+ if def_restr_plan:
+ self._get_room_values_restrictions(
+ def_restr_plan.id,
+ vroom.id,
+ date_str,
+ day_vals)
+ date_dt = date_dt + timedelta(days=1)
+ return True
+
+ @api.model
+ def _generate_booking_vals(self, broom, checkin_str, checkout_str,
+ is_cancellation, wchannel_info, wstatus, crcode,
+ rcode, vroom, split_booking, dates_checkin,
+ dates_checkout, book):
+ # Generate Reservation Day Lines
+ reservation_line_ids = []
+ tprice = 0.0
+ for brday in broom['roomdays']:
+ wndate = date_utils.get_datetime(
+ brday['day'],
+ dtformat=DEFAULT_WUBOOK_DATE_FORMAT
+ ).replace(tzinfo=pytz.utc)
+ if date_utils.date_in(wndate,
+ dates_checkin[0],
+ dates_checkout[0] - timedelta(days=1),
+ hours=False) == 0:
+ reservation_line_ids.append((0, False, {
+ 'date': wndate.strftime(
+ DEFAULT_SERVER_DATE_FORMAT),
+ 'price': brday['price']
+ }))
+ tprice += brday['price']
+ persons = vroom.wcapacity
+ if 'ancillary' in broom and 'guests' in broom['ancillary']:
+ persons = broom['ancillary']['guests']
+ vals = {
+ 'checkin': checkin_str,
+ 'checkout': checkout_str,
+ 'adults': persons,
+ 'children': book['children'],
+ '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,
+ 'to_read': True,
+ 'state': is_cancellation and 'cancelled' or 'draft',
+ 'virtual_room_id': vroom.id,
+ 'splitted': split_booking,
+ 'wbook_json': json.dumps(book),
+ 'wmodified': book['was_modified']
+ }
+ _logger.info("===== CONTRUCT RESERV")
+ _logger.info(vals)
+ return vals
+
+ @api.model
+ def _generate_partner_vals(self, book):
+ country_id = self.env['res.country'].search([
+ ('code', '=', str(book['customer_country']))
+ ], limit=1)
+ # lang = self.env['res.lang'].search([('code', '=', book['customer_language_iso'])], limit=1)
+ return {
+ 'name': "%s, %s" %
+ (book['customer_surname'], book['customer_name']),
+ 'country_id': country_id and country_id.id,
+ 'city': book['customer_city'],
+ 'phone': book['customer_phone'],
+ 'zip': book['customer_zip'],
+ 'street': book['customer_address'],
+ 'email': book['customer_mail'],
+ 'unconfirmed': True,
+ # 'lang': lang and lang.id,
+ }
+
+ # FIXME: Super big method!!! O_o
+ @api.model
+ def _generate_reservations(self, bookings):
+ _logger.info("=== BOOKINGS FROM WUBOOK")
+ _logger.info(bookings)
+ default_arrival_hour = self.env['ir.default'].sudo().get(
+ 'hotel.config.settings', 'default_arrival_hour')
+ default_departure_hour = self.env['ir.default'].sudo().get(
+ 'hotel.config.settings', 'default_departure_hour')
+
+ # Get user timezone
+ tz_hotel = self.env['ir.default'].sudo().get(
+ 'hotel.config.settings', 'tz_hotel')
+ res_partner_obj = self.env['res.partner']
+ hotel_reserv_obj = self.env['hotel.reservation']
+ hotel_folio_obj = self.env['hotel.folio']
+ hotel_vroom_obj = self.env['hotel.room.type']
+ # Space for store some data for construct folios
+ processed_rids = []
+ failed_reservations = []
+ checkin_utc_dt = False
+ checkout_utc_dt = False
+ split_booking = False
+ for book in bookings: # This create a new folio
+ splitted_map = {}
+ is_cancellation = book['status'] in WUBOOK_STATUS_BAD
+ bstatus = str(book['status'])
+ rcode = str(book['reservation_code'])
+ crcode = str(book['channel_reservation_code']) \
+ if book['channel_reservation_code'] else 'undefined'
+
+ # Can't process failed reservations
+ # (for example set a invalid new reservation and receive in
+ # the same transaction an cancellation)
+ if crcode in failed_reservations:
+ self.create_channel_connector_issue(
+ 'reservation',
+ "Can't process a reservation that previusly failed!",
+ '', wid=book['reservation_code'])
+ continue
+
+ # Get dates for the reservation (GMT->UTC)
+ arr_hour = default_arrival_hour if book['arrival_hour'] == "--" \
+ else book['arrival_hour']
+ checkin = "%s %s" % (book['date_arrival'], arr_hour)
+ checkin_dt = date_utils.get_datetime(
+ checkin,
+ dtformat=DEFAULT_WUBOOK_DATETIME_FORMAT,
+ stz=tz_hotel)
+ checkin_utc_dt = date_utils.dt_as_timezone(checkin_dt, 'UTC')
+ checkin = checkin_utc_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
+
+ checkout = "%s %s" % (book['date_departure'],
+ default_departure_hour)
+ checkout_dt = date_utils.get_datetime(
+ checkout,
+ dtformat=DEFAULT_WUBOOK_DATETIME_FORMAT,
+ stz=tz_hotel)
+ checkout_utc_dt = date_utils.dt_as_timezone(checkout_dt, 'UTC')
+ checkout = checkout_utc_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
+
+ # Search Folio. If exists.
+ folio_id = False
+ if crcode != 'undefined':
+ reserv_folio = hotel_reserv_obj.search([
+ ('wchannel_reservation_code', '=', crcode)
+ ], limit=1)
+ if reserv_folio:
+ folio_id = reserv_folio.folio_id
+ else:
+ reserv_folio = hotel_reserv_obj.search([
+ ('wrid', '=', rcode)
+ ], limit=1)
+ if reserv_folio:
+ folio_id = reserv_folio.folio_id
+
+ # Need update reservations?
+ sreservs = hotel_reserv_obj.search([('wrid', '=', rcode)])
+ reservs = folio_id.room_lines if folio_id else sreservs
+ reservs_processed = False
+ if any(reservs):
+ folio_id = reservs[0].folio_id
+ for reserv in reservs:
+ if reserv.wrid == rcode:
+ reserv.with_context({'wubook_action': False}).write({
+ 'wstatus': str(book['status']),
+ 'wstatus_reason': book.get('status_reason', ''),
+ 'to_read': True,
+ 'to_assign': True,
+ 'price_unit': book['amount'],
+ 'wcustomer_notes': book['customer_notes'],
+ 'wbook_json': json.dumps(book),
+ })
+ if reserv.partner_id.unconfirmed:
+ reserv.partner_id.write(
+ self._generate_partner_vals(book)
+ )
+ reservs_processed = True
+ if is_cancellation:
+ reserv.with_context({
+ 'wubook_action': False}).action_cancel()
+ elif reserv.state == 'cancelled':
+ reserv.with_context({
+ 'wubook_action': False,
+ }).write({
+ 'discount': 0.0,
+ 'state': 'confirm',
+ })
+
+ # Do Nothing if already processed 'wrid'
+ if reservs_processed:
+ processed_rids.append(rcode)
+ continue
+
+ # Search Customer
+ customer_mail = book.get('customer_mail', False)
+ partner_id = False
+ if customer_mail:
+ partner_id = res_partner_obj.search([
+ ('email', '=', customer_mail)
+ ], limit=1)
+ if not partner_id:
+ partner_id = res_partner_obj.create(self._generate_partner_vals(book))
+
+ # Search Wubook Channel Info
+ wchannel_info = self.env['wubook.channel.info'].search(
+ [('wid', '=', str(book['id_channel']))], limit=1)
+
+ reservations = []
+ used_rooms = []
+ # Iterate booked rooms
+ for broom in book['booked_rooms']:
+ vroom = hotel_vroom_obj.search([
+ ('wrid', '=', broom['room_id'])
+ ], limit=1)
+ if not vroom:
+ self.create_channel_connector_issue(
+ 'reservation',
+ "Can't found any virtual room associated to '%s' \
+ in this hotel" % book['rooms'],
+ '', wid=book['reservation_code'])
+ failed_reservations.append(crcode)
+ continue
+
+ dates_checkin = [checkin_utc_dt, False]
+ dates_checkout = [checkout_utc_dt, False]
+ split_booking = False
+ split_booking_parent = False
+ # This perhaps create splitted reservation
+ while dates_checkin[0]:
+ checkin_str = dates_checkin[0].strftime(
+ DEFAULT_SERVER_DATETIME_FORMAT)
+ checkout_str = dates_checkout[0].strftime(
+ DEFAULT_SERVER_DATETIME_FORMAT)
+ vals = self._generate_booking_vals(
+ broom,
+ checkin_str,
+ checkout_str,
+ is_cancellation,
+ wchannel_info,
+ bstatus,
+ crcode,
+ rcode,
+ vroom,
+ split_booking,
+ dates_checkin,
+ dates_checkout,
+ book,
+ )
+ if vals['price_unit'] != book['amount']:
+ self.create_channel_connector_issue(
+ 'reservation',
+ "Invalid reservation total price! %.2f != %.2f" % (vals['price_unit'], book['amount']),
+ '', wid=book['reservation_code'])
+
+ free_rooms = hotel_vroom_obj.check_availability_virtual_room(
+ checkin_str,
+ checkout_str,
+ virtual_room_id=vroom.id,
+ notthis=used_rooms)
+ if any(free_rooms):
+ vals.update({
+ 'product_id': free_rooms[0].product_id.id,
+ 'name': free_rooms[0].name,
+ })
+ reservations.append((0, False, vals))
+ used_rooms.append(free_rooms[0].id)
+
+ if split_booking:
+ if not split_booking_parent:
+ split_booking_parent = len(reservations)
+ else:
+ splitted_map.setdefault(
+ split_booking_parent,
+ []).append(len(reservations))
+ dates_checkin = [dates_checkin[1], False]
+ dates_checkout = [dates_checkout[1], False]
+ else:
+ date_diff = (dates_checkout[0].replace(
+ hour=0, minute=0, second=0,
+ microsecond=0) -
+ dates_checkin[0].replace(
+ hour=0, minute=0, second=0,
+ microsecond=0)).days
+ if date_diff <= 0:
+ if split_booking:
+ if split_booking_parent:
+ del reservations[split_booking_parent-1:]
+ if split_booking_parent in splitted_map:
+ del splitted_map[split_booking_parent]
+ # Can't found space for reservation
+ vals = self._generate_booking_vals(
+ broom,
+ checkin_utc_dt,
+ checkout_utc_dt,
+ is_cancellation,
+ wchannel_info,
+ bstatus,
+ crcode,
+ rcode,
+ vroom,
+ False,
+ (checkin_utc_dt, False),
+ (checkout_utc_dt, False),
+ book,
+ )
+ vals.update({
+ 'product_id':
+ vroom.room_ids[0].product_id.id,
+ 'name': vroom.name,
+ 'overbooking': True,
+ })
+ reservations.append((0, False, vals))
+ self.create_channel_connector_issue(
+ 'reservation',
+ "Reservation imported with overbooking state",
+ '', wid=rcode)
+ dates_checkin = [False, False]
+ dates_checkout = [False, False]
+ split_booking = False
+ else:
+ split_booking = True
+ dates_checkin = [
+ dates_checkin[0],
+ dates_checkin[0] + timedelta(days=date_diff-1)
+ ]
+ dates_checkout = [
+ dates_checkout[0] - timedelta(days=1),
+ checkout_utc_dt
+ ]
+
+ if split_booking:
+ self.create_channel_connector_issue(
+ 'reservation',
+ "Reservation Splitted",
+ '', wid=rcode)
+
+ # Create Folio
+ if not any(failed_reservations) and any(reservations):
+ try:
+ # TODO: Improve 'addons_list' & discounts
+ addons = str(book['addons_list']) if any(book['addons_list']) else ''
+ discounts = book.get('discount', '')
+ vals = {
+ 'room_lines': reservations,
+ 'wcustomer_notes': "%s\nADDONS:\n%s\nDISCOUNT:\n%s" % (
+ book['customer_notes'], addons, discounts),
+ 'channel_type': 'web',
+ }
+ _logger.info("=== FOLIO CREATE")
+ _logger.info(reservations)
+ if folio_id:
+ folio_id.with_context({
+ 'wubook_action': False}).write(vals)
+ else:
+ vals.update({
+ 'partner_id': partner_id.id,
+ 'wseed': book['sessionSeed']
+ })
+ folio_id = hotel_folio_obj.with_context({
+ 'wubook_action': False}).create(vals)
+
+ # Update Reservation Spitted Parents
+ sorted_rlines = folio_id.room_lines.sorted(key='id')
+ for k_pid, v_pid in splitted_map.iteritems():
+ preserv = sorted_rlines[k_pid-1]
+ for pid in v_pid:
+ creserv = sorted_rlines[pid-1]
+ creserv.parent_reservation = preserv.id
+
+ processed_rids.append(rcode)
+ except Exception as e_msg:
+ self.create_channel_connector_issue(
+ 'reservation',
+ e_msg[0],
+ '', wid=rcode)
+ failed_reservations.append(crcode)
+ return (processed_rids, any(failed_reservations),
+ checkin_utc_dt, checkout_utc_dt)
+
+ @api.model
+ def _generate_pricelists(self, price_plans):
+ product_listprice_obj = self.env['product.pricelist']
+ count = 0
+ for plan in price_plans:
+ if 'vpid' in plan:
+ continue # Ignore Virtual Plans
+
+ vals = {
+ 'name': plan['name'],
+ 'wdaily': plan['daily'] == 1,
+ }
+ plan_id = product_listprice_obj.search([
+ ('wpid', '=', str(plan['id']))
+ ], limit=1)
+ if not plan_id:
+ vals.update({
+ 'wpid': str(plan['id']),
+ })
+ product_listprice_obj.with_context({
+ 'wubook_action': False}).create(vals)
+ else:
+ plan_id.with_context({'wubook_action': False}).write(vals)
+ count = count + 1
+ return count
+
+ @api.model
+ def _generate_pricelist_items(self, channel_plan_id, date_from, date_to, plan_prices):
+ hotel_virtual_room_obj = self.env['hotel.room.type']
+ pricelist = self.env['product.pricelist'].search([
+ ('wpid', '=', channel_plan_id)
+ ], limit=1)
+ if pricelist:
+ pricelist_item_obj = self.env['product.pricelist.item']
+ dfrom_dt = date_utils.get_datetime(date_from)
+ dto_dt = date_utils.get_datetime(date_to)
+ days_diff = date_utils.date_diff(dfrom_dt, dto_dt, hours=False) + 1
+ for i in range(0, days_diff):
+ ndate_dt = dfrom_dt + timedelta(days=i)
+ for k_rid, v_rid in plan_prices.iteritems():
+ vroom = hotel_virtual_room_obj.search([
+ ('wrid', '=', k_rid)
+ ], limit=1)
+ if vroom:
+ pricelist_item = pricelist_item_obj.search([
+ ('pricelist_id', '=', pricelist.id),
+ ('date_start', '=', ndate_dt.strftime(
+ DEFAULT_SERVER_DATE_FORMAT)),
+ ('date_end', '=', ndate_dt.strftime(
+ DEFAULT_SERVER_DATE_FORMAT)),
+ ('compute_price', '=', 'fixed'),
+ ('applied_on', '=', '1_product'),
+ ('product_tmpl_id', '=', vroom.product_id.product_tmpl_id.id)
+ ], limit=1)
+ vals = {
+ 'fixed_price': plan_prices[k_rid][i],
+ 'wpushed': True,
+ }
+ if pricelist_item:
+ pricelist_item.with_context({
+ 'wubook_action': False}).write(vals)
+ else:
+ vals.update({
+ 'pricelist_id': pricelist.id,
+ 'date_start': ndate_dt.strftime(
+ DEFAULT_SERVER_DATE_FORMAT),
+ 'date_end': ndate_dt.strftime(
+ DEFAULT_SERVER_DATE_FORMAT),
+ 'compute_price': 'fixed',
+ 'applied_on': '1_product',
+ 'product_tmpl_id': vroom.product_id.product_tmpl_id.id
+ })
+ pricelist_item_obj.with_context({
+ 'wubook_action': False}).create(vals)
+ return True
+
+ @api.model
+ def _generate_restrictions(self, restriction_plans):
+ restriction_obj = self.env['hotel.virtual.room.restriction']
+ count = 0
+ for plan in restriction_plans:
+ vals = {
+ 'name': plan['name'],
+ }
+ plan_id = restriction_obj.search([
+ ('wpid', '=', str(plan['id']))
+ ], limit=1)
+ if not plan_id:
+ vals.update({
+ 'wpid': str(plan['id']),
+ })
+ restriction_obj.with_context({
+ 'wubook_action': False,
+ 'rules': plan.get('rules'),
+ }).create(vals)
+ else:
+ plan_id.with_context({'wubook_action': False}).write(vals)
+ count = count + 1
+ return count
+
+ @api.model
+ def _generate_restriction_items(self, plan_restrictions):
+ hotel_virtual_room_obj = self.env['hotel.room.type']
+ reserv_restriction_obj = self.env['hotel.virtual.room.restriction']
+ restriction_item_obj = self.env['hotel.virtual.room.restriction.item']
+ _logger.info("===== RESTRICTIONS")
+ _logger.info(plan_restrictions)
+ for k_rpid, v_rpid in plan_restrictions.iteritems():
+ restriction_id = reserv_restriction_obj.search([
+ ('wpid', '=', k_rpid)
+ ], limit=1)
+ if restriction_id:
+ for k_rid, v_rid in v_rpid.iteritems():
+ vroom = hotel_virtual_room_obj.search([
+ ('wrid', '=', k_rid)
+ ], limit=1)
+ if vroom:
+ for item in v_rid:
+ date_dt = date_utils.get_datetime(
+ item['date'],
+ dtformat=DEFAULT_WUBOOK_DATE_FORMAT)
+ restriction_item = restriction_item_obj.search([
+ ('restriction_id', '=', restriction_id.id),
+ ('date_start', '=', date_dt.strftime(
+ DEFAULT_SERVER_DATE_FORMAT)),
+ ('date_end', '=', date_dt.strftime(
+ DEFAULT_SERVER_DATE_FORMAT)),
+ ('applied_on', '=', '0_virtual_room'),
+ ('virtual_room_id', '=', vroom.id)
+ ], limit=1)
+ vals = {
+ 'closed_arrival': item['closed_arrival'],
+ 'closed': item['closed'],
+ 'min_stay': item['min_stay'],
+ 'closed_departure': item['closed_departure'],
+ 'max_stay': item['max_stay'],
+ 'max_stay_arrival': item['max_stay_arrival'],
+ 'min_stay_arrival': item['min_stay_arrival'],
+ 'wpushed': True,
+ }
+ if restriction_item:
+ restriction_item.with_context({
+ 'wubook_action': False}).write(vals)
+ else:
+ vals.update({
+ 'restriction_id': restriction_id.id,
+ 'date_start': date_dt.strftime(
+ DEFAULT_SERVER_DATE_FORMAT),
+ 'date_end': date_dt.strftime(
+ DEFAULT_SERVER_DATE_FORMAT),
+ 'applied_on': '0_virtual_room',
+ 'virtual_room_id': vroom.id
+ })
+ restriction_item_obj.with_context({
+ 'wubook_action': False}).create(vals)
+
+ return True
+
+ @api.model
+ def _generate_wubook_channel_info(self, channels):
+ channel_info_obj = self.env['wubook.channel.info']
+ count = 0
+ for k_cid, v_cid in channels.iteritems():
+ vals = {
+ 'name': v_cid['name'],
+ 'ical': v_cid['ical'] == 1,
+ }
+ channel_info = channel_info_obj.search([
+ ('wid', '=', k_cid)
+ ], limit=1)
+ if channel_info:
+ channel_info.write(vals)
+ else:
+ vals.update({
+ 'wid': k_cid
+ })
+ channel_info_obj.create(vals)
+ count = count + 1
+ return count
+
+ @api.model
+ def get_rooms(self):
+ count = 0
+ try:
+ results = self.backend_adapter.fetch_rooms()
+
+ vroom_obj = self.env['hotel.room.type']
+ count = len(results)
+ for room in results:
+ vals = {
+ 'name': room['name'],
+ 'wrid': room['id'],
+ 'wscode': room['shortname'],
+ 'list_price': room['price'],
+ 'wcapacity': room['occupancy'],
+ # 'max_real_rooms': room['availability'],
+ }
+ vroom = vroom_obj.search([('wrid', '=', room['id'])], limit=1)
+ if vroom:
+ vroom.with_context({'wubook_action': False}).write(vals)
+ else:
+ vroom_obj.with_context({'wubook_action': False}).create(vals)
+ except ValidationError:
+ self.create_issue('room', _("Can't import rooms from WuBook"), results)
+
+ return count
+
+ @api.model
+ def fetch_rooms_values(self, dfrom, dto, rooms=False,
+ set_wmax_avail=False):
+ # Sanitize Dates
+ now_dt = date_utils.now()
+ dfrom_dt = date_utils.get_datetime(dfrom)
+ dto_dt = date_utils.get_datetime(dto)
+ if dto_dt < now_dt:
+ return True
+ if dfrom_dt < now_dt:
+ dfrom_dt = now_dt
+ if dfrom_dt > dto_dt:
+ dtemp_dt = dfrom_dt
+ dfrom_dt = dto_dt
+ dto_dt = dtemp_dt
+
+ try:
+ results = self.backend_adapter.fetch_rooms_values(
+ dfrom_dt.strftime(DEFAULT_WUBOOK_DATE_FORMAT),
+ dto_dt.strftime(DEFAULT_WUBOOK_DATE_FORMAT),
+ rooms)
+ self.generate_room_values(dfrom, dto, results,
+ set_wmax_avail=set_wmax_avail)
+ except ValidationError:
+ self.create_issue('room', _("Can't fetch rooms values from WuBook"),
+ results, dfrom=dfrom, dto=dto)
+ return False
+ return True
+
+ @api.model
+ def fetch_new_bookings(self):
+ try:
+ results = self.backend_adapter.fetch_new_bookings()
+ processed_rids, errors, checkin_utc_dt, checkout_utc_dt = \
+ self._generate_reservations(results)
+ if any(processed_rids):
+ uniq_rids = list(set(processed_rids))
+ rcodeb, resultsb = self.backend_adapter.mark_bookings(uniq_rids)
+ if rcodeb != 0:
+ self.create_issue(
+ 'wubook',
+ _("Problem trying mark bookings (%s)") %
+ str(processed_rids),
+ '')
+ # Update Odoo availability (don't wait for wubook)
+ # This cause abuse service in first import!!
+ if checkin_utc_dt and checkout_utc_dt:
+ self.backend_adapter.fetch_rooms_values(
+ checkin_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT),
+ checkout_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT))
+ except ValidationError:
+ self.create_issue(
+ 'reservation',
+ _("Can't process reservations from wubook"),
+ results)
+ return False
+ return True
+
+ @api.model
+ def fetch_booking(self, channel_reservation_id):
+ try:
+ results = self.backend_adapter.fetch_booking(channel_reservation_id)
+ processed_rids, errors, checkin_utc_dt, checkout_utc_dt = \
+ self.generate_reservations(results)
+ if any(processed_rids):
+ self.backend_adapter.mark_bookings(list(set(processed_rids)))
+
+ # Update Odoo availability (don't wait for wubook)
+ if checkin_utc_dt and checkout_utc_dt:
+ self.backend_adapter.fetch_rooms_values(
+ checkin_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT),
+ checkout_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT))
+ except ValidationError:
+ self.create_channel_connector_issue(
+ 'reservation',
+ _("Can't process reservations from wubook"),
+ results, wid=wrid)
+ return False
+ return True
+
+ @api.model
+ def import_pricing_plans(self):
+ try:
+ results = self.backend_adapter.get_pricing_plans()
+ count = self._generate_pricelists(results)
+ except ValidationError:
+ self.create_issue(
+ 'plan',
+ _("Can't get pricing plans from wubook"),
+ results)
+ return 0
+ return count
+
+ @api.model
+ def fetch_plan_prices(self, channel_plan_id, date_from, date_to, rooms=None):
+ try:
+ results = self.backend_adapter.fetch_plan_prices(
+ channel_plan_id,
+ date_from,
+ date_to,
+ rooms)
+ self._generate_pricelist_items(channel_plan_id, date_from, date_to, results)
+ except ValidationError:
+ self.create_issue(
+ 'plan',
+ _("Can't fetch plan prices from wubook"),
+ results)
+ return False
+ return True
+
+ @api.model
+ def fetch_all_plan_prices(self, date_from, date_to, rooms=None):
+ no_errors = True
+ channel_plan_ids = self.env['product.pricelist'].search([
+ ('wpid', '!=', False), ('wpid', '!=', '')
+ ]).mapped('wpid')
+ if any(channel_plan_ids):
+ try:
+ for channel_plan_id in channel_plan_ids:
+ results = self.backend_adapter.fetch_plan_prices(
+ channel_plan_id,
+ date_from,
+ date_to,
+ rooms)
+ self._generate_pricelist_items(channel_plan_id, date_from, date_to, results)
+ except ValidationError:
+ self.create_issue(
+ 'plan',
+ "Can't fetch all plan prices from wubook!",
+ results, wid=channel_plan_id, dfrom=date_from, dto=date_to)
+ return False
+ return no_errors
+
+ @api.model
+ def import_restriction_plans(self):
+ try:
+ results = self.backend_adapter.rplan_rplans()
+ count = self._generate_restrictions(results)
+ except ValidationError:
+ self.create_issue(
+ 'rplan',
+ _("Can't fetch restriction plans from wubook"),
+ results)
+ return 0
+ return count
+
+ @api.model
+ def fetch_rplan_restrictions(self, date_from, date_to, channel_restriction_plan_id=False):
+ try:
+ results = self.backend_adapter.wired_rplan_get_rplan_values(
+ date_from,
+ date_to,
+ int(channel_restriction_plan_id))
+ if any(results):
+ self._generate_restriction_items(results)
+ except ValidationError:
+ self.create_issue(
+ 'rplan',
+ _("Can't fetch plan restrictions from wubook"),
+ results,
+ wid=channel_restriction_plan_id,
+ dfrom=date_from, dto=date_to)
+ return False
+ return True
+
+ @api.model
+ def import_channels_info(self):
+ try:
+ results = self.backend_adapter.get_channels_info()
+ count = self._generate_wubook_channel_info(results)
+ except ValidationError:
+ self.create_issue(
+ 'channel',
+ _("Can't import channels info from wubook"),
+ results)
+ return 0
+ return count
diff --git a/hotel_channel_connector/controllers/__init__.py b/hotel_channel_connector/controllers/__init__.py
index ccdb3ead6..4f27ee78d 100644
--- a/hotel_channel_connector/controllers/__init__.py
+++ b/hotel_channel_connector/controllers/__init__.py
@@ -1,22 +1,3 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import main
diff --git a/hotel_channel_connector/controllers/main.py b/hotel_channel_connector/controllers/main.py
index 50efa0d55..5e06b04f1 100644
--- a/hotel_channel_connector/controllers/main.py
+++ b/hotel_channel_connector/controllers/main.py
@@ -1,24 +1,5 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging
from openerp import http, _
from openerp.http import request
diff --git a/hotel_channel_connector/data/menus.xml b/hotel_channel_connector/data/menus.xml
index f6259ceb1..17dabeeb7 100644
--- a/hotel_channel_connector/data/menus.xml
+++ b/hotel_channel_connector/data/menus.xml
@@ -1,6 +1,5 @@
-
-
+
WuBook Channel Info
@@ -38,5 +37,4 @@
-
-
+
diff --git a/hotel_channel_connector/data/sequences.xml b/hotel_channel_connector/data/sequences.xml
index cb58030f8..4143cc28e 100644
--- a/hotel_channel_connector/data/sequences.xml
+++ b/hotel_channel_connector/data/sequences.xml
@@ -1,13 +1,11 @@
-
-
-
+
+
Virtual Room Short Code
- hotel.virtual.room
+ hotel.room.type
4
-
-
\ No newline at end of file
+
diff --git a/hotel_channel_connector/models/__init__.py b/hotel_channel_connector/models/__init__.py
index 16670f20c..df7e001e3 100644
--- a/hotel_channel_connector/models/__init__.py
+++ b/hotel_channel_connector/models/__init__.py
@@ -1,24 +1,5 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import res_config
from . import inherited_hotel_virtual_room
from . import inherited_product_pricelist
@@ -30,4 +11,4 @@ from . import inherited_hotel_reservation
from . import inherited_hotel_folio
from . import inherited_res_partner
from . import wubook_channel_info
-from . import wubook_issue
+from . import hotel_channel_connector_issue
diff --git a/hotel_channel_connector/models/hotel_channel_connector_issue.py b/hotel_channel_connector/models/hotel_channel_connector_issue.py
index 511812f1c..2d68b4404 100644
--- a/hotel_channel_connector/models/hotel_channel_connector_issue.py
+++ b/hotel_channel_connector/models/hotel_channel_connector_issue.py
@@ -1,24 +1,5 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields, api, _
from openerp.exceptions import ValidationError
@@ -34,7 +15,6 @@ class HotelChannelConnectorIssue(models.Model):
('plan', 'Price Plan'),
('room', 'Room'),
('avail', 'Availability')], required=True)
- channel_name = fields.Char("Channel Name")
to_read = fields.Boolean("To Read", default=True)
internal_message = fields.Char("Internal Message", old_name='message')
date_start = fields.Date("From", readonly=True)
diff --git a/hotel_channel_connector/models/inherited_hotel_folio.py b/hotel_channel_connector/models/inherited_hotel_folio.py
index e98a04f86..2fb23e6b2 100644
--- a/hotel_channel_connector/models/inherited_hotel_folio.py
+++ b/hotel_channel_connector/models/inherited_hotel_folio.py
@@ -1,24 +1,5 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields, api
diff --git a/hotel_channel_connector/models/inherited_hotel_reservation.py b/hotel_channel_connector/models/inherited_hotel_reservation.py
index 9369b10f2..1ded7f79d 100644
--- a/hotel_channel_connector/models/inherited_hotel_reservation.py
+++ b/hotel_channel_connector/models/inherited_hotel_reservation.py
@@ -1,24 +1,5 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging
from openerp import models, fields, api, _
from openerp.exceptions import UserError, ValidationError
diff --git a/hotel_channel_connector/models/inherited_hotel_virtual_room.py b/hotel_channel_connector/models/inherited_hotel_virtual_room.py
index 298bc2d1d..8f5c3f40e 100644
--- a/hotel_channel_connector/models/inherited_hotel_virtual_room.py
+++ b/hotel_channel_connector/models/inherited_hotel_virtual_room.py
@@ -1,30 +1,11 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields, api, _
from openerp.exceptions import ValidationError
class HotelVirtualRoom(models.Model):
- _inherit = 'hotel.virtual.room'
+ _inherit = 'hotel.room.type'
@api.depends('wcapacity')
@api.onchange('room_ids', 'room_type_ids')
@@ -39,14 +20,16 @@ class HotelVirtualRoom(models.Model):
@api.constrains('wcapacity')
def _check_wcapacity(self):
- if self.wcapacity < 1:
- raise ValidationError(_("wcapacity can't be less than one"))
+ for record in self:
+ if record.wcapacity < 1:
+ raise ValidationError(_("wcapacity can't be less than one"))
@api.multi
@api.constrains('wscode')
def _check_wscode(self):
- if len(self.wscode) > 4: # Wubook scode max. length
- raise ValidationError(_("SCODE Can't be longer than 4 characters"))
+ for record in self:
+ if len(record.wscode) > 4: # Wubook scode max. length
+ raise ValidationError(_("SCODE Can't be longer than 4 characters"))
@api.multi
def get_restrictions(self, date):
@@ -78,7 +61,7 @@ class HotelVirtualRoom(models.Model):
if self._context.get('wubook_action', True) and \
self.env['wubook'].is_valid_account():
seq_obj = self.env['ir.sequence']
- shortcode = seq_obj.next_by_code('hotel.virtual.room')[:4]
+ shortcode = seq_obj.next_by_code('hotel.room.type')[:4]
wrid = self.env['wubook'].create_room(
shortcode,
vroom.name,
diff --git a/hotel_channel_connector/models/inherited_product_pricelist.py b/hotel_channel_connector/models/inherited_product_pricelist.py
index 1fe9c646e..7681f0070 100644
--- a/hotel_channel_connector/models/inherited_product_pricelist.py
+++ b/hotel_channel_connector/models/inherited_product_pricelist.py
@@ -1,24 +1,5 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from datetime import datetime, timedelta
from openerp import models, fields, api, _
from openerp.exceptions import ValidationError
@@ -50,7 +31,7 @@ class ProductPricelist(models.Model):
if not min_date or not max_date:
return prices
days_diff = abs((max_date - min_date).days)
- vrooms = self.env['hotel.virtual.room'].search([
+ vrooms = self.env['hotel.room.type'].search([
('wrid', '!=', ''),
('wrid', '!=', False)
])
@@ -65,7 +46,7 @@ class ProductPricelist(models.Model):
uom=vroom.product_id.product_tmpl_id.uom_id.id)
prices[vroom.wrid].append(product_id.price)
else:
- vrooms = self.env['hotel.virtual.room'].search([
+ vrooms = self.env['hotel.room.type'].search([
('wrid', '!=', ''),
('wrid', '!=', False)
])
diff --git a/hotel_channel_connector/models/inherited_product_pricelist_item.py b/hotel_channel_connector/models/inherited_product_pricelist_item.py
index aedc234a1..c1c3a58f7 100644
--- a/hotel_channel_connector/models/inherited_product_pricelist_item.py
+++ b/hotel_channel_connector/models/inherited_product_pricelist_item.py
@@ -1,24 +1,5 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields, api
from openerp.exceptions import ValidationError
@@ -31,20 +12,22 @@ class ProductPricelistItem(models.Model):
@api.constrains('fixed_price')
def _check_fixed_price(self):
- vroom = self.env['hotel.virtual.room'].search([
- ('product_id.product_tmpl_id', '=', self.product_tmpl_id.id)
+ vroom_obj = self.env['hotel.room.type']
+ for record in self:
+ vroom = vroom_obj.search([
+ ('product_id.product_tmpl_id', '=', record.product_tmpl_id.id)
], limit=1)
- if vroom and vroom.wrid and self.compute_price == 'fixed' \
- and self.fixed_price <= 0.0:
- raise ValidationError(_("Price need be greater than zero"))
+ if vroom and vroom.wrid and record.compute_price == 'fixed' \
+ and record.fixed_price <= 0.0:
+ raise ValidationError(_("Price need be greater than zero"))
@api.model
def create(self, vals):
if self._context.get('wubook_action', True) and \
self.env['wubook'].is_valid_account():
pricelist_id = self.env['product.pricelist'].browse(
- vals.get('pricelist_id'))
- vroom = self.env['hotel.virtual.room'].search([
+ vals.get('pricelist_id'))
+ vroom = self.env['hotel.room.type'].search([
('product_id.product_tmpl_id', '=',
vals.get('product_tmpl_id')),
('wrid', '!=', False)
@@ -64,7 +47,7 @@ class ProductPricelistItem(models.Model):
record.pricelist_id
product_tmpl_id = vals.get('product_tmpl_id') or \
record.product_tmpl_id.id
- vroom = self.env['hotel.virtual.room'].search([
+ vroom = self.env['hotel.room.type'].search([
('product_id.product_tmpl_id', '=', product_tmpl_id),
('wrid', '!=', False)
])
diff --git a/hotel_channel_connector/models/inherited_res_partner.py b/hotel_channel_connector/models/inherited_res_partner.py
index 123e626b2..75afaecb9 100644
--- a/hotel_channel_connector/models/inherited_res_partner.py
+++ b/hotel_channel_connector/models/inherited_res_partner.py
@@ -1,23 +1,5 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields, api
diff --git a/hotel_channel_connector/models/inherited_reservation_restriction.py b/hotel_channel_connector/models/inherited_reservation_restriction.py
index 40243f0aa..5462500e3 100644
--- a/hotel_channel_connector/models/inherited_reservation_restriction.py
+++ b/hotel_channel_connector/models/inherited_reservation_restriction.py
@@ -1,24 +1,5 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from datetime import datetime, timedelta
from openerp import models, fields, api, _
from openerp.exceptions import ValidationError
@@ -49,7 +30,7 @@ class ReservationRestriction(models.Model):
if not min_date or not max_date:
return prices
days_diff = abs((max_date - min_date).days)
- vrooms = self.env['hotel.virtual.room'].search([
+ vrooms = self.env['hotel.room.type'].search([
('wrid', '!=', ''),
('wrid', '!=', False)
])
diff --git a/hotel_channel_connector/models/inherited_reservation_restriction_item.py b/hotel_channel_connector/models/inherited_reservation_restriction_item.py
index 95710accf..f771907da 100644
--- a/hotel_channel_connector/models/inherited_reservation_restriction_item.py
+++ b/hotel_channel_connector/models/inherited_reservation_restriction_item.py
@@ -1,24 +1,5 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields, api
diff --git a/hotel_channel_connector/models/inherited_virtual_room_availability.py b/hotel_channel_connector/models/inherited_virtual_room_availability.py
index 036d0def3..576bef901 100644
--- a/hotel_channel_connector/models/inherited_virtual_room_availability.py
+++ b/hotel_channel_connector/models/inherited_virtual_room_availability.py
@@ -1,24 +1,5 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from datetime import timedelta
from openerp import models, fields, api, _
from openerp.exceptions import ValidationError
@@ -42,42 +23,45 @@ class VirtualRoomAvailability(models.Model):
@api.constrains('avail')
def _check_avail(self):
- vroom_obj = self.env['hotel.virtual.room']
- cavail = len(vroom_obj.check_availability_virtual_room(
- self.date,
- self.date,
- virtual_room_id=self.virtual_room_id.id))
- max_avail = min(cavail,
- self.virtual_room_id.total_rooms_count)
- if self.avail > max_avail:
- self.env['wubook.issue'].sudo().create({
- 'section': 'avail',
- 'message': _("The new availability can't be greater than \
- the actual availability \
- \n[%s]\nInput: %d\Limit: %d") % (self.virtual_room_id.name,
- self.avail,
- max_avail),
- 'wid': self.virtual_room_id.wrid,
- 'date_start': self.date,
- 'date_end': self.date,
- })
- # Auto-Fix wubook availability
- date_dt = date_utils.get_datetime(self.date)
- self.env['wubook'].update_availability([{
- 'id': self.virtual_room_id.wrid,
- 'days': [{
- 'date': date_dt.strftime(DEFAULT_WUBOOK_DATE_FORMAT),
- 'avail': max_avail,
- }],
- }])
+ vroom_obj = self.env['hotel.room.type']
+ issue_obj = self.env['wubook.issue']
+ wubook_obj = self.env['wubook']
+ for record in self:
+ cavail = len(vroom_obj.check_availability_virtual_room(
+ record.date,
+ record.date,
+ virtual_room_id=record.virtual_room_id.id))
+ max_avail = min(cavail, record.virtual_room_id.total_rooms_count)
+ if record.avail > max_avail:
+ issue_obj.sudo().create({
+ 'section': 'avail',
+ 'message': _("The new availability can't be greater than \
+ the actual availability \
+ \n[%s]\nInput: %d\Limit: %d") % (record.virtual_room_id.name,
+ record.avail,
+ record),
+ 'wid': record.virtual_room_id.wrid,
+ 'date_start': record.date,
+ 'date_end': record.date,
+ })
+ # Auto-Fix wubook availability
+ date_dt = date_utils.get_datetime(record.date)
+ wubook_obj.update_availability([{
+ 'id': record.virtual_room_id.wrid,
+ 'days': [{
+ 'date': date_dt.strftime(DEFAULT_WUBOOK_DATE_FORMAT),
+ 'avail': max_avail,
+ }],
+ }])
return super(VirtualRoomAvailability, self)._check_avail()
@api.constrains('wmax_avail')
def _check_wmax_avail(self):
- if self.wmax_avail > self.virtual_room_id.total_rooms_count:
- raise ValidationError(_("max avail for wubook can't be high \
- than toal rooms \
- count: %d") % self.virtual_room_id.total_rooms_count)
+ for record in self:
+ if record.wmax_avail > record.virtual_room_id.total_rooms_count:
+ raise ValidationError(_("max avail for wubook can't be high \
+ than toal rooms \
+ count: %d") % record.virtual_room_id.total_rooms_count)
@api.onchange('virtual_room_id')
def onchange_virtual_room_id(self):
@@ -97,7 +81,7 @@ class VirtualRoomAvailability(models.Model):
# Not count end day of the reservation
date_diff = date_utils.date_diff(checkin, checkout, hours=False)
- vroom_obj = self.env['hotel.virtual.room']
+ vroom_obj = self.env['hotel.room.type']
virtual_room_avail_obj = self.env['hotel.virtual.room.availability']
vrooms = vroom_obj.search([
diff --git a/hotel_channel_connector/models/res_config.py b/hotel_channel_connector/models/res_config.py
index 6cda8dfff..479249564 100644
--- a/hotel_channel_connector/models/res_config.py
+++ b/hotel_channel_connector/models/res_config.py
@@ -1,24 +1,5 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import os
import binascii
import logging
@@ -93,9 +74,9 @@ class WubookConfiguration(models.TransientModel):
})
if wubook_obj.init_connection():
ir_seq_obj = self.env['ir.sequence']
- vrooms = self.env['hotel.virtual.room'].search([])
+ vrooms = self.env['hotel.room.type'].search([])
for vroom in vrooms:
- shortcode = ir_seq_obj.next_by_code('hotel.virtual.room')[:4]
+ shortcode = ir_seq_obj.next_by_code('hotel.room.type')[:4]
wrid = wubook_obj.create_room(
shortcode,
vroom.name,
diff --git a/hotel_channel_connector/models/wubook_channel_info.py b/hotel_channel_connector/models/wubook_channel_info.py
index 9a6fe35ae..72830aa89 100644
--- a/hotel_channel_connector/models/wubook_channel_info.py
+++ b/hotel_channel_connector/models/wubook_channel_info.py
@@ -1,24 +1,5 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# OpenERP, Open Source Management Solution
-# Copyright (C) 2017 Solucións Aloxa S.L.
-# Alexandre Díaz
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
+# Copyright 2018 Alexandre Díaz
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from openerp import models, fields, api
diff --git a/hotel_channel_connector/static/src/js/wubook_listview_import_buttons.js b/hotel_channel_connector/static/src/js/wubook_listview_import_buttons.js
index fbc78a968..bd27cead7 100644
--- a/hotel_channel_connector/static/src/js/wubook_listview_import_buttons.js
+++ b/hotel_channel_connector/static/src/js/wubook_listview_import_buttons.js
@@ -1,10 +1,9 @@
-odoo.define('wubook.listview_button_import_rooms', function(require) {
+odoo.define('hotel_channel_connector.listview_button_import_rooms', function(require) {
'use strict';
/*
- * Hotel WuBook
+ * Hotel Channel Connector
* GNU Public License
- * Aloxa Solucions S.L.
- * Alexandre Díaz
+ * Alexandre Díaz
*/
var ListView = require('web.ListView');
@@ -148,7 +147,7 @@ function push_availability(){
new Model('wubook').call('push_availability', [false]).then(function(results){
self.do_notify(_t('Operation Success'), _t('Availability successfully pushed'), false);
}).fail(function(){
- self.do_warn(_t('Operation Errors'), _t('Errors while pushing availability to WuBook. See issues log.'), true);
+ self.do_warn(_t('Operation Errors'), _t('Errors while pushing availability to Channel. See issues log.'), true);
});
return false;
@@ -158,30 +157,30 @@ ListView.include({
render_buttons: function () {
this._super.apply(this, arguments); // Sets this.$buttons
- if (this.dataset.model === 'hotel.virtual.room') {
- this.$buttons.append("");
- this.$buttons.find('.oe_wubook_import_rooms').on('click', import_rooms.bind(this));
+ if (this.dataset.model === 'hotel.room.type') {
+ this.$buttons.append("");
+ this.$buttons.find('.oe_channel_connector_import_rooms').on('click', import_rooms.bind(this));
} else if (this.dataset.model === 'hotel.folio') {
- this.$buttons.append("");
- this.$buttons.find('.oe_wubook_import_reservations').on('click', import_reservations.bind(this));
+ this.$buttons.append("");
+ this.$buttons.find('.oe_channel_connector_import_reservations').on('click', import_reservations.bind(this));
} else if (this.dataset.model === 'product.pricelist') {
- this.$buttons.append("");
- this.$buttons.find('.oe_wubook_import_price_plans').on('click', import_price_plans.bind(this));
- this.$buttons.append("");
- this.$buttons.find('.oe_wubook_push_price_plans').on('click', push_price_plans.bind(this));
+ this.$buttons.append("");
+ this.$buttons.find('.oe_channel_connector_import_price_plans').on('click', import_price_plans.bind(this));
+ this.$buttons.append("");
+ this.$buttons.find('.oe_channel_connector_push_price_plans').on('click', push_price_plans.bind(this));
} else if (this.dataset.model === 'wubook.channel.info') {
- this.$buttons.append("");
- this.$buttons.find('.oe_wubook_import_channels_info').on('click', import_channels_info.bind(this));
+ this.$buttons.append("");
+ this.$buttons.find('.oe_channel_connector_import_channels_info').on('click', import_channels_info.bind(this));
} else if (this.dataset.model === 'hotel.virtual.room.restriction') {
- this.$buttons.append("");
- this.$buttons.find('.oe_wubook_import_restriction_plans').on('click', import_restriction_plans.bind(this));
- this.$buttons.append("");
- this.$buttons.find('.oe_wubook_push_restriction_plans').on('click', push_restriction_plans.bind(this));
+ this.$buttons.append("");
+ this.$buttons.find('.oe_channel_connector_import_restriction_plans').on('click', import_restriction_plans.bind(this));
+ this.$buttons.append("");
+ this.$buttons.find('.oe_channel_connector_push_restriction_plans').on('click', push_restriction_plans.bind(this));
} else if (this.dataset.model === 'hotel.virtual.room.availability') {
- this.$buttons.append("");
- this.$buttons.find('.oe_wubook_import_availability').on('click', import_availability.bind(this));
- this.$buttons.append("");
- this.$buttons.find('.oe_wubook_push_availability').on('click', push_availability.bind(this));
+ this.$buttons.append("");
+ this.$buttons.find('.oe_channel_connector_import_availability').on('click', import_availability.bind(this));
+ this.$buttons.append("");
+ this.$buttons.find('.oe_channel_connector_push_availability').on('click', push_availability.bind(this));
}
}
});
diff --git a/hotel_channel_connector/tests/common.py b/hotel_channel_connector/tests/common.py
index 00859b10d..90d29b73b 100644
--- a/hotel_channel_connector/tests/common.py
+++ b/hotel_channel_connector/tests/common.py
@@ -45,12 +45,12 @@ class TestHotelWubook(TestHotel):
return True
@api.model
- def wubook_create_wubook_issue(self, section, message, wmessage,
+ def wubook_create_channel_connector_issue(self, section, message, wmessage,
wid=False, dfrom=False, dto=False):
_logger.info("ISSUE CREATED:\n\t- %s\n\t--- %s", section, message)
- cls.env['wubook']._patch_method('create_wubook_issue',
- wubook_create_wubook_issue)
+ cls.env['wubook']._patch_method('create_channel_connector_issue',
+ wubook_create_channel_connector_issue)
cls.env['wubook']._patch_method('is_valid_account', wubook_ommit)
cls.env['wubook']._patch_method('initialize', wubook_ommit)
cls.env['wubook']._patch_method('push_activation', wubook_ommit)
@@ -123,7 +123,7 @@ class TestHotelWubook(TestHotel):
rooms = []
rooms_occu = []
booked_rooms = []
- vroom_obj = self.env['hotel.virtual.room']
+ vroom_obj = self.env['hotel.room.type']
max_persons = 0
for k_room, v_room in rinfo.iteritems():
vroom = vroom_obj.search([
@@ -273,7 +273,7 @@ class TestHotelWubook(TestHotel):
@classmethod
def tearDownClass(cls):
# Remove mocks
- cls.env['wubook']._revert_method('create_wubook_issue')
+ cls.env['wubook']._revert_method('create_channel_connector_issue')
cls.env['wubook']._revert_method('is_valid_account')
cls.env['wubook']._revert_method('initialize')
cls.env['wubook']._revert_method('push_activation')
diff --git a/hotel_channel_connector/tests/test_hotel_virtual_room_model.py b/hotel_channel_connector/tests/test_hotel_virtual_room_model.py
index 91eb66363..691ffeaac 100644
--- a/hotel_channel_connector/tests/test_hotel_virtual_room_model.py
+++ b/hotel_channel_connector/tests/test_hotel_virtual_room_model.py
@@ -60,7 +60,7 @@ class TestHotelVirtualRoom(TestHotelWubook):
self.hotel_vroom_budget.sudo(self.user_hotel_manager).import_rooms()
def test_create(self):
- vroom_obj = self.env['hotel.virtual.room']
+ vroom_obj = self.env['hotel.room.type']
vroom = vroom_obj.sudo(self.user_hotel_manager).create({
'name': 'Budget Room',
'virtual_code': '001',
diff --git a/hotel_channel_connector/views/inherited_hotel_virtual_room_views.xml b/hotel_channel_connector/views/inherited_hotel_virtual_room_views.xml
index 64a54b3f0..0e8193b74 100644
--- a/hotel_channel_connector/views/inherited_hotel_virtual_room_views.xml
+++ b/hotel_channel_connector/views/inherited_hotel_virtual_room_views.xml
@@ -2,7 +2,7 @@
- hotel.virtual.room
+ hotel.room.type