mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
[WIP][IMP][11.0] hotel
This commit is contained in:
@@ -4,7 +4,6 @@
|
||||
import datetime
|
||||
from openerp import models, fields, api, _
|
||||
from openerp.exceptions import except_orm, ValidationError
|
||||
from odoo.addons.hotel import date_utils
|
||||
|
||||
|
||||
class Cardex(models.Model):
|
||||
@@ -53,7 +52,7 @@ class Cardex(models.Model):
|
||||
@api.onchange('enter_date', 'exit_date')
|
||||
def check_change_dates(self):
|
||||
if self.exit_date <= self.enter_date:
|
||||
date_1 = date_utils.get_datetime(self.enter_date)
|
||||
date_1 = fields.Date.from_string(self.enter_date)
|
||||
date_2 = date_1 + datetime.timedelta(days=1)
|
||||
self.update({'exit_date': date_2, })
|
||||
raise ValidationError(
|
||||
|
||||
@@ -14,7 +14,6 @@ from odoo.tools import (
|
||||
DEFAULT_SERVER_DATETIME_FORMAT,
|
||||
DEFAULT_SERVER_DATE_FORMAT)
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.addons.hotel import date_utils
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
from odoo.addons import decimal_precision as dp
|
||||
@@ -267,10 +266,8 @@ class HotelFolio(models.Model):
|
||||
|
||||
@api.multi
|
||||
def action_folios_amount(self):
|
||||
now_utc_dt = date_utils.now()
|
||||
now_utc_str = now_utc_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
reservations = self.env['hotel.reservation'].search([
|
||||
('checkout', '<=', now_utc_str)
|
||||
('checkout', '<=', fields.Date.today())
|
||||
])
|
||||
folio_ids = reservations.mapped('folio_id.id')
|
||||
folios = self.env['hotel.folio'].search([('id', 'in', folio_ids)])
|
||||
|
||||
@@ -284,7 +284,7 @@ class HotelReservation(models.Model):
|
||||
'channel_type': vals.get('channel_type')})
|
||||
#~ colors = self._generate_color()
|
||||
vals.update({
|
||||
'last_updated_res': date_utils.now(hours=True).strftime(DEFAULT_SERVER_DATETIME_FORMAT),
|
||||
'last_updated_res': fields.Datetime.now(),
|
||||
#~ 'reserve_color': colors[0],
|
||||
#~ 'reserve_color_text': colors[1],
|
||||
})
|
||||
@@ -306,8 +306,7 @@ class HotelReservation(models.Model):
|
||||
def write(self, vals):
|
||||
if self.notify_update(vals):
|
||||
vals.update({
|
||||
'last_updated_res': date_utils.now(hours=True).strftime(
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
'last_updated_res': fields.Datetime.now()
|
||||
})
|
||||
for record in self:
|
||||
if record.compute_price_out_vals(vals):
|
||||
@@ -902,15 +901,9 @@ class HotelReservation(models.Model):
|
||||
@api.model
|
||||
def daily_plan(self):
|
||||
_logger.info('daily_plan')
|
||||
today_utc_dt = date_utils.now()
|
||||
yesterday_utc_dt = today_utc_dt - timedelta(days=1)
|
||||
hotel_tz = self.env['ir.default'].sudo().get('res.config.settings',
|
||||
'tz_hotel')
|
||||
today_dt = date_utils.dt_as_timezone(today_utc_dt, hotel_tz)
|
||||
yesterday_dt = date_utils.dt_as_timezone(yesterday_utc_dt, hotel_tz)
|
||||
|
||||
today_str = today_dt.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||
yesterday_str = yesterday_dt.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||
today_str = fields.Date.today()
|
||||
yesterday_utc_dt = datetime.now() - timedelta(days=1)
|
||||
yesterday_str = yesterday_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||
reservations_to_checkout = self.env['hotel.reservation'].search([
|
||||
('state', 'not in', ['done']),
|
||||
('checkout', '<', today_str)
|
||||
|
||||
@@ -4,7 +4,6 @@ from datetime import datetime
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
|
||||
from odoo.addons.hotel import date_utils
|
||||
|
||||
|
||||
class HotelRoomTypeRestrictionItem(models.Model):
|
||||
@@ -59,8 +58,8 @@ class HotelRoomTypeRestrictionItem(models.Model):
|
||||
self.date_start = False
|
||||
self.date_end = False
|
||||
elif self.date_start and self.date_end:
|
||||
date_start_dt = date_utils.get_datetime(self.date_start)
|
||||
date_end_dt = date_utils.get_datetime(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"))
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import logging
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.addons.hotel import date_utils
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
from odoo.addons import decimal_precision as dp
|
||||
@@ -91,12 +90,12 @@ class HotelServiceLine(models.Model):
|
||||
('mail', 'Mail'),
|
||||
('phone', 'Phone'),
|
||||
('call', 'Call Center'),
|
||||
('web','Web')], 'Sales Channel')
|
||||
('web', 'Web')], 'Sales Channel')
|
||||
|
||||
ser_checkin = fields.Datetime('From Date', required=True,
|
||||
default=_service_checkin)
|
||||
ser_checkout = fields.Datetime('To Date', required=True,
|
||||
default=_service_checkout)
|
||||
ser_checkin = fields.Date('From Date', required=True,
|
||||
default=_service_checkin)
|
||||
ser_checkout = fields.Date('To Date', required=True,
|
||||
default=_service_checkout)
|
||||
ser_room_line = fields.Many2one('hotel.reservation', 'Room',
|
||||
default=_default_ser_room_line)
|
||||
|
||||
@@ -199,20 +198,17 @@ class HotelServiceLine(models.Model):
|
||||
-----------------------------------------------------------------
|
||||
@param self: object pointer
|
||||
'''
|
||||
now_utc_dt = date_utils.now()
|
||||
now_utc = fields.Date.today()
|
||||
if not self.ser_checkin:
|
||||
self.ser_checkin = now_utc_dt.strftime(
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
self.ser_checkin = now_utc
|
||||
if not self.ser_checkout:
|
||||
self.ser_checkout = now_utc_dt.strftime(
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
chkin_utc_dt = date_utils.get_datetime(self.ser_checkin)
|
||||
chkout_utc_dt = date_utils.get_datetime(self.ser_checkout)
|
||||
self.ser_checkout = now_utc
|
||||
chkin_utc_dt = fields.Date.from_string(self.ser_checkin)
|
||||
chkout_utc_dt = fields.Date.from_string(self.ser_checkout)
|
||||
if chkout_utc_dt < chkin_utc_dt:
|
||||
raise UserError(_('Checkout must be greater or equal checkin date'))
|
||||
if self.ser_checkin and self.ser_checkout:
|
||||
diffDate = date_utils.date_diff(self.ser_checkin,
|
||||
self.ser_checkout, hours=False) + 1
|
||||
diffDate = abs((self.ser_checkout - self.ser_checkin).days) + 1
|
||||
# FIXME: Finalize method!
|
||||
|
||||
@api.multi
|
||||
|
||||
@@ -5,7 +5,6 @@ from openerp import models, fields, api
|
||||
from openerp.tools import (
|
||||
DEFAULT_SERVER_DATE_FORMAT,
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
from odoo.addons.hotel import date_utils
|
||||
|
||||
|
||||
class MassiveChangesWizard(models.TransientModel):
|
||||
@@ -17,8 +16,8 @@ class MassiveChangesWizard(models.TransientModel):
|
||||
('1', 'Restrictions'),
|
||||
('2', 'Pricelist'),
|
||||
], string='Section', default='0')
|
||||
date_start = fields.Datetime('Start Date', required=True)
|
||||
date_end = fields.Datetime('End Date', required=True)
|
||||
date_start = fields.Date('Start Date', required=True)
|
||||
date_end = fields.Date('End Date', required=True)
|
||||
dmo = fields.Boolean('Monday', default=True)
|
||||
dtu = fields.Boolean('Tuesday', default=True)
|
||||
dwe = fields.Boolean('Wednesday', default=True)
|
||||
@@ -28,12 +27,11 @@ class MassiveChangesWizard(models.TransientModel):
|
||||
dsu = fields.Boolean('Sunday', default=True)
|
||||
applied_on = fields.Selection([
|
||||
('0', 'Global'),
|
||||
('1', 'Virtual Room'),
|
||||
('1', 'Room Type'),
|
||||
], string='Applied On', default='0')
|
||||
# room_type_ids = fields.Many2many('hotel.virtual.room',
|
||||
# string="Virtual Rooms")
|
||||
room_type_ids = fields.Many2many('hotel.room.type',
|
||||
string="Room Types")
|
||||
room_type_ids = fields.Many2many('hotel.room.type', string="Room Types")
|
||||
|
||||
# Availability fields
|
||||
change_avail = fields.Boolean(default=False)
|
||||
@@ -251,12 +249,10 @@ class MassiveChangesWizard(models.TransientModel):
|
||||
def _do_massive_change(self):
|
||||
hotel_room_type_obj = self.env['hotel.room.type']
|
||||
for record in self:
|
||||
date_start_dt = date_utils.get_datetime(record.date_start,
|
||||
hours=False)
|
||||
date_start_dt = fields.Date.from_string(record.date_start)
|
||||
date_end_dt = fields.Date.from_string(record.date_end)
|
||||
# Use min '1' for same date
|
||||
diff_days = date_utils.date_diff(record.date_start,
|
||||
record.date_end,
|
||||
hours=False) + 1
|
||||
diff_days = abs((date_end_dt - date_start_dt).days) + 1
|
||||
wedays = (record.dmo, record.dtu, record.dwe, record.dth,
|
||||
record.dfr, record.dsa, record.dsu)
|
||||
room_types = record.room_type_id if record.applied_on == '1' \
|
||||
|
||||
@@ -21,10 +21,9 @@ class SplitReservationWizard(models.TransientModel):
|
||||
reservation_id = self.env['hotel.reservation'].browse(
|
||||
self.env.context.get('active_id'))
|
||||
if reservation_id:
|
||||
date_start_dt = date_utils.get_datetime(reservation_id.checkin)
|
||||
date_end_dt = date_utils.get_datetime(reservation_id.checkout)
|
||||
date_diff = date_utils.date_diff(date_start_dt, date_end_dt,
|
||||
hours=False)
|
||||
date_start_dt = fields.Date.from_string(reservation_id.checkin)
|
||||
date_end_dt = fields.Date.from_string(reservation_id.checkout)
|
||||
date_diff = abs((date_end_dt - date_start_dt).days)
|
||||
for record in self:
|
||||
new_start_date_dt = date_start_dt + \
|
||||
timedelta(days=date_diff-record.nights)
|
||||
@@ -41,7 +40,7 @@ class SplitReservationWizard(models.TransientModel):
|
||||
tprice = [0.0, 0.0]
|
||||
div_dt = date_utils.dt_no_hours(new_start_date_dt)
|
||||
for rline in reservation_id.reservation_lines:
|
||||
rline_dt = date_utils.get_datetime(rline.date, hours=False)
|
||||
rline_dt = fields.Date.from_string(rline.date)
|
||||
if rline_dt >= div_dt:
|
||||
reservation_lines[1].append((0, False, {
|
||||
'date': rline.date,
|
||||
|
||||
@@ -5,9 +5,8 @@ from datetime import datetime, timedelta
|
||||
from odoo.tools import (
|
||||
DEFAULT_SERVER_DATE_FORMAT,
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
from odoo import models, api, _
|
||||
from odoo import models, api, _, fields
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.addons.hotel import date_utils
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -176,8 +175,9 @@ class HotelCalendarManagement(models.TransientModel):
|
||||
|
||||
@api.model
|
||||
def _hcalendar_availability_json_data(self, dfrom, dto):
|
||||
date_start = date_utils.get_datetime(dfrom, hours=False)
|
||||
date_diff = date_utils.date_diff(dfrom, dto, hours=False) + 1
|
||||
date_start = fields.Date.from_string(dfrom)
|
||||
date_end = fields.Date.from_string(dto)
|
||||
date_diff = abs((date_end - date_start).days) + 1
|
||||
room_types = self.env['hotel.room.type'].search([])
|
||||
json_data = {}
|
||||
|
||||
@@ -208,7 +208,7 @@ class HotelCalendarManagement(models.TransientModel):
|
||||
|
||||
@api.model
|
||||
def _hcalendar_events_json_data(self, dfrom, dto):
|
||||
date_start = date_utils.get_datetime(dfrom, hours=False) - timedelta(days=1)
|
||||
date_start = fields.Date.from_string(dfrom) - timedelta(days=1)
|
||||
date_start_str = date_start.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
user_id = self.env['res.users'].browse(self.env.uid)
|
||||
domain = []
|
||||
@@ -239,8 +239,9 @@ class HotelCalendarManagement(models.TransientModel):
|
||||
|
||||
@api.model
|
||||
def _hcalendar_get_count_reservations_json_data(self, dfrom, dto):
|
||||
date_start = date_utils.get_datetime(dfrom, hours=False)
|
||||
date_diff = date_utils.date_diff(dfrom, dto, hours=False) + 1
|
||||
date_start = fields.Date.from_string(dfrom)
|
||||
date_end = fields.Date.from_string(dto)
|
||||
date_diff = abs((date_end - date_start).days) + 1
|
||||
room_type_obj = self.env['hotel.room.type']
|
||||
room_types = room_type_obj.search([])
|
||||
json_data = {}
|
||||
|
||||
@@ -7,7 +7,6 @@ from odoo.exceptions import ValidationError
|
||||
from odoo.tools import (
|
||||
DEFAULT_SERVER_DATE_FORMAT,
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
from odoo.addons.hotel import date_utils
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -95,8 +94,7 @@ class HotelReservation(models.Model):
|
||||
|
||||
@api.model
|
||||
def get_hcalendar_reservations_data(self, dfrom, dto, rooms):
|
||||
date_start = date_utils.get_datetime(dfrom, hours=False) \
|
||||
- timedelta(days=1)
|
||||
date_start = fields.Date.from_string(dfrom) - timedelta(days=1)
|
||||
date_start_str = date_start.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
reservations_raw = self.env['hotel.reservation'].search(
|
||||
[
|
||||
@@ -122,9 +120,9 @@ class HotelReservation(models.Model):
|
||||
'res.config.settings', 'parity_pricelist_id')
|
||||
if pricelist_id:
|
||||
pricelist_id = int(pricelist_id)
|
||||
date_start = date_utils.get_datetime(dfrom, hours=False) \
|
||||
- timedelta(days=1)
|
||||
date_diff = date_utils.date_diff(date_start, dto, hours=False) + 1
|
||||
date_start = fields.Date.from_string(dfrom) - timedelta(days=1)
|
||||
date_end = fields.Date.from_string(dto)
|
||||
date_diff = abs((date_end - date_start).days) + 1
|
||||
# Get Prices
|
||||
json_rooms_prices = {pricelist_id: []}
|
||||
room_typed_ids = self.env['hotel.room.type'].search(
|
||||
@@ -162,9 +160,9 @@ class HotelReservation(models.Model):
|
||||
'res.config.settings', 'parity_restrictions_id')
|
||||
if restriction_id:
|
||||
restriction_id = int(restriction_id)
|
||||
date_start = date_utils.get_datetime(dfrom, hours=False) \
|
||||
- timedelta(days=1)
|
||||
date_diff = date_utils.date_diff(dfrom, dto, hours=False) + 1
|
||||
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
|
||||
# Get Prices
|
||||
json_rooms_rests = {}
|
||||
room_types = self.env['hotel.room.type'].search(
|
||||
@@ -202,8 +200,7 @@ class HotelReservation(models.Model):
|
||||
|
||||
@api.model
|
||||
def get_hcalendar_events_data(self, dfrom, dto):
|
||||
date_start = date_utils.get_datetime(dfrom, hours=False) \
|
||||
- timedelta(days=1)
|
||||
date_start = fields.Date.from_string(dfrom) - timedelta(days=1)
|
||||
date_start_str = date_start.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
user_id = self.env['res.users'].browse(self.env.uid)
|
||||
domain = []
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo import models, fields, api
|
||||
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from odoo.addons.hotel import date_utils
|
||||
|
||||
|
||||
class IrDefault(models.Model):
|
||||
@@ -26,8 +25,7 @@ class IrDefault(models.Model):
|
||||
fixed_price = pitem.fixed_price
|
||||
room_type = room_type_obj.search([
|
||||
('product_id.product_tmpl_id', '=', product_tmpl_id),
|
||||
('date_start', '>=', date_utils.now().strftime(
|
||||
DEFAULT_SERVER_DATETIME_FORMAT))
|
||||
('date_start', '>=', fields.Date.today())
|
||||
], limit=1)
|
||||
room_pr_cached_obj.create({
|
||||
'room_type_id': room_type.id,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo import models, fields, api
|
||||
from odoo.addons.hotel import date_utils
|
||||
|
||||
|
||||
class HotelConfiguration(models.TransientModel):
|
||||
|
||||
@@ -13,7 +13,6 @@ var AbstractModel = require('web.AbstractModel'),
|
||||
return AbstractModel.extend({
|
||||
init: function () {
|
||||
this._super.apply(this, arguments);
|
||||
this.end_date = null;
|
||||
},
|
||||
|
||||
load: function (params) {
|
||||
|
||||
@@ -3,13 +3,12 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
import time
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
from datetime import datetime, timedelta
|
||||
from openerp.exceptions import ValidationError
|
||||
from openerp.tools import (
|
||||
DEFAULT_SERVER_DATE_FORMAT,
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
from openerp import models, fields, api, _
|
||||
from odoo.addons.hotel import date_utils
|
||||
import odoo.addons.decimal_precision as dp
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -25,46 +24,24 @@ class FolioWizard(models.TransientModel):
|
||||
@api.model
|
||||
def _get_default_checkin(self):
|
||||
folio = False
|
||||
default_arrival_hour = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'default_arrival_hour')
|
||||
if 'folio_id' in self._context:
|
||||
folio = self.env['hotel.folio'].search([
|
||||
('id', '=', self._context['folio_id'])
|
||||
])
|
||||
if folio and folio.room_lines:
|
||||
return folio.room_lines[0].checkin
|
||||
else:
|
||||
tz_hotel = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'tz_hotel')
|
||||
now_utc_dt = date_utils.now()
|
||||
ndate = "%s %s:00" % \
|
||||
(now_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT),
|
||||
default_arrival_hour)
|
||||
ndate_dt = date_utils.get_datetime(ndate, stz=tz_hotel)
|
||||
ndate_dt = date_utils.dt_as_timezone(ndate_dt, 'UTC')
|
||||
return ndate_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
return fields.Date.today()
|
||||
|
||||
@api.model
|
||||
def _get_default_checkout(self):
|
||||
folio = False
|
||||
default_departure_hour = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'default_departure_hour')
|
||||
if 'folio_id' in self._context:
|
||||
folio = self.env['hotel.folio'].search([
|
||||
('id', '=', self._context['folio_id'])
|
||||
])
|
||||
if folio and folio.room_lines:
|
||||
return folio.room_lines[0].checkout
|
||||
else:
|
||||
tz_hotel = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'tz_hotel')
|
||||
now_utc_dt = date_utils.now() + timedelta(days=1)
|
||||
ndate = "%s %s:00" % \
|
||||
(now_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT),
|
||||
default_departure_hour)
|
||||
ndate_dt = date_utils.get_datetime(ndate, stz=tz_hotel)
|
||||
ndate_dt = date_utils.dt_as_timezone(ndate_dt, 'UTC')
|
||||
return ndate_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
return fields.Date.today()
|
||||
|
||||
@api.model
|
||||
def _get_default_channel_type(self):
|
||||
@@ -109,10 +86,9 @@ class FolioWizard(models.TransientModel):
|
||||
if line.rooms_num > line.max_rooms:
|
||||
raise ValidationError(_("Too many rooms!"))
|
||||
elif line.room_type_id:
|
||||
checkout_dt = date_utils.get_datetime(line.checkout)
|
||||
occupied = self.env['hotel.reservation'].occupied(
|
||||
line.checkin,
|
||||
checkout_dt.strftime(DEFAULT_SERVER_DATE_FORMAT))
|
||||
line.checkout)
|
||||
rooms_occupied = occupied.mapped('product_id.id')
|
||||
free_rooms = self.env['hotel.room'].search([
|
||||
('product_id.id', 'not in', rooms_occupied),
|
||||
@@ -122,15 +98,9 @@ class FolioWizard(models.TransientModel):
|
||||
product_list = self.env['product.product'].search([
|
||||
('id', 'in', room_ids)
|
||||
])
|
||||
nights = date_utils.date_diff(line.checkin,
|
||||
line.checkout,
|
||||
hours=False)
|
||||
hotel_tz = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings',
|
||||
'hotel_tz')
|
||||
start_date_utc_dt = date_utils.get_datetime(self.checkin)
|
||||
start_date_dt = date_utils.dt_as_timezone(start_date_utc_dt,
|
||||
hotel_tz)
|
||||
checkin_dt = fields.Date.from_string(line.checkin)
|
||||
checkout_dt = fields.Date.from_string(line.checkout)
|
||||
nights = abs((checkout_dt - checkin_dt).days)
|
||||
for room in product_list:
|
||||
pricelist_id = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'parity_pricelist_id')
|
||||
@@ -138,7 +108,7 @@ class FolioWizard(models.TransientModel):
|
||||
pricelist_id = int(pricelist_id)
|
||||
res_price = 0
|
||||
for i in range(0, nights):
|
||||
ndate = start_date_dt + timedelta(days=i)
|
||||
ndate = checkin_dt + timedelta(days=i)
|
||||
ndate_str = ndate.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||
prod = line.room_type_id.product_id.with_context(
|
||||
lang=self.partner_id.lang,
|
||||
@@ -178,44 +148,30 @@ class FolioWizard(models.TransientModel):
|
||||
@param self: object pointer
|
||||
'''
|
||||
self.ensure_one()
|
||||
if not self.checkin:
|
||||
self.checkin = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
if not self.checkout:
|
||||
self.checkout = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
checkin_dt = datetime.now() if not self.checkin else fields.Date.from_string(self.checkin)
|
||||
checkout_dt = datetime.now() if not self.checkout else fields.Date.from_string(self.checkout)
|
||||
if checkin_dt >= checkout_dt:
|
||||
checkout_dt = checkin_dt + timedelta(days=1)
|
||||
|
||||
# UTC -> Hotel tz
|
||||
tz = self.env['ir.default'].sudo().get('res.config.settings',
|
||||
'tz_hotel')
|
||||
chkin_utc_dt = date_utils.get_datetime(self.checkin)
|
||||
chkout_utc_dt = date_utils.get_datetime(self.checkout)
|
||||
chekin_str = checkin_dt.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||
chekout_str = checkout_dt.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||
|
||||
if chkin_utc_dt >= chkout_utc_dt:
|
||||
dpt_hour = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'default_departure_hour')
|
||||
checkout_str = (chkin_utc_dt + timedelta(days=1)).strftime(
|
||||
DEFAULT_SERVER_DATE_FORMAT)
|
||||
checkout_str = "%s %s:00" % (checkout_str, dpt_hour)
|
||||
checkout_dt = date_utils.get_datetime(checkout_str, stz=tz)
|
||||
checkout_utc_dt = date_utils.dt_as_timezone(checkout_dt, 'UTC')
|
||||
self.checkout = checkout_utc_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
checkout_dt = date_utils.get_datetime(self.checkout, stz=tz)
|
||||
# Reservation end day count as free day. Not check it
|
||||
checkout_dt -= timedelta(days=1)
|
||||
room_type_ids = self.env['hotel.room.type'].search([])
|
||||
room_types = []
|
||||
|
||||
for room_type in room_type_ids:
|
||||
room_types.append((0, False, {
|
||||
'room_type_id': room_type.id,
|
||||
'checkin': self.checkin,
|
||||
'checkout': self.checkout,
|
||||
'folio_wizard_id': self.id,
|
||||
}))
|
||||
self.room_type_wizard_ids = room_types
|
||||
cmds = room_type_ids.mapped(lambda x: (0, False, {
|
||||
'room_type_id': x.id,
|
||||
'checkin': chekin_str,
|
||||
'checkout': chekout_str,
|
||||
'folio_wizard_id': self.id,
|
||||
}))
|
||||
self.write({
|
||||
'checkin': chekin_str,
|
||||
'checkout': chekout_str,
|
||||
'room_type_wizard_ids': cmds,
|
||||
})
|
||||
for room_type in self.room_type_wizard_ids:
|
||||
room_type.update_price()
|
||||
|
||||
@api.depends('room_type_wizard_ids','reservation_wizard_ids','service_wizard_ids')
|
||||
@api.depends('room_type_wizard_ids', 'reservation_wizard_ids', 'service_wizard_ids')
|
||||
def _computed_total(self):
|
||||
total = 0
|
||||
for line in self.service_wizard_ids:
|
||||
@@ -305,24 +261,25 @@ class HotelRoomTypeWizards(models.TransientModel):
|
||||
default=_get_default_checkout)
|
||||
can_confirm = fields.Boolean(compute="_can_confirm")
|
||||
|
||||
@api.multi
|
||||
def _can_confirm(self):
|
||||
for room_type in self:
|
||||
date_start = date_utils.get_datetime(room_type.checkin)
|
||||
date_end = date_utils.get_datetime(room_type.checkout)
|
||||
date_diff = date_utils.date_diff(date_start, date_end, hours=False)
|
||||
room_type.can_confirm = room_type.max_rooms > 0 and room_type.min_stay <= date_diff
|
||||
for record in self:
|
||||
date_start = fields.Date.from_string(record.checkin)
|
||||
date_end = fields.Date.from_string(record.checkout)
|
||||
date_diff = abs((date_end - date_start).days)
|
||||
record.can_confirm = record.max_rooms > 0 and record.min_stay <= date_diff
|
||||
|
||||
def _compute_max(self):
|
||||
for res in self:
|
||||
user = self.env['res.users'].browse(self.env.uid)
|
||||
date_start = date_utils.get_datetime(res.checkin)
|
||||
date_end = date_utils.get_datetime(res.checkout)
|
||||
date_diff = date_utils.date_diff(date_start, date_end, hours=False)
|
||||
date_start = fields.Date.from_string(res.checkin)
|
||||
date_end = fields.Date.from_string(res.checkout)
|
||||
date_diff = abs((date_end - date_start).days)
|
||||
minstay_restrictions = self.env['hotel.room.type.restriction.item'].search([
|
||||
('room_type_id','=',res.room_type_id.id),
|
||||
('room_type_id', '=', res.room_type_id.id),
|
||||
])
|
||||
avail_restrictions = self.env['hotel.room.type.availability'].search([
|
||||
('room_type_id','=',res.room_type_id.id)
|
||||
('room_type_id', '=', res.room_type_id.id)
|
||||
])
|
||||
real_max = len(res.room_type_id.check_availability_room(
|
||||
res.checkin,
|
||||
@@ -361,32 +318,17 @@ class HotelRoomTypeWizards(models.TransientModel):
|
||||
@api.onchange('rooms_num', 'discount', 'price', 'room_type_id', 'checkin', 'checkout')
|
||||
def update_price(self):
|
||||
for record in self:
|
||||
checkin = record.checkin or record.folio_wizard_id.checkin
|
||||
checkout = record.checkout or record.folio_wizard_id.checkout
|
||||
if record.rooms_num > record.max_rooms:
|
||||
raise ValidationError(_("There are not enough rooms!"))
|
||||
# UTC -> Hotel tz
|
||||
tz = self.env['ir.default'].sudo().get('res.config.settings',
|
||||
'tz_hotel')
|
||||
chkin_utc_dt = date_utils.get_datetime(checkin)
|
||||
chkout_utc_dt = date_utils.get_datetime(checkout)
|
||||
|
||||
checkin = record.checkin or record.folio_wizard_id.checkin
|
||||
checkout = record.checkout or record.folio_wizard_id.checkout
|
||||
chkin_utc_dt = fields.Date.from_string(checkin)
|
||||
chkout_utc_dt = fields.Date.from_string(checkout)
|
||||
if chkin_utc_dt >= chkout_utc_dt:
|
||||
dpt_hour = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'default_departure_hour')
|
||||
checkout_str = (chkin_utc_dt + timedelta(days=1)).strftime(
|
||||
DEFAULT_SERVER_DATE_FORMAT)
|
||||
checkout_str = "%s %s:00" % (checkout_str, dpt_hour)
|
||||
checkout_dt = date_utils.get_datetime(checkout_str, stz=tz)
|
||||
checkout_utc_dt = date_utils.dt_as_timezone(checkout_dt, 'UTC')
|
||||
checkout = checkout_utc_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
checkout_dt = date_utils.get_datetime(checkout, stz=tz)
|
||||
# Reservation end day count as free day. Not check it
|
||||
checkout_dt -= timedelta(days=1)
|
||||
nights = date_utils.date_diff(checkin, checkout, hours=False)
|
||||
start_date_dt = date_utils.dt_as_timezone(chkin_utc_dt, tz)
|
||||
# Reservation end day count as free day. Not check it
|
||||
checkout_dt -= timedelta(days=1)
|
||||
chkout_utc_dt = chkin_utc_dt + timedelta(days=1)
|
||||
chkout_utc_dt -= timedelta(days=1)
|
||||
nights = abs((chkout_utc_dt - chkin_utc_dt).days)
|
||||
|
||||
pricelist_id = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'parity_pricelist_id')
|
||||
@@ -395,7 +337,7 @@ class HotelRoomTypeWizards(models.TransientModel):
|
||||
|
||||
res_price = 0
|
||||
for i in range(0, nights):
|
||||
ndate = start_date_dt + timedelta(days=i)
|
||||
ndate = chkin_utc_dt + timedelta(days=i)
|
||||
ndate_str = ndate.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||
prod = record.room_type_id.product_id.with_context(
|
||||
lang=record.folio_wizard_id.partner_id.lang,
|
||||
@@ -460,7 +402,7 @@ class ReservationWizard(models.TransientModel):
|
||||
if line.adults == 0:
|
||||
line.adults = room.capacity
|
||||
line.room_type_id = room.price_room_type.id
|
||||
checkout_dt = date_utils.get_datetime(line.checkout)
|
||||
checkout_dt = fields.Date.from_string(line.checkout)
|
||||
checkout_dt -= timedelta(days=1)
|
||||
occupied = self.env['hotel.reservation'].occupied(
|
||||
line.checkin,
|
||||
@@ -479,23 +421,18 @@ class ReservationWizard(models.TransientModel):
|
||||
if not self.checkout:
|
||||
self.checkout = self.folio_wizard_id.checkout
|
||||
|
||||
hotel_tz = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'hotel_tz')
|
||||
start_date_utc_dt = date_utils.get_datetime(line.checkin)
|
||||
start_date_dt = date_utils.dt_as_timezone(start_date_utc_dt,
|
||||
hotel_tz)
|
||||
start_date_utc_dt = fields.Date.from_string(line.checkin)
|
||||
end_date_utc_dt = fields.Date.from_string(line.checkout)
|
||||
|
||||
if line.room_type_id:
|
||||
pricelist_id = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'parity_pricelist_id')
|
||||
if pricelist_id:
|
||||
pricelist_id = int(pricelist_id)
|
||||
nights = date_utils.date_diff(line.checkin,
|
||||
line.checkout,
|
||||
hours=False)
|
||||
nights = abs((end_date_utc_dt - start_date_utc_dt).days)
|
||||
res_price = 0
|
||||
for i in range(0, nights):
|
||||
ndate = start_date_dt + timedelta(days=i)
|
||||
ndate = start_date_utc_dt + timedelta(days=i)
|
||||
ndate_str = ndate.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||
prod = line.room_type_id.product_id.with_context(
|
||||
lang=self.partner_id.lang,
|
||||
@@ -508,11 +445,10 @@ class ReservationWizard(models.TransientModel):
|
||||
res_price = res_price - (res_price * self.discount) * 0.01
|
||||
line.amount_reservation = res_price
|
||||
line.price = res_price
|
||||
checkout_dt = date_utils.get_datetime(self.checkout)
|
||||
checkout_dt -= timedelta(days=1)
|
||||
end_date_utc_dt -= timedelta(days=1)
|
||||
occupied = self.env['hotel.reservation'].occupied(
|
||||
self.checkin,
|
||||
checkout_dt.strftime(DEFAULT_SERVER_DATE_FORMAT))
|
||||
line.checkin,
|
||||
end_date_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT))
|
||||
rooms_occupied = occupied.mapped('product_id.id')
|
||||
domain_rooms = [
|
||||
('isroom', '=', True),
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
'views/channel_hotel_room_type_availability_views.xml',
|
||||
'views/channel_hotel_room_type_restriction_views.xml',
|
||||
'views/channel_product_pricelist_views.xml',
|
||||
'views/channel_connector_backend_views.xml',
|
||||
'views/channel_connector_menu.xml',
|
||||
'data/menus.xml',
|
||||
'data/sequences.xml',
|
||||
#'security/ir.model.access.csv',
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import _
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.addons.component.core import AbstractComponent
|
||||
from odoo.addons.queue_job.exception import RetryableJobError
|
||||
from odoo.tools import (
|
||||
@@ -50,6 +52,14 @@ class WuBookServer(object):
|
||||
self._token = None
|
||||
self._login_data = login_data
|
||||
|
||||
def __enter__(self):
|
||||
# we do nothing, api is lazy
|
||||
return self
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
if self._server is not None:
|
||||
self.close()
|
||||
|
||||
@property
|
||||
def server(self):
|
||||
if self._server is None and self._login_data.is_valid():
|
||||
@@ -86,16 +96,6 @@ class HotelChannelInterfaceAdapter(AbstractComponent):
|
||||
_inherit = ['base.backend.adapter', 'base.hotel.channel.connector']
|
||||
_usage = 'backend.adapter'
|
||||
|
||||
def _select_versions(self):
|
||||
return [
|
||||
('1.2', '1.2'),
|
||||
]
|
||||
version = fields.Selection(
|
||||
selection='_select_versions',
|
||||
string='Version',
|
||||
required=True,
|
||||
)
|
||||
|
||||
def create_room(self, shortcode, name, capacity, price, availability):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
@@ -2,11 +2,20 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
import logging
|
||||
from odoo.addons.component.core import AbstractComponent
|
||||
import pytz
|
||||
import json
|
||||
from datetime import timedelta
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.addons.component.core import AbstractComponent, Component
|
||||
from odoo.addons.hotel import date_utils
|
||||
from odoo import _
|
||||
from odoo.tools import (
|
||||
DEFAULT_SERVER_DATE_FORMAT,
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
from .backend_adapter import DEFAULT_WUBOOK_DATE_FORMAT
|
||||
from .backend_adapter import (
|
||||
DEFAULT_WUBOOK_DATE_FORMAT,
|
||||
DEFAULT_WUBOOK_DATETIME_FORMAT,
|
||||
WUBOOK_STATUS_BAD)
|
||||
from odoo import api
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -28,8 +37,8 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
||||
'avail': day_vals.get('avail', 0),
|
||||
'wpushed': True,
|
||||
}
|
||||
if set_wmax_avail:
|
||||
vals.update({'wmax_avail': day_vals.get('avail', 0)})
|
||||
if set_max_avail:
|
||||
vals.update({'max_avail': day_vals.get('avail', 0)})
|
||||
if room_type_avail:
|
||||
room_type_avail.with_context({
|
||||
'wubook_action': False,
|
||||
@@ -723,35 +732,6 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
||||
return False
|
||||
return True
|
||||
|
||||
@api.model
|
||||
def fetch_new_bookings(self):
|
||||
try:
|
||||
results = self.backend_adapter.fetch_new_bookings()
|
||||
processed_rids, errors, checkin_utc_dt, checkout_utc_dt = \
|
||||
self._generate_reservations(results)
|
||||
if any(processed_rids):
|
||||
uniq_rids = list(set(processed_rids))
|
||||
rcodeb, resultsb = self.backend_adapter.mark_bookings(uniq_rids)
|
||||
if rcodeb != 0:
|
||||
self.create_issue(
|
||||
'wubook',
|
||||
_("Problem trying mark bookings (%s)") %
|
||||
str(processed_rids),
|
||||
'')
|
||||
# Update Odoo availability (don't wait for wubook)
|
||||
# This cause abuse service in first import!!
|
||||
if checkin_utc_dt and checkout_utc_dt:
|
||||
self.backend_adapter.fetch_rooms_values(
|
||||
checkin_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT),
|
||||
checkout_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT))
|
||||
except ValidationError:
|
||||
self.create_issue(
|
||||
'reservation',
|
||||
_("Can't process reservations from wubook"),
|
||||
results)
|
||||
return False
|
||||
return True
|
||||
|
||||
@api.model
|
||||
def fetch_booking(self, channel_reservation_id):
|
||||
try:
|
||||
@@ -770,7 +750,7 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
||||
self.create_channel_connector_issue(
|
||||
'reservation',
|
||||
_("Can't process reservations from wubook"),
|
||||
results, wid=wrid)
|
||||
results, channel_object_id=channel_reservation_id)
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
from contextlib import contextmanager
|
||||
from odoo import models, api, fields
|
||||
from ...components.backend_adapter import WuBookLogin, WuBookAdapter
|
||||
from ...components.backend_adapter import WuBookLogin, WuBookServer
|
||||
|
||||
class ChannelBackend(models.Model):
|
||||
_name = 'channel.backend'
|
||||
@@ -19,8 +19,8 @@ class ChannelBackend(models.Model):
|
||||
"""
|
||||
return [('1.2', '1.2+')]
|
||||
|
||||
name = fields.Char('Name')
|
||||
version = fields.Selection(selection='select_versions', required=True)
|
||||
|
||||
username = fields.Char('Channel Service Username')
|
||||
passwd = fields.Char('Channel Service Password')
|
||||
lcode = fields.Char('Channel Service lcode')
|
||||
@@ -28,21 +28,25 @@ class ChannelBackend(models.Model):
|
||||
default='https://wired.wubook.net/xrws/')
|
||||
pkey = fields.Char('Channel Service PKey')
|
||||
|
||||
@api.multi
|
||||
def import_reservations(self):
|
||||
channel_hotel_reservation = self.env['channel.hotel.reservation']
|
||||
for backend in self:
|
||||
channel_hotel_reservation.import_reservations(backend)
|
||||
return True
|
||||
|
||||
@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)
|
||||
wubook_login = WuBookLogin(
|
||||
self.server,
|
||||
self.username,
|
||||
self.passwd,
|
||||
self.lcode,
|
||||
self.pkey)
|
||||
with WuBookAdapter(wubook_login) as channel_api:
|
||||
with WuBookServer(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:
|
||||
# from the components we'll be able to do: self.work.channel_api
|
||||
with _super.work_on(model_name, channel_api=channel_api, **kwargs) as work:
|
||||
yield work
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import models, fields
|
||||
from odoo import models, fields, api
|
||||
from odoo.addons.queue_job.job import job
|
||||
|
||||
|
||||
class ChannelBinding(models.AbstractModel):
|
||||
|
||||
@@ -2,3 +2,4 @@
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import common
|
||||
from . import importer
|
||||
|
||||
@@ -49,6 +49,13 @@ class ChannelHotelReservation(models.Model):
|
||||
wstatus_reason = fields.Char("WuBook Status Reason", readonly=True)
|
||||
wmodified = fields.Boolean("WuBook Modified", readonly=True, default=False)
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@api.model
|
||||
def import_reservations(self, backend):
|
||||
with backend.work_on(self._name) as work:
|
||||
importer = work.component(usage='channel.hotel.reservation.importer')
|
||||
return importer.fetch_new_bookings()
|
||||
|
||||
@api.depends('channel_reservation_id', 'ota_id')
|
||||
def _is_from_ota(self):
|
||||
for record in self:
|
||||
|
||||
16
hotel_channel_connector/models/hotel_reservation/importer.py
Normal file
16
hotel_channel_connector/models/hotel_reservation/importer.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# 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 import fields, api, _
|
||||
from odoo.tools import (
|
||||
DEFAULT_SERVER_DATE_FORMAT,
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
|
||||
|
||||
class HotelReservationImporter(Component):
|
||||
_name = 'channel.hotel.reservation.importer'
|
||||
_inherit = 'hotel.channel.importer'
|
||||
_apply_on = ['channel.hotel.reservation']
|
||||
_usage = 'hotel.reservation.importer'
|
||||
@@ -11,7 +11,7 @@ class HotelFolio(models.Model):
|
||||
@api.depends('room_lines')
|
||||
def _has_channel_reservations(self):
|
||||
for record in self:
|
||||
channel_reservations = record.room_lines.filtered(lambda x: x.channel_room_id)
|
||||
channel_reservations = record.room_lines.filtered(lambda x: x.room_id)
|
||||
record.has_channel_reservations = any(channel_reservations)
|
||||
|
||||
wseed = fields.Char("Wubook Session Seed", readonly=True)
|
||||
@@ -22,9 +22,8 @@ class HotelFolio(models.Model):
|
||||
old_name='whas_wubook_reservations')
|
||||
|
||||
@job(default_channel='root.channel')
|
||||
@api.multi
|
||||
@api.model
|
||||
def import_reservations(self):
|
||||
self.ensure_one()
|
||||
with self.backend_id.work_on(self._name) as work:
|
||||
importer = work.component(usage='channel.importer')
|
||||
importer.fetch_new_bookings()
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
odoo.define('hotel_channel_connector.ListController', function(require) {
|
||||
'use strict';
|
||||
/*
|
||||
* Hotel Channel Connector
|
||||
* GNU Public License
|
||||
* Alexandre Díaz <dev@redneboa.es>
|
||||
*/
|
||||
|
||||
var ListController = require('web.ListController');
|
||||
var Core = require('web.core');
|
||||
|
||||
var _t = Core._t;
|
||||
|
||||
ListController.include({
|
||||
|
||||
renderButtons: function () {
|
||||
this._super.apply(this, arguments); // Sets this.$buttons
|
||||
|
||||
if (this.modelName === 'hotel.room.type') {
|
||||
this.$buttons.append("<button class='btn btm-sm o_channel_connector_import_rooms' type='button'>"+_t('Fetch from Channel')+"</button>");
|
||||
this.$buttons.find('.o_channel_connector_import_rooms').on('click', this._importRooms.bind(this));
|
||||
} else if (this.modelName === 'hotel.folio') {
|
||||
this.$buttons.append("<button class='btn btm-sm o_channel_connector_import_reservations' type='button'>"+_t('Fetch from Channel')+"</button>");
|
||||
this.$buttons.find('.o_channel_connector_import_reservations').on('click', this._importReservations.bind(this));
|
||||
} else if (this.modelName === 'product.pricelist') {
|
||||
this.$buttons.append("<button class='btn btm-sm o_channel_connector_import_price_plans' type='button'>"+_t('Fetch from Channel')+"</button>");
|
||||
this.$buttons.find('.o_channel_connector_import_price_plans').on('click', this._importPricePlans.bind(this));
|
||||
this.$buttons.append("<button class='btn btm-sm btn-danger o_channel_connector_push_price_plans' type='button'>"+_t('Push to Channel')+"</button>");
|
||||
this.$buttons.find('.o_channel_connector_push_price_plans').on('click', this._pushPricePlans.bind(this));
|
||||
} else if (this.modelName === 'wubook.channel.info') {
|
||||
this.$buttons.append("<button class='btn btm-sm o_channel_connector_import_channels_info' type='button'>"+_t('Fetch from Channel')+"</button>");
|
||||
this.$buttons.find('.o_channel_connector_import_channels_info').on('click', this._importChannelsInfo.bind(this));
|
||||
} else if (this.modelName === 'hotel.room.type.restriction') {
|
||||
this.$buttons.append("<button class='btn btm-sm o_channel_connector_import_restriction_plans' type='button'>"+_t('Fetch from Channel')+"</button>");
|
||||
this.$buttons.find('.o_channel_connector_import_restriction_plans').on('click', this._importRestrictionPlans.bind(this));
|
||||
this.$buttons.append("<button class='btn btm-sm btn-danger o_channel_connector_push_restriction_plans' type='button'>"+_t('Push to Channel')+"</button>");
|
||||
this.$buttons.find('.o_channel_connector_push_restriction_plans').on('click', this._pushRestrictionPlans.bind(this));
|
||||
} else if (this.modelName === 'hotel.room.type.availability') {
|
||||
this.$buttons.append("<button class='btn btm-sm o_channel_connector_import_availability' type='button'>"+_t('Fetch from Channel')+"</button>");
|
||||
this.$buttons.find('.o_channel_connector_import_availability').on('click', this._importAvailability.bind(this));
|
||||
this.$buttons.append("<button class='btn btm-sm btn-danger o_channel_connector_push_availability' type='button'>"+_t('Push to Channel')+"</button>");
|
||||
this.$buttons.find('.o_channel_connector_push_availability').on('click', this._pushAvailability.bind(this));
|
||||
}
|
||||
},
|
||||
|
||||
_importRooms: function () {
|
||||
var self = this;
|
||||
this.dataset._model.call('import_rooms', [false]).then(function(results){
|
||||
if (!results[0]) {
|
||||
self.do_warn(_t('Operation Errors'), _t('Errors while importing rooms. See issues registry.'), true);
|
||||
}
|
||||
if (results[0] || results[1] > 0) {
|
||||
if (results[1] > 0) {
|
||||
self.do_notify(_t('Operation Success'), `<b>${results[1]}</b>` + ' ' + _t('Rooms successfully imported'), false);
|
||||
} else {
|
||||
self.do_notify(_t('Operation Success'), _t('No new rooms found. Everything is done.'), false);
|
||||
}
|
||||
var active_view = self.ViewManager.active_view;
|
||||
active_view.controller.reload(); // list view only has reload
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_importReservations: function () {
|
||||
var self = this;
|
||||
console.log(this);
|
||||
this.model.import_reservations().then(function(results){
|
||||
console.log(results);
|
||||
if (!results[0]) {
|
||||
self.do_warn(_t('Operation Errors'), _t('Errors while importing reservations. See issues registry.'), true);
|
||||
}
|
||||
if (results[0] || results[1] > 0) {
|
||||
if (results[1] > 0) {
|
||||
self.do_notify(_t('Operation Success'), `<b>${results[1]}</b>` + ' ' + _t('Reservations successfully imported'), false);
|
||||
} else {
|
||||
self.do_notify(_t('Operation Success'), _t('No new reservations found. Everything is done.'), false);
|
||||
}
|
||||
var active_view = self.ViewManager.active_view;
|
||||
active_view.controller.reload(); // list view only has reload
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_importPricePlans: function () {
|
||||
var self = this;
|
||||
this.dataset._model.call('import_price_plans', [false]).then(function(results){
|
||||
if (!results[0]) {
|
||||
self.do_warn(_t('Operation Errors'), _t('Errors while importing price plans from WuBook. See issues log.'), true);
|
||||
}
|
||||
if (results[0] || results[1] > 0) {
|
||||
if (results[1] > 0) {
|
||||
self.do_notify(_t('Operation Success'), `<b>${results[1]}</b>` + ' ' + _t('Price Plans successfully imported'), false);
|
||||
} else {
|
||||
self.do_notify(_t('Operation Success'), _t('No new price plans found. Everything is done.'), false);
|
||||
}
|
||||
var active_view = self.ViewManager.active_view;
|
||||
active_view.controller.reload(); // list view only has reload
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_pushPricePlans: function () {
|
||||
var self = this;
|
||||
new Model('wubook').call('push_priceplans', [false]).then(function(results){
|
||||
self.do_notify(_t('Operation Success'), _t('Price Plans successfully pushed'), false);
|
||||
}).fail(function(){
|
||||
self.do_warn(_t('Operation Errors'), _t('Errors while pushing price plans to WuBook. See issues log.'), true);
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_importChannelsInfo: function () {
|
||||
var self = this;
|
||||
this.dataset._model.call('import_channels_info', [false]).then(function(results){
|
||||
if (!results[0]) {
|
||||
self.do_warn(_t('Operation Errors'), _t('Errors while importing channels info from WuBook. See issues log.'), true);
|
||||
}
|
||||
if (results[0] || results[1] > 0) {
|
||||
if (results[1] > 0) {
|
||||
self.do_notify(_t('Operation Success'), `<b>${results[1]}</b>` + ' ' + _t('Channels Info successfully imported'), false);
|
||||
} else {
|
||||
self.do_notify(_t('Operation Success'), _t('No new channels info found. Everything is done.'), false);
|
||||
}
|
||||
var active_view = self.ViewManager.active_view;
|
||||
active_view.controller.reload(); // list view only has reload
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_importRestrictionPlans: function () {
|
||||
var self = this;
|
||||
this.dataset._model.call('import_restriction_plans', [false]).then(function(results){
|
||||
if (!results[0]) {
|
||||
self.do_warn(_t('Operation Errors'), _t('Errors while importing restriction plans from WuBook. See issues log.'), true);
|
||||
}
|
||||
if (results[0] || results[1] > 0) {
|
||||
if (results[1] > 0) {
|
||||
self.do_notify(_t('Operation Success'), `<b>${results[1]}</b>` + ' ' + _t('Restriction Plans successfully imported'), false);
|
||||
} else {
|
||||
self.do_notify(_t('Operation Success'), _t('No new restriction plans found. Everything is done.'), false);
|
||||
}
|
||||
var active_view = self.ViewManager.active_view;
|
||||
active_view.controller.reload(); // list view only has reload
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_pushRestrictionPlans: function () {
|
||||
var self = this;
|
||||
new Model('wubook').call('push_restrictions', [false]).then(function(results){
|
||||
self.do_notify(_t('Operation Success'), _t('Restrictions successfully pushed'), false);
|
||||
}).fail(function(){
|
||||
self.do_warn(_t('Operation Errors'), _t('Errors while pushing restrictions to WuBook. See issues log.'), true);
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_importAvailability: function () {
|
||||
this.do_action('hotel_wubook_proto.action_wubook_import_availability');
|
||||
return false;
|
||||
},
|
||||
|
||||
_pushAvailability: function () {
|
||||
var self = this;
|
||||
new Model('wubook').call('push_availability', [false]).then(function(results){
|
||||
self.do_notify(_t('Operation Success'), _t('Availability successfully pushed'), false);
|
||||
}).fail(function(){
|
||||
self.do_warn(_t('Operation Errors'), _t('Errors while pushing availability to Channel. See issues log.'), true);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
odoo.define('hotel_channel_connector.ListModel', function(require) {
|
||||
'use strict';
|
||||
/*
|
||||
* Hotel Channel Connector
|
||||
* GNU Public License
|
||||
* Alexandre Díaz <dev@redneboa.es>
|
||||
*/
|
||||
|
||||
var BasicModel = require('web.BasicModel'),
|
||||
Session = require('web.session');
|
||||
|
||||
return BasicModel.extend({
|
||||
|
||||
import_reservations: function() {
|
||||
return this._rpc({
|
||||
model: 'hotel.folio',
|
||||
method: 'import_reservations',
|
||||
args: undefined,
|
||||
context: Session.user_context,
|
||||
});
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,18 @@
|
||||
odoo.define('hotel_channel_connector.ListView', function(require) {
|
||||
'use strict';
|
||||
/*
|
||||
* Hotel Channel Connector
|
||||
* GNU Public License
|
||||
* Alexandre Díaz <dev@redneboa.es>
|
||||
*/
|
||||
|
||||
var ListView = require('web.ListView'),
|
||||
ListModel = require('hotel_channel_connector.ListModel');
|
||||
|
||||
ListView.include({
|
||||
config: _.extend({}, ListView.prototype.config, {
|
||||
Model: ListModel,
|
||||
}),
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,188 +0,0 @@
|
||||
odoo.define('hotel_channel_connector.listview_button_import_rooms', function(require) {
|
||||
'use strict';
|
||||
/*
|
||||
* Hotel Channel Connector
|
||||
* GNU Public License
|
||||
* Alexandre Díaz <dev@redneboa.es>
|
||||
*/
|
||||
|
||||
var ListView = require('web.ListView');
|
||||
var Core = require('web.core');
|
||||
var Model = require('web.DataModel');
|
||||
|
||||
var _t = Core._t;
|
||||
|
||||
function import_rooms(){
|
||||
var self = this;
|
||||
this.dataset._model.call('import_rooms', [false]).then(function(results){
|
||||
if (!results[0]) {
|
||||
self.do_warn(_t('Operation Errors'), _t('Errors while importing rooms. See issues registry.'), true);
|
||||
}
|
||||
if (results[0] || results[1] > 0) {
|
||||
if (results[1] > 0) {
|
||||
self.do_notify(_t('Operation Success'), `<b>${results[1]}</b>` + ' ' + _t('Rooms successfully imported'), false);
|
||||
} else {
|
||||
self.do_notify(_t('Operation Success'), _t('No new rooms found. Everything is done.'), false);
|
||||
}
|
||||
var active_view = self.ViewManager.active_view;
|
||||
active_view.controller.reload(); // list view only has reload
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function import_reservations(){
|
||||
var self = this;
|
||||
this.dataset._model.call('import_reservations', [false]).then(function(results){
|
||||
console.log(results);
|
||||
if (!results[0]) {
|
||||
self.do_warn(_t('Operation Errors'), _t('Errors while importing reservations. See issues registry.'), true);
|
||||
}
|
||||
if (results[0] || results[1] > 0) {
|
||||
if (results[1] > 0) {
|
||||
self.do_notify(_t('Operation Success'), `<b>${results[1]}</b>` + ' ' + _t('Reservations successfully imported'), false);
|
||||
} else {
|
||||
self.do_notify(_t('Operation Success'), _t('No new reservations found. Everything is done.'), false);
|
||||
}
|
||||
var active_view = self.ViewManager.active_view;
|
||||
active_view.controller.reload(); // list view only has reload
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function import_price_plans(){
|
||||
var self = this;
|
||||
this.dataset._model.call('import_price_plans', [false]).then(function(results){
|
||||
if (!results[0]) {
|
||||
self.do_warn(_t('Operation Errors'), _t('Errors while importing price plans from WuBook. See issues log.'), true);
|
||||
}
|
||||
if (results[0] || results[1] > 0) {
|
||||
if (results[1] > 0) {
|
||||
self.do_notify(_t('Operation Success'), `<b>${results[1]}</b>` + ' ' + _t('Price Plans successfully imported'), false);
|
||||
} else {
|
||||
self.do_notify(_t('Operation Success'), _t('No new price plans found. Everything is done.'), false);
|
||||
}
|
||||
var active_view = self.ViewManager.active_view;
|
||||
active_view.controller.reload(); // list view only has reload
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function push_price_plans(){
|
||||
var self = this;
|
||||
new Model('wubook').call('push_priceplans', [false]).then(function(results){
|
||||
self.do_notify(_t('Operation Success'), _t('Price Plans successfully pushed'), false);
|
||||
}).fail(function(){
|
||||
self.do_warn(_t('Operation Errors'), _t('Errors while pushing price plans to WuBook. See issues log.'), true);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function import_channels_info(){
|
||||
var self = this;
|
||||
this.dataset._model.call('import_channels_info', [false]).then(function(results){
|
||||
if (!results[0]) {
|
||||
self.do_warn(_t('Operation Errors'), _t('Errors while importing channels info from WuBook. See issues log.'), true);
|
||||
}
|
||||
if (results[0] || results[1] > 0) {
|
||||
if (results[1] > 0) {
|
||||
self.do_notify(_t('Operation Success'), `<b>${results[1]}</b>` + ' ' + _t('Channels Info successfully imported'), false);
|
||||
} else {
|
||||
self.do_notify(_t('Operation Success'), _t('No new channels info found. Everything is done.'), false);
|
||||
}
|
||||
var active_view = self.ViewManager.active_view;
|
||||
active_view.controller.reload(); // list view only has reload
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function import_restriction_plans(){
|
||||
var self = this;
|
||||
this.dataset._model.call('import_restriction_plans', [false]).then(function(results){
|
||||
if (!results[0]) {
|
||||
self.do_warn(_t('Operation Errors'), _t('Errors while importing restriction plans from WuBook. See issues log.'), true);
|
||||
}
|
||||
if (results[0] || results[1] > 0) {
|
||||
if (results[1] > 0) {
|
||||
self.do_notify(_t('Operation Success'), `<b>${results[1]}</b>` + ' ' + _t('Restriction Plans successfully imported'), false);
|
||||
} else {
|
||||
self.do_notify(_t('Operation Success'), _t('No new restriction plans found. Everything is done.'), false);
|
||||
}
|
||||
var active_view = self.ViewManager.active_view;
|
||||
active_view.controller.reload(); // list view only has reload
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function push_restriction_plans(){
|
||||
var self = this;
|
||||
new Model('wubook').call('push_restrictions', [false]).then(function(results){
|
||||
self.do_notify(_t('Operation Success'), _t('Restrictions successfully pushed'), false);
|
||||
}).fail(function(){
|
||||
self.do_warn(_t('Operation Errors'), _t('Errors while pushing restrictions to WuBook. See issues log.'), true);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function import_availability(){
|
||||
this.do_action('hotel_wubook_proto.action_wubook_import_availability');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function push_availability(){
|
||||
var self = this;
|
||||
new Model('wubook').call('push_availability', [false]).then(function(results){
|
||||
self.do_notify(_t('Operation Success'), _t('Availability successfully pushed'), false);
|
||||
}).fail(function(){
|
||||
self.do_warn(_t('Operation Errors'), _t('Errors while pushing availability to Channel. See issues log.'), true);
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ListView.include({
|
||||
render_buttons: function () {
|
||||
this._super.apply(this, arguments); // Sets this.$buttons
|
||||
|
||||
if (this.dataset.model === 'hotel.room.type') {
|
||||
this.$buttons.append("<button class='oe_button oe_channel_connector_import_rooms oe_highlight' type='button'>"+_t('Fetch from Channel')+"</button>");
|
||||
this.$buttons.find('.oe_channel_connector_import_rooms').on('click', import_rooms.bind(this));
|
||||
} else if (this.dataset.model === 'hotel.folio') {
|
||||
this.$buttons.append("<button class='oe_button oe_channel_connector_import_reservations oe_highlight' type='button'>"+_t('Fetch from Channel')+"</button>");
|
||||
this.$buttons.find('.oe_channel_connector_import_reservations').on('click', import_reservations.bind(this));
|
||||
} else if (this.dataset.model === 'product.pricelist') {
|
||||
this.$buttons.append("<button class='oe_button oe_channel_connector_import_price_plans oe_highlight' type='button'>"+_t('Fetch from Channel')+"</button>");
|
||||
this.$buttons.find('.oe_channel_connector_import_price_plans').on('click', import_price_plans.bind(this));
|
||||
this.$buttons.append("<button class='oe_button oe_channel_connector_push_price_plans' style='background-color:red; color:white;' type='button'>"+_t('Push to Channel')+"</button>");
|
||||
this.$buttons.find('.oe_channel_connector_push_price_plans').on('click', push_price_plans.bind(this));
|
||||
} else if (this.dataset.model === 'wubook.channel.info') {
|
||||
this.$buttons.append("<button class='oe_button oe_channel_connector_import_channels_info oe_highlight' type='button'>"+_t('Fetch from Channel')+"</button>");
|
||||
this.$buttons.find('.oe_channel_connector_import_channels_info').on('click', import_channels_info.bind(this));
|
||||
} else if (this.dataset.model === 'hotel.room.type.restriction') {
|
||||
this.$buttons.append("<button class='oe_button oe_channel_connector_import_restriction_plans oe_highlight' type='button'>"+_t('Fetch from Channel')+"</button>");
|
||||
this.$buttons.find('.oe_channel_connector_import_restriction_plans').on('click', import_restriction_plans.bind(this));
|
||||
this.$buttons.append("<button class='oe_button oe_channel_connector_push_restriction_plans' style='background-color:red; color:white;' type='button'>"+_t('Push to Channel')+"</button>");
|
||||
this.$buttons.find('.oe_channel_connector_push_restriction_plans').on('click', push_restriction_plans.bind(this));
|
||||
} else if (this.dataset.model === 'hotel.room.type.availability') {
|
||||
this.$buttons.append("<button class='oe_button oe_channel_connector_import_availability oe_highlight' type='button'>"+_t('Fetch from Channel')+"</button>");
|
||||
this.$buttons.find('.oe_channel_connector_import_availability').on('click', import_availability.bind(this));
|
||||
this.$buttons.append("<button class='oe_button oe_channel_connector_push_availability' style='background-color:red; color:white;' type='button'>"+_t('Push to Channel')+"</button>");
|
||||
this.$buttons.find('.oe_channel_connector_push_availability').on('click', push_availability.bind(this));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="view_channel_backend_form" model="ir.ui.view">
|
||||
<field name="name">channel.backend.form</field>
|
||||
<field name="model">channel.backend</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Channel Backend">
|
||||
<header>
|
||||
<button name="synchronize_metadata"
|
||||
type="object"
|
||||
class="oe_highlight"
|
||||
string="Synchronize Metadata"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<label for="name" class="oe_edit_only"/>
|
||||
<h1>
|
||||
<field name="name" class="oe_inline" />
|
||||
</h1>
|
||||
<group name="channel" string="Channel Configuration">
|
||||
<notebook>
|
||||
<page string="API" name="api">
|
||||
<group colspan="4" col="4">
|
||||
<field name="version" colspan="4"/>
|
||||
<field name="server" colspan="2"/>
|
||||
<field name="lcode" colspan="2"/>
|
||||
<field name="username" colspan="2"/>
|
||||
<field name="passwd" password="1" colspan="2"/>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</group>
|
||||
<notebook>
|
||||
<page name="import" string="Imports">
|
||||
<p class="oe_grey oe_inline">
|
||||
By clicking on the buttons,
|
||||
you will initiate the synchronizations
|
||||
with Channel.
|
||||
Note that the import or exports
|
||||
won't be done directly,
|
||||
they will create 'Jobs'
|
||||
executed as soon as possible.
|
||||
</p>
|
||||
<p class="oe_grey oe_inline">
|
||||
Once imported,
|
||||
some types of records,
|
||||
like the reservations,
|
||||
need a manual review.
|
||||
You will find the list
|
||||
of the new records to review
|
||||
in the menu 'Connectors > Checkpoint'.
|
||||
</p>
|
||||
<group>
|
||||
<label string="Import Reservations" class="oe_inline"/>
|
||||
<div>
|
||||
<button name="import_reservations"
|
||||
type="object"
|
||||
class="oe_highlight"
|
||||
string="Import in background"/>
|
||||
</div>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_channel_backend_tree" model="ir.ui.view">
|
||||
<field name="name">channel.backend.tree</field>
|
||||
<field name="model">channel.backend</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Channel Backend">
|
||||
<field name="name"/>
|
||||
<field name="username"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_channel_backend" model="ir.actions.act_window">
|
||||
<field name="name">Channel Backends</field>
|
||||
<field name="res_model">channel.backend</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_id" ref="view_channel_backend_tree"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
15
hotel_channel_connector/views/channel_connector_menu.xml
Normal file
15
hotel_channel_connector/views/channel_connector_menu.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<menuitem id="menu_channel_connector_root"
|
||||
parent="connector.menu_connector_root"
|
||||
name="Channel"
|
||||
sequence="10"
|
||||
groups="connector.group_connector_manager"/>
|
||||
|
||||
<menuitem id="menu_cannel_backend"
|
||||
name="Backends"
|
||||
parent="menu_channel_connector_root"
|
||||
action="action_channel_backend"/>
|
||||
|
||||
</odoo>
|
||||
@@ -4,7 +4,9 @@
|
||||
<!-- Backend stuff -->
|
||||
<template id="assets_backend" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<script type="text/javascript" src="/hotel_channel_connector/static/src/js/wubook_listview_import_buttons.js"></script>
|
||||
<script type="text/javascript" src="/hotel_channel_connector/static/src/js/views/list/list_model.js"></script>
|
||||
<script type="text/javascript" src="/hotel_channel_connector/static/src/js/views/list/list_controller.js"></script>
|
||||
<script type="text/javascript" src="/hotel_channel_connector/static/src/js/views/list/list_view.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user