mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
323 lines
14 KiB
Python
323 lines
14 KiB
Python
# -*- coding: utf-8 -*-
|
|
##############################################################################
|
|
#
|
|
# OpenERP, Open Source Management Solution
|
|
# Copyright (C) 2017-19 Alda Hotels <informatica@aldahotels.com>
|
|
# Jose Luis Algara <osotranquilo@gmail.com>
|
|
#
|
|
# 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 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 = '<?xml version="1.0" encoding="ISO-8859-1"?>'
|
|
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
|