String ranges in Google Apps Script - google-apps-script

I have a sheet that I need to get values from and set in a new sheet, one of these values requires me to slice string value at indices 20,26. I can achieve this using .getValue().slice(20,26) and .setValue(). However, the same data is set in all rows, which is to be expected since I am only getting a single cell of data. To resolve this I tried a for loop which failed.
When I attempt .getValues().slice(20,26) it returns an empty array which throws the following error: The number of rows in the data does not match the number of rows in the range. The data has 0 but the range has 20.
My code is below and I welcome any guidance.
function pj() {
// Get Active spreadsheet.
var sheet = SpreadsheetApp.getActiveSpreadsheet();
//Get last row processed and update
var startRow =sheet.getSheetByName("Index").getRange("A1").getValue();
startRow++;
// Get payments sheet.
var paymentSheet = sheet.getSheetByName("Payments");
var clientSheet = sheet.getSheetByName("Client Details");
var lastRow = paymentSheet.getLastRow();
//Inputs
var firstName = paymentSheet.getRange(startRow, 3, (lastRow-startRow+1), 1).getValues();
var lastName= paymentSheet.getRange(startRow, 4, (lastRow-startRow+1), 1).getValues();
var paymentId = paymentSheet.getRange(startRow, 14, (lastRow-startRow+1), 1).getValues().slice(20,26);
}
//Outputs
clientSheet.getRange(2,1,(lastRow-startRow+1),1).setValues(firstName);
clientSheet.getRange(2,8, (lastRow-startRow+1),1).setValues(paymentId);
//Update the last row processed
sheet.getSheetByName('Index').getRange("A1").setValue(lastRow);
}
Please see image of the sheet I am working with, as you will see column N contains a payment ID, which holds a unique identifier for the client that I need to extract in order to upload this data into Salesforce. It seems the issue is that Logger.log is reporting the string correctly as it goes through the array, but is reporting the length as 1. I've tried changing the format of that column various ways, Text, Number etc but it doesn't seem to make any difference to the reported length. I'm assuming this is why the split function isn't working, but I'm not sure why it's happening?Sheet

I guessed at a lot of this but it should look similar to this:
function pj() {
var ss=SpreadsheetApp.getActive();
var isht=ss.getSheetByName("Index");
var startRow=isht.getRange("A1").getValue()+1;
var psht=ss.getSheetByName("Payments");
var csht=ss.getSheetByName("Client Details");
var lastRow=psht.getLastRow();
var prg=psht.getRange(startRow,1,psht.getLastRow()-startRow+1,14);
var pvals=prg.getValues();
pvals.forEach(function(r,i){
csht.getRange(i+2,1).setValue(r[2]);
csht.getRange(i+2,2).setValue(r[3]);
csht.getRange(i+2,8).setValue(r[13].slice(20,26));
});
isht.getRange("A1").setValue(csht.getLastRow());
}

Related

How to separate column into two separate columns by condition App Script

