Run Google script on single sheet instead of entire spreadsheet - javascript

With my spreadsheet, I have 2 Google forms tied to 2 sheets. When a form gets submitted the script executes and does it's thing. However, I only want the script to execute based on a submission from a single sheet. As it is now, the script executes when either of the forms get submitted.
My two sheets are:
Job Submission
and Order Submission
Any advice?
// Work Order
// Get template from Google Docs and name it
var docTemplate = ""; // *** replace with your template ID ***
var docName = "Work Order";
var printerId = "";
function addDates() {
var date = new Date(); // your form date
var holiday = ["09/04/2017","10/09/2017","11/23/2017","12/24/2017","12/25/2017","01/01/2018"]; //Define holiday dates in MM/dd/yyyy
var days = 5; //No of days you want to add
date.setDate(date.getDate());
var counter = 0;
if(days > 0 ){
while (counter < days) {
date.setDate(date.getDate() + 1 );
var check = date.getDay();
var holidayCheck = holiday.indexOf(Utilities.formatDate(date, "EDT", "MM/dd/yyyy"));
if (check != 0 && check != 6 && holidayCheck == -1) {
counter++;
}
}
}
Logger.log(date) //for this example will give 08/16/2017
return date;
}
function createNewDoc(values) {
//Get information from form and set as variables
var email_address = "";
var job_name = values[1];
var order_count = values[2];
var order_form = values[7];
var print_services = values[3];
var priority = values[5];
var notes = values[6];
var formattedDate = Utilities.formatDate(new Date(), "EDT", "MM/dd/yyyy");
var expirationDate = Utilities.formatDate(addDates(), "EDT", "MM/dd/yyyy");
// Get document template, copy it as a new temp doc, and save the Doc's id
var copyId = DriveApp.getFileById(docTemplate)
.makeCopy(docName+' for '+job_name)
.getId();
// Open the temporary document
var copyDoc = DocumentApp.openById(copyId);
// Get the document's body section
var copyBody = copyDoc.getActiveSection();
// Replace place holder keys,in our google doc template
copyBody.replaceText('keyJobName', job_name);
copyBody.replaceText('keyOrderCount', order_count);
copyBody.replaceText('keyOrderForm', order_form);
copyBody.replaceText('keyPrintServices', print_services);
copyBody.replaceText('keyPriority', priority);
copyBody.replaceText('keyNotes', notes);
copyBody.replaceText('keyDate', formattedDate);
copyBody.replaceText('keyDue', expirationDate);
// Save and close the temporary document
copyDoc.saveAndClose();
// Convert temporary document to PDF by using the getAs blob conversion
var pdf = DriveApp.getFileById(copyId).getAs("application/pdf");
// Attach PDF and send the email
var subject = "New Job Submission - " + job_name;
var body = "Here is the work order for " + job_name + ". Job is due " + expirationDate + ".";
MailApp.sendEmail(email_address, subject, body, {htmlBody: body, attachments: pdf});
// Move file to folder
var file = DriveApp.getFileById(copyId);
DriveApp.getFolderById("").addFile(file);
file.getParents().next().removeFile(file);
var newDocName = docName + ' for ' + job_name;
return [copyId, newDocName];
}
function printGoogleDocument(copyId, docName) {
// For notes on ticket options see https://developers.google.com/cloud-print/docs/cdd?hl=en
var ticket = {
version: "1.0",
print: {
color: {
type: "STANDARD_COLOR"
},
duplex: {
type: "NO_DUPLEX"
},
}
};
var payload = {
"printerid" : "",
"content" : copyId,
"title" : docName,
"contentType" : "google.kix", // allows you to print google docs
"ticket" : JSON.stringify(ticket),
};
var response = UrlFetchApp.fetch('https://www.google.com/cloudprint/submit', {
method: "POST",
payload: payload,
headers: {
Authorization: 'Bearer ' + GoogleCloudPrint.getCloudPrintService().getAccessToken()
},
"muteHttpExceptions": true
});
// If successful, should show a job here: https://www.google.com/cloudprint/#jobs
response = JSON.parse(response);
if (response.success) {
Logger.log("%s", response.message);
} else {
Logger.log("Error Code: %s %s", response.errorCode, response.message);
}
return response;
}
// When Form Gets submitted
function onFormSubmit(e) {
var values = e.values;
var returnedDocValues = createNewDoc(values);
var copyId = returnedDocValues[0];
var docName= returnedDocValues[1];
printGoogleDocument(copyId, docName);
}
Edit:
I'm not sure how to do a complete or verifiable example since it's dependent on the form submission. I don't often work with javascript so I'm still learning.
Anyway, I updated my onFormSubmit function, however, my other functions have failed to execute. The script doesn't create the doc and in turn doesn't get sent to the google cloud print
// When Form Gets submitted
function onFormSubmit(e) {
// Initialize
var rng = e.range;
var sheet = rng.getSheet();
var name = sheet.getName();
// If the response was not submitted to the right sheet, exit.
if(name != "Job Submission") return;
var values = e.values;
var returnedDocValues = createNewDoc(values);
var copyId = returnedDocValues[0];
var docName= returnedDocValues[1];
printGoogleDocument(copyId, docName);
}

