diff --git a/pms/demo/pms_master_data.xml b/pms/demo/pms_master_data.xml
index f838f6dfe..a19bd690e 100644
--- a/pms/demo/pms_master_data.xml
+++ b/pms/demo/pms_master_data.xml
@@ -92,9 +92,11 @@
Room
+ RO
Conference
+ CO
diff --git a/pms/models/pms_room_type_class.py b/pms/models/pms_room_type_class.py
index ba448c839..f78e9a1ad 100644
--- a/pms/models/pms_room_type_class.py
+++ b/pms/models/pms_room_type_class.py
@@ -1,7 +1,9 @@
# Copyright 2017 Alexandre Díaz
# Copyright 2017 Dario Lodeiros
+# Copyright 2021 Eric Antones
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-from odoo import fields, models
+from odoo import _, api, fields, models
+from odoo.exceptions import ValidationError
class PmsRoomTypeClass(models.Model):
@@ -22,10 +24,69 @@ class PmsRoomTypeClass(models.Model):
"pms.property", string="Properties", required=False, ondelete="restrict"
)
room_type_ids = fields.One2many("pms.room.type", "class_id", "Types")
- code_class = fields.Char("Code")
+ code_class = fields.Char("Code", required=True)
active = fields.Boolean("Active", default=True)
sequence = fields.Integer("Sequence", default=0)
- _sql_constraints = [
- ("code_class_unique", "unique(code_class)", "Room Class Code must be unique!")
- ]
+ @api.model
+ def get_unique_by_property_code(self, pms_property_id, code_class=None):
+ """
+ :param pms_property_id: property ID
+ :param code_class: room type code (optional)
+ :return: - recordset of
+ - all the pms.room.type.class of the pms_property_id
+ if code_class not defined
+ - one or 0 pms.room.type.class if code_class defined
+ - ValidationError if more than one code_class found by
+ the same pms_property_id
+ """
+ # TODO: similiar code as room.type -> unify
+ domain = []
+ if code_class:
+ domain += ["&", ("code_class", "=", code_class)]
+ domain += [
+ "|",
+ ("pms_property_ids", "in", pms_property_id),
+ ("pms_property_ids", "=", False),
+ ]
+ records = self.search(domain)
+ res, res_priority = {}, {}
+ for rec in records:
+ res_priority.setdefault(rec.code_class, -1)
+ priority = rec.pms_property_ids and 1 or 0
+ if priority > res_priority[rec.code_class]:
+ res.setdefault(rec.code_class, rec.id)
+ res[rec.code_class], res_priority[rec.code_class] = rec.id, priority
+ elif priority == res_priority[rec.code_class]:
+ raise ValidationError(
+ _(
+ "Integrity error: There's multiple room types "
+ "with the same code %s and properties"
+ )
+ % rec.code_class
+ )
+ return self.browse(list(res.values()))
+
+ @api.constrains("code_class", "pms_property_ids")
+ def _check_code_property_uniqueness(self):
+ # TODO: similiar code as room.type -> unify
+ msg = _(
+ "Already exists another room type class with the same code and properties"
+ )
+ for rec in self:
+ if not rec.pms_property_ids:
+ if self.search(
+ [
+ ("id", "!=", rec.id),
+ ("code_class", "=", rec.code_class),
+ ("pms_property_ids", "=", False),
+ ]
+ ):
+ raise ValidationError(msg)
+ else:
+ for pms_property in rec.pms_property_ids:
+ other = rec.get_unique_by_property_code(
+ pms_property.id, rec.code_class
+ )
+ if other and other != rec:
+ raise ValidationError(msg)
diff --git a/pms/tests/__init__.py b/pms/tests/__init__.py
index 2b46906e6..ae06865ac 100644
--- a/pms/tests/__init__.py
+++ b/pms/tests/__init__.py
@@ -27,6 +27,7 @@ from . import test_pms_sale_channel
from . import test_pms_folio
from . import test_pms_room_type_availability_rules
from . import test_pms_room_type
+from . import test_pms_room_type_class
from . import test_pms_wizard_massive_changes
from . import test_pms_wizard_folio
from . import test_pms_res_users
diff --git a/pms/tests/test_pms_folio.py b/pms/tests/test_pms_folio.py
index 079fe2ebc..c4e2c0cca 100644
--- a/pms/tests/test_pms_folio.py
+++ b/pms/tests/test_pms_folio.py
@@ -26,7 +26,9 @@ class TestPmsFolio(TestHotel):
)
# create room type class
- self.room_type_class = self.env["pms.room.type.class"].create({"name": "Room"})
+ self.room_type_class = self.env["pms.room.type.class"].create(
+ {"name": "Room", "code_class": "ROOM"}
+ )
# create room type
self.room_type_double = self.env["pms.room.type"].create(
diff --git a/pms/tests/test_pms_pricelist.py b/pms/tests/test_pms_pricelist.py
index 3e42862f5..7f201405e 100644
--- a/pms/tests/test_pms_pricelist.py
+++ b/pms/tests/test_pms_pricelist.py
@@ -31,7 +31,7 @@ class TestPmsPricelist(common.TransactionCase):
}
)
self.room_type_class = self.env["pms.room.type.class"].create(
- {"name": "Room Class"}
+ {"name": "Room Class", "code_class": "ROOM"}
)
self.room_type = self.env["pms.room.type"].create(
diff --git a/pms/tests/test_pms_pricelist_priority.py b/pms/tests/test_pms_pricelist_priority.py
index 635f3a67c..fc07803bc 100644
--- a/pms/tests/test_pms_pricelist_priority.py
+++ b/pms/tests/test_pms_pricelist_priority.py
@@ -38,7 +38,7 @@ class TestPmsPricelistRules(common.TransactionCase):
)
self.room_type_class = self.env["pms.room.type.class"].create(
- {"name": "Room Class"}
+ {"name": "Room Class", "code_class": "ROOM"}
)
self.room_type = self.env["pms.room.type"].create(
diff --git a/pms/tests/test_pms_reservation.py b/pms/tests/test_pms_reservation.py
index 7e0b671f7..31bb389b9 100644
--- a/pms/tests/test_pms_reservation.py
+++ b/pms/tests/test_pms_reservation.py
@@ -26,7 +26,9 @@ class TestPmsReservations(TestHotel):
)
# create room type class
- self.room_type_class = self.env["pms.room.type.class"].create({"name": "Room"})
+ self.room_type_class = self.env["pms.room.type.class"].create(
+ {"name": "Room", "code_class": "ROOM"}
+ )
# create room type
self.room_type_double = self.env["pms.room.type"].create(
diff --git a/pms/tests/test_pms_room.py b/pms/tests/test_pms_room.py
index 29223a39d..2c3dec771 100644
--- a/pms/tests/test_pms_room.py
+++ b/pms/tests/test_pms_room.py
@@ -28,7 +28,7 @@ class TestPmsRoom(common.TransactionCase):
)
self.room_type_class = self.env["pms.room.type.class"].create(
- {"name": "Room Class"}
+ {"name": "Room Class", "code_class": "ROOM"}
)
self.room_type = self.env["pms.room.type"].create(
diff --git a/pms/tests/test_pms_room_type.py b/pms/tests/test_pms_room_type.py
index 362f43368..f04696a94 100644
--- a/pms/tests/test_pms_room_type.py
+++ b/pms/tests/test_pms_room_type.py
@@ -704,6 +704,7 @@ class TestRoomTypeCodePropertyUniqueness(TestRoomType):
room_type_class = self.env["pms.room.type.class"].create(
{
"name": "Room Type Class",
+ "code_class": "ROOM",
"pms_property_ids": [
(4, self.p2.id),
],
diff --git a/pms/tests/test_pms_room_type_availability_rules.py b/pms/tests/test_pms_room_type_availability_rules.py
index 111ef0dca..60e92a600 100644
--- a/pms/tests/test_pms_room_type_availability_rules.py
+++ b/pms/tests/test_pms_room_type_availability_rules.py
@@ -41,7 +41,7 @@ class TestPmsRoomTypeAvailabilityRules(TestHotel):
)
# pms.room.type.class
self.test_room_type_class = self.env["pms.room.type.class"].create(
- {"name": "Room"}
+ {"name": "Room", "code_class": "ROOM"}
)
# pms.room.type
diff --git a/pms/tests/test_pms_room_type_class.py b/pms/tests/test_pms_room_type_class.py
new file mode 100644
index 000000000..0a54d336a
--- /dev/null
+++ b/pms/tests/test_pms_room_type_class.py
@@ -0,0 +1,386 @@
+# Copyright 2021 Eric Antones
+# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
+
+from odoo.exceptions import ValidationError
+from odoo.tests.common import SavepointCase
+
+
+class TestRoomTypeClass(SavepointCase):
+ def setUp(self):
+ super().setUp()
+ self.p1 = self.browse_ref("pms.main_pms_property")
+ self.m1 = self.p1.company_id
+ self.p2 = self.env["pms.property"].create(
+ {
+ "name": "p2",
+ "company_id": self.m1.id,
+ "default_pricelist_id": self.ref("product.list0"),
+ }
+ )
+ self.m2 = self.env["res.company"].create(
+ {
+ "name": "Company m2",
+ }
+ )
+ self.p3 = self.env["pms.property"].create(
+ {
+ "name": "p3",
+ "company_id": self.m2.id,
+ "default_pricelist_id": self.ref("product.list0"),
+ }
+ )
+
+
+class TestRoomTypeClassCodePropertyIntegrity(TestRoomTypeClass):
+ # external integrity
+ def test_external_case_01(self):
+ """
+ PRE: - room type class cl1 exists
+ - cl1 has code c1
+ - cl1 has property p1
+ - p1 has company m1
+ ACT: - create a new cl2 class
+ - cl2 has code c1
+ - cl2 has property p1
+ - p1 has company m1
+ POST: - Integrity error: the room type already exists
+ - cl2 not created
+ """
+ # ARRANGE
+ # cl1
+ self.env["pms.room.type.class"].create(
+ {
+ "name": "Room type class cl1",
+ "code_class": "c1",
+ "pms_property_ids": [(6, 0, [self.p1.id])],
+ }
+ )
+
+ # ACT & ASSERT
+ with self.assertRaises(
+ ValidationError, msg="The room type class has been created and it shouldn't"
+ ):
+ # cl2
+ self.env["pms.room.type.class"].create(
+ {
+ "name": "Room type class cl2",
+ "code_class": "c1",
+ "pms_property_ids": [(6, 0, [self.p1.id])],
+ }
+ )
+
+ def test_external_case_02(self):
+ """
+ PRE: - room type class cl1 exists
+ - cl1 has code c1
+ - cl1 has property p1
+ - p1 has company m1
+ ACT: - create a new cl2 class
+ - cl2 has code c1
+ - cl2 has property p1, p2, p3
+ - p1, p2 has company m1
+ - p3 has company m2
+ POST: - Integrity error: the room type class already exists
+ - cl2 not created
+ """
+ # ARRANGE
+ # cl1
+ self.env["pms.room.type.class"].create(
+ {
+ "name": "Room type class cl1",
+ "code_class": "c1",
+ "pms_property_ids": [(6, 0, [self.p1.id])],
+ }
+ )
+
+ # ACT & ASSERT
+ with self.assertRaises(
+ ValidationError, msg="The room type class has been created and it shouldn't"
+ ):
+ # cl2
+ self.env["pms.room.type.class"].create(
+ {
+ "name": "Room type class cl2",
+ "code_class": "c1",
+ "pms_property_ids": [(6, 0, [self.p1.id, self.p2.id, self.p3.id])],
+ }
+ )
+
+
+class TestRoomTypeClassCodePropertyUniqueness(TestRoomTypeClass):
+ # test with one room type class
+ def test_single_case_01(self):
+ """
+ PRE: - room type class cl1 exists
+ - cl1 has code c1
+ - cl1 has 2 properties p1 and p2
+ - p1 and p2 have the same company m1
+ ACT: - search room type class with code c1 and property p1
+ - p1 has company m1
+ POST: - only cl1 room type class found
+ """
+ # ARRANGE
+ cl1 = self.env["pms.room.type.class"].create(
+ {
+ "name": "Room type class cl1",
+ "code_class": "c1",
+ "pms_property_ids": [(6, 0, [self.p1.id, self.p3.id])],
+ }
+ )
+
+ # ACT
+ room_type_class = self.env["pms.room.type.class"].get_unique_by_property_code(
+ self.p1.id, "c1"
+ )
+
+ # ASSERT
+ self.assertEqual(
+ room_type_class.id, cl1.id, "Expected room type class not found"
+ )
+
+ def test_single_case_02(self):
+ """
+ PRE: - room type class cl1 exists
+ - cl1 has code c1
+ - cl1 has 2 properties p1 and p3
+ - p1 and p2 have different companies
+ - p1 have company m1 and p3 have company m2
+ ACT: - search room type class with code c1 and property p1
+ - p1 has company m1
+ POST: - only cl1 room type found
+ """
+ # ARRANGE
+ cl1 = self.env["pms.room.type.class"].create(
+ {
+ "name": "Room type class cl1",
+ "code_class": "c1",
+ "pms_property_ids": [(6, 0, [self.p1.id, self.p3.id])],
+ }
+ )
+
+ # ACT
+ room_type_class = self.env["pms.room.type.class"].get_unique_by_property_code(
+ self.p1.id, "c1"
+ )
+
+ # ASSERT
+ self.assertEqual(
+ room_type_class.id, cl1.id, "Expected room type class not found"
+ )
+
+ def test_single_case_03(self):
+ """
+ PRE: - room type class cl1 exists
+ - cl1 has code c1
+ - cl1 with 2 properties p1 and p2
+ - p1 and p2 have same company m1
+ ACT: - search room type class with code c1 and property p3
+ - p3 have company m2
+ POST: - no room type found
+ """
+ # ARRANGE
+ # cl1
+ self.env["pms.room.type.class"].create(
+ {
+ "name": "Room type class cl1",
+ "code_class": "c1",
+ "pms_property_ids": [(6, 0, [self.p1.id, self.p2.id])],
+ }
+ )
+
+ # ACT
+ room_type_class = self.env["pms.room.type.class"].get_unique_by_property_code(
+ self.p3.id, "c1"
+ )
+
+ # ASSERT
+ self.assertFalse(
+ room_type_class, "Room type class found but it should not have found any"
+ )
+
+ def test_single_case_04(self):
+ """
+ PRE: - room type class cl1 exists
+ - cl1 has code c1
+ - cl1 properties are null
+ ACT: - search room type class with code c1 and property p1
+ - p1 have company m1
+ POST: - only cl1 room type class found
+ """
+ # ARRANGE
+ cl1 = self.env["pms.room.type.class"].create(
+ {
+ "name": "Room type class cl1",
+ "code_class": "c1",
+ "pms_property_ids": False,
+ }
+ )
+
+ # ACT
+ room_type_class = self.env["pms.room.type.class"].get_unique_by_property_code(
+ self.p1.id, "c1"
+ )
+
+ # ASSERT
+ self.assertEqual(
+ room_type_class.id, cl1.id, "Expected room type class not found"
+ )
+
+ # tests with more than one room type class
+ def test_multiple_case_01(self):
+ """
+ PRE: - room type class cl1 exists
+ - cl1 has code c1
+ - cl1 has 2 properties p1 and p2
+ - p1 and p2 have the same company m1
+ - room type class cl2 exists
+ - cl2 has code c1
+ - cl2 has no properties
+ ACT: - search room type class with code c1 and property p1
+ - p1 have company m1
+ POST: - only cl1 room type class found
+ """
+ # ARRANGE
+ cl1 = self.env["pms.room.type.class"].create(
+ {
+ "name": "Room type class cl1",
+ "code_class": "c1",
+ "pms_property_ids": [(6, 0, [self.p1.id, self.p3.id])],
+ }
+ )
+ # cl2
+ self.env["pms.room.type.class"].create(
+ {
+ "name": "Room type class cl2",
+ "code_class": "c1",
+ "pms_property_ids": False,
+ }
+ )
+
+ # ACT
+ room_type_class = self.env["pms.room.type.class"].get_unique_by_property_code(
+ self.p1.id, "c1"
+ )
+
+ # ASSERT
+ self.assertEqual(
+ room_type_class.id, cl1.id, "Expected room type class not found"
+ )
+
+ def test_multiple_case_02(self):
+ """
+ PRE: - room type class cl1 exists
+ - cl1 has code c1
+ - cl1 has property p1
+ - p1 have the company m1
+ - room type class cl2 exists
+ - cl2 has code c1
+ - cl2 has no properties
+ ACT: - search room type class with code c1 and property p2
+ - p2 have company m1
+ POST: - only cl1 room type class found
+ """
+ # ARRANGE
+ # cl1
+ self.env["pms.room.type.class"].create(
+ {
+ "name": "Room type class cl1",
+ "code_class": "c1",
+ "pms_property_ids": [(6, 0, [self.p1.id])],
+ }
+ )
+ cl2 = self.env["pms.room.type.class"].create(
+ {
+ "name": "Room type class cl2",
+ "code_class": "c1",
+ "pms_property_ids": False,
+ }
+ )
+
+ # ACT
+ room_type_class = self.env["pms.room.type.class"].get_unique_by_property_code(
+ self.p2.id, "c1"
+ )
+
+ # ASSERT
+ self.assertEqual(
+ room_type_class.id, cl2.id, "Expected room type class not found"
+ )
+
+ def test_multiple_case_03(self):
+ """
+ PRE: - room type class cl1 exists
+ - cl1 has code c1
+ - cl1 has property p1
+ - p1 have the company m1
+ - room type class cl2 exists
+ - cl2 has code c1
+ - cl2 has no properties
+ ACT: - search room type class with code c1 and property p3
+ - p3 have company m2
+ POST: - only cl2 room type class found
+ """
+ # ARRANGE
+ # cl1
+ self.env["pms.room.type.class"].create(
+ {
+ "name": "Room type class cl1",
+ "code_class": "c1",
+ "pms_property_ids": [(6, 0, [self.p1.id])],
+ }
+ )
+ cl2 = self.env["pms.room.type.class"].create(
+ {
+ "name": "Room type class cl2",
+ "code_class": "c1",
+ "pms_property_ids": False,
+ }
+ )
+
+ # ACT
+ room_type_class = self.env["pms.room.type.class"].get_unique_by_property_code(
+ self.p3.id, "c1"
+ )
+
+ # ASSERT
+ self.assertEqual(
+ room_type_class.id, cl2.id, "Expected room type class not found"
+ )
+
+ def test_multiple_case_04(self):
+ """
+ PRE: - room type class cl1 exists
+ - cl1 has code c1
+ - cl1 has property p1
+ - p1 have the company m1
+ - room type cl2 exists
+ - cl2 has code c1
+ - cl2 has no properties
+ ACT: - search room type class with code c1 and property p3
+ - p3 have company m2
+ POST: - r2 room type class found
+ """
+ # ARRANGE
+ # cl1
+ self.env["pms.room.type.class"].create(
+ {
+ "name": "Room type class cl1",
+ "code_class": "c1",
+ "pms_property_ids": [(6, 0, [self.p1.id])],
+ }
+ )
+ cl2 = self.env["pms.room.type.class"].create(
+ {
+ "name": "Room type class cl2",
+ "code_class": "c1",
+ "pms_property_ids": False,
+ }
+ )
+
+ # ACT
+ room_type_class = self.env["pms.room.type.class"].get_unique_by_property_code(
+ self.p3.id, "c1"
+ )
+
+ # ASSERT
+ self.assertEqual(room_type_class.id, cl2.id, "Expected room type not found")
diff --git a/pms/tests/test_pms_wizard_folio.py b/pms/tests/test_pms_wizard_folio.py
index 27d783017..6fb60a273 100644
--- a/pms/tests/test_pms_wizard_folio.py
+++ b/pms/tests/test_pms_wizard_folio.py
@@ -41,7 +41,7 @@ class TestPmsWizardMassiveChanges(TestHotel):
# CREATION OF ROOM TYPE CLASS
self.test_room_type_class = self.env["pms.room.type.class"].create(
- {"name": "Room"}
+ {"name": "Room", "code_class": "ROOM"}
)
self.test_room_type_class.flush()
diff --git a/pms/tests/test_pms_wizard_massive_changes.py b/pms/tests/test_pms_wizard_massive_changes.py
index def56b5ab..bc947b20e 100644
--- a/pms/tests/test_pms_wizard_massive_changes.py
+++ b/pms/tests/test_pms_wizard_massive_changes.py
@@ -34,7 +34,7 @@ class TestPmsWizardMassiveChanges(TestHotel):
)
# pms.room.type.class
self.test_room_type_class = self.env["pms.room.type.class"].create(
- {"name": "Room"}
+ {"name": "Room", "code_class": "ROOM"}
)
# pms.room.type