How to write progress in cell - javascript

I've created a function in Google Apps Script which downloads and renames the list files in Google Drive. I want to have their progress written in a particular cell. For example if first image has been downloaded and renamed in Drive so the text should be reflected in "PROGRESS" column with "COMPLETED" text.
Respectively the number of images will be downloaded and renamed, the text of "COMPLETED" should be reflected in the column next to their cells in a particular column called "PROGRESS", so if all of the images have been downloaded all of the cells under "PROGRESS" column should have "completed" in all of the columns.
Please help me as I have literally tried every thing but it is not getting done.
**below is the image elaboration what I want:
**
IMAGE ELABORATION
[GOOGLE SHEET URL]
https://docs.google.com/spreadsheets/d/1jItuI2tQbpH4A5b9CFS9xWV3mNtnrV2jMRYPxEZSvlM/edit?usp=sharing
[CODE]
function onOpen() {
SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
.createMenu('Custom Menu')
.addItem('Show alert', 'showAlert')
.addToUi();
}
function showAlert() {
var ui = SpreadsheetApp.getUi(); // Same variations.
var result = ui.alert(
'Please confirm',
'Are you sure you want to continue?',
ui.ButtonSet.YES_NO);
// Process the user's response.
if (result == ui.Button.YES){
// User clicked "Yes".
{
let sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
let lastRow = sheet.getLastRow();
for (let i = 0; i < lastRow - 1; i++) {
let folder = DriveApp.getFolderById("Folder_id");
let url = sheet.getRange(2 + i, 1).getValue();
let image = SpreadsheetApp.newCellImage().setSourceUrl(url);
let blob = UrlFetchApp.fetch(url).getBlob();
let name = sheet.getRange(2 + i, 2).getValue();
folder.createFile(blob).setName(name);
SpreadsheetApp.getUi().alert("task has been completed");
}
};
}
else {
// User clicked "No" or X in the title bar.
ui.alert('Permission denied.');
}
}

Move the confirmation to a position AFTER the loop. Something like this.
// Process the user's response.
if (result == ui.Button.YES){
// User clicked "Yes".
let sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
let lastRow = sheet.getLastRow();
for (let i = 0; i < lastRow - 1; i++) {
let folder = DriveApp.getFolderById("Folder_id");
let url = sheet.getRange(2 + i, 1).getValue();
let image = SpreadsheetApp.newCellImage().setSourceUrl(url);
let blob = UrlFetchApp.fetch(url).getBlob();
let name = sheet.getRange(2 + i, 2).getValue();
folder.createFile(blob).setName(name);
sheet.getRange(2+i,3).setValue("Completed")
SpreadsheetApp.flush()
}
SpreadsheetApp.getUi().alert("task has been completed")
}
else {
// User clicked "No" or X in the title bar.
ui.alert('Permission denied.');
}

Related

How to add a color stripe to every last row of a student attendance sheet using Google App Scripts?

