mirror of
https://github.com/frappe/erpnext.git
synced 2026-02-16 08:05:00 +00:00
Merge pull request #51199 from Jatin3128/subscription_date_fix
fix(subscription): add cancellation and date validation
This commit is contained in:
@@ -222,7 +222,11 @@ class Subscription(Document):
|
||||
"""
|
||||
if self.is_trialling():
|
||||
self.status = "Trialing"
|
||||
elif self.status == "Active" and self.end_date and getdate(posting_date) > getdate(self.end_date):
|
||||
elif (
|
||||
not self.has_outstanding_invoice()
|
||||
and self.end_date
|
||||
and getdate(posting_date) > getdate(self.end_date)
|
||||
):
|
||||
self.status = "Completed"
|
||||
elif self.is_past_grace_period():
|
||||
self.status = self.get_status_for_past_grace_period()
|
||||
@@ -562,6 +566,17 @@ class Subscription(Document):
|
||||
self.current_invoice_start, self.current_invoice_end
|
||||
) and self.can_generate_new_invoice(posting_date):
|
||||
self.generate_invoice(posting_date=posting_date)
|
||||
if self.end_date:
|
||||
next_start = add_days(self.current_invoice_end, 1)
|
||||
|
||||
if getdate(next_start) > getdate(self.end_date):
|
||||
if self.cancel_at_period_end:
|
||||
self.cancel_subscription()
|
||||
else:
|
||||
self.set_subscription_status(posting_date=posting_date)
|
||||
|
||||
self.save()
|
||||
return
|
||||
self.update_subscription_period(add_days(self.current_invoice_end, 1))
|
||||
elif posting_date and getdate(posting_date) > getdate(self.current_invoice_end):
|
||||
self.update_subscription_period()
|
||||
|
||||
@@ -17,6 +17,7 @@ from frappe.utils.data import (
|
||||
nowdate,
|
||||
)
|
||||
|
||||
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
|
||||
from erpnext.accounts.doctype.subscription.subscription import get_prorata_factor
|
||||
|
||||
EXTRA_TEST_RECORD_DEPENDENCIES = ("UOM", "Item Group", "Item")
|
||||
@@ -583,6 +584,105 @@ class TestSubscription(IntegrationTestCase):
|
||||
subscription.process(nowdate())
|
||||
self.assertEqual(len(subscription.invoices), 1)
|
||||
|
||||
def test_subscription_auto_cancellation(self):
|
||||
create_plan(
|
||||
plan_name="_Test plan name 10",
|
||||
cost=80,
|
||||
currency="INR",
|
||||
billing_interval="Day",
|
||||
billing_interval_count=3,
|
||||
)
|
||||
start_date = getdate("2025-01-01")
|
||||
subscription = create_subscription(
|
||||
start_date=start_date,
|
||||
end_date=add_days(start_date, 8),
|
||||
cancel_at_period_end=1,
|
||||
generate_new_invoices_past_due_date=1,
|
||||
generate_invoice_at="Beginning of the current subscription period",
|
||||
plans=[{"plan": "_Test plan name 10", "qty": 1}],
|
||||
)
|
||||
subscription.process(posting_date=add_days(start_date, 2))
|
||||
self.assertEqual(len(subscription.invoices), 1)
|
||||
|
||||
subscription.process(posting_date=add_days(start_date, 5))
|
||||
self.assertEqual(len(subscription.invoices), 2)
|
||||
|
||||
subscription.process(posting_date=add_days(start_date, 8))
|
||||
self.assertEqual(len(subscription.invoices), 3)
|
||||
self.assertEqual(subscription.status, "Cancelled")
|
||||
|
||||
def test_subscription_auto_cancellation_uneven_cycle(self):
|
||||
create_plan(
|
||||
plan_name="_Test plan name 10",
|
||||
cost=80,
|
||||
currency="INR",
|
||||
billing_interval="Day",
|
||||
billing_interval_count=3,
|
||||
)
|
||||
start_date = getdate("2025-01-01")
|
||||
subscription = create_subscription(
|
||||
start_date=start_date,
|
||||
end_date=add_days(start_date, 6),
|
||||
cancel_at_period_end=1,
|
||||
generate_new_invoices_past_due_date=1,
|
||||
generate_invoice_at="Beginning of the current subscription period",
|
||||
plans=[{"plan": "_Test plan name 10", "qty": 1}],
|
||||
)
|
||||
|
||||
subscription.process(posting_date=add_days(start_date, 2))
|
||||
self.assertEqual(len(subscription.invoices), 1)
|
||||
|
||||
subscription.process(posting_date=add_days(start_date, 5))
|
||||
self.assertEqual(len(subscription.invoices), 2)
|
||||
|
||||
# partial last cycle invoice
|
||||
subscription.process(posting_date=add_days(start_date, 6))
|
||||
self.assertEqual(len(subscription.invoices), 3)
|
||||
|
||||
self.assertEqual(subscription.status, "Cancelled")
|
||||
|
||||
self.assertRaises(frappe.ValidationError, subscription.process, posting_date=add_days(start_date, 7))
|
||||
|
||||
def test_subscription_auto_completion(self):
|
||||
create_plan(
|
||||
plan_name="_Test Plan 3 Day",
|
||||
cost=100,
|
||||
billing_interval="Day",
|
||||
billing_interval_count=3,
|
||||
currency="INR",
|
||||
)
|
||||
|
||||
start_date = getdate("2025-01-01")
|
||||
end_date = add_days(start_date, 6)
|
||||
|
||||
subscription = create_subscription(
|
||||
start_date=start_date,
|
||||
end_date=end_date,
|
||||
party_type="Customer",
|
||||
party="_Test Customer",
|
||||
generate_invoice_at="Beginning of the current subscription period",
|
||||
generate_new_invoices_past_due_date=1,
|
||||
plans=[{"plan": "_Test Plan 3 Day", "qty": 1}],
|
||||
)
|
||||
|
||||
for day in range(0, 10):
|
||||
if subscription.status == "Cancelled":
|
||||
break
|
||||
subscription.process(posting_date=add_days(start_date, day))
|
||||
|
||||
invoices = frappe.get_all(
|
||||
"Sales Invoice",
|
||||
filters={"subscription": subscription.name, "docstatus": 1},
|
||||
fields=["name", "from_date", "to_date"],
|
||||
order_by="from_date asc",
|
||||
)
|
||||
for invoice in invoices:
|
||||
pi = get_payment_entry("Sales Invoice", invoice.name)
|
||||
pi.submit()
|
||||
# After processing through all days, subscription should be completed
|
||||
subscription.process(posting_date=add_days(end_date, 1))
|
||||
self.assertEqual(subscription.status, "Completed")
|
||||
|
||||
|
||||
def make_plans():
|
||||
create_plan(plan_name="_Test Plan Name", cost=900, currency="INR")
|
||||
@@ -659,6 +759,7 @@ def create_subscription(**kwargs):
|
||||
subscription.trial_period_start = kwargs.get("trial_period_start")
|
||||
subscription.trial_period_end = kwargs.get("trial_period_end")
|
||||
subscription.start_date = kwargs.get("start_date")
|
||||
subscription.end_date = kwargs.get("end_date")
|
||||
subscription.generate_invoice_at = kwargs.get("generate_invoice_at")
|
||||
subscription.additional_discount_percentage = kwargs.get("additional_discount_percentage")
|
||||
subscription.additional_discount_amount = kwargs.get("additional_discount_amount")
|
||||
@@ -667,6 +768,7 @@ def create_subscription(**kwargs):
|
||||
subscription.submit_invoice = kwargs.get("submit_invoice")
|
||||
subscription.days_until_due = kwargs.get("days_until_due")
|
||||
subscription.number_of_days = kwargs.get("number_of_days")
|
||||
subscription.cancel_at_period_end = kwargs.get("cancel_at_period_end")
|
||||
|
||||
if not kwargs.get("plans"):
|
||||
subscription.append("plans", {"plan": "_Test Plan Name", "qty": 1})
|
||||
|
||||
Reference in New Issue
Block a user