【问题标题】:Script functions but trigger fails脚本函数但触发器失败
【发布时间】:2020-07-01 20:16:08
【问题描述】:

我有一个工作流程,用户可以在其中填写 Google 表单,然后关联的 Google 表格信息填充 Google Doc 并发送电子邮件。 该脚本在我的所有测试中都可以正常运行,但是当我尝试设置可安装触发器时,它会一次又一次地失败。

function CreatePro2() {
  
  // specify doc template and get values from spread
  var sleepINT = 1500
  var templateid = "XXXXXXXXXXXXXXXXXX"; // template file id
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  ss.toast("ENGINE INITIALIZING & Feeding the unicorns");
  Utilities.sleep(sleepINT);
  var sheet = ss.getActiveSheet();
  var data = sheet.getRange(2,1,1,23).getValues(); // starting with row 2 and column 1 as our upper-left most column, 
                                                   // get values from cells from 1 row down, and 15 columns along - hence (2,1,1,15)
  //sheet.getRange("F7").setValue('=IMAGE("https://s-media-cache-ak0.pinimg.com/564x/58/5d/8f/585d8f802867c25df8f1ecc0cf7cadc8.jpg",1)');                                                 
  ss.toast("10%: data captured"); 
  Utilities.sleep(sleepINT);
  
  
  //Create and set a counter for the invoice number, then grab the new invoice number
  var oldInvoiceNumber = sheet.getRange("G2").getValue();
  oldInvoiceNumber += 1;
  sheet.getRange("G2").clear();
  sheet.getRange("G2").setValue(oldInvoiceNumber);
  sheet.getRange("G2").setBackgroundColor("#cecece");
  
  var newInvNumber = sheet.getRange("G2").getValue();
  
  ss.toast("20%: invoice number updated"); 
  Utilities.sleep(sleepINT);
  
  // Make a copy of the invoice template, then Fill up it up with the data from the spreadsheet.
  //NOTE: body.replace method does not have to be in any specific order.
  
  for (var i in data) {
     var replaceTextToImage = function(body, searchText, fileId) {
    var width = 590; // Please set this.
    var blob = DriveApp.getFileById(fileId).getBlob();
    var r = body.findText(searchText).getElement();
    r.asText().setText("");
    var img = r.getParent().asParagraph().insertInlineImage(0, blob);
    var w = img.getWidth();
    var h = img.getHeight();
    img.setWidth(width);
      img.setHeight(width * h / w);}
     
    var row = data[i];
    var docid = DriveApp.getFileById(templateid).makeCopy().getId();
    var doc = DocumentApp.openById(docid);
    var body = doc.getActiveSection();
    var Image = row[10].split("=")[1];
    var selectBody = doc.getBody();    
    
    
    body.replaceText("%NAME%", row[0]);
    body.replaceText("%ADD_LN1%", row[1]);
    body.replaceText("%EMAIL%", row[2]);
    body.replaceText("%PHONE%", row[3]);
    body.replaceText("%DATE%", row[4]);
    body.replaceText("%EXPDATE%", row[5]);
    body.replaceText("%INV_NUM%", row[6] +=1);
    body.replaceText("%PTOTAL%", row[7]);
    body.replaceText("%DESC1%", row[8]);
    body.replaceText("%FEE1%", row[9]);  
    replaceTextToImage(body, '%IMAGE%', Image);
    
    doc.saveAndClose();
    
    ss.toast("30%: template data replaced");
    Utilities.sleep(sleepINT);
    
    //copy the modified template to the specified folder, then delete the first copy we made (to modify it) 
    var file = DriveApp.getFileById(doc.getId());
    var newfolder = DriveApp.getFolderById("YYYYYYYYYYYYYYYYYYYY");
    var oldfolder = DriveApp.getFolderById("ZZZZZZZZZZZZZZZZZZZZ");
    newfolder.addFile(file);
    oldfolder.removeFile(file);
    
    ss.toast("40%: invoice has been put in correct folder");
    Utilities.sleep(sleepINT);
    
    //customize the title for the invoice
    var usernamefordoctitle = sheet.getRange(2, 1, 1, 1).getValues() // this is grabbing the customer name field (A2)
    var name = doc.getName();
    doc.setName(newInvNumber + ' - Invoice for ' + usernamefordoctitle);
    ss.toast("50%: named new invoice");
    Utilities.sleep(sleepINT);

    //create and organize pdf version
    var pdffolder = DriveApp.getFolderById("***************");
    var pdfFILE = DriveApp.getFileById(doc.getId()).getAs('application/pdf');
    pdfFILE.setName(doc.getName() + ".pdf");
    var theFolder = pdffolder;
    var theFile = DriveApp.createFile(pdfFILE);
    theFolder.addFile(theFile);
    ss.toast("60%: PDF generated");
    Utilities.sleep(sleepINT);
    
    var email_status = sheet.getRange("C4").getValue();
    
    if (email_status == "YES" ) {
        //send a pdf copy to customer 
        var pdfEMAIL = DriveApp.getFileById(doc.getId()).getAs('application/pdf').getBytes();
      var emailName = sheet.getRange("A11").getValue()
      var emailToName = emailName; // add designer name here
        var message = "Hi " + emailToName + "!, please find " + usernamefordoctitle + "'s project proposal attached. Reply to this email if you run into any issues.";
        var emailAdd = sheet.getRange("A10").getValue()
        var emailTo = emailAdd; // add designer email here
        var subject = "Proposal for " + usernamefordoctitle + " by" + emailToName + " - Proposal No: " + newInvNumber;
        
        var attach = {fileName:"PROPOSAL " + newInvNumber + " " + usernamefordoctitle + '.pdf',content:pdfEMAIL, mimeType:'application/pdf'};
        MailApp.sendEmail(emailTo, subject, message, {attachments:[attach]});
        ss.toast("70%: emailed customer");
        Utilities.sleep(sleepINT);
        
        }
        
    else {
        
        ss.toast("No email sent");
        
        }
      }
  

  Utilities.sleep(sleepINT);
  ss.toast("90%: feeding the unicorns some more")
  Utilities.sleep(sleepINT);
  ss.toast("100%: high-fiving the neighbour")
  Utilities.sleep(sleepINT);
  ss.toast("SUCCESS Invoice " + newInvNumber + " has been created. It's in a new doc with the ID " + docid); 
  Utilities.sleep(10000);
}

