How to search and match if a sheet name from a cell value in another sheet in google apps script and copy cells - javascript

I have three sheets, in the JOBS sheet if the user email address matches a sheet name in the QUOTATIONS workbook then the price is taken from that sheet for the specified product in column P. If no sheet name is found then the price for that product is taking from the PRODUCTS sheet. The price also depends on the currency which is specified in the JOBS sheet.
A sample of the expected results can be viewed in the JOBS sheet in column Q at https://docs.google.com/spreadsheets/d/1up7cUvQqL-LcA7EeuM65B0zjcRT46LGwN2x3C_4j0bY/edit?usp=sharing
If the user has a quotation and the email matches a sheet name then the price comes from QUOTATIONS workbook at
https://docs.google.com/spreadsheets/d/10tb0zE_8i849T-hL6mU-Pw_4V-aMzNZJGNOFYG1F3qk/edit?usp=sharing
If the user has no quotation and there is no matching email address the price comes from the products sheet
https://docs.google.com/spreadsheets/d/1pt7YnN9fmoD4PE0o9oVPezK8Qz6ZmabyJbWXfdzFeMU/edit?usp=sharing
I have the following script which does match the price between the products sheet and the jobs sheet but unable to have it also check if a sheet name exists and it matches the email address in the jobs sheet and then gets the price from that sheet. Assistance is appreciated, thanks
function updateQuotationPrice() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var jobSheet = ss.getSheetByName('JOBS');
var productSheet = SpreadsheetApp.openById("1pt7YnN9fmoD4PE0o9oVPezK8Qz6ZmabyJbWXfdzFeMU").getSheetByName('PRODUCTS');
var quotationSheet = SpreadsheetApp.openById("10tb0zE_8i849T-hL6mU-Pw_4V-aMzNZJGNOFYG1F3qk");
var sheetNames = []
var sheets = quotationSheet.getSheets()//.forEach(function(sheet){sheets[sheet.getName()]=sheet;});
sheets.forEach(function (sheet) {
sheetNames.push(sheet.getName());
console.log(sheets)
});
var objEuro = productSheet.getRange("A2:D" + productSheet.getLastRow()).getValues().reduce((o, r) => (o[r[0]] = r[3], o), {});
var objSterling = productSheet.getRange("A2:D" + productSheet.getLastRow()).getValues().reduce((o, r) => (o[r[0]] = r[2], o), {});
var objQuotationEuro = sheets.getRange("A2:D" + sheets.getLastRow()).getValues().reduce((o, r) => (o[r[0]] = r[3], o), {});
var objQuotationSterling = sheets.getRange("A2:D" + sheets.getLastRow()).getValues().reduce((o, r) => (o[r[0]] = r[2], o), {});
var range = jobSheet.getRange("O2:AK" + jobSheet.getLastRow());
var euroValues = range.getValues().map(r => [objEuro[r[0]] || null]);
var sterlingValues = range.getValues().map(r => [objSterling[r[0]] || null]);
var quotationEuroValues = range.getValues().map(r => [objQuotationEuro[r[0]] || null]);
var quotationSterlingValues = range.getValues().map(r => [objQuotationSterling[r[0]] || null]);
var vs = jobSheet.getRange("O2:R"+ jobSheet.getLastRow()).getValues();
vs.forEach((r) => {
if(r[0] == "EURO" && r[1].match(/^A/i) && sheets != r[3] ){
range.offset(0, 2, euroValues.length, 1).setValues(euroValues)};
if(r[0] == "STERLING" && r[1].match(/^A/i) && sheets != r[3]){
range.offset(0, 2, sterlingValues.length, 1).setValues(sterlingValues)}
if(r[0] == "EURO" && r[1].match(/^A/i) && sheets == r[3] ){
range.offset(0, 2, quotationValues.length, 1).setValues(quotationEuroValues)}
if(r[0] == "STERLING" && r[1].match(/^A/i) && sheets == r[3] ){
range.offset(0, 2, quotationValues.length, 1).setValues(quotationSterlingValues)}
});
}

