def get_rate_response(self):
        gateway = self.data.get('gateway')
        try:
            backend_api_id = SQLMobileBackend.get_backend_api_id(gateway, is_couch_id=True)
        except Exception as e:
            log_accounting_error(
                "Failed to get backend for calculating an sms rate due to: %s"
                % e
            )
            raise SMSRateCalculatorError("Could not obtain connection information.")

        country_code = self.data.get('country_code')
        if country_code == NONMATCHING_COUNTRY:
            country_code = None
        direction = self.data.get('direction')

        gateway_fee = SmsGatewayFee.get_by_criteria(
            backend_api_id, direction, backend_instance=gateway,
            country_code=country_code,
        )
        usage_fee = SmsUsageFee.get_by_criteria(direction, self.request.domain)
        usd_gateway_fee = gateway_fee.amount / gateway_fee.currency.rate_to_default
        usd_total = usage_fee.amount + usd_gateway_fee

        return {
            'rate': _("%s per 160 character SMS") % fmt_dollar_amount(usd_total),
        }
Exemple #2
0
def create_wire_credits_invoice(domain_name,
                                account_created_by,
                                account_entry_point,
                                amount,
                                invoice_items,
                                contact_emails):
    account = BillingAccount.get_or_create_account_by_domain(
        domain_name,
        created_by=account_created_by,
        entry_point=account_entry_point
    )[0]
    wire_invoice = WirePrepaymentInvoice.objects.create(
        domain=domain_name,
        date_start=datetime.datetime.utcnow(),
        date_end=datetime.datetime.utcnow(),
        date_due=None,
        balance=amount,
        account=account,
    )
    wire_invoice.items = invoice_items

    record = WirePrepaymentBillingRecord.generate_record(wire_invoice)
    if record.should_send_email:
        try:
            record.send_email(contact_emails=contact_emails)
        except Exception as e:
            log_accounting_error(
                "Error sending email for WirePrepaymentBillingRecord %d: %s" % (record.id, e.message),
                show_stack_trace=True,
            )
    else:
        record.skipped_email = True
        record.save()
Exemple #3
0
def create_wire_credits_invoice(domain_name,
                                account_created_by,
                                account_entry_point,
                                amount,
                                invoice_items,
                                contact_emails):
    account = BillingAccount.get_or_create_account_by_domain(
        domain_name,
        created_by=account_created_by,
        created_by_invoicing=True,
        entry_point=account_entry_point
    )[0]
    wire_invoice = WirePrepaymentInvoice.objects.create(
        domain=domain_name,
        date_start=datetime.datetime.utcnow(),
        date_end=datetime.datetime.utcnow(),
        date_due=None,
        balance=amount,
        account=account,
    )
    wire_invoice.items = invoice_items

    record = WirePrepaymentBillingRecord.generate_record(wire_invoice)
    try:
        record.send_email(contact_emails=contact_emails)
    except Exception as e:
        log_accounting_error(e.message)
Exemple #4
0
def check_credit_line_balances():
    for credit_line in CreditLine.objects.all():
        expected_balance = sum(credit_line.creditadjustment_set.values_list('amount', flat=True))
        if expected_balance != credit_line.balance:
            log_accounting_error(
                'Credit line %s has balance %s, expected %s' % (credit_line.id, credit_line.balance, expected_balance)
            )
Exemple #5
0
    def get(self, request, *args, **kwargs):
        statement_id = kwargs.get('statement_id')
        if statement_id is None:
            raise Http404()
        try:
            invoice_pdf = InvoicePdf.get(statement_id)
        except ResourceNotFound:
            raise Http404()

        try:
            if not invoice_pdf.is_customer:
                raise NotImplementedError
            else:
                invoice = CustomerInvoice.objects.get(pk=invoice_pdf.invoice_id)
        except (Invoice.DoesNotExist, WireInvoice.DoesNotExist, CustomerInvoice.DoesNotExist):
            raise Http404()

        filename = "%(pdf_id)s_%(edition)s_%(filename)s" % {
            'pdf_id': invoice_pdf._id,
            'edition': 'customer',
            'filename': invoice_pdf.get_filename(invoice),
        }
        try:
            data = invoice_pdf.get_data(invoice)
            response = HttpResponse(data, content_type='application/pdf')
            response['Content-Disposition'] = 'inline;filename="%s' % filename
        except Exception as e:
            log_accounting_error('Fetching invoice PDF failed: %s' % e)
            return HttpResponse(_("Could not obtain billing statement. "
                                  "An issue has been submitted."))
        return response
