diff --git a/hotel_data_bi/README.rst b/hotel_data_bi/README.rst new file mode 100644 index 000000000..accc16833 --- /dev/null +++ b/hotel_data_bi/README.rst @@ -0,0 +1,74 @@ +REVENUE EXPORTER +============= + +Export Odoo data for Revenue MyDataBI + +Usage +======= +To use this module, you need to: + +Create a user and give the "Hotel Management / Export data BI" permission. + +To connect to Odoo via xmlrpc there are examples in https://www.odoo.com/documentation/10.0/api_integration.html in the "Calling methods" section with examples in several languages. + +A python example: +import xmlrpclib + +url = 'https://www.example.org' + +username = 'username@example.org' + +password = '123passwordexample' + +db = 'example_db_name' + +common = xmlrpclib.ServerProxy('{}/xmlrpc/2/common'.format(url)) + +uid = common.authenticate(db, username, password, {}) + +models = xmlrpclib.ServerProxy('{}/xmlrpc/2/object'.format(url)) + +models.execute_kw(db, uid, password,'data_bi','export_data_bi', [ 8, '2018-01-01']) + +In the parameters of export_data_bi: + +archivo == 1 'Tarifa' + +archivo == 2 'Canal' + +archivo == 3 'Hotel' + +archivo == 4 'Pais' + +archivo == 5 'Regimen' + +archivo == 6 'Reservas' + +archivo == 7 'Capacidad' + +archivo == 8 'Tipo Habitación' + +archivo == 9 'Budget' + +archivo == 10 'Bloqueos' + +archivo == 11 'Motivo Bloqueo' + +archivo == 12 'Segmentos' + +archivo == 13 'Clientes' + +archivo == 14 'Estado Reservas' + +fechafoto = start date to take data + +in the example recive 8 'Tipo Habitación' from '2018-01-01' + + +Credits +======= + +Creator +------------ + +* Jose Luis Algara (Alda hotels) diff --git a/hotel_data_bi/__init__.py b/hotel_data_bi/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/hotel_data_bi/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/hotel_data_bi/__manifest__.py b/hotel_data_bi/__manifest__.py new file mode 100644 index 000000000..2b398871e --- /dev/null +++ b/hotel_data_bi/__manifest__.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# Copyright 2018-2019 Jose Luis Algara Toledo +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + 'name': 'Hotel Data Bi', + 'description': """ + Export hotel data for business intelligence + + To use this module you need to: + + Create a user and give the 'Hotel Management/Export data BI' permission. + """, + 'summary': "Export hotel data for business intelligence", + 'version': '2.0', + 'license': 'AGPL-3', + 'author': "Jose Luis Algara (Alda hotels) ", + 'website': 'www.aldahotels.com', + 'depends': ['hotel', 'hotel_l10n_es', 'hotel_channel_connector'], + 'category': 'hotel/revenue', + 'data': [ + 'views/budget.xml', + 'views/inherit_res_company.xml', + 'security/data_bi.xml', + 'security/ir.model.access.csv', + ], + 'demo': [ + ], + 'installable': True, + 'auto_install': False, + 'application': False, +} diff --git a/hotel_data_bi/models/__init__.py b/hotel_data_bi/models/__init__.py new file mode 100644 index 000000000..1de849e11 --- /dev/null +++ b/hotel_data_bi/models/__init__.py @@ -0,0 +1,3 @@ +from . import inherit_res_company +from . import budget +from . import data_bi diff --git a/hotel_data_bi/models/budget.py b/hotel_data_bi/models/budget.py new file mode 100644 index 000000000..b184fbad4 --- /dev/null +++ b/hotel_data_bi/models/budget.py @@ -0,0 +1,48 @@ +# Copyright 2019 Jose Luis Algara (Alda hotels) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models +from datetime import date + + +def get_years(): + """Return a year list, to select in year field.""" + year_list = [] + for i in range(2018, 2036): + year_list.append((i, str(i))) + return year_list + + +class Budget(models.Model): + """Establish and save the budget for DataBI control by revenue""" + + _name = 'budget' + + # fecha Primer día del mes + month = fields.Selection([(1, 'January'), (2, 'February'), (3, 'March'), + (4, 'April'), (5, 'May'), (6, 'June'), + (7, 'July'), (8, 'August'), (9, 'September'), + (10, 'October'), (11, 'November'), + (12, 'December'), ], + string='Month', required=True) + year = fields.Selection(get_years(), string='Year', required=True) + room_nights = fields.Float("Room Nights", required=True, digits=(6, 2)) + # Número de Room Nights + room_revenue = fields.Float("Room Revenue", required=True, digits=(6, 2)) + # Ingresos por Reservas + estancias = fields.Integer("Number of Stays") # Número de Estancias + # ID_Tarifa numérico Código de la Tarifa + # ID_Canal numérico Código del Canal + # ID_Pais numérico Código del País + # ID_Regimen numérico Cóigo del Régimen + # ID_Tipo_Habitacion numérico Código del Tipo de Habitación + # iD_Segmento numérico Código del Segmento + # ID_Cliente numérico Código del Cliente + # Pension_Revenue numérico con dos decimales Ingresos por Pensión + + @api.model + def export_data_bi(self, + archivo=False, + fechafoto=date.today().strftime('%Y-%m-%d')): + apidata = self.env['data_bi'] + return apidata.export_data_bi(self) diff --git a/hotel_data_bi/models/data_bi.py b/hotel_data_bi/models/data_bi.py new file mode 100644 index 000000000..bd7ce8ec4 --- /dev/null +++ b/hotel_data_bi/models/data_bi.py @@ -0,0 +1,548 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2018 -2019 Alda Hotels +# Jose Luis Algara +# +# 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 . +# +############################################################################## +from openerp import models, api, _ +from datetime import date, datetime, timedelta +import json +import logging +_logger = logging.getLogger(__name__) + + +def inv_percent(amount, percent): + """Return the amount to which a percentage was applied.""" + return round(amount*(100/float(100-percent)) - amount, 2) + + +class Data_Bi(models.Model): + """Management and export data for MopSolution MyDataBI.""" + + _name = 'data_bi' + + @api.model + def export_data_bi(self, + archivo=False, + fechafoto=date.today().strftime('%Y-%m-%d')): + u"""Prepare a Json Objet to export data for MyDataBI. + + Generate a dicctionary to by send in JSON + archivo = response file type + archivo == 0 'ALL' + archivo == 1 'Tarifa' + archivo == 2 'Canal' + archivo == 3 'Hotel' + archivo == 4 'Pais' + archivo == 5 'Regimen' + archivo == 6 'Reservas' + archivo == 7 'Capacidad' + archivo == 8 'Tipo Habitación' + archivo == 9 'Budget' + archivo == 10 'Bloqueos' + archivo == 11 'Motivo Bloqueo' + archivo == 12 'Segmentos' + archivo == 13 'Clientes' + archivo == 14 'Estado Reservas' + fechafoto = start date to take data + """ + + if type(fechafoto) is dict: + fechafoto = date.today() + else: + fechafoto = datetime.strptime(fechafoto, '%Y-%m-%d').date() + + _logger.warning("Init Export Data_Bi Module") + if not isinstance(archivo, int): + archivo = 0 + dic_param = [] + dic_param.append({'Archivo': archivo, + 'Fechafoto': fechafoto.strftime('%Y-%m-%d')}) + compan = self.env.user.company_id + limit_ago = (fechafoto - timedelta( + days=self.env.user.company_id.data_bi_days)).strftime('%Y-%m-%d') + + dic_export = [] # Diccionario con todo lo necesario para exportar. + if (archivo == 0) or (archivo == 7) or (archivo == 8): + room_types = self.env['hotel.room.type'].search([]) + if (archivo == 0) or (archivo == 10) or (archivo == 6): + line_res = self.env['hotel.reservation.line'].search( + [('date', '>=', limit_ago)], order="id") + estado_array = ['draft', 'confirm', 'booking', 'done', 'cancelled'] + + if (archivo == 0) or (archivo == 1): + dic_tarifa = self.data_bi_tarifa(compan.id_hotel) + dic_export.append({'Tarifa': dic_tarifa}) + if (archivo == 0) or (archivo == 2): + dic_canal = self.data_bi_canal(compan.id_hotel) + dic_export.append({'Canal': dic_canal}) + if (archivo == 0) or (archivo == 3): + dic_hotel = self.data_bi_hotel(compan) + dic_export.append({'Hotel': dic_hotel}) + if (archivo == 0) or (archivo == 4): + dic_pais = self.data_bi_pais(compan.id_hotel) + dic_export.append({'Pais': dic_pais}) + if (archivo == 0) or (archivo == 5): + dic_regimen = self.data_bi_regimen(compan.id_hotel) + dic_export.append({'Regimen': dic_regimen}) + if (archivo == 0) or (archivo == 7): + dic_capacidad = self.data_bi_capacidad(compan.id_hotel, room_types) + dic_export.append({'Capacidad': dic_capacidad}) + if (archivo == 0) or (archivo == 8): + dic_tipo_habitacion = self.data_bi_habitacione(compan.id_hotel, + room_types) + dic_export.append({'Tipo Habitación': dic_tipo_habitacion}) + if (archivo == 0) or (archivo == 9): + dic_budget = self.data_bi_budget(compan.id_hotel) + dic_export.append({'Budget': dic_budget}) + if (archivo == 0) or (archivo == 10): + dic_bloqueos = self.data_bi_bloqueos(compan.id_hotel, line_res) + dic_export.append({'Bloqueos': dic_bloqueos}) + if (archivo == 0) or (archivo == 11): + dic_moti_bloq = self.data_bi_moti_bloq(compan.id_hotel) + dic_export.append({'Motivo Bloqueo': dic_moti_bloq}) + if (archivo == 0) or (archivo == 12): + dic_segmentos = self.data_bi_segment(compan.id_hotel) + dic_export.append({'Segmentos': dic_segmentos}) + if (archivo == 0) or (archivo == 13) or (archivo == 6): + dic_clientes = self.data_bi_client(compan.id_hotel) + dic_export.append({'Clientes': dic_clientes}) + if (archivo == 0) or (archivo == 14): + dic_estados = self.data_bi_estados(compan.id_hotel, estado_array) + dic_export.append({'Estado Reservas': dic_estados}) + if (archivo == 0) or (archivo == 6): + dic_reservas = self.data_bi_reservas(compan.id_hotel, + line_res, + estado_array, + dic_clientes) + dic_export.append({'Reservas': dic_reservas}) + + dictionaryToJson = json.dumps(dic_export) + _logger.warning("End Export Data_Bi Module to Json") + # Debug Stop ------------------- + # import wdb; wdb.set_trace() + # Debug Stop ------------------- + + return dictionaryToJson + + @api.model + def data_bi_tarifa(self, compan): + _logger.info("DataBi: Calculating all fees") + dic_tarifa = [] # Diccionario con las tarifas + tarifas = self.env['product.pricelist'].search_read([], ['name']) + for tarifa in tarifas: + dic_tarifa.append({'ID_Hotel': compan, + 'ID_Tarifa': tarifa['id'], + 'Descripcion': tarifa['name']}) + return dic_tarifa + + @api.model + def data_bi_canal(self, compan): + _logger.info("DataBi: Calculating all channels") + dic_canal = [] # Diccionario con los Canales + canal_array = ['Puerta', 'Mail', 'Telefono', 'Call Center', 'Web', + 'Agencia', 'Touroperador', 'Virtual Door'] + for i in range(0, len(canal_array)): + dic_canal.append({'ID_Hotel': compan, + 'ID_Canal': i, + 'Descripcion': canal_array[i]}) + return dic_canal + + @api.model + def data_bi_hotel(self, compan): + _logger.info("DataBi: Calculating hotel names") + dic_hotel = [] # Diccionario con el/los nombre de los hoteles + dic_hotel.append({'ID_Hotel': compan.id_hotel, + 'Descripcion': compan.property_name}) + return dic_hotel + + @api.model + def data_bi_pais(self, compan): + _logger.info("DataBi: Calculating all countries") + dic_pais = [] + # Diccionario con los nombre de los Paises usando los del INE + paises = self.env['code.ine'].search_read([], ['code', 'name']) + for pais in paises: + dic_pais.append({'ID_Hotel': compan, + 'ID_Pais': pais['code'], + 'Descripcion': pais['name']}) + return dic_pais + + @api.model + def data_bi_regimen(self, compan): + _logger.info("DataBi: Calculating all board services") + dic_regimen = [] # Diccionario con los Board Services + board_services = self.env['hotel.board.service'].search_read([]) + dic_regimen.append({'ID_Hotel': compan, + 'ID_Regimen': 0, + 'Descripcion': 'Sin régimen'}) + for board_service in board_services: + dic_regimen.append({'ID_Hotel': compan, + 'ID_Regimen': board_service['id'], + 'Descripcion': board_service['name']}) + return dic_regimen + + @api.model + def data_bi_estados(self, compan, estado_array): + _logger.info("DataBi: Calculating all the states of the reserves") + dic_estados = [] # Diccionario con los Estados Reserva + estado_array_txt = ['Borrador', 'Confirmada', 'Hospedandose', + 'Checkout', 'Cancelada'] + # estado_array = ['draft', 'confirm', 'booking', 'done', 'cancelled'] + for i in range(0, len(estado_array)): + dic_estados.append({'ID_Hotel': compan, + 'ID_EstadoReserva': i, + 'Descripcion': estado_array_txt[i]}) + return dic_estados + + @api.model + def data_bi_habitacione(self, compan, rooms): + _logger.info("DataBi: Calculating all room types") + dic_tipo_habitacion = [] # Diccionario con Rooms types + for room in rooms: + dic_tipo_habitacion.append({ + 'ID_Hotel': compan, + 'ID_Tipo_Habitacion': room['id'], + 'Descripcion': room['name'], + 'Estancias': room['capacity']}) + return dic_tipo_habitacion + + @api.model + def data_bi_capacidad(self, compan, rooms): + _logger.info("DataBi: Calculating all the capacitys") + dic_capacidad = [] # Diccionario con las capacidades + for room in rooms: + dic_capacidad.append({ + 'ID_Hotel': compan, + 'Hasta_Fecha': + (date.today() + timedelta(days=365 * 3)).strftime("%Y-%m-%d"), + 'ID_Tipo_Habitacion': room['id'], + 'Nro_Habitaciones': room['total_rooms_count']}) + return dic_capacidad + + @api.model + def data_bi_budget(self, compan): + _logger.info("DataBi: Calculating budget") + budgets = self.env['budget'].search([]) + dic_budget = [] # Diccionario con las previsiones Budget + for budget in budgets: + dic_budget.append({'ID_Hotel': compan, + 'Fecha': str(budget.year) + '-' + + str(budget.month).zfill(2) + '-01', + # 'ID_Tarifa': 0, + # 'ID_Canal': 0, + # 'ID_Pais': 0, + # 'ID_Regimen': 0, + # 'ID_Tipo_Habitacion': 0, + # 'ID_Cliente': 0, + 'Room_Nights': budget.room_nights, + 'Room_Revenue': budget.room_revenue, + # 'Pension_Revenue': 0, + 'Estancias': budget.estancias}) + # Fecha fecha Primer día del mes + # ID_Tarifa numérico Código de la Tarifa + # ID_Canal numérico Código del Canal + # ID_Pais numérico Código del País + # ID_Regimen numérico Cóigo del Régimen + # ID_Tipo_Habitacion numérico Código del Tipo de Habitación + # iD_Segmento numérico Código del Segmento + # ID_Cliente numérico Código del Cliente + # Pension_Revenue numérico con dos decimales Ingresos por Pensión + return dic_budget + + @api.model + def data_bi_moti_bloq(self, compan): + _logger.info("DataBi: Calculating all blocking reasons") + dic_moti_bloq = [] # Diccionario con Motivo de Bloqueos + bloqeo_array = ['Staff', _('Out of Service')] + for i in range(0, len(bloqeo_array)): + dic_moti_bloq.append({'ID_Hotel': compan, + 'ID_Motivo_Bloqueo': i, + 'Descripcion': bloqeo_array[i]}) + return dic_moti_bloq + + @api.model + def data_bi_segment(self, compan): + _logger.info("DataBi: Calculating all the segmentations") + dic_segmentos = [] # Diccionario con Segmentación + lineas = self.env['res.partner.category'].search([]) + for linea in lineas: + if linea.parent_id.name: + seg_desc = linea.parent_id.name + " / " + linea.name + dic_segmentos.append({'ID_Hotel': compan, + 'ID_Segmento': linea.id, + 'Descripcion': seg_desc}) + return dic_segmentos + + @api.model + def data_bi_client(self, compan): + dic_clientes = [] # Diccionario con Clientes (OTAs y agencias) + dic_clientes.append({'ID_Hotel': compan, + 'ID_Cliente': 0, + 'Descripcion': u'Ninguno'}) + lineas = self.env['channel.ota.info'].search([]) + + for linea in lineas: + dic_clientes.append({'ID_Hotel': compan, + 'ID_Cliente': linea.id, + 'Descripcion': linea.name}) + + lineas = self.env['res.partner'].search([('is_tour_operator', + '=', True)]) + id_cli_count = 700 + for linea in lineas: + dic_clientes.append({'ID_Hotel': compan, + 'ID_Cliente': id_cli_count, + 'Descripcion': linea.name}) + id_cli_count += 1 + + dic_clientes.append({'ID_Hotel': compan, + 'ID_Cliente': 999, + 'Descripcion': u'Web Propia'}) + dic_clientes.append({'ID_Hotel': compan, + 'ID_Cliente': 901, + 'Descripcion': u'Expedia Empaquedata'}) + dic_clientes.append({'ID_Hotel': compan, + 'ID_Cliente': 902, + 'Descripcion': u'Expedia Sin Comisión'}) + dic_clientes.append({'ID_Hotel': compan, + 'ID_Cliente': 903, + 'Descripcion': u'Puerta'}) + dic_clientes.append({'ID_Hotel': compan, + 'ID_Cliente': 904, + 'Descripcion': u'E-Mail'}) + dic_clientes.append({'ID_Hotel': compan, + 'ID_Cliente': 905, + 'Descripcion': u'Teléfono'}) + dic_clientes.append({'ID_Hotel': compan, + 'ID_Cliente': 906, + 'Descripcion': u'Call-Center'}) + dic_clientes.append({'ID_Hotel': compan, + 'ID_Cliente': 907, + 'Descripcion': u'Agencia'}) + dic_clientes.append({'ID_Hotel': compan, + 'ID_Cliente': 908, + 'Descripcion': u'Touroperador'}) + return dic_clientes + + @api.model + def data_bi_bloqueos(self, compan, lines): + _logger.info("DataBi: Calculating all reservations blocked") + dic_bloqueos = [] # Diccionario con Bloqueos + lines = lines.filtered( + lambda n: (n.reservation_id.reservation_type != 'normal') and ( + n.reservation_id.state != 'cancelled')) + for line in lines: + # if linea.reservation_id.state != 'cancelled': + if line.reservation_id.reservation_type == 'out': + id_m_b = 1 + else: + id_m_b = 0 + dic_bloqueos.append({ + 'ID_Hotel': compan, + 'Fecha_desde': line.date, + 'Fecha_hasta': (datetime.strptime(line.date, "%Y-%m-%d") + + timedelta(days=1)).strftime("%Y-%m-%d"), + 'ID_Tipo_Habitacion': line.reservation_id.room_type_id.id, + 'ID_Motivo_Bloqueo': id_m_b, + 'Nro_Habitaciones': 1}) + return dic_bloqueos + + @api.model + def data_bi_reservas(self, compan, lineas, estado_array, dic_clientes): + dic_reservas = [] + lineas = lineas.filtered( + lambda n: (n.reservation_id.reservation_type == 'normal') and ( + n.price > 0)) + channels = {'door': 0, + 'mail': 1, + 'phone': 2, + 'call': 3, + 'web': 4, + 'agency': 5, + 'operator': 6, + 'virtualdoor': 7} + + for linea in lineas: + id_segmen = 0 + if len(linea.reservation_id.segmentation_ids) > 0: + id_segmen = linea.reservation_id.segmentation_ids[0].id + elif len(linea.reservation_id.partner_id.category_id) > 0: + id_segmen = ( + linea.reservation_id.partner_id.category_id[0].id) + precio_neto = linea.price + precio_dto = 0 + precio_iva = 0 + precio_comision = 0 + + if linea.reservation_id.ota_id.id: + ota_prices = self.data_bi_comisiones_ota(linea) + precio_neto = ota_prices[0]['precio_neto'] + precio_dto = ota_prices[0]['precio_dto'] + precio_iva = ota_prices[0]['precio_iva'] + precio_comision = ota_prices[0]['precio_comision'] + + # if linea.reservation_id.id == 6742: + # # # Debug Stop ------------------- + # import wdb; wdb.set_trace() + # # # Debug Stop ------------------- + if linea.reservation_id.discount != 0: + precio_dto = linea.price * ( + linea.reservation_id.discount/100) + + dic_reservas.append({ + 'ID_Reserva': linea.reservation_id.folio_id.name, + 'ID_Hotel': compan, + 'ID_EstadoReserva': estado_array.index( + linea.reservation_id.state), + 'FechaVenta': linea.reservation_id.create_date[0:10], + 'ID_Segmento': id_segmen, + # 'ID_Cliente': channel_c, + 'ID_Canal': channels[linea.reservation_id.channel_type], + 'FechaExtraccion': date.today().strftime('%Y-%m-%d'), + 'Entrada': linea.date, + 'Salida': (datetime.strptime(linea.date, "%Y-%m-%d") + + timedelta(days=1)).strftime("%Y-%m-%d"), + 'Noches': 1, + 'ID_TipoHabitacion': linea.reservation_id.room_type_id.id, + 'ID_HabitacionDuerme': + linea.reservation_id.room_id.room_type_id.id, + 'ID_Regimen': 0, + 'Adultos': linea.reservation_id.adults, + 'Menores': linea.reservation_id.children, + 'Cunas': 0, + 'PrecioDiario': precio_neto, + 'PrecioComision': precio_comision, + 'PrecioIva': precio_iva, + 'PrecioDto': precio_dto, + 'ID_Tarifa': linea.reservation_id.pricelist_id.id, + # 'ID_Pais': id_codeine + }) + # ID_Reserva numérico Código único de la reserva + # ID_Hotel numérico Código del Hotel + # ID_EstadoReserva numérico Código del estado de la reserva + # FechaVenta fecha Fecha de la venta de la reserva + # ID_Segmento numérico Código del Segmento de la reserva + # ID_Cliente Numérico Código del Cliente de la reserva + # ID_Canal numérico Código del Canal + # FechaExtraccion fecha Fecha de la extracción de los datos (Foto) + # Entrada fecha Fecha de entrada + # Salida fecha Fecha de salida + # Noches numérico Nro. de noches de la reserva + # ID_TipoHabitacion numérico Código del Tipo de Habitación + # ID_Regimen numérico Código del Tipo de Régimen + # Adultos numérico Nro. de adultos + # Menores numérico Nro. de menores + # Cunas numérico Nro. de cunas + # PrecioDiario numérico con 2 decimales Precio por noche de la reserva + # ID_Tarifa numérico Código de la tarifa aplicada a la reserva + # ID_Pais numérico Código del país + return dic_reservas + + @api.model + def data_bi_comisiones_ota(self, reserva): + response_dic = [] + precio_neto = reserva.price + precio_comision = 0 + precio_iva = 0 + precio_dto = 0 + if reserva.reservation_id.ota_id.ota_id == "2": + # Booking. 15% comision + precio_comision = (precio_neto*15/100) + precio_neto -= precio_comision + precio_iva = (precio_neto*10/100) + precio_neto -= precio_iva + + if reserva.reservation_id.ota_id.ota_id == "9": + # Hotelbeds 20% comision + precio_comision = (precio_neto*20/100) + precio_neto -= precio_comision + precio_iva = (precio_neto*10/100) + precio_neto -= precio_iva + + if reserva.reservation_id.ota_id.ota_id == "11": + # HRS 20% comision + precio_comision = (precio_neto*20/100) + precio_neto -= precio_comision + precio_iva = (precio_neto*10/100) + precio_neto -= precio_iva + + if reserva.reservation_id.ota_id.ota_id == "1": + # Expedia. + precio_comision = (precio_neto*15/100) + precio_neto -= precio_comision + precio_iva = (precio_neto*10/100) + precio_neto -= precio_iva + data = json.loads( + reserva.reservation_id.channel_bind_ids.channel_raw_data) + + jsonBooked = data['booked_rooms'][0] + if jsonBooked.get('ancillary').get( + 'channel_rate_name') is not None: + jsonRate = jsonBooked.get('ancillary').get( + 'channel_rate_name') + # _logger.warning("EXPEDIA ancillary : %s - %s", + # jsonRate, reserva.id) + + elif jsonBooked.get('roomdays')[0].get( + 'ancillary').get( + 'channel_rate_name') is not None: + jsonRate = jsonBooked.get( + 'roomdays')[0].get( + 'ancillary').get('channel_rate_name') + # _logger.warning("EXPEDIA roomdays : %s - %s", + # jsonRate, reserva.id) + + else: + _logger.critical( + "EXPEDIA Tarifa No Contemplada : " + + jsonBooked) + + jsonRefundable = jsonRate.upper().find('REFUNDABLE') + # _logger.warning("EXPEDIA Tarifa : %s", jsonRate) + # _logger.warning("EXPEDIA Tarifa : %s y %s", + # jsonRate, str(jsonRefundable)) + + # 10 % Iva + precio_iva = round((precio_neto-(precio_neto/1.1)), 2) + # 18 % comision ? + precio_comision = inv_percent( + precio_neto, self.env.user.company_id.expedia_rate) + precio_neto += precio_comision + # 3% Refundable ? + if jsonRefundable >= 0: + precio_dto = inv_percent(precio_neto, 3) + precio_neto += precio_dto + # _logger.warning("ODOO: %s , precio_neto: %s , precio_comision: \ + # %s , precio_iva: %s , precio_dto: %s", reserva.price, + # precio_neto, precio_comision, precio_iva, + # precio_dto) + + response_dic.append({'ota': reserva.reservation_id.ota_id.id, + 'ota_id': reserva.reservation_id.ota_id.ota_id, + 'precio_odoo': reserva.price, + 'precio_neto': precio_neto, + 'precio_comision': precio_comision, + 'precio_iva': precio_iva, + 'precio_dto': precio_dto, + }) + return response_dic + + # # Debug Stop ------------------- + # import wdb; wdb.set_trace() + # # Debug Stop ------------------- diff --git a/hotel_data_bi/models/inherit_res_company.py b/hotel_data_bi/models/inherit_res_company.py new file mode 100644 index 000000000..303bf541a --- /dev/null +++ b/hotel_data_bi/models/inherit_res_company.py @@ -0,0 +1,24 @@ +# Copyright 2019 Jose Luis Algara (Alda hotels) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class Inherit_res_company(models.Model): + _inherit = 'res.company' + + id_hotel = fields.Integer( + 'Unique ID for DataBI', default=0, + help='It must be unique to be able to identify the hotel, \ + within a hotel group.') + expedia_rate = fields.Integer( + 'Expedia Rate DataBI', + default=18, required=True, digits=(2), + help='It is the commission percentage negotiated with the \ + Expedia company, expressed with two digits. \ + Example: 18 = 18% commission.') + data_bi_days = fields.Integer( + 'Days to download', + default=60, required=True, digits=(3), + help='Number of days, which are downloaded data, \ + backwards, by default are 60 days to download.') diff --git a/hotel_data_bi/security/data_bi.xml b/hotel_data_bi/security/data_bi.xml new file mode 100644 index 000000000..521038794 --- /dev/null +++ b/hotel_data_bi/security/data_bi.xml @@ -0,0 +1,10 @@ + + + + + + + Hotel Management / Export data BI + + + diff --git a/hotel_data_bi/security/ir.model.access.csv b/hotel_data_bi/security/ir.model.access.csv new file mode 100644 index 000000000..99a2df307 --- /dev/null +++ b/hotel_data_bi/security/ir.model.access.csv @@ -0,0 +1,14 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +ir_model_hotel_budget,hoteldatabi.budget.manager,hotel_data_bi.model_budget,hotel.group_hotel_manager,1,1,1,1 +ir_model_hotel_budget_user,hoteldatabi.budget.user,hotel_data_bi.model_budget,hotel.group_hotel_user,0,0,0,0 +ir_model_hotel_data_bi_export_data,hoteldatabi.data_bi.export_data,hotel_data_bi.model_data_bi,hotel_data_bi.group_hotel_export_data,1,0,0,0 +access_room_type,hoteldatabi.hotel_room_type,hotel.model_hotel_room_type,hotel_data_bi.group_hotel_export_data,1,0,0,0 +access_hotel_reservation_line,hoteldatabi.hotel_reservation_line,hotel.model_hotel_reservation_line,hotel_data_bi.group_hotel_export_data,1,0,0,0 +access_hotel_reservation,hoteldatabi.hotel_reservation,hotel.model_hotel_reservation,hotel_data_bi.group_hotel_export_data,1,0,0,0 +access_hotel_board_service,hoteldatabi.hotel_board_service,hotel.model_hotel_board_service,hotel_data_bi.group_hotel_export_data,1,0,0,0 +access_code_ine,hoteldatabi.code_ine,hotel_l10n_es.model_code_ine,hotel_data_bi.group_hotel_export_data,1,0,0,0 +access_budget ,hoteldatabi.budget,hotel_data_bi.model_budget,hotel_data_bi.group_hotel_export_data,1,0,0,0 +access_channel_ota_info,hoteldatabi.channel_ota_info,hotel_channel_connector.model_channel_ota_info,hotel_data_bi.group_hotel_export_data,1,0,0,0 +access_hotel_folio,hoteldatabi.hotel_folio,hotel.model_hotel_folio,hotel_data_bi.group_hotel_export_data,1,0,0,0 +access_hotel_room,hoteldatabi.hotel_room,hotel.model_hotel_room,hotel_data_bi.group_hotel_export_data,1,0,0,0 +access_channel_hotel_reservation,hoteldatabi.channel_hotel_reservation,hotel_channel_connector.model_channel_hotel_reservation,hotel_data_bi.group_hotel_export_data,1,0,0,0 diff --git a/hotel_data_bi/static/description/icon.png b/hotel_data_bi/static/description/icon.png new file mode 100644 index 000000000..0ad91d0d3 Binary files /dev/null and b/hotel_data_bi/static/description/icon.png differ diff --git a/hotel_data_bi/views/budget.xml b/hotel_data_bi/views/budget.xml new file mode 100644 index 000000000..6c380fb6b --- /dev/null +++ b/hotel_data_bi/views/budget.xml @@ -0,0 +1,71 @@ + + + + + + + + + + + budget.form (in hotel_data_bi) + budget + +
+ + + + +
+
+
+ + + + + +
+
+
+
+
+
+
+
+
+ + + + budget.tree (in hotel_data_bi) + budget + + + + + + + + + + + +
diff --git a/hotel_data_bi/views/inherit_res_company.xml b/hotel_data_bi/views/inherit_res_company.xml new file mode 100644 index 000000000..05b3865ab --- /dev/null +++ b/hotel_data_bi/views/inherit_res_company.xml @@ -0,0 +1,23 @@ + + + + + + + + databi.config.view_company_form + res.company + + + + + + + + + + + + + +