Suggestion
I have created another approach wherein I still used the forEach() function to process the data. However, I used the filter() and includes() function to help in the data matching process.
Script
You may use the following script as basis for your script.
function updateQuotationPrice() {
var ss1 = SpreadsheetApp.openById("User Update Sheet ID"); //User Update
var ss2 = SpreadsheetApp.openById("Quotation Sheet ID"); //Quotation
var ss3 = SpreadsheetApp.openById("Projects Sheet ID"); //Projects
//Extract data from User Update
var lr1 = ss1.getSheetByName("Jobs").getLastRow();
var data1 = ss1.getSheetByName("Jobs").getRange(2, 13, lr1 - 1, 4).getValues();
//Extract data from Quotation Spreadsheet
var sheetNames2 = [];
ss2.getSheets().forEach(x => sheetNames2.push(x.getName()));
//Process data 1
var output = [];
data1.forEach(x => {
if (sheetNames2.includes(x[0]) && ss2.getSheetByName(x[0]).getDataRange().getValues().filter(y => y.includes(x[3])).length > 0) { // added new condition here
if (x[2] == "EURO") {
output.push([ss2.getSheetByName(x[0]).getDataRange().getValues().filter(y => y.includes(x[3]))[0][3]]);
}
else if (x[2] == "STERLING") {
output.push([ss2.getSheetByName(x[0]).getDataRange().getValues().filter(y => y.includes(x[3]))[0][2]]);
}
}
else {
if (x[2] == "EURO") {
output.push([ss3.getSheetByName("Products").getDataRange().getValues().filter(y => y.includes(x[3]))[0][3]]);
}
else if (x[2] == "STERLING") {
output.push([ss3.getSheetByName("Products").getDataRange().getValues().filter(y => y.includes(x[3]))[0][2]]);
}
}
});
//Output
ss1.getSheetByName("Jobs").getRange(2, 17, lr1 - 1, 1).setValues(output);
}
Output
References
forEach()
filter()
includes()

Related

Method search on google sheet data from one column using google script?

I had tried to search data like below flow picture and script to search data from google sheet using google app script but the script using is not working properly but can someone tell me how to setup search function to find data like flow on image? thanx
[Flow searching data][1]
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [ {name: "Search", functionName: "searchRecord"} ];
ss.addMenu("Commands", menuEntries);
}
function searchRecord()
{
var ss = SpreadsheetApp.getActiveSpreadsheet()
var wsSearchingData = ss.getSheetByName("Searching Data")
var wsDatabase = ss.getSheetByName("Database")
var searchString = wsSearchingData.getRange("E4").getValue();
var column =1; //column Index
var columnValues = wsDatabase.getRange(2, column, wsDatabase.getLastRow()).getValues(); //1st is header row
var searchResult = columnValues.findIndex(searchString); //Row Index - 2
var searchValue = wsDatabase.getRange("B2:B2041").getValues()
var matchingDatabase = searchValue.map(searchColumn => {
var matchColumn = columnValues.find(r => r[0] == searchColumn[0])
return matchColumn = matchColumn ? [matchColumn[2]] : null
})
console.log(matchingDatabase)
if(searchResult != -1)
{
//searchResult + 2 is row index.
SpreadsheetApp.getActiveSpreadsheet().setActiveRange(sheet.getRange(searchResult + 1, 1))
}
Array.prototype.findIndex = function(search){
if(search == "") return false;
for (var i=0; i<this.length; i++)
if (this[i] == search) return i;
wsSearchingData.getRange("B11").setValue(search[0]);
wsSearchingData.getRange("C11").setValue(search[1]);
wsSearchingData.getRange("D11").setValue(search[2]);
wsSearchingData.getRange("E11").setValue(search[3]);
wsSearchingData.getRange("F11").setValue(search[4]);
return;
}
}
[1]: https://i.stack.imgur.com/HF9K8.png
var searchResult = columnValues.findIndex(searchString); //Row Index - 2
replace the above code with:
var searchResult = columnValues.filter(r=>r[1]==searchString)
You can then put searchResult directly as output in the sheet. Make sure that [1] in the above contains the column index of Name in the columnValues Array.

GAS Function not setting value as intended in sheet

