Merge PR #52 into 14.0

Signed-off-by DarioLodeiros
This commit is contained in:
OCA-git-bot
2021-08-13 07:33:35 +00:00
9 changed files with 751 additions and 80 deletions

View File

@@ -604,16 +604,20 @@ class PmsFolio(models.Model):
) )
def _compute_sale_line_ids(self): def _compute_sale_line_ids(self):
for folio in self: for folio in self:
for reservation in folio.reservation_ids: if folio.reservation_type == "normal":
# RESERVATION LINES for reservation in folio.reservation_ids:
# res = self.env['pms.reservation'].browse(reservation.id) # RESERVATION LINES
self.generate_reservation_lines_sale_lines(folio, reservation) # res = self.env['pms.reservation'].browse(reservation.id)
self.generate_reservation_lines_sale_lines(folio, reservation)
# RESERVATION SERVICES # RESERVATION SERVICES
self.generate_reservation_services_sale_lines(folio, reservation) self.generate_reservation_services_sale_lines(folio, reservation)
# FOLIO SERVICES # FOLIO SERVICES
self.generate_folio_services_sale_lines(folio) self.generate_folio_services_sale_lines(folio)
else:
for reservation in folio.reservation_ids:
reservation.sale_line_ids = False
@api.depends("pms_property_id") @api.depends("pms_property_id")
def _compute_company_id(self): def _compute_company_id(self):
@@ -765,7 +769,7 @@ class PmsFolio(models.Model):
else: else:
order.invoice_status = "no" order.invoice_status = "no"
@api.depends("partner_id", "partner_id.name", "agency_id") @api.depends("partner_id", "partner_id.name", "agency_id", "reservation_type")
def _compute_partner_name(self): def _compute_partner_name(self):
for record in self: for record in self:
self._apply_partner_name(record) self._apply_partner_name(record)
@@ -841,22 +845,24 @@ class PmsFolio(models.Model):
@api.depends("checkin_partner_ids", "checkin_partner_ids.state") @api.depends("checkin_partner_ids", "checkin_partner_ids.state")
def _compute_pending_checkin_data(self): def _compute_pending_checkin_data(self):
for folio in self: for folio in self:
folio.pending_checkin_data = len( if folio.reservation_type != "out":
folio.checkin_partner_ids.filtered(lambda c: c.state == "draft") folio.pending_checkin_data = len(
) folio.checkin_partner_ids.filtered(lambda c: c.state == "draft")
)
@api.depends("pending_checkin_data") @api.depends("pending_checkin_data")
def _compute_ratio_checkin_data(self): def _compute_ratio_checkin_data(self):
self.ratio_checkin_data = 0 self.ratio_checkin_data = 0
for folio in self.filtered("reservation_ids"): for folio in self.filtered("reservation_ids"):
folio.ratio_checkin_data = ( if folio.reservation_type != "out":
( folio.ratio_checkin_data = (
sum(folio.reservation_ids.mapped("adults")) (
- folio.pending_checkin_data sum(folio.reservation_ids.mapped("adults"))
- folio.pending_checkin_data
)
* 100
/ sum(folio.reservation_ids.mapped("adults"))
) )
* 100
/ sum(folio.reservation_ids.mapped("adults"))
)
# TODO: Add return_ids to depends # TODO: Add return_ids to depends
@api.depends( @api.depends(
@@ -871,7 +877,9 @@ class PmsFolio(models.Model):
def _compute_amount(self): def _compute_amount(self):
for record in self: for record in self:
if record.reservation_type in ("staff", "out"): if record.reservation_type in ("staff", "out"):
record.amount_total = 0
vals = { vals = {
"payment_state": False,
"pending_amount": 0, "pending_amount": 0,
"invoices_paid": 0, "invoices_paid": 0,
} }

View File

@@ -342,9 +342,10 @@ class PmsReservation(models.Model):
reservation_type = fields.Selection( reservation_type = fields.Selection(
string="Reservation Type", string="Reservation Type",
help="Type of reservations. It can be 'normal', 'staff' or 'out of service", help="Type of reservations. It can be 'normal', 'staff' or 'out of service",
related="folio_id.reservation_type",
store=True, store=True,
readonly=False, readonly=False,
compute="_compute_reservation_type",
selection=[("normal", "Normal"), ("staff", "Staff"), ("out", "Out of Service")],
) )
splitted = fields.Boolean( splitted = fields.Boolean(
string="Splitted", string="Splitted",
@@ -867,7 +868,7 @@ class PmsReservation(models.Model):
for reservation in self: for reservation in self:
if reservation.reservation_type in ("out", "staff"): if reservation.reservation_type in ("out", "staff"):
reservation.pricelist_id = False reservation.pricelist_id = False
if reservation.agency_id and reservation.agency_id.apply_pricelist: elif reservation.agency_id and reservation.agency_id.apply_pricelist:
reservation.pricelist_id = ( reservation.pricelist_id = (
reservation.agency_id.property_product_pricelist reservation.agency_id.property_product_pricelist
) )
@@ -986,7 +987,8 @@ class PmsReservation(models.Model):
record.allowed_checkin = ( record.allowed_checkin = (
True True
if ( if (
record.state in ["draft", "confirm", "arrival_delayed"] record.reservation_type != "out"
and record.state in ["draft", "confirm", "arrival_delayed"]
and record.checkin <= fields.Date.today() and record.checkin <= fields.Date.today()
) )
else False else False
@@ -1133,13 +1135,13 @@ class PmsReservation(models.Model):
reservation.commission_amount = 0 reservation.commission_amount = 0
# REVIEW: Dont run with set room_type_id -> room_id(compute)-> No set adults¿? # REVIEW: Dont run with set room_type_id -> room_id(compute)-> No set adults¿?
@api.depends("preferred_room_id") @api.depends("preferred_room_id", "reservation_type")
def _compute_adults(self): def _compute_adults(self):
for reservation in self: for reservation in self:
if reservation.preferred_room_id: if reservation.preferred_room_id and reservation.reservation_type != "out":
if reservation.adults == 0: if reservation.adults == 0:
reservation.adults = reservation.preferred_room_id.capacity reservation.adults = reservation.preferred_room_id.capacity
elif not reservation.adults: elif not reservation.adults or reservation.reservation_type == "out":
reservation.adults = 0 reservation.adults = 0
@api.depends("reservation_line_ids", "reservation_line_ids.room_id") @api.depends("reservation_line_ids", "reservation_line_ids.room_id")
@@ -1177,6 +1179,8 @@ class PmsReservation(models.Model):
line.invoice_status = "no" line.invoice_status = "no"
else: else:
line.invoice_status = "no" line.invoice_status = "no"
if line.reservation_type != "normal":
line.invoice_status = "no"
@api.depends("reservation_line_ids") @api.depends("reservation_line_ids")
def _compute_nights(self): def _compute_nights(self):
@@ -1262,10 +1266,19 @@ class PmsReservation(models.Model):
else: else:
record.shared_folio = False record.shared_folio = False
@api.depends("partner_id", "partner_id.name", "agency_id") @api.depends(
"partner_id",
"partner_id.name",
"agency_id",
"reservation_type",
"out_service_description",
)
def _compute_partner_name(self): def _compute_partner_name(self):
for record in self: for record in self:
self.env["pms.folio"]._apply_partner_name(record) if record.reservation_type != "out":
self.env["pms.folio"]._apply_partner_name(record)
else:
record.partner_name = record.out_service_description
@api.depends("partner_id", "partner_id.email", "agency_id") @api.depends("partner_id", "partner_id.email", "agency_id")
def _compute_email(self): def _compute_email(self):
@@ -1340,6 +1353,14 @@ class PmsReservation(models.Model):
else: else:
reservation.rooms = reservation.preferred_room_id.name reservation.rooms = reservation.preferred_room_id.name
@api.depends("folio_id", "folio_id.reservation_type")
def _compute_reservation_type(self):
for record in self:
if record.folio_id:
record.reservation_type = record.folio_id.reservation_type
else:
record.reservation_type = "normal"
def _search_allowed_checkin(self, operator, value): def _search_allowed_checkin(self, operator, value):
if operator not in ("=",): if operator not in ("=",):
raise UserError( raise UserError(
@@ -1451,6 +1472,7 @@ class PmsReservation(models.Model):
if ( if (
not record.checkin_partner_ids.filtered(lambda c: c.state == "onboard") not record.checkin_partner_ids.filtered(lambda c: c.state == "onboard")
and record.state == "onboard" and record.state == "onboard"
and record.reservation_type != "out"
): ):
raise ValidationError( raise ValidationError(
_("No person from reserve %s has arrived", record.name) _("No person from reserve %s has arrived", record.name)
@@ -1496,6 +1518,19 @@ class PmsReservation(models.Model):
record, record.service_ids.service_line_ids record, record.service_ids.service_line_ids
) )
@api.constrains("reservation_type")
def _check_same_reservation_type(self):
for record in self:
if len(record.folio_id.reservation_ids) > 1:
for reservation in record.folio_id.reservation_ids:
if reservation.reservation_type != record.reservation_type:
raise ValidationError(
_(
"The reservation type must be the "
"same for all reservations in folio"
)
)
# Action methods # Action methods
def open_partner(self): def open_partner(self):
""" Utility method used to add an "View Customer" button in reservation views """ """ Utility method used to add an "View Customer" button in reservation views """
@@ -1618,6 +1653,8 @@ class PmsReservation(models.Model):
raise ValidationError(_("Partner contact name is required")) raise ValidationError(_("Partner contact name is required"))
# Create the folio in case of need # Create the folio in case of need
# (To allow to create reservations direct) # (To allow to create reservations direct)
if vals.get("reservation_type"):
folio_vals["reservation_type"] = vals.get("reservation_type")
folio = self.env["pms.folio"].create(folio_vals) folio = self.env["pms.folio"].create(folio_vals)
vals.update( vals.update(
{ {

View File

@@ -353,6 +353,7 @@ class PmsReservationLine(models.Model):
not reservation.room_type_id not reservation.room_type_id
or not reservation.pricelist_id or not reservation.pricelist_id
or not reservation.pms_property_id or not reservation.pms_property_id
or reservation.reservation_type != "normal"
): ):
line.price = 0 line.price = 0
elif not line.price or self._context.get("force_recompute"): elif not line.price or self._context.get("force_recompute"):

View File

@@ -547,35 +547,38 @@ class PmsService(models.Model):
def _get_price_unit_line(self, date=False): def _get_price_unit_line(self, date=False):
self.ensure_one() self.ensure_one()
folio = self.folio_id if self.reservation_id.reservation_type == "normal":
reservation = self.reservation_id folio = self.folio_id
origin = reservation if reservation else folio reservation = self.reservation_id
if origin: origin = reservation if reservation else folio
partner = origin.partner_id if origin:
pricelist = origin.pricelist_id partner = origin.partner_id
board_room_type = False pricelist = origin.pricelist_id
product_context = dict( board_room_type = False
self.env.context, product_context = dict(
lang=partner.lang, self.env.context,
partner=partner.id, lang=partner.lang,
quantity=self.product_qty, partner=partner.id,
date=folio.date_order if folio else fields.Date.today(), quantity=self.product_qty,
pricelist=pricelist.id, date=folio.date_order if folio else fields.Date.today(),
board_service=board_room_type.id if board_room_type else False, pricelist=pricelist.id,
uom=self.product_id.uom_id.id, board_service=board_room_type.id if board_room_type else False,
fiscal_position=False, uom=self.product_id.uom_id.id,
property=self.reservation_id.pms_property_id.id, fiscal_position=False,
) property=self.reservation_id.pms_property_id.id,
if date: )
product_context["consumption_date"] = date if date:
if reservation and self.is_board_service: product_context["consumption_date"] = date
product_context["board_service"] = reservation.board_service_room_id.id if reservation and self.is_board_service:
product = self.product_id.with_context(product_context) product_context[
return self.env["account.tax"]._fix_tax_included_price_company( "board_service"
self._get_display_price(product), ] = reservation.board_service_room_id.id
product.taxes_id, product = self.product_id.with_context(product_context)
self.tax_ids, return self.env["account.tax"]._fix_tax_included_price_company(
origin.company_id, self._get_display_price(product),
) product.taxes_id,
else: self.tax_ids,
return 0 origin.company_id,
)
else:
return 0

View File

@@ -3,6 +3,7 @@ import datetime
from freezegun import freeze_time from freezegun import freeze_time
from odoo import fields from odoo import fields
from odoo.exceptions import ValidationError
from .common import TestPms from .common import TestPms
@@ -333,3 +334,227 @@ class TestPmsFolio(TestPms):
"The pending amount on a partially paid folio it \ "The pending amount on a partially paid folio it \
does not correspond to the amount that it should", does not correspond to the amount that it should",
) )
def test_reservation_type_folio(self):
"""
Check that the reservation_type of a folio with
a reservation with the default reservation_type is equal
to 'normal'.
---------------
A folio is created. A reservation is created to which the
value of the folio_id is the id of the previously created
folio. Then it is verified that the value of the reservation_type
field of the folio is 'normal'.
"""
# ARRANGE AND ACT
self.partner1 = self.env["res.partner"].create({"name": "Ana"})
folio1 = self.env["pms.folio"].create(
{
"pms_property_id": self.pms_property1.id,
"partner_id": self.partner1.id,
}
)
self.env["pms.reservation"].create(
{
"room_type_id": self.room_type_double.id,
"checkin": fields.date.today(),
"checkout": fields.date.today() + datetime.timedelta(days=1),
"folio_id": folio1.id,
}
)
# ASSERT
self.assertEqual(
folio1.reservation_type,
"normal",
"The default reservation type of the folio should be 'normal'",
)
def test_invoice_status_staff_reservation(self):
"""
Check that the value of the invoice_status field is 'no'
on a page with reservation_type equal to 'staff'.
------------
A reservation is created with the reservation_type field
equal to 'staff'. Then it is verified that the value of
the invoice_status field of the folio created with the
reservation is equal to 'no'.
"""
# ARRANGE
checkin = fields.date.today()
checkout = fields.date.today() + datetime.timedelta(days=3)
self.partner1 = self.env["res.partner"].create({"name": "Pedro"})
# ACT
reservation = self.env["pms.reservation"].create(
{
"checkin": checkin,
"checkout": checkout,
"room_type_id": self.room_type_double.id,
"partner_id": self.partner1.id,
"pms_property_id": self.pms_property1.id,
"pricelist_id": self.pricelist1.id,
"reservation_type": "staff",
}
)
# ASSERT
self.assertEqual(
reservation.folio_id.invoice_status,
"no",
"The invoice status of the folio in a staff reservation should be 'no' ",
)
def test_invoice_status_out_reservation(self):
"""
Check that the value of the invoice_status field is 'no'
on a page with reservation_type equal to 'out'.
------------
A reservation is created with the reservation_type field
equal to 'out'. Then it is verified that the value of
the invoice_status field of the folio created with the
reservation is equal to 'no'.
"""
# ARRANGE
checkin = fields.date.today()
checkout = fields.date.today() + datetime.timedelta(days=3)
self.partner1 = self.env["res.partner"].create({"name": "Pedro"})
# ACT
reservation = self.env["pms.reservation"].create(
{
"checkin": checkin,
"checkout": checkout,
"room_type_id": self.room_type_double.id,
"partner_id": self.partner1.id,
"pms_property_id": self.pms_property1.id,
"pricelist_id": self.pricelist1.id,
"reservation_type": "out",
}
)
# ASSERT
self.assertEqual(
reservation.folio_id.invoice_status,
"no",
"The invoice status of the folio in a out reservation should be 'no' ",
)
def test_amount_total_staff_reservation(self):
"""
Check that the amount_total field of the folio whose
reservation has the reservation_type field as staff
is not calculated.
-------------------------
A folio is created. A reservation is created to which the
value of the folio_id is the id of the previously created
folio and the field reservation_type equal to 'staff'. Then
it is verified that the value of the amount_total field of
the folio is 0.
"""
# ARRANGE
checkin = fields.date.today()
checkout = fields.date.today() + datetime.timedelta(days=3)
self.partner1 = self.env["res.partner"].create({"name": "Pedro"})
# ACT
folio1 = self.env["pms.folio"].create(
{
"pms_property_id": self.pms_property1.id,
"partner_id": self.partner1.id,
}
)
self.env["pms.reservation"].create(
{
"room_type_id": self.room_type_double.id,
"checkin": checkin,
"checkout": checkout,
"folio_id": folio1.id,
"reservation_type": "staff",
}
)
# ASSERT
self.assertEqual(
folio1.amount_total,
0.0,
"The amount total of the folio in a staff reservation should be 0",
)
def test_amount_total_out_reservation(self):
"""
Check that the amount_total field of the folio whose
reservation has the reservation_type field as out
is not calculated.
-------------------------
A folio is created. A reservation is created to which the
value of the folio_id is the id of the previously created
folio and the field reservation_type equal to 'out'. Then
it is verified that the value of the amount_total field of
the folio is 0.
"""
# ARRANGE
checkin = fields.date.today()
checkout = fields.date.today() + datetime.timedelta(days=3)
self.partner1 = self.env["res.partner"].create({"name": "Pedro"})
# ACT
folio1 = self.env["pms.folio"].create(
{
"pms_property_id": self.pms_property1.id,
"partner_id": self.partner1.id,
}
)
self.env["pms.reservation"].create(
{
"room_type_id": self.room_type_double.id,
"checkin": checkin,
"checkout": checkout,
"folio_id": folio1.id,
"reservation_type": "out",
}
)
# ASSERT
self.assertEqual(
folio1.amount_total,
0.0,
"The amount total of the folio in a out of service reservation should be 0",
)
def test_reservation_type_incongruence(self):
"""
Check that a reservation cannot be created
with the reservation_type field different from the
reservation_type of its folio.
-------------
A folio is created. A reservation is created to which the
value of the folio_id is the id of the previously created
folio and the field reservation_type by default('normal').
Then it is tried to create another reservation with its
reservation_type equal to 'staff'. But it should throw an
error because the value of the reservation_type of the
folio is equal to 'normal'.
"""
self.partner1 = self.env["res.partner"].create({"name": "Ana"})
folio1 = self.env["pms.folio"].create(
{
"pms_property_id": self.pms_property1.id,
"partner_id": self.partner1.id,
}
)
self.env["pms.reservation"].create(
{
"room_type_id": self.room_type_double.id,
"checkin": fields.date.today(),
"checkout": fields.date.today() + datetime.timedelta(days=3),
"folio_id": folio1.id,
}
)
with self.assertRaises(
ValidationError,
msg="You cannot create reservations with different reservation_type for a folio",
):
self.env["pms.reservation"].create(
{
"room_type_id": self.room_type_double.id,
"checkin": fields.date.today(),
"checkout": fields.date.today() + datetime.timedelta(days=3),
"folio_id": folio1.id,
"reservation_type": "staff",
}
)

View File

@@ -31,6 +31,14 @@ class TestPmsFolioSaleLine(TestPms):
"capacity": 2, "capacity": 2,
} }
) )
self.room2 = self.env["pms.room"].create(
{
"pms_property_id": self.pms_property1.id,
"name": "Double 102",
"room_type_id": self.room_type_double.id,
"capacity": 2,
}
)
self.product_test1 = self.env["product.product"].create( self.product_test1 = self.env["product.product"].create(
{ {
@@ -1179,3 +1187,67 @@ class TestPmsFolioSaleLine(TestPms):
expected_folio_service_sale_lines expected_folio_service_sale_lines
), ),
) )
def test_no_sale_lines_staff_reservation(self):
"""
Check that the sale_line_ids of a folio whose reservation
is of type 'staff' are not created.
-----
A reservation is created with the reservation_type field
with value 'staff'. Then it is verified that the
sale_line_ids of the folio created with the creation of
the reservation are equal to False.
"""
# ARRANGE
self.partner1 = self.env["res.partner"].create({"name": "Alberto"})
checkin = fields.date.today()
checkout = fields.date.today() + datetime.timedelta(days=3)
# ACT
reservation = self.env["pms.reservation"].create(
{
"checkin": checkin,
"checkout": checkout,
"room_type_id": self.room_type_double.id,
"partner_id": self.partner1.id,
"pms_property_id": self.pms_property1.id,
"pricelist_id": self.pricelist1.id,
"reservation_type": "staff",
}
)
# ASSERT
self.assertFalse(
reservation.folio_id.sale_line_ids,
"Folio sale lines should not be generated for a staff type reservation ",
)
def test_no_sale_lines_out_reservation(self):
"""
Check that the sale_line_ids of a folio whose reservation
is of type 'out' are not created.
-----
A reservation is created with the reservation_type field
with value 'out'. Then it is verified that the
sale_line_ids of the folio created with the creation of
the reservation are equal to False.
"""
# ARRANGE
self.partner1 = self.env["res.partner"].create({"name": "Alberto"})
checkin = fields.date.today()
checkout = fields.date.today() + datetime.timedelta(days=3)
# ACT
reservation = self.env["pms.reservation"].create(
{
"checkin": checkin,
"checkout": checkout,
"room_type_id": self.room_type_double.id,
"partner_id": self.partner1.id,
"pms_property_id": self.pms_property1.id,
"pricelist_id": self.pricelist1.id,
"reservation_type": "out",
}
)
# ASSERT
self.assertFalse(
reservation.folio_id.sale_line_ids,
"Folio sale lines should not be generated for a out of service type reservation ",
)

View File

@@ -46,6 +46,7 @@ class TestPmsReservations(TestPms):
"name": "Double 102", "name": "Double 102",
"room_type_id": self.room_type_double.id, "room_type_id": self.room_type_double.id,
"capacity": 2, "capacity": 2,
"extra_beds_allowed": 1,
} }
) )
@@ -55,6 +56,7 @@ class TestPmsReservations(TestPms):
"name": "Double 103", "name": "Double 103",
"room_type_id": self.room_type_double.id, "room_type_id": self.room_type_double.id,
"capacity": 2, "capacity": 2,
"extra_beds_allowed": 1,
} }
) )
self.partner1 = self.env["res.partner"].create( self.partner1 = self.env["res.partner"].create(
@@ -2902,3 +2904,258 @@ class TestPmsReservations(TestPms):
reservation.discount, reservation.discount,
"Room discount isn't the expected", "Room discount isn't the expected",
) )
def test_default_normal_reservation_type(self):
"""
Check that the default reservation type is "normal".
-----------
A reservation is created without defining the reservation_type
field and it is checked that it is 'normal'
"""
# ARRANGE
checkin = fields.date.today()
checkout = fields.date.today() + datetime.timedelta(days=3)
self.partner1 = self.env["res.partner"].create({"name": "Ana"})
folio1 = self.env["pms.folio"].create(
{
"pms_property_id": self.pms_property1.id,
"partner_id": self.partner1.id,
}
)
# ACT
self.room_type_double.write({"list_price": 30})
reservation = self.env["pms.reservation"].create(
{
"checkin": checkin,
"checkout": checkout,
"room_type_id": self.room_type_double.id,
"partner_id": self.partner1.id,
"pms_property_id": self.pms_property1.id,
"pricelist_id": self.pricelist1.id,
"folio_id": folio1.id,
}
)
# ASSERT
self.assertEqual(
reservation.reservation_type,
"normal",
"The default reservation type should be 'normal'",
)
def test_price_normal_reservation(self):
"""
Check the price of a normal type reservation.
-----------
A reservation is created for a room with price 30.
Then it is verified that the total price of the
reservation is equal to the price of the room multiplied
by the number of days of the reservation.
"""
# ARRANGE
checkin = fields.date.today()
checkout = fields.date.today() + datetime.timedelta(days=3)
# ACT
self.room_type_double.write({"list_price": 30})
reservation = self.env["pms.reservation"].create(
{
"checkin": checkin,
"checkout": checkout,
"room_type_id": self.room_type_double.id,
"partner_id": self.partner1.id,
"pms_property_id": self.pms_property1.id,
"pricelist_id": self.pricelist1.id,
}
)
diff_days = (checkout - checkin).days
expected_price = self.room_type_double.list_price * diff_days
# ASSERT
self.assertEqual(
reservation.price_total,
expected_price,
"The expected price of the reservation is not correct",
)
def test_price_staff_reservation(self):
"""
Check that the price of a staff type reservation
is not calculated.
-------------
A reservation is created with the reservation_type field as 'staff'.
Then it is verified that the price of the reservation is equal to 0.
"""
# ARRANGE
checkin = fields.date.today()
checkout = fields.date.today() + datetime.timedelta(days=3)
# ACT
self.room_type_double.write({"list_price": 30})
reservation = self.env["pms.reservation"].create(
{
"checkin": checkin,
"checkout": checkout,
"room_type_id": self.room_type_double.id,
"partner_id": self.partner1.id,
"pms_property_id": self.pms_property1.id,
"pricelist_id": self.pricelist1.id,
"reservation_type": "staff",
}
)
# ASSERT
self.assertEqual(
reservation.price_total,
0.0,
"The expected price of the reservation is not correct",
)
def test_price_out_of_service_reservation(self):
"""
Check that the price of a out type reservation
is not calculated.
-------------
A reservation is created with the reservation_type field as 'out'.
Then it is verified that the price of the reservation is equal to 0.
"""
# ARRANGE
checkin = fields.date.today()
checkout = fields.date.today() + datetime.timedelta(days=3)
# ACT
self.room_type_double.write({"list_price": 30})
reservation = self.env["pms.reservation"].create(
{
"checkin": checkin,
"checkout": checkout,
"room_type_id": self.room_type_double.id,
"partner_id": self.partner1.id,
"pms_property_id": self.pms_property1.id,
"pricelist_id": self.pricelist1.id,
"reservation_type": "out",
}
)
# ASSERT
self.assertEqual(
reservation.price_total,
0.0,
"The expected price of the reservation is not correct",
)
def test_no_pricelist_staff_reservation(self):
"""
Check that in a staff type reservation the pricelist is False.
-------------
A reservation is created with the reservation_type field as 'staff'.
Then it is verified that the pricelist of the reservation is False.
"""
# ARRANGE
checkin = fields.date.today()
checkout = fields.date.today() + datetime.timedelta(days=3)
# ACT
reservation = self.env["pms.reservation"].create(
{
"checkin": checkin,
"checkout": checkout,
"room_type_id": self.room_type_double.id,
"partner_id": self.partner1.id,
"pms_property_id": self.pms_property1.id,
"reservation_type": "staff",
}
)
self.assertFalse(
reservation.pricelist_id,
"The pricelist of a staff reservation should be False",
)
def test_no_pricelist_out_reservation(self):
"""
Check that in a out type reservation the pricelist is False.
-------------
A reservation is created with the reservation_type field as 'out'.
Then it is verified that the pricelist of the reservation is False.
"""
# ARRANGE
checkin = fields.date.today()
checkout = fields.date.today() + datetime.timedelta(days=3)
# ACT
self.room_type_double.write({"list_price": 30})
reservation = self.env["pms.reservation"].create(
{
"checkin": checkin,
"checkout": checkout,
"room_type_id": self.room_type_double.id,
"partner_id": self.partner1.id,
"pms_property_id": self.pms_property1.id,
"reservation_type": "out",
}
)
self.assertFalse(
reservation.pricelist_id,
"The pricelist of a out of service reservation should be False",
)
def test_reservation_type_by_folio(self):
"""
Check that the reservation type field in a reservation is the
same as the reservation type on the folio that contains
that reservation.
--------------------------
A folio is created with the field reservation_type as 'staff'.
A reservation is created to which the
value of the folio_id is the id of the previously created
folio. Then it is verified that the value of the reservation_type
field of the reservation is the same that reservation_type in the folio:
'staff'.
"""
# ARRANGE AND ACT
self.partner1 = self.env["res.partner"].create({"name": "Ana"})
folio1 = self.env["pms.folio"].create(
{
"pms_property_id": self.pms_property1.id,
"partner_id": self.partner1.id,
"reservation_type": "staff",
}
)
reservation1 = self.env["pms.reservation"].create(
{
"room_type_id": self.room_type_double.id,
"checkin": fields.date.today(),
"checkout": fields.date.today() + datetime.timedelta(days=1),
"folio_id": folio1.id,
}
)
# ASSERT
self.assertEqual(
reservation1.reservation_type,
"staff",
"The reservation type of the folio should be 'staff'",
)
def test_no_partner_id_out_reservation(self):
"""
Check that a reservation of type out of service does not
have a partner_id.
------------------
A reservation is created without a partner_id and with the
value of the field reservation_type as '' out. Then it is
checked that the partner_id field of the reservation is False
"""
# ARRANGE
checkin = fields.date.today()
checkout = fields.date.today() + datetime.timedelta(days=3)
# ACT
reservation = self.env["pms.reservation"].create(
{
"checkin": checkin,
"checkout": checkout,
"room_type_id": self.room_type_double.id,
"pms_property_id": self.pms_property1.id,
"reservation_type": "out",
"partner_name": "Install furniture",
}
)
self.assertFalse(
reservation.partner_id,
"The partner of an out of service reservation should be False",
)

