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
|
import datetime
|
||||||
from openerp import models, fields, api, _
|
from openerp import models, fields, api, _
|
||||||
from openerp.exceptions import except_orm, ValidationError
|
from openerp.exceptions import except_orm, ValidationError
|
||||||
from odoo.addons.hotel import date_utils
|
|
||||||
|
|
||||||
|
|
||||||
class Cardex(models.Model):
|
class Cardex(models.Model):
|
||||||
@@ -53,7 +52,7 @@ class Cardex(models.Model):
|
|||||||
@api.onchange('enter_date', 'exit_date')
|
@api.onchange('enter_date', 'exit_date')
|
||||||
def check_change_dates(self):
|
def check_change_dates(self):
|
||||||
if self.exit_date <= self.enter_date:
|
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)
|
date_2 = date_1 + datetime.timedelta(days=1)
|
||||||
self.update({'exit_date': date_2, })
|
self.update({'exit_date': date_2, })
|
||||||
raise ValidationError(
|
raise ValidationError(
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ from odoo.tools import (
|
|||||||
DEFAULT_SERVER_DATETIME_FORMAT,
|
DEFAULT_SERVER_DATETIME_FORMAT,
|
||||||
DEFAULT_SERVER_DATE_FORMAT)
|
DEFAULT_SERVER_DATE_FORMAT)
|
||||||
from odoo import models, fields, api, _
|
from odoo import models, fields, api, _
|
||||||
from odoo.addons.hotel import date_utils
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
from odoo.addons import decimal_precision as dp
|
from odoo.addons import decimal_precision as dp
|
||||||
@@ -267,10 +266,8 @@ class HotelFolio(models.Model):
|
|||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
def action_folios_amount(self):
|
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([
|
reservations = self.env['hotel.reservation'].search([
|
||||||
('checkout', '<=', now_utc_str)
|
('checkout', '<=', fields.Date.today())
|
||||||
])
|
])
|
||||||
folio_ids = reservations.mapped('folio_id.id')
|
folio_ids = reservations.mapped('folio_id.id')
|
||||||
folios = self.env['hotel.folio'].search([('id', 'in', folio_ids)])
|
folios = self.env['hotel.folio'].search([('id', 'in', folio_ids)])
|
||||||
|
|||||||
@@ -284,7 +284,7 @@ class HotelReservation(models.Model):
|
|||||||
'channel_type': vals.get('channel_type')})
|
'channel_type': vals.get('channel_type')})
|
||||||
#~ colors = self._generate_color()
|
#~ colors = self._generate_color()
|
||||||
vals.update({
|
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': colors[0],
|
||||||
#~ 'reserve_color_text': colors[1],
|
#~ 'reserve_color_text': colors[1],
|
||||||
})
|
})
|
||||||
@@ -306,8 +306,7 @@ class HotelReservation(models.Model):
|
|||||||
def write(self, vals):
|
def write(self, vals):
|
||||||
if self.notify_update(vals):
|
if self.notify_update(vals):
|
||||||
vals.update({
|
vals.update({
|
||||||
'last_updated_res': date_utils.now(hours=True).strftime(
|
'last_updated_res': fields.Datetime.now()
|
||||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
|
||||||
})
|
})
|
||||||
for record in self:
|
for record in self:
|
||||||
if record.compute_price_out_vals(vals):
|
if record.compute_price_out_vals(vals):
|
||||||
@@ -902,15 +901,9 @@ class HotelReservation(models.Model):
|
|||||||
@api.model
|
@api.model
|
||||||
def daily_plan(self):
|
def daily_plan(self):
|
||||||
_logger.info('daily_plan')
|
_logger.info('daily_plan')
|
||||||
today_utc_dt = date_utils.now()
|
today_str = fields.Date.today()
|
||||||
yesterday_utc_dt = today_utc_dt - timedelta(days=1)
|
yesterday_utc_dt = datetime.now() - timedelta(days=1)
|
||||||
hotel_tz = self.env['ir.default'].sudo().get('res.config.settings',
|
yesterday_str = yesterday_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||||
'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)
|
|
||||||
reservations_to_checkout = self.env['hotel.reservation'].search([
|
reservations_to_checkout = self.env['hotel.reservation'].search([
|
||||||
('state', 'not in', ['done']),
|
('state', 'not in', ['done']),
|
||||||
('checkout', '<', today_str)
|
('checkout', '<', today_str)
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ from datetime import datetime
|
|||||||
from odoo import models, fields, api, _
|
from odoo import models, fields, api, _
|
||||||
from odoo.exceptions import ValidationError
|
from odoo.exceptions import ValidationError
|
||||||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
|
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
|
||||||
from odoo.addons.hotel import date_utils
|
|
||||||
|
|
||||||
|
|
||||||
class HotelRoomTypeRestrictionItem(models.Model):
|
class HotelRoomTypeRestrictionItem(models.Model):
|
||||||
@@ -59,8 +58,8 @@ class HotelRoomTypeRestrictionItem(models.Model):
|
|||||||
self.date_start = False
|
self.date_start = False
|
||||||
self.date_end = False
|
self.date_end = False
|
||||||
elif self.date_start and self.date_end:
|
elif self.date_start and self.date_end:
|
||||||
date_start_dt = date_utils.get_datetime(self.date_start)
|
date_start_dt = fields.Date.from_string(self.date_start)
|
||||||
date_end_dt = date_utils.get_datetime(self.date_end)
|
date_end_dt = fields.Date.from_string(self.date_end)
|
||||||
if date_end_dt < date_start_dt:
|
if date_end_dt < date_start_dt:
|
||||||
raise ValidationError(_("Invalid Dates"))
|
raise ValidationError(_("Invalid Dates"))
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import logging
|
|||||||
from odoo import models, fields, api, _
|
from odoo import models, fields, api, _
|
||||||
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||||
from odoo.exceptions import UserError
|
from odoo.exceptions import UserError
|
||||||
from odoo.addons.hotel import date_utils
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
from odoo.addons import decimal_precision as dp
|
from odoo.addons import decimal_precision as dp
|
||||||
@@ -91,12 +90,12 @@ class HotelServiceLine(models.Model):
|
|||||||
('mail', 'Mail'),
|
('mail', 'Mail'),
|
||||||
('phone', 'Phone'),
|
('phone', 'Phone'),
|
||||||
('call', 'Call Center'),
|
('call', 'Call Center'),
|
||||||
('web','Web')], 'Sales Channel')
|
('web', 'Web')], 'Sales Channel')
|
||||||
|
|
||||||
ser_checkin = fields.Datetime('From Date', required=True,
|
ser_checkin = fields.Date('From Date', required=True,
|
||||||
default=_service_checkin)
|
default=_service_checkin)
|
||||||
ser_checkout = fields.Datetime('To Date', required=True,
|
ser_checkout = fields.Date('To Date', required=True,
|
||||||
default=_service_checkout)
|
default=_service_checkout)
|
||||||
ser_room_line = fields.Many2one('hotel.reservation', 'Room',
|
ser_room_line = fields.Many2one('hotel.reservation', 'Room',
|
||||||
default=_default_ser_room_line)
|
default=_default_ser_room_line)
|
||||||
|
|
||||||
@@ -199,20 +198,17 @@ class HotelServiceLine(models.Model):
|
|||||||
-----------------------------------------------------------------
|
-----------------------------------------------------------------
|
||||||
@param self: object pointer
|
@param self: object pointer
|
||||||
'''
|
'''
|
||||||
now_utc_dt = date_utils.now()
|
now_utc = fields.Date.today()
|
||||||
if not self.ser_checkin:
|
if not self.ser_checkin:
|
||||||
self.ser_checkin = now_utc_dt.strftime(
|
self.ser_checkin = now_utc
|
||||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
|
||||||
if not self.ser_checkout:
|
if not self.ser_checkout:
|
||||||
self.ser_checkout = now_utc_dt.strftime(
|
self.ser_checkout = now_utc
|
||||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
chkin_utc_dt = fields.Date.from_string(self.ser_checkin)
|
||||||
chkin_utc_dt = date_utils.get_datetime(self.ser_checkin)
|
chkout_utc_dt = fields.Date.from_string(self.ser_checkout)
|
||||||
chkout_utc_dt = date_utils.get_datetime(self.ser_checkout)
|
|
||||||
if chkout_utc_dt < chkin_utc_dt:
|
if chkout_utc_dt < chkin_utc_dt:
|
||||||
raise UserError(_('Checkout must be greater or equal checkin date'))
|
raise UserError(_('Checkout must be greater or equal checkin date'))
|
||||||
if self.ser_checkin and self.ser_checkout:
|
if self.ser_checkin and self.ser_checkout:
|
||||||
diffDate = date_utils.date_diff(self.ser_checkin,
|
diffDate = abs((self.ser_checkout - self.ser_checkin).days) + 1
|
||||||
self.ser_checkout, hours=False) + 1
|
|
||||||
# FIXME: Finalize method!
|
# FIXME: Finalize method!
|
||||||
|
|
||||||
@api.multi
|
@api.multi
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ from openerp import models, fields, api
|
|||||||
from openerp.tools import (
|
from openerp.tools import (
|
||||||
DEFAULT_SERVER_DATE_FORMAT,
|
DEFAULT_SERVER_DATE_FORMAT,
|
||||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
from odoo.addons.hotel import date_utils
|
|
||||||
|
|
||||||
|
|
||||||
class MassiveChangesWizard(models.TransientModel):
|
class MassiveChangesWizard(models.TransientModel):
|
||||||
@@ -17,8 +16,8 @@ class MassiveChangesWizard(models.TransientModel):
|
|||||||
('1', 'Restrictions'),
|
('1', 'Restrictions'),
|
||||||
('2', 'Pricelist'),
|
('2', 'Pricelist'),
|
||||||
], string='Section', default='0')
|
], string='Section', default='0')
|
||||||
date_start = fields.Datetime('Start Date', required=True)
|
date_start = fields.Date('Start Date', required=True)
|
||||||
date_end = fields.Datetime('End Date', required=True)
|
date_end = fields.Date('End Date', required=True)
|
||||||
dmo = fields.Boolean('Monday', default=True)
|
dmo = fields.Boolean('Monday', default=True)
|
||||||
dtu = fields.Boolean('Tuesday', default=True)
|
dtu = fields.Boolean('Tuesday', default=True)
|
||||||
dwe = fields.Boolean('Wednesday', default=True)
|
dwe = fields.Boolean('Wednesday', default=True)
|
||||||
@@ -28,12 +27,11 @@ class MassiveChangesWizard(models.TransientModel):
|
|||||||
dsu = fields.Boolean('Sunday', default=True)
|
dsu = fields.Boolean('Sunday', default=True)
|
||||||
applied_on = fields.Selection([
|
applied_on = fields.Selection([
|
||||||
('0', 'Global'),
|
('0', 'Global'),
|
||||||
('1', 'Virtual Room'),
|
('1', 'Room Type'),
|
||||||
], string='Applied On', default='0')
|
], string='Applied On', default='0')
|
||||||
# room_type_ids = fields.Many2many('hotel.virtual.room',
|
# room_type_ids = fields.Many2many('hotel.virtual.room',
|
||||||
# string="Virtual Rooms")
|
# string="Virtual Rooms")
|
||||||
room_type_ids = fields.Many2many('hotel.room.type',
|
room_type_ids = fields.Many2many('hotel.room.type', string="Room Types")
|
||||||
string="Room Types")
|
|
||||||
|
|
||||||
# Availability fields
|
# Availability fields
|
||||||
change_avail = fields.Boolean(default=False)
|
change_avail = fields.Boolean(default=False)
|
||||||
@@ -251,12 +249,10 @@ class MassiveChangesWizard(models.TransientModel):
|
|||||||
def _do_massive_change(self):
|
def _do_massive_change(self):
|
||||||
hotel_room_type_obj = self.env['hotel.room.type']
|
hotel_room_type_obj = self.env['hotel.room.type']
|
||||||
for record in self:
|
for record in self:
|
||||||
date_start_dt = date_utils.get_datetime(record.date_start,
|
date_start_dt = fields.Date.from_string(record.date_start)
|
||||||
hours=False)
|
date_end_dt = fields.Date.from_string(record.date_end)
|
||||||
# Use min '1' for same date
|
# Use min '1' for same date
|
||||||
diff_days = date_utils.date_diff(record.date_start,
|
diff_days = abs((date_end_dt - date_start_dt).days) + 1
|
||||||
record.date_end,
|
|
||||||
hours=False) + 1
|
|
||||||
wedays = (record.dmo, record.dtu, record.dwe, record.dth,
|
wedays = (record.dmo, record.dtu, record.dwe, record.dth,
|
||||||
record.dfr, record.dsa, record.dsu)
|
record.dfr, record.dsa, record.dsu)
|
||||||
room_types = record.room_type_id if record.applied_on == '1' \
|
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(
|
reservation_id = self.env['hotel.reservation'].browse(
|
||||||
self.env.context.get('active_id'))
|
self.env.context.get('active_id'))
|
||||||
if reservation_id:
|
if reservation_id:
|
||||||
date_start_dt = date_utils.get_datetime(reservation_id.checkin)
|
date_start_dt = fields.Date.from_string(reservation_id.checkin)
|
||||||
date_end_dt = date_utils.get_datetime(reservation_id.checkout)
|
date_end_dt = fields.Date.from_string(reservation_id.checkout)
|
||||||
date_diff = date_utils.date_diff(date_start_dt, date_end_dt,
|
date_diff = abs((date_end_dt - date_start_dt).days)
|
||||||
hours=False)
|
|
||||||
for record in self:
|
for record in self:
|
||||||
new_start_date_dt = date_start_dt + \
|
new_start_date_dt = date_start_dt + \
|
||||||
timedelta(days=date_diff-record.nights)
|
timedelta(days=date_diff-record.nights)
|
||||||
@@ -41,7 +40,7 @@ class SplitReservationWizard(models.TransientModel):
|
|||||||
tprice = [0.0, 0.0]
|
tprice = [0.0, 0.0]
|
||||||
div_dt = date_utils.dt_no_hours(new_start_date_dt)
|
div_dt = date_utils.dt_no_hours(new_start_date_dt)
|
||||||
for rline in reservation_id.reservation_lines:
|
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:
|
if rline_dt >= div_dt:
|
||||||
reservation_lines[1].append((0, False, {
|
reservation_lines[1].append((0, False, {
|
||||||
'date': rline.date,
|
'date': rline.date,
|
||||||
|
|||||||
@@ -5,9 +5,8 @@ from datetime import datetime, timedelta
|
|||||||
from odoo.tools import (
|
from odoo.tools import (
|
||||||
DEFAULT_SERVER_DATE_FORMAT,
|
DEFAULT_SERVER_DATE_FORMAT,
|
||||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
from odoo import models, api, _
|
from odoo import models, api, _, fields
|
||||||
from odoo.exceptions import ValidationError
|
from odoo.exceptions import ValidationError
|
||||||
from odoo.addons.hotel import date_utils
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@@ -176,8 +175,9 @@ class HotelCalendarManagement(models.TransientModel):
|
|||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _hcalendar_availability_json_data(self, dfrom, dto):
|
def _hcalendar_availability_json_data(self, dfrom, dto):
|
||||||
date_start = date_utils.get_datetime(dfrom, hours=False)
|
date_start = fields.Date.from_string(dfrom)
|
||||||
date_diff = date_utils.date_diff(dfrom, dto, hours=False) + 1
|
date_end = fields.Date.from_string(dto)
|
||||||
|
date_diff = abs((date_end - date_start).days) + 1
|
||||||
room_types = self.env['hotel.room.type'].search([])
|
room_types = self.env['hotel.room.type'].search([])
|
||||||
json_data = {}
|
json_data = {}
|
||||||
|
|
||||||
@@ -208,7 +208,7 @@ class HotelCalendarManagement(models.TransientModel):
|
|||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _hcalendar_events_json_data(self, dfrom, dto):
|
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)
|
date_start_str = date_start.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
user_id = self.env['res.users'].browse(self.env.uid)
|
user_id = self.env['res.users'].browse(self.env.uid)
|
||||||
domain = []
|
domain = []
|
||||||
@@ -239,8 +239,9 @@ class HotelCalendarManagement(models.TransientModel):
|
|||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _hcalendar_get_count_reservations_json_data(self, dfrom, dto):
|
def _hcalendar_get_count_reservations_json_data(self, dfrom, dto):
|
||||||
date_start = date_utils.get_datetime(dfrom, hours=False)
|
date_start = fields.Date.from_string(dfrom)
|
||||||
date_diff = date_utils.date_diff(dfrom, dto, hours=False) + 1
|
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_type_obj = self.env['hotel.room.type']
|
||||||
room_types = room_type_obj.search([])
|
room_types = room_type_obj.search([])
|
||||||
json_data = {}
|
json_data = {}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ from odoo.exceptions import ValidationError
|
|||||||
from odoo.tools import (
|
from odoo.tools import (
|
||||||
DEFAULT_SERVER_DATE_FORMAT,
|
DEFAULT_SERVER_DATE_FORMAT,
|
||||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
from odoo.addons.hotel import date_utils
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@@ -95,8 +94,7 @@ class HotelReservation(models.Model):
|
|||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def get_hcalendar_reservations_data(self, dfrom, dto, rooms):
|
def get_hcalendar_reservations_data(self, dfrom, dto, rooms):
|
||||||
date_start = date_utils.get_datetime(dfrom, hours=False) \
|
date_start = fields.Date.from_string(dfrom) - timedelta(days=1)
|
||||||
- timedelta(days=1)
|
|
||||||
date_start_str = date_start.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
date_start_str = date_start.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
reservations_raw = self.env['hotel.reservation'].search(
|
reservations_raw = self.env['hotel.reservation'].search(
|
||||||
[
|
[
|
||||||
@@ -122,9 +120,9 @@ class HotelReservation(models.Model):
|
|||||||
'res.config.settings', 'parity_pricelist_id')
|
'res.config.settings', 'parity_pricelist_id')
|
||||||
if pricelist_id:
|
if pricelist_id:
|
||||||
pricelist_id = int(pricelist_id)
|
pricelist_id = int(pricelist_id)
|
||||||
date_start = date_utils.get_datetime(dfrom, hours=False) \
|
date_start = fields.Date.from_string(dfrom) - timedelta(days=1)
|
||||||
- timedelta(days=1)
|
date_end = fields.Date.from_string(dto)
|
||||||
date_diff = date_utils.date_diff(date_start, dto, hours=False) + 1
|
date_diff = abs((date_end - date_start).days) + 1
|
||||||
# Get Prices
|
# Get Prices
|
||||||
json_rooms_prices = {pricelist_id: []}
|
json_rooms_prices = {pricelist_id: []}
|
||||||
room_typed_ids = self.env['hotel.room.type'].search(
|
room_typed_ids = self.env['hotel.room.type'].search(
|
||||||
@@ -162,9 +160,9 @@ class HotelReservation(models.Model):
|
|||||||
'res.config.settings', 'parity_restrictions_id')
|
'res.config.settings', 'parity_restrictions_id')
|
||||||
if restriction_id:
|
if restriction_id:
|
||||||
restriction_id = int(restriction_id)
|
restriction_id = int(restriction_id)
|
||||||
date_start = date_utils.get_datetime(dfrom, hours=False) \
|
date_start = fields.Date.from_string(dfrom) - timedelta(days=1)
|
||||||
- timedelta(days=1)
|
date_end = fields.Date.from_string(dto)
|
||||||
date_diff = date_utils.date_diff(dfrom, dto, hours=False) + 1
|
date_diff = abs((date_end - date_sart).days) + 1
|
||||||
# Get Prices
|
# Get Prices
|
||||||
json_rooms_rests = {}
|
json_rooms_rests = {}
|
||||||
room_types = self.env['hotel.room.type'].search(
|
room_types = self.env['hotel.room.type'].search(
|
||||||
@@ -202,8 +200,7 @@ class HotelReservation(models.Model):
|
|||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def get_hcalendar_events_data(self, dfrom, dto):
|
def get_hcalendar_events_data(self, dfrom, dto):
|
||||||
date_start = date_utils.get_datetime(dfrom, hours=False) \
|
date_start = fields.Date.from_string(dfrom) - timedelta(days=1)
|
||||||
- timedelta(days=1)
|
|
||||||
date_start_str = date_start.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
date_start_str = date_start.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
user_id = self.env['res.users'].browse(self.env.uid)
|
user_id = self.env['res.users'].browse(self.env.uid)
|
||||||
domain = []
|
domain = []
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
from odoo import models, fields, api
|
from odoo import models, fields, api
|
||||||
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||||
from odoo.addons.hotel import date_utils
|
|
||||||
|
|
||||||
|
|
||||||
class IrDefault(models.Model):
|
class IrDefault(models.Model):
|
||||||
@@ -26,8 +25,7 @@ class IrDefault(models.Model):
|
|||||||
fixed_price = pitem.fixed_price
|
fixed_price = pitem.fixed_price
|
||||||
room_type = room_type_obj.search([
|
room_type = room_type_obj.search([
|
||||||
('product_id.product_tmpl_id', '=', product_tmpl_id),
|
('product_id.product_tmpl_id', '=', product_tmpl_id),
|
||||||
('date_start', '>=', date_utils.now().strftime(
|
('date_start', '>=', fields.Date.today())
|
||||||
DEFAULT_SERVER_DATETIME_FORMAT))
|
|
||||||
], limit=1)
|
], limit=1)
|
||||||
room_pr_cached_obj.create({
|
room_pr_cached_obj.create({
|
||||||
'room_type_id': room_type.id,
|
'room_type_id': room_type.id,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
from odoo import models, fields, api
|
from odoo import models, fields, api
|
||||||
from odoo.addons.hotel import date_utils
|
|
||||||
|
|
||||||
|
|
||||||
class HotelConfiguration(models.TransientModel):
|
class HotelConfiguration(models.TransientModel):
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ var AbstractModel = require('web.AbstractModel'),
|
|||||||
return AbstractModel.extend({
|
return AbstractModel.extend({
|
||||||
init: function () {
|
init: function () {
|
||||||
this._super.apply(this, arguments);
|
this._super.apply(this, arguments);
|
||||||
this.end_date = null;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
load: function (params) {
|
load: function (params) {
|
||||||
|
|||||||
@@ -3,13 +3,12 @@
|
|||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
import time
|
import time
|
||||||
import logging
|
import logging
|
||||||
from datetime import timedelta
|
from datetime import datetime, timedelta
|
||||||
from openerp.exceptions import ValidationError
|
from openerp.exceptions import ValidationError
|
||||||
from openerp.tools import (
|
from openerp.tools import (
|
||||||
DEFAULT_SERVER_DATE_FORMAT,
|
DEFAULT_SERVER_DATE_FORMAT,
|
||||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
from openerp import models, fields, api, _
|
from openerp import models, fields, api, _
|
||||||
from odoo.addons.hotel import date_utils
|
|
||||||
import odoo.addons.decimal_precision as dp
|
import odoo.addons.decimal_precision as dp
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -25,46 +24,24 @@ class FolioWizard(models.TransientModel):
|
|||||||
@api.model
|
@api.model
|
||||||
def _get_default_checkin(self):
|
def _get_default_checkin(self):
|
||||||
folio = False
|
folio = False
|
||||||
default_arrival_hour = self.env['ir.default'].sudo().get(
|
|
||||||
'res.config.settings', 'default_arrival_hour')
|
|
||||||
if 'folio_id' in self._context:
|
if 'folio_id' in self._context:
|
||||||
folio = self.env['hotel.folio'].search([
|
folio = self.env['hotel.folio'].search([
|
||||||
('id', '=', self._context['folio_id'])
|
('id', '=', self._context['folio_id'])
|
||||||
])
|
])
|
||||||
if folio and folio.room_lines:
|
if folio and folio.room_lines:
|
||||||
return folio.room_lines[0].checkin
|
return folio.room_lines[0].checkin
|
||||||
else:
|
return fields.Date.today()
|
||||||
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)
|
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _get_default_checkout(self):
|
def _get_default_checkout(self):
|
||||||
folio = False
|
folio = False
|
||||||
default_departure_hour = self.env['ir.default'].sudo().get(
|
|
||||||
'res.config.settings', 'default_departure_hour')
|
|
||||||
if 'folio_id' in self._context:
|
if 'folio_id' in self._context:
|
||||||
folio = self.env['hotel.folio'].search([
|
folio = self.env['hotel.folio'].search([
|
||||||
('id', '=', self._context['folio_id'])
|
('id', '=', self._context['folio_id'])
|
||||||
])
|
])
|
||||||
if folio and folio.room_lines:
|
if folio and folio.room_lines:
|
||||||
return folio.room_lines[0].checkout
|
return folio.room_lines[0].checkout
|
||||||
else:
|
return fields.Date.today()
|
||||||
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)
|
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _get_default_channel_type(self):
|
def _get_default_channel_type(self):
|
||||||
@@ -109,10 +86,9 @@ class FolioWizard(models.TransientModel):
|
|||||||
if line.rooms_num > line.max_rooms:
|
if line.rooms_num > line.max_rooms:
|
||||||
raise ValidationError(_("Too many rooms!"))
|
raise ValidationError(_("Too many rooms!"))
|
||||||
elif line.room_type_id:
|
elif line.room_type_id:
|
||||||
checkout_dt = date_utils.get_datetime(line.checkout)
|
|
||||||
occupied = self.env['hotel.reservation'].occupied(
|
occupied = self.env['hotel.reservation'].occupied(
|
||||||
line.checkin,
|
line.checkin,
|
||||||
checkout_dt.strftime(DEFAULT_SERVER_DATE_FORMAT))
|
line.checkout)
|
||||||
rooms_occupied = occupied.mapped('product_id.id')
|
rooms_occupied = occupied.mapped('product_id.id')
|
||||||
free_rooms = self.env['hotel.room'].search([
|
free_rooms = self.env['hotel.room'].search([
|
||||||
('product_id.id', 'not in', rooms_occupied),
|
('product_id.id', 'not in', rooms_occupied),
|
||||||
@@ -122,15 +98,9 @@ class FolioWizard(models.TransientModel):
|
|||||||
product_list = self.env['product.product'].search([
|
product_list = self.env['product.product'].search([
|
||||||
('id', 'in', room_ids)
|
('id', 'in', room_ids)
|
||||||
])
|
])
|
||||||
nights = date_utils.date_diff(line.checkin,
|
checkin_dt = fields.Date.from_string(line.checkin)
|
||||||
line.checkout,
|
checkout_dt = fields.Date.from_string(line.checkout)
|
||||||
hours=False)
|
nights = abs((checkout_dt - checkin_dt).days)
|
||||||
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)
|
|
||||||
for room in product_list:
|
for room in product_list:
|
||||||
pricelist_id = self.env['ir.default'].sudo().get(
|
pricelist_id = self.env['ir.default'].sudo().get(
|
||||||
'res.config.settings', 'parity_pricelist_id')
|
'res.config.settings', 'parity_pricelist_id')
|
||||||
@@ -138,7 +108,7 @@ class FolioWizard(models.TransientModel):
|
|||||||
pricelist_id = int(pricelist_id)
|
pricelist_id = int(pricelist_id)
|
||||||
res_price = 0
|
res_price = 0
|
||||||
for i in range(0, nights):
|
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)
|
ndate_str = ndate.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||||
prod = line.room_type_id.product_id.with_context(
|
prod = line.room_type_id.product_id.with_context(
|
||||||
lang=self.partner_id.lang,
|
lang=self.partner_id.lang,
|
||||||
@@ -178,44 +148,30 @@ class FolioWizard(models.TransientModel):
|
|||||||
@param self: object pointer
|
@param self: object pointer
|
||||||
'''
|
'''
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
if not self.checkin:
|
checkin_dt = datetime.now() if not self.checkin else fields.Date.from_string(self.checkin)
|
||||||
self.checkin = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
checkout_dt = datetime.now() if not self.checkout else fields.Date.from_string(self.checkout)
|
||||||
if not self.checkout:
|
if checkin_dt >= checkout_dt:
|
||||||
self.checkout = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
checkout_dt = checkin_dt + timedelta(days=1)
|
||||||
|
|
||||||
# UTC -> Hotel tz
|
chekin_str = checkin_dt.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||||
tz = self.env['ir.default'].sudo().get('res.config.settings',
|
chekout_str = checkout_dt.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||||
'tz_hotel')
|
|
||||||
chkin_utc_dt = date_utils.get_datetime(self.checkin)
|
|
||||||
chkout_utc_dt = date_utils.get_datetime(self.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')
|
|
||||||
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_type_ids = self.env['hotel.room.type'].search([])
|
||||||
room_types = []
|
cmds = room_type_ids.mapped(lambda x: (0, False, {
|
||||||
|
'room_type_id': x.id,
|
||||||
for room_type in room_type_ids:
|
'checkin': chekin_str,
|
||||||
room_types.append((0, False, {
|
'checkout': chekout_str,
|
||||||
'room_type_id': room_type.id,
|
'folio_wizard_id': self.id,
|
||||||
'checkin': self.checkin,
|
}))
|
||||||
'checkout': self.checkout,
|
self.write({
|
||||||
'folio_wizard_id': self.id,
|
'checkin': chekin_str,
|
||||||
}))
|
'checkout': chekout_str,
|
||||||
self.room_type_wizard_ids = room_types
|
'room_type_wizard_ids': cmds,
|
||||||
|
})
|
||||||
for room_type in self.room_type_wizard_ids:
|
for room_type in self.room_type_wizard_ids:
|
||||||
room_type.update_price()
|
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):
|
def _computed_total(self):
|
||||||
total = 0
|
total = 0
|
||||||
for line in self.service_wizard_ids:
|
for line in self.service_wizard_ids:
|
||||||
@@ -305,24 +261,25 @@ class HotelRoomTypeWizards(models.TransientModel):
|
|||||||
default=_get_default_checkout)
|
default=_get_default_checkout)
|
||||||
can_confirm = fields.Boolean(compute="_can_confirm")
|
can_confirm = fields.Boolean(compute="_can_confirm")
|
||||||
|
|
||||||
|
@api.multi
|
||||||
def _can_confirm(self):
|
def _can_confirm(self):
|
||||||
for room_type in self:
|
for record in self:
|
||||||
date_start = date_utils.get_datetime(room_type.checkin)
|
date_start = fields.Date.from_string(record.checkin)
|
||||||
date_end = date_utils.get_datetime(room_type.checkout)
|
date_end = fields.Date.from_string(record.checkout)
|
||||||
date_diff = date_utils.date_diff(date_start, date_end, hours=False)
|
date_diff = abs((date_end - date_start).days)
|
||||||
room_type.can_confirm = room_type.max_rooms > 0 and room_type.min_stay <= date_diff
|
record.can_confirm = record.max_rooms > 0 and record.min_stay <= date_diff
|
||||||
|
|
||||||
def _compute_max(self):
|
def _compute_max(self):
|
||||||
for res in self:
|
for res in self:
|
||||||
user = self.env['res.users'].browse(self.env.uid)
|
user = self.env['res.users'].browse(self.env.uid)
|
||||||
date_start = date_utils.get_datetime(res.checkin)
|
date_start = fields.Date.from_string(res.checkin)
|
||||||
date_end = date_utils.get_datetime(res.checkout)
|
date_end = fields.Date.from_string(res.checkout)
|
||||||
date_diff = date_utils.date_diff(date_start, date_end, hours=False)
|
date_diff = abs((date_end - date_start).days)
|
||||||
minstay_restrictions = self.env['hotel.room.type.restriction.item'].search([
|
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([
|
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(
|
real_max = len(res.room_type_id.check_availability_room(
|
||||||
res.checkin,
|
res.checkin,
|
||||||
@@ -361,32 +318,17 @@ class HotelRoomTypeWizards(models.TransientModel):
|
|||||||
@api.onchange('rooms_num', 'discount', 'price', 'room_type_id', 'checkin', 'checkout')
|
@api.onchange('rooms_num', 'discount', 'price', 'room_type_id', 'checkin', 'checkout')
|
||||||
def update_price(self):
|
def update_price(self):
|
||||||
for record in 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:
|
if record.rooms_num > record.max_rooms:
|
||||||
raise ValidationError(_("There are not enough 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:
|
if chkin_utc_dt >= chkout_utc_dt:
|
||||||
dpt_hour = self.env['ir.default'].sudo().get(
|
chkout_utc_dt = chkin_utc_dt + timedelta(days=1)
|
||||||
'res.config.settings', 'default_departure_hour')
|
chkout_utc_dt -= timedelta(days=1)
|
||||||
checkout_str = (chkin_utc_dt + timedelta(days=1)).strftime(
|
nights = abs((chkout_utc_dt - chkin_utc_dt).days)
|
||||||
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)
|
|
||||||
|
|
||||||
pricelist_id = self.env['ir.default'].sudo().get(
|
pricelist_id = self.env['ir.default'].sudo().get(
|
||||||
'res.config.settings', 'parity_pricelist_id')
|
'res.config.settings', 'parity_pricelist_id')
|
||||||
@@ -395,7 +337,7 @@ class HotelRoomTypeWizards(models.TransientModel):
|
|||||||
|
|
||||||
res_price = 0
|
res_price = 0
|
||||||
for i in range(0, nights):
|
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)
|
ndate_str = ndate.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||||
prod = record.room_type_id.product_id.with_context(
|
prod = record.room_type_id.product_id.with_context(
|
||||||
lang=record.folio_wizard_id.partner_id.lang,
|
lang=record.folio_wizard_id.partner_id.lang,
|
||||||
@@ -460,7 +402,7 @@ class ReservationWizard(models.TransientModel):
|
|||||||
if line.adults == 0:
|
if line.adults == 0:
|
||||||
line.adults = room.capacity
|
line.adults = room.capacity
|
||||||
line.room_type_id = room.price_room_type.id
|
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)
|
checkout_dt -= timedelta(days=1)
|
||||||
occupied = self.env['hotel.reservation'].occupied(
|
occupied = self.env['hotel.reservation'].occupied(
|
||||||
line.checkin,
|
line.checkin,
|
||||||
@@ -479,23 +421,18 @@ class ReservationWizard(models.TransientModel):
|
|||||||
if not self.checkout:
|
if not self.checkout:
|
||||||
self.checkout = self.folio_wizard_id.checkout
|
self.checkout = self.folio_wizard_id.checkout
|
||||||
|
|
||||||
hotel_tz = self.env['ir.default'].sudo().get(
|
start_date_utc_dt = fields.Date.from_string(line.checkin)
|
||||||
'res.config.settings', 'hotel_tz')
|
end_date_utc_dt = fields.Date.from_string(line.checkout)
|
||||||
start_date_utc_dt = date_utils.get_datetime(line.checkin)
|
|
||||||
start_date_dt = date_utils.dt_as_timezone(start_date_utc_dt,
|
|
||||||
hotel_tz)
|
|
||||||
|
|
||||||
if line.room_type_id:
|
if line.room_type_id:
|
||||||
pricelist_id = self.env['ir.default'].sudo().get(
|
pricelist_id = self.env['ir.default'].sudo().get(
|
||||||
'res.config.settings', 'parity_pricelist_id')
|
'res.config.settings', 'parity_pricelist_id')
|
||||||
if pricelist_id:
|
if pricelist_id:
|
||||||
pricelist_id = int(pricelist_id)
|
pricelist_id = int(pricelist_id)
|
||||||
nights = date_utils.date_diff(line.checkin,
|
nights = abs((end_date_utc_dt - start_date_utc_dt).days)
|
||||||
line.checkout,
|
|
||||||
hours=False)
|
|
||||||
res_price = 0
|
res_price = 0
|
||||||
for i in range(0, nights):
|
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)
|
ndate_str = ndate.strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||||
prod = line.room_type_id.product_id.with_context(
|
prod = line.room_type_id.product_id.with_context(
|
||||||
lang=self.partner_id.lang,
|
lang=self.partner_id.lang,
|
||||||
@@ -508,11 +445,10 @@ class ReservationWizard(models.TransientModel):
|
|||||||
res_price = res_price - (res_price * self.discount) * 0.01
|
res_price = res_price - (res_price * self.discount) * 0.01
|
||||||
line.amount_reservation = res_price
|
line.amount_reservation = res_price
|
||||||
line.price = res_price
|
line.price = res_price
|
||||||
checkout_dt = date_utils.get_datetime(self.checkout)
|
end_date_utc_dt -= timedelta(days=1)
|
||||||
checkout_dt -= timedelta(days=1)
|
|
||||||
occupied = self.env['hotel.reservation'].occupied(
|
occupied = self.env['hotel.reservation'].occupied(
|
||||||
self.checkin,
|
line.checkin,
|
||||||
checkout_dt.strftime(DEFAULT_SERVER_DATE_FORMAT))
|
end_date_utc_dt.strftime(DEFAULT_SERVER_DATE_FORMAT))
|
||||||
rooms_occupied = occupied.mapped('product_id.id')
|
rooms_occupied = occupied.mapped('product_id.id')
|
||||||
domain_rooms = [
|
domain_rooms = [
|
||||||
('isroom', '=', True),
|
('isroom', '=', True),
|
||||||
|
|||||||
@@ -39,6 +39,8 @@
|
|||||||
'views/channel_hotel_room_type_availability_views.xml',
|
'views/channel_hotel_room_type_availability_views.xml',
|
||||||
'views/channel_hotel_room_type_restriction_views.xml',
|
'views/channel_hotel_room_type_restriction_views.xml',
|
||||||
'views/channel_product_pricelist_views.xml',
|
'views/channel_product_pricelist_views.xml',
|
||||||
|
'views/channel_connector_backend_views.xml',
|
||||||
|
'views/channel_connector_menu.xml',
|
||||||
'data/menus.xml',
|
'data/menus.xml',
|
||||||
'data/sequences.xml',
|
'data/sequences.xml',
|
||||||
#'security/ir.model.access.csv',
|
#'security/ir.model.access.csv',
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# 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.component.core import AbstractComponent
|
||||||
from odoo.addons.queue_job.exception import RetryableJobError
|
from odoo.addons.queue_job.exception import RetryableJobError
|
||||||
from odoo.tools import (
|
from odoo.tools import (
|
||||||
@@ -50,6 +52,14 @@ class WuBookServer(object):
|
|||||||
self._token = None
|
self._token = None
|
||||||
self._login_data = login_data
|
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
|
@property
|
||||||
def server(self):
|
def server(self):
|
||||||
if self._server is None and self._login_data.is_valid():
|
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']
|
_inherit = ['base.backend.adapter', 'base.hotel.channel.connector']
|
||||||
_usage = 'backend.adapter'
|
_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):
|
def create_room(self, shortcode, name, capacity, price, availability):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,20 @@
|
|||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
import logging
|
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 (
|
from odoo.tools import (
|
||||||
DEFAULT_SERVER_DATE_FORMAT,
|
DEFAULT_SERVER_DATE_FORMAT,
|
||||||
DEFAULT_SERVER_DATETIME_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
|
from odoo import api
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -28,8 +37,8 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
'avail': day_vals.get('avail', 0),
|
'avail': day_vals.get('avail', 0),
|
||||||
'wpushed': True,
|
'wpushed': True,
|
||||||
}
|
}
|
||||||
if set_wmax_avail:
|
if set_max_avail:
|
||||||
vals.update({'wmax_avail': day_vals.get('avail', 0)})
|
vals.update({'max_avail': day_vals.get('avail', 0)})
|
||||||
if room_type_avail:
|
if room_type_avail:
|
||||||
room_type_avail.with_context({
|
room_type_avail.with_context({
|
||||||
'wubook_action': False,
|
'wubook_action': False,
|
||||||
@@ -723,35 +732,6 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
return False
|
return False
|
||||||
return True
|
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
|
@api.model
|
||||||
def fetch_booking(self, channel_reservation_id):
|
def fetch_booking(self, channel_reservation_id):
|
||||||
try:
|
try:
|
||||||
@@ -770,7 +750,7 @@ class HotelChannelConnectorImporter(AbstractComponent):
|
|||||||
self.create_channel_connector_issue(
|
self.create_channel_connector_issue(
|
||||||
'reservation',
|
'reservation',
|
||||||
_("Can't process reservations from wubook"),
|
_("Can't process reservations from wubook"),
|
||||||
results, wid=wrid)
|
results, channel_object_id=channel_reservation_id)
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from odoo import models, api, fields
|
from odoo import models, api, fields
|
||||||
from ...components.backend_adapter import WuBookLogin, WuBookAdapter
|
from ...components.backend_adapter import WuBookLogin, WuBookServer
|
||||||
|
|
||||||
class ChannelBackend(models.Model):
|
class ChannelBackend(models.Model):
|
||||||
_name = 'channel.backend'
|
_name = 'channel.backend'
|
||||||
@@ -19,8 +19,8 @@ class ChannelBackend(models.Model):
|
|||||||
"""
|
"""
|
||||||
return [('1.2', '1.2+')]
|
return [('1.2', '1.2+')]
|
||||||
|
|
||||||
|
name = fields.Char('Name')
|
||||||
version = fields.Selection(selection='select_versions', required=True)
|
version = fields.Selection(selection='select_versions', required=True)
|
||||||
|
|
||||||
username = fields.Char('Channel Service Username')
|
username = fields.Char('Channel Service Username')
|
||||||
passwd = fields.Char('Channel Service Password')
|
passwd = fields.Char('Channel Service Password')
|
||||||
lcode = fields.Char('Channel Service lcode')
|
lcode = fields.Char('Channel Service lcode')
|
||||||
@@ -28,21 +28,25 @@ class ChannelBackend(models.Model):
|
|||||||
default='https://wired.wubook.net/xrws/')
|
default='https://wired.wubook.net/xrws/')
|
||||||
pkey = fields.Char('Channel Service PKey')
|
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
|
@contextmanager
|
||||||
@api.multi
|
@api.multi
|
||||||
def work_on(self, model_name, **kwargs):
|
def work_on(self, model_name, **kwargs):
|
||||||
self.ensure_one()
|
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(
|
wubook_login = WuBookLogin(
|
||||||
self.server,
|
self.server,
|
||||||
self.username,
|
self.username,
|
||||||
self.passwd,
|
self.passwd,
|
||||||
self.lcode,
|
self.lcode,
|
||||||
self.pkey)
|
self.pkey)
|
||||||
with WuBookAdapter(wubook_login) as channel_api:
|
with WuBookServer(wubook_login) as channel_api:
|
||||||
_super = super(ChannelBackend, self)
|
_super = super(ChannelBackend, self)
|
||||||
# from the components we'll be able to do: self.work.magento_api
|
# from the components we'll be able to do: self.work.channel_api
|
||||||
with _super.work_on(model_name, **kwargs) as work:
|
with _super.work_on(model_name, channel_api=channel_api, **kwargs) as work:
|
||||||
yield work
|
yield work
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
# Copyright 2018 Alexandre Díaz <dev@redneboa.es>
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# 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):
|
class ChannelBinding(models.AbstractModel):
|
||||||
|
|||||||
@@ -2,3 +2,4 @@
|
|||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
|
|
||||||
from . import common
|
from . import common
|
||||||
|
from . import importer
|
||||||
|
|||||||
@@ -49,6 +49,13 @@ class ChannelHotelReservation(models.Model):
|
|||||||
wstatus_reason = fields.Char("WuBook Status Reason", readonly=True)
|
wstatus_reason = fields.Char("WuBook Status Reason", readonly=True)
|
||||||
wmodified = fields.Boolean("WuBook Modified", readonly=True, default=False)
|
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')
|
@api.depends('channel_reservation_id', 'ota_id')
|
||||||
def _is_from_ota(self):
|
def _is_from_ota(self):
|
||||||
for record in 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')
|
@api.depends('room_lines')
|
||||||
def _has_channel_reservations(self):
|
def _has_channel_reservations(self):
|
||||||
for record in 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)
|
record.has_channel_reservations = any(channel_reservations)
|
||||||
|
|
||||||
wseed = fields.Char("Wubook Session Seed", readonly=True)
|
wseed = fields.Char("Wubook Session Seed", readonly=True)
|
||||||
@@ -22,9 +22,8 @@ class HotelFolio(models.Model):
|
|||||||
old_name='whas_wubook_reservations')
|
old_name='whas_wubook_reservations')
|
||||||
|
|
||||||
@job(default_channel='root.channel')
|
@job(default_channel='root.channel')
|
||||||
@api.multi
|
@api.model
|
||||||
def import_reservations(self):
|
def import_reservations(self):
|
||||||
self.ensure_one()
|
|
||||||
with self.backend_id.work_on(self._name) as work:
|
with self.backend_id.work_on(self._name) as work:
|
||||||
importer = work.component(usage='channel.importer')
|
importer = work.component(usage='channel.importer')
|
||||||
importer.fetch_new_bookings()
|
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 -->
|
<!-- Backend stuff -->
|
||||||
<template id="assets_backend" inherit_id="web.assets_backend">
|
<template id="assets_backend" inherit_id="web.assets_backend">
|
||||||
<xpath expr="." position="inside">
|
<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>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user