@lowdefy/docs 3.22.0 → 3.23.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -0
- package/actions/JsAction.yaml +2 -2
- package/blocks/display/DangerousHtml.yaml +11 -12
- package/blocks/display/DangerousMarkdown.yaml +8 -8
- package/blocks/input/MultipleSelector.yaml +80 -0
- package/blocks/input/Selector.yaml +62 -0
- package/concepts/custom-blocks.yaml +2 -2
- package/concepts/custom-code.yaml +3 -3
- package/concepts/lowdefy-schema.yaml +16 -0
- package/connections/AxiosHttp.yaml +1 -1
- package/deployment/aws-lambda.yaml +2 -2
- package/deployment/docker.yaml +2 -2
- package/head.html +2 -0
- package/howto/generate-csv.yaml.njk +251 -0
- package/howto/generate-pdf.yaml.njk +651 -0
- package/howto/generateCsv/lowdefy.yaml +63 -0
- package/howto/generateCsv/public/csvMake.js +27 -0
- package/howto/generatePdf/inv_template.yaml +200 -0
- package/howto/generatePdf/lowdefy.yaml +116 -0
- package/howto/generatePdf/my_header.html +1 -0
- package/howto/generatePdf/public/logo_example.png +0 -0
- package/howto/generatePdf/public/modules/importUmd.js +7 -0
- package/howto/generatePdf/public/modules/pdfMake.js +7 -0
- package/howto/generatePdf/public/modules/vfs_fonts.js +12 -0
- package/lowdefy.yaml +1 -1
- package/menus.yaml +25 -1
- package/operators/_actions.yaml +1 -1
- package/operators/_change_case.yaml +4 -4
- package/operators/_js.yaml +2 -2
- package/operators/_ref.yaml +16 -8
- package/operators/_switch.yaml +51 -0
- package/package.json +2 -2
- package/pages.yaml +12 -0
- package/public/images/authors/gervwyk.jpeg +0 -0
- package/public/images/authors/sandile.jpeg +0 -0
- package/public/images/howto/header_generate_csv.jpg +0 -0
- package/public/images/howto/header_generate_pdf.jpg +0 -0
- package/public/logo_example.png +0 -0
- package/public/modules/csvMake.js +27 -0
- package/public/modules/importUmd.js +7 -0
- package/public/modules/pdfMake.js +7 -0
- package/public/modules/vfs_fonts.js +12 -0
- package/public/sitemap.xml +216 -201
- package/templates/blocks/exampleTransformer.js +1 -1
- package/templates/blog.yaml.njk +221 -0
- package/templates/footer.yaml.njk +2 -2
- package/tutorial/tutorial-create-page.yaml +1 -1
- package/tutorial/tutorial-start.yaml +1 -1
- package/users/login-and-logout.yaml +2 -2
- package/users/openid-connect.yaml +1 -0
- package/users/protected-pages.yaml +2 -2
- package/users/roles.yaml +2 -2
- package/users/users-introduction.yaml +1 -1
- package/version.yaml +1 -1
|
@@ -0,0 +1,651 @@
|
|
|
1
|
+
# Copyright 2020-2021 Lowdefy, Inc
|
|
2
|
+
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
_ref:
|
|
16
|
+
path: templates/blog.yaml.njk
|
|
17
|
+
vars:
|
|
18
|
+
pageId: generate-pdf-document-from-data
|
|
19
|
+
pageTitle: How to generate PDFs using Lowdefy
|
|
20
|
+
section: How To
|
|
21
|
+
filePath: howto/generate-pdf.yaml
|
|
22
|
+
pageImage: /public/images/howto/header_generate_pdf.jpg
|
|
23
|
+
discussionsLink: https://github.com/lowdefy/lowdefy/discussions/889
|
|
24
|
+
authorProfile: /public/images/authors/gervwyk.jpeg
|
|
25
|
+
authorName: |
|
|
26
|
+
<div>Gerrie van Wyk</div>
|
|
27
|
+
<a href="https://twitter.com/gervwyk">Follow @gervwyk on Twitter</a>
|
|
28
|
+
articleLinks:
|
|
29
|
+
- title: Generate CSV in Lowdefy
|
|
30
|
+
pageId: generate-csv-files-from-data
|
|
31
|
+
content:
|
|
32
|
+
- id: md1
|
|
33
|
+
type: MarkdownWithCode
|
|
34
|
+
properties:
|
|
35
|
+
content: |
|
|
36
|
+
It is possible to extend the functionality of Lowdefy beyond the framework's current capabilities by creating custom blocks, actions or operators. In this how-to example we will create a custom action to generate PDF documents client side or in the browser.
|
|
37
|
+
|
|
38
|
+
The full project folder for this how-to is available at:
|
|
39
|
+
https://github.com/lowdefy/lowdefy/tree/main/packages/docs/howto/generatePdf
|
|
40
|
+
|
|
41
|
+
To see how this works, click this button to generate a PDF of an example invoice that will be discussed in this how-to.
|
|
42
|
+
|
|
43
|
+
- id: pdf_generate_button
|
|
44
|
+
type: Button
|
|
45
|
+
style:
|
|
46
|
+
textAlign: center
|
|
47
|
+
properties:
|
|
48
|
+
title: Generate & Download PDF
|
|
49
|
+
icon: DownloadOutlined
|
|
50
|
+
color: '#6293F8'
|
|
51
|
+
events:
|
|
52
|
+
onMount:
|
|
53
|
+
- id: init_data
|
|
54
|
+
type: SetState
|
|
55
|
+
params:
|
|
56
|
+
invoice:
|
|
57
|
+
id: '0030135'
|
|
58
|
+
account_id: 'A-11344'
|
|
59
|
+
inv_date:
|
|
60
|
+
_date: now
|
|
61
|
+
subtotal: 397.034
|
|
62
|
+
discount: -19.8517
|
|
63
|
+
vat: 59.5551
|
|
64
|
+
total: 436.7374
|
|
65
|
+
balance: 413.2330
|
|
66
|
+
customer:
|
|
67
|
+
name: Service Center
|
|
68
|
+
phone: +123-456-7890
|
|
69
|
+
vat_nmr: 12-333-4567
|
|
70
|
+
address: |
|
|
71
|
+
123 Main St.
|
|
72
|
+
Anytown
|
|
73
|
+
CA
|
|
74
|
+
US
|
|
75
|
+
9999
|
|
76
|
+
services:
|
|
77
|
+
- name: Hosting and Maintannce
|
|
78
|
+
qty: 1
|
|
79
|
+
price: 235.90
|
|
80
|
+
code: X12-33C
|
|
81
|
+
- name: Developer Hours
|
|
82
|
+
qty: 16
|
|
83
|
+
price: 60.345
|
|
84
|
+
code: X12-39A
|
|
85
|
+
- name: Designer Hours
|
|
86
|
+
qty: 4
|
|
87
|
+
price: 40.122
|
|
88
|
+
code: X12-21A
|
|
89
|
+
- name: Project Management
|
|
90
|
+
qty: 2
|
|
91
|
+
price: 60.667
|
|
92
|
+
code: X12-49A
|
|
93
|
+
onClick:
|
|
94
|
+
- id: generate_pdf
|
|
95
|
+
type: JsAction
|
|
96
|
+
params:
|
|
97
|
+
name: pdfMake
|
|
98
|
+
args:
|
|
99
|
+
_ref: howto/generatePdf/inv_template.yaml
|
|
100
|
+
|
|
101
|
+
- id: md2
|
|
102
|
+
type: MarkdownWithCode
|
|
103
|
+
properties:
|
|
104
|
+
content: |
|
|
105
|
+
Now click this button to share this article on Twitter 😉
|
|
106
|
+
- id: twitter_button
|
|
107
|
+
type: Button
|
|
108
|
+
style:
|
|
109
|
+
textAlign: center
|
|
110
|
+
properties:
|
|
111
|
+
title: Share this post
|
|
112
|
+
icon: UploadOutlined
|
|
113
|
+
color: '#6293F8'
|
|
114
|
+
events:
|
|
115
|
+
onClick:
|
|
116
|
+
- id: share_twitter
|
|
117
|
+
type: Link
|
|
118
|
+
params:
|
|
119
|
+
newTab: true
|
|
120
|
+
url: https://twitter.com/intent/tweet?url=https%3A%2F%2Fdocs.lowdefy.com%2Fgenerate-pdf-document-from-data&text=Learn%20to%20generate%20pdf%20documents%20from%20data%20using%20@lowdefy%20-%20an%20open-source%2C%20self-hosted%2C%20low-code%20from%20work%20to%20build%20web%20apps%20and%20internal%20tools%20with%20ease.%20&hashtags=opensource%20%23selfhosted%20%23lowcode%20%23internaltools
|
|
121
|
+
- id: md3
|
|
122
|
+
type: MarkdownWithCode
|
|
123
|
+
properties:
|
|
124
|
+
content: |
|
|
125
|
+
## Generate PDF TLDR;
|
|
126
|
+
|
|
127
|
+
1. Select a client side PDF library and add the JavaScript to your Lowdefy app, we'll be using [pdfMake](https://github.com/bpampuch/pdfmake).
|
|
128
|
+
2. Register a [JsAction](/JsAction) method to generate the PDF document.
|
|
129
|
+
3. Load the custom JavaScript using a script tag.
|
|
130
|
+
4. Add a button with a onClick action to call the generate PDF method.
|
|
131
|
+
5. Define the content of your PDF and add data variables as needed.
|
|
132
|
+
- id: md_vid
|
|
133
|
+
type: DangerousMarkdown
|
|
134
|
+
properties:
|
|
135
|
+
DOMPurifyOptions:
|
|
136
|
+
ADD_TAGS:
|
|
137
|
+
- iframe
|
|
138
|
+
content: |
|
|
139
|
+
<div style="position: relative; padding-bottom: 62.5%; height: 0;"><iframe src="https://www.loom.com/embed/771948a63b0240238d7edb0d0a9a59e7" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;"></iframe></div>
|
|
140
|
+
- id: md2_1
|
|
141
|
+
type: MarkdownWithCode
|
|
142
|
+
properties:
|
|
143
|
+
content: |
|
|
144
|
+
## Background
|
|
145
|
+
|
|
146
|
+
Generating PDFs are often required in workflow applications where data needs to be parsed into a document. These type of documents can be anything from quotes or invoices to contracts or even recipes. Making these documents represent the latest data, or exactly match the desired formatting can be tricky and time consuming. Auto generated PDFs are a great solution.
|
|
147
|
+
|
|
148
|
+
> This how-to assumes that you are already running a Lowdefy app locally in dev mode. If not:
|
|
149
|
+
> 1) Create a empty folder.
|
|
150
|
+
> 2) Open your terminal or cmd and `cd` to your empty folder.
|
|
151
|
+
> 3) Run `npx lowdefy@latest init && npx lowdefy@latest dev` to initialize and start your Lowdefy app development server.
|
|
152
|
+
|
|
153
|
+
## 1. Choosing a open-source PDF library
|
|
154
|
+
|
|
155
|
+
The power of open-source is mind blowing. There are a number of well tested, popular, easy to use and free PDF generating libraries that we can possibly use. We'll be using pdfMake since it is well documented, and simple configuration settings. Some of the popular ones are:
|
|
156
|
+
- [pdfMake](https://github.com/bpampuch/pdfmake)
|
|
157
|
+
- [JsPDF](https://github.com/MrRio/jsPDF)
|
|
158
|
+
- [PDFKit](https://github.com/foliojs/pdfkit)
|
|
159
|
+
- [Puppeteer](https://github.com/puppeteer/puppeteer)
|
|
160
|
+
- [PDF-lib](https://github.com/Hopding/pdf-lib)
|
|
161
|
+
|
|
162
|
+
> If you use open-source libraries to automate your business and save you time, please try to thank the maintainers by contributing where possible or simply providing sponsorship. Look for the sponsorship links usually found in the project readme files.
|
|
163
|
+
|
|
164
|
+
## 2. Register a custom JavaScript Action
|
|
165
|
+
|
|
166
|
+
Lowdefy actions are triggered by page events, like `onClick` when a user clicks a button, or `onEnter` when the page loads. Lowdefy comes with a list of predefined actions, however, sometimes custom code is the best awnser. Let's create a custom action which will generate a PDF based on pdfMake config.
|
|
167
|
+
|
|
168
|
+
1) Create a `public` folder inside your Lowdefy working directory.
|
|
169
|
+
2) Since all content in the `public` folder is served by the Lowdefy server, simply create a `pdfMake.js` file inside the `public` folder.
|
|
170
|
+
3) Add this script to the file and save.
|
|
171
|
+
|
|
172
|
+
###### /public/modules/pdfMake.js
|
|
173
|
+
```js
|
|
174
|
+
import importUmd from './importUmd.js';
|
|
175
|
+
import vfs from './vfs_fonts.js';
|
|
176
|
+
const pdfMake = await importUmd(
|
|
177
|
+
`https://cdn.jsdelivr.net/npm/pdfmake@0.2.2/build/pdfmake.min.js`
|
|
178
|
+
);
|
|
179
|
+
const pdfMakeFn = async (
|
|
180
|
+
context,
|
|
181
|
+
filename,
|
|
182
|
+
docDefinition,
|
|
183
|
+
tableLayouts,
|
|
184
|
+
fonts
|
|
185
|
+
) => {
|
|
186
|
+
await pdfMake
|
|
187
|
+
.createPdf(docDefinition, tableLayouts, fonts, vfs)
|
|
188
|
+
.download(filename);
|
|
189
|
+
};
|
|
190
|
+
window.lowdefy.registerJsAction('pdfMake', pdfMakeFn);
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
This script does a few things, first, it imports [importUmd.js](/public/modules/importUmd.js) and the [vfs_fonts.js](/public/modules/vfs_fonts.js) file also from our `public` folder. Then it loads [pdfMake](https://cdn.jsdelivr.net/npm/pdfmake@0.2.2/build/pdfmake.min.js) from [jsdelivr](https://www.jsdelivr.com/). Then we create an async function `pdfMakeFn` which takes some parameters like the `filename` and `docDefinition` and passes it to pdfMake as it is being called.
|
|
194
|
+
|
|
195
|
+
Finally, it registers the `pdfMakeFn` function as a custom [JsAction](/JsAction) using `window.lowdefy.registerJsAction`. This gives our new method to the Lowdefy logic engine to use.
|
|
196
|
+
|
|
197
|
+
> IMPORTANT: We mentioned two additional files here. [`importUmd.js`](/public/modules/importUmd.js) is a helper function to load umd modules from a source, and [`vfs_fonts.js`](/public/modules/vfs_fonts.js) is a virtualized font which we provide to pdfMake. Download these files and copy them into your `public` folder.
|
|
198
|
+
|
|
199
|
+
## 3. Load the custom JavaScript using a script tag
|
|
200
|
+
|
|
201
|
+
With our JavaScript ready, we need to load the JavaScript onto our page in order for it to be evaluated by the browser.
|
|
202
|
+
|
|
203
|
+
Create a `my_header.html` file inside your project route and add the following HTML:
|
|
204
|
+
|
|
205
|
+
###### /my_header.html
|
|
206
|
+
```html
|
|
207
|
+
<script defer type="module" src="/public/modules/pdfMake.js"></script>
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
This loads the `pdfMake.js` module file into HTML.
|
|
211
|
+
|
|
212
|
+
Also, add the HTML file to your Lowdefy application header. To do this, use the `app.html.appendHead` Lowdefy config property. Your `lowdefy.yaml` file should look something like this:
|
|
213
|
+
|
|
214
|
+
###### /lowdefy.yaml
|
|
215
|
+
```yaml
|
|
216
|
+
name: Generate a PDF
|
|
217
|
+
lowdefy: {{ version }}
|
|
218
|
+
|
|
219
|
+
app:
|
|
220
|
+
html:
|
|
221
|
+
appendHead:
|
|
222
|
+
_ref: my_header.html
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Congratulations 🎉 your custom JSAction is now available in you Lowdefy app and ready to use.
|
|
226
|
+
|
|
227
|
+
Up until this part, this how-to has been very generic and will likely be the same for most apps using pdfMake to generate PDFs.
|
|
228
|
+
|
|
229
|
+
In the next part we'll configure our example app to generate a PDF.
|
|
230
|
+
|
|
231
|
+
## 4. Generate a PDF when a button is clicked
|
|
232
|
+
|
|
233
|
+
Next, we want to add a button to the page, and when the button is clicked, our PDF will be generated and downloaded, client side.
|
|
234
|
+
|
|
235
|
+
Let's make this quick and simple, we'll change our Lowdefy config to:
|
|
236
|
+
|
|
237
|
+
###### /lowdefy.yaml
|
|
238
|
+
```yaml
|
|
239
|
+
name: Generate a PDF
|
|
240
|
+
lowdefy: 3.23.2
|
|
241
|
+
|
|
242
|
+
app:
|
|
243
|
+
html:
|
|
244
|
+
appendHead:
|
|
245
|
+
_ref: my_header.html
|
|
246
|
+
|
|
247
|
+
pages:
|
|
248
|
+
- id: generate-a-pdf
|
|
249
|
+
type: PageHeaderMenu
|
|
250
|
+
blocks:
|
|
251
|
+
- id: generate_pdf_button
|
|
252
|
+
type: Button
|
|
253
|
+
properties:
|
|
254
|
+
title: Download PDF
|
|
255
|
+
icon: DownloadOutlined
|
|
256
|
+
events:
|
|
257
|
+
onClick:
|
|
258
|
+
- id: make_pdf
|
|
259
|
+
type: JsAction
|
|
260
|
+
params:
|
|
261
|
+
name: pdfMake
|
|
262
|
+
args:
|
|
263
|
+
- my_file_name.pdf
|
|
264
|
+
- pageMargins: 50
|
|
265
|
+
defaultStyle:
|
|
266
|
+
fontSize: 10
|
|
267
|
+
content:
|
|
268
|
+
- text: This pdf has been generated with Lowdefy and pdfMake.
|
|
269
|
+
bold: true
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
When you run this app, you'll have a 'Download PDF' button, and when clicked, a pdf will be generated and downloaded. This example should work like the button below.
|
|
273
|
+
|
|
274
|
+
- id: make_pdf_button
|
|
275
|
+
type: Button
|
|
276
|
+
style:
|
|
277
|
+
textAlign: center
|
|
278
|
+
properties:
|
|
279
|
+
title: Download PDF
|
|
280
|
+
icon: DownloadOutlined
|
|
281
|
+
events:
|
|
282
|
+
onClick:
|
|
283
|
+
- id: make_pdf
|
|
284
|
+
type: JsAction
|
|
285
|
+
params:
|
|
286
|
+
name: pdfMake
|
|
287
|
+
args:
|
|
288
|
+
- my_file_name.pdf
|
|
289
|
+
- pageMargins: 50
|
|
290
|
+
defaultStyle:
|
|
291
|
+
fontSize: 10
|
|
292
|
+
content:
|
|
293
|
+
- text: This pdf has been generated with Lowdefy and pdfMake.
|
|
294
|
+
bold: true
|
|
295
|
+
- id: md4
|
|
296
|
+
type: MarkdownWithCode
|
|
297
|
+
properties:
|
|
298
|
+
content: |
|
|
299
|
+
## 4. Define the content of the PDF
|
|
300
|
+
|
|
301
|
+
Finally to demonstrate how powerful this can be, we'll build out our pdfMake config to generate an invoice. In practice we would request the account data from our database and then pass the data to pdfMake when the button is clicked. For this example, we'll just hard code the invoice data and set it to the page state. The full project folder for this example is available at: https://github.com/lowdefy/lowdefy/tree/main/packages/docs/howto/generatePdf
|
|
302
|
+
|
|
303
|
+
###### /lowdefy.yaml
|
|
304
|
+
```yaml
|
|
305
|
+
lowdefy: 3.23.2
|
|
306
|
+
name: Generate PDF from data with Lowdefy
|
|
307
|
+
|
|
308
|
+
app:
|
|
309
|
+
html:
|
|
310
|
+
appendHead:
|
|
311
|
+
_ref: my_header.html
|
|
312
|
+
|
|
313
|
+
pages:
|
|
314
|
+
- id: example
|
|
315
|
+
type: PageHeaderMenu
|
|
316
|
+
properties:
|
|
317
|
+
title: Example
|
|
318
|
+
events:
|
|
319
|
+
onEnter:
|
|
320
|
+
- id: init_data
|
|
321
|
+
type: SetState
|
|
322
|
+
params:
|
|
323
|
+
invoice:
|
|
324
|
+
id: '0030135'
|
|
325
|
+
account_id: 'A-11344'
|
|
326
|
+
inv_date:
|
|
327
|
+
_date: now
|
|
328
|
+
subtotal: 397.034
|
|
329
|
+
discount: -19.8517
|
|
330
|
+
vat: 59.5551
|
|
331
|
+
total: 436.7374
|
|
332
|
+
balance: 413.2330
|
|
333
|
+
customer:
|
|
334
|
+
name: Service Center
|
|
335
|
+
phone: +123-456-7890
|
|
336
|
+
vat_nmr: 12-333-4567
|
|
337
|
+
address: |
|
|
338
|
+
123 Main St.
|
|
339
|
+
Anytown
|
|
340
|
+
CA
|
|
341
|
+
US
|
|
342
|
+
9999
|
|
343
|
+
services:
|
|
344
|
+
- name: Hosting and Maintannce
|
|
345
|
+
qty: 1
|
|
346
|
+
price: 235.90
|
|
347
|
+
code: X12-33C
|
|
348
|
+
- name: Developer Hours
|
|
349
|
+
qty: 16
|
|
350
|
+
price: 60.345
|
|
351
|
+
code: X12-39A
|
|
352
|
+
- name: Designer Hours
|
|
353
|
+
qty: 4
|
|
354
|
+
price: 40.122
|
|
355
|
+
code: X12-21A
|
|
356
|
+
- name: Project Management
|
|
357
|
+
qty: 2
|
|
358
|
+
price: 60.667
|
|
359
|
+
code: X12-49A
|
|
360
|
+
areas:
|
|
361
|
+
content:
|
|
362
|
+
justify: center
|
|
363
|
+
blocks:
|
|
364
|
+
- id: docs_button
|
|
365
|
+
type: Button
|
|
366
|
+
properties:
|
|
367
|
+
size: large
|
|
368
|
+
title: Generate Invoice
|
|
369
|
+
color: '#1890ff'
|
|
370
|
+
events:
|
|
371
|
+
onClick:
|
|
372
|
+
- id: make_pdf
|
|
373
|
+
type: JsAction
|
|
374
|
+
params:
|
|
375
|
+
name: pdfMake
|
|
376
|
+
args:
|
|
377
|
+
_ref: inv_template.yaml
|
|
378
|
+
```
|
|
379
|
+
|
|
380
|
+
Note that we have split out the pdfMake config into a seperate file `inv_template.yaml`. This makes it more readible and the same template used in various parts of our app config. This is implemented using the [`_ref`](/_ref) operator.
|
|
381
|
+
|
|
382
|
+
###### `/inv_template.yaml`
|
|
383
|
+
```yaml
|
|
384
|
+
- _nunjucks:
|
|
385
|
+
on:
|
|
386
|
+
_state: invoice
|
|
387
|
+
template: 'INV-{{ id }}-{{ inv_date | date("DD-MM-YYYY") }}.pdf'
|
|
388
|
+
- pageMargins: [50, 25, 50, 70]
|
|
389
|
+
defaultStyle:
|
|
390
|
+
fontSize: 10
|
|
391
|
+
images:
|
|
392
|
+
logo:
|
|
393
|
+
_string.concat:
|
|
394
|
+
- _location: origin
|
|
395
|
+
- /public/logo_example.png
|
|
396
|
+
footer:
|
|
397
|
+
_function:
|
|
398
|
+
- columns:
|
|
399
|
+
- qr:
|
|
400
|
+
_string.concat:
|
|
401
|
+
- _location: origin
|
|
402
|
+
- /invoice?id="
|
|
403
|
+
- _state: invoice.id
|
|
404
|
+
- '"'
|
|
405
|
+
margin: [50, 0, 0, 0]
|
|
406
|
+
fit: '64'
|
|
407
|
+
- alignment: 'right'
|
|
408
|
+
fontSize: 7
|
|
409
|
+
margin: [0, 0, 50, 0]
|
|
410
|
+
text:
|
|
411
|
+
__nunjucks:
|
|
412
|
+
template: 'Page {{ page }} of {{ total }}'
|
|
413
|
+
on:
|
|
414
|
+
page:
|
|
415
|
+
__args: 0
|
|
416
|
+
total:
|
|
417
|
+
__args: 1
|
|
418
|
+
content:
|
|
419
|
+
- columns:
|
|
420
|
+
- width: 'auto'
|
|
421
|
+
margin: [0, 20, 0, 0]
|
|
422
|
+
stack:
|
|
423
|
+
- fontSize: 9
|
|
424
|
+
text: |
|
|
425
|
+
|
|
426
|
+
- fontSize: 7
|
|
427
|
+
text: |
|
|
428
|
+
Example Services Ltd.
|
|
429
|
+
112 Street Name
|
|
430
|
+
City, State 12345
|
|
431
|
+
Country
|
|
432
|
+
001-AB
|
|
433
|
+
|
|
434
|
+
+00-1234-5566
|
|
435
|
+
info@example.com
|
|
436
|
+
|
|
437
|
+
Vat Number: 444 5555 0000
|
|
438
|
+
|
|
439
|
+
- width: '*'
|
|
440
|
+
text: ' '
|
|
441
|
+
- width: 110
|
|
442
|
+
stack:
|
|
443
|
+
- width: 110
|
|
444
|
+
image: logo
|
|
445
|
+
- margin: [0, 5, 0, 0]
|
|
446
|
+
alignment: right
|
|
447
|
+
fontSize: 7
|
|
448
|
+
text: |
|
|
449
|
+
Example Services Ltd.
|
|
450
|
+
Reg Number: 2001/22224/09
|
|
451
|
+
|
|
452
|
+
- margin: [0, 20, 0, 20]
|
|
453
|
+
text: Customer Invoice
|
|
454
|
+
bold: true
|
|
455
|
+
alignment: center
|
|
456
|
+
fontSize: 14
|
|
457
|
+
- columns:
|
|
458
|
+
- width: 150
|
|
459
|
+
bold: true
|
|
460
|
+
text: |
|
|
461
|
+
INVOICE NUMBER:
|
|
462
|
+
DATE ISSUED:
|
|
463
|
+
ACCOUNT NUMBER:
|
|
464
|
+
- width: '*'
|
|
465
|
+
text:
|
|
466
|
+
_nunjucks:
|
|
467
|
+
template: |
|
|
468
|
+
{{ id }}
|
|
469
|
+
{{ inv_date | date("YYYY/MM/DD") }}
|
|
470
|
+
{{ account_id }}
|
|
471
|
+
on:
|
|
472
|
+
_state: invoice
|
|
473
|
+
- width: 150
|
|
474
|
+
bold: true
|
|
475
|
+
text: |
|
|
476
|
+
CUSTOMER:
|
|
477
|
+
ADDRESS:
|
|
478
|
+
- width: '*'
|
|
479
|
+
text:
|
|
480
|
+
_nunjucks:
|
|
481
|
+
template: |
|
|
482
|
+
{{ customer.name }}
|
|
483
|
+
{{ customer.address }}
|
|
484
|
+
on:
|
|
485
|
+
_state: invoice
|
|
486
|
+
|
|
487
|
+
- layout: 'lightHorizontalLines'
|
|
488
|
+
margin: [0, 10, 0, 0]
|
|
489
|
+
table:
|
|
490
|
+
widths: [70, '*', 70, 70, 70]
|
|
491
|
+
headerRows: 1
|
|
492
|
+
body:
|
|
493
|
+
_json.parse:
|
|
494
|
+
_nunjucks:
|
|
495
|
+
on:
|
|
496
|
+
services:
|
|
497
|
+
_state: invoice.services
|
|
498
|
+
template: |
|
|
499
|
+
[
|
|
500
|
+
[
|
|
501
|
+
{ "text": "ITEM CODE", "bold": true },
|
|
502
|
+
{ "text": "SERVICE", "bold": true },
|
|
503
|
+
{ "text": "UNIT PRICE", "bold": true, "alignment": "right" },
|
|
504
|
+
{ "text": "QTY", "bold": true, "alignment": "right" },
|
|
505
|
+
{ "text": "COST", "bold": true, "alignment": "right" }
|
|
506
|
+
],
|
|
507
|
+
{% for item in services %}
|
|
508
|
+
[
|
|
509
|
+
"{{ loop.index }}: {{ item.code }}",
|
|
510
|
+
"{{ item.name | safe }}",
|
|
511
|
+
{ "text": "{{ ( item.price / item.qty ).toFixed(2) }}", "alignment": "right"},
|
|
512
|
+
{ "text": "{{ item.qty }}", "alignment": "right"},
|
|
513
|
+
{ "text": "{{ item.price.toFixed(2) }}", "alignment": "right"}
|
|
514
|
+
{% if loop.last %} ] {% else %} ], {% endif %}
|
|
515
|
+
{% endfor %}
|
|
516
|
+
]
|
|
517
|
+
- layout: 'headerLineOnly'
|
|
518
|
+
margin: [0, -5, 0, 0]
|
|
519
|
+
table:
|
|
520
|
+
widths: ['*', 70, 70, 70]
|
|
521
|
+
headerRows: 1
|
|
522
|
+
body:
|
|
523
|
+
- - ''
|
|
524
|
+
- ''
|
|
525
|
+
- ''
|
|
526
|
+
- ''
|
|
527
|
+
- - ''
|
|
528
|
+
- alignment: right
|
|
529
|
+
text: 'Subtotal:'
|
|
530
|
+
- ''
|
|
531
|
+
- alignment: right
|
|
532
|
+
text:
|
|
533
|
+
_number.toFixed:
|
|
534
|
+
- _state: invoice.subtotal
|
|
535
|
+
- 2
|
|
536
|
+
- - ''
|
|
537
|
+
- alignment: right
|
|
538
|
+
text: 'Discount (5%):'
|
|
539
|
+
- ''
|
|
540
|
+
- alignment: right
|
|
541
|
+
text:
|
|
542
|
+
_number.toFixed:
|
|
543
|
+
- _state: invoice.discount
|
|
544
|
+
- 2
|
|
545
|
+
- - ''
|
|
546
|
+
- alignment: right
|
|
547
|
+
text: 'VAT (15%):'
|
|
548
|
+
- ''
|
|
549
|
+
- alignment: right
|
|
550
|
+
text:
|
|
551
|
+
_number.toFixed:
|
|
552
|
+
- _state: invoice.vat
|
|
553
|
+
- 2
|
|
554
|
+
- - ''
|
|
555
|
+
- alignment: right
|
|
556
|
+
text: 'Total:'
|
|
557
|
+
- ''
|
|
558
|
+
- alignment: right
|
|
559
|
+
text:
|
|
560
|
+
_number.toFixed:
|
|
561
|
+
- _state: invoice.total
|
|
562
|
+
- 2
|
|
563
|
+
- layout: 'headerLineOnly'
|
|
564
|
+
margin: [0, -5, 0, 0]
|
|
565
|
+
table:
|
|
566
|
+
widths: ['*', 70, 70, 70]
|
|
567
|
+
headerRows: 1
|
|
568
|
+
body:
|
|
569
|
+
- - ''
|
|
570
|
+
- ''
|
|
571
|
+
- ''
|
|
572
|
+
- ''
|
|
573
|
+
- - ''
|
|
574
|
+
- alignment: right
|
|
575
|
+
bold: true
|
|
576
|
+
text: 'BALANCE DUE:'
|
|
577
|
+
- ''
|
|
578
|
+
- alignment: right
|
|
579
|
+
bold: true
|
|
580
|
+
text:
|
|
581
|
+
_number.toFixed:
|
|
582
|
+
- _state: invoice.balance
|
|
583
|
+
- 2
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
The above example will generate a PDF invoice with a logo, a QR code, a footer, a header, a table with the invoice details, and a table with the invoice items. Click the button to see this in action.
|
|
587
|
+
|
|
588
|
+
- id: generate_invoice
|
|
589
|
+
type: Button
|
|
590
|
+
style:
|
|
591
|
+
textAlign: center
|
|
592
|
+
properties:
|
|
593
|
+
title: Generate Invoice
|
|
594
|
+
icon: DownloadOutlined
|
|
595
|
+
color: '#6293F8'
|
|
596
|
+
events:
|
|
597
|
+
onMount:
|
|
598
|
+
- id: init_data
|
|
599
|
+
type: SetState
|
|
600
|
+
params:
|
|
601
|
+
invoice:
|
|
602
|
+
id: '0030135'
|
|
603
|
+
account_id: 'A-11344'
|
|
604
|
+
inv_date:
|
|
605
|
+
_date: now
|
|
606
|
+
subtotal: 397.034
|
|
607
|
+
discount: -19.8517
|
|
608
|
+
vat: 59.5551
|
|
609
|
+
total: 436.7374
|
|
610
|
+
balance: 413.2330
|
|
611
|
+
customer:
|
|
612
|
+
name: Service Center
|
|
613
|
+
phone: +123-456-7890
|
|
614
|
+
vat_nmr: 12-333-4567
|
|
615
|
+
address: |
|
|
616
|
+
123 Main St.
|
|
617
|
+
Anytown
|
|
618
|
+
CA
|
|
619
|
+
US
|
|
620
|
+
9999
|
|
621
|
+
services:
|
|
622
|
+
- name: Hosting and Maintannce
|
|
623
|
+
qty: 1
|
|
624
|
+
price: 235.90
|
|
625
|
+
code: X12-33C
|
|
626
|
+
- name: Developer Hours
|
|
627
|
+
qty: 16
|
|
628
|
+
price: 60.345
|
|
629
|
+
code: X12-39A
|
|
630
|
+
- name: Designer Hours
|
|
631
|
+
qty: 4
|
|
632
|
+
price: 40.122
|
|
633
|
+
code: X12-21A
|
|
634
|
+
- name: Project Management
|
|
635
|
+
qty: 2
|
|
636
|
+
price: 60.667
|
|
637
|
+
code: X12-49A
|
|
638
|
+
onClick:
|
|
639
|
+
- id: generate_pdf
|
|
640
|
+
type: JsAction
|
|
641
|
+
params:
|
|
642
|
+
name: pdfMake
|
|
643
|
+
args:
|
|
644
|
+
_ref: howto/generatePdf/inv_template.yaml
|
|
645
|
+
- id: md5
|
|
646
|
+
type: MarkdownWithCode
|
|
647
|
+
properties:
|
|
648
|
+
content: |
|
|
649
|
+
## Conclusion
|
|
650
|
+
|
|
651
|
+
This how-to aims to demonstrate how easy custom JsActions in Lowdefy can be. With Lowdefy's ability to reference data and use JavaScript libraries like [pdfMake](https://github.com/bpampuch/pdfmake), Lowdefy becomes a superpower capable of even generating advanced PDFs with ease. Check out the project folder for this how-to and why not give it a try: https://github.com/lowdefy/lowdefy/tree/main/packages/docs/howto/generatePdf
|