I am trying to take the Data in the scan it columns and conditionally filter it into the commercial or manufacturing sheet.
I tried writing a formula as an if function basically saying if it equals "Company" put it in manufacturing column, if not(if the rest) then put into commercial column.
I tried coding it backend in app script, but had an issue grabbing the last row from scan it and correctly adding the item #, vendor, and quantity into the last row of either Commercial or Manufactured.
The scan it section is an importrange function so more data will be entered into it once the code is working correctly.
I ran into dead ends with both. This is obviously an advanced code and I only did a little bit of coding in college. Below is a script that I had been messing with trying to get it to filter the data properly, but I couldn't get it to run. Any help would be appreciated!
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1')
//Get last rows for MFG
var mfgvalues = sheet.getRange(3, 5, sheet.getLastRow()).getValues();
//var mfglast = mfgvalues.filter(String).length;
//Get last rows for Comm
var commvalues = sheet.getRange(3, 1, sheet.getLastRow()).getValues();
//var commlast = commvalues.filter(String).length;
//Get last rows for Scann
var scanvalues = sheet.getRange(2, 12, sheet.getLastRow()).getValues();
//var scanlast = scanvalues.filter(String).length;
//Filter Accordingly
if (scanvalues == "IMMCO") {
var scanrange = sheet.getRange("L2:N").getLastRow().getValues();
//var scanlastrow = scanrange.getLastRow().getValues();
var mfgrow = sheet.getRange("E3:G").getLastRow();
scanlastrow.copyTo(mfgrow)
} else {
var scanrange = sheet.getRange("L:N").getLastRow.getValues();
//var scanlastrow = scanrange.getLastRow().getValues();
var commrow = sheets.getRange("A3:C").getLastrow()
scanlastrow.copyTo(commrow)
}
}
https://docs.google.com/spreadsheets/d/1D0FvVoTADi3t3ENPceB14QYYI4lNI6C3xj2OF-St7Is/edit?usp=sharing
GOOGLE SHEET OUTPUT WANTED
Option1:
Using FILTER() to filter your data set if vendor name is equal to "COMPANY" as mentioned in your description
Formula in Cell A3:
=filter(L3:N,LEN(L3:L)>0,UPPER(M3:M)<>"COMPANY")
Formula in Cell E3:
=filter(L3:N,LEN(L3:L)>0,UPPER(M3:M)="COMPANY")
Output:
Option2:
Using apps script to filter your data set.
Sample Code:
function filter(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1');
//Get item count for Scann
var scanCnt = sheet.getRange('L3:L').getValues().flat().filter(String).length;
Logger.log(scanCnt);
//Get last rows for Comm
var commLastRow = sheet.getRange('A1:A').getValues().flat().filter(String).length;
Logger.log(commLastRow);
//Get last rows for MFG
var mfgLastRow = sheet.getRange('E1:E').getValues().flat().filter(String).length;
Logger.log(mfgLastRow);
//Get Scann data if item count is not zero
if(scanCnt){
var commItem = [];
var mfgItem = [];
var dataRange = sheet.getRange(3,12,scanCnt,3);
var data = dataRange.getDisplayValues();
//Loop all scann data and separate mfg with comm
Logger.log(data.length)
data.forEach(item => {
Logger.log(item);
if(item[1].toUpperCase() == "COMPANY"){
mfgItem.push(item);
}else{
commItem.push(item);
}
});
Logger.log(mfgItem);
Logger.log(commItem);
//Append comm items
sheet.getRange(commLastRow+1,1,commItem.length,commItem[0].length).setValues(commItem);
//Append mfg items
sheet.getRange(mfgLastRow+1,5,mfgItem.length,mfgItem[0].length).setValues(mfgItem);
//Optional: Clear content of scann column
dataRange.clearContent();
}
}
What it does?
Get the item count to filter in Scan it column by selecting the range L3:L. Get its value. Change 2-d array to 1-d array using array.flat(). Use array.filter() to remove empty values. Then get its length
Get the last row of Commercial(ColumnA) and Manufactured(ColumnE) column.
If item count obtained in step1 is not zero. Then get the data range and its value
Loop all data value (by row) one-by-one. Check if vendor index is equal to "COMPANY" then add it to mfgItem array. Else, add it to commItem array
Append mfgItem and commItem under Manufactured Column and Commercial Column
(Optional) Clear the data under Scan-it Column
Note:
You can check the execution log to further understand the procedure done. I included some debug logs in the sample code.
Output:

Conditionally edit cells based of the value in cells in other rows - Google Sheet using Google Script

