add ability to cancel, restart and refresh subscription
This commit is contained in:
parent
2cccad0274
commit
8f37926ca8
@ -3,6 +3,75 @@
|
|||||||
|
|
||||||
frappe.ui.form.on('Subscriptions', {
|
frappe.ui.form.on('Subscriptions', {
|
||||||
refresh: function(frm) {
|
refresh: function(frm) {
|
||||||
|
if(!frm.is_new()){
|
||||||
|
if(frm.doc.status !== 'Canceled'){
|
||||||
|
frm.add_custom_button(
|
||||||
|
__('Cancel Subscription'),
|
||||||
|
() => frm.events.cancel_this_subscription(frm)
|
||||||
|
);
|
||||||
|
frm.add_custom_button(
|
||||||
|
__('Fetch Subscription Updates'),
|
||||||
|
() => frm.events.get_subscription_updates(frm)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if(frm.doc.status === 'Canceled'){
|
||||||
|
frm.add_custom_button(
|
||||||
|
__('Restart Subscription'),
|
||||||
|
() => frm.events.renew_this_subscription(frm)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
cancel_this_subscription: function(frm) {
|
||||||
|
const doc = frm.doc;
|
||||||
|
frappe.confirm(
|
||||||
|
__('This action will stop future billing. Are you sure you want to cancel this subscription?'),
|
||||||
|
function() {
|
||||||
|
frappe.call({
|
||||||
|
method:
|
||||||
|
"erpnext.accounts.doctype.subscriptions.subscriptions.cancel_subscription",
|
||||||
|
args: {name: doc.name},
|
||||||
|
callback: function(data){
|
||||||
|
if(!data.exc){
|
||||||
|
frm.reload_doc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
renew_this_subscription: function(frm) {
|
||||||
|
const doc = frm.doc;
|
||||||
|
frappe.confirm(
|
||||||
|
__('You will lose records of previously generated invoices. Are you sure you want to restart this subscription?'),
|
||||||
|
function() {
|
||||||
|
frappe.call({
|
||||||
|
method:
|
||||||
|
"erpnext.accounts.doctype.subscriptions.subscriptions.restart_subscription",
|
||||||
|
args: {name: doc.name},
|
||||||
|
callback: function(data){
|
||||||
|
if(!data.exc){
|
||||||
|
frm.reload_doc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
get_subscription_updates: function(frm) {
|
||||||
|
const doc = frm.doc;
|
||||||
|
frappe.call({
|
||||||
|
method:
|
||||||
|
"erpnext.accounts.doctype.subscriptions.subscriptions.get_subscription_updates",
|
||||||
|
args: {name: doc.name},
|
||||||
|
callback: function(data){
|
||||||
|
if(!data.exc){
|
||||||
|
frm.reload_doc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -14,8 +14,8 @@ class Subscriptions(Document):
|
|||||||
# update start just before the subscription doc is created
|
# update start just before the subscription doc is created
|
||||||
self.update_subscription_period()
|
self.update_subscription_period()
|
||||||
|
|
||||||
def update_subscription_period(self):
|
def update_subscription_period(self, date=None):
|
||||||
self.set_current_invoice_start()
|
self.set_current_invoice_start(date)
|
||||||
self.set_current_invoice_end()
|
self.set_current_invoice_end()
|
||||||
|
|
||||||
def set_current_invoice_start(self, date=None):
|
def set_current_invoice_start(self, date=None):
|
||||||
@ -228,16 +228,19 @@ class Subscriptions(Document):
|
|||||||
"""
|
"""
|
||||||
if self.status == 'Active':
|
if self.status == 'Active':
|
||||||
self.process_for_active()
|
self.process_for_active()
|
||||||
elif self.status == 'Past Due Date':
|
elif self.status in ['Past Due Date', 'Unpaid']:
|
||||||
self.process_for_past_due_date()
|
self.process_for_past_due_date()
|
||||||
self.save()
|
|
||||||
# process_for_unpaid()
|
if self.status != 'Canceled':
|
||||||
|
self.save()
|
||||||
|
|
||||||
def process_for_active(self):
|
def process_for_active(self):
|
||||||
if getdate(nowdate()) > getdate(self.current_invoice_end) and not self.has_outstanding_invoice():
|
if getdate(nowdate()) > getdate(self.current_invoice_end) and not self.has_outstanding_invoice():
|
||||||
self.generate_invoice()
|
self.generate_invoice()
|
||||||
|
if self.current_invoice_is_past_due():
|
||||||
|
self.status = 'Past Due Date'
|
||||||
|
|
||||||
if self.current_invoice_is_past_due():
|
if self.current_invoice_is_past_due() and getdate(nowdate()) > getdate(self.current_invoice_end):
|
||||||
self.status = 'Past Due Date'
|
self.status = 'Past Due Date'
|
||||||
|
|
||||||
def process_for_past_due_date(self):
|
def process_for_past_due_date(self):
|
||||||
@ -247,7 +250,7 @@ class Subscriptions(Document):
|
|||||||
else:
|
else:
|
||||||
if self.is_not_outstanding(current_invoice):
|
if self.is_not_outstanding(current_invoice):
|
||||||
self.status = 'Active'
|
self.status = 'Active'
|
||||||
self.update_subscription_period()
|
self.update_subscription_period(nowdate())
|
||||||
else:
|
else:
|
||||||
self.set_status_grace_period()
|
self.set_status_grace_period()
|
||||||
|
|
||||||
@ -261,3 +264,41 @@ class Subscriptions(Document):
|
|||||||
else:
|
else:
|
||||||
return not self.is_not_outstanding(current_invoice)
|
return not self.is_not_outstanding(current_invoice)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def cancel_subscription(self):
|
||||||
|
"""
|
||||||
|
This sets the subscription as cancelled. It will stop invoices from being generated
|
||||||
|
but it will not affect already created invoices.
|
||||||
|
"""
|
||||||
|
self.status = 'Canceled'
|
||||||
|
self.cancelation_date = nowdate()
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
def restart_subscription(self):
|
||||||
|
"""
|
||||||
|
This sets the subscription as active. The subscription will be made to be like a new
|
||||||
|
subscription but new trial periods will not be allowed.
|
||||||
|
"""
|
||||||
|
self.status = 'Active'
|
||||||
|
self.cancelation_date = None
|
||||||
|
self.update_subscription_period(nowdate())
|
||||||
|
self.invoices = []
|
||||||
|
self.save()
|
||||||
|
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def cancel_subscription(name):
|
||||||
|
subscription = frappe.get_doc('Subscriptions', name)
|
||||||
|
subscription.cancel_subscription()
|
||||||
|
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def restart_subscription(name):
|
||||||
|
subscription = frappe.get_doc('Subscriptions', name)
|
||||||
|
subscription.restart_subscription()
|
||||||
|
|
||||||
|
|
||||||
|
@frappe.whitelist()
|
||||||
|
def get_subscription_updates(name):
|
||||||
|
subscription = frappe.get_doc('Subscriptions', name)
|
||||||
|
subscription.process()
|
@ -267,5 +267,123 @@ class TestSubscriptions(unittest.TestCase):
|
|||||||
|
|
||||||
subscription.delete()
|
subscription.delete()
|
||||||
|
|
||||||
|
def test_subcription_cancelation(self):
|
||||||
|
subscription = frappe.new_doc('Subscriptions')
|
||||||
|
subscription.subscriber = '_Test Customer'
|
||||||
|
subscription.append('plans', {'plan': '_Test Plan Name'})
|
||||||
|
subscription.save()
|
||||||
|
subscription.cancel_subscription()
|
||||||
|
|
||||||
|
self.assertEqual(subscription.status, 'Canceled')
|
||||||
|
|
||||||
|
subscription.delete()
|
||||||
|
|
||||||
|
def test_subcription_cancelation_and_process(self):
|
||||||
|
settings = frappe.get_single('Subscription Settings')
|
||||||
|
default_grace_period_action = settings.cancel_after_grace
|
||||||
|
settings.cancel_after_grace = 1
|
||||||
|
settings.save()
|
||||||
|
|
||||||
|
subscription = frappe.new_doc('Subscriptions')
|
||||||
|
subscription.subscriber = '_Test Customer'
|
||||||
|
subscription.append('plans', {'plan': '_Test Plan Name'})
|
||||||
|
subscription.insert()
|
||||||
|
subscription.set_current_invoice_start('2018-01-01')
|
||||||
|
subscription.set_current_invoice_end()
|
||||||
|
subscription.process() # generate first invoice
|
||||||
|
invoices = len(subscription.invoices)
|
||||||
|
|
||||||
|
self.assertEqual(subscription.status, 'Past Due Date')
|
||||||
|
self.assertEqual(len(subscription.invoices), invoices)
|
||||||
|
|
||||||
|
subscription.cancel_subscription()
|
||||||
|
self.assertEqual(subscription.status, 'Canceled')
|
||||||
|
self.assertEqual(len(subscription.invoices), invoices)
|
||||||
|
|
||||||
|
subscription.process()
|
||||||
|
self.assertEqual(subscription.status, 'Canceled')
|
||||||
|
self.assertEqual(len(subscription.invoices), invoices)
|
||||||
|
|
||||||
|
subscription.process()
|
||||||
|
self.assertEqual(subscription.status, 'Canceled')
|
||||||
|
self.assertEqual(len(subscription.invoices), invoices)
|
||||||
|
|
||||||
|
settings.cancel_after_grace = default_grace_period_action
|
||||||
|
settings.save()
|
||||||
|
subscription.delete()
|
||||||
|
|
||||||
|
def test_subscription_restart_and_process(self):
|
||||||
|
settings = frappe.get_single('Subscription Settings')
|
||||||
|
default_grace_period_action = settings.cancel_after_grace
|
||||||
|
settings.grace_period = 0
|
||||||
|
settings.cancel_after_grace = 0
|
||||||
|
settings.save()
|
||||||
|
|
||||||
|
subscription = frappe.new_doc('Subscriptions')
|
||||||
|
subscription.subscriber = '_Test Customer'
|
||||||
|
subscription.append('plans', {'plan': '_Test Plan Name'})
|
||||||
|
subscription.insert()
|
||||||
|
subscription.set_current_invoice_start('2018-01-01')
|
||||||
|
subscription.set_current_invoice_end()
|
||||||
|
subscription.process() # generate first invoice
|
||||||
|
|
||||||
|
self.assertEqual(subscription.status, 'Past Due Date')
|
||||||
|
|
||||||
|
subscription.process()
|
||||||
|
self.assertEqual(subscription.status, 'Unpaid')
|
||||||
|
|
||||||
|
subscription.cancel_subscription()
|
||||||
|
self.assertEqual(subscription.status, 'Canceled')
|
||||||
|
|
||||||
|
subscription.restart_subscription()
|
||||||
|
self.assertEqual(subscription.status, 'Active')
|
||||||
|
self.assertEqual(len(subscription.invoices), 0)
|
||||||
|
|
||||||
|
subscription.process()
|
||||||
|
self.assertEqual(subscription.status, 'Active')
|
||||||
|
self.assertEqual(len(subscription.invoices), 0)
|
||||||
|
|
||||||
|
subscription.process()
|
||||||
|
self.assertEqual(subscription.status, 'Active')
|
||||||
|
self.assertEqual(len(subscription.invoices), 0)
|
||||||
|
|
||||||
|
settings.cancel_after_grace = default_grace_period_action
|
||||||
|
settings.save()
|
||||||
|
subscription.delete()
|
||||||
|
|
||||||
|
def test_subscription_unpaid_back_to_active(self):
|
||||||
|
settings = frappe.get_single('Subscription Settings')
|
||||||
|
default_grace_period_action = settings.cancel_after_grace
|
||||||
|
settings.cancel_after_grace = 0
|
||||||
|
settings.save()
|
||||||
|
|
||||||
|
subscription = frappe.new_doc('Subscriptions')
|
||||||
|
subscription.subscriber = '_Test Customer'
|
||||||
|
subscription.append('plans', {'plan': '_Test Plan Name'})
|
||||||
|
subscription.insert()
|
||||||
|
subscription.set_current_invoice_start('2018-01-01')
|
||||||
|
subscription.set_current_invoice_end()
|
||||||
|
subscription.process() # generate first invoice
|
||||||
|
|
||||||
|
self.assertEqual(subscription.status, 'Past Due Date')
|
||||||
|
|
||||||
|
subscription.process()
|
||||||
|
# This should change status to Canceled since grace period is 0
|
||||||
|
self.assertEqual(subscription.status, 'Unpaid')
|
||||||
|
|
||||||
|
invoice = subscription.get_current_invoice()
|
||||||
|
invoice.db_set('outstanding_amount', 0)
|
||||||
|
invoice.db_set('status', 'Paid')
|
||||||
|
|
||||||
|
subscription.process()
|
||||||
|
self.assertEqual(subscription.status, 'Active')
|
||||||
|
|
||||||
|
subscription.process()
|
||||||
|
self.assertEqual(subscription.status, 'Active')
|
||||||
|
|
||||||
|
settings.cancel_after_grace = default_grace_period_action
|
||||||
|
settings.save()
|
||||||
|
subscription.delete()
|
||||||
|
|
||||||
def test_subscription_creation_with_multiple_plans(self):
|
def test_subscription_creation_with_multiple_plans(self):
|
||||||
pass
|
pass
|
||||||
|
Loading…
x
Reference in New Issue
Block a user