changeset f6d4d86c2fa0 in modules/sale_subscription:default
details: 
https://hg.tryton.org/modules/sale_subscription?cmd=changeset;node=f6d4d86c2fa0
description:
        Ensure recurrence generates at least one occurrence

        Depending on the start date, a recurrence does not always generate 
occurrence.

        issue10001
        review349361002
diffstat:

 exceptions.py   |   4 ++++
 message.xml     |   6 ++++++
 subscription.py |  49 +++++++++++++++++++++++++++++++++++++++++--------
 3 files changed, 51 insertions(+), 8 deletions(-)

diffs (103 lines):

diff -r 8412a0fb2ccf -r f6d4d86c2fa0 exceptions.py
--- a/exceptions.py     Sat Dec 19 17:08:47 2020 +0100
+++ b/exceptions.py     Fri Feb 12 20:24:06 2021 +0100
@@ -5,6 +5,10 @@
 from trytond.model.exceptions import ValidationError
 
 
+class InvalidRecurrence(ValidationError):
+    pass
+
+
 class InvoiceError(UserError):
     pass
 
diff -r 8412a0fb2ccf -r f6d4d86c2fa0 message.xml
--- a/message.xml       Sat Dec 19 17:08:47 2020 +0100
+++ b/message.xml       Fri Feb 12 20:24:06 2021 +0100
@@ -3,6 +3,12 @@
 this repository contains the full copyright notices and license terms. -->
 <tryton>
     <data grouped="1">
+        <record model="ir.message" id="msg_invoice_recurrence_invalid">
+            <field name="text">The invoice recurrence of subscription 
"%(subscription)s" does not generate any occurrence.</field>
+        </record>
+        <record model="ir.message" id="msg_consumption_recurrence_invalid">
+            <field name="text">The consumption recurrence of line "%(line)s" 
of subscription "%(subscription)s" does not generate any occurrence.</field>
+        </record>
         <record model="ir.message" id="msg_consumption_modify_invoiced">
             <field name="text">You cannot modify invoiced consumption 
"%(consumption)s".</field>
         </record>
diff -r 8412a0fb2ccf -r f6d4d86c2fa0 subscription.py
--- a/subscription.py   Sat Dec 19 17:08:47 2020 +0100
+++ b/subscription.py   Fri Feb 12 20:24:06 2021 +0100
@@ -21,7 +21,7 @@
 from trytond.modules.company.model import (
     employee_field, set_employee, reset_employee)
 from trytond.modules.product import price_digits, round_price
-from .exceptions import InvoiceError
+from .exceptions import InvalidRecurrence, InvoiceError
 
 
 class Subscription(Workflow, ModelSQL, ModelView):
@@ -267,7 +267,23 @@
         dt = datetime.datetime.combine(date, datetime.time())
         inc = (start_date == date) and not self.next_invoice_date
         next_date = rruleset.after(dt, inc=inc)
-        return next_date.date()
+        if next_date:
+            return next_date.date()
+
+    @classmethod
+    def validate(cls, subscriptions):
+        super().validate(subscriptions)
+        for subscription in subscriptions:
+            subscription.validate_invoice_recurrence()
+
+    def validate_invoice_recurrence(self):
+        start_date = self.invoice_start_date or self.start_date
+        try:
+            self.invoice_recurrence.rruleset(start_date)[0]
+        except IndexError:
+            raise InvalidRecurrence(gettext(
+                    'sale_subscription.msg_invoice_recurrence_invalid',
+                    subscription=self.rec_name))
 
     @classmethod
     def copy(cls, subscriptions, default=None):
@@ -791,12 +807,29 @@
         rruleset = self.consumption_recurrence.rruleset(self.start_date)
         dt = datetime.datetime.combine(date, datetime.time())
         inc = (self.start_date == date) and not self.next_consumption_date
-        next_date = rruleset.after(dt, inc=inc).date()
-        for end_date in [self.end_date, self.subscription.end_date]:
-            if end_date:
-                if next_date > end_date:
-                    return None
-        return next_date
+        next_date = rruleset.after(dt, inc=inc)
+        if next_date:
+            next_date = next_date.date()
+            for end_date in [self.end_date, self.subscription.end_date]:
+                if end_date:
+                    if next_date > end_date:
+                        return None
+            return next_date
+
+    @classmethod
+    def validate(cls, lines):
+        super().validate(lines)
+        for line in lines:
+            line.validate_consumption_recurrence()
+
+    def validate_consumption_recurrence(self):
+        try:
+            self.consumption_recurrence.rruleset(self.start_date)[0]
+        except IndexError:
+            raise InvalidRecurrence(gettext(
+                    'sale_subscription.msg_consumption_recurrence_invalid',
+                    line=self.rec_name,
+                    subscription=self.subscription.rec_name))
 
     @classmethod
     def copy(cls, lines, default=None):

Reply via email to