mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
[WIP] Hotel Channel Connector
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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([
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<odoo>
|
||||
|
||||
<record id="virtual_room_view_form" model="ir.ui.view">
|
||||
<field name="model">hotel.virtual.room</field>
|
||||
<field name="model">hotel.room.type</field>
|
||||
<field name="inherit_id" ref="hotel.virtual_room_view_form" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='name']" position="after">
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,22 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from . import models
|
||||
|
||||
@@ -1,25 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# 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
|
||||
|
||||
@@ -1,24 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# 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
|
||||
|
||||
@@ -1,24 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from openerp import models, api
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# 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
|
||||
@@ -1,24 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# 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()
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -1,23 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from . import test_folio
|
||||
|
||||
@@ -1,25 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# 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
|
||||
|
||||
@@ -1,25 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# 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
|
||||
|
||||
@@ -1,33 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# 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.) <alex@aloxa.eu>",
|
||||
'author': "Alexandre Díaz <dev@redneboa.es>",
|
||||
'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',
|
||||
],
|
||||
|
||||
7
hotel_channel_connector/components/__init__.py
Normal file
7
hotel_channel_connector/components/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# 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
|
||||
552
hotel_channel_connector/components/backend_adapter.py
Normal file
552
hotel_channel_connector/components/backend_adapter.py
Normal file
@@ -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
|
||||
8
hotel_channel_connector/components/binder.py
Normal file
8
hotel_channel_connector/components/binder.py
Normal file
@@ -0,0 +1,8 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# 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 = []
|
||||
19
hotel_channel_connector/components/core.py
Normal file
19
hotel_channel_connector/components/core.py
Normal file
@@ -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),
|
||||
})
|
||||
169
hotel_channel_connector/components/exporter.py
Normal file
169
hotel_channel_connector/components/exporter.py
Normal file
@@ -0,0 +1,169 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# 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
|
||||
871
hotel_channel_connector/components/importer.py
Normal file
871
hotel_channel_connector/components/importer.py
Normal file
@@ -0,0 +1,871 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# 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
|
||||
@@ -1,22 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from . import main
|
||||
|
||||
@@ -1,24 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
import logging
|
||||
from openerp import http, _
|
||||
from openerp.http import request
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<odoo>
|
||||
|
||||
<record model="ir.actions.act_window" id="open_wubook_channel_info_tree_all">
|
||||
<field name="name">WuBook Channel Info</field>
|
||||
@@ -38,5 +37,4 @@
|
||||
<menuitem id="wubook_config_menu" name="Settings"
|
||||
sequence="3" action="action_wubook_config" parent="wubook_menu"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<odoo noupdate="1">
|
||||
|
||||
<record model="ir.sequence" id="seq_vroom_id">
|
||||
<field name="name">Virtual Room Short Code</field>
|
||||
<field name="code">hotel.virtual.room</field>
|
||||
<field name="code">hotel.room.type</field>
|
||||
<field name="prefix"></field>
|
||||
<field name="padding">4</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
</odoo>
|
||||
|
||||
@@ -1,24 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# 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
|
||||
|
||||
@@ -1,24 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# 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)
|
||||
|
||||
@@ -1,24 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from openerp import models, fields, api
|
||||
|
||||
|
||||
|
||||
@@ -1,24 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# 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
|
||||
|
||||
@@ -1,30 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# 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,
|
||||
|
||||
@@ -1,24 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# 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)
|
||||
])
|
||||
|
||||
@@ -1,24 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# 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)
|
||||
])
|
||||
|
||||
@@ -1,23 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from openerp import models, fields, api
|
||||
|
||||
|
||||
|
||||
@@ -1,24 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# 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)
|
||||
])
|
||||
|
||||
@@ -1,24 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from openerp import models, fields, api
|
||||
|
||||
|
||||
|
||||
@@ -1,24 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# 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([
|
||||
|
||||
@@ -1,24 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# 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,
|
||||
|
||||
@@ -1,24 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from openerp import models, fields, api
|
||||
|
||||
|
||||
|
||||
@@ -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. <info@aloxa.eu>
|
||||
* Alexandre Díaz <alex@aloxa.eu>
|
||||
* Alexandre Díaz <dev@redneboa.es>
|
||||
*/
|
||||
|
||||
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("<button class='oe_button oe_wubook_import_rooms oe_highlight' type='button'>"+_t('Fetch from WuBook')+"</button>");
|
||||
this.$buttons.find('.oe_wubook_import_rooms').on('click', import_rooms.bind(this));
|
||||
if (this.dataset.model === 'hotel.room.type') {
|
||||
this.$buttons.append("<button class='oe_button oe_channel_connector_import_rooms oe_highlight' type='button'>"+_t('Fetch from Channel')+"</button>");
|
||||
this.$buttons.find('.oe_channel_connector_import_rooms').on('click', import_rooms.bind(this));
|
||||
} else if (this.dataset.model === 'hotel.folio') {
|
||||
this.$buttons.append("<button class='oe_button oe_wubook_import_reservations oe_highlight' type='button'>"+_t('Fetch from WuBook')+"</button>");
|
||||
this.$buttons.find('.oe_wubook_import_reservations').on('click', import_reservations.bind(this));
|
||||
this.$buttons.append("<button class='oe_button oe_channel_connector_import_reservations oe_highlight' type='button'>"+_t('Fetch from Channel')+"</button>");
|
||||
this.$buttons.find('.oe_channel_connector_import_reservations').on('click', import_reservations.bind(this));
|
||||
} else if (this.dataset.model === 'product.pricelist') {
|
||||
this.$buttons.append("<button class='oe_button oe_wubook_import_price_plans oe_highlight' type='button'>"+_t('Fetch from WuBook')+"</button>");
|
||||
this.$buttons.find('.oe_wubook_import_price_plans').on('click', import_price_plans.bind(this));
|
||||
this.$buttons.append("<button class='oe_button oe_wubook_push_price_plans' style='background-color:red; color:white;' type='button'>"+_t('Push to WuBook')+"</button>");
|
||||
this.$buttons.find('.oe_wubook_push_price_plans').on('click', push_price_plans.bind(this));
|
||||
this.$buttons.append("<button class='oe_button oe_channel_connector_import_price_plans oe_highlight' type='button'>"+_t('Fetch from Channel')+"</button>");
|
||||
this.$buttons.find('.oe_channel_connector_import_price_plans').on('click', import_price_plans.bind(this));
|
||||
this.$buttons.append("<button class='oe_button oe_channel_connector_push_price_plans' style='background-color:red; color:white;' type='button'>"+_t('Push to Channel')+"</button>");
|
||||
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("<button class='oe_button oe_wubook_import_channels_info oe_highlight' type='button'>"+_t('Fetch from WuBook')+"</button>");
|
||||
this.$buttons.find('.oe_wubook_import_channels_info').on('click', import_channels_info.bind(this));
|
||||
this.$buttons.append("<button class='oe_button oe_channel_connector_import_channels_info oe_highlight' type='button'>"+_t('Fetch from Channel')+"</button>");
|
||||
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("<button class='oe_button oe_wubook_import_restriction_plans oe_highlight' type='button'>"+_t('Fetch from WuBook')+"</button>");
|
||||
this.$buttons.find('.oe_wubook_import_restriction_plans').on('click', import_restriction_plans.bind(this));
|
||||
this.$buttons.append("<button class='oe_button oe_wubook_push_restriction_plans' style='background-color:red; color:white;' type='button'>"+_t('Push to WuBook')+"</button>");
|
||||
this.$buttons.find('.oe_wubook_push_restriction_plans').on('click', push_restriction_plans.bind(this));
|
||||
this.$buttons.append("<button class='oe_button oe_channel_connector_import_restriction_plans oe_highlight' type='button'>"+_t('Fetch from Channel')+"</button>");
|
||||
this.$buttons.find('.oe_channel_connector_import_restriction_plans').on('click', import_restriction_plans.bind(this));
|
||||
this.$buttons.append("<button class='oe_button oe_channel_connector_push_restriction_plans' style='background-color:red; color:white;' type='button'>"+_t('Push to Channel')+"</button>");
|
||||
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("<button class='oe_button oe_wubook_import_availability oe_highlight' type='button'>"+_t('Fetch from WuBook')+"</button>");
|
||||
this.$buttons.find('.oe_wubook_import_availability').on('click', import_availability.bind(this));
|
||||
this.$buttons.append("<button class='oe_button oe_wubook_push_availability' style='background-color:red; color:white;' type='button'>"+_t('Push to WuBook')+"</button>");
|
||||
this.$buttons.find('.oe_wubook_push_availability').on('click', push_availability.bind(this));
|
||||
this.$buttons.append("<button class='oe_button oe_channel_connector_import_availability oe_highlight' type='button'>"+_t('Fetch from Channel')+"</button>");
|
||||
this.$buttons.find('.oe_channel_connector_import_availability').on('click', import_availability.bind(this));
|
||||
this.$buttons.append("<button class='oe_button oe_channel_connector_push_availability' style='background-color:red; color:white;' type='button'>"+_t('Push to Channel')+"</button>");
|
||||
this.$buttons.find('.oe_channel_connector_push_availability').on('click', push_availability.bind(this));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<odoo>
|
||||
|
||||
<record id="virtual_room_view_form" model="ir.ui.view">
|
||||
<field name="model">hotel.virtual.room</field>
|
||||
<field name="model">hotel.room.type</field>
|
||||
<field name="inherit_id" ref="hotel.virtual_room_view_form" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='name']" position="after">
|
||||
|
||||
Reference in New Issue
Block a user