Merge PR #302 into 14.0

Signed-off-by DarioLodeiros
This commit is contained in:
OCA-git-bot
2024-12-15 17:52:01 +00:00
5 changed files with 315 additions and 3 deletions

View File

@@ -791,6 +791,12 @@ class PmsCheckinPartner(models.Model):
_("Is not possible to create the proposed check-in in this reservation") _("Is not possible to create the proposed check-in in this reservation")
) )
def write(self, vals):
res = super().write(vals)
for record in self:
record.reservation_id._update_tourist_tax_service()
return res
def unlink(self): def unlink(self):
reservations = self.mapped("reservation_id") reservations = self.mapped("reservation_id")
res = super().unlink() res = super().unlink()

View File

@@ -7,6 +7,7 @@ import time
from odoo import _, api, fields, models from odoo import _, api, fields, models
from odoo.exceptions import UserError, ValidationError from odoo.exceptions import UserError, ValidationError
from odoo.tools.safe_eval import safe_eval
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@@ -924,9 +925,11 @@ class PmsReservation(models.Model):
room_type_id=False, # Allows to choose any available room room_type_id=False, # Allows to choose any available room
current_lines=reservation.reservation_line_ids.ids, current_lines=reservation.reservation_line_ids.ids,
pricelist_id=reservation.pricelist_id.id, pricelist_id=reservation.pricelist_id.id,
class_id=reservation.room_type_id.class_id.id class_id=(
reservation.room_type_id.class_id.id
if reservation.room_type_id if reservation.room_type_id
else False, else False
),
real_avail=True, real_avail=True,
) )
reservation.allowed_room_ids = pms_property.free_room_ids reservation.allowed_room_ids = pms_property.free_room_ids
@@ -2152,6 +2155,7 @@ class PmsReservation(models.Model):
record.action_cancel() record.action_cancel()
record._check_services(vals) record._check_services(vals)
record._add_tourist_tax_service()
return record return record
def write(self, vals): def write(self, vals):
@@ -2221,6 +2225,8 @@ class PmsReservation(models.Model):
# that not take access to possible extra beds service in vals # that not take access to possible extra beds service in vals
if "adults" in vals: if "adults" in vals:
self._check_capacity() self._check_capacity()
if "checkin" in vals or "checkout" in vals or "reservation_line_ids" in vals:
self._update_tourist_tax_service()
return res return res
def _get_folio_vals(self, reservation_vals): def _get_folio_vals(self, reservation_vals):
@@ -2575,3 +2581,116 @@ class PmsReservation(models.Model):
"target": "self", "target": "self",
"url": self.get_portal_url(), "url": self.get_portal_url(),
} }
def _add_tourist_tax_service(self):
for record in self:
tourist_tax_products = self.env["product.product"].search(
[("is_tourist_tax", "=", True)]
)
for product in tourist_tax_products:
if product.touristic_calculation == "occupancy":
checkins = record.checkin_partner_ids.filtered_domain(
safe_eval(product.occupancy_domain)
)
quantity = len(checkins)
elif product.touristic_calculation == "nights":
if not record.filtered_domain(safe_eval(product.nights_domain)):
continue
quantity = (record.checkout - record.checkin).days
elif product.touristic_calculation == "occupancyandnights":
checkins = record.checkin_partner_ids.filtered_domain(
safe_eval(product.occupancy_domain)
)
if not record.filtered_domain(safe_eval(product.nights_domain)):
continue
quantity = len(checkins) * (record.checkout - record.checkin).days
else:
quantity = 1
if quantity == 0:
continue
product = product.with_context(
lang=record.partner_id.lang,
partner=record.partner_id.id,
quantity=quantity,
date=record.date_order,
consumption_date=record.checkin,
pricelist=record.pricelist_id.id,
uom=product.uom_id.id,
property=record.pms_property_id.id,
)
price = self.env["account.tax"]._fix_tax_included_price_company(
product.price,
product.taxes_id,
record.tax_ids,
record.pms_property_id.company_id,
)
self.env["pms.service"].create(
{
"reservation_id": record.id,
"product_id": product.id,
"quantity": quantity,
"price_unit": price,
}
)
def _update_tourist_tax_service(self):
for record in self:
services = self.env["pms.service"].search(
[
("reservation_id", "=", record.id),
("product_id.is_tourist_tax", "=", True),
]
)
for service in services:
product = service.product_id
if product.touristic_calculation == "occupancy":
checkins = record.checkin_partner_ids.filtered_domain(
safe_eval(product.occupancy_domain)
)
quantity = len(checkins)
elif product.touristic_calculation == "nights":
if not record.filtered_domain(safe_eval(product.nights_domain)):
service.unlink()
continue
quantity = (record.checkout - record.checkin).days
elif product.touristic_calculation == "occupancyandnights":
checkins = record.checkin_partner_ids.filtered_domain(
safe_eval(product.occupancy_domain)
)
if not record.filtered_domain(safe_eval(product.nights_domain)):
service.unlink()
continue
quantity = len(checkins) * (record.checkout - record.checkin).days
else:
quantity = 1
if quantity == 0:
service.unlink()
continue
product = product.with_context(
lang=record.partner_id.lang,
partner=record.partner_id.id,
quantity=quantity,
date=record.date_order,
consumption_date=record.checkin,
pricelist=record.pricelist_id.id,
uom=product.uom_id.id,
property=record.pms_property_id.id,
)
price = self.env["account.tax"]._fix_tax_included_price_company(
product.price,
product.taxes_id,
record.tax_ids,
record.pms_property_id.company_id,
)
service.write(
{
"quantity": quantity,
"price_unit": price,
}
)