As part of a student attendance system, I would like to add a color stripe to every last row of a class for attendance using App Scripts. My columns of Google Sheets are: (i) Date, (ii) Email, (iii) Latitude, (iv) Longitude, and (v) Subject-code. Tried many ways but did not find the solution.
var sss = SpreadsheetApp.getActiveSpreadsheet();
var ssID = sss.getId();
var sheetName = sss.getName();
var sheet = sss.getSheetByName("TempDataSet");
var sheet1 = sss.insertSheet('TempDataSet_temp');
sheet.getDataRange().copyTo(sheet1.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
sheet.getDataRange().copyTo(sheet1.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_FORMAT, false);
var shID = sheet1.getSheetId().toString();
sheet1.getRange(2, 1, sheet.getLastRow() -1, sheet.getLastColumn()).sort({column: 1, ascending: false});
var columns_delete = [7,2]; //[7,5,4,2];
columns_delete.forEach(col=>sheet1.deleteColumn(col));
//const sss = SpreadsheetApp.getActiveSpreadsheet();
//const sheet = sss.getSheetByName("TempDataSet");
const subs = sheet.getRange('F2:F'+sheet.getLastRow()).getValues().flat();
const usubs = subs.filter((value, index, self)=>self.indexOf(value) === index);
const dts = sheet.getRange('A2:A'+sheet.getLastRow()).getDisplayValues().flat();
const udts = dts.filter((value, index, self)=>self.indexOf(value) === index);
if(usubs.length>1){
subs.forEach((s,i)=>{
if(i>1){
if(subs[i]!=subs[i-1]){
sheet.getRange(i+1,1,1,5).setBackground('yellow');
}}});
}
else if (udts.length>1){
dts.forEach((d,i)=>{
if(i>1){
if(dts[i]!=dts[i-1]){
sheet.getRange(i+1,1,1,5).setBackground('yellow');
}}});
}
var from = Session.getActiveUser().getEmail();
var subject = 'Batch Attendance Record for Your Reference';
var body = 'Dear Student,'+ '\n\n' + 'Greetings! Please find the batch attendance record attached. Stay safe and blessed.' + '\n\n' + 'Thank you.';
var requestData = {"method": "GET", "headers":{"Authorization":"Bearer "+ScriptApp.getOAuthToken()}};
var url = "https://docs.google.com/spreadsheets/d/"+ ssID + "/export?format=xlsx&id="+ssID+"&gid="+shID;
var result = UrlFetchApp.fetch(url , requestData);
var contents = result.getContent();
sss.deleteSheet(sss.getSheetByName('TempDataSet_temp'));
var sheet2 = sss.getSheetByName('StudentList');
var data = sheet2.getLastRow();
var students = [];
var students = sheet2.getRange(2, 6, data).getValues();
//MailApp.sendEmail(students.toString(), subject ,body, {attachments:[{fileName:sheetName+".xlsx", content:contents, mimeType:"MICROSOFT_EXCEL"}]});
for (var i=0; i<students.length; i++){ // you are looping through rows and selecting the 1st and only column index
if (students[i][0] !== ''){
MailApp.sendEmail(students[i][0].toString(), subject ,body, {attachments:[{fileName:sheetName+".xlsx", content:contents, mimeType:"MICROSOFT_EXCEL"}]});
//MailApp.sendEmail(students[i][0].toString(), subject ,body, {from: from, attachments:[{fileName:"YourAttendaceRecord.xlsx", content:contents, mimeType:"MICROSOFT_EXCEL"}]});
}
}
Explanation:
Based on your question, I understand the following steps:
Check if you have at least two unique subjects in column E. One way to do that is to find the unique list of subjects. If the length of that list is 2 or more it means that you have different subjects. In that case, the first block of the if statement evaluates to true and you add a yellow line in the row before the subject is changed.
If you have only one subject, namely the length of the unique list of subjects is 1 the first block of the if statement will evaluate to false. In that case, the script will check whether column A has 2 or more unique dates. If it does, the second block of the if statement will be executed and the script will add a yellow line in the row before the date is changed. Otherwise, it won't do anything.
Solution:
You can execute color() as a standalone script. I would advice you to save this function in a new .gs file and then simply call it within your current script. Namely, put color() anywhere you want in the code snippet you provided.
function color() {
const sss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = sss.getSheetByName("TempDataSet");
const subs = sheet.getRange('E2:E'+sheet.getLastRow()).getValues().flat();
const usubs = subs.filter((value, index, self)=>self.indexOf(value) === index);
const dts = sheet.getRange('A2:A'+sheet.getLastRow()).getDisplayValues().flat();
const udts = dts.filter((value, index, self)=>self.indexOf(value) === index);
if(usubs.length>1){
subs.forEach((s,i)=>{
if(i>1){
if(subs[i]!=subs[i-1]){
sheet.getRange(i+1,1,1,5).setBackground('yellow');
}}});
}
else if (udts.length>1){
dts.forEach((d,i)=>{
if(i>1){
if(dts[i]!=dts[i-1]){
sheet.getRange(i+1,1,1,5).setBackground('yellow');
}}});
}
}
Complete Solution:
function sendEmails(){
var sss = SpreadsheetApp.getActiveSpreadsheet();
var ssID = sss.getId();
var sheetName = sss.getName();
var sheet = sss.getSheetByName("TempDataSet");
var sheet1 = sss.insertSheet('TempDataSet_temp');
sheet.getDataRange().copyTo(sheet1.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_VALUES, false);
sheet.getDataRange().copyTo(sheet1.getActiveRange(), SpreadsheetApp.CopyPasteType.PASTE_FORMAT, false);
var shID = sheet1.getSheetId().toString();
sheet1.getRange(2, 1, sheet.getLastRow() -1, sheet.getLastColumn()).sort({column: 1, ascending: true});
var columns_delete = [7,2]; //[7,5,4,2];
columns_delete.forEach(col=>sheet1.deleteColumn(col));
SpreadsheetApp.flush();
const subs = sheet1.getRange('E2:E'+sheet1.getLastRow()).getValues().flat();
const usubs = subs.filter((value, index, self)=>self.indexOf(value) === index);
const dts = sheet1.getRange('A2:A'+sheet1.getLastRow()).getDisplayValues().flat();
const udts = dts.filter((value, index, self)=>self.indexOf(value) === index);
if(usubs.length>1){
subs.forEach((s,i)=>{
if(i>1){
if(subs[i]!=subs[i-1]){
sheet1.getRange(i+1,1,1,5).setBackground('yellow');
}}});
}
else if (udts.length>1){
dts.forEach((d,i)=>{
if(i>1){
if(dts[i]!=dts[i-1]){
sheet1.getRange(i+1,1,1,5).setBackground('yellow');
}}});
}
SpreadsheetApp.flush();
var from = Session.getActiveUser().getEmail();
var subject = 'Batch Attendance Record for Your Reference';
var body = 'Dear Student,'+ '\n\n' + 'Greetings! Please find the batch attendance record attached. Stay safe and blessed.' + '\n\n' + 'Thank you.';
var requestData = {"method": "GET", "headers":{"Authorization":"Bearer "+ScriptApp.getOAuthToken()}};
var url = "https://docs.google.com/spreadsheets/d/"+ ssID + "/export?format=xlsx&id="+ssID+"&gid="+shID;
var result = UrlFetchApp.fetch(url , requestData);
var contents = result.getContent();
sss.deleteSheet(sss.getSheetByName('TempDataSet_temp'));
var sheet2 = sss.getSheetByName('StudentList');
var data = sheet2.getLastRow();
var students = [];
var students = sheet2.getRange(2, 6, data).getValues();
//MailApp.sendEmail(students.toString(), subject ,body, {attachments:[{fileName:sheetName+".xlsx", content:contents, mimeType:"MICROSOFT_EXCEL"}]});
for (var i=0; i<students.length; i++){ // you are looping through rows and selecting the 1st and only column index
if (students[i][0] !== ''){
MailApp.sendEmail(students[i][0].toString(), subject ,body, {attachments:[{fileName:sheetName+".xlsx", content:contents, mimeType:"MICROSOFT_EXCEL"}]});
//MailApp.sendEmail(students[i][0].toString(), subject ,body, {from: from, attachments:[{fileName:"YourAttendaceRecord.xlsx", content:contents, mimeType:"MICROSOFT_EXCEL"}]});
}
}
}

How to send whole row of data in my spreadsheet via email based on single cell edit (Google Script / GAS)

We have set up a workflow spreadsheet that has job information such as client name, job details etc. I have a nifty script that hides a whole row if you choose "Complete" from a drop down menu in the final column of that row.
What I am trying to do now is send an email with all the data in the row we are hiding.
UPDATED: Here is the code I have so far:
/**
* TITLE:
* Hide a row if a value is inputted then send an email
*/
//**GLOBALS**
// Sheet the data is on.
var SHEET = "Live Jobs";
// The value that will cause the row to hide.
var VALUE = "Complete";
// The column we will be using
var COLUMN_NUMBER = 22
function onEdit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var activeSheet = ss.getActiveSheet();
//Ensure on correct sheet.
if(SHEET == activeSheet.getName()){
var cell = ss.getActiveCell()
var cellValue = cell.getValue();
//Ensure we are looking at the correct column.
if(cell.getColumn() == COLUMN_NUMBER){
//If the cell matched the value we require,hide the row.
if(cellValue == VALUE){
activeSheet.hideRow(cell)
SendEmail(e);
};
};
};
}
/**
* Sends emails with data from the current spreadsheet.
*/
function SendEmail(e) {
// Fetch the email address
var correctSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Live Jobs');
var emailRange = correctSheet.getRange('Z1');
var emailAddress = emailRange.getValue();
var sheet = SpreadsheetApp.getActiveSheet();
var cell = sheet.getActiveCell()
var rowValue = cell.getRow();
var startRow = rowValue; // First row of data to process
var numRows = 2; // Number of rows to process
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(startRow, 1, 1, 5);
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i in data) {
var row = data[i];
var message = row; // Second column
var subject = 'Sending emails from a Spreadsheet';
MailApp.sendEmail(emailAddress, subject, message);
}
}
Now, the hide row works, and the email function works if I run it from the Google Script editor, but for some reason, the email does not fire when I select "Complete" but IT WAS WORKING YESTERDAY!!!
Any tips?
M
Try this:
You probably can't do this with a simple trigger since sending email requires authorization.
var SHEET = "Live Jobs";
var VALUE = "Complete";
var COLUMN_NUMBER = 22
function onEdit(e) {
var sh=e.range.getSheet();
if(sh.getName()==SHEET){
if(e.range.columnStart==COLUMN_NUMBER && e.value==VALUE){
sh.hideRow(e.range.rowStart);
SendEmail(e);
}
}
}
}
function SendEmail(e) {
MailApp.sendEmail(e.range.getSheet().getRange('Z1').getValue(), 'Invoice Job Alert', e.range.getSheet(e.range.rowStart,1,1,e.range.getSheet().getLastColumn()).getValues()[0].join(','));
}