Exemple #6
0
 def post(self, request, *args, **kwargs):
     if self.async_response is not None:
         return self.async_response
     if ('account_basic' in self.request.POST
             and self.basic_account_form.is_valid()):
         self.basic_account_form.update_basic_info(self.account)
         messages.success(request, "Account successfully updated.")
         return HttpResponseRedirect(self.page_url)
     elif ('account_contact' in self.request.POST
           and self.contact_form.is_valid()):
         self.contact_form.save()
         messages.success(request, "Account Contact Info successfully updated.")
         return HttpResponseRedirect(self.page_url)
     elif ('adjust' in self.request.POST
           and self.credit_form.is_valid()):
         try:
             if self.credit_form.adjust_credit(web_user=request.user.username):
                 messages.success(request, "Successfully adjusted credit.")
                 return HttpResponseRedirect(self.page_url)
         except CreditLineError as e:
             log_accounting_error(
                 "failed to add credit in admin UI due to: %s"
                 % e
             )
             messages.error(request, "Issue adding credit: %s" % e)
     return self.get(request, *args, **kwargs)
Exemple #7
0
def create_wire_credits_invoice(domain_name,
                                amount,
                                invoice_items,
                                contact_emails):
    wire_invoice = WirePrepaymentInvoice.objects.create(
        domain=domain_name,
        date_start=datetime.datetime.utcnow(),
        date_end=datetime.datetime.utcnow(),
        date_due=None,
        balance=amount,
    )
    wire_invoice.items = invoice_items

    record = WirePrepaymentBillingRecord.generate_record(wire_invoice)
    if record.should_send_email:
        try:
            for email in contact_emails:
                record.send_email(contact_email=email)
        except Exception as e:
            log_accounting_error(
                "Error sending email for WirePrepaymentBillingRecord %d: %s" % (record.id, six.text_type(e)),
                show_stack_trace=True,
            )
    else:
        record.skipped_email = True
        record.save()
Exemple #8
0
def send_purchase_receipt(payment_record, core_product, domain,
                          template_html, template_plaintext,
                          additional_context):
    username = payment_record.payment_method.web_user

    try:
        web_user = WebUser.get_by_username(username)
        email = web_user.get_email()
        name = web_user.first_name
    except ResourceNotFound:
        log_accounting_error(
            "Strange. A payment attempt was made by a user that "
            "we can't seem to find! %s" % username
        )
        name = email = username

    context = {
        'name': name,
        'amount': fmt_dollar_amount(payment_record.amount),
        'project': domain,
        'date_paid': payment_record.date_created.strftime(USER_DATE_FORMAT),
        'product': core_product,
        'transaction_id': payment_record.public_transaction_id,
    }
    context.update(additional_context)

    email_html = render_to_string(template_html, context)
    email_plaintext = render_to_string(template_plaintext, context)

    send_HTML_email(
        ugettext("Payment Received - Thank You!"), email, email_html,
        text_content=email_plaintext,
        email_from=get_dimagi_from_email_by_product(core_product),
    )
Exemple #9
0
def warn_subscriptions_still_active(based_on_date=None):
    ending_date = based_on_date or datetime.date.today()
    subscriptions_still_active = Subscription.objects.filter(
        date_end__lte=ending_date,
        is_active=True,
    )
    for subscription in subscriptions_still_active:
        log_accounting_error("%s is still active." % subscription)
Exemple #10
0
 def pay_autopayable_invoices(self, date_due):
     """ Pays the full balance of all autopayable invoices on date_due """
     autopayable_invoices = Invoice.autopayable_invoices(date_due)
     for invoice in autopayable_invoices:
         try:
             self._pay_invoice(invoice)
         except Exception as e:
             log_accounting_error("Error autopaying invoice %d: %s" % (invoice.id, e.message))
Exemple #11
0
    def create_wire_invoice(self, balance):

        # Gather relevant invoices
        if self.account and self.account.is_customer_billing_account:
            invoices = CustomerInvoice.objects.filter(account=self.account)
        else:
            invoices = Invoice.objects.filter(
                subscription__subscriber__domain=self.domain.name,
                is_hidden=False,
                date_paid__exact=None
            ).order_by('-date_start')
            self.account = BillingAccount.get_or_create_account_by_domain(
                self.domain.name,
                created_by=self.__class__.__name__,
                entry_point=EntryPoint.SELF_STARTED
            )[0]

        # If no start date supplied, default earliest start date of unpaid invoices
        if self.date_start:
            date_start = self.date_start
        else:
            date_start = invoices.aggregate(Min('date_start'))['date_start__min']

        # If no end date supplied, default latest end date of unpaid invoices
        if self.date_end:
            date_end = self.date_end
        else:
            date_end = invoices.aggregate(Max('date_end'))['date_end__max']

        if not date_end:
            date_end = datetime.datetime.today()

        date_due = date_end + datetime.timedelta(DEFAULT_DAYS_UNTIL_DUE)

        wire_invoice = WireInvoice.objects.create(
            domain=self.domain.name,
            date_start=date_start,
            date_end=date_end,
            date_due=date_due,
            balance=balance,
        )

        record = WireBillingRecord.generate_record(wire_invoice)

        if record.should_send_email:
            try:
                for email in self.contact_emails:
                    record.send_email(contact_email=email)
            except InvoiceEmailThrottledError as e:
                # Currently wire invoices are never throttled
                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 wire_invoice
