Beispiel #1
0
    def test_create_subscription_trial_with_wrong_dates(self):
        subscription = dataent.new_doc('Subscription')
        subscription.customer = '_Test Customer'
        subscription.trial_period_end = nowdate()
        subscription.trial_period_start = add_days(nowdate(), 30)
        subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})

        self.assertRaises(dataent.ValidationError, subscription.save)
        subscription.delete()
Beispiel #2
0
    def restart_subscription(self):
        """
		This sets the subscription as active. The subscription will be made to be like a new
		subscription and the `Subscription` will lose all the history of generated invoices
		it has.
		"""
        if self.status == 'Cancelled':
            self.status = 'Active'
            self.db_set('start', nowdate())
            self.update_subscription_period(nowdate())
            self.invoices = []
            self.save()
        else:
            dataent.throw(
                _('You cannot restart a Subscription that is not cancelled.'))
Beispiel #3
0
    def cancel_subscription_at_period_end(self):
        """
		Called when `Subscription.cancel_at_period_end` is truthy
		"""
        self.status = 'Cancelled'
        if not self.cancelation_date:
            self.cancelation_date = nowdate()
Beispiel #4
0
    def test_prepaid_subscriptions_with_prorate_true(self):
        settings = dataent.get_single('Subscription Settings')
        to_prorate = settings.prorate
        settings.prorate = 1
        settings.save()

        subscription = dataent.new_doc('Subscription')
        subscription.customer = '_Test Customer'
        subscription.generate_invoice_at_period_start = True
        subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
        subscription.save()
        subscription.cancel_subscription()

        self.assertEqual(len(subscription.invoices), 1)

        current_inv = subscription.get_current_invoice()
        self.assertEqual(current_inv.status, "Unpaid")

        diff = flt(
            date_diff(nowdate(), subscription.current_invoice_start) + 1)
        plan_days = flt(
            date_diff(subscription.current_invoice_end,
                      subscription.current_invoice_start) + 1)
        prorate_factor = flt(diff / plan_days)

        self.assertEqual(flt(current_inv.grand_total, 2),
                         flt(prorate_factor * 900, 2))

        settings.prorate = to_prorate
        settings.save()

        subscription.delete()
Beispiel #5
0
    def test_create_subscription_without_trial_with_correct_period(self):
        subscription = dataent.new_doc('Subscription')
        subscription.customer = '_Test Customer'
        subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
        subscription.save()

        self.assertEqual(subscription.trial_period_start, None)
        self.assertEqual(subscription.trial_period_end, None)
        self.assertEqual(subscription.current_invoice_start, nowdate())
        self.assertEqual(subscription.current_invoice_end,
                         add_to_date(nowdate(), months=1, days=-1))
        # No invoice is created
        self.assertEqual(len(subscription.invoices), 0)
        self.assertEqual(subscription.status, 'Active')

        subscription.delete()
Beispiel #6
0
    def test_subscription_cancellation_invoices_with_prorata_true(self):
        settings = dataent.get_single('Subscription Settings')
        to_prorate = settings.prorate
        settings.prorate = 1
        settings.save()

        subscription = dataent.new_doc('Subscription')
        subscription.customer = '_Test Customer'
        subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
        subscription.save()
        subscription.cancel_subscription()

        invoice = subscription.get_current_invoice()
        diff = flt(
            date_diff(nowdate(), subscription.current_invoice_start) + 1)
        plan_days = flt(
            date_diff(subscription.current_invoice_end,
                      subscription.current_invoice_start) + 1)
        prorate_factor = flt(diff / plan_days)

        self.assertEqual(flt(invoice.grand_total, 2),
                         flt(prorate_factor * 900, 2))

        settings.prorate = to_prorate
        settings.save()

        subscription.delete()
Beispiel #7
0
    def test_create_subscription_with_trial_with_correct_period(self):
        subscription = dataent.new_doc('Subscription')
        subscription.customer = '_Test Customer'
        subscription.trial_period_start = nowdate()
        subscription.trial_period_end = add_days(nowdate(), 30)
        subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
        subscription.save()

        self.assertEqual(subscription.trial_period_start, nowdate())
        self.assertEqual(subscription.trial_period_end,
                         add_days(nowdate(), 30))
        self.assertEqual(subscription.trial_period_start,
                         subscription.current_invoice_start)
        self.assertEqual(subscription.trial_period_end,
                         subscription.current_invoice_end)
        self.assertEqual(subscription.invoices, [])
        self.assertEqual(subscription.status, 'Trialling')

        subscription.delete()
Beispiel #8
0
    def is_prepaid_to_invoice(self):
        if not self.generate_invoice_at_period_start:
            return False

        if self.is_new_subscription():
            return True

        # Check invoice dates and make sure it doesn't have outstanding invoices
        return getdate(nowdate()) >= getdate(
            self.current_invoice_start) and not self.has_outstanding_invoice()
Beispiel #9
0
    def period_has_passed(end_date):
        """
		Returns true if the given `end_date` has passed
		"""
        # todo: test for illegal time
        if not end_date:
            return True

        end_date = getdate(end_date)
        return getdate(nowdate()) > getdate(end_date)
Beispiel #10
0
    def is_past_grace_period(self):
        """
		Returns `True` if the grace period for the `Subscription` has passed
		"""
        current_invoice = self.get_current_invoice()
        if self.current_invoice_is_past_due(current_invoice):
            subscription_settings = dataent.get_single('Subscription Settings')
            grace_period = cint(subscription_settings.grace_period)

            return getdate(nowdate()) > add_days(current_invoice.due_date,
                                                 grace_period)