If your onFormSubmit function is on a script bounded to the spreadsheet, the event object includes a range object. You could use getSheet to get the sheet and then getName to get the sheet name.
Example:
function onFormSubmit(e){
// Initialize
var rng = e.range;
var sheet = rng.getSheet();
var name = sheet.getName();
// If the response was not submitted to the right sheet, exit.
if(name != "Responses 1") return;
//Otherwise continue
}

Going off of Ruben's suggestion, here is what I ended up with
function onFormSubmit(e) {
// Initialize
var name = e.range.getSheet().getName();
// If the response was not submitted to the right sheet, exit.
if (name != "Job Submission") return;
var values = e.values;
var returnedDocValues = createNewDoc(values);
var copyId = returnedDocValues[0];
var docName = returnedDocValues[1];
printGoogleDocument(copyId, docName);
}

Related

How to create a google doc for each row of a spreadsheet?

Yo!
This is my code that uses the last line of a spreadsheet to generate a google docs, in addition, it places a link to this document in the source spreadsheet. Is it possible to create code that does this for all rows in a worksheet? I'm having trouble using .range() to read the lines individually. The reason for this is simply to maintain and update generated versus updated data.
In advance, thank you!
var app=SpreadsheetApp.openById("Google ID");
var sheet=app.getSheetByName('Respostas ao formulário 1')
function autoFillLastRow() {
var range=sheet.getDataRange().getValues();
var elem = range.pop();
//e.values is an array of form values
var timestamp = elem[0];
//conversor de datas
let data = new Date(timestamp);
let dataFormatada = ((data.getDate() )) + "/" + ((data.getMonth() + 1)) + "/" + data.getFullYear();
var firstName = elem[1];
var lastName = elem[2];
var title = elem[3];
//file is the template file, and you get it by ID
var file = DriveApp.getFileById('Google Drive ID');
//We can make a copy of the template, name it, and optionally tell it what folder to live in
//file.makeCopy will return a Google Drive file object
var folder = DriveApp.getFolderById('Google Drive ID')
var copy = file.makeCopy(dataFormatada + ', ' + firstName, folder);
//Once we've got the new file created, we need to open it as a document by using its ID
var doc = DocumentApp.openById(copy.getId());
//Since everything we need to change is in the body, we need to get that
var body = doc.getBody();
//Then we call all of our replaceText methods
body.replaceText('{{Nome}}', firstName);
body.replaceText('{{Sobrenome}}', lastName);
body.replaceText('{{Título}}', title);
//Lastly we save and close the document to persist our changes
doc.saveAndClose();
//edit cell
var coluna = 5;
var linha = sheet.getLastRow();
var docId = doc.getId();
sheet.getRange(linha, coluna,1,1).setValue("https://docs.google.com/document/d/" + docId);
}
Create document for every row of spreadsheet
function createDocforEveryRowofSpreadsheet() {
var ss = SpreadsheetApp.openById("Google ID");
var sh = ss.getSheetByName('Respostas ao formulário 1')
var file = DriveApp.getFileById('Google Drive ID');
var folder = DriveApp.getFolderById('Google Drive ID')
var [hA,...vs] = sh.getDataRange().getValues();
vs.forEach((r,i) => {
var ts = r[0];
let data = new Date(ts);
let dataFormatada = Utilities.formatDate(new Date(ts), Spreadsheet.getSpreadsheetTimeZone(), "dd/MM/yyyy")
var firstName = r[1];
var lastName = r[2];
var title = r[3];
var copy = file.makeCopy(dataFormatada + ', ' + firstName, folder);
var doc = DocumentApp.openById(copy.getId());
var body = doc.getBody();
body.replaceText('{{Nome}}', firstName);
body.replaceText('{{Sobrenome}}', lastName);
body.replaceText('{{Título}}', title);
doc.saveAndClose();
})
}

