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_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)) 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('1100.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('2.0000'))
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_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_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 _create_sms_line_items_for_quarter(self): invoice_start, invoice_end = get_previous_month_date_range( self.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() return invoice.lineitem_set.get_feature_by_type(FeatureType.SMS)
def test_no_invoice_before_start(self): """ Test that an invoice is not created if its subscriptions didn't start in the previous month. """ invoice_start, invoice_end = get_previous_month_date_range( self.subscription.date_start) invoice_factory = CustomerAccountInvoiceFactory( account=self.account, date_start=invoice_start, date_end=invoice_end) invoice_factory.create_invoice() self.assertEqual(CustomerInvoice.objects.count(), 0)
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) 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(), 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) 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() 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_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) invoice_start, invoice_end = get_previous_month_date_range( self.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() 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_product_line_items_in_yearly_invoice(self): 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() self.assertGreater(invoice.balance, Decimal('0.0000')) self.assertEqual(invoice.account, self.account) # There should be two product line items, with 3 months billed for each num_product_line_items = invoice.lineitem_set.get_products().count() self.assertEqual(num_product_line_items, 2) for product_line_item in invoice.lineitem_set.get_products().all(): self.assertEqual(product_line_item.quantity, 12)
def setUp(self): super(TestInvoicingMethods, self).setUp() self.invoice_start = datetime.date(2018, 5, 1) self.invoice_end = datetime.date(2018, 5, 31) self.domain = generator.arbitrary_domain() self.account = BillingAccount.get_or_create_account_by_domain( domain=self.domain, created_by="TEST" )[0] self.account.is_customer_billing_account = True self.account.save() self.invoice_factory = CustomerAccountInvoiceFactory(self.invoice_start, self.invoice_end, self.account) self.advanced_plan = DefaultProductPlan.get_default_plan_version(edition=SoftwarePlanEdition.ADVANCED) self.advanced_plan.plan.is_customer_software_plan = True self.pro_plan = DefaultProductPlan.get_default_plan_version(edition=SoftwarePlanEdition.PRO) self.pro_plan.plan.is_customer_software_plan = True self.subscription = Subscription.new_domain_subscription( self.account, self.domain.name, self.advanced_plan, date_start=self.invoice_start, date_end=self.invoice_end )
def generate_invoices(based_on_date=None): """ Generates all invoices for the past month. """ today = based_on_date or datetime.date.today() invoice_start, invoice_end = get_previous_month_date_range(today) log_accounting_info( "Starting up invoices for %(start)s - %(end)s" % { 'start': invoice_start.strftime(USER_DATE_FORMAT), 'end': invoice_end.strftime(USER_DATE_FORMAT), }) all_domain_ids = [d['id'] for d in Domain.get_all(include_docs=False)] for domain_doc in iter_docs(Domain.get_db(), all_domain_ids): domain_obj = Domain.wrap(domain_doc) if not domain_obj.is_active: continue try: invoice_factory = DomainInvoiceFactory(invoice_start, invoice_end, domain_obj) invoice_factory.create_invoices() log_accounting_info("Sent invoices for domain %s" % domain_obj.name) except CreditLineError as e: log_accounting_error( "There was an error utilizing credits for " "domain %s: %s" % (domain_obj.name, e), show_stack_trace=True, ) except InvoiceError as e: log_accounting_error( "Could not create invoice for domain %s: %s" % (domain_obj.name, e), show_stack_trace=True, ) except Exception as e: log_accounting_error( "Error occurred while creating invoice for " "domain %s: %s" % (domain_obj.name, e), show_stack_trace=True, ) all_customer_billing_accounts = BillingAccount.objects.filter( is_customer_billing_account=True) for account in all_customer_billing_accounts: try: if account.invoicing_plan == InvoicingPlan.QUARTERLY: customer_invoice_start = invoice_start - relativedelta( months=2) elif account.invoicing_plan == InvoicingPlan.YEARLY: customer_invoice_start = invoice_start - relativedelta( months=11) else: customer_invoice_start = invoice_start invoice_factory = CustomerAccountInvoiceFactory( account=account, date_start=customer_invoice_start, date_end=invoice_end) invoice_factory.create_invoice() except CreditLineError as e: log_accounting_error( "There was an error utilizing credits for " "domain %s: %s" % (domain_obj.name, e), show_stack_trace=True, ) except InvoiceError as e: log_accounting_error( "Could not create invoice for domain %s: %s" % (domain_obj.name, e), show_stack_trace=True, ) except Exception as e: log_accounting_error( "Error occurred while creating invoice for " "domain %s: %s" % (domain_obj.name, e), show_stack_trace=True, ) if not settings.UNIT_TESTING: _invoicing_complete_soft_assert(False, "Invoicing is complete!")