diff --git a/pms/demo/pms_reservation.xml b/pms/demo/pms_reservation.xml
index fb6c62c86..af310f088 100644
--- a/pms/demo/pms_reservation.xml
+++ b/pms/demo/pms_reservation.xml
@@ -10,6 +10,7 @@
+
@@ -18,6 +19,7 @@
+
@@ -41,6 +43,7 @@
+
@@ -49,6 +52,7 @@
1
+
@@ -57,6 +61,7 @@
2
+
@@ -65,6 +70,7 @@
1
+
@@ -84,6 +90,7 @@
+
@@ -101,6 +108,7 @@
+
@@ -110,6 +118,7 @@
+
@@ -118,6 +127,7 @@
1
+
@@ -127,6 +137,7 @@
1
+
@@ -136,6 +147,7 @@
+
@@ -144,6 +156,7 @@
1
+
@@ -154,6 +167,7 @@
+
@@ -169,6 +183,7 @@
/>
+
@@ -179,6 +194,7 @@
+
@@ -187,6 +203,7 @@
2
+
@@ -196,6 +213,7 @@
+
@@ -211,6 +229,7 @@
/>
+
@@ -220,6 +239,7 @@
+
@@ -229,6 +249,7 @@
1
+
@@ -238,6 +259,7 @@
+
@@ -246,6 +268,7 @@
2
+
@@ -256,6 +279,7 @@
+
@@ -272,6 +296,7 @@
/>
+
@@ -288,6 +313,7 @@
+
@@ -304,6 +330,7 @@
/>
+
@@ -328,6 +355,7 @@
+
@@ -336,6 +364,7 @@
+
@@ -343,6 +372,7 @@
+
@@ -350,6 +380,7 @@
+
diff --git a/pms/models/pms_folio.py b/pms/models/pms_folio.py
index eff7eca71..bdce61a81 100644
--- a/pms/models/pms_folio.py
+++ b/pms/models/pms_folio.py
@@ -17,6 +17,7 @@ class PmsFolio(models.Model):
_description = "PMS Folio"
_inherit = ["mail.thread", "mail.activity.mixin", "portal.mixin"]
_order = "date_order"
+ _check_company_auto = True
# Default Methods ang Gets
def name_get(self):
@@ -60,6 +61,7 @@ class PmsFolio(models.Model):
readonly=False,
states={"done": [("readonly", True)]},
help="Room reservation detail.",
+ check_company=True,
)
number_of_rooms = fields.Integer(
"Number of Rooms",
@@ -73,6 +75,10 @@ class PmsFolio(models.Model):
states={"done": [("readonly", True)]},
help="Services detail provide to customer and it will "
"include in main Invoice.",
+ check_company=True,
+ domain="['|',"
+ "('pms_property_id','=',pms_property_id),"
+ "('pms_property_id','=',False)]",
)
sale_line_ids = fields.One2many(
"folio.sale.line",
@@ -121,6 +127,9 @@ class PmsFolio(models.Model):
store=True,
readonly=False,
help="Pricelist for current folio.",
+ domain="['|',"
+ "(pms_property_id, 'in', 'pms_property_ids'),"
+ "('pms_property_ids','=',False)]",
)
commission = fields.Float(
string="Commission",
@@ -231,7 +240,12 @@ class PmsFolio(models.Model):
fiscal_position_id = fields.Many2one(
"account.fiscal.position", string="Fiscal Position"
)
- closure_reason_id = fields.Many2one("room.closure.reason")
+ closure_reason_id = fields.Many2one(
+ "room.closure.reason",
+ domain="['|',"
+ "(pms_property_id, 'in', 'pms_property_ids'),"
+ "('pms_property_ids', '=', False)]",
+ )
segmentation_ids = fields.Many2many(
"res.partner.category", string="Segmentation", ondelete="restrict"
)
@@ -482,11 +496,13 @@ class PmsFolio(models.Model):
@api.depends("partner_id")
def _compute_partner_invoice_ids(self):
- for folio in self:
+ for folio in self.filtered("partner_id"):
folio.partner_invoice_ids = False
addr = folio.partner_id.address_get(["invoice"])
if not addr["invoice"] in folio.partner_invoice_ids.ids:
folio.partner_invoice_ids = [(4, addr["invoice"])]
+ # Avoid CacheMissing
+ self.filtered(lambda f: not f.partner_invoice_ids).partner_invoice_ids = False
@api.depends("partner_id")
def _compute_payment_term_id(self):
@@ -1249,6 +1265,18 @@ class PmsFolio(models.Model):
_("The Sale Channel does not correspond to the agency's")
)
+ @api.constrains(
+ "closure_reason_id",
+ )
+ def _check_property_integrity(self):
+ for rec in self:
+ if rec.pms_property_id:
+ if (
+ rec.pms_property_id.id
+ not in rec.closure_reason_id.pms_property_ids.ids
+ ):
+ raise ValidationError(_("Property not allowed"))
+
@api.model
def _prepare_down_payment_section_line(self, **optional_values):
"""
diff --git a/pms/models/pms_reservation.py b/pms/models/pms_reservation.py
index 835437dfd..507906805 100644
--- a/pms/models/pms_reservation.py
+++ b/pms/models/pms_reservation.py
@@ -82,6 +82,7 @@ class PmsReservation(models.Model):
tracking=True,
ondelete="restrict",
copy=False,
+ check_company=True,
)
board_service_room_id = fields.Many2one(
"pms.board.service.room.type",
@@ -90,6 +91,10 @@ class PmsReservation(models.Model):
store=True,
readonly=False,
tracking=True,
+ domain="["
+ "'|',"
+ "('pms_property_ids', 'in', pms_property_id),"
+ "('pms_property_ids', '=', False)]",
)
room_type_id = fields.Many2one(
"pms.room.type",
@@ -100,6 +105,9 @@ class PmsReservation(models.Model):
store=True,
readonly=False,
copy=False,
+ domain="['|',"
+ "('pms_property_ids', 'in', pms_property_id),"
+ "('pms_property_ids', '=', False)]",
)
partner_id = fields.Many2one(
"res.partner",
@@ -128,12 +136,20 @@ class PmsReservation(models.Model):
store=True,
readonly=False,
)
- closure_reason_id = fields.Many2one(related="folio_id.closure_reason_id")
+ closure_reason_id = fields.Many2one(
+ related="folio_id.closure_reason_id",
+ domain="['|',"
+ "(pms_property_id, 'in', 'pms_property_ids'),"
+ "('pms_property_ids', '=', False)]",
+ )
company_id = fields.Many2one(
related="folio_id.company_id", string="Company", store=True, readonly=True
)
pms_property_id = fields.Many2one(
"pms.property",
+ related="folio_id.pms_property_id",
+ store=True,
+ readonly=False,
default=lambda self: self.env.user.get_active_property_ids()[0],
)
reservation_line_ids = fields.One2many(
@@ -150,6 +166,10 @@ class PmsReservation(models.Model):
compute="_compute_service_ids",
store=True,
readonly=False,
+ check_company=True,
+ domain="['|',"
+ "('pms_property_id', '=', pms_property_id),"
+ "('pms_property_id', '=', False)]",
)
pricelist_id = fields.Many2one(
"product.pricelist",
@@ -159,6 +179,9 @@ class PmsReservation(models.Model):
store=True,
readonly=False,
tracking=True,
+ domain="['|',"
+ "('pms_property_ids', 'in', pms_property_id),"
+ "('pms_property_ids', '=', False)]",
)
show_update_pricelist = fields.Boolean(
string="Has Pricelist Changed",
@@ -1325,6 +1348,45 @@ class PmsReservation(models.Model):
if record.agency_id and not record.agency_id.is_agency:
raise ValidationError(_("booking agency with wrong configuration: "))
+ @api.constrains("pms_property_id", "preferred_room_id")
+ def _check_room_property_integrity(self):
+ for record in self:
+ if record.pms_property_id and record.preferred_room_id.pms_property_id:
+ if record.pms_property_id != record.preferred_room_id.pms_property_id:
+ raise ValidationError(
+ _("Property doesn't match with room property")
+ )
+
+ @api.constrains("pms_property_id", "room_type_id")
+ def _check_room_type_property_integrity(self):
+ for record in self:
+ if record.pms_property_id and record.room_type_id.pms_property_ids:
+ if (
+ record.pms_property_id.id
+ not in record.room_type_id.pms_property_ids.ids
+ ):
+ raise ValidationError(_("Property isn't allowed in Room Type"))
+
+ @api.constrains("pms_property_id", "pricelist_id")
+ def _check_pricelist_property_integrity(self):
+ for record in self:
+ if record.pms_property_id and record.pricelist_id.pms_property_ids:
+ if (
+ record.pms_property_id.id
+ not in record.pricelist_id.pms_property_ids.ids
+ ):
+ raise ValidationError(_("Property isn't allowed in Pricelist"))
+
+ @api.constrains("pms_property_id", "board_service_room_id")
+ def _check_board_service_property_integrity(self):
+ for record in self:
+ if record.pms_property_id and record.board_service_room_id.pms_property_ids:
+ if (
+ record.pms_property_id.id
+ not in record.board_service_room_id.pms_property_ids.ids
+ ):
+ raise ValidationError(_("Property isn't allowed in Board Service"))
+
# Action methods
def open_folio(self):
@@ -1409,15 +1471,16 @@ class PmsReservation(models.Model):
def create(self, vals):
if "folio_id" in vals:
folio = self.env["pms.folio"].browse(vals["folio_id"])
- elif "partner_id" in vals or "agency_id" in vals:
+ elif "pms_property_id" in vals and (
+ "partner_id" in vals or "agency_id" in vals
+ ):
folio_vals = {
- "partner_id": int(vals.get("partner_id"))
- if vals.get("partner_id")
- else False,
- "agency_id": int(vals.get("agency_id"))
- if vals.get("agency_id")
- else False,
+ "pms_property_id": vals["pms_property_id"],
}
+ if vals.get("partner_id"):
+ folio_vals["partner_id"] = vals.get("partner_id")
+ elif vals.get("agency_id"):
+ folio_vals["agency_id"] = vals.get("agency_id")
# Create the folio in case of need
# (To allow to create reservations direct)
folio = self.env["pms.folio"].create(folio_vals)
@@ -1427,6 +1490,10 @@ class PmsReservation(models.Model):
"reservation_type": vals.get("reservation_type"),
}
)
+ else:
+ raise ValidationError(
+ _("The client and Property are mandatory in the reservation")
+ )
if vals.get("name", _("New")) == _("New") or "name" not in vals:
vals["name"] = self.env["ir.sequence"]._next_sequence_property(
pms_property_id=folio.pms_property_id.id,
diff --git a/pms/models/pms_room_type.py b/pms/models/pms_room_type.py
index a7f2e3d6a..b46b4122e 100644
--- a/pms/models/pms_room_type.py
+++ b/pms/models/pms_room_type.py
@@ -137,7 +137,7 @@ class PmsRoomType(models.Model):
)
return self.browse(list(res.values()))
- @api.constrains("pms_property_ids")
+ @api.constrains("pms_property_ids", "class_id")
def _check_integrity_property_class(self):
for record in self:
if record.pms_property_ids and record.class_id.pms_property_ids:
diff --git a/pms/tests/test_pms_folio.py b/pms/tests/test_pms_folio.py
index 47f43094e..c07bc1cc8 100644
--- a/pms/tests/test_pms_folio.py
+++ b/pms/tests/test_pms_folio.py
@@ -3,6 +3,7 @@ import datetime
from freezegun import freeze_time
from odoo import fields
+from odoo.exceptions import ValidationError
from .common import TestHotel
@@ -60,8 +61,34 @@ class TestPmsFolio(TestHotel):
}
)
+ def create_multiproperty_scenario(self):
+ self.property1 = self.env["pms.property"].create(
+ {
+ "name": "Property_1",
+ "company_id": self.env.ref("base.main_company").id,
+ "default_pricelist_id": self.env.ref("product.list0").id,
+ }
+ )
+
+ self.property2 = self.env["pms.property"].create(
+ {
+ "name": "Property_2",
+ "company_id": self.env.ref("base.main_company").id,
+ "default_pricelist_id": self.env.ref("product.list0").id,
+ }
+ )
+
+ self.property3 = self.env["pms.property"].create(
+ {
+ "name": "Property_3",
+ "company_id": self.env.ref("base.main_company").id,
+ "default_pricelist_id": self.env.ref("product.list0").id,
+ }
+ )
+
def test_commission_and_partner_correct(self):
# ARRANGE
+ self.create_common_scenario()
PmsFolio = self.env["pms.folio"]
PmsReservation = self.env["pms.reservation"]
PmsPartner = self.env["res.partner"]
@@ -83,6 +110,7 @@ class TestPmsFolio(TestHotel):
folio = PmsFolio.create(
{
"agency_id": agency.id,
+ "pms_property_id": self.property.id,
}
)
@@ -202,3 +230,23 @@ class TestPmsFolio(TestHotel):
date=fields.date.today(),
)
self.assertEqual(r_test.folio_id.pending_amount, left_to_pay)
+
+ def test_closure_reason_property(self):
+ self.create_multiproperty_scenario()
+ cl_reason = self.env["room.closure.reason"].create(
+ {
+ "name": "closure_reason_test",
+ "pms_property_ids": [
+ (4, self.property1.id),
+ (4, self.property2.id),
+ ],
+ }
+ )
+
+ with self.assertRaises(ValidationError):
+ self.env["pms.folio"].create(
+ {
+ "pms_property_id": self.property3.id,
+ "closure_reason_id": cl_reason.id,
+ }
+ )
diff --git a/pms/tests/test_pms_reservation.py b/pms/tests/test_pms_reservation.py
index b0dbcbf95..28d744d6d 100644
--- a/pms/tests/test_pms_reservation.py
+++ b/pms/tests/test_pms_reservation.py
@@ -69,6 +69,40 @@ class TestPmsReservations(TestHotel):
)
self.demo_user = self.env.ref("base.user_admin")
+ def create_multiproperty_scenario(self):
+ self.property1 = self.env["pms.property"].create(
+ {
+ "name": "Property_1",
+ "company_id": self.env.ref("base.main_company").id,
+ "default_pricelist_id": self.env.ref("product.list0").id,
+ }
+ )
+
+ self.property2 = self.env["pms.property"].create(
+ {
+ "name": "Property_2",
+ "company_id": self.env.ref("base.main_company").id,
+ "default_pricelist_id": self.env.ref("product.list0").id,
+ }
+ )
+
+ self.property3 = self.env["pms.property"].create(
+ {
+ "name": "Property_3",
+ "company_id": self.env.ref("base.main_company").id,
+ "default_pricelist_id": self.env.ref("product.list0").id,
+ }
+ )
+ self.room_type_class = self.env["pms.room.type.class"].create(
+ {"name": "Room Class", "code_class": "RCTEST"}
+ )
+
+ self.board_service = self.env["pms.board.service"].create(
+ {
+ "name": "Board Service Test",
+ }
+ )
+
@freeze_time("1980-11-01")
def test_create_reservation_start_date(self):
# TEST CASE
@@ -788,3 +822,84 @@ class TestPmsReservations(TestHotel):
self.assertEqual(
r1.state, "done", "The reservation status should be done after checkout."
)
+
+ def test_multiproperty_checks(self):
+ """
+ # TEST CASE
+ Multiproperty checks in reservation
+ +---------------+------+------+------+----+----+
+ | reservation | property1 |
+ +---------------+------+------+------+----+----+
+ | room | property2 |
+ | room_type | property2, property3 |
+ | board_service | property2, property3 |
+ | pricelist | property2, property3 |
+ +---------------+------+------+------+----+----+
+ """
+ # ARRANGE
+ self.create_multiproperty_scenario()
+ host = self.env["res.partner"].create(
+ {
+ "name": "Miguel",
+ "phone": "654667733",
+ "email": "miguel@example.com",
+ }
+ )
+ self.reservation_test = self.env["pms.reservation"].create(
+ {
+ "checkin": fields.date.today(),
+ "checkout": fields.date.today() + datetime.timedelta(days=1),
+ "pms_property_id": self.property1.id,
+ "partner_id": host.id,
+ }
+ )
+
+ room_type_test = self.env["pms.room.type"].create(
+ {
+ "pms_property_ids": [
+ (4, self.property3.id),
+ (4, self.property2.id),
+ ],
+ "name": "Single",
+ "code_type": "SIN",
+ "class_id": self.room_type_class.id,
+ "list_price": 30,
+ }
+ )
+
+ room = self.env["pms.room"].create(
+ {
+ "name": "Room 101",
+ "pms_property_id": self.property2.id,
+ "room_type_id": room_type_test.id,
+ }
+ )
+
+ pricelist = self.env["product.pricelist"].create(
+ {
+ "name": "pricelist_test",
+ "pms_property_ids": [
+ (4, self.property2.id),
+ (4, self.property3.id),
+ ],
+ }
+ )
+
+ board_service_room_type = self.env["pms.board.service.room.type"].create(
+ {
+ "pms_board_service_id": self.board_service.id,
+ "pms_room_type_id": room_type_test.id,
+ "pms_property_ids": [self.property2.id, self.property3.id],
+ }
+ )
+ test_cases = [
+ {"preferred_room_id": room.id},
+ {"room_type_id": room_type_test.id},
+ {"pricelist_id": pricelist.id},
+ {"board_service_room_id": board_service_room_type.id},
+ ]
+
+ for test_case in test_cases:
+ with self.subTest(k=test_case):
+ with self.assertRaises(ValidationError):
+ self.reservation_test.write(test_case)
diff --git a/pms/tests/test_pms_sale_channel.py b/pms/tests/test_pms_sale_channel.py
index 1cab21ead..d5eadd372 100644
--- a/pms/tests/test_pms_sale_channel.py
+++ b/pms/tests/test_pms_sale_channel.py
@@ -9,8 +9,19 @@ from .common import TestHotel
@freeze_time("2010-01-01")
class TestPmsSaleChannel(TestHotel):
+ def create_common_scenario(self):
+ # create a property
+ self.property = self.env["pms.property"].create(
+ {
+ "name": "MY PROPERTY TEST",
+ "company_id": self.env.ref("base.main_company").id,
+ "default_pricelist_id": self.env.ref("product.list0").id,
+ }
+ )
+
def test_not_agency_as_agency(self):
# ARRANGE
+ self.create_common_scenario()
PmsReservation = self.env["pms.reservation"]
not_agency = self.env["res.partner"].create(
{"name": "partner1", "is_agency": False}
@@ -23,11 +34,13 @@ class TestPmsSaleChannel(TestHotel):
"checkin": datetime.datetime.now(),
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
"agency_id": not_agency.id,
+ "pms_property_id": self.property.id,
}
)
def test_channel_type_id_only_directs(self):
# ARRANGE
+ self.create_common_scenario()
PmsReservation = self.env["pms.reservation"]
PmsSaleChannel = self.env["pms.sale.channel"]
# ACT
@@ -39,6 +52,7 @@ class TestPmsSaleChannel(TestHotel):
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
"channel_type_id": salechannel.id,
"partner_id": partner1.id,
+ "pms_property_id": self.property.id,
}
)
# ASSERT
@@ -50,6 +64,7 @@ class TestPmsSaleChannel(TestHotel):
def test_agency_id_is_agency(self):
# ARRANGE
+ self.create_common_scenario()
PmsReservation = self.env["pms.reservation"]
PmsSaleChannel = self.env["pms.sale.channel"]
salechannel = PmsSaleChannel.create(
@@ -68,6 +83,7 @@ class TestPmsSaleChannel(TestHotel):
"checkin": datetime.datetime.now(),
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
"agency_id": agency.id,
+ "pms_property_id": self.property.id,
}
)
# ASSERT
diff --git a/pms/wizards/wizard_folio.py b/pms/wizards/wizard_folio.py
index 030dd464d..7ee1b9ffc 100644
--- a/pms/wizards/wizard_folio.py
+++ b/pms/wizards/wizard_folio.py
@@ -145,7 +145,7 @@ class FolioWizard(models.TransientModel):
"room_type_id": line.room_type_id.id,
"partner_id": folio.partner_id.id,
"pricelist_id": folio.pricelist_id.id,
- "pms_property_id": record.pms_property_id.id,
+ "pms_property_id": folio.pms_property_id.id,
}
)
res.reservation_line_ids.discount = record.discount * 100
diff --git a/pms_l10n_es/tests/test_partner.py b/pms_l10n_es/tests/test_partner.py
index d912b7ac0..3c17d603d 100644
--- a/pms_l10n_es/tests/test_partner.py
+++ b/pms_l10n_es/tests/test_partner.py
@@ -9,8 +9,18 @@ from odoo.tests import common
@freeze_time("2011-03-16")
class TestResPartner(common.SavepointCase):
+ def create_common_scenario(self):
+ self.property_test = self.property = self.env["pms.property"].create(
+ {
+ "name": "My property test",
+ "company_id": self.env.ref("base.main_company").id,
+ "default_pricelist_id": self.env.ref("product.list0").id,
+ }
+ )
+
def test_check_precheckin_state(self):
# arrange
+ self.create_common_scenario()
today = fields.date.today()
partner = self.env["res.partner"].create(
{
@@ -29,6 +39,7 @@ class TestResPartner(common.SavepointCase):
"checkout": today + datetime.timedelta(days=3),
"partner_id": partner.id,
"adults": 1,
+ "pms_property_id": self.property_test.id,
}
# action
reservation = self.env["pms.reservation"].create(reservation_vals)
@@ -46,8 +57,9 @@ class TestResPartner(common.SavepointCase):
)
def test_error_action_on_board(self):
- today = fields.date.today()
# arrange
+ self.create_common_scenario()
+ today = fields.date.today()
partner = self.env["res.partner"].create(
{
"name": "partner1",
@@ -58,6 +70,7 @@ class TestResPartner(common.SavepointCase):
"checkout": today + datetime.timedelta(days=3),
"partner_id": partner.id,
"adults": 1,
+ "pms_property_id": self.property_test.id,
}
# action
reservation = self.env["pms.reservation"].create(reservation_vals)
@@ -74,7 +87,7 @@ class TestResPartner(common.SavepointCase):
def test_right_action_on_board(self):
# arrange
- # arrange
+ self.create_common_scenario()
today = fields.date.today()
partner = self.env["res.partner"].create(
{
@@ -93,6 +106,7 @@ class TestResPartner(common.SavepointCase):
"checkout": today + datetime.timedelta(days=3),
"partner_id": partner.id,
"adults": 1,
+ "pms_property_id": self.property_test.id,
}
# action
reservation = self.env["pms.reservation"].create(reservation_vals)