Exemple #12
0
 def pay_autopayable_invoices(self, date_due):
     """ Pays the full balance of all autopayable invoices on date_due """
     autopayable_invoices = Invoice.autopayable_invoices(date_due)
     for invoice in autopayable_invoices:
         try:
             self._pay_invoice(invoice)
         except Exception as e:
             log_accounting_error("Error autopaying invoice %d: %s" %
                                  (invoice.id, e.message))
Exemple #13
0
def warn_subscriptions_not_active(based_on_date=None):
    based_on_date = based_on_date or datetime.date.today()
    subscriptions_not_active = Subscription.objects.filter(
        Q(date_end=None) | Q(date_end__gt=based_on_date),
        date_start__lte=based_on_date,
        is_active=False,
    )
    for subscription in subscriptions_not_active:
        log_accounting_error("%s is not active" % subscription)
 def _handle_card_declined(invoice, payment_method):
     from corehq.apps.accounting.tasks import send_autopay_failed
     log_accounting_error(
         "[Autopay] An automatic payment failed for invoice: {} "
         "because the card was declined. This invoice will not be automatically paid. "
         "Not necessarily actionable, but be aware that this happened."
         .format(invoice.id)
     )
     send_autopay_failed.delay(invoice, payment_method)
Exemple #15
0
def warn_subscriptions_without_domain():
    domains_with_active_subscription = Subscription.visible_objects.filter(
        is_active=True, ).values_list('subscriber__domain',
                                      flat=True).distinct()
    for domain_name in set(domains_with_active_subscription) - set(
            Domain.get_all_names()):
        log_accounting_error(
            'Domain %s has an active subscription but does not exist.' %
            domain_name)
Exemple #16
0
def warn_subscriptions_not_active(based_on_date=None):
    based_on_date = based_on_date or datetime.date.today()
    subscriptions_not_active = Subscription.objects.filter(
        Q(date_end=None) | Q(date_end__gt=based_on_date),
        date_start__lte=based_on_date,
        is_active=False,
    )
    for subscription in subscriptions_not_active:
        log_accounting_error("%s is not active" % subscription)
Exemple #17
0
    def create_wire_invoice(self, balance):

        # Gather relevant invoices
        invoices = Invoice.objects.filter(
            subscription__subscriber__domain=self.domain,
            is_hidden=False,
            date_paid__exact=None,
        ).order_by('-date_start')

        account = BillingAccount.get_or_create_account_by_domain(
            self.domain.name,
            created_by=self.__class__.__name__,
            entry_point=EntryPoint.SELF_STARTED,
        )[0]

        # If no start date supplied, default earliest start date of unpaid invoices
        if self.date_start:
            date_start = self.date_start
        else:
            date_start = invoices.aggregate(
                Min('date_start'))['date_start__min']

        # If no end date supplied, default latest end date of unpaid invoices
        if self.date_end:
            date_end = self.date_end
        else:
            date_end = invoices.aggregate(Max('date_end'))['date_end__max']

        if not date_end:
            date_end = datetime.datetime.today()

        date_due = date_end + datetime.timedelta(DEFAULT_DAYS_UNTIL_DUE)

        wire_invoice = WireInvoice.objects.create(
            domain=self.domain.name,
            date_start=date_start,
            date_end=date_end,
            date_due=date_due,
            balance=balance,
        )

        record = WireBillingRecord.generate_record(wire_invoice)

        if record.should_send_email:
            try:
                record.send_email(contact_emails=self.contact_emails)
            except InvoiceEmailThrottledError as e:
                # Currently wire invoices are never throttled
                if not self.logged_throttle_error:
                    log_accounting_error(e.message)
                    self.logged_throttle_error = True
        else:
            record.skipped_email = True
            record.save()

        return wire_invoice
Exemple #18
0
def warn_active_subscriptions_per_domain_not_one():
    for domain_name in Domain.get_all_names():
        active_subscription_count = Subscription.visible_objects.filter(
            subscriber__domain=domain_name,
            is_active=True,
        ).count()
        if active_subscription_count > 1:
            log_accounting_error("Multiple active subscriptions found for domain %s" % domain_name)
        elif active_subscription_count == 0 and Domain.get_by_name(domain_name).is_active:
            log_accounting_error("There is no active subscription for domain %s" % domain_name)
