[IMP]pms_l10n_es: Traveller report flow

This commit is contained in:
Darío Lodeiros
2022-12-15 20:07:32 +01:00
parent e9d4bd784e
commit bc21bba4dd
6 changed files with 566 additions and 426 deletions

View File

@@ -712,9 +712,6 @@ class PmsCheckinPartner(models.Model):
lambda c: c.state == "dummy"
)
if len(reservation.checkin_partner_ids) < reservation.adults:
if vals.get("identifier", _("New")) == _("New") or "identifier" not in vals:
pms_property = reservation.pms_property_id
vals["identifier"] = pms_property.checkin_sequence_id._next_do()
return super(PmsCheckinPartner, self).create(vals)
if len(dummy_checkins) > 0:
dummy_checkins[0].write(vals)
@@ -844,6 +841,7 @@ class PmsCheckinPartner(models.Model):
}
record.update(vals)
record.reservation_id.state = "onboard"
record.identifier = record.pms_property_id.checkin_sequence_id._next_do()
def action_done(self):
for record in self.filtered(lambda c: c.state == "onboard"):

View File

@@ -33,6 +33,7 @@
"data/pms_data.xml",
"data/queue_data.xml",
"data/queue_job_function_data.xml",
"data/pms_traveler_report_notification_email_template.xml",
"security/ir.model.access.csv",
"views/pms_property_views.xml",
"views/pms_room_views.xml",

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data noupdate="1">
<record model="ir.cron" id="autosend_traveller_report">
<field name="name">Automatic Send Traveller Report</field>
<field name="active" eval="False" />
@@ -17,5 +18,6 @@
/>
<field name="code">model.send_file_institution_async()</field>
</record>
</data>
</odoo>

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data>
<record id="notification_send_error_travel_report_email" model="mail.template">
<field name="name">Travel Report Send</field>
<field
name="model_id"
ref="pms_l10n_es.model_pms_log_institution_traveller_report"
/>
<field
name="subject"
>Error: ${object.pms_property_id.name}, ${object.target_date} Error sending the Traveler report</field>
<field
name="email_from"
>${object.pms_property_id.company_id.partner_id.email | safe}</field>
<field
name="email_to"
>${object.pms_property_id.partner_id.email | safe}</field>
<field name="body_html" type="html">
<div>
There was an error sending the traveler report
</div>
</field>
</record>
</data>
<data>
<record
id="notification_send_success_travel_report_email"
model="mail.template"
>
<field name="name">Travel Report Send</field>
<field
name="model_id"
ref="pms_l10n_es.model_pms_log_institution_traveller_report"
/>
<field
name="subject"
>Succes: ${object.pms_property_id.name}, ${object.target_date} Traveler report sent successfully</field>
<field
name="email_from"
>${object.pms_property_id.company_id.partner_id.email | safe}</field>
<field
name="email_to"
>${object.pms_property_id.partner_id.email | safe}</field>
<field name="body_html" type="html">
<div>
Traveler report sent successfully
</div>
</field>
</record>
</data>
</odoo>

View File

