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 _create_invoice_for_subscription(self, subscription): def _get_invoice_start(sub, date_start): if sub.date_start > date_start: return sub.date_start else: return date_start def _get_invoice_end(sub, date_end): if sub.date_end is not None and sub.date_end <= date_end: # Since the Subscription is actually terminated on date_end # have the invoice period be until the day before date_end. return sub.date_end - datetime.timedelta(days=1) else: return date_end if subscription.is_trial: # Don't create invoices for trial subscriptions log_accounting_info( "Skipping invoicing for Subscription %s because it's a trial." % subscription.pk ) return if ( subscription.skip_invoicing_if_no_feature_charges and not subscription.plan_version.feature_charges_exist_for_domain(self.domain) ): log_accounting_info( "Skipping invoicing for Subscription %s because there are no feature charges." % subscription.pk ) return invoice_start = _get_invoice_start(subscription, self.date_start) invoice_end = _get_invoice_end(subscription, self.date_end) with transaction.atomic(): invoice = self._generate_invoice(subscription, invoice_start, invoice_end) record = BillingRecord.generate_record(invoice) if record.should_send_email: try: record.send_email(contact_emails=self.recipients) except InvoiceEmailThrottledError as e: if not self.logged_throttle_error: log_accounting_error(e.message) self.logged_throttle_error = True else: record.skipped_email = True record.save() return invoice
def _create_invoice_for_subscription(self, subscription): def _get_invoice_start(sub, date_start): return max(sub.date_start, date_start) def _get_invoice_end(sub, date_end): if sub.date_end is not None and sub.date_end <= date_end: # Since the Subscription is actually terminated on date_end # have the invoice period be until the day before date_end. return sub.date_end - datetime.timedelta(days=1) else: return date_end invoice_start = _get_invoice_start(subscription, self.date_start) invoice_end = _get_invoice_end(subscription, self.date_end) with transaction.atomic(): invoice = self._generate_invoice(subscription, invoice_start, invoice_end) record = BillingRecord.generate_record(invoice) if record.should_send_email: try: if invoice.subscription.service_type == SubscriptionType.IMPLEMENTATION: if self.recipients: for email in self.recipients: record.send_email(contact_email=email) elif invoice.account.dimagi_contact: record.send_email( contact_email=invoice.account.dimagi_contact, cc_emails=[settings.ACCOUNTS_EMAIL]) else: record.send_email( contact_email=settings.ACCOUNTS_EMAIL) else: for email in self.recipients or invoice.get_contact_emails( ): record.send_email(contact_email=email) except InvoiceEmailThrottledError as e: if not self.logged_throttle_error: log_accounting_error(str(e)) self.logged_throttle_error = True else: record.skipped_email = True record.save() return invoice
def setUp(self): super(TestBillingRecord, self).setUp() self.billing_contact = generator.arbitrary_web_user() self.dimagi_user = generator.arbitrary_web_user(is_dimagi=True) self.domain = Domain(name='test') self.domain.save() self.invoice_start, self.invoice_end = get_previous_month_date_range() self.currency = generator.init_default_currency() self.account = generator.billing_account(self.dimagi_user, self.billing_contact) self.subscription, self.subscription_length = generator.generate_domain_subscription_from_date( datetime.date.today(), self.account, self.domain.name ) self.invoice = Invoice( subscription=self.subscription, date_start=self.invoice_start, date_end=self.invoice_end, is_hidden=False, ) self.billing_record = BillingRecord(invoice=self.invoice)
def _create_invoice_for_subscription(self, subscription): def _get_invoice_start(sub, date_start): return max(sub.date_start, date_start) def _get_invoice_end(sub, date_end): if sub.date_end is not None and sub.date_end <= date_end: # Since the Subscription is actually terminated on date_end # have the invoice period be until the day before date_end. return sub.date_end - datetime.timedelta(days=1) else: return date_end invoice_start = _get_invoice_start(subscription, self.date_start) invoice_end = _get_invoice_end(subscription, self.date_end) with transaction.atomic(): invoice = self._generate_invoice(subscription, invoice_start, invoice_end) record = BillingRecord.generate_record(invoice) if record.should_send_email: try: if invoice.subscription.service_type == SubscriptionType.IMPLEMENTATION: if self.recipients: for email in self.recipients: record.send_email(contact_email=email) elif invoice.account.dimagi_contact: record.send_email(contact_email=invoice.account.dimagi_contact, cc_emails=[settings.ACCOUNTS_EMAIL]) else: record.send_email(contact_email=settings.ACCOUNTS_EMAIL) else: for email in self.recipients or invoice.contact_emails: record.send_email(contact_email=email) except InvoiceEmailThrottledError as e: if not self.logged_throttle_error: log_accounting_error(six.text_type(e)) self.logged_throttle_error = True else: record.skipped_email = True record.save() return invoice
def _create_invoice_for_subscription(self, subscription): def _get_invoice_start(sub, date_start): if sub.date_start > date_start: return sub.date_start else: return date_start def _get_invoice_end(sub, date_end): if ( sub.date_end is not None and sub.date_end <= date_end ): # Since the Subscription is actually terminated on date_end # have the invoice period be until the day before date_end. return sub.date_end - datetime.timedelta(days=1) else: return date_end if subscription.is_trial: # Don't create invoices for trial subscriptions log_accounting_info( "Skipping invoicing for Subscription %s because it's a trial." % subscription.pk ) return invoice_start = _get_invoice_start(subscription, self.date_start) invoice_end = _get_invoice_end(subscription, self.date_end) with transaction.atomic(): invoice = self._generate_invoice(subscription, invoice_start, invoice_end) record = BillingRecord.generate_record(invoice) try: record.send_email() except InvoiceEmailThrottledError as e: if not self.logged_throttle_error: log_accounting_error(e.message) self.logged_throttle_error = True return invoice
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.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, is_new_invoice = Invoice.objects.get_or_create( subscription=subscription, date_start=invoice_start, date_end=invoice_end, is_hidden=subscription.do_not_invoice, ) if not is_new_invoice: raise InvoiceAlreadyCreatedError("invoice id: {id}".format(id=invoice.id)) 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() total_balance = sum(invoice.balance for invoice in Invoice.objects.filter( is_hidden=False, subscription__subscriber__domain=invoice.get_domain(), )) if total_balance > SMALL_INVOICE_THRESHOLD: 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) invoice.date_due = self.date_end + datetime.timedelta(days_until_due) 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 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 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.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, is_new_invoice = Invoice.objects.get_or_create( subscription=subscription, date_start=invoice_start, date_end=invoice_end, is_hidden=subscription.do_not_invoice, ) if not is_new_invoice: raise InvoiceAlreadyCreatedError( "invoice id: {id}".format(id=invoice.id)) 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() total_balance = sum( invoice.balance for invoice in Invoice.objects.filter( is_hidden=False, subscription__subscriber__domain=invoice.get_domain(), )) if total_balance > SMALL_INVOICE_THRESHOLD: 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) invoice.date_due = self.date_end + datetime.timedelta( days_until_due) 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