diff --git a/pms/__manifest__.py b/pms/__manifest__.py
index 501bdd552..d05633ccf 100644
--- a/pms/__manifest__.py
+++ b/pms/__manifest__.py
@@ -46,6 +46,8 @@
"report/invoice.xml",
# "templates/pms_email_template.xml",
"data/menus.xml",
+ "data/queue_data.xml",
+ "data/queue_job_function_data.xml",
"wizards/wizard_payment_folio.xml",
"wizards/folio_make_invoice_advance_views.xml",
"wizards/pms_booking_engine_views.xml",
diff --git a/pms/data/queue_data.xml b/pms/data/queue_data.xml
new file mode 100644
index 000000000..d7020bd8a
--- /dev/null
+++ b/pms/data/queue_data.xml
@@ -0,0 +1,9 @@
+
+
+
+
+ autoinvoing folios
+
+
+
+
diff --git a/pms/data/queue_job_function_data.xml b/pms/data/queue_job_function_data.xml
new file mode 100644
index 000000000..da067a8cd
--- /dev/null
+++ b/pms/data/queue_job_function_data.xml
@@ -0,0 +1,15 @@
+
+
+
+
+ autoinvoice_folio
+
+
+
+
+
+ autovalidate_folio_invoice
+
+
+
+
diff --git a/pms/models/folio_sale_line.py b/pms/models/folio_sale_line.py
index 9d18795ca..236dd1c9e 100644
--- a/pms/models/folio_sale_line.py
+++ b/pms/models/folio_sale_line.py
@@ -539,9 +539,9 @@ class FolioSaleLine(models.Model):
where Total_sol depends on the invoice policy of the product.
Note: Draft invoice are ignored on purpose, the 'to invoice' amount should
- come only from the SO lines.
+ come only from the folio lines.
"""
- for line in self:
+ for line in self.filtered("invoice_lines"):
amount_to_invoice = 0.0
if line.state != "draft":
# Note: do not use price_subtotal field as it returns
diff --git a/pms/models/pms_folio.py b/pms/models/pms_folio.py
index 3ceeacced..8a533a50b 100644
--- a/pms/models/pms_folio.py
+++ b/pms/models/pms_folio.py
@@ -285,6 +285,13 @@ class PmsFolio(models.Model):
compute="_compute_get_invoiced",
search="_search_invoice_ids",
)
+ untaxed_amount_to_invoice = fields.Monetary(
+ string="Amount to invoice",
+ help="The amount to invoice",
+ readonly=True,
+ store=True,
+ compute="_compute_untaxed_amount_to_invoice",
+ )
payment_state = fields.Selection(
string="Payment Status",
help="The state of the payment",
@@ -493,6 +500,9 @@ class PmsFolio(models.Model):
"nothin to invoice, even when there may be ordered "
"quantities pending to invoice.",
copy=False,
+ compute="_compute_force_nothing_to_invoice",
+ readonly=False,
+ store=True,
)
internal_comment = fields.Text(
string="Internal Folio Notes",
@@ -555,11 +565,6 @@ class PmsFolio(models.Model):
compute="_compute_days_to_checkout",
search="_search_days_to_checkout",
)
- autoinvoice_date = fields.Date(
- string="Autoinvoice Date",
- compute="_compute_autoinvoice_date",
- store=True,
- )
invoice_to_agency = fields.Boolean(
string="Invoice Agency",
help="""Indicates if agency invoices partner
@@ -1024,7 +1029,7 @@ class PmsFolio(models.Model):
for folio in self:
folio.access_url = "/my/folios/%s" % (folio.id)
- @api.depends("state", "sale_line_ids.invoice_status")
+ @api.depends("state", "sale_line_ids.invoice_status", "force_nothing_to_invoice")
def _compute_get_invoice_status(self):
"""
Compute the invoice status of a Folio. Possible statuses:
@@ -1057,21 +1062,41 @@ class PmsFolio(models.Model):
line_invoice_status = [
d[1] for d in line_invoice_status_all if d[0] == order.id
]
- if order.force_nothing_to_invoice:
- order.invoice_status = "no"
- elif any(
+ if not order.force_nothing_to_invoice and any(
invoice_status == "to_invoice" for invoice_status in line_invoice_status
):
order.invoice_status = "to_invoice"
elif any(inv.state == "draft" for inv in order.move_ids):
order.invoice_status = "to_confirm"
- elif line_invoice_status and all(
+ elif line_invoice_status and any(
invoice_status == "invoiced" for invoice_status in line_invoice_status
):
- order.invoice_status = "invoiced"
+ if (
+ all(
+ invoice_status == "invoiced"
+ for invoice_status in line_invoice_status
+ )
+ or order.force_nothing_to_invoice
+ ):
+ order.invoice_status = "invoiced"
+ else:
+ order.invoice_status = "no"
else:
order.invoice_status = "no"
+ @api.depends("untaxed_amount_to_invoice", "amount_total")
+ def _compute_force_nothing_to_invoice(self):
+ # If the invoice amount and amount total are the same,
+ # and the qty to invoice is not 0, we force nothing to invoice
+ for order in self:
+ if (
+ order.untaxed_amount_to_invoice <= 0
+ and sum(order.sale_line_ids.mapped("qty_to_invoice")) != 0
+ ):
+ order.force_nothing_to_invoice = True
+ else:
+ order.force_nothing_to_invoice = False
+
@api.depends("partner_id", "partner_id.name", "agency_id", "reservation_type")
def _compute_partner_name(self):
for record in self:
@@ -1174,6 +1199,12 @@ class PmsFolio(models.Model):
/ sum(folio.reservation_ids.mapped("adults"))
)
+ def _compute_untaxed_amount_to_invoice(self):
+ for folio in self:
+ folio.untaxed_amount_to_invoice = sum(
+ folio.mapped("sale_line_ids.untaxed_amount_to_invoice")
+ )
+
# TODO: Add return_ids to depends
@api.depends(
"amount_total",
@@ -1851,11 +1882,9 @@ class PmsFolio(models.Model):
invoice_vals_list = self._get_group_vals_list(invoice_vals_list)
partner_invoice = self.env["res.partner"].browse(partner_invoice_id)
- partner_invoice_policy = (
- self.pms_property_id.default_invoicing_policy
- if partner_invoice.invoicing_policy == "property"
- else partner_invoice.invoicing_policy
- )
+ partner_invoice_policy = self.pms_property_id.default_invoicing_policy
+ if partner_invoice and partner_invoice.invoicing_policy != "property":
+ partner_invoice_policy = partner_invoice.invoicing_policy
invoice_date = False
if date:
invoice_date = date
@@ -1899,11 +1928,13 @@ class PmsFolio(models.Model):
"Please contact your administrator to unlock it."
)
)
- if invoice_date < datetime.date.today():
+ if invoice_date < datetime.date.today() and not self._context.get(
+ "autoinvoice"
+ ):
invoice_date = datetime.date.today()
key_field = (
"invoice_date"
- if invoice_date == fields.Date.today()
+ if invoice_date <= fields.Date.today()
else "invoice_date_due"
)
for vals in invoice_vals_list:
diff --git a/pms/models/pms_property.py b/pms/models/pms_property.py
index 803dcd6d7..61601a8c4 100644
--- a/pms/models/pms_property.py
+++ b/pms/models/pms_property.py
@@ -661,7 +661,7 @@ class PmsProperty(models.Model):
return True
@api.model
- def autoinvoicing(self, offset=0):
+ def autoinvoicing(self, offset=0, with_delay=False):
"""
This method is used to invoicing automatically the folios
and validate the draft invoices created by the folios
@@ -689,58 +689,11 @@ class PmsProperty(models.Model):
)
)
for folio in folios_to_invoice:
- try:
- # REVIEW: folio sale line "_compute_auotinvoice_date" sometimes
- # dont work in services (probably cache issue¿?), we ensure that the date is
- # set or recompute this
- for line in folio.sale_line_ids.filtered(
- lambda l: not l.autoinvoice_date
- ):
- line._compute_autoinvoice_date()
- # REVIEW: Reverse downpayment invoices if the downpayment is not included
- # in the service invoice (qty_to_invoice < 0)
- downpayment_invoices = (
- folio.sale_line_ids.filtered(
- lambda l: l.is_downpayment and l.qty_to_invoice < 0
- )
- .mapped("invoice_lines")
- .mapped("move_id")
- .filtered(lambda i: i.is_simplified_invoice)
- )
- if downpayment_invoices:
- downpayment_invoices._reverse_moves(cancel=True)
- invoices = folio.with_context(autoinvoice=True)._create_invoices(
- grouped=True,
- final=True,
- )
- for invoice in invoices:
- if (
- invoice.amount_total
- > invoice.pms_property_id.max_amount_simplified_invoice
- and invoice.journal_id.is_simplified_invoice
- ):
- hosts_to_invoice = (
- invoice.folio_ids.partner_invoice_ids.filtered(
- lambda p: p._check_enought_invoice_data()
- ).mapped("id")
- )
- if hosts_to_invoice:
- invoice.partner_id = hosts_to_invoice[0]
- invoice.journal_id = (
- invoice.pms_property_id.journal_normal_invoice_id
- )
- else:
- mens = _(
- "The total amount of the simplified invoice is higher than the "
- "maximum amount allowed for simplified invoices, and dont have "
- "enought data in hosts to create a normal invoice."
- )
- if self.folio_ids:
- self.folio_ids.message_post(body=mens)
- raise ValidationError(mens)
- invoice.action_post()
- except Exception as e:
- folio.message_post(body=_("Error in autoinvoicing folio: " + str(e)))
+ if with_delay:
+ self.with_delay().autoinvoice_folio(folio)
+ else:
+ self.autoinvoice_folio(folio)
+
draft_invoices_to_post = self.env["account.move"].search(
[
("state", "=", "draft"),
@@ -749,12 +702,67 @@ class PmsProperty(models.Model):
]
)
for invoice in draft_invoices_to_post:
- try:
- invoice.action_post()
- except Exception as e:
- invoice.message_post(body=_("Error in autovalidate invoice: " + str(e)))
+ if with_delay:
+ self.with_delay().autovalidate_folio_invoice(invoice)
+ else:
+ self.autovalidate_folio_invoice(invoice)
return True
+ def autovalidate_folio_invoice(self, invoice):
+ try:
+ invoice.action_post()
+ except Exception as e:
+ invoice.message_post(body=_("Error in autovalidate invoice: " + str(e)))
+
+ def autoinvoice_folio(self, folio):
+ try:
+ # REVIEW: folio sale line "_compute_auotinvoice_date" sometimes
+ # dont work in services (probably cache issue¿?), we ensure that the date is
+ # set or recompute this
+ for line in folio.sale_line_ids.filtered(lambda l: not l.autoinvoice_date):
+ line._compute_autoinvoice_date()
+ # REVIEW: Reverse downpayment invoices if the downpayment is not included
+ # in the service invoice (qty_to_invoice < 0)
+ downpayment_invoices = (
+ folio.sale_line_ids.filtered(
+ lambda l: l.is_downpayment and l.qty_to_invoice < 0
+ )
+ .mapped("invoice_lines")
+ .mapped("move_id")
+ .filtered(lambda i: i.is_simplified_invoice)
+ )
+ if downpayment_invoices:
+ downpayment_invoices._reverse_moves(cancel=True)
+ invoices = folio.with_context(autoinvoice=True)._create_invoices(
+ grouped=True,
+ final=True,
+ )
+ for invoice in invoices:
+ if (
+ invoice.amount_total
+ > invoice.pms_property_id.max_amount_simplified_invoice
+ and invoice.journal_id.is_simplified_invoice
+ ):
+ hosts_to_invoice = invoice.folio_ids.partner_invoice_ids.filtered(
+ lambda p: p._check_enought_invoice_data()
+ ).mapped("id")
+ if hosts_to_invoice:
+ invoice.partner_id = hosts_to_invoice[0]
+ invoice.journal_id = (
+ invoice.pms_property_id.journal_normal_invoice_id
+ )
+ else:
+ mens = _(
+ "The total amount of the simplified invoice is higher than the "
+ "maximum amount allowed for simplified invoices, and dont have "
+ "enought data in hosts to create a normal invoice."
+ )
+ folio.message_post(body=mens)
+ raise ValidationError(mens)
+ invoice.action_post()
+ except Exception as e:
+ folio.message_post(body=_("Error in autoinvoicing folio: " + str(e)))
+
@api.constrains("journal_normal_invoice_id")
def _check_journal_normal_invoice(self):
for pms_property in self.filtered("journal_normal_invoice_id"):