Functions Rerunning in GAS

I'm using GAS to send and receive texts. There is one function that send texts (sendTexts.gs) and one that receives (receiveTexts.gs). I have both of these functions linked to individual buttons on the sheet, but when I run one function, both are running (texts get sent every time). Is there a cache or something that needs to be cleared? The receiveTexts has no commands in the code that could send messages in it, and based on logger testing, I know that both are running when I only click one.
EDIT: This also occurs in the GAS "terminal". If I click run in the script editor both run.
Here is the code with personal/individual info (codes/phone numbers edited out):
function sendSms(to, body) {
var playerArray = getMeta();
Logger.log(playerArray);
var messages_url = "https://api.twilio.com/2010-04-01/Accounts/EDIT/Messages.json";
var payload = {
"To": to,
"Body" : body,
"From" : "EDIT"
};
var options = {
"method" : "post",
"payload" : payload
};
options.headers = {
"Authorization" : "Basic " + Utilities.base64Encode("EDIT")
};
UrlFetchApp.fetch(messages_url, options);
}
function sendAll() {
var spreadsheet = SpreadsheetApp.getActive();
var text = SpreadsheetApp.setActiveSheet(spreadsheet.getSheetByName('Meta')).getRange('B4').getValue();
var playerArray = getMeta();
Logger.log(text);
for (i=0; i<playerArray.length;i++) {
try {
var number = playerArray[i][1];
Logger.log(number);
response_data = sendSms(number, text);
status = "sent";
} catch(err) {
Logger.log(err);
status = "error";
}
Logger.log(status);
}
}
function sendTexts() {
sendAll();
}
Logger.log("ran send texts");
Here is the receive texts code with the same adjustments:
function receiveTexts() {
var spreadsheet = SpreadsheetApp.getActive();
var ACCOUNT_SID = "EDIT";
var ACCOUNT_TOKEN = "EDIT";
var toPhoneNumber = "+EDIT";
var sheet = spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Meta'), true);
var playerArray = getMeta();
var numberToRetrieve = playerArray.length;
var hoursOffset = 0;
var options = {
"method" : "get"
};
options.headers = {
"Authorization" : "Basic " + Utilities.base64Encode(ACCOUNT_SID + ":" + ACCOUNT_TOKEN)
};
var url="https://api.twilio.com/2010-04-01/Accounts/" + ACCOUNT_SID + "/Messages.json?To=" + toPhoneNumber + "&PageSize=" + numberToRetrieve;
var response = UrlFetchApp.fetch(url,options);
// -------------------------------------------
// Parse the JSON data and put it into the spreadsheet's active page.
// Documentation: https://www.twilio.com/docs/api/rest/response
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Meta'), true);
var numRounds = spreadsheet.getRange('B2').getValue();
var theSheet = SpreadsheetApp.setActiveSheet(spreadsheet.getSheetByName('Attacks'),true);
var theColumn = (numRounds*2)+1;
var dataAll = JSON.parse(response.getContentText());
for (i=0; i<dataAll.messages.length; i++){
var sentNumber = dataAll.messages[i].from;
Logger.log(sentNumber);
for (k=0; k<playerArray.length;k++){
Logger.log(playerArray[k][1]);
if (playerArray[k][1]==sentNumber){
var player = k;
Logger.log('Success');
Logger.log(player);
break;
}
}
var playerRow = playerArray[player][0];
Logger.log(playerRow);
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Attacks'),true);
theSheet.getRange(playerRow, theColumn).setValue(dataAll.messages[i].body);
}
spreadsheet.setActiveSheet(spreadsheet.getSheetByName('Meta'), true);
sheet.getRange(2,2).setValue(numRounds +1);
}
Logger.log("texts received ran");
EDIT2: I separated out getMeta into a separate file. Now when I run getMeta, it also runs the other two scripts. Anytime any one script is run, all three run. This makes me think it's not related to the code, but related to some setting or something. Does the order of the scripts in the sidebar matter? I feel like that's not it because running any of the three causes all three to be run.