This is the Google Sheet, it can be copied: https://docs.google.com/spreadsheets/d/1ffIRGiGkiy5WFzSAvWNOY_3cqNXgTAOtO6o8vxS-BFU/edit?usp=sharing
The Function 'AddNewMembers' does not function, even if "isAdded == "No" it will not setValue(recruit_id)
function AddNewMembers(event){
event = {range: SpreadsheetApp.getActiveRange()}
CheckHandleSteamIDNotation(event)
SpreadsheetApp.flush();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var recruitment_log = ss.getSheetByName('RL1');
var main_roster = ss.getSheetByName('Main Roster');
var isAdded = recruitment_log.getRange('R3').getValue();
if(isAdded == "No") {
var recruit_id = "'" + recruitment_log.getRange('J3').getValue();
main_roster.getRange('I100').setValue(recruit_id);
}
}
function CheckHandleSteamIDNotation(event)
{
let formSheet = SpreadsheetApp.getActiveSheet();
let header = formSheet.getRange(1,1,1,formSheet.getMaxColumns()).getValues();
let formRange = formSheet.getRange(formSheet.getLastRow(), 1, 1, formSheet.getMaxColumns());
let formValues = formRange.getValues();
for(let i = 0; i < header[0].length; i++)
{
if(header[0][i].includes("SteamID"))
{
formValues[0][i] = "'" + formValues[0][i];
}
}
formRange.setValues(formValues);
}
Since the provided script above contains var isAdded = recruitment_log.getRange('R3').getValue(); the value of R3 is currently set to "Yes" that is why the condition for the script below is not running.
if(isAdded == "No") {
var recruit_id = "'" + recruitment_log.getRange('J3').getValue();
main_roster.getRange('I100').setValue(recruit_id);
}
Try this modification:
function AddNewMembers(event) {
event = { range: SpreadsheetApp.getActiveRange() }
CheckHandleSteamIDNotation(event)
SpreadsheetApp.flush();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var recruitment_log = ss.getSheetByName('RL1');
var main_roster = ss.getSheetByName('Main Roster');
//Gets all the data values on recruitment_log
var isAdded = recruitment_log.getRange(3, 1, recruitment_log.getLastRow(), recruitment_log.getLastColumn()).getValues();
//Gets the last row starting I17
var lastrow = main_roster.getRange(17, 9, main_roster.getLastRow() , 1).getValues().filter((x => x > 1)).length
//Sets the value on the last blank row
isAdded.map(x => x[17].toString().toLocaleLowerCase() == "no" ? "'" + main_roster.getRange(17 + lastrow,9).setValue(x[9]) : x)
}
I made modifications on your isAdded variable to the following to get the entire range of data on RL1 sheet.
var isAdded = recruitment_log.getRange(3, 1, recruitment_log.getLastRow(), recruitment_log.getLastColumn()).getValues();
This part of script was only used to get the current length of data for the New Operatives. Using .filter() method to filter out empty array elements, since getValues() gets blank cells if there is formatting applied on the spreadsheet.
var lastrow = main_roster.getRange(17, 9, main_roster.getLastRow() , 1).getValues().filter((x => x > 1)).length
Using ES6 .map() method to create a new array for the data that hasn't been added to the main roster sheet file.
isAdded.map(x => x[17].toString().toLocaleLowerCase() == "no" ? "'" + main_roster.getRange(17 + lastrow,9).setValue(x[9]) : x)
Screenshot:
Reference:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter#description

How to compare a value with each item of range

for the last 3 days (my first 3 days of coding) i've been trying to code an script to get my google contacts that have certain keyword, it being "Catamarca", on their name and also to delete that keyword after they've been added to the spreadsheet leaving only their name.
I've been succesfull in all of this. But now i want to only run the script on an existing database, and only run it if the new contacts are not on the sheet already, and not write over the existing ones.
Here is my code so far:
function impContacts() {
// variables
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("GContacts");
var grupo = ContactsApp.getContactGroupById("http://www.google.com/m8/feeds/groups/email#gmail.com/base/6")
const contactos = grupo.getContacts();
const arraycontacts = [];
// get the last row on B with data on it
const lastRow = sheet.getLastRow();
const Avals = sheet.getRange("B2:B" + lastRow).getValues();
const Alast = lastRow - Avals.reverse().findIndex(c => c[0] != '');
Logger.log(Alast);
var rangeInteres = sheet.getRange(2, 1, Alast, sheet.getLastColumn()).getValues();
// look for contacts that has in their name the word "Catamarca", and save them with their id, name and phone.
contactos.forEach(contacto => {
var phone = ""
if (contacto.getPhones()[0]) {
phone = contacto.getPhones()[0].getPhoneNumber()
};
var name = ""
if (contacto.getFullName().match("Catamarca")){
name = contacto.getFullName();
};
var idcont = ""
if (name == rangeInteres.forEach(namme =>
{
oldName = namme[1];
Logger.log(oldName);}))
{
idcont =
rangeInteres.forEach(id => {
oldId= id[0];
Logger.log(oldId);})
}
else
{
idcont = contacto.getId().replace(/\D/g, '')
};
const datoscont = [idcont, name, phone];
arraycontacts.push(datoscont);
})
// save new contact
sheet.getRange(2, 1, arraycontacts.length, 3).setValues(arraycontacts);
// look for "catamarca"
range = sheet.getRange("B2:B")
var textFind = range.createTextFinder("Catamarca");
textFind.matchEntireCell(false);
textFind.ignoreDiacritics(true);
textFind.matchCase(false);
var textFound = textFind.findNext();
// Si encuentra coincidencia reemplazar por ""
if (textFound !== null) {
var vals = textFound.getValues();
textFind.replaceAllWith("");
}
}
What i need to keep the most is the ID of the existing contacts (the IDs are different from the ones coming from google contacts but the names are the same), because they are linked to an app created using AppSheet.
I believe there should be a way to accomplish this by editing this part of the code
var idcont = ""
if (name == rangeInteres.forEach(namme =>
{
oldName = namme[1];
Logger.log(oldName);}))
{
idcont =
rangeInteres.forEach(id => {
oldId= id[0];
Logger.log(oldId);})
}
else
{
idcont = contacto.getId().replace(/\D/g, '')
};
In my head and with my current knowledge, the code should be working, but it's not, I mean, it runs, but overwrites everything.