当我运行这个脚本时,一切都按预期工作并且电子邮件被发送。 当我尝试使用已安装的触发器时,它给了我以下错误:

Exception: Invalid argument: id at replaceTextToImage(Code:35:25) at CreatePro2(Code:62:5)

我不懂 javascript,所以我只是通过反复试验拼凑起来,所以我为混乱的代码道歉。

我可以使用不会导致此问题的替代触发方法吗?

任何帮助将不胜感激!

【问题讨论】:

  • 你能用 Logger.log()/console.log() var Image 吗?因为错误告诉你它不是一个无效的 id。
  • 我猜测 body、searchtext 和 fileId 是全局变量,并且在触发器上运行时它们可能不会被初始化。尝试将它们放入函数中。另外我会用标准的循环语法替换 (var i in data) 你应该只使用该语法来通过对象中的键进行交互。
  • 你好@AFischer!除了@Salix 和@Cooper 的要求,您能否查看replaceTextToImage(body, '%IMAGE%', Image); 行?代码可能需要 Image 变量中的图像标识符,但提供的标识符可能有问题。为防止出现这种情况,请尝试对经过验证的 id 进行硬编码。
  • 感谢您的回复! @Salix 我该如何实现那个记录器?
  • 感谢@Cooper!我将如何将它们放入函数中?就像我说的,我一般不懂 javascript 或编程,所以把这些放在一起一直让我很紧张。

标签: google-apps-script google-sheets google-forms


【解决方案1】:

我说的是这一行:

