143 lines
5.3 KiB
Python
143 lines
5.3 KiB
Python
# Copyright 2020 Camptocamp SA
|
|
# Copyright 2023 ACSONE SA/NV
|
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
|
|
from odoo import api, fields, models
|
|
from odoo.fields import Datetime
|
|
from odoo.osv.expression import AND
|
|
|
|
from odoo.addons.queue_job.job import identity_exact
|
|
|
|
|
|
class SaleOrder(models.Model):
|
|
_inherit = "sale.order"
|
|
|
|
invoicing_mode = fields.Selection(
|
|
related="partner_invoice_id.invoicing_mode",
|
|
store=True,
|
|
index=True,
|
|
)
|
|
|
|
one_invoice_per_order = fields.Boolean(
|
|
compute="_compute_one_invoice_per_order",
|
|
readonly=False,
|
|
store=True,
|
|
help="You can check or uncheck this if you want the periodic invoicing"
|
|
" grouping this sale order with other ones or not.",
|
|
)
|
|
|
|
@api.depends("partner_invoice_id")
|
|
def _compute_one_invoice_per_order(self):
|
|
# We depends only on partner as if we change it, we should recompute
|
|
# but not if the parameter on it has changed (this allows to set a different
|
|
# value on each sale order).
|
|
for order in self:
|
|
order.one_invoice_per_order = order.partner_invoice_id.one_invoice_per_order
|
|
|
|
@api.model
|
|
def cron_generate_standard_invoices(self):
|
|
company_ids = self._get_companies_standard_invoicing()
|
|
if company_ids:
|
|
self.generate_invoices(company_ids)
|
|
|
|
@api.model
|
|
def _get_generate_invoices_state_domain(self):
|
|
return [("invoice_status", "=", "to invoice")]
|
|
|
|
@api.model
|
|
def _get_generate_invoices_domain(self, companies, invoicing_mode="standard"):
|
|
return AND(
|
|
[
|
|
self._get_generate_invoices_state_domain(),
|
|
[
|
|
("invoicing_mode", "=", invoicing_mode),
|
|
("company_id", "in", companies.ids),
|
|
],
|
|
]
|
|
)
|
|
|
|
@api.model
|
|
def generate_invoices(
|
|
self,
|
|
companies=None,
|
|
invoicing_mode="standard",
|
|
last_execution_field="invoicing_mode_standard_last_execution",
|
|
):
|
|
"""
|
|
Generate invoices in job queues depending on the invoicing
|
|
mode (stadndard by default)
|
|
"""
|
|
if companies is None:
|
|
companies = self.env.company
|
|
domain = self._get_generate_invoices_domain(
|
|
companies=companies, invoicing_mode=invoicing_mode
|
|
)
|
|
saleorder_groups = self.read_group(
|
|
domain,
|
|
["partner_invoice_id", "sale_ids:array_agg(id)"],
|
|
groupby=self._get_invoice_grouping_keys(),
|
|
lazy=False,
|
|
)
|
|
for saleorder_group in saleorder_groups:
|
|
self.with_delay(
|
|
identity_key=identity_exact,
|
|
description=self.env._("Generate invoices by partner"),
|
|
)._generate_invoices_by_partner(saleorder_group["sale_ids"])
|
|
companies.write({last_execution_field: Datetime.now()})
|
|
return saleorder_groups
|
|
|
|
@api.model
|
|
def _get_invoice_grouping_keys(self) -> list:
|
|
"""
|
|
We override the standard (in sale) grouping function in order to
|
|
add some missing keys. We remove also the partner_id key.
|
|
"""
|
|
keys = super()._get_invoice_grouping_keys()
|
|
if "partner_invoice_id" not in keys:
|
|
keys.append("partner_invoice_id")
|
|
if "payment_term_id" not in keys:
|
|
keys.append("payment_term_id")
|
|
# Removing unwanted keys as we group on invoiced partner
|
|
if "partner_id" in keys:
|
|
keys.remove("partner_id")
|
|
return keys
|
|
|
|
def _get_generated_invoices(self, partition):
|
|
"""
|
|
Hook to get the generated invoices as in some extended modules,
|
|
those invoices should not be validated yet.
|
|
"""
|
|
return self._create_invoices(grouped=partition, final=True)
|
|
|
|
def _generate_invoices_by_partner(self, saleorder_ids):
|
|
"""Generate invoices for a group of sale order belonging to a customer."""
|
|
today = fields.Date.context_today(self)
|
|
sale_orders = (
|
|
self.browse(saleorder_ids)
|
|
.exists()
|
|
.filtered_domain(self._get_generate_invoices_state_domain())
|
|
)
|
|
if not sale_orders:
|
|
return "No sale order found to invoice ?"
|
|
# Create invoices using grouping when needed, so partition sales
|
|
invoice_ids = set()
|
|
for partition, partitioned_sales in sale_orders.partition(
|
|
lambda sale: sale.one_invoice_per_order
|
|
).items():
|
|
invoices = partitioned_sales._get_generated_invoices(partition=partition)
|
|
# Update invoices date to be sure no long validation (jobs) put
|
|
# the further day date on invoices.
|
|
invoices.write({"invoice_date": today})
|
|
# Update each partner next invoice date
|
|
partitioned_sales.partner_invoice_id._update_next_invoice_date()
|
|
invoice_ids.update(invoices.ids)
|
|
for invoice in invoices:
|
|
description = self.env._("Validate %s invoice", invoice.display_name)
|
|
invoice.with_delay(
|
|
identity_key=identity_exact, description=description
|
|
)._validate_invoice()
|
|
return self.env["account.move"].browse(invoice_ids)
|
|
|
|
@api.model
|
|
def _get_companies_standard_invoicing(self):
|
|
return self.env["res.company"].search([])
|