diff --git a/pms/models/pms_folio.py b/pms/models/pms_folio.py
index d58d701d7..46f793f54 100644
--- a/pms/models/pms_folio.py
+++ b/pms/models/pms_folio.py
@@ -564,17 +564,21 @@ class PmsFolio(models.Model):
target_lines = folio_lines_to_invoice
if self._context.get("lines_auto_add") and folio_partner_invoice_id:
- if folio_partner_invoice_id.default_invoice_lines == "overnights":
+ folio_partner_invoice = self.env["res.partner"].browse(
+ folio_partner_invoice_id
+ )
+ if folio_partner_invoice.default_invoice_lines == "overnights":
target_lines = target_lines.filtered(
- lambda r: r.is_board_service or r.reservation_id.overnight_room
+ lambda r: r.is_board_service
+ or (r.reservation_line_ids and r.reservation_id.overnight_room)
)
- elif folio_partner_invoice_id.default_invoice_lines == "reservations":
+ elif folio_partner_invoice.default_invoice_lines == "reservations":
target_lines = target_lines.filtered(
- lambda r: r.is_board_service or r.reservation_id
+ lambda r: r.is_board_service or r.reservation_line_ids
)
- elif folio_partner_invoice_id.default_invoice_lines == "services":
+ elif folio_partner_invoice.default_invoice_lines == "services":
target_lines = target_lines.filtered(
- lambda r: not r.is_board_service or r.service_id
+ lambda r: not r.is_board_service or r.service_line_ids
)
groups_invoice_lines = [
{
@@ -659,7 +663,7 @@ class PmsFolio(models.Model):
(0, 0, invoice_line_id) for invoice_line_id in invoice_lines_vals
]
- invoice_vals_list.append(invoice_vals)
+ invoice_vals_list.append(invoice_vals)
return invoice_vals_list
def _get_tax_amount_by_group(self):
@@ -684,7 +688,7 @@ class PmsFolio(models.Model):
]
return res
- @api.depends("partner_id", "invoice_status", "last_checkout")
+ @api.depends("partner_id", "invoice_status", "last_checkout", "partner_invoice_ids")
def _compute_autoinvoice_date(self):
self.autoinvoice_date = False
for record in self.filtered(lambda r: r.invoice_status == "to_invoice"):
@@ -706,18 +710,18 @@ class PmsFolio(models.Model):
if not partner or partner.invoicing_policy == "property"
else partner.margin_days_autoinvoice
)
- return self.checkout + timedelta(days=margin_days)
+ return self.last_checkout + timedelta(days=margin_days)
if invoicing_policy == "month_day":
month_day = (
self.pms_property_id.invoicing_month_day
if not partner or partner.invoicing_policy == "property"
else partner.invoicing_month_day
)
- if self.checkout.day <= month_day:
- self.autoinvoice_date = self.checkout.replace(day=month_day)
+ if self.last_checkout.day <= month_day:
+ self.autoinvoice_date = self.last_checkout.replace(day=month_day)
else:
self.autoinvoice_date = (
- self.checkout + relativedelta.relativedelta(months=1)
+ self.last_checkout + relativedelta.relativedelta(months=1)
).replace(day=month_day)
@api.depends("reservation_ids", "reservation_ids.state")
@@ -1605,7 +1609,6 @@ class PmsFolio(models.Model):
lines_to_invoice=lines_to_invoice,
partner_invoice_id=partner_invoice_id,
)
-
if not invoice_vals_list:
raise self._nothing_to_invoice_error()
@@ -1685,7 +1688,7 @@ class PmsFolio(models.Model):
# However, he should not be able to create an invoice from scratch.
moves = self.env["account.move"]
for invoice_vals in invoice_vals_list:
- if invoice_vals["partner_id"]:
+ if invoice_vals["move_type"] == "out_invoice":
move = (
self.env["account.move"]
.sudo()
@@ -1727,11 +1730,6 @@ class PmsFolio(models.Model):
(making sure to call super() to establish a clean extension chain).
"""
self.ensure_one()
- if not partner_invoice_id:
- partner_invoice_id = (
- self.partner_invoice_ids[0].id if self.partner_invoice_ids else False
- )
-
journal = self._get_folio_default_journal(partner_invoice_id)
if not journal:
journal = (
diff --git a/pms/models/pms_property.py b/pms/models/pms_property.py
index 634570170..6aa918749 100644
--- a/pms/models/pms_property.py
+++ b/pms/models/pms_property.py
@@ -143,7 +143,7 @@ class PmsProperty(models.Model):
is_canceled_auto_mail = fields.Boolean(string="Auto Send Cancellation Mail")
default_invoicing_policy = fields.Selection(
- string="Invoicing Policy",
+ string="Default Invoicing Policy",
selection=[
("manual", "Manual"),
("checkout", "Checkout"),
diff --git a/pms/models/pms_reservation.py b/pms/models/pms_reservation.py
index 9367b7ea3..3cc624c89 100644
--- a/pms/models/pms_reservation.py
+++ b/pms/models/pms_reservation.py
@@ -1851,8 +1851,23 @@ class PmsReservation(models.Model):
record = super(PmsReservation, self).create(vals)
if record.preconfirm and record.state == "draft":
record.confirm()
+
+ record._check_services(vals)
+
return record
+ def write(self, vals):
+ asset = super(PmsReservation, self).write(vals)
+ self._check_services(vals)
+ return asset
+
+ def _check_services(self, vals):
+ # If we create a reservation with board service and other service at the same time,
+ # compute_service_ids dont run (compute with readonly to False),
+ # and we must force it to compute the services linked with the board service:
+ if "board_service_room_id" in vals and "service_ids" in vals:
+ self._compute_service_ids()
+
def update_prices(self):
self.ensure_one()
for line in self.reservation_line_ids:
diff --git a/pms/tests/test_pms_folio_invoice.py b/pms/tests/test_pms_folio_invoice.py
index c64412a17..dc7cceca0 100644
--- a/pms/tests/test_pms_folio_invoice.py
+++ b/pms/tests/test_pms_folio_invoice.py
@@ -147,7 +147,7 @@ class TestPmsFolioInvoice(TestPms):
] = 1
r1.folio_id._create_invoices(
lines_to_invoice=dict_lines,
- partner_invoice_id=self.env.ref("base.res_partner_1"),
+ partner_invoice_id=self.env.ref("base.res_partner_1").id,
)
# test does not work without invalidating cache
@@ -165,7 +165,7 @@ class TestPmsFolioInvoice(TestPms):
] = 2
r1.folio_id._create_invoices(
lines_to_invoice=dict_lines,
- partner_invoice_id=self.env.ref("base.res_partner_12"),
+ partner_invoice_id=self.env.ref("base.res_partner_12").id,
)
self.assertNotEqual(
r1.folio_id.move_ids.mapped("partner_id")[0],
@@ -579,14 +579,156 @@ class TestPmsFolioInvoice(TestPms):
"The quantity of board services to be invoice is wrong",
)
+ def test_autoinvoice_folio_checkout_property_policy(self):
+ """
+ Test create and invoice the cron by property preconfig automation
+ --------------------------------------
+ Set property default_invoicing_policy to checkout with 0 days with
+ margin, and check that the folio autoinvoice date is set to last checkout
+ folio date
+ """
+ # ARRANGE
+ self.property.default_invoicing_policy = "checkout"
+ self.property.margin_days_autoinvoice = 0
+
+ # ACT
+ self.reservation1 = self.env["pms.reservation"].create(
+ {
+ "pms_property_id": self.property.id,
+ "checkin": datetime.date.today(),
+ "checkout": datetime.date.today() + datetime.timedelta(days=3),
+ "adults": 2,
+ "room_type_id": self.room_type_double.id,
+ "partner_id": self.partner_id.id,
+ }
+ )
+
+ # ASSERT
+ self.assertEqual(
+ datetime.date.today() + datetime.timedelta(days=3),
+ self.reservation1.folio_id.autoinvoice_date,
+ "The autoinvoice date in folio with property checkout policy is wrong",
+ )
+
+ def test_autoinvoice_folio_checkout_partner_policy(self):
+ """
+ Test create and invoice the cron by partner preconfig automation
+ --------------------------------------
+ Set partner invoicing_policy to checkout with 2 days with
+ margin, and check that the folio autoinvoice date is set to last checkout
+ folio date + 2 days
+ """
+ # ARRANGE
+ self.partner_id.invoicing_policy = "checkout"
+ self.partner_id.margin_days_autoinvoice = 2
+
+ # ACT
+ self.reservation1 = self.env["pms.reservation"].create(
+ {
+ "pms_property_id": self.property.id,
+ "checkin": datetime.date.today(),
+ "checkout": datetime.date.today() + datetime.timedelta(days=3),
+ "adults": 2,
+ "room_type_id": self.room_type_double.id,
+ "partner_id": self.partner_id.id,
+ }
+ )
+
+ # ASSERT
+ self.assertEqual(
+ datetime.date.today() + datetime.timedelta(days=5),
+ self.reservation1.folio_id.autoinvoice_date,
+ "The autoinvoice date in folio with property checkout policy is wrong",
+ )
+
+ def test_autoinvoice_folio_overnights_partner_policy(self):
+ """
+ Test create and invoice the cron by partner preconfig automation
+ with only overnights reservations (included board services)
+ --------------------------------------
+ Set partner invoicing_policy to checkout, create a reservation
+ with room, board service and normal service, run autoinvoicing
+ method and check that only room and board service was invoiced
+ in partner1,
+
+ """
+ # ARRANGE
+ self.partner_id.invoicing_policy = "checkout"
+ self.partner_id.margin_days_autoinvoice = 0
+ self.partner_id.default_invoice_lines = "overnights"
+ self.product1 = self.env["product.product"].create(
+ {
+ "name": "Test Product 1",
+ }
+ )
+
+ self.product2 = self.env["product.product"].create(
+ {
+ "name": "Test Product 2",
+ }
+ )
+
+ self.service = self.env["pms.service"].create(
+ {
+ "is_board_service": False,
+ "product_id": self.product2.id,
+ }
+ )
+
+ self.board_service1 = self.env["pms.board.service"].create(
+ {
+ "name": "Test Board Service 1",
+ "default_code": "CB1",
+ }
+ )
+
+ self.board_service_line1 = self.env["pms.board.service.line"].create(
+ {
+ "product_id": self.product1.id,
+ "pms_board_service_id": self.board_service1.id,
+ "amount": 10,
+ }
+ )
+
+ self.board_service_room_type1 = self.env["pms.board.service.room.type"].create(
+ {
+ "pms_room_type_id": self.room_type_double.id,
+ "pms_board_service_id": self.board_service1.id,
+ }
+ )
+ # ACT
+ self.reservation1 = self.env["pms.reservation"].create(
+ {
+ "pms_property_id": self.property.id,
+ "checkin": datetime.date.today() - datetime.timedelta(days=3),
+ "checkout": datetime.date.today(),
+ "adults": 2,
+ "room_type_id": self.room_type_double.id,
+ "partner_id": self.partner_id.id,
+ "board_service_room_id": self.board_service_room_type1.id,
+ "service_ids": [(4, self.service.id)],
+ }
+ )
+ self.property.autoinvoicing()
+
+ # ASSERT
+ overnight_sale_lines = self.reservation1.folio_id.sale_line_ids.filtered(
+ lambda line: line.reservation_line_ids or line.is_board_service
+ )
+ partner_invoice = self.reservation1.folio_id.move_ids.filtered(
+ lambda inv: inv.partner_id == self.partner_id
+ )
+ self.assertEqual(
+ partner_invoice.mapped("line_ids.folio_line_ids.id"),
+ overnight_sale_lines.ids,
+ "Billed services and overnights invoicing wrong compute",
+ )
+
def _test_invoice_line_group_by_room_type_sections(self):
"""Test create and invoice from the Folio, and check qty invoice/to invoice,
and the grouped invoice lines by room type, by one
line by unit prices/qty with nights"""
- def _test_autoinvoice_folio(self):
- """ Test create and invoice the cron by partner preconfig automation """
-
def _test_downpayment(self):
"""Test invoice qith a way of downpaument and check dowpayment's
folio line is created and also check a total amount of invoice is
diff --git a/pms/views/account_bank_statement_views.xml b/pms/views/account_bank_statement_views.xml
index 8b0f18ca4..2d41ad417 100644
--- a/pms/views/account_bank_statement_views.xml
+++ b/pms/views/account_bank_statement_views.xml
@@ -4,9 +4,10 @@
account.bank.statement
+
-
-
+
+