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_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_community_over_limit(self): """ For a domain under community (no subscription) with users over the community limit, make sure that: - 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 """ domain = generator.arbitrary_domain() num_active = generator.create_excess_community_users(domain) tasks.generate_invoices() subscriber = Subscriber.objects.get(domain=domain.name) invoice = Invoice.objects.filter(subscription__subscriber=subscriber).get() 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')) num_to_charge = num_active - generator.MAX_COMMUNITY_USERS 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) domain.delete()
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_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_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_community_over_limit(self): """ For a domain under community (no subscription) with users over the community limit, make sure that: - 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 """ domain = generator.arbitrary_domain() num_active = generator.create_excess_community_users(domain) account = BillingAccount.get_or_create_account_by_domain( domain, created_by=self.dimagi_user)[0] billing_contact = generator.arbitrary_contact_info(account, self.dimagi_user) billing_contact.save() account.date_confirmed_extra_charges = datetime.date.today() account.save() tasks.generate_invoices() subscriber = Subscriber.objects.get(domain=domain.name) invoice = Invoice.objects.filter(subscription__subscriber=subscriber).get() 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')) num_to_charge = num_active - self.community_plan.user_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) domain.delete()
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_subscription_level_user_credits(self): # Add User usage num_users = self.user_rate.monthly_limit + 10 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) # Cover the cost of 1 User on the Standard subscription CreditLine.add_credit( amount=Decimal(2.0000), feature_type=FeatureType.USER, subscription=self.subscription ) # Cover the cost of 5 Users on the Advanced subscription CreditLine.add_credit( amount=Decimal(10.0000), feature_type=FeatureType.USER, subscription=self.sub2 ) calculate_users_in_all_domains(self.invoice_date) tasks.generate_invoices(self.invoice_date) self.assertEqual(CustomerInvoice.objects.count(), 1) invoice = CustomerInvoice.objects.first() self.assertEqual(invoice.balance, Decimal(1500.0000))
def test_community(self): """ For Community plans (plan monthly fee is 0.0) that incur other rate charges, like users or SMS messages, make sure that the following is true: - base_description is None - unit_description is None - unit_cost is equal to 0 - quantity is equal to 0 - total and subtotal are 0.0 """ domain = generator.arbitrary_domain() generator.create_excess_community_users(domain) tasks.generate_invoices() subscriber = Subscriber.objects.get(domain=domain.name) invoice = Invoice.objects.filter(subscription__subscriber=subscriber).get() 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.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, Decimal('0.0000')) self.assertEqual(product_line_item.total, Decimal('0.0000')) 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_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) calculate_users_in_all_domains(self.invoice_date) tasks.generate_invoices(self.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_community_invoice(self): """ For an unsubscribed domain with any charges over the community limit for the month of invoicing, make sure that an invoice is generated in addition to a subscription for that month to the community plan. """ domain = generator.arbitrary_domain() generator.create_excess_community_users(domain) account = BillingAccount.get_or_create_account_by_domain( domain, created_by=self.dimagi_user)[0] billing_contact = generator.arbitrary_contact_info(account, self.dimagi_user) billing_contact.save() account.date_confirmed_extra_charges = datetime.date.today() account.save() tasks.generate_invoices() subscriber = Subscriber.objects.get(domain=domain.name) invoices = Invoice.objects.filter(subscription__subscriber=subscriber) self.assertEqual(invoices.count(), 1) invoice = invoices.get() self.assertEqual(invoice.subscription.subscriber.domain, domain.name) self.assertEqual(invoice.subscription.date_start, invoice.date_start) self.assertEqual( invoice.subscription.date_end - datetime.timedelta(days=1), invoice.date_end ) domain.delete()
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_sms_over_limit_in_yearly_invoice(self): num_sms = random.randint(self.sms_rate.monthly_limit + 1, self.sms_rate.monthly_limit + 2) billables = arbitrary_sms_billables_for_domain( self.domain, self.sms_date, num_sms ) num_sms_advanced = random.randint(self.advanced_sms_rate.monthly_limit + 1, self.advanced_sms_rate.monthly_limit + 2) advanced_billables = arbitrary_sms_billables_for_domain( self.domain2, self.sms_date, num_sms_advanced ) tasks.generate_invoices(self.invoice_date) self.assertEqual(CustomerInvoice.objects.count(), 1) invoice = CustomerInvoice.objects.first() sms_line_items = invoice.lineitem_set.get_feature_by_type(FeatureType.SMS) self.assertEqual(sms_line_items.count(), 2) for sms_line_item in sms_line_items: self.assertIsNone(sms_line_item.base_description) self.assertEqual(sms_line_item.base_cost, Decimal('0.0000')) self.assertEqual(sms_line_item.quantity, 1) if self.advanced_sms_rate.feature == sms_line_item.feature_rate.feature: sms_cost = sum( billable.gateway_charge + billable.usage_charge for billable in advanced_billables[self.advanced_sms_rate.monthly_limit:] ) else: sms_cost = sum( billable.gateway_charge + billable.usage_charge for billable in billables[self.sms_rate.monthly_limit:] ) self.assertEqual(sms_line_item.unit_cost, sms_cost) self.assertEqual(sms_line_item.total, sms_cost)
def test_subscription_level_sms_credits(self): # Add SMS usage arbitrary_sms_billables_for_domain( self.domain, self.sms_date, self.sms_rate.monthly_limit + 1 ) arbitrary_sms_billables_for_domain( self.domain2, self.sms_date, num_sms=self.advanced_rate.monthly_limit + 10 ) # Cover the cost of 1 SMS on the Standard subscription CreditLine.add_credit( amount=Decimal(0.7500), feature_type=FeatureType.SMS, subscription=self.subscription ) # Cover the cost of 10 SMS on the Advanced subscription CreditLine.add_credit( amount=Decimal(7.5000), feature_type=FeatureType.SMS, subscription=self.sub2, ) tasks.generate_invoices(self.invoice_date) self.assertEqual(CustomerInvoice.objects.count(), 1) invoice = CustomerInvoice.objects.first() self.assertEqual(invoice.balance, Decimal('1500.0000'))
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) tasks.generate_invoices(self.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_no_invoice_before_start(self): """ Test that an invoice is not created if its subscriptions didn't start in the previous month. """ calculate_users_in_all_domains(self.subscription.date_start) tasks.generate_invoices(self.subscription.date_start) self.assertEqual(CustomerInvoice.objects.count(), 0)
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 test_sms_over_limit_in_yearly_invoice(self): num_sms = random.randint(self.sms_rate.monthly_limit + 1, self.sms_rate.monthly_limit + 2) billables = arbitrary_sms_billables_for_domain(self.domain, self.sms_date, num_sms) num_sms_advanced = random.randint( self.advanced_sms_rate.monthly_limit + 1, self.advanced_sms_rate.monthly_limit + 2) advanced_billables = arbitrary_sms_billables_for_domain( self.domain2, self.sms_date, num_sms_advanced) tasks.generate_invoices(self.invoice_date) self.assertEqual(CustomerInvoice.objects.count(), 1) invoice = CustomerInvoice.objects.first() sms_line_items = invoice.lineitem_set.get_feature_by_type( FeatureType.SMS) self.assertEqual(sms_line_items.count(), 2) for sms_line_item in sms_line_items: self.assertIsNone(sms_line_item.base_description) self.assertEqual(sms_line_item.base_cost, Decimal('0.0000')) self.assertEqual(sms_line_item.quantity, 1) if self.advanced_sms_rate.feature == sms_line_item.feature_rate.feature: sms_cost = sum( billable.gateway_charge + billable.usage_charge for billable in advanced_billables[self.advanced_sms_rate.monthly_limit:]) else: sms_cost = sum( billable.gateway_charge + billable.usage_charge for billable in billables[self.sms_rate.monthly_limit:]) self.assertEqual(sms_line_item.unit_cost, sms_cost) self.assertEqual(sms_line_item.total, sms_cost)
def test_community_invoice(self): """ For an unsubscribed domain with any charges over the community limit for the month of invoicing, make sure that an invoice is generated in addition to a subscription for that month to the community plan. """ domain = generator.arbitrary_domain() generator.create_excess_community_users(domain) account = BillingAccount.get_or_create_account_by_domain( domain, created_by=self.dimagi_user)[0] billing_contact = generator.arbitrary_contact_info(account, self.dimagi_user) account.date_confirmed_extra_charges = datetime.date.today() account.save() tasks.generate_invoices() subscriber = Subscriber.objects.get(domain=domain.name) invoices = Invoice.objects.filter(subscription__subscriber=subscriber) self.assertEqual(invoices.count(), 1) invoice = invoices.get() self.assertEqual(invoice.subscription.subscriber.domain, domain.name) self.assertEqual(invoice.subscription.date_start, invoice.date_start) self.assertEqual( invoice.subscription.date_end - datetime.timedelta(days=1), invoice.date_end ) domain.delete()
def setUp(self): super(TestAdjustBalanceForm, self).setUp() invoice_date = self.subscription.date_start + relativedelta(months=1) calculate_users_in_all_domains( datetime.date(invoice_date.year, invoice_date.month, 1)) generate_invoices(invoice_date) self.invoice = Invoice.objects.first()
def test_subscription_level_sms_credits(self): # Add SMS usage arbitrary_sms_billables_for_domain(self.domain, self.sms_date, self.sms_rate.monthly_limit + 1) arbitrary_sms_billables_for_domain( self.domain2, self.sms_date, num_sms=self.advanced_rate.monthly_limit + 10) # Cover the cost of 1 SMS on the Standard subscription CreditLine.add_credit(amount=Decimal(0.7500), feature_type=FeatureType.SMS, subscription=self.subscription) # Cover the cost of 10 SMS on the Advanced subscription CreditLine.add_credit( amount=Decimal(7.5000), feature_type=FeatureType.SMS, subscription=self.sub2, ) calculate_users_in_all_domains(self.invoice_date) tasks.generate_invoices(self.invoice_date) self.assertEqual(CustomerInvoice.objects.count(), 1) invoice = CustomerInvoice.objects.first() self.assertEqual(invoice.balance, Decimal('1500.0000'))
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_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_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 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_community_over_limit(self): """ For a domain under community (no subscription) with users over the community limit, make sure that: - 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 """ domain = generator.arbitrary_domain() num_active = generator.create_excess_community_users(domain) account = BillingAccount.get_or_create_account_by_domain( domain, created_by=self.dimagi_user)[0] billing_contact = generator.arbitrary_contact_info(account, self.dimagi_user) account.date_confirmed_extra_charges = datetime.date.today() account.save() tasks.generate_invoices() subscriber = Subscriber.objects.get(domain=domain.name) invoice = Invoice.objects.filter(subscription__subscriber=subscriber).get() 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')) community_plan = DefaultProductPlan.get_default_plan_version() num_to_charge = num_active - community_plan.user_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) domain.delete()
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_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_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(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_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 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 _generate_invoices(cls): """ 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(cls.subscription.date_start, cls.subscription_length - 2) tasks.generate_invoices(invoice_date)
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 test_community_no_charges_no_invoice(self): """ No invoices should be generated for domains that are not on a subscription and do not have any per_excess charges on users or SMS messages """ domain = generator.arbitrary_domain() tasks.generate_invoices() self.assertRaises(ObjectDoesNotExist, lambda: Invoice.objects.get(subscription__subscriber__domain=domain.name)) domain.delete()
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 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_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_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_community_no_charges_no_invoice(self): """ No invoices should be generated for domains that are not on a subscription and do not have any per_excess charges on users or SMS messages """ domain = generator.arbitrary_domain() tasks.generate_invoices() self.assertRaises(Invoice.DoesNotExist, lambda: Invoice.objects.get(subscription__subscriber__domain=domain.name)) domain.delete()
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_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_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 test_contracted_invoice_email_recipient(self): """ For contracted invoices, emails should be sent to [email protected] """ expected_recipient = ["*****@*****.**", "*****@*****.**"] tasks.generate_invoices(self.invoice_date) self.assertEqual(Invoice.objects.count(), 1) actual_recipient = Invoice.objects.first().email_recipients self.assertEqual(actual_recipient, expected_recipient)
def test_contracted_invoice_email_template(self): """ Emails for contracted invoices should use the contracted invoices template """ expected_template = BillingRecord.INVOICE_CONTRACTED_HTML_TEMPLATE tasks.generate_invoices(self.invoice_date) self.assertEqual(BillingRecord.objects.count(), 1) actual_template = BillingRecord.objects.first().html_template self.assertTrue(actual_template, expected_template)
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'))