Attach receipt PDF to "payment successful" email #96850

Closed
Anna Sirota wants to merge 5 commits from attach-pdf-to-email into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
13 changed files with 37 additions and 279 deletions
Showing only changes of commit 0dd3e65c7c - Show all commits

View File

@ -10,7 +10,7 @@ from . import models
import looper.models import looper.models
import looper.signals import looper.signals
from blender_fund_main.utils import absolute_url, is_noreply from blender_fund_main.utils import absolute_url, is_noreply, html_to_text
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -62,8 +62,8 @@ def construct_membership_mail(membership: models.Membership) -> typing.Tuple[str
email_body_html = loader.render_to_string( email_body_html = loader.render_to_string(
f'blender_fund_main/emails/membership_{verb}.html', context) f'blender_fund_main/emails/membership_{verb}.html', context)
email_body_txt = loader.render_to_string( # Generate plain text content from the HTML one
f'blender_fund_main/emails/membership_{verb}.txt', context) email_body_txt = html_to_text(email_body_html)
return email_body_html, email_body_txt, context['subject'] return email_body_html, email_body_txt, context['subject']
@ -110,8 +110,8 @@ def construct_payment_mail(
email_body_html = loader.render_to_string( email_body_html = loader.render_to_string(
f'blender_fund_main/emails/payment_{order.status}.html', context) f'blender_fund_main/emails/payment_{order.status}.html', context)
email_body_txt = loader.render_to_string( # Generate plain text content from the HTML one
f'blender_fund_main/emails/payment_{order.status}.txt', context) email_body_txt = html_to_text(email_body_html)
return email_body_html, email_body_txt, context['subject'] return email_body_html, email_body_txt, context['subject']
@ -141,8 +141,8 @@ def construct_managed_subscription_mail(subscription: looper.models.Subscription
email_body_html = loader.render_to_string( email_body_html = loader.render_to_string(
'blender_fund_main/emails/managed_memb_notif.html', context) 'blender_fund_main/emails/managed_memb_notif.html', context)
email_body_txt = loader.render_to_string( # Generate plain text content from the HTML one
'blender_fund_main/emails/managed_memb_notif.txt', context) email_body_txt = html_to_text(email_body_html)
return email_body_html, email_body_txt, context['subject'] return email_body_html, email_body_txt, context['subject']
@ -182,9 +182,8 @@ def construct_donation_received_mail(order):
email_body_html = loader.render_to_string( email_body_html = loader.render_to_string(
f'blender_fund_main/emails/{verb}.html', context f'blender_fund_main/emails/{verb}.html', context
) )
email_body_txt = loader.render_to_string( # Generate plain text content from the HTML one
f'blender_fund_main/emails/{verb}.txt', context email_body_txt = html_to_text(email_body_html)
)
return email_body_html, email_body_txt, context['subject'] return email_body_html, email_body_txt, context['subject']

View File

@ -1,5 +0,0 @@
{% if link_membership_url %}
One more step: **to manage or cancel this membership**{% if membership.level.bid_badge_name %} and claim your {{ membership.subscription.plan }} badge{% endif %},
follow the link below and sign in with your Blender ID.
{{ link_membership_url }}{% endif %}

View File

@ -1,26 +0,0 @@
{% extends "email_layout.txt" %}
{% block body %}Thank you for donating to the Blender Development Fund!
{% if not user and link_donation_url %}To view your donation receipt {% if order.campaign_set.count %}and to claim your badge {% endif %}follow the link below and sign in with your Blender ID.
{{ link_donation_url }}
{% endif %}
Payment information:
====================
Receipt ID: {{ order.id }}
Amount: {{ order.price.with_currency_symbol_nonocents }}
Payment method: {{ order.payment_method.recognisable_name|capfirst }}
Date: {{ order.paid_at|date:"Y-m-d" }}
Description: {{ order.name }}
Billing information:
====================
{{ order.email }}
{{ order.billing_address|linebreaksbr }}
{% if user and receipt_pdf_url %}
To download PDF of the receipt follow the link below:
{{ receipt_url }}{% endif %}
{% if user and receipts_url %}You can also find this receipt at {{ receipts_url }}{% endif %}
Your donations help dozens of people to work on Blender development, online infrastructure and documentation.
Check our annual reports and the grants overview here: https://fund.blender.org/grants/
{% endblock %}

View File

@ -1,12 +1,14 @@
{% extends "email_layout.html" %} {% extends "email_layout.html" %}
{% block body %} {% block body %}{% spaceless %}
<p> <p>
{{ user.customer.billing_address.full_name }} has a {{ membership.level.name }} membership that just {{ user.customer.billing_address.full_name }} has a {{ membership.level.name }} membership that just
passed its 'next payment' date. passed its 'next payment' date.
</p> </p>
<p>Check out <a href="{{ memb_admin_url }}">the membership</a> and/or <p>
<a href="{{ subs_admin_url }}">the subscription</a> in the Dev Fund admin. See DevFund admin links:
</p>
</p>{% endblock %} <p>
- The Membership: {{ memb_admin_url }}<br/>
- The Subscription: {{ subs_admin_url }}<br/>
</p>
{% endspaceless %}{% endblock %}

View File

@ -1,8 +0,0 @@
{% extends "email_layout.txt" %}
{% block body %}{{ user.customer.billing_address.full_name }} has a {{ membership.level.name }} membership that just
passed its 'next payment' date.
Some Dev Fund admin links:
- The Membership: {{ memb_admin_url }}
- The Subscription: {{ subs_admin_url }}
{% endblock %}

View File

@ -1,3 +0,0 @@
{% extends "email_layout.txt" %}
{% block body %}Your Blender Fund membership was activated! Thanks for your support.
{% include "blender_fund_main/emails/_link_membership_cta.txt" %}{% endblock %}

View File

@ -1,27 +0,0 @@
{% extends "email_layout.txt" %}
{% block body %}Thank you for joining the Blender Development Fund. You chose to pay
for your {{ membership.level.name }} membership by bank transfer, which
means that we will be waiting for you to perform this transfer.
{% include "blender_fund_main/emails/_link_membership_cta.txt" %}
Your membership will be activated as soon as we have handled your bank transfer.
When paying, please mention the following:
Blender Fund Membership subs-{{ subscription.id }}
Please send your payment of {{ subscription.price.with_currency_symbol }} to:
Stichting Blender Foundation
Buikslotermeerplein 161
1025 ET Amsterdam, the Netherlands
Bank: ING Bank
Bijlmerdreef 109
1102 BW Amsterdam, the Netherlands
BIC/Swift code: INGB NL 2A
IBAN: NL45 INGB 0009356121 (for Euro countries)
Tax number NL 8111.66.223
{% endblock %}

View File

@ -1,3 +0,0 @@
{% extends "email_layout.txt" %}
{% block body %}Your Blender Fund membership was deactivated.
{% include "blender_fund_main/emails/_link_membership_cta.txt" %}{% endblock %}

View File

@ -1,10 +0,0 @@
{% extends "email_layout.txt" %}
{% block body %}
Automatic payment of your Blender Development Fund membership failed. We have tried
{{ order.collection_attempts }} times, but none of those attempts was succesful. As a result, we have suspended
your membership for now.
The error we received from the payment provider was: {{ failure_message }}.
{% include "blender_fund_main/emails/_link_membership_cta.txt" %}{% if not link_membership_url %}
To resume your membership, please visit {{ pay_url }}{% endif %}
{% endblock %}

View File

@ -1,11 +0,0 @@
{% extends "email_layout.txt" %}
{% block body %}Automatic payment of your Blender Development Fund membership ({{ order.price.with_currency_symbol }})
was successful. Thank you for your contribution!
{% include "blender_fund_main/emails/_link_membership_cta.txt" %}
You will find the online receipt at {{ receipt_url }}
Your contribution helps dozens of people to work on Blender development, online infrastructure and documentation.
Check our annual reports and the grants overview here: https://fund.blender.org/grants/
In case this transaction was not authorized by you, please contact us by responding to this email. We will refund immediately.
{% endblock %}

View File

@ -1,11 +0,0 @@
{% extends "email_layout.txt" %}
{% block body %}Automatic payment of your Blender Development Fund membership failed. Don't worry, we will
automatically try again soon. This was collection attempt {{ order.collection_attempts }} of {{ maximum_collection_attemps }}. If things still fail
after that, we'll send you another email.
The error we received from the payment provider was: {{ failure_message }}.
{% include "blender_fund_main/emails/_link_membership_cta.txt" %}{% if not link_membership_url %}
For now you can either wait for another automatic try, or visit
{{ pay_url }}
to pay manually.{% endif %}
{% endblock %}

View File

@ -11,41 +11,7 @@ from ..models import Membership
from blender_fund_main.utils import absolute_url, html_to_text from blender_fund_main.utils import absolute_url, html_to_text
import blender_fund_main.tasks as tasks import blender_fund_main.tasks as tasks
expected_mail_body = '''Dear Erik von Namenstein, expected_mail_body = '''Blender Development Fund membership Bank Payment
Thank you for joining the Blender Development Fund. You chose to pay
for your Silver membership by bank transfer, which
means that we will be waiting for you to perform this transfer.
Your membership will be activated as soon as we have handled your bank transfer.
When paying, please mention the following:
Blender Fund Membership subs-1
Please send your payment of  10.00 to:
Stichting Blender Foundation
Buikslotermeerplein 161
1025 ET Amsterdam, the Netherlands
Bank: ING Bank
Bijlmerdreef 109
1102 BW Amsterdam, the Netherlands
BIC/Swift code: INGB NL 2A
IBAN: NL45 INGB 0009356121 (for Euro countries)
Tax number NL 8111.66.223
You can always go to https://example.com/settings/membership/1 to view and update your membership.
--
Kind regards,
Blender Foundation
'''
expected_mail_html_text = '''Blender Development Fund membership Bank Payment
@ -81,50 +47,13 @@ Tax number NL 8111.66.223
You can always go to https://example.com/settings/membership/1 to view and update your membership. You can always go to https://fund.local:8010/settings/membership/1 to view and update your membership.
-- --
Kind regards, Kind regards,
Blender Foundation''' Blender Foundation''' # noqa: E501
expected_mail_w_token_body = '''Dear Erik von Namenstein, expected_mail_w_token_body = '''Blender Development Fund membership Bank Payment
Thank you for joining the Blender Development Fund. You chose to pay
for your Silver membership by bank transfer, which
means that we will be waiting for you to perform this transfer.
One more step: **to manage or cancel this membership** and claim your Silver badge,
follow the link below and sign in with your Blender ID.
https://example.com/link-membership/{token}/
Your membership will be activated as soon as we have handled your bank transfer.
When paying, please mention the following:
Blender Fund Membership subs-1
Please send your payment of  10.00 to:
Stichting Blender Foundation
Buikslotermeerplein 161
1025 ET Amsterdam, the Netherlands
Bank: ING Bank
Bijlmerdreef 109
1102 BW Amsterdam, the Netherlands
BIC/Swift code: INGB NL 2A
IBAN: NL45 INGB 0009356121 (for Euro countries)
Tax number NL 8111.66.223
--
Kind regards,
Blender Foundation
'''
expected_mail_w_token_html_text = '''Blender Development Fund membership Bank Payment
@ -141,7 +70,7 @@ One more step: to manage or cancel this membership and claim your Silver badge,
follow the link below and sign in with your Blender ID. follow the link below and sign in with your Blender ID.
https://example.com/link-membership/{token}/ https://fund.local:8010/link-membership/{token}/
@ -179,7 +108,7 @@ Blender Foundation'''
new=tasks.send_mail_membership_status_changed.task_function, new=tasks.send_mail_membership_status_changed.task_function,
) )
class CheckoutTestCase(AbstractBaseTestCase): class CheckoutTestCase(AbstractBaseTestCase):
fixtures = ['gateways', 'devfund', 'systemuser'] fixtures = ['default_site', 'gateways', 'devfund', 'systemuser']
def setUp(self): def setUp(self):
self.user = User.objects.create_user('explodingchicken', 'chicken@example.com') self.user = User.objects.create_user('explodingchicken', 'chicken@example.com')
@ -233,7 +162,7 @@ class CheckoutTestCase(AbstractBaseTestCase):
self.assertEqual(the_mail.body, expected_mail_body, the_mail.body) self.assertEqual(the_mail.body, expected_mail_body, the_mail.body)
self.assertEqual( self.assertEqual(
html_to_text(alt0_body), html_to_text(alt0_body),
expected_mail_html_text, expected_mail_body,
html_to_text(the_mail.alternatives[0][0]), html_to_text(the_mail.alternatives[0][0]),
) )
@ -262,6 +191,6 @@ class CheckoutTestCase(AbstractBaseTestCase):
self.assertEqual(alt0_type, 'text/html') self.assertEqual(alt0_type, 'text/html')
self.assertEqual( self.assertEqual(
html_to_text(alt0_body), html_to_text(alt0_body),
expected_mail_w_token_html_text.format(token=token), expected_mail_w_token_body.format(token=token),
html_to_text(alt0_body), html_to_text(alt0_body),
) )

View File

@ -20,58 +20,25 @@ import blender_fund_main.tasks as tasks
expected_managed_email_subj = 'Blender Development Fund managed membership needs attention' expected_managed_email_subj = 'Blender Development Fund managed membership needs attention'
expected_managed_email_body = '''Dear admin@example.com, expected_managed_email_body = '''Blender Development Fund managed membership needs attention
Jane Doe has a Silver membership that just
passed its 'next payment' date.
Some Dev Fund admin links:
- The Membership: https://fund.local:8010/admin/blender_fund_main/membership/1/change/
- The Subscription: https://fund.local:8010/admin/looper/subscription/1/change/
--
Kind regards,
Blender Foundation
'''
expected_managed_email_html_stripped = '''Blender Development Fund managed membership needs attention
Dear admin@example.com, Dear admin@example.com,
Jane Doe has a Silver membership that just Jane Doe has a Silver membership that just
passed its 'next payment' date. passed its 'next payment' date.
See DevFund admin links:
Check out https://fund.local:8010/admin/blender_fund_main/membership/1/change/ and/or - The Membership: https://fund.local:8010/admin/blender_fund_main/membership/1/change/
https://fund.local:8010/admin/looper/subscription/1/change/ in the Dev Fund admin. - The Subscription: https://fund.local:8010/admin/looper/subscription/1/change/
-- --
Kind regards, Kind regards,
Blender Foundation''' Blender Foundation'''
expected_soft_failed_email_body = '''Dear Jane Doe, expected_soft_failed_email_body = '''Blender Development Fund: payment failed (but we'll try again)
Automatic payment of your Blender Development Fund membership failed. Don't worry, we will
automatically try again soon. This was collection attempt 1 of 3. If things still fail
after that, we'll send you another email.
The error we received from the payment provider was: fake error message.
For now you can either wait for another automatic try, or visit
https://fund.local:8010/checkout/pay/1
to pay manually.
You can always go to https://fund.local:8010/settings/membership/1 to view and update your membership.
--
Kind regards,
Blender Foundation
''' # noqa: E501
expected_soft_failed_email_html_stripped = '''Blender Development Fund: payment failed (but we'll try again)
@ -102,24 +69,7 @@ You can always go to https://fund.local:8010/settings/membership/1 to view and u
-- --
Kind regards, Kind regards,
Blender Foundation''' # noqa: E501 Blender Foundation''' # noqa: E501
expected_failed_email_body = '''Dear Jane Doe, expected_failed_email_body = '''Blender Development Fund: payment failed
Automatic payment of your Blender Development Fund membership failed. We have tried
3 times, but none of those attempts was succesful. As a result, we have suspended
your membership for now.
The error we received from the payment provider was: fake error message.
To resume your membership, please visit https://fund.local:8010/checkout/pay/1
You can always go to https://fund.local:8010/settings/membership/1 to view and update your membership.
--
Kind regards,
Blender Foundation
''' # noqa: E501
expected_failed_email_html_stripped = '''Blender Development Fund: payment failed
@ -147,25 +97,7 @@ You can always go to https://fund.local:8010/settings/membership/1 to view and u
-- --
Kind regards, Kind regards,
Blender Foundation''' # noqa: E501 Blender Foundation''' # noqa: E501
expected_payment_received_email_body = '''Dear Jane Doe, expected_payment_received_email_body = '''Blender Development Fund: payment received
Automatic payment of your Blender Development Fund membership ( 10.00)
was successful. Thank you for your contribution!
You will find the online receipt at https://fund.local:8010/settings/receipts/1
Your contribution helps dozens of people to work on Blender development, online infrastructure and documentation.
Check our annual reports and the grants overview here: https://fund.blender.org/grants/
In case this transaction was not authorized by you, please contact us by responding to this email. We will refund immediately.
You can always go to https://fund.local:8010/settings/membership/1 to view and update your membership.
--
Kind regards,
Blender Foundation
''' # noqa: E501
expected_payment_received_email_html_stripped = '''Blender Development Fund: payment received
@ -312,7 +244,7 @@ class TestClockEmails(AbstractLooperTestCase):
self.assertEqual(email.body, expected_soft_failed_email_body, email.body) self.assertEqual(email.body, expected_soft_failed_email_body, email.body)
self.assertEqual( self.assertEqual(
html_to_text(email.alternatives[0][0]), html_to_text(email.alternatives[0][0]),
expected_soft_failed_email_html_stripped, expected_soft_failed_email_body,
html_to_text(email.alternatives[0][0]), html_to_text(email.alternatives[0][0]),
) )
self.assertEqual(len(email.attachments), 0) self.assertEqual(len(email.attachments), 0)
@ -377,7 +309,7 @@ class TestClockEmails(AbstractLooperTestCase):
self.assertEqual(email.body, expected_failed_email_body, email.body) self.assertEqual(email.body, expected_failed_email_body, email.body)
self.assertEqual( self.assertEqual(
html_to_text(email.alternatives[0][0]), html_to_text(email.alternatives[0][0]),
expected_failed_email_html_stripped, expected_failed_email_body,
html_to_text(email.alternatives[0][0]), html_to_text(email.alternatives[0][0]),
) )
self.assertEqual(len(email.attachments), 0) self.assertEqual(len(email.attachments), 0)
@ -438,7 +370,7 @@ class TestClockEmails(AbstractLooperTestCase):
self.assertEqual(email.body, expected_payment_received_email_body, email.body) self.assertEqual(email.body, expected_payment_received_email_body, email.body)
self.assertEqual( self.assertEqual(
html_to_text(email.alternatives[0][0]), html_to_text(email.alternatives[0][0]),
expected_payment_received_email_html_stripped, expected_payment_received_email_body,
html_to_text(email.alternatives[0][0]), html_to_text(email.alternatives[0][0]),
) )
self.assertEqual(len(email.attachments), 1) self.assertEqual(len(email.attachments), 1)
@ -484,7 +416,7 @@ class TestClockEmails(AbstractLooperTestCase):
self.assertEqual(email.body, expected_managed_email_body, email.body) self.assertEqual(email.body, expected_managed_email_body, email.body)
self.assertEqual( self.assertEqual(
html_to_text(email.alternatives[0][0]), html_to_text(email.alternatives[0][0]),
expected_managed_email_html_stripped, expected_managed_email_body,
html_to_text(email.alternatives[0][0]), html_to_text(email.alternatives[0][0]),
) )
self.assertEqual(len(email.attachments), 0) self.assertEqual(len(email.attachments), 0)