forked from GithubBackups/healthchecks
Remove PDF invoice generation bits - these are unlikely to ever be useful in the open source version.
This commit is contained in:
parent
34925f2cdf
commit
accdfb637b
@ -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()
|
@ -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"):
|
||||
|
@ -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")
|
||||
|
@ -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"])
|
@ -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)
|
@ -16,10 +16,6 @@ urlpatterns = [
|
||||
views.payment_method,
|
||||
name="hc-payment-method",
|
||||
),
|
||||
path(
|
||||
"invoice/pdf/<slug:transaction_id>/", 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),
|
||||
]
|
||||
|
@ -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()
|
||||
|
@ -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 %}
|
@ -6,7 +6,6 @@
|
||||
<th>Amount</th>
|
||||
<th>Type</th>
|
||||
<th>Status</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{% for tx in transactions %}
|
||||
<tr {% if tx.type == "credit" %}class="text-muted"{% endif %}>
|
||||
@ -29,12 +28,6 @@
|
||||
</td>
|
||||
<td>{{ tx.type|capfirst }}</td>
|
||||
<td><code>{{ tx.status }}</code></td>
|
||||
<td>
|
||||
{% if tx.type == "credit" %}
|
||||
{% else %}
|
||||
<a href="{% url 'hc-invoice-pdf' tx.id %}">PDF Invoice</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor%}
|
||||
</table>
|
||||
|
Loading…
x
Reference in New Issue
Block a user