Google 用于在电子表格中添加 csv 的电子表格自定义函数

Google Spreadsheet custom function to add csv in spreadsheet

我正在使用 Google 电子表格,在我的 google 电子表格中,我想从我的 RESTful 网络服务导入数据。

我无法使用 =IMPORTDATA,因为我需要向 url 添加一个 header 以进行身份​​验证。

这是我目前拥有的自定义函数:

function fetchFromUrl() {
  var url = "https://disclosedurl";
  var response = UrlFetchApp.fetch(url, {
    "headers": {
      "Authorization": "OAUTH token",
    }
  });
  var result = response.getContentText();

  var csvData = CSVToArray(result, ",");
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getActiveSheet();

  for (var i = 0; i < csvData.length; i++) {
    sheet.getRange(i+9, 1, 1, csvData[i].length).setValues(new Array(csvData[i]));
  }
}

当我从电子表格中的单元格调用此函数时,出现此错误。

Error: You do not have permission to call setValues (line 56).

我看到这个问题经常出现,但我一直无法修复它。是否有更好的方法来完成此操作,或者我是否在我的自定义函数中遗漏了一些授予权限的内容?

编辑:因为我没有您的源数据,所以我继续随机获取 CSV 文件,只是为了测试您拥有它的方式,但这并不容易。这将是一个非常草率的解决方法,并不值得。

您为什么选择在这种情况下尝试自定义公式?

我在下面复制的脚本与您所做的很接近,但导入的是电子表格而不是 CSV。

function DoStuff(All) 
{
  var sheet    = SpreadsheetApp.getActive().getSheetByName('Main');          //Syncs sheet by name into var
  var StartRow = 33;
  var StartCol = 1;
  var AddRows  = 12;
  var AddCols  = 3;
  var DD     = sheet.getSheetValues(StartRow,StartCol,AddRows,AddCols);    //Build array from data off of sheet into variable -- getSheetValues(Row,Col,Add-Rows,Add-Cols)
  for (var i = 0, DDL = DD.length; i < DDL; i++)                                      //Builds 2d Looping-Array to allow choosing of columns at a future point
    {
      var col     = DD[i];                                                   //Retrieves all columns from array
      var SheetID = col[1];                                                    //Returns certain column (Starts counting columns at 0)
      var ImportedSheet = col[2];                                              //Returns certain column (Starts counting columns at 0)
      var TimeFrame = col[0];                                                  //Returns certain column (Starts counting columns at 0)
      var FuncName = "DoStuff";
      var ImportedSheetEmpty = isEmpty_(ImportedSheet)  
      var SheetIDEmpty = isEmpty_(SheetID)  
      if (SheetIDEmpty == false && ImportedSheetEmpty == true) 
      { 
        var CurrentEmpty = getFirstEmptyRowUsingArray_('Database');
        var LocNum    = SpreadsheetApp.openById(SheetID).getSheetByName('Sheet1').getRange('J2:J').getValues();
        var LocNum    = cleanArray_(LocNum);
        var TotInvAmt = SpreadsheetApp.openById(SheetID).getSheetByName('Sheet1').getRange('H2:H').getValues();
        var InvDate   = SpreadsheetApp.openById(SheetID).getSheetByName('Sheet1').getRange('F2:F').getValues();
        var DistNTax  = SpreadsheetApp.openById(SheetID).getSheetByName('Sheet1').getRange('N2:S').getValues();
        var DistNTax  = SumColArray_(DistNTax);
        SpreadsheetApp.getActive().getSheetByName('Database').getRange(CurrentEmpty,3,LocNum.length,   LocNum[0].length   ).setValues(LocNum).setNumberFormat('@STRING@');      //getRange(Row,Col,RowAdd,ColAdd)
        SpreadsheetApp.getActive().getSheetByName('Database').getRange(CurrentEmpty,4,TotInvAmt.length,TotInvAmt[0].length).setValues(TotInvAmt);   //getRange(Row,Col,RowAdd,ColAdd)
        SpreadsheetApp.getActive().getSheetByName('Database').getRange(CurrentEmpty,6,InvDate.length,  InvDate[0].length  ).setValues(InvDate);     //getRange(Row,Col,RowAdd,ColAdd)
        for (var d = 0; d < LocNum.length; d++)                                    //Builds 2d Looping-Array to allow choosing of columns at a future point
        {
          SpreadsheetApp.getActive().getSheetByName('Database').getRange(CurrentEmpty + d,1).setValue(FuncName);    //getRange(Row,Col,RowAdd,ColAdd)
          SpreadsheetApp.getActive().getSheetByName('Database').getRange(CurrentEmpty + d,2).setValue(TimeFrame);   //getRange(Row,Col,RowAdd,ColAdd)
          SpreadsheetApp.getActive().getSheetByName('Database').getRange(CurrentEmpty + d,5).setValue(DistNTax[d]);   //getRange(Row,Col,RowAdd,ColAdd)
        }
        sheet.getRange(StartRow + i, 3).setValue("Successful");
      }
    }
  if(All!=1)
  {
    UpdateDashboard();
  }
  SpreadsheetApp.flush();                                            //Applies all pending Spreadsheet changes
}