Exemple #19
0
def warn_active_subscriptions_per_domain_not_one():
    for domain_name in Domain.get_all_names():
        active_subscription_count = Subscription.objects.filter(
            subscriber__domain=domain_name,
            is_active=True,
        ).count()
        if active_subscription_count > 1:
            log_accounting_error("Multiple active subscriptions found for domain %s" % domain_name)
        elif active_subscription_count == 0:
            log_accounting_error("There is no active subscription for domain %s" % domain_name)
Exemple #20
0
 def paginated_list(self):
     for invoice in self.paginated_invoices.page(self.page).object_list:
         try:
             last_billing_record = CustomerBillingRecord.objects.filter(
                 invoice=invoice).latest('date_created')
             if invoice.is_paid:
                 payment_status = (
                     _("Paid on %s.") %
                     invoice.date_paid.strftime(USER_DATE_FORMAT))
                 payment_class = "label label-default"
             else:
                 payment_status = _("Not Paid")
                 payment_class = "label label-danger"
             date_due = ((invoice.date_due.strftime(USER_DATE_FORMAT)
                          if not invoice.is_paid else _("Already Paid"))
                         if invoice.date_due else _("None"))
             yield {
                 'itemData': {
                     'id':
                     invoice.id,
                     'invoice_number':
                     invoice.invoice_number,
                     'start':
                     invoice.date_start.strftime(USER_DATE_FORMAT),
                     'end':
                     invoice.date_end.strftime(USER_DATE_FORMAT),
                     'plan':
                     None,
                     'payment_status':
                     payment_status,
                     'payment_class':
                     payment_class,
                     'date_due':
                     date_due,
                     'pdfUrl':
                     reverse(BillingStatementPdfView.urlname,
                             args=[
                                 self.domain,
                                 last_billing_record.pdf_data_id
                             ]),
                     'canMakePayment': (not invoice.is_paid
                                        and self.can_pay_invoices),
                     'balance':
                     "%s" % quantize_accounting_decimal(invoice.balance),
                 },
                 'template': 'statement-row-template',
             }
         except CustomerBillingRecord.DoesNotExist:
             log_accounting_error(
                 "An invoice was generated for %(invoice_id)d "
                 "(domain: %(domain)s), but no billing record!" % {
                     'invoice_id': invoice.id,
                     'domain': self.domain,
                 },
                 show_stack_trace=True)
Exemple #21
0
    def create_wire_invoice(self, balance):

        # Gather relevant invoices
        invoices = Invoice.objects.filter(
            subscription__subscriber__domain=self.domain,
            is_hidden=False,
            date_paid__exact=None,
        ).order_by('-date_start')

        account = BillingAccount.get_or_create_account_by_domain(
            self.domain.name,
            created_by=self.__class__.__name__,
            created_by_invoicing=True,
            entry_point=EntryPoint.SELF_STARTED,
        )[0]

        # If no start date supplied, default earliest start date of unpaid invoices
        if self.date_start:
            date_start = self.date_start
        else:
            date_start = invoices.aggregate(Min('date_start'))['date_start__min']

        # If no end date supplied, default latest end date of unpaid invoices
        if self.date_end:
            date_end = self.date_end
        else:
            date_end = invoices.aggregate(Max('date_end'))['date_end__max']

        if not date_end:
            date_end = datetime.datetime.today()

        date_due = date_end + datetime.timedelta(DEFAULT_DAYS_UNTIL_DUE)

        # TODO: figure out how to handle line items
        wire_invoice = WireInvoice.objects.create(
            domain=self.domain.name,
            date_start=date_start,
            date_end=date_end,
            date_due=date_due,
            balance=balance,
            account=account
        )

        record = WireBillingRecord.generate_record(wire_invoice)

        try:
            record.send_email(contact_emails=self.contact_emails)
        except InvoiceEmailThrottledError as e:
            # Currently wire invoices are never throttled
            if not self.logged_throttle_error:
                log_accounting_error(e.message)
                self.logged_throttle_error = True

        return wire_invoice
Exemple #22
0
def create_billable_for_sms(msg, delay=True):
    if not msg.domain:
        return
    try:
        from corehq.apps.sms.tasks import store_billable
        if delay:
            store_billable.delay(msg)
        else:
            store_billable(msg)
    except Exception as e:
        log_accounting_error("Errors Creating SMS Billable: %s" % e)
