提交Google表单后从PDF生成PDF时出现问题 [英] Problems generating PDFs from Google Forms after it is submitted

查看:111
本文介绍了提交Google表单后从PDF生成PDF时出现问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个Google脚本,该脚本基于Google表单的字段填充Google Doc模板,并通过电子邮件将生成的PDF发送给用户.

在此详细说明了我执行的所有步骤:

代码工作正常.现在我需要用户在按发送表单"后,可以编辑其响应.因此,我决定选中受访者可以在提交后进行编辑".然后,我需要通过带有编辑字段的 GmailApp 重新发送文档.因此,我创建了一个新触发器: Edit (来自电子表格).另一个触发器是表单提交.

但是我有问题.当用户编辑字段并再次按下发送表格"时,触发编辑"按钮将被取消.已激活,并显示以下错误:无法发送电子邮件:没有收件人.

如果我转到电子表格答复,则可以看到已编辑的行(因为单元格的注释为答复的人已更新此值"),并且列邮件未编辑,但仍然抛出异常.

如果从未编辑过 cEmail ,我们如何解决此问题?

搜索

我可以找到一些有趣的答案:

他们似乎描述了当触发编辑"时,可以生成空白行.被激活.但是,我不知道为什么会发生这种情况,以及如何解决它,因为新用户提交答案后会自动编辑电子表格响应.

解决方案

在编辑表单响应时,表单提交事件对象属性 values namedValues 仅包含值对于那些已编辑的问题.

要纠正错误无法发送电子邮件:没有收件人,请替换

  GmailApp.sendEmail(cEmail,'< subject> ;,'< body>',{attachments:[attachment.getAs(MimeType.PDF)]}); 

作者

  const receiverIdx = 1;//这是具有收件人电子邮件地址的列的从0开始的索引const收件人= cEmail?cEmail:e.range.getValues().flat()[recipientIdx]GmailApp.sendEmail(收件人,'< subject>','< body>',{attachments:[attachment.getAs(MimeType.PDF)]}); 

P.S.代替对分配给 recipientIdx 的值进行硬编码,您可以使用一些代码基于列标题来获取它.

注意:以上内容只能防止问题中提到的错误.为了使脚本起作用,您将必须对所有字段应用相同的想法:使用 e.range.getValues().flat()从电子表格中读取缺少的值./p>

相关

I am creating a Google Script that fills a Google Doc template based on the fields of a Google Forms and sends the generated PDF via email to the user.

All of the steps that I followed are explained in detail here: Hacking it: Generate PDFs from Google Forms

The script (obtained from the article) is:

function onSubmit(e) {
  const rg = e.range;
  const sh = rg.getSheet();
  
  //Get all the form submitted data
  //Note: This data is dependent on the headers. If headers, are changed update these as well.
  const cName = e.namedValues['Client Name'][0];
  const cEmail = e.namedValues['Client Email'][0];
  const cAddress = e.namedValues['Client Address'][0];
  const cMobile = e.namedValues['Client Mobile'][0];
  const sendCopy = e.namedValues['Send client a copy?'][0];
  const paymentType = e.namedValues['What is your agreed upon payment schedule?'][0];
  const fixedCost = e.namedValues['What was your agreed upon cost for the project?'][0];
  const hourlyRate = e.namedValues['Hourly Rate'][0];
  const manHours = e.namedValues['Total man hours'][0];
  const services = e.namedValues['Select the services'][0];
  
  //Consequential Data
  const tax = 18.5
  var subtotal = 0;
  var taxAmt = 0;
  var payableAmt = 0;
      
  //if the user has selected hourly payment model
  //Note: Be careful that the responses match the elements on the actual form
  switch (paymentType ){
    case 'Hourly Rate':
      subtotal = hourlyRate*manHours;
      taxAmt = subtotal * (tax/100);
      payableAmt = +subtotal + +taxAmt;
      break;
    case 'Fixed Cost':
      subtotal = fixedCost;
      taxAmt = fixedCost * (tax/100)
      payableAmt = +fixedCost + +taxAmt;
      break;            
  }
  
  const invoiceID = 'IN' + Math.random().toString().substr(2, 9);
  var formattedDate = Utilities.formatDate(new Date(), "IST", "dd-MMM-yyyy");
  
  //Set the consequential data in the columns of the spreadsheet for record keeping
  //Note: These variable are dependent on the sheet's columns so if that changes, please update.
  const row = rg.getRow();
  
  const payableAmtCol = 2; //B
  const invoiceIDCol = 3; //C
  
  sh.getRange(row,payableAmtCol).setValue(payableAmt);
  sh.getRange(row,invoiceIDCol).setValue(invoiceID); 
  
  
  //Build a new invoice from the file
  //Folder and file IDs
  const invoiceFolderID = '<invoice-folder-id>';
  const invoiceFolder = DriveApp.getFolderById(invoiceFolderID);
  
  const templateFileID = '<template-id>';
  const newFilename = 'Invoice_' + invoiceID;
  
  //Make a copy of the template file
  const newInvoiceFileID = DriveApp.getFileById(templateFileID).makeCopy(newFilename, invoiceFolder).getId();;
  
  //Get the invoice body into a variable
  var document = DocumentApp.openById(newInvoiceFileID);
  var body = document.getBody();
  
  //Replace all the {{ }} text in the invoice body
  body.replaceText('{{Invoice num}}', invoiceID);
  body.replaceText('{{Date}}', formattedDate);
  body.replaceText('{{Client Name}}', cName);
  body.replaceText('{{Client Address}}', cAddress);
  body.replaceText('{{Client Mobile}}', cMobile);
  body.replaceText('{{Client Email}}', cEmail);
  body.replaceText('{{Services}}', services.split(', ').join('\n'));
  
  body.replaceText('{{Subtotal}}', subtotal);
  body.replaceText('{{Tax Value}}', taxAmt);
  body.replaceText('{{Total}}', payableAmt);
  
  //In the case of hourly rate payment type, let's add an additional message giving the rate and the man hours.
  if(paymentType.includes('Hourly Rate')){
     //It should look something like this on the invoice
     //Hourly Rate
     //Rate of Rs.1200/hour
     //Completed 50 man hours
     const message = paymentType + '\nRate of Rs.' + hourlyRate + '/hour\nCompleted ' + manHours + ' man hours';
     body.replaceText('{{Payment Type}}', message);
  } else {
    body.replaceText('{{Payment Type}}', paymentType);
  }
  
  document.saveAndClose();
  
    //send email with the file
  var attachment = DriveApp.getFileById(newInvoiceFileID);
    GmailApp.sendEmail(cEmail, '<subject>, 
                     '<body>', 
                     {attachments: [attachment.getAs(MimeType.PDF)]});
}

The code works fine. Now I need that the user can edit its response after he press "Send Form" on Google Forms. So I decided to check "Respondents can edit after submit". Then I need to send the document again via GmailApp with the edited fields. So I created a new trigger: Edit (from a Spreadsheet). The other trigger is Form submit.

However I have a problem. When the user edits a field and press, again, "Send Form", the trigger "Edit" is activated with the following error: Failed to send email: no recipient.

If I go to the Spreadsheet responses I can see the edited row (because the cell has a comment "The person who responded has updated this value"), and the column mail is not edited but it stills throwing the exception.

How can we solve this problem if cEmail was never edited?

Searchs

I could find some interesting answers:

They seem to describe that a blank row can be generated when the trigger "Edit" is activated. However I don't see why this could happen, and how I can solve it since the Spreadsheet Responses is automatically edited after a new user submit an answer.

解决方案

When a form response is edited the on form submit event object properties values and namedValues only include values for those questions that were edited.

To fix the error Failed to send email: no recipient, replace

 GmailApp.sendEmail(cEmail, '<subject>, 
                     '<body>', 
                     {attachments: [attachment.getAs(MimeType.PDF)]});

by

const recipientIdx = 1; // This is the 0 based index of the column having the recipient email address
const recipient = cEmail ? cEmail : e.range.getValues().flat()[recipientIdx]
 GmailApp.sendEmail(recipient , '<subject>', 
                     '<body>', 
                     {attachments: [attachment.getAs(MimeType.PDF)]});

P.S. Instead of hardcoding the value assigned to recipientIdx you might use some code to get it based on the column headers.

NOTE: The above only will prevent the error mentioned in the question. In order to make the script work you will have to apply the same idea for all the fields: Read the missing values from the spreadsheet by using the e.range.getValues().flat().

Related

这篇关于提交Google表单后从PDF生成PDF时出现问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