以下是我在项目中包含在单独的 .GS 文件中以执行操作的所有辅助函数。

//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`
// Subtract Days from Date Function
//
// if 'TimeFrame' is 7/20/2016 from 'var TimeFrame = col[0];' in a loop and you want to email someone 10 days before that date you would:
// subDaysFromDate_(TimeFrame,'10')
// would return 7/10/2016 

function subDaysFromDate_(date,d)
{
    if ( Object.prototype.toString.call(date) === "[object Date]" ) 
  { //date it is a date object
    if ( isNaN( date.getTime() ) ) 
    {  // d.valueOf() could also work
      Logger.log('Inbound date error #1: ' + date);  // date is not valid
      return
    }
    else 
    {
      var result = new Date(date.getTime()-d*(24*3600*1000));
      return result
      }
  }
  else
  {
    Logger.log('inbound date error #2: ' + date);
    return
  }
}

//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`



//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`
//Script Based ImportRange

//Example importRange_('0AodPsgg.......................','Sheet1','A:G','Common','C7','y')
//Explanation importRange_('Importing Spreadsheet Key','Importing Spreadsheet Tab Name','Importing Spreadsheet Tab's Range','Destination Spreadsheet Tab Name','Destination Spreadsheet Tab's placement','Will add note to the first cell of import')

function importRange_(Source_Key,Source_Sheet,Source_Range,Set_Sheet,Set_Pos,Add_Note) 
{
  var Load = SpreadsheetApp.openById(Source_Key).getSheetByName(Source_Sheet).getRange(Source_Range).getValues();
  var Name = SpreadsheetApp.openById(Source_Key).getName();
  var RowVal = SpreadsheetApp.getActive().getSheetByName(Set_Sheet).getRange(Set_Pos).getRow();
  var ColVal = SpreadsheetApp.getActive().getSheetByName(Set_Sheet).getRange(Set_Pos).getColumn();
  if(Add_Note.toUpperCase() == 'Y')
  {
    SpreadsheetApp.getActive().getSheetByName(Set_Sheet).getRange(RowVal,ColVal,1,1).setNote("Import Script Updated On: " + Utilities.formatDate(new Date(), "PST", "MM-dd-yyyy hh:mm a")+"\nSS Name: "+Name+"\nRange: "+Source_Sheet+"!"+Source_Range+"\nSS Key: "+ Source_Key);      
  }
  SpreadsheetApp.getActive().getSheetByName(Set_Sheet).getRange(RowVal,ColVal,Load.length,Load[0].length).setValues(Load);
  SpreadsheetApp.flush();
  SpreadsheetApp.getActiveSpreadsheet().toast('At: '+Set_Sheet+'!'+Set_Pos,'Import Completed:');
}
//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`



//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`
//--//Dependent on isEmpty_()
//Find Last Row on Database
function getFirstEmptyRowUsingArray_(sheetname) 
    {
      var data = SpreadsheetApp.getActive().getSheetByName(sheetname).getDataRange().getValues();
      for(var n = data.length ; n<0 ;  n--)
      {
        if(isEmpty_(data[n][0])=false)
        {
          n++;
          break;
        }
      }
      n++
        return (n);
    }
