Example #1
0
def send_autopay_failed(invoice):
    subscription = invoice.subscription
    auto_payer = subscription.account.auto_pay_user
    payment_method = StripePaymentMethod.objects.get(web_user=auto_payer)
    autopay_card = payment_method.get_autopay_card(subscription.account)
    web_user = WebUser.get_by_username(auto_payer)
    if web_user:
        recipient = web_user.get_email()
    else:
        recipient = auto_payer
    domain = invoice.get_domain()

    context = {
        'domain': domain,
        'subscription_plan': subscription.plan_version.plan.name,
        'billing_date': datetime.date.today(),
        'invoice_number': invoice.invoice_number,
        'autopay_card': autopay_card,
        'domain_url': absolute_reverse('dashboard_default', args=[domain]),
        'billing_info_url': absolute_reverse('domain_update_billing_info', args=[domain]),
        'support_email': settings.INVOICING_CONTACT_EMAIL,
    }

    template_html = 'accounting/email/autopay_failed.html'
    template_plaintext = 'accounting/email/autopay_failed.txt'

    send_HTML_email(
        subject="Subscription Payment for CommCare Invoice %s was declined" % invoice.invoice_number,
        recipient=recipient,
        html_content=render_to_string(template_html, context),
        text_content=render_to_string(template_plaintext, context),
        email_from=get_dimagi_from_email(),
    )
Example #2
0
def send_html_email_async(self, subject, recipient, html_content,
                          text_content=None, cc=None,
                          email_from=settings.DEFAULT_FROM_EMAIL,
                          file_attachments=None, bcc=None, smtp_exception_skip_list=None):
    """ Call with send_HTML_email_async.delay(*args, **kwargs)
    - sends emails in the main celery queue
    - if sending fails, retry in 15 min
    - retry a maximum of 10 times
    """
    try:
        send_HTML_email(subject, recipient, html_content,
                        text_content=text_content, cc=cc, email_from=email_from,
                        file_attachments=file_attachments, bcc=bcc,
                        smtp_exception_skip_list=smtp_exception_skip_list)
    except Exception as e:
        from corehq.util.python_compatibility import soft_assert_type_text
        if isinstance(recipient, six.string_types):
            soft_assert_type_text(recipient)
        recipient = list(recipient) if not isinstance(recipient, six.string_types) else [recipient]
        notify_exception(
            None,
            message="Encountered error while sending email",
            details={
                'subject': subject,
                'recipients': ', '.join(recipient),
                'error': e,
            }
        )
        self.retry(exc=e)
Example #3
0
def send_purchase_receipt(payment_record, domain,
                          template_html, template_plaintext,
                          additional_context):
    username = payment_record.payment_method.web_user
    web_user = WebUser.get_by_username(username)
    if web_user:
        email = web_user.get_email()
        name = web_user.first_name
    else:
        log_accounting_error(
            "Strange. A payment attempt was made by a user that "
            "we can't seem to find! %s" % username,
            show_stack_trace=True,
        )
        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),
        '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(
        _("Payment Received - Thank You!"), email, email_html,
        text_content=email_plaintext,
        email_from=get_dimagi_from_email(),
    )
Example #4
0
def send_bookkeeper_email(month=None, year=None, emails=None):
    today = datetime.date.today()

    # now, make sure that we send out LAST month's invoices if we did
    # not specify a month or year.
    today = get_previous_month_date_range(today)[0]

    month = month or today.month
    year = year or today.year

    from corehq.apps.accounting.interface import InvoiceInterface
    request = HttpRequest()
    params = urlencode((
        ('report_filter_statement_period_use_filter', 'on'),
        ('report_filter_statement_period_month', month),
        ('report_filter_statement_period_year', year),
    ))
    request.GET = QueryDict(params)
    request.couch_user = FakeUser(
        domain="hqadmin",
        username="******",
    )
    invoice = InvoiceInterface(request)
    invoice.is_rendered_as_email = True
    first_of_month = datetime.date(year, month, 1)
    email_context = {
        'month': first_of_month.strftime("%B"),
    }
    email_content = render_to_string(
        'accounting/email/bookkeeper.html', email_context)
    email_content_plaintext = render_to_string(
        'accounting/email/bookkeeper.txt', email_context)

    format_dict = Format.FORMAT_DICT[Format.CSV]
    excel_attachment = {
        'title': 'Invoices_%(period)s.%(extension)s' % {
            'period': first_of_month.strftime('%B_%Y'),
            'extension': format_dict['extension'],
        },
        'mimetype': format_dict['mimetype'],
        'file_obj': invoice.excel_response,
    }

    emails = emails or settings.BOOKKEEPER_CONTACT_EMAILS
    for email in emails:
        send_HTML_email(
            "Invoices for %s" % datetime.date(year, month, 1).strftime(USER_MONTH_FORMAT),
            email,
            email_content,
            email_from=settings.DEFAULT_FROM_EMAIL,
            text_content=email_content_plaintext,
            file_attachments=[excel_attachment],
        )

    log_accounting_info(
        "Sent Bookkeeper Invoice Summary for %(month)s "
        "to %(emails)s." % {
            'month': first_of_month.strftime(USER_MONTH_FORMAT),
            'emails': ", ".join(emails)
        })
Example #5
0
def send_gateway_fee_report_out():
    backend_api_ids = SmsGatewayFeeCriteria.objects.values_list('backend_api_id', flat=True).distinct()
    first_day_previous_month = add_months_to_date(date.today(), -1)
    billables_in_month = SmsBillable.objects.filter(
        date_sent__year=first_day_previous_month.year,
        date_sent__month=first_day_previous_month.month,
        is_valid=True,
    )

    costs_by_backend = defaultdict(list)
    for backend_api_id in backend_api_ids:
        billables_in_month_by_backend_api_id = billables_in_month.filter(
            gateway_fee__criteria__backend_api_id=backend_api_id
        )
        relevant_currencies = [
            Currency.objects.get(id=id)
            for id in billables_in_month_by_backend_api_id.values_list(
                'gateway_fee__currency', flat=True).distinct()
        ]
        for currency in relevant_currencies:
            cost_by_backend_and_currency = sum(
                billable.gateway_charge * (billable.gateway_fee_conversion_rate or 1)
                for billable in billables_in_month_by_backend_api_id.filter(
                    gateway_fee__currency=currency
                )
            )
            costs_by_backend[backend_api_id].append((cost_by_backend_and_currency, currency.code))

    subject = "[{}] Cost per SMS Gateway Monthly Summary".format(settings.SERVER_ENVIRONMENT)

    def _get_cost_string(cost, currency_code):
        cost_template = '%.2f %s'
        cost_string_in_original_currency = cost_template % (cost, currency_code)
        default_code = Currency.get_default().code
        if currency_code == default_code:
            return cost_string_in_original_currency
        else:
            cost_string_in_default_currency = cost_template % (
                cost / Currency.objects.get(code=currency_code).rate_to_default,
                default_code
            )
            return '%s (%s)' % (
                cost_string_in_original_currency,
                cost_string_in_default_currency
            )


    send_HTML_email(
        subject,
        settings.ACCOUNTS_EMAIL,
        ''.join(
            '<p>{}: {}</p>'.format(
                backend_api_id, '; '.join(
                    _get_cost_string(cost, currency_code) for (cost, currency_code) in cost_by_backend
                )
            )
            for (backend_api_id, cost_by_backend) in costs_by_backend.items()
        )
    )
Example #6
0
def bulk_archive_forms(domain, couch_user, uploaded_data):
    # archive using Excel-data
    response = archive_forms_old(domain, couch_user.user_id, couch_user.username, uploaded_data)

    for msg in response['success']:
        logger.info("[Data interfaces] %s", msg)
    for msg in response['errors']:
        logger.info("[Data interfaces] %s", msg)

    html_content = render_to_string('data_interfaces/archive_email.html', response)
    send_HTML_email(_('Your archived forms'), couch_user.email, html_content)
Example #7
0
def send_report_download_email(title, recipient, link):
    subject = "%s: Requested export excel data"
    body = "The export you requested for the '%s' report is ready.<br>" \
           "You can download the data at the following link: %s<br><br>" \
           "Please remember that this link will only be active for 24 hours."

    send_HTML_email(
        _(subject) % title,
        recipient,
        _(body) % (title, "<a href='%s'>%s</a>" % (link, link)),
        email_from=settings.DEFAULT_FROM_EMAIL
    )
