Skip to content

Commit

Permalink
Fix PDF on Django 1.11 (#577)
Browse files Browse the repository at this point in the history
* Fix migration 0043_...

* Use a xhtml2pdf version that is compatible with django 1.8 and 1.11

* Add git to dockerfile in order to install xhtml2pdf

* Pin a released version of xhtml2pdf

* Bump version 0.4.2
  • Loading branch information
vtemian committed Nov 16, 2017
1 parent 7899998 commit 109a036
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 12 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 0.4.1 (2017-11-16)
- Remove django-xhtml2pdf
- Adapt pdf generation for Django 1.8 and 1.11

## 0.4.1 (2017-11-15)
Add deleted customer and id filters on document list endpoint.

Expand Down
7 changes: 4 additions & 3 deletions requirements/common.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ django-model-utils
django-annoying
pytz
PyJWT

# python-dev is required for xhtml2pdf to work
xhtml2pdf
django-xhtml2pdf
xhtml2pdf==0.2b1

pyvat
PyPDF2
furl
html5lib==0.999

cryptography==1.9
sqlparse==0.2.2
django-autocomplete-light==3.2.9
Expand Down
1 change: 0 additions & 1 deletion settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
'django_fsm',
'rest_framework',
'django_filters',
'django_xhtml2pdf',

# Dev tools
# 'django_extensions',
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def read(fname):

setup(
name="django-silver",
version='0.4.1',
version='0.4.2',
description=read('DESCRIPTION'),
long_description=read('README.rst'),
license='Apache 2.0',
Expand Down
1 change: 1 addition & 0 deletions silver/migrations/0043_auto_20171113_1048.py
Original file line number Diff line number Diff line change
Expand Up @@ -309,3 +309,4 @@ class Migration(migrations.Migration):
reverse_sql=""
)
]

10 changes: 8 additions & 2 deletions silver/models/documents/pdf.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import uuid

from django_xhtml2pdf.utils import generate_pdf_template_object
from xhtml2pdf import pisa

from django.conf import settings
from django.core.files.base import ContentFile
Expand All @@ -9,6 +9,8 @@
from django.http import HttpResponse
from django.utils.module_loading import import_string

from silver.utils.pdf import fetch_resources


def get_storage():
storage_settings = getattr(settings, 'SILVER_DOCUMENT_STORAGE', None)
Expand Down Expand Up @@ -37,7 +39,11 @@ def url(self):
def generate(self, template, context, upload=True):
pdf_file_object = HttpResponse(content_type='application/pdf')

generate_pdf_template_object(template, pdf_file_object, context)
html = template.render(context)
pisa.pisaDocument(src=html.encode("UTF-8"),
dest=pdf_file_object,
encoding='UTF-8',
link_callback=fetch_resources)

if not pdf_file_object:
return
Expand Down
19 changes: 14 additions & 5 deletions silver/tests/tasks/test_generate_pdfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
from silver.tasks import generate_pdfs, generate_pdf
from silver.tests.factories import InvoiceFactory, ProformaFactory

from silver.utils.pdf import fetch_resources


@pytest.mark.django_db
def test_generate_pdfs_task(monkeypatch):
Expand Down Expand Up @@ -47,18 +49,21 @@ def test_generate_pdfs_task(monkeypatch):


@pytest.mark.django_db
def test_generate_pdf_task(settings, tmpdir, monkeypatch):
@patch('silver.models.documents.base.BillingDocumentBase.get_template')
@patch('silver.models.documents.pdf.HttpResponse')
def test_generate_pdf_task(mock_http_response, mock_get_template, settings,
tmpdir, monkeypatch):
settings.MEDIA_ROOT = tmpdir.strpath

invoice = InvoiceFactory.create()
invoice.issue()

assert invoice.pdf.dirty

generate_pdf_mock = MagicMock()
pisa_document_mock = MagicMock()

monkeypatch.setattr('silver.models.documents.pdf.generate_pdf_template_object',
generate_pdf_mock)
monkeypatch.setattr('silver.models.documents.pdf.pisa.pisaDocument',
pisa_document_mock)

generate_pdf(invoice.id, invoice.kind)

Expand All @@ -70,4 +75,8 @@ def test_generate_pdf_task(settings, tmpdir, monkeypatch):

assert invoice.pdf.url == settings.MEDIA_URL + invoice.get_pdf_upload_path()

assert generate_pdf_mock.call_count == 1
assert pisa_document_mock.call_count == 1
pisa_document_mock.assert_called_once_with(src=mock_get_template().render().encode('UTF-8'),
dest=mock_http_response(),
encoding='UTF-8',
link_callback=fetch_resources)
33 changes: 33 additions & 0 deletions silver/utils/pdf.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import os

from django.conf import settings


class UnsupportedMediaPathException(Exception):
pass


def fetch_resources(uri, rel):
"""
Callback to allow xhtml2pdf/reportlab to retrieve Images,Stylesheets, etc.
`uri` is the href attribute from the html link element.
`rel` gives a relative path, but it's not used here.
"""
if settings.MEDIA_URL and uri.startswith(settings.MEDIA_URL):
path = os.path.join(settings.MEDIA_ROOT,
uri.replace(settings.MEDIA_URL, ""))
elif settings.STATIC_URL and uri.startswith(settings.STATIC_URL):
path = os.path.join(settings.STATIC_ROOT,
uri.replace(settings.STATIC_URL, ""))
if not os.path.exists(path):
for d in settings.STATICFILES_DIRS:
path = os.path.join(d, uri.replace(settings.STATIC_URL, ""))
if os.path.exists(path):
break
elif uri.startswith("http://") or uri.startswith("https://"):
path = uri
else:
raise UnsupportedMediaPathException('media urls must start with %s or %s' % (
settings.MEDIA_URL, settings.STATIC_URL))

return path

0 comments on commit 109a036

Please sign in to comment.