mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
@@ -791,6 +791,12 @@ class PmsCheckinPartner(models.Model):
|
||||
_("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):
|
||||
reservations = self.mapped("reservation_id")
|
||||
res = super().unlink()
|
||||
|
||||
@@ -7,6 +7,7 @@ import time
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -924,9 +925,11 @@ class PmsReservation(models.Model):
|
||||
room_type_id=False, # Allows to choose any available room
|
||||
current_lines=reservation.reservation_line_ids.ids,
|
||||
pricelist_id=reservation.pricelist_id.id,
|
||||
class_id=reservation.room_type_id.class_id.id
|
||||
if reservation.room_type_id
|
||||
else False,
|
||||
class_id=(
|
||||
reservation.room_type_id.class_id.id
|
||||
if reservation.room_type_id
|
||||
else False
|
||||
),
|
||||
real_avail=True,
|
||||
)
|
||||
reservation.allowed_room_ids = pms_property.free_room_ids
|
||||
@@ -2152,6 +2155,7 @@ class PmsReservation(models.Model):
|
||||
record.action_cancel()
|
||||
|
||||
record._check_services(vals)
|
||||
record._add_tourist_tax_service()
|
||||
return record
|
||||
|
||||
def write(self, vals):
|
||||
@@ -2221,6 +2225,8 @@ class PmsReservation(models.Model):
|
||||
# that not take access to possible extra beds service in vals
|
||||
if "adults" in vals:
|
||||
self._check_capacity()
|
||||
if "checkin" in vals or "checkout" in vals or "reservation_line_ids" in vals:
|
||||
self._update_tourist_tax_service()
|
||||
return res
|
||||
|
||||
def _get_folio_vals(self, reservation_vals):
|
||||
@@ -2575,3 +2581,116 @@ class PmsReservation(models.Model):
|
||||
"target": "self",
|
||||
"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,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -64,6 +64,31 @@ class ProductTemplate(models.Model):
|
||||
help="Indicates if that product is available in PMS",
|
||||
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")
|
||||
def _compute_daily_limit(self):
|
||||
|
||||
143
pms/tests/test_tourist_taxes.py
Normal file
143
pms/tests/test_tourist_taxes.py
Normal 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",
|
||||
)
|
||||
@@ -28,6 +28,7 @@
|
||||
<group>
|
||||
<field name="per_day" />
|
||||
<field name="per_person" />
|
||||
<field name="is_tourist_tax" />
|
||||
<field
|
||||
name="consumed_on"
|
||||
widget="radio"
|
||||
@@ -36,6 +37,24 @@
|
||||
</group>
|
||||
</group>
|
||||
</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>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
Reference in New Issue
Block a user