paint-brush
Cách tạo ứng dụng web lập hóa đơn PDF bằng NodeJS và Foxit PDF SDKtừ tác giả@foxitsoftware
8,192 lượt đọc
8,192 lượt đọc

Cách tạo ứng dụng web lập hóa đơn PDF bằng NodeJS và Foxit PDF SDK

từ tác giả Foxit Software9m2023/06/23
Read on Terminal Reader

dài quá đọc không nổi

Lập hóa đơn kỹ thuật số đã trở thành một thông lệ phổ biến trong các ngành công nghiệp khác nhau. Các nhà phát triển ứng dụng web thường phải đối mặt với nhiệm vụ tạo và gửi hóa đơn PDF theo chương trình. Thư viện __PDF của Foxit cung cấp giải pháp nhanh chóng và an toàn để tạo tệp PDF. Trong hướng dẫn này, chúng tôi sẽ hướng dẫn bạn quy trình xây dựng một ứng dụng web cho phép bộ phận thanh toán của bạn quản lý hóa đơn chưa thanh toán một cách hiệu quả.
featured image - Cách tạo ứng dụng web lập hóa đơn PDF bằng NodeJS và Foxit PDF SDK
Foxit Software HackerNoon profile picture
0-item
1-item


Tạo hóa đơn thanh toán là một khía cạnh quan trọng của bất kỳ doanh nghiệp nào và lập hóa đơn kỹ thuật số đã trở thành một thông lệ phổ biến trong các ngành khác nhau. Trong bối cảnh này, các nhà phát triển ứng dụng web thường phải đối mặt với nhiệm vụ tạo và gửi hóa đơn PDF theo chương trình.


Cho dù bạn đang tự động hóa quy trình tạo và thông báo Hóa đơn hay phát triển Giao diện người dùng đồ họa (GUI) để chủ động nhắc nhở khách hàng về các Hóa đơn chưa thanh toán, thách thức kỹ thuật ban đầu nằm ở việc tạo Hóa đơn PDF. Mặc dù bạn có thể phát triển tập lệnh tùy chỉnh để tạo PDF, nhưng đó sẽ là một công việc quan trọng. Mặc dù các dịch vụ dựa trên web thuận tiện nhưng chúng có thể không phù hợp nếu bạn có thỏa thuận bảo mật với khách hàng của mình vì việc gửi dữ liệu đến dịch vụ của bên thứ ba qua internet có thể gây ra mối lo ngại.


May mắn thay, Foxit's thư viện PDF cung cấp một giải pháp nhanh chóng và an toàn để tạo các tệp PDF. Bằng cách sử dụng của họ Trình chuyển đổi HTML sang PDF , bạn có thể chuyển đổi bất kỳ tài liệu HTML nào, kể cả Hóa đơn, thành tệp PDF có thể được đính kèm vào email hoặc cung cấp cho khách hàng tải xuống từ ứng dụng web của bạn.


Hướng dẫn này sẽ hướng dẫn bạn qua quá trình tạo một Node.js ứng dụng tận dụng Foxit PDF SDK để tạo Hóa đơn PDF từ Hóa đơn HTML trong ứng dụng web. Sau khi được tạo, bạn sẽ sử dụng Nodemailer để gửi Hóa đơn qua SMTP đến địa chỉ email của khách hàng. Bạn có thể làm theo các bước được nêu dưới đây hoặc truy cập cơ sở mã hoàn chỉnh trên kho lưu trữ GitHub của Foxit .


Xây dựng ứng dụng web để tạo và gửi hóa đơn PDF

Trong hướng dẫn này, chúng tôi sẽ hướng dẫn bạn quy trình xây dựng một ứng dụng web cho phép bộ phận thanh toán của bạn quản lý các hóa đơn chưa thanh toán một cách hiệu quả. Bạn sẽ tạo nhiều tính năng khác nhau, bao gồm công cụ nội bộ để theo dõi, trang hiển thị hóa đơn chưa thanh toán và trang xem trước cho từng Hóa đơn. Người dùng sẽ có tùy chọn gửi email nhắc nhở cho khách hàng bằng Hóa đơn đính kèm.


Đối với dự án này, chúng tôi sẽ sử dụng Thể hiện khung web, CSS thuần túy để tạo kiểu, và Nodemailer cho chức năng email.


