mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
[IMP]pms: autoinvoicing folio cron improvements
This commit is contained in:
@@ -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
9
pms/data/queue_data.xml
Normal 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>
|
||||
15
pms/data/queue_job_function_data.xml
Normal file
15
pms/data/queue_job_function_data.xml
Normal 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>
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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"):
|
||||
|
||||
Reference in New Issue
Block a user