cc131fe081
inv5 YYYYMM20 posted INV4 YYYYMM15 posted INV3 YYYYMM10 posted INV2 YYYYMM05 posted INV1 YYYYMM01 posted if we pass INV3 to draft and change the date to YYYYYMM15 or YYYYYMM05 it should be able to validate, but if we change the date higher than YYYYYMM15 or lower than YYYYYMM05 it should not be able to validate.
175 lines
6.0 KiB
Python
175 lines
6.0 KiB
Python
# Copyright 2015-2019 ACSONE SA/NV (<http://acsone.eu>)
|
|
# Copyright 2021 CorporateHub (https://corporatehub.eu)
|
|
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
|
|
|
from odoo import _, models
|
|
from odoo.exceptions import UserError
|
|
from odoo.osv import expression
|
|
from odoo.tools.misc import format_date
|
|
|
|
|
|
class AccountMove(models.Model):
|
|
_inherit = "account.move"
|
|
|
|
def _get_conflicting_invoices_domain(self):
|
|
self.ensure_one()
|
|
domain = [
|
|
("journal_id", "=", self.journal_id.id),
|
|
("move_type", "!=", "entry"),
|
|
]
|
|
if self.journal_id.refund_sequence:
|
|
domain.append(("move_type", "=", self.move_type))
|
|
return domain
|
|
|
|
def _get_older_conflicting_invoices_domain(self):
|
|
self.ensure_one()
|
|
return expression.AND(
|
|
[
|
|
self._get_conflicting_invoices_domain(),
|
|
[
|
|
("state", "=", "draft"),
|
|
("invoice_date", "!=", False),
|
|
("invoice_date", "<", self.invoice_date),
|
|
],
|
|
]
|
|
)
|
|
|
|
def _raise_older_conflicting_invoices(self):
|
|
self.ensure_one()
|
|
raise UserError(
|
|
_(
|
|
"Chronology conflict: A conflicting draft invoice dated before "
|
|
"{date_invoice} exists, please validate it first."
|
|
).format(date_invoice=format_date(self.env, self.invoice_date))
|
|
)
|
|
|
|
def _get_newer_conflicting_invoices_domain(self):
|
|
self.ensure_one()
|
|
return expression.AND(
|
|
[
|
|
self._get_conflicting_invoices_domain(),
|
|
[("state", "=", "posted"), ("invoice_date", ">", self.invoice_date)],
|
|
]
|
|
)
|
|
|
|
def _raise_newer_conflicting_invoices(self):
|
|
self.ensure_one()
|
|
raise UserError(
|
|
_(
|
|
"Chronology conflict: A conflicting validated invoice dated after "
|
|
"{date_invoice} exists."
|
|
).format(date_invoice=format_date(self.env, self.invoice_date))
|
|
)
|
|
|
|
def _get_sequence_order_conflicting_invoices_domain(self):
|
|
self.ensure_one()
|
|
|
|
if not self.name or self.name == "/":
|
|
return expression.FALSE_DOMAIN
|
|
|
|
last_sequence = self._get_last_sequence()
|
|
if not last_sequence or self.name > last_sequence:
|
|
return expression.FALSE_DOMAIN
|
|
|
|
return expression.AND(
|
|
[
|
|
[("name", "=", last_sequence)],
|
|
self._get_conflicting_invoices_domain(),
|
|
[("state", "=", "posted"), ("invoice_date", "<", self.invoice_date)],
|
|
]
|
|
)
|
|
|
|
def _raise_sequence_ordering_conflict(self):
|
|
self.ensure_one()
|
|
raise UserError(
|
|
_(
|
|
"Chronology conflict: An invoice with a higher number {highest_name}"
|
|
" dated before {date_invoice} exists."
|
|
).format(
|
|
highest_name=self._get_last_sequence(),
|
|
date_invoice=format_date(self.env, self.invoice_date),
|
|
)
|
|
)
|
|
|
|
def _conflicting_inv_after_sequence_before_inv_date_domain(self):
|
|
return expression.AND(
|
|
[
|
|
(
|
|
("name", ">", self.name),
|
|
("invoice_date", "<", self.invoice_date),
|
|
)
|
|
]
|
|
)
|
|
|
|
def _conflicting_inv_before_sequence_after_inv_date_domain(self):
|
|
return expression.AND(
|
|
[
|
|
(
|
|
("name", "<", self.name),
|
|
("invoice_date", ">", self.invoice_date),
|
|
)
|
|
]
|
|
)
|
|
|
|
def _get_sequence_order_conflicting_previously_validated(self):
|
|
self.ensure_one()
|
|
return expression.AND(
|
|
[
|
|
self._get_conflicting_invoices_domain(),
|
|
expression.OR(
|
|
[
|
|
self._conflicting_inv_after_sequence_before_inv_date_domain(),
|
|
self._conflicting_inv_before_sequence_after_inv_date_domain(),
|
|
]
|
|
),
|
|
]
|
|
)
|
|
|
|
def _raise_sequence_order_conflicting_previously_validated(self):
|
|
self.ensure_one()
|
|
before_inv = self.search(
|
|
self._conflicting_inv_after_sequence_before_inv_date_domain(), limit=1
|
|
)
|
|
after_inv = self.search(
|
|
self._conflicting_inv_before_sequence_after_inv_date_domain(), limit=1
|
|
)
|
|
if after_inv:
|
|
time = "before"
|
|
else:
|
|
time = "after"
|
|
raise UserError(
|
|
_(
|
|
"Chronology conflict: Invoice {name} cannot be {time} "
|
|
"invoice {inv_name}."
|
|
).format(
|
|
name=self.name,
|
|
time=time,
|
|
inv_name=after_inv.name if after_inv else before_inv.name,
|
|
date_invoice=format_date(self.env, self.invoice_date),
|
|
)
|
|
)
|
|
|
|
def write(self, vals):
|
|
if vals.get("state") != "posted":
|
|
return super().write(vals)
|
|
previously_validated = self.filtered(lambda m: m.name and m.name != "/")
|
|
newly_posted = self.filtered(lambda move: move.state != "posted")
|
|
res = super().write(vals)
|
|
for move in newly_posted & self.filtered("journal_id.check_chronology"):
|
|
if self.search(
|
|
move._get_sequence_order_conflicting_invoices_domain(), limit=1
|
|
):
|
|
move._raise_sequence_ordering_conflict()
|
|
if self.search(move._get_older_conflicting_invoices_domain(), limit=1):
|
|
move._raise_older_conflicting_invoices()
|
|
if move in previously_validated:
|
|
if self.search(
|
|
move._get_sequence_order_conflicting_previously_validated(), limit=1
|
|
):
|
|
move._raise_sequence_order_conflicting_previously_validated()
|
|
continue
|
|
if self.search(move._get_newer_conflicting_invoices_domain(), limit=1):
|
|
move._raise_newer_conflicting_invoices()
|
|
|
|
return res
|