Stripe checkout #104411

Merged
Anna Sirota merged 61 commits from stripe into main 2024-06-17 18:08:41 +02:00
7 changed files with 38 additions and 186 deletions
Showing only changes of commit b3899a9558 - Show all commits

View File

@ -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
View File

@ -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"

View File

@ -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"

View File

@ -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 %}

View File

@ -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

View File

@ -1 +0,0 @@
Blender Studio Subscription: Action Required

View File

@ -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
@ -23,9 +23,9 @@ Billing Address
E-mail: {order.email}{expected_vatin}
{expected_external_reference}Invoice Number:
{order.number}
Invoice Date:
Invoice Date:
{expected_date}
Payment method:
Payment method:
Product
Quantity
Price
@ -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',
),
)