var replaceTextToImage = function(body, searchText, fileId) {

在我对它们做任何事情之前,我需要看看它们是如何定义的。因此,您将不得不更加努力地找到并分享这些声明。

我们需要在这里解决未定义的变量。参考我的cmets。

function CreatePro2() {
  var sleepINT = 1500
  var templateid = "XXXXXXXXXXXXXXXXXX";
  var ss = SpreadsheetApp.getActive(); 
  var sheet = ss.getActiveSheet();
  var data = sheet.getRange(2,1,1,23).getValues();
  var oldInvoiceNumber = sheet.getRange("G2").getValue();
  oldInvoiceNumber += 1;
  sheet.getRange("G2").clear();
  sheet.getRange("G2").setValue(oldInvoiceNumber);
  sheet.getRange("G2").setBackgroundColor("#cecece");
  var newInvNumber = sheet.getRange("G2").getValue();
  for (var i=0;i<data.length;i++) {
    var replaceTextToImage = function(body, searchText, fileId) {//body,searchText and fileId undefined
      var width = 590;
      var blob = DriveApp.getFileById(fileId).getBlob();//fileId is undefined
      var r = body.findText(searchText).getElement();//searchText is undefined
      r.asText().setText("");
      var img = r.getParent().asParagraph().insertInlineImage(0, blob);
      var w = img.getWidth();
      var h = img.getHeight();
      img.setWidth(width);
      img.setHeight(width * h / w);
    }
    var row = data[i];
    var docid = DriveApp.getFileById(templateid).makeCopy().getId();
    var doc = DocumentApp.openById(docid);
    var body = doc.getActiveSection();//Who is making the selection?
    var Image = row[10].split("=")[1];
    var selectBody = doc.getBody();    
    body.replaceText("%NAME%", row[0]);//body is undefined
    body.replaceText("%ADD_LN1%", row[1]);
    body.replaceText("%EMAIL%", row[2]);
    body.replaceText("%PHONE%", row[3]);
    body.replaceText("%DATE%", row[4]);
    body.replaceText("%EXPDATE%", row[5]);
    body.replaceText("%INV_NUM%", row[6] +=1);
    body.replaceText("%PTOTAL%", row[7]);
    body.replaceText("%DESC1%", row[8]);
    body.replaceText("%FEE1%", row[9]);  
    replaceTextToImage(body, '%IMAGE%', Image);
    doc.saveAndClose();
    var file = DriveApp.getFileById(doc.getId());
    var newfolder = DriveApp.getFolderById("YYYYYYYYYYYYYYYYYYYY");
    var oldfolder = DriveApp.getFolderById("ZZZZZZZZZZZZZZZZZZZZ");
    newfolder.addFile(file);
    oldfolder.removeFile(file);    
    var usernamefordoctitle = sheet.getRange(2, 1, 1, 1).getValues();
    var name = doc.getName();
    doc.setName(newInvNumber + ' - Invoice for ' + usernamefordoctitle);    
    var pdffolder = DriveApp.getFolderById("***************");
    var pdfFILE = DriveApp.getFileById(doc.getId()).getAs('application/pdf');
    pdfFILE.setName(doc.getName() + ".pdf");
    var theFolder = pdffolder;
    var theFile = DriveApp.createFile(pdfFILE);
    theFolder.addFile(theFile);    
    var email_status = sheet.getRange("C4").getValue();
    if (email_status == "YES" ) {
      var pdfEMAIL = DriveApp.getFileById(doc.getId()).getAs('application/pdf').getBytes();
      var emailName = sheet.getRange("A11").getValue()
      var emailToName = emailName;
      var message = "Hi " + emailToName + "!, please find " + usernamefordoctitle + "'s project proposal attached. Reply to this email if you run into any issues.";
      var emailAdd = sheet.getRange("A10").getValue()
      var emailTo = emailAdd;
      var subject = "Proposal for " + usernamefordoctitle + " by" + emailToName + " - Proposal No: " + newInvNumber;      
      var attach = {fileName:"PROPOSAL " + newInvNumber + " " + usernamefordoctitle + '.pdf',content:pdfEMAIL, mimeType:'application/pdf'};
      MailApp.sendEmail(emailTo, subject, message, {attachments:[attach]});
    } else {
      ss.toast("No email sent");
    }
  }
}

您不是程序员且不懂 javascript 的事实可能需要您聘请某人来帮助您,但我无法解决我无法生成的问题,也无法移动我不知道的声明无权访问,所以你必须这样做。

【讨论】:

    【解决方案2】:

    所以我注意到代码正在使用活动电子表格。根据您的触发器是什么,是否有可能不是您想要的活动电子表格?

    当您从脚本编辑器运行脚本时,您通常会从与其关联的电子表格中打开它,这意味着活动的电子表格始终是正确的。

    我建议您直接打开电子表格。这样您就可以确定始终拥有正确的电子表格。

    您可以通过将var ss = SpreadsheetApp.getActiveSpreadsheet(); 更改为var ss = SpreadsheetApp.openById(id); doc 来使用id 来完成此操作

    或使用网址:var ss = SpreadsheetApp.openByUrl(url);doc

    如果它发生变化,您也可以像稍后在代码中那样搜索文件并使用以下命令打开文件:var ss = SpreadsheetApp.open(file);doc


    [编辑] 我注意到的另一件事,但这应该在运行脚本时给你一个错误,而不仅仅是安装的触发器......这里是这一行: //sheet.getRange("F7").setValue('=IMAGE("https://s-media-cache-ak0.pinimg.com/564x/58/5d/8f/585d8f802867c25df8f1ecc0cf7cadc8.jpg",1)')

    如果您获取 Image 的 fileId 的单元格内容相似,那将是一个问题。 由于您将 Image 定义为 var Image = row[10].split("=")[1];,这意味着 ID 是 '=' 之后的内容,但 'IMAGE("https://s-media-cache-ak0.pinimg.com/564x/58/5d/8f/585d8f802867c25df8f1ecc0cf7cadc8 .jpg",1)' 不是 ID。

    你能告诉我们第[10]行的内容是什么吗?


    如果这不是它获取错误图像 ID 的原因,您需要进行一些调试并检查您的变量是否与您认为的一样:

    您可以使用Logger.log(data) 记录您要检查的变量。只需确保在定义该变量后完成。 doc

    如果您这样做,请在您的问题中分享结果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-06-08
      • 2023-01-02
      • 2023-03-06
      • 1970-01-01
      • 2019-04-13
      • 2019-04-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多