Exemple #23
0
 def response_inbound_sms(domain, new_plan_version):
     """
     All Reminder rules utilizing "survey" will be deactivated.
     """
     try:
         _deactivate_schedules(domain, survey_only=True)
     except Exception:
         log_accounting_error(
             "Failed to downgrade inbound sms for domain %s." % domain.name)
         return False
     return True
Exemple #24
0
def _ensure_role(role_slug, apps):
    Role = apps.get_model('django_prbac', 'Role')
    try:
        role = Role.objects.get(slug=role_slug)
    except Role.DoesNotExist:
        log_accounting_error(
            "Could not find the role '%s'. Did you forget to run cchq_prbac_bootstrap?"
            % role_slug)
        log_accounting_error("Aborting. You should figure this out.")
        raise
    return role
Exemple #25
0
 def create_invoices(self):
     subscriptions = self._get_subscriptions()
     self._ensure_full_coverage(subscriptions)
     for subscription in subscriptions:
         try:
             self._create_invoice_for_subscription(subscription)
         except InvoiceAlreadyCreatedError as e:
             log_accounting_error(
                 "Invoice already existed for domain %s: %s" % (self.domain.name, e),
                 show_stack_trace=True,
             )
 def create_invoices(self):
     subscriptions = self._get_subscriptions()
     self._ensure_full_coverage(subscriptions)
     for subscription in subscriptions:
         try:
             self._create_invoice_for_subscription(subscription)
         except InvoiceAlreadyCreatedError as e:
             log_accounting_error(
                 "Invoice already existed for domain %s: %s" % (self.domain.name, e),
                 show_stack_trace=True,
             )
Exemple #27
0
def check_credit_line_balances():
    for credit_line in CreditLine.objects.all():
        expected_balance = sum(credit_line.creditadjustment_set.values_list('amount', flat=True))
        if expected_balance != credit_line.balance:
            try:
                # needed for sending to sentry
                raise CreditLineBalanceMismatchError()
            except CreditLineBalanceMismatchError:
                log_accounting_error(
                    f'Credit line {credit_line.id} has balance {credit_line.balance},'
                    f' expected {expected_balance}'
                )
Exemple #28
0
def _ensure_role(role_slug, apps):
    Role = apps.get_model('django_prbac', 'Role')
    try:
        role = Role.objects.get(slug=role_slug)
    except Role.DoesNotExist:
        log_accounting_error(
            "Could not find the role '%s'. Did you forget to run cchq_prbac_bootstrap?"
            % role_slug
        )
        log_accounting_error("Aborting. You should figure this out.")
        raise
    return role
Exemple #29
0
 def response_outbound_sms(domain, new_plan_version):
     """
     Reminder rules will be deactivated.
     """
     try:
         _deactivate_schedules(domain)
     except Exception:
         log_accounting_error(
             "Failed to downgrade outbound sms for domain %s." %
             domain.name)
         return False
     return True
Exemple #30
0
def warn_subscriptions_still_active(based_on_date=None):
    ending_date = based_on_date or datetime.date.today()
    subscriptions_still_active = Subscription.visible_objects.filter(
        date_end__lte=ending_date,
        is_active=True,
    )
    for subscription in subscriptions_still_active:
        try:
            # needed for sending to sentry
            raise SubscriptionTaskError()
        except SubscriptionTaskError:
            log_accounting_error(f"{subscription} is still active.")
Exemple #31
0
def warn_subscriptions_without_domain():
    domains_with_active_subscription = Subscription.visible_objects.filter(
        is_active=True,
    ).values_list('subscriber__domain', flat=True).distinct()
    for domain_name in set(domains_with_active_subscription) - set(Domain.get_all_names()):
        # we need to put a try/except here so that sentry captures logging
        try:
            raise ActiveSubscriptionWithoutDomain()
        except ActiveSubscriptionWithoutDomain:
            log_accounting_error(
                f'Domain {domain_name} has an active subscription but does not exist.'
            )
Exemple #32
0
def warn_subscriptions_not_active(based_on_date=None):
    based_on_date = based_on_date or datetime.date.today()
    subscriptions_not_active = Subscription.visible_objects.filter(
        Q(date_end=None) | Q(date_end__gt=based_on_date),
        date_start__lte=based_on_date,
        is_active=False,
    )
    for subscription in subscriptions_not_active:
        try:
            # needed for sending to sentry
            raise SubscriptionTaskError()
        except SubscriptionTaskError:
            log_accounting_error(f"{subscription} is not active.")