I've got limited knowledge of google script and I'm trying to get better every day. I'm trying to conditionally set the value of 2 cells based on the value in cells contained in other rows. I've got a sample sheet (here) with appointments on it. You'll also see the output desired on the output sheet.
When two or more appointments are taken by the same person based on his email address I want to write Yes in column Duplicate for every duplicate appointments but the most recent (based on Column E, that is the date when the appointment was created) and that are greater than the current date (if the appointment is already in the past no need to do anything). I also want to set the value of the column L to "Not Coming" which is a cell containing a data validation that I already automated on my main spreadsheet.
Here is the script that I already designed based on other questions answered here on stackoverflow. I'm not really familiar with indexes and how to proceed with them. The script runs without errors but nothing happens.
var currentDate = new Date()
// Master
var sheetMaster = ss.getSheets()[0];
var allValues=sheetMaster.getRange(2,1,sheetMaster.getLastRow()-1,sheetMaster.getLastColumn()).getValues();
var emailValues=sheetMaster.getRange(2,3,sheetMaster.getLastRow()-1,3).getValues();
var dateCreatedAtValues=sheetMaster.getRange(2,5,sheetMaster.getLastRow()-1,5).getValues();
var duplicateColumn=sheetMaster.getRange(2,11,sheetMaster.getLastRow()-1,11);
var eM=[];//emails
var dA=[];//dates
var eR=[];//entire rows
var dC=[];//duplicateColumn Yes or empty
function analyzeDuplicateEntries() {
for(var i=0;i<emailValues.length;i++) {
var idx=eM.indexOf(emailValues[i][0]);
if(idx==-1) {
eM.push(emailValues[i][0]);
dA.push(dateCreatedAtValues[i][0]);
eR.push(allValues[i]);
}
else if(new Date(dateCreatedAtValues[i][0]).valueOf() > new Date(dA[idx]).valueOf() && new Date(dateCreatedAtValues[i][0]).valueOf()> currentDate) {
duplicateColumn[i][0].setValue("Yes");
}
}
} ```
You are retrieving the wrong column and set the values to a range cell incorrectly
var mailValues=sheetMaster.getRange(2,3,sheetMaster.getLastRow()-1,3).getValues(); will return columns 3 to 5 (see documentation, while your emails are in column B, that is column 2.
Pay attention that the first parameter in getRange(row, column, numRows, numColumns) is the number of the columns to retrieve, rather than the last column
Mind that to use setValue on a range that contains more than one cell, you need to retrieve first the respective cell with getCell()
Take thereby into consideration that the cell indexes start with 1 (opposed to array indexes that start with 0`).
A simple (not optimal) way to rewrite your code would be:
var ss = SpreadsheetApp.getActiveSpreadsheet();
var currentDate = new Date()
// Master
var sheetMaster = ss.getSheets()[0];
var allValues=sheetMaster.getRange(2,1,sheetMaster.getLastRow()-1,sheetMaster.getLastColumn()).getValues();
var emailValues=sheetMaster.getRange(2,2,sheetMaster.getLastRow()-1,1).getValues();
var dateCreatedAtValues=sheetMaster.getRange(2,5,sheetMaster.getLastRow()-1,1).getValues();
var duplicateColumn=sheetMaster.getRange(2,11,sheetMaster.getLastRow()-1,1);
var eM=[];//emails
var dA=[];//dates
var eR=[];//entire rows
var dC=[];//duplicateColumn Yes or empty
function analyzeDuplicateEntries() {
for(var i=0;i<emailValues.length;i++) {
var idx=eM.indexOf(emailValues[i][0]);
if(idx==-1) {
eM.push(emailValues[i][0]);
dA.push(dateCreatedAtValues[i][0]);
eR.push(allValues[i]);
}
else if(new Date(dateCreatedAtValues[i][0]).valueOf() > new Date(dA[idx]).valueOf() && new Date(dateCreatedAtValues[i][0]).valueOf()> currentDate) {
duplicateColumn.getCell(i+1, 1).setValue("Yes");
}
}
}

How to copy cell value to another sheet base on criteria (Apps Script)

I'm trying to write some Apps Script to pull only the email addresses which match from an array of companies into another sheet for processing. This should also remove the #company.com extension and leave me with just the username.
So on Sheet 1:
In Column E, we have the Company names under Header: "Company"
In Column D, we have the Email Addresses under Header: "Emails"
On Sheet 2:
In Column A, we need the Username result under Header: "Username"
Currently the below script which should have 2 results, comes back with:
this
Any help with this would be immensely appreciated as I'm losing my mind.
Thank you!
function pullUsernames() {
//Get Sheet1
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
//Set Values for Search
var valuesToWatch = ['Company1','Company2'];
var range = sheet.getRange(2,5,sheet.getLastRow()-1).getValues();
var emails = sheet.getRange(2,4,lr-1).getValues();
//For Loop to match values, etc.
for(var i=0; i < range.length; i++){
if(valuesToWatch.indexOf(range[i][0])){;
var targetSS = SpreadsheetApp.openById("1hpIIgkXMgrlOfYqfS4A3ro8BFQB02dAy5G40Y7vUI2c").getSheetByName("Sheet2");
var targetRange = targetSS.getRange(i+1,1,targetSS.getLastRow(),1);
var usernames = String(emails[i][0]).replace("#company.com", "")
targetRange.setValue(usernames[i][0]);
} //if
} //for
} //Function
There were a bunch of issues in your code and I decided to optimize them. Feel free to modify the code if needed.
Issues:
Both range and emails can be fetched together instead of separate
Brought targetSS outside the loop since it is only static based on your issue
I don't quite get your getRange, I assume you want to append the usernames on the last row? If so, then use appendRow instead.
Since I didn't use the array index now, I used includes instead to check if the data is in valuesToWatch.
Your email string manipulation is quite hard coded so I replaced it with a better solution, removing anything but the characters before #.
Code:
function pullUsernames() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("Sheet1");
// update your targetSS, made it under same ss for easier testing
var targetSS = ss.getSheetByName("Sheet2");
// set values for search
var valuesToWatch = ['Company1', 'Company2'];
// get email and company columns in one go
var data = sheet.getRange(2, 4, sheet.getLastRow() - 1, 2).getValues();
// each row of data contains email and company formatted as [email, company].
data.forEach(function ([email, company]){
if(valuesToWatch.includes(company))
// remove anything from # onwards from email and append at last row
targetSS.appendRow([email.substring(0, email.lastIndexOf("#"))]);
});
}
Sample Data:
Sample Output:

