diff --git a/hotel_ine/__init__.py b/hotel_ine/__init__.py new file mode 100644 index 000000000..c6369ae7d --- /dev/null +++ b/hotel_ine/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 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 . import wizard +from . import models diff --git a/hotel_ine/__manifest__.py b/hotel_ine/__manifest__.py new file mode 100644 index 000000000..00247262e --- /dev/null +++ b/hotel_ine/__manifest__.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Odoo, Open Source Management Solution +# Copyright (C) 2019 Jose Luis Algara Toledo +# +# 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 . +# +############################################################################## +{ + 'name': 'Hotel Ine', + 'description': """ + Create de INE Report""", + 'version': '1.0.0', + 'license': 'AGPL-3', + 'summary': "Export hotel data for INE report", + 'author': "Jose Luis Algara (Alda hotels) ", + 'website': 'www.aldahotels.com', + 'depends': ['hotel', 'hotel_l10n_es'], + 'category': 'hotel/ine', + 'data': [ + 'wizard/inewizard.xml', + 'views/inherited_hotel_room_view.xml', + ], + 'demo': [ + ], + 'installable': True, + 'auto_install': False, + 'application': False, +} diff --git a/hotel_ine/models/__init__.py b/hotel_ine/models/__init__.py new file mode 100644 index 000000000..c96e3b034 --- /dev/null +++ b/hotel_ine/models/__init__.py @@ -0,0 +1 @@ +from . import inherited_hotel_room diff --git a/hotel_ine/models/inherited_hotel_room.py b/hotel_ine/models/inherited_hotel_room.py new file mode 100644 index 000000000..cbd11348a --- /dev/null +++ b/hotel_ine/models/inherited_hotel_room.py @@ -0,0 +1,9 @@ +# Copyright 2019 Jose Luis Algara +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +from odoo import models, fields + + +class HotelRoom(models.Model): + _inherit = 'hotel.room' + + in_ine = fields.Boolean('Included in the INE statistics', default=True) diff --git a/hotel_ine/static/description/icon.png b/hotel_ine/static/description/icon.png new file mode 100755 index 000000000..c066d3473 Binary files /dev/null and b/hotel_ine/static/description/icon.png differ diff --git a/hotel_ine/views/inherited_hotel_room_view.xml b/hotel_ine/views/inherited_hotel_room_view.xml new file mode 100644 index 000000000..7f0a2ba51 --- /dev/null +++ b/hotel_ine/views/inherited_hotel_room_view.xml @@ -0,0 +1,18 @@ + + + + + hotel.room + + + + + + + + + + + + + diff --git a/hotel_ine/wizard/__init__.py b/hotel_ine/wizard/__init__.py new file mode 100644 index 000000000..53a5cd324 --- /dev/null +++ b/hotel_ine/wizard/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 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 . import inewizard diff --git a/hotel_ine/wizard/inewizard.py b/hotel_ine/wizard/inewizard.py new file mode 100644 index 000000000..d6d498663 --- /dev/null +++ b/hotel_ine/wizard/inewizard.py @@ -0,0 +1,315 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2017-19 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, fields, api +import base64 +import datetime +import calendar +import xml.etree.cElementTree as ET +from odoo.exceptions import UserError +import logging +_logger = logging.getLogger(__name__) + + +def get_years(): + year_list = [] + for i in range(2017, get_year()+1): + year_list.append((i, str(i))) + return year_list + + +def get_year(): + now = datetime.datetime.now() + return int(now.year) + + +def get_month(): + now = datetime.datetime.now() + month = int(now.month)-1 + if month <= 0: + month = 12 + return month + + +class Wizard(models.TransientModel): + _name = 'ine.wizard' + + txt_filename = fields.Char() + txt_binary = fields.Binary() + + ine_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', default=get_month()) + ine_year = fields.Selection(get_years(), default=get_year(), string='Year') + + adr_screen = fields.Char() + rev_screen = fields.Char() + + @api.one + def generate_file(self): + _logger.warning("Start Export INE XML file") + last_day = calendar.monthrange(self.ine_year, self.ine_month)[1] + ine_start_search = datetime.date(self.ine_year, self.ine_month, 1) + ine_end_search = ine_start_search + datetime.timedelta(days=last_day) + compan = self.env.user.company_id + active_room = self.env['hotel.room'].search([('in_ine', '=', True)]) + message = "" + if not compan.property_name: + message = 'The NAME of the property is not established' + if not compan.name: + message = 'The NAME of the company is not established' + if not compan.vat: + message = 'The VAT is not established' + if not compan.ine_tourism: + message = 'The tourism number of the property is not established' + if message != "": + raise UserError(message) + return + encuesta = ET.Element("ENCUESTA") + cabezera = ET.SubElement(encuesta, "CABECERA") + fecha = ET.SubElement(cabezera, "FECHA_REFERENCIA") + ET.SubElement(fecha, "MES").text = str(self.ine_month) + ET.SubElement(fecha, "ANYO").text = str(self.ine_year) + ET.SubElement(cabezera, "DIAS_ABIERTO_MES_REFERENCIA").text = ( + str(last_day)) + ET.SubElement(cabezera, "RAZON_SOCIAL").text = compan.name + ET.SubElement(cabezera, "NOMBRE_ESTABLECIMIENTO").text = ( + compan.property_name) + ET.SubElement(cabezera, "CIF_NIF").text = compan.vat[2:] + ET.SubElement(cabezera, "NUMERO_REGISTRO").text = compan.ine_tourism + ET.SubElement(cabezera, "DIRECCION").text = compan.street + ET.SubElement(cabezera, "CODIGO_POSTAL").text = compan.zip + ET.SubElement(cabezera, "LOCALIDAD").text = compan.city + ET.SubElement(cabezera, "MUNICIPIO").text = compan.city + ET.SubElement(cabezera, "PROVINCIA" + ).text = compan.state_id.display_name + ET.SubElement(cabezera, "TELEFONO_1").text = ( + compan.phone.replace(' ', '')[0:12]) + ET.SubElement(cabezera, "TIPO").text = ( + compan.ine_category_id.category_type) + ET.SubElement(cabezera, "CATEGORIA").text = compan.ine_category_id.name + + ET.SubElement(cabezera, "HABITACIONES").text = str(len(active_room)) + ET.SubElement(cabezera, "PLAZAS_DISPONIBLES_SIN_SUPLETORIAS" + ).text = str(compan.ine_seats) + ET.SubElement(cabezera, "URL").text = compan.website + alojamiento = ET.SubElement(encuesta, "ALOJAMIENTO") + + all_room_nights = self.env['hotel.reservation.line'].search([ + ('date', '>=', ine_start_search), + ('date', '<=', ine_end_search), + ('reservation_id.room_id.in_ine', '=', True), + ('reservation_id.reservation_type', '=', 'normal'), + ]) + room_nights = all_room_nights.filtered( + lambda n: (self.get_codeine(n.reservation_id))) + + # Creating the empty dictionary system + dic_tabla = [] + for room_night in room_nights: + ine_code = self.get_codeine(room_night.reservation_id) + if not next((item for item in dic_tabla if item["ine"] == ine_code), False): + for x in range(1, last_day+1): + dic_tabla.append({'ine': ine_code, + 'dia': x, + 'entradas': 0, + 'salidas': 0, + 'pernocta': 0 + }) + + # Adding overnight stays per day and INE code + for dia in range(1, last_day+1): + for room_night in room_nights.filtered( + lambda x: x.date == str(self.ine_year)+'-'+str( + self.ine_month).zfill(2)+'-'+str(dia).zfill(2)): + ine_code = self.get_codeine(room_night.reservation_id) + for idx, val in enumerate(dic_tabla): + if val['ine'] == ine_code and val['dia'] == dia: + dic_tabla[idx]['pernocta'] += room_night.reservation_id.adults + + # Calculating outputs and entries + count = 1 + last_stay = 0 + for idx, row in enumerate(dic_tabla): + if count == last_day: + last_stay = 0 + count = 1 + count += 1 + if last_stay < dic_tabla[idx]['pernocta']: + dic_tabla[idx]['entradas'] += dic_tabla[idx]['pernocta'] + elif last_stay > dic_tabla[idx]['pernocta']: + dic_tabla[idx]['salidas'] += last_stay - dic_tabla[idx][ + 'pernocta'] + last_stay = dic_tabla[idx]['pernocta'] + + # "Print" outputs and entries + ine_residen = "" + for idx, row in enumerate(dic_tabla): + if ine_residen != dic_tabla[idx]['ine']: + ine_residen = dic_tabla[idx]['ine'] + residencia = ET.SubElement(alojamiento, "RESIDENCIA") + if len(dic_tabla[idx]['ine']) > 3: + ET.SubElement(residencia, "ID_PROVINCIA_ISLA" + ).text = str(dic_tabla[idx]['ine']) + else: + ET.SubElement(residencia, "ID_PAIS" + ).text = str(dic_tabla[idx]['ine']) + if ((dic_tabla[idx]['entradas'] != 0) + or (dic_tabla[idx]['salidas'] != 0) + or (dic_tabla[idx]['pernocta'] != 0)): + movimiento = ET.SubElement(residencia, "MOVIMIENTO") + ET.SubElement(movimiento, "N_DIA").text = ( + "%02d" % dic_tabla[idx]['dia']) + ET.SubElement(movimiento, "ENTRADAS").text = str( + dic_tabla[idx]['entradas']) + ET.SubElement(movimiento, "SALIDAS").text = str( + dic_tabla[idx]['salidas']) + ET.SubElement(movimiento, "PERNOCTACIONES").text = str( + dic_tabla[idx]['pernocta']) + + habitaciones = ET.SubElement(encuesta, "HABITACIONES") + # Bucle de HABITACIONES_MOVIMIENTO + + ingresos = 0 + habitaci = 0 + hab_vend = 0 + for dia in range(1, last_day+1): + suple = 0 + doble = 0 + dindi = 0 + otras = 0 + + habitaci += len(active_room) + habitaci -= self.env['hotel.reservation.line'].search([ + ('date', '=', str(self.ine_year)+'-'+str( + self.ine_month).zfill(2)+'-'+str(dia).zfill(2)), + ('reservation_id.reservation_type', '!=', 'normal'), + ], count=True) + for room_night in room_nights.filtered(lambda x: x.date == str( + self.ine_year)+'-'+str( + self.ine_month).zfill(2)+'-'+str( + dia).zfill(2)): + ingresos += room_night.price + hab_vend += 1 + + if room_night.reservation_id.room_id.capacity == 2: + if room_night.reservation_id.adults == 1: + dindi += 1 + else: + doble += 1 + else: + otras += 1 + if len(room_night.reservation_id.service_ids): + for service in room_night.reservation_id.service_ids: + if service.product_id.is_extra_bed: + suple += 1 + + habitaciones_m = ET.SubElement(habitaciones, + "HABITACIONES_MOVIMIENTO") + ET.SubElement(habitaciones_m, + "HABITACIONES_N_DIA").text = "%02d" % (dia) + ET.SubElement(habitaciones_m, + "PLAZAS_SUPLETORIAS").text = str(suple) + ET.SubElement(habitaciones_m, + "HABITACIONES_DOBLES_USO_DOBLE").text = str(doble) + ET.SubElement(habitaciones_m, + "HABITACIONES_DOBLES_USO_INDIVIDUAL").text = str( + dindi) + ET.SubElement(habitaciones_m, + "HABITACIONES_OTRAS").text = str(otras) + + precios = ET.SubElement(encuesta, "PRECIOS") + ET.SubElement(precios, + "REVPAR_MENSUAL").text = str(round(ingresos/habitaci, 2)) + ET.SubElement(precios, + "ADR_MENSUAL").text = str(round(ingresos/hab_vend, 2)) + ET.SubElement(precios, "ADR_TOUROPERADOR_TRADICIONAL").text = '0' + ET.SubElement(precios, + "PCTN_HABITACIONES_OCUPADAS_TOUROPERADOR_TRADICIONAL" + ).text = '0' + ET.SubElement(precios, + "ADR_TOUROPERADOR_ONLINE").text = '0' + ET.SubElement(precios, + "PCTN_HABITACIONES_OCUPADAS_TOUROPERADOR_ONLINE" + ).text = '0' + ET.SubElement(precios, + "ADR_EMPRESAS").text = '0' + ET.SubElement(precios, + "PCTN_HABITACIONES_OCUPADAS_EMPRESAS").text = '0' + ET.SubElement(precios, + "ADR_AGENCIA_DE_VIAJE_TRADICIONAL").text = '0' + ET.SubElement(precios, + "PCTN_HABITACIONES_OCUPADAS_AGENCIA_TRADICIONAL" + ).text = '0' + ET.SubElement(precios, "ADR_AGENCIA_DE_VIAJE_ONLINE").text = '0' + ET.SubElement(precios, + "PCTN_HABITACIONES_OCUPADAS_AGENCIA_ONLINE" + ).text = '0' + ET.SubElement(precios, "ADR_PARTICULARES").text = '0' + ET.SubElement(precios, + "PCTN_HABITACIONES_OCUPADAS_PARTICULARES").text = '0' + ET.SubElement(precios, + "ADR_GRUPOS").text = '0' + ET.SubElement(precios, + "PCTN_HABITACIONES_OCUPADAS_GRUPOS").text = '0' + ET.SubElement(precios, "ADR_INTERNET").text = '0' + ET.SubElement(precios, + "PCTN_HABITACIONES_OCUPADAS_INTERNET").text = '0' + ET.SubElement(precios, "ADR_OTROS").text = '0' + ET.SubElement(precios, + "PCTN_HABITACIONES_OCUPADAS_OTROS").text = '0' + + personal = ET.SubElement(encuesta, "PERSONAL_OCUPADO") + ET.SubElement(personal, "PERSONAL_NO_REMUNERADO").text = '0' + ET.SubElement(personal, + "PERSONAL_REMUNERADO_FIJO").text = str( + compan.ine_permanent_staff) + ET.SubElement(personal, + "PERSONAL_REMUNERADO_EVENTUAL").text = str( + compan.ine_eventual_staff) + + xmlstr = '' + xmlstr += ET.tostring(encuesta).decode('utf-8') + return self.write({ + 'txt_filename': 'INE_'+str(self.ine_month)+'_'+str( + self.ine_year) + '.' + 'xml', + 'adr_screen': 'ADR en el mes de la encuesta: '+str( + round(ingresos/habitaci, 2)) + '€ y ', + 'rev_screen': ' RevPar : '+str(round(ingresos/hab_vend, 2))+'€', + 'txt_binary': base64.encodestring(xmlstr.encode()) + }) + + @api.model + def get_codeine(self, reserva): + response = False + code = reserva[0].partner_id.code_ine_id + if code: + response = code.code + else: + for l in reserva[0].folio_id.checkin_partner_ids: + if l.code_ine_id: + response = l.code_ine_id.code + return response diff --git a/hotel_l10n_es/wizard/ine_wizard.xml b/hotel_ine/wizard/inewizard.xml old mode 100755 new mode 100644 similarity index 78% rename from hotel_l10n_es/wizard/ine_wizard.xml rename to hotel_ine/wizard/inewizard.xml index 2838cb1c6..02a326938 --- a/hotel_l10n_es/wizard/ine_wizard.xml +++ b/hotel_ine/wizard/inewizard.xml @@ -1,15 +1,16 @@ - + + - - ine.wizard.form + + INE File Download ine.wizard
@@ -21,13 +22,13 @@
- - + +
@@ -48,4 +49,6 @@ action="action_ine_download" /> - + + + diff --git a/hotel_l10n_es/__manifest__.py b/hotel_l10n_es/__manifest__.py index 2b7bfe214..5b9c8e978 100755 --- a/hotel_l10n_es/__manifest__.py +++ b/hotel_l10n_es/__manifest__.py @@ -43,7 +43,6 @@ 'report/report_parte_viajero.xml', 'views/report_viajero.xml', 'wizard/police_wizard.xml', - 'wizard/ine_wizard.xml', 'views/category_tourism.xml', 'views/code_ine.xml', 'views/inherit_res_company.xml', diff --git a/hotel_l10n_es/static/description/icon.png b/hotel_l10n_es/static/description/icon.png new file mode 100755 index 000000000..367e0ad23 Binary files /dev/null and b/hotel_l10n_es/static/description/icon.png differ diff --git a/hotel_l10n_es/wizard/__init__.py b/hotel_l10n_es/wizard/__init__.py index 9da10d1bc..d6b079854 100755 --- a/hotel_l10n_es/wizard/__init__.py +++ b/hotel_l10n_es/wizard/__init__.py @@ -21,4 +21,3 @@ ############################################################################## from . import police_wizard -from . import ine_wizard diff --git a/hotel_l10n_es/wizard/ine_wizard.py b/hotel_l10n_es/wizard/ine_wizard.py deleted file mode 100755 index 3b06f8723..000000000 --- a/hotel_l10n_es/wizard/ine_wizard.py +++ /dev/null @@ -1,441 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2017 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 odoo import models, fields, api, _ -import base64 -import datetime -import calendar -import xml.etree.cElementTree as ET -from openerp.exceptions import UserError - - -def get_years(): - year_list = [] - for i in range(2017, get_year()+1): - year_list.append((i, str(i))) - return year_list - - -def get_year(): - now = datetime.datetime.now() - return int(now.year) - - -def get_month(): - now = datetime.datetime.now() - month = int(now.month)-1 - if month <= 0: - month = 12 - return month - - -class IneWizard(models.TransientModel): - _name = 'ine.wizard' - - txt_filename = fields.Char() - txt_binary = fields.Binary() - ine_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', default=get_month()) - ine_year = fields.Selection(get_years(), default=get_year(), string='Year') - adr_screen = fields.Char() - rev_screen = fields.Char() - - @api.one - def generate_file(self): - month_first_date = datetime.datetime(self.ine_year, self.ine_month, 1) - last_day = calendar.monthrange(self.ine_year, self.ine_month)[1] - 1 - month_end_date = month_first_date + datetime.timedelta(days=last_day) - m_f_d_search = datetime.date(self.ine_year, self.ine_month, 1) - m_e_d_search = m_f_d_search + datetime.timedelta(days=last_day) - last_day += 1 - - # Seleccionamos los que tienen Entrada en el mes + salida en el mes + - # entrada antes y salida despues. Ordenandolos. - lines = self.env['hotel.checkin.partner'].search( - ['|', '|', '&', ('exit_date', '>=', m_f_d_search), - ('exit_date', '<=', m_e_d_search), '&', - ('enter_date', '>=', m_f_d_search), - ('enter_date', '<=', m_e_d_search), '&', - ('enter_date', '<=', m_f_d_search), - ('exit_date', '>=', m_e_d_search)], order="enter_date") - lines = lines.sorted( - key=lambda r: str(r.partner_id.code_ine_id)+r.enter_date) - - if len(lines) > 0: - - company = self.env.user.company_id - - encuesta = ET.Element("ENCUESTA") - cabezera = ET.SubElement(encuesta, "CABECERA") - fecha = ET.SubElement(cabezera, "FECHA_REFERENCIA") - ET.SubElement(fecha, "MES").text = '{:02d}'.format(self.ine_month) - ET.SubElement(fecha, "ANYO").text = str(self.ine_year) - month_end_date = ( - datetime.datetime(self.ine_year, self.ine_month, 1) + - datetime.timedelta(days=calendar.monthrange( - self.ine_year, self.ine_month)[1] - 1)) - ET.SubElement(cabezera, "DIAS_ABIERTO_MES_REFERENCIA").text = ( - str(month_end_date.day)) - ET.SubElement(cabezera, "RAZON_SOCIAL").text = company.name - ET.SubElement(cabezera, "NOMBRE_ESTABLECIMIENTO").text = ( - company.property_name) - ET.SubElement(cabezera, "CIF_NIF").text = company.vat[2:] - ET.SubElement(cabezera, "NUMERO_REGISTRO").text = company.ine_tourism - ET.SubElement(cabezera, "DIRECCION").text = company.street - ET.SubElement(cabezera, "CODIGO_POSTAL").text = company.zip - ET.SubElement(cabezera, "LOCALIDAD").text = company.city - ET.SubElement(cabezera, "MUNICIPIO").text = company.city - ET.SubElement(cabezera, "PROVINCIA" - ).text = company.state_id.display_name - ET.SubElement(cabezera, "TELEFONO_1").text = ( - company.phone.replace(' ', '')[0:12]) - ET.SubElement(cabezera, "TIPO").text = company.ine_category_id.category_type - ET.SubElement(cabezera, "CATEGORIA").text = company.ine_category_id.name - active_room = self.env['hotel.room'].search_count( - [('capacity', '>', 0)]) - ET.SubElement(cabezera, "HABITACIONES").text = str(active_room) - ET.SubElement(cabezera, "PLAZAS_DISPONIBLES_SIN_SUPLETORIAS" - ).text = str(company.ine_seats) - ET.SubElement(cabezera, "URL").text = company.website - alojamiento = ET.SubElement(encuesta, "ALOJAMIENTO") - # Bucle de RESIDENCIA - - # Init Variables - ine_entrada = [] - ine_salidas = [] - ine_pernoct = [] - ine_pernoct_total = [] - for x in range(last_day+1): - ine_entrada.append(0) - ine_salidas.append(0) - ine_pernoct.append(0) - ine_pernoct_total.append(0) - - # Cabezera - code_control = lines[0].partner_id.code_ine_id.code - - if code_control is False: - raise UserError(_('ERROR: Usuario sin codigo de INE: ' - + lines[0].partner_id.name)) - - for line in lines: - # Si ha cambiado el codigo - if code_control != line.partner_id.code_ine_id.code: - residencia = ET.SubElement(alojamiento, "RESIDENCIA") - if len(code_control) > 3: - ET.SubElement(residencia, "ID_PROVINCIA_ISLA" - ).text = str(code_control) - else: - ET.SubElement(residencia, "ID_PAIS" - ).text = str(code_control) - - for x in range(1, last_day+1): - if ine_entrada[x]+ine_salidas[x]+ine_pernoct[x] > 0: - movimiento = ET.SubElement(residencia, - "MOVIMIENTO") - ET.SubElement(movimiento, "N_DIA" - ).text = "%02d" % (x) - ET.SubElement(movimiento, "ENTRADAS" - ).text = str(ine_entrada[x]) - ET.SubElement(movimiento, "SALIDAS" - ).text = str(ine_salidas[x]) - ET.SubElement(movimiento, "PERNOCTACIONES" - ).text = str(ine_pernoct[x]) - # Guardamos el total de pernoctaciones/dia - ine_pernoct_total[x] += ine_pernoct[x] - - # Reset Variables - ine_entrada = [] - ine_salidas = [] - ine_pernoct = [] - for x in xrange(last_day+1): - ine_entrada.append(0) - ine_salidas.append(0) - ine_pernoct.append(0) - - code_control = line.partner_id.code_ine_id.code - - # Hacemos las sumas - f_entrada = line.enter_date.split('-') - f_salida = line.exit_date.split('-') - # Ha entrado este mes - if int(f_entrada[1]) == self.ine_month: - ine_entrada[int(f_entrada[2])] += 1 - cuenta_entrada = int(f_entrada[2]) - else: - # No marco entrada y cuento desde el dia 1 - cuenta_entrada = 1 - # Ha salido este mes - if int(f_salida[1]) == self.ine_month: - ine_salidas[int(f_salida[2])] += 1 - cuenta_salida = int(f_salida[2]) - else: - # No marco entrada y cuento desde el dia 1 - cuenta_salida = last_day+1 - # Contando pernoctaciones - for i in range(cuenta_salida-cuenta_entrada): - ine_pernoct[cuenta_entrada+i] += 1 - # Fin de cuenta desde Cardex - - habitaciones = ET.SubElement(encuesta, "HABITACIONES") - # Bucle de HABITACIONES_MOVIMIENTO - - month_adr_sum = 0 - month_adr_rooms = 0 - month_revpar_staff_rooms = 0 - movimientos = [] - - # Reset Variables - ine_entrada = [] - ine_salidas = [] - for x in range(last_day+1): - ine_entrada.append(0) - ine_salidas.append(0) - - for x in range(last_day+1): - movimientos.append([0, 0, 0, 0, 0, 0, active_room]) - # movimientos.append(['suple','doble','indi','otra','adr_sum', - # 'adr_rum','adr_staff']) - - lines_res = self.env['hotel.reservation'].search( - ['|', '|', '&', ('checkout', '>=', str(m_f_d_search)), - ('checkout', '<=', str(m_e_d_search)), '&', - ('checkin', '>=', str(m_f_d_search)), - ('checkin', '<=', str(m_e_d_search)), '&', - ('checkin', '<=', str(m_f_d_search)), - ('checkout', '>=', str(m_e_d_search))], order="checkin") - for line_res in lines_res: - room = line_res.room_id - # No es Staff o Out y esta booking - if (line_res.reservation_type == 'normal') and ( - (line_res.state == 'booking') or (line_res.state == 'done')): - - # calculamos capacidad de habitacion - # !!!!! ATENCION !!!! - # pendiente de añadir un campo con las supletorias. - # asumimos de momento que por defecto supletorias sera - # 0 por ejemplo para todas...... - # cambiar/calcular la siguiente linea. - suple_room = 0 - - capacidad = room.capacity + suple_room - - # Cuadramos adultos con los checkin realizados. - if line_res.adults > line_res.checkin_partner_count: - adultos = line_res.checkin_partner_count - else: - adultos = line_res.adults - - f_entrada = line_res.checkin.split('-') - f_salida = line_res.checkout.split('-') - f_entrada[2] = f_entrada[2].split()[0] - f_salida[2] = f_salida[2].split()[0] - # Ha entrado este mes - if int(f_entrada[1]) == self.ine_month: - ine_entrada[int(f_entrada[2])] += 1 - cuenta_entrada = int(f_entrada[2]) - else: - # No marco entrada y cuento desde el dia 1 - cuenta_entrada = 1 - # Ha salido este mes? - if int(f_salida[1]) == self.ine_month: - ine_salidas[int(f_salida[2])] += 1 - cuenta_salida = int(f_salida[2]) - else: - # No marco salida y cuento hasta el dia last_day - cuenta_salida = last_day + 1 - - # para las noches que ha estado - for dia_x in range(cuenta_entrada, cuenta_salida+1): - # si no supera el numero de habitaciones ni de - # pernoctaciones totales del dia... - if ((movimientos[dia_x-1][1]+movimientos[dia_x-1][2] + - movimientos[dia_x-1][3]) < active_room and ( - ((movimientos[dia_x-1][1]*2) + - movimientos[dia_x-1][2] + - movimientos[dia_x-1][3]) < - ine_pernoct_total[dia_x-1])): - if capacidad == 1: - # Habitacion Individual - movimientos[dia_x-1][3] += 1 - if adultos > 1: - # Supletorias - movimientos[dia_x-1][0] += 1 - elif capacidad == 2: - # Habitacion Doble - if adultos == 1: - # Uso individual - movimientos[dia_x-1][2] += 1 - else: - # Doble - movimientos[dia_x-1][1] += 1 - if adultos > 2: - # Doble + supletorias - movimientos[dia_x-1][0] += (adultos-2) - elif capacidad > 2: - # Otras Habitaciones - movimientos[dia_x-1][3] += 1 - else: - raise UserError(str(dia_x) + - 'Exceso de habitaciones ' + - str(line_res) + ' ' + line_res.name + - ' ' + line_res.partner_id.name + - ' PERNOCT.: ' + - str(ine_pernoct_total[dia_x-1])) - - # ADR y RevPar - for xx_lines in line_res.reservation_line_ids: - # ADR calculo - xx_dia = xx_lines.date.split('-') - if int(xx_dia[1]) == self.ine_month: - movimientos[int(xx_dia[2])][4] += xx_lines.price - movimientos[int(xx_dia[2])][5] += 1 - - else: - # Staff o Out - for xx_lines in line_res.reservation_line_ids: - xx_dia = xx_lines.date.split('-') - if int(xx_dia[1]) == self.ine_month: - # Restamos una Habitacion no valida para RevPar - movimientos[int(xx_dia[2])][6] -= 1 - - for dia_x in xrange(1, last_day+1): - # Si la suma de los durmiendo es superior a pernoctaciones INE - suma_durmiendo = ((movimientos[dia_x][1]*2) - + movimientos[dia_x][2] - + movimientos[dia_x][3]) - if suma_durmiendo > ine_pernoct_total[dia_x]: - suma_durmiendo = (suma_durmiendo - - ine_pernoct_total[dia_x]) - if suma_durmiendo == 1: - if movimientos[dia_x][2] > 0: - # quitamos una individual - movimientos[dia_x][2] -= 1 - elif movimientos[dia_x][3] > 0: - # quitamos una otras - movimientos[dia_x][3] -= 1 - elif suma_durmiendo == 2: - if movimientos[dia_x][1] > 0: - # quitamos una doble - movimientos[dia_x][1] -= 1 - elif movimientos[dia_x][3] > 0: - # quitamos una otras - movimientos[dia_x][3] -= 1 - habitaciones_m = ET.SubElement(habitaciones, - "HABITACIONES_MOVIMIENTO") - ET.SubElement(habitaciones_m, - "HABITACIONES_N_DIA").text = "%02d" % (dia_x) - if ine_pernoct_total[dia_x] > company.ine_seats: - # Añadimos Supletorias por si excedemos plazas - movimientos[dia_x][0] = (ine_pernoct_total[dia_x] - - company.ine_seats) - ET.SubElement(habitaciones_m, - "PLAZAS_SUPLETORIAS").text = str( - movimientos[dia_x][0]) - ET.SubElement(habitaciones_m, - "HABITACIONES_DOBLES_USO_DOBLE").text = str( - movimientos[dia_x][1]) - ET.SubElement(habitaciones_m, - "HABITACIONES_DOBLES_USO_INDIVIDUAL").text = str( - movimientos[dia_x][2]) - ET.SubElement(habitaciones_m, - "HABITACIONES_OTRAS").text = str( - movimientos[dia_x][3]) - - # calculo ADR - month_adr_sum += movimientos[dia_x][4] - month_adr_rooms += movimientos[dia_x][5] - month_revpar_staff_rooms += movimientos[dia_x][6] - - precios = ET.SubElement(encuesta, "PRECIOS") - ET.SubElement(precios, - "REVPAR_MENSUAL").text = str( - round(month_adr_sum/month_revpar_staff_rooms, 2)) - ET.SubElement(precios, - "ADR_MENSUAL").text = str( - round(month_adr_sum/month_adr_rooms, 2)) - ET.SubElement(precios, "ADR_TOUROPERADOR_TRADICIONAL").text = '0' - ET.SubElement(precios, - "PCTN_HABITACIONES_OCUPADAS_TOUROPERADOR_TRADICIONAL" - ).text = '0' - ET.SubElement(precios, - "ADR_TOUROPERADOR_ONLINE").text = '0' - ET.SubElement(precios, - "PCTN_HABITACIONES_OCUPADAS_TOUROPERADOR_ONLINE" - ).text = '0' - ET.SubElement(precios, - "ADR_EMPRESAS").text = '0' - ET.SubElement(precios, - "PCTN_HABITACIONES_OCUPADAS_EMPRESAS").text = '0' - ET.SubElement(precios, - "ADR_AGENCIA_DE_VIAJE_TRADICIONAL").text = '0' - ET.SubElement(precios, - "PCTN_HABITACIONES_OCUPADAS_AGENCIA_TRADICIONAL" - ).text = '0' - ET.SubElement(precios, "ADR_AGENCIA_DE_VIAJE_ONLINE").text = '0' - ET.SubElement(precios, - "PCTN_HABITACIONES_OCUPADAS_AGENCIA_ONLINE" - ).text = '0' - ET.SubElement(precios, "ADR_PARTICULARES").text = '0' - ET.SubElement(precios, - "PCTN_HABITACIONES_OCUPADAS_PARTICULARES").text = '0' - ET.SubElement(precios, - "ADR_GRUPOS").text = '0' - ET.SubElement(precios, - "PCTN_HABITACIONES_OCUPADAS_GRUPOS").text = '0' - ET.SubElement(precios, "ADR_INTERNET").text = '0' - ET.SubElement(precios, - "PCTN_HABITACIONES_OCUPADAS_INTERNET").text = '0' - ET.SubElement(precios, "ADR_OTROS").text = '0' - ET.SubElement(precios, - "PCTN_HABITACIONES_OCUPADAS_OTROS").text = '0' - - personal = ET.SubElement(encuesta, "PERSONAL_OCUPADO") - ET.SubElement(personal, "PERSONAL_NO_REMUNERADO").text = '0' - ET.SubElement(personal, - "PERSONAL_REMUNERADO_FIJO").text = str( - company.permanentstaff) - ET.SubElement(personal, - "PERSONAL_REMUNERADO_EVENTUAL").text = str( - company.eventualstaff) - - xmlstr = '' - xmlstr += ET.tostring(encuesta) - # file=base64.encodestring( xmlstr ) - return self.write({ - 'txt_filename': 'INE_'+str(self.ine_month)+'_'+str( - self.ine_year) + '.' + 'xml', - 'adr_screen': _('ADR in the month of the survey: ')+str( - round(month_adr_sum/month_adr_rooms, 2))+_('€ and '), - 'rev_screen': ' RevPar : '+str(round( - month_adr_sum/month_revpar_staff_rooms, 2))+'€', - 'txt_binary': base64.encodestring(xmlstr) - }) - else: - return self.write({ - 'rev_screen': _('No data in this month') - })