BUTTON to move data from multiple google sheets into one master

My boss told to move same set of data from 40 multiple google sheets into one master sheets which are filled by 40 people separately currently am working on it with an ADD on function
is there any way to put a submit button on each sheets so that when user fill the data and click on submit button the data go direct to the master sheets ?
I have the script which is working fine with sheets but the only cons of that is the script only combine the tabs into same spreadsheet
here is code :
const masterSheet = "ASM-A30";
const masterSheetFormulaCell = "A2";
const ignoreSheets = ["Verified NDRx","Business Tracker","NDRX","PMT_EBx","PMT_EBx.","NDRx PMT Business Tracker.","Analysis"];
const dataRange = "A2:AA";
const checkRange = "A2:A" ;
//end set variables
const ss = SpreadsheetApp.getActiveSpreadsheet() ;
ignoreSheets.push(masterSheet) ;
const allsheets = ss.getSheets() ;
const filteredListofSheets = allsheets.filter(s => ignoreSheets.indexOf(s.getSheetName()) == -1);
let formulaArray = filteredListofSheets.map(s => `FILTER({'${s.getSheetName()}'!${dataRange},"${s.getSheetName()} - Row "&ROW('${s.getSheetName()}'!${dataRange})}, '${s.getSheetName()}'!${checkRange}<>"")`);
let formulaText = "={" + formulaArray.join(";")+ "}"
//console.1og( formulaText) ;
ss. getSheetByName(masterSheet).getRange(masterSheetFormulaCell) .setFormula(formulaText) ;
}
Try this
const ignoreSheets = ["Verified NDRx","Business Tracker","NDRX","PMT_EBx","PMT_EBx.","NDRx PMT Business Tracker.","Analysis"];
const masterSheet = "ASM-A30";
function compile() {
let result = []
SpreadsheetApp.getActiveSpreadsheet().getSheets().filter(s => ignoreSheets.indexOf(s.getSheetName()) == -1).forEach((s,i) => {
let [headers, ...data] = s.getDataRange().getValues()
if (i == 0) { result.push(headers.flat()) }
data.forEach(r => result.push(r))
})
if(result.length) {
var master = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(masterSheet)
master.clearContents()
master.getRange(1, 1, result.length, result[0].length).setValues(result)
SpreadsheetApp.getActiveSpreadsheet().toast('Updated!');
}
}
to add rows, change
if (i == 0) { }
and try
var master = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(masterSheet)
// master.clearContents()
master.getRange(+master.getLastRow()+1, 1, result.length, result[0].length).setValues(result)
SpreadsheetApp.getActiveSpreadsheet().toast('Updated!');

Google sheet script to match and copy based from another adjacent cell

