使用 Zoho Forms 使用 Docs 模板生成 PDF
Posted
技术标签:
【中文标题】使用 Zoho Forms 使用 Docs 模板生成 PDF【英文标题】:Generation of PDF using Docs Template using Zoho Forms 【发布时间】:2021-12-26 17:18:00 【问题描述】:我使用 Zoho 创建了表单,其回复链接到 Google 表格。 google sheet的链接如下。用户提交表单后,数据会自动上传到 google sheet 中。
https://docs.google.com/spreadsheets/d/1bE9RdYs9g3tdawbUzSUz2sG_SknlwfONA9_5MVztJu8/edit?usp=sharing
我在谷歌文档中创建了一个模板来生成 PDF。模板链接如下:
https://docs.google.com/document/d/1NAU9ZpxxIZko0fy8IltgbZ7Em5IMZKq-JRBge9umYHg/edit
表格链接如下:
https://zfrmz.in/iqzvLxSYT6yPvyQwkevD
我已经写下了以下脚本,以便在提交 Zoho 表单后生成 PDF。
function afterFormSubmit(e)
const info = e.namedValues;
const pdfFile = createPDF(info);
const entryRow = e.range.getRow();
const ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2")
ws.getRange(entryRow, 63).setValue(pdfFile.getUrl());
ws.getRange(entryRow, 64).setValue(pdfFile.getName());
sendEmail(e.namedValues ['Email address'][0],pdfFile);
function sendEmail(email,pdfFile)
GmailApp.sendEmail(email, "Daily Transation Summary Report", "Please find the attached DTR",
attachments : [pdfFile],
name: 'My Company'
);
function createPDF(info)
const pdfFolder = DriveApp.getFolderById("1ebglel6vwMGXByeG4wHBBvJu9u0zJeMJ");
const tempFolder = DriveApp.getFolderById("1ebglel6vwMGXByeG4wHBBvJu9u0zJeMJ");
const templateDoc = DriveApp.getFileById("1kyFimRMdHQZV85F5P6JyCHv1DQ3KJFv1hx5o7lIcNZo");
const newTempFile = templateDoc.makeCopy(tempFolder);
const openDoc = DocumentApp.openById(newTempFile.getId());
const body = openDoc.getBody();
body.replaceText("Name of Person", info['Name of Person'][0]);
body.replaceText("Date of Report", info['Date of Report'][0]);
body.replaceText("Name of Outlet", info['Name of Outlet'][0]);
body.replaceText("Opening Petty Cash Balance", info['Opening Petty Cash Balance'][0]);
body.replaceText("Total Petty Cash Received", info['Total Petty Cash Received'][0]);
body.replaceText("Closing Petty Cash Balance", info['Closing Petty Cash Balance'][0]);
body.replaceText("Total Petty Cash Paid", info['Total Petty Cash Paid'][0]);
body.replaceText("Available Float Cash Balance", info['Available Float Cash Balance'][0]);
body.replaceText("Milk For Outlet", info['Milk For Outlet'][0]);
body.replaceText("Staff Milk/Toast etc.", info['Staff Milk/Toast etc.'][0]);
body.replaceText("Petrol Expenses", info['Petrol Expenses'][0]);
body.replaceText("Water Tank Charges", info['Water Tank Charges'][0]);
body.replaceText("Repair And Maintenance", info['Repair And Maintenance'][0]);
body.replaceText("Freight Paid", info['Freight Paid'][0]);
body.replaceText("Purchase of Soya Chaap", info['Purchase of Soya Chaap'][0]);
body.replaceText("Purchase of Rumali Roti", info['Purchase of Rumali Roti'][0]);
body.replaceText("Purchase of Egg Tray", info['Purchase of Egg Tray'][0]);
body.replaceText("Other Expenses", info['Other Expenses'][0]);
body.replaceText("Total Tip Amount (PAYTM & CARD)", info['Total Tip Amount (PAYTM & CARD)'][0]);
body.replaceText("Cash Sales - Outlet", info['Cash Sales - Outlet'][0]);
body.replaceText("Cash Sales - KCCO App", info['Cash Sales - KCCO App'][0]);
body.replaceText("Card Sales", info['Card Sales'][0]);
body.replaceText("Credit (Udhar) Sales", info['Credit (Udhar) Sales'][0]);
body.replaceText("Paytm Sales", info['Paytm Sales'][0]);
body.replaceText("KCCO App Sales Razor Pay", info['KCCO App Sales Razor Pay'][0]);
body.replaceText("Swiggy Sales", info['Swiggy Sales'][0]);
body.replaceText("Zomato Sales", info['Zomato Sales'][0]);
body.replaceText("Dunzo Sales", info['Dunzo Sales'][0]);
body.replaceText("Zomato Gold Sales", info['Zomato Gold Sales'][0]);
body.replaceText("Dine Out Sales", info['Dine Out Sales'][0]);
body.replaceText("Total Cancelled Bill Amount", info['Total Cancelled Bill Amount'][0]);
body.replaceText("Total Sales of the Day (Total of Above)", info['Total Sales of the Day (Total of Above)'][0]);
body.replaceText("Total Sales of the Day (As Per PetPooja)", info['Total Sales of the Day (As Per PetPooja)'][0]);
body.replaceText("Old Due Receipts - Cash", info['Old Due Receipts - Cash'][0]);
body.replaceText("Old Due Receipts - Other Modes", info['Old Due Receipts - Other Modes'][0]);
body.replaceText("Tip Receipts - Card", info['Tip Receipts - Card'][0]);
body.replaceText("Tip Receipts - Paytm", info['Tip Receipts - Paytm'][0]);
body.replaceText("Currency Note of INR 2000", info['Currency Note of INR 2000'][0]);
body.replaceText("Currency Note of INR 500", info['Currency Note of INR 500'][0]);
body.replaceText(" Currency Note of INR 200", info[' Currency Note of INR 200'][0]);
body.replaceText("Currency Note of INR 100", info['Currency Note of INR 100'][0]);
body.replaceText("Currency Note of INR 50", info['Currency Note of INR 50'][0]);
body.replaceText("Currency Note of INR 20", info['Currency Note of INR 20'][0]);
body.replaceText("Currency Note of INR 10", info['Currency Note of INR 10'][0]);
body.replaceText("Other Currency Note/Coins", info['Other Currency Note/Coins'][0]);
body.replaceText("Total Available Cash to Handover", info['Total Available Cash to Handover'][0]);
body.replaceText("S.No.//Name of Person// Mobile No// Credit Approval By// Bill No// Total Amount of Credit", info['S.No.//Name of Person// Mobile No// Credit Approval By// Bill No// Total Amount of Credit'][0]);
body.replaceText("Total No. of Bills of Credit Recovery", info['Total No. of Bills of Credit Recovery'][0]);
body.replaceText("S.No.//Name of Person// Mobile No// Mode of Payment// Bill No// Total Amount Received", info['S.No.//Name of Person// Mobile No// Mode of Payment// Bill No// Total Amount Received'][0]);
body.replaceText("Total No. of Complementary Bills During the Day", info['Total No. of Complementary Bills During the Day'][0]);
body.replaceText("S.No.//Name of Person// Mobile No//Reason// Bill No//Amount Settled", info['S.No.//Name of Person// Mobile No//Reason// Bill No//Amount Settled'][0]);
body.replaceText("Total No. of Cancelled Bills During the Day", info['Total No. of Cancelled Bills During the Day'][0]);
body.replaceText("S.No.//Name of Person// Mobile No// Bill No// Bill Amount", info['S.No.//Name of Person// Mobile No// Bill No// Bill Amount'][0]);
body.replaceText("S.No.// Bill No// Mode of Payment//Tip Amount Received", info['S.No.// Bill No// Mode of Payment//Tip Amount Received'][0]);
body.replaceText("No. of Cylinders Received at Outlet", info['No. of Cylinders Received at Outlet'][0]);
openDoc.saveAndClose();
const blobPDF = newTempFile.getAs(MimeType.PDF);
const pdfFile = pdfFolder.createFile(blobPDF).setName(info['Name of Outlet'][0]+ " " + info['Date of Report'][0]);
tempFolder.removeFile(newTempFile);
return pdfFile;
【问题讨论】:
进一步检查afterFormSubmit(e)
不存在为 Installable Trigger。运行 Apps 脚本时遇到什么错误?
【参考方案1】:
建议:
由于您使用的是向您的 Google 表格文件发送数据的第三方表单(Zoho 表单),因此很遗憾,afterFormSubmit
或 onFormSubmit
似乎无法在您的设置中使用。但是,正如所讨论的,您可能希望在 time-driven 触发器上检查下面这个经过调整的示例脚本作为解决方法:
在这个解决方法中,我在
CC
列上添加了一个标识符,其中代码在CC
列的最后一行添加了一个带有“完成”的值,表明数据已经通过电子邮件发送。这样,每次time driven
触发器启动时,它不会一直重新发送相同的数据,而只会重新发送CC
行上尚未“完成”的新的最后一行。
脚本 - 更新
function sendEmail(email,pdfFile)
GmailApp.sendEmail(email, "Daily Transation Summary Report", "Please find the attached DTR",
attachments : [pdfFile],
name: 'My Company'
);
function afterFormSubmit() // Add this function to a time driven trigger
var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("DTR - Final Response");
var lastRow = ss.getRange("A1:A").getValues().filter(String).length;
var emailCheck = ss.getRange("CC"+lastRow);
const info = ss.getRange("A"+lastRow+":CB"+lastRow).getValues(); //Get the last submitted row data from the DTR - Final Response.
const ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet2");
const entryRow = ws.getLastRow() + 1;
if(emailCheck.getValue()!= "Done") // checks if the last row with data on DTR - Final Response sheet on CC column has 'Done" value or not
const pdfFile = createPDF(info);
sendEmail(info[0][78],pdfFile);
emailCheck.setValue("Done"); //Set value on CC column of the data row that has been submitted via email with "Done" indication that it has already been sent via email
ws.getRange(entryRow, 63).setValue(pdfFile.getUrl());
ws.getRange(entryRow, 64).setValue(pdfFile.getName());
Logger.log("PDF sent to email: "+ info[0][78])
else
Logger.log("This data has already been sent with PDF name: "+info[0][3]+ " " + info[0][2])
return; //if current row data on CC column has "Done" value it means it was already send via email, so it will be ignored.
function createPDF(info)
const pdfFolder = DriveApp.getFolderById("1lxR27p9zVQi416j3Lq2ZRsLGb0xcdQ1a");
const tempFolder = DriveApp.getFolderById("1VaIeCeN6RlqACSXg_MGT7BRa5cyPMpbN");
const templateDoc = DriveApp.getFileById("1Stvxgn76qxti40EeRzgS3UlQJ94Dh9oldYVhfCHUnMY");
const newTempFile = templateDoc.makeCopy(tempFolder);
const openDoc = DocumentApp.openById(newTempFile.getId());
const body = openDoc.getBody();
// made some test on my end to a few data
body.replaceText("Name of Person", info[0][4]);
body.replaceText("Date of Report", info[0][2]);
body.replaceText("Outlet", info[0][3]);
body.replaceText("Opening Petty Cash Balance", info[0][57]);
body.replaceText("Total Petty Cash Received from H.O.", info[0][24]);
body.replaceText("Closing Petty Cash Balance", info[0][28]);
// made some test on my end to a few data
openDoc.saveAndClose();
const blobPDF = newTempFile.getAs(MimeType.PDF);
const pdfFile = pdfFolder.createFile(blobPDF).setName(info[0][3]+ " " + info[0][2]);
tempFolder.removeFile(newTempFile);
return pdfFile;
快速测试结果
要在
DTR - Final Response
工作表上使用的最后一行数据示例(Zoho 表单中最近提交的数据):
将
afterFormSubmit
函数添加到time-driven trigger
(在我的测试中,它将每分钟运行一次):
PDF 已通过电子邮件发送到我在最后一行添加的测试电子邮件帐户
然后将 PDF URL 和 PDF 文件名发布在最后一行数据的
Sheet 2
列 63 和 64 上。
来自 Apps 脚本编辑器的时间驱动触发器日志:
【讨论】:
我已将表单提交的所有数据移至“DTR - Final Response”。电子邮件 ID 链接在“DTR - 最终响应”表中,我也在其中安装了触发器。提交表单后,我想将 PDF 发送到电子邮件 ID。 请指导一下.. 我明白了,既然您想在提交表单后将 PDF 发送到电子邮件 ID,那么我很抱歉,因为 Zoho 表单提交到 Google 表格不会触发 @987654347 @ 或onFormSubmit
基于我的几次测试。
是的,让我们看看我能提供什么帮助...
@Admin-RKPareekCo 不客气,我很高兴它对你有用。如果您不介意,您可能需要单击左侧的接受按钮(复选图标)。通过这样做,社区中可能与您有同样担忧的其他人会知道他们的问题可以得到解决,并且他们会在搜索时轻松看到此帖子。以上是关于使用 Zoho Forms 使用 Docs 模板生成 PDF的主要内容,如果未能解决你的问题,请参考以下文章
是否可以使用 Zoho API 将 Zoho 分析中的数据与 Zoho Books 同步?
在 Azure Function 上获取数据时,HttpClient.GetAsync() 会产生 AggregateException