diff --git a/pms_l10n_es/data/cron_jobs.xml b/pms_l10n_es/data/cron_jobs.xml
index f8e0d7934..ffcc62c4c 100644
--- a/pms_l10n_es/data/cron_jobs.xml
+++ b/pms_l10n_es/data/cron_jobs.xml
@@ -45,9 +45,9 @@
SES Automatic Sending Pending Traveller Reports Communications
- 1
+ 30
- days
+ minutes
-1
code
diff --git a/pms_l10n_es/models/pms_property.py b/pms_l10n_es/models/pms_property.py
index 8df9882d4..f4fe7e026 100644
--- a/pms_l10n_es/models/pms_property.py
+++ b/pms_l10n_es/models/pms_property.py
@@ -42,7 +42,6 @@ class PmsProperty(models.Model):
string="Institution lessor id",
help="Id provided by institution to send data from lessor.",
)
-
ine_tourism_number = fields.Char(
"Tourism number",
help="Registration number in the Ministry of Tourism. Used for INE statistics.",
diff --git a/pms_l10n_es/models/pms_reservation.py b/pms_l10n_es/models/pms_reservation.py
index eeaaf5db9..eb6492f55 100644
--- a/pms_l10n_es/models/pms_reservation.py
+++ b/pms_l10n_es/models/pms_reservation.py
@@ -15,6 +15,38 @@ class PmsReservation(models.Model):
string="Is SES",
readonly=True,
compute="_compute_is_ses",
+ store=True,
+ )
+ ses_status_reservation = fields.Selection(
+ string="SES Status",
+ help="Status of the reservation in SES",
+ selection=[
+ ("not_applicable", "Not Applicable"),
+ ("to_send", "Pending Notification"),
+ ("to_process", "Pending Processing"),
+ ("error_create", "Error Creating"),
+ ("error_sending", "Error Sending"),
+ ("error_processing", "Error Processing"),
+ ("processed", "Processed"),
+ ],
+ compute="_compute_ses_status_reservation",
+ store=True,
+ )
+ ses_status_traveller_report = fields.Selection(
+ string="SES Status traveller",
+ help="Status of the traveller report in SES",
+ selection=[
+ ("not_applicable", "Not Applicable"),
+ ("incomplete", "Incomplete checkin data"),
+ ("to_send", "Pending Notification"),
+ ("to_process", "Pending Processing"),
+ ("error_create", "Error Creating"),
+ ("error_sending", "Error Sending"),
+ ("error_processing", "Error Processing"),
+ ("processed", "Processed"),
+ ],
+ compute="_compute_ses_status_traveller_report",
+ store=True,
)
@api.depends("pms_property_id")
@@ -22,6 +54,38 @@ class PmsReservation(models.Model):
for record in self:
record.is_ses = record.pms_property_id.institution == "ses"
+ @api.depends("ses_communication_ids", "ses_communication_ids.state")
+ def _compute_ses_status_reservation(self):
+ for record in self:
+ if record.pms_property_id.institution != "ses":
+ record.ses_status_reservation = "not_applicable"
+ continue
+ communication = record.ses_communication_ids.filtered(
+ lambda x: x.entity == "RH"
+ )
+ if len(communication) > 1:
+ # get the last communication
+ communication = communication.sorted(key=lambda x: x.create_date)[-1]
+ record.ses_status_reservation = (
+ communication.state if communication else "error_create"
+ )
+
+ @api.depends("ses_communication_ids", "ses_communication_ids.state")
+ def _compute_ses_status_traveller_report(self):
+ for record in self:
+ if record.pms_property_id.institution != "ses":
+ record.ses_status_traveller_report = "not_applicable"
+ continue
+ communication = record.ses_communication_ids.filtered(
+ lambda x: x.entity == "PV"
+ )
+ if len(communication) > 1:
+ # get the last communication
+ communication = communication.sorted(key=lambda x: x.create_date)[-1]
+ record.ses_status_traveller_report = (
+ communication.state if communication else "error_create"
+ )
+
@api.model
def create_communication(self, reservation_id, operation, entity):
self.env["pms.ses.communication"].create(
@@ -100,6 +164,9 @@ class PmsReservation(models.Model):
def write(self, vals):
for record in self:
- if record.pms_property_id.institution == "ses":
+ if (
+ record.pms_property_id.institution == "ses"
+ and record.reservation_type != "out"
+ ):
self.create_communication_after_update_reservation(record, vals)
return super(PmsReservation, self).write(vals)
diff --git a/pms_l10n_es/models/pms_ses_communication.py b/pms_l10n_es/models/pms_ses_communication.py
index 6119cea67..a96ad5437 100644
--- a/pms_l10n_es/models/pms_ses_communication.py
+++ b/pms_l10n_es/models/pms_ses_communication.py
@@ -5,6 +5,8 @@ from odoo import fields, models
class PmsSesCommunication(models.Model):
_name = "pms.ses.communication"
_description = "SES Communication"
+ _order = "create_date desc"
+
reservation_id = fields.Many2one(
string="Reservation",
help="Reservation related to this communication",
@@ -12,6 +14,14 @@ class PmsSesCommunication(models.Model):
required=True,
comodel_name="pms.reservation",
)
+ pms_property_id = fields.Many2one(
+ comodel_name="pms.property",
+ string="Property",
+ help="Property related to this communication",
+ related="reservation_id.pms_property_id",
+ index=True,
+ store=True,
+ )
communication_id = fields.Char(
string="Communication ID",
help="ID of the communication",
@@ -37,7 +47,6 @@ class PmsSesCommunication(models.Model):
string="Query status time",
help="Date and time of the last state query",
)
-
state = fields.Selection(
string="State",
help="State of the communication",
@@ -52,7 +61,6 @@ class PmsSesCommunication(models.Model):
("processed", "Processed"),
],
)
-
sending_result = fields.Text(
string="Sending Result",
help="Notification sending result",
@@ -86,3 +94,10 @@ class PmsSesCommunication(models.Model):
string="SOAP Resp. Status",
help="SOAP response status query",
)
+
+ def force_send_communication(self):
+ for record in self:
+ self.env["traveller.report.wizard"].ses_send_communication(
+ entity=record.entity,
+ communication_id=record.communication_id,
+ )
diff --git a/pms_l10n_es/tests/test_pms_ses_communication.py b/pms_l10n_es/tests/test_pms_ses_communication.py
index 7610a2b0f..676b28b30 100644
--- a/pms_l10n_es/tests/test_pms_ses_communication.py
+++ b/pms_l10n_es/tests/test_pms_ses_communication.py
@@ -221,65 +221,3 @@ class TestPmsSesCommunication(TestPms):
reservation_communications,
"Update adults should create 2 notifications with operations A and B",
)
-
- def test_create_notification_when_checkin_partner_on_board(self):
- # ARRANGE
- partner = self.env["res.partner"].create(
- {
- "name": "name test",
- "firstname": "firstname test",
- "lastname": "lastname test",
- "lastname2": "lastname2 test",
- "birthdate_date": "1995-12-10",
- "gender": "male",
- "nationality_id": self.env.ref("base.es").id,
- "residence_street": "street test",
- "residence_city": "city test",
- "residence_zip": "zip test",
- "residence_country_id": self.env.ref("base.us").id,
- }
- )
- reservation = self.env["pms.reservation"].create(
- {
- "pms_property_id": self.pms_property1.id,
- "room_type_id": self.room_type.id,
- "checkin": fields.date.today(),
- "checkout": fields.date.today() + datetime.timedelta(days=13),
- "adults": 1,
- "children": 0,
- "sale_channel_origin_id": self.sale_channel_direct1.id,
- "partner_name": "Test reservation",
- }
- )
- document_type_dni = self.env["res.partner.id_category"].search(
- [("code", "=", "D")], limit=1
- )
- checkin_partner = self.env["pms.checkin.partner"].create(
- {
- "reservation_id": reservation.id,
- "partner_id": partner.id,
- "document_number": "11111111H",
- "document_type": document_type_dni.id,
- "document_expedition_date": fields.date.today()
- + datetime.timedelta(days=1),
- "support_number": "123456",
- }
- )
- checkin_partner.action_on_board()
- # ACT
- self.env[
- "traveller.report.wizard"
- ].create_pending_notifications_traveller_report()
- # ASSERT
- last_notification = self.env["pms.ses.communication"].search(
- [
- ("reservation_id", "=", reservation.id),
- ("operation", "=", "A"),
- ("state", "=", "to_send"),
- ("entity", "=", "PV"),
- ],
- )
- self.assertTrue(
- last_notification,
- "Notification should be created when checkin partner is on board",
- )
diff --git a/pms_l10n_es/views/pms_ses_communication_views.xml b/pms_l10n_es/views/pms_ses_communication_views.xml
index 3268b5e1b..440961e45 100644
--- a/pms_l10n_es/views/pms_ses_communication_views.xml
+++ b/pms_l10n_es/views/pms_ses_communication_views.xml
@@ -42,7 +42,15 @@
pms.ses.communication.tree
pms.ses.communication
-
+
+
@@ -64,17 +72,84 @@
pms.ses.communication
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Force Send Communication
+
+ code
+
+ records.force_send_communication()
+
+
+ form,list
+
+
SES Communications
pms.ses.communication
diff --git a/pms_l10n_es/wizards/traveller_report.py b/pms_l10n_es/wizards/traveller_report.py
index 66dca9a1b..2fec5fa5a 100644
--- a/pms_l10n_es/wizards/traveller_report.py
+++ b/pms_l10n_es/wizards/traveller_report.py
@@ -6,6 +6,7 @@ import json
import logging
import re
import time
+import traceback
import xml.etree.cElementTree as ET
import zipfile
@@ -45,7 +46,7 @@ def replace_multiple_spaces(text: str) -> str:
def clean_string_only_letters(string):
clean_string = re.sub(r"[^a-zA-Z\s]", "", string).upper()
clean_string = " ".join(clean_string.split())
- return
+ return clean_string
def clean_string_only_numbers_and_letters(string):
@@ -200,7 +201,7 @@ def _ses_xml_person_personal_info_elements(persona, checkin_partner):
)
-def _ses_xml_municipality_code(residence_zip):
+def _ses_xml_municipality_code(residence_zip, pms_property):
with open(
get_module_resource(
"pms_l10n_es", "static/src/", "pms.ine.zip.municipality.ine.relation.csv"
@@ -212,6 +213,11 @@ def _ses_xml_municipality_code(residence_zip):
for fila in lector:
if residence_zip in fila[0]:
return fila[1][:5]
+ # REVIEW: If the zip code is not found,
+ # use provisory pms_property zip code
+ property_zip = pms_property.zip
+ if property_zip:
+ return property_zip[:5]
raise ValidationError(_("The guest does not have a valid zip code."))
@@ -225,7 +231,10 @@ def _ses_xml_person_address_elements(persona, checkin_partner):
)
if checkin_partner.residence_country_id.code == CODE_SPAIN:
- municipio_code = _ses_xml_municipality_code(checkin_partner.residence_zip)
+ municipio_code = _ses_xml_municipality_code(
+ residence_zip=checkin_partner.residence_zip,
+ pms_property=checkin_partner.reservation_id.pms_property_id,
+ )
if municipio_code:
ET.SubElement(direccion, "codigoMunicipio").text = municipio_code
else:
@@ -358,11 +367,15 @@ def _handle_request_exception(communication, e):
)
else:
if communication.state == "to_send":
- communication.sending_result = f"Request error: {e}"
+ communication.sending_result = (
+ f"Request error: {traceback.format_exc()}"
+ )
else:
- communication.processing_result = f"Request error: {e}"
+ communication.processing_result = (
+ f"Request error: {traceback.format_exc()}"
+ )
else:
- communication.sending_result = f"Unexpected error: {e}"
+ communication.sending_result = f"Unexpected error: {traceback.format_exc()}"
class TravellerReport(models.TransientModel):
@@ -979,7 +992,7 @@ class TravellerReport(models.TransientModel):
comunicacion = ET.SubElement(solicitud, "comunicacion")
_ses_xml_contract_elements(comunicacion, reservation, people)
for checkin_partner in reservation.checkin_partner_ids.filtered(
- lambda x: x.state == "onboard"
+ lambda x: x.state in ["onboard", "done"]
):
_ses_xml_person_elements(comunicacion, checkin_partner)
@@ -998,7 +1011,7 @@ class TravellerReport(models.TransientModel):
):
raise ValidationError(_("The reservations must be from the same property."))
elif all(
- state != "onboard"
+ state not in ["onboard", "done"]
for state in self.env["pms.reservation"]
.browse(reservation_ids)
.mapped("checkin_partner_ids")
@@ -1006,7 +1019,7 @@ class TravellerReport(models.TransientModel):
):
raise ValidationError(_("There are no guests onboard."))
elif not ignore_some_not_onboard and any(
- state != "onboard"
+ state not in ["onboard", "done"]
for state in self.env["pms.reservation"]
.browse(reservation_ids)
.mapped("checkin_partner_ids")
@@ -1032,7 +1045,9 @@ class TravellerReport(models.TransientModel):
num_people_on_board = len(
self.env["pms.reservation"]
.browse(reservation_id)
- .checkin_partner_ids.filtered(lambda x: x.state == "onboard")
+ .checkin_partner_ids.filtered(
+ lambda x: x.state in ["onboard", "done"]
+ )
)
ET.SubElement(
solicitud,
@@ -1057,14 +1072,14 @@ class TravellerReport(models.TransientModel):
return xml_str
@api.model
- def ses_send_communications(self, entity):
-
- for communication in self.env["pms.ses.communication"].search(
- [
- ("state", "=", "to_send"),
- ("entity", "=", entity),
- ]
- ):
+ def ses_send_communications(self, entity, communication_id=False):
+ domain = [
+ ("state", "=", "to_send"),
+ ("entity", "=", entity),
+ ]
+ if communication_id:
+ domain.append(("id", "=", communication_id))
+ for communication in self.env["pms.ses.communication"].search(domain):
data = False
try:
if communication.operation == DELETE_OPERATION_CODE:
@@ -1074,7 +1089,9 @@ class TravellerReport(models.TransientModel):
("state", "!=", "to_send"),
("entity", "=", communication.entity),
("operation", "=", CREATE_OPERATION_CODE),
- ]
+ ],
+ order="id desc",
+ limit=1,
)
data = (
"