First stab at building a PDF for printable claim labels
This commit is contained in:
Родитель
62456ca5e8
Коммит
5422ae73eb
|
@ -0,0 +1,143 @@
|
|||
#!/usr/bin/env python
|
||||
"""Quick and dirty render-to-PDF for badge award claim codes"""
|
||||
|
||||
import logging
|
||||
import urllib
|
||||
import urllib2
|
||||
try:
|
||||
from cStringIO import cStringIO as StringIO
|
||||
except ImportError:
|
||||
from StringIO import StringIO
|
||||
|
||||
from reportlab.pdfgen import canvas
|
||||
from reportlab.lib import pagesizes
|
||||
from reportlab.lib.units import inch
|
||||
from reportlab.platypus import (
|
||||
SimpleDocTemplate, BaseDocTemplate, Paragraph, Spacer, PageBreak,
|
||||
Frame, FrameBreak, PageTemplate, Image, Table)
|
||||
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
||||
from reportlab.rl_config import defaultPageSize
|
||||
from reportlab.lib.units import inch
|
||||
from reportlab.lib.enums import TA_LEFT, TA_CENTER
|
||||
from reportlab.lib import colors
|
||||
|
||||
from django.http import (HttpResponseRedirect, HttpResponse,
|
||||
HttpResponseForbidden, HttpResponseNotFound)
|
||||
|
||||
from django.utils.html import conditional_escape
|
||||
|
||||
|
||||
# Constants hard-coded to print onto Avery 5630 or Avery 5260 labels
|
||||
# TODO: Make formats / templates switchable
|
||||
top_margin = (0.5 * inch)
|
||||
left_margin = (0.1875 * inch)
|
||||
width = 2.52 * inch
|
||||
height = 1.0 * inch
|
||||
vertical_spacing = 0 * inch
|
||||
horizontal_spacing = 0.10 * inch
|
||||
columns = 3
|
||||
rows = 10
|
||||
|
||||
|
||||
def render_claims_to_pdf(request, slug, claim_group, deferred_awards):
|
||||
response = HttpResponse(content_type='application/pdf; charset=utf-8')
|
||||
response['Content-Disposition'] = ('attachment; filename="%s-%s.pdf"' %
|
||||
(slug.encode('utf-8', 'replace'), claim_group))
|
||||
doc = BaseDocTemplate(response, pageSize=pagesizes.letter,
|
||||
topMargin=top_margin, leftMargin=left_margin)
|
||||
|
||||
debug = (request.GET.get('debug', False) is not False)
|
||||
|
||||
# TODO: Turn off the boundaries, once we're done tweaking the layout to
|
||||
# match label sheets
|
||||
# if debug: show_boundary = 1
|
||||
# else: show_boundary = 0
|
||||
show_boundary = 1
|
||||
|
||||
# Build frames for labels in the template
|
||||
frames = []
|
||||
for r_idx in range(0, rows):
|
||||
for c_idx in range(0, columns):
|
||||
frames.append(Frame(
|
||||
left_margin + (c_idx * (width + horizontal_spacing)),
|
||||
doc.height - (r_idx * (height + vertical_spacing)),
|
||||
width, height,
|
||||
leftPadding=0, rightPadding=0,
|
||||
bottomPadding=0, topPadding=0,
|
||||
showBoundary=show_boundary
|
||||
))
|
||||
|
||||
# Add the template to the page.
|
||||
template = PageTemplate(frames=frames)
|
||||
doc.addPageTemplates(template)
|
||||
|
||||
# Build some common styles
|
||||
style = ParagraphStyle(name='normal', alignment=TA_CENTER,
|
||||
fontName='Helvetica', fontSize=9, leading=9)
|
||||
code_style = ParagraphStyle(name='code', alignment=TA_CENTER,
|
||||
fontName='Courier', fontSize=9.5, leading=9.5)
|
||||
|
||||
# Fill out the template with claim codes.
|
||||
items = []
|
||||
for da in deferred_awards:
|
||||
badge = da.badge
|
||||
award_url = request.build_absolute_uri(da.get_claim_url())
|
||||
|
||||
badge_img = StringIO(badge.image.file.read())
|
||||
|
||||
# TODO: Stop abusing the Google Charts API and get our own QR code
|
||||
# baking on premises.
|
||||
try:
|
||||
qr_url = ("http://chart.apis.google.com/chart?%s" %
|
||||
urllib.urlencode({'chs':'%sx%s' % (250, 250),
|
||||
'cht':'qr', 'chl':award_url, 'choe':'UTF-8'}))
|
||||
qr_img = StringIO(urllib2.urlopen(qr_url).read())
|
||||
except Exception, e:
|
||||
return HttpResponse('QR code generation failed: %s' % e,
|
||||
status=500)
|
||||
|
||||
# Build the badge label out as a table...
|
||||
table_data = (
|
||||
(
|
||||
Image(badge_img, 0.6 * inch, 0.6 * inch),
|
||||
Image(qr_img, 0.6 * inch, 0.6 * inch)
|
||||
),
|
||||
(
|
||||
# Use resize_para to shrink the font size as title gets longer.
|
||||
resize_para(badge.title),
|
||||
(
|
||||
resize_para(request.build_absolute_uri('/'),
|
||||
max_width=0.85 * inch),
|
||||
Paragraph(da.claim_code.upper(), code_style),
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
table_style = (
|
||||
('ALIGN', (0,0), (-1,-1), 'CENTER'),
|
||||
)
|
||||
|
||||
if debug:
|
||||
table_style = table_style + (
|
||||
('GRID', (0,0), (-1,-1), 1, colors.black),
|
||||
)
|
||||
|
||||
items.append(Table(table_data, style=table_style))
|
||||
items.append(FrameBreak())
|
||||
|
||||
doc.build(items)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def resize_para(str, max_size=11.0, min_size=2.0, max_width=(0.3125*inch),
|
||||
font_name='Helvetica', alignment=TA_CENTER):
|
||||
size = max_size
|
||||
while size > min_size:
|
||||
para = Paragraph(str, ParagraphStyle(name='Size %s' % size,
|
||||
alignment=alignment, fontName=font_name, fontSize=size,
|
||||
leading=size+0.25))
|
||||
if para.minWidth() <= max_width:
|
||||
break
|
||||
size -= 0.125
|
||||
return para
|
|
@ -22,6 +22,9 @@ urlpatterns = patterns('badger.views',
|
|||
name='badger.award_detail'),
|
||||
url(r'^badge/(?P<slug>[^/]+)/claims/?$', 'manage_claims',
|
||||
name='badger.manage_claims'),
|
||||
url(r'^badge/(?P<slug>[^/]+)/claims/(?P<claim_group>.+)\.pdf$', 'claims_list',
|
||||
kwargs=dict(format='pdf'),
|
||||
name='badger.claims_list_pdf'),
|
||||
url(r'^badge/(?P<slug>[^/]+)/claims/(?P<claim_group>[^/]+)/?$', 'claims_list',
|
||||
name='badger.claims_list'),
|
||||
url(r'^claim/(?P<claim_code>[^/]+)/?$', 'claim_deferred_award',
|
||||
|
|
|
@ -216,13 +216,18 @@ def claim_deferred_award(request, claim_code=None):
|
|||
|
||||
@require_http_methods(['GET', 'POST'])
|
||||
@login_required
|
||||
def claims_list(request, slug, claim_group):
|
||||
def claims_list(request, slug, claim_group, format="html"):
|
||||
badge = get_object_or_404(Badge, slug=slug)
|
||||
if not badge.allows_manage_deferred_awards_by(request.user):
|
||||
return HttpResponseForbidden()
|
||||
|
||||
deferred_awards = badge.get_claim_group(claim_group)
|
||||
|
||||
if format == "pdf":
|
||||
from badger.printing import render_claims_to_pdf
|
||||
return render_claims_to_pdf(request, slug, claim_group,
|
||||
deferred_awards)
|
||||
|
||||
return render_to_response('badger/claims_list.html', dict(
|
||||
badge=badge, claim_group=claim_group,
|
||||
deferred_awards=deferred_awards
|
||||
|
|
Загрузка…
Ссылка в новой задаче