Need help customising partially working google sheets app script - google-apps-script

I have the following code which I cobbled from answers
function myFunction() {
var sheetName = "QR CODE DATA"; // Sheet name
var folderId = "FOLDER NAME"; // Folder ID
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(sheetName);
var url = "https://api.qrserver.com/v1/create-qr-code/?size=120x120&data=";
var keys = ["-Tipo:", "-Ubicación:", "-# registro:", "-ID-C:", "-# Serial:", "-Pas:", "-Di I:", "-Asi:", "-RP:", "-Ar:"];
var values = sheet.getRange(2, 2, sheet.getLastRow() - 1, 11).getValues()
.filter(function(e) {return e.some(function(f) {return f})})
.map(function(row) { row.splice(4, 1); return row;
}); var length = values.length;
var reqs = values.map(function(e) {return {url: url + encodeURIComponent(keys.map(function(f, j) {return f + e[j]}).join("\r"))}});
var res = UrlFetchApp.fetchAll(reqs);
res.forEach(function(r, i) {
var blob = r.getBlob().setName(length == values.length ? "row" + (i + 2) + ".png" : "row" + (length + 1) + ".png");
DriveApp.getFolderById(folderId).createFile(blob); }); }
But this saves the PNG files into the directory as 'Row 2' 'Row 3' etc...
I would like this to use the data in Column A to name the files, but I dont know where to start.
Any help appreciated.

Answer for 1st question:
From your following question,
But this saves all of the files into the directory as 'Row 2' 'Row 3' etc...
I would like this to use the data in Column A to name the files
In this case, how about the following modification?
Modified script:
function myFunction() {
var sheetName = "QR CODE DATA"; // Sheet name
var folderId = "FOLDER NAME"; // Folder ID
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(sheetName);
var url = "https://api.qrserver.com/v1/create-qr-code/?size=120x120&data=";
var keys = ["-Tipo:", "-Ubicación:", "-# registro:", "-ID-C:", "-# Serial:", "-Pas:", "-Di I:", "-Asi:", "-RP:", "-Ar:"];
// -- Modified
var filteredValues = sheet.getRange(2, 1, sheet.getLastRow() - 1, 12).getDisplayValues()
.filter(function (e) { return e.some(function (f) { return f }) });
var filenames = filteredValues.map(function (r) { return r.splice(0, 1) });
var values = filteredValues.map(function (row) {
row.splice(4, 1);
return row;
});
// ---
var reqs = values.map(function (e) { return { url: url + encodeURIComponent(keys.map(function (f, j) { return f + e[j] }).join("\r")) } });
var res = UrlFetchApp.fetchAll(reqs);
res.forEach(function (r, i) {
var blob = r.getBlob().setName(filenames[i]); // Modified
DriveApp.getFolderById(folderId).createFile(blob);
});
}
When this script is run, the values are retrieved from the column "A" and they are used as the filenames of the files.
Answer for 2nd question:
I thought that the following question is your 2nd question. When I saw your 2nd question, unfortunately, it is largely different from your 1st question.
What I am trying to do is generate QR Codes from the values of a google sheet. The URL's that I wish to generate a QR Code for are located in Column B of a Sheet. Column A contains the name of the item the QR Code is for, so, I need to create a QR Code File as a PNG or JPEG and save it to a google drive folder, using the URL from column B, with the filename of column A
From this 2nd question, the sample script is as follows.
Sample script:
function myFunction() {
var sheetName = "QR CODE DATA"; // Sheet name
var folderId = "FOLDER NAME"; // Folder ID
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName(sheetName);
var values = sheet.getRange("A2:B" + sheet.getLastRow()).getDisplayValues().filter(([a, b]) => a && b);
var reqs = values.map(([, url]) => ({ url }));
var res = UrlFetchApp.fetchAll(reqs);
res.forEach(function (r, i) {
var blob = r.getBlob().setName(values[i][0]);
DriveApp.getFolderById(folderId).createFile(blob);
});
}

Related

Find matching value in a file for multiple spreadsheets

