I am new with Google App Scripts and have a spreadsheet with 2 columns: https://docs.google.com/spreadsheets/d/1J3IR3y7VemlrKNsJ8u0gzaUAZy6wBb7qncPfKkab4l4/edit#gid=0
The scripts I'm using:
function sendEmail() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet1'); // change Sheet1 to the name of your sheet
const data = sh.getRange('A2:B'+sh.getLastRow()).getValues();
data.forEach(r=>{
let salesValue = r[1];
if (salesValue = 0){
let name = r[0];
let message = 'There are no sales for ' + name;
let subject = 'No SALES.'
MailApp.sendEmail('myemail#email.com', subject, message);
}
});
}
This works but sends me one email per each business name. So, based on the data in the sheet, I will get 2 emails.
I would like to send one email only to group of emails on a daily basis when the sales column (B) equals ZERO. Assume that the sheet is updated daily and I want to set a trigger to run the script daily.
Your email send is in the forEach loop so every row that is zero (change the if comparison to ==) it is sending the email. Bring that to the bottom and you'll just get one email. This might get you closer to what you're looking for:
function sendEmail() {
const ss = SpreadsheetApp.getActive();
const sh = ss.getSheetByName('Sheet1'); // change Sheet1 to the name of your sheet
const data = sh.getRange('A2:B'+sh.getLastRow()).getValues();
let zeroSales = []
data.forEach(r=>{
let salesValue = r[1];
if (salesValue == 0){
let name = r[0];
zeroSales.push(name)
}
});
if (zeroSales.length > 0) {
let subject = 'No SALES.'
let message = 'There are no sales for ' + zeroSales.join(', ')
MailApp.sendEmail('myemail#email.com', subject, message);
}
}
Related
I have a function in Google Apps Script that fetches to a serverless api I created which returns our company's Facebook ad spend for the previous day.
function fetchAdData() {
const url = SERVERLESS_ENDPOINT
let response = UrlFetchApp.fetch(url);
const json = response.getContentText();
const GBP = Intl.NumberFormat("en-GB", {
style: "currency",
currency: "GBP",
minimumFractionDigits: 2
});
let data = JSON.parse(json)
let result = data.map((ad) => {
return [ad.date, ad.campaign, GBP.format(ad.spend)]
})
return result
}
I'm using a macro and daily trigger to make the function run daily to give us a daily rundown of the previous day's campaigns and spend:
function DailyAdSpendFetch() {
const ss = SpreadsheetApp.getActive();
const spreadsheet = ss.getSheetByName('ADSPEND');
let data = '=fetchAdData()'
spreadsheet.appendRow([data])
};
The functions work as expected but are overwriting the previous day's values whenever it is called. So for example instead of having:
Date
Campaign
Spend
2022-09-26
AD_CAMPAIGN_1
£100
2022-09-27
AD_CAMPAIGN_2
£200
2022-09-28
AD_CAMPAIGN_3
£300
I'm getting:
Date
Campaign
Spend
2022-09-28
AD_CAMPAIGN_3
£300
2022-09-28
AD_CAMPAIGN_3
£300
2022-09-28
AD_CAMPAIGN_3
£300
I've tried setting the value instead of appending the row :
function DailyAdSpendFetch() {
var ss = SpreadsheetApp.getActive();
var spreadsheet = ss.getSheetByName('ADSPEND');
let data = '=fetchAdData()'
let lastRow = spreadsheet.getLastRow()
let activeCell = spreadsheet.getRange(`A${lastRow}`);
spreadsheet.setCurrentCell(activeCell);
spreadsheet.getCurrentCell().offset(1, 0).activate();
spreadsheet.getCurrentCell().setValue([data]);
};
But I get the same result.
This is my first time working in Google Apps Script so any help would be massively appreciated!
This should do. All in one function. You get the last row of the sheet and add 1 as starting point to set the values. Also the Intl.NumberFormat changes your number to formatted text so you cannot use it in you're sheet to sum. Do the formatting in you're sheet.
function fetchAdData() {
const url = SERVERLESS_ENDPOINT
const response = UrlFetchApp.fetch(url);
const result = JSON.parse(response.getContentText()).map((ad) => {
return [ad.date, ad.campaign, ad.spend]
})
const ss = SpreadsheetApp.getActive();
const sheet = ss.getSheetByName('ADSPEND');
sheet.getRange(sheet.getLastRow() + 1, 1, result.length, result[0].length).setValues(result)
}
Submit values from userform (selected cells) to another google spreadsheet and then find them (search), modify and post it again.
I have a source sheet (userform), I need to get values from the selected cells and ranges, submit the values to the destination sheet (another spreadsheet) using ID.
I have attached a Screenshot explaining with color code where the data should go. https://i.stack.imgur.com/Yrfje.jpg
[SCREENSHOT][1]
Also Shared two spreadsheets with actual data (Userform and Datasheet) for your reference
https://docs.google.com/spreadsheets/d/1NY_ckzEWxU7DCGro5tTqzpiOi6iG5PAQFxpZg0OKodY/edit?usp=sharing
https://docs.google.com/spreadsheets/d/1QL0jaNts2YRkZTlxmS0bk7V1fVVHBsJFmxS5C05PEmA/edit?usp=sharing
Please help to enhance this below code (thanks to #[Yuri Khristich][2])
var ss = SpreadsheetApp.getActiveSpreadsheet();
var form_sheet = ss.getSheetByName('UserForm');
var data1 = form_sheet.getRange(['c3:c8']).getValues().flat();
var [num, date, name, id, project,group] = data1;
var data2 = form_sheet.getRange('b10:e20').getValues();
var data_sheet = ss.getSheetByName('DataSheet');
var nums = data_sheet.getRange('a:a').getValues().flat();
var row = nums.indexOf(num);
if (row < 0 ) {
var new_row = [num, date, name, id, project, group, JSON.stringify(data2)];
data_sheet.appendRow(new_row)
} else {
var range = data_sheet.getRange('g' + ++row);
range.setValue(JSON.stringify(data2));
}
}
function searchRecord() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var form_sheet = ss.getSheetByName('UserForm');
var num = form_sheet.getRange('b1').getValue();
var data_sheet = ss.getSheetByName('DataSheet');
var nums = data_sheet.getRange('a:a').getValues().flat();
var row = nums.indexOf(num);
if (row < 0) {
ss.toast('Nothing was found')
return;
}
row++;
var data1 = data_sheet.getRange('a' + row + ':g' + row).getValues().flat();
var data2 = JSON.parse(data1.pop());
form_sheet.getRange('c3:c8').clearContent().setValues(data1.map(x => [x]));
form_sheet.getRange('b10:e20').clearContent().setValues(data2)
}
// Function to submit the data to DataSheet sheet
function oldsubmitData() {
var myGooglSheet= SpreadsheetApp.getActiveSpreadsheet(); //declare a variable and set with active google sheet
var shUserForm= myGooglSheet.getSheetByName("UserForm"); //delcare a variable and set with the User Form worksheet
var datasheet = myGooglSheet.getSheetByName("DataSheet"); ////delcare a variable and set with the DataSheet worksheet
var namedRanges = SpreadsheetApp.getActiveSheet().getNamedRanges();
if (namedRanges.length > 1) {
Logger.log(namedRanges[0].getName());
}
//to create the instance of the user-interface environment to use the messagebox features
var ui = SpreadsheetApp.getUi();
// Display a dialog box with a title, message, and "Yes" and "No" buttons. The user can also
// close the dialog by clicking the close button in its title bar.
var response = ui.alert("Submit", 'Do you want to submit the data?',ui.ButtonSet.YES_NO);
// Checking the user response and proceed with clearing the form if user selects Yes
if (response == ui.Button.NO)
{return;//exit from this function
}
//Validating the entry. If validation is true then proceed with transferring the data to DataSheet sheet
// if (validateEntry()==true)
{
var blankRow=datasheet.getLastRow()+1; //identify the next blank row
datasheet.getRange(blankRow, 1).setValue(shUserForm.getRange("C3").getValue()); //Date
datasheet.getRange(blankRow, 2).setValue(shUserForm.getRange("C4").getValue()); //UserForm Number
datasheet.getRange(blankRow, 3).setValue(shUserForm.getRange("C5").getValue()); //Student Name
datasheet.getRange(blankRow, 4).setValue(shUserForm.getRange("C6").getValue()); //ID
datasheet.getRange(blankRow, 5).setValue(shUserForm.getRange("C7").getValue()); //Project
datasheet.getRange(blankRow, 6).setValue(shUserForm.getRange("C8").getValue()); //Group Name
//I stuck here, get values from moving row (E,13 to 16)
//datasheet.getRange(blankRow, 8).setValue(shUserForm.getNamedRanges("TotalPresent").getValue());// TotalPresent
//datasheet.getRange(blankRow, 8).setValue(shUserForm.getNamedRanges("SoundRoomDay").getValue());// SoundRoomDAy
//datasheet.getRange(blankRow, 9).setValue(shUserForm.getNamedRanges("GroupDay").getValue());// GroupDay
//datasheet.getRange(blankRow, 10).setValue(shUserForm.getNamedRanges("TotalDays").getValue());// TotalDays
// date function to update the current date and time as submittted on
datasheet.getRange(blankRow, 12).setValue(new Date()).setNumberFormat('yyyy-mm-dd h:mm'); //Submitted On
//get the email address of the person running the script and update as Submitted By
datasheet.getRange(blankRow, 13).setValue(Session.getActiveUser().getEmail()); //Submitted By
var ss = SpreadsheetApp.getActiveSpreadsheet();
var form_sheet = ss.getSheetByName('UserForm');
var num = form_sheet.getRange('c3').getValue();
var data = form_sheet.getRange('b10:e20').getValues();
var datasheet = ss.getSheetByName('DataSheet');
var nums = datasheet.getRange('a:a').getValues().flat();
var row = nums.indexOf(num);
if (row < 0) return;
var range = datasheet.getRange('g' + ++row);
range.setValue(JSON.stringify(data));
ui.alert(' "New Data Saved - StudentID #' + shUserForm.getRange("C5").getValue() +' "');
}
}```
-code by-----------------------
[1]: https://i.stack.imgur.com/Yrfje.jpg
[2]: https://stackoverflow.com/users/14265469/yuri-khristich
I guessed your goal is as follows.
You want to copy the values from UserForm of PRINTNOTE_A to DataSheet of WB-Datasheet 2.
You want to copy the values of cells C3,C7,C8,D8,D6,D4,E8,E19,E20,E21,E22 and B10:E18 of UserForm sheet to the same row.
You want to search the column "A" of DataSheet sheet using the value of cell B1 of UserForm sheet, you want to put the values in the same row.
You want to achieve this using Google Apps Script.
By guessing your question, I propose a sample script as follows.
In order to retrieve the values from the distributed cells, in this sample script, I used Sheets API.
Sample script:
Before you use this script, please enable Sheets API at Advanced Google Services.
From your script, this script is used as the container-bound script of PRINTNOTE_A. So, please copy and paste this script to the script editor of PRINTNOTE_A Spreadsheet.
function sample() {
const dstSpreadsheetId = "###"; // Please set the destination Spreadsheet ID (WB-DataSheet_B).
const dstSheetName = "DataSheet";
const srcSheetName = "UserForm";
// Retrieve values from source sheet and create an array and search value.
const srcSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
const ranges = ["B1", "C3", "C7", "C8", "D8", "D6", "D4", "E8", "E8", "E19", "E20", "E21", "E22", "B10:E18"];
const [search, ...values] = Sheets.Spreadsheets.Values.batchGet(srcSpreadsheet.getId(), { ranges: ranges.map(r => `'${srcSheetName}'!${r}`) }).valueRanges.flatMap(({ values, range }) => {
if (range.includes("B10:E18")) return values.flat();
return values[0][0];
});
// Put the array to the destination sheet using the search value.
const dstSheet = SpreadsheetApp.openById(dstSpreadsheetId).getSheetByName(dstSheetName);
const range = dstSheet.getRange("A2:A" + dstSheet.getLastRow()).createTextFinder(search).findNext();
if (range) {
dstSheet.getRange(range.getRow(), 2, 1, values.length).setValues([values]);
} else {
dstSheet.getRange(dstSheet.getLastRow() + 1, 1, 1, values.length + 1).setValues([[search, ...values]]);
}
}
From your replying of but new values are not getting submitted in the next blank row., I updated my proposed answer. In the current script, when the search value is not found, the values are appended to the destination sheet.
Note:
This sample script is for your provided 2 Spreadsheets. And, I tested this script using your provided Spreadsheets. So when you changed the Spreadsheet and your actual Spreadsheets are different from your provided sample Spreadsheet, this script might not be able to be used. Please be careful about this.
References:
Method: spreadsheets.values.batchGet
createTextFinder(findText) of Class Range
I am new to coding, specifically using google script. I have a spreadsheet with documents and document ids, and when overdue the due date changes to red and done like a traffic light system.
However what I need to set up for work is an automatic email to be sent out when a value in column L = 1 (based on the red and other values in the row being true) and if the value is 0 I want the script to pass over it and move down through the column.
I have tried reading and testing codes around using do and while and for etc, but I just can’t get it to work.
So what I have set up is inefficient and rudimentary I’m sure, but it works, just slowly - see code below.
When it does hit a 1, it then uses activate cells and offsets to get values from cells in the corresponding row and package up an email and send. The script then moves down and checks the next cell, but because I’m using activate and calling multiple functions it is taking a long time to cycle through the column.
The column is L and the range in use is L2:L60
I’d be so grateful if anyone can point me in the right direction of what the best method would be for this please.
function Findfirstcell()
{
SpreadsheetApp.getActive().getRange('l2').activate();
GetLvalue();
}
function GetLvalue()
{
var st= SpreadsheetApp.getActive().getActiveSheet().getActiveCell().getValue();
if (st < 1)
Movetonext();
else
Createemail();
}
function Createemail()
{
var ss= SpreadsheetApp.getActive()
var x = ss.getActiveSheet()
const s= x.getActiveCell();
var y= s.offset(0,-5);
var v= y.getValue();
var t= s.offset(0,-10);
var z= s.offset(0,-11);
var p= t.getValue();
var w= z.getValue();
var emailAddress = v+'#gmail.com'
var message = p+" is overdue - Document ID "+w
var subject = w+" is Overdue"
MailApp.sendEmail(emailAddress, subject, message);
var w= s.offset(0,-3);
w.setValue('Sent')
var end= s.offset(1,0);
end.activate();
GetLvalue();
}
function Movetonext()
{
var ss= SpreadsheetApp.getActive();
var s= ss.getActiveSheet().getActiveCell();
var end= s.offset(1,0);
end.activate();
var v= s.getValue();
if (v < 0)
ss.getRange('a1').activate();
else
GetLvalue();
}
I have tried several other methods with no success as mentioned, one being below, where it does it for the first row (which may be because the value is 1), but it does not then continue down the column.
I assumed as the condition had failed, triggering function createemail and there is nothing to loop it back
function Findfirstcell()
{
var ss= SpreadsheetApp.getActiveSheet().getActiveCell('l2').activate;
// Or
var ss= SpreadsheetApp.getActiveSheet().getRange('l2:l60');
for(ss<0; ss>0; ss++){createemail();}
}
function createemail()
{
var st= SpreadsheetApp.getActive().getCurrentCell();
var y= st.offset(0,-5);
var v= y.getValue();
var t= st.offset(0,-10);
var z= st.offset(0,-11);
var p= t.getValue();
var w= z.getValue();
var emailAddress = v+'#gmail.com'
var message = p+" is overdue - Document ID "+w
var subject = w+" is Overdue"
MailApp.sendEmail(emailAddress, subject, message);
}
Any guidance would be greatly appreciated
I believe your goal is as follows.
You want to check whether the value of the column "L" is 0 or 1.
When the value is 1 and the value of column "I" is not Sent, you want to send an email using the values of columns "A", "B" and "G".
When the email is sent, you want to put the value of Sent to the column "I".
You want to reduce the process cost of your script.
In this case, how about the following flow?
Retrieve values from the active sheet.
Check the value of column "I" and "L" and send the email and return the range list.
When the email is sent, the value of "Sent" is put to the column "I".
When this flow is reflected to a Google Apps Script, it becomes as follows.
Sample script:
function myFunction() {
// 1. Retrieve values from the active sheet.
const sheet = SpreadsheetApp.getActiveSheet();
const [, ...values] = sheet.getDataRange().getValues();
// 2. Check the value of column "I" and "L" and send the email and return the range list.
const rangeList = values.reduce((ar, [a, b, , , , , g, , i, , , l], r) => {
if (l > 0 && i != "Sent") {
var emailAddress = g + '#gmail.com';
var message = b + " is overdue - Document ID " + a;
var subject = a + " is Overdue";
MailApp.sendEmail(emailAddress, subject, message);
ar.push(`i${r + 2}`);
}
return ar;
}, []);
// 3. When the email is sent, the value of "Sent" is put to the column "I".
if (rangeList.length > 0) sheet.getRangeList(rangeList).setValue("Sent");
}
References:
reduce()
getRangeList(a1Notations)
I have a google sheets tool where I automatically get the number of products on our site every hour with the Shopify API.
https://docs.google.com/spreadsheets/d/1m1lF6jLWPIKhJDOut_G-2tX_zYW4fU9dHKwIs03rr1Y/edit?usp=sharing
I need to develop a code for this tool. This code will check this product number after each product number search and if this product number is below 1000, it should send me a mail informing the product number. How can I improve this?
The function that takes the number of products from the site
function _1() {
var spreadsheet = SpreadsheetApp.getActiveSheet();
var startCol = 1
var lastRow = spreadsheet.getLastRow();
var rawtext = UrlFetchApp.fetch("https://kolayoto.com/collections/lastikleri.json").getContentText()
var jsonObj = JSON.parse(rawtext);
var contentObj = jsonObj.collection
var columns = Object.keys(contentObj)
var colName = []
var result = []
for (var i = 0; i < columns.length; i++){
var key = columns[i]
var value = contentObj[key]
result.push(value)
}
var numRow = 1
var numCol = columns.length
if(lastRow+1 == 1){
spreadsheet.getRange(lastRow+1, startCol, numRow, numCol).setValues([columns]);
spreadsheet.getRange(lastRow+2, startCol, numRow, numCol).setValues([result]);
}else {
spreadsheet.getRange(lastRow+1, startCol, numRow, numCol).setValues([result]);
}
spreadsheet.getRange(lastRow+1, startCol).activate();
};
The function that should take the Products Count number of the last row and send mail if it is less than 1000. (It is not working and has not been completed yet.) https://gyazo.com/e2fd5cdc4043dec00da1fce0e3c6c0ca (6562 is products count)
function SendEmail() {
// Fetch the monthly sales
var spreadsheet = SpreadsheetApp.getActiveSheet();
// I need your help in here. How can I get the products count in the last row after each run?
// Check totals sales
if (productsCount < 1000){
// Send Alert Email.
var message = 'KolayOto Lastik Ürün Sayısı Uyarısı!'; // Second column
var subject = 'Ürün sayısı uyarısı!';
MailApp.sendEmail("bbelcioglu#sekizgen.com", subject, message);
MailApp.sendEmail("berk.belcioglu#gmail.com", subject, message);
}
}
I hope I could explain the problems enough. I would be glad if you help.
Thanks.
I believe your goal as follows.
You want to retrieve the Products Count number from the URL using Google Apps Script.
In this case, you want to return the value of 6562.
You want to return that value at the function of _1().
For this, how about this answer?
Modification points:
When the returned value from the URL is seen, the Products Count number can be retrieved with contentObj.products_count.
Modified script:
When your script of _1() is modified, it becomes as follows.
From:
spreadsheet.getRange(lastRow+1, startCol).activate();
};
To:
spreadsheet.getRange(lastRow+1, startCol).activate();
return contentObj.products_count; // <--- Added
};
And, by above modification, SendEmail() can be modified as follows.
function SendEmail() {
var productsCount = _1(); // <--- Added
// Fetch the monthly sales
var spreadsheet = SpreadsheetApp.getActiveSheet();
// I need your help in here. How can I get the products count in the last row after each run?
// Check totals sales
if (productsCount < 1000){
// Send Alert Email.
var message = 'KolayOto Lastik Ürün Sayısı Uyarısı!'; // Second column
var subject = 'Ürün sayısı uyarısı!';
MailApp.sendEmail("bbelcioglu#sekizgen.com", subject, message);
MailApp.sendEmail("berk.belcioglu#gmail.com", subject, message);
}
}
I'm in creating a volunteer registration system for the organization I work with. I want to write a script so that any time I run the script from the dropdown menu, it scans the spreadsheet row by row, and determines what the application status is. If the status is open, I want it to then determine if the status open email has been sent, if it hasn't, send the email, and change the value of the open_email value for that row to "SENT". If the app status is closed, I want it to do the same thing for the closed email.
Volunteer Spreadsheet
Basically, I want to run this function whenever we get new volunteer applications so that they receive emails based on their application status.
I've been successful in writing the function to scan the rows and send the emails based on the application status, but I can't seem to figure out how to get it to change the value of the cell after it has sent the corresponding email.
Here is the code for the mail merge function:
//function for menu item 1
function volunteerMailMerge() {
SpreadsheetApp.getUi();
//references
var ss = SpreadsheetApp.openById("1Ei86oBsafBc6GdFeKFFGdbljyUzbWRFRF8eWvnoYdIU");
var sheet = ss.getSheetByName("Application Status");
var range = sheet.getDataRange(); //sets range to all data in the spreadsheet
var values = sheet.getDataRange().getValues(); //translates the range into values in an array
var headers = values.shift(); //removes headers from values array
//loop through rows
for (var i = 0; i < values.length; i++) {
var firstName = values[i][0];
var lastName = values[i][1];
var email = values[i][2];
var position = values[i][3];
var status = values[i][4];
//mailmerge
if (status == "OPEN" && openEmail == "") {
//if app status is open, and openEmail hasn't been sent, do this
GmailApp.sendEmail(email, "SAFE Volunteer Application",{
htmlBody: "email body",
});
//change value of column 5 on the current row
} else {};
};
}
To change a Google Sheet cell value use setValue(value)
Sets the value of the range. The value can be numeric, string, boolean
or date. If it begins with '=' it is interpreted as a formula.
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var cell = sheet.getRange("B2");
cell.setValue(100);