điều kiện tiên quyết:


Tạo ứng dụng Express mới

Để tạo một ứng dụng web bản soạn sẵn Express mới, bạn cần sử dụng trình tạo ứng dụng :


 npx express-generator --git --view=hbs


Thao tác này sẽ tạo một ứng dụng web có tệp .gitignore tay lái tập tin mẫu.

Tiếp theo, bạn cần thêm gói npm Nodemailer và cài đặt các phụ thuộc Express':


 npm i nodemailer && npm i


Ứng dụng mặc định do Express tạo ra cung cấp cho bạn hai tệp định tuyến: /routes/index.js/routes/users.js . Xóa định tuyến users.js và tạo một tệp định tuyến mới có tên là invoices.js . Thêm route mới này vào tệp app.js của bạn và xóa usersRoute :


 ... var indexRouter = require('./routes/index'); var invoicesRouter = require('./routes/invoices'); var app = express(); ... app.use('/', indexRouter); app.use('/invoices', invoicesRouter); ...


Phần lớn công việc trong ứng dụng này nằm trong bộ định tuyến hóa đơn.


Trước khi tạo tuyến đường, bạn sẽ cần một số dữ liệu có thể sử dụng. Trong ứng dụng thực tế, bạn có thể sẽ kết nối với cơ sở dữ liệu, nhưng với mục đích minh họa, hãy thêm dữ liệu hóa đơn của bạn vào tệp JSON.