Example #8
0
def upload(dropbox_helper_id, access_token, size, max_retries):
    from .models import DropboxUploadHelper
    helper = DropboxUploadHelper.objects.get(id=dropbox_helper_id)

    def progress_callback(bytes_uploaded, helper=helper, size=size):
        helper.progress = float(bytes_uploaded) / size
        helper.save()

    try:
        dropbox_path = '/{}'.format(os.path.basename(helper.src))
        path_display = upload_to_dropbox(access_token, dropbox_path, helper.src, progress_callback)
    except Exception as e:
        helper.failure_reason = str(e)
        helper.save()

    couch_user = CouchUser.get_by_username(helper.user.username)
    if helper.failure_reason is None:
        dbx = Dropbox(access_token)
        path_link_metadata = dbx.sharing_create_shared_link_with_settings(
            path_display,
            SharedLinkSettings(
                requested_visibility=RequestedVisibility.team_only,
            ),
        )
        context = {
            'share_url': path_link_metadata.url,
            'path': os.path.join(
                'Apps',
                settings.DROPBOX_APP_NAME,
                path_link_metadata.name,
            )
        }
        with localize(couch_user.get_language_code()):
            subject = _('{} has been uploaded to dropbox!'.format(helper.dest))
            html_content = render_to_string('dropbox/emails/upload_success.html', context)
            text_content = render_to_string('dropbox/emails/upload_success.txt', context)
    else:
        context = {
            'reason': helper.failure_reason,
            'path': helper.dest
        }
        with localize(couch_user.get_language_code()):
            subject = _('{} has failed to upload to dropbox'.format(helper.dest))
            html_content = render_to_string('dropbox/emails/upload_error.html', context)
            text_content = render_to_string('dropbox/emails/upload_error.txt', context)

    send_HTML_email(
        subject,
        helper.user.email,
        html_content,
        text_content=text_content,
    )
Example #9
0
def fm_reminder_email():
    """
    Reminds FMs to update their domains with up to date information
    """
    email_domains = incomplete_domains_to_email()

    for domain in email_domains:
        email_content = render_to_string('domain/email/fm_outreach.html',
                                         domain)
        email_content_plaintext = render_to_string(
            'domain/email/fm_outreach.txt', domain)
        send_HTML_email(
            "Please update your project settings for " + domain['domain_name'],
            domain['email_to'],
            email_content,
            email_from=settings.MASTER_LIST_EMAIL,
            text_content=email_content_plaintext,
            cc=[settings.MASTER_LIST_EMAIL],
        )
Example #10
0
def self_starter_email():
    """
    Emails MASTER_LIST_EMAIL incomplete self started domains

    Doesn't actually look at self-started attribute.
    """
    domains = incomplete_self_started_domains()

    if len(domains) > 0:
        email_content = render_to_string(
            'domain/email/self_starter.html', {'domains': domains})
        email_content_plaintext = render_to_string(
            'domain/email/self_starter.txt', {'domains': domains})
        send_HTML_email(
            "Incomplete Self Started Domains",
            settings.MASTER_LIST_EMAIL,
            email_content,
            text_content=email_content_plaintext,
        )
Example #11
0
def send_autopay_failed(invoice_id):
    context = get_context_to_send_autopay_failed_email(invoice_id)

    template_html = 'accounting/email/autopay_failed.html'
    html_content = render_to_string(template_html, context['template_context'])

    template_plaintext = 'accounting/email/autopay_failed.txt'
    text_content = render_to_string(template_plaintext,
                                    context['template_context'])

    send_HTML_email(
        subject=
        _(f"Subscription Payment for CommCare Invoice {context['invoice_number']} was declined"
          ),
        recipient=context['email_to'],
        html_content=html_content,
        text_content=text_content,
        email_from=context['email_from'],
    )
Example #12
0
def fm_reminder_email():
    """
    Reminds FMs to update their domains with up to date information
    """
    email_domains = incomplete_domains_to_email()

    for domain in email_domains:
        email_content = render_to_string(
            'domain/email/fm_outreach.html', domain)
        email_content_plaintext = render_to_string(
            'domain/email/fm_outreach.txt', domain)
        send_HTML_email(
            "Please update your project settings for " + domain['domain_name'],
            domain['email_to'],
            email_content,
            email_from=settings.MASTER_LIST_EMAIL,
            text_content=email_content_plaintext,
            cc=[settings.MASTER_LIST_EMAIL],
        )
Example #13
0
def send_html_email_async(self, subject, recipient, html_content,
                          text_content=None, cc=None,
                          email_from=settings.DEFAULT_FROM_EMAIL,
                          file_attachments=None, bcc=None,
                          smtp_exception_skip_list=None,
                          messaging_event_id=None):
    """ Call with send_HTML_email_async.delay(*args, **kwargs)
    - sends emails in the main celery queue
    - if sending fails, retry in 15 min
    - retry a maximum of 10 times
    """
    try:
        send_HTML_email(
            subject,
            recipient,
            html_content,
            text_content=text_content,
            cc=cc,
            email_from=email_from,
            file_attachments=file_attachments,
            bcc=bcc,
            smtp_exception_skip_list=smtp_exception_skip_list,
            messaging_event_id=messaging_event_id
        )
    except Exception as e:
        recipient = list(recipient) if not isinstance(recipient, str) else [recipient]
        notify_exception(
            None,
            message="Encountered error while sending email",
            details={
                'subject': subject,
                'recipients': ', '.join(recipient),
                'error': e,
            }
        )
        try:
            self.retry(exc=e)
            if messaging_event_id is not None:
                mark_subevent_gateway_error(messaging_event_id, e, retrying=True)
        except MaxRetriesExceededError:
            if messaging_event_id is not None:
                mark_subevent_gateway_error(messaging_event_id, e, retrying=False)
Example #14
0
    def send_report(self, recipient):
        yesterday = datetime.date.today() - datetime.timedelta(days=1)
        yesterday_string = yesterday.strftime("%d %b %Y")
        table = self._generate_report_table()

        file_to_attach = io.BytesIO()
        export_from_tables([[yesterday_string, table]], file_to_attach,
                           Format.XLS_2007)

        email_context = {
            'date_of_report': yesterday_string,
        }
        email_content = render_to_string('accounting/email/credits_on_hq.html',
                                         email_context)
        email_content_plaintext = render_to_string(
            'accounting/email/credits_on_hq.txt', email_context)
        format_dict = Format.FORMAT_DICT[Format.XLS_2007]

        file_attachment = {
            'title':
            'Credits_on_hq_{}_{}'.format(
                yesterday.isoformat(),
                settings.SERVER_ENVIRONMENT,
            ),
            'mimetype':
            format_dict['mimetype'],
            'file_obj':
            file_to_attach,
        }

        from_email = "Dimagi Finance <{}>".format(settings.DEFAULT_FROM_EMAIL)
        send_HTML_email(
            "{} Credits on HQ {}".format(
                yesterday_string,
                settings.SERVER_ENVIRONMENT,
            ),
            recipient,
            email_content,
            email_from=from_email,
            text_content=email_content_plaintext,
            file_attachments=[file_attachment],
        )
Example #15
0
def send_autopay_failed(invoice, payment_method):
    subscription = invoice.subscription
    auto_payer = subscription.account.auto_pay_user
    payment_method = StripePaymentMethod.objects.get(web_user=auto_payer)
    autopay_card = payment_method.get_autopay_card(subscription.account)
    web_user = WebUser.get_by_username(auto_payer)
    if web_user:
        recipient = web_user.get_email()
    else:
        recipient = auto_payer
    domain = invoice.get_domain()

    context = {
        'domain':
        domain,
        'subscription_plan':
        subscription.plan_version.plan.name,
        'billing_date':
        datetime.date.today(),
        'invoice_number':
        invoice.invoice_number,
        'autopay_card':
        autopay_card,
        'domain_url':
        absolute_reverse('dashboard_default', args=[domain]),
        'billing_info_url':
        absolute_reverse('domain_update_billing_info', args=[domain]),
        'support_email':
        settings.INVOICING_CONTACT_EMAIL,
    }

    template_html = 'accounting/autopay_failed_email.html'
    template_plaintext = 'accounting/autopay_failed_email.txt'

    send_HTML_email(
        subject="Subscription Payment for CommCare Invoice %s was declined" %
        invoice.invoice_number,
        recipient=recipient,
        html_content=render_to_string(template_html, context),
        text_content=render_to_string(template_plaintext, context),
        email_from=get_dimagi_from_email(),
    )