//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`



//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`
//--//Dependent on isEmpty_()
// Blank Array Extractor/Rebuilder
function cleanArray_(actual)
{
    var newArray = new Array();
    for(var i = 0, aL = actual.length; i<aL; i++)
    {
        if (isEmpty_(actual[i]) == false)
        {
            newArray.push(actual[i]);
        }
    }
    return newArray;
}
//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`



//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`
// Even/Odd
function isEven_(value) {
    if (value%2 == 0)
        return true;
    else
        return false;
}
//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`



//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`
//--//Dependent on cleanArray_()
// Array Col Sum Agent
function SumColArray_(sumagent)
{
    var newArray = new Array();
    for(var i = 0, sL = sumagent.length; i<sL; i++)
    {
       var totalsum = 0
       var CleanForSum = cleanArray_(sumagent[i]);
       for(var d = 0, CFSL = CleanForSum.length; d<CFSL; d++)
       {  
        totalsum += CleanForSum[d];
       }
      newArray.push(Math.round(totalsum));
    }
    return newArray;
}
//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`



//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`
// Empty String Check
function isEmpty_(string) 
{

    if(!string)             return true;         
    if(string == '')        return true;
    if(string === false)    return true; 
    if(string === null)     return true; 
    if(string == undefined) return true;
    string = string+' '; // check for a bunch of whitespace
    if('' == (string.replace(/^\s\s*/, '').replace(/\s\s*$/, ''))) return true;       
    return false;        
}
//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`



//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`
//--//Dependent on isEmpty_() && getFirstEmptyRowUsingArray_()
// Script Look-up
/*
Benefit of this script is:
-That google sheets will not continually do lookups on data that is not changing with using this function
-Unlike Vlookup you can have it look at for reference data at any point in the row.  Does not have to be in the first column for it to work like Vlookup.

Useage:

var LocNum    = SpreadsheetApp.openById(SheetID).getSheetByName('Sheet1').getRange('J2:J').getValues();
FinderLookUpReturnArrayRange_(LocNum,0,'Data','A:G',[3],'test',1,1,'No');


-Loads all Locations numbers from J2:J into a variable 
--looks for Location Numbers in Column 0 of Referance sheet and range eg "Data!A:G"
---Returns results to Column 3 of Target Sheet and range eg "test!A1" or "1,1"

*/


