Skip to content

Commit 72e7f40

Browse files
committed
render pdf invoice using pdfkit
1 parent 50a56f0 commit 72e7f40

File tree

5 files changed

+64
-24
lines changed

5 files changed

+64
-24
lines changed

notebooks/walkthrough/04-invoicing.ipynb

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@
256256
{
257257
"data": {
258258
"text/plain": [
259-
"'2022-02-22-01'"
259+
"'2022-02-23-01'"
260260
]
261261
},
262262
"execution_count": 8,
@@ -335,7 +335,7 @@
335335
"\n",
336336
"<head>\n",
337337
" <meta charset=\"utf-8\">\n",
338-
" <title>Invoice No. 2022-02-22-01</title>\n",
338+
" <title>Invoice No. 2022-02-23-01</title>\n",
339339
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n",
340340
"\n",
341341
" \n",
@@ -388,8 +388,8 @@
388388
" </tr>\n",
389389
" <tr>\n",
390390
" <td>\n",
391-
" Invoice Date: <strong>2022-02-22</strong><br>\n",
392-
" Invoice Number: <strong>2022-02-22-01</strong>\n",
391+
" Invoice Date: <strong>2022-02-23</strong><br>\n",
392+
" Invoice Number: <strong>2022-02-23-01</strong>\n",
393393
" </td>\n",
394394
" <td>\n",
395395
" </td>\n",
@@ -412,7 +412,7 @@
412412
" <tbody>\n",
413413
" \n",
414414
" <tr>\n",
415-
" <td>2022-02-22</td>\n",
415+
" <td>2022-02-23</td>\n",
416416
" <td>Heating Repair - February 2022</td>\n",
417417
" <td class=\"right\">16</td>\n",
418418
" <td class=\"right\">hour</td>\n",
@@ -441,7 +441,7 @@
441441
" Account No: <strong>BZ99830994950003161565</strong>\n",
442442
" </div>\n",
443443
" </td>\n",
444-
" <td class=\"bold\">2022-03-08</td>\n",
444+
" <td class=\"bold\">2022-03-09</td>\n",
445445
" <td>€152.00</td>\n",
446446
" <td class=\"bold\">€952.00</td>\n",
447447
" </tr>\n",
@@ -556,22 +556,44 @@
556556
"_Your turn:_"
557557
]
558558
},
559+
{
560+
"cell_type": "code",
561+
"execution_count": null,
562+
"id": "8cb0c038-a9ee-4dc4-9288-31fd227a1109",
563+
"metadata": {},
564+
"outputs": [],
565+
"source": []
566+
},
559567
{
560568
"cell_type": "markdown",
561-
"id": "8d877684-d7b8-4f4b-8335-10e65cfc353c",
569+
"id": "bd02559b-8cbd-4692-a21f-39fd771f5475",
562570
"metadata": {},
563571
"source": [
564-
"## Send the Invoice Automatically"
572+
"You can also render the invoice to PDF. For now, this requires the native [wkhtmltopdf](https://wkhtmltopdf.org) tool to be installed."
565573
]
566574
},
567575
{
568576
"cell_type": "code",
569-
"execution_count": null,
570-
"id": "10f1ecd1-ae92-4fa9-836e-3ce51b66af47",
577+
"execution_count": 14,
578+
"id": "4eeb3a78-64ab-4ebf-b69d-6c5b99285b7b",
571579
"metadata": {},
572580
"outputs": [],
573581
"source": [
574-
"my_invoice"
582+
"tuttle.rendering.render_invoice(\n",
583+
" user=app.user, \n",
584+
" invoice=my_invoice,\n",
585+
" style=\"anvil\",\n",
586+
" out_dir=invoice_dir,\n",
587+
" format=\"pdf\"\n",
588+
")"
589+
]
590+
},
591+
{
592+
"cell_type": "markdown",
593+
"id": "8d877684-d7b8-4f4b-8335-10e65cfc353c",
594+
"metadata": {},
595+
"source": [
596+
"## Send the Invoice Automatically"
575597
]
576598
},
577599
{

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ ics
1616
babel
1717
email-validator
1818
loguru
19+
pdfkit

templates/invoice-anvil/web/README.md

Lines changed: 0 additions & 3 deletions
This file was deleted.

templates/invoice-anvil/web/scripts.js

Lines changed: 0 additions & 10 deletions
This file was deleted.

tuttle/rendering.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22

33
from pathlib import Path
44
import shutil
5+
import glob
56

67
import jinja2
78
from babel.numbers import format_currency
89
import pandas
10+
import pdfkit
911

1012
from .model import User, Invoice, Timesheet, Project
1113
from .view import Timeline
@@ -18,6 +20,25 @@ def get_template_path(template_name) -> str:
1820
return template_path
1921

2022

23+
def convert_html_to_pdf(
24+
in_path,
25+
out_path,
26+
css_paths=[],
27+
):
28+
"""_summary_
29+
30+
Args:
31+
source_dir (_type_): _description_
32+
dest_dir (_type_): _description_
33+
"""
34+
try:
35+
pdfkit.from_file(input=in_path, output_path=out_path, css=css_paths)
36+
except OSError:
37+
# Exit with code 1 due to network error: ProtocolUnknownError
38+
# ignore this error since a correct output is produced anyway
39+
pass
40+
41+
2142
def render_invoice(
2243
user: User,
2344
invoice: Invoice,
@@ -87,6 +108,15 @@ def as_percentage(number):
87108
invoice_dir / stylesheet_folder_path,
88109
dirs_exist_ok=True,
89110
)
111+
if format == "pdf":
112+
css_paths = [
113+
path for path in glob.glob(f"{invoice_dir}/**/*.css", recursive=True)
114+
]
115+
convert_html_to_pdf(
116+
in_path=str(invoice_path),
117+
css_paths=css_paths,
118+
out_path=invoice_dir / Path(f"{prefix}.pdf"),
119+
)
90120

91121

92122
def render_timesheet(

0 commit comments

Comments
 (0)