I am trying to look for matching cells in column R,T,and V in the reference table with column C in the main sheet. If there is a match then copy the assigned number in Q,S, and U and past it in column B next to the its match.
I have done the example manually.
Suggestion
Perhaps you can try this sample script:
Script [UPDATED]
function findMatch() {
var sh = SpreadsheetApp.getActiveSpreadsheet();
var lastRow = sh.getDataRange().getLastRow();
var reference = [];
var row = 1;
var data = sh.getRange("Q1:V"+lastRow).getDisplayValues().filter(function(x) {
return (x.join('').length !== 0);
});
sh.getRange("C1:C"+lastRow).getDisplayValues().forEach( x => {
reference.push([fixForUsage(x),row]);
row += 1;
});
reference.forEach(aisle => {
if(aisle[0] == "" || aisle[0].toString().toLowerCase().includes("aisle"))return;
data.forEach(match => {
var currentData = match[1] +"-"+match[3]+"-"+match[5];
if(currentData.includes(aisle[0])){
//get its number
if(match[1] == ""){
if(match[3] == ""){
if(match[5] == ""){
}else{
//if not empty
Logger.log("Find \""+aisle[0]+"\" from sheet row#"+aisle[1]+"\nRESULT:"+"\nFound a match on these data!: "+match+"\nHeader: \'"+data[0][4]+"\'\nNumber: "+match[4]);
pasteData(sh,aisle[1], data[0][4], match[4]);
}
}else{
//if not empty
Logger.log(+"Find \""+aisle[0]+"\" from sheet row#"+aisle[1]+"\nRESULT:"+"\nFound a match on these data!: "+match+"\nHeader: \'"+data[0][2]+"\'\nNumber: "+match[2]);
pasteData(sh,aisle[1],data[0][2],match[2]);
}
}else{
//if not empty
Logger.log("Find \""+aisle[0]+"\" from sheet row#"+aisle[1]+"\nRESULT:"+"\nFound a match on these data!: "+match+"\nHeader: \'"+data[0][0]+"\'\nNumber: "+match[0]);
pasteData(sh,aisle[1],data[0][0],match[0]);
}
}
});
});
}
function pasteData(sh,row, colAData, colBData){
sh.getRange("B"+row).setValue(colBData);
sh.getRange("A"+row).setValue(colAData);
}
function fixForUsage(x){ //This is to let the code know that e.q. 53-7 is 53-07
var part = x.toString().split("-");
if(part.length == 2 && part[1].length == 1){
return part[0]+"-0"+part[1];
}else{
return x;
}
}
Sample Sheet
Columns A, B, C:
Columns Q, R, S, T, U, V:
Sample Demonstration
After running the script from the Apps Script editor:
Apps Script editor log results for review:
Here is another solution (updated):
function myFunction() {
var sh = SpreadsheetApp.getActiveSheet();
// get all data
var data = sh.getRange('q2:v16').getDisplayValues();
var cols_QR = data.map(x => ({'crane': 'C5-1', 'seq': x[0], 'aisle': x[1]}));
var cols_ST = data.map(x => ({'crane': 'C5-4', 'seq': x[2], 'aisle': x[3]}));
var cols_UV = data.map(x => ({'crane': 'C5-2', 'seq': x[4], 'aisle': x[5]}));
data = [...cols_QR, ...cols_ST, ...cols_UV];
data = data.filter(x => x.aisle != '');
data.forEach((x,i) => data[i].aisle = fix(x.aisle)); // <--- new line
// create the object 'aisles'
var aisles = {}
for (let obj of data) aisles[obj.aisle] = {'crane': obj.crane, 'seq': obj.seq}
// get target range and target data
var target_range = sh.getRange('a2:c' + sh.getLastRow());
var target_data = target_range.getDisplayValues();
// fill target range with info from the 'aisles' object
for (let row in target_data) {
try {
let orig_key = target_data[row][2]; // <--- updated line
let key = fix(orig_key); // <--- new line
target_data[row] = [ aisles[key].crane, aisles[key].seq, orig_key ]; // <--- updated line
} catch(e) {}
}
// fill the target range with updated data
target_range.setValues(target_data);
}
// function to convert '10-1 1/4' --> '10-01', '8-0' --> '08-00', etc
function fix(key) {
return key.split(' ')[0]
.split('-').map(x => x.length == 1 ? '0' + x : x)
.join('-').slice(0,5);
}
Initial data:
Results:
Sheet
I decided don't add in my variant the function that makes true this: '53-7' == '53-07' and '11' == '11-0', etc, because I think it's a rather bad and error-prone idea. It will silently hide many errors in your data. But I can add it if you want.
Update
The function can be something like this:
function fix(key) {
return key.split(' ')[0]
.split('-').map(x => x.length == 1 ? '0' + x : x)
.join('-').slice(0,5);
}
// test
const keys = ['10-1 1/4', '11-0', '9-11 1/2', '8-0', '53-06', '52-7', '53-07', '104', '8-02-S', '08-01'];
keys.forEach(key => console.log(fix(key) + ' <--- ' + key));
I've added the function fix() and several lines to my original code.
But actually functions like this can cause additional troubles. For example I have no idea what means '104'? If it should be '10-04'? Or may be '01-04'? Or something else? You need be well prepared if you decide to play the risky game.
Note: you can change orig_key to key in this line:
target_data[row] = [ aisles[key].crane, aisles[key].seq, orig_key ];
This way you will get the 'fixed' values in the target table instead of original ones.

Categories