View File

@@ -123,6 +123,7 @@
type="object" type="object"
class="oe_stat_button" class="oe_stat_button"
name="action_checks" name="action_checks"
attrs="{'invisible': [('reservation_type', 'in', 'out')]}"
> >
<field <field
name="ratio_checkin_data" name="ratio_checkin_data"
@@ -148,6 +149,7 @@
type="object" type="object"
class="oe_stat_button" class="oe_stat_button"
icon="fa-magic" icon="fa-magic"
attrs="{'invisible': [('reservation_type', 'not in', 'normal')]}"
> >
<span class="o_stat_text">Change in Group</span> <span class="o_stat_text">Change in Group</span>
</button> </button>
@@ -165,6 +167,7 @@
type="object" type="object"
class="oe_stat_button" class="oe_stat_button"
icon="fa-globe icon" icon="fa-globe icon"
attrs="{'invisible': [('reservation_type', '!=', 'normal')]}"
> >
<div class="o_field_widget o_stat_info"> <div class="o_field_widget o_stat_info">
<span class="o_stat_text">Customer</span> <span class="o_stat_text">Customer</span>
@@ -183,6 +186,19 @@
bg_color="bg-warning" bg_color="bg-warning"
attrs="{'invisible': [('payment_state', '!=', 'partial')]}" attrs="{'invisible': [('payment_state', '!=', 'partial')]}"
/> />
<widget
name="web_ribbon"
title="Staff"
bg_color="bg-info"
attrs="{'invisible': [('reservation_type', 'not in', 'staff')]}"
/>
<widget
name="web_ribbon"
title="Out of Service"
bg_color="bg-dark"
attrs="{'invisible': [('reservation_type', 'not in', 'out')]}"
/>
<h2> <h2>
<field name="name" /> <field name="name" />
</h2> </h2>
@@ -239,7 +255,10 @@
name="sale_details" name="sale_details"
> >
<field name="pms_property_id" invisible="0" /> <field name="pms_property_id" invisible="0" />
<field name="pricelist_id" /> <field
name="pricelist_id"
attrs="{'invisible': [('reservation_type', 'not in', 'normal')]}"
/>
<field <field
name="company_id" name="company_id"
options="{'no_create': True}" options="{'no_create': True}"
@@ -249,10 +268,13 @@
name="reservation_type" name="reservation_type"
attrs="{'readonly':[('state','not in',('draft'))]}" attrs="{'readonly':[('state','not in',('draft'))]}"
/> />
<field name="agency_id" /> <field
name="agency_id"
attrs="{'invisible': [('reservation_type', 'not in', 'normal')]}"
/>
<field <field
name="channel_type_id" name="channel_type_id"
attrs="{'readonly':[('agency_id','!=', False)]}" attrs="{'readonly':[('agency_id','!=', False)], 'invisible':[('reservation_type', 'not in', 'normal')]}"
/> />
<field name="internal_comment" /> <field name="internal_comment" />
</group> </group>
@@ -260,6 +282,7 @@
class="oe_subtotal_footer oe_right" class="oe_subtotal_footer oe_right"
colspan="2" colspan="2"
name="folio_total" name="folio_total"
attrs="{'invisible':[('reservation_type', '!=', 'normal')]}"
> >
<field <field
name="amount_untaxed" name="amount_untaxed"
@@ -302,7 +325,10 @@
<field name="invoices_paid" invisible="1" /> <field name="invoices_paid" invisible="1" />
</group> </group>
<notebook colspan="4" col="1"> <notebook colspan="4" col="1">
<page string="Sale Lines"> <page
string="Sale Lines"
attrs="{'invisible':[('reservation_type', '!=', 'normal')]}"
>
<field <field
name="sale_line_ids" name="sale_line_ids"
widget="section_and_note_one2many" widget="section_and_note_one2many"
@@ -465,7 +491,11 @@
}" }"
/> />
</page> </page>
<page name="invoicing" string="Invoicing"> <page
name="invoicing"
string="Invoicing"
attrs="{'invisible':[('reservation_type', '!=', 'normal')]}"
>
<div <div
class="alert alert-info" class="alert alert-info"
role="alert" role="alert"
@@ -525,12 +555,17 @@
decoration-muted="state == 'cancel'" decoration-muted="state == 'cancel'"
default_order="create_date desc" default_order="create_date desc"
> >
<field name="name" /> <field
name="name"
decoration-info="reservation_type == 'staff'"
decoration-bf="reservation_type == 'out'"
/>
<field name="partner_id" invisible="1" /> <field name="partner_id" invisible="1" />
<field name="partner_name" select="1" /> <field name="partner_name" select="1" />
<field name="date_order" select="1" /> <field name="date_order" select="1" />
<field name="user_id" widget="many2one_avatar_user" optional="show" /> <field name="user_id" widget="many2one_avatar_user" optional="show" />
<field name="reservation_ids" widget="many2many_tags" optional="show" /> <field name="reservation_ids" widget="many2many_tags" optional="show" />
<field name="reservation_type" invisible="1" />
<field <field
name="amount_total" name="amount_total"
sum="Total amount" sum="Total amount"

