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(), )
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)
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(), )
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) })
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() ) )
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)
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 )
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, )
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], )
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, )
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'], )
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], )
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)
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], )
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(), )
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)
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 )
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)
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)
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'}], )
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)
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()))
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(), )
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)
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'}], )
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)
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(), })
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, )
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) })
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(), })
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)
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, ) )
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'}], )