View File

@@ -64,6 +64,31 @@ class ProductTemplate(models.Model):
help="Indicates if that product is available in PMS", help="Indicates if that product is available in PMS",
default=True, default=True,
) )
is_tourist_tax = fields.Boolean(
string="Is tourist tax",
help="Indicates if that product is a tourist tax",
default=False,
)
touristic_calculation = fields.Selection(
string="Touristic calculation",
help="Indicates how the tourist tax is calculated",
selection=[
("occupany", "Occupancy"),
("nights", "Nights"),
("occupancyandnights", "Occupancy and Nights"),
],
default="occupancyandnights",
)
occupancy_domain = fields.Char(
string="Occupancy domain",
help="Domain to filter checkins",
default="",
)
nights_domain = fields.Char(
string="Nights domain",
help="Domain to filter reservations",
default="[('state', '!=', 'cancel')]",
)
@api.depends_context("allowed_pms_property_ids") @api.depends_context("allowed_pms_property_ids")
def _compute_daily_limit(self): def _compute_daily_limit(self):

View File

@@ -0,0 +1,143 @@
import datetime
from odoo import fields
from odoo.tests.common import TransactionCase
class TestTouristTaxes(TransactionCase):
def setUp(self):
super(TestTouristTaxes, self).setUp()
self.product_tourist_tax = self.env["product.product"].create(
{
"name": "Tourist Tax",
"is_tourist_tax": True,
"touristic_calculation": "occupancy",
"occupancy_domain": "[('state', '!=', 'cancel')]",
"nights_domain": "[('state', '!=', 'cancel')]",
}
)
self.partner = self.env["res.partner"].create(
{
"name": "Test Partner",
}
)
self.room_type = self.env["pms.room.type"].create(
{
"name": "Test Room Type",
"product_id": self.env["product.product"]
.create(
{
"name": "Room Product",
"type": "service",
}
)
.id,
}
)
self.room = self.env["pms.room"].create(
{
"name": "Test Room",
"room_type_id": self.room_type.id,
}
)
self.reservation = self.env["pms.reservation"].create(
{
"partner_id": self.partner.id,
"room_type_id": self.room_type.id,
"checkin": fields.Date.today(),
"checkout": fields.Date.today() + datetime.timedelta(days=2),
"adults": 2,
}
)
def test_add_tourist_tax_service(self):
"""
Test that a tourist tax service is created when adding a reservation.
Steps:
1. Add a tourist tax service to the reservation.
2. Search for the created service.
3. Assert that the service is created and the quantity is correct.
"""
self.reservation._add_tourist_tax_service()
service = self.env["pms.service"].search(
[
("reservation_id", "=", self.reservation.id),
("product_id", "=", self.product_tourist_tax.id),
]
)
self.assertEqual(len(service), 1, "Tourist tax service should be created")
self.assertEqual(service.quantity, 2, "Tourist tax quantity should be 2")
def test_update_tourist_tax_service(self):
"""
Test that a tourist tax service is updated when modifying the reservation.
Steps:
1. Add a tourist tax service to the reservation.
2. Update the number of adults in the reservation.
3. Update the tourist tax service.
4. Search for the updated service.
5. Assert that the service is updated and the quantity is correct.
"""
self.reservation._add_tourist_tax_service()
self.reservation.adults = 3
self.reservation._update_tourist_tax_service()
service = self.env["pms.service"].search(
[
("reservation_id", "=", self.reservation.id),
("product_id", "=", self.product_tourist_tax.id),
]
)
self.assertEqual(len(service), 1, "Tourist tax service should be updated")
self.assertEqual(
service.quantity, 3, "Tourist tax quantity should be updated to 3"
)
def test_no_tourist_tax_service_when_quantity_zero(self):
"""
Test that no tourist tax service is created when the quantity is zero.
Steps:
1. Set the tourist tax calculation to 'occupancyandnights'.
2. Add a tourist tax service to the reservation.
3. Search for the created service.
4. Assert that no service is created.
"""
self.product_tourist_tax.touristic_calculation = "occupancyandnights"
self.reservation._add_tourist_tax_service()
service = self.env["pms.service"].search(
[
("reservation_id", "=", self.reservation.id),
("product_id", "=", self.product_tourist_tax.id),
]
)
self.assertEqual(
len(service),
0,
"Tourist tax service should not be created when quantity is zero",
)
def test_remove_tourist_tax_service_when_quantity_zero(self):
"""
Test that a tourist tax service is removed when the quantity becomes zero.
Steps:
1. Set the tourist tax calculation to 'occupancy'.
2. Add a tourist tax service to the reservation.
3. Update the number of adults in the reservation to zero.
4. Update the tourist tax service.
5. Search for the updated service.
6. Assert that the service is removed.
"""
self.product_tourist_tax.touristic_calculation = "occupancy"
self.reservation._add_tourist_tax_service()
self.reservation.adults = 0
self.reservation._update_tourist_tax_service()
service = self.env["pms.service"].search(
[
("reservation_id", "=", self.reservation.id),
("product_id", "=", self.product_tourist_tax.id),
]
)
self.assertEqual(
len(service),
0,
"Tourist tax service should be removed when quantity is zero",
)

View File

@@ -28,6 +28,7 @@
<group> <group>
<field name="per_day" /> <field name="per_day" />
<field name="per_person" /> <field name="per_person" />
<field name="is_tourist_tax" />
<field <field
name="consumed_on" name="consumed_on"
widget="radio" widget="radio"
@@ -36,6 +37,24 @@
</group> </group>
</group> </group>
</page> </page>
<page
string="Tourist tax configuration"
attrs="{'invisible': [('is_tourist_tax', '=', False)]}"
>
<group>
<field name="touristic_calculation" />
<field
name="occupancy_domain"
widget="domain"
options="{'model': 'pms.checkin.partner'}"
/>
<field
name="nights_domain"
widget="domain"
options="{'model': 'pms.reservation'}"
/>
</group>
</page>
</xpath> </xpath>
</field> </field>
</record> </record>