Example #16
0
def build_last_month_GIR():
    last_month = last_month_datespan()
    try:
        generator = GIRTableGenerator([last_month])
        generator.build_table()
    except Exception as e:
        soft_assert(to=[settings.DATA_EMAIL],
                    send_to_ops=False)(False,
                                       "Error in his month's GIR generation")
        # pass it so it gets logged in celery as an error as well
        raise e

    message = 'Global impact report generation for month {} is now ready. To download go to' \
              ' http://www.commcarehq.org/hq/admin/download_gir/'.format(
                  last_month
              )
    send_HTML_email('GIR data is ready',
                    settings.DATA_EMAIL,
                    message,
                    text_content=message)
Example #17
0
def build_last_month_GIR():
    def _last_month_datespan():
        today = datetime.date.today()
        first_of_this_month = datetime.date(day=1, month=today.month, year=today.year)
        last_month = first_of_this_month - datetime.timedelta(days=1)
        return DateSpan.from_month(last_month.month, last_month.year)

    last_month = _last_month_datespan()
    generator = GIRTableGenerator([last_month])
    generator.build_table()

    message = 'Global impact report generation for month {} is now ready. To download go to' \
              ' http://www.commcarehq.org/hq/admin/download_gir/'.format(
                  last_month
              )
    send_HTML_email(
        'GIR data is ready',
        settings.DATA_EMAIL,
        message,
        text_content=message
    )
Example #18
0
def build_last_month_GIR():
    def _last_month_datespan():
        today = datetime.date.today()
        first_of_this_month = datetime.date(day=1,
                                            month=today.month,
                                            year=today.year)
        last_month = first_of_this_month - datetime.timedelta(days=1)
        return DateSpan.from_month(last_month.month, last_month.year)

    last_month = _last_month_datespan()
    generator = GIRTableGenerator([last_month])
    generator.build_table()

    message = 'Global impact report generation for month {} is now ready. To download go to' \
              ' http://www.commcarehq.org/hq/admin/download_gir/'.format(
                  last_month
              )
    send_HTML_email('GIR data is ready',
                    settings.DATA_EMAIL,
                    message,
                    text_content=message)
Example #19
0
def send_html_email_async(self,
                          subject,
                          recipient,
                          html_content,
                          text_content=None,
                          cc=None,
                          email_from=settings.DEFAULT_FROM_EMAIL,
                          file_attachments=None,
                          bcc=None,
                          smtp_exception_skip_list=None):
    """ Call with send_HTML_email_async.delay(*args, **kwargs)
    - sends emails in the main celery queue
    - if sending fails, retry in 15 min
    - retry a maximum of 10 times
    """
    try:
        send_HTML_email(subject,
                        recipient,
                        html_content,
                        text_content=text_content,
                        cc=cc,
                        email_from=email_from,
                        file_attachments=file_attachments,
                        bcc=bcc,
                        smtp_exception_skip_list=smtp_exception_skip_list)
    except Exception as e:
        from corehq.util.python_compatibility import soft_assert_type_text
        if isinstance(recipient, six.string_types):
            soft_assert_type_text(recipient)
        recipient = list(recipient) if not isinstance(
            recipient, six.string_types) else [recipient]
        notify_exception(None,
                         message="Encountered error while sending email",
                         details={
                             'subject': subject,
                             'recipients': ', '.join(recipient),
                             'error': e,
                         })
        self.retry(exc=e)
Example #20
0
def _send_data_validation_email(csv_columns, month, bad_data):
    # intentionally using length here because the query will need to evaluate anyway to send the CSV file
    if all(len(v) == 0 for _, v in six.iteritems(bad_data)):
        return

    bad_wasting_awcs = bad_data.get('bad_wasting_awcs', [])
    bad_stunting_awcs = bad_data.get('bad_stunting_awcs', [])
    bad_underweight_awcs = bad_data.get('bad_underweight_awcs', [])
    bad_lbw_awcs = bad_data.get('bad_lbw_awcs', [])

    csv_file = io.StringIO()
    writer = csv.writer(csv_file)
    writer.writerow(('type',) + csv_columns)
    _icds_add_awcs_to_file(writer, 'wasting', bad_wasting_awcs)
    _icds_add_awcs_to_file(writer, 'stunting', bad_stunting_awcs)
    _icds_add_awcs_to_file(writer, 'underweight', bad_underweight_awcs)
    _icds_add_awcs_to_file(writer, 'low_birth_weight', bad_lbw_awcs)

    email_content = """
    Incorrect wasting AWCs: {bad_wasting_awcs}
    Incorrect stunting AWCs: {bad_stunting_awcs}
    Incorrect underweight AWCs: {bad_underweight_awcs}
    Incorrect low birth weight AWCs: {bad_lbw_awcs}

    Please see attached file for more details
    """.format(
        bad_wasting_awcs=len(bad_wasting_awcs),
        bad_stunting_awcs=len(bad_stunting_awcs),
        bad_underweight_awcs=len(bad_underweight_awcs),
        bad_lbw_awcs=len(bad_lbw_awcs),
    )

    filename = month.strftime('validation_results_%s.csv' % SERVER_DATE_FORMAT)
    send_HTML_email(
        '[{}] - ICDS Dashboard Validation Results'.format(settings.SERVER_ENVIRONMENT),
        DASHBOARD_TEAM_EMAILS, email_content,
        file_attachments=[{'file_obj': csv_file, 'title': filename, 'mimetype': 'text/csv'}],
    )
Example #21
0
def send_html_email_async(self,
                          subject,
                          recipient,
                          html_content,
                          text_content=None,
                          cc=None,
                          email_from=settings.DEFAULT_FROM_EMAIL,
                          file_attachments=None,
                          bcc=None,
                          ga_track=False,
                          ga_tracking_info=None):
    """ Call with send_HTML_email_async.delay(*args, **kwargs)
    - sends emails in the main celery queue
    - if sending fails, retry in 15 min
    - retry a maximum of 10 times
    """
    try:
        send_HTML_email(subject,
                        recipient,
                        html_content,
                        text_content=text_content,
                        cc=cc,
                        email_from=email_from,
                        file_attachments=file_attachments,
                        bcc=bcc,
                        ga_track=ga_track,
                        ga_tracking_info=ga_tracking_info)
    except Exception as e:
        recipient = list(recipient) if not isinstance(
            recipient, basestring) else [recipient]
        notify_exception(None,
                         message="Encountered error while sending email",
                         details={
                             'subject': subject,
                             'recipients': ', '.join(recipient),
                             'error': e,
                         })
        self.retry(exc=e)
Example #22
0
def _send_data_validation_email(csv_columns, month, bad_data):
    # intentionally using length here because the query will need to evaluate anyway to send the CSV file
    if all(len(v) == 0 for _, v in six.iteritems(bad_data)):
        return

    bad_wasting_awcs = bad_data.get('bad_wasting_awcs', [])
    bad_stunting_awcs = bad_data.get('bad_stunting_awcs', [])
    bad_underweight_awcs = bad_data.get('bad_underweight_awcs', [])
    bad_lbw_awcs = bad_data.get('bad_lbw_awcs', [])

    csv_file = io.StringIO()
    writer = csv.writer(csv_file)
    writer.writerow(('type',) + csv_columns)
    _icds_add_awcs_to_file(writer, 'wasting', bad_wasting_awcs)
    _icds_add_awcs_to_file(writer, 'stunting', bad_stunting_awcs)
    _icds_add_awcs_to_file(writer, 'underweight', bad_underweight_awcs)
    _icds_add_awcs_to_file(writer, 'low_birth_weight', bad_lbw_awcs)

    email_content = """
    Incorrect wasting AWCs: {bad_wasting_awcs}
    Incorrect stunting AWCs: {bad_stunting_awcs}
    Incorrect underweight AWCs: {bad_underweight_awcs}
    Incorrect low birth weight AWCs: {bad_lbw_awcs}

    Please see attached file for more details
    """.format(
        bad_wasting_awcs=len(bad_wasting_awcs),
        bad_stunting_awcs=len(bad_stunting_awcs),
        bad_underweight_awcs=len(bad_underweight_awcs),
        bad_lbw_awcs=len(bad_lbw_awcs),
    )

    filename = month.strftime('validation_results_%s.csv' % SERVER_DATE_FORMAT)
    send_HTML_email(
        '[{}] - ICDS Dashboard Validation Results'.format(settings.SERVER_ENVIRONMENT),
        DASHBOARD_TEAM_EMAILS, email_content,
        file_attachments=[{'file_obj': csv_file, 'title': filename, 'mimetype': 'text/csv'}],
    )