function FinderLookUpReturnArrayRange_(Search_Key,SearchKey_Ref_IndexOffSet,Ref_Sheet,Ref_Range,IndexOffSetForReturn,Set_Sheet,Set_PosRow,Set_PosCol,ReturnMultiResults)   
{
  var twoDimensionalArray = [];
  var data = SpreadsheetApp.getActive().getSheetByName(Refv_Sheet).getRange(Ref_Range).getValues();         //Syncs sheet by name and range into var
  for (var i = 0, Il=Search_Key.length; i<Il; i++)                                                         // i = number of rows to index and search  
  {
    var Sending = [];                                                                                      //Making a Blank Array
    var newArray = [];                                                                                     //Making a Blank Array
    var Found ="";
    for (nn=0,NNL=data.length;nn<NNL;nn++)                                                                 //nn = will be the number of row that the data is found at
    {
      if(Found==1 && ReturnMultiResults=='No')                                                                                         //if statement for found if found = 1 it will to stop all other logic in nn loop from running
      {
        break;                                                                                             //Breaking nn loop once found
      }
      if (data[nn][SearchKey_Ref_IndexOffSet]==Search_Key[i])                                              //if statement is triggered when the search_key is found.
      {
        var newArray = [];
        for (var cc=0,CCL=IndexOffSetForReturn.length;cc<CCL;cc++)                                         //cc = numbers of columns to referance
        {
          
          var iosr = IndexOffSetForReturn[cc];                                                             //Loading the value of current cc
          var Sending = data[nn][iosr];                                                                    //Loading data of Level nn offset by value of cc
          if(isEmpty_(Sending)==true)                                                                      //if statement for if one of the returned Column level cells are blank
          {
          var Sending =  "#N/A";                                                                           //Sets #N/A on all column levels that are blank
          }
          if (CCL>1)                                                                                       //if statement for multi-Column returns
          {
            
            newArray.push(Sending);
            if(CCL-1 == cc)                                                                                //if statement for pulling all columns into larger array
            {
              twoDimensionalArray.push(newArray);
              //Logger.log(twoDimensionalArray);
              var Found = 1;                                                                              //Modifying found to 1 if found to stop all other logic in nn loop
              break;                                                                                      //Breaking cc loop once found
            }
          }
          else if (CCL<=1)                                                                                 //if statement for single-Column returns
          {
            twoDimensionalArray.push(Sending);
            var Found = 1;                                                                                 //Modifying found to 1 if found to stop all other logic in nn loop
            break;                                                                                         //Breaking cc loop once found
          }
        }
      }
      if(NNL-1==nn && isEmpty_(Sending)==true)                                                             //following if statement is for if the current item in lookup array is not found.  Nessessary for data structure.
      {
        for(var na=0,NAL=IndexOffSetForReturn.length;na<NAL;na++)                                          //looping for the number of columns to place "#N/A" in to preserve data structure
        {
          if (NAL<=1)                                                                                      //checks to see if it's a single column return
          {
            var Sending = "#N/A";
            twoDimensionalArray.push(Sending);
          }
          else if (NAL>1)                                                                                  //checks to see if it's a Multi column return
          {
            var Sending = "#N/A";
            newArray.push(Sending);
          }
        }
        if (NAL>1)                                                                                         //checks to see if it's a Multi column return
        {
          twoDimensionalArray.push(newArray);  
        }
      }
    }
  }
  if(typeof Set_PosRow != "number")                                                                        //checks to see if what kinda of variable Set_PosRow is.  if its anything other than a number it will goto next avaible row
  {
    var Set_PosRow = getFirstEmptyRowUsingArray_(Set_Sheet);                                               //for usage in a database like entry without having to manually look for the next level.
  }
  for (var l = 0,lL=Search_Key.length; l<lL; l++)                                                          //Builds 2d Looping-Array to allow choosing of columns at a future point
  {
    if (CCL<=1)                                                                                            //checks to see if it's a single column return for running setValue
    {
      SpreadsheetApp.getActive().getSheetByName(Set_Sheet).getRange(Set_PosRow + l,Set_PosCol).setValue(twoDimensionalArray[l]);
    }
  }
    if (CCL>1)                                                                                             //checks to see if it's a multi column return for running setValues
    {
      SpreadsheetApp.getActive().getSheetByName(Set_Sheet).getRange(Set_PosRow,Set_PosCol,twoDimensionalArray.length,twoDimensionalArray[0].length).setValues(twoDimensionalArray);
    }
  SpreadsheetApp.flush();
}
//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`



//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`
//--//Dependent on pad_()

//Build a list of warehouse email address.

//example 'var CHeckMails = WhseEmailPasser_(LocNum,["GM","ADMIN","SHOP"],"W");'
function WhseEmailPasser_(IncomingWhseNum, WhseEmails, WorD)
{
  var EmailArray = [];  
  if (IncomingWhseNum < 1000)
  {
    var PadWhseNum = pad_(IncomingWhseNum,3);
  }
  else if (IncomingWhseNum >= 1000)
  {
    var PadWhseNum = pad_(IncomingWhseNum,5);
  }
  for(var w=0, wL = WhseEmails.length; w<wL; w++)
  {
    var CurrentEmail = WhseEmails[w].toUpperCase();
    if(CurrentEmail=="HR")
    {
      var Email = CurrentEmail + PadWhseNum + "@Company.COM"; 
      EmailArray.push(Email);
      continue;
    }
    var Email = WorD + PadWhseNum + CurrentEmail + "@Company.COM";
    EmailArray.push(Email);
  }
  EmailArray.push("");  //Needed for the last comma when used in emailer function.
  return EmailArray.toString();
}
//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`


//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`
// Pad a number with x amound of Zero

