add ability to cancel, restart and refresh subscription

This commit is contained in:
tundebabzy 2018-03-01 04:50:04 +01:00
parent 2cccad0274
commit 8f37926ca8
3 changed files with 235 additions and 7 deletions

View File

@ -3,6 +3,75 @@
frappe.ui.form.on('Subscriptions', {
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();
}
}
});
}
});

View File

@ -14,8 +14,8 @@ class Subscriptions(Document):
# update start just before the subscription doc is created
self.update_subscription_period()
def update_subscription_period(self):
self.set_current_invoice_start()
def update_subscription_period(self, date=None):
self.set_current_invoice_start(date)
self.set_current_invoice_end()
def set_current_invoice_start(self, date=None):
@ -228,16 +228,19 @@ class Subscriptions(Document):
"""
if self.status == '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.save()
# process_for_unpaid()
if self.status != 'Canceled':
self.save()
def process_for_active(self):
if getdate(nowdate()) > getdate(self.current_invoice_end) and not self.has_outstanding_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'
def process_for_past_due_date(self):
@ -247,7 +250,7 @@ class Subscriptions(Document):
else:
if self.is_not_outstanding(current_invoice):
self.status = 'Active'
self.update_subscription_period()
self.update_subscription_period(nowdate())
else:
self.set_status_grace_period()
@ -261,3 +264,41 @@ class Subscriptions(Document):
else:
return not self.is_not_outstanding(current_invoice)
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()

View File

@ -267,5 +267,123 @@ class TestSubscriptions(unittest.TestCase):
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):
pass