Spreadsheet.flush is not working properly on my Google Apps Script - google-apps-script

Here are my 2 spreadsheets:
Gsheet1: Googlesheet for replication (only employee # and employee name would change)
Gsheet2: Config sheet (contains the employee #, employee name, replication status, pubHTML link) that would feed employee # and employee name on Gsheet1
So I have this code that have these functionalities below:
Replicate Gsheet1 depending on the number of employees (I currently have 800+ employees) on Gsheet2 and dump it to a google drive folder.
after replication, will set a "completed" replication status to Gsheet2.
Change the revision properties of the replicated sheet and make it published to web.
Get the link of the published web (pubhtml) and put it on Gsheet2 pubHTML link column.
What happens is when I try to logger.log the results of this code below assuming that I have 2 records on my Gsheet2, it loops three times, the first and third record in loop are the same.
var TemplatesFromDrive = DriveApp.getFolderById(SpreadsheetApp.getActive().getSheetByName("Master Config").getRange("B2").getValue()).getFiles();
while (TemplatesFromDrive.hasNext()) {
var File = TemplatesFromDrive.next();
Logger.log(File.getName());
I was thinking if it's because of the Spreadsheet.flush() that I'm missing. Where is the best place where I can put it on my code so my loop will work properly? Below is my full code.
function replicateCards() {
var ss = SpreadsheetApp.openById('Gsheet2-xxxx');
var copyCard = SpreadsheetApp.openById('Gsheet1-xxxx');
var getID = DriveApp.getFileById(copyCard.getId())
var card = copyCard.getSheetByName("Card");
var mastersheet = ss.getSheetByName("Mastersheet");
var employeeNumber2 = ss.getRange("A2:A").getValues;
var getLastRow = mastersheet.getLastRow();
var destinationFolder = DriveApp.getFolderById('googledrivefolder-xxx');
var changeColorToGrayList = card.getRangeList(['C7', 'E7', 'G7', 'I7', 'K7', 'M7', 'O7', 'Q7',
'C9', 'E9', 'G9', 'I9', 'K9', 'M9', 'O9', 'Q9',
'C11', 'E11', 'G11', 'I11', 'K11', 'M11', 'O11', 'Q11']);
var setValueToZero = card.getRangeList(['C8', 'E8', 'G8', 'I8', 'K8', 'M8', 'O8', 'Q8',
'C10', 'E10', 'G10', 'I10', 'K10', 'M10', 'O10', 'Q10',
'C12', 'E12', 'G12', 'I12', 'K12', 'M12', 'O12', 'Q12']);
for (i = 1; i < getLastRow; i++) {
var badgeStatus = mastersheet.getRange(i + 1, 5).getValue();
if (badgeStatus == "") {
var employeeNumber = mastersheet.getRange(i + 1, 1).getValue();
var employeeName = mastersheet.getRange(i + 1, 2).getValue();
copyCard.getRange("H3").setValue(employeeNumber);
copyCard.getRange("C3").setValue(employeeName);
SpreadsheetApp.flush();
getID.makeCopy(employeeNumber, destinationFolder);
mastersheet.getRange(1 + i, 5).setValue("completed");
SpreadsheetApp.flush();
var files = DriveApp.getFolderById(SpreadsheetApp.openById("Gsheet1-xxxx").getSheetByName("Config Sheet").getRange("B1").getValue()).getFiles();
while (files.hasNext()) {
var file = files.next();
Logger.log(file.getName());
var Found = false;
for (var j = 0; j < employeeNumber2.length; i++) {
if (employeeNumber2[j][0] == file.getName()) {
Found = true;
}
}
if (Found) {
continue;
}
try {
var fileId = file.getId();
var fileName = file.getName();
var revisions = Drive.Revisions.list(fileId);
var lastRevisionId = revisions.items[revisions.items.length - 1].id;
// get the resource and set the publish parameters
var resource = Drive.Revisions.get(fileId, lastRevisionId);
// Logger.log(resource);
resource.published = true;
resource.publishAuto = true;
resource.publishedOutsideDomain = true;
// publish to the web
Drive.Revisions.update(resource, fileId, lastRevisionId);
SpreadsheetApp.flush();
var openByID = SpreadsheetApp.openById(fileId);
SpreadsheetApp.flush();
var googleDriveSheet = openByID.getUrl().replace("edit", "pubhtml"); // or replace("edit", "pub");
SpreadsheetApp.flush();
mastersheet.getRange(1 + j, 9).setValue(googleDriveSheet);
SpreadsheetApp.flush();
} catch (err) {
Logger.log(err);
}
}
}
}
}

Change var getLastRow = mastersheet.getLastRow(); to var getLastRow = mastersheet.getLastRow()-1;
The reason why is because you've started to get your data from the
second row.
If you would start at the third, you should do var getLastRow = mastersheet.getLastRow()-2; ...

Related

Update a cell and return PDF file of the sheet

I've this spreadsheet that is of 2 sheets, Data nd Report.
function doPost(e) {
var DATA_SHEET = "Data";
var REPORT_SHEET = "Report";
var FILE_Id = "1sXSWMQfPkkwDS4lsSpnV2y54lhKFpdeY8brqyGtuc_k";
// Prevent concurrent access overwritting data
// we want a public lock, one that locks for all invocations
var lock = LockService.getPublicLock();
lock.waitLock(30000); // wait 30 seconds before conceding defeat.
// As we are passing JSON in the body, we need to unpairse it
var jsonString = e.postData.getDataAsString();
e.parameter = JSON.parse(jsonString);
try {
// next set where we write the data - you could write to multiple/alternate destinations
// var doc = SpreadsheetApp.openById(SCRIPT_PROP.getProperty("key"));
var doc = SpreadsheetApp.openById(FILE_Id);
var sheet = doc.getSheetByName(DATA_SHEET);
var report = doc.getSheetByName(REPORT_SHEET);
// we'll assume header is in row 1 but you can override with header_row in GET/POST data
var headRow = e.parameter.header_row || 1;
var headers = sheet.getRange(1, 1, 1, sheet.getLastColumn()).getValues()[0];
var lastRow = sheet.getLastRow()
var nextRow = lastRow + 1; // get next row
var row = [];
if(lastRow < 10){
RefID = "PRF.00" + lastRow
} else {
if(lastRow < 100){
RefID = "PRF..0" + lastRow
} else {
RefID = "PRF.." + lastRow
}
}
// loop through the header columns
for (i in headers){
if (headers[i] == "Ref"){ // special case if you include a 'Timestamp' column
row.push(RefID);
} else { // else use header name to get data
if (headers[i] == "Timestamp"){ // special case if you include a 'Timestamp' column
row.push(new Date());
} else { // else use header name to get data
row.push(e.parameter[headers[i]]);
}
}
}
// more efficient to set values as [][] array than individually
sheet.getRange(nextRow, 1, 1, row.length).setValues([row]);
/*********************************************/
// report.getRange("D4").setValue(RefID);
// Need to create the PDF here and send it back to the client
/*********************************************/
// return json success results
return ContentService
.createTextOutput(JSON.stringify({"result":"success", "row": nextRow}))
.setMimeType(ContentService.MimeType.JSON);
} catch(e){
// if error return this
return ContentService
.createTextOutput(JSON.stringify({"result":"error", "error": e}))
.setMimeType(ContentService.MimeType.JSON);
} finally { //release lock
lock.releaseLock();
}
}
The Report sheet looks like this:
And the Data sheet looks like this:
What I'm trying to do is:
[Done] Receiving data from client and post in the Data sheet, with assigning RefID and Timestamp which is done correctly.
[Done] Update the data in the merged cells (D4:F4) at the Report sheet with the latest RefID that had been added, I worked it withreport.getRange("D4").setValue(RefID);
[No idea how to make it] Once step 2 is done, some vlookup statements are working at the Report sheet, I want to generate a PDF from this sheet and send it back to the client.
UPDATE
I tried this to get the PDF, but did not work, it created copy of the sheet, but failed in converting the vlookup merged cells into text, and failed to generate the pdf file:
function printPDF() {
var file = SpreadsheetApp.openById(FILE_Id);
var sourceSheet = file.getSheetByName(REPORT_SHEET);
var folder = DriveApp.getFolderById(FOLDER_Id);
//Copy whole spreadsheet
var destSpreadsheet = SpreadsheetApp.open(DriveApp.getFileById(FILE_Id).makeCopy("tmp_convert_to_pdf", folder))
//delete redundant sheets
var sheets = destSpreadsheet.getSheets();
for (i = 0; i < sheets.length; i++) {
if (sheets[i].getSheetName() != REPORT_SHEET){
destSpreadsheet.deleteSheet(sheets[i]);
}
}
var destSheet = destSpreadsheet.getSheets()[0];
//replace cell values with text (to avoid broken references)
var sourceRange = sourceSheet.getRange(1,1,20,8);
var sourcevalues = sourceRange.getValues();
var destRange = destSheet.getRange(1, 1, 20, 8);
destRange.setValues(sourcevalues);
//save to pdf
var theBlob = destSpreadsheet.getBlob().getAs('application/pdf').setName(REPORT);
var newFile = folder.createFile(theBlob);
//Delete the temporary sheet
DriveApp.getFileById(destSpreadsheet.getId()).setTrashed(true);
}
Modification points:
If you want to make the additional script of printPDF() work correctly, please put SpreadsheetApp.flush() before the blob is retrieved from Spreadsheet.
In the case of the Google Docs (Document, Spreadsheet and Slides), when the blob is retrieved from the file, the format is automatically changed to PDF format. It seems that this is the current specification.
When above points are reflected to your script, it becomes as follows.
Modified script:
From:
var theBlob = destSpreadsheet.getBlob().getAs('application/pdf').setName(REPORT);
var newFile = folder.createFile(theBlob);
To:
SpreadsheetApp.flush(); // Added
var theBlob = destSpreadsheet.getBlob().setName(REPORT); // Modified. This is the same with destSpreadsheet.getBlob().getAs('application/pdf').setName(REPORT)
var newFile = folder.createFile(theBlob);
Then your full code be as:
function printPDF(RefID) {
var file = SpreadsheetApp.openById(FILE_Id);
var sourceSheet = file.getSheetByName(REPORT_SHEET);
sourceSheet.getRange("D4").setValue(RefID);
var folder = DriveApp.getFolderById(FOLDER_Id);
//Copy whole spreadsheet
var destSpreadsheet = SpreadsheetApp.open(DriveApp.getFileById(FILE_Id).makeCopy("tmp_convert_to_pdf", folder))
// Copy sheet data into values to avoid reference issues
var destSheet = destSpreadsheet.getSheetByName(REPORT_SHEET);
var sourceRange = sourceSheet.getRange(1,1,destSheet.getMaxRows(), destSheet.getMaxColumns());
var sourcevalues = sourceRange.getValues();
var destRange = destSheet.getRange(1, 1, destSheet.getMaxRows(), destSheet.getMaxColumns());
destRange.setValues(sourcevalues);
//delete redundant sheets
var sheets = destSpreadsheet.getSheets();
for (i = 0; i < sheets.length; i++) {
if (sheets[i].getSheetName() != REPORT_SHEET){
destSpreadsheet.deleteSheet(sheets[i]);
}
}
//save to pdf
SpreadsheetApp.flush(); // Added
var theBlob = destSpreadsheet.getBlob().setName(REPORT); // Modified. This is the same with
// destSpreadsheet.getBlob().getAs('application/pdf').setName(REPORT)
var newFile = folder.createFile(theBlob);
//Delete the temporary sheet
DriveApp.getFileById(destSpreadsheet.getId()).setTrashed(true);
}
Reference:
flush()
getBlob().getAs('application/pdf') will not work. You need to use a Google API for converting a sheet to PDF.
You need to do something along the following lines:
const url = `https://docs.google.com/spreadsheets/d/${FILE_Id}/export?exportFormat=pdf&format=pdf`;
const options = {
headers: {
Authorization: `Bearer ${ScriptApp.getOAuthToken()}`
}
};
const blob = UrlFetchApp.fetch(url, options).setName(`${REPORT}`);

Google Script on Attaching List of excel files from a Spreadsheet

I two spreadsheet Main and AddFiles wherein Add file has Two columns Subject and Attachments where under attachments is the list of excel file names with like file1.xlsx and file2.xlsx. Where I uploaded this file in my Google Drive under the Report folder.
I used the code below but always got an error on the last execution. It doesn't recognize the .getAs(MimeType.xlsx)
var sheet = SpreadsheetApp.getActiveSheet();
var dataRange = sheet.getRange(2,1,1,1)
data = dataRange.getValues()
var e = data[0][0]
for (var i = 0; i < (e-1); i++) {
draftmail();
}
function draftmail(){
var sheet = SpreadsheetApp.getActiveSheet();
var dataRange = sheet.getRange(1,1,1,1)
var data = dataRange.getValues()
var msg = data[0][0]
var sheet2 = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("AddFiles");
var startRowx = 1
var numRowx = 1
var dataRangeTox = sheet.getRange(startRowx,3,numRowx,1)
var datax = dataRangeTox.getValues()
for (x in datax) {
var rowx = datax[x];
var to = rowx[0];
var Starta = 2 + i
var numRowa = 1
var dataRangeToa = sheet2.getRange(Starta,1,1,1)
var dataa = dataRangeToa.getValues()
for (a in dataa) {
var rowa = dataa[a];
var subject = rowa[0];
var Startb = 2 + i
var numRowb = 1
var dataRangeTob = sheet2.getRange(Startb,2,1,1)
var datab = dataRangeTob.getValues()
for (b in datab) {
var rowb = datab[b];
var datafile = rowb[0];
var file = DriveApp.getFilesByName(datafile)
var startRowy = 1
var numRowy = 1
var dataRangeToy = sheet.getRange(startRowy,4,numRowy,1)
var datay = dataRangeToy.getValues()
for (y in datay) {
var rowy = datay[y];
var carboncopy = rowy[0];
if (file.hasNext()){
GmailApp.createDraft(to,subject,msg,{ cc: carboncopy}, {
attachments: [file[0].getAs(MimeType.xlsx)],
})
}
}
}
}
}
}
Modification points:
Assuming that everything else works properly in your code, you should make the following changes:
cc and attachments should be passed as a single json object.
file[0] should be file.next().
MimeType.xlsx should be MimeType.MICROSOFT_EXCEL.
Solution:
GmailApp.createDraft(to,subject,msg,
{ cc: carboncopy,
attachments: [file.next().getAs(MimeType.MICROSOFT_EXCEL)]
})
References:
Class GmailApp
Google Apps Script: XLSX from Gmail to Google Sheets: invalid mime type. Content type seems to be application/octet?
Class FileIterator
When you call
file = DriveApp.getFilesByName(datafile)
it returns a FileIterator collection, which is not indexed like an array (file[0]) but rather requires you to call file.next() to get the next file.
In addition, the MimeType Enum for an .xlsx file is MimeType.MICROSOFT_EXCEL.
So change
attachments: [file[0].getAs(MimeType.xlsx)]
to this instead:
attachments: [file.next().getAs(MimeType.MICROSOFT_EXCEL)]

How to optimize fileiterator (to avoid timeout) in Google Scripts

I am hitting the Google Scripts 6-minute timeout. The script is running through quite a few folders and subfolders. I am hoping that there is either (or both):
A way to optimize the script to more efficiently/intelligently run through the dataset/iterators?
A way to use a getContinuationToken()
Any help would be much appreciated!
I have tried to limit the number of folders/subfolders the script runs through. Even on a 'minimal' run, it times out. And FYI, my goal is to:
make a copy of files that are NOT owned by 'me'...
change the name of the original file (that was not owned by me) to be 'delete'
Here is the code:
FOLDERS = ["0B4FiuEqe8ftGb2lSbjJzakJDNWs"]; /*, "0B4FiuEqe8ftGN2YxZFU5RlhMSDQ", "0B4FiuEqe8ftGN2YxZFU5RlhMSDQ", "1D_1u_KwcLOsBuKyQ7NCsKDd8DB5JwOn6"];*/
function copyNonOwnedFiles() {
var arr = FOLDERS
for (var j = 0; j < arr.length; j++) {
var folderTOP = DriveApp.getFolderById(arr[j]);
var folders = folderTOP.getFolders();
var me = Session.getActiveUser().getEmail();
//RUN #1 = this runs through all of the subfolders
//iterator 1
while (folders.hasNext()) {
var folder = folders.next();
//get all files within these folders
var files = folder.getFiles();
//iterator 2
while (files.hasNext()) {
var file = files.next();
var Owner = file.getOwner().getEmail();
if( Owner !== me ){
var name = file.getName();
file.makeCopy(name);
file.setName('delete');
}
}
}
//RUN #2 = this runs through the parent folder
var files2 = folderTOP.getFiles();
//iterator 2
while (files2.hasNext()) {
var file2 = files2.next();
var Owner = file2.getOwner().getEmail();
if( Owner !== me ){
var name2 = file2.getName();
file2.makeCopy(name2);
file2.setName('delete');
}
}
}
}
Try this:
This script will find the files owned by the active user, in the folders with the listed ids and display them on a modeless dialog. This script will probably need to utilize lock service for multiple simultaneous users.
var myFiles=[];
var ids=["0B4FiuEqe8ftGb2lSbjJzakJDNWs", "0B4FiuEqe8ftGN2YxZFU5RlhMSDQ", "0B4FiuEqe8ftGN2YxZFU5RlhMSDQ", "1D_1u_KwcLOsBuKyQ7NCsKDd8DB5JwOn6"];
var me='';
function getMyFiles() {
myFiles=[];
me=Session.getActiveUser().getEmail();
for(var i=0;i<ids.length;i++) {
getFnF(DriveApp.getFolderById(ids[i]));
}
var html="<style>th,td{border:1px solid black;}</style><table><tr><th>Item</th><th>Name</th><th>Url</th></tr>";
for(var i=0;i<myFiles.length;i++) {
html+=Utilities.formatString('<tr><td>%s</td><td>%s</td><td>Link</td></tr>',i+1,myFiles[i].name,myFiles[i].url);
}
html+='</table><input type="button" value="Close" onClick="google.script.host.close();" />';
var userInterface=HtmlService.createHtmlOutput(html);
var title=Utilities.formatString('Files Owned by: %s',me);
SpreadsheetApp.getUi().showModelessDialog(userInterface, title)
}
function getFnF(folder) {
var folder= folder || DriveApp.getRootFolder();
var files=folder.getFiles();
while(files.hasNext()) {
var file=files.next();
if(file.getOwner().getEmail()==me) {
myFiles.push({name:file.getName(),url:file.getUrl()});
}
}
var subfolders=folder.getFolders()
while(subfolders.hasNext()) {
var subfolder=subfolders.next();
getFnF(subfolder);
}
}
for anyone who has this same question or a similar one... I found that it was much faster/easier/less resource intensive to use a search than a file iterator
dataSheetName = "List";
function onOpen(){
var ui = SpreadsheetApp.getUi();
ui.createMenu('Custom Menu')
.addItem('List Files', 'ListFiles')
.addSeparator()
.addToUi();
}
function ListFiles() {
var sheet = SpreadsheetApp.getActive();
var dataSheet = sheet.getSheetByName(dataSheetName);
// Clear Sheet
var lastRow = dataSheet.getLastRow();
if (lastRow > 0) {
dataSheet.getRange(2, 1, lastRow, dataSheet.getLastColumn()).clearContent();
}
dataSheet.getRange("E2").setValue("Process Started at: " + new Date());
Logger.log("Start: " + new Date());
// var row = ['File Name', 'File Id'];
var row = ['File Name', 'File Id'];
var data = [];
data.push(row);
// Find files modified in the last 24 hours
var totalDays = 30;
var today = new Date();
var oneDayAgo = new Date(today.getTime() - totalDays * 24 * 60 * 60 * 1000);
var startTime = oneDayAgo.toISOString();
// The magic search expression
var search = '(trashed = false) and (modifiedDate > "' + startTime + '") and not (title contains \'DELETE\') and not (\'me\' in owners) ';
// var search = "(mimeType='image/jpeg') and not (title contains 'DELETE') ";
// var search = " not ('me' in owners) and not (title contains 'DELETE') ";
// var search = " not ('me' in owners) ";
//var search = 'sharedWithMe';
// 'me' in owners
var i = 1;
var files = DriveApp.searchFiles(search);
Logger.log("2: " + new Date());
dataSheet.getRange("E3").setValue("Search Completed at: " + new Date());
// while (files.hasNext() && (i < 10000) {
while (files.hasNext() ) {
var file = files.next();
try {
// data.push([file.getName(),file.getId()]);
data.push([file.getName(), file.getId()]);
}
catch (e) {
Logger.log(file.getName());
}
// i += i;
}
// Write data
var dataRange = dataSheet.getRange(1, 1, data.length, row.length);
dataRange.setValues(data);
Logger.log("3: " + new Date());
dataSheet.getRange("E4").setValue("List Completed at: " + new Date());
}

Script for uploading web files (via links in Google Spreadsheet) to Google Drive

I'm trying to write script for Google Spreadsheet which will upload all files linked in column A (only URLs) to specific folder (which name is written in column B).
table example
I'm partially succesfull. I can upload first linked file. But I don't know how to edit this script to upload all the files. Where am I wrong?
This script was found here and edited by me.
function downloadFile() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Pokus");
var fileURLs = sheet.getRange(1, 1, sheet.getLastRow()).getValues();
var foldernames = sheet.getRange(1, 2, sheet.getLastRow()).getValues();
for (i = 0; i < fileURLs.length; i++) {
var response = UrlFetchApp.fetch(fileURLs[i], {muteHttpExceptions: true});
var rc = response.getResponseCode();
if (rc == 200) {
var fileBlob = response.getBlob();
var folder = DriveApp.getFoldersByName(foldernames[i]).next();
if (folder != null) {
var file = folder.createFile(fileBlob);
fileName = file.getName();
fileSize = file.getSize();
}
}
var fileInfo = { "rc":rc, "fileName":fileName, "fileSize":fileSize };
return fileInfo;
}
}
I'm beginner in writing scripts and I'm not experienced. Could someone help?
How about this modification?
Modification points :
There is return fileInfo; in for loop. So at 1st loop, it's returned from the function. By this, only first linked file can be uploaded.
All information can be retrieved by modifying fileInfo to an array.
Modified script :
function downloadFile() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Pokus");
var fileURLs = sheet.getRange(1, 1, sheet.getLastRow()).getValues();
var foldernames = sheet.getRange(1, 2, sheet.getLastRow()).getValues();
var fileInfo = []; // Added
for (i = 0; i < fileURLs.length; i++) {
var response = UrlFetchApp.fetch(fileURLs[i], {muteHttpExceptions: true});
var rc = response.getResponseCode();
if (rc == 200) {
var fileBlob = response.getBlob();
var folder = DriveApp.getFoldersByName(foldernames[i]).next();
if (folder != null) {
var file = folder.createFile(fileBlob);
fileName = file.getName();
fileSize = file.getSize();
}
}
fileInfo.push({ "rc":rc, "fileName":fileName, "fileSize":fileSize }); // Modified
}
return fileInfo; // Modified
}
Note :
When there are many upload files, an error might occur.
If I misunderstand your question, I'm sorry.

Force refresh ImportXML

I want to force an importXML to auto-refresh every five minutes. This is the script I am trying to run and getting the error "Bad value (line 7, file "RefreshImports" . I do not know why. I found it here: Periodically refresh IMPORTXML() spreadsheet function
function RefreshImports() {
var lock = LockService.getScriptLock();
if (!lock.tryLock(5000)) return; // Wait up to 5s for previous
refresh to end.
var id = "[YOUR SPREADSHEET ID]";
var ss = SpreadsheetApp.openById(id);
var sheet = ss.getSheetByName("[SHEET NAME]");
var dataRange = sheet.getDataRange();
var formulas = dataRange.getFormulas();
var content = "";
var now = new Date();
var time = now.getTime();
var re = /.*[^a-z0-9]import(?:xml|data|feed|html|range)\(.*/gi;
var re2 = /((\?|&)(update=[0-9]*))/gi;
var re3 = /(",)/gi;
for (var row = 0; row < formulas.length; row++) {
for (var col = 0; col < formulas[0].length; col++) {
content = formulas[row][col];
if (content != "") {
var match = content.search(re);
if (match !== -1) {
// import function is used in this cell
var updatedContent = content.toString().replace(re2, "$2update=" +
time);
if (updatedContent == content) {
// No querystring exists yet in url
updatedContent = content.toString().replace(re3, "?update=" + time +
"$1");
}
// Update url in formula with querystring param
sheet.getRange(row + 1, col + 1).setFormula(updatedContent);
}
}
}
}
// Done refresh; release the lock.
lock.releaseLock();
// Show last updated time on sheet somewhere
sheet.getRange(7, 2).setValue("Rates were last updated at " +
now.toLocaleTimeString())
}
In the code where it says "[YOUR SPREADSHEET ID]", I am to enter the name of my spreadsheet correct? I do not know anything about this.
On [YOUR SPREADSHEET ID] you should add the spreadsheet id, not it's name.
The spreadsheet id for
https://docs.google.com/spreadsheets/d/1Xhgfr3z4EwPtjS4aahytU_3TOVxjNb8JvHo88h3nZaE/edit#gid=14522064
is
1Xhgfr3z4EwPtjS4aahytU_3TOVxjNb8JvHo88h3nZaE
I found it easier to use the URL instead the id, here is the bit of code:
var url = "URL OF SPREADSHEET";
var sheetName = "NAME OF SPECIFIC SHEET";
var ss = SpreadsheetApp.openByUrl(url);
var sheet = ss.getSheetByName(sheetName);