From c2459c481b763b90e3771a9307698652e160f0e3 Mon Sep 17 00:00:00 2001 From: Denis Roussel Date: Thu, 16 Jun 2022 15:43:54 +0200 Subject: [PATCH 1/4] [14.0][FIX] contract: Compute correctly the recurring next date at end --- contract/models/contract.py | 12 +++-------- contract/models/contract_line.py | 13 ++++++++++++ contract/tests/test_contract.py | 34 ++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/contract/models/contract.py b/contract/models/contract.py index 5eb58479f..8abbccf99 100644 --- a/contract/models/contract.py +++ b/contract/models/contract.py @@ -322,15 +322,9 @@ class ContractContract(models.Model): and (not l.display_type or l.is_recurring_note) ) ).mapped("recurring_next_date") - # we give priority to computation from date_start if modified - if ( - contract._origin - and contract._origin.date_start != contract.date_start - or not recurring_next_date - ): - super(ContractContract, contract)._compute_recurring_next_date() - else: - contract.recurring_next_date = min(recurring_next_date) + contract.recurring_next_date = ( + min(recurring_next_date) if recurring_next_date else False + ) @api.depends("contract_line_ids.create_invoice_visibility") def _compute_create_invoice_visibility(self): diff --git a/contract/models/contract_line.py b/contract/models/contract_line.py index c38f75ed3..bdfc1927b 100644 --- a/contract/models/contract_line.py +++ b/contract/models/contract_line.py @@ -669,6 +669,10 @@ class ContractLine(models.Model): ), } + def _prepare_value_for_contract_stop(self, date_end): + self.ensure_one() + return {"date_end": date_end} + def stop(self, date_end, manual_renew_needed=False, post_message=True): """ Put date_end on contract line @@ -687,6 +691,15 @@ class ContractLine(models.Model): rec.write( rec._prepare_value_for_stop(date_end, manual_renew_needed) ) + if not rec.contract_id.line_recurrence: + # FIXME: This should not happen. As recurring_next_date + # is computed on contract from lines ones, the only + # write({"date_end"}) on lines should be sufficent + # The set_recurrence_field() on date_end should be + # suppressed. + rec.contract_id.write( + rec._prepare_value_for_contract_stop(date_end) + ) if post_message: msg = _( """Contract line for {product} diff --git a/contract/tests/test_contract.py b/contract/tests/test_contract.py index 4fc1ac1d7..24a86442d 100644 --- a/contract/tests/test_contract.py +++ b/contract/tests/test_contract.py @@ -2322,6 +2322,40 @@ class TestContract(TestContractBase): self.assertFalse(self.contract.terminate_reason_id) self.assertFalse(self.contract.terminate_comment) + def test_action_terminate_contract_check_recurring_dates(self): + """ + The use case here is to use a contract with recurrence on its level. + + Create a first invoice + Then, terminate it => Lines should have a end_date + Then, create a new invoice (the last one). + The recurring next date should be False. + """ + group_can_terminate_contract = self.env.ref("contract.can_terminate_contract") + group_can_terminate_contract.users |= self.env.user + self.contract3.contract_line_ids.write({"date_start": "2018-03-01"}) + self.contract3.recurring_create_invoice() + self.assertEqual(to_date("2018-04-01"), self.contract3.recurring_next_date) + + action = self.contract3.action_terminate_contract() + wizard = ( + self.env[action["res_model"]] + .with_context(action["context"]) + .create( + { + "terminate_date": "2018-04-02", + "terminate_reason_id": self.terminate_reason.id, + "terminate_comment": "terminate_comment", + } + ) + ) + wizard.terminate_contract() + # This is the last invoice + self.contract3.recurring_create_invoice() + + # Recurring next date should be False + self.assertFalse(self.contract3.recurring_next_date) + def test_terminate_date_before_last_date_invoiced(self): self.contract.recurring_create_invoice() self.assertEqual(self.acct_line.last_date_invoiced, to_date("2018-02-14")) From b358e36739082afe86127edbb899d11591e71105 Mon Sep 17 00:00:00 2001 From: Denis Roussel Date: Thu, 16 Jun 2022 15:51:52 +0200 Subject: [PATCH 2/4] [14.0][FIX] contract: Don't write recurring_next_date as computed value --- contract/models/contract_line.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/contract/models/contract_line.py b/contract/models/contract_line.py index bdfc1927b..399bc43d2 100644 --- a/contract/models/contract_line.py +++ b/contract/models/contract_line.py @@ -659,14 +659,6 @@ class ContractLine(models.Model): "date_end": date_end, "is_auto_renew": False, "manual_renew_needed": manual_renew_needed, - "recurring_next_date": self.get_next_invoice_date( - self.next_period_date_start, - self.recurring_invoicing_type, - self.recurring_invoicing_offset, - self.recurring_rule_type, - self.recurring_interval, - max_date_end=date_end, - ), } def _prepare_value_for_contract_stop(self, date_end): From c1a0f02ac32ae502039352741facc4ec2105826e Mon Sep 17 00:00:00 2001 From: Denis Roussel Date: Fri, 17 Jun 2022 10:11:06 +0200 Subject: [PATCH 3/4] [14.0][IMP] contract: Don't set recurrence field for recurring_next_date as full computed --- contract/models/abstract_contract_line.py | 5 ----- contract/models/contract.py | 4 ++++ 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/contract/models/abstract_contract_line.py b/contract/models/abstract_contract_line.py index dce583376..b738de241 100644 --- a/contract/models/abstract_contract_line.py +++ b/contract/models/abstract_contract_line.py @@ -162,11 +162,6 @@ class ContractAbstractContractLine(models.AbstractModel): def _compute_date_start(self): self._set_recurrence_field("date_start") - @api.depends("contract_id.recurring_next_date", "contract_id.line_recurrence") - def _compute_recurring_next_date(self): - super()._compute_recurring_next_date() - self._set_recurrence_field("recurring_next_date") - @api.depends("display_type", "note_invoicing_mode") def _compute_is_recurring_note(self): for record in self: diff --git a/contract/models/contract.py b/contract/models/contract.py index 8abbccf99..ccaf3b30e 100644 --- a/contract/models/contract.py +++ b/contract/models/contract.py @@ -314,6 +314,8 @@ class ContractContract(models.Model): "contract_line_ids.is_canceled", ) def _compute_recurring_next_date(self): + # Compute the recurring_next_date on the contract based on the one + # defined on line level. for contract in self: recurring_next_date = contract.contract_line_ids.filtered( lambda l: ( @@ -322,6 +324,8 @@ class ContractContract(models.Model): and (not l.display_type or l.is_recurring_note) ) ).mapped("recurring_next_date") + # Take the earliest or set it as False if contract is stopped + # (no recurring_next_date). contract.recurring_next_date = ( min(recurring_next_date) if recurring_next_date else False ) From 4307cf149d1eb637da156f59562e41a6c15f5d40 Mon Sep 17 00:00:00 2001 From: Denis Roussel Date: Fri, 17 Jun 2022 10:11:47 +0200 Subject: [PATCH 4/4] [14.0][IMP] contract_sale_generation: recompute recurring_next_date after creation in tests --- contract_sale_generation/tests/common.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/contract_sale_generation/tests/common.py b/contract_sale_generation/tests/common.py index cea97f152..dad87c2d9 100644 --- a/contract_sale_generation/tests/common.py +++ b/contract_sale_generation/tests/common.py @@ -100,7 +100,10 @@ class ContractSaleCommon: line_form.recurring_rule_type = "monthly" line_form.recurring_interval = 1 line_form.date_start = "2020-01-15" - line_form.recurring_next_date = "2020-01-15" + # TODO: Check why this is needed after Form use + # At _exit_, during the recurring_next_date compute on contract, + # contract_line_ids is void... + cls.contract._compute_recurring_next_date() cls.contract_line = cls.contract.contract_line_ids[1] cls.contract2 = cls.env["contract.contract"].create(