Send SMS from Google Sheet - google-sheets

I got the script to send SMS for all the rows in a google sheet using Twilio example.
I want to send SMS acknowledgement to my customers from the below google sheet
https://docs.google.com/spreadsheets/d/1Jpka0Wn8cQ6J6Be8Ks5vF-JJ50ykdCuMIetrWjAi7Kw/edit?usp=sharing
I want SMS to go only once to all the customers for whom the Status is not starting with "Sent" and where the phone number is starting with "+91"
The SMS will be like this
Complaint No "SER 160530" with us registered on "16/5/16" for customer "TNEB" due to "CT Failed". Please call 18004257865 for details
The message is made up of some text and the value from some cells in a particular row
The "Status" column must get updated "Sent SMS to xxxxxxxx on xxxx at xx:xx:xx:xx"
Is it possible to run the script every one hour automatically?
Is there any free alternative to send SMS from Google sheet?

To execute your script every hour you can set up a time driven trigger. Here is the documentation for setting up a trigger.
Here is my workaround for sending texts out of a Google Sheet for free, it might not work for your specific need, but is an option:
Every mobile phone carrier offers an email to sms option that is free. Examples of these email addresses are here. For example if I am wanting to text someone on the Sprint network I would attach the phone number to their domain like: 13032223333#messaging.sprintpcs.com. If you are able to collect or look up the carrier for the phone numbers you can set up a simple function to connect the two and use a mail merge option like the one below to send out your texts. Here is the documentation the the mail merge that will mark sent messages and prevent multiple texts from going out to the same contact.
// This constant is written in column C for rows for which an email
// has been sent successfully.
var EMAIL_SENT = "EMAIL_SENT";
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 = row[1]; // Second column
var emailSent = row[2]; // Third column
if (emailSent != EMAIL_SENT) { // Prevents sending duplicates
var subject = "Sending emails from a Spreadsheet";
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();
}
}
}

Sending A2P sms, that is sms from an application to a person, costs money, because operators charge for accessing their networks. There might exist some free routes as Torey mentions, but they have limitations and could be pretty unreliable.
Instead of scripting your own sms service, you can try Cloudcom, which is a Google Sheets add-on with a user interface. Full disclosure, I have built and sell this product. Some of the features that could be useful in your case are scheduling and merging custom fields into the message body.

Related

How can I combine three ranges in Google Sheets where there isn't always data in two of them and with a function on one?

I have three ranges of data from YouTube that I want to combine into a single table. The three ranges are:
YouTube subscriber numbers by day (the days for the combined sheet will pull from here)
YouTube videos with lifetime stats and publish date
YouTube channel statistics by day
I have data for every day on the first--subscriber numbers--going back years. The videos have the publish date, and I want to do a unique count on videos so that they show on the day they were published (so: "How many videos were published on X date?"). And finally, showing the channel stats by day, which don't go back as far as the subscriber numbers, but will be every day going forward.
Here's an example sheet, open for editing that shows sample data for the three sheets as well as desired output.
https://docs.google.com/spreadsheets/d/1Ckif5Vo8rLo1HEPUqer7mhyCXfMGlIjdw1wMz6JcPfA/edit?usp=sharing
One option would be to use an Apps Script custom function. To achieve this, follow these steps:
In your spreadsheet, select Tools > Script editor to open a script bound to your file.
Copy this function in the script editor, and save the project (check inline comments):
function GET_COMBINED_TABLE(subscribersRange, videosRange, otherStatsRange) {
const headers = subscribersRange.shift();
headers.push("Distinct Count of Video ID by date", ...otherStatsRange.shift().slice(1));
subscribersRange = subscribersRange.filter(r => r[0]);
videosRange = videosRange.filter(r => r[0]);
otherStatsRange = otherStatsRange.filter(r => r[0]);
videosRange.shift();
const combinedData = subscribersRange.map(row => { // Iterate through subscribers data
const rowDate = row[0];
let videoCount = videosRange.filter(videosRow => videosRow[0] && sameDay(videosRow[0],rowDate)).length; // Check how many rows have this date in videos
videoCount = videoCount ? videoCount : "";
let otherStats = otherStatsRange.find(otherStatsRow => sameDay(otherStatsRow[0], rowDate)); // Find same date in other stats sheet
otherStats = otherStats ? otherStats.slice(1) : new Array(5).fill("");
return [...row, videoCount, ...otherStats]; // Combine row data from 3 different sheets
});
return [headers, ...combinedData]; // Combine headers and data
}
const sameDay = (first, second) => {
return first.getFullYear() === second.getFullYear() && first.getMonth() === second.getMonth() && first.getDate() === second.getDate();
}
Now, if you go back to your spreadsheet, you can use this function like any in-built one. You just have to provide the appropriate ranges as function arguments:
Note:
If you want to use this function in any spreadsheet without having to add the function to the associated script, consider deploying this as a Sheets add-on.
Reference:
Custom Functions in Google Sheets

Googlesheet editing permission of specific range to specific gmail id