I have multiple spreadsheets in a folder, for each spreadsheet and I would like to get the matching data from an external file.
For example if my spreadsheet is called 'iphone 7' I would like to get in that sheet all the records from my external file containing 'iphone 7'
Here is how far I got (I am pretty new to scripting !) :
function myfunction()
{
var root = DriveApp.getFoldersByName("Produits");
while (root.hasNext())
{
var folder = root.next(); //If the folder is available, get files in the folder
var files = folder.getFiles();
while(files.hasNext()) //For each file,
{
var spreadsheet = SpreadsheetApp.open(files.next());
//import data from URL
var csvUrl = "https://incensy.tempurl.host/test-ct-flux.csv";
var csvContent = UrlFetchApp.fetch(csvUrl).getContentText();
var csvData = Utilities.parseCsv(csvContent);
var sheets = spreadsheet.getSheets()
var sheetIndex=0
var sheet = sheets[sheetIndex]
sheet.getRange(2, 1, csvData.length, csvData[0].length).setValues(csvData);
//Only keep data that contains the file name
var name = spreadsheet.getName();
let range = sheet.getDataRange(),
maxRows = sheet.getMaxRows(),
srchCol_1 = 2,
srchPatt_1 = new RegExp(name, "i"),
newRangeVals = range.getValues().filter(r => r[0] && srchPatt_1.exec(r[srchCol_1])),
numRows = newRangeVals.length;
range.clearContent();
sheet.getRange(2,1, numRows, newRangeVals[0].length).setValues(newRangeVals);
console.log('myfunction')
sheet.deleteRows(numRows + 1, maxRows - numRows);
}
}
}
There is something wrong in the second part of the code I cannot figure out.
In your situation, how about the following modification?
Modified script:
function myfunction() {
var keywords = ["sample1", "sample2"]; // Please set the keywords you want to filter to the column "C".
// Retrieve CSV data.
var csvUrl = "https://incensy.tempurl.host/test-ct-flux.csv";
var csvContent = UrlFetchApp.fetch(csvUrl).getContentText();
var csvData = Utilities.parseCsv(csvContent, ";");
// Retrieve Spreadsheet and put the CSV data.
var root = DriveApp.getFoldersByName("Produits");
while (root.hasNext()) {
var folder = root.next();
var files = folder.getFiles();
while (files.hasNext()) {
var spreadsheet = SpreadsheetApp.open(files.next());
var name = spreadsheet.getName().toUpperCase();
var values = csvData.reduce((ar, r) => {
if (!keywords.some(e => r[2].includes(e)) && r.join("").toUpperCase().includes(name)) {
ar.push(r);
}
return ar;
}, []);
if (values.length == 0) continue;
var sheet = spreadsheet.getSheets()[0];
sheet.clearContents().getRange(1, 1, values.length, values[0].length).setValues(values);
}
}
}
In this modification, the CSV data is retrieved at the outside of the while loop. Using the retrieved CSV data and each Spreadsheet name, the data is put to the 1st tab of each Spreadsheet.
References:
reduce()
toUpperCase()
includes()

Insert the link into the keyword in the sheet file

Please help me:
I have a sheet file with 2 columns
Column A is the keyword, column B is the link to insert the keyword. Eg:
Column A Column B
Key1 Link1
Key2 Link2
... ...
How to automatically find keywords in the DOCS file and then insert Link?
Here is my idea, but it doesn't work
function insertLink() {
var file,files,folder,folders,newestFileID;
var filethaythe = DriveApp.getFilesByName('Set Link');
var ss = SpreadsheetApp.open(filethaythe.next());//ID sheet thư viện thay thế
SpreadsheetApp.setActiveSpreadsheet(ss);
SpreadsheetApp.setActiveSheet(ss.getSheets()[0]);
var sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Trang tính1');
var sheet = ss.getSheetByName('Trang tính1');
var values = sheet.getDataRange().getValues();
folders = DriveApp.getFoldersByName('test3');
while (folders.hasNext()) {
folder = folders.next();
files = folder.getFilesByType("application/vnd.google-apps.document");
while (files.hasNext()){
file = files.next();
var newestFileID = file.getId();
Utilities.sleep(500);
var currentDoc = DocumentApp.openById(newestFileID);
var dongcuoi= sh.getLastRow();
var dc = dongcuoi +1;
var rgtxt = currentDoc.getBody();
var rgrep = ss.getSheets()[0].getRange("A1:B"+dc);
var repA = rgrep.getValues().filter(r => r.every(c => c.toString()));
repA.forEach(e => rgtxt.setLinkUrl(...e));
currentDoc.saveAndClose();
break
}
};
}
I believe your goal as follows.
You want to set the hyperlink to the word on Google Document.
The words and hyperlinks are retrieved from Google Spreadsheet.
In this case, how about the following modification?
Modified script:
function insertLink() {
// 1. Retrieve values from Spreadsheet.
var file,files,folder,folders,newestFileID;
var filethaythe = DriveApp.getFilesByName('Set Link');
var ss = SpreadsheetApp.open(filethaythe.next());
var sheet = ss.getSheetByName('Trang tính1');
var values = sheet.getDataRange().getValues();
// 2. Retrieve Google Document.
folders = DriveApp.getFoldersByName('test3');
while (folders.hasNext()) {
folder = folders.next();
files = folder.getFilesByType("application/vnd.google-apps.document");
while (files.hasNext()) {
file = files.next();
var newestFileID = file.getId();
// 3. Search words and set hyperlinks on Google Document.
var currentDoc = DocumentApp.openById(newestFileID);
var rgtxt = currentDoc.getBody();
values.forEach(([a, b]) => {
var s = rgtxt.findText(a);
while (s) {
var start = s.getStartOffset();
s.getElement().asText().setLinkUrl(start, start + a.length - 1, b);
s = rgtxt.findText(a, s);
}
});
currentDoc.saveAndClose();
break
}
}
}
In order to search the word, the method of findText is used. And, the method of setLinkUrl sets the hyperlink to the searched word.
References:
findText(searchPattern, from)
setLinkUrl(startOffset, endOffsetInclusive, url)