Example #23
0
def send_gateway_fee_report_out():
    backend_api_ids = SmsGatewayFeeCriteria.objects.values_list(
        'backend_api_id', flat=True).distinct()
    first_day_previous_month = add_months_to_date(date.today(), -1)
    billables_in_month = SmsBillable.objects.filter(
        date_sent__year=first_day_previous_month.year,
        date_sent__month=first_day_previous_month.month,
        is_valid=True,
    )

    costs_by_backend = defaultdict(list)
    for backend_api_id in backend_api_ids:
        billables_in_month_by_backend_api_id = billables_in_month.filter(
            gateway_fee__criteria__backend_api_id=backend_api_id)
        relevant_currencies = [
            Currency.objects.get(id=id)
            for id in billables_in_month_by_backend_api_id.values_list(
                'gateway_fee__currency', flat=True).distinct()
        ]
        for currency in relevant_currencies:
            cost_by_backend_and_currency = sum(
                billable.gateway_charge *
                (billable.gateway_fee_conversion_rate or 1)
                for billable in billables_in_month_by_backend_api_id.filter(
                    gateway_fee__currency=currency))
            costs_by_backend[backend_api_id].append(
                (cost_by_backend_and_currency, currency.code))

    subject = "[{}] Cost per SMS Gateway Monthly Summary".format(
        settings.SERVER_ENVIRONMENT)

    send_HTML_email(
        subject, settings.ACCOUNTS_EMAIL,
        ''.join('<p>{}: {}</p>'.format(
            backend_api_id, '; '.join('%.2f %s' % (cost, currency)
                                      for (cost, currency) in cost_by_backend))
                for (backend_api_id,
                     cost_by_backend) in costs_by_backend.items()))
Example #24
0
def send_purchase_receipt(payment_record, domain,
                          template_html, template_plaintext,
                          additional_context):
    username = payment_record.payment_method.web_user
    web_user = WebUser.get_by_username(username)
    if web_user:
        email = web_user.get_email()
        name = web_user.first_name
    else:
        try:
            # needed for sentry
            raise AccountingCommunicationError()
        except AccountingCommunicationError:
            log_accounting_error(
                f"A payment attempt was made by a user that "
                f"does not exist: {username}",
                show_stack_trace=True,
            )
        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),
        '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(
        _("Payment Received - Thank You!"), email, email_html,
        text_content=email_plaintext,
        email_from=get_dimagi_from_email(),
    )
Example #25
0
def execute_data_management(request_id):
    request = DataManagementRequest.objects.get(pk=request_id)
    processed, skipped, logs = request.execute()
    serialized = DataManagementRequestSerializer().to_representation(request)
    file_attachments = []
    for filename, filepath in logs.items():
        with open(filepath) as logfile:
            file_attachments.append({
                'title': filename,
                'file_obj': io.StringIO(logfile.read()),
                'mimetype': 'text/html',
            })
    subject = f"Data Management Task Result {serialized['name']} on {request.domain}"

    context = {
        'processed': processed,
        'skipped': skipped,
    }
    context.update(serialized)
    send_HTML_email(subject,
                    request.initiated_by,
                    render_to_string(
                        'data_management/email/data_management.html', context),
                    file_attachments=file_attachments)
Example #26
0
def send_prepaid_credits_export():
    if settings.ENTERPRISE_MODE:
        return

    headers = [
        'Account Name', 'Project Space', 'Edition', 'Start Date', 'End Date',
        '# General Credits', '# Product Credits', '# User Credits', '# SMS Credits', 'Last Date Modified'
    ]

    body = []
    for subscription in Subscription.visible_objects.filter(
        service_type=SubscriptionType.PRODUCT,
    ).order_by('subscriber__domain', 'id'):
        general_credit_lines = CreditLine.get_credits_by_subscription_and_features(subscription)
        product_credit_lines = CreditLine.get_credits_by_subscription_and_features(subscription, is_product=True)
        user_credit_lines = CreditLine.get_credits_by_subscription_and_features(
            subscription, feature_type=FeatureType.USER)
        sms_credit_lines = CreditLine.get_credits_by_subscription_and_features(
            subscription, feature_type=FeatureType.SMS)
        all_credit_lines = general_credit_lines | product_credit_lines | user_credit_lines | sms_credit_lines

        body.append([
            subscription.account.name, subscription.subscriber.domain, subscription.plan_version.plan.edition,
            subscription.date_start, subscription.date_end,
            sum(credit_line.balance for credit_line in general_credit_lines),
            sum(credit_line.balance for credit_line in product_credit_lines),
            sum(credit_line.balance for credit_line in user_credit_lines),
            sum(credit_line.balance for credit_line in sms_credit_lines),
            max(
                credit_line.last_modified for credit_line in all_credit_lines
            ).strftime(SERVER_DATETIME_FORMAT_NO_SEC)
            if all_credit_lines else 'N/A',
        ])

    for account in BillingAccount.objects.order_by('name', 'id'):
        general_credit_lines = CreditLine.get_credits_for_account(account)
        product_credit_lines = CreditLine.get_credits_for_account(account, is_product=True)
        user_credit_lines = CreditLine.get_credits_for_account(account, feature_type=FeatureType.USER)
        sms_credit_lines = CreditLine.get_credits_for_account(account, feature_type=FeatureType.SMS)
        all_credit_lines = general_credit_lines | product_credit_lines | user_credit_lines | sms_credit_lines

        body.append([
            account.name, '', '', '', '',
            sum(credit_line.balance for credit_line in general_credit_lines),
            sum(credit_line.balance for credit_line in product_credit_lines),
            sum(credit_line.balance for credit_line in user_credit_lines),
            sum(credit_line.balance for credit_line in sms_credit_lines),
            max(
                credit_line.last_modified for credit_line in all_credit_lines
            ).strftime(SERVER_DATETIME_FORMAT_NO_SEC)
            if all_credit_lines else 'N/A',
        ])

    file_obj = io.StringIO()
    writer = csv.writer(file_obj)
    writer.writerow(headers)
    for row in body:
        writer.writerow([
            val if isinstance(val, six.text_type) else bytes(val)
            for val in row
        ])

    date_string = datetime.datetime.utcnow().strftime(SERVER_DATE_FORMAT)
    filename = 'prepaid-credits-export_%s_%s.csv' % (settings.SERVER_ENVIRONMENT, date_string)
    send_HTML_email(
        '[%s] Prepaid Credits Export - %s' % (settings.SERVER_ENVIRONMENT, date_string),
        settings.ACCOUNTS_EMAIL,
        'See attached file.',
        file_attachments=[{'file_obj': file_obj, 'title': filename, 'mimetype': 'text/csv'}],
    )
