def test_over_limit(self): """ Make sure that the Line Item for the SMS Rate has the following: - base_description is None - base_cost is 0.0 - unit_description is not None - unit_cost is greater than 0.0 - quantity is equal to 1 - total and subtotals are greater than zero """ invoice_date = utils.months_from_date(self.subscription.date_start, random.randint(2, self.subscription_length)) sms_date = utils.months_from_date(invoice_date, -1) num_sms = random.randint(self.sms_rate.monthly_limit + 1, self.sms_rate.monthly_limit + 2) generator.arbitrary_sms_billables_for_domain(self.subscription.subscriber.domain, INCOMING, sms_date, num_sms) generator.arbitrary_sms_billables_for_domain(self.subscription.subscriber.domain, OUTGOING, sms_date, num_sms) tasks.generate_invoices(invoice_date) invoice = self.subscription.invoice_set.latest("date_created") sms_line_item = invoice.lineitem_set.get_feature_by_type(FeatureType.SMS).get() # there is no base cost self.assertIsNone(sms_line_item.base_description) self.assertEqual(sms_line_item.base_cost, Decimal("0.0000")) self.assertEqual(sms_line_item.quantity, 1) self.assertGreater(sms_line_item.unit_cost, Decimal("0.0000")) self.assertIsNotNone(sms_line_item.unit_description) self.assertGreater(sms_line_item.subtotal, Decimal("0.0000")) self.assertGreater(sms_line_item.total, Decimal("0.0000")) self._delete_sms_billables()
def test_prorate(self): """ Make sure that the product is prorated for the first and last invoices, which fall in a partial month: - base_cost is 0.0 - base_description is None - unit_description is not None - unit_cost is prorated - quantity > 1 - subtotal = unit_cost * quantity """ first_invoice_date = utils.months_from_date(self.subscription.date_start, 1) tasks.generate_invoices(first_invoice_date) last_invoice_date = utils.months_from_date(self.subscription.date_end, 1) tasks.generate_invoices(last_invoice_date) for invoice in self.subscription.invoice_set.all(): product_line_items = invoice.lineitem_set.filter(feature_rate__exact=None) self.assertEqual(product_line_items.count(), 1) product_line_item = product_line_items.get() self.assertGreater(product_line_item.quantity, 1) self.assertEqual(product_line_item.unit_cost, self.prorate) self.assertIsNotNone(product_line_item.unit_description) self.assertEqual(product_line_item.base_cost, Decimal('0.0000')) self.assertIsNone(product_line_item.base_description) self.assertEqual(product_line_item.subtotal, product_line_item.unit_cost * product_line_item.quantity) # no adjustments self.assertEqual(product_line_item.total, product_line_item.unit_cost * product_line_item.quantity)
def setUp(self): super(TestSmsLineItem, self).setUp() self.sms_rate = self.subscription.plan_version.feature_rates.filter( feature__feature_type=FeatureType.SMS).get() self.invoice_date = utils.months_from_date( self.subscription.date_start, random.randint(2, self.subscription_length)) self.sms_date = utils.months_from_date(self.invoice_date, -1)
def setUpClass(cls): super(TestSmsLineItem, cls).setUpClass() cls.sms_rate = cls.subscription.plan_version.feature_rates.filter( feature__feature_type=FeatureType.SMS).get() cls.invoice_date = utils.months_from_date( cls.subscription.date_start, random.randint(2, cls.subscription_length)) cls.sms_date = utils.months_from_date(cls.invoice_date, -1)
def setUpClass(cls): super(TestSmsLineItem, cls).setUpClass() cls.sms_rate = cls.subscription.plan_version.feature_rates.filter( feature__feature_type=FeatureType.SMS ).get() cls.invoice_date = utils.months_from_date( cls.subscription.date_start, random.randint(2, cls.subscription_length) ) cls.sms_date = utils.months_from_date(cls.invoice_date, -1)
def setUp(self): super(TestSmsLineItem, self).setUp() self.sms_rate = self.subscription.plan_version.feature_rates.filter( feature__feature_type=FeatureType.SMS ).get() self.invoice_date = utils.months_from_date( self.subscription.date_start, random.randint(2, self.subscription_length) ) self.sms_date = utils.months_from_date(self.invoice_date, -1)
def setUp(self): super(TestWireInvoice, self).setUp() invoice_date = utils.months_from_date(self.subscription.date_start, 2) tasks.generate_invoices(invoice_date) invoice_date = utils.months_from_date(self.subscription.date_start, 3) tasks.generate_invoices(invoice_date) self.invoices = Invoice.objects.all() self.domain_name = self.invoices[0].get_domain()
def test_prorate(self): """ Make sure that the product is prorated for the first and last invoices, which fall in a partial month: - base_cost is 0.0 - base_description is None - unit_description is not None - unit_cost is prorated - quantity > 1 - subtotal = unit_cost * quantity """ first_invoice_date = utils.months_from_date( self.subscription.date_start, 1) tasks.generate_invoices(first_invoice_date) last_invoice_date = utils.months_from_date(self.subscription.date_end, 1) tasks.generate_invoices(last_invoice_date) for invoice in self.subscription.invoice_set.all(): product_line_items = invoice.lineitem_set.filter( feature_rate__exact=None) self.assertEqual(product_line_items.count(), 1) product_line_item = product_line_items.get() days_prorated_by_invoice_start_date = { datetime.date(2016, 2, 23): 7, datetime.date(2017, 5, 1): 22, } days_in_month_by_invoice_start_date = { datetime.date(2016, 2, 23): 29, datetime.date(2017, 5, 1): 31, } self.assertEqual( product_line_item.quantity, days_prorated_by_invoice_start_date[invoice.date_start]) self.assertEqual( product_line_item.unit_cost, Decimal("%.2f" % round( self.product_rate.monthly_fee / days_in_month_by_invoice_start_date[invoice.date_start], 2))) self.assertIsNotNone(product_line_item.unit_description) self.assertEqual(product_line_item.base_cost, Decimal('0.0000')) self.assertIsNone(product_line_item.base_description) self.assertEqual( product_line_item.subtotal, product_line_item.unit_cost * product_line_item.quantity) # no adjustments self.assertEqual( product_line_item.total, product_line_item.unit_cost * product_line_item.quantity)
def setUp(self): super(TestWireInvoice, self).setUp() invoice_date = utils.months_from_date(self.subscription.date_start, 2) tasks.calculate_users_in_all_domains(invoice_date) tasks.generate_invoices(invoice_date) invoice_date = utils.months_from_date(self.subscription.date_start, 3) tasks.calculate_users_in_all_domains(invoice_date) tasks.generate_invoices(invoice_date) self.invoices = Invoice.objects.all()
def setUp(self): super(TestCustomerAccountWireInvoice, self).setUp() self.account.is_customer_billing_account = True self.account.save() invoice_date = utils.months_from_date(self.subscription.date_start, 2) tasks.calculate_users_in_all_domains(invoice_date) tasks.generate_invoices(invoice_date) invoice_date = utils.months_from_date(self.subscription.date_start, 3) tasks.calculate_users_in_all_domains(invoice_date) tasks.generate_invoices(invoice_date)
def _generate_invoice_and_subscription(days_ago, is_customer_billing_account=False): """ :param days_ago: The number of days ago an invoice should be due :return: random domain, with invoices generated on the backend """ invoice_due_date = datetime.date.today() - datetime.timedelta(days=days_ago) billing_contact = generator.create_arbitrary_web_user_name() dimagi_user = generator.create_arbitrary_web_user_name(is_dimagi=True) account = generator.billing_account( dimagi_user, billing_contact ) account.is_customer_billing_account = is_customer_billing_account account.save() domain = generator.arbitrary_domain() subscription_start_date = utils.months_from_date(invoice_due_date, -2) subscription = generator.generate_domain_subscription( account, domain, date_start=subscription_start_date, date_end=None, plan_version=DefaultProductPlan.get_default_plan_version( SoftwarePlanEdition.ADVANCED ), service_type=SubscriptionType.PRODUCT, ) subscription.is_active = True subscription.save() invoice_date = utils.months_from_date(invoice_due_date, -1) DomainUserHistory.objects.create( domain=domain.name, num_users=20, record_date=invoice_date - datetime.timedelta(days=1) ) tasks.generate_invoices(invoice_date) # for testing purposes, force the latest invoice due_date to be # the "invoice_due_date" specified above if is_customer_billing_account: latest_invoice = CustomerInvoice.objects.filter( account=account, ).latest('date_created') else: latest_invoice = subscription.invoice_set.latest('date_created') latest_invoice.date_due = invoice_due_date latest_invoice.save() return domain, latest_invoice
def setUp(self): super(TestCustomerAccountWireInvoice, self).setUp() self.account.is_customer_billing_account = True self.account.save() invoice_date = utils.months_from_date(self.subscription.date_start, 2) tasks.generate_invoices(invoice_date) invoice_date = utils.months_from_date(self.subscription.date_start, 3) tasks.generate_invoices(invoice_date) self.invoices = CustomerInvoice.objects.all() self.domain_name = self.invoices.first().subscriptions.first().subscriber.domain
def setUp(self): super(TestQuarterlyInvoicing, self).setUp() self.user_rate = self.subscription.plan_version.feature_rates \ .filter(feature__feature_type=FeatureType.USER).get() self.advanced_rate = self.advanced_plan.feature_rates.filter( feature__feature_type=FeatureType.USER).get() self.initialize_domain_user_history_objects() self.sms_rate = self.subscription.plan_version.feature_rates.filter( feature__feature_type=FeatureType.SMS).get() self.advanced_sms_rate = self.advanced_plan.feature_rates.filter( feature__feature_type=FeatureType.SMS).get() self.invoice_date = utils.months_from_date( self.subscription.date_start, random.randint(2, self.subscription_length)) self.sms_date = utils.months_from_date(self.invoice_date, -1)
def test_product_line_items(self): invoice_date = utils.months_from_date( self.subscription.date_start, random.randint(2, self.subscription_length)) invoice_start, invoice_end = get_previous_month_date_range( invoice_date) invoice_factory = CustomerAccountInvoiceFactory( account=self.account, date_start=invoice_start, date_end=invoice_end) invoice_factory.create_invoice() self.assertEqual(CustomerInvoice.objects.count(), 1) invoice = CustomerInvoice.objects.first() product_line_items = invoice.lineitem_set.get_products() self.assertEqual(product_line_items.count(), 2) for line_item in product_line_items: self.assertTrue(line_item.base_description == 'One month of CommCare Advanced Software Plan.' or line_item.base_description == 'One month of CommCare Standard Software Plan.') self.assertTrue( line_item.base_cost == self.product_rate.monthly_fee or line_item.base_cost == self.advanced_plan.product_rate.monthly_fee)
def test_product_line_items(self): invoice_date = utils.months_from_date( self.subscription.date_start, random.randint(2, self.subscription_length)) calculate_users_in_all_domains(invoice_date) tasks.generate_invoices(invoice_date) self.assertEqual(CustomerInvoice.objects.count(), 1) invoice = CustomerInvoice.objects.first() product_line_items = invoice.lineitem_set.get_products() self.assertEqual(product_line_items.count(), 2) product_descriptions = [ line_item.base_description for line_item in product_line_items ] self.assertItemsEqual(product_descriptions, [ 'One month of CommCare Advanced Edition Software Plan.', 'One month of CommCare Standard Edition Software Plan.' ]) product_costs = [ line_item.base_cost for line_item in product_line_items ] self.assertItemsEqual(product_costs, [ self.product_rate.monthly_fee, self.advanced_plan.product_rate.monthly_fee ])
def test_under_limit(self): num_users = random.randint(0, self.user_rate.monthly_limit) generator.arbitrary_commcare_users_for_domain(self.domain.name, num_users) num_users_advanced = random.randint(0, self.advanced_rate.monthly_limit) generator.arbitrary_commcare_users_for_domain(self.domain2.name, num_users_advanced) invoice_date = utils.months_from_date( self.subscription.date_start, random.randint(2, self.subscription_length)) tasks.generate_invoices(invoice_date) self.assertEqual(CustomerInvoice.objects.count(), 1) invoice = CustomerInvoice.objects.first() self.assertEqual(invoice.balance, Decimal('1500.0000')) user_line_items = invoice.lineitem_set.get_feature_by_type( FeatureType.USER) self.assertEqual(user_line_items.count(), 2) for user_line_item in user_line_items: self.assertEqual(user_line_item.quantity, 0) self.assertEqual(user_line_item.subtotal, Decimal('0.0000')) self.assertEqual(user_line_item.total, Decimal('0.0000')) self.assertIsNone(user_line_item.base_description) self.assertEqual(user_line_item.base_cost, Decimal('0.0000')) self.assertIsNone(user_line_item.unit_description) self.assertEqual(user_line_item.unit_cost, Decimal('1.0000'))
def setUp(self): super(TestUserLineItem, self).setUp() self.user_rate = self.subscription.plan_version.feature_rates \ .filter(feature__feature_type=FeatureType.USER).get() self.advanced_rate = self.advanced_plan.feature_rates.filter(feature__feature_type=FeatureType.USER).get() self.invoice_date = utils.months_from_date(self.subscription.date_start, random.randint(2, self.subscription_length))
def test_date_due_gets_set_autopay(self): """Date due always gets set for autopay """ Subscription.objects.all().delete() plan = DefaultProductPlan.objects.get( edition=SoftwarePlanEdition.STANDARD, product_type=SoftwareProductType.COMMCARE, is_trial=False).plan.get_version() subscription_length = 4 subscription_start_date = datetime.date(2016, 2, 23) subscription_end_date = add_months_to_date(subscription_start_date, subscription_length) autopay_subscription = generator.generate_domain_subscription( self.account, self.domain, date_start=subscription_start_date, date_end=subscription_end_date, plan_version=plan) autopay_subscription.account.update_autopay_user( self.billing_contact.username, self.domain) invoice_date_autopay = utils.months_from_date( autopay_subscription.date_start, 1) tasks.generate_invoices(invoice_date_autopay) autopay_invoice = autopay_subscription.invoice_set.last() self.assertTrue(autopay_invoice.balance <= SMALL_INVOICE_THRESHOLD) self.assertIsNotNone(autopay_invoice.date_due)
def test_hide_invoices(self): """ Tests hiding invoices via the management command """ invoice_date = utils.months_from_date( self.subscription.date_start, random.randint(2, self.subscription_length)) tasks.generate_invoices(invoice_date) invoices = self.subscription.invoice_set.all() # Basic hide invoices call_command('hide_invoices_by_id', *[i.pk for i in invoices]) for i in invoices: self.assertTrue( super(InvoiceBaseManager, Invoice.objects).get_queryset().get( pk=i.pk).is_hidden_to_ops) # Basic unhide invoices call_command('hide_invoices_by_id', *[i.pk for i in invoices], unhide=True) for i in invoices: self.assertFalse( super(InvoiceBaseManager, Invoice.objects).get_queryset().get( pk=i.pk).is_hidden_to_ops)
def test_over_limit(self): num_users = self.user_rate.monthly_limit + 1 generator.arbitrary_commcare_users_for_domain(self.domain.name, num_users) num_users_advanced = self.advanced_rate.monthly_limit + 1 generator.arbitrary_commcare_users_for_domain(self.domain2.name, num_users_advanced) invoice_date = utils.months_from_date(self.subscription.date_start, random.randint(2, self.subscription_length)) tasks.generate_invoices(invoice_date) self.assertEqual(CustomerInvoice.objects.count(), 1) invoice = CustomerInvoice.objects.first() user_line_items = invoice.lineitem_set.get_feature_by_type(FeatureType.USER) self.assertEqual(user_line_items.count(), 2) for user_line_item in user_line_items: self.assertIsNone(user_line_item.base_description) self.assertEqual(user_line_item.base_cost, Decimal('0.0000')) num_to_charge = num_users - self.user_rate.monthly_limit self.assertEqual(num_to_charge, user_line_item.quantity) if self.user_rate.feature.name == user_line_item.feature_rate.feature.name: self.assertEqual(user_line_item.unit_cost, self.user_rate.per_excess_fee) self.assertEqual(user_line_item.total, self.user_rate.per_excess_fee * num_to_charge) self.assertEqual(user_line_item.subtotal, self.user_rate.per_excess_fee * num_to_charge) elif user_line_item.feature_rate.feature.name == self.advanced_rate.feature.name: self.assertEqual(user_line_item.unit_cost, self.advanced_rate.per_excess_fee) self.assertEqual(user_line_item.total, self.advanced_rate.per_excess_fee * num_to_charge) self.assertEqual(user_line_item.subtotal, self.advanced_rate.per_excess_fee * num_to_charge)
def test_date_due_set_large_invoice(self): """Date Due only gets set for a large invoice (> $100)""" Subscription.objects.all().delete() plan = DefaultProductPlan.objects.get( edition=SoftwarePlanEdition.ADVANCED, product_type=SoftwareProductType.COMMCARE, is_trial=False ).plan.get_version() subscription_length = 5 # months subscription_start_date = datetime.date(2016, 2, 23) subscription_end_date = add_months_to_date(subscription_start_date, subscription_length) subscription = generator.generate_domain_subscription( self.account, self.domain, date_start=subscription_start_date, date_end=subscription_end_date, plan_version=plan ) invoice_date_large = utils.months_from_date(subscription.date_start, 3) tasks.generate_invoices(invoice_date_large) large_invoice = subscription.invoice_set.last() self.assertTrue(large_invoice.balance > SMALL_INVOICE_THRESHOLD) self.assertIsNotNone(large_invoice.date_due)
def test_date_due_not_set_small_invoice(self): """Date Due doesn't get set if the invoice is small""" Subscription.objects.all().delete() plan = DefaultProductPlan.objects.get( edition=SoftwarePlanEdition.STANDARD, product_type=SoftwareProductType.COMMCARE, is_trial=False ).plan.get_version() subscription_length = 5 # months subscription_start_date = datetime.date(2016, 2, 23) subscription_end_date = add_months_to_date(subscription_start_date, subscription_length) subscription = generator.generate_domain_subscription( self.account, self.domain, date_start=subscription_start_date, date_end=subscription_end_date, plan_version=plan, ) invoice_date_small = utils.months_from_date(subscription.date_start, 1) tasks.generate_invoices(invoice_date_small) small_invoice = subscription.invoice_set.first() self.assertTrue(small_invoice.balance <= SMALL_INVOICE_THRESHOLD) self.assertIsNone(small_invoice.date_due)
def test_date_due_gets_set_autopay(self): """Date due always gets set for autopay """ Subscription.objects.all().delete() plan = DefaultProductPlan.objects.get( edition=SoftwarePlanEdition.STANDARD, product_type=SoftwareProductType.COMMCARE, is_trial=False ).plan.get_version() subscription_length = 4 subscription_start_date = datetime.date(2016, 2, 23) subscription_end_date = add_months_to_date(subscription_start_date, subscription_length) autopay_subscription = generator.generate_domain_subscription( self.account, self.domain, date_start=subscription_start_date, date_end=subscription_end_date, plan_version=plan ) autopay_subscription.account.update_autopay_user(self.billing_contact.username, self.domain) invoice_date_autopay = utils.months_from_date(autopay_subscription.date_start, 1) tasks.generate_invoices(invoice_date_autopay) autopay_invoice = autopay_subscription.invoice_set.last() self.assertTrue(autopay_invoice.balance <= SMALL_INVOICE_THRESHOLD) self.assertIsNotNone(autopay_invoice.date_due)
def setUp(self): super(TestQuarterlyInvoicing, self).setUp() self.user_rate = self.subscription.plan_version.feature_rates \ .filter(feature__feature_type=FeatureType.USER).get() self.advanced_rate = self.advanced_plan.feature_rates.filter(feature__feature_type=FeatureType.USER).get() self.initialize_domain_user_history_objects() self.sms_rate = self.subscription.plan_version.feature_rates.filter( feature__feature_type=FeatureType.SMS ).get() self.advanced_sms_rate = self.advanced_plan.feature_rates.filter( feature__feature_type=FeatureType.SMS ).get() self.invoice_date = utils.months_from_date( self.subscription.date_start, random.randint(2, self.subscription_length) ) self.sms_date = utils.months_from_date(self.invoice_date, -1)
def test_multiple_subscription_invoice(self): invoice_date = utils.months_from_date( self.subscription.date_start, random.randint(2, self.subscription_length)) invoice_start, invoice_end = get_previous_month_date_range( invoice_date) invoice_factory = CustomerAccountInvoiceFactory( account=self.account, date_start=invoice_start, date_end=invoice_end) invoice_factory.create_invoice() self.assertEqual(CustomerInvoice.objects.count(), 1) invoice = CustomerInvoice.objects.first() self.assertGreater(invoice.balance, Decimal('0.0000')) self.assertEqual(invoice.account, self.account) num_product_line_items = invoice.lineitem_set.get_products().count() self.assertEqual(num_product_line_items, 2) num_feature_line_items = invoice.lineitem_set.get_features().count() self.assertEqual( num_feature_line_items, self.subscription.plan_version.feature_rates.count() + self.sub2.plan_version.feature_rates.count())
def test_only_invoice_active_subscriptions(self): """ Test that only active subscriptions are invoiced. Two subscriptions of the same plan only create one product line item and one set of feature line items """ invoice_date = utils.months_from_date(self.sub2.date_end, 1) invoice_start, invoice_end = get_previous_month_date_range( invoice_date) invoice_factory = CustomerAccountInvoiceFactory( account=self.account, date_start=invoice_start, date_end=invoice_end) invoice_factory.create_invoice() self.assertEqual(CustomerInvoice.objects.count(), 1) invoice = CustomerInvoice.objects.first() self.assertEqual(invoice.balance, Decimal('1000.0000')) self.assertEqual(invoice.account, self.account) num_product_line_items = invoice.lineitem_set.get_products().count() self.assertEqual(num_product_line_items, 1) num_feature_line_items = invoice.lineitem_set.get_features().count() self.assertEqual(num_feature_line_items, self.sub2.plan_version.feature_rates.count())
def test_date_due_set_large_invoice(self): """Date Due only gets set for a large invoice (> $100)""" Subscription.objects.all().delete() plan = DefaultProductPlan.objects.get( edition=SoftwarePlanEdition.ADVANCED, product_type=SoftwareProductType.COMMCARE, is_trial=False).plan.get_version() subscription_length = 5 # months subscription_start_date = datetime.date(2016, 2, 23) subscription_end_date = add_months_to_date(subscription_start_date, subscription_length) subscription = generator.generate_domain_subscription( self.account, self.domain, date_start=subscription_start_date, date_end=subscription_end_date, plan_version=plan) invoice_date_large = utils.months_from_date(subscription.date_start, 3) tasks.generate_invoices(invoice_date_large) large_invoice = subscription.invoice_set.last() self.assertTrue(large_invoice.balance > SMALL_INVOICE_THRESHOLD) self.assertIsNotNone(large_invoice.date_due)
def test_user_over_limit_in_yearly_invoice(self): num_users = self.user_rate.monthly_limit + 1 generator.arbitrary_commcare_users_for_domain(self.domain.name, num_users) num_users_advanced = self.advanced_rate.monthly_limit + 2 generator.arbitrary_commcare_users_for_domain(self.domain2.name, num_users_advanced) self.account.invoicing_plan = InvoicingPlan.YEARLY self.account.save() invoice_date = utils.months_from_date(self.subscription.date_start, 14) invoice_start, invoice_end = get_previous_month_date_range( invoice_date) invoice_start = invoice_start - relativedelta(months=11) invoice_factory = CustomerAccountInvoiceFactory( account=self.account, date_start=invoice_start, date_end=invoice_end) invoice_factory.create_invoice() self.assertEqual(CustomerInvoice.objects.count(), 1) invoice = CustomerInvoice.objects.first() user_line_items = invoice.lineitem_set.get_feature_by_type( FeatureType.USER) self.assertEqual(user_line_items.count(), 2) for user_line_item in user_line_items: if self.user_rate.feature.name == user_line_item.feature_rate.feature.name: self.assertEqual(user_line_item.quantity, 12) elif user_line_item.feature_rate.feature.name == self.advanced_rate.feature.name: self.assertEqual(user_line_item.quantity, 24)
def test_date_due_not_set_small_invoice(self): """Date Due doesn't get set if the invoice is small""" Subscription.objects.all().delete() plan = DefaultProductPlan.objects.get( edition=SoftwarePlanEdition.STANDARD, product_type=SoftwareProductType.COMMCARE, is_trial=False).plan.get_version() subscription_length = 5 # months subscription_start_date = datetime.date(2016, 2, 23) subscription_end_date = add_months_to_date(subscription_start_date, subscription_length) subscription = generator.generate_domain_subscription( self.account, self.domain, date_start=subscription_start_date, date_end=subscription_end_date, plan_version=plan, ) invoice_date_small = utils.months_from_date(subscription.date_start, 1) tasks.generate_invoices(invoice_date_small) small_invoice = subscription.invoice_set.first() self.assertTrue(small_invoice.balance <= SMALL_INVOICE_THRESHOLD) self.assertIsNone(small_invoice.date_due)
def test_under_limit(self): """ Make sure that the User rate produced: - base_description is None - base_cost is 0.0 - unit_cost is equal to the per_excess_fee - quantity is equal to 0 - unit_description is None - total and subtotals are 0.0 """ invoice_date = utils.months_from_date(self.subscription.date_start, random.randint(2, self.subscription_length)) num_users = lambda: random.randint(0, self.user_rate.monthly_limit) num_active = num_users() generator.arbitrary_commcare_users_for_domain(self.domain.name, num_active) num_inactive = num_users() generator.arbitrary_commcare_users_for_domain(self.domain.name, num_inactive, is_active=False) tasks.generate_invoices(invoice_date) invoice = self.subscription.invoice_set.latest('date_created') user_line_item = invoice.lineitem_set.get_feature_by_type(FeatureType.USER).get() self.assertIsNone(user_line_item.base_description) self.assertEqual(user_line_item.base_cost, Decimal('0.0000')) self.assertIsNone(user_line_item.unit_description) self.assertEqual(user_line_item.quantity, 0) self.assertEqual(user_line_item.unit_cost, self.user_rate.per_excess_fee) self.assertEqual(user_line_item.subtotal, Decimal('0.0000')) self.assertEqual(user_line_item.total, Decimal('0.0000'))
def test_over_limit(self): """ Make sure that the User rate produced: - base_description is None - base_cost is 0.0 - unit_description is not None - unit_cost is equal to the per_excess_fee on the user rate - quantity is equal to number of commcare users in that domain minus the monthly_limit on the user rate - total and subtotals are equal to number of extra users * per_excess_fee """ invoice_date = utils.months_from_date(self.subscription.date_start, random.randint(2, self.subscription_length)) num_users = lambda: random.randint(self.user_rate.monthly_limit + 1, self.user_rate.monthly_limit + 2) num_active = num_users() generator.arbitrary_commcare_users_for_domain(self.domain.name, num_active) num_inactive = num_users() generator.arbitrary_commcare_users_for_domain(self.domain.name, num_inactive, is_active=False) tasks.generate_invoices(invoice_date) invoice = self.subscription.invoice_set.latest('date_created') user_line_item = invoice.lineitem_set.get_feature_by_type(FeatureType.USER).get() # there is no base cost self.assertIsNone(user_line_item.base_description) self.assertEqual(user_line_item.base_cost, Decimal('0.0000')) num_to_charge = num_active - self.user_rate.monthly_limit self.assertIsNotNone(user_line_item.unit_description) self.assertEqual(user_line_item.quantity, num_to_charge) self.assertEqual(user_line_item.unit_cost, self.user_rate.per_excess_fee) self.assertEqual(user_line_item.subtotal, num_to_charge * self.user_rate.per_excess_fee) self.assertEqual(user_line_item.total, num_to_charge * self.user_rate.per_excess_fee)
def test_invoice_credit(self): """ Make sure that subscription and account level credits get applied to the invoice balance appropriately. """ invoice_monthly_total = self.product_rate.monthly_fee + self.monthly_user_fee subscription_credit, account_credit = self._generate_subscription_and_account_invoice_credits( invoice_monthly_total, self.subscription, self.account) # other subscription credit that shouldn't count toward this invoice other_domain = generator.arbitrary_domain() # so that the other subscription doesn't draw from the same account credits, have it start 4 months later new_subscription_start = utils.months_from_date( self.subscription.date_start, 4) other_subscription = generator.generate_domain_subscription( self.account, other_domain, date_start=new_subscription_start, date_end=add_months_to_date(new_subscription_start, self.min_subscription_length), ) # other account credit that shouldn't count toward this invoice other_account = generator.billing_account( self.dimagi_user, generator.arbitrary_web_user()) self._generate_subscription_and_account_invoice_credits( invoice_monthly_total, other_subscription, other_account) self._test_final_invoice_balance() self._test_credit_use(subscription_credit) self._test_credit_use(account_credit)
def _generate_invoices(self): """ Create invoices for both autopayable and non-autopayable subscriptions """ # invoice date is 2 months before the end of the subscription (this is arbitrary) invoice_date = utils.months_from_date(self.subscription.date_start, self.subscription_length - 2) tasks.generate_invoices(invoice_date)
def test_invoice_credit(self): """ Make sure that subscription and account level credits get applied to the invoice balance appropriately. """ invoice_monthly_total = self.product_rate.monthly_fee + self.monthly_user_fee subscription_credit, account_credit = self._generate_subscription_and_account_invoice_credits( invoice_monthly_total, self.subscription, self.account ) # other subscription credit that shouldn't count toward this invoice other_domain = generator.arbitrary_domain() # so that the other subscription doesn't draw from the same account credits, have it start 4 months later new_subscription_start = utils.months_from_date(self.subscription.date_start, 4) other_subscription = generator.generate_domain_subscription( self.account, other_domain, date_start=new_subscription_start, date_end=add_months_to_date(new_subscription_start, self.min_subscription_length), ) # other account credit that shouldn't count toward this invoice other_account = generator.billing_account(self.dimagi_user, generator.create_arbitrary_web_user_name()) self._generate_subscription_and_account_invoice_credits( invoice_monthly_total, other_subscription, other_account ) self._test_final_invoice_balance() self._test_credit_use(subscription_credit) self._test_credit_use(account_credit) other_domain.delete()
def test_no_invoice_after_end(self): """ No invoices should be generated for the months after the end date of the subscription. """ invoice_date = utils.months_from_date(self.subscription.date_end, 2) tasks.generate_invoices(invoice_date) self.assertEqual(self.subscription.invoice_set.count(), 0)
def test_standard(self): """ For the Product Line Item, make sure that the Product rate is not prorated: - base_cost uses the correct monthly fee - base_description is not None - unit_description is None - unit_cost is 0.0 - quantity is 1 - subtotal = monthly fee """ invoice_date = utils.months_from_date(self.subscription.date_start, random.randint(2, self.subscription_length)) tasks.generate_invoices(invoice_date) invoice = self.subscription.invoice_set.latest('date_created') product_line_items = invoice.lineitem_set.filter(feature_rate__exact=None) self.assertEqual(product_line_items.count(), 1) product_line_item = product_line_items.get() self.assertIsNotNone(product_line_item.base_description) self.assertEqual(product_line_item.base_cost, self.product_rate.monthly_fee) self.assertIsNone(product_line_item.unit_description) self.assertEqual(product_line_item.unit_cost, Decimal('0.0000')) self.assertEqual(product_line_item.quantity, 1) self.assertEqual(product_line_item.subtotal, self.product_rate.monthly_fee) # no adjustments self.assertEqual(product_line_item.total, self.product_rate.monthly_fee)
def _low_credits_context(self): context = {} current_subscription = Subscription.get_active_subscription_by_domain( self.domain) if current_subscription: monthly_fee = current_subscription.plan_version.product_rate.monthly_fee if monthly_fee: prepaid_credits = get_total_credits_available_for_product( current_subscription) num_months_remaining = prepaid_credits / monthly_fee prepaid_remaining_date = months_from_date( date.today(), num_months_remaining) partial_month_remaining = num_months_remaining % 1 num_days_in_month = 30 # Approximate prepaid_remaining_date += timedelta( days=int(partial_month_remaining * num_days_in_month)) prepaid_days_remaining = (prepaid_remaining_date - date.today()).days if 0 < prepaid_days_remaining < 63: context['show_prepaid_modal'] = True context['prepaid_days_remaining'] = prepaid_days_remaining context['prepaid_weeks_remaining'] = max( prepaid_days_remaining // 7, 1) context['monthly_fee'] = monthly_fee context[ 'edition'] = current_subscription.plan_version.plan.edition context['prepaid_remaining_date'] = prepaid_remaining_date return context
def setUp(self): super(TestBillingAutoPay, self).setUp() self.account.created_by_domain = self.domain self.account.save() self.currency = generator.init_default_currency() self.web_user = generator.arbitrary_web_user() self.dimagi_user = generator.arbitrary_web_user(is_dimagi=True) self.fake_card = FakeStripeCard() self.fake_stripe_customer = FakeStripeCustomer(cards=[self.fake_card]) self.account.update_autopay_user(self.web_user.username, self.domain) self.invoice_date = utils.months_from_date(self.subscription.date_start, random.randint(2, self.subscription_length)) self.account_2 = generator.billing_account(self.dimagi_user, self.web_user) self.domain_2 = generator.arbitrary_domain() self.subscription_2, self.subscription_length_2 = generator.generate_domain_subscription_from_date( generator.get_start_date(), self.account_2, self.domain_2.name, min_num_months=self.min_subscription_length, ) tasks.generate_invoices(self.invoice_date)
def test_date_due_not_set_small_invoice(self): """Date Due doesn't get set if the invoice is small""" invoice_date_small = utils.months_from_date(self.subscription.date_start, 1) tasks.generate_invoices(invoice_date_small) small_invoice = self.subscription.invoice_set.first() self.assertTrue(small_invoice.balance <= SMALL_INVOICE_THRESHOLD) self.assertIsNone(small_invoice.date_due)
def test_no_invoice_after_end(self): """ No invoices should be generated for the months after the end date of the subscriptions. """ invoice_date = utils.months_from_date(self.sub2.date_end, 2) calculate_users_in_all_domains(invoice_date) tasks.generate_invoices(invoice_date) self.assertEqual(CustomerInvoice.objects.count(), 0)
def setUp(self): super(TestContractedInvoices, self).setUp() self.subscription.service_type = SubscriptionType.IMPLEMENTATION self.subscription.save() self.invoice_date = utils.months_from_date( self.subscription.date_start, random.randint(2, self.subscription_length))
def test_prorate(self): """ Make sure that the product is prorated for the first and last invoices, which fall in a partial month: - base_cost is 0.0 - base_description is None - unit_description is not None - unit_cost is prorated - quantity > 1 - subtotal = unit_cost * quantity """ first_invoice_date = utils.months_from_date(self.subscription.date_start, 1) tasks.generate_invoices(first_invoice_date) last_invoice_date = utils.months_from_date(self.subscription.date_end, 1) tasks.generate_invoices(last_invoice_date) for invoice in self.subscription.invoice_set.all(): product_line_items = invoice.lineitem_set.filter(feature_rate__exact=None) self.assertEqual(product_line_items.count(), 1) product_line_item = product_line_items.get() days_prorated_by_invoice_start_date = { datetime.date(2016, 2, 23): 7, datetime.date(2017, 5, 1): 22, } days_in_month_by_invoice_start_date = { datetime.date(2016, 2, 23): 29, datetime.date(2017, 5, 1): 31, } self.assertEqual(product_line_item.quantity, days_prorated_by_invoice_start_date[invoice.date_start]) self.assertEqual( product_line_item.unit_cost, Decimal("%.2f" % round( self.product_rate.monthly_fee / days_in_month_by_invoice_start_date[invoice.date_start], 2 )) ) self.assertIsNotNone(product_line_item.unit_description) self.assertEqual(product_line_item.base_cost, Decimal('0.0000')) self.assertIsNone(product_line_item.base_description) self.assertEqual(product_line_item.subtotal, product_line_item.unit_cost * product_line_item.quantity) # no adjustments self.assertEqual(product_line_item.total, product_line_item.unit_cost * product_line_item.quantity)
def test_date_due_gets_set_autopay(self): """Date due always gets set for autopay """ self.subscription.account.update_autopay_user(self.billing_contact, self.domain) invoice_date_autopay = utils.months_from_date(self.subscription.date_start, 1) tasks.generate_invoices(invoice_date_autopay) autopay_invoice = self.subscription.invoice_set.last() self.assertTrue(autopay_invoice.balance <= SMALL_INVOICE_THRESHOLD) self.assertIsNotNone(autopay_invoice.date_due)
def test_unspecified_recipients_product(self): self._setup_product_subscription_with_admin_user() invoice_date = utils.months_from_date(self.subscription.date_start, 1) tasks.generate_invoices(invoice_date) self.assertEqual(len(mail.outbox), 1) self.assertListEqual(mail.outbox[0].to, ['*****@*****.**']) self.assertListEqual(mail.outbox[0].cc, [])
def setUp(self): super(TestContractedInvoices, self).setUp() self.subscription.service_type = SubscriptionType.IMPLEMENTATION self.subscription.save() self.invoice_date = utils.months_from_date( self.subscription.date_start, random.randint(2, self.subscription_length) )
def test_implementation_subscription_without_dimagi_contact(self): self._setup_implementation_subscription_without_dimagi_contact() invoice_date = utils.months_from_date(self.subscription.date_start, 1) tasks.generate_invoices(invoice_date) self.assertEqual(len(mail.outbox), 1) sent_email = mail.outbox[0] self.assertListEqual(sent_email.to, [settings.ACCOUNTS_EMAIL]) self.assertListEqual(sent_email.cc, [])
def test_date_due_set_large_invoice(self): """Date Due only gets set for a large invoice (> $100)""" self.subscription.plan_version = generator.subscribable_plan_version(SoftwarePlanEdition.ADVANCED) self.subscription.save() invoice_date_large = utils.months_from_date(self.subscription.date_start, 3) tasks.generate_invoices(invoice_date_large) large_invoice = self.subscription.invoice_set.last() self.assertTrue(large_invoice.balance > SMALL_INVOICE_THRESHOLD) self.assertIsNotNone(large_invoice.date_due)
def test_product_subscription(self): self._setup_product_subscription() invoice_date = utils.months_from_date(self.subscription.date_start, 1) tasks.generate_invoices(invoice_date) self.assertEqual(len(mail.outbox), 2) self.assertListEqual(mail.outbox[0].to, ['*****@*****.**']) self.assertListEqual(mail.outbox[0].cc, []) self.assertListEqual(mail.outbox[1].to, ['*****@*****.**']) self.assertListEqual(mail.outbox[1].cc, [])
def months_product_active_over_period(self, num_months): # Calculate the number of months out of num_months the subscription was active quantity = 0 date_start = months_from_date(self.invoice.date_end, -(num_months - 1)) while date_start < self.invoice.date_end: if self.subscription.date_end and self.subscription.date_end <= date_start: continue elif self.subscription.date_start <= date_start: quantity += 1 date_start = date_start + relativedelta(months=1) return quantity
def _test_final_invoice_balance(self): for month_num in range(2, 5): invoice_date = utils.months_from_date(self.subscription.date_start, month_num) tasks.generate_invoices(invoice_date) invoice = self.subscription.invoice_set.latest('date_end') if month_num < 4: # the first two invoices for the line item should be covered by its credit line self.assertEqual(invoice.balance, Decimal('0.0000')) else: self.assertNotEqual(invoice.balance, Decimal('0.0000'))
def _test_specified_recipients(self): DomainInvoiceFactory( self.subscription.date_start, utils.months_from_date(self.subscription.date_start, 1) - datetime.timedelta(days=1), self.subscription.subscriber.domain, recipients=['*****@*****.**', '*****@*****.**'] ).create_invoices() self.assertEqual(len(mail.outbox), 2) self.assertListEqual(mail.outbox[0].to, ['*****@*****.**']) self.assertListEqual(mail.outbox[0].cc, []) self.assertListEqual(mail.outbox[1].to, ['*****@*****.**']) self.assertListEqual(mail.outbox[1].cc, [])
def test_account_level_product_credits(self): CreditLine.add_credit( amount=self.subscription.plan_version.product_rate.monthly_fee / 2, account=self.account, is_product=True ) invoice_date = utils.months_from_date(self.subscription.date_start, random.randint(2, self.subscription_length)) tasks.generate_invoices(invoice_date) self.assertEqual(CustomerInvoice.objects.count(), 1) invoice = CustomerInvoice.objects.first() self.assertEqual(invoice.balance, Decimal('1350.0000'))