Merge pull request #27783 from hrwX/subscription_generation_fix_develop
fix(Subscription): reorder updation of end date
diff --git a/erpnext/accounts/doctype/subscription/subscription.py b/erpnext/accounts/doctype/subscription/subscription.py
index 8171b3b..de95502 100644
--- a/erpnext/accounts/doctype/subscription/subscription.py
+++ b/erpnext/accounts/doctype/subscription/subscription.py
@@ -33,7 +33,7 @@
# update start just before the subscription doc is created
self.update_subscription_period(self.start_date)
- def update_subscription_period(self, date=None):
+ def update_subscription_period(self, date=None, return_date=False):
"""
Subscription period is the period to be billed. This method updates the
beginning of the billing period and end of the billing period.
@@ -41,28 +41,41 @@
The beginning of the billing period is represented in the doctype as
`current_invoice_start` and the end of the billing period is represented
as `current_invoice_end`.
- """
- self.set_current_invoice_start(date)
- self.set_current_invoice_end()
- def set_current_invoice_start(self, date=None):
+ If return_date is True, it wont update the start and end dates.
+ This is implemented to get the dates to check if is_current_invoice_generated
"""
- This sets the date of the beginning of the current billing period.
+ _current_invoice_start = self.get_current_invoice_start(date)
+ _current_invoice_end = self.get_current_invoice_end(_current_invoice_start)
+
+ if return_date:
+ return _current_invoice_start, _current_invoice_end
+
+ self.current_invoice_start = _current_invoice_start
+ self.current_invoice_end = _current_invoice_end
+
+ def get_current_invoice_start(self, date=None):
+ """
+ This returns the date of the beginning of the current billing period.
If the `date` parameter is not given , it will be automatically set as today's
date.
"""
- if self.is_new_subscription() and self.trial_period_end and getdate(self.trial_period_end) > getdate(self.start_date):
- self.current_invoice_start = add_days(self.trial_period_end, 1)
- elif self.trial_period_start and self.is_trialling():
- self.current_invoice_start = self.trial_period_start
- elif date:
- self.current_invoice_start = date
- else:
- self.current_invoice_start = nowdate()
+ _current_invoice_start = None
- def set_current_invoice_end(self):
+ if self.is_new_subscription() and self.trial_period_end and getdate(self.trial_period_end) > getdate(self.start_date):
+ _current_invoice_start = add_days(self.trial_period_end, 1)
+ elif self.trial_period_start and self.is_trialling():
+ _current_invoice_start = self.trial_period_start
+ elif date:
+ _current_invoice_start = date
+ else:
+ _current_invoice_start = nowdate()
+
+ return _current_invoice_start
+
+ def get_current_invoice_end(self, date=None):
"""
- This sets the date of the end of the current billing period.
+ This returns the date of the end of the current billing period.
If the subscription is in trial period, it will be set as the end of the
trial period.
@@ -71,44 +84,47 @@
current billing period where `x` is the billing interval from the
`Subscription Plan` in the `Subscription`.
"""
- if self.is_trialling() and getdate(self.current_invoice_start) < getdate(self.trial_period_end):
- self.current_invoice_end = self.trial_period_end
+ _current_invoice_end = None
+
+ if self.is_trialling() and getdate(date) < getdate(self.trial_period_end):
+ _current_invoice_end = self.trial_period_end
else:
billing_cycle_info = self.get_billing_cycle_data()
if billing_cycle_info:
- if self.is_new_subscription() and getdate(self.start_date) < getdate(self.current_invoice_start):
- self.current_invoice_end = add_to_date(self.start_date, **billing_cycle_info)
+ if self.is_new_subscription() and getdate(self.start_date) < getdate(date):
+ _current_invoice_end = add_to_date(self.start_date, **billing_cycle_info)
# For cases where trial period is for an entire billing interval
- if getdate(self.current_invoice_end) < getdate(self.current_invoice_start):
- self.current_invoice_end = add_to_date(self.current_invoice_start, **billing_cycle_info)
+ if getdate(self.current_invoice_end) < getdate(date):
+ _current_invoice_end = add_to_date(date, **billing_cycle_info)
else:
- self.current_invoice_end = add_to_date(self.current_invoice_start, **billing_cycle_info)
+ _current_invoice_end = add_to_date(date, **billing_cycle_info)
else:
- self.current_invoice_end = get_last_day(self.current_invoice_start)
+ _current_invoice_end = get_last_day(date)
if self.follow_calendar_months:
billing_info = self.get_billing_cycle_and_interval()
billing_interval_count = billing_info[0]['billing_interval_count']
calendar_months = get_calendar_months(billing_interval_count)
calendar_month = 0
- current_invoice_end_month = getdate(self.current_invoice_end).month
- current_invoice_end_year = getdate(self.current_invoice_end).year
+ current_invoice_end_month = getdate(_current_invoice_end).month
+ current_invoice_end_year = getdate(_current_invoice_end).year
for month in calendar_months:
if month <= current_invoice_end_month:
calendar_month = month
if cint(calendar_month - billing_interval_count) <= 0 and \
- getdate(self.current_invoice_start).month != 1:
+ getdate(date).month != 1:
calendar_month = 12
current_invoice_end_year -= 1
- self.current_invoice_end = get_last_day(cstr(current_invoice_end_year) + '-' \
- + cstr(calendar_month) + '-01')
+ _current_invoice_end = get_last_day(cstr(current_invoice_end_year) + '-' + cstr(calendar_month) + '-01')
- if self.end_date and getdate(self.current_invoice_end) > getdate(self.end_date):
- self.current_invoice_end = self.end_date
+ if self.end_date and getdate(_current_invoice_end) > getdate(self.end_date):
+ _current_invoice_end = self.end_date
+
+ return _current_invoice_end
@staticmethod
def validate_plans_billing_cycle(billing_cycle_data):
@@ -488,8 +504,9 @@
def is_current_invoice_generated(self):
invoice = self.get_current_invoice()
+ _current_start_date, _current_end_date = self.update_subscription_period(date=add_days(self.current_invoice_end, 1), return_date=True)
- if invoice and getdate(self.current_invoice_start) <= getdate(invoice.posting_date) <= getdate(self.current_invoice_end):
+ if invoice and getdate(_current_start_date) <= getdate(invoice.posting_date) <= getdate(_current_end_date):
return True
return False
@@ -542,15 +559,15 @@
else:
self.set_status_grace_period()
- if getdate() > getdate(self.current_invoice_end):
- self.update_subscription_period(add_days(self.current_invoice_end, 1))
-
# Generate invoices periodically even if current invoice are unpaid
if self.generate_new_invoices_past_due_date and not self.is_current_invoice_generated() and (self.is_postpaid_to_invoice()
or self.is_prepaid_to_invoice()):
prorate = frappe.db.get_single_value('Subscription Settings', 'prorate')
self.generate_invoice(prorate)
+ if getdate() > getdate(self.current_invoice_end):
+ self.update_subscription_period(add_days(self.current_invoice_end, 1))
+
@staticmethod
def is_paid(invoice):
"""
diff --git a/erpnext/accounts/doctype/subscription/test_subscription.py b/erpnext/accounts/doctype/subscription/test_subscription.py
index e2cf4d5..0f7a0a8 100644
--- a/erpnext/accounts/doctype/subscription/test_subscription.py
+++ b/erpnext/accounts/doctype/subscription/test_subscription.py
@@ -18,6 +18,7 @@
from erpnext.accounts.doctype.subscription.subscription import get_prorata_factor
+test_dependencies = ("UOM", "Item Group", "Item")
def create_plan():
if not frappe.db.exists('Subscription Plan', '_Test Plan Name'):
@@ -68,7 +69,6 @@
supplier.insert()
class TestSubscription(unittest.TestCase):
-
def setUp(self):
create_plan()