Example #27
0
def send_email_report(self, recipient_emails, domain, report_slug, report_type,
                      request_data, once, cleaned_data):
    """
    Function invokes send_HTML_email to email the html text report.
    If the report is too large to fit into email then a download link is
    sent via email to download report
    :Parameter recipient_list:
            list of recipient to whom email is to be sent
    :Parameter domain:
            domain name
    :Parameter report_slug:
            report slug
    :Parameter report_type:
            type of the report
    :Parameter request_data:
            Dict containing request data
    :Parameter once
            boolean argument specifying whether the report is once off report
            or scheduled report
    :Parameter cleaned_data:
            Dict containing cleaned data from the submitted form
    """
    from corehq.apps.reports.views import _render_report_configs, render_full_report_notification

    user_id = request_data['couch_user']
    couch_user = CouchUser.get_by_user_id(user_id)
    mock_request = HttpRequest()

    mock_request.method = 'GET'
    mock_request.GET = request_data['GET']

    config = ReportConfig()

    # see ReportConfig.query_string()
    object.__setattr__(config, '_id', 'dummy')
    config.name = _("Emailed report")
    config.report_type = report_type
    config.report_slug = report_slug
    config.owner_id = user_id
    config.domain = domain

    config.start_date = request_data['datespan'].startdate.date()
    if request_data['datespan'].enddate:
        config.date_range = 'range'
        config.end_date = request_data['datespan'].enddate.date()
    else:
        config.date_range = 'since'

    GET = dict(six.iterlists(request_data['GET']))
    exclude = ['startdate', 'enddate', 'subject', 'send_to_owner', 'notes', 'recipient_emails']
    filters = {}
    for field in GET:
        if field not in exclude:
            filters[field] = GET.get(field)

    config.filters = filters

    subject = cleaned_data['subject'] or _("Email report from CommCare HQ")

    try:
        content = _render_report_configs(
            mock_request, [config], domain, user_id, couch_user, True, lang=couch_user.language,
            notes=cleaned_data['notes'], once=once
        )[0]
        body = render_full_report_notification(None, content).content

        for recipient in recipient_emails:
            send_HTML_email(subject, recipient,
                            body, email_from=settings.DEFAULT_FROM_EMAIL,
                            smtp_exception_skip_list=LARGE_FILE_SIZE_ERROR_CODES)

    except Exception as er:
        notify_exception(
            None,
            message="Encountered error while generating report or sending email",
            details={
                'subject': subject,
                'recipients': str(recipient_emails),
                'error': er,
            }
        )
        if getattr(er, 'smtp_code', None) in LARGE_FILE_SIZE_ERROR_CODES or type(er) == ESError:
            # If the email doesn't work because it is too large to fit in the HTML body,
            # send it as an excel attachment.
            report_state = {
                'request': request_data,
                'request_params': json_request(request_data['GET']),
                'domain': domain,
                'context': {},
            }
            export_all_rows_task(config.report, report_state, recipient_list=recipient_emails)
        else:
            self.retry(exc=er)
Example #28
0
def weekly_digest():
    today = datetime.date.today()
    in_forty_days = today + datetime.timedelta(days=40)

    ending_in_forty_days = [
        sub for sub in Subscription.objects.filter(
            date_end__lte=in_forty_days,
            date_end__gte=today,
            is_active=True,
            is_trial=False,
        ).exclude(account__dimagi_contact='', ) if not sub.is_renewed
    ]

    if not ending_in_forty_days:
        log_accounting_info(
            "Did not send summary of ending subscriptions because "
            "there are none.")
        return

    table = [[
        "Project Space",
        "Account",
        "Plan",
        "Salesforce Contract ID",
        "Dimagi Contact",
        "Start Date",
        "End Date",
        "Receives Invoice",
        "Created By",
    ]]

    def _fmt_row(sub):
        try:
            created_by_adj = SubscriptionAdjustment.objects.filter(
                subscription=sub,
                reason=SubscriptionAdjustmentReason.CREATE).order_by(
                    'date_created')[0]
            created_by = dict(SubscriptionAdjustmentMethod.CHOICES).get(
                created_by_adj.method, "Unknown")
        except (IndexError, SubscriptionAdjustment.DoesNotExist):
            created_by = "Unknown"
        return [
            sub.subscriber.domain,
            "%s (%s)" % (sub.account.name, sub.account.id),
            sub.plan_version.plan.name,
            sub.salesforce_contract_id,
            sub.account.dimagi_contact,
            sub.date_start,
            sub.date_end,
            "No" if sub.do_not_invoice else "YES",
            created_by,
        ]

    table.extend([_fmt_row(sub) for sub in ending_in_forty_days])

    file_to_attach = StringIO()
    export_from_tables([['End in 40 Days', table]], file_to_attach,
                       Format.XLS_2007)

    email_context = {
        'today': today.isoformat(),
        'forty_days': in_forty_days.isoformat(),
    }
    email_content = render_to_string('accounting/digest_email.html',
                                     email_context)
    email_content_plaintext = render_to_string('accounting/digest_email.txt',
                                               email_context)

    format_dict = Format.FORMAT_DICT[Format.XLS_2007]
    file_attachment = {
        'title': 'Subscriptions_%(start)s_%(end)s.xls' % {
            'start': today.isoformat(),
            'end': in_forty_days.isoformat(),
        },
        'mimetype': format_dict['mimetype'],
        'file_obj': file_to_attach,
    }
    from_email = "Dimagi Accounting <%s>" % settings.DEFAULT_FROM_EMAIL
    env = ("[{}] ".format(settings.SERVER_ENVIRONMENT.upper())
           if settings.SERVER_ENVIRONMENT != "production" else "")
    email_subject = "{}Subscriptions ending in 40 Days from {}".format(
        env, today.isoformat())
    send_HTML_email(
        email_subject,
        settings.ACCOUNTS_EMAIL,
        email_content,
        email_from=from_email,
        text_content=email_content_plaintext,
        file_attachments=[file_attachment],
    )

    log_accounting_info("Sent summary of ending subscriptions from %(today)s" %
                        {
                            'today': today.isoformat(),
                        })
Example #29
0
def upload(dropbox_helper_id, access_token, size, max_retries):
    from .models import DropboxUploadHelper
    helper = DropboxUploadHelper.objects.get(id=dropbox_helper_id)
    dbx = Dropbox(access_token)

    try:
        with open(helper.src, 'rb') as f:
            chunk = f.read(CHUNK_SIZE)
            offset = len(chunk)

            upload_session = dbx.files_upload_session_start(chunk)

            while True:
                chunk = f.read(CHUNK_SIZE)
                if not chunk:
                    break
                helper.progress = offset / size
                helper.save()
                dbx.files_upload_session_append_v2(
                    chunk,
                    UploadSessionCursor(
                        upload_session.session_id,
                        offset,
                    ),
                )
                offset += len(chunk)

            file_metadata = dbx.files_upload_session_finish(
                b'',
                UploadSessionCursor(
                    upload_session.session_id,
                    offset=offset,
                ),
                CommitInfo(
                    '/{}'.format(os.path.basename(helper.src)),
                    # When writing the file it won't overwrite an existing file, just add
                    # another file like "filename (2).txt"
                    WriteMode('add'),
                ),
            )
    except Exception as e:
        helper.failure_reason = str(e)
        helper.save()

    couch_user = CouchUser.get_by_username(helper.user.username)
    if helper.failure_reason is None:
        path_link_metadata = dbx.sharing_create_shared_link_with_settings(
            file_metadata.path_display,
            SharedLinkSettings(
                requested_visibility=RequestedVisibility.team_only, ),
        )
        context = {
            'share_url':
            path_link_metadata.url,
            'path':
            os.path.join(
                u'Apps',
                settings.DROPBOX_APP_NAME,
                path_link_metadata.name,
            )
        }
        with localize(couch_user.get_language_code()):
            subject = _(u'{} has been uploaded to dropbox!'.format(
                helper.dest))
            html_content = render_to_string(
                'dropbox/emails/upload_success.html', context)
            text_content = render_to_string(
                'dropbox/emails/upload_success.txt', context)
    else:
        context = {'reason': helper.failure_reason, 'path': helper.dest}
        with localize(couch_user.get_language_code()):
            subject = _(u'{} has failed to upload to dropbox'.format(
                helper.dest))
            html_content = render_to_string('dropbox/emails/upload_error.html',
                                            context)
            text_content = render_to_string('dropbox/emails/upload_error.txt',
                                            context)

    send_HTML_email(
        subject,
        helper.user.email,
        html_content,
        text_content=text_content,
    )
Example #30
0
def send_bookkeeper_email(month=None, year=None, emails=None):
    today = datetime.date.today()

    # now, make sure that we send out LAST month's invoices if we did
    # not specify a month or year.
    today = get_previous_month_date_range(today)[0]

    month = month or today.month
    year = year or today.year

    from corehq.apps.accounting.interface import InvoiceInterface
    request = HttpRequest()
    params = urlencode((
        ('report_filter_statement_period_use_filter', 'on'),
        ('report_filter_statement_period_month', month),
        ('report_filter_statement_period_year', year),
    ))
    request.GET = QueryDict(params)
    request.couch_user = FakeUser(
        domain="hqadmin",
        username="******",
    )
    invoice = InvoiceInterface(request)
    invoice.is_rendered_as_email = True
    first_of_month = datetime.date(year, month, 1)
    email_context = {
        'month': first_of_month.strftime("%B"),
    }
    email_content = render_to_string('accounting/bookkeeper_email.html',
                                     email_context)
    email_content_plaintext = render_to_string(
        'accounting/bookkeeper_email_plaintext.html', email_context)

    format_dict = Format.FORMAT_DICT[Format.CSV]
    excel_attachment = {
        'title': 'Invoices_%(period)s.%(extension)s' % {
            'period': first_of_month.strftime('%B_%Y'),
            'extension': format_dict['extension'],
        },
        'mimetype': format_dict['mimetype'],
        'file_obj': invoice.excel_response,
    }

    emails = emails or settings.BOOKKEEPER_CONTACT_EMAILS
    for email in emails:
        send_HTML_email(
            "Invoices for %s" %
            datetime.date(year, month, 1).strftime(USER_MONTH_FORMAT),
            email,
            email_content,
            email_from=settings.DEFAULT_FROM_EMAIL,
            text_content=email_content_plaintext,
            file_attachments=[excel_attachment],
        )

    log_accounting_info(
        "Sent Bookkeeper Invoice Summary for %(month)s "
        "to %(emails)s." % {
            'month': first_of_month.strftime(USER_MONTH_FORMAT),
            'emails': ", ".join(emails)
        })