How to set a time-driven (clock) trigger for a function that needs parameters sent to it?

I'm trying to have a function run with a time-driven (clock) trigger. My issue is, the function needs variables sent to it as parameters. Normally if I'm not using a trigger I'll just send it directly like this.
<script>
function runFunction(){
google.script.run.myFunction(x,y,z);
}
</script>
And on the server side, I'll call them easily.
function myFunction(x,y,z){
var a = x;
var b = y;
var c = z;
Logger.log(a+b+c);
}
But when I'm using a time-driven (clock) trigger to run the function how can I get x,y,z into the function.
I searched around and saw one method of creating scriptProperties out of the parameters in the trigger function like this.
EDITED This is the actual code.
Client side.
<script>
function sendCall() {
var testNumber = document.getElementById('numberCall').value;
var testGroup = document.getElementById('groupsCall').value;
var testtime = document.getElementById('scheduleCall').value;
var now = document.getElementsByName('sendTimeCall')[0].checked;
var number;
if(testNumber == ''){
number = null;
}else{
number = testNumber;
}
var group;
if(testGroup == ""){
group = null;
}else{
group = testGroup;
}
var time;
if(testtime == ''){
time = null;
}else{
time = testtime;
}
var file = document.getElementsByName('audio')[0].files[0];
var name = file.name;
var reader = new FileReader();
reader.onload = function (e) {
var content = reader.result;
google.script.run.withSuccessHandler(success2).triggerCall(group, number, content, time, now, name);
return false;
}
reader.readAsDataURL(file);
}
</script>
Server side - Trigger Function.
function triggerCall(group, number, content, time, now, name){
var scriptProperties = PropertiesService.getScriptProperties();
scriptProperties.setProperties({
'GROUP_CALL': group,
'AUDIO': content,
'NUMBER_CALL': number,
'FILE_NAME': name
});
var status;
if(now){
status = 'Call Sent';
}else{
status = 'Call Scheduled';
}
if(now){
return makeCall(status);
}else{
// Set here the date you want to schedule the one-time trigger
var rawdate = time;
var today_D = new Date(new Date().toLocaleString("en-US", {timeZone: "America/New_York"}));
var scheduled_D = new Date(rawdate);
var time_af = Math.abs(scheduled_D - today_D) / 36e5;
ScriptApp.newTrigger("makeCall")
.timeBased()
.after(time_af * 60 *60 * 1000)
.create();
}
return status;
}
Server side - Here is The function that actually does the work.
function makeCall(status) {
var scriptProperties = PropertiesService.getScriptProperties();
var blob = scriptProperties.getProperty('AUDIO');
var number = scriptProperties.getProperty('NUMBER_CALL');
var group = scriptProperties.getProperty('GROUP_CALL');
var name = scriptProperties.getProperty('FILE_NAME');
var fullNumber;
if(group){
var ss = SpreadsheetApp.openById('xxxxxxxxxxxxxxxxxxx');
var sheet = ss.getSheetByName(group)
var length = sheet.getLastRow();
var values = sheet.getRange(1, 1, length).getValues();
fullNumber = values.flat();
}else{
var num = number;
var prefix = '+1';
var removeDashes = num.replace(/-/g,"");
var format = prefix + removeDashes;
var comma = format.replace(/ /g, ' +1');
fullNumber = comma.split(' ')
}
//upload file to drive
var folder = DriveApp.getFolderById('xxxxxxxxxxxxxxxxxxxxxx');
var blob = blob.split(",");
var blob = Utilities.newBlob(Utilities.base64Decode(blob[1]), 'audio/mpeg', name);
var file = folder.createFile(blob);
file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
var id = file.getId();
for (var i = 0; i < fullNumber.length; i++){
//the url with HTTP request to create a call and parameters
var callsUrl = "https://api.twilio.com/2010-04-01/Accounts/ACxxxxxxxxxxxxxxxx/Calls.json";
var payload = {
"To": fullNumber[i],
"From" : "+177777777",
"Twiml" : "<Response><Play>https://docs.google.com/uc?export=play&id=" + id + "</Play></Response>",
};
var options = {
"method" : "post",
"payload" : payload
};
options.headers = {
"Authorization" : "Basic " + Utilities.base64Encode("xxxxxxxxxxx:xxxxxxxx")
};
UrlFetchApp.fetch(callsUrl, options);
}
scriptProperties.deleteProperty('AUDIO');
scriptProperties.deleteProperty('NUMBER_CALL');
scriptProperties.deleteProperty('GROUP_CALL');
scriptProperties.deleteProperty('FILE_NAME');
return status;
}
The problem is when I run the above code without the file input it works, But when I run it as above the function doesn't work. I did some trouble shooting and I think it has to do with transferring the file as a Data URL via the properties method. Is there a limit to how long of a string the VALUE can be?
in a nut shell these are the 2 points of my question.
Any other ideas how to send parameters to a triggered function
How I could do it using PropertiesService.
I would like to propose the following modification.
Modification points:
I think that the reason of your issue might be due to the maximum data size for PropertiesService. In the current stage, it seems that "Properties total storage" is "500kB / property store". I thought that in this case, when you upload a file, the file size might be over than it.
In order to remove your issue, how about creating content as a temporal file and put the file ID to the PropertiesService?
When above points are reflected to your script, it becomes as follows.
Pattern 1:
In this pattern, content is saved as a temporal file and that is used in the function of makeCall().
triggerCall()
function triggerCall(group, number, content, time, now, name){
var scriptProperties = PropertiesService.getScriptProperties();
var tempFile = DriveApp.createFile("tempFile.txt", content, MimeType.PLAIN_TEXT); // Added
scriptProperties.setProperties({'GROUP_CALL': group,'AUDIO': tempFile.getId(),'NUMBER_CALL': number,'FILE_NAME': name}); // Modified
var status;
if(now){
status = 'Call Sent';
}else{
status = 'Call Scheduled';
}
if(now){
return makeCall(status);
}else{
var rawdate = time;
var today_D = new Date(new Date().toLocaleString("en-US", {timeZone: "America/New_York"}));
var scheduled_D = new Date(rawdate);
var time_af = Math.abs(scheduled_D - today_D) / 36e5;
ScriptApp.newTrigger("makeCall").timeBased().after(time_af * 60 *60 * 1000).create();
}
return status;
}
makeCall()
function makeCall(status) {
var scriptProperties = PropertiesService.getScriptProperties();
var tempfileId = scriptProperties.getProperty('AUDIO'); // Modified
var number = scriptProperties.getProperty('NUMBER_CALL');
var group = scriptProperties.getProperty('GROUP_CALL');
var name = scriptProperties.getProperty('FILE_NAME');
var fullNumber;
if(group){
var ss = SpreadsheetApp.openById('xxxxxxxxxxxxxxxxxxx');
var sheet = ss.getSheetByName(group)
var length = sheet.getLastRow();
var values = sheet.getRange(1, 1, length).getValues();
fullNumber = values.flat();
}else{
var num = number;
var prefix = '+1';
var removeDashes = num.replace(/-/g,"");
var format = prefix + removeDashes;
var comma = format.replace(/ /g, ' +1');
fullNumber = comma.split(' ')
}
var folder = DriveApp.getFolderById('xxxxxxxxxxxxxxxxxxxxxx');
var tempFile = DriveApp.getFileById(tempfileId); // Added
var text = tempFile.getBlob().getDataAsString(); // Added
tempFile.setTrashed(true); // Added
var blob = text.split(","); // Modified
var blob = Utilities.newBlob(Utilities.base64Decode(blob[1]), 'audio/mpeg', name);
var file = folder.createFile(blob);
file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
var id = file.getId();
for (var i = 0; i < fullNumber.length; i++){
var callsUrl = "https://api.twilio.com/2010-04-01/Accounts/ACxxxxxxxxxxxxxxxx/Calls.json";
var payload = {"To": fullNumber[i],"From" : "+177777777","Twiml" : "<Response><Play>https://docs.google.com/uc?export=play&id=" + id + "</Play></Response>"};
var options = {"method" : "post","payload" : payload};
options.headers = {"Authorization" : "Basic " + Utilities.base64Encode("xxxxxxxxxxx:xxxxxxxx")};
UrlFetchApp.fetch(callsUrl, options);
}
scriptProperties.deleteProperty('AUDIO');
scriptProperties.deleteProperty('NUMBER_CALL');
scriptProperties.deleteProperty('GROUP_CALL');
scriptProperties.deleteProperty('FILE_NAME');
return status;
}
Pattern 2:
In this pattern, content is saved to a file as the decoded data and that is used in the function of makeCall().
triggerCall()
function triggerCall(group, number, content, time, now, name){
var scriptProperties = PropertiesService.getScriptProperties();
var folder = DriveApp.getFolderById('xxxxxxxxxxxxxxxxxxxxxx'); // Added
var blob = content.split(","); // Added
var blob = Utilities.newBlob(Utilities.base64Decode(blob[1]), 'audio/mpeg', name); // Added
var file = folder.createFile(blob); // Added
scriptProperties.setProperties({'GROUP_CALL': group,'AUDIO': file.getId(),'NUMBER_CALL': number,'FILE_NAME': name}); // Modified
var status;
if(now){
status = 'Call Sent';
}else{
status = 'Call Scheduled';
}
if(now){
return makeCall(status);
}else{
var rawdate = time;
var today_D = new Date(new Date().toLocaleString("en-US", {timeZone: "America/New_York"}));
var scheduled_D = new Date(rawdate);
var time_af = Math.abs(scheduled_D - today_D) / 36e5;
ScriptApp.newTrigger("makeCall").timeBased().after(time_af * 60 *60 * 1000).create();
}
return status;
}
makeCall()
function makeCall(status) {
var scriptProperties = PropertiesService.getScriptProperties();
var fileId = scriptProperties.getProperty('AUDIO'); // Modified
var number = scriptProperties.getProperty('NUMBER_CALL');
var group = scriptProperties.getProperty('GROUP_CALL');
var name = scriptProperties.getProperty('FILE_NAME');
var fullNumber;
if(group){
var ss = SpreadsheetApp.openById('xxxxxxxxxxxxxxxxxxx');
var sheet = ss.getSheetByName(group)
var length = sheet.getLastRow();
var values = sheet.getRange(1, 1, length).getValues();
fullNumber = values.flat();
}else{
var num = number;
var prefix = '+1';
var removeDashes = num.replace(/-/g,"");
var format = prefix + removeDashes;
var comma = format.replace(/ /g, ' +1');
fullNumber = comma.split(' ')
}
var file = DriveApp.getFileById(fileId); // Modified
file.setSharing(DriveApp.Access.ANYONE_WITH_LINK, DriveApp.Permission.VIEW);
var id = file.getId();
for (var i = 0; i < fullNumber.length; i++){
var callsUrl = "https://api.twilio.com/2010-04-01/Accounts/ACxxxxxxxxxxxxxxxx/Calls.json";
var payload = {"To": fullNumber[i],"From" : "+177777777","Twiml" : "<Response><Play>https://docs.google.com/uc?export=play&id=" + id + "</Play></Response>"};
var options = {"method" : "post","payload" : payload};
options.headers = {"Authorization" : "Basic " + Utilities.base64Encode("xxxxxxxxxxx:xxxxxxxx")};
UrlFetchApp.fetch(callsUrl, options);
}
scriptProperties.deleteProperty('AUDIO');
scriptProperties.deleteProperty('NUMBER_CALL');
scriptProperties.deleteProperty('GROUP_CALL');
scriptProperties.deleteProperty('FILE_NAME');
return status;
}
Note:
In this modified script, when a file is uploaded, content is saved as a temporal file and the file ID is put to the PropertiesService. When makeCall is run, content is retrieved by the file ID and convert to the blob and saved it as a file. And the temporal file is removed. By this, the limitation of PropertiesService can be cleared.
But, in the current stage, the maximum blob size of Google Apps Script is 50 MB (52,428,800 bytes). So when the uploaded file size is over 50 MB, an error occurs. In this case, the file is converted to the base64 data. So, the maximum size is the size of base64 data. Please be careful this.
Reference:
Current limitations