Google Spread Sheet Export CSV in the same folder

I am using the script below, working very well (thanks to Ted Bell).
But I need to adapt it because I need the CSV file saved in the same folder as the spreadsheet.
Could you please help me with this matter?
The code below creates a new folder each time on My Drive.
The CSV is ok regarding its name and its format: with semicolon delimiter.
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var csvMenuEntries = [{
name: "export as csv file",
functionName: "saveAsCSV"
}];
ss.addMenu("CSV Export", csvMenuEntries);
var a1 = ss.getRange("A1").getValue();
var name = "MyCompanyName_"+a1;
ss.rename(name);
};
function saveAsCSV() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var ssname = ss.getName();
var sheet = ss.getActiveSheet();
var sheetname = sheet.getSheetName();
//Logger.log("DEBUG: the name of the spreadsheet is "+ssname);//DEBUG
//Logger.log("DEBUG: the sheet name is "+sheetname);// DEBUG
//// create a folder from the name of the spreadsheet
var folder = DriveApp.createFolder(ssname.toLowerCase() + '_' +
sheetname.toLowerCase().replace(/ /g, '_') + '_csv_' + new Date().getTime());
//Logger.log("DEBUG: the folder name is "+folder);//DEBUG
// append ".csv" extension to the sheet name
var fileName = ssname + '_' + sheetname + ".csv";
// convert all available sheet data to csv format
var csvFile = so_4225484202(fileName);
// create a file in the Docs List with the given name and the csv data
folder.createFile(fileName, csvFile);
Browser.msgBox('Files are waiting in a folder named ' + folder.getName());
}
function isValidDate(date) {
return date && Object.prototype.toString.call(date) === "[object Date]" && !isNaN(date);
}
function so_4225484202(filename) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var paramsheet = ss.getSheetByName("Parameters");
var linearray = [];
var rowdata = [];
var csv = "";
var fieldvalue = "";
var param = paramsheet.getRange(2, 2, 2);
var paramValues = param.getValues();
//Logger.log("DEBUG: parameters = "+param.getA1Notation());//DEBUG
var fieldDelimiter = paramValues[0][0];
var textDelimiter = paramValues[1][0];
//Logger.log("DEBUG: field delimiter: "+fieldDelimiter+", text delim:
"+textDelimiter);//DEBUG
var rangeData = sheet.getDataRange();
var lastColumn = rangeData.getLastColumn();
var lastRow = rangeData.getLastRow();
//Logger.log("DEBUG: lastColumn: "+lastColumn+", lastRow: "+lastRow);//DEBUG
// Get array of values in the Data Range
var rangeValues = rangeData.getValues();
// Loop through array and build values for csv
for (i = 0; i < lastRow; i++) {
for (j = 0; j < lastColumn; j++) {
var value = rangeValues[i][j];
var theType = typeof value;
if (theType === "object") {
var testdate = isValidDate(value);
//Logger.log("if typeof is object: testdate: "+testdate);//DEBUG
var testtype = typeof testdate;
if (testtype === "boolean") {
// variable is a boolean
//Logger.log("Its a date");//DEBUG
theType = "date";
} else {
//Logger.log("Its not a date");//DEBUG
}
}
if (theType === "string") {
value = textDelimiter + value + textDelimiter;
}
rowdata.push([value]);
};
//Logger.log("DEBUG: rowdata: "+rowdata);//DEBUG
csv += rowdata.join(fieldDelimiter) + "\n";
var rowdata = [];
};
//Logger.log("DEBUG: csv: "+csv);//DEBUG
return csv;
}
You want to create the CSV file in the same folder of the active Spreadsheet.
You want to achieve this by modifying your script.
If my understanding is correct, how about this answer? Please think of this as just one of several possible answers.
Modification point:
In order to retrieve the folder of the active Spreadsheet, DriveApp.getFileById(ss.getId()).getParents().next() is used for retrieving the folder.
Modified script:
Please modify the function of saveAsCSV() in your script as follows.
From:
var folder = DriveApp.createFolder(ssname.toLowerCase() + '_' + sheetname.toLowerCase().replace(/ /g, '_') + '_csv_' + new Date().getTime());
To:
var folder = DriveApp.getFileById(ss.getId()).getParents().next();
References:
getId()
getFileById()
getParents()
If I misunderstood your question and this was not the direction you want, I apologize.

