Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prep for #878: move invoice-related QR code from receipt modules to invoice modules #1287

Merged
merged 9 commits into from
Dec 17, 2023
30 changes: 0 additions & 30 deletions apps/common/receipt.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"))

Expand All @@ -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)

Expand Down
38 changes: 37 additions & 1 deletion apps/payments/invoice.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from decimal import Decimal
from io import BytesIO
import logging
import shutil
import os.path
Expand All @@ -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
Expand All @@ -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")
Expand Down
18 changes: 18 additions & 0 deletions tests/_utils.py
Original file line number Diff line number Diff line change
@@ -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
31 changes: 31 additions & 0 deletions tests/test_invoice.py
Original file line number Diff line number Diff line change
@@ -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)
47 changes: 2 additions & 45 deletions tests/test_receipt.py
Original file line number Diff line number Diff line change
@@ -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():
Expand All @@ -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"

Expand Down
Loading