Merge PR #303 into 14.0

Signed-off-by DarioLodeiros
This commit is contained in:
OCA-git-bot
2024-12-26 10:12:01 +00:00
5 changed files with 239 additions and 77 deletions

View File

@@ -30,7 +30,6 @@ class PmsReservation(models.Model):
("processed", "Processed"), ("processed", "Processed"),
], ],
compute="_compute_ses_status_reservation", compute="_compute_ses_status_reservation",
store=True,
) )
ses_status_traveller_report = fields.Selection( ses_status_traveller_report = fields.Selection(
string="SES Status traveller", string="SES Status traveller",
@@ -46,15 +45,20 @@ class PmsReservation(models.Model):
("processed", "Processed"), ("processed", "Processed"),
], ],
compute="_compute_ses_status_traveller_report", compute="_compute_ses_status_traveller_report",
store=True,
) )
@api.depends("pms_property_id") @api.depends("pms_property_id", "preferred_room_id")
def _compute_is_ses(self): def _compute_is_ses(self):
for record in self: for record in self:
record.is_ses = record.pms_property_id.institution == "ses" if (
record.preferred_room_id
and record.preferred_room_id.institution_independent_account
and record.preferred_room_id.institution == "ses"
):
record.is_ses = True
else:
record.is_ses = record.pms_property_id.institution == "ses"
@api.depends("ses_communication_ids", "ses_communication_ids.state")
def _compute_ses_status_reservation(self): def _compute_ses_status_reservation(self):
for record in self: for record in self:
if record.pms_property_id.institution != "ses": if record.pms_property_id.institution != "ses":
@@ -70,7 +74,6 @@ class PmsReservation(models.Model):
communication.state if communication else "error_create" communication.state if communication else "error_create"
) )
@api.depends("ses_communication_ids", "ses_communication_ids.state")
def _compute_ses_status_traveller_report(self): def _compute_ses_status_traveller_report(self):
for record in self: for record in self:
if record.pms_property_id.institution != "ses": if record.pms_property_id.institution != "ses":
@@ -88,11 +91,13 @@ class PmsReservation(models.Model):
@api.model @api.model
def create_communication(self, reservation_id, operation, entity): def create_communication(self, reservation_id, operation, entity):
reservation = self.env["pms.reservation"].browse(reservation_id)
self.env["pms.ses.communication"].create( self.env["pms.ses.communication"].create(
{ {
"reservation_id": reservation_id, "reservation_id": reservation_id,
"operation": operation, "operation": operation,
"entity": entity, "entity": entity,
"room_id": reservation.preferred_room_id.id,
} }
) )
@@ -164,9 +169,6 @@ class PmsReservation(models.Model):
def write(self, vals): def write(self, vals):
for record in self: for record in self:
if ( if record.is_ses and record.reservation_type != "out":
record.pms_property_id.institution == "ses"
and record.reservation_type != "out"
):
self.create_communication_after_update_reservation(record, vals) self.create_communication_after_update_reservation(record, vals)
return super(PmsReservation, self).write(vals) return super(PmsReservation, self).write(vals)

View File

@@ -3,8 +3,43 @@ from odoo import fields, models
class PmsRoom(models.Model): class PmsRoom(models.Model):
_inherit = "pms.room" _inherit = "pms.room"
in_ine = fields.Boolean( in_ine = fields.Boolean(
string="In INE", string="In INE",
help="Take it into account to generate INE statistics", help="Take it into account to generate INE statistics",
default=True, default=True,
) )
institution_independent_account = fields.Boolean(
string="Independent account for institution (travel reports)",
help="This room has an independent account",
default=False,
)
institution = fields.Selection(
[
("ses", "SES"),
("ertxaintxa", "Ertxaintxa (soon)"),
("mossos", "Mossos_d'esquadra (soon)"),
],
string="Institution",
help="Institution to send daily guest data.",
required=False,
)
institution_property_id = fields.Char(
string="Institution property id",
help="Id provided by institution to send data from property.",
)
ses_url = fields.Char(
string="SES URL",
help="URL to send the data to SES",
)
institution_user = fields.Char(
string="Institution user", help="User provided by institution to send the data."
)
institution_password = fields.Char(
string="Institution password",
help="Password provided by institution to send the data.",
)
institution_lessor_id = fields.Char(
string="Institution lessor id",
help="Id provided by institution to send data from lessor.",
)