Example #31
0
def weekly_digest():
    today = datetime.date.today()
    in_forty_days = today + datetime.timedelta(days=40)

    ending_in_forty_days = [sub for sub in Subscription.visible_objects.filter(
            date_end__lte=in_forty_days,
            date_end__gte=today,
            is_active=True,
            is_trial=False,
        ).exclude(
            account__dimagi_contact='',
        ) if not sub.is_renewed]

    if not ending_in_forty_days:
        log_accounting_info(
            "Did not send summary of ending subscriptions because "
            "there are none."
        )
        return

    table = [[
        "Project Space", "Account", "Plan", "Salesforce Contract ID",
        "Dimagi Contact", "Start Date", "End Date", "Receives Invoice",
        "Created By",
    ]]

    def _fmt_row(sub):
        try:
            created_by_adj = SubscriptionAdjustment.objects.filter(
                subscription=sub,
                reason=SubscriptionAdjustmentReason.CREATE
            ).order_by('date_created')[0]
            created_by = dict(SubscriptionAdjustmentMethod.CHOICES).get(
                created_by_adj.method, "Unknown")
        except (IndexError, SubscriptionAdjustment.DoesNotExist):
            created_by = "Unknown"
        return [
            sub.subscriber.domain,
            "%s (%s)" % (sub.account.name, sub.account.id),
            sub.plan_version.plan.name,
            sub.salesforce_contract_id,
            sub.account.dimagi_contact,
            sub.date_start,
            sub.date_end,
            "No" if sub.do_not_invoice else "YES",
            created_by,
        ]

    table.extend([_fmt_row(sub) for sub in ending_in_forty_days])

    file_to_attach = io.BytesIO()
    export_from_tables(
        [['End in 40 Days', table]],
        file_to_attach,
        Format.XLS_2007
    )

    email_context = {
        'today': today.isoformat(),
        'forty_days': in_forty_days.isoformat(),
    }
    email_content = render_to_string(
        'accounting/email/digest.html', email_context)
    email_content_plaintext = render_to_string(
        'accounting/email/digest.txt', email_context)

    format_dict = Format.FORMAT_DICT[Format.XLS_2007]
    file_attachment = {
        'title': 'Subscriptions_%(start)s_%(end)s.xls' % {
            'start': today.isoformat(),
            'end': in_forty_days.isoformat(),
        },
        'mimetype': format_dict['mimetype'],
        'file_obj': file_to_attach,
    }
    from_email = "Dimagi Accounting <%s>" % settings.DEFAULT_FROM_EMAIL
    env = ("[{}] ".format(settings.SERVER_ENVIRONMENT.upper())
           if settings.SERVER_ENVIRONMENT != "production" else "")
    email_subject = "{}Subscriptions ending in 40 Days from {}".format(env, today.isoformat())
    send_HTML_email(
        email_subject,
        settings.ACCOUNTS_EMAIL,
        email_content,
        email_from=from_email,
        text_content=email_content_plaintext,
        file_attachments=[file_attachment],
    )

    log_accounting_info(
        "Sent summary of ending subscriptions from %(today)s" % {
            'today': today.isoformat(),
        })