Google Apps Script Not Loading Functions for Everyone, only me

My onSheetOpen / showSidebar is not working for anyone but me when opening my events Google sheet. I have set up triggers to launch both the onSheetOpen and showSidebar for myself, but this is not working for anyone else who opens the spreadsheet. Can anyone help figure out why this might be the case? Below is the code I'm using.
/**
* Set up custom sidebar.
* TRIGGER: spreadsheet event 'on open'
*/
function onSheetOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Actions')
.addItem("Register interest in current opportunity", 'registerInterest')
.addItem("Show sidebar", 'showSidebar')
.addToUi();
showSidebar();
}
/**
* Renders the sidebar
* TRIGGER: spreadsheet event 'on open' & custom menu option
*/
function showSidebar() {
try {
var htmlOutput = HtmlService.createHtmlOutputFromFile('sidebar');
SpreadsheetApp.getUi().showSidebar(htmlOutput);
} catch(e) {
// Just ignore - means user doesn't have edit access to sheet
}
}
/**
* Main function. Grabs the required data from the currently-selected row, registers interest
* in that data in a separate sheet, and sends a confirmation email to the user.
*/
function registerInterest() {
//var spreadsheet = SpreadsheetApp.getActive();
// These are the attributes we capture and store in the 'interest' sheet
var who = Session.getActiveUser().getEmail();
var when = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), 'yyyy-MM-dd HH:mm:ss');
var data = getRowOfInterest(SpreadsheetApp.getActiveSheet());
var id = Utilities.getUuid();
Logger.log(id)
if(data.what && data.what.length > 0) {
// Get the Google Sheets ID of the target 'interest' sheet
var id = getConfigValue("InterestSheet");
if(id) {
// Now try and open that sheet for updating
var ss = SpreadsheetApp.openById(id);
if(ss) {
var sheet = ss.getSheetByName('Interest');
if(sheet) {
// All good; log interest. First, create the new row of data for the target sheet
sheet.appendRow([ when, who, data.what, data.subject, data.location, data.industry, data.capabilities ]);
// Second, grab our 'template' email from config & use that to send a confirmation
// email to the person registering their interest
var body = getConfigValue('InterestEmail');
MailApp.sendEmail(who, getConfigValue('InterestSubject'), null, { noReply: true, htmlBody: body });
} else {
throw Error('can\'t open the \'Interest expressed\' sheet (or it doesn\'t exist)');
}
} else {
throw Error('can\'t open the \'Interest expressed\' sheet');
}
} else {
throw Error('\'Interest expressed\' sheet not specified');
}
}
}
/**
* Utility to derive the required data for registering interest.
* Called from the registerInterest() function
*/
function getRowOfInterest(sheet) {
var result = {};
var row = sheet.getActiveRange().getRow(); // Get the currently-selected row index
var fullRange = sheet.getRange(row, 1, 1, sheet.getLastColumn()); // Get the entire row of data
//var fullRange = sheet.getRange(row, 1, 1, 9);
Logger.log(fullRange.getValues())
var data = fullRange.getValues();
if(data[0] && data[0].length > 0) {
for(var n = 0; n < data[0].length; n++) {
// Populate specific attributes in the 'result' object - tailor this as you see fit
if(n==0) result.subject = data[0][n];
if(n==6) result.what = data[0][n] + ' ';
//if(n==5 || n==7) result.what += data[0][n] + ' ';
if(n==7) result.location = data[0][n];
if(n==11) result.industry = data[0][n];
if(n==12) result.capabilities = data[0][n];
}
result.what += '(' + sheet.getName() + ')';
result.industry;
result.capabilities;
return result;
}
}
function getSomeRange(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var row = sheet.getActiveRange().getRow(); // Get the currently-selected row index
var myRange = sheet.getRange(row, 1, 1, sheet.getLastColumn());
//Logger.log("Number of rows in range is "+myRange.getNumRows()+ " Number of columns in range is "+ myRange.getNumColumns());
}
/**
* Utility to pull specified data from a config sheet. This assumes that a sheet called 'Config'
* is populated thus:
* Column contains a load of 'key' and column 2 contains the corresponding 'values'
* Called from registerInterest() function
*/
function getConfigValue(key) {
var sheet = SpreadsheetApp.getActive().getSheetByName('Config');
var result;
if(sheet) {
// Scan column 1 for key and return value in column 2
var data = sheet.getDataRange().getValues();
for(var n = 0; n < data.length; ++n) {
if(data[n][0].toString().match(key)) result = data[n][1];
}
}
return result;
}
function hideExpiredEvents() {
var ss=SpreadsheetApp.getActive();
var sh=ss.getSheetByName('Events');
var exsh=ss.getSheetByName('Expired Events');
var sr=2;
var rg=sh.getRange(sr,1,sh.getLastRow()-sr+1,sh.getLastColumn());
var vA=rg.getValues();
Logger.log(vA);
var dt=new Date();
var d=0;//deleted row counter
var today=new Date(dt.getFullYear(),dt.getMonth(),dt.getDate(0)).valueOf();
for(var i=0;i<vA.length;i++) {
if(new Date(vA[i][3]).valueOf()<today) {
exsh.appendRow(vA[i]);//move to bottom of expired events
sh.deleteRow(i+sr-d++);//increment deleted row counter
}
}
}
Unfortunately, it seems that the issue you are encountering might be a bug.
What you can do in this case is to star the issue on Issue Tracker here by clicking the ★ next to the issue number and post a comment as well saying that you are affected by the issue.

