Stripe checkout #104411
@ -144,7 +144,6 @@ class SubscriptionEmailPreviewAdmin(looper.admin.mixins.NoAddDeleteMixin, EmailA
|
||||
'payment_failed',
|
||||
'managed_notification',
|
||||
'subscription_expired',
|
||||
'paypal_subscription_cancelled',
|
||||
):
|
||||
emails.append(self.get_object(request, object_id=mail_name))
|
||||
return emails
|
||||
|
24
poetry.lock
generated
24
poetry.lock
generated
@ -2221,16 +2221,26 @@ diagrams = ["jinja2", "railroad-diagrams"]
|
||||
|
||||
[[package]]
|
||||
name = "pypdf2"
|
||||
version = "1.28.6"
|
||||
version = "3.0.1"
|
||||
description = "A pure-python PDF library capable of splitting, merging, cropping, and transforming PDF files"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7"
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "PyPDF2-1.28.6-py3-none-any.whl", hash = "sha256:d7118f0187153257b1f906dcfcd8236608f4987b6a9999b7c5ad49114706a1ad"},
|
||||
{file = "PyPDF2-1.28.6.tar.gz", hash = "sha256:c0840835d18357b077da05bdad1423f5e29419f318135b6a6542895930dc4905"},
|
||||
{file = "PyPDF2-3.0.1.tar.gz", hash = "sha256:a74408f69ba6271f71b9352ef4ed03dc53a31aa404d29b5d31f53bfecfee1440"},
|
||||
{file = "pypdf2-3.0.1-py3-none-any.whl", hash = "sha256:d16e4205cfee272fbdc0568b68d82be796540b1537508cef59388f839c191928"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
typing_extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}
|
||||
|
||||
[package.extras]
|
||||
crypto = ["PyCryptodome"]
|
||||
dev = ["black", "flit", "pip-tools", "pre-commit (<2.18.0)", "pytest-cov", "wheel"]
|
||||
docs = ["myst_parser", "sphinx", "sphinx_rtd_theme"]
|
||||
full = ["Pillow", "PyCryptodome"]
|
||||
image = ["Pillow"]
|
||||
|
||||
[[package]]
|
||||
name = "python-bidi"
|
||||
version = "0.4.2"
|
||||
@ -2344,7 +2354,7 @@ resolved_reference = "419abd659ae5a4a6cb6ea9b54aa4bde17aefeb5b"
|
||||
name = "pyyaml"
|
||||
version = "6.0"
|
||||
description = "YAML parser and emitter for Python"
|
||||
category = "main"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -2518,7 +2528,7 @@ requests = ">=2.0.1,<3.0.0"
|
||||
name = "responses"
|
||||
version = "0.24.1"
|
||||
description = "A utility library for mocking out the `requests` Python library."
|
||||
category = "main"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
@ -2947,4 +2957,4 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools"
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.8"
|
||||
content-hash = "04753b00e94c929ee66201ce0b11c3119d6ef150ba8e0ca2a6f6c5cf82f49917"
|
||||
content-hash = "386b423472b0adf961feb4bbb54dcb2d1170ca5600c843f7bb92d519235193c1"
|
||||
|
@ -22,7 +22,6 @@ markupsafe = "^1.1.1"
|
||||
meilisearch = "^0.18.0"
|
||||
django-taggit = "^1.3.0"
|
||||
boto3 = "1.18.56"
|
||||
responses = "^0.24.0"
|
||||
attrs = "^19.3.0"
|
||||
Flask = "1.0.3"
|
||||
bleach = "^3.2.1"
|
||||
@ -64,7 +63,8 @@ freezegun = "^1.0.0"
|
||||
django-sslserver = "^0.22"
|
||||
djhtml = "1.4.0"
|
||||
phpserialize = "^1.3"
|
||||
PyPDF2 = "^1.26.0"
|
||||
PyPDF2 = "^3.0.1"
|
||||
responses = "^0.24.0"
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
tblib = "^3.0.0"
|
||||
|
@ -1,116 +0,0 @@
|
||||
{% extends "emails/email_base.html" %}
|
||||
{% load subscriptions %}
|
||||
|
||||
{% block header_logo %}
|
||||
{# have a title instead of the logo with the remote image #}
|
||||
<div style="text-align: center; font-weight: bold;">{{ subject }}</div>
|
||||
{% endblock header_logo %}
|
||||
|
||||
{% block body %}
|
||||
<p>Dear {% firstof user.customer.billing_address.full_name user.full_name user.email %},</p>
|
||||
<p>
|
||||
As you may have heard, Blender Studio's subscription system recently got a new shiny update,
|
||||
more on that in <a href="https://studio.blender.org/blog/subscription-system-update-2021/">the blog post</a>.
|
||||
</p>
|
||||
<p>Due to this update, the old PayPal Subscriptions payment method is no longer supported.</p>
|
||||
<p>
|
||||
This means that PayPal's billing agreement that was used to pay for subscription #{{ subscription.pk }} has been cancelled,
|
||||
and <b>no more charges will be made until subscription's payment method is updated</b>.
|
||||
</p>
|
||||
<p>For this reason, we ask you to update the payment method using the following link:</p>
|
||||
<p style="text-align: center">
|
||||
<a style="
|
||||
text-decoration: none;
|
||||
background-color: #009eff;
|
||||
border-bottom-color: #009eff;
|
||||
border-bottom-left-radius: 8px;
|
||||
border-bottom-right-radius: 8px;
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 0px;
|
||||
border-img-source: none;
|
||||
border-left-color: #009eff;
|
||||
border-left-style: solid;
|
||||
border-left-width: 0px;
|
||||
border-right-color: #009eff;
|
||||
border-right-style: solid;
|
||||
border-right-width: 0px;
|
||||
border-top-color: #009eff;
|
||||
border-top-left-radius: 8px;
|
||||
border-top-right-radius: 8px;
|
||||
border-top-style: solid;
|
||||
border-top-width: 0px;
|
||||
box-sizing: border-box;
|
||||
color: #ffffff;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
line-height: 16px;
|
||||
margin-bottom: 0px;
|
||||
margin-left: 0px;
|
||||
margin-right: 0px;
|
||||
margin-top: 0px;
|
||||
overflow: visible;
|
||||
overflow-x: visible;
|
||||
overflow-y: visible;
|
||||
padding-bottom: 14px;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
padding-top: 14px;
|
||||
text-align: center;
|
||||
text-transform: none;
|
||||
vertical-align: middle;
|
||||
width: auto;" href="{{ site_url }}{% url "subscriptions:payment-method-change" subscription_id=subscription.pk %}">Update payment method</a>
|
||||
</p>
|
||||
<p>There you can choose to use the same PayPal account, however going through the process of updating the payment method is still necessary.</p>
|
||||
|
||||
<h3>Subscription information:</h3>
|
||||
<hr/>
|
||||
<table style="
|
||||
color: #C7C7C7;
|
||||
font-family: 'Lucida Grande', 'Helvetica Neue', 'Helvetica', 'Arial', 'Verdana', sans-serif;
|
||||
">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Subscription #:</td>
|
||||
<td style="padding-left: 1em;">{{ subscription.id }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Renewal type:</td>
|
||||
<td style="padding-left: 1em;">{{ subscription.collection_method }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Renewal period:</td>
|
||||
<td style="padding-left: 1em;">{{ subscription|renewal_period }}</td>
|
||||
</tr>
|
||||
{% with taxable=subscription.taxable %}
|
||||
<tr>
|
||||
<td>Recurring total:</td>
|
||||
<td style="padding-left: 1em;">{{ taxable.price.with_currency_symbol }}</td>
|
||||
</tr>
|
||||
{% endwith %}
|
||||
<tr>
|
||||
<td>Payment method:</td>
|
||||
<td style="padding-left: 1em;">PayPal Billing Agreement {{ billing_agreement_id }} <b>(cancelled)</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Last payment:</td>
|
||||
<td style="padding-left: 1em;">{{ billing_agreement_last_payment_date|date }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Payment due:</td>
|
||||
<td style="padding-left: 1em;">{{ subscription.next_payment|date }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>In case you choose not to update the subscription, it will be cancelled a few weeks after payment due date.</p>
|
||||
|
||||
<p>We hope for your understanding and thank you for your support! 🧡</p>
|
||||
|
||||
<p>
|
||||
--<br />
|
||||
Best regards,<br />
|
||||
|
||||
Blender Studio Team
|
||||
</p>
|
||||
{% endblock body %}
|
@ -1,33 +0,0 @@
|
||||
{% load subscriptions %}Dear {% firstof user.customer.billing_address.full_name user.full_name user.email %},
|
||||
|
||||
As you may have heard, Blender Studio's subscription system recently got a new shiny update,
|
||||
more on that in the blog post https://studio.blender.org/blog/subscription-system-update-2021/ .
|
||||
|
||||
Due to this update, the old PayPal Subscriptions payment method is no longer supported.
|
||||
This means that PayPal's billing agreement that was used to pay for subscription #{{ subscription.pk }} has been cancelled,
|
||||
and no more charges will be made until subscription's payment method is updated.
|
||||
|
||||
For this reason, we ask you to update the payment method using the following link:
|
||||
|
||||
{{ site_url }}{% url "subscriptions:payment-method-change" subscription_id=subscription.pk %}
|
||||
|
||||
There you can choose to use the same PayPal account, however going through the process of updating the payment method is still necessary.
|
||||
|
||||
Subscription information:
|
||||
-------------------------
|
||||
Subscription #: {{ subscription.id }}
|
||||
Renewal type: {{ subscription.collection_method }}
|
||||
Renewal period: {{ subscription|renewal_period }}{% with taxable=subscription.taxable %}
|
||||
Recurring total: {{ taxable.price.with_currency_symbol }}{% endwith %}
|
||||
Payment method: PayPal Billing Agreement {{ billing_agreement_id }} (cancelled)
|
||||
Last payment: {{ billing_agreement_last_payment_date|date }}
|
||||
Payment due: {{ subscription.next_payment|date }}
|
||||
|
||||
In case you choose not to update the subscription, it will be cancelled a few weeks after payment due date.
|
||||
|
||||
We hope for your understanding and thank you for your continued support! 🧡
|
||||
|
||||
--
|
||||
Best regards,
|
||||
|
||||
Blender Studio Team
|
@ -1 +0,0 @@
|
||||
Blender Studio Subscription: Action Required
|
@ -2,7 +2,7 @@ from decimal import Decimal
|
||||
from io import BytesIO
|
||||
from unittest.mock import patch, Mock
|
||||
|
||||
from PyPDF2 import PdfFileReader
|
||||
from PyPDF2 import PdfReader
|
||||
from django.test.testcases import TestCase
|
||||
from django.urls import reverse
|
||||
from freezegun import freeze_time
|
||||
@ -33,9 +33,13 @@ Blender Studio Subscription
|
||||
{expected_team_prefix}Subscription #: {order.subscription_id}
|
||||
Renewal type: Automatic
|
||||
Renewal period: Monthly{expected_team_seats}
|
||||
1 {expected_currency_symbol} {expected_price}{expected_additional_note}
|
||||
Subtotal {expected_currency_symbol} {expected_subtotal}{expected_vat}
|
||||
Total {expected_currency_symbol} {expected_total}'''
|
||||
1
|
||||
{expected_currency_symbol} {expected_price}{expected_additional_note}
|
||||
Subtotal
|
||||
{expected_currency_symbol} {expected_subtotal}{expected_vat}
|
||||
Total
|
||||
{expected_currency_symbol} {expected_total}
|
||||
'''
|
||||
|
||||
|
||||
def _fake_ap_date_format(date) -> str:
|
||||
@ -71,19 +75,10 @@ class TestReceiptPDFView(TestCase):
|
||||
)
|
||||
|
||||
def _extract_text_from_pdf(self, response):
|
||||
pdf = PdfFileReader(BytesIO(response.content))
|
||||
self.assertEqual(1, pdf.getNumPages())
|
||||
pdf_page = pdf.getPage(0)
|
||||
return (
|
||||
# FIXME: PyPDF2 extracts text with a lot of additional newlines
|
||||
pdf_page.extract_text()
|
||||
.replace('\n\n', '\n')
|
||||
.replace('\n ', ' ')
|
||||
.replace('\n:', ':')
|
||||
.replace('\n• \n', ' • ')
|
||||
.replace('\n$ \n', ' $ ')
|
||||
.strip()
|
||||
)
|
||||
pdf = PdfReader(BytesIO(response.content))
|
||||
self.assertEqual(1, len(pdf.pages))
|
||||
pdf_page = pdf.pages[0]
|
||||
return pdf_page.extract_text()
|
||||
|
||||
def test_get_pdf_unpaid_order_not_found(self):
|
||||
unpaid_order = OrderFactory(
|
||||
@ -166,13 +161,13 @@ class TestReceiptPDFView(TestCase):
|
||||
expected_vatin='',
|
||||
expected_external_reference='',
|
||||
expected_date=_fake_ap_date_format(order.paid_at),
|
||||
expected_currency_symbol='•',
|
||||
expected_currency_symbol='€',
|
||||
expected_team_prefix='',
|
||||
expected_team_seats='',
|
||||
expected_price='12.52',
|
||||
expected_additional_note='',
|
||||
expected_subtotal='12.52 (ex. VAT)',
|
||||
expected_vat='\nVAT (19%) • 2.38',
|
||||
expected_vat='\nVAT (19%)\n€ 2.38',
|
||||
expected_total='14.90',
|
||||
),
|
||||
)
|
||||
@ -212,8 +207,7 @@ class TestReceiptPDFView(TestCase):
|
||||
expected_vatin='\nVATIN: DE123456789',
|
||||
expected_external_reference='',
|
||||
expected_date=_fake_ap_date_format(order.paid_at),
|
||||
# FIXME(anna): PyPDF2's extract_text() doesn't extract EUR sign for some reason
|
||||
expected_currency_symbol='•',
|
||||
expected_currency_symbol='€',
|
||||
expected_team_prefix='',
|
||||
expected_team_seats='',
|
||||
expected_price='12.52',
|
||||
@ -263,14 +257,13 @@ class TestReceiptPDFView(TestCase):
|
||||
expected_vatin='\nVATIN: NL123456789',
|
||||
expected_external_reference='',
|
||||
expected_date=_fake_ap_date_format(order.paid_at),
|
||||
# FIXME(anna): PyPDF2's extract_text() doesn't extract EUR sign for some reason
|
||||
expected_currency_symbol='•',
|
||||
expected_currency_symbol='€',
|
||||
expected_team_prefix='',
|
||||
expected_team_seats='',
|
||||
expected_price='12.31',
|
||||
expected_subtotal='12.31 (ex. VAT)',
|
||||
expected_additional_note='',
|
||||
expected_vat='\nVAT (21%) • 2.59',
|
||||
expected_vat='\nVAT (21%)\n€ 2.59',
|
||||
expected_total='14.90',
|
||||
),
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user