[IMP]pms: autoinvoicing folio cron improvements

This commit is contained in:
Darío Lodeiros
2023-02-05 20:37:13 +01:00
parent 993b34349a
commit e6063a172b
6 changed files with 142 additions and 77 deletions

View File

@@ -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",

9
pms/data/queue_data.xml Normal file
View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data noupdate="1">
<record id="channel_autoinvocing_folios" model="queue.job.channel">
<field name="name">autoinvoing folios</field>
<field name="parent_id" ref="queue_job.channel_root" />
</record>
</data>
</odoo>

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8" ?>
<odoo noupdate="1">
<record id="autoinvoice_folio_job_function" model="queue.job.function">
<field name="model_id" ref="pms.model_pms_property" />
<field name="method">autoinvoice_folio</field>
<field name="channel_id" ref="pms.channel_autoinvocing_folios" />
<field name="retry_pattern" eval="{1: 10, 5: 30, 10: 60, 15: 300}" />
</record>
<record id="autoinvoice_folio_job_function" model="queue.job.function">
<field name="model_id" ref="pms.model_pms_property" />
<field name="method">autovalidate_folio_invoice</field>
<field name="channel_id" ref="pms.channel_autoinvocing_folios" />
<field name="retry_pattern" eval="{1: 10, 5: 30, 10: 60, 15: 300}" />
</record>
</odoo>

View File

@@ -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

View File

@@ -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:

View File

@@ -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"):