目录
构建Web应用程序以创建和发送PDF发票
先决条件
创建新的Express应用程序
创建发票路由
添加视图和样式
使用Foxit生成PDF
使用Nodemailer发送电子邮件
结论
获得报酬是任何业务中最关键的功能之一,数字发票正在成为标准做法。考虑到这一点,Web应用程序开发人员通常负责以编程方式生成和发送PDF发票。
无论您是自动化发票生成和通知流程,还是构建允许您的团队主动提醒客户未结发票的GUI,您将面临的第一个技术障碍是生成PDF发票。虽然您可以编写自定义PDF生成脚本,但这是一项艰巨的任务。基于Web的服务很方便,但如果您与客户签订了保密协议,则通过Internet将数据发送到第三方服务可能会有问题。
幸运的是,福昕的PDF工具可以让您快速安全地生成PDF文件。使用他们的HTML到PDF转换器,您可以将任何HTML文档(包括发票)转换为PDF文件,您可以将其附加到电子邮件或允许客户从您的Web应用程序下载。
在本教程中,您将了解如何创建一个NodeJS应用程序,该应用程序使用Foxit PDF SDK从Web应用程序中的HTML发票生成PDF发票。创建后,您将使用Nodemailer通过SMTP将发票发送到客户的电子邮件地址。您可以按照以下每个步骤操作或[在GitHub上下载完成的代码库)。
访问Foxit PDF SDK Web Demo并通过探索配置和功能亲身体验。
构建Web应用程序以创建和发送PDF发票在本教程中,您将创建一个内部工具来帮助您的计费部门跟进未付发票。您将创建一个列出所有未结发票的页面和一个用于预览每个发票的页面。用户将能够单击链接向每个客户发送电子邮件提醒,并附上发票。
您将使用Express Web框架、Pure CSS进行样式设置和Nodemailer发送电子邮件。
先决条件- NodeJS版本8+和NPM版本5+
- Foxit SDK(可在此处免费试用下载)
- Foxit HTML到PDF转换插件
- Mailtrap(如果您想测试SMTP电子邮件传输)
要创建一个新的样板Express Web应用程序,请使用应用程序生成器:
npx express-generator --git --view=hbs
这将创建一个带有.gitignore文件和Handlebars模板文件的Web应用程序。
接下来,添加Nodemailer npm包并安装Express的依赖项:
npm i nodemailer && npm i
Express生成的默认应用程序带有两个路由文件:/routes/index.js和/routes/users.js。删除users.js路由并创建一个名为invoices.js的新路由文件。将此新路由添加到您的app.js文件并删除usersRoute:
...
var indexRouter = require('./routes/index');
var invoicesRouter = require('./routes/invoices');
var app = express();
...
app.use('/', indexRouter);
app.use('/invoices', invoicesRouter);
...
发票路由器是您在此应用程序中完成大部分工作的地方。
在创建路由之前,您需要一些数据。在实际应用程序中,您可能会连接到数据库,但出于演示目的,您会将发票数据添加到JSON文件中。
在/data/invoices.json创建一个新文件并添加以下内容:
[
{
"id": "47427759-9362-4f8e-bfe4-2d3733534e83",
"customer": "Bins and Sons",
"contact_name": "Verne McKim",
"contact_email": "vmckim0@example.com",
"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": "jpretious1@example.com",
"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": "estollenberg2@example.com",
"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
}
]
这三张发票包含客户、计划和计费数据,可帮助您在下一部分生成发票。
创建发票路由routes/invoices.js文件将在您的应用程序中创建三个新路由:
- /invoices——来自上述平面数据文件的所有发票的列表。
- /invoices/:id ——发票预览,因此用户可以在将发票发送给客户之前查看发票的外观。
- /invoices/:id/email ——生成PDF发票并将其发送到存档的联系人电子邮件的端点。
最后一条路由将在稍后解决,但您可以从添加前两条路由开始。打开invoices.js文件并添加以下内容:
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;
您的应用程序几乎可以测试了,但首先,您需要创建两个视图文件。
添加视图和样式Express将逻辑和表示分离为routes/和views/。在views/目录中添加两个新文件: invoice-list.js和invoice-single.js。
将以下内容添加到您的invoice-list.js文件中:
Unpaid Invoices
{{#if success}}
Success! The invoice has been sent to the client.
{{/if}}
{{#if error}}
Whoops! Something went wrong and your invoice could not be sent.
{{/if}}
{{#each invoices}}
{{this.customer}}
ID: {{this.id}}
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?