def _generate_rate_credits_for_testing(self, fee, rate_kwarg, generate_invoice_credit=True): """ Generates enough line item credit for two invoicing periods. """ rate_credit_by_account = CreditLine.add_rate_credit( fee, self.account, **rate_kwarg ) self.assertEqual(CreditAdjustment.objects.filter(credit_line=rate_credit_by_account).count(), 1) rate_credit_by_subscription = CreditLine.add_rate_credit( fee, self.account, subscription=self.subscription, **rate_kwarg ) self.assertEqual(CreditAdjustment.objects.filter(credit_line=rate_credit_by_subscription).count(), 1) if generate_invoice_credit: # this credit should not count toward the line item subscription_credit = CreditLine.add_subscription_credit( fee, self.subscription ) self.assertEqual(CreditAdjustment.objects.filter(credit_line=subscription_credit).count(), 1) return rate_credit_by_account, rate_credit_by_subscription
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_product_line_item_credits(self): """ Make sure that the product line item Credit Lines are properly created and that the appropriate CreditAdjustments are being recorded. Also that available credit lines are being applied to the invoices properly. """ rate_credit_by_account = CreditLine.add_credit( self.product_rate.monthly_fee, account=self.account, product_type=SoftwareProductType.ANY) self.assertEqual( CreditAdjustment.objects.filter( credit_line=rate_credit_by_account).count(), 1) rate_credit_by_subscription = CreditLine.add_credit( self.product_rate.monthly_fee, product_type=SoftwareProductType.ANY, subscription=self.subscription) self.assertEqual( CreditAdjustment.objects.filter( credit_line=rate_credit_by_subscription, ).count(), 1) subscription_credit = CreditLine.add_credit( self.product_rate.monthly_fee, subscription=self.subscription, ) self.assertEqual( CreditAdjustment.objects.filter( credit_line=subscription_credit).count(), 1) self._test_line_item_crediting( lambda invoice: invoice.lineitem_set.get_products().get()) self._test_credit_use(rate_credit_by_account) self._test_credit_use(rate_credit_by_subscription)
def test_get_credits_by_subscription_and_features_only_returns_active_credits( self): # Add credits to subscription product_credit = self.add_product_credit(100.00) sms_credit = self.add_sms_credit(200.00) user_credit = self.add_user_credit(300.00) # Deactivate one credit sms_credit.is_active = False sms_credit.save() # Check that get_credits_by_subscription_and_features only returns active credit lines product_credits = CreditLine.get_credits_by_subscription_and_features( subscription=self.subscription, is_product=True) self.assertEqual(1, product_credits.count()) self.assertEqual(product_credit, product_credits.first()) user_credits = CreditLine.get_credits_by_subscription_and_features( subscription=self.subscription, feature_type=FeatureType.USER) self.assertEqual(1, user_credits.count()) self.assertEqual(user_credit, user_credits.first()) sms_credits = CreditLine.get_credits_by_subscription_and_features( subscription=self.subscription, feature_type=FeatureType.SMS) self.assertEqual(0, sms_credits.count())
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 _auto_generate_credits(self, line_item): CreditLine.add_credit( line_item.subtotal, subscription=self.subscription, product_type=SoftwareProductType.ANY, permit_inactive=True, )
def _auto_generate_credits(self, line_item): CreditLine.add_credit( line_item.subtotal, subscription=self.subscription, product_type=self.rate.product.product_type, permit_inactive=True, )
def test_combined_credits(self): """ Test that line item credits get applied first to the line items and invoice credits get applied to the remaining balance. """ user_rate_credit_by_account = CreditLine.add_credit( self.monthly_user_fee, account=self.account, feature_type=self.user_rate.feature.feature_type, ) self.assertEqual(CreditAdjustment.objects.filter( credit_line=user_rate_credit_by_account).count(), 1 ) user_rate_credit_by_subscription = CreditLine.add_credit( self.monthly_user_fee, feature_type=self.user_rate.feature.feature_type, subscription=self.subscription ) self.assertEqual(CreditAdjustment.objects.filter( credit_line=user_rate_credit_by_subscription ).count(), 1) subscription_credit, account_credit = self._generate_subscription_and_account_invoice_credits( self.product_rate.monthly_fee, self.subscription, self.account ) self._test_final_invoice_balance() self._test_credit_use(subscription_credit) self._test_credit_use(user_rate_credit_by_subscription) self._test_credit_use(subscription_credit) self._test_credit_use(account_credit)
def _auto_generate_credits(self, line_item): CreditLine.add_credit( line_item.subtotal, subscription=self.subscription, is_product=True, permit_inactive=True, )
def test_feature_line_item_credits(self): """ Make sure that the feature line item Credit Lines are properly created and that the appropriate CreditAdjustments are being recorded. Also that available credit lines are being applied to the invoices properly. """ rate_credit_by_account = CreditLine.add_credit( self.monthly_user_fee, account=self.account, feature_type=self.user_rate.feature.feature_type, ) self.assertEqual(CreditAdjustment.objects.filter( credit_line=rate_credit_by_account).count(), 1 ) rate_credit_by_subscription = CreditLine.add_credit( self.monthly_user_fee, feature_type=self.user_rate.feature.feature_type, subscription=self.subscription ) self.assertEqual(CreditAdjustment.objects.filter( credit_line=rate_credit_by_subscription ).count(), 1) subscription_credit = CreditLine.add_credit( self.monthly_user_fee, subscription=self.subscription ) self.assertEqual(CreditAdjustment.objects.filter( credit_line=subscription_credit).count(), 1 ) self._test_line_item_crediting( lambda invoice: invoice.lineitem_set.get_feature_by_type(FeatureType.USER).get() ) self._test_credit_use(rate_credit_by_account) self._test_credit_use(rate_credit_by_subscription)
def test_get_credits_by_subscription_and_features_only_returns_active_credits(self): # Add credits to subscription product_credit = self.add_product_credit(100.00) sms_credit = self.add_sms_credit(200.00) user_credit = self.add_user_credit(300.00) # Deactivate one credit sms_credit.is_active = False sms_credit.save() # Check that get_credits_by_subscription_and_features only returns active credit lines product_credits = CreditLine.get_credits_by_subscription_and_features( subscription=self.subscription, is_product=True ) self.assertEqual(1, product_credits.count()) self.assertEqual(product_credit, product_credits.first()) user_credits = CreditLine.get_credits_by_subscription_and_features( subscription=self.subscription, feature_type=FeatureType.USER ) self.assertEqual(1, user_credits.count()) self.assertEqual(user_credit, user_credits.first()) sms_credits = CreditLine.get_credits_by_subscription_and_features( subscription=self.subscription, feature_type=FeatureType.SMS ) self.assertEqual(0, sms_credits.count())
def get_credits_available_for_product_in_subscription(current_subscription): return sum([ credit_line.balance for credit_line in itertools.chain( CreditLine.get_credits_by_subscription_and_features(current_subscription, is_product=True), CreditLine.get_credits_by_subscription_and_features(current_subscription), ) ])
def get_credits_available_for_product_in_account(account): return sum([ credit_line.balance for credit_line in itertools.chain( CreditLine.get_credits_for_account(account, is_product=True), CreditLine.get_credits_for_account(account), ) ])
def test_combined_credits(self): """ Test that line item credits get applied first to the line items and invoice credits get applied to the remaining balance. """ user_rate_credit_by_account = CreditLine.add_credit( self.monthly_user_fee, account=self.account, feature_type=self.user_rate.feature.feature_type, ) self.assertEqual( CreditAdjustment.objects.filter( credit_line=user_rate_credit_by_account).count(), 1) user_rate_credit_by_subscription = CreditLine.add_credit( self.monthly_user_fee, feature_type=self.user_rate.feature.feature_type, subscription=self.subscription) self.assertEqual( CreditAdjustment.objects.filter( credit_line=user_rate_credit_by_subscription).count(), 1) subscription_credit, account_credit = self._generate_subscription_and_account_invoice_credits( self.product_rate.monthly_fee, self.subscription, self.account) self._test_final_invoice_balance() self._test_credit_use(subscription_credit) self._test_credit_use(user_rate_credit_by_subscription) self._test_credit_use(subscription_credit) self._test_credit_use(account_credit)
def update_credits(self, payment_record): for feature in self.features: feature_amount = feature['amount'] if feature_amount >= 0.5: self.credit_lines.append( CreditLine.add_credit( feature_amount, account=self.account, subscription=self.subscription, feature_type=feature['type'], payment_record=payment_record, )) else: log_accounting_error( "{account} tried to make a payment for {feature} for less than $0.5." "You should follow up with them.".format( account=self.account, feature=feature['type'])) for product in self.products: plan_amount = product['amount'] if plan_amount >= 0.5: self.credit_lines.append( CreditLine.add_credit( plan_amount, account=self.account, subscription=self.subscription, product_type=SoftwareProductType.ANY, payment_record=payment_record, )) else: log_accounting_error( "{account} tried to make a payment for {product} for less than $0.5." "You should follow up with them.".format( account=self.account, product=product['type']))
def test_transfer_credit_without_credit(self): original_credit_balance = 0 CreditLine.add_credit( original_credit_balance, account=self.subscription.account, subscription=self.subscription, ) original_balance = self.invoice.balance adjustment_amount = random.randint(1, 5) adjust_balance_form = AdjustBalanceForm( self.invoice, { 'adjustment_type': 'credit', 'custom_amount': adjustment_amount, 'method': CreditAdjustmentReason.TRANSFER, 'note': 'some text', 'invoice_id': self.invoice.id, } ) self.assertTrue(adjust_balance_form.is_valid()) adjust_balance_form.adjust_balance() self.assertEqual(original_balance, self.invoice.balance) self.assertEqual(original_credit_balance, sum( credit_line.balance for credit_line in CreditLine.get_credits_for_invoice(self.invoice) ))
def test_product_line_item_credits(self): """ Make sure that the product line item Credit Lines are properly created and that the appropriate CreditAdjustments are being recorded. Also that available credit lines are being applied to the invoices properly. """ rate_credit_by_account = CreditLine.add_credit( self.product_rate.monthly_fee, account=self.account, product_type=SoftwareProductType.ANY ) self.assertEqual(CreditAdjustment.objects.filter( credit_line=rate_credit_by_account).count(), 1 ) rate_credit_by_subscription = CreditLine.add_credit( self.product_rate.monthly_fee, product_type=SoftwareProductType.ANY, subscription=self.subscription ) self.assertEqual(CreditAdjustment.objects.filter( credit_line=rate_credit_by_subscription, ).count(), 1) subscription_credit = CreditLine.add_credit( self.product_rate.monthly_fee, subscription=self.subscription, ) self.assertEqual(CreditAdjustment.objects.filter( credit_line=subscription_credit).count(), 1 ) self._test_line_item_crediting( lambda invoice: invoice.lineitem_set.get_products().get() ) self._test_credit_use(rate_credit_by_account) self._test_credit_use(rate_credit_by_subscription)
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 _generate_subscription_and_account_invoice_credits(self, monthly_fee, subscription, account): subscription_credit = CreditLine.add_credit(monthly_fee, subscription=subscription) self.assertEqual(CreditAdjustment.objects.filter(credit_line=subscription_credit).count(), 1) account_credit = CreditLine.add_credit(monthly_fee, account=account) self.assertEqual(CreditAdjustment.objects.filter(credit_line=account_credit).count(), 1) return subscription_credit, account_credit
def test_feature_line_item_credits(self): """ Make sure that the feature line item Credit Lines are properly created and that the appropriate CreditAdjustments are being recorded. Also that available credit lines are being applied to the invoices properly. """ rate_credit_by_account = CreditLine.add_credit( self.monthly_user_fee, account=self.account, feature_type=self.user_rate.feature.feature_type, ) self.assertEqual( CreditAdjustment.objects.filter( credit_line=rate_credit_by_account).count(), 1) rate_credit_by_subscription = CreditLine.add_credit( self.monthly_user_fee, feature_type=self.user_rate.feature.feature_type, subscription=self.subscription) self.assertEqual( CreditAdjustment.objects.filter( credit_line=rate_credit_by_subscription).count(), 1) subscription_credit = CreditLine.add_credit( self.monthly_user_fee, subscription=self.subscription) self.assertEqual( CreditAdjustment.objects.filter( credit_line=subscription_credit).count(), 1) self._test_line_item_crediting( lambda invoice: invoice.lineitem_set.get_feature_by_type( FeatureType.USER).get()) self._test_credit_use(rate_credit_by_account) self._test_credit_use(rate_credit_by_subscription)
def update_credits(self, payment_record): for feature in self.features: feature_amount = feature['amount'] if feature_amount >= 0.5: self.credit_lines.append(CreditLine.add_credit( feature_amount, account=self.account, subscription=self.subscription, feature_type=feature['type'], payment_record=payment_record, )) else: logger.error("[BILLING] {account} tried to make a payment for {feature} for less than $0.5." "You should follow up with them.".format(account=self.account, feature=feature['type'])) for product in self.products: plan_amount = product['amount'] if plan_amount >= 0.5: self.credit_lines.append(CreditLine.add_credit( plan_amount, account=self.account, subscription=self.subscription, product_type=product['type'], payment_record=payment_record, )) else: logger.error("[BILLING] {account} tried to make a payment for {product} for less than $0.5." "You should follow up with them.".format(account=self.account, product=product['type']))
def test_transfers(self): advanced_plan = DefaultProductPlan.get_default_plan_by_domain(self.domain, edition=SoftwarePlanEdition.ADVANCED) standard_plan = DefaultProductPlan.get_default_plan_by_domain(self.domain, edition=SoftwarePlanEdition.STANDARD) first_sub = Subscription.new_domain_subscription(self.account, self.domain, advanced_plan) product_credit = CreditLine.add_credit( self.product_credit_amt, subscription=first_sub, product_type=SoftwareProductType.COMMCARE ) feature_credit = CreditLine.add_credit( self.feature_credit_amt, subscription=first_sub, feature_type=FeatureType.USER ) subscription_credit = CreditLine.add_credit(self.subscription_credit_amt, subscription=first_sub) original_credits = [product_credit, feature_credit, subscription_credit] second_sub = first_sub.change_plan(standard_plan) second_credits = self._ensure_transfer(original_credits) for credit_line in second_credits: self.assertEqual(credit_line.subscription.pk, second_sub.pk) second_sub.date_end = datetime.date.today() + datetime.timedelta(days=5) second_sub.save() third_sub = second_sub.renew_subscription() third_credits = self._ensure_transfer(second_credits) for credit_line in third_credits: self.assertEqual(credit_line.subscription.pk, third_sub.pk) third_sub.cancel_subscription() account_credits = self._ensure_transfer(third_credits) for credit_line in account_credits: self.assertIsNone(credit_line.subscription) self.assertEqual(credit_line.account.pk, self.account.pk)
def create_invoice_for_subscription(self, subscription): if subscription.is_trial: # Don't create invoices for trial subscriptions logger.info("[BILLING] Skipping invoicing for Subscription " "%s because it's a trial." % subscription.pk) return if subscription.auto_generate_credits: for product_rate in subscription.plan_version.product_rates.all(): CreditLine.add_credit( product_rate.monthly_fee, subscription=subscription, product_type=product_rate.product.product_type ) days_until_due = DEFAULT_DAYS_UNTIL_DUE if subscription.date_delay_invoicing is not None: td = subscription.date_delay_invoicing - self.date_end days_until_due = max(days_until_due, td.days) date_due = self.date_end + datetime.timedelta(days_until_due) if subscription.date_start > self.date_start: invoice_start = subscription.date_start else: invoice_start = self.date_start if subscription.date_end is not None and subscription.date_end <= self.date_end: # Since the Subscription is actually terminated on date_end # have the invoice period be until the day before date_end. invoice_end = subscription.date_end - datetime.timedelta(days=1) else: invoice_end = self.date_end invoice = Invoice( subscription=subscription, date_start=invoice_start, date_end=invoice_end, date_due=date_due, is_hidden=subscription.do_not_invoice, ) invoice.save() if subscription.subscriptionadjustment_set.count() == 0: # record that the subscription was created SubscriptionAdjustment.record_adjustment( subscription, method=SubscriptionAdjustmentMethod.TASK, invoice=invoice ) self.generate_line_items(invoice, subscription) invoice.calculate_credit_adjustments() invoice.update_balance() invoice.save() record = BillingRecord.generate_record(invoice) try: record.send_email() except InvoiceEmailThrottledError as e: if not self.logged_throttle_error: logger.error("[BILLING] %s" % e) self.logged_throttle_error = True return invoice
def add_sms_credit(self, amount): sms_credit = CreditLine.add_credit(amount, subscription=self.subscription, feature_type=FeatureType.SMS) sms_credits = CreditLine.get_credits_by_subscription_and_features( subscription=self.subscription, feature_type=FeatureType.SMS ) self.assertEqual(1, sms_credits.count()) self.assertEqual(sms_credit, sms_credits.first()) return sms_credit
def add_product_rate(): CreditLine.add_rate_credit( amount, get_account_for_rate(), product_rate=SoftwareProductRate.objects.get(id=self.cleaned_data["product_rate"]), subscription=subscription, note=note, )
def add_product_credit(self, amount): product_credit = CreditLine.add_credit(amount, subscription=self.subscription, is_product=True) product_credits = CreditLine.get_credits_by_subscription_and_features( subscription=self.subscription, is_product=True ) self.assertEqual(1, product_credits.count()) self.assertEqual(product_credit, product_credits.first()) return product_credit
def add_feature_rate(): CreditLine.add_rate_credit( amount, get_account_for_rate(), feature_rate=FeatureRate.objects.get(id=self.cleaned_data["feature_rate"]), subscription=subscription, note=note, )
def add_user_credit(self, amount): user_credit = CreditLine.add_credit(amount, subscription=self.subscription, feature_type=FeatureType.USER) user_credits = CreditLine.get_credits_by_subscription_and_features( subscription=self.subscription, feature_type=FeatureType.USER ) self.assertEqual(1, user_credits.count()) self.assertEqual(user_credit, user_credits.first()) return user_credit
def add_account_credit(self, amount): account_credit = CreditLine.add_credit(amount, account=self.account) self.assertEqual( CreditLine.get_credits_for_account(self.account).count(), 1) self.assertEqual( account_credit, CreditLine.get_credits_for_account(self.account).first()) return account_credit
def test_transfers(self): advanced_plan = DefaultProductPlan.get_default_plan_version( edition=SoftwarePlanEdition.ADVANCED ) standard_plan = DefaultProductPlan.get_default_plan_version( edition=SoftwarePlanEdition.STANDARD ) first_sub = Subscription.new_domain_subscription( self.account, self.domain.name, advanced_plan, date_start=datetime.date.today() - relativedelta(days=1), ) product_credit = CreditLine.add_credit( self.product_credit_amt, subscription=first_sub, is_product=True, ) feature_credit = CreditLine.add_credit( self.feature_credit_amt, subscription=first_sub, feature_type=FeatureType.USER, ) subscription_credit = CreditLine.add_credit( self.subscription_credit_amt, subscription=first_sub, ) original_credits = [ product_credit, feature_credit, subscription_credit, ] second_sub = first_sub.change_plan(standard_plan) second_credits = self._ensure_transfer(original_credits) for credit_line in second_credits: self.assertEqual(credit_line.subscription.pk, second_sub.pk) second_sub.date_end = datetime.date.today() + datetime.timedelta(days=5) second_sub.save() third_sub = second_sub.renew_subscription() deactivate_subscriptions(second_sub.date_end) third_sub = Subscription.visible_objects.get(id=third_sub.id) third_credits = self._ensure_transfer(second_credits) for credit_line in third_credits: self.assertEqual(credit_line.subscription.pk, third_sub.pk) third_sub.date_end = third_sub.date_start + relativedelta(days=1) third_sub.save() Subscription.new_domain_subscription( self.other_account, self.domain, DefaultProductPlan.get_default_plan_version(), date_start=third_sub.date_end, ) deactivate_subscriptions(third_sub.date_end) account_credits = self._ensure_transfer(third_credits) for credit_line in account_credits: self.assertIsNone(credit_line.subscription) self.assertEqual(credit_line.account.pk, self.account.pk)
def test_balance_adjustment(self): """ Makes sure that the balance is added to the same invoice and same line item credit. """ product_credit = CreditLine.add_credit( self.product_rate.monthly_fee, account=self.account, product_type=self.product_rate.product.product_type ) self.assertEqual(CreditAdjustment.objects.filter(credit_line=product_credit).count(), 1) CreditLine.add_credit( self.product_rate.monthly_fee, account=self.account, product_type=self.product_rate.product.product_type ) self.assertEqual(CreditAdjustment.objects.filter(credit_line=product_credit).count(), 2) current_product_credit = CreditLine.objects.get(id=product_credit.id) self.assertEqual(current_product_credit.balance, self.product_rate.monthly_fee * 2) subscription_credit = CreditLine.add_credit(self.monthly_user_fee, subscription=self.subscription) self.assertEqual(CreditAdjustment.objects.filter(credit_line=subscription_credit).count(), 1) CreditLine.add_credit(self.monthly_user_fee, subscription=self.subscription) self.assertEqual(CreditAdjustment.objects.filter(credit_line=subscription_credit).count(), 2) current_subscription_credit = CreditLine.objects.get(id=subscription_credit.id) self.assertEqual(current_subscription_credit.balance, self.monthly_user_fee * 2) account_credit = CreditLine.add_credit(self.product_rate.monthly_fee, account=self.account) self.assertEqual(CreditAdjustment.objects.filter(credit_line=account_credit).count(), 1) CreditLine.add_credit(self.monthly_user_fee, account=self.account) self.assertEqual(CreditAdjustment.objects.filter(credit_line=account_credit).count(), 2) current_account_credit = CreditLine.objects.get(id=account_credit.id) self.assertEqual(current_account_credit.balance, self.product_rate.monthly_fee + self.monthly_user_fee)
def _generate_subscription_and_account_invoice_credits(self, monthly_fee, subscription, account): subscription_credit = CreditLine.add_credit( monthly_fee, subscription=subscription, ) self.assertEqual(CreditAdjustment.objects.filter(credit_line=subscription_credit).count(), 1) account_credit = CreditLine.add_credit( monthly_fee, account=account ) self.assertEqual(CreditAdjustment.objects.filter(credit_line=account_credit).count(), 1) return subscription_credit, account_credit
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'))
def update_credits(self, payment_record): # record the credit to the account CreditLine.add_credit( payment_record.amount, account=self.invoice.subscription.account, payment_record=payment_record, ) CreditLine.add_credit( -payment_record.amount, account=self.invoice.subscription.account, invoice=self.invoice, ) self.invoice.update_balance() self.invoice.save()
def _get_credit_info(self, subscription): return { 'general_credit': self._fmt_credit( self._credit_grand_total( CreditLine.get_credits_by_subscription_and_features( subscription))), 'account_general_credit': self._fmt_credit( self._credit_grand_total( CreditLine.get_credits_for_account(subscription.account) if subscription.account else None)), }
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)) calculate_users_in_all_domains(invoice_date) tasks.generate_invoices(invoice_date) self.assertEqual(CustomerInvoice.objects.count(), 1) invoice = CustomerInvoice.objects.first() self.assertEqual(invoice.balance, Decimal('1350.0000'))
def test_transfers(self): advanced_plan = DefaultProductPlan.get_default_plan( edition=SoftwarePlanEdition.ADVANCED) standard_plan = DefaultProductPlan.get_default_plan( edition=SoftwarePlanEdition.STANDARD) first_sub = Subscription.new_domain_subscription( self.account, self.domain.name, advanced_plan) product_credit = CreditLine.add_credit( self.product_credit_amt, subscription=first_sub, product_type=SoftwareProductType.ANY, ) feature_credit = CreditLine.add_credit( self.feature_credit_amt, subscription=first_sub, feature_type=FeatureType.USER, ) subscription_credit = CreditLine.add_credit( self.subscription_credit_amt, subscription=first_sub, ) original_credits = [ product_credit, feature_credit, subscription_credit, ] second_sub = first_sub.change_plan(standard_plan) second_credits = self._ensure_transfer(original_credits) for credit_line in second_credits: self.assertEqual(credit_line.subscription.pk, second_sub.pk) second_sub.date_end = datetime.date.today() + datetime.timedelta( days=5) second_sub.save() third_sub = second_sub.renew_subscription() deactivate_subscriptions(second_sub.date_end) third_credits = self._ensure_transfer(second_credits) for credit_line in third_credits: self.assertEqual(credit_line.subscription.pk, third_sub.pk) third_sub.cancel_subscription() account_credits = self._ensure_transfer(third_credits) for credit_line in account_credits: self.assertIsNone(credit_line.subscription) self.assertEqual(credit_line.account.pk, self.account.pk)
def test_balance_adjustment(self): """ Makes sure that the balance is added to the same invoice and same line item credit. """ product_credit = CreditLine.add_credit( self.product_rate.monthly_fee, account=self.account, product_type=SoftwareProductType.ANY, ) self.assertEqual( CreditAdjustment.objects.filter( credit_line=product_credit).count(), 1) CreditLine.add_credit( self.product_rate.monthly_fee, account=self.account, product_type=SoftwareProductType.ANY, ) self.assertEqual( CreditAdjustment.objects.filter( credit_line=product_credit).count(), 2) current_product_credit = CreditLine.objects.get(id=product_credit.id) self.assertEqual(current_product_credit.balance, self.product_rate.monthly_fee * 2) subscription_credit = CreditLine.add_credit( self.monthly_user_fee, subscription=self.subscription) self.assertEqual( CreditAdjustment.objects.filter( credit_line=subscription_credit).count(), 1) CreditLine.add_credit( self.monthly_user_fee, subscription=self.subscription, ) self.assertEqual( CreditAdjustment.objects.filter( credit_line=subscription_credit).count(), 2) current_subscription_credit = CreditLine.objects.get( id=subscription_credit.id) self.assertEqual(current_subscription_credit.balance, self.monthly_user_fee * 2) account_credit = CreditLine.add_credit(self.product_rate.monthly_fee, account=self.account) self.assertEqual( CreditAdjustment.objects.filter( credit_line=account_credit).count(), 1) CreditLine.add_credit(self.monthly_user_fee, account=self.account) self.assertEqual( CreditAdjustment.objects.filter( credit_line=account_credit).count(), 2) current_account_credit = CreditLine.objects.get(id=account_credit.id) self.assertEqual(current_account_credit.balance, self.product_rate.monthly_fee + self.monthly_user_fee)
def test_subscription_credits_transfer_in_invoice(self): standard_plan = DefaultProductPlan.get_default_plan_version( edition=SoftwarePlanEdition.STANDARD) pro_plan = DefaultProductPlan.get_default_plan_version( edition=SoftwarePlanEdition.PRO) first_sub = Subscription.new_domain_subscription( self.account, self.domain.name, standard_plan, date_start=datetime.date(2019, 9, 1), ) credit_amount = Decimal('5000.00') CreditLine.add_credit( credit_amount, subscription=first_sub, ) # this is the key step where the expected transfer happens second_sub = first_sub.change_plan(pro_plan) first_sub = Subscription.visible_objects.get(id=first_sub.id) first_sub.date_end = datetime.date(2019, 9, 10) first_sub.save() second_sub.date_start = first_sub.date_end second_sub.save() invoice_date = utils.months_from_date(first_sub.date_start, 1) user_record_date = invoice_date - relativedelta(days=1) DomainUserHistory.objects.create(domain=self.domain, num_users=0, record_date=user_record_date) tasks.generate_invoices_based_on_date( utils.months_from_date(first_sub.date_start, 1)) self.assertEqual(first_sub.invoice_set.count(), 1) self.assertEqual(second_sub.invoice_set.count(), 1) first_invoice = first_sub.invoice_set.first() second_invoice = second_sub.invoice_set.first() self.assertEqual(first_invoice.balance, Decimal('0.0000')) self.assertEqual(second_invoice.balance, Decimal('0.0000')) self.assertEqual(self._get_credit_total(second_sub), Decimal('4490.0000'))
def test_get_credits_for_account_only_returns_active_credit(self): account_credit = self.add_account_credit(100.00) # Deactivate credit line account_credit.is_active = False account_credit.save() # Check that get_credits_for_account does not return deactivated credit line self.assertEqual(CreditLine.get_credits_for_account(self.account).count(), 0)
def test_account_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 CreditLine.add_credit( amount=Decimal(2.0000), feature_type=FeatureType.USER, account=self.account, ) tasks.generate_invoices(self.invoice_date) self.assertEqual(CustomerInvoice.objects.count(), 1) invoice = CustomerInvoice.objects.first() self.assertEqual(invoice.balance, Decimal(1509.0000))
def update_credits(self, payment_record): if self.general_credits: amount = self.general_credits['amount'] if amount >= 0.5: self.credit_lines.append(CreditLine.add_credit( amount, account=self.account, subscription=self.subscription, payment_record=payment_record, ))
def test_one_subscription_level_user_credit(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 2 Users on the Advanced subscription CreditLine.add_credit( amount=Decimal(4.0000), feature_type=FeatureType.USER, subscription=self.sub2 ) 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(1507.0000))
def update_credits(self, payment_record): # record the credit to the account if self.invoice.is_customer_invoice: customer_invoice = self.invoice subscription_invoice = None account = self.invoice.account else: customer_invoice = None subscription_invoice = self.invoice account = self.invoice.subscription.account CreditLine.add_credit( payment_record.amount, account=account, payment_record=payment_record, ) CreditLine.add_credit(-payment_record.amount, account=account, invoice=subscription_invoice, customer_invoice=customer_invoice) self.invoice.update_balance() self.invoice.save()
def test_get_non_general_credits_by_subscription_only_returns_active_credits(self): # Add credits to subscription product_credit = self.add_product_credit(100.00) sms_credit = self.add_sms_credit(200.00) user_credit = self.add_user_credit(300.00) non_general_credits = CreditLine.get_non_general_credits_by_subscription(subscription=self.subscription) self.assertEqual(3, non_general_credits.count()) self.assertIn(product_credit, non_general_credits) self.assertIn(sms_credit, non_general_credits) self.assertIn(user_credit, non_general_credits) # Deactivate one credit sms_credit.is_active = False sms_credit.save() non_general_credits = CreditLine.get_non_general_credits_by_subscription(subscription=self.subscription) self.assertEqual(2, non_general_credits.count()) self.assertIn(product_credit, non_general_credits) self.assertNotIn(sms_credit, non_general_credits) self.assertIn(user_credit, non_general_credits)
def test_one_subscription_level_user_credit(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 2 Users on the Advanced subscription CreditLine.add_credit( amount=Decimal(4.0000), feature_type=FeatureType.USER, subscription=self.sub2 ) 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() self.assertEqual(invoice.balance, Decimal(1507.0000))
def update_credits(self, payment_record): amount = payment_record.amount for invoice in self.invoices: deduct_amount = min(amount, invoice.balance) amount -= deduct_amount if deduct_amount > 0: if self.account and self.account.is_customer_billing_account: customer_invoice = invoice subscription_invoice = None account = self.account else: customer_invoice = None subscription_invoice = invoice account = invoice.subscription.account # TODO - refactor duplicated functionality CreditLine.add_credit( deduct_amount, account=account, payment_record=payment_record, ) CreditLine.add_credit(-deduct_amount, account=account, invoice=subscription_invoice, customer_invoice=customer_invoice) invoice.update_balance() invoice.save() if amount: account = BillingAccount.get_or_create_account_by_domain( self.domain)[0] CreditLine.add_credit( amount, account=account, payment_record=payment_record, )
def update_credits(self, payment_record): amount = payment_record.amount for invoice in self.invoices: deduct_amount = min(amount, invoice.balance) amount -= deduct_amount if deduct_amount > 0: if self.account and self.account.is_customer_billing_account: customer_invoice = invoice subscription_invoice = None account = self.account else: customer_invoice = None subscription_invoice = invoice account = invoice.subscription.account # TODO - refactor duplicated functionality CreditLine.add_credit( deduct_amount, account=account, payment_record=payment_record, ) CreditLine.add_credit( -deduct_amount, account=account, invoice=subscription_invoice, customer_invoice=customer_invoice ) invoice.update_balance() invoice.save() if amount: account = BillingAccount.get_or_create_account_by_domain(self.domain)[0] CreditLine.add_credit( amount, account=account, payment_record=payment_record, )
def test_active_subscription_credits_transferred_to_account(self): credit_amount = random.randint(1, 10) CreditLine.add_credit( credit_amount, feature_type=FeatureType.SMS, subscription=self.current_subscription, ) self.domain.delete() subscription_credits = CreditLine.get_credits_by_subscription_and_features( self.current_subscription, feature_type=FeatureType.SMS, ) self.assertEqual(len(subscription_credits), 1) self.assertEqual(subscription_credits[0].balance, Decimal('0.0000')) account_credits = CreditLine.get_credits_for_account( self.current_subscription.account, feature_type=FeatureType.SMS, ) self.assertEqual(len(account_credits), 1) self.assertEqual(account_credits[0].balance, Decimal(credit_amount))