diff --git a/apps/common/receipt.py b/apps/common/receipt.py index bc092ecf3..c6b2be005 100644 --- a/apps/common/receipt.py +++ b/apps/common/receipt.py @@ -8,7 +8,6 @@ import barcode from barcode.writer import ImageWriter, SVGWriter import segno -from segno import helpers from main import external_url from models import event_year @@ -105,22 +104,6 @@ def make_qrfile(data, **kwargs): return qrfile -def make_epc_qrfile(payment, **kwargs): - qrfile = io.BytesIO() - # TODO: this isn't currently used. Need to fetch IBAN from payment.recommended_destination - # and name from somewhere - maybe config rather than hard-coding. - qr = helpers.make_epc_qr( - name="FIXME FIXME FIXME", - iban="FIXME FIXME FIXME", - amount=payment.amount, - reference=payment.bankref, - encoding=1, - ) - qr.save(qrfile, **kwargs) - qrfile.seek(0) - return qrfile - - def qrfile_to_svg(qrfile): return Markup(qrfile.getvalue().decode("utf-8")) @@ -138,19 +121,6 @@ def format_inline_qr(data): return qrfile_to_svg(qrfile) -def format_inline_epc_qr(payment): - qrfile = make_epc_qrfile( - payment, - kind="svg", - svgclass=None, - omitsize=True, - xmldecl=False, - svgns=False, - nl=False, - ) - return qrfile_to_svg(qrfile) - - def make_qr_png(url): return make_qrfile(url, kind="png", scale=3) diff --git a/apps/payments/invoice.py b/apps/payments/invoice.py index 412d7fd7c..db941c4c5 100644 --- a/apps/payments/invoice.py +++ b/apps/payments/invoice.py @@ -1,4 +1,5 @@ from decimal import Decimal +from io import BytesIO import logging import shutil import os.path @@ -14,11 +15,13 @@ send_file, ) from flask_login import login_required, current_user +from markupsafe import Markup +from segno import helpers from sqlalchemy.sql.functions import func from wtforms import TextAreaField, SubmitField from main import external_url, db -from ..common.receipt import format_inline_epc_qr, render_pdf +from ..common.receipt import render_pdf from models.product import Product, PriceTier from models.purchase import Purchase from ..common.forms import Form @@ -28,6 +31,39 @@ logger = logging.getLogger(__name__) +def make_epc_qrfile(payment, **kwargs): + qrfile = BytesIO() + # TODO: this isn't currently used. Need to fetch IBAN from payment.recommended_destination + # and name from somewhere - maybe config rather than hard-coding. + qr = helpers.make_epc_qr( + name="EMF Festivals Ltd", + iban=payment.recommended_destination.iban, + amount=payment.amount, + reference=payment.bankref, + encoding=1, + ) + qr.save(qrfile, **kwargs) + qrfile.seek(0) + return qrfile + + +def qrfile_to_svg(qrfile): + return Markup(qrfile.getvalue().decode("utf-8")) + + +def format_inline_epc_qr(payment): + qrfile = make_epc_qrfile( + payment, + kind="svg", + svgclass=None, + omitsize=True, + xmldecl=False, + svgns=False, + nl=False, + ) + return qrfile_to_svg(qrfile) + + class InvoiceForm(Form): company = TextAreaField("Company name") update = SubmitField("Update") diff --git a/tests/_utils.py b/tests/_utils.py new file mode 100644 index 000000000..56fb66662 --- /dev/null +++ b/tests/_utils.py @@ -0,0 +1,18 @@ +from io import BytesIO + +from cairosvg import svg2png +from PIL import Image + + +def render_svg(svg): + # pyzbar fails to decode qr codes under 52x52 and epc qr codes under 72x72 + png = svg2png(bytestring=svg, parent_width=80, parent_height=80) + png_file = BytesIO(png) + image = Image.open(png_file) + + # pillow renders alpha channel black by default + alpha = image.convert("RGBA").split()[-1] + opaque_image = Image.new("RGBA", image.size, "white") + opaque_image.paste(image, mask=alpha) + + return opaque_image diff --git a/tests/test_invoice.py b/tests/test_invoice.py new file mode 100644 index 000000000..8b45f941d --- /dev/null +++ b/tests/test_invoice.py @@ -0,0 +1,31 @@ +from pyzbar.pyzbar import decode + +from apps.payments.invoice import format_inline_epc_qr +from models.payment import BankPayment + +from tests._utils import render_svg + + +def test_format_inline_epc_qr(app): + payment = BankPayment(currency="EUR", amount=10) + + qr_inline = format_inline_epc_qr(payment) + qr_image = render_svg(qr_inline) + + expected = [ + "BCD", + "002", + "1", + "SCT", + "", + "EMF Festivals Ltd", + "GB47LOND11213141516171", + "EUR10", + "", + payment.bankref, + ] + + decoded = decode(qr_image) + assert len(decoded) == 1 + content = decoded[0].data.decode("utf-8") + assert content == "\n".join(expected) diff --git a/tests/test_receipt.py b/tests/test_receipt.py index dfb93fe75..f3a0956b2 100644 --- a/tests/test_receipt.py +++ b/tests/test_receipt.py @@ -1,26 +1,9 @@ -import pytest -import io - -from cairosvg import svg2png from PIL import Image from pyzbar.pyzbar import decode -from apps.common.receipt import format_inline_qr, format_inline_epc_qr, make_qr_png -from models.payment import BankPayment - - -def render_svg(svg): - # pyzbar fails to decode qr codes under 52x52 and epc qr codes under 72x72 - png = svg2png(bytestring=svg, parent_width=80, parent_height=80) - png_file = io.BytesIO(png) - image = Image.open(png_file) - - # pillow renders alpha channel black by default - alpha = image.convert("RGBA").split()[-1] - opaque_image = Image.new("RGBA", image.size, "white") - opaque_image.paste(image, mask=alpha) +from apps.common.receipt import format_inline_qr, make_qr_png - return opaque_image +from tests._utils import render_svg def test_format_inline_qr(): @@ -35,32 +18,6 @@ def test_format_inline_qr(): assert content == data -@pytest.mark.skip -def test_format_inline_epc_qr(): - payment = BankPayment(currency="EUR", amount=10) - - qr_inline = format_inline_epc_qr(payment) - qr_image = render_svg(qr_inline) - - expected = [ - "BCD", - "002", - "1", - "SCT", - "", - "Electromagnetic Field Ltd", - "GB21BARC20716472954433", - "EUR10", - "", - payment.bankref, - ] - - decoded = decode(qr_image) - assert len(decoded) == 1 - content = decoded[0].data.decode("utf-8") - assert content == "\n".join(expected) - - def test_make_qr_png(): data = "https://www.example.org"