How to check particular value in google spreadsheet

I picked this code online and I am trying to check if the value in the column B is 'Done' then the value will be be copied otherwise not. Here is the code I am using:
copy sheet function below will copy the datat from source sheet to destination sheet but what I want that it will only pick the row if the col B value contains Done
function copySheet() {
var sourceSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Source");
var destSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Destination");
var columns_to_be_copied =['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U'];
var columns_to_be_pasted =['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U'];
for (column in columns_to_be_copied) {
var copy_range_string = columns_to_be_copied[column] + ':' + columns_to_be_copied[column];
var paste_range_string = columns_to_be_pasted[column] + ':' + columns_to_be_pasted[column];
var source = sourceSheet.getRange(copy_range_string);
var destination = destSheet.getRange(paste_range_string);
if(findInColumn('A','Done') !== -1) {
copyTo(source,destination );
}
}
}
function copyTo(source,destination) {
var sourceSheet = source.getSheet();
var destSheet = destination.getSheet();
var sourceData = source.getValues();
var dest = destSheet.getRange(
destination.getRow(), // Top row of destination
destination.getColumn(), // left col of destination
sourceData.length, // # rows in source
sourceData[0].length); // # cols in source (elements in first row)
dest.setValues(sourceData);
SpreadsheetApp.flush();
}
function findInColumn(column, data) {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sprint");
var column = sheet.getRange(column + ":" + column); // like A:A
var values = column.getValues();
var row = 0;
while (values[row] && values[row][0] !== data) {
row++;
}
if (values[row][0] === data)
return row+1;
else
return -1;
}
As I am a fan of simple and easy to read (even after long time) solutions I would suggest the following script:
function main() {
var sourceSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Source');
var destinationSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Destination');
copyFromTo(sourceSheet, destinationSheet);
}
function copyFromTo(sourceSheet, destinationSheet) {
const ColumnB = 1; //Array indexing starts from 0
const FilterValue = 'Done';
var sourceValues = sourceSheet.getSheetValues(1, 1, 100, 28); //startRow, startColumn, numRows, numColumns
var filteredValues = sourceValues.filter(function(row) {
return row[ColumnB] === FilterValue;
});
destinationSheet.getRange(1, 1, filteredValues.length, filteredValues[0].length).setValues(filteredValues);
}
It's about the same function. I just modified it to facilitate my debugging process. It copies the columns from source to destination if Sprint has "Done" in that column.
function copySheet() {
var srcsh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Source");
var dessh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Destination");
var from = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U'];
var to = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U'];
for(var i=0;i<from.length;i++) {
var fromrg = from[i] + ':' + from[i];
var torg = to[i] + ':' + to[i];
var src = srcsh.getRange(fromrg);
var des = dessh.getRange(torg);
if(findInColumn(from[i],'Done')!== -1){
src.copyTo(des);
}
}
}
function findInColumn(col, data) {
var col=col || 'A';//This is here for initial testing so I could run the function without parameters.
var data=data || 'Done';
var sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sprint");
var rg = sh.getRange(col + "1:" + col + sh.getMaxRows());//MaxRows is kind of big but I was not sure what else you'd like to do and I dont know what your Sprint sheet looks like.
var vA = rg.getValues();
var rv=-1;
for(var i=0;i<vA.length;i++){
if(vA[i][0]==data){
rv=i+1;
break;
}
}
return rv;
}
I see that you changed the question a bit. This function looks in your sprint sheet as you show in your answer and copies from source to destination only those columns that have the word "Done" on any row of that column. But it checks every column in your "columns_to_be_copied" which I called "from". Originally, that's what your function was trying to do. So I just wanted to be clear what this function is doing. If it's not what you want then leave a comment and I'll delete it.

