mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
[DONE] 14.0 split join swap reservations (#85)
* [REF] pms: change name to reservation wizard * [IMP] pms: operations over reservations (split,join,swap) * [IMP]pms, swap reservation: order reservation by rooms and readonly compute fields * [IMP] wizard split reservation allowed_room_ids domain * [IMP] pms: refactor swap operations and tests cases * [FIX] pms: fix tests and & behaviour * [FIX] rebase code review compatibility Co-authored-by: Darío Lodeiros <dario@commitsun.com>
This commit is contained in:
@@ -71,7 +71,7 @@
|
||||
"views/account_journal_views.xml",
|
||||
"views/folio_portal_templates.xml",
|
||||
"views/reservation_portal_templates.xml",
|
||||
"wizards/wizard_reservation.xml",
|
||||
"wizards/wizard_split_join_swap_reservation.xml",
|
||||
"wizards/wizard_massive_changes.xml",
|
||||
"wizards/wizard_advanced_filters.xml",
|
||||
],
|
||||
|
||||
@@ -353,6 +353,7 @@ class PmsReservation(models.Model):
|
||||
string="Room/s",
|
||||
help="Rooms that are reserved",
|
||||
compute="_compute_rooms",
|
||||
store=True,
|
||||
tracking=True,
|
||||
)
|
||||
credit_card_details = fields.Text(
|
||||
@@ -1324,7 +1325,7 @@ class PmsReservation(models.Model):
|
||||
"view_type": "form",
|
||||
"view_mode": "form",
|
||||
"name": "Unify the reservation",
|
||||
"res_model": "pms.reservation.wizard",
|
||||
"res_model": "pms.reservation.split.join.swap.wizard",
|
||||
"target": "new",
|
||||
"type": "ir.actions.act_window",
|
||||
"context": {
|
||||
|
||||
@@ -163,9 +163,13 @@ class PmsReservationLine(models.Model):
|
||||
key=lambda r: (r.reservation_id, r.date)
|
||||
):
|
||||
reservation = line.reservation_id
|
||||
if reservation.preferred_room_id != line.room_id or not line.room_id:
|
||||
# If reservation has a preferred_room_id We can allow
|
||||
# select room_id regardless room_type_id selected on reservation
|
||||
if (
|
||||
reservation.preferred_room_id
|
||||
and reservation.preferred_room_id != line.room_id
|
||||
) or (
|
||||
(reservation.preferred_room_id or reservation.room_type_id)
|
||||
and not line.room_id
|
||||
):
|
||||
free_room_select = True if reservation.preferred_room_id else False
|
||||
# we get the rooms available for the entire stay
|
||||
rooms_available = self.env["pms.availability.plan"].rooms_available(
|
||||
|
||||
@@ -49,7 +49,8 @@ manager_access_property,manager_access_property,model_pms_property,pms.group_pms
|
||||
manager_access_pms_cancelation_rule,manager_access_pms_cancelation_rule,model_pms_cancelation_rule,pms.group_pms_manager,1,1,1,1
|
||||
manager_access_availability,manager_access_availability,model_pms_availability_plan,pms.group_pms_manager,1,1,1,1
|
||||
manager_access_pms_sale_channel,manager_access_pms_sale_channel,model_pms_sale_channel,pms.group_pms_manager,1,1,1,1
|
||||
user_access_pms_reservation_wizard,user_access_pms_reservation_wizard,model_pms_reservation_wizard,pms.group_pms_user,1,1,1,1
|
||||
user_access_pms_reservation_split_join_swap_wizard,user_access_pms_reservation_split_join_swap_wizard,model_pms_reservation_split_join_swap_wizard,pms.group_pms_user,1,1,1,1
|
||||
user_access_pms_wizard_reservation_lines_split,user_access_pms_wizard_reservation_lines_split,model_pms_wizard_reservation_lines_split,pms.group_pms_user,1,1,1,1
|
||||
user_access_pms_massive_changes_wizard,user_access_pms_massive_changes_wizard,model_pms_massive_changes_wizard,pms.group_pms_user,1,1,1,1
|
||||
user_access_pms_advanced_filters_wizard,user_access_pms_advanced_filters_wizard,model_pms_advanced_filters_wizard,pms.group_pms_user,1,1,1,1
|
||||
user_access_pms_folio_wizard,user_access_pms_folio_wizard,model_pms_folio_wizard,pms.group_pms_user,1,1,1,1
|
||||
|
||||
|
@@ -39,3 +39,4 @@ from . import test_pms_board_service_room_type
|
||||
from . import test_pms_board_service_room_type_line
|
||||
from . import test_pms_folio_invoice
|
||||
from . import test_pms_folio_sale_line
|
||||
from . import test_pms_wizard_split_join_swap_reservation
|
||||
|
||||
967
pms/tests/test_pms_wizard_split_join_swap_reservation.py
Normal file
967
pms/tests/test_pms_wizard_split_join_swap_reservation.py
Normal file
@@ -0,0 +1,967 @@
|
||||
import datetime
|
||||
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tests import common
|
||||
|
||||
|
||||
class TestPmsWizardMassiveChanges(common.SavepointCase):
|
||||
def create_common_scenario(self):
|
||||
# product.pricelist
|
||||
self.test_pricelist = self.env["product.pricelist"].create(
|
||||
{
|
||||
"name": "test pricelist 1",
|
||||
}
|
||||
)
|
||||
# pms.availability.plan
|
||||
self.test_availability_plan = self.env["pms.availability.plan"].create(
|
||||
{
|
||||
"name": "Availability plan for TEST",
|
||||
"pms_pricelist_ids": [(6, 0, [self.test_pricelist.id])],
|
||||
}
|
||||
)
|
||||
# sequences
|
||||
self.folio_sequence = self.env["ir.sequence"].create(
|
||||
{
|
||||
"name": "PMS Folio",
|
||||
"code": "pms.folio",
|
||||
"padding": 4,
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
}
|
||||
)
|
||||
self.reservation_sequence = self.env["ir.sequence"].create(
|
||||
{
|
||||
"name": "PMS Reservation",
|
||||
"code": "pms.reservation",
|
||||
"padding": 4,
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
}
|
||||
)
|
||||
self.checkin_sequence = self.env["ir.sequence"].create(
|
||||
{
|
||||
"name": "PMS Checkin",
|
||||
"code": "pms.checkin.partner",
|
||||
"padding": 4,
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
}
|
||||
)
|
||||
# pms.property
|
||||
self.test_property = self.env["pms.property"].create(
|
||||
{
|
||||
"name": "MY PMS TEST",
|
||||
"company_id": self.env.ref("base.main_company").id,
|
||||
"default_pricelist_id": self.test_pricelist.id,
|
||||
"folio_sequence_id": self.folio_sequence.id,
|
||||
"reservation_sequence_id": self.reservation_sequence.id,
|
||||
"checkin_sequence_id": self.checkin_sequence.id,
|
||||
}
|
||||
)
|
||||
# pms.room.type.class
|
||||
self.test_room_type_class = self.env["pms.room.type.class"].create(
|
||||
{"name": "Room", "default_code": "ROOM"}
|
||||
)
|
||||
|
||||
# pms.room.type
|
||||
self.test_room_type_single = self.env["pms.room.type"].create(
|
||||
{
|
||||
"pms_property_ids": [self.test_property.id],
|
||||
"name": "Single Test",
|
||||
"default_code": "SNG_Test",
|
||||
"class_id": self.test_room_type_class.id,
|
||||
}
|
||||
)
|
||||
# pms.room.type
|
||||
self.test_room_type_double = self.env["pms.room.type"].create(
|
||||
{
|
||||
"pms_property_ids": [self.test_property.id],
|
||||
"name": "Double Test",
|
||||
"default_code": "DBL_Test",
|
||||
"class_id": self.test_room_type_class.id,
|
||||
}
|
||||
)
|
||||
|
||||
# create rooms
|
||||
self.room1 = self.env["pms.room"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"name": "Double 101",
|
||||
"room_type_id": self.test_room_type_double.id,
|
||||
"capacity": 2,
|
||||
}
|
||||
)
|
||||
|
||||
self.room2 = self.env["pms.room"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"name": "Double 102",
|
||||
"room_type_id": self.test_room_type_double.id,
|
||||
"capacity": 2,
|
||||
}
|
||||
)
|
||||
|
||||
# self.room3 = self.env["pms.room"].create(
|
||||
# {
|
||||
# "pms_property_id": self.test_property.id,
|
||||
# "name": "Double 103",
|
||||
# "room_type_id": self.test_room_type_double.id,
|
||||
# "capacity": 2,
|
||||
# }
|
||||
# )
|
||||
|
||||
# UNIFY TESTS # review
|
||||
def test_unify_reservation_avail_should(self):
|
||||
# TEST CASE
|
||||
# Unify reservation in one room with avail for that room
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | room/date | 01 | 02 | 03 | 04 | 05 | 06 |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | Double 101 | r1 | | r1 | | | |
|
||||
# | Double 102 | | r1 | | | | |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# ARRANGE
|
||||
self.create_common_scenario()
|
||||
r1 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room1.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r1.flush()
|
||||
r1.reservation_line_ids[0].room_id = self.room2
|
||||
# ACT
|
||||
self.env["pms.reservation.split.join.swap.wizard"].reservation_join(
|
||||
r1, self.room2
|
||||
)
|
||||
# ASSERT
|
||||
self.assertEqual(
|
||||
r1.reservation_line_ids.mapped("room_id"),
|
||||
self.room2,
|
||||
"The unify operation should assign the indicated room to all nights",
|
||||
)
|
||||
|
||||
def test_unify_reservation_avail_not(self):
|
||||
# TEST CASE
|
||||
# Unify reservation in one room and
|
||||
# there's not availability for that room
|
||||
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | room/date | 01 | 02 | 03 | 04 | 05 | 06 |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | Double 101 | r1 | r1 | r2 | | | |
|
||||
# | Double 102 | r0 | r0 | r1 | | | |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# ARRANGE
|
||||
self.create_common_scenario()
|
||||
self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=2),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room2.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r2 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now() + datetime.timedelta(days=2),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room1.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r1 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"room_type_id": self.test_room_type_double.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r2.flush()
|
||||
# ACT & ASSERT
|
||||
with self.assertRaises(UserError):
|
||||
self.env["pms.reservation.split.join.swap.wizard"].reservation_join(
|
||||
r1, self.room1
|
||||
)
|
||||
|
||||
def test_unify_reservation_avail_not_room_exist(self):
|
||||
# TEST CASE
|
||||
# Unify reservation in one room and
|
||||
# the room indicated doesn't exist: pms.room()
|
||||
|
||||
# ARRANGE
|
||||
self.create_common_scenario()
|
||||
self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room1.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r2 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room2.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r2.flush()
|
||||
with self.assertRaises(UserError):
|
||||
self.env["pms.reservation.split.join.swap.wizard"].reservation_join(
|
||||
r2, self.env["pms.room"]
|
||||
)
|
||||
|
||||
# SWAP TESTS
|
||||
def test_swap_reservation_rooms_01(self):
|
||||
# TEST CASE
|
||||
|
||||
# Initial state
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | room/date | 01 | 02 | 03 | 04 | 05 | 06 |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | Double 101 | r1 | r1 | r1 | | | |
|
||||
# | Double 102 | r2 | r2 | r2 | | | |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
|
||||
# State after swap
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | room/date | 01 | 02 | 03 | 04 | 05 | 06 |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | Double 101 | r2 | r2 | r2 | | | |
|
||||
# | Double 102 | r1 | r1 | r1 | | | |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
|
||||
# ARRANGE
|
||||
self.create_common_scenario()
|
||||
r1 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room1.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r2 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room2.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r1.flush()
|
||||
r2.flush()
|
||||
# ACT
|
||||
self.env["pms.reservation.split.join.swap.wizard"].reservations_swap(
|
||||
datetime.datetime.now(),
|
||||
datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
self.room1.id,
|
||||
self.room2.id,
|
||||
)
|
||||
# ASSERT
|
||||
self.assertTrue(
|
||||
r1.reservation_line_ids.room_id == self.room2
|
||||
and r2.reservation_line_ids.room_id == self.room1
|
||||
)
|
||||
|
||||
def test_swap_reservation_rooms_02(self):
|
||||
# TEST CASE
|
||||
|
||||
# Initial state
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | room/date | 01 | 02 | 03 | 04 | 05 | 06 |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | Double 101 | | r1 | r1 | | | |
|
||||
# | Double 102 | r2 | r2 | r2 | | | |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
|
||||
# State after swap
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | room/date | 01 | 02 | 03 | 04 | 05 | 06 |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | Double 101 | | r2 | r2 | | | |
|
||||
# | Double 102 | r2 | r1 | r1 | | | |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
|
||||
# ARRANGE
|
||||
self.create_common_scenario()
|
||||
r1 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now() + datetime.timedelta(days=1),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room1.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r2 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room2.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r1.flush()
|
||||
r2.flush()
|
||||
# ACT
|
||||
self.env["pms.reservation.split.join.swap.wizard"].reservations_swap(
|
||||
datetime.datetime.now(),
|
||||
datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
self.room1.id,
|
||||
self.room2.id,
|
||||
)
|
||||
# ASSERT
|
||||
self.assertTrue(
|
||||
r1.reservation_line_ids.room_id == self.room2
|
||||
and r2.reservation_line_ids[1:].room_id == self.room1
|
||||
)
|
||||
|
||||
def test_swap_reservation_rooms_03(self):
|
||||
# TEST CASE
|
||||
|
||||
# Initial state
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | room/date | 01 | 02 | 03 | 04 | 05 | 06 |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | Double 101 | | r1 | r1 | | | |
|
||||
# | Double 102 | r2 | r2 | r2 | | | |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
|
||||
# State after swap
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | room/date | 01 | 02 | 03 | 04 | 05 | 06 |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | Double 101 | r2 | r2 | r2 | | | |
|
||||
# | Double 102 | | r1 | r1 | | | |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
|
||||
# ARRANGE
|
||||
self.create_common_scenario()
|
||||
r1 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now() + datetime.timedelta(days=1),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room1.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r2 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room2.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r1.flush()
|
||||
r2.flush()
|
||||
# ACT
|
||||
self.env["pms.reservation.split.join.swap.wizard"].reservations_swap(
|
||||
datetime.datetime.now(),
|
||||
datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
self.room2.id,
|
||||
self.room1.id,
|
||||
)
|
||||
# ASSERT
|
||||
self.assertTrue(
|
||||
r1.reservation_line_ids.room_id == self.room2
|
||||
and r2.reservation_line_ids.room_id == self.room1
|
||||
)
|
||||
|
||||
def test_swap_reservation_rooms_04(self):
|
||||
# TEST CASE
|
||||
|
||||
# Initial state
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | room/date | 01 | 02 | 03 | 04 | 05 | 06 |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | Double 101 | r1 | r1 | | | | |
|
||||
# | Double 102 | r2 | r2 | r2 | | | |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
|
||||
# State after swap
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | room/date | 01 | 02 | 03 | 04 | 05 | 06 |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | Double 101 | r2 | r2 | | | | |
|
||||
# | Double 102 | r1 | r1 | r2 | | | |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
|
||||
# ARRANGE
|
||||
self.create_common_scenario()
|
||||
r1 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=2),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room1.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r2 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room2.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r1.flush()
|
||||
r2.flush()
|
||||
# ACT
|
||||
self.env["pms.reservation.split.join.swap.wizard"].reservations_swap(
|
||||
datetime.datetime.now(),
|
||||
datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
self.room1.id,
|
||||
self.room2.id,
|
||||
)
|
||||
# ASSERT
|
||||
self.assertTrue(
|
||||
r1.reservation_line_ids.room_id == self.room2
|
||||
and r2.reservation_line_ids[:1].room_id == self.room1
|
||||
)
|
||||
|
||||
def test_swap_reservation_rooms_05(self):
|
||||
# TEST CASE
|
||||
|
||||
# Initial state
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | room/date | 01 | 02 | 03 | 04 | 05 | 06 |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | Double 101 | r1 | r1 | | | | |
|
||||
# | Double 102 | r2 | r2 | r2 | | | |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
|
||||
# State after swap
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | room/date | 01 | 02 | 03 | 04 | 05 | 06 |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | Double 101 | r2 | r2 | r2 | | | |
|
||||
# | Double 102 | r1 | r1 | | | | |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
|
||||
# ARRANGE
|
||||
self.create_common_scenario()
|
||||
r1 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=2),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room1.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r2 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room2.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r1.flush()
|
||||
r2.flush()
|
||||
# ACT
|
||||
self.env["pms.reservation.split.join.swap.wizard"].reservations_swap(
|
||||
datetime.datetime.now(),
|
||||
datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
self.room2.id,
|
||||
self.room1.id,
|
||||
)
|
||||
# ASSERT
|
||||
self.assertTrue(
|
||||
r1.reservation_line_ids.room_id == self.room2
|
||||
and r2.reservation_line_ids.room_id == self.room1
|
||||
)
|
||||
|
||||
def test_swap_reservation_rooms_06(self):
|
||||
# TEST CASE
|
||||
# Swap room1 with room2 should raise an error
|
||||
# because room1 has no reservation between
|
||||
# checkin & checkout provided
|
||||
|
||||
# Initial state
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | room/date | 01 | 02 | 03 | 04 | 05 | 06 |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | Double 101 | | | | | | |
|
||||
# | Double 102 | r1 | r1 | r1 | | | |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
|
||||
# State after swap
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | room/date | 01 | 02 | 03 | 04 | 05 | 06 |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | Double 101 | r1 | r1 | r1 | | | |
|
||||
# | Double 102 | | | | | | |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
|
||||
# ARRANGE
|
||||
self.create_common_scenario()
|
||||
r1 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room2.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
|
||||
# ACT
|
||||
self.env["pms.reservation.split.join.swap.wizard"].reservations_swap(
|
||||
datetime.datetime.now(),
|
||||
datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
self.room2.id,
|
||||
self.room1.id,
|
||||
)
|
||||
# ASSERT
|
||||
self.assertTrue(r1.reservation_line_ids.room_id == self.room1)
|
||||
|
||||
def test_swap_reservation_rooms_gap_01(self):
|
||||
# TEST CASE
|
||||
|
||||
# Initial state
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | room/date | 01 | 02 | 03 | 04 | 05 | 06 |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | Double 101 | r0 | | r1 | | | |
|
||||
# | Double 102 | r2 | r2 | r2 | | | |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
|
||||
# State after swap
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | room/date | 01 | 02 | 03 | 04 | 05 | 06 |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | Double 101 | r2 | | r2 | | | |
|
||||
# | Double 102 | r0 | r2 | r1 | | | |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
|
||||
# ARRANGE
|
||||
self.create_common_scenario()
|
||||
r0 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=1),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room1.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
|
||||
r1 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now() + datetime.timedelta(days=2),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room1.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r2 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room2.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r1.flush()
|
||||
r2.flush()
|
||||
# ACT
|
||||
self.env["pms.reservation.split.join.swap.wizard"].reservations_swap(
|
||||
datetime.datetime.now(),
|
||||
datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
self.room1.id,
|
||||
self.room2.id,
|
||||
)
|
||||
# ASSERT
|
||||
self.assertTrue(
|
||||
r0.reservation_line_ids.room_id == self.room2
|
||||
and r1.reservation_line_ids.room_id == self.room2
|
||||
and r2.reservation_line_ids[0].room_id == self.room1
|
||||
and r2.reservation_line_ids[2].room_id == self.room1
|
||||
and r2.reservation_line_ids[1].room_id == self.room2
|
||||
)
|
||||
|
||||
def test_swap_reservation_rooms_gap_02(self):
|
||||
# TEST CASE
|
||||
|
||||
# Initial state
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | room/date | 01 | 02 | 03 | 04 | 05 | 06 |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | Double 101 | r0 | | r1 | | | |
|
||||
# | Double 102 | r2 | r2 | r2 | | | |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
|
||||
# State after swap
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | room/date | 01 | 02 | 03 | 04 | 05 | 06 |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | Double 101 | r2 | r2 | r2 | | | |
|
||||
# | Double 102 | r0 | | r1 | | | |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
|
||||
# ARRANGE
|
||||
self.create_common_scenario()
|
||||
r0 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=1),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room1.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
|
||||
r1 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now() + datetime.timedelta(days=2),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room1.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r2 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room2.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r1.flush()
|
||||
r2.flush()
|
||||
# ACT
|
||||
self.env["pms.reservation.split.join.swap.wizard"].reservations_swap(
|
||||
datetime.datetime.now(),
|
||||
datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
self.room2.id,
|
||||
self.room1.id,
|
||||
)
|
||||
# ASSERT
|
||||
self.assertTrue(
|
||||
r0.reservation_line_ids.room_id == self.room2
|
||||
and r1.reservation_line_ids.room_id == self.room2
|
||||
and r2.reservation_line_ids.room_id == self.room1
|
||||
)
|
||||
|
||||
# NOT VALID TEST CASES
|
||||
def test_swap_reservation_not_valid_01(self):
|
||||
# TEST CASE
|
||||
# Swap room1 with room2 should raise an error
|
||||
# because room1 has no reservation between
|
||||
# checkin & checkout provided
|
||||
|
||||
# Initial state
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | room/date | 01 | 02 | 03 | 04 | 05 | 06 |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | Double 101 | | | | | | |
|
||||
# | Double 102 | r1 | r1 | r1 | | | |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
|
||||
# ARRANGE
|
||||
self.create_common_scenario()
|
||||
self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room2.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
|
||||
# ASSERT & ACT
|
||||
with self.assertRaises(UserError):
|
||||
self.env["pms.reservation.split.join.swap.wizard"].reservations_swap(
|
||||
datetime.datetime.now(),
|
||||
datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
self.room1.id,
|
||||
self.room2.id,
|
||||
)
|
||||
|
||||
# SPLIT TESTS
|
||||
def test_split_reservation_check_room_splitted_valid_01(self):
|
||||
# TEST CASE
|
||||
# A reservation is created with preferred room
|
||||
# The room for 1st night is switched to another room
|
||||
# Expected result:
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | room/date | 01 | 02 | 03 | 04 | 05 | 06 |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | Double 101 | | r1 | r1 | | | |
|
||||
# | Double 102 | r1 | | | | | |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
|
||||
# ARRANGE
|
||||
self.create_common_scenario()
|
||||
r1 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room1.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r1.flush()
|
||||
# ACT
|
||||
self.env["pms.reservation.split.join.swap.wizard"].reservation_split(
|
||||
r1, datetime.date.today(), self.room2
|
||||
)
|
||||
# ASSERT
|
||||
self.assertTrue(
|
||||
r1.reservation_line_ids[0].room_id == self.room2
|
||||
and r1.reservation_line_ids[1:].room_id == self.room1
|
||||
)
|
||||
|
||||
def test_split_reservation_check_room_splitted_valid_02(self):
|
||||
# TEST CASE
|
||||
# A reservation is created with preferred room
|
||||
# The room for 1st night is switched to another room
|
||||
# Expected result:
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | room/date | 01 | 02 | 03 | 04 | 05 | 06 |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | Double 101 | r1 | r1 | | | | |
|
||||
# | Double 102 | | | r1 | | | |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
|
||||
# ARRANGE
|
||||
self.create_common_scenario()
|
||||
r1 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room1.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r1.flush()
|
||||
# ACT
|
||||
self.env["pms.reservation.split.join.swap.wizard"].reservation_split(
|
||||
r1,
|
||||
(
|
||||
datetime.datetime(
|
||||
year=datetime.date.today().year,
|
||||
month=datetime.date.today().month,
|
||||
day=datetime.date.today().day,
|
||||
)
|
||||
+ datetime.timedelta(days=2)
|
||||
).date(),
|
||||
self.room2,
|
||||
)
|
||||
# ASSERT
|
||||
self.assertTrue(
|
||||
r1.reservation_line_ids[2].room_id == self.room2
|
||||
and r1.reservation_line_ids[:1].room_id == self.room1
|
||||
)
|
||||
|
||||
def test_split_reservation_check_room_splitted_valid_03(self):
|
||||
# TEST CASE
|
||||
# A reservation is created with preferred room
|
||||
# The room for 1st night is switched to another room
|
||||
# Expected result:
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | room/date | 01 | 02 | 03 | 04 | 05 | 06 |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
# | Double 101 | r1 | | r1 | | | |
|
||||
# | Double 102 | | r1 | | | | |
|
||||
# +------------+------+------+------+----+----+----+
|
||||
|
||||
# ARRANGE
|
||||
self.create_common_scenario()
|
||||
r1 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room1.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r1.flush()
|
||||
# ACT
|
||||
self.env["pms.reservation.split.join.swap.wizard"].reservation_split(
|
||||
r1,
|
||||
(
|
||||
datetime.datetime(
|
||||
year=datetime.date.today().year,
|
||||
month=datetime.date.today().month,
|
||||
day=datetime.date.today().day,
|
||||
)
|
||||
+ datetime.timedelta(days=1)
|
||||
).date(),
|
||||
self.room2,
|
||||
)
|
||||
# ASSERT
|
||||
self.assertTrue(
|
||||
r1.reservation_line_ids[1].room_id == self.room2
|
||||
and r1.reservation_line_ids[0].room_id == self.room1
|
||||
and r1.reservation_line_ids[2].room_id == self.room1
|
||||
)
|
||||
|
||||
def test_split_reservation_check_room_splitted_not_valid_01(self):
|
||||
# TEST CASE
|
||||
# Try to split the reservation for one night
|
||||
# and set with a non valid room
|
||||
|
||||
# ARRANGE
|
||||
self.create_common_scenario()
|
||||
r1 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room1.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r1.flush()
|
||||
room_not_exist = self.room3 = self.env["pms.room"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"name": "Double 103",
|
||||
"room_type_id": self.test_room_type_double.id,
|
||||
"capacity": 2,
|
||||
}
|
||||
)
|
||||
room_not_exist.unlink()
|
||||
# ACT & ASSERT
|
||||
with self.assertRaises(UserError):
|
||||
self.env["pms.reservation.split.join.swap.wizard"].reservation_split(
|
||||
r1, datetime.datetime.now(), room_not_exist
|
||||
)
|
||||
|
||||
def test_split_reservation_check_room_splitted_not_valid_02(self):
|
||||
# TEST CASE
|
||||
# Try to split the reservation for one night
|
||||
# and that night doesn't belong to reservation
|
||||
|
||||
# ARRANGE
|
||||
self.create_common_scenario()
|
||||
r1 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room1.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r1.flush()
|
||||
# ACT & ASSERT
|
||||
with self.assertRaises(UserError):
|
||||
self.env["pms.reservation.split.join.swap.wizard"].reservation_split(
|
||||
r1, datetime.datetime.now() + datetime.timedelta(days=100), self.room2
|
||||
)
|
||||
|
||||
def test_split_reservation_check_room_splitted_not_valid_03(self):
|
||||
# TEST CASE
|
||||
# Try to split the reservation for one night
|
||||
# and the reservation not exists
|
||||
|
||||
# ARRANGE
|
||||
self.create_common_scenario()
|
||||
r1 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room1.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r1.flush()
|
||||
# ACT & ASSERT
|
||||
with self.assertRaises(UserError):
|
||||
self.env["pms.reservation.split.join.swap.wizard"].reservation_split(
|
||||
self.env["pms.reservation"], datetime.datetime.now(), self.room2
|
||||
)
|
||||
|
||||
def test_split_reservation_check_room_splitted_not_valid_04(self):
|
||||
# TEST CASE
|
||||
# Try to split the reservation to one room
|
||||
# and the room is not available
|
||||
|
||||
# ARRANGE
|
||||
self.create_common_scenario()
|
||||
self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room2.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r1 = self.env["pms.reservation"].create(
|
||||
{
|
||||
"pms_property_id": self.test_property.id,
|
||||
"checkin": datetime.datetime.now(),
|
||||
"checkout": datetime.datetime.now() + datetime.timedelta(days=3),
|
||||
"adults": 2,
|
||||
"preferred_room_id": self.room1.id,
|
||||
"partner_id": self.env.ref("base.res_partner_12").id,
|
||||
}
|
||||
)
|
||||
r1.flush()
|
||||
# ACT & ASSERT
|
||||
with self.assertRaises(UserError):
|
||||
self.env["pms.reservation.split.join.swap.wizard"].reservation_split(
|
||||
r1, datetime.datetime.now(), self.room2
|
||||
)
|
||||
@@ -77,15 +77,18 @@
|
||||
style="margin-bottom:0px;"
|
||||
attrs="{'invisible': [('splitted','=',False)]}"
|
||||
>
|
||||
This reservation is part of splitted reservation, you can try to
|
||||
unify the reservation here
|
||||
This reservation is part of a splitted reservation, you can try to
|
||||
join the reservation here
|
||||
<bold>
|
||||
<button
|
||||
class="alert-link"
|
||||
type="object"
|
||||
name="open_reservation_wizard"
|
||||
string="Unify the reservation"
|
||||
string="Join the reservation"
|
||||
context="{'default_operation': 'join'}"
|
||||
/>
|
||||
|
||||
|
||||
</bold>
|
||||
</div>
|
||||
<sheet>
|
||||
@@ -949,4 +952,15 @@
|
||||
sequence="5"
|
||||
parent="pms.menu_reservations"
|
||||
/>
|
||||
|
||||
<record id="action_view_reservation_operations" model="ir.actions.act_window">
|
||||
<field name="name">Reservation operations</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">pms.reservation.split.join.swap.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
<field name="binding_model_id" ref="pms.model_pms_reservation" />
|
||||
<field name="binding_view_types">form</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from . import wizard_reservation
|
||||
from . import wizard_split_join_swap_reservation
|
||||
from . import wizard_massive_changes
|
||||
from . import wizard_advanced_filters
|
||||
from . import wizard_folio
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ReservationWizard(models.TransientModel):
|
||||
_name = "pms.reservation.wizard"
|
||||
allowed_rooms = fields.One2many("pms.room", compute="_compute_allowed_rooms")
|
||||
options = fields.Many2one("pms.room", string="Room")
|
||||
|
||||
def _compute_allowed_rooms(self):
|
||||
for record in self:
|
||||
record.allowed_rooms = self._context.get("rooms_available")
|
||||
|
||||
def unify(self):
|
||||
if self.options:
|
||||
for line in (
|
||||
self.env["pms.reservation"]
|
||||
.search([("id", "=", self._context.get("active_id"))])
|
||||
.reservation_line_ids
|
||||
):
|
||||
line.room_id = self.options
|
||||
@@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" ?>
|
||||
<odoo>
|
||||
<record id="reservation_wizard" model="ir.ui.view">
|
||||
<field name="name">Reservation Wizard</field>
|
||||
<field name="model">pms.reservation.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Choose The Details">
|
||||
<group>
|
||||
<field
|
||||
name="options"
|
||||
string="Suggested rooms to unify the reservation:"
|
||||
options="{'no_create': True,'no_open': True}"
|
||||
required="1"
|
||||
domain="[('id', 'in', allowed_rooms)]"
|
||||
/>
|
||||
<field name="allowed_rooms" invisible="1" />
|
||||
</group>
|
||||
<footer>
|
||||
<button
|
||||
name="unify"
|
||||
string="Unify"
|
||||
type="object"
|
||||
class="oe_highlight"
|
||||
/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
353
pms/wizards/wizard_split_join_swap_reservation.py
Normal file
353
pms/wizards/wizard_split_join_swap_reservation.py
Normal file
@@ -0,0 +1,353 @@
|
||||
import datetime
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class ReservationSplitJoinSwapWizard(models.TransientModel):
|
||||
_name = "pms.reservation.split.join.swap.wizard"
|
||||
operation = fields.Selection(
|
||||
[
|
||||
("swap", "Swap rooms"),
|
||||
("split", "Split reservation"),
|
||||
("join", "Join reservation"),
|
||||
],
|
||||
string="Operation",
|
||||
help="Operation to be applied on the reservation",
|
||||
default=lambda self: self._context.get("default_operation")
|
||||
if self._context.get("default_operation")
|
||||
else "swap",
|
||||
)
|
||||
reservation_id = fields.Many2one(
|
||||
string="Reservation",
|
||||
comodel_name="pms.reservation",
|
||||
default=lambda self: self.env["pms.reservation"]
|
||||
.browse(self._context.get("active_id"))
|
||||
.id
|
||||
if self._context.get("active_id")
|
||||
else False,
|
||||
)
|
||||
checkin = fields.Date(
|
||||
string="Check In",
|
||||
default=lambda self: self.env["pms.reservation"]
|
||||
.browse(self._context.get("active_id"))
|
||||
.checkin
|
||||
if self._context.get("active_id")
|
||||
else False,
|
||||
)
|
||||
checkout = fields.Date(
|
||||
string="Check Out",
|
||||
default=lambda self: self.env["pms.reservation"]
|
||||
.browse(self._context.get("active_id"))
|
||||
.checkout
|
||||
if self._context.get("active_id")
|
||||
else False,
|
||||
)
|
||||
reservations = fields.Many2many(
|
||||
string="Reservations",
|
||||
comodel_name="pms.reservation",
|
||||
compute="_compute_reservations",
|
||||
readonly=False,
|
||||
store=True,
|
||||
)
|
||||
room_source = fields.Many2one(
|
||||
string="Room Source",
|
||||
comodel_name="pms.room",
|
||||
domain="[('id', 'in', allowed_rooms_sources)]",
|
||||
default=lambda self: self.env["pms.reservation"]
|
||||
.browse(self._context.get("active_id"))
|
||||
.preferred_room_id
|
||||
if self._context.get("active_id")
|
||||
and not self.env["pms.reservation"]
|
||||
.browse(self._context.get("active_id"))
|
||||
.splitted
|
||||
else False,
|
||||
)
|
||||
room_target = fields.Many2one(
|
||||
string="Room Target",
|
||||
comodel_name="pms.room",
|
||||
domain="[('id', 'in', allowed_rooms_target)]",
|
||||
)
|
||||
allowed_rooms_sources = fields.Many2many(
|
||||
string="Allowed rooms source",
|
||||
comodel_name="pms.room",
|
||||
relation="pms_wizard_split_join_swap_reservation_rooms_source",
|
||||
column1="wizard_id",
|
||||
column2="room_id",
|
||||
compute="_compute_allowed_rooms_source",
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
allowed_rooms_target = fields.Many2many(
|
||||
string="Allowed rooms target",
|
||||
comodel_name="pms.room",
|
||||
relation="pms_wizard_split_join_swap_reservation_rooms_target",
|
||||
column1="wizard_id",
|
||||
column2="room_id",
|
||||
compute="_compute_allowed_rooms_target",
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
reservation_lines_to_change = fields.One2many(
|
||||
comodel_name="pms.wizard.reservation.lines.split",
|
||||
inverse_name="reservation_wizard_id",
|
||||
compute="_compute_reservation_lines",
|
||||
store=True,
|
||||
readonly=False,
|
||||
)
|
||||
|
||||
@api.depends("checkin", "checkout", "room_source", "room_target")
|
||||
def _compute_reservations(self):
|
||||
for record in self:
|
||||
if record.checkin and record.checkout:
|
||||
reservation_ids = list()
|
||||
for date_iterator in [
|
||||
record.checkin + datetime.timedelta(days=x)
|
||||
for x in range(0, (record.checkout - record.checkin).days)
|
||||
]:
|
||||
domain_lines = []
|
||||
if record.room_source and record.room_target:
|
||||
domain_lines.extend(
|
||||
[
|
||||
"|",
|
||||
("room_id", "=", record.room_source.id),
|
||||
("room_id", "=", record.room_target.id),
|
||||
]
|
||||
)
|
||||
|
||||
domain_lines.append(("date", "=", date_iterator))
|
||||
lines = self.env["pms.reservation.line"].search(domain_lines)
|
||||
reservation_ids.extend(lines.mapped("reservation_id.id"))
|
||||
reservations = (
|
||||
self.env["pms.reservation"]
|
||||
.search(
|
||||
[
|
||||
("id", "in", reservation_ids),
|
||||
("rooms", "!=", False),
|
||||
]
|
||||
)
|
||||
.sorted("rooms")
|
||||
)
|
||||
record.reservations = reservations
|
||||
else:
|
||||
record.reservations = False
|
||||
|
||||
@api.depends("reservation_id")
|
||||
def _compute_reservation_lines(self):
|
||||
for record in self:
|
||||
if record.reservation_id:
|
||||
cmds = [(5, 0, 0)]
|
||||
for line in record.reservation_id.reservation_line_ids:
|
||||
cmds.append(
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"reservation_wizard_id": record.id,
|
||||
"room_id": line.room_id,
|
||||
"date": line.date,
|
||||
},
|
||||
)
|
||||
)
|
||||
record.reservation_lines_to_change = cmds
|
||||
else:
|
||||
record.reservation_lines_to_change = False
|
||||
|
||||
@api.depends("checkin", "checkout")
|
||||
def _compute_allowed_rooms_source(self):
|
||||
for record in self:
|
||||
record.allowed_rooms_sources = (
|
||||
record.reservations.reservation_line_ids.mapped("room_id")
|
||||
)
|
||||
|
||||
@api.depends_context("default_operation")
|
||||
@api.depends("checkin", "checkout", "room_source", "operation")
|
||||
def _compute_allowed_rooms_target(self):
|
||||
for record in self:
|
||||
record.allowed_rooms_target = False
|
||||
record.room_target = False
|
||||
if record.checkin and record.checkout:
|
||||
rooms_available = self.env["pms.availability.plan"].rooms_available(
|
||||
checkin=record.checkin,
|
||||
checkout=record.checkout,
|
||||
room_type_id=False, # Allows to choose any available room
|
||||
current_lines=record.reservation_id.reservation_line_ids.ids,
|
||||
pricelist_id=record.reservation_id.pricelist_id.id,
|
||||
pms_property_id=record.reservation_id.pms_property_id.id,
|
||||
)
|
||||
domain = [("capacity", ">=", record.reservation_id.adults)]
|
||||
if record.room_source:
|
||||
domain.append(("id", "!=", record.room_source.id))
|
||||
|
||||
if record.operation == "swap":
|
||||
domain.append(
|
||||
(
|
||||
"id",
|
||||
"in",
|
||||
record.reservations.reservation_line_ids.mapped(
|
||||
"room_id"
|
||||
).ids,
|
||||
)
|
||||
)
|
||||
else:
|
||||
domain.extend(
|
||||
[
|
||||
("id", "in", rooms_available.ids),
|
||||
]
|
||||
)
|
||||
rooms = self.env["pms.room"].search(domain)
|
||||
record.allowed_rooms_target = rooms
|
||||
|
||||
@api.model
|
||||
def reservation_split(self, reservation, date, room):
|
||||
if not reservation:
|
||||
raise UserError(_("Invalid reservation"))
|
||||
if not reservation or not reservation.reservation_line_ids.filtered(
|
||||
lambda x: x.date == date
|
||||
):
|
||||
raise UserError(_("Invalid date for reservation line "))
|
||||
|
||||
if not self.browse(room.id):
|
||||
raise UserError(_("The room does not exist"))
|
||||
rooms_available = self.env["pms.availability.plan"].rooms_available(
|
||||
checkin=date,
|
||||
checkout=(
|
||||
datetime.datetime(year=date.year, month=date.month, day=date.day)
|
||||
+ datetime.timedelta(days=1)
|
||||
).date(),
|
||||
current_lines=reservation.reservation_line_ids.ids,
|
||||
pricelist_id=reservation.pricelist_id.id,
|
||||
pms_property_id=reservation.pms_property_id.id,
|
||||
)
|
||||
if room not in rooms_available:
|
||||
raise UserError(_("The room is not available"))
|
||||
|
||||
reservation.reservation_line_ids.filtered(
|
||||
lambda x: x.date == date
|
||||
).room_id = room.id
|
||||
|
||||
@api.model
|
||||
def reservation_join(self, reservation, room):
|
||||
rooms_available = self.env["pms.availability.plan"].rooms_available(
|
||||
checkin=reservation.checkin,
|
||||
checkout=reservation.checkout,
|
||||
current_lines=reservation.reservation_line_ids.ids,
|
||||
pricelist_id=reservation.pricelist_id.id,
|
||||
pms_property_id=reservation.pms_property_id.id,
|
||||
)
|
||||
if room in rooms_available:
|
||||
for line in (
|
||||
self.env["pms.reservation"]
|
||||
.search([("id", "=", reservation.id)])
|
||||
.reservation_line_ids
|
||||
):
|
||||
line.room_id = room.id
|
||||
else:
|
||||
raise UserError(_("Room {} not available.".format(room.name)))
|
||||
|
||||
@api.model
|
||||
def reservations_swap(self, checkin, checkout, source, target):
|
||||
reservations = self.env["pms.reservation"].search(
|
||||
[("checkin", ">=", checkin), ("checkout", "<=", checkout)]
|
||||
)
|
||||
lines = self.env["pms.reservation.line"].search_count(
|
||||
[("room_id", "=", source), ("reservation_id", "in", reservations.ids)]
|
||||
)
|
||||
if not lines:
|
||||
raise UserError(_("There's no reservations lines with provided room"))
|
||||
|
||||
for date_iterator in [
|
||||
checkin + datetime.timedelta(days=x)
|
||||
for x in range(0, (checkout - checkin).days)
|
||||
]:
|
||||
line_room_source = self.env["pms.reservation.line"].search(
|
||||
[("date", "=", date_iterator), ("room_id", "=", source)]
|
||||
)
|
||||
line_room_target = self.env["pms.reservation.line"].search(
|
||||
[("date", "=", date_iterator), ("room_id", "=", target)]
|
||||
)
|
||||
if line_room_source and line_room_target:
|
||||
|
||||
# this causes an unique error constraint
|
||||
line_room_target.occupies_availability = False
|
||||
line_room_source.occupies_availability = False
|
||||
|
||||
line_room_target.room_id = source
|
||||
line_room_source.room_id = target
|
||||
|
||||
self.flush()
|
||||
|
||||
line_room_target._compute_occupies_availability()
|
||||
line_room_source._compute_occupies_availability()
|
||||
|
||||
else:
|
||||
line_room_source.room_id = target
|
||||
|
||||
def action_split(self):
|
||||
for record in self:
|
||||
for line in record.reservation_lines_to_change:
|
||||
self.reservation_split(
|
||||
record.reservation_id,
|
||||
line.date,
|
||||
line.room_id,
|
||||
)
|
||||
|
||||
def action_join(self):
|
||||
for record in self:
|
||||
self.reservation_join(record.reservation_id, record.room_target)
|
||||
|
||||
def action_swap(self):
|
||||
self.reservations_swap(
|
||||
self.checkin, self.checkout, self.room_source.id, self.room_target.id
|
||||
)
|
||||
|
||||
|
||||
class ReservationLinesToSplit(models.TransientModel):
|
||||
_name = "pms.wizard.reservation.lines.split"
|
||||
|
||||
reservation_wizard_id = fields.Many2one(
|
||||
comodel_name="pms.reservation.split.join.swap.wizard",
|
||||
)
|
||||
date = fields.Date(
|
||||
string="Date",
|
||||
)
|
||||
room_id = fields.Many2one(
|
||||
string="Room",
|
||||
comodel_name="pms.room",
|
||||
domain="[('id', 'in', allowed_room_ids)]",
|
||||
)
|
||||
allowed_room_ids = fields.Many2many(
|
||||
string="Allowed Rooms",
|
||||
help="It contains all available rooms for this line",
|
||||
comodel_name="pms.room",
|
||||
compute="_compute_allowed_room_ids",
|
||||
store=True,
|
||||
# readonly=False
|
||||
)
|
||||
|
||||
@api.depends(
|
||||
"date",
|
||||
"room_id",
|
||||
"reservation_wizard_id.reservation_id.pricelist_id",
|
||||
)
|
||||
def _compute_allowed_room_ids(self):
|
||||
for line in self:
|
||||
reservation = line.reservation_wizard_id.reservation_id
|
||||
rooms_available = False
|
||||
if line.date and reservation:
|
||||
if reservation.overbooking or reservation.state in ("cancelled"):
|
||||
line.allowed_room_ids = self.env["pms.room"].search(
|
||||
[("active", "=", True)]
|
||||
)
|
||||
return
|
||||
rooms_available = self.env["pms.availability.plan"].rooms_available(
|
||||
checkin=line.date,
|
||||
checkout=line.date + datetime.timedelta(days=1),
|
||||
room_type_id=False, # Allows to choose any available room
|
||||
pricelist_id=reservation.pricelist_id.id,
|
||||
pms_property_id=reservation.pms_property_id.id,
|
||||
)
|
||||
rooms_available += line.room_id
|
||||
line.allowed_room_ids = rooms_available
|
||||
else:
|
||||
line.allowed_room_ids = False
|
||||
127
pms/wizards/wizard_split_join_swap_reservation.xml
Normal file
127
pms/wizards/wizard_split_join_swap_reservation.xml
Normal file
@@ -0,0 +1,127 @@
|
||||
<?xml version="1.0" ?>
|
||||
<odoo>
|
||||
<record id="reservation_wizard" model="ir.ui.view">
|
||||
<field name="name">Split, join or swap reservations</field>
|
||||
<field name="model">pms.reservation.split.join.swap.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<div class="row">
|
||||
<div class="col-3">
|
||||
<label for="operation" class="font-weight-bold" />
|
||||
<br />
|
||||
<field name="operation" widget="radio" />
|
||||
<field name="allowed_rooms_sources" invisible="1" />
|
||||
<field name="allowed_rooms_target" invisible="1" />
|
||||
</div>
|
||||
<div class="col-5">
|
||||
<span attrs="{'invisible': [('operation','=','swap')]}">
|
||||
<label for="reservation_id" /> <br />
|
||||
<field name="reservation_id" readonly="1" /><br />
|
||||
</span>
|
||||
<span attrs="{'invisible': [('operation','!=','swap')]}">
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<label for="checkin" /> <br />
|
||||
<field
|
||||
name="checkin"
|
||||
widget="daterange"
|
||||
options="{'related_end_date': 'checkout'}"
|
||||
/><br />
|
||||
<label for="checkout" /> <br />
|
||||
<field
|
||||
name="checkout"
|
||||
widget="daterange"
|
||||
options="{'related_start_date': 'checkin'}"
|
||||
/><br />
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<div>
|
||||
<span attrs="{'invisible': [('operation','!=','swap')]}">
|
||||
<label for="room_source" />
|
||||
<br />
|
||||
<field name="room_source" />
|
||||
<br />
|
||||
</span>
|
||||
<label
|
||||
attrs="{'invisible': [('operation','!=','swap')]}"
|
||||
for="room_target"
|
||||
/>
|
||||
<label
|
||||
attrs="{'invisible': [('operation','!=','join')]}"
|
||||
for="room_target"
|
||||
string="Room"
|
||||
/>
|
||||
<br />
|
||||
<field
|
||||
name="room_target"
|
||||
attrs="{'invisible': [('operation','=','split')]}"
|
||||
/>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="col-12"
|
||||
attrs="{'invisible': [('operation','!=','swap')]}"
|
||||
>
|
||||
<field name="reservations" nolabel="1" readonly="1">
|
||||
<tree>
|
||||
<field string="Reservation" name="name" />
|
||||
<field name="checkin" />
|
||||
<field name="checkout" />
|
||||
<field name="rooms" />
|
||||
</tree>
|
||||
</field>
|
||||
</div>
|
||||
<div
|
||||
class="col-12"
|
||||
attrs="{'invisible': [('operation','!=','split')]}"
|
||||
>
|
||||
<field
|
||||
name="reservation_lines_to_change"
|
||||
nolabel="1"
|
||||
default_order="rooms"
|
||||
>
|
||||
<tree editable="bottom" create="false" delete="false">
|
||||
<field name="reservation_wizard_id" invisible="1" />
|
||||
<field name="allowed_room_ids" invisible="1" />
|
||||
<field name="date" readonly="0" />
|
||||
<field
|
||||
name="room_id"
|
||||
domain="[('id', 'in', allowed_room_ids)]"
|
||||
/>
|
||||
</tree>
|
||||
</field>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="text-right">
|
||||
<button string="Cancel" class="oe_link border" special="cancel" />
|
||||
or
|
||||
<button
|
||||
name="action_join"
|
||||
attrs="{'invisible': [('operation','!=','join')]}"
|
||||
string="Join reservation"
|
||||
type="object"
|
||||
class="oe_highlight"
|
||||
/>
|
||||
<button
|
||||
name="action_split"
|
||||
attrs="{'invisible': [('operation','!=','split')]}"
|
||||
string="Split reservation"
|
||||
type="object"
|
||||
class="oe_highlight"
|
||||
/>
|
||||
<button
|
||||
name="action_swap"
|
||||
attrs="{'invisible': [('operation','!=','swap')]}"
|
||||
string="Swap reservation rooms"
|
||||
type="object"
|
||||
class="oe_highlight"
|
||||
/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user