//example 'var PadWhseNum = pad_(IncomingWhseNum,5);'
function pad_(n, width, z)
{
  z = z || '0';
  n = n + '';
  return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
}
//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`


//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`
function frenchDate_(date) 
{
  if ( Object.prototype.toString.call(date) === "[object Date]" ) 
  { //date it is a date object
    if ( isNaN( date.getTime() ) ) 
    {  // d.valueOf() could also work
      Logger.log('Inbound date error #1: ' + date);  // date is not valid
      return
    }
    else 
    {
      var month = ['janvier','février','mars','avril','mai','juin','juillet','août','septembre','octobre','novembre','décembre'];
      var day = ['dimanche','lundi','mardi','mercredi','jeudi','vendredi','samedi'];
      var m = month[date.getMonth()];
      var d = day[date.getDay()];
      var dateStringFr = d+' '+date.getDate()+' '+m+' '+date.getFullYear();
      return dateStringFr
    }
  }
  else
  {
    Logger.log('inbound date error #2: ' + date);
    return
  }
}
  
/*
you want to use the following format:

le xxxxx 15 cccc 2015.

replace xxxxx with days  (no capitals for weekdays in french)

Monday = lundi
Tuesday = mardi
Wednesday = mercredi
Thursday = jeudi
Friday = vendredi
Saturday = samedi
Sunday = dimanche

replace cccc with the month ( again, no capital )
January = janvier
February = février 
March = mars
April = avril
May = mai
June = juin
July = juillet
August = août
September = septembr
October = octobre 
November = novembre
December = décembre 
*/
//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`



//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`
//--//Dependent on getColumnOffsetOfCurrentParameter_()
//Script version to conditional Formatting.
//e.g. 'setRowColors_('Status',0);'
function setRowColors_(TargetColumnHeaderContent,TargetRowForHeader)
{
  var range = SpreadsheetApp.getActiveSheet().getDataRange();
  var TargetColumnOffset = getColumnOffsetOfCurrentParameter_(TargetColumnHeaderContent,TargetRowForHeader);
  if (typeof TargetColumnOffset === 'undefined')
  {
    Logger.log("Column Header not found");
    return
  }
  for (var i = range.getRow(); i < range.getLastRow(); i++) 
  {
    var rowRange = range.offset(i, 0, 1);
    var status = rowRange.offset(0, TargetColumnOffset).getValue();
    if (status == 'Completed')
    {
      rowRange.setBackgroundColor("#DEAD01");  //goldenRod
    }
    else if (status == 'In Progress')
    {
      rowRange.setBackgroundColor("#FFDD88");  //Dim Yellow
    }
    else if (status == 'Not Started')
    {
      rowRange.setBackgroundColor("#CC6666");  //maroon 
    }
  }
}
//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`


//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`
//Returns the offset value of the column (Row 1) titled "Status"
//(eg, if the 7th column is labeled "Status", this function returns 6)
function getColumnOffsetOfCurrentParameter_(ColumnHeader,Row)
{
  Row = typeof Row !== 'undefined' ? Row : 0;  //Pre-Defined Row 1 as the title line if user does not load the second parameter with a Row Number call.
  var lastColumn = SpreadsheetApp.getActiveSheet().getLastColumn();
  var range = SpreadsheetApp.getActiveSheet().getRange(1,1,1,lastColumn);
  for (var i = 0; i < range.getLastColumn(); i++)
  {
    if (range.offset(Row, i, 1, 1).getValue() == ColumnHeader)
    {
      return i;
    }
  }
}
//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`



//~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`~,~`

我猜这种方法行不通,基于这篇文章,其他人也面临着同样的问题。我采用了图像解决方法,将脚本分配给图像并在您按下图像时被调用。

The following error message is displayed: You do not have permission  
to call setValue. The reason as to why it’s not allowed is beyond me but
the same question was asked on the Google support forums where a Google 
employee simply stated it wasn’t possible. The workarounds that he 
suggested were “…running your script inside the editor, or from a drawing

Link供参考:http://jonrh.is/oddities-in-scripting-for-google-docs-spreadsheet/