I want to allow editing of specific range to specific gmail id. For example A1 contains gmail id of Tom and I want to allow Tom to edit B1 to G1, and A2 contains gmail id of James and I want to allow James to edit B2 to G2. How Should I do that. There are 400 different gmail id of different persons I want to allow them to edit specific ranges according to the gmail id present in column A. How should I do that. Manually doing this is very time consuming.
How to protect specific cells on a spreadsheet
You can use the following sample code that protects the cells from A1 to B10.
// Protect range A1:B10, then remove all other users from the list of editors.
var ss = SpreadsheetApp.getActive();
var range = ss.getRange('A1:B10');
var protection = range.protect().setDescription('user name or ID just as a reference');
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
Since you will have the list of IDs on the same spreadsheet, you can modify the code and use a loop to grab the ID from each user and set the protected range and user according to your needs.
Something really important for this to work is that if you run this script you need to be the owner of the spreadsheet, otherwise you may get an error.
You will also need to have the users' email address along with the ID to set them as editors.

Google Sheets - Generate next invoice number, multiple points of sale

Situation:
1 company, 3 different points of sale.
I have to make 3 different stacks of invoices.
Invoice numbers are 1/1/1, 1/1/2, 1/1/3, where the first number is incremental, second number is always 1 & third number is the point of sale identifier.
First sheet is data input.
Second is the is invoice generator.
Sheet 3, 4 & 5 are point of sale invoice archive.
I managed to get next invoice number generated depending on the point of sale using the index and left functions in separate cells but i get the error message along with the result that i actually wanted.
Is there a simple way to get generated IDs from POS1, POS2, POS3 sheets into a drop-down list data validation without any error?
Sheet Racun ->Click on the invoice number, choose point of sale (eg. POS1).
Go to sheet POS1 and click save.
https://docs.google.com/spreadsheets/d/1RD_rkbtmhC-OKh2dAtc32Qo1p42RdgKaiZsnI8uRKyg/edit?usp=sharing
I am sorry if i didnt explain myself correctly. English is not my mother language.
Suggestion
You can try adding this onOpen() function below on your Apps Script to automatically get the generated IDs from POS1,POS2,POS3 sheets & build a new data validation drop-down on cell C11 of the Racun sheet.
Script
function CopyRow(){
var sh = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
var data = sh.getRange('A3:F3').getDisplayValues();
var lastRow = sh.getLastRow()+1
sh.getRange('A'+lastRow+':F'+lastRow).setNumberFormat("#").setValues(data);
}
function onOpen(){
var sh = SpreadsheetApp.getActive();
var cell = SpreadsheetApp.getActive().getSheetByName("Racun").getRange('C11');
var values = [sh.getSheetByName("POS1").getRange("K2").getValue()+" (POS1)",
sh.getSheetByName("POS2").getRange("K2").getValue()+" (POS2)",
sh.getSheetByName("POS3").getRange("K2").getValue()+" (POS3)"];
var rule = SpreadsheetApp.newDataValidation().requireValueInList(values).build();
cell.setDataValidation(rule);
}
Sample Demonstration
After saving & running the script or re-opening of your sheet, you will see the new drop-down:
NOTE:
On your POS1,POS2,POS3 sheets, just change the formula on cell A3 with =LEFT(Racun!C11, LEN(Racun!C11)-6) to get the generated IDs, as seen below:

How to check a google spreadsheet before processing a form?

I have tickets I'm selling for an event, and I have a google spreadsheet with a list of email addresses that should get a discount.
I'd like to check the google sheet once a user types in their email address in the form, and then if theirs is in our list, the discount gets applied.
I can't seem to figure out how to do this. The example code here: https://developers.google.com/sheets/api/quickstart/js requires users to allow access to their google drive, which isn't what I need. I just need to check my own spreadsheet.
How might I do this?
You can use Apps Script (since you're using Forms), if you want a handy solution. I don't know the complexity of your usecase but I'll just demo that this is doable:
So this is my spreadsheet, you can see the names on Column A:
name(0,0)
floyd(1,0)
conor(2,0)
john
carmack
borja
adam
I'm going to look for "adam"
function findPerson() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var range = ss.getSheets()[0].getRange("A1:A7").getValues();
for(var i = 0; i < range.length ; i++){
Logger.log(range[i]);
if( range[i] == "adam"){
Logger.log("FOUND YAH!");
}
}
}
And there, I found him! ;)
If that's a Google Form you're using, the next step would be learning how to Connect Spreadsheet to Google Forms

How to protect from editing only rows that are odd numbered?

In Google Sheets how do I protect the rows in Column A which are odd from any kind of edits?
I would like to use this function
=ISODD(ROW(A1))
Protected sheets and ranges gives you this by default
Sheet1!A1
I can do this
Sheet1!A1:A1000
which will protect all 1000 rows but how do I use functions in that so I can only use ODD rows.
Here is a picture of that feature:
As mentioned in the comments on your question, I don't believe there is currently any way of manipulating range protection with Google Apps Script.
So the only option that I can think of is to manually apply the protection to 500 individual cells (in your example).
A workaround - that is not particularly tidy - is to use data validation to thwart (ultimately not prevent) entering data in even rows, with this sort of arrangement (accessed from Data, Validation...):
Savvy users who have access to the spreadsheet will be able to go in to data validation and circumvent this, though.
Google has created api for protecting sheets using google app script.
For example, to protect range A1:B10, You can run
var ss = SpreadsheetApp.getActive();
var range = ss.getRange('A1:B10');
var protection = range.protect().setDescription('Sample protected range');
If You want to protect rows alternatively, You can try something like this
function alternateRowProtection() {
var totalRows = SpreadsheetApp.getActiveRange().getNumRows();
var sheet = SpreadsheetApp.getActiveSheet();
var row = 1;
while (row < totalRows)
{
if(row%2 == 0){
sheet.getRange(row).protect().setDescription('This is protected.');
}
row++;
}
}

Resources