@@ -7,7 +7,7 @@ CODE_SPAIN = "ES"
_logger = logging.getLogger(__name__)
class PmsCheckinParnert(models.Model):
class PmsCheckinPartner(models.Model):
_inherit = "pms.checkin.partner"
support_number = fields.Char(
@@ -35,7 +35,7 @@ class PmsCheckinParnert(models.Model):
@api.model
def _checkin_mandatory_fields(self, country=False, depends=False):
mandatory_fields = super(PmsCheckinParnert, self)._checkin_mandatory_fields(
mandatory_fields = super(PmsCheckinPartner, self)._checkin_mandatory_fields(
depends
)
mandatory_fields.extend(
@@ -60,6 +60,6 @@ class PmsCheckinParnert(models.Model):
@api.model
def _checkin_manual_fields(self, country=False, depends=False):
manual_fields = super(PmsCheckinParnert, self)._checkin_manual_fields(depends)
manual_fields = super(PmsCheckinPartner, self)._checkin_manual_fields(depends)
manual_fields.extend(["support_number"])
return manual_fields

View File

@@ -2,17 +2,21 @@ import base64
import datetime
import io
import json
import logging
import re
import time
import PyPDF2
import requests
from bs4 import BeautifulSoup as bs
from dateutil.relativedelta import relativedelta
from odoo import _, api, fields, models
from odoo.exceptions import MissingError, ValidationError
from odoo.modules.module import get_module_resource
_logger = logging.getLogger(__name__)
class TravellerReport(models.TransientModel):
_name = "traveller.report.wizard"
@@ -48,55 +52,51 @@ class TravellerReport(models.TransientModel):
# build content
content = self.generate_checkin_list(
property_id=pms_property.id,
pms_property_id=pms_property.id,
date_target=self.date_target,
)
if content:
txt_binary = self.env["traveller.report.wizard"].create(
{
"txt_filename": pms_property.institution_property_id + ".999",
"txt_binary": base64.b64encode(str.encode(content)),
"txt_message": content,
}
)
self.txt_filename = pms_property.institution_property_id + ".999"
self.txt_binary = base64.b64encode(str.encode(content))
self.txt_message = content
return {
"name": _("Traveller Report"),
"res_id": txt_binary.id,
"res_id": self.id,
"res_model": "traveller.report.wizard",
"target": "new",
"type": "ir.actions.act_window",
"view_id": self.env.ref("pms_l10n_es.traveller_report_wizard").id,
"view_mode": "form",
"view_type": "form",
}
def generate_checkin_list(self, property_id, date_target=False):
def generate_checkin_list(
self, pms_property_id, date_target=False, checkin_ids=False
):
regex = re.compile("[^a-zA-Z0-9]")
# check if there's guests info pending to send
if not checkin_ids:
if not date_target:
date_target = fields.date.today()
# check if there's guests info pending to send
if self.env["pms.checkin.partner"].search_count(
[
("state", "in", ["onboard", "done"]),
("arrival", ">=", str(date_target) + " 0:00:00"),
("pms_property_id", "=", property_id),
]
):
pms_property = (
self.env["pms.property"]
.with_context(lang="es_ES")
.search([("id", "=", property_id)])
)
# get checkin partners info to send
lines = self.env["pms.checkin.partner"].search(
[
domain = [
("state", "in", ["onboard", "done"]),
("arrival", ">=", str(date_target) + " 0:00:00"),
("arrival", "<=", str(date_target) + " 23:59:59"),
("pms_property_id", "=", property_id),
("pms_property_id", "=", pms_property_id),
]
else:
domain = [
("id", "in", checkin_ids),
]
pms_property = (
self.env["pms.property"]
.with_context(lang="es_ES")
.search([("id", "=", pms_property_id)])
)
# get checkin partners info to send
lines = self.env["pms.checkin.partner"].search(domain)
# build the property info record
# 1 | property id | property name | date | nº of checkin partners
content = (
@@ -138,6 +138,11 @@ class TravellerReport(models.TransientModel):
return content
def send_file_gc(self, file_content, called_from_user, pms_property):
try:
_logger.info(
"Sending file to Guardia Civil, Property %s, date: %s"
% (pms_property.name, self.date_target)
)
url = "https://hospederias.guardiacivil.es/"
login_route = "/hospederias/login.do"
upload_file_route = "/hospederias/cargaFichero.do"
@@ -160,7 +165,7 @@ class TravellerReport(models.TransientModel):
data=login_payload,
verify=get_module_resource("pms_l10n_es", "static", "cert.pem"),
)
time.sleep(0.1)
time.sleep(0.4)
# check if authentication was successful / unsuccessful or the
# resource cannot be accessed
@@ -175,7 +180,9 @@ class TravellerReport(models.TransientModel):
raise ValidationError(_("Connection could not be established"))
# build the file to send
files = {"fichero": (pms_property.institution_user + ".999", file_content)}
files = {
"fichero": (pms_property.institution_user + ".999", file_content)
}
# send file
response_file_sent = session.post(
@@ -184,7 +191,7 @@ class TravellerReport(models.TransientModel):
files=files,
verify=get_module_resource("pms_l10n_es", "static", "cert.pem"),
)
time.sleep(0.1)
time.sleep(0.4)
# logout & close connection
session.get(
@@ -202,37 +209,36 @@ class TravellerReport(models.TransientModel):
for e in errors:
msg += "Error en línea " + e.select("a")[0].text + ": "
msg += e.select("a")[2].text + "\n"
self.env["pms.log.institution.traveller.report"].create(
return self.env["pms.log.institution.traveller.report"].create(
{
"error_sending_data": True,
"txt_incidencies_from_institution": msg,
"pms_property_id": pms_property.id,
"target_date": target_date,
"txt_message": _("Error in file sended"),
"txt_incidencies_from_institution": msg,
}
)
raise ValidationError(msg)
else:
self.env["pms.log.institution.traveller.report"].create(
return self.env["pms.log.institution.traveller.report"].create(
{
"error_sending_data": False,
"pms_property_id": pms_property.id,
"target_date": target_date,
"txt_message": _("Successful file sending"),
}
)
if called_from_user:
message = {
"type": "ir.actions.client",
"tag": "display_notification",
"params": {
"title": _("Sent succesfully!"),
"message": _("Successful file sending"),
"sticky": False,
},
except Exception as e:
return self.env["pms.log.institution.traveller.report"].create(
{
"error_sending_data": True,
"pms_property_id": pms_property.id,
"target_date": target_date,
"txt_message": str(e),
}
return message
)
def send_file_pn(self, file_content, called_from_user, pms_property):
try:
base_url = "https://webpol.policia.es"
headers = {
"User-Agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 "
@@ -247,18 +253,19 @@ class TravellerReport(models.TransientModel):
"/e-hotel/hospederia/vista/seguimientoHospederia"
)
files_sent_list_route = "/e-hotel/hospederia/listar/ficherosHospederia"
last_file_errors_route = "/e-hotel/hospederia/report/erroresFicheroHospederia"
last_file_errors_route = (
"/e-hotel/hospederia/report/erroresFicheroHospederia"
)
logout_route = "/e-hotel/execute_logout"
target_date = self.date_target or fields.date.today()
session = requests.session()
# retrieve token
response_pre_login = session.post(
base_url + pre_login_route,
headers=headers,
verify=False,
)
time.sleep(0.1)
time.sleep(0.3)
token = bs(response_pre_login.text, "html.parser").select(
"input[name='_csrf']"
)[0]["value"]
@@ -277,7 +284,7 @@ class TravellerReport(models.TransientModel):
},
verify=False,
)
time.sleep(0.1)
time.sleep(0.3)
headers["x-csrf-token"] = token
# retrieve file name to send
response_name_file_route = session.post(
@@ -285,7 +292,7 @@ class TravellerReport(models.TransientModel):
headers=headers,
verify=False,
)
time.sleep(0.1)
time.sleep(0.2)
soup = bs(response_name_file_route.text, "html.parser")
file_name = soup.select("#msjNombreFichero > b > u")[0].text
@@ -308,7 +315,7 @@ class TravellerReport(models.TransientModel):
if upload_result.status_code != 200:
raise MissingError(_("Could not upload file."))
time.sleep(0.1)
time.sleep(0.2)
# retrieve property data
response_pre_files_sent_list_route = session.post(
@@ -324,7 +331,7 @@ class TravellerReport(models.TransientModel):
if response_pre_files_sent_list_route.status_code != 200:
raise MissingError(_("Could not get property_info."))
time.sleep(0.1)
time.sleep(0.2)
soup = bs(response_pre_files_sent_list_route.text, "html.parser")
property_specific_data = {
@@ -405,7 +412,7 @@ class TravellerReport(models.TransientModel):
if response_last_file_errors_route.status_code != 200:
raise ValidationError(_("Could last files sent"))
time.sleep(0.1)
time.sleep(0.4)
soup = bs(response_last_file_errors_route.text, "html.parser")
# get file sent pdf report
response_last_file_errors_route = session.get(
@@ -417,34 +424,42 @@ class TravellerReport(models.TransientModel):
if response_last_file_errors_route.status_code != 200:
raise ValidationError(_("Could last files sent"))
time.sleep(0.1)
time.sleep(0.4)
pdfReader = PyPDF2.PdfFileReader(
io.BytesIO(response_last_file_errors_route.content)
)
if (
pdfReader.getPage(0).extractText().find("ERRORES Y AVISOS HUESPEDES")
pdfReader.getPage(0)
.extractText()
.find("ERRORES Y AVISOS HUESPEDES")
== -1
):
message = _("Successful file sending")
error = False
log = self.env["pms.log.institution.traveller.report"].create(
{
"error_sending_data": False,
"pms_property_id": pms_property.id,
"target_date": target_date,
"txt_message": _("Successful file sending"),
}
)
else:
message = _("Errors (check the pdf file).")
error = True
self.env["pms.log.institution.traveller.report"].create(
log = self.env["pms.log.institution.traveller.report"].create(
{
"error_sending_data": error,
"txt_incidencies_from_institution": message,
"txt_message": message,
"pms_property_id": pms_property.id,
"target_date": target_date,
"file_incidencies_from_institution": base64.b64encode(
response_last_file_errors_route.content
),
"txt_filename": file_name + ".pdf",
"pms_property_id": pms_property.id,
"target_date": target_date,
}
)
# do logout
session.post(
base_url + logout_route,
@@ -452,21 +467,22 @@ class TravellerReport(models.TransientModel):
verify=False,
data={"_csrf": token},
)
session.close()
if called_from_user:
message = {
"type": "ir.actions.client",
"tag": "display_notification",
"params": {
"title": _("Sent succesfully!"),
"message": _("Successful file sending"),
"sticky": False,
},
return log
except Exception as e:
return self.env["pms.log.institution.traveller.report"].create(
{
"error_sending_data": True,
"txt_message": str(e),
"pms_property_id": pms_property.id,
"target_date": target_date,
}
return message
)
def send_file_institution(self, pms_property=False):
def send_file_institution(
self, pms_property=False, checkin_ids=False, offset=0, date_target=False
):
try:
called_from_user = False
if not pms_property:
called_from_user = True
@@ -482,14 +498,83 @@ class TravellerReport(models.TransientModel):
raise ValidationError(
_("The guest information sending settings is not complete.")
)
file_content = self.generate_checkin_list(pms_property.id)
if not date_target:
date_target = fields.Date.today()
date_target = date_target - relativedelta(days=offset)
file_content = self.generate_checkin_list(
pms_property_id=pms_property.id,
date_target=date_target,
checkin_ids=checkin_ids,
)
if pms_property.institution == "policia_nacional":
return self.send_file_pn(file_content, called_from_user, pms_property)
log = self.send_file_pn(file_content, called_from_user, pms_property)
elif pms_property.institution == "guardia_civil":
return self.send_file_gc(file_content, called_from_user, pms_property)
log = self.send_file_gc(file_content, called_from_user, pms_property)
if log.error_sending_data:
_logger.warning(
"""
Error sending file, Property %s, date: %s, message: %s
"""
% (pms_property.name, self.date_target, log.txt_message)
)
raise ValidationError(log.txt_incidencies_from_institution)
_logger.info(
"""
Successful file sending, sending confirmation mail,
Property %s, date: %s" % (pms_property.name, self.date_target)
"""
)
if called_from_user:
message = {
"type": "ir.actions.client",
"tag": "display_notification",
"params": {
"title": _("Sent succesfully!"),
"message": _("Successful file sending"),
"sticky": False,
},
}
return message
else:
template = self.env.ref(
"pms_l10n_es.notification_send_success_travel_report_email"
)
template.send_mail(log.id, force_send=True)
except Exception as e:
_logger.warning(
"""
Error sending file, Property %s, date: %s, message: %s
"""
% (pms_property.name, self.date_target, str(e))
)
if called_from_user:
message = {
"type": "ir.actions.client",
"tag": "display_notification",
"params": {
"title": _("Error!"),
"message": _("Error sending file: %s" % e),
"sticky": False,
},
}
return message
else:
log = self.env["pms.log.institution.traveller.report"].create(
{
"error_sending_data": True,
"txt_incidencies_from_institution": str(e),
"pms_property_id": pms_property.id,
"target_date": date_target,
}
)
template = self.env.ref(
"pms_l10n_es.notification_send_error_travel_report_email"
)
template.send_mail(log.id, force_send=True)
@api.model
def send_file_institution_async(self):
def send_file_institution_async(self, offset=0):
for prop in self.env["pms.property"].search([]):
if prop.institution:
self.with_delay().send_file_institution(prop)
self.send_file_institution(prop, offset)
time.sleep(0.5)