mirror of
https://github.com/frappe/erpnext.git
synced 2026-05-22 14:39:19 +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():
|
if self.is_trialling():
|
||||||
self.status = "Trialing"
|
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"
|
self.status = "Completed"
|
||||||
elif self.is_past_grace_period():
|
elif self.is_past_grace_period():
|
||||||
self.status = self.get_status_for_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
|
self.current_invoice_start, self.current_invoice_end
|
||||||
) and self.can_generate_new_invoice(posting_date):
|
) and self.can_generate_new_invoice(posting_date):
|
||||||
self.generate_invoice(posting_date=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))
|
self.update_subscription_period(add_days(self.current_invoice_end, 1))
|
||||||
elif posting_date and getdate(posting_date) > getdate(self.current_invoice_end):
|
elif posting_date and getdate(posting_date) > getdate(self.current_invoice_end):
|
||||||
self.update_subscription_period()
|
self.update_subscription_period()
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ from frappe.utils.data import (
|
|||||||
nowdate,
|
nowdate,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
|
||||||
from erpnext.accounts.doctype.subscription.subscription import get_prorata_factor
|
from erpnext.accounts.doctype.subscription.subscription import get_prorata_factor
|
||||||
|
|
||||||
EXTRA_TEST_RECORD_DEPENDENCIES = ("UOM", "Item Group", "Item")
|
EXTRA_TEST_RECORD_DEPENDENCIES = ("UOM", "Item Group", "Item")
|
||||||
@@ -583,6 +584,105 @@ class TestSubscription(IntegrationTestCase):
|
|||||||
subscription.process(nowdate())
|
subscription.process(nowdate())
|
||||||
self.assertEqual(len(subscription.invoices), 1)
|
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():
|
def make_plans():
|
||||||
create_plan(plan_name="_Test Plan Name", cost=900, currency="INR")
|
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_start = kwargs.get("trial_period_start")
|
||||||
subscription.trial_period_end = kwargs.get("trial_period_end")
|
subscription.trial_period_end = kwargs.get("trial_period_end")
|
||||||
subscription.start_date = kwargs.get("start_date")
|
subscription.start_date = kwargs.get("start_date")
|
||||||
|
subscription.end_date = kwargs.get("end_date")
|
||||||
subscription.generate_invoice_at = kwargs.get("generate_invoice_at")
|
subscription.generate_invoice_at = kwargs.get("generate_invoice_at")
|
||||||
subscription.additional_discount_percentage = kwargs.get("additional_discount_percentage")
|
subscription.additional_discount_percentage = kwargs.get("additional_discount_percentage")
|
||||||
subscription.additional_discount_amount = kwargs.get("additional_discount_amount")
|
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.submit_invoice = kwargs.get("submit_invoice")
|
||||||
subscription.days_until_due = kwargs.get("days_until_due")
|
subscription.days_until_due = kwargs.get("days_until_due")
|
||||||
subscription.number_of_days = kwargs.get("number_of_days")
|
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"):
|
if not kwargs.get("plans"):
|
||||||
subscription.append("plans", {"plan": "_Test Plan Name", "qty": 1})
|
subscription.append("plans", {"plan": "_Test Plan Name", "qty": 1})
|
||||||
|
|||||||
Reference in New Issue
Block a user