From accdfb637b047c9d36f23d116c57791598e50d14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C4=93teris=20Caune?= Date: Sun, 15 Sep 2019 18:39:32 +0300 Subject: [PATCH] Remove PDF invoice generation bits - these are unlikely to ever be useful in the open source version. --- hc/payments/invoices.py | 98 ----------------------- hc/payments/models.py | 7 -- hc/payments/tests/test_billing_history.py | 2 +- hc/payments/tests/test_charge_webhook.py | 74 ----------------- hc/payments/tests/test_pdf_invoice.py | 65 --------------- hc/payments/urls.py | 4 - hc/payments/views.py | 48 +---------- templates/payments/address_plain.html | 8 -- templates/payments/billing_history.html | 7 -- 9 files changed, 2 insertions(+), 311 deletions(-) delete mode 100644 hc/payments/invoices.py delete mode 100644 hc/payments/tests/test_charge_webhook.py delete mode 100644 hc/payments/tests/test_pdf_invoice.py delete mode 100644 templates/payments/address_plain.html diff --git a/hc/payments/invoices.py b/hc/payments/invoices.py deleted file mode 100644 index 7edc8bdc..00000000 --- a/hc/payments/invoices.py +++ /dev/null @@ -1,98 +0,0 @@ -# coding: utf-8 - -try: - from reportlab.lib.pagesizes import A4 - from reportlab.lib.units import inch - from reportlab.pdfgen.canvas import Canvas - - W, H = A4 -except ImportError: - # Don't crash if reportlab is not installed. - Canvas = object - - -def f(dt): - return dt.strftime("%b. %-d, %Y") - - -class PdfInvoice(Canvas): - def __init__(self, fileobj): - Canvas.__init__(self, fileobj, pagesize=A4, pageCompression=0) - self.head_y = H - inch * 0.5 - - def linefeed(self): - self.head_y -= inch / 8 - - def text(self, s, align="left", size=10, bold=False): - self.head_y -= inch / 24 - self.linefeed() - self.setFont("Helvetica-Bold" if bold else "Helvetica", size) - - if align == "left": - self.drawString(inch * 0.5, self.head_y, s) - elif align == "right": - self.drawRightString(W - inch * 0.5, self.head_y, s) - elif align == "center": - self.drawCentredString(W / 2, self.head_y, s) - - self.head_y -= inch / 24 - - def hr(self): - self.setLineWidth(inch / 72 / 8) - self.line(inch * 0.5, self.head_y, W - inch * 0.5, self.head_y) - - def row(self, items, align="left", bold=False, size=10): - self.head_y -= inch / 8 - self.linefeed() - - self.setFont("Helvetica-Bold" if bold else "Helvetica", size) - - self.drawString(inch * 0.5, self.head_y, items[0]) - self.drawString(inch * 3.5, self.head_y, items[1]) - self.drawString(inch * 5.5, self.head_y, items[2]) - self.drawRightString(W - inch * 0.5, self.head_y, items[3]) - - self.head_y -= inch / 8 - - def render(self, tx, bill_to): - invoice_id = "MS-HC-%s" % tx.id.upper() - self.setTitle(invoice_id) - - self.text("SIA Monkey See Monkey Do", size=16) - self.linefeed() - self.text("Gaujas iela 4-2") - self.text("Valmiera, LV-4201, Latvia") - self.text("VAT: LV44103100701") - self.linefeed() - - created = f(tx.created_at) - self.text("Date Issued: %s" % created, align="right") - self.text("Invoice Id: %s" % invoice_id, align="right") - self.linefeed() - - self.hr() - self.row(["Description", "Start", "End", tx.currency_iso_code], bold=True) - self.hr() - start = f(tx.subscription_details.billing_period_start_date) - end = f(tx.subscription_details.billing_period_end_date) - if tx.currency_iso_code == "USD": - amount = "$%s" % tx.amount - elif tx.currency_iso_code == "EUR": - amount = "€%s" % tx.amount - else: - amount = "%s %s" % (tx.currency_iso_code, tx.amount) - - self.row(["healthchecks.io paid plan", start, end, amount]) - - self.hr() - self.row(["", "", "", "Total: %s" % amount], bold=True) - self.linefeed() - - self.text("Bill to:", bold=True) - for s in bill_to.split("\n"): - self.text(s.strip()) - - self.linefeed() - - self.showPage() - self.save() diff --git a/hc/payments/models.py b/hc/payments/models.py index c26bc2db..7ff831e8 100644 --- a/hc/payments/models.py +++ b/hc/payments/models.py @@ -173,13 +173,6 @@ class Subscription(models.Model): return self._address - def flattened_address(self): - if self.address_id: - ctx = {"a": self.address, "email": self.user.email} - return render_to_string("payments/address_plain.html", ctx) - else: - return self.user.email - @property def transactions(self): if not hasattr(self, "_tx"): diff --git a/hc/payments/tests/test_billing_history.py b/hc/payments/tests/test_billing_history.py index 16391785..3d758e53 100644 --- a/hc/payments/tests/test_billing_history.py +++ b/hc/payments/tests/test_billing_history.py @@ -23,4 +23,4 @@ class BillingHistoryTestCase(BaseTestCase): self.client.login(username="alice@example.org", password="password") r = self.client.get("/accounts/profile/billing/history/") self.assertContains(r, "123") - self.assertContains(r, "def456") + self.assertContains(r, "456") diff --git a/hc/payments/tests/test_charge_webhook.py b/hc/payments/tests/test_charge_webhook.py deleted file mode 100644 index 7ca3faa3..00000000 --- a/hc/payments/tests/test_charge_webhook.py +++ /dev/null @@ -1,74 +0,0 @@ -from mock import Mock, patch -from unittest import skipIf - -from django.core import mail -from django.utils.timezone import now -from hc.payments.models import Subscription -from hc.test import BaseTestCase - -try: - import reportlab -except ImportError: - reportlab = None - - -class ChargeWebhookTestCase(BaseTestCase): - def setUp(self): - super(ChargeWebhookTestCase, self).setUp() - self.sub = Subscription(user=self.alice) - self.sub.subscription_id = "test-id" - self.sub.customer_id = "test-customer-id" - self.sub.send_invoices = True - self.sub.save() - - self.tx = Mock() - self.tx.id = "abc123" - self.tx.customer_details.id = "test-customer-id" - self.tx.created_at = now() - self.tx.currency_iso_code = "USD" - self.tx.amount = 5 - self.tx.subscription_details.billing_period_start_date = now() - self.tx.subscription_details.billing_period_end_date = now() - - @skipIf(reportlab is None, "reportlab not installed") - @patch("hc.payments.views.Subscription.objects.by_braintree_webhook") - def test_it_works(self, mock_getter): - mock_getter.return_value = self.sub, self.tx - - r = self.client.post("/pricing/charge/") - self.assertEqual(r.status_code, 200) - - # See if email was sent - self.assertEqual(len(mail.outbox), 1) - msg = mail.outbox[0] - self.assertEqual(msg.subject, "Invoice from Mychecks") - self.assertEqual(msg.to, ["alice@example.org"]) - self.assertEqual(msg.attachments[0][0], "MS-HC-ABC123.pdf") - - @patch("hc.payments.views.Subscription.objects.by_braintree_webhook") - def test_it_obeys_send_invoices_flag(self, mock_getter): - mock_getter.return_value = self.sub, self.tx - - self.sub.send_invoices = False - self.sub.save() - - r = self.client.post("/pricing/charge/") - self.assertEqual(r.status_code, 200) - - # It should not send the email - self.assertEqual(len(mail.outbox), 0) - - @skipIf(reportlab is None, "reportlab not installed") - @patch("hc.payments.views.Subscription.objects.by_braintree_webhook") - def test_it_uses_invoice_email(self, mock_getter): - mock_getter.return_value = self.sub, self.tx - - self.sub.invoice_email = "alices_accountant@example.org" - self.sub.save() - - r = self.client.post("/pricing/charge/") - self.assertEqual(r.status_code, 200) - - # See if the email was sent to Alice's accountant: - self.assertEqual(len(mail.outbox), 1) - self.assertEqual(mail.outbox[0].to, ["alices_accountant@example.org"]) diff --git a/hc/payments/tests/test_pdf_invoice.py b/hc/payments/tests/test_pdf_invoice.py deleted file mode 100644 index 64010f0f..00000000 --- a/hc/payments/tests/test_pdf_invoice.py +++ /dev/null @@ -1,65 +0,0 @@ -from mock import Mock, patch -from unittest import skipIf - -from django.utils.timezone import now -from hc.payments.models import Subscription -from hc.test import BaseTestCase - -try: - import reportlab -except ImportError: - reportlab = None - - -class PdfInvoiceTestCase(BaseTestCase): - def setUp(self): - super(PdfInvoiceTestCase, self).setUp() - self.sub = Subscription(user=self.alice) - self.sub.subscription_id = "test-id" - self.sub.customer_id = "test-customer-id" - self.sub.save() - - self.tx = Mock() - self.tx.id = "abc123" - self.tx.customer_details.id = "test-customer-id" - self.tx.created_at = now() - self.tx.currency_iso_code = "USD" - self.tx.amount = 5 - self.tx.subscription_details.billing_period_start_date = now() - self.tx.subscription_details.billing_period_end_date = now() - - @skipIf(reportlab is None, "reportlab not installed") - @patch("hc.payments.models.braintree") - def test_it_works(self, mock_braintree): - mock_braintree.Transaction.find.return_value = self.tx - - self.client.login(username="alice@example.org", password="password") - r = self.client.get("/invoice/pdf/abc123/") - self.assertTrue(b"ABC123" in r.content) - self.assertTrue(b"alice@example.org" in r.content) - - @patch("hc.payments.models.braintree") - def test_it_checks_customer_id(self, mock_braintree): - - tx = Mock() - tx.id = "abc123" - tx.customer_details.id = "test-another-customer-id" - tx.created_at = None - mock_braintree.Transaction.find.return_value = tx - - self.client.login(username="alice@example.org", password="password") - r = self.client.get("/invoice/pdf/abc123/") - self.assertEqual(r.status_code, 403) - - @skipIf(reportlab is None, "reportlab not installed") - @patch("hc.payments.models.braintree") - def test_it_shows_company_data(self, mock): - self.sub.address_id = "aa" - self.sub.save() - - mock.Transaction.find.return_value = self.tx - mock.Address.find.return_value = {"company": "Alice and Partners"} - - self.client.login(username="alice@example.org", password="password") - r = self.client.get("/invoice/pdf/abc123/") - self.assertTrue(b"Alice and Partners" in r.content) diff --git a/hc/payments/urls.py b/hc/payments/urls.py index b72d9ed7..1f72a055 100644 --- a/hc/payments/urls.py +++ b/hc/payments/urls.py @@ -16,10 +16,6 @@ urlpatterns = [ views.payment_method, name="hc-payment-method", ), - path( - "invoice/pdf//", views.pdf_invoice, name="hc-invoice-pdf" - ), path("pricing/update/", views.update, name="hc-update-subscription"), path("pricing/token/", views.token, name="hc-get-client-token"), - path("pricing/charge/", views.charge_webhook), ] diff --git a/hc/payments/views.py b/hc/payments/views.py index d864754f..485b8f97 100644 --- a/hc/payments/views.py +++ b/hc/payments/views.py @@ -1,21 +1,11 @@ -from io import BytesIO - from django.conf import settings from django.contrib import messages from django.contrib.auth.decorators import login_required -from django.http import ( - HttpResponseBadRequest, - HttpResponseForbidden, - JsonResponse, - HttpResponse, -) +from django.http import HttpResponseBadRequest, JsonResponse from django.shortcuts import get_object_or_404, redirect, render -from django.views.decorators.csrf import csrf_exempt from django.views.decorators.http import require_POST from hc.api.models import Check -from hc.lib import emails from hc.payments.forms import InvoiceEmailingForm -from hc.payments.invoices import PdfInvoice from hc.payments.models import Subscription @@ -184,39 +174,3 @@ def billing_history(request): ctx = {"transactions": transactions} return render(request, "payments/billing_history.html", ctx) - - -@login_required -def pdf_invoice(request, transaction_id): - sub, tx = Subscription.objects.by_transaction(transaction_id) - - # Does this transaction belong to a customer we know about? - if sub is None or tx is None: - return HttpResponseForbidden() - - # Does the transaction's customer match the currently logged in user? - if sub.user != request.user and not request.user.is_superuser: - return HttpResponseForbidden() - - response = HttpResponse(content_type="application/pdf") - filename = "MS-HC-%s.pdf" % tx.id.upper() - response["Content-Disposition"] = 'attachment; filename="%s"' % filename - PdfInvoice(response).render(tx, sub.flattened_address()) - return response - - -@csrf_exempt -@require_POST -def charge_webhook(request): - sub, tx = Subscription.objects.by_braintree_webhook(request) - if sub.send_invoices: - filename = "MS-HC-%s.pdf" % tx.id.upper() - - sink = BytesIO() - PdfInvoice(sink).render(tx, sub.flattened_address()) - ctx = {"tx": tx} - - recipient = sub.invoice_email or sub.user.email - emails.invoice(recipient, ctx, filename, sink.getvalue()) - - return HttpResponse() diff --git a/templates/payments/address_plain.html b/templates/payments/address_plain.html deleted file mode 100644 index 0c348c0f..00000000 --- a/templates/payments/address_plain.html +++ /dev/null @@ -1,8 +0,0 @@ -{% if a.company %}{{ a.company }} -{% else %}{{ email }} -{% endif %}{% if a.extended_address %}VAT: {{ a.extended_address }} -{% endif %}{% if a.street_address %}{{ a.street_address }} -{% endif %}{% if a.locality %}{{ a.locality }} -{% endif %}{% if a.region %}{{ a.region }} -{% endif %}{% if a.country_name %}{{ a.country_name }} -{% endif %}{% if a.postal_code %}{{ a.postal_code }}{% endif %} \ No newline at end of file diff --git a/templates/payments/billing_history.html b/templates/payments/billing_history.html index 8e31b7f0..5c263866 100644 --- a/templates/payments/billing_history.html +++ b/templates/payments/billing_history.html @@ -6,7 +6,6 @@ Amount Type Status - {% for tx in transactions %} @@ -29,12 +28,6 @@ {{ tx.type|capfirst }} {{ tx.status }} - - {% if tx.type == "credit" %} - {% else %} - PDF Invoice - {% endif %} - {% endfor%}