Exemple #33
0
def send_subscription_reminder_emails(num_days, exclude_trials=True):
    today = datetime.date.today()
    date_in_n_days = today + datetime.timedelta(days=num_days)
    ending_subscriptions = Subscription.objects.filter(date_end=date_in_n_days)
    if exclude_trials:
        ending_subscriptions = ending_subscriptions.filter(is_trial=False)
    for subscription in ending_subscriptions:
        try:
            # only send reminder emails if the subscription isn't renewed
            if not subscription.is_renewed:
                subscription.send_ending_reminder_email()
        except Exception as e:
            log_accounting_error(e.message)
 def _email_invoice(self):
     record = CustomerBillingRecord.generate_record(self.customer_invoice)
     try:
         if self.recipients:
             for email in self.recipients:
                 record.send_email(contact_email=email)
         elif self.account.dimagi_contact:
             record.send_email(contact_email=self.account.dimagi_contact,
                               cc_emails=[settings.ACCOUNTS_EMAIL])
         else:
             record.send_email(contact_email=settings.ACCOUNTS_EMAIL)
     except InvoiceEmailThrottledError as e:
         log_accounting_error(str(e))
 def response_inbound_sms(domain, new_plan_version):
     """
     All Reminder rules utilizing "survey" will be deactivated.
     """
     try:
         _deactivate_schedules(domain, survey_only=True)
     except Exception:
         log_accounting_error(
             "Failed to downgrade inbound sms for domain %s."
             % domain.name
         )
         return False
     return True
Exemple #36
0
    def _handle_card_declined(invoice, payment_method, e):
        from corehq.apps.accounting.tasks import send_autopay_failed

        # https://stripe.com/docs/api/python#error_handling
        body = e.json_body
        err = body.get('error', {})

        log_accounting_error(
            "[Autopay] An automatic payment failed for invoice: {} "
            "because the card was declined. This invoice will not be automatically paid. "
            "Not necessarily actionable, but be aware that this happened. "
            "error = {}".format(invoice.id, err))
        send_autopay_failed.delay(invoice, payment_method)
 def response_outbound_sms(domain, new_plan_version):
     """
     Reminder rules will be deactivated.
     """
     try:
         _deactivate_schedules(domain)
     except Exception:
         log_accounting_error(
             "Failed to downgrade outbound sms for domain %s."
             % domain.name
         )
         return False
     return True
Exemple #38
0
def archive_logos(domain_name):
    try:
        for app in get_all_apps(domain_name):
            if isinstance(app, HQMediaMixin):
                has_archived = app.archive_logos()
                if has_archived:
                    app.save()
    except Exception as e:
        log_accounting_error(
            "Failed to remove all commcare logos for domain %s." % domain_name,
            show_stack_trace=True,
        )
        raise e
    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
Exemple #40
0
def _assign_explicit_community_subscriptions(apps, schema_editor):
    today = date.today()
    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_name = domain_doc['name']
        from_date = date(today.year, today.month, 1)
        try:
            while from_date <= today:
                ensure_explicit_community_subscription(domain_name, from_date)
                from_date += timedelta(days=1)
        except Exception as e:
            log_accounting_error(
                "During community subscription assignment for domain %s: %s" %
                (domain_name, e.message))
Exemple #41
0
def send_subscription_reminder_emails(num_days):
    today = datetime.date.today()
    date_in_n_days = today + datetime.timedelta(days=num_days)
    ending_subscriptions = Subscription.objects.filter(
        date_end=date_in_n_days, do_not_email_reminder=False, is_trial=False)
    for subscription in ending_subscriptions:
        try:
            # only send reminder emails if the subscription isn't renewed
            if not subscription.is_renewed:
                subscription.send_ending_reminder_email()
        except Exception as e:
            log_accounting_error(
                "Error sending reminder for subscription %d: %s" %
                (subscription.id, e.message))
Exemple #42
0
def deactivate_subscriptions(based_on_date=None):
    """
    Deactivates all subscriptions ending today (or, for testing, based on the date specified)
    """
    ending_date = based_on_date or datetime.date.today()
    ending_subscriptions = Subscription.objects.filter(
        date_end=ending_date,
        is_active=True,
    )
    for subscription in ending_subscriptions:
        try:
            _deactivate_subscription(subscription, ending_date)
        except Exception as e:
            log_accounting_error(e.message)
Exemple #43
0
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 = Domain.wrap(domain_doc)
        try:
            invoice_factory = DomainInvoiceFactory(invoice_start, invoice_end,
                                                   domain)
            invoice_factory.create_invoices()
            log_accounting_info("Sent invoices for domain %s" % domain.name)
        except CreditLineError as e:
            log_accounting_error("There was an error utilizing credits for "
                                 "domain %s: %s" % (domain.name, e))
        except InvoiceError as e:
            log_accounting_error("Could not create invoice for domain %s: %s" %
                                 (domain.name, e))
        except InvoiceAlreadyCreatedError as e:
            log_accounting_error("Invoice already existed for domain %s: %s" %
                                 (domain.name, e))
        except Exception as e:
            log_accounting_error("Error occurred while creating invoice for "
                                 "domain %s: %s" % (domain.name, e))

    if not settings.UNIT_TESTING:
        _invoicing_complete_soft_assert(False, "Invoicing is complete!")
