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) try: recipient = WebUser.get_by_username(auto_payer).get_email() except ResourceNotFound: 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_by_product(subscription.plan_version.product_rate.product.product_type), )
def url(self): try: if self.is_configurable_report: url_base = absolute_reverse(self.report_slug, args=[self.domain, self.subreport_slug]) else: url_base = absolute_reverse(self._dispatcher.name(), kwargs=self.url_kwargs) return url_base + '?' + self.query_string except UnsupportedSavedReportError: return "#" except Exception as e: logging.exception(e.message) return "#"
def process_email_request(domain, download_id, email_address): dropbox_url = absolute_reverse('dropbox_upload', args=(download_id,)) download_url = "{}?get_file".format(absolute_reverse('retrieve_download', args=(download_id,))) try: allow_dropbox_sync = get_download_context(download_id).get('allow_dropbox_sync', False) except TaskFailedError: allow_dropbox_sync = False dropbox_message = '' if allow_dropbox_sync: dropbox_message = _('<br/><br/>You can also upload your data to Dropbox with the link below:<br/>' '{}').format(dropbox_url) email_body = _('Your CommCare export for {} is ready! Click on the link below to download your requested data:' '<br/>{}{}').format(domain, download_url, dropbox_message) send_HTML_email(_('CommCare Export Complete'), email_address, email_body)
def get_name_or_link(self, d, internal_settings=False): if not getattr(self, 'show_name', None): reverse_str = "domain_homepage" if not internal_settings else "domain_internal_settings" return mark_safe('<a href="%s">%s</a>' % (absolute_reverse(reverse_str, args=[d['name']]), d.get('hr_name') or d['name'])) else: return d['name']
def report_context(self): ret = {} try: patient_doc = self.get_case() has_error = False except Exception: has_error = True patient_doc = None if patient_doc is None: self.report_template_path = "reports/careplan/nopatient.html" if has_error: ret['error_message'] = "Patient not found" else: ret['error_message'] = "No patient selected" return ret ret['patient_doc'] = patient_doc ret.update({ 'case_hierarchy_options': { "show_view_buttons": False, "get_case_url": lambda case_id: absolute_reverse('case_details', args=[self.domain, case_id]), "columns": self.related_cases_columns, "related_type_info": self.related_type_info }, 'case': patient_doc, }) self.report_template_path = "reports/careplan/patient_careplan.html" return ret
def page_context(self): # The webhook secret is a piece of data that is sent to hq on each # Telerivet inbound request. It's used to tie an inbound request to # a Telerivet backend. webhook_secret = uuid.uuid4().hex # The request token is only used for the purposes of using this UI to # setup a Telerivet backend. We need a way to post the webhook_secret # to create the backend, but we want hq to be the origin of the secret # generation. So instead, the request_token resolves to the webhook_secret # via a redis lookup which expires in 1 week. request_token = uuid.uuid4().hex self.set_cached_webhook_secret(request_token, webhook_secret) domain_has_default_gateway = SQLMobileBackend.get_domain_default_backend( SQLMobileBackend.SMS, self.domain, id_only=True ) is not None return { 'outgoing_sms_form': TelerivetOutgoingSMSForm(), 'test_sms_form': TelerivetPhoneNumberForm(), 'finalize_gateway_form': FinalizeGatewaySetupForm( initial={ 'set_as_default': (FinalizeGatewaySetupForm.NO if domain_has_default_gateway else FinalizeGatewaySetupForm.YES), } ), 'webhook_url': absolute_reverse('telerivet_in'), 'webhook_secret': webhook_secret, 'request_token': request_token, }
def email_enterprise_report(domain, slug, couch_user): account = BillingAccount.get_account_by_domain(domain) report = EnterpriseReport.create(slug, account.id, couch_user) # Generate file csv_file = io.StringIO() writer = csv.writer(csv_file) writer.writerow(report.headers) writer.writerows(report.rows) # Store file in redis hash_id = uuid.uuid4().hex redis = get_redis_client() redis.set(hash_id, csv_file.getvalue()) redis.expire(hash_id, 60 * 60 * 24) csv_file.close() # Send email url = absolute_reverse("enterprise_dashboard_download", args=[domain, report.slug, str(hash_id)]) link = "<a href='{}'>{}</a>".format(url, url) subject = _("Enterprise Dashboard: {}").format(report.title) body = "The enterprise report you requested for the account {} is ready.<br>" \ "You can download the data at the following link: {}<br><br>" \ "Please remember that this link will only be active for 24 hours.".format(account.name, link) send_html_email_async(subject, couch_user.username, body)
def _link(self): try: link = absolute_reverse('case_data', args=[self.report.domain, self.case.get('_id')]) except NoReverseMatch: return _("No link found") return html.mark_safe( "<a class='ajax_dialog' href='{}' target='_blank'>{}</a>".format(link, _("View Case")) )
def app_to_json(app): return { 'name': app.name, 'version': app.version, 'app_id': app.get_id, 'download_url': absolute_reverse('direct_ccz', args=[domain], params={'app_id': app.get_id}) }
def test_get_value(self): doc = {'external_blobs': {'1234.jpg': {}}, 'photo': '1234.jpg'} result = self.column.get_value('my-domain', '1234', doc, [PathNode(name='form')]) self.assertEqual( result, absolute_reverse('api_form_attachment', args=('my-domain', '1234', '1234.jpg')) )
def get_user_link(self, user): user_link_template = '<a href="%(link)s">%(username)s</a>' from corehq.apps.users.views.mobile import EditCommCareUserView user_link = user_link_template % { "link": absolute_reverse(EditCommCareUserView.urlname, args=[self.domain, user._id]), "username": user.username_in_report } return self.table_cell(user.raw_username, user_link)
def send_overdue_reminders(today=None): from corehq.apps.domain.views import DomainSubscriptionView from corehq.apps.domain.views import DomainBillingStatementsView today = today or datetime.date.today() invoices = Invoice.objects.filter(is_hidden=False, subscription__service_type=SubscriptionType.PRODUCT, date_paid__isnull=True, date_due__lt=today)\ .exclude(subscription__plan_version__plan__edition=SoftwarePlanEdition.ENTERPRISE)\ .order_by('date_due')\ .select_related('subscription__subscriber') domains = set() for invoice in invoices: if invoice.get_domain() not in domains: domains.add(invoice.get_domain()) total = Invoice.objects.filter(is_hidden=False, subscription__subscriber__domain=invoice.get_domain())\ .aggregate(Sum('balance'))['balance__sum'] if total >= 100: domain = Domain.get_by_name(invoice.get_domain()) current_subscription = Subscription.get_subscribed_plan_by_domain(domain)[1] if not current_subscription.skip_auto_downgrade: days_ago = (today - invoice.date_due).days context = { 'domain': invoice.get_domain(), 'total': total, 'subscription_url': absolute_reverse(DomainSubscriptionView.urlname, args=[invoice.get_domain()]), 'statements_url': absolute_reverse(DomainBillingStatementsView.urlname, args=[invoice.get_domain()]), 'date_60': invoice.date_due + datetime.timedelta(days=60), 'contact_email': settings.INVOICING_CONTACT_EMAIL } if days_ago == 61: _downgrade_domain(current_subscription) _send_downgrade_notice(invoice, context) elif days_ago == 58: _send_downgrade_warning(invoice, context) elif days_ago == 30: _send_overdue_notice(invoice, context) elif days_ago == 1: _create_overdue_notification(invoice, context)
def send_activation_email(self): url = absolute_reverse("orgs_accept_invitation", args=[self.organization, self.get_id]) params = {"organization": self.organization, "url": url, "inviter": self.get_inviter().formatted_name} text_content = render_to_string("orgs/email/org_invite.txt", params) html_content = render_to_string("orgs/email/org_invite.html", params) subject = 'Invitation from %s to join CommCareHQ' % self.get_inviter().formatted_name send_HTML_email(subject, self.email, html_content, text_content=text_content, email_from=settings.DEFAULT_FROM_EMAIL)
def _build_remote_request_queries(self): return [ RemoteRequestQuery( url=absolute_reverse('remote_search', args=[self.app.domain]), storage_instance=RESULTS_INSTANCE, template='case', data=self._get_remote_request_query_datums(), prompts=self._build_query_prompts() ) ]
def _build_remote_request_post(self): return RemoteRequestPost( url=absolute_reverse('claim_case', args=[self.domain]), relevant=self.module.search_config.relevant, data=[ QueryData( key='case_id', ref=QuerySessionXPath('case_id').instance(), ), ] )
def test_get_value_excel_format(self): column = MultiMediaExportColumn(item=MultiMediaItem(path=[PathNode(name="form"), PathNode(name="photo")])) result = column.get_value( "my-domain", "1234", {"photo": "1234.jpg"}, [PathNode(name="form")], transform_dates=True ) self.assertEqual( result, '=HYPERLINK("{}?attachment=1234.jpg")'.format( absolute_reverse("download_attachment", args=("my-domain", "1234")) ), )
def test_get_value(self): column = MultiMediaExportColumn(item=MultiMediaItem(path=[PathNode(name="form"), PathNode(name="photo")])) result = column.get_value("my-domain", "1234", {"photo": "1234.jpg"}, [PathNode(name="form")]) self.assertEqual( result, "{}?attachment=1234.jpg".format(absolute_reverse("download_attachment", args=("my-domain", "1234"))) ) result = column.get_value("my-domain", "1234", {"photo": None}, [PathNode(name="form")]) self.assertEqual(result, MISSING_VALUE) result = column.get_value("my-domain", "1234", {"photo": ""}, [PathNode(name="form")]) self.assertEqual(result, "")
def to_json(self, data, options=None): options = options or {} domain = data.pop('domain', None) if not domain: raise Exception('API requires domain to be set! Did you add it in a custom create_response function?') case_type = data.pop('case_type', None) if not case_type: raise Exception( 'API requires case_type to be set! Did you add it in a custom create_response function?' ) api_path = data.pop('api_path', None) if not api_path: raise Exception( 'API requires api_path to be set! Did you add it in a custom create_response function?' ) data = self.to_simple(data, options) data['@odata.context'] = '{}#{}'.format(absolute_reverse('odata_meta', args=[domain]), case_type) next_url = data.pop('meta', {}).get('next') if next_url: data['@odata.nextLink'] = '{}{}{}'.format(get_url_base(), api_path, next_url) # move "objects" to "value" data['value'] = data.pop('objects') # clean properties def _clean_property_name(name): # for whatever ridiculous reason, at least in Tableau, # when these are nested inside an object they can't have underscores in them return name.replace('_', '') for i, case_json in enumerate(data['value']): case_json['properties'] = {_clean_property_name(k): v for k, v in case_json['properties'].items()} case_type_to_properties = get_case_type_to_properties(domain) properties_to_include = [ 'casename', 'casetype', 'dateopened', 'ownerid', 'backendid' ] + case_type_to_properties.get(case_type, []) for value in data['value']: for remove_property in [ 'id', 'indexed_on', 'indices', 'resource_uri', ]: value.pop(remove_property) properties = value.get('properties') for property_name in list(properties): if property_name not in properties_to_include: properties.pop(property_name) return json.dumps(data, cls=DjangoJSONEncoder, sort_keys=True)
def get(self, request, domain): data = { '@odata.context': absolute_reverse('odata_meta', args=[domain]), 'value': [ { 'name': case_type, 'kind': 'EntitySet', 'url': case_type, } for case_type in get_case_types_for_domain_es(domain) ] } return add_odata_headers(JsonResponse(data))
def get_resource_uri(self, bundle_or_obj=None): if isinstance(bundle_or_obj, Bundle): obj = bundle_or_obj.obj elif bundle_or_obj is None: return None else: obj = bundle_or_obj return absolute_reverse('api_dispatch_detail', kwargs={ 'resource_name': self._meta.resource_name, 'domain': obj.domain, 'api_name': self._meta.api_name, 'location_id': obj.location_id })
def test_get_value(self): column = MultiMediaExportColumn( item=MultiMediaItem( path=[PathNode(name='form'), PathNode(name='photo')], ), ) result = column.get_value('my-domain', '1234', {'photo': '1234.jpg'}, [PathNode(name='form')]) self.assertEqual( result, '{}?attachment=1234.jpg'.format( absolute_reverse('download_attachment', args=('my-domain', '1234')) ) )
def setUpClass(cls): super(RemoteAuthTest, cls).setUpClass() cls.master_domain = uuid.uuid4().hex cls.linked_domain = uuid.uuid4().hex cls.domain = create_domain(cls.master_domain) cls.couch_user = WebUser.create(cls.master_domain, "test", "foobar") cls.django_user = cls.couch_user.get_django_user() cls.api_key, _ = ApiKey.objects.get_or_create(user=cls.django_user) cls.auth_headers = {'HTTP_AUTHORIZATION': 'apikey test:%s' % cls.api_key.key} cls.linked_domain_requester = absolute_reverse('domain_homepage', args=[cls.linked_domain]) cls.domain_link = DomainLink.link_domains(cls.linked_domain_requester, cls.master_domain)
def _apply_downgrade_process(oldest_unpaid_invoice, total, today, subscription=None): from corehq.apps.domain.views.accounting import DomainBillingStatementsView, DomainSubscriptionView from corehq.apps.accounting.views import EnterpriseBillingStatementsView context = { 'total': format(total, '7.2f'), 'date_60': oldest_unpaid_invoice.date_due + datetime.timedelta(days=60), 'contact_email': settings.INVOICING_CONTACT_EMAIL } if oldest_unpaid_invoice.is_customer_invoice: domain = oldest_unpaid_invoice.subscriptions.first().subscriber.domain context.update({ 'statements_url': absolute_reverse( EnterpriseBillingStatementsView.urlname, args=[domain]), 'domain_or_account': oldest_unpaid_invoice.account.name }) else: domain = subscription.subscriber.domain context.update({ 'domain': domain, 'subscription_url': absolute_reverse(DomainSubscriptionView.urlname, args=[domain]), 'statements_url': absolute_reverse(DomainBillingStatementsView.urlname, args=[domain]), 'domain_or_account': domain }) days_ago = (today - oldest_unpaid_invoice.date_due).days if days_ago == 61: if not oldest_unpaid_invoice.is_customer_invoice: # We do not automatically downgrade customer invoices _downgrade_domain(subscription) _send_downgrade_notice(oldest_unpaid_invoice, context) elif days_ago == 58: _send_downgrade_warning(oldest_unpaid_invoice, context) elif days_ago == 30: _send_overdue_notice(oldest_unpaid_invoice, context)
def _apply_downgrade_process(subscription, oldest_unpaid_invoice, total, today): from corehq.apps.domain.views.accounting import DomainBillingStatementsView, DomainSubscriptionView days_ago = (today - oldest_unpaid_invoice.date_due).days domain = subscription.subscriber.domain context = { 'domain': domain, 'total': total, 'subscription_url': absolute_reverse(DomainSubscriptionView.urlname, args=[domain]), 'statements_url': absolute_reverse(DomainBillingStatementsView.urlname, args=[domain]), 'date_60': oldest_unpaid_invoice.date_due + datetime.timedelta(days=60), 'contact_email': settings.INVOICING_CONTACT_EMAIL } if days_ago == 61: _downgrade_domain(subscription) _send_downgrade_notice(oldest_unpaid_invoice, context) elif days_ago == 58: _send_downgrade_warning(oldest_unpaid_invoice, context) elif days_ago == 30: _send_overdue_notice(oldest_unpaid_invoice, context) elif days_ago == 1: _create_overdue_notification(oldest_unpaid_invoice, context)
def test_get_value_excel_format(self): doc = {'external_blobs': {'1234.jpg': {}}, 'photo': '1234.jpg'} result = self.column.get_value( 'my-domain', '1234', doc, [PathNode(name='form')], transform_dates=True, ) self.assertEqual( result, '=HYPERLINK("{}")'.format( absolute_reverse('api_form_attachment', args=('my-domain', '1234', '1234.jpg')) ) )
def _send_email(user, report, hash_id): domain = report.domain or user.get_domains()[0] link = absolute_reverse("export_report", args=[domain, str(hash_id), report.export_format]) title = "%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( _(title) % report.name, user.get_email(), _(body) % (report.name, "<a href='%s'>%s</a>" % (link, link)), email_from=settings.DEFAULT_FROM_EMAIL )
def get_url(cls, domain=None, render_as=None, **kwargs): # NOTE: I'm pretty sure this doesn't work if you ever pass in render_as # but leaving as is for now, as it should be obvious as soon as that # breaks something if isinstance(cls, cls): domain = getattr(cls, 'domain') render_as = getattr(cls, 'rendered_as') if render_as is not None and render_as not in cls.dispatcher.allowed_renderings(): raise ValueError('The render_as parameter is not one of the following allowed values: %s' % ', '.join(cls.dispatcher.allowed_renderings())) url_args = [domain] if domain is not None else [] if render_as is not None: url_args.append(render_as+'/') return absolute_reverse(cls.dispatcher.name(), args=url_args + [cls.slug])
def _do_request_to_remote_hq(relative_url, remote_details, linked_domain, params=None, method='get'): """ :param relative_url: Relative URL on remote HQ :param remote_details: RemoteDetails object containing remote URL base and auth details :param linked_domain: Used for permission check on remote system :param params: GET/POST params to include :param method: :return: """ url_base = remote_details.url_base username = remote_details.username api_key = remote_details.api_key full_url = '%s%s' % (url_base, relative_url) headers = { 'HQ-REMOTE-REQUESTER': absolute_reverse('domain_homepage', args=[linked_domain]) } try: response = requests.request( method, full_url, params=params, auth=ApiKeyAuth(username, api_key), headers=headers ) except ConnectionError: notify_exception(None, "Error performing remote app request", details={ 'remote_url': full_url, 'params': params, 'headers': headers }) raise RemoteRequestError() if response.status_code == 401: raise RemoteAuthError(response.status_code) elif response.status_code == 403: raise ActionNotPermitted(response.status_code) elif response.status_code != 200: notify_exception(None, "Error performing remote app request", details={ 'remote_url': full_url, 'response_code': response.status_code, 'params': params }) raise RemoteRequestError(response.status_code) return response
def check_es_index(): """ Verify that the Case and soon to be added XForm Elastic indices are up to date with what's in couch This code is also called in the HQ admin page as well """ es_status = {} es_status.update(check_es_cluster_health()) es_status.update(check_case_es_index()) es_status.update(check_xform_es_index()) es_status.update(check_reportcase_es_index()) es_status.update(check_reportxform_es_index()) do_notify = False message = [] if es_status[CLUSTER_HEALTH] == 'red': do_notify = True message.append("Cluster health is red - something is up with the ES machine") for index in es_status.keys(): if index == CLUSTER_HEALTH: continue pillow_status = es_status[index] if not pillow_status['status']: do_notify = True message.append( "Elasticsearch %s Index Issue: %s" % (index, es_status[index]['message'])) if do_notify: message.append( "This alert can give false alarms due to timing lag, so please double check " + absolute_reverse("system_info") + " and the Elasticsearch Status section to make sure." ) notify_exception(None, message='\n'.join(message))
def send_mobile_experience_reminder(recipient, full_name): url = absolute_reverse("login") params = { "full_name": full_name, "url": url, 'url_prefix': '' if settings.STATIC_CDN else 'http://' + get_site_domain(), } message_plaintext = render_to_string( 'registration/email/mobile_signup_reminder.txt', params) message_html = render_to_string( 'registration/email/mobile_signup_reminder.html', params) subject = ugettext('Visit CommCareHQ on your computer!') try: send_html_email_async.delay(subject, recipient, message_html, text_content=message_plaintext, email_from=settings.DEFAULT_FROM_EMAIL) except Exception: logging.warning( "Can't send email, but the message was:\n%s" % message_plaintext) raise
def _bulk_case_upload_api(request, domain): try: upload_file = request.FILES["file"] case_type = request.POST["case_type"] if not upload_file or not case_type: raise Exception except Exception: raise ImporterError("Invalid POST request. " "Both 'file' and 'case_type' are required") search_field = request.POST.get('search_field', 'case_id') create_new_cases = request.POST.get('create_new_cases') == 'on' if search_field == 'case_id': default_search_column = 'case_id' elif search_field == 'external_id': default_search_column = 'external_id' else: raise ImporterError("Illegal value for search_field: %s" % search_field) search_column = request.POST.get('search_column', default_search_column) name_column = request.POST.get('name_column', 'name') upload_comment = request.POST.get('comment') case_upload, context = _process_file_and_get_upload( upload_file, request, domain) case_upload.check_file() with case_upload.get_spreadsheet() as spreadsheet: columns = spreadsheet.get_header_columns() excel_fields = columns # hide search column and matching case fields from the update list if search_column in excel_fields: excel_fields.remove(search_column) custom_fields = [] case_fields = [] #Create the field arrays for the importer in the same format #as the "Step 2" Web UI from the manual process for f in excel_fields: if f == name_column: custom_fields.append("") case_fields.append("name") else: custom_fields.append(f) case_fields.append("") config = importer_util.ImporterConfig(couch_user_id=request.couch_user._id, excel_fields=excel_fields, case_fields=case_fields, custom_fields=custom_fields, search_column=search_column, case_type=case_type, search_field=search_field, create_new_cases=create_new_cases) case_upload.trigger_upload(domain, config, comment=upload_comment) upload_id = case_upload.upload_id status_url = absolute_reverse('case_importer_upload_status', args=(domain, upload_id)) return json_response({ "code": 200, "message": "success", "status_url": status_url })
def draw_footer(self): width = inches(5.00) left_x = inches(0.5) options = "PAYMENT OPTIONS:" self.canvas.setFontSize(SMALL_FONT_SIZE) options_text = Paragraph(options, ParagraphStyle('')) options_text.wrapOn(self.canvas, width, inches(.12)) options_text.drawOn(self.canvas, left_x, inches(3.5)) self.canvas.setFontSize(DEFAULT_FONT_SIZE) flywire = """<strong>International payments:</strong> Make payments in your local currency via bank transfer or credit card by following this link: <link href='{flywire_link}' color='blue'>{flywire_link}</link><br />""".format( flywire_link="https://wl.flywire.com/?destination=DMG") flywire_text = Paragraph(flywire, ParagraphStyle('')) flywire_text.wrapOn(self.canvas, width, inches(.4)) flywire_text.drawOn(self.canvas, left_x, inches(2.95)) from corehq.apps.domain.views.accounting import DomainBillingStatementsView credit_card = """<strong>Credit card payments (USD)</strong> can be made online here:<br /> <link href='{payment_page}' color='blue'>{payment_page}</link><br />""".format( payment_page=absolute_reverse(DomainBillingStatementsView.urlname, args=[self.project_name])) credit_card_text = Paragraph(credit_card, ParagraphStyle('')) credit_card_text.wrapOn(self.canvas, width, inches(.5)) credit_card_text.drawOn(self.canvas, left_x, inches(2.4)) ach_or_wire = """<strong>ACH or Wire:</strong> If you make payment via ACH or Wire, please make sure to email <font color='blue'>{invoicing_contact_email}</font> so that we can match your payment to the correct invoice. Please include: Invoice No., Project Space, and payment date in the email. <br />""".format( invoicing_contact_email=settings.INVOICING_CONTACT_EMAIL, ) ach_or_wire_text = Paragraph(ach_or_wire, ParagraphStyle('')) ach_or_wire_text.wrapOn(self.canvas, width, inches(.5)) ach_or_wire_text.drawOn(self.canvas, left_x, inches(1.7)) ach_payment_text = """<strong>ACH payment</strong> (preferred over wire payment for transfer in the US):<br /> Bank: {bank_name} Bank Address: {bank_address} Account Number: {account_number} Routing Number or ABA: {routing_number_ach}<br />""".format( bank_name=self.bank_name, bank_address=self.bank_address, account_number=self.account_number, routing_number_ach=self.routing_number_ach) wire_payment_text = """<strong>Wire payment</strong>:<br /> Bank: {bank_name} Bank Address: {bank_address} Account Number: {account_number} Routing Number or ABA: {routing_number_wire} Swift Code: {swift_code}<br/>""".format( bank_name=self.bank_name, bank_address=self.bank_address, account_number=self.account_number, routing_number_wire=self.routing_number_wire, swift_code=self.swift_code) payment_info2 = Paragraph( '\n'.join([ ach_payment_text, wire_payment_text, ]), ParagraphStyle('')) payment_info2.wrapOn(self.canvas, width - inches(0.1), inches(0.9)) payment_info2.drawOn(self.canvas, inches(0.6), inches(0.5))
def _fmt_submission_link(self, submission_id): url = absolute_reverse("render_form_data", args=[self.domain, submission_id]) display_text = _("View Submission") ret = self.table_cell(display_text, '<a href="%s">%s</a>' % (url, display_text)) ret['raw'] = submission_id return ret
def draw_footer(self): from corehq.apps.domain.views import DomainBillingStatementsView totals_x = inches(5.85) line_height = inches(0.25) subtotal_y = inches(3.5) tax_y = subtotal_y - line_height credit_y = tax_y - line_height total_y = credit_y - (line_height * 2) totals_money_x = totals_x + inches(1) self.canvas.setFillColorRGB(*LIGHT_GRAY) self.canvas.rect( inches(5.7), inches(2.3), inches(2.05), inches(0.5), fill=1 ) self.canvas.setFillColorRGB(*BLACK) self.canvas.drawString(totals_x, subtotal_y, "Subtotal:") self.canvas.drawString(totals_x, tax_y, "Tax (%0.2f%%):" % self.tax_rate) self.canvas.drawString(totals_x, credit_y, "Credit:") self.canvas.drawString(totals_x, total_y, "Total:") self.canvas.drawString( totals_money_x, subtotal_y, get_money_str(self.subtotal) ) self.canvas.drawString( totals_money_x, tax_y, get_money_str(self.applied_tax) ) self.canvas.drawString( totals_money_x, credit_y, get_money_str(self.applied_credit) ) self.canvas.drawString( totals_money_x, total_y, get_money_str(self.total) ) self.canvas.setFontSize(SMALL_FONT_SIZE) self.canvas.drawString(inches(5.85), inches(2.1), "Thank you for using CommCare HQ.") self.canvas.setFontSize(DEFAULT_FONT_SIZE) width = inches(5.00) left_x = inches(0.5) options = "PAYMENT OPTIONS:" self.canvas.setFontSize(SMALL_FONT_SIZE) options_text = Paragraph(options, ParagraphStyle('')) options_text.wrapOn(self.canvas, width, inches(.12)) options_text.drawOn(self.canvas, left_x, inches(3.5)) self.canvas.setFontSize(DEFAULT_FONT_SIZE) flywire = """<strong>International payments:</strong> Make payments in your local currency via bank transfer or credit card by following this link: <link href='{flywire_link}' color='blue'>{flywire_link}</link><br />""".format( flywire_link="https://wl.flywire.com/?destination=DMG" ) flywire_text = Paragraph(flywire, ParagraphStyle('')) flywire_text.wrapOn(self.canvas, width, inches(.4)) flywire_text.drawOn(self.canvas, left_x, inches(2.95)) credit_card = """<strong>Credit card payments (USD)</strong> can be made online here:<br /> <link href='{payment_page}' color='blue'>{payment_page}</link><br />""".format( payment_page=absolute_reverse( DomainBillingStatementsView.urlname, args=[self.project_name]) ) credit_card_text = Paragraph(credit_card, ParagraphStyle('')) credit_card_text.wrapOn(self.canvas, width, inches(.5)) credit_card_text.drawOn(self.canvas, left_x, inches(2.4)) ach_or_wire = """<strong>ACH or Wire:</strong> If you make payment via ACH or Wire, please make sure to email <font color='blue'>{invoicing_contact_email}</font> so that we can match your payment to the correct invoice. Please include: Invoice No., Project Space, and payment date in the email. <br />""".format( invoicing_contact_email=settings.INVOICING_CONTACT_EMAIL, ) ach_or_wire_text = Paragraph(ach_or_wire, ParagraphStyle('')) ach_or_wire_text.wrapOn(self.canvas, width, inches(.5)) ach_or_wire_text.drawOn(self.canvas, left_x, inches(1.7)) ach_payment_text = """<strong>ACH payment</strong> (preferred over wire payment for transfer in the US):<br /> Bank: {bank_name} Bank Address: {bank_address} Account Number: {account_number} Routing Number or ABA: {routing_number_ach}<br />""".format( bank_name=self.bank_name, bank_address=self.bank_address, account_number=self.account_number, routing_number_ach=self.routing_number_ach ) wire_payment_text = """<strong>Wire payment</strong>:<br /> Bank: {bank_name} Bank Address: {bank_address} Account Number: {account_number} Routing Number or ABA: {routing_number_wire} Swift Code: {swift_code}<br/>""".format( bank_name=self.bank_name, bank_address=self.bank_address, account_number=self.account_number, routing_number_wire=self.routing_number_wire, swift_code=self.swift_code ) payment_info2 = Paragraph('\n'.join([ ach_payment_text, wire_payment_text, ]), ParagraphStyle('')) payment_info2.wrapOn(self.canvas, width - inches(0.1), inches(0.9)) payment_info2.drawOn(self.canvas, inches(0.6), inches(0.5))
def get_awc_reports_pse(config, month, domain, show_test=False): selected_month = datetime(*month) last_months = (selected_month - relativedelta(months=1)) last_day_of_selected_month = ( selected_month + relativedelta(months=1)) - relativedelta(days=1) map_image_data = DailyAttendanceView.objects.filter( pse_date__range=(selected_month, last_day_of_selected_month), **config).values('awc_name', 'form_location_lat', 'form_location_long', 'image_name', 'doc_id', 'pse_date').order_by('-pse_date') kpi_data_tm = AggAwcMonthly.objects.filter( month=selected_month, **config).values('awc_name').annotate(days_open=Sum('awc_days_open')) kpi_data_lm = AggAwcMonthly.objects.filter( month=last_months, **config).values('awc_name').annotate(days_open=Sum('awc_days_open')) open_count_data = DailyAttendanceView.objects.filter( pse_date__range=(selected_month, last_day_of_selected_month), **config).values('awc_name', 'pse_date').annotate( open_count=Sum('awc_open_count'), ).order_by('pse_date') daily_attendance = DailyAttendanceView.objects.filter( pse_date__range=(selected_month, last_day_of_selected_month), **config).values('awc_name', 'pse_date').annotate( avg_percent=Avg('attended_children_percent'), attended=Sum('attended_children'), eligible=Sum('eligible_children')) if not show_test: map_image_data = apply_exclude(domain, map_image_data) kpi_data_tm = apply_exclude(domain, kpi_data_tm) kpi_data_lm = apply_exclude(domain, kpi_data_lm) open_count_data = apply_exclude(domain, open_count_data) daily_attendance = apply_exclude(domain, daily_attendance) attended_children_chart = {} dates = [ dt for dt in rrule( DAILY, dtstart=selected_month, until=last_day_of_selected_month) ] for date in dates: attended_children_chart[int(date.strftime("%s")) * 1000] = { 'avg_percent': 0, 'attended': 0, 'eligible': 0 } open_count_chart = {} open_count_dates = [ dt for dt in rrule(WEEKLY, dtstart=selected_month, until=last_day_of_selected_month, byweekday=MO) ] for date in open_count_dates: first_day_of_week = date - timedelta(days=date.isoweekday() - 1) milliseconds = int(first_day_of_week.strftime("%s")) * 1000 open_count_chart[milliseconds] = 0 for chart_row in open_count_data: first_day_of_week = chart_row['pse_date'] - timedelta( days=chart_row['pse_date'].isoweekday() - 1) pse_week = int(first_day_of_week.strftime("%s")) * 1000 if pse_week in open_count_chart: open_count_chart[pse_week] += (chart_row['open_count'] or 0) else: open_count_chart[pse_week] = (chart_row['open_count'] or 0) for daily_attendance_row in daily_attendance: pse_day = int(daily_attendance_row['pse_date'].strftime("%s")) * 1000 attended_children_chart[pse_day] = { 'avg_percent': daily_attendance_row['avg_percent'] or 0, 'attended': daily_attendance_row['attended'] or 0, 'eligible': daily_attendance_row['eligible'] or 0 } map_data = {} date_to_image_data = {} for map_row in map_image_data: lat = map_row['form_location_lat'] longitude = map_row['form_location_long'] awc_name = map_row['awc_name'] image_name = map_row['image_name'] doc_id = map_row['doc_id'] pse_date = map_row['pse_date'] if lat and longitude: key = doc_id.replace('-', '') map_data.update({ key: { 'lat': float(lat), 'lng': float(longitude), 'focus': 'true', 'message': awc_name, } }) if image_name: date_str = pse_date.strftime("%d/%m/%Y") date_to_image_data[date_str] = map_row images = [] tmp_image = [] for idx, date in enumerate( rrule(DAILY, dtstart=selected_month, until=last_day_of_selected_month)): date_str = date.strftime("%d/%m/%Y") image_data = date_to_image_data.get(date_str) if image_data: image_name = image_data['image_name'] doc_id = image_data['doc_id'] tmp_image.append({ 'id': idx, 'image': absolute_reverse('icds_image_accessor', args=(domain, doc_id, image_name)), 'date': date_str }) else: tmp_image.append({'id': idx, 'image': None, 'date': date_str}) if (idx + 1) % 4 == 0: images.append(tmp_image) tmp_image = [] if tmp_image: images.append(tmp_image) return { 'kpi': [[{ 'label': _('AWC Days Open'), 'help_text': _((""" Total number of days the AWC is open in the given month. The AWC is expected to be open 6 days a week (Not on Sundays and public holidays) """)), 'percent': percent_increase( 'days_open', kpi_data_tm, kpi_data_lm, ), 'value': get_value(kpi_data_tm, 'days_open'), 'all': '', 'format': 'number', 'frequency': 'month', 'color': 'green' if percent_increase( 'days_open', kpi_data_tm, kpi_data_lm, ) > 0 else 'red', }]], 'charts': [[{ 'key': 'AWC Days Open per week', 'values': sorted([ dict(x=x_val, y=y_val) for x_val, y_val in six.iteritems(open_count_chart) ], key=lambda d: d['x']), "strokeWidth": 2, "classed": "dashed", "color": MapColors.BLUE }], [ { 'key': 'PSE - Daily Attendance', 'values': sorted([ dict(x=x_val, y=y_val['avg_percent'], attended=y_val['attended'], eligible=y_val['eligible']) for x_val, y_val in six.iteritems(attended_children_chart) ], key=lambda d: d['x']), "strokeWidth": 2, "classed": "dashed", "color": MapColors.BLUE }, ]], 'map': { 'markers': map_data, }, 'images': images }
def case_detail_url(self): try: return absolute_reverse('case_details', args=[self.report.domain, self.case_id]) except NoReverseMatch: return None
def _normalize_meta(name, meta): return { 'content_type': meta.content_type, 'length': meta.content_length, 'url': absolute_reverse('api_form_attachment', args=(domain, form_id, name)) }
def get_report_content(self, lang, attach_excel=False): """ Get the report's HTML content as rendered by the static view format. """ try: if self.report is None: return ReportContent( _("The report used to create this scheduled report is no" " longer available on CommCare HQ. Please delete this" " scheduled report and create a new one using an available" " report."), None, ) except Exception: pass from django.http import HttpRequest, QueryDict mock_request = HttpRequest() mock_request.couch_user = self.owner mock_request.user = self.owner.get_django_user() mock_request.domain = self.domain mock_request.couch_user.current_domain = self.domain mock_request.couch_user.language = lang mock_request.method = 'GET' mock_query_string_parts = [self.query_string, 'filterSet=true'] if self.is_configurable_report: mock_query_string_parts.append(urlencode(self.filters, True)) mock_query_string_parts.append( urlencode(self.get_date_range(), True)) mock_request.GET = QueryDict('&'.join(mock_query_string_parts)) # Make sure the request gets processed by PRBAC Middleware CCHQPRBACMiddleware.apply_prbac(mock_request) try: dispatch_func = functools.partial( self._dispatcher.__class__.as_view(), mock_request, **self.view_kwargs) email_response = dispatch_func(render_as='email') if email_response.status_code == 302: return ReportContent( _("We are sorry, but your saved report '%(config_name)s' " "is no longer accessible because the owner %(username)s " "is no longer active.") % { 'config_name': self.name, 'username': self.owner.username }, None, ) return ReportContent( json.loads(email_response.content)['report'], dispatch_func(render_as='excel') if attach_excel else None, ) except PermissionDenied: return ReportContent( _("We are sorry, but your saved report '%(config_name)s' " "is no longer accessible because your subscription does " "not allow Custom Reporting. Please talk to your Project " "Administrator about enabling Custom Reports. If you " "want CommCare HQ to stop sending this message, please " "visit %(saved_reports_url)s to remove this " "Emailed Report.") % { 'config_name': self.name, 'saved_reports_url': absolute_reverse('saved_reports', args=[mock_request.domain]), }, None, ) except Http404: return ReportContent( _("We are sorry, but your saved report '%(config_name)s' " "can not be generated since you do not have the correct permissions. " "Please talk to your Project Administrator about getting permissions for this" "report.") % { 'config_name': self.name, }, None, ) except UnsupportedSavedReportError: return ReportContent( _("We are sorry, but your saved report '%(config_name)s' " "is no longer available. If you think this is a mistake, please report an issue." ) % { 'config_name': self.name, }, None, ) except Exception: notify_exception(None, "Error generating report: {}".format( self.report_slug), details={ 'domain': self.domain, 'user': self.owner.username, 'report': self.report_slug, 'report config': self.get_id }) return ReportContent( _("An error occurred while generating this report."), None)
def case_detail_url(self): try: return absolute_reverse('case_data', args=[self.case['domain'], self.case_id]) except NoReverseMatch: return None
def get_default_domain_url(domain): from corehq.apps.domain.views import DefaultProjectSettingsView return absolute_reverse( DefaultProjectSettingsView.urlname, args=[domain], )
def _send_email(user, report, hash_id, recipient, subject=None): link = absolute_reverse( "export_report", args=[report.domain, str(hash_id), report.export_format]) send_report_download_email(report.name, recipient, link, subject)
def get_awc_reports_pse(config, month, domain, show_test=False): now = datetime.utcnow() last_30_days = (now - relativedelta(days=30)) selected_month = datetime(*month) last_months = (selected_month - relativedelta(months=1)) last_three_months = (selected_month - relativedelta(months=3)) last_day_of_next_month = (selected_month + relativedelta(months=1)) - relativedelta(days=1) map_image_data = DailyAttendanceView.objects.filter( pse_date__range=(last_30_days, now), **config).values('awc_name', 'form_location_lat', 'form_location_long', 'image_name', 'doc_id', 'pse_date').order_by('-pse_date') kpi_data_tm = AggAwcMonthly.objects.filter( month=selected_month, **config).values('awc_name').annotate(days_open=Sum('awc_days_open')) kpi_data_lm = AggAwcMonthly.objects.filter( month=last_months, **config).values('awc_name').annotate(days_open=Sum('awc_days_open')) chart_data = DailyAttendanceView.objects.filter( pse_date__range=(last_three_months, last_day_of_next_month), **config).values( 'awc_name', 'pse_date', 'attended_children_percent').annotate( open_count=Sum('awc_open_count'), ).order_by('pse_date') if not show_test: map_image_data = apply_exclude(domain, map_image_data) kpi_data_tm = apply_exclude(domain, kpi_data_tm) kpi_data_lm = apply_exclude(domain, kpi_data_lm) chart_data = apply_exclude(domain, chart_data) open_count_chart = {} attended_children_chart = {} for chart_row in chart_data: first_day_of_week = chart_row['pse_date'] - timedelta( days=chart_row['pse_date'].isoweekday() - 1) pse_week = int(first_day_of_week.strftime("%s")) * 1000 if pse_week in open_count_chart: open_count_chart[pse_week] += (chart_row['open_count'] or 0) attended_children_chart[pse_week].append( (chart_row['attended_children_percent'] or 0)) else: open_count_chart[pse_week] = (chart_row['open_count'] or 0) attended_children_chart[pse_week] = [ chart_row['attended_children_percent'] or 0 ] map_data = {} date_to_image_data = {} for map_row in map_image_data: lat = map_row['form_location_lat'] long = map_row['form_location_long'] awc_name = map_row['awc_name'] image_name = map_row['image_name'] doc_id = map_row['doc_id'] pse_date = map_row['pse_date'] if lat and long: key = doc_id.replace('-', '') map_data.update({ key: { 'lat': float(lat), 'lng': float(long), 'focus': 'true', 'message': awc_name, } }) if image_name: date_str = pse_date.strftime("%d/%m/%Y") date_to_image_data[date_str] = map_row images = [] tmp_image = [] for idx, date in enumerate(rrule(DAILY, dtstart=last_30_days, until=now)): date_str = date.strftime("%d/%m/%Y") image_data = date_to_image_data.get(date_str) if image_data: image_name = image_data['image_name'] doc_id = image_data['doc_id'] tmp_image.append({ 'id': idx, 'image': absolute_reverse('api_form_attachment', args=(domain, doc_id, image_name)), 'date': date_str }) else: tmp_image.append({'id': idx, 'image': None, 'date': date_str}) if (idx + 1) % 4 == 0: images.append(tmp_image) tmp_image = [] if tmp_image: images.append(tmp_image) return { 'kpi': [[{ 'label': _('AWC Days Open'), 'help_text': _((""" Total number of days the AWC is open in the given month. The AWC is expected to be open 6 days a week (Not on Sundays and public holidays) """)), 'percent': percent_increase( 'days_open', kpi_data_tm, kpi_data_lm, ), 'value': get_value(kpi_data_tm, 'days_open'), 'all': '', 'format': 'number', 'frequency': 'month', 'color': 'green' if percent_increase( 'days_open', kpi_data_tm, kpi_data_lm, ) > 0 else 'red', }]], 'charts': [[{ 'key': 'AWC Days Open per week', 'values': sorted([ dict(x=x_val, y=y_val) for x_val, y_val in open_count_chart.iteritems() ], key=lambda d: d['x']), "strokeWidth": 2, "classed": "dashed", "color": BLUE }], [ { 'key': 'PSE- Average Weekly Attendance', 'values': sorted([ dict(x=x_val, y=(sum(y_val) / len(y_val))) for x_val, y_val in attended_children_chart.iteritems() ], key=lambda d: d['x']), "strokeWidth": 2, "classed": "dashed", "color": BLUE }, ]], 'map': { 'markers': map_data, }, 'images': images }
def get_report_content(self, lang, attach_excel=False): """ Get the report's HTML content as rendered by the static view format. """ from corehq.apps.locations.middleware import LocationAccessMiddleware try: if self.report is None: return ReportContent( _("The report used to create this scheduled report is no" " longer available on CommCare HQ. Please delete this" " scheduled report and create a new one using an available" " report."), None, ) except Exception: pass if getattr(self.report, 'is_deprecated', False): return ReportContent( self.report.deprecation_email_message or _("[DEPRECATED] %s report has been deprecated and will stop working soon. " "Please update your saved reports email settings if needed." % self.report.name ), None, ) mock_request = HttpRequest() mock_request.couch_user = self.owner mock_request.user = self.owner.get_django_user() mock_request.domain = self.domain mock_request.couch_user.current_domain = self.domain mock_request.couch_user.language = lang mock_request.method = 'GET' mock_request.bypass_two_factor = True mock_query_string_parts = [self.query_string, 'filterSet=true'] if self.is_configurable_report: mock_query_string_parts.append(urlencode(self.filters, True)) mock_query_string_parts.append(urlencode(self.get_date_range(), True)) mock_request.GET = QueryDict('&'.join(mock_query_string_parts)) # Make sure the request gets processed by PRBAC Middleware CCHQPRBACMiddleware.apply_prbac(mock_request) LocationAccessMiddleware.apply_location_access(mock_request) try: dispatch_func = functools.partial(self._dispatcher.__class__.as_view(), mock_request, **self.view_kwargs) email_response = dispatch_func(render_as='email') if email_response.status_code == 302: return ReportContent( _( "We are sorry, but your saved report '%(config_name)s' " "is no longer accessible because the owner %(username)s " "is no longer active." ) % { 'config_name': self.name, 'username': self.owner.username }, None, ) try: content_json = json.loads(email_response.content) except ValueError: email_text = email_response.content else: email_text = content_json['report'] excel_attachment = dispatch_func(render_as='excel') if attach_excel else None return ReportContent(email_text, excel_attachment) except PermissionDenied: return ReportContent( _( "We are sorry, but your saved report '%(config_name)s' " "is no longer accessible because your subscription does " "not allow Custom Reporting. Please talk to your Project " "Administrator about enabling Custom Reports. If you " "want CommCare HQ to stop sending this message, please " "visit %(saved_reports_url)s to remove this " "Emailed Report." ) % { 'config_name': self.name, 'saved_reports_url': absolute_reverse( 'saved_reports', args=[mock_request.domain] ), }, None, ) except Http404: return ReportContent( _( "We are sorry, but your saved report '%(config_name)s' " "can not be generated since you do not have the correct permissions. " "Please talk to your Project Administrator about getting permissions for this" "report." ) % { 'config_name': self.name, }, None, ) except UnsupportedSavedReportError: return ReportContent( _( "We are sorry, but your saved report '%(config_name)s' " "is no longer available. If you think this is a mistake, please report an issue." ) % { 'config_name': self.name, }, None, )