From a07aba7188b5af677d650357d33332a3df4982c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dar=C3=ADo=20Lodeiros?= Date: Sun, 31 Dec 2023 12:01:53 +0100 Subject: [PATCH] [ADD]pms_api_rest: OTA API configurations --- pms_api_rest/__manifest__.py | 1 + pms_api_rest/models/__init__.py | 1 + pms_api_rest/models/ota_property_settings.py | 34 +++++++++++ pms_api_rest/models/pms_property.py | 7 +++ pms_api_rest/models/res_users.py | 11 ++++ pms_api_rest/security/ir.model.access.csv | 3 + pms_api_rest/services/pms_folio_service.py | 59 +++++++++++++++++--- pms_api_rest/views/pms_property_views.xml | 16 ++++++ pms_api_rest/views/res_users_views.xml | 12 ++++ 9 files changed, 137 insertions(+), 7 deletions(-) create mode 100644 pms_api_rest/models/ota_property_settings.py create mode 100644 pms_api_rest/security/ir.model.access.csv diff --git a/pms_api_rest/__manifest__.py b/pms_api_rest/__manifest__.py index fdde38e46..1c48864e8 100644 --- a/pms_api_rest/__manifest__.py +++ b/pms_api_rest/__manifest__.py @@ -21,6 +21,7 @@ "python": ["jwt", "simplejson", "marshmallow", "jose"], }, "data": [ + "security/ir.model.access.csv", "data/sql_reports.xml", "data/auth_jwt_validator.xml", "data/pms_app_reset_password_template.xml", diff --git a/pms_api_rest/models/__init__.py b/pms_api_rest/models/__init__.py index 09f08a589..06aad4285 100644 --- a/pms_api_rest/models/__init__.py +++ b/pms_api_rest/models/__init__.py @@ -5,3 +5,4 @@ from . import sql_export from . import pms_room_type_class from . import account_bank_statement from . import product_template +from . import ota_property_settings diff --git a/pms_api_rest/models/ota_property_settings.py b/pms_api_rest/models/ota_property_settings.py new file mode 100644 index 000000000..0298b8bbc --- /dev/null +++ b/pms_api_rest/models/ota_property_settings.py @@ -0,0 +1,34 @@ +from odoo import fields, models + + +class OtaPropertySettings(models.Model): + _name = "ota.property.settings" + + pms_property_id = fields.Many2one( + string="PMS Property", + help="PMS Property", + comodel_name="pms.property", + default=lambda self: self.env.user.get_active_property_ids()[0], + ) + agency_id = fields.Many2one( + string="Partner", + help="Partner", + comodel_name="res.partner", + domain=[("is_agency", "=", True)], + ) + pms_api_alowed_payments = fields.Boolean( + string="PMS API Allowed Payments", + help="PMS API Allowed Payments", + ) + pms_api_payment_journal_id = fields.Many2one( + string="Payment Journal", + help="Payment Journal", + comodel_name="account.journal", + ) + pms_api_payment_identifier = fields.Char( + string="Payment Identifier", + help=""" + Text string used by the OTA to identify a prepaid reservation. + The string will be searched within the partnerRequests parameter. + """, + ) diff --git a/pms_api_rest/models/pms_property.py b/pms_api_rest/models/pms_property.py index c15c95dd1..3ef24dd61 100644 --- a/pms_api_rest/models/pms_property.py +++ b/pms_api_rest/models/pms_property.py @@ -93,3 +93,10 @@ class PmsProperty(models.Model): string="Hotel image", store=True, ) + + ota_property_settings_ids = fields.One2many( + string="OTA Property Settings", + help="OTA Property Settings", + comodel_name="ota.property.settings", + inverse_name="pms_property_id", + ) diff --git a/pms_api_rest/models/res_users.py b/pms_api_rest/models/res_users.py index c394fb418..0708fb705 100644 --- a/pms_api_rest/models/res_users.py +++ b/pms_api_rest/models/res_users.py @@ -22,6 +22,17 @@ class ResUsers(models.Model): readonly=False, ) + pms_api_client = fields.Boolean( + string="PMS API Client", + help="PMS API Client", + ) + + pms_api_payment_journal_id = fields.Many2one( + string="Payment Journal", + help="Payment Journal", + comodel_name="account.journal", + ) + def _get_default_avail_rule_fields(self): default_avail_rule_fields = self.env["ir.model.fields"].search( [ diff --git a/pms_api_rest/security/ir.model.access.csv b/pms_api_rest/security/ir.model.access.csv new file mode 100644 index 000000000..f818625d3 --- /dev/null +++ b/pms_api_rest/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +user_access_ota_property_settings,user_access_ota_property_settings,model_ota_property_settings,pms.group_pms_user,1,0,0,0 +manager_access_ota_property_settings,manager_access_ota_property_settings,model_ota_property_settings,pms.group_pms_manager,1,1,1,1 diff --git a/pms_api_rest/services/pms_folio_service.py b/pms_api_rest/services/pms_folio_service.py index 6c4e61da7..508a7c923 100644 --- a/pms_api_rest/services/pms_folio_service.py +++ b/pms_api_rest/services/pms_folio_service.py @@ -772,12 +772,7 @@ class PmsFolioService(Component): ("ref", "ilike", transaction.reference), ] ): - # TODO: Move this to the user API payment configuration - journal = ( - self.env["channel.wubook.backend"] - .search([("pms_property_id", "=", folio.pms_property_id.id)]) - .wubook_journal_id - ) + journal = transaction.journalId if transaction.transactionType == "inbound": folio.do_payment( journal, @@ -1438,7 +1433,7 @@ class PmsFolioService(Component): # - Channel Manager # - Booking Engine # - ... - if "neobookings" in self.env.user.login: + if self.env.user.pms_api_client: return "external_app" return "internal_app" @@ -1605,6 +1600,8 @@ class PmsFolioService(Component): skip_compute_service_ids=True, force_overbooking=True if call_type == "external_app" else False, ).write(folio_vals) + # Compute OTA transactions + pms_folio_info.transactions = self.normalize_payments_structure(pms_folio_info) if pms_folio_info.transactions: self.compute_transactions(folio, pms_folio_info.transactions) # Force update availability @@ -1618,6 +1615,54 @@ class PmsFolioService(Component): date_to=date_to, ) + def normalize_payments_structure(self, pms_folio_info): + """ + This method use the OTA payment structure to normalize the structure + and incorporate them in the transactions datamodel param + """ + if pms_folio_info.transactions: + for transaction in pms_folio_info.transactions: + if not transaction.journalId: + ota_conf = self.env["ota.property.settings"].search( + [ + ("pms_property_id", "=", pms_folio_info.pmsPropertyId), + ("agency_id", "=", self.env.user.partner_id.id), + ] + ) + transaction.journalId = ota_conf.pms_api_payment_journal_id.id + elif pms_folio_info.agencyId: + ota_conf = self.env["ota.property.settings"].search( + [ + ("pms_property_id", "=", pms_folio_info.pmsPropertyId), + ("agency_id", "=", pms_folio_info.agencyId), + ] + ) + # TODO: Review where to input the data to identify payments, + # as partnerRequest in the reservation doesn't seem like the best location. + if ( + ota_conf + and ota_conf.pms_api_alowed_payments + and any( + [ + reservation.partnerRequests + and ota_conf.pms_api_payment_identifier + in reservation.partnerRequests + for reservation in pms_folio_info.reservations + ] + ) + ): + journal = ota_conf.pms_api_payment_journal_id + pmsTransactionInfo = self.env.datamodels["pms.transaction.info"] + pms_folio_info.transactions = [ + pmsTransactionInfo( + journalId=journal.id, + transactionType="inbound", + amount=pms_folio_info.totalPrice, + date=fields.Date.today().strftime("%Y-%m-%d"), + reference=pms_folio_info.externalReference, + ) + ] + def wrapper_reservations(self, folio, info_reservations): """ This method is used to create or update the reservations in folio diff --git a/pms_api_rest/views/pms_property_views.xml b/pms_api_rest/views/pms_property_views.xml index 39b4a2bfc..03a52368f 100644 --- a/pms_api_rest/views/pms_property_views.xml +++ b/pms_api_rest/views/pms_property_views.xml @@ -90,6 +90,22 @@ + + + + + + + + + + + + + diff --git a/pms_api_rest/views/res_users_views.xml b/pms_api_rest/views/res_users_views.xml index 0049c4906..7233cd26a 100644 --- a/pms_api_rest/views/res_users_views.xml +++ b/pms_api_rest/views/res_users_views.xml @@ -17,6 +17,18 @@ options="{'no_create': True}" domain="['&',('model_id', '=', 'pms.availability.plan.rule'), ('name', 'in', ('min_stay', 'max_stay', 'quota', 'max_stay_arrival', 'closed_arrival', 'closed', 'closed_departure', 'min_stay_arrival', 'max_avail'))]" /> + +