View File

@@ -130,8 +130,9 @@
string="Print All Checkins" string="Print All Checkins"
type="object" type="object"
icon="fa-print" icon="fa-print"
attrs="{'invisible':[ attrs="{'invisible':['|',
('checkin_partner_ids','=', []) ('checkin_partner_ids','=', []),
('reservation_type', 'in', ('out'))
]}" ]}"
/> />
<button <button
@@ -139,6 +140,7 @@
type="object" type="object"
class="oe_stat_button" class="oe_stat_button"
icon="fa-globe icon" icon="fa-globe icon"
attrs="{'invisible':[('reservation_type','not in',('normal'))]}"
> >
<div class="o_field_widget o_stat_info"> <div class="o_field_widget o_stat_info">
<span class="o_stat_text">Customer</span> <span class="o_stat_text">Customer</span>
@@ -200,8 +202,8 @@
type="object" type="object"
class="oe_stat_button" class="oe_stat_button"
name="action_checkin_partner_view" name="action_checkin_partner_view"
attrs="{'invisible': [ attrs="{'invisible': ['|',
('allowed_checkin', '!=', True), ('allowed_checkin', '!=', True), ('reservation_type','in',('out'))
]}" ]}"
> >
<field <field
@@ -221,6 +223,19 @@
title="Partial" title="Partial"
bg_color="bg-warning" bg_color="bg-warning"
attrs="{'invisible': [('folio_payment_state', '!=', 'partial')]}" attrs="{'invisible': [('folio_payment_state', '!=', 'partial')]}"
/>
<widget
name="web_ribbon"
title="Staff"
bg_color="bg-info"
attrs="{'invisible': [('reservation_type', 'not in', 'staff')]}"
/>
<widget
name="web_ribbon"
title="Out of Service"
bg_color="bg-dark"
attrs="{'invisible': [('reservation_type', 'not in', 'out')]}"
/> />
<div <div
class="card bg-danger mb8" class="card bg-danger mb8"
@@ -286,11 +301,6 @@
attrs="{'invisible': [('splitted','=',True)]}" attrs="{'invisible': [('splitted','=',True)]}"
/> />
</h3> </h3>
<field
name="out_service_description"
placeholder="Out service description"
attrs="{'invisible':[('reservation_type','not in',('out'))]}"
/>
<group col="8"> <group col="8">
<group <group
colspan="2" colspan="2"
@@ -298,12 +308,20 @@
string="General Info" string="General Info"
name="contact_details" name="contact_details"
> >
<field name="partner_id" invisible="0" /> <field
name="partner_id"
attrs="{'invisible':[('reservation_type','in',('out'))]}"
/>
<field <field
name="partner_name" name="partner_name"
placeholder="Guest" placeholder="Guest"
attrs="{'invisible':[('reservation_type','in',('out'))]}" attrs="{'invisible':[('reservation_type','in',('out'))]}"
/> />
<field
name="out_service_description"
placeholder="Out service description"
attrs="{'invisible':[('reservation_type','not in',('out'))]}"
/>
<field <field
name="email" name="email"
placeholder="email" placeholder="email"
@@ -340,6 +358,7 @@
<field <field
name="pricelist_id" name="pricelist_id"
options="{'no_open':True,'no_create': True}" options="{'no_open':True,'no_create': True}"
attrs="{'invisible': [('reservation_type', '!=', 'normal')]}"
/> />
<!--<field <!--<field
name="agency_id" name="agency_id"
@@ -376,10 +395,13 @@
nolabel="1" nolabel="1"
placeholder="Reservation Notes" placeholder="Reservation Notes"
/> />
<field name="agency_id" /> <field
name="agency_id"
attrs="{'invisible': [('reservation_type', '!=', 'normal')]}"
/>
<field <field
name="channel_type_id" name="channel_type_id"
attrs="{'readonly':[('agency_id','!=', False)]}" attrs="{'readonly':[('agency_id','!=', False)], 'invisible': [('reservation_type', '!=', 'normal')]}"
/> />
</group> </group>
<group <group
@@ -387,6 +409,7 @@
class="oe_subtotal_footer oe_right" class="oe_subtotal_footer oe_right"
name="reservation_total" name="reservation_total"
string="Amounts" string="Amounts"
attrs="{'invisible':[('reservation_type', '!=', 'normal')]}"
> >
<field <field
name="price_services" name="price_services"
@@ -483,7 +506,11 @@
<field name="pms_property_id" invisible="1" /> <field name="pms_property_id" invisible="1" />
</tree> </tree>
</field> </field>
<group string="Services" name="reservation_services"> <group
string="Services"
name="reservation_services"
attrs="{'invisible':[('reservation_type', 'in', ('out'))]}"
>
<field <field
name="service_ids" name="service_ids"
context="{'default_reservation_id': active_id, 'default_folio_id': folio_id, 'form_view_ref':'pms.pms_service_view_form'}" context="{'default_reservation_id': active_id, 'default_folio_id': folio_id, 'form_view_ref':'pms.pms_service_view_form'}"
@@ -596,7 +623,7 @@
<page <page
name="invoicing" name="invoicing"
string="Invoicing" string="Invoicing"
attrs="{'invisible': [('reservation_type','in',('out'))]}" attrs="{'invisible': [('reservation_type','in',('out','staff'))]}"
> >
</page> </page>
<page name="others" string="Others"> <page name="others" string="Others">
@@ -667,8 +694,14 @@
decoration-bf="splitted" decoration-bf="splitted"
js_class="pms_booking_engine_request_tree" js_class="pms_booking_engine_request_tree"
> >
<field name="reservation_type" invisible="1" />
<field name="folio_id" optional="show" decoration-bf="1" /> <field name="folio_id" optional="show" decoration-bf="1" />
<field name="name" optional="show" /> <field
name="name"
optional="show"
decoration-info="reservation_type == 'staff'"
decoration-bf="reservation_type == 'out'"
/>
<field name="splitted" invisible="1" /> <field name="splitted" invisible="1" />
<field name="pricelist_id" invisible="1" /> <field name="pricelist_id" invisible="1" />
<field name="rooms" /> <field name="rooms" />