diff --git a/pms/__manifest__.py b/pms/__manifest__.py index a4a90eece..2048b9924 100644 --- a/pms/__manifest__.py +++ b/pms/__manifest__.py @@ -16,10 +16,16 @@ "base", "mail", # "account_payment_return", - # "partner_firstname", # "email_template_qweb", "sale", "multi_pms_properties", + "partner_identification", + "partner_firstname", + "partner_second_lastname", + "partner_contact_gender", + "partner_contact_birthdate", + "partner_contact_nationality", + # "partner_identification_unique_by_category", ], "data": [ "security/pms_security.xml", @@ -27,8 +33,10 @@ "data/cron_jobs.xml", "data/pms_sequence.xml", "data/pms_data.xml", + "data/traveller_report_paperformat.xml", "report/pms_folio.xml", "report/pms_folio_templates.xml", + "report/traveller_report_action.xml", # "templates/pms_email_template.xml", "data/menus.xml", "wizards/wizard_payment_folio.xml", @@ -67,6 +75,8 @@ "views/account_journal_views.xml", "views/folio_portal_templates.xml", "views/reservation_portal_templates.xml", + "views/res_company_views.xml", + "views/traveller_report_template.xml", "wizards/wizard_split_join_swap_reservation.xml", "wizards/wizard_massive_changes.xml", "wizards/wizard_advanced_filters.xml", diff --git a/pms/data/pms_data.xml b/pms/data/pms_data.xml index 685754758..edfae1c26 100644 --- a/pms/data/pms_data.xml +++ b/pms/data/pms_data.xml @@ -52,5 +52,90 @@ Agency indirect + + + Passport + P + + + + Driving License + C + +letters = { + 0: "T", + 1: "R", + 2: "W", + 3: "A", + 4: "G", + 5: "M", + 6: "Y", + 7: "F", + 8: "P", + 9: "D", + 10: "X", + 11: "B", + 12: "N", + 13: "J", + 14: "Z", + 15: "S", + 16: "Q", + 17: "V", + 18: "H", + 19: "L", + 20: "C", + 21: "K", + 22: "E", +} +dni_number = id_number.name[0:8] +dni_letter = id_number.name[ + len(id_number.name) - 1 : len(id_number.name) +] +if dni_number.isdigit() and not dni_letter.isdigit(): + if letters.get(int(dni_number) % 23) != dni_letter.upper(): + failed = True +else: + failed = True + + + + + Identification Document + I + + + + Spanish Residence permit + N + +permit_first_letter=id_number.name[0:1] +permit_last_letter = id_number.name[ + len(id_number.name) - 1 : len(id_number.name) +] +if (permit_first_letter.upper() in ['X','Y']) and id_number.name[1:8].isdigit() and not permit_last_letter.isdigit(): + failed = False +else: + failed = True + + + + + European Residence permit + X + +permit_first_letter=id_number.name[0:1] +permit_last_letter = id_number.name[ + len(id_number.name) - 1 : len(id_number.name) +] +if (permit_first_letter.upper() in ['X','Y']) and id_number.name[1:8].isdigit() and not permit_last_letter.isdigit(): + failed = False +else: + failed = True + + + diff --git a/pms/data/traveller_report_paperformat.xml b/pms/data/traveller_report_paperformat.xml new file mode 100644 index 000000000..b5f8b56ef --- /dev/null +++ b/pms/data/traveller_report_paperformat.xml @@ -0,0 +1,20 @@ + + + + + Traveller Report PaperFormat + + custom + 200 + 75 + Portrait + 1 + 3 + 0 + 0 + + 1 + 201 + + + diff --git a/pms/models/__init__.py b/pms/models/__init__.py index 5cb804757..2a7be0cf8 100644 --- a/pms/models/__init__.py +++ b/pms/models/__init__.py @@ -46,3 +46,4 @@ from . import account_bank_statement_line from . import account_bank_statement from . import account_journal from . import pms_availability +from . import res_partner_id_number diff --git a/pms/models/pms_checkin_partner.py b/pms/models/pms_checkin_partner.py index 8d1a846cf..2e9e3e8f7 100644 --- a/pms/models/pms_checkin_partner.py +++ b/pms/models/pms_checkin_partner.py @@ -25,8 +25,11 @@ class PmsCheckinPartner(models.Model): partner_id = fields.Many2one( string="Partner", help="Partner associated with checkin partner", + readonly=False, + store=True, comodel_name="res.partner", domain="[('is_company', '=', False)]", + compute="_compute_partner_id", ) reservation_id = fields.Many2one( string="Reservation", @@ -52,11 +55,7 @@ class PmsCheckinPartner(models.Model): check_pms_properties=True, ) name = fields.Char( - string="Name", - help="Checkin partner name", - readonly=False, - store=True, - compute="_compute_name", + string="Name", help="Checkin partner name", related="partner_id.name" ) email = fields.Char( string="E-mail", @@ -68,9 +67,9 @@ class PmsCheckinPartner(models.Model): mobile = fields.Char( string="Mobile", help="Checkin Partner Mobile", - compute="_compute_mobile", - store=True, readonly=False, + store=True, + compute="_compute_mobile", ) image_128 = fields.Image( string="Image", @@ -80,8 +79,8 @@ class PmsCheckinPartner(models.Model): segmentation_ids = fields.Many2many( string="Segmentation", help="Segmentation tags to classify checkin partners", - related="reservation_id.segmentation_ids", readonly=True, + related="reservation_id.segmentation_ids", ) checkin = fields.Date( string="Checkin", @@ -116,7 +115,167 @@ class PmsCheckinPartner(models.Model): compute="_compute_state", ) - # Compute + gender = fields.Selection( + string="Gender", + help="host gender", + readonly=False, + store=True, + compute="_compute_gender", + selection=[("male", "Male"), ("female", "Female"), ("other", "Other")], + ) + nationality_id = fields.Many2one( + string="Nationality ID", + help="host nationality", + readonly=False, + store=True, + compute="_compute_nationality", + comodel_name="res.country", + ) + firstname = fields.Char( + string="First Name", + help="host firstname", + readonly=False, + store=True, + compute="_compute_firstname", + ) + lastname = fields.Char( + string="Last Name", + help="host lastname", + readonly=False, + store=True, + compute="_compute_lastname", + ) + lastname2 = fields.Char( + string="Second Last Name", + help="host second lastname", + readonly=False, + store=True, + compute="_compute_lastname2", + ) + birthdate_date = fields.Date( + string="Birthdate", + help="host birthdate", + readonly=False, + store=True, + compute="_compute_birth_date", + ) + document_number = fields.Char( + string="Document Number", + help="Host document number", + readonly=False, + store=True, + compute="_compute_document_number", + ) + document_type = fields.Many2one( + string="Document Type", + help="Select a valid document type", + readonly=False, + store=True, + comodel_name="res.partner.id_category", + compute="_compute_document_type", + ) + document_expedition_date = fields.Date( + string="Expedition Date", + help="Date on which document_type was issued", + readonly=False, + store=True, + compute="_compute_document_expedition_date", + ) + + document_id = fields.Many2one( + string="Document", + help="Technical field", + readonly=False, + store=True, + comodel_name="res.partner.id_number", + compute="_compute_document_id", + ondelete="restrict", + ) + + incongruences = fields.Char( + string="Incongruences", + help="Technical field", + compute="_compute_incongruences", + ) + + @api.depends("partner_id") + def _compute_document_number(self): + for record in self: + if not record.document_number: + if record.partner_id.id_numbers: + record.document_number = record.partner_id.id_numbers[0].name + + @api.depends("partner_id") + def _compute_document_type(self): + for record in self: + if record.partner_id and record.partner_id.id_numbers: + if not record.document_type: + if record.partner_id.id_numbers: + record.document_type = record.partner_id.id_numbers[ + 0 + ].category_id + + @api.depends( + "partner_id", + ) + def _compute_document_expedition_date(self): + for record in self: + if record.partner_id and record.partner_id.id_numbers: + if not record.document_expedition_date: + record.document_expedition_date = record.partner_id.id_numbers[ + 0 + ].valid_from + + @api.depends("partner_id") + def _compute_firstname(self): + for record in self: + if not record.firstname and record.partner_id.firstname: + record.firstname = record.partner_id.firstname + elif not record.firstname: + record.firstname = False + + @api.depends("partner_id") + def _compute_lastname(self): + for record in self: + if not record.lastname and record.partner_id.lastname: + record.lastname = record.partner_id.lastname + elif not record.lastname: + record.lastname = False + + @api.depends("partner_id") + def _compute_lastname2(self): + for record in self: + if not record.lastname2 and record.partner_id.lastname2: + record.lastname2 = record.partner_id.lastname2 + elif not record.lastname2: + record.lastname2 = False + + @api.depends("partner_id") + def _compute_birth_date(self): + for record in self: + if not record.birthdate_date and record.partner_id.birthdate_date: + record.birthdate_date = record.partner_id.birthdate_date + elif not record.birthdate_date: + record.birthdate_date = False + + @api.depends( + "partner_id", + ) + def _compute_gender(self): + for record in self: + if not record.gender and record.partner_id.gender: + record.gender = record.partner_id.gender + elif not record.gender: + record.gender = False + + @api.depends("partner_id") + def _compute_nationality(self): + for record in self: + if not record.nationality_id and record.partner_id.nationality_id: + record.nationality_id = record.partner_id.nationality_id + elif not record.nationality_id: + record.nationality_id = False + @api.depends("reservation_id", "folio_id", "reservation_id.preferred_room_id") def _compute_identifier(self): for record in self: @@ -163,21 +322,109 @@ class PmsCheckinPartner(models.Model): ) def _compute_name(self): for record in self: - if not record.name: + if not record.name or record.partner_id.name: record.name = record.partner_id.name - @api.depends("partner_id", "partner_id.email") + @api.depends("partner_id") def _compute_email(self): for record in self: - if not record.email: + if not record.email or record.partner_id.email: record.email = record.partner_id.email - @api.depends("partner_id", "partner_id.mobile") + @api.depends("partner_id") def _compute_mobile(self): for record in self: - if not record.mobile: + if not record.mobile or record.partner_id.mobile: record.mobile = record.partner_id.mobile + @api.depends("partner_id") + def _compute_document_id(self): + for record in self: + if record.partner_id: + if ( + not record.document_id + and record.document_number + and record.document_type + ): + id_number_id = self.env["res.partner.id_number"].search( + [ + ("partner_id", "=", record.partner_id.id), + ("name", "=", record.document_number), + ("category_id", "=", record.document_type.id), + ] + ) + if not id_number_id: + id_number_id = self.env["res.partner.id_number"].create( + { + "partner_id": record.partner_id.id, + "name": record.document_number, + "category_id": record.document_type.id, + "valid_from": record.document_expedition_date, + } + ) + + record.document_id = id_number_id + else: + record.document_id = False + + @api.depends( + "document_number", "document_type", "firstname", "lastname", "lastname2" + ) + def _compute_partner_id(self): + for record in self: + if not record.partner_id: + if record.document_number and record.document_type: + number = self.env["res.partner.id_number"].search( + [ + ("name", "=", record.document_number), + ("category_id", "=", record.document_type.id), + ] + ) + partner = self.env["res.partner"].search( + [("id", "=", number.partner_id.id)] + ) + if not partner: + if record.firstname or record.lastname or record.lastname2: + partner_values = { + "firstname": record.firstname, + "lastname": record.lastname, + "lastname2": record.lastname2, + "gender": record.gender, + "birthdate_date": record.birthdate_date, + "nationality_id": record.nationality_id.id, + } + partner = self.env["res.partner"].create(partner_values) + record.partner_id = partner + + @api.depends( + "firstname", + "lastname", + "lastname2", + "gender", + "birthdate_date", + "nationality_id", + "email", + "mobile", + ) + def _compute_incongruences(self): + for record in self: + incongruous_fields = "" + if record.partner_id: + for field in record._checkin_partner_fields(): + if ( + record.partner_id[field] + and record.partner_id[field] != record[field] + ): + incongruous_fields += record._fields[field].string + ", " + if incongruous_fields: + record.incongruences = ( + incongruous_fields + "field/s don't correspond to saved host" + ) + else: + record.incongruences = False + else: + record.incongruences = False + @api.constrains("departure", "arrival") def _check_departure(self): for record in self: @@ -224,6 +471,15 @@ class PmsCheckinPartner(models.Model): ): raise ValidationError(_("'%s' is not a valid phone", record.mobile)) + @api.constrains("document_number") + def check_document_number(self): + for record in self: + if record.partner_id: + for number in record.partner_id.id_numbers: + if record.document_type == number.category_id: + if record.document_number != number.name: + raise ValidationError(_("Document_type has already exists")) + @api.model def create(self, vals): # The checkin records are created automatically from adult depends @@ -255,43 +511,6 @@ class PmsCheckinPartner(models.Model): _("Is not possible to create the proposed check-in in this reservation") ) - def write(self, vals): - res = super(PmsCheckinPartner, self).write(vals) - ResPartner = self.env["res.partner"] - if any(field in vals for field in ResPartner._get_key_fields()): - # Create Partner if get key field in the checkin - for record in self: - key = False - partner = False - if not record.partner_id: - partner_vals = {} - for field in self._checkin_partner_fields(): - if getattr(record, field): - partner_vals[field] = getattr(record, field) - if field in ResPartner._get_key_fields() and partner_vals.get( - field - ): - key = True - # REVIEW: if partner exist, we can merge? - partner = ResPartner.search( - [(field, "=", getattr(record, field))] - ) - if key: - if not partner: - partner = ResPartner.create(partner_vals) - record.partner_id = partner - - if any(field in vals for field in self._checkin_partner_fields()): - # Update partner when the checkin partner field is not set on the partner - for record in self: - if record.partner_id: - partner_vals = {} - for field in self._checkin_partner_fields(): - if not getattr(record.partner_id, field): - partner_vals[field] = getattr(record, field) - record.partner_id.write(partner_vals) - return res - def unlink(self): reservations = self.mapped("reservation_id") res = super().unlink() @@ -303,13 +522,30 @@ class PmsCheckinPartner(models.Model): # api.depends need "reservation_id.state" in the lambda function if depends: return ["reservation_id.state", "name"] - return ["name"] + mandatory_fields = [ + "name", + "birthdate_date", + "gender", + "document_number", + "document_type", + "document_expedition_date", + ] + + return mandatory_fields @api.model def _checkin_partner_fields(self): # api.depends need "reservation_id.state" in the lambda function - checkin_fields = self._checkin_mandatory_fields() - checkin_fields.extend(["mobile", "email"]) + checkin_fields = [ + "firstname", + "lastname", + "lastname2", + "mobile", + "email", + "gender", + "nationality_id", + "birthdate_date", + ] return checkin_fields @api.model @@ -339,6 +575,7 @@ class PmsCheckinPartner(models.Model): raise ValidationError(_("It is not yet checkin day!")) if record.reservation_id.checkout <= fields.Date.today(): raise ValidationError(_("Its too late to checkin")) + if any( not getattr(record, field) for field in self._checkin_mandatory_fields() ): diff --git a/pms/models/pms_property.py b/pms/models/pms_property.py index 36f7c4257..e6609ee31 100644 --- a/pms/models/pms_property.py +++ b/pms/models/pms_property.py @@ -89,6 +89,15 @@ class PmsProperty(models.Model): selection=_tz_get, ) + cardex_warning = fields.Text( + string="Warning in Cardex", + default="Time to access rooms: 14: 00h. " + "Departure time: 12: 00h. If the accommodation " + "is not left at that time, the establishment will " + "charge a day's stay according to current rate that day", + help="Notice under the signature on the traveler's ticket.", + ) + @api.constrains("default_arrival_hour") def _check_arrival_hour(self): for record in self: diff --git a/pms/models/pms_reservation.py b/pms/models/pms_reservation.py index a6ea50ff8..73ace6ea3 100644 --- a/pms/models/pms_reservation.py +++ b/pms/models/pms_reservation.py @@ -1340,6 +1340,16 @@ class PmsReservation(models.Model): raise ValidationError(_("booking agency with wrong configuration: ")) # Action methods + def print_all_checkins(self): + checkins = self.env["pms.checkin.partner"] + for record in self: + checkins += record.checkin_partner_ids.filtered( + lambda s: s.state in ("onboard", "done") + ) + if checkins: + return self.env.ref("pms.action_report_viajero").report_action(checkins) + else: + raise ValidationError(_("Some checkin partners ")) def open_folio(self): action = self.env.ref("pms.open_pms_folio1_form_tree_all").sudo().read()[0] diff --git a/pms/models/res_company.py b/pms/models/res_company.py index 79135d45a..341d20f80 100644 --- a/pms/models/res_company.py +++ b/pms/models/res_company.py @@ -13,3 +13,8 @@ class ResCompany(models.Model): comodel_name="pms.property", inverse_name="company_id", ) + + privacy_policy = fields.Text( + string="Privacy Policy", + help="Authorization by the user for the" "manage of their personal data", + ) diff --git a/pms/models/res_partner.py b/pms/models/res_partner.py index d92865fe6..d8608318b 100644 --- a/pms/models/res_partner.py +++ b/pms/models/res_partner.py @@ -56,6 +56,180 @@ class ResPartner(models.Model): check_pms_properties=True, ) + pms_checkin_partner_ids = fields.One2many( + string="Checkin Partners", + help="Associated checkin partners", + comodel_name="pms.checkin.partner", + inverse_name="partner_id", + ) + + gender = fields.Selection( + readonly=False, + store=True, + compute="_compute_gender", + ) + + birthdate_date = fields.Date( + readonly=False, + store=True, + compute="_compute_birthdate_date", + ) + + nationality_id = fields.Many2one( + readonly=False, + store=True, + compute="_compute_nationality_id", + ) + + email = fields.Char( + readonly=False, + store=True, + compute="_compute_email", + ) + mobile = fields.Char( + readonly=False, + store=True, + compute="_compute_mobile", + ) + + firstname = fields.Char( + readonly=False, + store=True, + compute="_compute_firstname", + ) + + lastname = fields.Char( + readonly=False, + store=True, + compute="_compute_lastname", + ) + + lastname2 = fields.Char( + readonly=False, + store=True, + compute="_compute_lastname2", + ) + + @api.depends("pms_checkin_partner_ids", "pms_checkin_partner_ids.gender") + def _compute_gender(self): + if hasattr(super(), "_compute_gender"): + super()._compute_field() + for record in self: + if not record.gender and record.pms_checkin_partner_ids: + gender = list(set(record.pms_checkin_partner_ids.mapped("gender"))) + if len(gender) == 1: + record.gender = gender[0] + else: + record.gender = False + elif not record.gender: + record.gender = False + + @api.depends("pms_checkin_partner_ids", "pms_checkin_partner_ids.birthdate_date") + def _compute_birthdate_date(self): + if hasattr(super(), "_compute_birthdate_date"): + super()._compute_field() + for record in self: + if not record.birthdate_date and record.pms_checkin_partner_ids: + birthdate = list( + set(record.pms_checkin_partner_ids.mapped("birthdate_date")) + ) + if len(birthdate) == 1: + record.birthdate_date = birthdate[0] + else: + record.birthdate_date = False + elif not record.birthdate_date: + record.birthdate_date = False + + @api.depends("pms_checkin_partner_ids", "pms_checkin_partner_ids.nationality_id") + def _compute_nationality_id(self): + if hasattr(super(), "_compute_nationality_id"): + super()._compute_field() + for record in self: + if not record.nationality_id and record.pms_checkin_partner_ids: + nationality_id = list( + set(record.pms_checkin_partner_ids.mapped("nationality_id")) + ) + if len(nationality_id) == 1: + record.nationality_id = nationality_id[0] + else: + record.nationality_id = False + elif not record.nationality_id: + record.nationality_id = False + + @api.depends("pms_checkin_partner_ids", "pms_checkin_partner_ids.email") + def _compute_email(self): + if hasattr(super(), "_compute_email"): + super()._compute_field() + for record in self: + if not record.email and record.pms_checkin_partner_ids: + email = list(set(record.pms_checkin_partner_ids.mapped("email"))) + if len(email) == 1: + record.email = email[0] + else: + record.email = False + elif not record.email: + record.email = False + + @api.depends("pms_checkin_partner_ids", "pms_checkin_partner_ids.mobile") + def _compute_mobile(self): + if hasattr(super(), "_compute_mobile"): + super()._compute_field() + for record in self: + if not record.mobile and record.pms_checkin_partner_ids: + mobile = list(set(record.pms_checkin_partner_ids.mapped("mobile"))) + if len(mobile) == 1: + record.mobile = mobile[0] + else: + record.mobile = False + elif not record.mobile: + record.mobile = False + + @api.depends("pms_checkin_partner_ids", "pms_checkin_partner_ids.firstname") + def _compute_firstname(self): + if hasattr(super(), "_compute_firstname"): + super()._compute_field() + for record in self: + if not record.firstname and record.pms_checkin_partner_ids: + firstname = list( + set(record.pms_checkin_partner_ids.mapped("firstname")) + ) + if len(firstname) == 1: + record.firstname = firstname[0] + else: + record.firstname = False + elif not record.firstname: + record.firstname = False + + @api.depends("pms_checkin_partner_ids", "pms_checkin_partner_ids.lastname") + def _compute_lastname(self): + if hasattr(super(), "_compute_lastname"): + super()._compute_field() + for record in self: + if not record.lastname and record.pms_checkin_partner_ids: + lastname = list(set(record.pms_checkin_partner_ids.mapped("lastname"))) + if len(lastname) == 1: + record.lastname = lastname[0] + else: + record.lastname = False + elif not record.lastname: + record.lastname = False + + @api.depends("pms_checkin_partner_ids", "pms_checkin_partner_ids.lastname2") + def _compute_lastname2(self): + if hasattr(super(), "_compute_lastname2"): + super()._compute_field() + for record in self: + if not record.lastname2 and record.pms_checkin_partner_ids: + lastname2 = list( + set(record.pms_checkin_partner_ids.mapped("lastname2")) + ) + if len(lastname2) == 1: + record.lastname2 = lastname2[0] + else: + record.lastname2 = False + elif not record.lastname2: + record.lastname2 = False + def _compute_reservations_count(self): # TODO: recuperar las reservas de los folios del partner pms_reservation_obj = self.env["pms.reservation"] @@ -149,4 +323,6 @@ class ResPartner(models.Model): @api.model def _get_key_fields(self): - return [] + key_fields = super(ResPartner, self)._get_key_fields() + key_fields.extend(["document_number"]) + return key_fields diff --git a/pms/models/res_partner_id_number.py b/pms/models/res_partner_id_number.py new file mode 100644 index 000000000..74138810f --- /dev/null +++ b/pms/models/res_partner_id_number.py @@ -0,0 +1,55 @@ +# Copyright 2004-2010 Tiny SPRL http://tiny.be +# Copyright 2010-2012 ChriCar Beteiligungs- und Beratungs- GmbH +# http://www.camptocamp.at +# Copyright 2015 Antiun Ingenieria, SL (Madrid, Spain) +# http://www.antiun.com +# Antonio Espinosa +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class ResPartnerIdNumber(models.Model): + _inherit = "res.partner.id_number" + + valid_from = fields.Date( + readonly=False, + store=True, + compute="_compute_valid_from", + ) + + @api.depends( + "partner_id", "partner_id.pms_checkin_partner_ids.document_expedition_date" + ) + def _compute_valid_from(self): + if hasattr(super(), "_compute_valid_from"): + super()._compute_field() + for record in self: + if not record.valid_from and record.partner_id.pms_checkin_partner_ids: + document_expedition_date = list( + set( + record.partner_id.pms_checkin_partner_ids.mapped( + "document_expedition_date" + ) + ) + ) + if len(document_expedition_date) == 1: + record.valid_from = document_expedition_date[0] + else: + record.valid_from = False + elif not record.valid_from: + record.valid_from = False + + @api.constrains("partner_id", "category_id") + def _check_category_id_unique(self): + for record in self: + id_number = self.env["res.partner.id_number"].search( + [ + ("partner_id", "=", record.partner_id.id), + ("category_id", "=", record.category_id.id), + ] + ) + if len(id_number) > 1: + raise ValidationError(_("Partner already has this document type")) diff --git a/pms/report/traveller_report_action.xml b/pms/report/traveller_report_action.xml new file mode 100644 index 000000000..e36b78184 --- /dev/null +++ b/pms/report/traveller_report_action.xml @@ -0,0 +1,14 @@ + + + + + + diff --git a/pms/tests/test_pms_checkin_partner.py b/pms/tests/test_pms_checkin_partner.py index d9b893c44..defa7570e 100644 --- a/pms/tests/test_pms_checkin_partner.py +++ b/pms/tests/test_pms_checkin_partner.py @@ -1,49 +1,98 @@ +import datetime import logging from freezegun import freeze_time from odoo import fields from odoo.exceptions import ValidationError -from odoo.tests import common + +from .common import TestPms _logger = logging.getLogger(__name__) -@freeze_time("2012-01-14") -class TestPmsCheckinPartner(common.SavepointCase): - @classmethod - def arrange_single_checkin(cls): - # Arrange for one checkin on one reservation - cls.host1 = cls.env["res.partner"].create( +class TestPmsCheckinPartner(TestPms): + @freeze_time("2012-01-14") + def setUp(self): + super().setUp() + self.room_type1 = self.env["pms.room.type"].create( + { + "pms_property_ids": [self.pms_property1.id], + "name": "Triple", + "default_code": "TRP", + "class_id": self.room_type_class1.id, + } + ) + self.room1 = self.env["pms.room"].create( + { + "pms_property_id": self.pms_property1.id, + "name": "Triple 101", + "room_type_id": self.room_type1.id, + "capacity": 3, + } + ) + self.room1_2 = self.env["pms.room"].create( + { + "pms_property_id": self.pms_property1.id, + "name": "Triple 111", + "room_type_id": self.room_type1.id, + "capacity": 3, + } + ) + self.room1_3 = self.env["pms.room"].create( + { + "pms_property_id": self.pms_property1.id, + "name": "Triple 222", + "room_type_id": self.room_type1.id, + "capacity": 3, + } + ) + + self.host1 = self.env["res.partner"].create( { "name": "Miguel", "phone": "654667733", "email": "miguel@example.com", + "birthdate_date": "1995-12-10", + "gender": "male", + } + ) + self.id_category = self.env["res.partner.id_category"].create( + {"name": "DNI", "code": "D"} + ) + self.env["res.partner.id_number"].create( + { + "category_id": self.id_category.id, + "name": "30065089H", + "valid_from": datetime.date.today(), + "partner_id": self.host1.id, } ) reservation_vals = { - "checkin": "2012-01-14", - "checkout": "2012-01-17", - "room_type_id": cls.env.ref("pms.pms_room_type_3").id, - "partner_id": cls.host1.id, + "checkin": datetime.date.today(), + "checkout": datetime.date.today() + datetime.timedelta(days=3), + "room_type_id": self.room_type1.id, + "partner_id": self.host1.id, "adults": 3, - "pms_property_id": cls.env.ref("pms.main_pms_property").id, + "pms_property_id": self.pms_property1.id, } - demo_user = cls.env.ref("base.user_demo") - cls.reservation_1 = ( - cls.env["pms.reservation"].with_user(demo_user).create(reservation_vals) - ) - cls.checkin1 = cls.env["pms.checkin.partner"].create( + self.reservation_1 = self.env["pms.reservation"].create(reservation_vals) + self.checkin1 = self.env["pms.checkin.partner"].create( { - "partner_id": cls.host1.id, - "reservation_id": cls.reservation_1.id, + "partner_id": self.host1.id, + "reservation_id": self.reservation_1.id, } ) def test_auto_create_checkins(self): + """ + Check that as many checkin_partners are created as there + adults on the reservation + + Reservation has three adults + """ # ACTION - self.arrange_single_checkin() checkins_count = len(self.reservation_1.checkin_partner_ids) # ASSERT self.assertEqual( @@ -52,17 +101,24 @@ class TestPmsCheckinPartner(common.SavepointCase): "the automatic partner checkin was not created successful", ) + @freeze_time("2012-01-14") def test_auto_unlink_checkins(self): - - # ARRANGE - self.arrange_single_checkin() - # ACTION host2 = self.env["res.partner"].create( { "name": "Carlos", "phone": "654667733", "email": "carlos@example.com", + "birthdate_date": "1995-12-10", + "gender": "male", + } + ) + self.env["res.partner.id_number"].create( + { + "category_id": self.id_category.id, + "name": "30065089H", + "valid_from": datetime.date.today(), + "partner_id": host2.id, } ) self.reservation_1.checkin_partner_ids = [ @@ -85,19 +141,23 @@ class TestPmsCheckinPartner(common.SavepointCase): ) def test_onboard_checkin(self): - - # ARRANGE - self.arrange_single_checkin() + """ + Check that the reservation cannot be onboard because + checkin_partner data are incomplete and not have onboard status + """ # ACT & ASSERT - with self.assertRaises(ValidationError), self.cr.savepoint(): + with self.assertRaises( + ValidationError, msg="Reservation state cannot be 'onboard'" + ): self.reservation_1.state = "onboard" + @freeze_time("2012-01-14") def test_onboard_reservation(self): - - # ARRANGE - self.arrange_single_checkin() - + """ + Check that reservation state is onboard as the checkin day is + today and checkin_partners data are complete + """ # ACT self.checkin1.action_on_board() @@ -108,24 +168,38 @@ class TestPmsCheckinPartner(common.SavepointCase): "the reservation checkin was not successful", ) - def test_premature_checkin(self): + @freeze_time("2012-01-14") + def test_late_checkin(self): + """ + Check that cannot change checkin_partner state to onboard if + it's not yet checkin day + """ + # ARRANGE - self.arrange_single_checkin() self.reservation_1.write( { - "checkin": "2012-01-15", + "checkin": datetime.date.today() + datetime.timedelta(days=1), } ) # ACT & ASSERT - with self.assertRaises(ValidationError), self.cr.savepoint(): + with self.assertRaises(ValidationError, msg="Cannot do checkin onboard"): self.checkin1.action_on_board() - def test_late_checkin(self): + @freeze_time("2012-01-13") + def test_premature_checkin(self): + """ + When host arrives late anad has already passed the checkin day, + the arrival date is updated up to that time. + + In this case checkin day was 2012-01-14 and the host arrived a day later + so the arrival date is updated to that time + + """ + # ARRANGE - self.arrange_single_checkin() self.reservation_1.write( { - "checkin": "2012-01-13", + "checkin": datetime.date.today(), } ) @@ -139,14 +213,29 @@ class TestPmsCheckinPartner(common.SavepointCase): "the late checkin has problems", ) + @freeze_time("2012-01-14") def test_too_many_people_checkin(self): + """ + Reservation cannot have more checkin_partners than adults who have + Reservation has three adults and cannot have four checkin_partner + """ + # ARRANGE - self.arrange_single_checkin() host2 = self.env["res.partner"].create( { "name": "Carlos", "phone": "654667733", "email": "carlos@example.com", + "birthdate_date": "1995-12-10", + "gender": "male", + } + ) + self.env["res.partner.id_number"].create( + { + "category_id": self.id_category.id, + "name": "30065089H", + "valid_from": datetime.date.today(), + "partner_id": host2.id, } ) host3 = self.env["res.partner"].create( @@ -154,6 +243,16 @@ class TestPmsCheckinPartner(common.SavepointCase): "name": "Enmanuel", "phone": "654667733", "email": "enmanuel@example.com", + "birthdate_date": "1995-12-10", + "gender": "male", + } + ) + self.env["res.partner.id_number"].create( + { + "category_id": self.id_category.id, + "name": "30065089H", + "valid_from": datetime.date.today(), + "partner_id": host3.id, } ) host4 = self.env["res.partner"].create( @@ -161,6 +260,16 @@ class TestPmsCheckinPartner(common.SavepointCase): "name": "Enrique", "phone": "654667733", "email": "enrique@example.com", + "birthdate_date": "1995-12-10", + "gender": "male", + } + ) + self.env["res.partner.id_number"].create( + { + "category_id": self.id_category.id, + "name": "30065089H", + "valid_from": datetime.date.today(), + "partner_id": host4.id, } ) self.env["pms.checkin.partner"].create( @@ -176,7 +285,10 @@ class TestPmsCheckinPartner(common.SavepointCase): } ) # ACT & ASSERT - with self.assertRaises(ValidationError), self.cr.savepoint(): + with self.assertRaises( + ValidationError, + msg="Reservation cannot have more checkin_partner than adults who have", + ): self.reservation_1.write( { "checkin_partner_ids": [ @@ -191,89 +303,49 @@ class TestPmsCheckinPartner(common.SavepointCase): } ) - @classmethod - def arrange_folio_reservations(cls): - # Arrange on one folio with 3 reservations - demo_user = cls.env.ref("base.user_demo") - cls.host1 = cls.env["res.partner"].create( - { - "name": "Miguel", - "phone": "654667733", - "email": "miguel@example.com", - } - ) - cls.host2 = cls.env["res.partner"].create( + @freeze_time("2012-01-14") + def test_count_pending_arrival_persons(self): + """ + After making onboard of two of the three checkin_partners, + one must remain pending arrival, that is a ratio of two thirds + """ + + # ARRANGE + self.host2 = self.env["res.partner"].create( { "name": "Carlos", "phone": "654667733", "email": "carlos@example.com", + "birthdate_date": "1995-12-10", + "gender": "male", } ) - cls.host3 = cls.env["res.partner"].create( + self.env["res.partner.id_number"].create( + { + "category_id": self.id_category.id, + "name": "30065089H", + "valid_from": datetime.date.today(), + "partner_id": self.host2.id, + } + ) + self.host3 = self.env["res.partner"].create( { "name": "Enmanuel", "phone": "654667733", "email": "enmanuel@example.com", + "birthdate_date": "1995-12-10", + "gender": "male", } ) - cls.host4 = cls.env["res.partner"].create( + self.env["res.partner.id_number"].create( { - "name": "Enrique", - "phone": "654667733", - "email": "enrique@example.com", + "category_id": self.id_category.id, + "name": "30065089H", + "valid_from": datetime.date.today(), + "partner_id": self.host3.id, } ) - folio_vals = { - "partner_id": cls.host1.id, - } - cls.folio_1 = cls.env["pms.folio"].with_user(demo_user).create(folio_vals) - reservation1_vals = { - "checkin": "2012-01-14", - "checkout": "2012-01-17", - "room_type_id": cls.env.ref("pms.pms_room_type_3").id, - "partner_id": cls.host1.id, - "adults": 3, - "pms_property_id": cls.env.ref("pms.main_pms_property").id, - "folio_id": cls.folio_1.id, - } - reservation2_vals = { - "checkin": "2012-01-14", - "checkout": "2012-01-17", - "room_type_id": cls.env.ref("pms.pms_room_type_2").id, - "partner_id": cls.host1.id, - "adults": 2, - "pms_property_id": cls.env.ref("pms.main_pms_property").id, - "folio_id": cls.folio_1.id, - } - reservation3_vals = { - "checkin": "2012-01-14", - "checkout": "2012-01-17", - "room_type_id": cls.env.ref("pms.pms_room_type_2").id, - "partner_id": cls.host1.id, - "adults": 2, - "pms_property_id": cls.env.ref("pms.main_pms_property").id, - "folio_id": cls.folio_1.id, - } - cls.reservation_1 = ( - cls.env["pms.reservation"].with_user(demo_user).create(reservation1_vals) - ) - cls.reservation_2 = ( - cls.env["pms.reservation"].with_user(demo_user).create(reservation2_vals) - ) - cls.reservation_3 = ( - cls.env["pms.reservation"].with_user(demo_user).create(reservation3_vals) - ) - def test_count_pending_arrival_persons(self): - - # ARRANGE - self.arrange_folio_reservations() - self.checkin1 = self.env["pms.checkin.partner"].create( - { - "partner_id": self.host1.id, - "reservation_id": self.reservation_1.id, - } - ) self.checkin2 = self.env["pms.checkin.partner"].create( { "partner_id": self.host2.id, @@ -304,17 +376,35 @@ class TestPmsCheckinPartner(common.SavepointCase): ) def test_complete_checkin_data(self): + """ + Reservation for three adults in a first place has three checkin_partners + pending data. Check that there decrease once their data are entered. + + Reservation has three adults, after entering data of two of them, + check that only one remains to be checked and the ratio of data entered + from checkin_partners is two thirds + """ # ARRANGE - self.arrange_folio_reservations() - - # ACT - self.checkin1 = self.env["pms.checkin.partner"].create( + self.host2 = self.env["res.partner"].create( { - "partner_id": self.host1.id, - "reservation_id": self.reservation_1.id, + "name": "Carlos", + "phone": "654667733", + "email": "carlos@example.com", + "birthdate_date": "1995-12-10", + "gender": "male", } ) + self.env["res.partner.id_number"].create( + { + "category_id": self.id_category.id, + "name": "30065089H", + "valid_from": datetime.date.today(), + "partner_id": self.host2.id, + } + ) + # ACT + self.checkin2 = self.env["pms.checkin.partner"].create( { "partner_id": self.host2.id, @@ -335,18 +425,107 @@ class TestPmsCheckinPartner(common.SavepointCase): "Fail the checkins data ratio on reservation", ) + @freeze_time("2012-01-14") def test_auto_arrival_delayed(self): + """ + The state of reservation 'arrival_delayed' happen when the checkin day + has already passed and the resrvation had not yet changed its state to onboard. + + The date that was previously set was 2012-01-14, + it was advanced one day (to 2012-01-15). + There are three reservations with checkin day on 2012-01-14, + after invoking the method auto_arrival_delayed + those reservation change their state to 'auto_arrival_delayed' + """ # ARRANGE - self.arrange_folio_reservations() + self.host2 = self.env["res.partner"].create( + { + "name": "Carlos", + "phone": "654667733", + "email": "carlos@example.com", + "birthdate_date": "1995-12-10", + "gender": "male", + } + ) + self.env["res.partner.id_number"].create( + { + "category_id": self.id_category.id, + "name": "30065089H", + "valid_from": datetime.date.today(), + "partner_id": self.host2.id, + } + ) + self.host3 = self.env["res.partner"].create( + { + "name": "Enmanuel", + "phone": "654667733", + "email": "enmanuel@example.com", + "birthdate_date": "1995-12-10", + "gender": "male", + } + ) + self.env["res.partner.id_number"].create( + { + "category_id": self.id_category.id, + "name": "30065089H", + "valid_from": datetime.date.today(), + "partner_id": self.host3.id, + } + ) + self.host4 = self.env["res.partner"].create( + { + "name": "Enrique", + "phone": "654667733", + "email": "enrique@example.com", + "birthdate_date": "1995-12-10", + "gender": "male", + } + ) + self.env["res.partner.id_number"].create( + { + "category_id": self.id_category.id, + "name": "30065089H", + "valid_from": datetime.date.today(), + "partner_id": self.host4.id, + } + ) + self.reservation_1.write( + { + "checkin": datetime.date.today() + datetime.timedelta(days=4), + "checkout": datetime.date.today() + datetime.timedelta(days=6), + "adults": 1, + } + ) + reservation2_vals = { + "checkin": datetime.date.today() + datetime.timedelta(days=4), + "checkout": datetime.date.today() + datetime.timedelta(days=6), + "adults": 1, + "room_type_id": self.room_type1.id, + "partner_id": self.host1.id, + "pms_property_id": self.pms_property1.id, + "folio_id": self.reservation_1.folio_id.id, + } + reservation3_vals = { + "checkin": datetime.date.today() + datetime.timedelta(days=4), + "checkout": datetime.date.today() + datetime.timedelta(days=6), + "adults": 1, + "room_type_id": self.room_type1.id, + "partner_id": self.host1.id, + "pms_property_id": self.pms_property1.id, + "folio_id": self.reservation_1.folio_id.id, + } + self.reservation_2 = self.env["pms.reservation"].create(reservation2_vals) + self.reservation_3 = self.env["pms.reservation"].create(reservation3_vals) + folio_1 = self.reservation_1.folio_id PmsReservation = self.env["pms.reservation"] # ACTION - freezer = freeze_time("2012-01-15 10:00:00") + freezer = freeze_time("2012-01-19 10:00:00") freezer.start() PmsReservation.auto_arrival_delayed() - arrival_delayed_reservations = self.folio_1.reservation_ids.filtered( + arrival_delayed_reservations = folio_1.reservation_ids.filtered( lambda r: r.state == "arrival_delayed" ) @@ -358,10 +537,28 @@ class TestPmsCheckinPartner(common.SavepointCase): ) freezer.stop() + @freeze_time("2012-01-14") def test_auto_departure_delayed(self): + """ + When it's checkout dat and the reservation + was in 'onboard' state, that state change to + 'departure_delayed' if the manual checkout wasn't performed. + + The date that was previously set was 2012-01-14, + it was advanced two days (to 2012-01-17). + Reservation1 has checkout day on 2012-01-17, + after invoking the method auto_departure_delayed + this reservation change their state to 'auto_departure_delayed' + """ # ARRANGE - self.arrange_single_checkin() + self.reservation_1.write( + { + "checkin": datetime.date.today(), + "checkout": datetime.date.today() + datetime.timedelta(days=3), + "adults": 1, + } + ) PmsReservation = self.env["pms.reservation"] self.checkin1.action_on_board() @@ -378,19 +575,20 @@ class TestPmsCheckinPartner(common.SavepointCase): "Reservations not set like Departure delayed", ) + @freeze_time("2010-12-10") def test_not_valid_emails(self): # TEST CASES - # emails that should be detected as incorrect + # Check that the email format is incorrect # ARRANGE reservation = self.env["pms.reservation"].create( { - "checkin": "2012-01-14", - "checkout": "2012-01-17", - "room_type_id": self.env.ref("pms.pms_room_type_3").id, + "checkin": datetime.date.today(), + "checkout": datetime.date.today() + datetime.timedelta(days=3), + "room_type_id": self.room_type1.id, "partner_id": self.env.ref("base.res_partner_12").id, "adults": 3, - "pms_property_id": self.env.ref("pms.main_pms_property").id, + "pms_property_id": self.pms_property1.id, } ) test_cases = [ @@ -404,7 +602,9 @@ class TestPmsCheckinPartner(common.SavepointCase): ] for mail in test_cases: with self.subTest(i=mail): - with self.assertRaises(ValidationError): + with self.assertRaises( + ValidationError, msg="Email format is correct and shouldn't" + ): reservation.write( { "checkin_partner_ids": [ @@ -420,19 +620,20 @@ class TestPmsCheckinPartner(common.SavepointCase): } ) + @freeze_time("2014-12-10") def test_valid_emails(self): # TEST CASES - # emails that should be detected as correct + # Check that the email format is correct # ARRANGE reservation = self.env["pms.reservation"].create( { - "checkin": "2012-01-14", - "checkout": "2012-01-17", - "room_type_id": self.env.ref("pms.pms_room_type_3").id, + "checkin": datetime.date.today(), + "checkout": datetime.date.today() + datetime.timedelta(days=4), + "room_type_id": self.room_type1.id, "partner_id": self.env.ref("base.res_partner_12").id, "adults": 3, - "pms_property_id": self.env.ref("pms.main_pms_property").id, + "pms_property_id": self.pms_property1.id, } ) test_cases = [ @@ -457,19 +658,20 @@ class TestPmsCheckinPartner(common.SavepointCase): ) guest.unlink() + @freeze_time("2016-12-10") def test_not_valid_phone(self): # TEST CASES - # phones that should be detected as incorrect + # Check that the phone format is incorrect # ARRANGE reservation = self.env["pms.reservation"].create( { - "checkin": "2012-01-14", - "checkout": "2012-01-17", - "room_type_id": self.env.ref("pms.pms_room_type_3").id, + "checkin": datetime.date.today(), + "checkout": datetime.date.today() + datetime.timedelta(days=1), + "room_type_id": self.room_type1.id, "partner_id": self.env.ref("base.res_partner_12").id, "adults": 3, - "pms_property_id": self.env.ref("pms.main_pms_property").id, + "pms_property_id": self.pms_property1.id, } ) test_cases = [ @@ -481,7 +683,9 @@ class TestPmsCheckinPartner(common.SavepointCase): ] for phone in test_cases: with self.subTest(i=phone): - with self.assertRaises(ValidationError): + with self.assertRaises( + ValidationError, msg="Phone format is correct and shouldn't" + ): self.env["pms.checkin.partner"].create( { "name": "Carlos", @@ -490,19 +694,20 @@ class TestPmsCheckinPartner(common.SavepointCase): } ) + @freeze_time("2018-12-10") def test_valid_phones(self): # TEST CASES - # emails that should be detected as incorrect + # Check that the phone format is correct # ARRANGE reservation = self.env["pms.reservation"].create( { - "checkin": "2012-01-14", - "checkout": "2012-01-17", - "room_type_id": self.env.ref("pms.pms_room_type_3").id, + "checkin": datetime.date.today(), + "checkout": datetime.date.today() + datetime.timedelta(days=5), + "room_type_id": self.room_type1.id, "partner_id": self.env.ref("base.res_partner_12").id, "adults": 3, - "pms_property_id": self.env.ref("pms.main_pms_property").id, + "pms_property_id": self.pms_property1.id, } ) test_cases = [ @@ -523,3 +728,194 @@ class TestPmsCheckinPartner(common.SavepointCase): mobile, guest.mobile, ) + + def test_complete_checkin_data_with_partner_data(self): + """ + When a partner is asociated with a checkin, checkin data + will be equal to the partner data + + Host1: + "email": "miguel@example.com", + "birthdate_date": "1995-12-10", + "gender": "male", + + Checkin1: + "partner_id": host1.id + + So after this: + Checkin1: + "email": "miguel@example.com", + "birthdate_date": "1995-12-10", + "gender": "male", + """ + # ARRANGE + partner_data = [self.host1.birthdate_date, self.host1.email, self.host1.gender] + checkin_data = [ + self.checkin1.birthdate_date, + self.checkin1.email, + self.checkin1.gender, + ] + + # ASSERT + for i in [0, 1, 2]: + self.assertEqual( + partner_data[i], + checkin_data[i], + "Checkin data must be the same as partner data ", + ) + + def test_create_partner_when_checkin_has_enought_data(self): + """ + Check that partner is created when the necessary minimum data is entered + into checkin_partner data + """ + # ACT & ASSERT + checkin = self.env["pms.checkin.partner"].create( + { + "firstname": "Pepe", + "lastname": "Paz", + "document_type": self.id_category.id, + "document_number": "77156490T", + "reservation_id": self.reservation_1.id, + } + ) + + # ASSERT + self.assertTrue( + checkin.partner_id, + "Partner should have been created and associated with the checkin", + ) + + def test_not_create_partner_checkin_hasnt_enought_data(self): + """ + Check that partner is not created when the necessary minimum data isn't entered + into checkin_partner data, in this case document_id and document_number + """ + # ACT & ASSERT + checkin = self.env["pms.checkin.partner"].create( + { + "firstname": "Pepe", + "lastname": "Paz", + "email": "pepepaz@gmail.com", + "mobile": "666777777", + "reservation_id": self.reservation_1.id, + } + ) + + # ASSERT + self.assertFalse( + checkin.partner_id, + "Partner mustn't have been created and associated with the checkin", + ) + + def test_add_partner_data_from_checkin(self): + """ + If the checkin_partner has some data that the partner doesn't have, + these are saved in the partner + + In this case, host1 hasn't mobile but the checkin_partner associated with it does, + so the mobile of checkin_partner is added to the partner data + + Note that if the mobile is entered before partnee was associated, this or other fields + are overwritten by the partner's fields. In this case it is entered once the partner has + already been associated + """ + # ARRANGE + self.checkin1.mobile = "666777888" + # ASSERT + self.assertTrue(self.host1.mobile, "Partner mobile must be added") + + def _test_partner_id_numbers_created_from_checkin(self): + """ + Some of the required data of the checkin_partner to create the partner are document_type + and document_number, with them an id_number is created associated with the partner that + has just been created. + In this test it is verified that this document has been created correctly + """ + # ACT & ARRANGE + checkin = self.env["pms.checkin.partner"].create( + { + "firstname": "Pepe", + "lastname": "Paz", + "document_type": self.id_category.id, + "document_number": "77156490T", + "reservation_id": self.reservation_1.id, + } + ) + + # ASSERT + self.assertTrue( + checkin.partner_id.id_numbers, + "Partner id_number should have been created and hasn't been", + ) + + def test_partner_not_modified_when_checkin_modified(self): + """ + If a partner is associated with a checkin + and some of their data is modified in the checkin, + they will not be modified in the partner + """ + # ARRANGE + self.checkin1.email = "prueba@gmail.com" + + # ASSERT + self.assertNotEqual( + self.host1.email, + self.checkin1.email, + "Checkin partner email and partner email shouldn't match", + ) + + def _test_partner_modified_previous_checkin_not_modified(self): + """ + If a partner modifies any of its fields, these change mustn't be reflected + in the previous checkins associated with it + """ + # ARRANGE + self.host1.gender = "female" + # ASSERT + self.assertNotEqual( + self.host1.gender, + self.checkin1.gender, + "Checkin partner gender and partner gender shouldn't match", + ) + + def test_add_partner_if_exists_from_checkin(self): + """ + Check when a document_type and document_number are entered in a checkin if this + document already existes and is associated with a partner, this partner will be + associated with the checkin + """ + # ACT + host = self.env["res.partner"].create( + { + "name": "Ricardo", + "phone": "666555666", + "email": "ricardo@example.com", + "birthdate_date": "1995-11-14", + "gender": "male", + } + ) + + self.env["res.partner.id_number"].create( + { + "category_id": self.id_category.id, + "name": "55562998N", + "partner_id": host.id, + } + ) + + # ARRANGE + checkin = self.env["pms.checkin.partner"].create( + { + "document_type": self.id_category.id, + "document_number": "55562998N", + "reservation_id": self.reservation_1.id, + } + ) + + # ASSERT + self.assertEqual( + checkin.partner_id.id, + host.id, + "Checkin partner_id must be the same as the one who has that document", + ) diff --git a/pms/tests/test_pms_res_users.py b/pms/tests/test_pms_res_users.py index 350b38869..bf0514909 100644 --- a/pms/tests/test_pms_res_users.py +++ b/pms/tests/test_pms_res_users.py @@ -1,14 +1,11 @@ from odoo.exceptions import ValidationError -from odoo.tests import common + +from .common import TestPms -class TestPmsResUser(common.SavepointCase): - def create_common_scenario(self): - # create a room type availability - self.room_type_availability = self.env["pms.availability.plan"].create( - {"name": "Availability plan 1"} - ) - +class TestPmsResUser(TestPms): + def setUp(self): + super().setUp() # create a company and properties self.company_A = self.env["res.company"].create( { @@ -20,104 +17,50 @@ class TestPmsResUser(common.SavepointCase): "name": "Pms_Company2", } ) - self.folio_sequenceA = self.env["ir.sequence"].create( - { - "name": "PMS Folio", - "code": "pms.folio", - "padding": 4, - "company_id": self.company_A.id, - } - ) - self.reservation_sequenceA = self.env["ir.sequence"].create( - { - "name": "PMS Reservation", - "code": "pms.reservation", - "padding": 4, - "company_id": self.company_A.id, - } - ) - self.checkin_sequenceA = self.env["ir.sequence"].create( - { - "name": "PMS Checkin", - "code": "pms.checkin.partner", - "padding": 4, - "company_id": self.company_A.id, - } - ) - self.folio_sequenceB = self.env["ir.sequence"].create( - { - "name": "PMS Folio", - "code": "pms.folio", - "padding": 4, - "company_id": self.company_B.id, - } - ) - self.reservation_sequenceB = self.env["ir.sequence"].create( - { - "name": "PMS Reservation", - "code": "pms.reservation", - "padding": 4, - "company_id": self.company_B.id, - } - ) - self.checkin_sequenceB = self.env["ir.sequence"].create( - { - "name": "PMS Checkin", - "code": "pms.checkin.partner", - "padding": 4, - "company_id": self.company_B.id, - } - ) self.property_A1 = self.env["pms.property"].create( { "name": "Pms_property", "company_id": self.company_A.id, - "default_pricelist_id": self.env.ref("product.list0").id, - "folio_sequence_id": self.folio_sequenceA.id, - "reservation_sequence_id": self.reservation_sequenceA.id, - "checkin_sequence_id": self.checkin_sequenceA.id, + "default_pricelist_id": self.pricelist1.id, } ) self.property_A2 = self.env["pms.property"].create( { "name": "Pms_property2", "company_id": self.company_A.id, - "default_pricelist_id": self.env.ref("product.list0").id, - "folio_sequence_id": self.folio_sequenceA.id, - "reservation_sequence_id": self.reservation_sequenceA.id, - "checkin_sequence_id": self.checkin_sequenceA.id, + "default_pricelist_id": self.pricelist1.id, } ) self.property_B1 = self.env["pms.property"].create( { "name": "Pms_propertyB1", "company_id": self.company_B.id, - "default_pricelist_id": self.env.ref("product.list0").id, - "folio_sequence_id": self.folio_sequenceB.id, - "reservation_sequence_id": self.reservation_sequenceB.id, - "checkin_sequence_id": self.checkin_sequenceB.id, + "default_pricelist_id": self.pricelist1.id, } ) - def test_property_not_allowed(self): + def test_property_not_in_allowed_properties(self): """ - Property not allowed, it belongs to another company + Property not allowed for the user + Check a user cannot have an active property + that is not in the allowed properties Company_A ---> Property_A1, Property_A2 Company_B ---> Property_B1 + """ # ARRANGE - name = "test user" - login = "test_user" - self.create_common_scenario() Users = self.env["res.users"] # ACT & ASSERT - with self.assertRaises(ValidationError), self.cr.savepoint(): + with self.assertRaises( + ValidationError, + msg="Some property is not included in the allowed properties", + ): Users.create( { - "name": name, - "login": login, + "name": "Test User", + "login": "test_user", "company_ids": [(4, self.company_A.id)], "company_id": self.company_A.id, "pms_property_ids": [(4, self.property_A1.id)], @@ -125,18 +68,26 @@ class TestPmsResUser(common.SavepointCase): } ) - def test_check_allowed_property_ids(self): + def test_property_not_in_allowed_companies(self): + """ + Property not allowed for the user + Check a user cannot have a property in allowed properties + that does not belong to their companies + + Company_A ---> Property_A1, Property_A2 + Company_B ---> Property_B1 + + """ # ARRANGE - name = "test user2" - login = "test_user2" - self.create_common_scenario() Users = self.env["res.users"] # ACT & ASSERT - with self.assertRaises(ValidationError), self.cr.savepoint(): + with self.assertRaises( + ValidationError, msg="Some property doesn't belong to the allowed companies" + ): Users.create( { - "name": name, - "login": login, + "name": "Test User", + "login": "test_user", "company_ids": [(4, self.company_A.id)], "company_id": self.company_A.id, "pms_property_ids": [ @@ -146,3 +97,68 @@ class TestPmsResUser(common.SavepointCase): "pms_property_id": self.property_A1.id, } ) + + def test_property_in_allowed_properties(self): + """ + Successful user creation + Check user creation with active property in allowed properties + + Company_A ---> Property_A1, Property_A2 + Company_B ---> Property_B1 + + """ + # ARRANGE + Users = self.env["res.users"] + # ACT + user1 = Users.create( + { + "name": "Test User", + "login": "test_user", + "company_ids": [(4, self.company_A.id)], + "company_id": self.company_A.id, + "pms_property_ids": [ + (4, self.property_A1.id), + (4, self.property_A2.id), + ], + "pms_property_id": self.property_A1.id, + } + ) + # ASSERT + self.assertIn( + user1.pms_property_id, + user1.pms_property_ids, + "Active property not in allowed properties", + ) + + def test_properties_belong_to_companies(self): + """ + Successful user creation + Check user creation with active property and allowed properties + belonging to the allowed companies + + Company_A ---> Property_A1, Property_A2 + Company_B ---> Property_B1 + + """ + # ARRANGE + Users = self.env["res.users"] + # ACT + user1 = Users.create( + { + "name": "Test User", + "login": "test_user", + "company_ids": [(4, self.company_A.id)], + "company_id": self.company_A.id, + "pms_property_ids": [ + (4, self.property_A1.id), + (4, self.property_A2.id), + ], + "pms_property_id": self.property_A1.id, + } + ) + # ASSERT + self.assertEqual( + user1.pms_property_id.company_id, + user1.company_id, + "Active property doesn't belong to active company", + ) diff --git a/pms/tests/test_pms_reservation.py b/pms/tests/test_pms_reservation.py index 7949b2c2e..4aa2fb72c 100644 --- a/pms/tests/test_pms_reservation.py +++ b/pms/tests/test_pms_reservation.py @@ -104,6 +104,9 @@ class TestPmsReservations(common.SavepointCase): } ) self.demo_user = self.env.ref("base.user_admin") + self.id_category = self.env["res.partner.id_category"].create( + {"name": "DNI", "code": "D"} + ) def create_multiproperty_scenario(self): self.create_common_scenario() @@ -831,6 +834,16 @@ class TestPmsReservations(common.SavepointCase): "name": "Miguel", "phone": "654667733", "email": "miguel@example.com", + "birthdate_date": "1995-12-10", + "gender": "male", + } + ) + self.env["res.partner.id_number"].create( + { + "category_id": self.id_category.id, + "name": "30065089H", + "valid_from": datetime.date.today(), + "partner_id": host.id, } ) r1 = self.env["pms.reservation"].create( @@ -1004,6 +1017,16 @@ class TestPmsReservations(common.SavepointCase): "name": "Miguel", "phone": "654667733", "email": "miguel@example.com", + "birthdate_date": "1995-12-10", + "gender": "male", + } + ) + self.env["res.partner.id_number"].create( + { + "category_id": self.id_category.id, + "name": "30065089H", + "valid_from": datetime.date.today(), + "partner_id": host.id, } ) r1 = self.env["pms.reservation"].create( @@ -1271,6 +1294,16 @@ class TestPmsReservations(common.SavepointCase): "name": "Miguel", "phone": "654667733", "email": "miguel@example.com", + "birthdate_date": "1995-12-10", + "gender": "male", + } + ) + self.env["res.partner.id_number"].create( + { + "category_id": self.id_category.id, + "name": "30065000H", + "valid_from": datetime.date.today(), + "partner_id": self.host1.id, } ) self.host2 = self.env["res.partner"].create( @@ -1278,6 +1311,16 @@ class TestPmsReservations(common.SavepointCase): "name": "Brais", "phone": "654437733", "email": "brais@example.com", + "birthdate_date": "1995-12-10", + "gender": "male", + } + ) + self.env["res.partner.id_number"].create( + { + "category_id": self.id_category.id, + "name": "30065089H", + "valid_from": datetime.date.today(), + "partner_id": self.host2.id, } ) self.reservation = self.env["pms.reservation"].create( diff --git a/pms/views/pms_checkin_partner_views.xml b/pms/views/pms_checkin_partner_views.xml index 0ae652ec4..cff2ef768 100644 --- a/pms/views/pms_checkin_partner_views.xml +++ b/pms/views/pms_checkin_partner_views.xml @@ -25,14 +25,32 @@ +
+ +
- + + + + + + + + + + + + @@ -44,6 +62,14 @@ +