Google scripts for Spreadsheets (If statements)

I am hoping someone can help me with this issue. I am new to coding. I have a google spreadsheet with a script that pushes out an email. I am attempting to have the script ignore the rows where the script has already sent out an email on.
function onOpen() {
var ui = SpreadsheetApp.getUi();
// Or DocumentApp or FormApp.
ui.createMenu('Email Menu')
.addItem('Send Email', 'myFunction')
.addSeparator()
.addToUi();
};
function myFunction() {
var msg = 'Email sent!';
var ss = SpreadsheetApp.getActiveSpreadsheet()
var sheet = ss.getActiveSheet();
var range = sheet.getDataRange();
var values = range.getValues();
var EMAIL_SENT = "EMAIL_SENT";
var startRow = 2;
for (i=1; i<values.length;i++) {
//sent = values[i][4]; //added this in to try and skip a row if "X" was in Sent Column
//if (sent ==" ", ) //added this in to try and skip a row if "X" was in Send Column
var email = values[i][0];
var name = values[i][i];
var subject = values[i][2];
var body = values[i][3];
var sent = values[i][5];
if (sent != EMAIL_SENT){
MailApp.sendEmail(email, subject, body);
sheet.getRange(startRow + i,5).setValue(EMAIL_SENT);
SpreadsheetApp.getUi().alert(msg);
}
}}
Google spreadsheet
Implement the following changes in your for loop:
for (i=1; i<values.length;i++) {
var email = values[i][0];
var name = values[i][1]; //not [i][i] !
var subject = values[i][2];
var body = values[i][3];
var sent = values[i][4];
if (sent !== EMAIL_SENT){
sheet.getRange(i+1,5).setValue(EMAIL_SENT);
}
}
Basically get rid of the startRow variable (if you are not using elsewhere) and just use (i+1,5) to place "EMAIL_SENT" in the right column. I have removed parts of your code for the sake of clarity.
Small fix. Replace
sheet.getRange(startRow + i,5).setValue(EMAIL_SENT);
to
sheet.getRange(startRow + i - 1, 6).setValue(EMAIL_SENT);
According to the rest of the script, this should be the most simple fix. This assumes sent column is F (column 6) not E (column 5). Sample sheet including updated script is here.
And! You should change var name = values[i][i]; to var name = values[i][1]; as #jrook pointed. I missed it...