Exemple #44
0
    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
Exemple #45
0
def calculate_users_in_all_domains(today=None):
    today = today or datetime.date.today()
    for domain in Domain.get_all_names():
        num_users = CommCareUser.total_by_domain(domain)
        record_date = today - relativedelta(days=1)
        try:
            DomainUserHistory.objects.create(domain=domain,
                                             num_users=num_users,
                                             record_date=record_date)
        except Exception as e:
            log_accounting_error(
                "Something went wrong while creating DomainUserHistory for domain %s: %s"
                % (domain, e),
                show_stack_trace=True,
            )
 def response_commcare_logo_uploader(self):
     """Make sure no existing applications are using a logo.
     """
     try:
         for app in get_all_apps(self.domain.name):
             has_restored = app.restore_logos()
             if has_restored:
                 app.save()
         return True
     except Exception:
         log_accounting_error(
             "Failed to restore all commcare logos for domain %s."
             % self.domain.name
         )
         return False
Exemple #47
0
 def create_invoices(self):
     subscriptions = self._get_subscriptions()
     self._ensure_full_coverage(subscriptions)
     for subscription in subscriptions:
         try:
             if subscription.account.is_customer_billing_account:
                 log_accounting_info("Skipping invoice for subscription: %s, because it is part of a Customer "
                                     "Billing Account." % (subscription))
             elif should_create_invoice(subscription, self.domain, self.date_start, self.date_end):
                 self._create_invoice_for_subscription(subscription)
         except InvoiceAlreadyCreatedError as e:
             log_accounting_error(
                 "Invoice already existed for domain %s: %s" % (self.domain.name, e),
                 show_stack_trace=True,
             )
 def response_data_cleanup(domain, new_plan_version):
     """
     Any active automatic case update rules should be deactivated.
     """
     try:
         AutomaticUpdateRule.objects.filter(
             domain=domain.name,
             deleted=False,
             active=True,
         ).update(active=False)
         return True
     except Exception:
         log_accounting_error("Failed to deactivate automatic update rules "
                              "for domain %s." % domain.name)
         return False
 def response_commcare_logo_uploader(domain, new_plan_version):
     """Make sure no existing applications are using a logo.
     """
     try:
         for app in get_all_apps(domain.name):
             if isinstance(app, HQMediaMixin):
                 has_restored = app.restore_logos()
                 if has_restored:
                     app.save()
         return True
     except Exception:
         log_accounting_error(
             "Failed to restore all commcare logos for domain %s." %
             domain.name)
         return False
Exemple #50
0
def deactivate_subscriptions(based_on_date=None):
    """
    Deactivates all subscriptions ending today (or, for testing, based on the date specified)
    """
    ending_date = based_on_date or datetime.date.today()
    ending_subscriptions = Subscription.objects.filter(
        date_end=ending_date,
        is_active=True,
    )
    for subscription in ending_subscriptions:
        try:
            _deactivate_subscription(subscription, ending_date)
        except Exception as e:
            log_accounting_error('Error deactivating subscription %d: %s' %
                                 (subscription.id, e.message))
Exemple #51
0
 def create_invoices(self):
     subscriptions = self._get_subscriptions()
     self._ensure_full_coverage(subscriptions)
     for subscription in subscriptions:
         try:
             if subscription.account.is_customer_billing_account:
                 log_accounting_info("Skipping invoice for subscription: %s, because it is part of a Customer "
                                     "Billing Account." % (subscription))
             elif should_create_invoice(subscription, self.domain, self.date_start, self.date_end):
                 self._create_invoice_for_subscription(subscription)
         except InvoiceAlreadyCreatedError as e:
             log_accounting_error(
                 "Invoice already existed for domain %s: %s" % (self.domain.name, e),
                 show_stack_trace=True,
             )
Exemple #52
0
 def create_invoice(self):
     for sub in self.account.subscription_set.filter(do_not_invoice=False):
         if not sub.plan_version.plan.edition == SoftwarePlanEdition.COMMUNITY \
                 and should_create_invoice(sub, sub.subscriber.domain, self.date_start, self.date_end):
             self.subscriptions[sub.plan_version].append(sub)
     if not self.subscriptions:
         return
     try:
         self._generate_customer_invoice()
         self._email_invoice()
     except InvoiceAlreadyCreatedError as e:
         log_accounting_error(
             "Invoice already existed for account %s: %s" % (self.account.name, e),
             show_stack_trace=True,
         )