Trigger WhatsApp message when someone from google sheets

Is it possible to automatically send WhatsApp messages if someone fills my google form,currently storing data into a google sheet. In this form, users fill in their Name and phone number. I want to automatically send them a welcome message when they fill the form. I have successfully sent a welcome email in a similar google form with the help of App Script.
This is what I did in case of email:
function sendMail() {
SpreadsheetApp.getActiveSpreadsheet().getSheetByName("CRM").activate()
var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var lr = ss.getLastRow();
var quotaLeft = MailApp.getRemainingDailyQuota();
// Logger.log(quotaLeft)
if((lr-1) > quotaLeft){
Browser.msgBox("You have only " + quotaLeft + " E-mail left, mails were not sent")
} else{
for(var i=2; i<=lr;i++){
var currentEmail = ss.getRange(i, 1).getValue();
var currentSub = ss.getRange(i, 3).getValue();
var currentName = ss.getRange(i, 2).getValue();
var templateText = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Templates").getRange(i, 2).getValue();
var name = templateText.replace("{name}", currentName);
MailApp.sendEmail(currentEmail, currentSub, name)
}
Browser.msgBox("Welcome emails sent")
}
}
It's possible if you use twillo. Try the below code
function sampletTextMessage(){
var ACCOUNT_SID = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
var ACCOUNT_TOKEN = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
var options = {
"method" : "post",
'headers' : {
"Authorization" : "Basic " + Utilities.base64Encode(ACCOUNT_SID + ":" + ACCOUNT_TOKEN),
},
'payload' :{
'Body' : 'Your Twilio code is 1238432',
'To' : 'whatsapp:+91XXXXXXXXX3',
'From': 'whatsapp:+1XXXXXXXXX6',
},
'muteHttpExceptions' : true
};
var url="https://api.twilio.com/2010-04-01/Accounts/" + ACCOUNT_SID + "/Messages.json";
var response = UrlFetchApp.fetch(url,options);
Logger.log(response);
}
Register in https://panel.rapiwha.com/landing/login.php. Link your number and get the API Key.
Put the below code in your sheet
Install a Trigger "On Form Submit"
//
//
function onFormSubmit(e) {
var today=new Date();
var shtname = e.source.getActiveSheet().getName();
switch (shtname) {
case "SaleOrder":
var resp = e.source.getActiveSheet().getRange(e.range.rowStart,1, e.range.rowStart,4 ).getValues();
//name is the first question
//mobile no is second question (with country code, without + sign)
var api_key="xxxxxx"; //from rapiwah
var wup = "Dear " +resp[0][1]+" Thank you for contacting us. We will get back yo you soon";
var formurl2= 'https://panel.rapiwha.com/send_message.php?apikey='+api_key+'&number=' + resp[0][2] +'&text='+wup;
var formurl3 = formurl2.replace(/#/g, "");
var formurl4 = formurl3.replace(/,/g, "");
var formurl = formurl4.replace(/ /g, "%20");
var response = UrlFetchApp.fetch(formurl);
break;
//
default:
break;
}
}

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.

Categories