Tạo một tệp mới tại /data/invoices.json và thêm vào bên dưới:


 [ { "id": "47427759-9362-4f8e-bfe4-2d3733534e83", "customer": "Bins and Sons", "contact_name": "Verne McKim", "contact_email": "[email protected]", "address": "3 Burning Wood Street", "city_state": "Memphis, TN 38118", "plan_id": "41595-5514", "plan_name": "Starter", "subtotal": 499.99, "fee": 50.00, "total": 549.99 }, { "id": "1afdd2fa-6353-437c-a923-e43baac506f4", customer": "Koepp Group", "contact_name": "Junia Pretious", "contact_email": "[email protected]", "address": "7170 Fairfield Hill", "city_state": "Los Angeles, CA 90026", "plan_id": "43419-355", "plan_name": "Professional", "amount": 999.99, "fee": 50.00, "total": 1049.99 }, { "id": "59c216f8-7471-4ec2-a527-ab3641dc49aa", "customer": "Lynch-Bednar", "contact_name": "Evelin Stollenberg", "contact_email": "[email protected]", "address": "9951 Erie Place", "city_state": "Chicago, IL 60605", "plan_id": "63323-714", "plan_name": "Starter", "amount": 499.99, "fee": 50.00, "total": 549.99 } ]


Ba hóa đơn bạn có thể thấy ở trên chứa dữ liệu khách hàng, gói và thanh toán sẽ giúp bạn tạo hóa đơn trong phần tiếp theo.


Tạo các tuyến hóa đơn

Tệp routes/invoices.js sẽ tạo ba tuyến mới trong ứng dụng của bạn:

  • /invoices – Danh sách tất cả các hóa đơn từ tệp dữ liệu phẳng ở trên.
  • /invoices/:id – Bản xem trước hóa đơn để người dùng có thể xem hóa đơn trông như thế nào trước khi gửi cho khách hàng.
  • /invoices/:id/email – Điểm cuối tạo và gửi hóa đơn PDF tới email liên hệ có trong hồ sơ.


Mở tệp hóa invoices.js và thêm đoạn mã sau để xác định hai tuyến đường đầu tiên:


 const express = require('express'); const router = express.Router(); const invoices = require('../data/invoices.json'); // Import exec to run the Foxit HTML to PDF executable const { exec } = require('child_process'); // Import nodemailer to send emails const nodemailer = require('nodemailer'); router.get('/', function(req, res) { res.render('invoice-list', { invoices: invoices, // Accepts errors and successes as query string arguments success: req.query['success'], error: req.query['error'], }); }); router.get('/:id', function(req, res) { const invoice = invoices.find(invoice => invoice.id === req.params['id']); // If the invoice doesn't exist, redirect the user back to the list page if (!invoice) { res.redirect('/invoices'); } // Make the date format pretty const date = new Date().toLocaleDateString("en", { year:"numeric", day:"2-digit", month:"2-digit", }); res.render('invoice-single', { invoice, date }); }); router.get('/:id/email', function(req, res) { // Coming soon. }); module.exports = router;


Ứng dụng của bạn gần như đã sẵn sàng để thử nghiệm, nhưng trước tiên bạn cần tạo hai tệp dạng xem.


Thêm Chế độ xem và Kiểu

Express tách biệt logic và cách trình bày thành routes/views/ . Bây giờ thêm hai tệp mới vào thư mục views/ : invoice-list.hbs vàvoice invoice-single.hbs .


Ngoài ra, hãy thêm phần sau vào invoice-list.hbs của bạn:


 <h1><a href="/invoices">Unpaid Invoices</a></h1> {{#if success}} <p class="success"><strong>Success!</strong> The invoice has been sent to the client.</p> {{/if}} {{#if error}} <p class="error"><strong>Whoops!</strong> Something went wrong and your invoice could not be sent.</p> {{/if}} {{#each invoices}} <h3>{{this.customer}}</h3> <p>ID: {{this.id}} <br/> <a href="/invoices/{{this.id}}">View</a> | <a href="/invoices/{{this.id}}/email">Email Reminder</a> </p> {{/each}}


Mở tệp hóa đơn điện invoice-single.hbs và thêm tệp này:


 <div class="pure-g"> <div class="pure-u-1-2"> <h1>Invoice</h1> </div> <div class="pure-u-1-2" style="text-align: right;"> <p class="muted">Issued on {{ date }}</p> </div> </div> <div class="pure-g"> <div class="pure-u-1-2"> <h3>Provider</h3> <p> <strong>Tiller, Inc.</strong><br/> 1255 S. Clark<br/> Chicago, IL 60608 </p> </div> <div class="pure-u-1-2" style="text-align: right;"> <h3>Billed to</h3> <p> <strong>{{invoice.customer}}</strong><br/> {{invoice.contact_name}}<br/> {{invoice.address}}<br/> {{invoice.city_state}} </p> </div> </div> <table class="pure-table pure-table-horizontal"> <thead> <tr> <th>ID</th> <th>Plan Name</th> <th class="text-right">Amount</th> </tr> </thead> <tbody> <tr> <td>{{invoice.plan_id}}</td> <td>{{invoice.plan_name}}</td> <td class="text-right">${{invoice.subtotal}}</td> </tr> <tr> <td></td> <td class="text-right">Subtotal:</td> <td class="text-right">${{invoice.subtotal}}</td> </tr> <tr> <td></td> <td class="text-right">Taxes and Fees:</td> <td class="text-right">${{invoice.fee}}</td> </tr> <tr class="bold"> <td></td> <td class="text-right">Total:</td> <td class="text-right">${{invoice.total}}</td> </tr> </tbody> </table> <div class="footer"> <p>Please make checks payable to <strong>Tiller, Inc</strong>. Invoices are due 30 days after date issued.</p> <p>Thank you for your business!</p> </div>


Để thêm kiểu vào biểu định kiểu ứng dụng của bạn và kết hợp Mô-đun CSS thuần túy để có giao diện hấp dẫn trực quan, vui lòng mở tệp views/layout.hbs và thay thế nội dung của tệp bằng đoạn mã sau. Thao tác này sẽ nhập Pure và tạo bố cục lưới cột đơn:


 <!DOCTYPE html> <html> <head> <title>{{title}}</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://unpkg.com/[email protected]/build/pure-min.css" integrity="sha384-cg6SkqEOCV1NbJoCu11+bm0NvBRc8IYLRGXkmNrqUBfTjmMYwNKPWBTIKyw9mHNJ" crossorigin="anonymous"> <link rel='stylesheet' href='/stylesheets/style.css' /> </head> <body> <div class="container"> <div class="pure-g"> <div class="pure-u-1"> {{{body}}} </div> </div> </div> </body> </html>


Mở public/style.css file của ứng dụng của bạn và thêm đoạn mã CSS sau:


 body { background-color: #f7f7f7; color: #333333; } a { color: #156d6a; } h1 a, h2 a, h3 a { text-decoration: none; } table { width: 100%; } .container { background-color: #ffffff; max-width: 700px; margin: 0 auto; padding: 30px; } .muted { color: #999999; } .bold { font-weight: bold; } .text-right { text-align: right; } .footer p { margin-top: 30px; } .success { background-color: #c0f5f3; color: #0d928d; padding: 10px; } .error { background-color: #f5c0c0; color: #792525; padding: 10px; }


Mặc dù không bắt buộc nhưng việc thêm kiểu dáng vào hóa đơn của bạn có thể nâng cao vẻ ngoài chuyên nghiệp của chúng, vì Foxit nắm bắt tất cả kiểu dáng từ tài liệu HTML của bạn khi tạo tệp PDF.

Bây giờ, bạn đã sẵn sàng để kiểm tra ứng dụng của mình. Vui lòng run npm start trong giao diện dòng lệnh của bạn và mở trình duyệt web của bạn tới localhost:3000/invoices Bạn sẽ thấy một danh sách các hóa đơn tương tự như sau:


Nhấp vào “Xem” để xem trước từng hóa đơn.



Trong hai bước cuối cùng, bạn sẽ sử dụng công cụ Foxit__ HTML to PDF __ để tạo hóa đơn PDF. Sau khi hóa đơn được tạo, bạn sẽ tiến hành đính kèm chúng vào email bằng Nodemailer trước khi gửi chúng.


Tạo tệp PDF với Foxit

SDK của Foxit cung cấp nhiều chức năng để tạo và thao tác PDF, bao gồm khả năng tạo tệp PDF từ tài liệu HTML hoặc URL. Quá trình tải xuống và biên dịch tệp thực thi HTML sang PDF có sẵn đây . Khi bạn đã thực hiện thành công bản demo từ dòng lệnh của mình, bạn có thể tiến hành các bước tiếp theo.


Thư viện child_process của nút bao gồm một hàm gọi là exec() cho phép bạn thực thi các hàm dòng lệnh. Phương pháp này rất hữu ích để chạy các tệp thực thi C++ từ Foxit. Để thực thi tệp thực thi HTML sang PDF, vui lòng cập nhật tuyến đường /:id/email của bạn bằng mã sau:


 ... router.get('/:id/email', function(req, res) { // Set the executable path and output folder const htmlToPdfPath = '/path/to/foxit/html2pdf'; const outputFolder = __dirname + '/../invoices/'; // Get the invoice const invoice = invoices.find(invoice => invoice.id === req.params['id']); if (!invoice) { res.redirect('/invoices?error=1'); } // Convert the HTML to PDF exec( `${htmlToPdfPath} -html /invoices/${req.params['id']} -o ${outputFolder}${req.params['id']}.pdf`, (err, stdout, stderr) => { if (err || stderr) { console.error(err, stderr); res.redirect('/invoices?error=1'); } else { // For now: log the output file path console.log(`PDF generated and saved to ${outputFolder}${req.params['id']}.pdf`); res.redirect('/invoices?success=1'); } }); });


Trước khi chạy mã này, vui lòng đảm bảo rằng bạn cập nhật biến htmlToPdfPath để phản ánh đúng đường dẫn tới tệp thực thi htmltopdf của bạn.


Để gửi lời nhắc qua email cho hóa đơn, vui lòng quay lại danh sách hóa đơn của bạn và nhấp vào “Lời nhắc qua email” cho bất kỳ hóa đơn cụ thể nào. Hành động này sẽ kích hoạt ứng dụng Node gọi tệp thực thi htmltopdf . Đổi lại, tệp thực thi sẽ chuyển đổi hóa đơn từ tài liệu HTML do Express cung cấp thành tệp PDF. Bạn có thể định vị tệp PDF kết quả trong thư mục invoices/ của ứng dụng web của mình.


Bây giờ bạn đã có khả năng tạo Hóa đơn PDF, bước cuối cùng là gửi các hóa đơn này cho khách hàng của bạn.

Gửi email với Nodemailer

Nodemailer cung cấp một giao diện thuận tiện cho phép bạn truy cập các lớp vận chuyển email khác nhau. SMTP là một trong những tùy chọn được sử dụng phổ biến nhất, nhưng bạn cũng có thể sử dụng các dịch vụ như Amazon SES hoặc lệnh sendmail của máy chủ làm các tùy chọn thay thế.


Để kiểm tra Nodemailer, bạn có thể sử dụng tùy chọn JSON của luồng truyền tải , cho phép bạn ghi thông báo vào bảng điều khiển của mình. Để thiết lập và gửi thư của bạn bằng Nodemailer, hãy thêm đoạn mã sau ngay bên dưới câu lệnh “PDF được tạo và lưu vào…” console.log trong định tuyến /invoices/:id/email của bạn:


 ... // Construct the message const message = { from: '[email protected]', to: invoice.contact_email, subject: 'Reminder: Your Invoice from Tiller, Inc. is Due', html: `<p>Hey ${invoice.contact_name},</p><p>I just wanted to remind you that your invoice for last month's services is now due. I've attached it here for your convenience.</p><p>Thanks for your business!</p>`, attachments: [ { filename: 'invoice.pdf', path: `${outputFolder}${req.params['id']}.pdf`, } ] }; // Use mailer to send invoice nodemailer .createTransport({jsonTransport: true}) .sendMail(message, function (err, info) { if (err) { res.redirect('/invoices?error=1'); } else { console.log(info.message); res.redirect('/invoices?success=1'); } }); ...


Vui lòng làm mới ứng dụng Node của bạn và nhấp vào “Lời nhắc qua email” cho bất kỳ hóa đơn nào. Lần này, bạn sẽ quan sát đối tượng dữ liệu email hoàn chỉnh được hiển thị dưới dạng JSON trong bảng điều khiển của mình.


 { "from": { "address": "[email protected]", "name": "" }, "to": [ { "address": "[email protected]", "name": "" } ], "subject": "Reminder: Your Invoice from Tiller, Inc. is Due", "html": "<p>Hey Junia Pretious,</p><p>I just wanted to remind you that your invoice for last month's services is now due. I've attached it here for your convenience.</p><p>Thanks for your business!</p>", "attachments": [ { "content": "JVBERi0xLjMKJcTl8uXrp...", "filename": "invoice.pdf", "contentType": "application/pdf", "encoding": "base64" } ], "headers": {}, "messageId": "<[email protected]>" }


Chuỗi attachments.content đại diện cho tệp PDF được mã hóa. Để cho ngắn gọn, tôi đã cắt bớt nó trong ví dụ trên.


Để kiểm tra email bằng cách sử dụng thực tế máy chủ SMTP , bạn có thể dùng bẫy thư . Giả sử bạn có tài khoản với Mailtrap, hãy thay thế lệnh gọi createTransport({jsonTransport: true}) bằng đoạn mã sau:


 createTransport({ host: "smtp.mailtrap.io", port: 2525, auth: { user: "<YOUR_MAILTRAP_USERID>", pass: "<YOUR_MAILTRAP_PASS>" } })


Khi gửi Hóa đơn qua email, Mailtrap sẽ chụp đầu ra và cung cấp cho bạn tùy chọn tải xuống tệp đính kèm PDF. Nếu bạn truy cập vào tài khoản Mailtrap của mình, bạn sẽ tìm thấy một email tương tự như ví dụ bên dưới:



Khi bạn đã sẵn sàng triển khai ứng dụng của mình vào sản xuất, hãy thay thế thông tin đăng nhập SMTP của Mailtrap bằng máy chủ thư sản xuất. Ứng dụng web của chúng tôi hiện cung cấp khả năng tạo và tự động gửi Hóa đơn PDF cho khách hàng theo yêu cầu từ nhóm thanh toán của chúng tôi.


Nếu bạn yêu cầu một giải pháp để trình bày Hóa đơn trực tuyến và gửi chúng dưới dạng PDF, ứng dụng của chúng tôi sẽ cung cấp một nền tảng đáng tin cậy. Mặc dù công cụ HTML to PDF của Foxit là một tùy chọn thuận tiện và hiệu quả để tạo tệp PDF, nhưng điều quan trọng cần lưu ý là họ cũng cung cấp nhiều giải pháp khác. Với họ bộ công cụ phát triển phần mềm (SDK) có sẵn cho nhiều nền tảng , Foxit nổi bật là lựa chọn lý tưởng khi tích hợp chức năng PDF vào các ứng dụng web, thiết bị di động hoặc máy tính để bàn của bạn.


Cũng được xuất bản ở đây .