How to export google sheet as CSV by selected columns

I have a Google sheet want to export as CSV file. But there are 2 columns in the sheet I don't want to export.
For example, in the picturecolumn, I don't want to export column "N" and "P"
Here are the Apps Script code I wrote for export
function menu() {
var ui = SpreadsheetApp.getUi();
var menu = ui.createMenu('Menu');
var item = menu.addItem('PICC', 'picc');
var item2 = menu.addItem('Export to CSV', 'csv');
item.addToUi();
item2.addToUi()
};
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var csvMenuEntries = [{name: "Download Primary Time File", functionName: "saveAsCSV"}];
//ss.addMenu("Creating a Timetable", csvMenuEntries);
var ui = SpreadsheetApp.getUi();
var menu = ui.createMenu('Menu');
var item = menu.addItem('PICC', 'picc');
var item2 = menu.addItem('Export to CSV', 'csv');
item.addToUi();
item2.addToUi()
};
function saveAsCSV() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("sheet1");
// create a folder from the name of the spreadsheet
var folder = DriveApp.createFolder(ss.getName().toLowerCase().replace(/ /g,'_') + '_csv_' + new Date().getTime());
// append ".csv" extension to the sheet name
fileName = sheet.getName() + ".csv";
// convert all available sheet data to csv format
var csvFile = convertRangeToCsvFile_(fileName, sheet);
// create a file in the Docs List with the given name and the csv data
var file = folder.createFile(fileName, csvFile);
//File downlaod
var downloadURL = file.getDownloadUrl().slice(0, -8);
showurl(downloadURL);
}
function showurl(downloadURL) {
var app = UiApp.createApplication().setHeight('60').setWidth('150');
//Change what the popup says here
app.setTitle("Your timetable CSV is ready!");
var panel = app.createPopupPanel()
//Change what the download button says here
var link = app.createAnchor('Click here to download', downloadURL);
panel.add(link);
app.add(panel);
var doc = SpreadsheetApp.getActive();
doc.show(app);
}
function convertRangeToCsvFile_(csvFileName, sheet) {
// get available data range in the spreadsheet
var activeRange = sheet.getDataRange();
try {
var data = activeRange.getValues();
var csvFile = undefined;
// loop through the data in the range and build a string with the csv data
if (data.length > 1) {
var csv = "";
for (var row = 1; row < data.length; row++) {
for (var col = 0; col < data[row].length; col++) {
if (data[row][col].toString().indexOf(",") != -1) {
data[row][col] = "\"" + data[row][col] + "\"";
}
}
// join each row's columns
// add a carriage return to end of each row, except for the last one
if (row < data.length-1) {
csv += data[row].join(",") + "\r\n";
}
else {
csv += data[row];
}
}
csvFile = csv;
}
return csvFile;
}
catch(err) {
Logger.log(err);
Browser.msgBox(err);
}
}
As you can see, I used for loop to export the rows and columns, how can I make change to let the two columns not showing in the export CSV
How about this modification?
Modification points :
Modify convertRangeToCsvFile_().
From data retrieved by getValues(), it removes the columns "N" and "P".
In order to reflect this, please modify as follows.
From :
var data = activeRange.getValues();
var csvFile = undefined;
To :
var data = activeRange.getValues();
data = data.map(function(e){return e.filter(function(_, i){return i != 13 && i != 15})}); // Added
var csvFile = undefined;
If I misunderstand your question, please tell me. I would like to modify it.