mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
[WIP][MIG][11.0] Hotel module review
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2018 Alexandre Díaz
|
||||
# Copyright 2018 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from . import currency_exchange
|
||||
@@ -21,11 +21,11 @@ from . import inherit_product_product
|
||||
from . import inherit_res_company
|
||||
# from . import virtual_room
|
||||
from . import inherit_account_payment
|
||||
from . import hotel_virtual_room_restriction
|
||||
from . import hotel_virtual_room_restriction_item
|
||||
from . import hotel_room_type_restriction
|
||||
from . import hotel_room_type_restriction_item
|
||||
from . import hotel_reservation_line
|
||||
from . import cardex
|
||||
from . import hotel_virtual_room_availability
|
||||
from . import hotel_room_type_availability
|
||||
from . import inherit_product_pricelist
|
||||
from . import res_config
|
||||
from . import inherit_res_partner
|
||||
|
||||
@@ -1,25 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Dario Lodeiros <>
|
||||
#
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# Copyright 2018 Alexandre Díaz
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
import datetime
|
||||
from openerp import models, fields, api, _
|
||||
from openerp.exceptions import except_orm, ValidationError
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2018 Dario Lodeiros
|
||||
# Copyright 2018 Alexandre Díaz
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from decimal import Decimal
|
||||
import time
|
||||
# For Python 3.0 and later
|
||||
from urllib.request import urlopen
|
||||
from openerp import models, fields, api, _
|
||||
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||
|
||||
|
||||
class CurrencyExchangeRate(models.Model):
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2018 Alexandre Díaz
|
||||
# Copyright 2018 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
import json
|
||||
from datetime import datetime, timedelta
|
||||
@@ -11,17 +10,19 @@ from odoo.tools.misc import formatLang
|
||||
class HotelDashboard(models.Model):
|
||||
_name = "hotel.dashboard"
|
||||
|
||||
# FIXME
|
||||
def _get_count(self):
|
||||
resevations_count = self.env['hotel.reservation'].search(
|
||||
resevations_count = self.env['hotel.reservation'].search_count(
|
||||
[('sate', '=', 'confirm')])
|
||||
folios_count = self.env['hotel.folio'].search(
|
||||
folios_count = self.env['hotel.folio'].search_count(
|
||||
[('sate', '=', 'sales_order')])
|
||||
next_arrivals_count = self.env['hotel.reservation'].search(
|
||||
next_arrivals_count = self.env['hotel.reservation'].search_count(
|
||||
[('is_checkin', '=', True)])
|
||||
|
||||
self.orders_count = len(orders_count)
|
||||
self.quotations_count = len(quotations_count)
|
||||
self.orders_done_count = len(orders_done_count)
|
||||
|
||||
@api.one
|
||||
def _kanban_dashboard(self):
|
||||
if self.graph_type == 'bar':
|
||||
@@ -40,25 +41,33 @@ class HotelDashboard(models.Model):
|
||||
color = fields.Integer(string='Color Index')
|
||||
name = fields.Char(string="Name")
|
||||
type = fields.Char(default="sale")
|
||||
graph_type = fields.Selection([('line','Line'),('bar','Bar'),('none','None')])
|
||||
reservations_count = fields.Integer(compute = '_get_count')
|
||||
folios_count = fields.Integer(compute= '_get_count')
|
||||
next_arrivals_count = fields.Integer(compute= '_get_count')
|
||||
graph_type = fields.Selection([
|
||||
('line', 'Line'),
|
||||
('bar', 'Bar'),
|
||||
('none', 'None')])
|
||||
reservations_count = fields.Integer(compute='_get_count')
|
||||
folios_count = fields.Integer(compute='_get_count')
|
||||
next_arrivals_count = fields.Integer(compute='_get_count')
|
||||
kanban_dashboard = fields.Text(compute='_kanban_dashboard')
|
||||
kanban_dashboard_graph = fields.Text(compute='_kanban_dashboard_graph')
|
||||
show_on_dashboard = fields.Boolean(string='Show journal on dashboard', help="Whether this journal should be displayed on the dashboard or not", default=True)
|
||||
show_on_dashboard = fields.Boolean(
|
||||
string='Show journal on dashboard',
|
||||
help="Whether this journal should be displayed on the dashboard or not",
|
||||
default=True)
|
||||
|
||||
@api.multi
|
||||
def get_bar_graph_datas(self):
|
||||
data = []
|
||||
today = datetime.strptime(fields.Date.context_today(self), DF)
|
||||
day_of_week = int(format_datetime(today, 'e', locale=self._context.get('lang') or 'en_US'))
|
||||
for i in range(0,15):
|
||||
if i==0:
|
||||
for i in range(0, 15):
|
||||
if i == 0:
|
||||
label = _('Today')
|
||||
else:
|
||||
label = format_date(today + timedelta(days=i) , 'd', locale=self._context.get('lang') or 'en_US')
|
||||
data.append({'label':label,'value':0.0, 'type': 'past' if i<0 else 'future'})
|
||||
label = format_date(today + timedelta(days=i),
|
||||
'd',
|
||||
locale=self._context.get('lang') or 'en_US')
|
||||
data.append({'label':label, 'value':0.0, 'type': 'past' if i < 0 else 'future'})
|
||||
# Build SQL query to find amount aggregated by week
|
||||
select_sql_clause = """SELECT count(id) as total from hotel_reservation where state != 'cancelled'"""
|
||||
query = "("+select_sql_clause+" and date(checkin) = '"+today.strftime(DF)+"')"
|
||||
@@ -68,8 +77,8 @@ class HotelDashboard(models.Model):
|
||||
|
||||
self.env.cr.execute(query)
|
||||
query_results = self.env.cr.dictfetchall()
|
||||
for index in range(0, len(query_results)):
|
||||
data[index]['value'] = query_results[index].get('total')
|
||||
for index_k, index_v in enumerate(query_results):
|
||||
data[index_k]['value'] = index_v.get('total')
|
||||
return [{'values': data}]
|
||||
|
||||
@api.multi
|
||||
|
||||
@@ -1,30 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Dario Lodeiros <>
|
||||
#
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from openerp import models, fields, api, _
|
||||
|
||||
|
||||
class HotelFloor(models.Model):
|
||||
|
||||
_name = "hotel.floor"
|
||||
_description = "Ubication"
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017-2018 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
import datetime
|
||||
from datetime import datetime
|
||||
import time
|
||||
import pytz
|
||||
import logging
|
||||
@@ -78,9 +77,9 @@ class HotelFolio(models.Model):
|
||||
help="Hotel room reservation detail.",)
|
||||
|
||||
service_line_ids = fields.One2many('hotel.service', 'folio_id',
|
||||
readonly=False,
|
||||
states={'done': [('readonly', True)]},
|
||||
help="Hotel services detail provide to "
|
||||
readonly=False,
|
||||
states={'done': [('readonly', True)]},
|
||||
help="Hotel services detail provide to "
|
||||
"customer and it will include in "
|
||||
"main Invoice.")
|
||||
hotel_invoice_id = fields.Many2one('account.invoice', 'Invoice')
|
||||
@@ -98,23 +97,21 @@ class HotelFolio(models.Model):
|
||||
'sent': [('readonly', False)]},
|
||||
help="Pricelist for current folio.")
|
||||
pending_amount = fields.Monetary(compute='compute_amount',
|
||||
store=True,
|
||||
string="Pending in Folio")
|
||||
store=True,
|
||||
string="Pending in Folio")
|
||||
refund_amount = fields.Monetary(compute='compute_amount',
|
||||
store=True,
|
||||
string="Payment Returns")
|
||||
invoices_paid = fields.Monetary(compute='compute_amount',
|
||||
store=True, track_visibility='onchange',
|
||||
string="Payments")
|
||||
store=True, track_visibility='onchange',
|
||||
string="Payments")
|
||||
|
||||
booking_pending = fields.Integer('Booking pending',
|
||||
compute='_compute_cardex_count')
|
||||
cardex_count = fields.Integer('Cardex counter',
|
||||
compute='_compute_cardex_count')
|
||||
cardex_pending = fields.Boolean('Cardex Pending',
|
||||
compute='_compute_cardex_count')
|
||||
cardex_pending_num = fields.Integer('Cardex Pending',
|
||||
compute='_compute_cardex_count')
|
||||
cardex_pending_count = fields.Integer('Cardex Pending',
|
||||
compute='_compute_cardex_count')
|
||||
checkins_reservations = fields.Integer('checkins reservations')
|
||||
checkouts_reservations = fields.Integer('checkouts reservations')
|
||||
partner_internal_comment = fields.Text(string='Internal Partner Notes',
|
||||
@@ -173,12 +170,11 @@ class HotelFolio(models.Model):
|
||||
sequence = fields.Integer(string='Sequence', default=10)
|
||||
# sale.order
|
||||
amount_total = fields.Float(string='Total', store=True, readonly=True,
|
||||
track_visibility='always')
|
||||
track_visibility='always')
|
||||
|
||||
def _computed_rooms_char(self):
|
||||
for record in self:
|
||||
rooms = ', '.join(record.mapped('room_lines.room_id.name'))
|
||||
record.rooms_char = rooms
|
||||
record.rooms_char = ', '.join(record.mapped('room_lines.room_id.name'))
|
||||
|
||||
@api.multi
|
||||
def _compute_num_invoices(self):
|
||||
@@ -219,9 +215,8 @@ class HotelFolio(models.Model):
|
||||
def action_payments(self):
|
||||
self.ensure_one()
|
||||
payments_obj = self.env['account.payment']
|
||||
payments = payments_obj.search([('folio_id','=',self.id)])
|
||||
payment_ids = payments.mapped('id')
|
||||
invoices = self.mapped('invoice_ids.id')
|
||||
payments = payments_obj.search([('folio_id', '=', self.id)])
|
||||
#invoices = self.mapped('invoice_ids.id')
|
||||
return{
|
||||
'name': _('Payments'),
|
||||
'view_type': 'form',
|
||||
@@ -229,7 +224,7 @@ class HotelFolio(models.Model):
|
||||
'res_model': 'account.payment',
|
||||
'target': 'new',
|
||||
'type': 'ir.actions.act_window',
|
||||
'domain': [('id', 'in', payment_ids)],
|
||||
'domain': [('id', 'in', payments.ids)],
|
||||
}
|
||||
|
||||
@api.multi
|
||||
@@ -251,16 +246,16 @@ class HotelFolio(models.Model):
|
||||
return_move_ids = []
|
||||
acc_pay_obj = self.env['account.payment']
|
||||
payments = acc_pay_obj.search([
|
||||
'|',
|
||||
('invoice_ids', 'in', self.invoice_ids.ids),
|
||||
('folio_id', '=', self.id)
|
||||
])
|
||||
'|',
|
||||
('invoice_ids', 'in', self.invoice_ids.ids),
|
||||
('folio_id', '=', self.id)
|
||||
])
|
||||
return_move_ids += self.invoice_ids.filtered(
|
||||
lambda invoice: invoice.type == 'out_refund').mapped(
|
||||
'payment_move_line_ids.move_id.id')
|
||||
return_lines = self.env['payment.return.line'].search([(
|
||||
'move_line_ids','in',payments.mapped(
|
||||
'move_line_ids.id'))])
|
||||
'payment_move_line_ids.move_id.id')
|
||||
return_lines = self.env['payment.return.line'].search([
|
||||
('move_line_ids', 'in', payments.mapped('move_line_ids.id')),
|
||||
])
|
||||
return_move_ids += return_lines.mapped('return_id.move_id.id')
|
||||
|
||||
return{
|
||||
@@ -323,19 +318,24 @@ class HotelFolio(models.Model):
|
||||
# }
|
||||
|
||||
@api.model
|
||||
def create(self, vals, check=True):
|
||||
def create(self, vals):
|
||||
if vals.get('name', _('New')) == _('New'):
|
||||
if 'company_id' in vals:
|
||||
vals['name'] = self.env['ir.sequence'].with_context(force_company=vals['company_id']).next_by_code('sale.order') or _('New')
|
||||
vals['name'] = self.env['ir.sequence'].with_context(
|
||||
force_company=vals['company_id']
|
||||
).next_by_code('sale.order') or _('New')
|
||||
else:
|
||||
vals['name'] = self.env['ir.sequence'].next_by_code('hotel.folio') or _('New')
|
||||
|
||||
# Makes sure partner_invoice_id' and 'pricelist_id' are defined
|
||||
if any(f not in vals for f in ['partner_invoice_id', 'partner_shipping_id', 'pricelist_id']):
|
||||
lfields = ('partner_invoice_id', 'partner_shipping_id', 'pricelist_id')
|
||||
if any(f not in vals for f in lfields):
|
||||
partner = self.env['res.partner'].browse(vals.get('partner_id'))
|
||||
addr = partner.address_get(['delivery', 'invoice'])
|
||||
vals['partner_invoice_id'] = vals.setdefault('partner_invoice_id', addr['invoice'])
|
||||
vals['pricelist_id'] = vals.setdefault('pricelist_id', partner.property_product_pricelist and partner.property_product_pricelist.id)
|
||||
vals['pricelist_id'] = vals.setdefault(
|
||||
'pricelist_id',
|
||||
partner.property_product_pricelist and partner.property_product_pricelist.id)
|
||||
result = super(HotelFolio, self).create(vals)
|
||||
return result
|
||||
|
||||
@@ -358,12 +358,15 @@ class HotelFolio(models.Model):
|
||||
|
||||
addr = self.partner_id.address_get(['invoice'])
|
||||
values = {
|
||||
'pricelist_id': self.partner_id.property_product_pricelist and self.partner_id.property_product_pricelist.id or False,
|
||||
'pricelist_id': self.partner_id.property_product_pricelist and \
|
||||
self.partner_id.property_product_pricelist.id or False,
|
||||
'partner_invoice_id': addr['invoice'],
|
||||
'user_id': self.partner_id.user_id.id or self.env.uid
|
||||
}
|
||||
if self.env['ir.config_parameter'].sudo().get_param('sale.use_sale_note') and self.env.user.company_id.sale_note:
|
||||
values['note'] = self.with_context(lang=self.partner_id.lang).env.user.company_id.sale_note
|
||||
if self.env['ir.config_parameter'].sudo().get_param('sale.use_sale_note') and \
|
||||
self.env.user.company_id.sale_note:
|
||||
values['note'] = self.with_context(
|
||||
lang=self.partner_id.lang).env.user.company_id.sale_note
|
||||
|
||||
if self.partner_id.team_id:
|
||||
values['team_id'] = self.partner_id.team_id.id
|
||||
@@ -409,10 +412,11 @@ class HotelFolio(models.Model):
|
||||
|
||||
@api.multi
|
||||
def action_done(self):
|
||||
for line in self.room_lines:
|
||||
room_lines = self.mapped('room_lines')
|
||||
for line in room_lines:
|
||||
if line.state == "booking":
|
||||
line.action_reservation_checkout()
|
||||
|
||||
|
||||
@api.multi
|
||||
def action_cancel(self):
|
||||
'''
|
||||
@@ -457,7 +461,7 @@ class HotelFolio(models.Model):
|
||||
'domain': [('reservation_id', 'in', rooms)],
|
||||
'target': 'new',
|
||||
}
|
||||
|
||||
|
||||
@api.model
|
||||
def daily_plan(self):
|
||||
_logger.info('daily_plan')
|
||||
@@ -486,26 +490,19 @@ class HotelFolio(models.Model):
|
||||
@api.multi
|
||||
def _compute_cardex_count(self):
|
||||
_logger.info('_compute_cardex_amount')
|
||||
for fol in self:
|
||||
num_cardex = 0
|
||||
pending = False
|
||||
if fol.reservation_type == 'normal':
|
||||
for reser in fol.room_lines:
|
||||
if reser.state != 'cancelled' and \
|
||||
not reser.parent_reservation:
|
||||
num_cardex += len(reser.cardex_ids)
|
||||
fol.cardex_count = num_cardex
|
||||
pending = 0
|
||||
for reser in fol.room_lines:
|
||||
if reser.state != 'cancelled' and \
|
||||
not reser.parent_reservation:
|
||||
pending += (reser.adults + reser.children) \
|
||||
- len(reser.cardex_ids)
|
||||
if pending <= 0:
|
||||
fol.cardex_pending = False
|
||||
else:
|
||||
fol.cardex_pending = True
|
||||
fol.cardex_pending_num = pending
|
||||
for record in self:
|
||||
if record.reservation_type == 'normal':
|
||||
write_vals = {}
|
||||
filtered_reservs = record.filtered(
|
||||
lambda x: x.room_lines.state != 'cancelled' and \
|
||||
not x.room_lines.parent_reservation)
|
||||
|
||||
mapped_cardex = filtered_reservs.mapped('cardex_ids.id')
|
||||
write_vals.update({'cardex_count': len(mapped_cardex)})
|
||||
mapped_cardex_count = filtered_reservs.mapped(
|
||||
lambda x: (x.adults + x.children) - len(x.cardex_ids))
|
||||
write_vals.update({'cardex_pending_count': sum(mapped_cardex_count)})
|
||||
record.write(write_vals)
|
||||
|
||||
"""
|
||||
MAILING PROCESS
|
||||
@@ -586,15 +583,15 @@ class HotelFolio(models.Model):
|
||||
self.ensure_one()
|
||||
ir_model_data = self.env['ir.model.data']
|
||||
try:
|
||||
template_id = (ir_model_data.get_object_reference
|
||||
('hotel',
|
||||
'mail_template_hotel_reservation')[1])
|
||||
template_id = ir_model_data.get_object_reference(
|
||||
'hotel',
|
||||
'mail_template_hotel_reservation')[1]
|
||||
except ValueError:
|
||||
template_id = False
|
||||
try:
|
||||
compose_form_id = (ir_model_data.get_object_reference
|
||||
('mail',
|
||||
'email_compose_message_wizard_form')[1])
|
||||
compose_form_id = ir_model_data.get_object_reference(
|
||||
'mail',
|
||||
'email_compose_message_wizard_form')[1]
|
||||
except ValueError:
|
||||
compose_form_id = False
|
||||
ctx = dict()
|
||||
@@ -632,15 +629,15 @@ class HotelFolio(models.Model):
|
||||
self.ensure_one()
|
||||
ir_model_data = self.env['ir.model.data']
|
||||
try:
|
||||
template_id = (ir_model_data.get_object_reference
|
||||
('hotel',
|
||||
'mail_template_hotel_exit')[1])
|
||||
template_id = ir_model_data.get_object_reference(
|
||||
'hotel',
|
||||
'mail_template_hotel_exit')[1]
|
||||
except ValueError:
|
||||
template_id = False
|
||||
try:
|
||||
compose_form_id = (ir_model_data.get_object_reference
|
||||
('mail',
|
||||
'email_compose_message_wizard_form')[1])
|
||||
compose_form_id = ir_model_data.get_object_reference(
|
||||
'mail',
|
||||
'email_compose_message_wizard_form')[1]
|
||||
except ValueError:
|
||||
compose_form_id = False
|
||||
ctx = dict()
|
||||
@@ -679,15 +676,15 @@ class HotelFolio(models.Model):
|
||||
self.ensure_one()
|
||||
ir_model_data = self.env['ir.model.data']
|
||||
try:
|
||||
template_id = (ir_model_data.get_object_reference
|
||||
('hotel',
|
||||
'mail_template_hotel_cancel')[1])
|
||||
template_id = ir_model_data.get_object_reference(
|
||||
'hotel',
|
||||
'mail_template_hotel_cancel')[1]
|
||||
except ValueError:
|
||||
template_id = False
|
||||
try:
|
||||
compose_form_id = (ir_model_data.get_object_reference
|
||||
('mail',
|
||||
'email_compose_message_wizard_form')[1])
|
||||
compose_form_id = ir_model_data.get_object_reference(
|
||||
'mail',
|
||||
'email_compose_message_wizard_form')[1]
|
||||
except ValueError:
|
||||
compose_form_id = False
|
||||
ctx = dict()
|
||||
@@ -722,15 +719,14 @@ class HotelFolio(models.Model):
|
||||
@param self: The object pointer
|
||||
@return: send a mail
|
||||
"""
|
||||
now_str = time.strftime(dt)
|
||||
now_date = datetime.strptime(now_str, dt)
|
||||
now_date = fields.Datetime.now()
|
||||
ir_model_data = self.env['ir.model.data']
|
||||
template_id = (ir_model_data.get_object_reference
|
||||
('hotel_reservation',
|
||||
'mail_template_reservation_reminder_24hrs')[1])
|
||||
template_id = ir_model_data.get_object_reference(
|
||||
'hotel_reservation',
|
||||
'mail_template_reservation_reminder_24hrs')[1]
|
||||
template_rec = self.env['mail.template'].browse(template_id)
|
||||
for reserv_rec in self.search([]):
|
||||
checkin_date = (datetime.strptime(reserv_rec.checkin, dt))
|
||||
checkin_date = datetime.strptime(reserv_rec.checkin, dt)
|
||||
difference = relativedelta(now_date, checkin_date)
|
||||
if(difference.days == -1 and reserv_rec.partner_id.email and
|
||||
reserv_rec.state == 'confirm'):
|
||||
@@ -742,11 +738,17 @@ class HotelFolio(models.Model):
|
||||
self.ensure_one()
|
||||
info_grouped = []
|
||||
for rline in self.room_lines:
|
||||
if (import_all or rline.to_send) and not rline.parent_reservation and rline.state == state:
|
||||
if (import_all or rline.to_send) and \
|
||||
not rline.parent_reservation and rline.state == state:
|
||||
dates = rline.get_real_checkin_checkout()
|
||||
vals = {
|
||||
'num': len(
|
||||
self.room_lines.filtered(lambda r: r.get_real_checkin_checkout()[0] == dates[0] and r.get_real_checkin_checkout()[1] == dates[1] and r.room_type_id.id == rline.room_type_id.id and (r.to_send or import_all) and not r.parent_reservation and r.state == rline.state)
|
||||
self.room_lines.filtered(
|
||||
lambda r: r.get_real_checkin_checkout()[0] == dates[0] and \
|
||||
r.get_real_checkin_checkout()[1] == dates[1] and \
|
||||
r.room_type_id.id == rline.room_type_id.id and \
|
||||
(r.to_send or import_all) and not r.parent_reservation and \
|
||||
r.state == rline.state)
|
||||
),
|
||||
'room_type': {
|
||||
'id': rline.room_type_id.id,
|
||||
@@ -760,10 +762,13 @@ class HotelFolio(models.Model):
|
||||
}
|
||||
founded = False
|
||||
for srline in info_grouped:
|
||||
if srline['num'] == vals['num'] and srline['room_type']['id'] == vals['room_type']['id'] and srline['checkin'] == vals['checkin'] and srline['checkout'] == vals['checkout']:
|
||||
if srline['num'] == vals['num'] and \
|
||||
srline['room_type']['id'] == vals['room_type']['id'] and \
|
||||
srline['checkin'] == vals['checkin'] and \
|
||||
srline['checkout'] == vals['checkout']:
|
||||
founded = True
|
||||
break
|
||||
if not founded:
|
||||
info_grouped.append(vals)
|
||||
return sorted(sorted(info_grouped, key=lambda k: k['num'], reverse=True), key=lambda k: k['room_type']['id'])
|
||||
|
||||
return sorted(sorted(info_grouped,key=lambda k: k['num'], reverse=True),
|
||||
key=lambda k: k['room_type']['id'])
|
||||
|
||||
@@ -1,24 +1,19 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017-2018 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo.exceptions import except_orm, UserError, ValidationError
|
||||
import logging
|
||||
import time
|
||||
from datetime import timedelta
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.tools import (
|
||||
misc,
|
||||
DEFAULT_SERVER_DATE_FORMAT,
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
from odoo import models, fields, api, _
|
||||
from decimal import Decimal
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from dateutil import tz
|
||||
from datetime import datetime, timedelta, date
|
||||
from odoo.addons import decimal_precision as dp
|
||||
from odoo.addons.hotel import date_utils
|
||||
import pytz
|
||||
import time
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
from odoo.addons import decimal_precision as dp
|
||||
|
||||
class HotelReservation(models.Model):
|
||||
|
||||
@@ -48,7 +43,8 @@ class HotelReservation(models.Model):
|
||||
tz_hotel = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'tz_hotel')
|
||||
today = fields.Date.context_today(self.with_context(tz=tz_hotel))
|
||||
return (fields.Date.from_string(today) + timedelta(days=1)).strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||
return (fields.Date.from_string(today) + timedelta(days=1)).strftime(
|
||||
DEFAULT_SERVER_DATE_FORMAT)
|
||||
|
||||
def _get_default_arrival_hour(self):
|
||||
folio = False
|
||||
@@ -102,18 +98,17 @@ class HotelReservation(models.Model):
|
||||
# Has this reservation more charges associates in folio?, Yes?, then, this is share folio ;)
|
||||
for record in self:
|
||||
if record.folio_id:
|
||||
if len(record.folio_id.room_lines) > 1 or \
|
||||
record.folio_id.service_line_ids.filtered(lambda x: (
|
||||
x.ser_room_line != record.id)):
|
||||
record.shared_folio = True
|
||||
else:
|
||||
record.shared_folio = False
|
||||
record.shared_folio = len(record.folio_id.room_lines) > 1 or \
|
||||
any(record.folio_id.service_line_ids.filtered(
|
||||
lambda x: x.ser_room_line != record.id))
|
||||
|
||||
@api.depends('checkin', 'checkout')
|
||||
def _computed_nights(self):
|
||||
for res in self:
|
||||
if res.checkin and res.checkout:
|
||||
res.nights = (fields.Date.from_string(res.checkout) - fields.Date.from_string(res.checkin)).days
|
||||
res.nights = (
|
||||
fields.Date.from_string(res.checkout) - fields.Date.from_string(res.checkin)
|
||||
).days
|
||||
|
||||
_name = 'hotel.reservation'
|
||||
_description = 'Hotel Reservation'
|
||||
@@ -191,11 +186,9 @@ class HotelReservation(models.Model):
|
||||
# The value is a method name returning a Domains
|
||||
cardex_count = fields.Integer('Cardex counter',
|
||||
compute='_compute_cardex_count')
|
||||
cardex_pending = fields.Boolean('Cardex Pending',
|
||||
compute='_compute_cardex_count',
|
||||
search='_search_cardex_pending')
|
||||
cardex_pending_num = fields.Integer('Cardex Pending Num',
|
||||
compute='_compute_cardex_count')
|
||||
cardex_pending_count = fields.Integer('Cardex Pending Num',
|
||||
compute='_compute_cardex_count',
|
||||
search='_search_cardex_pending')
|
||||
# check_rooms = fields.Boolean('Check Rooms')
|
||||
is_checkin = fields.Boolean()
|
||||
is_checkout = fields.Boolean()
|
||||
@@ -226,29 +219,31 @@ class HotelReservation(models.Model):
|
||||
preconfirm = fields.Boolean('Auto confirm to Save', default=True)
|
||||
to_send = fields.Boolean('To Send', default=True)
|
||||
has_confirmed_reservations_to_send = fields.Boolean(
|
||||
related='folio_id.has_confirmed_reservations_to_send',
|
||||
readonly=True)
|
||||
related='folio_id.has_confirmed_reservations_to_send',
|
||||
readonly=True)
|
||||
has_cancelled_reservations_to_send = fields.Boolean(
|
||||
related='folio_id.has_cancelled_reservations_to_send',
|
||||
readonly=True)
|
||||
related='folio_id.has_cancelled_reservations_to_send',
|
||||
readonly=True)
|
||||
has_checkout_to_send = fields.Boolean(
|
||||
related='folio_id.has_checkout_to_send',
|
||||
readonly=True)
|
||||
related='folio_id.has_checkout_to_send',
|
||||
readonly=True)
|
||||
# order_line = fields.One2many('sale.order.line', 'order_id', string='Order Lines', states={'cancel': [('readonly', True)], 'done': [('readonly', True)]}, copy=True, auto_join=True)
|
||||
# product_id = fields.Many2one('product.product', related='order_line.product_id', string='Product')
|
||||
# product_uom = fields.Many2one('product.uom', string='Unit of Measure', required=True)
|
||||
# product_uom_qty = fields.Float(string='Quantity', digits=dp.get_precision('Product Unit of Measure'), required=True, default=1.0)
|
||||
|
||||
currency_id = fields.Many2one('res.currency',
|
||||
related='pricelist_id.currency_id',
|
||||
string='Currency', readonly=True, required=True)
|
||||
related='pricelist_id.currency_id',
|
||||
string='Currency', readonly=True, required=True)
|
||||
# invoice_status = fields.Selection([
|
||||
# ('upselling', 'Upselling Opportunity'),
|
||||
# ('invoiced', 'Fully Invoiced'),
|
||||
# ('to invoice', 'To Invoice'),
|
||||
# ('no', 'Nothing to Invoice')
|
||||
# ], string='Invoice Status', compute='_compute_invoice_status', store=True, readonly=True, default='no')
|
||||
tax_id = fields.Many2many('account.tax', string='Taxes', domain=['|', ('active', '=', False), ('active', '=', True)])
|
||||
tax_id = fields.Many2many('account.tax',
|
||||
string='Taxes',
|
||||
domain=['|', ('active', '=', False), ('active', '=', True)])
|
||||
# qty_to_invoice = fields.Float(
|
||||
# string='To Invoice', store=True, readonly=True,
|
||||
# digits=dp.get_precision('Product Unit of Measure'))
|
||||
@@ -257,9 +252,18 @@ class HotelReservation(models.Model):
|
||||
# digits=dp.get_precision('Product Unit of Measure'))
|
||||
# qty_delivered = fields.Float(string='Delivered', copy=False, digits=dp.get_precision('Product Unit of Measure'), default=0.0)
|
||||
# qty_delivered_updateable = fields.Boolean(compute='_compute_qty_delivered_updateable', string='Can Edit Delivered', readonly=True, default=True)
|
||||
price_subtotal = fields.Monetary(string='Subtotal', readonly=True, store=True, compute='_compute_amount_reservation')
|
||||
price_total = fields.Monetary(string='Total', readonly=True, store=True, compute='_compute_amount_reservation')
|
||||
price_tax = fields.Float(string='Taxes', readonly=True, store=True, compute='_compute_amount_reservation')
|
||||
price_subtotal = fields.Monetary(string='Subtotal',
|
||||
readonly=True,
|
||||
store=True,
|
||||
compute='_compute_amount_reservation')
|
||||
price_total = fields.Monetary(string='Total',
|
||||
readonly=True,
|
||||
store=True,
|
||||
compute='_compute_amount_reservation')
|
||||
price_tax = fields.Float(string='Taxes',
|
||||
readonly=True,
|
||||
store=True,
|
||||
compute='_compute_amount_reservation')
|
||||
# FIXME discount per night
|
||||
discount = fields.Float(string='Discount (%)', digits=dp.get_precision('Discount'), default=0.0)
|
||||
|
||||
@@ -286,11 +290,13 @@ class HotelReservation(models.Model):
|
||||
#~ 'reserve_color_text': colors[1],
|
||||
})
|
||||
if self.compute_price_out_vals(vals):
|
||||
days_diff = (fields.Date.from_string(vals['checkout']) - fields.Date.from_string(vals['checkin'])).days
|
||||
vals.update(record.prepare_reservation_lines(
|
||||
days_diff = (
|
||||
fields.Date.from_string(vals['checkout']) - fields.Date.from_string(vals['checkin'])
|
||||
).days
|
||||
vals.update(self.prepare_reservation_lines(
|
||||
vals['checkin'],
|
||||
days_diff,
|
||||
vals = vals)) #REVISAR el unlink
|
||||
vals=vals)) #REVISAR el unlink
|
||||
record = super(HotelReservation, self).create(vals)
|
||||
#~ if (record.state == 'draft' and record.folio_id.state == 'sale') or \
|
||||
#~ record.preconfirm:
|
||||
@@ -301,18 +307,22 @@ 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': date_utils.now(hours=True).strftime(
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
})
|
||||
for record in self:
|
||||
if record.compute_price_out_vals(vals):
|
||||
days_diff = (fields.Date.from_string(record.checkout) - fields.Date.from_string(record.checkin)).days
|
||||
days_diff = (
|
||||
fields.Date.from_string(record.checkout) - \
|
||||
fields.Date.from_string(record.checkin)
|
||||
).days
|
||||
record.update(record.prepare_reservation_lines(
|
||||
vals['checkin'],
|
||||
days_diff,
|
||||
vals = vals)) #REVISAR el unlink
|
||||
vals=vals)) #REVISAR el unlink
|
||||
if ('checkin' in vals and record.checkin != vals['checkin']) or \
|
||||
('checkout' in vals and record.checkout != vals['checkout']) or \
|
||||
('state' in vals and record.state != vals['state']) :
|
||||
('state' in vals and record.state != vals['state']):
|
||||
vals.update({'to_send': True})
|
||||
res = super(HotelReservation, self).write(vals)
|
||||
return res
|
||||
@@ -321,9 +331,9 @@ class HotelReservation(models.Model):
|
||||
def _prepare_add_missing_fields(self, values):
|
||||
""" Deduce missing required fields from the onchange """
|
||||
res = {}
|
||||
onchange_fields = ['room_id', 'pricelist_id',
|
||||
'reservation_type', 'currency_id']
|
||||
if values.get('partner_id') and values.get('room_type_id') and any(f not in values for f in onchange_fields):
|
||||
onchange_fields = ['room_id', 'pricelist_id', 'reservation_type', 'currency_id']
|
||||
if values.get('partner_id') and values.get('room_type_id') and \
|
||||
any(f not in values for f in onchange_fields):
|
||||
line = self.new(values)
|
||||
line.onchange_room_id()
|
||||
for field in onchange_fields:
|
||||
@@ -345,7 +355,7 @@ class HotelReservation(models.Model):
|
||||
@api.multi
|
||||
def overbooking_button(self):
|
||||
self.ensure_one()
|
||||
return self.write({'overbooking': not self.overbooking})
|
||||
self.overbooking = not self.overbooking
|
||||
|
||||
@api.multi
|
||||
def open_folio(self):
|
||||
@@ -388,8 +398,8 @@ class HotelReservation(models.Model):
|
||||
def _check_adults(self):
|
||||
for record in self:
|
||||
if record.adults > record.room_id.capacity:
|
||||
raise ValidationError(
|
||||
_("Reservation persons can't be higher than room capacity"))
|
||||
raise ValidationError(
|
||||
_("Reservation persons can't be higher than room capacity"))
|
||||
if record.adults == 0:
|
||||
raise ValidationError(_("Reservation has no adults"))
|
||||
|
||||
@@ -399,22 +409,24 @@ class HotelReservation(models.Model):
|
||||
|
||||
@api.onchange('adults', 'room_id')
|
||||
def onchange_room_id(self):
|
||||
# TODO: Usar vals y write
|
||||
if self.room_id:
|
||||
write_vals = {}
|
||||
if self.room_id.capacity < self.adults:
|
||||
self.adults = self.room_id.capacity
|
||||
raise UserError(
|
||||
_('%s people do not fit in this room! ;)') % (persons))
|
||||
_('%s people do not fit in this room! ;)') % (self.adults))
|
||||
if self.adults == 0:
|
||||
self.adults = self.room_id.capacity
|
||||
if not self.room_type_id: #Si el registro no existe, modificar room_type aunque ya esté establecido
|
||||
self.room_type_id = self.room_id.room_type_id
|
||||
write_vals.update({'adults': self.room_id.capacity})
|
||||
#Si el registro no existe, modificar room_type aunque ya esté establecido
|
||||
if not self.room_type_id:
|
||||
write_vals.update({'room_type_id': self.room_id.room_type_id.id})
|
||||
self.write(write_vals)
|
||||
|
||||
@api.onchange('partner_id')
|
||||
def onchange_partner_id(self):
|
||||
#TODO: Change parity pricelist by default pricelist
|
||||
values = {
|
||||
'pricelist_id': self.partner_id.property_product_pricelist and self.partner_id.property_product_pricelist.id or \
|
||||
'pricelist_id': self.partner_id.property_product_pricelist and \
|
||||
self.partner_id.property_product_pricelist.id or \
|
||||
self.env['ir.default'].sudo().get('res.config.settings', 'parity_pricelist_id'),
|
||||
}
|
||||
self.update(values)
|
||||
@@ -423,11 +435,13 @@ class HotelReservation(models.Model):
|
||||
@api.onchange('room_type_id', 'pricelist_id', 'reservation_type')
|
||||
def onchange_overwrite_price_by_day(self):
|
||||
if self.room_type_id and self.checkin and self.checkout:
|
||||
days_diff = (fields.Date.from_string(self.checkout) - fields.Date.from_string(self.checkin)).days
|
||||
days_diff = (
|
||||
fields.Date.from_string(self.checkout) - fields.Date.from_string(self.checkin)
|
||||
).days
|
||||
self.update(self.prepare_reservation_lines(
|
||||
self.checkin,
|
||||
days_diff,
|
||||
update_old_prices = True))
|
||||
update_old_prices=True))
|
||||
|
||||
# When we need to update prices respecting those that were already established
|
||||
@api.onchange('checkin', 'checkout')
|
||||
@@ -439,15 +453,16 @@ class HotelReservation(models.Model):
|
||||
checkin_dt = fields.Date.from_string(self.checkin)
|
||||
checkout_dt = fields.Date.from_string(self.checkout)
|
||||
if checkin_dt >= checkout_dt:
|
||||
self.checkout = (fields.Date.from_string(self.checkin) + timedelta(days=1)).strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||
self.checkout = (fields.Date.from_string(self.checkin) + timedelta(days=1)).strftime(
|
||||
DEFAULT_SERVER_DATE_FORMAT)
|
||||
if self.room_type_id:
|
||||
days_diff = (fields.Date.from_string(self.checkout) - fields.Date.from_string(self.checkin)).days
|
||||
days_diff = (
|
||||
fields.Date.from_string(self.checkout) - fields.Date.from_string(self.checkin)
|
||||
).days
|
||||
self.update(self.prepare_reservation_lines(
|
||||
self.checkin,
|
||||
days_diff,
|
||||
update_old_prices = False))
|
||||
|
||||
|
||||
update_old_prices=False))
|
||||
|
||||
@api.onchange('checkin', 'checkout', 'room_type_id')
|
||||
def onchange_compute_reservation_description(self):
|
||||
@@ -468,8 +483,9 @@ class HotelReservation(models.Model):
|
||||
return
|
||||
occupied = self.env['hotel.reservation'].get_reservations(
|
||||
self.checkin,
|
||||
fields.Date.from_string(self.checkout).strftime(DEFAULT_SERVER_DATE_FORMAT)).filtered(
|
||||
lambda r: r.id != self._origin.id)
|
||||
fields.Date.from_string(self.checkout).strftime(
|
||||
DEFAULT_SERVER_DATE_FORMAT)).filtered(
|
||||
lambda r: r.id != self._origin.id)
|
||||
rooms_occupied = occupied.mapped('room_id.id')
|
||||
if self.room_id and self.room_id.id in rooms_occupied:
|
||||
warning_msg = _('You tried to change \
|
||||
@@ -488,7 +504,7 @@ class HotelReservation(models.Model):
|
||||
@api.multi
|
||||
def _generate_color(self):
|
||||
self.ensure_one()
|
||||
now_utc_dt = date_utils.now()
|
||||
now_utc_dt = fields.Datetime.now()
|
||||
# unused variables
|
||||
# diff_checkin_now = date_utils.date_diff(now_utc_dt, self.checkin,
|
||||
# hours=False)
|
||||
@@ -502,26 +518,22 @@ class HotelReservation(models.Model):
|
||||
return ('#4E9DC4', '#000000')
|
||||
|
||||
if self.reservation_type == 'staff':
|
||||
reserv_color = ir_values_obj.get('res.config.settings',
|
||||
'color_staff')
|
||||
reserv_color = ir_values_obj.get('res.config.settings', 'color_staff')
|
||||
reserv_color_text = ir_values_obj.get(
|
||||
'res.config.settings',
|
||||
'color_letter_staff')
|
||||
elif self.reservation_type == 'out':
|
||||
reserv_color = ir_values_obj.get('res.config.settings',
|
||||
'color_dontsell')
|
||||
reserv_color = ir_values_obj.get('res.config.settings', 'color_dontsell')
|
||||
reserv_color_text = ir_values_obj.get(
|
||||
'res.config.settings',
|
||||
'color_letter_dontsell')
|
||||
elif self.to_assign:
|
||||
reserv_color = ir_values_obj.get('res.config.settings',
|
||||
'color_to_assign')
|
||||
reserv_color = ir_values_obj.get('res.config.settings', 'color_to_assign')
|
||||
reserv_color_text = ir_values_obj.get(
|
||||
'res.config.settings',
|
||||
'color_letter_to_assign')
|
||||
elif self.state == 'draft':
|
||||
reserv_color = ir_values_obj.get('res.config.settings',
|
||||
'color_pre_reservation')
|
||||
reserv_color = ir_values_obj.get('res.config.settings', 'color_pre_reservation')
|
||||
reserv_color_text = ir_values_obj.get(
|
||||
'res.config.settings',
|
||||
'color_letter_pre_reservation')
|
||||
@@ -563,13 +575,13 @@ class HotelReservation(models.Model):
|
||||
@api.depends('state', 'reservation_type', 'folio_id.pending_amount', 'to_assign')
|
||||
def _compute_color(self):
|
||||
_logger.info('_compute_color')
|
||||
for rec in self:
|
||||
colors = rec._generate_color()
|
||||
rec.update({
|
||||
for record in self:
|
||||
colors = record._generate_color()
|
||||
record.update({
|
||||
'reserve_color': colors[0],
|
||||
'reserve_color_text': colors[1],
|
||||
})
|
||||
rec.folio_id.color = colors[0]
|
||||
record.folio_id.color = colors[0]
|
||||
|
||||
# hotel_reserv_obj = self.env['hotel.reservation']
|
||||
# if rec.splitted:
|
||||
@@ -595,27 +607,28 @@ class HotelReservation(models.Model):
|
||||
_logger.info('confirm')
|
||||
hotel_folio_obj = self.env['hotel.folio']
|
||||
hotel_reserv_obj = self.env['hotel.reservation']
|
||||
for r in self:
|
||||
for record in self:
|
||||
vals = {}
|
||||
if r.cardex_ids:
|
||||
if record.cardex_ids:
|
||||
vals.update({'state': 'booking'})
|
||||
else:
|
||||
vals.update({'state': 'confirm'})
|
||||
if r.checkin_is_today():
|
||||
if record.checkin_is_today():
|
||||
vals.update({'is_checkin': True})
|
||||
folio = hotel_folio_obj.browse(r.folio_id.id)
|
||||
folio = hotel_folio_obj.browse(record.folio_id.id)
|
||||
folio.checkins_reservations = folio.room_lines.search_count([
|
||||
('folio_id', '=', folio.id), ('is_checkin', '=', True)])
|
||||
r.write(vals)
|
||||
record.write(vals)
|
||||
|
||||
if r.splitted:
|
||||
master_reservation = r.parent_reservation or r
|
||||
if record.splitted:
|
||||
master_reservation = record.parent_reservation or record
|
||||
splitted_reservs = hotel_reserv_obj.search([
|
||||
('splitted', '=', True),
|
||||
'|', ('parent_reservation', '=', master_reservation.id),
|
||||
('id', '=', master_reservation.id),
|
||||
('folio_id', '=', r.folio_id.id),
|
||||
('id', '!=', r.id),
|
||||
'|',
|
||||
('parent_reservation', '=', master_reservation.id),
|
||||
('id', '=', master_reservation.id),
|
||||
('folio_id', '=', record.folio_id.id),
|
||||
('id', '!=', record.id),
|
||||
('state', '!=', 'confirm')
|
||||
])
|
||||
splitted_reservs.confirm()
|
||||
@@ -626,8 +639,8 @@ class HotelReservation(models.Model):
|
||||
'''
|
||||
@param self: object pointer
|
||||
'''
|
||||
for res in self:
|
||||
res.action_reservation_checkout()
|
||||
for record in self:
|
||||
record.action_reservation_checkout()
|
||||
return True
|
||||
|
||||
@api.multi
|
||||
@@ -649,8 +662,9 @@ class HotelReservation(models.Model):
|
||||
master_reservation = record.parent_reservation or record
|
||||
splitted_reservs = self.env['hotel.reservation'].search([
|
||||
('splitted', '=', True),
|
||||
'|', ('parent_reservation', '=', master_reservation.id),
|
||||
('id', '=', master_reservation.id),
|
||||
'|',
|
||||
('parent_reservation', '=', master_reservation.id),
|
||||
('id', '=', master_reservation.id),
|
||||
('folio_id', '=', record.folio_id.id),
|
||||
('id', '!=', record.id),
|
||||
('state', '!=', 'cancelled')
|
||||
@@ -661,14 +675,14 @@ class HotelReservation(models.Model):
|
||||
@api.multi
|
||||
def draft(self):
|
||||
for record in self:
|
||||
record.write({'state': 'draft'})
|
||||
|
||||
record.state = 'draft'
|
||||
if record.splitted:
|
||||
master_reservation = record.parent_reservation or record
|
||||
splitted_reservs = self.env['hotel.reservation'].search([
|
||||
('splitted', '=', True),
|
||||
'|', ('parent_reservation', '=', master_reservation.id),
|
||||
('id', '=', master_reservation.id),
|
||||
'|',
|
||||
('parent_reservation', '=', master_reservation.id),
|
||||
('id', '=', master_reservation.id),
|
||||
('folio_id', '=', record.folio_id.id),
|
||||
('id', '!=', record.id),
|
||||
('state', '!=', 'draft')
|
||||
@@ -696,21 +710,19 @@ class HotelReservation(models.Model):
|
||||
"""
|
||||
Compute the amounts of the reservation.
|
||||
"""
|
||||
for line in self:
|
||||
amount_room = 0
|
||||
for day in line.reservation_line_ids:
|
||||
amount_room += day.price
|
||||
for record in self:
|
||||
amount_room = sum(record.reservation_line_ids.mapped('price'))
|
||||
if amount_room > 0:
|
||||
product = line.room_type_id.product_id
|
||||
price = amount_room * (1 - (line.discount or 0.0) / 100.0)
|
||||
taxes = line.tax_id.compute_all(price, line.currency_id, 1, product=product)
|
||||
line.update({
|
||||
product = record.room_type_id.product_id
|
||||
price = amount_room * (1 - (record.discount or 0.0) * 0.01)
|
||||
taxes = record.tax_id.compute_all(price, record.currency_id, 1, product=product)
|
||||
record.update({
|
||||
'price_tax': sum(t.get('amount', 0.0) for t in taxes.get('taxes', [])),
|
||||
'price_total': taxes['total_included'],
|
||||
'price_subtotal': taxes['total_excluded'],
|
||||
})
|
||||
|
||||
@api.multi
|
||||
@api.model
|
||||
def prepare_reservation_lines(self, dfrom, days, vals=False, update_old_prices=False):
|
||||
total_price = 0.0
|
||||
cmds = [(5, 0, 0)]
|
||||
@@ -719,23 +731,24 @@ class HotelReservation(models.Model):
|
||||
pricelist_id = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'parity_pricelist_id')
|
||||
#~ pricelist_id = vals.get('pricelist_id') or self.pricelist_id.id
|
||||
product = self.env['hotel.room.type'].browse(vals.get('room_type_id') or self.room_type_id.id).product_id
|
||||
room_type_id = vals.get('room_type_id') or self.room_type_id.id
|
||||
product = self.env['hotel.room.type'].browse(room_type_id).product_id
|
||||
old_lines_days = self.mapped('reservation_line_ids.date')
|
||||
partner = self.env['res.partner'].browse(vals.get('partner_id') or self.partner_id.id)
|
||||
total_price = 0
|
||||
for i in range(0, days):
|
||||
idate = (fields.Date.from_string(dfrom) + timedelta(days=i)).strftime(DEFAULT_SERVER_DATE_FORMAT)
|
||||
idate = (fields.Date.from_string(dfrom) + timedelta(days=i)).strftime(
|
||||
DEFAULT_SERVER_DATE_FORMAT)
|
||||
old_line = self.reservation_line_ids.filtered(lambda r: r.date == idate)
|
||||
if update_old_prices or (idate not in old_lines_days):
|
||||
_logger.info("PASA 3")
|
||||
product = product.with_context(
|
||||
lang=partner.lang,
|
||||
partner=partner.id,
|
||||
quantity=1,
|
||||
date=idate,
|
||||
pricelist=pricelist_id,
|
||||
uom=product.uom_id.id)
|
||||
line_price = self.env['account.tax']._fix_tax_included_price_company(product.price, product.taxes_id, self.tax_id, self.company_id)
|
||||
lang=partner.lang,
|
||||
partner=partner.id,
|
||||
quantity=1,
|
||||
date=idate,
|
||||
pricelist=pricelist_id,
|
||||
uom=product.uom_id.id)
|
||||
line_price = self.env['account.tax']._fix_tax_included_price_company(
|
||||
product.price, product.taxes_id, self.tax_id, self.company_id)
|
||||
if old_line:
|
||||
cmds.append((1, old_line.id, {
|
||||
'price': line_price
|
||||
@@ -748,7 +761,6 @@ class HotelReservation(models.Model):
|
||||
else:
|
||||
line_price = old_line.price
|
||||
cmds.append((4, old_line.id))
|
||||
total_price += line_price
|
||||
return {'reservation_line_ids': cmds}
|
||||
|
||||
@api.multi
|
||||
@@ -798,7 +810,6 @@ class HotelReservation(models.Model):
|
||||
('reservation_line_ids.date', '<', dto),
|
||||
('state', '!=', 'cancelled'),
|
||||
('overbooking', '=', False)]
|
||||
reservations = self.env['hotel.reservation'].search(domain)
|
||||
return self.env['hotel.reservation'].search(domain)
|
||||
|
||||
@api.model
|
||||
@@ -860,21 +871,19 @@ class HotelReservation(models.Model):
|
||||
@api.multi
|
||||
def _compute_cardex_count(self):
|
||||
_logger.info('_compute_cardex_count')
|
||||
for res in self:
|
||||
res.cardex_count = len(res.cardex_ids)
|
||||
res.cardex_pending_num = (res.adults + res.children) \
|
||||
- len(res.cardex_ids)
|
||||
if (res.adults + res.children - len(res.cardex_ids)) <= 0:
|
||||
res.cardex_pending = False
|
||||
else:
|
||||
res.cardex_pending = True
|
||||
for record in self:
|
||||
record.write({
|
||||
'cardex_count': len(record.cardex_ids),
|
||||
'cardex_pending_count': (record.adults + record.children) \
|
||||
- len(record.cardex_ids)
|
||||
})
|
||||
|
||||
# https://www.odoo.com/es_ES/forum/ayuda-1/question/calculated-fields-in-search-filter-possible-118501
|
||||
@api.multi
|
||||
def _search_cardex_pending(self, operator, value):
|
||||
recs = self.search([]).filtered(lambda x: x.cardex_pending is True)
|
||||
if recs:
|
||||
return [('id', 'in', [x.id for x in recs])]
|
||||
self.ensure_one()
|
||||
recs = self.search([]).filtered(lambda x: x.cardex_pending_count > 0)
|
||||
return [('id', 'in', [x.id for x in recs])] if recs else []
|
||||
|
||||
@api.multi
|
||||
def action_reservation_checkout(self):
|
||||
@@ -908,8 +917,7 @@ class HotelReservation(models.Model):
|
||||
res.action_reservation_checkout()
|
||||
|
||||
reservations = self.env['hotel.reservation'].search([
|
||||
('reservation_line_ids.date', 'in', [today_str,
|
||||
yesterday_str]),
|
||||
('reservation_line_ids.date', 'in', [today_str, yesterday_str]),
|
||||
('state', 'in', ['confirm', 'booking'])
|
||||
])
|
||||
self._cr.execute("update hotel_reservation set is_checkin = False, \
|
||||
@@ -932,8 +940,7 @@ class HotelReservation(models.Model):
|
||||
@api.model
|
||||
def checkin_is_today(self):
|
||||
self.ensure_one()
|
||||
tz_hotel = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'tz_hotel')
|
||||
tz_hotel = self.env['ir.default'].sudo().get('res.config.settings', 'tz_hotel')
|
||||
today = fields.Date.context_today(self.with_context(tz=tz_hotel))
|
||||
return self.checkin == today
|
||||
|
||||
|
||||
@@ -1,26 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from odoo import models, fields, api, _
|
||||
# Copyright 2017-2018 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo import models, fields
|
||||
from odoo.addons import decimal_precision as dp
|
||||
from odoo.exceptions import except_orm, UserError, ValidationError
|
||||
|
||||
class HotelReservationLine(models.Model):
|
||||
_name = "hotel.reservation.line"
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
@@ -12,7 +11,7 @@ class HotelRoom(models.Model):
|
||||
_name = 'hotel.room'
|
||||
_description = 'Hotel Room'
|
||||
_order = "sequence, room_type_id, name"
|
||||
|
||||
|
||||
name = fields.Char('Room Name', required=True)
|
||||
active = fields.Boolean('Active', default=True)
|
||||
sequence = fields.Integer('Sequence', default=0)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
@@ -6,7 +5,6 @@ from odoo import models, fields, api, _
|
||||
|
||||
|
||||
class HotelRoomAmenities(models.Model):
|
||||
|
||||
_name = 'hotel.room.amenities'
|
||||
_description = 'Room amenities'
|
||||
# The record's name
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
@@ -6,7 +5,6 @@ from odoo import models, fields, api, _
|
||||
|
||||
|
||||
class HotelRoomAmenitiesType(models.Model):
|
||||
|
||||
_name = 'hotel.room.amenities.type'
|
||||
_description = 'Amenities Type'
|
||||
# The record's name
|
||||
|
||||
@@ -1,20 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from decimal import Decimal
|
||||
from datetime import datetime, timedelta
|
||||
import dateutil.parser
|
||||
# For Python 3.0 and later
|
||||
from urllib.request import urlopen
|
||||
import time
|
||||
from odoo.exceptions import except_orm, UserError, ValidationError
|
||||
from odoo.tools import (
|
||||
misc,
|
||||
DEFAULT_SERVER_DATE_FORMAT,
|
||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.addons.hotel import date_utils
|
||||
from odoo import models, fields, api
|
||||
|
||||
class HotelRoomType(models.Model):
|
||||
""" Before creating a 'room type', you need to consider the following:
|
||||
@@ -68,7 +55,7 @@ class HotelRoomType(models.Model):
|
||||
"""
|
||||
self.ensure_one()
|
||||
capacities = self.room_ids.mapped('capacity')
|
||||
return any(capacities) and min(capacities) or 0
|
||||
return min(capacities) if any(capacities) else 0
|
||||
|
||||
@api.model
|
||||
# TODO Rename to check_availability_room_type
|
||||
@@ -93,7 +80,7 @@ class HotelRoomType(models.Model):
|
||||
room_type_id = self.env['hotel.room.type'].search([
|
||||
('id', '=', room_type_id)
|
||||
])
|
||||
# QUESTION What linked represent? Rooms in this type ?
|
||||
# QUESTION What linked represent? Rooms in this type ?
|
||||
rooms_linked = self.room_ids
|
||||
free_rooms = free_rooms & rooms_linked
|
||||
return free_rooms.sorted(key=lambda r: r.sequence)
|
||||
@@ -106,9 +93,11 @@ class HotelRoomType(models.Model):
|
||||
@param vals: dictionary of fields value.
|
||||
@return: new record set for hotel room type.
|
||||
"""
|
||||
vals.update({'is_room_type': True})
|
||||
vals.update({'purchase_ok': False})
|
||||
vals.update({'type': 'service'})
|
||||
vals.update({
|
||||
'is_room_type': True,
|
||||
'purchase_ok': False,
|
||||
'type': 'service',
|
||||
})
|
||||
return super().create(vals)
|
||||
|
||||
@api.multi
|
||||
|
||||
@@ -1,33 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <alex@aloxa.eu>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
import logging
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import ValidationError
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HotelVirtualRoomAvailability(models.Model):
|
||||
class HotelRoomTypeAvailability(models.Model):
|
||||
_inherit = 'mail.thread'
|
||||
_name = 'hotel.virtual.room.availability'
|
||||
_name = 'hotel.room.type.availability'
|
||||
|
||||
# virtual_room_id = fields.Many2one('hotel.virtual.room', 'Virtual Room',
|
||||
# required=True, track_visibility='always',
|
||||
@@ -41,16 +22,19 @@ class HotelVirtualRoomAvailability(models.Model):
|
||||
track_visibility='always')
|
||||
date = fields.Date('Date', required=True, track_visibility='always')
|
||||
|
||||
_sql_constraints = [('vroom_registry_unique', 'unique(room_type_id, date)',
|
||||
'Only can exists one availability in the same day for the same room type!')]
|
||||
_sql_constraints = [
|
||||
('room_type_registry_unique',
|
||||
'unique(room_type_id, date)',
|
||||
'Only can exists one availability in the same day for the same room type!')
|
||||
]
|
||||
|
||||
@api.constrains('avail')
|
||||
def _check_avail(self):
|
||||
if self.avail < 0:
|
||||
self.avail = 0
|
||||
|
||||
vroom_obj = self.env['hotel.room.type']
|
||||
cavail = len(vroom_obj.check_availability_virtual_room(
|
||||
room_type_obj = self.env['hotel.room.type']
|
||||
cavail = len(room_type_obj.check_availability_virtual_room(
|
||||
self.date,
|
||||
self.date,
|
||||
room_type_id=self.room_type_id.id))
|
||||
31
hotel/models/hotel_room_type_restriction.py
Normal file
31
hotel/models/hotel_room_type_restriction.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
class HotelRoomTypeRestriction(models.Model):
|
||||
_name = 'hotel.room.type.restriction'
|
||||
|
||||
name = fields.Char('Restriction Plan Name', required=True)
|
||||
item_ids = fields.One2many('hotel.room.type.restriction.item',
|
||||
'restriction_id', string='Restriction Items',
|
||||
copy=True)
|
||||
active = fields.Boolean('Active',
|
||||
help='If unchecked, it will allow you to hide the \
|
||||
restriction plan without removing it.',
|
||||
default=True)
|
||||
|
||||
@api.multi
|
||||
@api.depends('name')
|
||||
def name_get(self):
|
||||
restriction_id = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'parity_restrictions_id')
|
||||
if restriction_id:
|
||||
restriction_id = int(restriction_id)
|
||||
names = []
|
||||
for record in self:
|
||||
if record.id == restriction_id:
|
||||
names.append((record.id, '%s (Parity)' % record.name))
|
||||
else:
|
||||
names.append((record.id, record.name))
|
||||
return names
|
||||
@@ -1,24 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <alex@aloxa.eu>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from datetime import datetime
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import ValidationError
|
||||
@@ -26,10 +7,10 @@ from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
|
||||
from odoo.addons.hotel import date_utils
|
||||
|
||||
|
||||
class HotelVirtualRoomRestrictionItem(models.Model):
|
||||
_name = 'hotel.virtual.room.restriction.item'
|
||||
class HotelRoomTypeRestrictionItem(models.Model):
|
||||
_name = 'hotel.room.type.restriction.item'
|
||||
|
||||
restriction_id = fields.Many2one('hotel.virtual.room.restriction',
|
||||
restriction_id = fields.Many2one('hotel.room.type.restriction',
|
||||
'Restriction Plan', ondelete='cascade',
|
||||
index=True)
|
||||
# virtual_room_id = fields.Many2one('hotel.virtual.room', 'Virtual Room',
|
||||
@@ -54,7 +35,7 @@ class HotelVirtualRoomRestrictionItem(models.Model):
|
||||
closed_departure = fields.Boolean('Closed Departure')
|
||||
closed_arrival = fields.Boolean('Closed Arrival')
|
||||
|
||||
_sql_constraints = [('vroom_registry_unique',
|
||||
_sql_constraints = [('room_type_registry_unique',
|
||||
'unique(restriction_id, room_type_id, date_start, date_end)',
|
||||
'Only can exists one restriction in the same day for the same room type!')]
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
import time
|
||||
import datetime
|
||||
import logging
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.tools import misc, DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from odoo.addons.hotel import date_utils
|
||||
from odoo.addons import decimal_precision as dp
|
||||
from odoo import models, fields, api
|
||||
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
class HotelService(models.Model):
|
||||
@@ -29,8 +25,9 @@ class HotelService(models.Model):
|
||||
def _default_ser_room_line(self):
|
||||
if 'room_lines' in self.env.context and self.env.context['room_lines']:
|
||||
ids = [item[1] for item in self.env.context['room_lines']]
|
||||
return self.env['hotel.reservation'].search([('id', 'in', ids)],
|
||||
limit=1)
|
||||
return self.env['hotel.reservation'].search([
|
||||
('id', 'in', ids),
|
||||
], limit=1)
|
||||
return False
|
||||
|
||||
_name = 'hotel.service'
|
||||
@@ -56,9 +53,9 @@ class HotelService(models.Model):
|
||||
('web', 'Web')], 'Sales Channel')
|
||||
|
||||
ser_checkin = fields.Datetime('From Date', required=True,
|
||||
default=_service_checkin)
|
||||
default=_service_checkin)
|
||||
ser_checkout = fields.Datetime('To Date', required=True,
|
||||
default=_service_checkout)
|
||||
default=_service_checkout)
|
||||
|
||||
|
||||
# TODO Hierarchical relationship for parent-child tree
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
import time
|
||||
import datetime
|
||||
import logging
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.tools import misc, DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.addons.hotel import date_utils
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -14,6 +13,8 @@ from odoo.addons import decimal_precision as dp
|
||||
|
||||
|
||||
class HotelServiceLine(models.Model):
|
||||
_name = 'hotel.service.line'
|
||||
_description = 'hotel Service line'
|
||||
|
||||
@api.one
|
||||
def copy(self, default=None):
|
||||
@@ -32,10 +33,11 @@ class HotelServiceLine(models.Model):
|
||||
@param field_name: Names of fields.
|
||||
@param arg: User defined arguments
|
||||
'''
|
||||
for folio in self:
|
||||
line = folio.service_line_id
|
||||
x = line._amount_line(field_name, arg)
|
||||
return x
|
||||
total_amount = 0
|
||||
for record in self:
|
||||
line = record.service_line_id
|
||||
total_amount += line._amount_line(field_name, arg)
|
||||
return total_amount
|
||||
|
||||
@api.multi
|
||||
def _number_packages(self, field_name, arg):
|
||||
@@ -44,10 +46,11 @@ class HotelServiceLine(models.Model):
|
||||
@param field_name: Names of fields.
|
||||
@param arg: User defined arguments
|
||||
'''
|
||||
for folio in self:
|
||||
line = folio.service_line_id
|
||||
x = line._number_packages(field_name, arg)
|
||||
return x
|
||||
total_packages = 0
|
||||
for record in self:
|
||||
line = record.service_line_id
|
||||
total_packages = line._number_packages(field_name, arg)
|
||||
return total_packages
|
||||
|
||||
@api.model
|
||||
def _service_checkin(self):
|
||||
@@ -69,8 +72,6 @@ class HotelServiceLine(models.Model):
|
||||
limit=1)
|
||||
return False
|
||||
|
||||
_name = 'hotel.service.line'
|
||||
_description = 'hotel Service line'
|
||||
# The record's name
|
||||
name = fields.Char('Service line', required=True)
|
||||
# services in the hotel are products
|
||||
@@ -93,13 +94,14 @@ class HotelServiceLine(models.Model):
|
||||
('web','Web')], 'Sales Channel')
|
||||
|
||||
ser_checkin = fields.Datetime('From Date', required=True,
|
||||
default=_service_checkin)
|
||||
default=_service_checkin)
|
||||
ser_checkout = fields.Datetime('To Date', required=True,
|
||||
default=_service_checkout)
|
||||
ser_room_line = fields.Many2one('hotel.reservation','Room', default=_default_ser_room_line)
|
||||
default=_service_checkout)
|
||||
ser_room_line = fields.Many2one('hotel.reservation', 'Room',
|
||||
default=_default_ser_room_line)
|
||||
|
||||
@api.model
|
||||
def create(self, vals, check=True):
|
||||
def create(self, vals):
|
||||
"""
|
||||
Overrides orm create method.
|
||||
@param self: The object pointer
|
||||
@@ -134,14 +136,17 @@ class HotelServiceLine(models.Model):
|
||||
@param self: object pointer
|
||||
'''
|
||||
if self.product_id:
|
||||
write_vals = {}
|
||||
if not (self.folio_id and self.folio_id.partner_id) and \
|
||||
self.ser_room_line:
|
||||
self.folio_id = self.ser_room_line.folio_id
|
||||
|
||||
self.name = self.product_id.name
|
||||
self.price_unit = self.product_id.lst_price
|
||||
self.product_uom = self.product_id.uom_id
|
||||
self.price_unit = self.product_id.price
|
||||
write_vals.update({'folio_id': self.ser_room_line.folio_id.id})
|
||||
write_vals.update({
|
||||
'name': self.product_id.name,
|
||||
'price_unit': self.product_id.lst_price,
|
||||
'product_uom': self.product_id.uom_id,
|
||||
'price_unit': self.product_id.price,
|
||||
})
|
||||
self.write(write_vals)
|
||||
|
||||
#~ self.price_unit = tax_obj._fix_tax_included_price(prod.price,
|
||||
#~ prod.taxes_id,
|
||||
@@ -208,26 +213,23 @@ class HotelServiceLine(models.Model):
|
||||
if self.ser_checkin and self.ser_checkout:
|
||||
diffDate = date_utils.date_diff(self.ser_checkin,
|
||||
self.ser_checkout, hours=False) + 1
|
||||
# FIXME: Finalize method!
|
||||
|
||||
@api.multi
|
||||
def button_confirm(self):
|
||||
'''
|
||||
@param self: object pointer
|
||||
'''
|
||||
for folio in self:
|
||||
line = folio.service_line_id
|
||||
x = line.button_confirm()
|
||||
return x
|
||||
self.ensure_one()
|
||||
self.service_line_id.button_confirm()
|
||||
|
||||
@api.multi
|
||||
def button_done(self):
|
||||
'''
|
||||
@param self: object pointer
|
||||
'''
|
||||
for folio in self:
|
||||
line = folio.service_line_id
|
||||
x = line.button_done()
|
||||
return x
|
||||
self.ensure_one()
|
||||
self.service_line_id.button_done()
|
||||
|
||||
@api.one
|
||||
def copy_data(self, default=None):
|
||||
@@ -235,8 +237,7 @@ class HotelServiceLine(models.Model):
|
||||
@param self: object pointer
|
||||
@param default: dict of default values to be set
|
||||
'''
|
||||
sale_line_obj = self.env['sale.order.line'
|
||||
].browse(self.service_line_id.id)
|
||||
sale_line_obj = self.env['sale.order.line'].browse(self.service_line_id.id)
|
||||
return sale_line_obj.copy_data(default=default)
|
||||
|
||||
@api.multi
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
@@ -6,10 +5,9 @@ from odoo import models, fields, api, _
|
||||
|
||||
|
||||
class HotelServiceType(models.Model):
|
||||
|
||||
_name = "hotel.service.type"
|
||||
_description = "Service Type"
|
||||
# The record's name
|
||||
|
||||
name = fields.Char('Service Type', required=True)
|
||||
# Used for activate records
|
||||
active = fields.Boolean('Active?', default=True)
|
||||
@@ -19,7 +17,7 @@ class HotelServiceType(models.Model):
|
||||
service_ids = fields.One2many('hotel.services', 'service_type_id',
|
||||
'Services in this category')
|
||||
|
||||
@api.multi
|
||||
def unlink(self):
|
||||
# self.ser_id.unlink()
|
||||
return super(HotelServiceType, self).unlink()
|
||||
# @api.multi
|
||||
# def unlink(self):
|
||||
# # self.ser_id.unlink()
|
||||
# return super(HotelServiceType, self).unlink()
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <alex@aloxa.eu>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from odoo import models, fields, api
|
||||
|
||||
|
||||
class VirtualRoomRestriction(models.Model):
|
||||
_name = 'hotel.virtual.room.restriction'
|
||||
|
||||
name = fields.Char('Restriction Plan Name', required=True)
|
||||
item_ids = fields.One2many('hotel.virtual.room.restriction.item',
|
||||
'restriction_id', string='Restriction Items',
|
||||
copy=True)
|
||||
active = fields.Boolean('Active',
|
||||
help='If unchecked, it will allow you to hide the \
|
||||
restriction plan without removing it.',
|
||||
default=True)
|
||||
|
||||
@api.multi
|
||||
@api.depends('name')
|
||||
def name_get(self):
|
||||
restriction_id = self.env['ir.default'].sudo().get(
|
||||
'res.config.settings', 'parity_restrictions_id')
|
||||
if restriction_id:
|
||||
restriction_id = int(restriction_id)
|
||||
names = []
|
||||
for record in self:
|
||||
if record.id == restriction_id:
|
||||
names.append((record.id, '%s (Parity)' % record.name))
|
||||
else:
|
||||
names.append((record.id, record.name))
|
||||
return names
|
||||
@@ -1,16 +1,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# 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
|
||||
from openerp import models, fields, api, _
|
||||
from openerp.exceptions import UserError, ValidationError
|
||||
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AccountInvoice(models.Model):
|
||||
|
||||
_inherit = 'account.invoice'
|
||||
|
||||
@api.model
|
||||
@@ -64,7 +61,8 @@ class AccountInvoice(models.Model):
|
||||
|
||||
@api.multi
|
||||
def action_invoice_open(self):
|
||||
to_open_invoices_without_vat = self.filtered(lambda inv: inv.state != 'open' and inv.partner_id.vat == False)
|
||||
to_open_invoices_without_vat = self.filtered(
|
||||
lambda inv: inv.state != 'open' and inv.partner_id.vat == False)
|
||||
if to_open_invoices_without_vat:
|
||||
vat_error = _("We need the VAT of the following companies")
|
||||
for invoice in to_open_invoices_without_vat:
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from decimal import Decimal
|
||||
import datetime
|
||||
# For Python 3.0 and later
|
||||
from urllib.request import urlopen
|
||||
import time
|
||||
import logging
|
||||
from openerp.exceptions import except_orm, UserError, ValidationError
|
||||
from openerp.tools import misc, DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from openerp.exceptions import except_orm
|
||||
from openerp import models, fields, api, _
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -40,7 +32,7 @@ class AccountPayment(models.Model):
|
||||
}
|
||||
return_vals = {
|
||||
'journal_id': journal.id,
|
||||
'line_ids': [(0,0,return_line_vals)],
|
||||
'line_ids': [(0, 0, return_line_vals)],
|
||||
}
|
||||
return_pay = self.env['payment.return'].create(return_vals)
|
||||
return {
|
||||
@@ -73,6 +65,7 @@ class AccountPayment(models.Model):
|
||||
@api.multi
|
||||
@api.depends('state')
|
||||
def _compute_folio_amount(self):
|
||||
# FIXME: Finalize method
|
||||
res = []
|
||||
fol = ()
|
||||
for payment in self:
|
||||
@@ -84,7 +77,7 @@ class AccountPayment(models.Model):
|
||||
])
|
||||
else:
|
||||
return
|
||||
if len(fol) == 0:
|
||||
if not any(fol):
|
||||
return
|
||||
elif len(fol) > 1:
|
||||
raise except_orm(_('Warning'), _('This pay is related with \
|
||||
|
||||
@@ -1,28 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# --------------------------------------------------------------------------
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2018-Darío Lodeiros Vázquez
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
#
|
||||
# ---------------------------------------------------------------------------
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from openerp import models, fields, api, _
|
||||
|
||||
|
||||
class PaymentReturn(models.Model):
|
||||
|
||||
_inherit = 'payment.return'
|
||||
|
||||
folio_id = fields.Many2one('hotel.folio', string='Folio')
|
||||
@@ -33,7 +14,9 @@ class PaymentReturn(models.Model):
|
||||
if pay:
|
||||
folio_ids = []
|
||||
for line in self.line_ids:
|
||||
payments = self.env['account.payment'].search([('move_line_ids','in',line.move_line_ids.ids)])
|
||||
folio_ids += payments.mapped('folio_id.id')
|
||||
payments = self.env['account.payment'].search([
|
||||
('move_line_ids', 'in', line.move_line_ids.ids)
|
||||
])
|
||||
folio_ids += payments.mapped('folio_id.id')
|
||||
folios = self.env['hotel.folio'].browse(folio_ids)
|
||||
folios.compute_amount()
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from openerp import models, fields, api, _
|
||||
|
||||
|
||||
class ProductCategory(models.Model):
|
||||
|
||||
_inherit = "product.category"
|
||||
|
||||
# isroomtype = fields.Boolean('Is Room Type')
|
||||
|
||||
@@ -1,23 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
from openerp import models, api
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
@@ -6,7 +5,6 @@ from openerp import models, fields, api, _
|
||||
|
||||
|
||||
class ProductProduct(models.Model):
|
||||
|
||||
_inherit = "product.product"
|
||||
|
||||
is_room_type = fields.Boolean('Is a Room Type', default=False)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
@@ -6,7 +5,6 @@ from openerp import models, fields, api, _
|
||||
|
||||
|
||||
class ResCompany(models.Model):
|
||||
|
||||
_inherit = 'res.company'
|
||||
|
||||
additional_hours = fields.Integer('Additional Hours',
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
@@ -6,23 +5,22 @@ from openerp import models, fields, api, _
|
||||
|
||||
|
||||
class ResPartner(models.Model):
|
||||
|
||||
_inherit = 'res.partner'
|
||||
|
||||
reservations_count = fields.Integer('Reservations',
|
||||
compute='_compute_reservations_count')
|
||||
folios_count = fields.Integer('Folios', compute='_compute_folios_count')
|
||||
|
||||
def _compute_reservations_count(self):
|
||||
hotel_reservation_obj = self.env['hotel.reservation']
|
||||
for partner in self:
|
||||
partner.reservations_count = hotel_reservation_obj.search_count([
|
||||
('partner_id.id', '=', partner.id)
|
||||
for record in self:
|
||||
record.reservations_count = hotel_reservation_obj.search_count([
|
||||
('partner_id.id', '=', record.id)
|
||||
])
|
||||
|
||||
def _compute_folios_count(self):
|
||||
hotel_folio_obj = self.env['hotel.folio']
|
||||
for partner in self:
|
||||
partner.folios_count = hotel_folio_obj.search_count([
|
||||
('partner_id.id', '=', partner.id)
|
||||
for record in self:
|
||||
record.folios_count = hotel_folio_obj.search_count([
|
||||
('partner_id.id', '=', record.id)
|
||||
])
|
||||
|
||||
reservations_count = fields.Integer('Reservations',
|
||||
compute='_compute_reservations_count')
|
||||
folios_count = fields.Integer('Folios', compute='_compute_folios_count')
|
||||
|
||||
@@ -1,24 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2018 Alexandre Díaz <dev@redneboa.es>
|
||||
#
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2017 Alexandre Díaz
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
@@ -28,13 +9,14 @@ class MailComposeMessage(models.TransientModel):
|
||||
|
||||
@api.multi
|
||||
def send_mail(self, auto_commit=False):
|
||||
if self._context.get('default_model') == 'hotel.folio' and self._context.get('default_res_id') and self._context.get('mark_so_as_sent'):
|
||||
if self._context.get('default_model') == 'hotel.folio' and \
|
||||
self._context.get('default_res_id') and self._context.get('mark_so_as_sent'):
|
||||
folio = self.env['hotel.folio'].browse([
|
||||
self._context['default_res_id']
|
||||
])
|
||||
if folio:
|
||||
cmds = []
|
||||
for lid in folio.room_lines._ids:
|
||||
for lid in folio.room_lines.ids:
|
||||
cmds.append((
|
||||
1,
|
||||
lid,
|
||||
|
||||
@@ -1,24 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2017 Solucións Aloxa S.L. <info@aloxa.eu>
|
||||
# Alexandre Díaz <alex@aloxa.eu>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
# Copyright 2017-2018 Alexandre Díaz
|
||||
# Copyright 2017 Dario Lodeiros
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||
import re
|
||||
import pytz
|
||||
from openerp import models, fields, api, _
|
||||
@@ -39,7 +21,7 @@ class HotelConfiguration(models.TransientModel):
|
||||
|
||||
parity_pricelist_id = fields.Many2one('product.pricelist',
|
||||
'Product Pricelist')
|
||||
parity_restrictions_id = fields.Many2one('hotel.virtual.room.restriction',
|
||||
parity_restrictions_id = fields.Many2one('hotel.room.type.restriction',
|
||||
'Restrictions')
|
||||
default_arrival_hour = fields.Char('Default Arrival Hour (GMT)',
|
||||
help="HH:mm Format", default="14:00")
|
||||
|
||||
Reference in New Issue
Block a user