@ -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() |
@ -23,4 +23,4 @@ class BillingHistoryTestCase(BaseTestCase): | |||
self.client.login(username="[email protected]", 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, ["[email protected]"]) | |||
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 = "[email protected]" | |||
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, ["[email protected]"]) |
@ -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="[email protected]", password="password") | |||
r = self.client.get("/invoice/pdf/abc123/") | |||
self.assertTrue(b"ABC123" in r.content) | |||
self.assertTrue(b"[email protected]" 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="[email protected]", 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="[email protected]", password="password") | |||
r = self.client.get("/invoice/pdf/abc123/") | |||
self.assertTrue(b"Alice and Partners" in r.content) |
@ -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 %} |