Converting Sheet data to a new Sheet

I'm trying to use Google Apps Script to communicate with Google Sheets to do the following:
We're trying to convert data from one Point of Sale system to a new one. In order to do this, I need to take certain columns of a sheet, manipulate them in various ways, and repopulate another sheet with the resulting data. I need to find products without a SKU number, and assign them a new one, starting at 10110 and incrementing from there.
function sku() {
// "From" Spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName("New POS Data");
// "To" Spreadsheet
// Spreadsheet key: the string at the end of the URL
var ssraw = SpreadsheetApp.openById("1BH-j4cOW9Ntg6FlPNXmNCUId_pm9BgyAh0cwrwB4z_A");
var sheetraw = ssraw.getSheetByName("Old POS Data");
var max = sheet.getLastRow();
// SKU / UPC
var range = sheetraw.getRange(2,18,max);
var data = range.getValues();
// Assign new sku if no old one
var skunum=[10110];
var newData = new Array();
for (var y = 0; y <= max; y++) {
if (data[y]==""){
newData.push(skunum);
skunum++;
var skunum=[skunum];
}
else {newData.push(data[y]);}
}
sheet.getRange(2,3,max).setValues(newData);
}
This gives me the error "Incorrect range height, was 1 but should be 30 (line 26, file "SKU")"
If I remove the brackets around newData in the last line, I get "Cannot convert Array to Object[][]. (line 27, file "")"
This has been driving me mental, if anyone can offer help, I would be very grateful.
Even if you get a one row or one column vector with getData() you will get an Object[][].
when you do:
if (data[y]==""){
newData.push(skunum);
skunum++;
var skunum=[skunum];
}
You check if [cellFromColumn] == "" which will evaluate to false as it's an array.
You then push the new/old sku number to a simple array which, for spreadsheets, is one row of columns.
Instead you want to push into the array a one element array containin the sku number like this:
newData.push(skunum);
...
newData.push([data[y]]);
This will create an array of rows, each row is an array with one element (one column)

Insert Comment - GoogleSpreadsheets

I'm looking to insert comments onto a certain cell once a script has run.
The script I am using is to insert a calendar entry - however I only want it to do this once. To do this, I will get the script to check if a comment/note is entered onto the cell. In theory, this should be easy but I'm having trouble making it select the right cell... Can anyone help? My code is below.
I'm after the comment to go in the cell that corresponds with var = date.
If anyone can give me pointers, I'd really appreciate!
Cheers,
Pete
function CalendarInputIVNShortlist() {`
`var sheet = SpreadsheetApp.getActiveSheet();
var startRow = 2; // First row of data to process
var numRows = 2; // Number of rows to process
var dataRange = sheet.getRange(startRow, 1, numRows, 26); //What data will be used
var data = dataRange.getValues();
var cal = CalendarApp.getDefaultCalendar(); //Gets the correct calendar
for (i in data) {
var row = data[i];
var title = row[1]; // Column with Title
var desc = row[15]; // Column with Next Steps
var date = row[5]; //Column with Date
var invite = row[2] //Column with PDC Chairs & IVN Owner
var sent = row[12] //Check Sent
sheet.getRange(data[i], 5).setNote(Sent)
cal.createAllDayEvent(title, new Date(date), {description:desc,guests:invite});
var Comment = dataRange(date).setNote("Inputted")
There's a problem here:
sheet.getRange(data[i], 5)
The first parameter you've used, data[i], is an array (that you've already equated to row a few lines earlier). The getRange() method variance you are looking for expects two Numbers as parameters. If your intent was to add a note to column 5 of the row currently being references in your loop, then you want:
sheet.getRange(i+startRow, 5).setNote(sent);
Another issue with that particular line is with Sent; I assume you wanted to reference the variable you has set equal to row[12], just above, which had a small letter 's' in its name.
Next, there's something wrong here:
var Comment = dataRange(date).setNote("Inputted")
What is dataRange()? Unless it's another function in your script, that returns a Range object relevant to the contents of row[5], I would guess you intended this:
sheet.getRange(i+startRow, 5).setNote("Inputted");
sheet.getRange() needs 2 integers as parameters : the row number and the column number.
In your code you are trying to assign an array (data[i]) as row nuber...this cannot work.
Since it counts from startRow and since array are 0 indexed I would suggest you try like that :
sheet.getRange(startRow+i, 5).setNote(Sent)