From cc131fe08193755e7398c22c1ad30cd6fd8edef1 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Thu, 15 Jun 2023 14:45:29 +0200 Subject: [PATCH] [FIX] account_invoice_constraint_chronology: 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. --- .../model/account_move.py | 62 +++++++++++++++++ ...t_account_invoice_constraint_chronology.py | 66 +++++++++++++++++++ 2 files changed, 128 insertions(+) diff --git a/account_invoice_constraint_chronology/model/account_move.py b/account_invoice_constraint_chronology/model/account_move.py index c95dfdcb..8829254c 100644 --- a/account_invoice_constraint_chronology/model/account_move.py +++ b/account_invoice_constraint_chronology/model/account_move.py @@ -91,6 +91,64 @@ class AccountMove(models.Model): ) ) + 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) @@ -105,6 +163,10 @@ class AccountMove(models.Model): 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() diff --git a/account_invoice_constraint_chronology/tests/test_account_invoice_constraint_chronology.py b/account_invoice_constraint_chronology/tests/test_account_invoice_constraint_chronology.py index e55bfbea..18a73d52 100644 --- a/account_invoice_constraint_chronology/tests/test_account_invoice_constraint_chronology.py +++ b/account_invoice_constraint_chronology/tests/test_account_invoice_constraint_chronology.py @@ -159,3 +159,69 @@ class TestAccountInvoiceConstraintChronology(common.TransactionCase): self.invoice_1_5.invoice_date = self.yesterday with self.assertRaises(UserError): self.invoice_1_5.action_post() + + def test_modify_invoice_date_validated_past_invoice(self): + # 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. + after_5_days = self.today + timedelta(days=5) + after_10_days = self.today + timedelta(days=10) + after_15_days = self.today + timedelta(days=15) + after_20_days = self.today + timedelta(days=20) + after_25_days = self.today + timedelta(days=25) + + self.invoice_1.action_post() + + self.invoice_1_a_5 = self.invoice_1.copy() + self.invoice_1_a_5.invoice_date = after_5_days + self.invoice_1_a_5.action_post() + self.invoice_1_a_10 = self.invoice_1.copy() + self.invoice_1_a_10.invoice_date = after_10_days + self.invoice_1_a_10.action_post() + self.invoice_1_a_15 = self.invoice_1.copy() + self.invoice_1_a_15.invoice_date = after_15_days + self.invoice_1_a_15.action_post() + self.invoice_1_a_20 = self.invoice_1.copy() + self.invoice_1_a_20.invoice_date = after_20_days + self.invoice_1_a_20.action_post() + self.invoice_1_a_25 = self.invoice_1.copy() + self.invoice_1_a_25.invoice_date = after_25_days + self.invoice_1_a_25.action_post() + + self.invoice_1_a_15.button_cancel() + self.invoice_1_a_15.button_draft() + self.invoice_1_a_15.invoice_date = after_10_days + self.invoice_1_a_15.action_post() + + self.invoice_1_a_15.button_cancel() + self.invoice_1_a_15.button_draft() + self.invoice_1_a_15.invoice_date = after_10_days - timedelta(days=1) + with self.assertRaisesRegex( + UserError, + "Chronology conflict: Invoice {} cannot be before invoice {}.".format( + self.invoice_1_a_15.name, self.invoice_1_a_10.name + ), + ): + self.invoice_1_a_15.action_post() + + self.invoice_1_a_15.button_cancel() + self.invoice_1_a_15.button_draft() + self.invoice_1_a_15.invoice_date = after_20_days + self.invoice_1_a_15.action_post() + + self.invoice_1_a_15.button_cancel() + self.invoice_1_a_15.button_draft() + self.invoice_1_a_15.invoice_date = after_20_days + timedelta(days=1) + with self.assertRaisesRegex( + UserError, + "Chronology conflict: Invoice {} cannot be after invoice {}.".format( + self.invoice_1_a_15.name, self.invoice_1_a_20.name + ), + ): + self.invoice_1_a_15.action_post()