mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
[WIP][MIG][11.0] connector
This commit is contained in:
@@ -47,12 +47,12 @@
|
||||
'views/inherit_product_product.xml',
|
||||
'views/hotel_room_amenities_type.xml',
|
||||
'views/hotel_room_amenities.xml',
|
||||
'views/reservation_restriction_views.xml',
|
||||
'views/reservation_restriction_item_views.xml',
|
||||
'views/hotel_room_type_restriction_views.xml',
|
||||
'views/hotel_room_type_restriction_item_views.xml',
|
||||
'views/hotel_reservation.xml',
|
||||
# 'views/room_type_views.xml',
|
||||
'views/cardex.xml',
|
||||
'views/room_type_availability.xml',
|
||||
'views/hotel_room_type_availability.xml',
|
||||
# 'views/hotel_dashboard.xml',
|
||||
'data/cron_jobs.xml',
|
||||
'data/records.xml',
|
||||
|
||||
@@ -16,8 +16,7 @@ class HotelRoomTypeRestrictionItem(models.Model):
|
||||
# required=True, ondelete='cascade')
|
||||
room_type_id = fields.Many2one('hotel.room.type', 'Room Type',
|
||||
required=True, ondelete='cascade')
|
||||
date_start = fields.Date('From')
|
||||
date_end = fields.Date("To")
|
||||
date = fields.Date('Date')
|
||||
applied_on = fields.Selection([
|
||||
('1_global', 'Global'),
|
||||
# ('0_room_type', 'Virtual Room')], string="Apply On", required=True,
|
||||
@@ -35,7 +34,7 @@ class HotelRoomTypeRestrictionItem(models.Model):
|
||||
closed_arrival = fields.Boolean('Closed Arrival')
|
||||
|
||||
_sql_constraints = [('room_type_registry_unique',
|
||||
'unique(restriction_id, room_type_id, date_start, date_end)',
|
||||
'unique(restriction_id, room_type_id, date)',
|
||||
'Only can exists one restriction in the same day for the same room type!')]
|
||||
|
||||
@api.constrains('min_stay', 'min_stay_arrival', 'max_stay',
|
||||
@@ -52,17 +51,6 @@ class HotelRoomTypeRestrictionItem(models.Model):
|
||||
raise ValidationError(
|
||||
("Max. Stay Arrival can't be less than zero"))
|
||||
|
||||
@api.constrains('date_start', 'date_end')
|
||||
def _check_date_start_date_end(self):
|
||||
if self.applied_on == '1_global':
|
||||
self.date_start = False
|
||||
self.date_end = False
|
||||
elif self.date_start and self.date_end:
|
||||
date_start_dt = fields.Date.from_string(self.date_start)
|
||||
date_end_dt = fields.Date.from_string(self.date_end)
|
||||
if date_end_dt < date_start_dt:
|
||||
raise ValidationError(_("Invalid Dates"))
|
||||
|
||||
@api.constrains('applied_on')
|
||||
def _check_applied_on(self):
|
||||
count = self.search_count([('applied_on', '=', '1_global')])
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<odoo>
|
||||
|
||||
<!-- FORM restriction -->
|
||||
<record id="reservation_restriction_item_view_form" model="ir.ui.view">
|
||||
<record id="room_type_restriction_item_view_form" model="ir.ui.view">
|
||||
<field name="name">hotel.room.type.restriction.item.form</field>
|
||||
<field name="model">hotel.room.type.restriction.item</field>
|
||||
<field name="arch" type="xml">
|
||||
@@ -13,12 +13,7 @@
|
||||
<field name="room_type_id" attrs="{'invisible':[['applied_on', '=', '1_global']]}" required="True"/>
|
||||
</group>
|
||||
<group>
|
||||
<group>
|
||||
<field name="date_start"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="date_end"/>
|
||||
</group>
|
||||
<field name="date"/>
|
||||
</group>
|
||||
<group>
|
||||
<group>
|
||||
@@ -37,7 +32,7 @@
|
||||
</record>
|
||||
|
||||
<!-- TREE restriction -->
|
||||
<record id="reservation_restriction_item_view_tree" model="ir.ui.view">
|
||||
<record id="room_type_restriction_item_view_tree" model="ir.ui.view">
|
||||
<field name="name">hotel.room.type.restriction.item.tree</field>
|
||||
<field name="model">hotel.room.type.restriction.item</field>
|
||||
<field name="arch" type="xml">
|
||||
@@ -45,8 +40,7 @@
|
||||
<field name="applied_on"/>
|
||||
<!-- <field name="room_type_id" attrs="{'invisible':[['applied_on', '=', '1_room_type']]}"/> -->
|
||||
<field name="room_type_id" attrs="{'invisible':[['applied_on', '=', '0_room_type']]}"/>
|
||||
<field name="date_start"/>
|
||||
<field name="date_end"/>
|
||||
<field name="date"/>
|
||||
<field name="min_stay"/>
|
||||
<field name="closed"/>
|
||||
</tree>
|
||||
@@ -2,7 +2,7 @@
|
||||
<odoo>
|
||||
|
||||
<!-- FORM restriction -->
|
||||
<record id="reservation_restriction_view_form" model="ir.ui.view">
|
||||
<record id="room_type_restriction_view_form" model="ir.ui.view">
|
||||
<field name="name">hotel.room.type.restriction.form</field>
|
||||
<field name="model">hotel.room.type.restriction</field>
|
||||
<field name="arch" type="xml">
|
||||
@@ -21,8 +21,7 @@
|
||||
<field name="applied_on"/>
|
||||
<!-- <field name="room_type_id" attr="{'invisible':[['applied_on', '=', '1_room_type']]}"/> -->
|
||||
<field name="room_type_id" attr="{'invisible':[['applied_on', '=', '0_room_type']]}"/>
|
||||
<field name="date_start"/>
|
||||
<field name="date_end"/>
|
||||
<field name="date"/>
|
||||
<field name="min_stay"/>
|
||||
<field name="closed"/>
|
||||
</tree>
|
||||
@@ -34,7 +33,7 @@
|
||||
</record>
|
||||
|
||||
<!-- TREE restriction -->
|
||||
<record id="reservation_restriction_view_tree" model="ir.ui.view">
|
||||
<record id="room_type_restriction_view_tree" model="ir.ui.view">
|
||||
<field name="name">hotel.room.type.restriction.tree</field>
|
||||
<field name="model">hotel.room.type.restriction</field>
|
||||
<field name="arch" type="xml">
|
||||
@@ -46,7 +45,7 @@
|
||||
</record>
|
||||
|
||||
<!-- Action of reservation restriction -->
|
||||
<record model="ir.actions.act_window" id="reservation_restriction_action">
|
||||
<record model="ir.actions.act_window" id="room_type_restriction_action">
|
||||
<field name="name">Reservation restrictions</field>
|
||||
<field name="res_model">hotel.room.type.restriction</field>
|
||||
<field name="view_type">form</field>
|
||||
@@ -55,7 +54,7 @@
|
||||
|
||||
<!-- MENUS -->
|
||||
<menuitem name="Restrictions" id="reservation_restriction_menu"
|
||||
action="reservation_restriction_action" sequence="22"
|
||||
action="room_type_restriction_action" sequence="22"
|
||||
parent="hotel.configuration_others"/>
|
||||
|
||||
</odoo>
|
||||
@@ -84,8 +84,7 @@ class HotelCalendarManagement(models.TransientModel):
|
||||
for k_res in restrictions.keys():
|
||||
for restriction in restrictions[k_res]:
|
||||
res_id = room_type_rest_item_obj.search([
|
||||
('date_start', '>=', restriction['date']),
|
||||
('date_end', '<=', restriction['date']),
|
||||
('date', '=', restriction['date']),
|
||||
('restriction_id', '=', int(restriction_id)),
|
||||
('applied_on', '=', '0_room_type'),
|
||||
('room_type_id', '=', int(k_res)),
|
||||
@@ -93,8 +92,7 @@ class HotelCalendarManagement(models.TransientModel):
|
||||
vals = self._get_restrictions_values(restriction)
|
||||
if not res_id:
|
||||
vals.update({
|
||||
'date_start': restriction['date'],
|
||||
'date_end': restriction['date'],
|
||||
'date': restriction['date'],
|
||||
'restriction_id': int(restriction_id),
|
||||
'applied_on': '0_room_type',
|
||||
'room_type_id': int(k_res),
|
||||
@@ -159,10 +157,9 @@ class HotelCalendarManagement(models.TransientModel):
|
||||
def _hcalendar_restriction_json_data(self, restrictions):
|
||||
json_data = {}
|
||||
for rec in restrictions:
|
||||
# TODO: date_end - date_start loop
|
||||
json_data.setdefault(rec.room_type_id.id, []).append({
|
||||
'id': rec.id,
|
||||
'date': rec.date_start,
|
||||
'date': rec.date,
|
||||
'min_stay': rec.min_stay,
|
||||
'min_stay_arrival': rec.min_stay_arrival,
|
||||
'max_stay': rec.max_stay,
|
||||
@@ -282,7 +279,7 @@ class HotelCalendarManagement(models.TransientModel):
|
||||
|
||||
room_type_rest_it_obj = self.env['hotel.room.type.restriction.item']
|
||||
restriction_item_ids = room_type_rest_it_obj.search([
|
||||
('date_start', '>=', dfrom), ('date_end', '<=', dto),
|
||||
('date', '>=', dfrom), ('date', '<=', dto),
|
||||
('restriction_id', '=', restriction_id),
|
||||
('applied_on', '=', '0_room_type'),
|
||||
])
|
||||
|
||||
@@ -162,7 +162,7 @@ class HotelReservation(models.Model):
|
||||
restriction_id = int(restriction_id)
|
||||
date_start = fields.Date.from_string(dfrom) - timedelta(days=1)
|
||||
date_end = fields.Date.from_string(dto)
|
||||
date_diff = abs((date_end - date_sart).days) + 1
|
||||
date_diff = abs((date_end - date_start).days) + 1
|
||||
# Get Prices
|
||||
json_rooms_rests = {}
|
||||
room_types = self.env['hotel.room.type'].search(
|
||||
@@ -176,8 +176,7 @@ class HotelReservation(models.Model):
|
||||
ndate_str = ndate.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||
rest_id = room_type_rest_obj.search([
|
||||
('room_type_id', '=', room_type.id),
|
||||
('date_start', '>=', ndate_str),
|
||||
('date_end', '<=', ndate_str),
|
||||
('date', '>=', ndate_str),
|
||||
('applied_on', '=', '0_room_type'),
|
||||
('restriction_id', '=', restriction_id)
|
||||
], limit=1)
|
||||
|
||||
@@ -10,7 +10,7 @@ class HotelRoomType(models.Model):
|
||||
|
||||
@api.multi
|
||||
def unlink(self):
|
||||
room_type_pr_cached_obj = self.env['hotel.room.pricelist.cached']
|
||||
room_type_pr_cached_obj = self.env['room.pricelist.cached']
|
||||
for record in self:
|
||||
pr_chached = room_type_pr_cached_obj.search([
|
||||
('room_id', '=', record.id)
|
||||
|
||||
@@ -10,7 +10,7 @@ class HotelRoomTypeResrtrictionItem(models.Model):
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
res = super(HotelVirtualRoomResrtrictionItem, self).create(vals)
|
||||
res = super(HotelRoomTypeResrtrictionItem, self).create(vals)
|
||||
restrictions_parity_id = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'parity_restrictions_id')
|
||||
if restrictions_parity_id:
|
||||
@@ -20,7 +20,7 @@ class HotelRoomTypeResrtrictionItem(models.Model):
|
||||
self.applied_on == '0_room_type':
|
||||
self.env['bus.hotel.calendar'].send_restriction_notification({
|
||||
'restriction_id': self.restriction_id.id,
|
||||
'date': self.date_start,
|
||||
'date': self.date,
|
||||
'min_stay': self.min_stay,
|
||||
'min_stay_arrival': self.min_stay_arrival,
|
||||
'max_stay': self.max_stay,
|
||||
@@ -39,7 +39,7 @@ class HotelRoomTypeResrtrictionItem(models.Model):
|
||||
'res.config.settings', 'parity_restrictions_id')
|
||||
if restrictions_parity_id:
|
||||
restrictions_parity_id = int(restrictions_parity_id)
|
||||
ret_vals = super(HotelVirtualRoomResrtrictionItem, self).write(vals)
|
||||
ret_vals = super(HotelRoomTypeResrtrictionItem, self).write(vals)
|
||||
|
||||
bus_hotel_calendar_obj = self.env['bus.hotel.calendar']
|
||||
for record in self:
|
||||
@@ -48,7 +48,7 @@ class HotelRoomTypeResrtrictionItem(models.Model):
|
||||
continue
|
||||
bus_hotel_calendar_obj.send_restriction_notification({
|
||||
'restriction_id': record.restriction_id.id,
|
||||
'date': record.date_start,
|
||||
'date': record.date,
|
||||
'min_stay': record.min_stay,
|
||||
'min_stay_arrival': record.min_stay_arrival,
|
||||
'max_stay': record.max_stay,
|
||||
@@ -86,7 +86,7 @@ class HotelRoomTypeResrtrictionItem(models.Model):
|
||||
'room_type_id': record.room_type_id.id,
|
||||
'id': record.id,
|
||||
})
|
||||
res = super(HotelVirtualRoomResrtrictionItem, self).unlink()
|
||||
res = super(HotelRoomTypeResrtrictionItem, self).unlink()
|
||||
bus_hotel_calendar_obj = self.env['bus.hotel.calendar']
|
||||
for uval in unlink_vals:
|
||||
bus_hotel_calendar_obj.send_restriction_notification(uval)
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
},
|
||||
'data': [
|
||||
'data/cron_jobs.xml',
|
||||
'wizard/wubook_installer.xml',
|
||||
'wizard/wubook_import_plan_prices.xml',
|
||||
'wizard/wubook_import_plan_restrictions.xml',
|
||||
'wizard/wubook_import_availability.xml',
|
||||
@@ -29,10 +28,9 @@
|
||||
'views/inherited_hotel_folio_views.xml',
|
||||
'views/inherited_product_pricelist_views.xml',
|
||||
'views/inherited_product_pricelist_item_views.xml',
|
||||
'views/inherited_reservation_restriction_views.xml',
|
||||
'views/inherited_reservation_restriction_item_views.xml',
|
||||
'views/inherited_hotel_room_type_restriction_views.xml',
|
||||
'views/inherited_res_partner_views.xml',
|
||||
'views/hotel_channel_connector_ota_info_views.xml',
|
||||
'views/channel_ota_info_views.xml',
|
||||
'views/hotel_channel_connector_issue_views.xml',
|
||||
'views/channel_hotel_reservation_views.xml',
|
||||
'views/channel_hotel_room_type_views.xml',
|
||||
|
||||
@@ -12,4 +12,5 @@ class HotelConnectorModelBinder(Component):
|
||||
'channel.hotel.room.type.availability',
|
||||
'channel.hotel.room.type.restriction',
|
||||
'channel.product.pricelist',
|
||||
'channel.ota.info',
|
||||
]
|
||||
|
||||
@@ -14,7 +14,7 @@ class BaseHotelChannelConnectorComponent(AbstractComponent):
|
||||
dfrom=False, dto=False):
|
||||
self.env['hotel.channel.connector.issue'].sudo().create({
|
||||
'section': section,
|
||||
'message': message,
|
||||
'internal_message': message,
|
||||
'channel_object_id': channel_object_id,
|
||||
'channel_message': channel_message,
|
||||
'date_start': dfrom,
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
import logging
|
||||
import psycopg2
|
||||
from contextlib import contextmanager
|
||||
from odoo.addons.connector.exception import (IDMissingInBackend,
|
||||
RetryableJobError)
|
||||
from odoo.addons.component.core import AbstractComponent
|
||||
from odoo.tools import (
|
||||
DEFAULT_SERVER_DATE_FORMAT,
|
||||
|
||||
@@ -663,28 +663,6 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
||||
|
||||
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 fetch_booking(self, channel_reservation_id):
|
||||
try:
|
||||
@@ -793,19 +771,6 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
||||
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 ChannelConnectorError as err:
|
||||
self.create_issue(
|
||||
'channel',
|
||||
_("Can't import channels info from wubook"),
|
||||
err.data['message'])
|
||||
return 0
|
||||
return count
|
||||
|
||||
class BatchImporter(AbstractComponent):
|
||||
""" The role of a BatchImporter is to search for a list of
|
||||
items to import, then it can either import them directly or delay
|
||||
|
||||
@@ -9,16 +9,19 @@
|
||||
|
||||
<menuitem id="menu_cannel_backend"
|
||||
name="Backends"
|
||||
sequence="1"
|
||||
parent="menu_channel_connector_root"
|
||||
action="action_channel_backend"/>
|
||||
|
||||
<menuitem id="hotel_channel_connector_ota_info_menu"
|
||||
<menuitem id="channel_ota_info_menu"
|
||||
name="OTA's"
|
||||
action="open_hotel_channel_connector_ota_info_tree_all"
|
||||
sequence="2"
|
||||
action="open_channel_ota_info_tree_all"
|
||||
parent="menu_channel_connector_root"/>
|
||||
|
||||
<menuitem id="hotel_channel_connector_issue_menu"
|
||||
name="Issues"
|
||||
sequence="3"
|
||||
action="open_hotel_channel_connector_issue_tree_all"
|
||||
parent="menu_channel_connector_root"/>
|
||||
|
||||
|
||||
@@ -2,17 +2,16 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import channel_binding
|
||||
|
||||
from . import channel_backend
|
||||
from . import res_config
|
||||
from . import hotel_room_type
|
||||
from . import product_pricelist
|
||||
from . import inherited_product_pricelist_item
|
||||
from . import hotel_room_type_restriction
|
||||
from . import inherited_reservation_restriction_item
|
||||
from . import hotel_room_type_restriction_item
|
||||
from . import hotel_room_type_availability
|
||||
from . import hotel_reservation
|
||||
from . import inherited_hotel_folio
|
||||
from . import inherited_res_partner
|
||||
from . import hotel_channel_connector_ota_info
|
||||
from . import channel_ota_info
|
||||
from . import hotel_channel_connector_issue
|
||||
from . import res_config
|
||||
|
||||
@@ -27,19 +27,27 @@ class ChannelBackend(models.Model):
|
||||
server = fields.Char('Channel Service Server',
|
||||
default='https://wired.wubook.net/xrws/')
|
||||
pkey = fields.Char('Channel Service PKey')
|
||||
security_token = fields.Char('Channel Service Security Token')
|
||||
|
||||
@api.multi
|
||||
def import_reservations(self):
|
||||
channel_hotel_reservation = self.env['channel.hotel.reservation']
|
||||
channel_hotel_reservation_obj = self.env['channel.hotel.reservation']
|
||||
for backend in self:
|
||||
channel_hotel_reservation.import_reservations(backend)
|
||||
channel_hotel_reservation_obj.import_reservations(backend)
|
||||
return True
|
||||
|
||||
@api.multi
|
||||
def import_rooms(self):
|
||||
channel_hotel_room_type = self.env['channel.hotel.room.type']
|
||||
channel_hotel_room_type_obj = self.env['channel.hotel.room.type']
|
||||
for backend in self:
|
||||
channel_hotel_room_type.import_rooms(backend)
|
||||
channel_hotel_room_type_obj.import_rooms(backend)
|
||||
return True
|
||||
|
||||
@api.multi
|
||||
def import_otas_info(self):
|
||||
channel_ota_info_obj = self.env['channel.ota.info']
|
||||
for backend in self:
|
||||
channel_ota_info_obj.import_otas_info(backend)
|
||||
return True
|
||||
|
||||
@contextmanager
|
||||
@@ -56,3 +64,163 @@ class ChannelBackend(models.Model):
|
||||
_super = super(ChannelBackend, self)
|
||||
with _super.work_on(model_name, channel_api=channel_api, **kwargs) as work:
|
||||
yield work
|
||||
|
||||
# Dangerus method: Usefull for cloned instances with new wubook account
|
||||
@api.multi
|
||||
def resync(self):
|
||||
self.ensure_one()
|
||||
|
||||
now_utc_dt = fields.Date.now()
|
||||
now_utc_str = now_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||
|
||||
# Reset Issues
|
||||
issue_ids = self.env['wubook.issue'].search([])
|
||||
issue_ids.write({
|
||||
'to_read': False
|
||||
})
|
||||
|
||||
# Push Virtual Rooms
|
||||
wubook_obj = self.env['wubook'].with_context({
|
||||
'init_connection': False
|
||||
})
|
||||
if wubook_obj.init_connection():
|
||||
ir_seq_obj = self.env['ir.sequence']
|
||||
room_types = self.env['hotel.room.type'].search([])
|
||||
for room_type in room_types:
|
||||
shortcode = ir_seq_obj.next_by_code('hotel.room.type')[:4]
|
||||
channel_room_id = wubook_obj.create_room(
|
||||
shortcode,
|
||||
room_type.name,
|
||||
room_type.wcapacity,
|
||||
room_type.list_price,
|
||||
room_type.total_rooms_count
|
||||
)
|
||||
if channel_room_id:
|
||||
room_type.with_context(wubook_action=False).write({
|
||||
'channel_room_id': channel_room_id,
|
||||
'wscode': shortcode,
|
||||
})
|
||||
else:
|
||||
room_type.with_context(wubook_action=False).write({
|
||||
'channel_room_id': '',
|
||||
'wscode': '',
|
||||
})
|
||||
# Create Restrictions
|
||||
room_type_rest_obj = self.env['hotel.room.type.restriction']
|
||||
restriction_ids = room_type_rest_obj.search([])
|
||||
for restriction in restriction_ids:
|
||||
if restriction.wpid != '0':
|
||||
channel_plan_id = wubook_obj.create_rplan(restriction.name)
|
||||
restriction.write({
|
||||
'channel_plan_id': channel_plan_id or ''
|
||||
})
|
||||
# Create Pricelist
|
||||
pricelist_ids = self.env['product.pricelist'].search([])
|
||||
for pricelist in pricelist_ids:
|
||||
channel_plan_id = wubook_obj.create_plan(pricelist.name, pricelist.is_daily_plan)
|
||||
pricelist.write({
|
||||
'channel_plan_id': channel_plan_id or ''
|
||||
})
|
||||
wubook_obj.close_connection()
|
||||
|
||||
# Reset Folios
|
||||
folio_ids = self.env['hotel.folio'].search([])
|
||||
folio_ids.with_context(wubook_action=False).write({
|
||||
'wseed': '',
|
||||
})
|
||||
|
||||
# Reset Reservations
|
||||
reservation_ids = self.env['hotel.reservation'].search([
|
||||
('channel_reservation_id', '!=', ''),
|
||||
('channel_reservation_id', '!=', False)
|
||||
])
|
||||
reservation_ids.with_context(wubook_action=False).write({
|
||||
'channel_reservation_id': '',
|
||||
'ota_id': False,
|
||||
'ota_reservation_id': '',
|
||||
'is_from_ota': False,
|
||||
'wstatus': 0
|
||||
})
|
||||
|
||||
# Get Parity Models
|
||||
pricelist_id = int(self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'parity_pricelist_id'))
|
||||
restriction_id = int(self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'parity_restrictions_id'))
|
||||
|
||||
room_type_restr_it_obj = self.env['hotel.room.type.restriction.item']
|
||||
# Secure Wubook Input
|
||||
restriction_item_ids = room_type_restr_it_obj.search([
|
||||
('applied_on', '=', '0_room_type'),
|
||||
('date_start', '<', now_utc_str),
|
||||
])
|
||||
if any(restriction_item_ids):
|
||||
restriction_item_ids.with_context(wubook_action=False).write({
|
||||
'wpushed': True
|
||||
})
|
||||
# Put to push restrictions
|
||||
restriction_item_ids = room_type_restr_it_obj.search([
|
||||
('restriction_id', '=', restriction_id),
|
||||
('applied_on', '=', '0_room_type'),
|
||||
('wpushed', '=', True),
|
||||
('date_start', '>=', now_utc_str),
|
||||
])
|
||||
if any(restriction_item_ids):
|
||||
restriction_item_ids.with_context(wubook_action=False).write({
|
||||
'wpushed': False
|
||||
})
|
||||
|
||||
# Secure Wubook Input
|
||||
pricelist_item_ids = self.env['product.pricelist.item'].search([
|
||||
('applied_on', '=', '1_product'),
|
||||
('compute_price', '=', 'fixed'),
|
||||
('date_start', '<', now_utc_str),
|
||||
])
|
||||
if any(pricelist_item_ids):
|
||||
pricelist_item_ids.with_context(wubook_action=False).write({
|
||||
'wpushed': True
|
||||
})
|
||||
# Put to push pricelists
|
||||
pricelist_item_ids = self.env['product.pricelist.item'].search([
|
||||
('pricelist_id', '=', pricelist_id),
|
||||
('applied_on', '=', '1_product'),
|
||||
('compute_price', '=', 'fixed'),
|
||||
('wpushed', '=', True),
|
||||
('date_start', '>=', now_utc_str),
|
||||
])
|
||||
if any(pricelist_item_ids):
|
||||
pricelist_item_ids.with_context(wubook_action=False).write({
|
||||
'wpushed': False
|
||||
})
|
||||
|
||||
# Secure Wubook Input
|
||||
availabity_ids = self.env['hotel.room.type.availability'].search([
|
||||
('date', '<', now_utc_str),
|
||||
])
|
||||
if any(availabity_ids):
|
||||
availabity_ids.with_context(wubook_action=False).write({
|
||||
'wpushed': True
|
||||
})
|
||||
# Put to push availability
|
||||
availabity_ids = self.env['hotel.room.type.availability'].search([
|
||||
('wpushed', '=', True),
|
||||
('date', '>=', now_utc_str),
|
||||
])
|
||||
if any(availabity_ids):
|
||||
availabity_ids.with_context(wubook_action=False).write({
|
||||
'wpushed': False
|
||||
})
|
||||
|
||||
# Generate Security Token
|
||||
self.env['ir.default'].sudo().set(
|
||||
'wubook.config.settings',
|
||||
'wubook_push_security_token',
|
||||
binascii.hexlify(os.urandom(16)).decode())
|
||||
self.env.cr.commit() # FIXME: Need do this
|
||||
|
||||
# Push Changes
|
||||
if wubook_obj.init_connection():
|
||||
wubook_obj.push_activation()
|
||||
wubook_obj.import_channels_info()
|
||||
wubook_obj.push_changes()
|
||||
wubook_obj.close_connection()
|
||||
|
||||
@@ -15,3 +15,8 @@ class ChannelBinding(models.AbstractModel):
|
||||
string='Hotel Channel Connector Backend',
|
||||
required=True,
|
||||
ondelete='restrict')
|
||||
|
||||
_sql_constraints = [
|
||||
('channel_uniq', 'unique(backend_id, external_id)',
|
||||
'A binding already exists with the same Channel ID.'),
|
||||
]
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import common
|
||||
from . import importer
|
||||
30
hotel_channel_connector/models/channel_ota_info/common.py
Normal file
30
hotel_channel_connector/models/channel_ota_info/common.py
Normal file
@@ -0,0 +1,30 @@
|
||||
# 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
|
||||
from odoo.addons.component.core import Component
|
||||
|
||||
class ChannelOtaInfo(models.Model):
|
||||
_name = 'channel.ota.info'
|
||||
_inherit = 'channel.binding'
|
||||
_description = 'Channel OTA Info'
|
||||
|
||||
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.model
|
||||
def import_otas_info(self, backend):
|
||||
with backend.work_on(self._name) as work:
|
||||
importer = work.component(usage='ota.info.importer')
|
||||
return importer.import_otas_info()
|
||||
|
||||
class HotelRoomTypeAdapter(Component):
|
||||
_name = 'channel.ota.info.adapter'
|
||||
_inherit = 'wubook.adapter'
|
||||
_apply_on = 'channel.ota.info'
|
||||
|
||||
def fetch_rooms(self):
|
||||
return super(HotelRoomTypeAdapter, self).fetch_rooms()
|
||||
62
hotel_channel_connector/models/channel_ota_info/importer.py
Normal file
62
hotel_channel_connector/models/channel_ota_info/importer.py
Normal file
@@ -0,0 +1,62 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.addons.component.core import Component
|
||||
from odoo.addons.hotel_channel_connector.components.core import ChannelConnectorError
|
||||
from odoo.addons.connector.components.mapper import mapping
|
||||
from odoo import fields, api, _
|
||||
from odoo.tools import (
|
||||
DEFAULT_SERVER_DATE_FORMAT,
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
|
||||
|
||||
class ChannelOtaInfoImporter(Component):
|
||||
_name = 'channel.ota.info.importer'
|
||||
_inherit = 'hotel.channel.importer'
|
||||
_apply_on = ['channel.ota.info']
|
||||
_usage = 'ota.info.importer'
|
||||
|
||||
@api.model
|
||||
def import_otas_info(self):
|
||||
count = 0
|
||||
try:
|
||||
results = self.backend_adapter.get_channels_info()
|
||||
|
||||
channel_ota_info_obj = self.env['channel.ota.info']
|
||||
ota_info_mapper = self.component(usage='import.mapper',
|
||||
model_name='channel.ota.info')
|
||||
for ota_id in results.keys():
|
||||
vals = {
|
||||
'id': ota_id,
|
||||
'name': results[ota_id]['name'],
|
||||
'ical': results[ota_id]['ical'] == 1,
|
||||
}
|
||||
map_record = ota_info_mapper.map_record(vals)
|
||||
ota_info_bind = channel_ota_info_obj.search([
|
||||
('ota_id', '=', ota_id)
|
||||
], limit=1)
|
||||
if ota_info_bind:
|
||||
ota_info_bind.write(map_record.values())
|
||||
else:
|
||||
ota_info_bind.create(map_record.values(for_create=True))
|
||||
count = count + 1
|
||||
except ChannelConnectorError as err:
|
||||
self.create_issue('room', _("Can't import rooms from WuBook"), err.data['message'])
|
||||
return count
|
||||
|
||||
|
||||
class ChannelOtaInfoImportMapper(Component):
|
||||
_name = 'channel.ota.info.import.mapper'
|
||||
_inherit = 'channel.import.mapper'
|
||||
_apply_on = 'channel.ota.info'
|
||||
|
||||
direct = [
|
||||
('id', 'ota_id'),
|
||||
('name', 'name'),
|
||||
('ical', 'ical'),
|
||||
]
|
||||
|
||||
@mapping
|
||||
def backend_id(self, record):
|
||||
return {'backend_id': self.backend_record.id}
|
||||
@@ -1,20 +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 odoo.addons.queue_job.job import job
|
||||
|
||||
class HotelChannelConnectorOTAInfo(models.Model):
|
||||
_name = 'hotel.channel.connector.ota.info'
|
||||
|
||||
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):
|
||||
self.ensure_one()
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
importer = work.component(usage='channel.importer')
|
||||
return importer.import_channels_info()
|
||||
@@ -26,7 +26,7 @@ class ChannelHotelReservation(models.Model):
|
||||
required=True,
|
||||
ondelete='cascade')
|
||||
channel_reservation_id = fields.Char("Channel Reservation ID", readonly=True, old_name='wrid')
|
||||
ota_id = fields.Many2one('hotel.channel.connector.ota.info',
|
||||
ota_id = fields.Many2one('channel.ota.info',
|
||||
string='Channel OTA ID',
|
||||
readonly=True,
|
||||
old_name='wchannel_id')
|
||||
|
||||
@@ -23,6 +23,15 @@ class ChannelHotelRoomType(models.Model):
|
||||
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.onchange('room_ids')
|
||||
def _get_capacity(self):
|
||||
for rec in self:
|
||||
rec.ota_capacity = rec.odoo_id.get_capacity()
|
||||
|
||||
def _check_self_unlink(self):
|
||||
if not self.odoo_id:
|
||||
self.sudo().unlink()
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@api.model
|
||||
def import_rooms(self, backend):
|
||||
@@ -48,53 +57,30 @@ class ChannelHotelRoomType(models.Model):
|
||||
@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]
|
||||
if not self.channel_room_id:
|
||||
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.total_rooms_count)
|
||||
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")
|
||||
exporter = work.component(usage='hotel.room.type.exporter')
|
||||
exporter.create_room(self)
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@related_action(action='related_action_unwrap_binding')
|
||||
@api.multi
|
||||
def modify_room(self):
|
||||
_logger.info("PASA A =======")
|
||||
self.ensure_one()
|
||||
_logger.info("PASA b =======")
|
||||
if self._context.get('wubook_action', True) and self.channel_room_id:
|
||||
_logger.info("PASA C =======")
|
||||
if self.channel_room_id:
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
_logger.info("PASA D =======")
|
||||
exporter = work.component(usage='hotel.room.type.exporter')
|
||||
exporter.modify_room(self)
|
||||
_logger.info("PASA E =======")
|
||||
|
||||
@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:
|
||||
if 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")
|
||||
exporter = work.component(usage='hotel.room.type.exporter')
|
||||
exporter.delete_room(self)
|
||||
|
||||
class HotelRoomType(models.Model):
|
||||
_inherit = 'hotel.room.type'
|
||||
@@ -104,10 +90,16 @@ class HotelRoomType(models.Model):
|
||||
inverse_name='odoo_id',
|
||||
string='Hotel Channel Connector Bindings')
|
||||
|
||||
capacity = fields.Integer("Capacity", compute="_compute_capacity")
|
||||
|
||||
@api.multi
|
||||
def _compute_capacity(self):
|
||||
for record in self:
|
||||
record.capacity = record.get_capacity()
|
||||
|
||||
@api.onchange('room_ids')
|
||||
def _get_capacity(self):
|
||||
for rec in self:
|
||||
rec.channel_bind_ids.ota_capacity = rec.get_capacity()
|
||||
def _onchange_room_ids(self):
|
||||
self._compute_capacity()
|
||||
|
||||
@api.multi
|
||||
def get_restrictions(self, date):
|
||||
@@ -115,13 +107,26 @@ class HotelRoomType(models.Model):
|
||||
'res.config.settings', 'parity_restrictions_id'))
|
||||
self.ensure_one()
|
||||
restriction = self.env['hotel.room.type.restriction.item'].search([
|
||||
('date_start', '=', date),
|
||||
('date_end', '=', date),
|
||||
('date', '=', date),
|
||||
('room_type_id', '=', self.id),
|
||||
('restriction_id', '=', restriction_plan_id)
|
||||
], limit=1)
|
||||
return restriction
|
||||
|
||||
@api.multi
|
||||
def create_bindings(self):
|
||||
backends = self.env['channel.backend'].search([])
|
||||
binding_obj = self.env['channel.hotel.room.type']
|
||||
for backend in backends:
|
||||
binding = binding_obj.search([
|
||||
('odoo_id', '=', self.id),
|
||||
('backend_id', '=', backend.id)], limit=1)
|
||||
if not binding:
|
||||
binding_obj.sudo().create({
|
||||
'odoo_id': self.id,
|
||||
'backend_id': backend.id,
|
||||
})
|
||||
|
||||
class HotelRoomTypeAdapter(Component):
|
||||
_name = 'channel.hotel.room.type.adapter'
|
||||
_inherit = 'wubook.adapter'
|
||||
@@ -140,6 +145,10 @@ class BindingHotelRoomTypeListener(Component):
|
||||
if 'name' in fields or 'list_price' in fields:
|
||||
record.channel_bind_ids[0].modify_room()
|
||||
|
||||
# @skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
|
||||
# def on_record_create(self, record, fields=None):
|
||||
# record.create_bindings()
|
||||
|
||||
class ChannelBindingRoomTypeListener(Component):
|
||||
_name = 'channel.binding.room.type.listener'
|
||||
_inherit = 'base.connector.listener'
|
||||
@@ -147,11 +156,11 @@ class ChannelBindingRoomTypeListener(Component):
|
||||
|
||||
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
|
||||
def on_record_create(self, record, fields=None):
|
||||
record.with_delay(priority=20).create_room()
|
||||
record.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()
|
||||
record.delete_room()
|
||||
|
||||
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
|
||||
def on_record_write(self, record, fields=None):
|
||||
|
||||
@@ -23,3 +23,31 @@ class HotelRoomTypeExporter(Component):
|
||||
binding.channel_short_code)
|
||||
except ChannelConnectorError as err:
|
||||
self.create_issue('room', _("Can't modify rooms in WuBook"), err.data['message'])
|
||||
|
||||
@api.model
|
||||
def delete_room(self, binding):
|
||||
try:
|
||||
return self.backend_adapter.delete_room(binding.channel_room_id)
|
||||
except ChannelConnectorError as err:
|
||||
self.create_issue('room', _("Can't delete room in WuBook"), err.data['message'])
|
||||
|
||||
@api.model
|
||||
def create_room(self, binding):
|
||||
try:
|
||||
seq_obj = self.env['ir.sequence']
|
||||
short_code = seq_obj.next_by_code('hotel.room.type')[:4]
|
||||
external_id = self.backend_adapter.create_room(
|
||||
short_code,
|
||||
binding.name,
|
||||
binding.ota_capacity,
|
||||
binding.list_price,
|
||||
binding.total_rooms_count
|
||||
)
|
||||
binding.write({
|
||||
'channel_room_id': external_id,
|
||||
'channel_short_code': short_code,
|
||||
})
|
||||
except ChannelConnectorError as err:
|
||||
self.create_issue('room', _("Can't delete room in WuBook"), err.data['message'])
|
||||
else:
|
||||
self.binder.bind(external_id, binding)
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
# 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 timedelta
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.addons.component.core import Component
|
||||
from odoo.addons.hotel_channel_connector.components.core import ChannelConnectorError
|
||||
from odoo.addons.connector.components.mapper import mapping
|
||||
from odoo.addons.hotel import date_utils
|
||||
from odoo import fields, api, _
|
||||
from odoo.tools import (
|
||||
DEFAULT_SERVER_DATE_FORMAT,
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
from odoo.addons.hotel_channel_connector.components.backend_adapter import DEFAULT_WUBOOK_DATE_FORMAT
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HotelRoomTypeImporter(Component):
|
||||
@@ -17,9 +22,6 @@ class HotelRoomTypeImporter(Component):
|
||||
_apply_on = ['channel.hotel.room.type']
|
||||
_usage = 'hotel.room.type.importer'
|
||||
|
||||
def _import_record(self, external_id, job_options=None, **kwargs):
|
||||
return super(HotelRoomTypeImporter, self)._import_record(external_id)
|
||||
|
||||
@api.model
|
||||
def get_rooms(self):
|
||||
count = 0
|
||||
@@ -40,10 +42,6 @@ class HotelRoomTypeImporter(Component):
|
||||
else:
|
||||
room_bind = channel_room_type_obj.with_context({'wubook_action': False}).create(
|
||||
map_record.values(for_create=True))
|
||||
room_bind.odoo_id.write({
|
||||
'list_price': room['price'],
|
||||
'name': room['name'],
|
||||
})
|
||||
except ChannelConnectorError as err:
|
||||
self.create_issue('room', _("Can't import rooms from WuBook"), err.data['message'])
|
||||
|
||||
@@ -76,6 +74,83 @@ class HotelRoomTypeImporter(Component):
|
||||
return False
|
||||
return True
|
||||
|
||||
@api.model
|
||||
def _map_room_values_availability(self, day_vals, set_max_avail):
|
||||
channel_room_type_avail_obj = self.env['channel.hotel.room.type.availability']
|
||||
room_avail_mapper = self.component(usage='import.mapper',
|
||||
model_name='channel.hotel.room.type.availability')
|
||||
map_record = room_avail_mapper.map_record(day_vals)
|
||||
map_record.update(channel_pushed=True)
|
||||
if set_max_avail:
|
||||
map_record.update(max_avail=day_vals.get('avail', 0))
|
||||
|
||||
channel_room_type_avail = channel_room_type_avail_obj.search([
|
||||
('room_type_id', '=', day_vals['room_type_id']),
|
||||
('date', '=', day_vals['date'])
|
||||
], limit=1)
|
||||
if channel_room_type_avail:
|
||||
channel_room_type_avail.with_context({
|
||||
'wubook_action': False,
|
||||
}).write(map_record.values())
|
||||
else:
|
||||
channel_room_type_avail_obj.with_context({
|
||||
'wubook_action': False,
|
||||
'mail_create_nosubscribe': True,
|
||||
}).create(map_record.values(for_create=True))
|
||||
|
||||
@api.model
|
||||
def _map_room_values_restrictions(self, day_vals):
|
||||
channel_room_type_restr_item_obj = self.env['channel.hotel.room.type.restriction.item']
|
||||
room_restriction_mapper = self.component(
|
||||
usage='import.mapper',
|
||||
model_name='channel.hotel.room.type.restriction.item')
|
||||
map_record = room_restriction_mapper.map_record(day_vals)
|
||||
map_record.update(channel_pushed=True)
|
||||
|
||||
room_type_restr = channel_room_type_restr_item_obj.search([
|
||||
('room_type_id', '=', day_vals['room_type_id']),
|
||||
('applied_on', '=', '0_room_type'),
|
||||
('date', '=', day_vals['date']),
|
||||
('restriction_id', '=', day_vals['restriction_plan_id']),
|
||||
])
|
||||
if room_type_restr:
|
||||
room_type_restr.with_context({
|
||||
'wubook_action': False,
|
||||
}).write(map_record.values())
|
||||
else:
|
||||
channel_room_type_restr_item_obj.with_context({
|
||||
'wubook_action': False,
|
||||
}).create(map_record.values(for_create=True))
|
||||
|
||||
@api.model
|
||||
def _generate_room_values(self, dfrom, dto, values, set_max_avail=False):
|
||||
channel_room_type_restr_obj = self.env['channel.hotel.room.type.restriction']
|
||||
channel_hotel_room_type_obj = self.env['channel.hotel.room.type']
|
||||
def_restr_plan = channel_room_type_restr_obj.search([('channel_plan_id', '=', '0')])
|
||||
_logger.info("==== ROOM VALUES (%s -- %s)", dfrom, dto)
|
||||
_logger.info(values)
|
||||
for k_rid, v_rid in values.iteritems():
|
||||
room_type = channel_hotel_room_type_obj.search([
|
||||
('channel_plan_id', '=', k_rid)
|
||||
], limit=1)
|
||||
if room_type:
|
||||
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)
|
||||
day_vals.update({
|
||||
'room_type_id': room_type.odoo_id.id,
|
||||
'date': date_str,
|
||||
})
|
||||
self._map_room_values_availability(day_vals, set_max_avail)
|
||||
if def_restr_plan:
|
||||
day_vals.update({
|
||||
'restriction_plan_id': def_restr_plan.odoo_id.id
|
||||
})
|
||||
self._map_room_values_restrictions(day_vals)
|
||||
date_dt = date_dt + timedelta(days=1)
|
||||
return True
|
||||
|
||||
class HotelRoomTypeImportMapper(Component):
|
||||
_name = 'channel.hotel.room.type.import.mapper'
|
||||
@@ -86,6 +161,8 @@ class HotelRoomTypeImportMapper(Component):
|
||||
('id', 'channel_room_id'),
|
||||
('shortname', 'channel_short_code'),
|
||||
('occupancy', 'ota_capacity'),
|
||||
('price', 'list_price'),
|
||||
('name', 'name'),
|
||||
]
|
||||
|
||||
@mapping
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import common
|
||||
from . import importer
|
||||
|
||||
@@ -38,7 +38,7 @@ class ChannelHotelRoomTypeAvailability(models.Model):
|
||||
for record in self:
|
||||
if record.channel_max_avail > record.odoo_id.room_type_id.total_rooms_count:
|
||||
raise ValidationError(_("max avail for channel can't be high \
|
||||
than toal rooms \
|
||||
than total rooms \
|
||||
count: %d") % record.odoo_id.room_type_id.total_rooms_count)
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# 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 timedelta
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.addons.component.core import Component
|
||||
from odoo.addons.hotel_channel_connector.components.core import ChannelConnectorError
|
||||
from odoo.addons.connector.components.mapper import mapping
|
||||
from odoo.addons.hotel import date_utils
|
||||
from odoo import fields, api, _
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HotelRoomTypeAvailabilityImporter(Component):
|
||||
_name = 'channel.hotel.room.type.availability.importer'
|
||||
_inherit = 'hotel.channel.importer'
|
||||
_apply_on = ['channel.hotel.room.type.availability']
|
||||
_usage = 'hotel.room.type.availability.importer'
|
||||
|
||||
|
||||
class HotelRoomTypeAvailabilityImportMapper(Component):
|
||||
_name = 'channel.hotel.room.type.availability.import.mapper'
|
||||
_inherit = 'channel.import.mapper'
|
||||
_apply_on = 'channel.hotel.room.type.availability'
|
||||
|
||||
direct = [
|
||||
('no_ota', 'no_ota'),
|
||||
('booked', 'booked'),
|
||||
('avail', 'avail'),
|
||||
('room_type_id', 'room_type_id'),
|
||||
('date', 'date'),
|
||||
]
|
||||
|
||||
@mapping
|
||||
def backend_id(self, record):
|
||||
return {'backend_id': self.backend_record.id}
|
||||
@@ -2,3 +2,4 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import common
|
||||
from . import importer
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# 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 timedelta
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.addons.component.core import Component
|
||||
from odoo.addons.hotel_channel_connector.components.core import ChannelConnectorError
|
||||
from odoo.addons.connector.components.mapper import mapping
|
||||
from odoo.addons.hotel import date_utils
|
||||
from odoo import fields, api, _
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HotelRoomTypeRestrictionImporter(Component):
|
||||
_name = 'channel.hotel.room.type.restriction.importer'
|
||||
_inherit = 'hotel.channel.importer'
|
||||
_apply_on = ['channel.hotel.room.type.restriction']
|
||||
_usage = 'hotel.room.type.restriction.importer'
|
||||
|
||||
|
||||
class HotelRoomTypeRestrictionImportMapper(Component):
|
||||
_name = 'channel.hotel.room.type.restriction.import.mapper'
|
||||
_inherit = 'channel.import.mapper'
|
||||
_apply_on = 'channel.hotel.room.type.restriction'
|
||||
|
||||
direct = [
|
||||
('no_ota', 'no_ota'),
|
||||
('booked', 'booked'),
|
||||
('avail', 'avail'),
|
||||
('room_type_id', 'room_type_id'),
|
||||
('date', 'date')
|
||||
]
|
||||
|
||||
@mapping
|
||||
def backend_id(self, record):
|
||||
return {'backend_id': self.backend_record.id}
|
||||
@@ -0,0 +1,5 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import common
|
||||
from . import importer
|
||||
@@ -0,0 +1,48 @@
|
||||
# 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.exceptions import ValidationError
|
||||
from odoo.addons.queue_job.job import job, related_action
|
||||
from odoo.addons.component.core import Component
|
||||
from odoo.addons.component_event import skip_if
|
||||
|
||||
class ChannelHotelRoomTypeRestrictionItem(models.Model):
|
||||
_name = 'channel.hotel.room.type.restriction.item'
|
||||
_inherit = 'channel.binding'
|
||||
_inherits = {'hotel.room.type.restriction.item': 'odoo_id'}
|
||||
_description = 'Channel Hotel Room Type Restriction Item'
|
||||
|
||||
odoo_id = fields.Many2one(comodel_name='hotel.room.type.restriction.item',
|
||||
string='Hotel Virtual Room Restriction',
|
||||
required=True,
|
||||
ondelete='cascade')
|
||||
channel_pushed = fields.Boolean("Channel Pushed", readonly=True, default=False,
|
||||
old_name='wpushed')
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@api.multi
|
||||
def update_channel_pushed(self, status):
|
||||
self.ensure_one()
|
||||
self.channel_pushed = status
|
||||
|
||||
class HotelRoomTypeRestrictionItem(models.Model):
|
||||
_inherit = 'hotel.room.type.restriction.item'
|
||||
|
||||
channel_bind_ids = fields.One2many(
|
||||
comodel_name='channel.hotel.room.type.restriction.item',
|
||||
inverse_name='odoo_id',
|
||||
string='Hotel Channel Connector Bindings')
|
||||
|
||||
class ChannelBindingHotelRoomTypeRestrictionItemListener(Component):
|
||||
_name = 'channel.binding.hotel.room.type.restriction.listener'
|
||||
_inherit = 'base.connector.listener'
|
||||
_apply_on = ['channel.hotel.room.type.restriction']
|
||||
|
||||
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
|
||||
def on_record_create(self, record, fields=None):
|
||||
record.update_channel_pushed(False)
|
||||
|
||||
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
|
||||
def on_record_write(self, record, fields=None):
|
||||
record.update_channel_pushed(False)
|
||||
@@ -0,0 +1,44 @@
|
||||
# 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 timedelta
|
||||
from odoo.addons.component.core import Component
|
||||
from odoo.addons.hotel_channel_connector.components.core import ChannelConnectorError
|
||||
from odoo.addons.connector.components.mapper import mapping, only_create
|
||||
from odoo.addons.hotel import date_utils
|
||||
from odoo import fields, api, _
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HotelRoomTypeRestrictionImporter(Component):
|
||||
_name = 'channel.hotel.room.type.restriction.item.importer'
|
||||
_inherit = 'hotel.channel.importer'
|
||||
_apply_on = ['channel.hotel.room.type.restriction.item']
|
||||
_usage = 'hotel.room.type.restriction.item.importer'
|
||||
|
||||
class HotelRoomTypeRestrictionItemImportMapper(Component):
|
||||
_name = 'channel.hotel.room.type.restriction.item.import.mapper'
|
||||
_inherit = 'channel.import.mapper'
|
||||
_apply_on = 'channel.hotel.room.type.restriction.item'
|
||||
|
||||
direct = [
|
||||
('min_stay', 'min_stay'),
|
||||
('min_stay_arrival', 'min_stay_arrival'),
|
||||
('max_stay', 'max_stay'),
|
||||
('max_stay_arrival', 'max_stay_arrival'),
|
||||
('closed', 'closed'),
|
||||
('closed_departure', 'closed_departure'),
|
||||
('closed_arrival', 'closed_arrival'),
|
||||
('room_type_id', 'room_type_id'),
|
||||
('date', 'date'),
|
||||
]
|
||||
|
||||
@only_create
|
||||
@mapping
|
||||
def applied_on(self, record):
|
||||
return {'applied_on': '0_room_type'}
|
||||
|
||||
@mapping
|
||||
def backend_id(self, record):
|
||||
return {'backend_id': self.backend_record.id}
|
||||
@@ -1,7 +1,7 @@
|
||||
# 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 odoo import models, fields, api
|
||||
|
||||
|
||||
class ResPartner(models.Model):
|
||||
|
||||
@@ -1,29 +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
|
||||
|
||||
|
||||
class ReservationRestrictionItem(models.Model):
|
||||
_inherit = 'hotel.room.type.restriction.item'
|
||||
|
||||
channel_pushed = fields.Boolean("Channel Pushed", default=False, readonly=True,
|
||||
old_name='wpushed')
|
||||
|
||||
@api.onchange('date_start')
|
||||
def _onchange_date_start(self):
|
||||
self.date_end = self.date_start
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
if vals.get('date_start'):
|
||||
vals['date_end'] = vals.get('date_start')
|
||||
return super(ReservationRestrictionItem, self).create(vals)
|
||||
|
||||
@api.multi
|
||||
def write(self, vals):
|
||||
if vals.get('date_start'):
|
||||
vals['date_end'] = vals.get('date_start')
|
||||
if self._context.get('channel_action', True):
|
||||
vals.update({'channel_pushed': False})
|
||||
return super(ReservationRestrictionItem, self).write(vals)
|
||||
@@ -1,196 +1,32 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# Copyright 2018 Alexandre Díaz
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
import os
|
||||
import binascii
|
||||
import logging
|
||||
from datetime import datetime, timedelta
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
|
||||
_logger = logging.getLogger(__name__)
|
||||
from openerp import models, fields, api
|
||||
|
||||
|
||||
class HotelChannelConnectorConfiguration(models.TransientModel):
|
||||
class HotelConfiguration(models.TransientModel):
|
||||
_inherit = 'res.config.settings'
|
||||
|
||||
channel_push_security_token = fields.Char('WuBook Push Notification Security Token')
|
||||
default_channel_connector = fields.Many2one(
|
||||
'channel.backend',
|
||||
'Default Channel Connector Backend')
|
||||
|
||||
@api.multi
|
||||
def set_values(self):
|
||||
super(HotelChannelConnectorConfiguration, self).set_values()
|
||||
super(HotelConfiguration, self).set_values()
|
||||
|
||||
self.env['ir.default'].sudo().set(
|
||||
'res.config.settings', 'channel_push_security_token',
|
||||
self.channel_push_security_token)
|
||||
'res.config.settings', 'default_channel_connector',
|
||||
self.default_channel_connector.id)
|
||||
|
||||
@api.model
|
||||
def get_values(self):
|
||||
res = super(HotelChannelConnectorConfiguration, self).get_values()
|
||||
res = super(HotelConfiguration, self).get_values()
|
||||
|
||||
# ONLY FOR v11. DO NOT FORWARD-PORT
|
||||
channel_push_security_token = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'channel_push_security_token')
|
||||
default_channel_connector = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'default_channel_connector')
|
||||
|
||||
res.update(
|
||||
channel_push_security_token=channel_push_security_token,
|
||||
default_channel_connector=default_channel_connector,
|
||||
)
|
||||
return res
|
||||
|
||||
# Dangerus method: Usefull for cloned instances with new wubook account
|
||||
@api.multi
|
||||
def resync(self):
|
||||
self.ensure_one()
|
||||
|
||||
now_utc_dt = fields.Date.now()
|
||||
now_utc_str = now_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||
|
||||
# Reset Issues
|
||||
issue_ids = self.env['wubook.issue'].search([])
|
||||
issue_ids.write({
|
||||
'to_read': False
|
||||
})
|
||||
|
||||
# Push Virtual Rooms
|
||||
wubook_obj = self.env['wubook'].with_context({
|
||||
'init_connection': False
|
||||
})
|
||||
if wubook_obj.init_connection():
|
||||
ir_seq_obj = self.env['ir.sequence']
|
||||
room_types = self.env['hotel.room.type'].search([])
|
||||
for room_type in room_types:
|
||||
shortcode = ir_seq_obj.next_by_code('hotel.room.type')[:4]
|
||||
channel_room_id = wubook_obj.create_room(
|
||||
shortcode,
|
||||
room_type.name,
|
||||
room_type.wcapacity,
|
||||
room_type.list_price,
|
||||
room_type.total_rooms_count
|
||||
)
|
||||
if channel_room_id:
|
||||
room_type.with_context(wubook_action=False).write({
|
||||
'channel_room_id': channel_room_id,
|
||||
'wscode': shortcode,
|
||||
})
|
||||
else:
|
||||
room_type.with_context(wubook_action=False).write({
|
||||
'channel_room_id': '',
|
||||
'wscode': '',
|
||||
})
|
||||
# Create Restrictions
|
||||
room_type_rest_obj = self.env['hotel.room.type.restriction']
|
||||
restriction_ids = room_type_rest_obj.search([])
|
||||
for restriction in restriction_ids:
|
||||
if restriction.wpid != '0':
|
||||
channel_plan_id = wubook_obj.create_rplan(restriction.name)
|
||||
restriction.write({
|
||||
'channel_plan_id': channel_plan_id or ''
|
||||
})
|
||||
# Create Pricelist
|
||||
pricelist_ids = self.env['product.pricelist'].search([])
|
||||
for pricelist in pricelist_ids:
|
||||
channel_plan_id = wubook_obj.create_plan(pricelist.name, pricelist.is_daily_plan)
|
||||
pricelist.write({
|
||||
'channel_plan_id': channel_plan_id or ''
|
||||
})
|
||||
wubook_obj.close_connection()
|
||||
|
||||
# Reset Folios
|
||||
folio_ids = self.env['hotel.folio'].search([])
|
||||
folio_ids.with_context(wubook_action=False).write({
|
||||
'wseed': '',
|
||||
})
|
||||
|
||||
# Reset Reservations
|
||||
reservation_ids = self.env['hotel.reservation'].search([
|
||||
('channel_reservation_id', '!=', ''),
|
||||
('channel_reservation_id', '!=', False)
|
||||
])
|
||||
reservation_ids.with_context(wubook_action=False).write({
|
||||
'channel_reservation_id': '',
|
||||
'ota_id': False,
|
||||
'ota_reservation_id': '',
|
||||
'is_from_ota': False,
|
||||
'wstatus': 0
|
||||
})
|
||||
|
||||
# Get Parity Models
|
||||
pricelist_id = int(self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'parity_pricelist_id'))
|
||||
restriction_id = int(self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'parity_restrictions_id'))
|
||||
|
||||
room_type_restr_it_obj = self.env['hotel.room.type.restriction.item']
|
||||
# Secure Wubook Input
|
||||
restriction_item_ids = room_type_restr_it_obj.search([
|
||||
('applied_on', '=', '0_room_type'),
|
||||
('date_start', '<', now_utc_str),
|
||||
])
|
||||
if any(restriction_item_ids):
|
||||
restriction_item_ids.with_context(wubook_action=False).write({
|
||||
'wpushed': True
|
||||
})
|
||||
# Put to push restrictions
|
||||
restriction_item_ids = room_type_restr_it_obj.search([
|
||||
('restriction_id', '=', restriction_id),
|
||||
('applied_on', '=', '0_room_type'),
|
||||
('wpushed', '=', True),
|
||||
('date_start', '>=', now_utc_str),
|
||||
])
|
||||
if any(restriction_item_ids):
|
||||
restriction_item_ids.with_context(wubook_action=False).write({
|
||||
'wpushed': False
|
||||
})
|
||||
|
||||
# Secure Wubook Input
|
||||
pricelist_item_ids = self.env['product.pricelist.item'].search([
|
||||
('applied_on', '=', '1_product'),
|
||||
('compute_price', '=', 'fixed'),
|
||||
('date_start', '<', now_utc_str),
|
||||
])
|
||||
if any(pricelist_item_ids):
|
||||
pricelist_item_ids.with_context(wubook_action=False).write({
|
||||
'wpushed': True
|
||||
})
|
||||
# Put to push pricelists
|
||||
pricelist_item_ids = self.env['product.pricelist.item'].search([
|
||||
('pricelist_id', '=', pricelist_id),
|
||||
('applied_on', '=', '1_product'),
|
||||
('compute_price', '=', 'fixed'),
|
||||
('wpushed', '=', True),
|
||||
('date_start', '>=', now_utc_str),
|
||||
])
|
||||
if any(pricelist_item_ids):
|
||||
pricelist_item_ids.with_context(wubook_action=False).write({
|
||||
'wpushed': False
|
||||
})
|
||||
|
||||
# Secure Wubook Input
|
||||
availabity_ids = self.env['hotel.room.type.availability'].search([
|
||||
('date', '<', now_utc_str),
|
||||
])
|
||||
if any(availabity_ids):
|
||||
availabity_ids.with_context(wubook_action=False).write({
|
||||
'wpushed': True
|
||||
})
|
||||
# Put to push availability
|
||||
availabity_ids = self.env['hotel.room.type.availability'].search([
|
||||
('wpushed', '=', True),
|
||||
('date', '>=', now_utc_str),
|
||||
])
|
||||
if any(availabity_ids):
|
||||
availabity_ids.with_context(wubook_action=False).write({
|
||||
'wpushed': False
|
||||
})
|
||||
|
||||
# Generate Security Token
|
||||
self.env['ir.default'].sudo().set(
|
||||
'wubook.config.settings',
|
||||
'wubook_push_security_token',
|
||||
binascii.hexlify(os.urandom(16)).decode())
|
||||
self.env.cr.commit() # FIXME: Need do this
|
||||
|
||||
# Push Changes
|
||||
if wubook_obj.init_connection():
|
||||
wubook_obj.push_activation()
|
||||
wubook_obj.import_channels_info()
|
||||
wubook_obj.push_changes()
|
||||
wubook_obj.close_connection()
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
<field name="arch" type="xml">
|
||||
<form string="Hotel Channel Backend">
|
||||
<header>
|
||||
<button name="synchronize_metadata"
|
||||
<button name="synchronize_push_urls"
|
||||
type="object"
|
||||
class="oe_highlight"
|
||||
string="Synchronize Metadata"/>
|
||||
string="Synchronize Push URL's"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<label for="name" class="oe_edit_only"/>
|
||||
@@ -27,6 +27,7 @@
|
||||
<field name="pkey" colspan="2"/>
|
||||
<field name="username" colspan="2"/>
|
||||
<field name="passwd" password="1" colspan="2"/>
|
||||
<field name="security_token" colspan="4"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
@@ -69,6 +70,15 @@
|
||||
string="Import in background"/>
|
||||
</div>
|
||||
</group>
|
||||
<group>
|
||||
<label string="Import OTA's Info" class="oe_inline"/>
|
||||
<div>
|
||||
<button name="import_otas_info"
|
||||
type="object"
|
||||
class="oe_highlight"
|
||||
string="Import in background"/>
|
||||
</div>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
<field name="model">channel.hotel.room.type</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Hotel Channel Virtual Room">
|
||||
<group>
|
||||
<field name="backend_id" attrs="{'visible': [('id','=', False)]}" />
|
||||
</group>
|
||||
<group>
|
||||
<field name="channel_room_id" />
|
||||
<field name="channel_short_code" />
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
<!-- Form view -->
|
||||
<record model="ir.ui.view" id="view_hotel_channel_connector_ota_info_form">
|
||||
<field name="name">hotel.channel.connector.ota.info.form</field>
|
||||
<field name="model">hotel.channel.connector.ota.info</field>
|
||||
<field name="name">channel.ota.info.form</field>
|
||||
<field name="model">channel.ota.info</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Channel OTA's Info" >
|
||||
<sheet>
|
||||
@@ -20,8 +20,8 @@
|
||||
|
||||
<!-- Tree view -->
|
||||
<record model="ir.ui.view" id="view_hotel_channel_connector_ota_info_tree">
|
||||
<field name="name">hotel.channel.connector.ota.info.tree</field>
|
||||
<field name="model">hotel.channel.connector.ota.info</field>
|
||||
<field name="name">channel.ota.info.tree</field>
|
||||
<field name="model">channel.ota.info</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Channel OTA's Info">
|
||||
<field name="ota_id" />
|
||||
@@ -30,9 +30,9 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.actions.act_window" id="open_hotel_channel_connector_ota_info_tree_all">
|
||||
<record model="ir.actions.act_window" id="open_channel_ota_info_tree_all">
|
||||
<field name="name">Hotel Channel Connector OTA's Info</field>
|
||||
<field name="res_model">hotel.channel.connector.ota.info</field>
|
||||
<field name="res_model">channel.ota.info</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
@@ -1,9 +1,9 @@
|
||||
<?xml version="1.0"?>
|
||||
<odoo>
|
||||
|
||||
<record id="reservation_restriction_view" model="ir.ui.view">
|
||||
<record id="room_type_restriction_view" model="ir.ui.view">
|
||||
<field name="model">hotel.room.type.restriction</field>
|
||||
<field name="inherit_id" ref="hotel.reservation_restriction_view_form" />
|
||||
<field name="inherit_id" ref="hotel.room_type_restriction_view_form" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//form[1]//sheet" position="before">
|
||||
<header>
|
||||
@@ -9,9 +9,10 @@
|
||||
<notebook>
|
||||
<page name="connector">
|
||||
<group string="Hotel Channel Bindings">
|
||||
<field name="channel_bind_ids" nolabel="1">
|
||||
<field name="capacity" invisible="1" />
|
||||
<field name="channel_bind_ids" context="{'default_ota_capacity': capacity}" nolabel="1">
|
||||
<tree>
|
||||
<field name="backend_id"/>
|
||||
<field name="backend_id" />
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<odoo>
|
||||
|
||||
<record id="reservation_restriction_item_form_view" model="ir.ui.view">
|
||||
<field name="model">hotel.room.type.restriction.item</field>
|
||||
<field name="inherit_id" ref="hotel.reservation_restriction_item_view_form" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='date_end']" position="attributes">
|
||||
<attribute name="readonly">True</attribute>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -19,7 +19,6 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from . import wubook_installer
|
||||
from . import wubook_import_plan_prices
|
||||
from . import wubook_import_plan_restrictions
|
||||
from . import wubook_import_availability
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
# -*- 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/>.
|
||||
#
|
||||
##############################################################################
|
||||
import os
|
||||
import binascii
|
||||
from openerp import models, fields, api, _
|
||||
from openerp.exceptions import ValidationError
|
||||
from ..components.backend_adapter import DEFAULT_WUBOOK_DATE_FORMAT
|
||||
from odoo.addons.hotel import date_utils
|
||||
|
||||
|
||||
class WuBookInstaller(models.TransientModel):
|
||||
_name = 'wubook.installer'
|
||||
_inherit = 'res.config.installer'
|
||||
|
||||
wubook_user = fields.Char('User', required=True)
|
||||
wubook_passwd = fields.Char('Password', required=True)
|
||||
wubook_lcode = fields.Char('LCode', required=True)
|
||||
wubook_server = fields.Char(string='Server',
|
||||
default='https://wired.wubook.net/xrws/',
|
||||
required=True)
|
||||
wubook_pkey = fields.Char('PKey', required=True)
|
||||
activate_push = fields.Boolean('Active Push Notifications', default=True)
|
||||
|
||||
@api.multi
|
||||
def execute(self):
|
||||
super(WuBookInstaller, self).execute()
|
||||
return self.execute_simple()
|
||||
|
||||
@api.multi
|
||||
def execute_simple(self):
|
||||
activate_push = True
|
||||
for rec in self:
|
||||
self.env['ir.default'].sudo().set('wubook.config.settings',
|
||||
'wubook_user',
|
||||
rec.wubook_user)
|
||||
self.env['ir.default'].sudo().set('wubook.config.settings',
|
||||
'wubook_passwd',
|
||||
rec.wubook_passwd)
|
||||
self.env['ir.default'].sudo().set('wubook.config.settings',
|
||||
'wubook_lcode',
|
||||
rec.wubook_lcode)
|
||||
self.env['ir.default'].sudo().set('wubook.config.settings',
|
||||
'wubook_server',
|
||||
rec.wubook_server)
|
||||
self.env['ir.default'].sudo().set('wubook.config.settings',
|
||||
'wubook_pkey',
|
||||
rec.wubook_pkey)
|
||||
activate_push = rec.activate_push
|
||||
self.env['ir.default'].sudo().set(
|
||||
'wubook.config.settings',
|
||||
'wubook_push_security_token',
|
||||
binascii.hexlify(os.urandom(16)).decode())
|
||||
self.env.cr.commit() # FIXME: Need do this
|
||||
|
||||
# Create Wubook Base Restrictions
|
||||
restr_obj = self.env['hotel.room.type.restriction'].with_context({
|
||||
'wubook_action': False
|
||||
})
|
||||
base_rest = restr_obj.search([('wpid', '=', '0')], limit=1)
|
||||
if not base_rest:
|
||||
nrest = restr_obj.create({
|
||||
'name': 'Base WuBook Restrictions',
|
||||
'wpid': '0',
|
||||
})
|
||||
if not nrest:
|
||||
raise ValidationError(_("Can't create base wubook restrictions"))
|
||||
|
||||
# Initialize WuBook
|
||||
wres = self.env['wubook'].initialize(activate_push)
|
||||
if not wres:
|
||||
raise ValidationError("Can't finish installation!")
|
||||
|
||||
# Open Next Step
|
||||
v_id = 'hotel_wubook_proto.view_wubook_configuration_installer_parity'
|
||||
return {
|
||||
'name': _("Configure Hotel Parity"),
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'wubook.installer.parity',
|
||||
'view_id': self.env.ref(v_id).id,
|
||||
'view_type': 'form',
|
||||
'view_mode': 'form',
|
||||
'target': 'new'
|
||||
}
|
||||
|
||||
|
||||
class WuBookInstallerParity(models.TransientModel):
|
||||
_name = 'wubook.installer.parity'
|
||||
_inherit = 'res.config.installer'
|
||||
|
||||
parity_pricelist_id = fields.Many2one('product.pricelist',
|
||||
'Product Pricelist')
|
||||
parity_restrictions_id = fields.Many2one('hotel.room.type.restriction',
|
||||
'Restrictions')
|
||||
import_data = fields.Boolean('Import Data From WuBook', default=False)
|
||||
date_start = fields.Date('Date Start')
|
||||
date_end = fields.Date('Date End')
|
||||
|
||||
@api.multi
|
||||
def execute(self):
|
||||
self.execute_simple()
|
||||
return super(WuBookInstallerParity, self).execute()
|
||||
|
||||
@api.multi
|
||||
def execute_simple(self):
|
||||
wubookObj = self.env['wubook']
|
||||
irValuesObj = self.env['ir.values']
|
||||
for rec in self:
|
||||
irValuesObj.sudo().set_default('res.config.settings',
|
||||
'parity_pricelist_id',
|
||||
rec.parity_pricelist_id.id)
|
||||
irValuesObj.sudo().set_default('res.config.settings',
|
||||
'parity_restrictions_id',
|
||||
rec.parity_restrictions_id.id)
|
||||
import_data = rec.import_data
|
||||
if rec.import_data:
|
||||
date_start_dt = date_utils.get_datetime(rec.date_start)
|
||||
date_end_dt = date_utils.get_datetime(rec.date_end)
|
||||
# Availability
|
||||
wresAvail = wubookObj.fetch_rooms_values(
|
||||
date_start_dt.strftime(DEFAULT_WUBOOK_DATE_FORMAT),
|
||||
date_end_dt.strftime(DEFAULT_WUBOOK_DATE_FORMAT))
|
||||
# Pricelist
|
||||
wresPrices = wubookObj.fetch_plan_prices(
|
||||
rec.parity_pricelist_id.wpid,
|
||||
date_start_dt.strftime(DEFAULT_WUBOOK_DATE_FORMAT),
|
||||
date_end_dt.strftime(DEFAULT_WUBOOK_DATE_FORMAT))
|
||||
# Restrictions
|
||||
wresRestr = wubookObj.fetch_rplan_restrictions(
|
||||
date_start_dt.strftime(DEFAULT_WUBOOK_DATE_FORMAT),
|
||||
date_end_dt.strftime(DEFAULT_WUBOOK_DATE_FORMAT),
|
||||
rec.parity_restrictions_id.wpid)
|
||||
|
||||
if not wresAvail or not wresPrices or not wresRestr:
|
||||
raise ValidationError(_("Errors importing data from WuBook"))
|
||||
|
||||
# Reservations
|
||||
wubookObj.fetch_new_bookings()
|
||||
@@ -1,90 +0,0 @@
|
||||
<odoo>
|
||||
|
||||
<record id="view_wubook_configuration_installer" model="ir.ui.view">
|
||||
<field name="name">wubook.installer.form</field>
|
||||
<field name="model">wubook.installer</field>
|
||||
<field name="inherit_id" ref="base.res_config_installer"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//form[1]" position="attributes">
|
||||
<attribute name="string">WuBook Configuration</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//footer[1]" position="replace">
|
||||
<footer>
|
||||
<button name="action_next" type="object" string="Continue" class="oe_highlight"/>
|
||||
</footer>
|
||||
</xpath>
|
||||
<xpath expr="//form/separator[1]" position="replace">
|
||||
<p class="oe_grey">
|
||||
WuBook API Configuration. This wizard will activate push request and synchronize rooms & reservations with Odoo.
|
||||
</p>
|
||||
<group>
|
||||
<field name="wubook_server" />
|
||||
</group>
|
||||
<group>
|
||||
<field name="wubook_user" />
|
||||
<field name="wubook_passwd" password="True" />
|
||||
</group>
|
||||
<group>
|
||||
<field name="wubook_lcode" />
|
||||
<field name="wubook_pkey" />
|
||||
</group>
|
||||
<group>
|
||||
<field name="activate_push" />
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_wubook_configuration_installer_parity" model="ir.ui.view">
|
||||
<field name="name">wubook.installer.parity.form</field>
|
||||
<field name="model">wubook.installer.parity</field>
|
||||
<field name="inherit_id" ref="base.res_config_installer"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//form[1]" position="attributes">
|
||||
<attribute name="string">WuBook Configuration Parity</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//footer[1]" position="replace">
|
||||
<footer>
|
||||
<button name="action_next" type="object" string="Finish Installation" class="oe_highlight"/>
|
||||
</footer>
|
||||
</xpath>
|
||||
<xpath expr="//form/separator[1]" position="replace">
|
||||
<p class="oe_grey">
|
||||
These models are used as masters
|
||||
</p>
|
||||
<group>
|
||||
<field name="parity_pricelist_id" domain="[('wpid', '!=', False),('wpid', '!=', '')]" required="True" />
|
||||
<field name="parity_restrictions_id" domain="[('wpid', '!=', False),('wpid', '!=', '')]" required="True" />
|
||||
</group>
|
||||
<group>
|
||||
<field name="import_data" />
|
||||
</group>
|
||||
<group attrs="{'invisible':[('import_data', '=', False)]}">
|
||||
<group>
|
||||
<field name="date_start" attrs="{'required':[('import_data', '=', True)]}" />
|
||||
</group>
|
||||
<group>
|
||||
<field name="date_end" attrs="{'required':[('import_data', '=', True)]}" />
|
||||
</group>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_wubook_configuration_installer" model="ir.actions.act_window">
|
||||
<field name="name">Configure WuBook Data</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">wubook.installer</field>
|
||||
<field name="view_id" ref="view_wubook_configuration_installer"/>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<!--record id="wubook_configuration_installer_todo" model="ir.actions.todo">
|
||||
<field name="action_id" ref="action_wubook_configuration_installer"/>
|
||||
<field name="sequence">3</field>
|
||||
<field name="type">automatic</field>
|
||||
</record-->
|
||||
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user