# -*- 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 = "%02d" % (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:].strip() 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.state', '!=', "cancelled"), ('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 pernocta_total = [] for dia in range(1, last_day+1): pernocta_total.append(0) 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 last_stay = 0 for idx, row in enumerate(dic_tabla): if dic_tabla[idx]['dia'] == 1: last_stay = 0 if last_stay < dic_tabla[idx]['pernocta']: dic_tabla[idx]['entradas'] += dic_tabla[idx]['pernocta'] - last_stay elif last_stay > dic_tabla[idx]['pernocta']: dic_tabla[idx]['salidas'] += last_stay - dic_tabla[idx][ 'pernocta'] # _logger.warning("%s: %s Perenocta: %s In: %s Out: %s Last=%s", dic_tabla[idx]['ine'], dic_tabla[idx]['dia'], dic_tabla[idx]['pernocta'], dic_tabla[idx]['entradas'], dic_tabla[idx]['salidas'],last_stay) last_stay = dic_tabla[idx]['pernocta'] pernocta_total[(dic_tabla[idx]['dia'])-1] += 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 # Here, we correct the extra beds if pernocta_total[dia-1] > suple + compan.ine_seats: suple = pernocta_total[dia-1] - compan.ine_seats 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