View File

@@ -22,6 +22,14 @@ class PmsSesCommunication(models.Model):
index=True, index=True,
store=True, store=True,
) )
room_id = fields.Many2one(
comodel_name="pms.room",
string="Room",
help="Room related to this communication",
related="reservation_id.preferred_room_id",
index=True,
store=True,
)
batch_id = fields.Char( batch_id = fields.Char(
string="Batch ID", string="Batch ID",
default=False, default=False,

View File

@@ -7,6 +7,22 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='sequence']" position="after"> <xpath expr="//field[@name='sequence']" position="after">
<field name="in_ine" /> <field name="in_ine" />
<field name="institution_independent_account" />
</xpath>
<xpath expr="//notebook" position="inside">
<page
string="Travel record institution"
attrs="{'invisible': [('institution_independent_account', '=', False)]}"
>
<group>
<field name="institution" />
<field name="institution_property_id" />
<field name="institution_lessor_id" />
<field name="ses_url" />
<field name="institution_user" />
<field name="institution_password" />
</group>
</page>
</xpath> </xpath>
</field> </field>
</record> </record>

View File

@@ -310,8 +310,15 @@ def _ses_xml_person_elements(comunicacion, checkin_partner):
def _get_auth_headers(communication): def _get_auth_headers(communication):
user = communication.reservation_id.pms_property_id.institution_user if (
password = communication.reservation_id.pms_property_id.institution_password communication.reservation_id.preferred_room_id
and communication.reservation_id.preferred_room_id.institution_independent_account
):
user = communication.reservation_id.preferred_room_id.institution_user
password = communication.reservation_id.preferred_room_id.institution_password
else:
user = communication.reservation_id.pms_property_id.institution_user
password = communication.reservation_id.pms_property_id.institution_password
user_and_password_base64 = "Basic " + base64.b64encode( user_and_password_base64 = "Basic " + base64.b64encode(
bytes(user + ":" + password, "utf-8") bytes(user + ":" + password, "utf-8")
@@ -412,13 +419,22 @@ class TravellerReport(models.TransientModel):
required=True, required=True,
default=lambda self: self.env.user.get_active_property_ids()[0], default=lambda self: self.env.user.get_active_property_ids()[0],
) )
room_id = fields.Many2one(
comodel_name="pms.room",
string="Room",
domain="""
[
('pms_property_id', '=', pms_property_id),
('institution_independent_account, '=', True),
('institution', '=', 'ses')
]
""",
)
is_ses = fields.Boolean( is_ses = fields.Boolean(
string="Is SES", string="Is SES",
readonly=True, readonly=True,
compute="_compute_is_ses", compute="_compute_is_ses",
) )
report_type = fields.Selection( report_type = fields.Selection(
string="Report Type", string="Report Type",
required=True, required=True,
@@ -431,31 +447,50 @@ class TravellerReport(models.TransientModel):
) )
@api.depends( @api.depends(
"pms_property_id", "date_target", "date_from", "date_to", "report_type" "pms_property_id",
"date_target",
"date_from",
"date_to",
"report_type",
"room_id",
) )
def _compute_txt_message(self): def _compute_txt_message(self):
for record in self: for record in self:
record.txt_message = False record.txt_message = False
@api.depends("pms_property_id.institution") @api.depends("pms_property_id.institution", "room_id.institution")
def _compute_is_ses(self): def _compute_is_ses(self):
for record in self: for record in self:
record.is_ses = record.pms_property_id.institution == "ses" if record.room_id:
record.is_ses = record.room_id.institution == "ses"
else:
record.is_ses = record.pms_property_id.institution == "ses"
def generate_file_from_user_action(self): def generate_file_from_user_action(self):
pms_property = self.env["pms.property"].search( pms_property = self.env["pms.property"].search(
[("id", "=", self.pms_property_id.id)] [("id", "=", self.pms_property_id.id)]
) )
# check if there's institution settings properly established room = self.room_id
if ( if not room:
not pms_property # check if there's institution settings properly established
or not pms_property.institution_property_id if (
or not pms_property.institution_user not pms_property
or not pms_property.institution_password or not pms_property.institution_property_id
): or not pms_property.institution_user
raise ValidationError( or not pms_property.institution_password
_("The guest information sending settings is not property set up.") ):
) raise ValidationError(
_("The guest information sending settings is not property set up.")
)
else:
if (
not room.institution_property_id
or not room.institution_user
or not room.institution_password
):
raise ValidationError(
_("The guest information sending settings is not property set up.")
)
content = False content = False
# build content # build content
@@ -464,12 +499,14 @@ class TravellerReport(models.TransientModel):
content = self.generate_ses_travellers_list( content = self.generate_ses_travellers_list(
pms_property_id=pms_property.id, pms_property_id=pms_property.id,
date_target=self.date_target, date_target=self.date_target,
room_id=room.id if room else False,
) )
elif self.report_type == "reservations": elif self.report_type == "reservations":
content = self.generate_ses_reservation_list( content = self.generate_ses_reservation_list(
pms_property_id=pms_property.id, pms_property_id=pms_property.id,
date_from=self.date_from, date_from=self.date_from,
date_to=self.date_to, date_to=self.date_to,
room_id=room.id if room else False,
) )
else: else:
content = self.generate_checkin_list( content = self.generate_checkin_list(
@@ -479,22 +516,26 @@ class TravellerReport(models.TransientModel):
if content: if content:
if self.is_ses: if self.is_ses:
institution_property_id = (
room.institution_property_id
if room
else pms_property.institution_property_id
)
if self.report_type == "travellers": if self.report_type == "travellers":
self.txt_filename = ( self.txt_filename = (
pms_property.institution_property_id institution_property_id
+ "-" + "-"
+ self.date_target.strftime("%Y%m%d") + self.date_target.strftime("%Y%m%d")
) )
else: else:
self.txt_filename = ( self.txt_filename = (
pms_property.institution_property_id institution_property_id
+ "-" + "-"
+ self.date_from.strftime("%Y%m%d") + self.date_from.strftime("%Y%m%d")
+ "-" + "-"
+ self.date_to.strftime("%Y%m%d") + self.date_to.strftime("%Y%m%d")
) )
self.txt_filename = self.txt_filename + ".xml" self.txt_filename = self.txt_filename + ".xml"
else: else:
self.txt_filename = ( self.txt_filename = (
pms_property.institution_property_id pms_property.institution_property_id
@@ -521,6 +562,7 @@ class TravellerReport(models.TransientModel):
} }
def generate_checkin_list(self, pms_property_id, date_target=False): def generate_checkin_list(self, pms_property_id, date_target=False):
# DEPRECATED
regex = re.compile("[^a-zA-Z0-9]") regex = re.compile("[^a-zA-Z0-9]")
# check if there's guests info pending to send # check if there's guests info pending to send
@@ -541,11 +583,13 @@ class TravellerReport(models.TransientModel):
lines = self.env["pms.checkin.partner"].search(domain) lines = self.env["pms.checkin.partner"].search(domain)
# build the property info record # build the property info record
# 1 | property id | property name | date | nº of checkin partners # 1 | property id | property name | date | nº of checkin partners
institution_property_id = pms_property.institution_property_id
name = pms_property.name
content = ( content = (
"1|" "1|"
+ pms_property.institution_property_id.upper() + institution_property_id.upper()
+ "|" + "|"
+ regex.sub(" ", pms_property.name.upper()) + regex.sub(" ", name.upper())
+ "|" + "|"
+ datetime.datetime.now().strftime("%Y%m%d|%H%M") + datetime.datetime.now().strftime("%Y%m%d|%H%M")
+ "|" + "|"
@@ -580,6 +624,7 @@ class TravellerReport(models.TransientModel):
return content return content
def send_file_gc(self, file_content, called_from_user, pms_property): def send_file_gc(self, file_content, called_from_user, pms_property):
# DEPRECATED
try: try:
_logger.info( _logger.info(
"Sending file to Guardia Civil, Property %s, date: %s" "Sending file to Guardia Civil, Property %s, date: %s"
@@ -680,6 +725,7 @@ class TravellerReport(models.TransientModel):
) )
def send_file_pn(self, file_content, called_from_user, pms_property): def send_file_pn(self, file_content, called_from_user, pms_property):
# DEPRECATED
try: try:
base_url = "https://webpol.policia.es" base_url = "https://webpol.policia.es"
headers = { headers = {
@@ -805,6 +851,7 @@ class TravellerReport(models.TransientModel):
) )
def send_file_institution(self, pms_property=False, offset=0, date_target=False): def send_file_institution(self, pms_property=False, offset=0, date_target=False):
# DEPRECATED
called_from_user = False called_from_user = False
log = False log = False
try: try:
@@ -898,33 +945,44 @@ class TravellerReport(models.TransientModel):
@api.model @api.model
def send_file_institution_async(self, offset=0): def send_file_institution_async(self, offset=0):
# DEPRECATED
for prop in self.env["pms.property"].search([]): for prop in self.env["pms.property"].search([]):
if prop.institution: if prop.institution:
self.send_file_institution(pms_property=prop, offset=offset) self.send_file_institution(pms_property=prop, offset=offset)
time.sleep(0.5) time.sleep(0.5)
# SES RESERVATIONS # SES RESERVATIONS
def generate_ses_reservation_list(self, pms_property_id, date_from, date_to): def generate_ses_reservation_list(
reservation_ids = ( self, pms_property_id, date_from, date_to, room_id=False
self.env["pms.reservation"] ):
.search( domain = [
[ ("pms_property_id", "=", pms_property_id),
("pms_property_id", "=", pms_property_id), ("state", "!=", "cancel"),
("state", "!=", "cancel"), ("reservation_type", "!=", "out"),
("reservation_type", "!=", "out"), "|",
"|", ("date_order", ">=", date_from),
("date_order", ">=", date_from), ("date_order", "<=", date_to),
("date_order", "<=", date_to), ]
] if room_id:
) domain.append(("preferred_room_id.room_id", "=", room_id))
.mapped("id") reservation_ids = self.env["pms.reservation"].search(domain).mapped("id")
)
return self.generate_xml_reservations(reservation_ids) return self.generate_xml_reservations(reservation_ids)
def generate_xml_reservation(self, solicitud, reservation_id): def generate_xml_reservation(self, solicitud, reservation_id):
reservation = self.env["pms.reservation"].browse(reservation_id) reservation = self.env["pms.reservation"].browse(reservation_id)
institution_property_id = False
if not reservation.pms_property_id.institution_property_id: if (
reservation.preferred_room_id
and reservation.preferred_room_id.institution_independent_account
):
institution_property_id = (
reservation.preferred_room_id.institution_property_id
)
else:
institution_property_id = (
reservation.pms_property_id.institution_property_id
)
if not institution_property_id:
raise ValidationError( raise ValidationError(
_("The property does not have an institution property id.") _("The property does not have an institution property id.")
) )
@@ -936,9 +994,7 @@ class TravellerReport(models.TransientModel):
establecimiento = ET.SubElement(comunicacion, "establecimiento") establecimiento = ET.SubElement(comunicacion, "establecimiento")
# SOLICITUD > COMUNICACION > ESTABLECIMIENTO > CODIGO # SOLICITUD > COMUNICACION > ESTABLECIMIENTO > CODIGO
ET.SubElement( ET.SubElement(establecimiento, "codigo").text = institution_property_id
establecimiento, "codigo"
).text = reservation.pms_property_id.institution_property_id
# SOLICITUD > COMUNICACION > CONTRATO # SOLICITUD > COMUNICACION > CONTRATO
_ses_xml_contract_elements(comunicacion, reservation) _ses_xml_contract_elements(comunicacion, reservation)
@@ -974,17 +1030,14 @@ class TravellerReport(models.TransientModel):
return xml_str return xml_str
# SES RESERVATIONS TRAVELLER REPORT # SES RESERVATIONS TRAVELLER REPORT
def generate_ses_travellers_list(self, pms_property_id, date_target): def generate_ses_travellers_list(self, pms_property_id, date_target, room_id=False):
reservation_ids = ( domain = [
self.env["pms.reservation"] ("pms_property_id", "=", pms_property_id),
.search( ("checkin", "=", date_target),
[ ]
("pms_property_id", "=", pms_property_id), if room_id:
("checkin", "=", date_target), domain.append(("preferred_room_id.room_id", "=", room_id))
] reservation_ids = self.env["pms.reservation"].search(domain).mapped("id")
)
.mapped("id")
)
return self.generate_xml_reservations_travellers_report(reservation_ids) return self.generate_xml_reservations_travellers_report(reservation_ids)
def generate_xml_reservation_travellers_report( def generate_xml_reservation_travellers_report(
@@ -1029,19 +1082,34 @@ class TravellerReport(models.TransientModel):
): ):
raise ValidationError(_("There are some guests not onboard.")) raise ValidationError(_("There are some guests not onboard."))
else: else:
reservations = self.env["pms.reservation"].browse(reservation_ids)
independent_accounts = reservations.filtered(
lambda r: r.preferred_room_id.institution_independent_account
)
if independent_accounts:
institution_property_ids = independent_accounts.mapped(
"preferred_room_id.institution_property_id"
)
if len(institution_property_ids) != 1:
raise ValidationError(
_(
"All reservation rooms must have the same institution property id."
)
)
institution_property_id = institution_property_ids[0]
else:
pms_property = reservations[0].pms_property_id
institution_property_id = pms_property.institution_property_id
if not institution_property_id:
raise ValidationError(
_("The property does not have an institution property id.")
)
# SOLICITUD # SOLICITUD
solicitud = ET.Element("solicitud") solicitud = ET.Element("solicitud")
pms_property = (
self.env["pms.reservation"].browse(reservation_ids[0]).pms_property_id
)
if not pms_property.institution_property_id:
raise ValidationError(
_("The property does not have an institution property id.")
)
# SOLICITUD -> CODIGO ESTABLECIMIENTO # SOLICITUD -> CODIGO ESTABLECIMIENTO
ET.SubElement( ET.SubElement(
solicitud, "codigoEstablecimiento" solicitud, "codigoEstablecimiento"
).text = pms_property.institution_property_id ).text = institution_property_id
for reservation_id in reservation_ids: for reservation_id in reservation_ids:
if ignore_some_not_onboard: if ignore_some_not_onboard:
num_people_on_board = len( num_people_on_board = len(
@@ -1084,6 +1152,17 @@ class TravellerReport(models.TransientModel):
for communication in self.env["pms.ses.communication"].search(domain): for communication in self.env["pms.ses.communication"].search(domain):
data = False data = False
try: try:
if (
communication.room_id
and communication.room_id.institution_independent_account
):
institution_lessor_id = communication.room_id.institution_lessor_id
ses_url = communication.room_id.ses_url
else:
institution_lessor_id = (
communication.reservation_id.pms_property_id.institution_lessor_id
)
ses_url = communication.reservation_id.pms_property_id.ses_url
if communication.operation == DELETE_OPERATION_CODE: if communication.operation == DELETE_OPERATION_CODE:
communication_to_cancel = self.env["pms.ses.communication"].search( communication_to_cancel = self.env["pms.ses.communication"].search(
[ [
@@ -1115,7 +1194,7 @@ class TravellerReport(models.TransientModel):
communication.communication_xml = data communication.communication_xml = data
data = _string_to_zip_to_base64(data) data = _string_to_zip_to_base64(data)
payload = _generate_payload( payload = _generate_payload(
communication.reservation_id.pms_property_id.institution_lessor_id, institution_lessor_id,
communication.operation, communication.operation,
communication.entity, communication.entity,
data, data,
@@ -1125,7 +1204,7 @@ class TravellerReport(models.TransientModel):
soap_response = requests.request( soap_response = requests.request(
"POST", "POST",
communication.reservation_id.pms_property_id.ses_url, ses_url,
headers=_get_auth_headers(communication), headers=_get_auth_headers(communication),
data=payload, data=payload,
verify=get_module_resource("pms_l10n_es", "static", "cert.pem"), verify=get_module_resource("pms_l10n_es", "static", "cert.pem"),
@@ -1162,6 +1241,17 @@ class TravellerReport(models.TransientModel):
] ]
): ):
try: try:
if (
communication.room_id
and communication.room_id.institution_independent_account
):
institution_lessor_id = communication.room_id.institution_lessor_id
ses_url = communication.room_id.ses_url
else:
institution_lessor_id = (
communication.reservation_id.pms_property_id.institution_lessor_id
)
ses_url = communication.reservation_id.pms_property_id.ses_url
time_difference = fields.Datetime.now() - communication.create_date time_difference = fields.Datetime.now() - communication.create_date
hours_difference = ( hours_difference = (
time_difference.days * 24 + time_difference.seconds // 3600 time_difference.days * 24 + time_difference.seconds // 3600
@@ -1181,7 +1271,7 @@ class TravellerReport(models.TransientModel):
communication.communication_xml = data communication.communication_xml = data
data = _string_to_zip_to_base64(data) data = _string_to_zip_to_base64(data)
payload = _generate_payload( payload = _generate_payload(
communication.reservation_id.pms_property_id.institution_lessor_id, institution_lessor_id,
communication.operation, communication.operation,
communication.entity, communication.entity,
data, data,
@@ -1191,7 +1281,7 @@ class TravellerReport(models.TransientModel):
soap_response = requests.request( soap_response = requests.request(
"POST", "POST",
communication.reservation_id.pms_property_id.ses_url, ses_url,
headers=_get_auth_headers(communication), headers=_get_auth_headers(communication),
data=payload, data=payload,
verify=get_module_resource("pms_l10n_es", "static", "cert.pem"), verify=get_module_resource("pms_l10n_es", "static", "cert.pem"),
@@ -1224,6 +1314,17 @@ class TravellerReport(models.TransientModel):
] ]
): ):
try: try:
if (
communication.room_id
and communication.room_id.institution_independent_account
):
institution_lessor_id = communication.room_id.institution_lessor_id
ses_url = communication.room_id.ses_url
else:
institution_lessor_id = (
communication.reservation_id.pms_property_id.institution_lessor_id
)
ses_url = communication.reservation_id.pms_property_id.ses_url
var_xml_get_batch = f""" var_xml_get_batch = f"""
<con:lotes <con:lotes
xmlns:con="http://www.neg.hospedajes.mir.es/consultarComunicacion"> xmlns:con="http://www.neg.hospedajes.mir.es/consultarComunicacion">
@@ -1233,7 +1334,7 @@ class TravellerReport(models.TransientModel):
communication.query_status_xml = var_xml_get_batch communication.query_status_xml = var_xml_get_batch
data = _string_to_zip_to_base64(var_xml_get_batch) data = _string_to_zip_to_base64(var_xml_get_batch)
payload = _generate_payload( payload = _generate_payload(
communication.reservation_id.pms_property_id.institution_lessor_id, institution_lessor_id,
"C", "C",
False, False,
data, data,
@@ -1243,7 +1344,7 @@ class TravellerReport(models.TransientModel):
soap_response = requests.request( soap_response = requests.request(
"POST", "POST",
communication.reservation_id.pms_property_id.ses_url, ses_url,
headers=_get_auth_headers(communication), headers=_get_auth_headers(communication),
data=payload, data=payload,
verify=get_module_resource("pms_l10n_es", "static", "cert.pem"), verify=get_module_resource("pms_l10n_es", "static", "cert.pem"),