Beispiel #11
0
    def current_invoice_is_past_due(self, current_invoice=None):
        """
		Returns `True` if the current generated invoice is overdue
		"""
        if not current_invoice:
            current_invoice = self.get_current_invoice()

        if not current_invoice:
            return False
        else:
            return getdate(nowdate()) > getdate(current_invoice.due_date)
Beispiel #12
0
    def process_for_active(self):
        """
		Called by `process` if the status of the `Subscription` is 'Active'.

		The possible outcomes of this method are:
		1. Generate a new invoice
		2. Change the `Subscription` status to 'Past Due Date'
		3. Change the `Subscription` status to 'Cancelled'
		"""
        if self.is_postpaid_to_invoice() or self.is_prepaid_to_invoice():
            self.generate_invoice()
            if self.current_invoice_is_past_due():
                self.status = 'Past Due Date'

        if self.current_invoice_is_past_due() and getdate(nowdate()) > getdate(
                self.current_invoice_end):
            self.status = 'Past Due Date'

        if self.cancel_at_period_end and getdate(nowdate()) > getdate(
                self.current_invoice_end):
            self.cancel_subscription_at_period_end()
Beispiel #13
0
    def set_current_invoice_start(self, date=None):
        """
		This sets 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.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()
Beispiel #14
0
    def test_subscription_invoice_days_until_due(self):
        subscription = dataent.new_doc('Subscription')
        subscription.customer = '_Test Customer'
        subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
        subscription.days_until_due = 10
        subscription.start = add_months(nowdate(), -1)
        subscription.insert()
        subscription.process()  # generate first invoice
        self.assertEqual(len(subscription.invoices), 1)
        self.assertEqual(subscription.status, 'Active')

        subscription.delete()
Beispiel #15
0
    def test_subscription_remains_active_during_invoice_period(self):
        subscription = dataent.new_doc('Subscription')
        subscription.customer = '_Test Customer'
        subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
        subscription.save()
        subscription.process()  # no changes expected

        self.assertEqual(subscription.status, 'Active')
        self.assertEqual(subscription.current_invoice_start, nowdate())
        self.assertEqual(subscription.current_invoice_end,
                         add_to_date(nowdate(), months=1, days=-1))
        self.assertEqual(len(subscription.invoices), 0)

        subscription.process()  # no changes expected still
        self.assertEqual(subscription.status, 'Active')
        self.assertEqual(subscription.current_invoice_start, nowdate())
        self.assertEqual(subscription.current_invoice_end,
                         add_to_date(nowdate(), months=1, days=-1))
        self.assertEqual(len(subscription.invoices), 0)

        subscription.process()  # no changes expected yet still
        self.assertEqual(subscription.status, 'Active')
        self.assertEqual(subscription.current_invoice_start, nowdate())
        self.assertEqual(subscription.current_invoice_end,
                         add_to_date(nowdate(), months=1, days=-1))
        self.assertEqual(len(subscription.invoices), 0)

        subscription.delete()
Beispiel #16
0
    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.
		"""
        if self.status != 'Cancelled':
            to_generate_invoice = True if self.status == 'Active' else False
            to_prorate = dataent.db.get_single_value('Subscription Settings',
                                                     'prorate')
            self.status = 'Cancelled'
            self.cancelation_date = nowdate()
            if to_generate_invoice:
                self.generate_invoice(prorate=to_prorate)
            self.save()
Beispiel #17
0
    def test_subscription_cancellation_invoices(self):
        settings = dataent.get_single('Subscription Settings')
        to_prorate = settings.prorate
        settings.prorate = 1
        settings.save()

        subscription = dataent.new_doc('Subscription')
        subscription.customer = '_Test Customer'
        subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
        subscription.save()

        self.assertEqual(subscription.status, 'Active')

        subscription.cancel_subscription()
        # Invoice must have been generated
        self.assertEqual(len(subscription.invoices), 1)

        invoice = subscription.get_current_invoice()
        diff = flt(
            date_diff(nowdate(), subscription.current_invoice_start) + 1)
        plan_days = flt(
            date_diff(subscription.current_invoice_end,
                      subscription.current_invoice_start) + 1)
        prorate_factor = flt(diff / plan_days)

        self.assertEqual(
            flt(
                get_prorata_factor(subscription.current_invoice_end,
                                   subscription.current_invoice_start), 2),
            flt(prorate_factor, 2))
        self.assertEqual(flt(invoice.grand_total, 2),
                         flt(prorate_factor * 900, 2))
        self.assertEqual(subscription.status, 'Cancelled')

        subscription.delete()
        settings.prorate = to_prorate
        settings.save()
Beispiel #18
0
def get_prorata_factor(period_end, period_start):
    diff = flt(date_diff(nowdate(), period_start) + 1)
    plan_days = flt(date_diff(period_end, period_start) + 1)
    prorate_factor = diff / plan_days

    return prorate_factor
Beispiel #19
0
 def is_postpaid_to_invoice(self):
     return getdate(nowdate()) > getdate(self.current_invoice_end) or \
      (getdate(nowdate()) >= getdate(self.current_invoice_end) and getdate(self.current_invoice_end) == getdate(self.current_invoice_start)) and \
      not self.has_outstanding_invoice()