mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
[WIP][MIG][11.0] Odoo Connector
This commit is contained in:
@@ -89,7 +89,7 @@ class HotelReservation(models.Model):
|
||||
'partner_phone': record.partner_id.mobile
|
||||
or record.partner_id.phone or _('Undefined'),
|
||||
'state': record.state,
|
||||
'fix_days': record.splitted or record.wis_from_channel,
|
||||
'fix_days': record.splitted or record.is_from_ota,
|
||||
'overbooking': record.overbooking,
|
||||
'price': record.folio_id.amount_total,
|
||||
'wrid': record.wrid,
|
||||
|
||||
@@ -7,13 +7,13 @@ class BaseHotelChannelConnectorComponent(AbstractComponent):
|
||||
_collection = 'hotel.channel.backend'
|
||||
|
||||
@api.model
|
||||
def create_issue(self, section, message, wmessage, wid=False,
|
||||
def create_issue(self, section, message, channel_message, channel_object_id=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),
|
||||
'channel_object_id': channel_object_id,
|
||||
'channel_message': channel_message,
|
||||
'date_start': dfrom,
|
||||
'date_end': dto,
|
||||
})
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from . import common
|
||||
37
hotel_channel_connector/models/channel_backend/common.py
Normal file
37
hotel_channel_connector/models/channel_backend/common.py
Normal file
@@ -0,0 +1,37 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
class ChannelBackend(models.Model):
|
||||
_name = 'channel.backend'
|
||||
_description = 'Hotel Channel Backend'
|
||||
_inherit = 'connector.backend'
|
||||
|
||||
@contextmanager
|
||||
@api.multi
|
||||
def work_on(self, model_name, **kwargs):
|
||||
self.ensure_one()
|
||||
lang = self.default_lang_id
|
||||
if lang.code != self.env.context.get('lang'):
|
||||
self = self.with_context(lang=lang.code)
|
||||
user = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'hotel_connector_user')
|
||||
passwd = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'hotel_connector_passwd')
|
||||
lcode = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'hotel_connector_lcode')
|
||||
pkey = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'hotel_connector_pkey')
|
||||
server_addr = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'hotel_connector_server')
|
||||
wubook_login = WuBookLogin(
|
||||
server_addr,
|
||||
user,
|
||||
passwd,
|
||||
lcode,
|
||||
pkey
|
||||
)
|
||||
with WuBookAdapter(wubook_login) as channel_api:
|
||||
_super = super(ChannelBackend, self)
|
||||
# from the components we'll be able to do: self.work.magento_api
|
||||
with _super.work_on(model_name, **kwargs) as work:
|
||||
yield work
|
||||
@@ -0,0 +1,3 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from . import common
|
||||
17
hotel_channel_connector/models/channel_binding/common.py
Normal file
17
hotel_channel_connector/models/channel_binding/common.py
Normal file
@@ -0,0 +1,17 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, models, fields
|
||||
from odoo.addons.queue_job.job import job, related_action
|
||||
|
||||
|
||||
class ChannelBinding(models.AbstractModel):
|
||||
_name = 'channel.binding'
|
||||
_inherit = 'external.binding'
|
||||
_description = 'Hotel Channel Connector Binding (abstract)'
|
||||
|
||||
backend_id = fields.Many2one(
|
||||
comodel_name='channel.backend',
|
||||
string='Hotel Channel Connector Backend',
|
||||
required=True,
|
||||
ondelete='restrict')
|
||||
@@ -20,8 +20,7 @@ class HotelChannelConnectorIssue(models.Model):
|
||||
date_start = fields.Date("From", readonly=True)
|
||||
date_end = fields.Date("To", readonly=True)
|
||||
channel_object_id = fields.Char("Channel Object ID", old_name='wid', readonly=True)
|
||||
channel_connector_message = fields.Char("Channel Connector Message",
|
||||
old_name='wmessage', readonly=True)
|
||||
channel_message = fields.Char("Channel Message", old_name='wmessage', readonly=True)
|
||||
|
||||
@api.multi
|
||||
def mark_readed(self):
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from . import common
|
||||
@@ -1,56 +1,38 @@
|
||||
# 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
|
||||
from ..wubook import (
|
||||
DEFAULT_WUBOOK_DATE_FORMAT,
|
||||
WUBOOK_STATUS_CONFIRMED,
|
||||
WUBOOK_STATUS_WAITING,
|
||||
WUBOOK_STATUS_REFUSED,
|
||||
WUBOOK_STATUS_ACCEPTED,
|
||||
WUBOOK_STATUS_CANCELLED,
|
||||
WUBOOK_STATUS_CANCELLED_PENALTY,
|
||||
WUBOOK_STATUS_BAD)
|
||||
from odoo.addons.hotel import date_utils
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class ChannelHotelReservation(models.Model):
|
||||
_name = 'channel.hotel.reservation'
|
||||
_inherit = 'channel.binding'
|
||||
_inherits = {'hotel.reservation': 'odoo_id'}
|
||||
_description = 'Channel Hotel Reservation'
|
||||
|
||||
class HotelReservation(models.Model):
|
||||
_inherit = 'hotel.reservation'
|
||||
|
||||
@api.multi
|
||||
def set_access_for_wubook_fields(self):
|
||||
for rec in self:
|
||||
user = self.env['res.users'].browse(self.env.uid)
|
||||
rec.able_to_modify_wubook = user.has_group('base.group_system')
|
||||
|
||||
@api.depends('channel_type','wchannel_id')
|
||||
def _get_origin_sale(self):
|
||||
@api.depends('channel_reservation_id', 'ota_id')
|
||||
def _is_from_ota(self):
|
||||
for record in self:
|
||||
if not record.channel_type:
|
||||
record.channel_type = 'door'
|
||||
record.origin_sale = (record.channel_type != 'web' or not record.wchannel_id) and \
|
||||
dict(self.fields_get(allfields=['channel_type'])['channel_type']['selection'])[record.channel_type] \
|
||||
or record.wchannel_id.name
|
||||
record.is_from_ota = (record.channel_reservation_id and record.ota_id)
|
||||
|
||||
@api.depends('wrid', 'wchannel_id')
|
||||
def _is_from_channel(self):
|
||||
for record in self:
|
||||
record.wis_from_channel = (record.wrid and record.wchannel_id)
|
||||
|
||||
wrid = fields.Char("WuBook Reservation ID", readonly=True)
|
||||
wchannel_id = fields.Many2one('wubook.channel.info',
|
||||
string='WuBook Channel ID',
|
||||
readonly=True)
|
||||
wchannel_reservation_code = fields.Char("WuBook Channel Reservation Code",
|
||||
readonly=True)
|
||||
wis_from_channel = fields.Boolean('WuBooK Is From Channel',
|
||||
compute=_is_from_channel, store=False,
|
||||
readonly=True)
|
||||
odoo_id = fields.Many2one(comodel_names='hotel.reservation',
|
||||
string='Reservation',
|
||||
required=True,
|
||||
ondelete='cascade')
|
||||
channel_reservation_id = fields.Char("Channel Reservation ID", readonly=True, old_name='wrid')
|
||||
ota_id = fields.Many2one('channel.ota.info',
|
||||
string='Channel OTA ID',
|
||||
readonly=True,
|
||||
old_name='wchannel_id')
|
||||
ota_reservation_id = fields.Char("Channel OTA Reservation Code",
|
||||
readonly=True,
|
||||
old_name='channel_reservation_code')
|
||||
is_from_ota = fields.Boolean('Is From OTA',
|
||||
compute=_is_from_ota, store=False,
|
||||
readonly=True,
|
||||
old_name='wis_from_channel')
|
||||
to_read = fields.Boolean('To Read', default=False)
|
||||
able_to_modify_wubook = fields.Boolean(compute=set_access_for_wubook_fields, string='Is user able to modify wubook fields?')
|
||||
wbook_json = fields.Text(readonly=True)
|
||||
able_to_modify_channel = fields.Boolean(compute=set_access_for_wubook_fields,
|
||||
string='Is user able to modify wubook fields?',
|
||||
old_name='able_to_modify_wubook')
|
||||
channel_raw_data = fields.Text(readonly=True, old_name='wbook_json')
|
||||
|
||||
wstatus = fields.Selection([
|
||||
('0', 'No WuBook'),
|
||||
@@ -63,33 +45,75 @@ class HotelReservation(models.Model):
|
||||
string='WuBook Status', default='0',
|
||||
readonly=True)
|
||||
wstatus_reason = fields.Char("WuBook Status Reason", readonly=True)
|
||||
wcustomer_notes = fields.Text(related='folio_id.wcustomer_notes')
|
||||
customer_notes = fields.Text(related='folio_id.customer_notes',
|
||||
old_name='wcustomer_notes')
|
||||
wmodified = fields.Boolean("WuBook Modified", readonly=True, default=False)
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@related_action(action='related_action_unwrap_binding')
|
||||
@api.multi
|
||||
def push_availability(self):
|
||||
self.ensure_one()
|
||||
if self._context.get('channel_action', True):
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
exporter = work.component(usage='channel.exporter')
|
||||
exporter.push_availability()
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@related_action(action='related_action_unwrap_binding')
|
||||
@api.multi
|
||||
def cancel_reservation(self):
|
||||
self.ensure_one()
|
||||
if self._context.get('channel_action', True):
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
adapter = work.component(usage='backend.adapter')
|
||||
wres = adapter.cancel_reservation(
|
||||
self.channel_reservation_id,
|
||||
_('Cancelled by %s') % partner_id.name)
|
||||
if not wres:
|
||||
raise ValidationError(_("Can't cancel reservation on WuBook"))
|
||||
|
||||
class HotelReservation(models.Model):
|
||||
_inherit = 'hotel.reservation'
|
||||
|
||||
@api.multi
|
||||
def set_access_for_wubook_fields(self):
|
||||
for rec in self:
|
||||
user = self.env['res.users'].browse(self.env.uid)
|
||||
rec.able_to_modify_channel = user.has_group('base.group_system')
|
||||
|
||||
@api.depends('channel_type', 'ota_id')
|
||||
def _get_origin_sale(self):
|
||||
for record in self:
|
||||
if not record.channel_type:
|
||||
record.channel_type = 'door'
|
||||
record.origin_sale = dict(
|
||||
self.fields_get(
|
||||
allfields=['channel_type'])['channel_type']['selection'])[record.channel_type] \
|
||||
if record.channel_type != 'web' or not record.ota_id \
|
||||
else record.ota_id.name
|
||||
|
||||
channel_bind_ids = fields.One2many(
|
||||
comodel_name='channel.hotel.reservation',
|
||||
inverse_name='odoo_id',
|
||||
string='Hotel Channel Connector Bindings')
|
||||
origin_sale = fields.Char('Origin', compute=_get_origin_sale,
|
||||
store=True)
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
if vals.get('wrid') != None:
|
||||
if vals.get('channel_reservation_id') != None:
|
||||
vals.update({'preconfirm': False})
|
||||
user = self.env['res.users'].browse(self.env.uid)
|
||||
if user.has_group('hotel.group_hotel_call'):
|
||||
vals.update({'to_read': True})
|
||||
res = super(HotelReservation, self).create(vals)
|
||||
if self._context.get('wubook_action', True) and \
|
||||
self.env['wubook'].is_valid_account():
|
||||
self.env['hotel.virtual.room.availability'].refresh_availability(
|
||||
vals['checkin'],
|
||||
vals['checkout'],
|
||||
vals['product_id'])
|
||||
self.env['wubook'].push_availability()
|
||||
self.env['hotel.virtual.room.availability'].refresh_availability(
|
||||
vals['checkin'],
|
||||
vals['checkout'],
|
||||
vals['product_id'])
|
||||
return res
|
||||
|
||||
# @api.multi
|
||||
# def read(self, fields=None, load='_classic_read'):
|
||||
# self.to_read = False
|
||||
# return super(HotelReservation, self).read(fields=fields, load=load)
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
if self._context.get('wubook_action', True) and \
|
||||
@@ -125,7 +149,6 @@ class HotelReservation(models.Model):
|
||||
new_vals[i]['checkin'],
|
||||
new_vals[i]['checkout'],
|
||||
new_vals[i]['product_id'])
|
||||
self.env['wubook'].push_availability()
|
||||
else:
|
||||
res = super(HotelReservation, self).write(vals)
|
||||
return res
|
||||
@@ -135,7 +158,7 @@ class HotelReservation(models.Model):
|
||||
vals = []
|
||||
for record in self:
|
||||
if record.wrid and not record.parent_reservation:
|
||||
raise UserError(_("You can't delete wubook reservations"))
|
||||
raise UserError(_("You can't delete OTA's reservations"))
|
||||
vals.append({
|
||||
'checkin': record.checkin,
|
||||
'checkout': record.checkout,
|
||||
@@ -150,7 +173,6 @@ class HotelReservation(models.Model):
|
||||
record['checkin'],
|
||||
record['checkout'],
|
||||
record['product_id'])
|
||||
self.env['wubook'].push_availability()
|
||||
return res
|
||||
|
||||
@api.multi
|
||||
@@ -159,9 +181,8 @@ class HotelReservation(models.Model):
|
||||
if waction:
|
||||
for record in self:
|
||||
# Can't cancel in Odoo
|
||||
if record.wis_from_channel:
|
||||
raise ValidationError(_("Can't cancel reservations \
|
||||
from OTA's"))
|
||||
if record.is_from_ota:
|
||||
raise ValidationError(_("Can't cancel reservations from OTA's"))
|
||||
user = self.env['res.users'].browse(self.env.uid)
|
||||
if user.has_group('hotel.group_hotel_call'):
|
||||
self.write({'to_read': True, 'to_assign': True})
|
||||
@@ -169,44 +190,37 @@ class HotelReservation(models.Model):
|
||||
res = super(HotelReservation, self).action_cancel()
|
||||
if waction and self.env['wubook'].is_valid_account():
|
||||
partner_id = self.env['res.users'].browse(self.env.uid).partner_id
|
||||
wubook_obj = self.env['wubook']
|
||||
for record in self:
|
||||
# Only can cancel reservations created directly in wubook
|
||||
if record.wrid and record.wrid != '' and \
|
||||
not record.wchannel_id and \
|
||||
if record.channel_reservation_id and not record.ota_id and \
|
||||
record.wstatus in ['1', '2', '4']:
|
||||
wres = wubook_obj.cancel_reservation(
|
||||
record.wrid,
|
||||
'Cancelled by %s' % partner_id.name)
|
||||
if not wres:
|
||||
raise ValidationError(_("Can't cancel reservation \
|
||||
on WuBook"))
|
||||
self._event('on_record_cancel').notify(record)
|
||||
return res
|
||||
|
||||
@api.multi
|
||||
def confirm(self):
|
||||
can_confirm = True
|
||||
for record in self:
|
||||
if record.wis_from_channel and int(record.wstatus) in WUBOOK_STATUS_BAD:
|
||||
if record.is_from_ota and int(record.wstatus) in WUBOOK_STATUS_BAD:
|
||||
can_confirm = False
|
||||
break
|
||||
if not can_confirm:
|
||||
raise ValidationError(_("Can't confirm cancelled reservations"))
|
||||
raise ValidationError(_("Can't confirm OTA's cancelled reservations"))
|
||||
return super(HotelReservation, self).confirm()
|
||||
|
||||
@api.multi
|
||||
def generate_copy_values(self, checkin=False, checkout=False):
|
||||
self.ensure_one()
|
||||
res = super(HotelReservation, self).generate_copy_values(
|
||||
checkin=checkin, checkout=checkout)
|
||||
res = super().generate_copy_values(checkin=checkin, checkout=checkout)
|
||||
res.update({
|
||||
'wrid': self.wrid,
|
||||
'wchannel_id': self.wchannel_id and self.wchannel_id.id or False,
|
||||
'wchannel_reservation_code': self.wchannel_reservation_code,
|
||||
'wis_from_channel': self.wis_from_channel,
|
||||
'channel_reservation_id': self.channel_reservation_id,
|
||||
'ota_id': self.ota_id and self.ota_id.id or False,
|
||||
'ota_reservation_code': self.ota_reservation_code,
|
||||
'is_from_ota': self.is_from_ota,
|
||||
'to_read': self.to_read,
|
||||
'wstatus': self.wstatus,
|
||||
'wstatus_reason': self.wstatus_reason,
|
||||
'wcustomer_notes': self.wcustomer_notes,
|
||||
'customer_notes': self.customer_notes,
|
||||
})
|
||||
return res
|
||||
|
||||
@@ -221,24 +235,37 @@ class HotelReservation(models.Model):
|
||||
|
||||
@api.model
|
||||
def _hcalendar_reservation_data(self, reservations):
|
||||
json_reservs, json_tooltips = super(
|
||||
HotelReservation,
|
||||
self)._hcalendar_reservation_data(reservations)
|
||||
json_reservs, json_tooltips = super()._hcalendar_reservation_data(reservations)
|
||||
|
||||
reserv_obj = self.env['hotel.reservation']
|
||||
for reserv in json_reservs:
|
||||
reservation = reserv_obj.browse(reserv[1])
|
||||
reserv[13] = reservation.splitted or reservation.wis_from_channel
|
||||
reserv[13] = reservation.splitted or reservation.is_from_ota
|
||||
|
||||
return (json_reservs, json_tooltips)
|
||||
|
||||
@api.multi
|
||||
def mark_as_readed(self):
|
||||
for record in self:
|
||||
record.write({'to_read': False, 'to_assign': False})
|
||||
self.write({'to_read': False, 'to_assign': False})
|
||||
|
||||
@api.onchange('checkin', 'checkout', 'product_id')
|
||||
def on_change_checkin_checkout_product_id(self):
|
||||
if not self.wis_from_channel:
|
||||
return super(HotelReservation, self).\
|
||||
on_change_checkin_checkout_product_id()
|
||||
if not self.is_from_ota:
|
||||
return super().on_change_checkin_checkout_product_id()
|
||||
|
||||
class ChannelBindingProductListener(Component):
|
||||
_name = 'channel.binding.hotel.reservation.listener'
|
||||
_inherit = 'base.connector.listener'
|
||||
_apply_on = ['channel.hotel.reservation']
|
||||
|
||||
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
|
||||
def on_record_write(self, record, fields=None):
|
||||
record.with_delay(priority=20).push_availability()
|
||||
|
||||
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
|
||||
def on_record_unlink(self, record, fields=None):
|
||||
record.with_delay(priority=20).push_availability()
|
||||
|
||||
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
|
||||
def on_record_cancel(self, record, fields=None):
|
||||
record.with_delay(priority=20).cancel_reservation()
|
||||
@@ -0,0 +1,3 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from . import common
|
||||
139
hotel_channel_connector/models/hotel_virtual_room/common.py
Normal file
139
hotel_channel_connector/models/hotel_virtual_room/common.py
Normal file
@@ -0,0 +1,139 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
class ChannelHotelVirtualRoom(models.Model):
|
||||
_name = 'channel.hotel.virtual.room'
|
||||
_inherit = 'channel.binding'
|
||||
_inherits = {'hotel.virtual.room': 'odoo_id'}
|
||||
_description = 'Channel Hotel Virtual Room'
|
||||
|
||||
@api.depends('ota_capacity')
|
||||
@api.onchange('room_ids', 'room_type_ids')
|
||||
def _get_capacity(self):
|
||||
for rec in self:
|
||||
rec.ota_capacity = rec.get_capacity()
|
||||
|
||||
odoo_id = fields.Many2one(comodel_names='hotel.virtual.room',
|
||||
string='Reservation',
|
||||
required=True,
|
||||
ondelete='cascade')
|
||||
channel_room_id = fields.Char("Channel Room ID", readonly=True, old_name='wrid')
|
||||
channel_short_code = fields.Char("Channel Short Code", readonly=True, old_name='wscode')
|
||||
ota_capacity = fields.Integer("OTA's Capacity", default=1, old_name='wcapacity')
|
||||
|
||||
@api.constrains('ota_capacity')
|
||||
def _check_ota_capacity(self):
|
||||
for record in self:
|
||||
if record.ota_capacity < 1:
|
||||
raise ValidationError(_("OTA's capacity can't be less than one"))
|
||||
|
||||
@api.multi
|
||||
@api.constrains('channel_short_code')
|
||||
def _check_channel_short_code(self):
|
||||
for record in self:
|
||||
if len(record.channel_short_code) > 4: # Wubook scode max. length
|
||||
raise ValidationError(_("Chanel short code can't be longer than 4 characters"))
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@related_action(action='related_action_unwrap_binding')
|
||||
@api.multi
|
||||
def create_room(self):
|
||||
self.ensure_one()
|
||||
if self._context.get('channel_action', True):
|
||||
seq_obj = self.env['ir.sequence']
|
||||
shortcode = seq_obj.next_by_code('hotel.room.type')[:4]
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
adapter = work.component(usage='backend.adapter')
|
||||
try:
|
||||
channel_room_id = adapter.create_room(
|
||||
shortcode,
|
||||
self.name,
|
||||
self.ota_capacity,
|
||||
self.list_price,
|
||||
self.max_real_rooms)
|
||||
if channel_room_id:
|
||||
self.write({
|
||||
'channel_room_id': channel_room_id,
|
||||
'channel_short_code': shortcode,
|
||||
})
|
||||
except ValidationError as e:
|
||||
self.create_issue('room', "Can't create room on channel", "sss")
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@related_action(action='related_action_unwrap_binding')
|
||||
@api.multi
|
||||
def modify_room(self):
|
||||
self.ensure_one()
|
||||
if self._context.get('channel_action', True) and self.channel_room_id:
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
adapter = work.component(usage='backend.adapter')
|
||||
try:
|
||||
adapter.modify_room(
|
||||
self.channel_room_id,
|
||||
self.name,
|
||||
self.ota_capacity,
|
||||
self.list_price,
|
||||
self.max_real_rooms,
|
||||
self.channel_short_code)
|
||||
except ValidationError as e:
|
||||
self.create_issue('room', "Can't modify room on channel", "sss")
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@related_action(action='related_action_unwrap_binding')
|
||||
@api.multi
|
||||
def delete_room(self):
|
||||
self.ensure_one()
|
||||
if self._context.get('channel_action', True) and self.channel_room_id:
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
adapter = work.component(usage='backend.adapter')
|
||||
try:
|
||||
adapter.delete_room(self.channel_room_id)
|
||||
except ValidationError as e:
|
||||
self.create_issue('room', "Can't delete room on channel", "sss")
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@api.multi
|
||||
def import_rooms(self):
|
||||
if self._context.get('channel_action', True):
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
importer = work.component(usage='channel.importer')
|
||||
return importer.import_rooms()
|
||||
|
||||
class HotelVirtualRoom(models.Model):
|
||||
_inherit = 'hotel.virtual.room'
|
||||
|
||||
channel_bind_ids = fields.One2many(
|
||||
comodel_name='channel.hotel.virtual.room',
|
||||
inverse_name='odoo_id',
|
||||
string='Hotel Channel Connector Bindings')
|
||||
|
||||
|
||||
@api.multi
|
||||
def get_restrictions(self, date):
|
||||
restriction_plan_id = int(self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'parity_restrictions_id'))
|
||||
self.ensure_one()
|
||||
restriction = self.env['hotel.virtual.room.restriction.item'].search([
|
||||
('date_start', '=', date),
|
||||
('date_end', '=', date),
|
||||
('virtual_room_id', '=', self.id),
|
||||
('restriction_id', '=', restriction_plan_id)
|
||||
], limit=1)
|
||||
return restriction
|
||||
|
||||
class ChannelBindingVirtualRoomListener(Component):
|
||||
_name = 'channel.binding.virtual.room.listener'
|
||||
_inherit = 'base.connector.listener'
|
||||
_apply_on = ['channel.virtual.room']
|
||||
|
||||
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
|
||||
def on_record_write(self, record, fields=None):
|
||||
record.with_delay(priority=20).create_room()
|
||||
|
||||
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
|
||||
def on_record_unlink(self, record, fields=None):
|
||||
record.with_delay(priority=20).delete_room()
|
||||
|
||||
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
|
||||
def on_record_write(self, record, fields=None):
|
||||
record.with_delay(priority=20).modidy_room()
|
||||
@@ -0,0 +1,3 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from . import common
|
||||
@@ -0,0 +1,116 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
class ChannelHotelVirtualRoomAvailability(models.Model):
|
||||
_name = 'channel.hotel.virtual.room.availability'
|
||||
_inherit = 'channel.binding'
|
||||
_inherits = {'hotel.virtual.room.availability': 'odoo_id'}
|
||||
_description = 'Channel Product Pricelist'
|
||||
|
||||
@api.model
|
||||
def _default_channel_max_avail(self):
|
||||
if self.virtual_room_id:
|
||||
return self.virtual_room_id.max_real_rooms
|
||||
return -1
|
||||
|
||||
odoo_id = fields.Many2one(comodel_names='product.pricelist',
|
||||
string='Pricelist',
|
||||
required=True,
|
||||
ondelete='cascade')
|
||||
channel_max_avail = fields.Integer("Max. Channel Avail",
|
||||
default=_default_channel_max_avail,
|
||||
old_name='wmax_avail')
|
||||
channel_pushed = fields.Boolean("Channel Pushed", readonly=True, default=False,
|
||||
old_name='wpushed')
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@related_action(action='related_action_unwrap_binding')
|
||||
@api.multi
|
||||
def create_plan(self):
|
||||
self.ensure_one()
|
||||
if self._context.get('channel_action', True):
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
adapter = work.component(usage='backend.adapter')
|
||||
try:
|
||||
channel_plan_id = adapter.create_plan(self.name,
|
||||
self.is_daily_plan and 1 or 0)
|
||||
if channel_plan_id:
|
||||
self.channel_plan_id = channel_plan_id
|
||||
except ValidationError as e:
|
||||
self.create_issue('room', "Can't create plan on channel", "sss")
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@related_action(action='related_action_unwrap_binding')
|
||||
@api.multi
|
||||
def update_plan_name(self):
|
||||
self.ensure_one()
|
||||
if self._context.get('channel_action', True):
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
adapter = work.component(usage='backend.adapter')
|
||||
try:
|
||||
adapter.update_plan_name(
|
||||
self.channel_plan_id,
|
||||
self.name)
|
||||
except ValidationError as e:
|
||||
self.create_issue('room', "Can't update plan name on channel", "sss")
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@related_action(action='related_action_unwrap_binding')
|
||||
@api.multi
|
||||
def delete_plan(self):
|
||||
self.ensure_one()
|
||||
if self._context.get('channel_action', True) and self.channel_room_id:
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
adapter = work.component(usage='backend.adapter')
|
||||
try:
|
||||
adapter.delete_plan(self.channel_plan_id)
|
||||
except ValidationError as e:
|
||||
self.create_issue('room', "Can't delete plan on channel", "sss")
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@api.multi
|
||||
def import_price_plans(self):
|
||||
if self._context.get('channel_action', True):
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
importer = work.component(usage='channel.importer')
|
||||
return importer.import_pricing_plans()
|
||||
|
||||
class ProductPricelist(models.Model):
|
||||
_inherit = 'product.pricelist'
|
||||
|
||||
channel_bind_ids = fields.One2many(
|
||||
comodel_name='channel.product.pricelist',
|
||||
inverse_name='odoo_id',
|
||||
string='Hotel Channel Connector Bindings')
|
||||
|
||||
@api.multi
|
||||
@api.depends('name')
|
||||
def name_get(self):
|
||||
pricelist_obj = self.env['product.pricelist']
|
||||
org_names = super(ProductPricelist, self).name_get()
|
||||
names = []
|
||||
for name in org_names:
|
||||
priclist_id = pricelist_obj.browse(name[0])
|
||||
if priclist_id.wpid:
|
||||
names.append((name[0], '%s (WuBook)' % name[1]))
|
||||
else:
|
||||
names.append((name[0], name[1]))
|
||||
return names
|
||||
|
||||
class ChannelBindingProductPricelistListener(Component):
|
||||
_name = 'channel.binding.product.pricelist.listener'
|
||||
_inherit = 'base.connector.listener'
|
||||
_apply_on = ['channel.product.pricelist']
|
||||
|
||||
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
|
||||
def on_record_write(self, record, fields=None):
|
||||
record.with_delay(priority=20).create_plan()
|
||||
|
||||
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
|
||||
def on_record_unlink(self, record, fields=None):
|
||||
record.with_delay(priority=20).delete_plan()
|
||||
|
||||
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
|
||||
def on_record_write(self, record, fields=None):
|
||||
if 'name' in fields:
|
||||
record.with_delay(priority=20).update_plan_name()
|
||||
@@ -0,0 +1,3 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from . import common
|
||||
@@ -0,0 +1,106 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
class ChannelHotelVirtualRoomRestriction(models.Model):
|
||||
_name = 'channel.hotel.virtual.room.restriction'
|
||||
_inherit = 'channel.binding'
|
||||
_inherits = {'hotel.virtual.room.restriction': 'odoo_id'}
|
||||
_description = 'Channel Hotel Virtual Room Restriction'
|
||||
|
||||
odoo_id = fields.Many2one(comodel_names='hotel.virtual.room.restriction',
|
||||
string='Hotel Virtual Room Restriction',
|
||||
required=True,
|
||||
ondelete='cascade')
|
||||
channel_plan_id = fields.Char("Channel Plan ID", readonly=True, old_name='wpid')
|
||||
is_daily_plan = fields.Boolean("Channel Daily Plan", default=True, old_name='wdaily_plan')
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@related_action(action='related_action_unwrap_binding')
|
||||
@api.multi
|
||||
def create_plan(self):
|
||||
self.ensure_one()
|
||||
if self._context.get('channel_action', True):
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
adapter = work.component(usage='backend.adapter')
|
||||
try:
|
||||
channel_plan_id = adapter.create_rplan(self.name)
|
||||
if channel_plan_id:
|
||||
self.channel_plan_id = channel_plan_id
|
||||
except ValidationError as e:
|
||||
self.create_issue('room', "Can't create restriction plan on channel", "sss")
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@related_action(action='related_action_unwrap_binding')
|
||||
@api.multi
|
||||
def update_plan_name(self):
|
||||
self.ensure_one()
|
||||
if self._context.get('channel_action', True):
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
adapter = work.component(usage='backend.adapter')
|
||||
try:
|
||||
adapter.rename_rplan(
|
||||
self.channel_plan_id,
|
||||
self.name)
|
||||
except ValidationError as e:
|
||||
self.create_issue('room', "Can't update restriction plan name on channel", "sss")
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@related_action(action='related_action_unwrap_binding')
|
||||
@api.multi
|
||||
def delete_plan(self):
|
||||
self.ensure_one()
|
||||
if self._context.get('channel_action', True) and self.channel_room_id:
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
adapter = work.component(usage='backend.adapter')
|
||||
try:
|
||||
adapter.delete_rplan(self.channel_plan_id)
|
||||
except ValidationError as e:
|
||||
self.create_issue('room', "Can't delete restriction plan on channel", "sss")
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@api.multi
|
||||
def import_restriction_plans(self):
|
||||
if self._context.get('channel_action', True):
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
importer = work.component(usage='channel.importer')
|
||||
return importer.import_restriction_plans()
|
||||
|
||||
class HotelVirtualRoomRestriction(models.Model):
|
||||
_inherit = 'hotel.virtual.room.restriction'
|
||||
|
||||
channel_bind_ids = fields.One2many(
|
||||
comodel_name='channel.hotel.virtual.room.restriction',
|
||||
inverse_name='odoo_id',
|
||||
string='Hotel Channel Connector Bindings')
|
||||
|
||||
@api.multi
|
||||
@api.depends('name')
|
||||
def name_get(self):
|
||||
vroom_restriction_obj = self.env['hotel.virtual.room.restriction']
|
||||
org_names = super(HotelVirtualRoomRestriction, self).name_get()
|
||||
names = []
|
||||
for name in org_names:
|
||||
restriction_id = vroom_restriction_obj.browse(name[0])
|
||||
if restriction_id.wpid:
|
||||
names.append((name[0], '%s (WuBook)' % name[1]))
|
||||
else:
|
||||
names.append((name[0], name[1]))
|
||||
return names
|
||||
|
||||
class ChannelBindingHotelVirtualRoomRestrictionListener(Component):
|
||||
_name = 'channel.binding.hotel.virtual.room.restriction.listener'
|
||||
_inherit = 'base.connector.listener'
|
||||
_apply_on = ['channel.hotel.virtual.room.restriction']
|
||||
|
||||
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
|
||||
def on_record_write(self, record, fields=None):
|
||||
record.with_delay(priority=20).create_plan()
|
||||
|
||||
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
|
||||
def on_record_unlink(self, record, fields=None):
|
||||
record.with_delay(priority=20).delete_plan()
|
||||
|
||||
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
|
||||
def on_record_write(self, record, fields=None):
|
||||
if 'name' in fields:
|
||||
record.with_delay(priority=20).update_plan_name()
|
||||
@@ -8,35 +8,37 @@ class HotelFolio(models.Model):
|
||||
|
||||
@api.depends('room_lines')
|
||||
def _has_channel_reservations(self):
|
||||
if any(self.room_lines):
|
||||
for room in self.room_lines:
|
||||
if room.channel_room_id and room.channel_room_id != '':
|
||||
self.has_channel_reservations = True
|
||||
return
|
||||
self.has_channel_reservations = False
|
||||
for record in self:
|
||||
channel_reservations = record.room_lines.filtered(lambda x: x.channel_room_id)
|
||||
record.has_channel_reservations = any(channel_reservations)
|
||||
|
||||
seed = fields.Char("WuBook Session Seed", old_name='wseed', readonly=True)
|
||||
customer_notes = fields.Text("WuBook Customer Notes",
|
||||
old_name='wcustomer_notes', readonly=True)
|
||||
has_channel_reservations = fields.Boolean(old_name='whas_wubook_reservations',
|
||||
compute=_has_channel_reservations,
|
||||
store=False)
|
||||
wseed = fields.Char("Wubook Session Seed", readonly=True)
|
||||
customer_notes = fields.Text("Channel Customer Notes",
|
||||
readonly=True, old_name='wcustomer_notes')
|
||||
has_channel_reservations = fields.Boolean(compute=_has_channel_reservations,
|
||||
store=False,
|
||||
old_name='whas_wubook_reservations')
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@api.multi
|
||||
def import_reservations(self):
|
||||
return self.env['hotel.channel.connector'].fetch_new_bookings()
|
||||
self.ensure_one()
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
importer = work.component(usage='channel.importer')
|
||||
importer.fetch_new_bookings()
|
||||
|
||||
@api.multi
|
||||
def action_confirm(self):
|
||||
for rec in self:
|
||||
for room in rec.room_lines:
|
||||
room.to_read = False
|
||||
room.to_assign = False
|
||||
return super(HotelFolio, self).action_confirm()
|
||||
rec.room_lines.write({
|
||||
'to_read': False,
|
||||
'to_assign': False,
|
||||
})
|
||||
return super().action_confirm()
|
||||
|
||||
@api.multi
|
||||
def get_grouped_reservations_json(self, state, import_all=False):
|
||||
super(HotelFolio, self).get_grouped_reservations_json(state, import_all=import_all)
|
||||
super().get_grouped_reservations_json(state, import_all=import_all)
|
||||
self.ensure_one()
|
||||
info_grouped = []
|
||||
for rline in self.room_lines:
|
||||
@@ -68,12 +70,14 @@ class HotelFolio(models.Model):
|
||||
|
||||
@api.depends('room_lines')
|
||||
def _compute_has_cancelled_reservations_to_send(self):
|
||||
super(HotelFolio, self)._compute_has_cancelled_reservations_to_send()
|
||||
has_to_send = False
|
||||
for rline in self.room_lines:
|
||||
if rline.splitted:
|
||||
super()._compute_has_cancelled_reservations_to_send()
|
||||
hotel_reserv_obj = self.env['hotel.reservation']
|
||||
for record in self:
|
||||
splitted_reservation_ids = record.room_lines.filtered(lambda x: x.splitted)
|
||||
has_to_send = False
|
||||
for rline in splitted_reservation_ids:
|
||||
master_reservation = rline.parent_reservation or rline
|
||||
has_to_send = self.env['hotel.reservation'].search_count([
|
||||
has_to_send = hotel_reserv_obj.search_count([
|
||||
('splitted', '=', True),
|
||||
('folio_id', '=', self.id),
|
||||
('to_send', '=', True),
|
||||
@@ -83,7 +87,6 @@ class HotelFolio(models.Model):
|
||||
('parent_reservation', '=', master_reservation.id),
|
||||
('id', '=', master_reservation.id),
|
||||
]) > 0
|
||||
elif rline.to_send and rline.state == 'cancelled' and not rline.wmodified:
|
||||
has_to_send = True
|
||||
break
|
||||
self.has_cancelled_reservations_to_send = has_to_send
|
||||
if has_to_send:
|
||||
break
|
||||
record.has_cancelled_reservations_to_send = has_to_send
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
# 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.room.type'
|
||||
|
||||
@api.depends('wcapacity')
|
||||
@api.onchange('room_ids', 'room_type_ids')
|
||||
def _get_capacity(self):
|
||||
hotel_room_obj = self.env['hotel.room']
|
||||
for rec in self:
|
||||
rec.wcapacity = rec.get_capacity()
|
||||
|
||||
wscode = fields.Char("WuBook Short Code", readonly=True)
|
||||
wrid = fields.Char("WuBook Room ID", readonly=True)
|
||||
wcapacity = fields.Integer("WuBook Capacity", default=1)
|
||||
|
||||
@api.constrains('wcapacity')
|
||||
def _check_wcapacity(self):
|
||||
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):
|
||||
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):
|
||||
restriction_plan_id = int(self.env['ir.default'].sudo().get(
|
||||
'hotel.config.settings', 'parity_restrictions_id'))
|
||||
self.ensure_one()
|
||||
restriction = self.env['hotel.virtual.room.restriction.item'].search([
|
||||
('date_start', '=', date),
|
||||
('date_end', '=', date),
|
||||
('virtual_room_id', '=', self.id),
|
||||
('restriction_id', '=', restriction_plan_id)
|
||||
], limit=1)
|
||||
return restriction
|
||||
# if restriction:
|
||||
# return restriction
|
||||
# else:
|
||||
# vroom_rest_it_obj = self.env['hotel.virtual.room.restriction.item']
|
||||
# global_restr = vroom_rest_it_obj.search([
|
||||
# ('applied_on', '=', '1_global'),
|
||||
# ('restriction_id', '=', restriction_plan_id)
|
||||
# ], limit=1)
|
||||
# if global_restr:
|
||||
# return global_restr
|
||||
# return False
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
vroom = super(HotelVirtualRoom, self).create(vals)
|
||||
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.room.type')[:4]
|
||||
wrid = self.env['wubook'].create_room(
|
||||
shortcode,
|
||||
vroom.name,
|
||||
vroom.wcapacity,
|
||||
vroom.list_price,
|
||||
vroom.max_real_rooms
|
||||
)
|
||||
if not wrid:
|
||||
raise ValidationError(_("Can't create room on WuBook"))
|
||||
vroom.with_context(wubook_action=False).write({
|
||||
'wrid': wrid,
|
||||
'wscode': shortcode,
|
||||
})
|
||||
return vroom
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
if self._context.get('wubook_action', True) and \
|
||||
self.env['wubook'].is_valid_account():
|
||||
wubook_obj = self.env['wubook']
|
||||
for record in self:
|
||||
if record.wrid and record.wrid != '':
|
||||
wres = wubook_obj.modify_room(
|
||||
vals.get('wrid', record.wrid),
|
||||
vals.get('name', record.name),
|
||||
vals.get('wcapacity', record.wcapacity),
|
||||
vals.get('list_price', record.list_price),
|
||||
vals.get('max_real_rooms', record.max_real_rooms),
|
||||
vals.get('wscode', record.wscode))
|
||||
if not wres:
|
||||
raise ValidationError(_("Can't modify room on WuBook"))
|
||||
return super(HotelVirtualRoom, self).write(vals)
|
||||
|
||||
@api.multi
|
||||
def unlink(self):
|
||||
if self._context.get('wubook_action', True) and \
|
||||
self.env['wubook'].is_valid_account():
|
||||
for record in self:
|
||||
if record.wrid and record.wrid != '':
|
||||
wres = self.env['wubook'].delete_room(record.wrid)
|
||||
if not wres:
|
||||
raise ValidationError(_("Can't delete room on WuBook"))
|
||||
return super(HotelVirtualRoom, self).unlink()
|
||||
|
||||
@api.multi
|
||||
def import_rooms(self):
|
||||
return self.env['wubook'].import_rooms()
|
||||
@@ -1,134 +0,0 @@
|
||||
# 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
|
||||
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
|
||||
|
||||
|
||||
class ProductPricelist(models.Model):
|
||||
_inherit = 'product.pricelist'
|
||||
|
||||
wpid = fields.Char("WuBook Plan ID", readonly=True)
|
||||
wdaily = fields.Boolean("WuBook Daily Plan", default=True)
|
||||
|
||||
@api.multi
|
||||
def get_wubook_prices(self):
|
||||
self.ensure_one()
|
||||
prices = {}
|
||||
if self.wdaily:
|
||||
min_date = False
|
||||
max_date = False
|
||||
for item in self.item_ids:
|
||||
if not item.date_start or not item.date_end:
|
||||
continue
|
||||
date_start_dt = fields.Datetime.from_string(item.date_start)
|
||||
date_end_dt = fields.Datetime.from_string(item.date_end)
|
||||
if not min_date or date_start_dt < min_date:
|
||||
min_date = date_start_dt
|
||||
if not max_date or date_end_dt > max_date:
|
||||
max_date = date_end_dt
|
||||
if not min_date or not max_date:
|
||||
return prices
|
||||
days_diff = abs((max_date - min_date).days)
|
||||
vrooms = self.env['hotel.room.type'].search([
|
||||
('wrid', '!=', ''),
|
||||
('wrid', '!=', False)
|
||||
])
|
||||
for vroom in vrooms:
|
||||
prices.update({vroom.wrid: []})
|
||||
for i in range(0, days_diff or 1):
|
||||
ndate_dt = min_date + timedelta(days=i)
|
||||
product_id = vroom.product_id.with_context(
|
||||
quantity=1,
|
||||
date=ndate_dt.strftime(DEFAULT_SERVER_DATE_FORMAT),
|
||||
pricelist=self.id,
|
||||
uom=vroom.product_id.product_tmpl_id.uom_id.id)
|
||||
prices[vroom.wrid].append(product_id.price)
|
||||
else:
|
||||
vrooms = self.env['hotel.room.type'].search([
|
||||
('wrid', '!=', ''),
|
||||
('wrid', '!=', False)
|
||||
])
|
||||
for item in self.item_ids:
|
||||
if not item.date_start or not item.date_end:
|
||||
continue
|
||||
date_start_dt = fields.Datetime.from_string(item.date_start)
|
||||
date_end_dt = fields.Datetime.from_string(item.date_end)
|
||||
days_diff = abs((date_end_dt - date_start_dt).days)
|
||||
vals = {}
|
||||
for vroom in vrooms:
|
||||
wdays = [False, False, False, False, False, False, False]
|
||||
for i in range(0, 7):
|
||||
ndate_dt = date_start_dt + timedelta(days=i)
|
||||
product_id = vroom.product_id.with_context(
|
||||
quantity=1,
|
||||
date=ndate_dt.strftime(DEFAULT_SERVER_DATE_FORMAT),
|
||||
pricelist=self.id,
|
||||
uom=vroom.product_id.product_tmpl_id.uom_id.id)
|
||||
wdays[ndate_dt.weekday()] = product_id.price
|
||||
vals.update({vroom.wrid: wdays})
|
||||
prices.update({
|
||||
'dfrom': item.date_start,
|
||||
'dto': item.date_end,
|
||||
'values': vals,
|
||||
})
|
||||
return prices
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
if self._context.get('wubook_action', True) and \
|
||||
self.env['wubook'].is_valid_account():
|
||||
wpid = self.env['wubook'].create_plan(vals['name'],
|
||||
vals.get('wdaily') and
|
||||
1 or 0)
|
||||
if not wpid:
|
||||
raise ValidationError(_("Can't create plan on WuBook"))
|
||||
vals.update({'wpid': wpid})
|
||||
pricelist = super(ProductPricelist, self).create(vals)
|
||||
return pricelist
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
nname = vals.get('name')
|
||||
if self._context.get('wubook_action', True) and nname and \
|
||||
self.env['wubook'].is_valid_account():
|
||||
for record in self:
|
||||
if record.wpid and record.wpid != '':
|
||||
wres = self.env['wubook'].update_plan_name(
|
||||
vals.get('wpid', record.wpid),
|
||||
nname)
|
||||
if not wres:
|
||||
raise ValidationError(_("Can't update plan name \
|
||||
on WuBook"))
|
||||
updated = super(ProductPricelist, self).write(vals)
|
||||
return updated
|
||||
|
||||
@api.multi
|
||||
def unlink(self):
|
||||
if self._context.get('wubook_action', True) and \
|
||||
self.env['wubook'].is_valid_account():
|
||||
for record in self:
|
||||
if record.wpid and record.wpid != '':
|
||||
wres = self.env['wubook'].delete_plan(record.wpid)
|
||||
if not wres:
|
||||
raise ValidationError(_("Can't delete plan on WuBook"))
|
||||
return super(ProductPricelist, self).unlink()
|
||||
|
||||
@api.multi
|
||||
def import_price_plans(self):
|
||||
return self.env['wubook'].import_pricing_plans()
|
||||
|
||||
@api.multi
|
||||
@api.depends('name')
|
||||
def name_get(self):
|
||||
pricelistObj = self.env['product.pricelist']
|
||||
org_names = super(ProductPricelist, self).name_get()
|
||||
names = []
|
||||
for name in org_names:
|
||||
priclist_id = pricelistObj.browse(name[0])
|
||||
if priclist_id.wpid:
|
||||
names.append((name[0], '%s (WuBook)' % name[1]))
|
||||
else:
|
||||
names.append((name[0], name[1]))
|
||||
return names
|
||||
@@ -7,50 +7,49 @@ from openerp.exceptions import ValidationError
|
||||
class ProductPricelistItem(models.Model):
|
||||
_inherit = 'product.pricelist.item'
|
||||
|
||||
wpushed = fields.Boolean("WuBook Pushed", default=True, readonly=True)
|
||||
wdaily = fields.Boolean(related='pricelist_id.wdaily', readonly=True)
|
||||
is_channel_pushed = fields.Boolean("WuBook Pushed", default=True, readonly=True,
|
||||
old_name='wpushed')
|
||||
is_daily_plan = fields.Boolean(related='pricelist_id.wdaily', readonly=True,
|
||||
old_name='wdaily')
|
||||
|
||||
@api.constrains('fixed_price')
|
||||
def _check_fixed_price(self):
|
||||
vroom_obj = self.env['hotel.room.type']
|
||||
vroom_obj = self.env['hotel.virtual.room']
|
||||
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 record.compute_price == 'fixed' \
|
||||
if vroom and vroom.channel_room_id 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():
|
||||
if self._context.get('channel_action', True):
|
||||
pricelist_id = self.env['product.pricelist'].browse(
|
||||
vals.get('pricelist_id'))
|
||||
vroom = self.env['hotel.room.type'].search([
|
||||
vroom = self.env['hotel.virtual.room'].search([
|
||||
('product_id.product_tmpl_id', '=',
|
||||
vals.get('product_tmpl_id')),
|
||||
('wrid', '!=', False)
|
||||
('channel_room_id', '!=', False)
|
||||
])
|
||||
if vroom and pricelist_id.wpid:
|
||||
vals.update({'wpushed': False})
|
||||
if vroom and pricelist_id.channel_plan_id:
|
||||
vals.update({'is_channel_pushed': False})
|
||||
return super(ProductPricelistItem, self).create(vals)
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
if self._context.get('wubook_action', True) and \
|
||||
self.env['wubook'].is_valid_account():
|
||||
if self._context.get('channel_action', True):
|
||||
prices_obj = self.env['product.pricelist']
|
||||
for record in self:
|
||||
pricelist_id = vals.get('pricelist_id') and \
|
||||
prices_obj.browse(vals.get('pricelist_id')) or \
|
||||
record.pricelist_id
|
||||
pricelist_id = prices_obj.browse(vals.get('pricelist_id')) if \
|
||||
vals.get('pricelist_id') else record.pricelist_id
|
||||
product_tmpl_id = vals.get('product_tmpl_id') or \
|
||||
record.product_tmpl_id.id
|
||||
vroom = self.env['hotel.room.type'].search([
|
||||
record.product_tmpl_id.id
|
||||
vroom = self.env['hotel.virtual.room'].search([
|
||||
('product_id.product_tmpl_id', '=', product_tmpl_id),
|
||||
('wrid', '!=', False)
|
||||
('channel_room_id', '!=', False),
|
||||
])
|
||||
if vroom and pricelist_id.wpid:
|
||||
vals.update({'wpushed': False})
|
||||
if vroom and pricelist_id.channel_plan_id:
|
||||
vals.update({'is_channel_pushed': False})
|
||||
return super(ProductPricelistItem, self).write(vals)
|
||||
|
||||
@@ -30,18 +30,15 @@ class ResPartner(models.Model):
|
||||
if folio_ids:
|
||||
folio_ids.write({
|
||||
'partner_id': org_partner_id.id,
|
||||
})
|
||||
folio_ids = self.env['hotel.folio'].search([
|
||||
('partner_invoice_id', '=', record.id)
|
||||
])
|
||||
if folio_ids:
|
||||
folio_ids.write({
|
||||
'partner_invoice_id': org_partner_id.id,
|
||||
})
|
||||
# DANGER: self-delete... perhaps best invisible?
|
||||
# record.unlink() This cause mistakes
|
||||
record.write({'active': False})
|
||||
# return {
|
||||
# 'type': 'ir.actions.act_window',
|
||||
# 'res_model': 'res.partner',
|
||||
# 'views': [[False, "form"]],
|
||||
# 'target': 'current',
|
||||
# 'res_id': org_partner_id.id,
|
||||
# }
|
||||
else:
|
||||
# If not found, this is the 'confirmed'
|
||||
vals.update({'unconfirmed': False})
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
# 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
|
||||
from openerp.tools import DEFAULT_SERVER_DATE_FORMAT
|
||||
|
||||
|
||||
class ReservationRestriction(models.Model):
|
||||
_inherit = 'hotel.virtual.room.restriction'
|
||||
|
||||
wpid = fields.Char("WuBook Restriction Plan ID", readonly=True)
|
||||
wdaily = fields.Boolean("Plan Daily", default=True, readonly=True)
|
||||
|
||||
@api.multi
|
||||
def get_wubook_restrictions(self):
|
||||
self.ensure_one()
|
||||
prices = {}
|
||||
min_date = False
|
||||
max_date = False
|
||||
for item in self.item_ids:
|
||||
if not item.date_start or not item.date_end:
|
||||
continue
|
||||
date_start_dt = fields.Datetime.from_string(item.date_start)
|
||||
date_end_dt = fields.Datetime.from_string(item.date_end)
|
||||
if not min_date or date_start_dt < min_date:
|
||||
min_date = date_start_dt
|
||||
if not max_date or date_end_dt > max_date:
|
||||
max_date = date_end_dt
|
||||
if not min_date or not max_date:
|
||||
return prices
|
||||
days_diff = abs((max_date - min_date).days)
|
||||
vrooms = self.env['hotel.room.type'].search([
|
||||
('wrid', '!=', ''),
|
||||
('wrid', '!=', False)
|
||||
])
|
||||
for vroom in vrooms:
|
||||
prices.update({vroom.wrid: []})
|
||||
for i in range(0, days_diff or 1):
|
||||
ndate_dt = min_date + timedelta(days=i)
|
||||
product_id = vroom.product_id.with_context(
|
||||
quantity=1,
|
||||
date=ndate_dt.strftime(DEFAULT_SERVER_DATE_FORMAT),
|
||||
pricelist=self.id,
|
||||
uom=vroom.product_id.product_tmpl_id.uom_id.id)
|
||||
prices[vroom.wrid].append(product_id.price)
|
||||
return prices
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
if self._context.get('wubook_action', True) and \
|
||||
self.env['wubook'].is_valid_account():
|
||||
wpid = self.env['wubook'].create_rplan(vals['name'])
|
||||
if not wpid:
|
||||
raise ValidationError(_("Can't create restriction plan on \
|
||||
WuBook"))
|
||||
vals.update({'wpid': wpid})
|
||||
|
||||
rules = self._context.get('rules')
|
||||
if rules:
|
||||
vals.update({'wdaily': False})
|
||||
|
||||
restriction = super(ReservationRestriction, self).create(vals)
|
||||
|
||||
if rules:
|
||||
# Basic Rules
|
||||
vroom_rest_it_obj = self.env['hotel.virtual.room.restriction.item']
|
||||
vroom_rest_it_obj.with_context({'wubook_action': False}).create({
|
||||
'closed_arrival': rules['closed_arrival'],
|
||||
'closed': rules['closed'],
|
||||
'min_stay': rules['min_stay'],
|
||||
'closed_departure': rules['closed_departure'],
|
||||
'max_stay': rules['max_stay'],
|
||||
'min_stay_arrival': rules['min_stay_arrival'],
|
||||
'restriction_id': restriction.id,
|
||||
'applied_on': '1_global',
|
||||
})
|
||||
|
||||
return restriction
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
nname = vals.get('name')
|
||||
if self._context.get('wubook_action', True) and nname and \
|
||||
self.env['wubook'].is_valid_account():
|
||||
for record in self:
|
||||
if record.wpid and record.wpid != '':
|
||||
wres = self.env['wubook'].rename_rplan(
|
||||
vals.get('wpid', record.wpid),
|
||||
nname)
|
||||
if not wres:
|
||||
raise ValidationError(_("Can't rename restriction plan \
|
||||
on WuBook"))
|
||||
updated = super(ReservationRestriction, self).write(vals)
|
||||
return updated
|
||||
|
||||
@api.multi
|
||||
def unlink(self):
|
||||
if self._context.get('wubook_action', True) and \
|
||||
self.env['wubook'].is_valid_account():
|
||||
for record in self:
|
||||
if record.wpid and record.wpid != '':
|
||||
wres = self.env['wubook'].delete_rplan(record.wpid)
|
||||
if not wres:
|
||||
raise ValidationError(_("Can't delete restriction plan \
|
||||
on WuBook"))
|
||||
return super(ReservationRestriction, self).unlink()
|
||||
|
||||
@api.multi
|
||||
def import_restriction_plans(self):
|
||||
return self.env['wubook'].import_restriction_plans()
|
||||
|
||||
@api.multi
|
||||
@api.depends('name')
|
||||
def name_get(self):
|
||||
roomRestrictionObj = self.env['hotel.virtual.room.restriction']
|
||||
org_names = super(ReservationRestriction, self).name_get()
|
||||
names = []
|
||||
for name in org_names:
|
||||
restriction_id = roomRestrictionObj.browse(name[0])
|
||||
if restriction_id.wpid:
|
||||
names.append((name[0], '%s (WuBook)' % name[1]))
|
||||
else:
|
||||
names.append((name[0], name[1]))
|
||||
return names
|
||||
@@ -6,7 +6,8 @@ from openerp import models, fields, api
|
||||
class ReservationRestrictionItem(models.Model):
|
||||
_inherit = 'hotel.virtual.room.restriction.item'
|
||||
|
||||
wpushed = fields.Boolean("WuBook Pushed", default=False, readonly=True)
|
||||
channel_pushed = fields.Boolean("WuBook Pushed", default=False, readonly=True,
|
||||
old_name='wpushed')
|
||||
|
||||
@api.onchange('date_start')
|
||||
def _onchange_date_start(self):
|
||||
@@ -22,6 +23,6 @@ class ReservationRestrictionItem(models.Model):
|
||||
def write(self, vals):
|
||||
if vals.get('date_start'):
|
||||
vals['date_end'] = vals.get('date_start')
|
||||
if self._context.get('wubook_action', True):
|
||||
vals.update({'wpushed': False})
|
||||
if self._context.get('channel_action', True):
|
||||
vals.update({'channel_pushed': False})
|
||||
return super(ReservationRestrictionItem, self).write(vals)
|
||||
|
||||
@@ -12,19 +12,21 @@ class VirtualRoomAvailability(models.Model):
|
||||
_inherit = 'hotel.virtual.room.availability'
|
||||
|
||||
@api.model
|
||||
def _default_wmax_avail(self):
|
||||
def _default_channel_max_avail(self):
|
||||
if self.virtual_room_id:
|
||||
return self.virtual_room_id.max_real_rooms
|
||||
return -1
|
||||
|
||||
wmax_avail = fields.Integer("Max. Wubook Avail",
|
||||
default=_default_wmax_avail)
|
||||
wpushed = fields.Boolean("WuBook Pushed", readonly=True, default=False)
|
||||
channel_max_avail = fields.Integer("Max. Channel Avail",
|
||||
default=_default_channel_max_avail,
|
||||
old_name='wmax_avail')
|
||||
channel_pushed = fields.Boolean("Channel Pushed", readonly=True, default=False,
|
||||
old_name='wpushed')
|
||||
|
||||
@api.constrains('avail')
|
||||
def _check_avail(self):
|
||||
vroom_obj = self.env['hotel.room.type']
|
||||
issue_obj = self.env['wubook.issue']
|
||||
vroom_obj = self.env['hotel.virtual.room']
|
||||
issue_obj = self.env['hotel.channel.connector.issue']
|
||||
wubook_obj = self.env['wubook']
|
||||
for record in self:
|
||||
cavail = len(vroom_obj.check_availability_virtual_room(
|
||||
@@ -35,7 +37,7 @@ class VirtualRoomAvailability(models.Model):
|
||||
if record.avail > max_avail:
|
||||
issue_obj.sudo().create({
|
||||
'section': 'avail',
|
||||
'message': _("The new availability can't be greater than \
|
||||
'message': _(r"The new availability can't be greater than \
|
||||
the actual availability \
|
||||
\n[%s]\nInput: %d\Limit: %d") % (record.virtual_room_id.name,
|
||||
record.avail,
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from . import common
|
||||
107
hotel_channel_connector/models/product_pricelist/common.py
Normal file
107
hotel_channel_connector/models/product_pricelist/common.py
Normal file
@@ -0,0 +1,107 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
class ChannelProductPricelist(models.Model):
|
||||
_name = 'channel.product.pricelist'
|
||||
_inherit = 'channel.binding'
|
||||
_inherits = {'product.pricelist': 'odoo_id'}
|
||||
_description = 'Channel Product Pricelist'
|
||||
|
||||
odoo_id = fields.Many2one(comodel_names='product.pricelist',
|
||||
string='Pricelist',
|
||||
required=True,
|
||||
ondelete='cascade')
|
||||
channel_plan_id = fields.Char("Channel Plan ID", readonly=True, old_name='wpid')
|
||||
is_daily_plan = fields.Boolean("Channel Daily Plan", default=True, old_name='wdaily_plan')
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@related_action(action='related_action_unwrap_binding')
|
||||
@api.multi
|
||||
def create_plan(self):
|
||||
self.ensure_one()
|
||||
if self._context.get('channel_action', True):
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
adapter = work.component(usage='backend.adapter')
|
||||
try:
|
||||
channel_plan_id = adapter.create_plan(self.name,
|
||||
self.is_daily_plan and 1 or 0)
|
||||
if channel_plan_id:
|
||||
self.channel_plan_id = channel_plan_id
|
||||
except ValidationError as e:
|
||||
self.create_issue('room', "Can't create plan on channel", "sss")
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@related_action(action='related_action_unwrap_binding')
|
||||
@api.multi
|
||||
def update_plan_name(self):
|
||||
self.ensure_one()
|
||||
if self._context.get('channel_action', True):
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
adapter = work.component(usage='backend.adapter')
|
||||
try:
|
||||
adapter.update_plan_name(
|
||||
self.channel_plan_id,
|
||||
self.name)
|
||||
except ValidationError as e:
|
||||
self.create_issue('room', "Can't update plan name on channel", "sss")
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@related_action(action='related_action_unwrap_binding')
|
||||
@api.multi
|
||||
def delete_plan(self):
|
||||
self.ensure_one()
|
||||
if self._context.get('channel_action', True) and self.channel_room_id:
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
adapter = work.component(usage='backend.adapter')
|
||||
try:
|
||||
adapter.delete_plan(self.channel_plan_id)
|
||||
except ValidationError as e:
|
||||
self.create_issue('room', "Can't delete plan on channel", "sss")
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@api.multi
|
||||
def import_price_plans(self):
|
||||
if self._context.get('channel_action', True):
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
importer = work.component(usage='channel.importer')
|
||||
return importer.import_pricing_plans()
|
||||
|
||||
class ProductPricelist(models.Model):
|
||||
_inherit = 'product.pricelist'
|
||||
|
||||
channel_bind_ids = fields.One2many(
|
||||
comodel_name='channel.product.pricelist',
|
||||
inverse_name='odoo_id',
|
||||
string='Hotel Channel Connector Bindings')
|
||||
|
||||
@api.multi
|
||||
@api.depends('name')
|
||||
def name_get(self):
|
||||
pricelist_obj = self.env['product.pricelist']
|
||||
org_names = super(ProductPricelist, self).name_get()
|
||||
names = []
|
||||
for name in org_names:
|
||||
priclist_id = pricelist_obj.browse(name[0])
|
||||
if priclist_id.wpid:
|
||||
names.append((name[0], '%s (WuBook)' % name[1]))
|
||||
else:
|
||||
names.append((name[0], name[1]))
|
||||
return names
|
||||
|
||||
class ChannelBindingProductPricelistListener(Component):
|
||||
_name = 'channel.binding.product.pricelist.listener'
|
||||
_inherit = 'base.connector.listener'
|
||||
_apply_on = ['channel.product.pricelist']
|
||||
|
||||
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
|
||||
def on_record_write(self, record, fields=None):
|
||||
record.with_delay(priority=20).create_plan()
|
||||
|
||||
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
|
||||
def on_record_unlink(self, record, fields=None):
|
||||
record.with_delay(priority=20).delete_plan()
|
||||
|
||||
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
|
||||
def on_record_write(self, record, fields=None):
|
||||
if 'name' in fields:
|
||||
record.with_delay(priority=20).update_plan_name()
|
||||
@@ -26,33 +26,33 @@ class WubookConfiguration(models.TransientModel):
|
||||
@api.multi
|
||||
def set_wubook_user(self):
|
||||
return self.env['ir.default'].sudo().set(
|
||||
'wubook.config.settings', 'wubook_user', self.wubook_user)
|
||||
'wubook.config.settings', 'wubook_user', self.wubook_user)
|
||||
|
||||
@api.multi
|
||||
def set_wubook_passwd(self):
|
||||
return self.env['ir.default'].sudo().set(
|
||||
'wubook.config.settings', 'wubook_passwd', self.wubook_passwd)
|
||||
'wubook.config.settings', 'wubook_passwd', self.wubook_passwd)
|
||||
|
||||
@api.multi
|
||||
def set_wubook_lcode(self):
|
||||
return self.env['ir.default'].sudo().set(
|
||||
'wubook.config.settings', 'wubook_lcode', self.wubook_lcode)
|
||||
'wubook.config.settings', 'wubook_lcode', self.wubook_lcode)
|
||||
|
||||
@api.multi
|
||||
def set_wubook_server(self):
|
||||
return self.env['ir.default'].sudo().set(
|
||||
'wubook.config.settings', 'wubook_server', self.wubook_server)
|
||||
'wubook.config.settings', 'wubook_server', self.wubook_server)
|
||||
|
||||
@api.multi
|
||||
def set_wubook_pkey(self):
|
||||
return self.env['ir.default'].sudo().set(
|
||||
'wubook.config.settings', 'wubook_pkey', self.wubook_pkey)
|
||||
'wubook.config.settings', 'wubook_pkey', self.wubook_pkey)
|
||||
|
||||
@api.multi
|
||||
def set_wubook_push_security_token(self):
|
||||
return self.env['ir.default'].sudo().set(
|
||||
'wubook.config.settings',
|
||||
'wubook_push_security_token', self.wubook_push_security_token)
|
||||
'wubook.config.settings',
|
||||
'wubook_push_security_token', self.wubook_push_security_token)
|
||||
|
||||
# Dangerus method: Usefull for cloned instances with new wubook account
|
||||
@api.multi
|
||||
@@ -77,21 +77,21 @@ class WubookConfiguration(models.TransientModel):
|
||||
vrooms = self.env['hotel.room.type'].search([])
|
||||
for vroom in vrooms:
|
||||
shortcode = ir_seq_obj.next_by_code('hotel.room.type')[:4]
|
||||
wrid = wubook_obj.create_room(
|
||||
channel_room_id = wubook_obj.create_room(
|
||||
shortcode,
|
||||
vroom.name,
|
||||
vroom.wcapacity,
|
||||
vroom.list_price,
|
||||
vroom.max_real_rooms
|
||||
)
|
||||
if wrid:
|
||||
if channel_room_id:
|
||||
vroom.with_context(wubook_action=False).write({
|
||||
'wrid': wrid,
|
||||
'channel_room_id': channel_room_id,
|
||||
'wscode': shortcode,
|
||||
})
|
||||
else:
|
||||
vroom.with_context(wubook_action=False).write({
|
||||
'wrid': '',
|
||||
'channel_room_id': '',
|
||||
'wscode': '',
|
||||
})
|
||||
# Create Restrictions
|
||||
@@ -99,16 +99,16 @@ class WubookConfiguration(models.TransientModel):
|
||||
restriction_ids = vroom_rest_obj.search([])
|
||||
for restriction in restriction_ids:
|
||||
if restriction.wpid != '0':
|
||||
wpid = wubook_obj.create_rplan(restriction.name)
|
||||
channel_plan_id = wubook_obj.create_rplan(restriction.name)
|
||||
restriction.write({
|
||||
'wpid': wpid or ''
|
||||
'channel_plan_id': channel_plan_id or ''
|
||||
})
|
||||
# Create Pricelist
|
||||
pricelist_ids = self.env['product.pricelist'].search([])
|
||||
for pricelist in pricelist_ids:
|
||||
wpid = wubook_obj.create_plan(pricelist.name, pricelist.wdaily)
|
||||
channel_plan_id = wubook_obj.create_plan(pricelist.name, pricelist.wdaily)
|
||||
pricelist.write({
|
||||
'wpid': wpid or ''
|
||||
'channel_plan_id': channel_plan_id or ''
|
||||
})
|
||||
wubook_obj.close_connection()
|
||||
|
||||
@@ -120,14 +120,14 @@ class WubookConfiguration(models.TransientModel):
|
||||
|
||||
# Reset Reservations
|
||||
reservation_ids = self.env['hotel.reservation'].search([
|
||||
('wrid', '!=', ''),
|
||||
('wrid', '!=', False)
|
||||
('channel_reservation_id', '!=', ''),
|
||||
('channel_reservation_id', '!=', False)
|
||||
])
|
||||
reservation_ids.with_context(wubook_action=False).write({
|
||||
'wrid': '',
|
||||
'wchannel_id': False,
|
||||
'wchannel_reservation_code': '',
|
||||
'wis_from_channel': False,
|
||||
'channel_reservation_id': '',
|
||||
'ota_id': False,
|
||||
'ota_reservation_id': '',
|
||||
'is_from_ota': False,
|
||||
'wstatus': 0
|
||||
})
|
||||
|
||||
|
||||
@@ -3,13 +3,17 @@
|
||||
from openerp import models, fields, api
|
||||
|
||||
|
||||
class WuBookChannelInfo(models.Model):
|
||||
_name = 'wubook.channel.info'
|
||||
class HotelChannelConnectorOTAInfo(models.Model):
|
||||
_name = 'hote.channel.connector.ota.info'
|
||||
|
||||
wid = fields.Char("WuBook Channel ID", required=True)
|
||||
name = fields.Char("Channel Name", required=True)
|
||||
ota_id = fields.Char("Channel OTA ID", required=True)
|
||||
name = fields.Char("OTA Name", required=True)
|
||||
ical = fields.Boolean("ical", default=False)
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@api.multi
|
||||
def import_channels_info(self):
|
||||
return self.env['wubook'].import_channels_info()
|
||||
self.ensure_one()
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
importer = work.component(usage='channel.importer')
|
||||
return importer.import_channels_info()
|
||||
|
||||
@@ -58,8 +58,8 @@ class TestHotelFolio(TestHotelWubook):
|
||||
('wrid', '=', processed_rids[0])
|
||||
], order='id ASC', limit=1)
|
||||
self.assertTrue(nreserv, "Can't found reservation")
|
||||
self.assertTrue(nreserv.folio_id.whas_wubook_reservations,
|
||||
"Can't found reservations from wubook")
|
||||
self.assertTrue(nreserv.folio_id.has_channel_reservations,
|
||||
"Can't found reservations from channel")
|
||||
|
||||
def test_import_reservations(self):
|
||||
now_utc_dt = date_utils.now()
|
||||
|
||||
@@ -31,7 +31,7 @@ from .common import TestHotelWubook
|
||||
|
||||
class TestHotelReservation(TestHotelWubook):
|
||||
|
||||
def test_is_from_channel(self):
|
||||
def test_is_from_ota(self):
|
||||
now_utc_dt = date_utils.now()
|
||||
checkin_utc_dt = now_utc_dt + timedelta(days=3)
|
||||
checkin_dt = date_utils.dt_as_timezone(checkin_utc_dt,
|
||||
@@ -64,9 +64,9 @@ class TestHotelReservation(TestHotelWubook):
|
||||
('wrid', 'in', processed_rids)
|
||||
])
|
||||
self.assertTrue(nreserv, "Reservation not found")
|
||||
self.assertTrue(nreserv.wis_from_channel)
|
||||
self.assertTrue(nreserv.is_from_ota)
|
||||
nreserv.wrid = ''
|
||||
self.assertFalse(nreserv.wis_from_channel)
|
||||
self.assertFalse(nreserv.is_from_ota)
|
||||
|
||||
def test_write(self):
|
||||
now_utc_dt = date_utils.now()
|
||||
|
||||
@@ -29,7 +29,7 @@ class MassiveChangesWizard(models.TransientModel):
|
||||
@api.multi
|
||||
def duplicate_reservation(self):
|
||||
reservation_id = self.env['hotel.reservation'].browse(
|
||||
self.env.context.get('active_id'))
|
||||
if reservation_id and reservation_id.wis_from_channel:
|
||||
self.env.context.get('active_id'))
|
||||
if reservation_id and reservation_id.is_from_ota:
|
||||
raise ValidationError(_("Can't duplicate a reservation from channel"))
|
||||
return super(MassiveChangesWizard, self).duplicate_reservation()
|
||||
|
||||
@@ -34,7 +34,7 @@ class MassivePriceChangeWizard(models.TransientModel):
|
||||
if not reservation_id:
|
||||
return False
|
||||
|
||||
if reservation_id.wis_from_channel:
|
||||
if reservation_id.is_from_ota:
|
||||
raise ValidationError(
|
||||
_("Can't change prices of reservations from OTA's"))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user