def _assign_explicit_community_subscriptions(apps, schema_editor):
    today = date.today()
    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_name = domain_doc['name']
        from_date = date(today.year, today.month, 1)
        try:
            while from_date <= today:
                ensure_explicit_community_subscription(domain_name, from_date)
                from_date += timedelta(days=1)
        except Exception as e:
            log_accounting_error(
                "During community subscription assignment for domain %s: %s"
                % (domain_name, e.message)
            )
Exemple #54
0
def restore_logos(self, domain_name):
    try:
        for app in get_all_apps(domain_name):
            if isinstance(app, HQMediaMixin):
                has_restored = app.restore_logos()
                if has_restored:
                    app.save()
    except ResourceConflict as e:
        raise self.retry(exc=e)
    except Exception as e:
        log_accounting_error(
            "Failed to restore all commcare logos for domain %s." % domain_name,
            show_stack_trace=True,
        )
        raise e
Exemple #55
0
def restore_logos(self, domain_name):
    try:
        for app in get_all_apps(domain_name):
            if isinstance(app, ApplicationMediaMixin):
                has_restored = app.restore_logos()
                if has_restored:
                    app.save()
    except ResourceConflict as e:
        raise self.retry(exc=e)
    except Exception as e:
        log_accounting_error(
            "Failed to restore all commcare logos for domain %s." % domain_name,
            show_stack_trace=True,
        )
        raise e
    def _handle_card_declined(invoice, e):
        from corehq.apps.accounting.tasks import send_autopay_failed

        # https://stripe.com/docs/api/python#error_handling
        body = e.json_body
        err = body.get('error', {})

        log_accounting_error(
            "[Autopay] An automatic payment failed for invoice: {invoice} ({domain})"
            "because the card was declined. This invoice will not be automatically paid. "
            "Not necessarily actionable, but be aware that this happened. "
            "error = {error}"
            .format(invoice=invoice.id, domain=invoice.get_domain(), error=err)
        )
        send_autopay_failed.delay(invoice)
Exemple #57
0
def send_subscription_reminder_emails(num_days):
    today = datetime.date.today()
    date_in_n_days = today + datetime.timedelta(days=num_days)
    ending_subscriptions = Subscription.objects.filter(
        date_end=date_in_n_days, do_not_email_reminder=False, is_trial=False
    )
    for subscription in ending_subscriptions:
        try:
            # only send reminder emails if the subscription isn't renewed
            if not subscription.is_renewed:
                subscription.send_ending_reminder_email()
        except Exception as e:
            log_accounting_error(
                "Error sending reminder for subscription %d: %s" % (subscription.id, e.message)
            )
Exemple #58
0
 def create_invoice(self):
     for sub in self.account.subscription_set.filter(do_not_invoice=False):
         if not sub.plan_version.plan.edition == SoftwarePlanEdition.COMMUNITY \
                 and should_create_invoice(sub, sub.subscriber.domain, self.date_start, self.date_end):
             self.subscriptions[sub.plan_version].append(sub)
     if not self.subscriptions:
         return
     try:
         self._generate_customer_invoice()
         self._email_invoice()
     except InvoiceAlreadyCreatedError as e:
         log_accounting_error(
             "Invoice already existed for account %s: %s" % (self.account.name, e),
             show_stack_trace=True,
         )
 def pay_autopayable_invoices(self, date_due=Ellipsis, domain=None):
     """
     Pays the full balance of all autopayable invoices on date_due
     Note: we use Ellipsis as the default value for date_due because date_due
     can actually be None in the db.
     """
     autopayable_invoices = Invoice.autopayable_invoices(date_due)
     if domain is not None:
         autopayable_invoices = autopayable_invoices.filter(
             subscription__subscriber__domain=domain)
     for invoice in autopayable_invoices:
         try:
             self._pay_invoice(invoice)
         except Exception as e:
             log_accounting_error("Error autopaying invoice %d: %s" %
                                  (invoice.id, e))
Exemple #60
0
 def response_data_cleanup(domain, new_plan_version):
     """
     Any active automatic case update rules should be deactivated.
     """
     try:
         AutomaticUpdateRule.by_domain(
             domain.name,
             AutomaticUpdateRule.WORKFLOW_CASE_UPDATE,
         ).update(active=False)
         AutomaticUpdateRule.clear_caches(
             domain.name, AutomaticUpdateRule.WORKFLOW_CASE_UPDATE)
         return True
     except Exception:
         log_accounting_error("Failed to deactivate automatic update rules "
                              "for domain %s." % domain.name)
         return False