Example #32
0
def upload(dropbox_helper_id, access_token, size, max_retries):
    from .models import DropboxUploadHelper
    helper = DropboxUploadHelper.objects.get(id=dropbox_helper_id)
    client = DropboxClient(access_token)
    retries = 0

    try:
        with open(helper.src, 'rb') as f:
            uploader = client.get_chunked_uploader(f, size)
            while uploader.offset < size:
                helper.progress = uploader.offset / size
                helper.save()
                try:
                    uploader.upload_chunked()
                except ErrorResponse as e:
                    if retries < max_retries:
                        retries += 1
                    else:
                        helper.failure_reason = str(e)
                        helper.save()
                        raise e

            upload = uploader.finish(helper.dest)
    except Exception as e:
        helper.failure_reason = str(e)
        helper.save()

    couch_user = CouchUser.get_by_username(helper.user.username)
    if helper.failure_reason is None:
        share = client.share(upload['path'])
        context = {
            'share_url':
            share.get('url', None),
            'path':
            u'Apps/{app}{dest}'.format(
                app=settings.DROPBOX_APP_NAME,
                dest=upload['path'],
            )
        }
        with localize(couch_user.get_language_code()):
            subject = _(u'{} has been uploaded to dropbox!'.format(
                helper.dest))
            html_content = render_to_string(
                'dropbox/emails/upload_success.html', context)
            text_content = render_to_string(
                'dropbox/emails/upload_success.txt', context)
    else:
        context = {'reason': helper.failure_reason, 'path': helper.dest}
        with localize(couch_user.get_language_code()):
            subject = _(u'{} has failed to upload to dropbox'.format(
                helper.dest))
            html_content = render_to_string('dropbox/emails/upload_error.html',
                                            context)
            text_content = render_to_string('dropbox/emails/upload_error.txt',
                                            context)

    send_HTML_email(
        subject,
        helper.user.email,
        html_content,
        text_content=text_content,
    )
    def handle(self, **options):
        compare_url = options.get('url', None)
        minutes = options.get('minutes', None)

        deploy = HqDeploy(date=datetime.utcnow(),
                          user=options['user'],
                          environment=options['environment'],
                          diff_url=compare_url)
        deploy.save()

        #  reset PillowTop errors in the hope that a fix has been deployed
        rows_updated = PillowError.bulk_reset_attempts(datetime.utcnow())
        if rows_updated:
            print("\n---------------- Pillow Errors Reset ----------------\n" \
                  "{} pillow errors queued for retry\n".format(rows_updated))

        deploy_notification_text = (
            "CommCareHQ has been successfully deployed to *{}* by *{}* in *{}* minutes. "
            .format(
                options['environment'],
                options['user'],
                minutes or '?',
            ))

        if options['environment'] == 'production':
            deploy_notification_text += "Monitor the {dashboard_link}. "

        if settings.MOBILE_INTEGRATION_TEST_TOKEN:
            deploy_notification_text += "Check the integration {integration_tests_link}. "
            requests.get(
                'https://jenkins.dimagi.com/job/integration-tests/build',
                params={'token': settings.MOBILE_INTEGRATION_TEST_TOKEN},
            )
            requests.get(
                'https://jenkins.dimagi.com/job/integration-tests-pipeline/build',
                params={'token': settings.MOBILE_INTEGRATION_TEST_TOKEN},
            )

        deploy_notification_text += "Find the diff {diff_link}"

        if hasattr(settings, 'MIA_THE_DEPLOY_BOT_API'):
            link = diff_link(STYLE_SLACK, compare_url)
            if options['environment'] == 'staging':
                channel = '#staging'
            elif options['environment'] == 'icds':
                channel = '#nic-server-standup'
            else:
                channel = '#hq-ops'
            requests.post(
                settings.MIA_THE_DEPLOY_BOT_API,
                data=json.dumps({
                    "username":
                    "******",
                    "channel":
                    channel,
                    "text":
                    deploy_notification_text.format(
                        dashboard_link=dashboard_link(STYLE_SLACK,
                                                      DASHBOARD_URL),
                        diff_link=link,
                        integration_tests_link=integration_tests_link(
                            STYLE_SLACK, INTEGRATION_TEST_URL)),
                }))

        if settings.DATADOG_API_KEY:
            tags = ['environment:{}'.format(options['environment'])]
            link = diff_link(STYLE_MARKDOWN, compare_url)
            datadog_api.Event.create(
                title="Deploy Success",
                text=deploy_notification_text.format(
                    dashboard_link=dashboard_link(STYLE_MARKDOWN,
                                                  DASHBOARD_URL),
                    diff_link=link,
                    integration_tests_link=integration_tests_link(
                        STYLE_MARKDOWN, INTEGRATION_TEST_URL)),
                tags=tags,
                alert_type="success")

            print("\n=============================================================\n" \
                  "Congratulations! Deploy Complete.\n\n" \
                  "Don't forget to keep an eye on the deploy dashboard to " \
                  "make sure everything is running smoothly.\n\n" \
                  "https://p.datadoghq.com/sb/5c4af2ac8-1f739e93ef" \
                  "\n=============================================================\n")

        if options['mail_admins']:
            message_body = get_deploy_email_message_body(
                user=options['user'], compare_url=compare_url)
            call_command('mail_admins', message_body, **{
                'subject': 'Deploy successful',
                'html': True
            })
            if settings.DAILY_DEPLOY_EMAIL:
                recipient = settings.DAILY_DEPLOY_EMAIL
                subject = 'Deploy Successful - {}'.format(
                    options['environment'])
                send_HTML_email(subject=subject,
                                recipient=recipient,
                                html_content=message_body)

        if settings.SENTRY_CONFIGURED and settings.SENTRY_API_KEY:
            create_update_sentry_release()
            notify_sentry_deploy(minutes)
    def handle(self, **options):
        compare_url = options.get('url', None)
        minutes = options.get('minutes', None)

        deploy = HqDeploy(
            date=datetime.utcnow(),
            user=options['user'],
            environment=options['environment'],
            diff_url=compare_url,
            commit=options['commit']
        )
        deploy.save()

        #  reset PillowTop errors in the hope that a fix has been deployed
        rows_updated = PillowError.bulk_reset_attempts(datetime.utcnow())
        if rows_updated:
            print("\n---------------- Pillow Errors Reset ----------------\n" \
                  "{} pillow errors queued for retry\n".format(rows_updated))

        deploy_notification_text = (
            "CommCareHQ has been successfully deployed to *{}* by *{}* in *{}* minutes. ".format(
                options['environment'],
                options['user'],
                minutes or '?',
            )
        )

        if options['environment'] == 'production':
            deploy_notification_text += "Monitor the {dashboard_link}. "

        if settings.MOBILE_INTEGRATION_TEST_TOKEN:
            deploy_notification_text += "Check the integration {integration_tests_link}. "
            requests.get(
                'https://jenkins.dimagi.com/job/integration-tests/build',
                params={'token': settings.MOBILE_INTEGRATION_TEST_TOKEN},
            )
            requests.get(
                'https://jenkins.dimagi.com/job/integration-tests-pipeline/build',
                params={'token': settings.MOBILE_INTEGRATION_TEST_TOKEN},
            )

        deploy_notification_text += "Find the diff {diff_link}"

        if settings.DATADOG_API_KEY:
            link = diff_link(compare_url)
            create_metrics_event(
                title="Deploy Success",
                text=deploy_notification_text.format(
                    dashboard_link=dashboard_link(DASHBOARD_URL),
                    diff_link=link,
                    integration_tests_link=integration_tests_link(INTEGRATION_TEST_URL)
                ),
                tags={'environment': options['environment']},
                alert_type="success"
            )

            print(
                "\n=============================================================\n"
                "Congratulations! Deploy Complete.\n\n"
                "Don't forget to keep an eye on the deploy dashboard to "
                "make sure everything is running smoothly.\n\n"
                "https://app.datadoghq.com/dashboard/xch-zwt-vzv/hq-deploy-dashboard?tpl_var_environment={}"
                "\n=============================================================\n".format(
                    settings.SERVER_ENVIRONMENT
                )
            )

        if options['mail_admins']:
            message_body = get_deploy_email_message_body(user=options['user'], compare_url=compare_url)
            subject = 'Deploy Successful - {}'.format(options['environment'])
            call_command('mail_admins', message_body, **{'subject': subject, 'html': True})
            if settings.DAILY_DEPLOY_EMAIL:
                recipient = settings.DAILY_DEPLOY_EMAIL

                send_HTML_email(subject=subject,
                                recipient=recipient,
                                html_content=message_body)

        if settings.SENTRY_CONFIGURED and settings.SENTRY_API_KEY:
            create_update_sentry_release()
            notify_sentry_deploy(minutes)
    def handle(self, **options):
        compare_url = options.get('url', None)
        minutes = options.get('minutes', None)

        deploy = HqDeploy(
            date=datetime.utcnow(),
            user=options['user'],
            environment=options['environment'],
            diff_url=compare_url
        )
        deploy.save()

        #  reset PillowTop errors in the hope that a fix has been deployed
        rows_updated = PillowError.bulk_reset_attempts(datetime.utcnow())
        if rows_updated:
            print("\n---------------- Pillow Errors Reset ----------------\n" \
                  "{} pillow errors queued for retry\n".format(rows_updated))

        deploy_notification_text = (
            "CommCareHQ has been successfully deployed to *{}* by *{}* in *{}* minutes. ".format(
                options['environment'],
                options['user'],
                minutes or '?',
            )
        )

        if options['environment'] == 'production':
            deploy_notification_text += "Monitor the {dashboard_link}. "

        if settings.MOBILE_INTEGRATION_TEST_TOKEN:
            deploy_notification_text += "Check the integration {integration_tests_link}. "
            requests.get(
                'https://jenkins.dimagi.com/job/integration-tests/build',
                params={'token': settings.MOBILE_INTEGRATION_TEST_TOKEN},
            )
            requests.get(
                'https://jenkins.dimagi.com/job/integration-tests-pipeline/build',
                params={'token': settings.MOBILE_INTEGRATION_TEST_TOKEN},
            )

        deploy_notification_text += "Find the diff {diff_link}"

        if hasattr(settings, 'MIA_THE_DEPLOY_BOT_API'):
            link = diff_link(STYLE_SLACK, compare_url)
            if options['environment'] == 'staging':
                channel = '#staging'
            elif options['environment'] == 'icds':
                channel = '#nic-server-standup'
            else:
                channel = '#hq-ops'
            requests.post(settings.MIA_THE_DEPLOY_BOT_API, data=json.dumps({
                "username": "******",
                "channel": channel,
                "text": deploy_notification_text.format(
                    dashboard_link=dashboard_link(STYLE_SLACK, DASHBOARD_URL),
                    diff_link=link,
                    integration_tests_link=integration_tests_link(STYLE_SLACK, INTEGRATION_TEST_URL)
                ),
            }))

        if settings.DATADOG_API_KEY:
            tags = ['environment:{}'.format(options['environment'])]
            link = diff_link(STYLE_MARKDOWN, compare_url)
            datadog_api.Event.create(
                title="Deploy Success",
                text=deploy_notification_text.format(
                    dashboard_link=dashboard_link(STYLE_MARKDOWN, DASHBOARD_URL),
                    diff_link=link,
                    integration_tests_link=integration_tests_link(STYLE_MARKDOWN, INTEGRATION_TEST_URL)
                ),
                tags=tags,
                alert_type="success"
            )

            print("\n=============================================================\n" \
                  "Congratulations! Deploy Complete.\n\n" \
                  "Don't forget to keep an eye on the deploy dashboard to " \
                  "make sure everything is running smoothly.\n\n" \
                  "https://p.datadoghq.com/sb/5c4af2ac8-1f739e93ef" \
                  "\n=============================================================\n")

        if options['mail_admins']:
            message_body = get_deploy_email_message_body(user=options['user'], compare_url=compare_url)
            call_command('mail_admins', message_body, **{'subject': 'Deploy successful', 'html': True})
            if settings.DAILY_DEPLOY_EMAIL:
                recipient = settings.DAILY_DEPLOY_EMAIL
                subject = 'Deploy Successful - {}'.format(options['environment'])
                send_HTML_email(subject=subject,
                                recipient=recipient,
                                html_content=message_body)

        if settings.SENTRY_CONFIGURED and settings.SENTRY_API_KEY:
            create_update_sentry_release()
            notify_sentry_deploy(minutes)