Gmail App Script Add BCC from Spreadsheet

I have created this code to send a template email from Google Spreadsheet. I really need to BCC another recipient. I have checked out Class Gmail App. It didn't quite make sense to me.
var EMAIL_SENT = "EMAIL_SENT";
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menu = [{
name: "Send Email",
functionName: "sendEmails2"
}];
ss.addMenu("Send Email", menu);
}
function sendEmails2() {
var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 2; // Number of rows to process
// Fetch the range of cells A2:B3
var dataRange = sheet.getRange(startRow, 1, numRows, 3)
// Fetch values for each row in the Range.
var data = dataRange.getValues();
for (var i = 0; i < data.length; ++i) {
var row = data[i];
var emailAddress = row[0]; // First column
var message = "Hello Team,\n\n" + row[1] + " Please do the Following:..."; // Second column
var emailSent = row[2]; // Third column
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
var subject = "Team Email";
MailApp.sendEmail(emailAddress, subject, message);
sheet.getRange(startRow + i, 3).setValue(EMAIL_SENT);
// Make sure the cell is updated right away in case the script is interrupted
SpreadsheetApp.flush();
}
}
}
Check the version of sendEmail(recipient, subject, body, options) method with optional arguments, which can include bcc.
Class GmailApp also has a similar method sendEmail(recipient, subject, body, options), which can include bcc.
Example:
...
var options = {
bcc: 'bccmail0#domain.ext, bccmail1#domain.ext'
};
MailApp.sendEmail(emailAddress, subject, message, options);
...

Categories