Example #36
0
def send_email_report(self, recipient_emails, domain, report_slug, report_type,
                      request_data, once, cleaned_data):
    """
    Function invokes send_HTML_email to email the html text report.
    If the report is too large to fit into email then a download link is
    sent via email to download report
    :Parameter recipient_list:
            list of recipient to whom email is to be sent
    :Parameter domain:
            domain name
    :Parameter report_slug:
            report slug
    :Parameter report_type:
            type of the report
    :Parameter request_data:
            Dict containing request data
    :Parameter once
            boolean argument specifying whether the report is once off report
            or scheduled report
    :Parameter cleaned_data:
            Dict containing cleaned data from the submitted form
    """
    from corehq.apps.reports.views import _render_report_configs, render_full_report_notification

    user_id = request_data['couch_user']
    couch_user = CouchUser.get_by_user_id(user_id)
    mock_request = HttpRequest()

    mock_request.method = 'GET'
    mock_request.GET = request_data['GET']

    config = ReportConfig()

    # see ReportConfig.query_string()
    object.__setattr__(config, '_id', 'dummy')
    config.name = _("Emailed report")
    config.report_type = report_type
    config.report_slug = report_slug
    config.owner_id = user_id
    config.domain = domain

    config.start_date = request_data['datespan'].startdate.date()
    if request_data['datespan'].enddate:
        config.date_range = 'range'
        config.end_date = request_data['datespan'].enddate.date()
    else:
        config.date_range = 'since'

    GET = dict(six.iterlists(request_data['GET']))
    exclude = [
        'startdate', 'enddate', 'subject', 'send_to_owner', 'notes',
        'recipient_emails'
    ]
    filters = {}
    for field in GET:
        if field not in exclude:
            filters[field] = GET.get(field)

    config.filters = filters

    subject = cleaned_data['subject'] or _("Email report from CommCare HQ")

    content = _render_report_configs(mock_request, [config],
                                     domain,
                                     user_id,
                                     couch_user,
                                     True,
                                     lang=couch_user.language,
                                     notes=cleaned_data['notes'],
                                     once=once)[0]
    body = render_full_report_notification(None, content).content

    try:
        for recipient in recipient_emails:
            send_HTML_email(
                subject,
                recipient,
                body,
                email_from=settings.DEFAULT_FROM_EMAIL,
                smtp_exception_skip_list=LARGE_FILE_SIZE_ERROR_CODES)

    except Exception as er:
        if getattr(er, 'smtp_code', None) in LARGE_FILE_SIZE_ERROR_CODES:
            # If the smtp server rejects the email because of its large size.
            # Then sends the report download link in the email.
            report_state = {
                'request': request_data,
                'request_params': json_request(request_data['GET']),
                'domain': domain,
                'context': {},
            }
            export_all_rows_task(config.report,
                                 report_state,
                                 recipient_list=recipient_emails)
        else:
            self.retry(exc=er)
    def handle(self, **options):
        dryrun = options.pop('dryrun')
        limit = options.pop('limit')
        force_convert_columns = options.pop('force_convert_columns')
        count = 0

        if dryrun:
            print('*** Running in dryrun mode. Will not save any conversion ***')

        print('*** Migrating {} exports ***'.format(limit or 'ALL'))
        skipped_domains = []

        for doc in Domain.get_all(include_docs=False):
            domain = doc['key']

            if not use_new_exports(domain):
                if not force_convert_columns:
                    try:
                        metas = migrate_domain(domain, dryrun=True, force_convert_columns=force_convert_columns)
                    except Exception:
                        print('Migration raised an exception, skipping.')
                        traceback.print_exc()
                        skipped_domains.append(domain)
                        continue

                    has_skipped_tables = any(map(lambda meta: bool(meta.skipped_tables), metas))
                    has_skipped_columns = any(map(lambda meta: bool(meta.skipped_columns), metas))
                    is_remote_app_migration = any(map(lambda meta: bool(meta.is_remote_app_migration), metas))
                    if has_skipped_tables or has_skipped_columns:
                        print('Skipping {} because we would have skipped columns'.format(domain))
                        skipped_domains.append(domain)
                        continue

                    if is_remote_app_migration:
                        print('Skipping {} because it contains remote apps'.format(domain))
                        skipped_domains.append(domain)
                        continue

                if not dryrun:
                    print('Migrating {}'.format(domain))
                    try:
                        migrate_domain(domain, dryrun=False, force_convert_columns=force_convert_columns)
                    except Exception:
                        print('Migration raised an exception, skipping.')
                        skipped_domains.append(domain)
                        continue
                else:
                    print('No skipped tables/columns. Not migrating since dryrun is specified')
                count += 1
            if limit is not None and count >= limit:
                break

        send_HTML_email(
            'Export migration results',
            '{}@{}'.format('commcarehq-ops+admins', 'dimagi.com'),

            '''
            Skipped domains: {} <br />
            Successfully migrated: {}
            '''.format(
                ', '.join(skipped_domains),
                count,
            )
        )
Example #38
0
def send_prepaid_credits_export():
    if settings.ENTERPRISE_MODE:
        return

    headers = [
        'Account Name', 'Project Space', 'Edition', 'Start Date', 'End Date',
        '# General Credits', '# Product Credits', '# User Credits', '# SMS Credits', 'Last Date Modified'
    ]

    body = []
    for subscription in Subscription.visible_objects.filter(
        service_type=SubscriptionType.PRODUCT,
    ).order_by('subscriber__domain', 'id'):
        general_credit_lines = CreditLine.get_credits_by_subscription_and_features(subscription)
        product_credit_lines = CreditLine.get_credits_by_subscription_and_features(subscription, is_product=True)
        user_credit_lines = CreditLine.get_credits_by_subscription_and_features(
            subscription, feature_type=FeatureType.USER)
        sms_credit_lines = CreditLine.get_credits_by_subscription_and_features(
            subscription, feature_type=FeatureType.SMS)
        all_credit_lines = general_credit_lines | product_credit_lines | user_credit_lines | sms_credit_lines

        body.append([
            subscription.account.name, subscription.subscriber.domain, subscription.plan_version.plan.edition,
            subscription.date_start, subscription.date_end,
            sum(credit_line.balance for credit_line in general_credit_lines),
            sum(credit_line.balance for credit_line in product_credit_lines),
            sum(credit_line.balance for credit_line in user_credit_lines),
            sum(credit_line.balance for credit_line in sms_credit_lines),
            max(
                credit_line.last_modified for credit_line in all_credit_lines
            ).strftime(SERVER_DATETIME_FORMAT_NO_SEC)
            if all_credit_lines else 'N/A',
        ])

    for account in BillingAccount.objects.order_by('name', 'id'):
        general_credit_lines = CreditLine.get_credits_for_account(account)
        product_credit_lines = CreditLine.get_credits_for_account(account, is_product=True)
        user_credit_lines = CreditLine.get_credits_for_account(account, feature_type=FeatureType.USER)
        sms_credit_lines = CreditLine.get_credits_for_account(account, feature_type=FeatureType.SMS)
        all_credit_lines = general_credit_lines | product_credit_lines | user_credit_lines | sms_credit_lines

        body.append([
            account.name, '', '', '', '',
            sum(credit_line.balance for credit_line in general_credit_lines),
            sum(credit_line.balance for credit_line in product_credit_lines),
            sum(credit_line.balance for credit_line in user_credit_lines),
            sum(credit_line.balance for credit_line in sms_credit_lines),
            max(
                credit_line.last_modified for credit_line in all_credit_lines
            ).strftime(SERVER_DATETIME_FORMAT_NO_SEC)
            if all_credit_lines else 'N/A',
        ])

    file_obj = io.StringIO()
    writer = csv.writer(file_obj)
    writer.writerow(headers)
    for row in body:
        writer.writerow([
            val if isinstance(val, six.text_type) else six.binary_type(val)
            for val in row
        ])

    date_string = datetime.datetime.utcnow().strftime(SERVER_DATE_FORMAT)
    filename = 'prepaid-credits-export_%s_%s.csv' % (settings.SERVER_ENVIRONMENT, date_string)
    send_HTML_email(
        '[%s] Prepaid Credits Export - %s' % (settings.SERVER_ENVIRONMENT, date_string),
        settings.ACCOUNTS_EMAIL,
        'See attached file.',
        file_attachments=[{'file_obj': file_obj, 'title': filename, 'mimetype': 'text/csv'}],
    )