From, a google spreadshhet, I'm trying to collect records from Zoho.
I've tested this code:
var urlgetRecords = 'https://crm.zoho.com/crm/private/json/Leads/getRecords?newFormat=1&authtoken=00000&scope=crmapi&selectColumns=Leads(First Name,Last Name,Email)&fromIndex=1&toIndex=2&sortColumnString=First Name&sortOrderString=desc';
var jsonResponse = UrlFetchApp.fetch(urlgetgetRecords);
This is what obtain:
{"response":{"result":{"Leads":{"row":[{"no":"1","FL":[{"content":"1412559000000441145","val":"LEADID"},{"content":"Víctor","val":"First
Name"},{"content":"Aguilera Moreno","val":"Last
Name"},{"content":"v-aguilera#hotmail.com","val":"Email"}]},{"no":"2","FL":[{"content":"1412559000000308001","val":"LEADID"},{"content":"Victor","val":"First
Name"},{"content":"Porta","val":"Last
Name"},{"content":"vporta#test.es","val":"Email"}]}]}},"uri":"/crm/private/json/Leads/getRecords"}}
Please, How can write every row in this response in a spreadsheet?
Thank you very much in advance :)
The Sandy Good's code is perfect.
I've had to add two more lines.
Finally the code that works is:
var urlgetRecords = 'https://crm.zoho.com/crm/private/json/Leads/getRecords?newFormat=1&authtoken=' + authToken + '&scope=crmapi&selectColumns=Leads(First Name,Last Name,Email)&fromIndex=1&toIndex=2&sortColumnString=First Name&sortOrderString=desc';
var jsonResponse = UrlFetchApp.fetch(urlgetRecords);
var jsonText = jsonResponse.getContentText();
var objetoFinal = JSON.parse(jsonText);
writeZohoToSheet(objetoFinal);
Thank you very much for your help #SandyGood
Write ZOHO data to Google spreadsheet. To use the code below, edit the sheet tab name in the getSheetByName('Sheet2') method to the sheet tab where you want the data to be appended to.
I've tested this code and it works:
function writeZohoToSheet(zohoDataObject) {
var zohoDataObject = {"response":
{"result":
{"Leads":
{"row":
[{"no":"1","FL":[
{"content":"12345678IDNumber","val":"LEADID"},
{"content":"Víctor","val":"First Name"},
{"content":"Aguilera Moreno","val":"Last Name"},
{"content":"v-agEmailTest#hotmail.com","val":"Email"}]
},
{"no":"2","FL":[
{"content":"987654321IDNumber","val":"LEADID"},
{"content":"Victor","val":"First Name"},
{"content":"Porta","val":"Last Name"},
{"content":"someEmail#test.es","val":"Email"}]
}
]
}
},"uri":"/crm/private/json/Leads/getRecords"}};
var rows = zohoDataObject.response.result.Leads.row;
Logger.log('rows: ' + rows);
Logger.log('rows.length: ' + rows.length);
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName('Sheet2');
var array = [], thisRow, thisContent, innerObj;
for (var r in rows) {
array = []; //reset
thisRow = rows[r];
thisContent = thisRow.FL;
array.push(r);
for (var i=0;i<thisContent.length;i+=1) {
innerObj = thisContent[i];
array.push(innerObj.val);
array.push(innerObj.content);
};
sh.appendRow(array);
};
};
You would call the function with:
writeZohoToSheet(jsonResponse);
Remove the "hard coded" object literal, or comment it out in order to pass in the retrieved object.
Related
I am using a script to automate form generation.
It basically loops over a list of elements, since each of them should have a different forms link.
How can I store the links generated corresponding to each group in a google spreadsheet?
I would like to have a spreadsheet in this way:
Group Link
138 https://docs.google.com/forms/idForm138
139 https://docs.google.com/forms/idForm139
Here's my code:
var lista_url=[]
var group=[137, 138, 139]
function createForm(group) {
// create & name Form
var item = "Speaker Information Form";
var form = FormApp.create(item)
.setTitle(item);
// single line text field
item = group;
form.addTextItem()
.setTitle(item)
.setRequired(true);
// multi-line "text area"
item = "Short biography (4-6 sentences)";
form.addParagraphTextItem()
.setTitle(item)
.setRequired(true);
// radiobuttons
item = "Handout format";
var choices = ["1-Pager", "Stapled", "Soft copy (PDF)", "none"];
form.addMultipleChoiceItem()
.setTitle(item)
.setChoiceValues(choices)
.setRequired(true);
// (multiple choice) checkboxes
item = "Microphone preference (if any)";
choices = ["wireless/lapel", "handheld", "podium/stand"];
form.addCheckboxItem()
.setTitle(item)
.setChoiceValues(choices);
var url_form= Logger.log('Published URL: ' + form.getPublishedUrl());
Logger.log('Group: '+group)
lista_url.push(url_form)
}
function generate_Form_links(group){
group.forEach(function(item, index){
console.log(item, index)
createForm(item)
}
}
generate_Form_links(group)
EDIT:
Implementing this raises this error: TypeError: infoArray.join is not a function
function excelformat(lista_url) {
var result_table = lista_url
var lineArray = [];
result_table.forEach(function(infoArray, index) {
var line = infoArray.join(" \t");
lineArray.push(index == 0 ? line : line);
});
var csvContent = lineArray.join("\r\n");
var excel_file = document.createElement('a');
excel_file.setAttribute('href', 'data:application/vnd.ms-excel;charset=utf-8,' + encodeURIComponent(csvContent));
excel_file.setAttribute('download', 'Visitor_History.xls');
document.body.appendChild(excel_file);
excel_file.click();
document.body.removeChild(excel_file);
}
excelformat(lista_url)
Not sure if I understand your task correctly. So, if you have the two arrays: group and links you can add their content in spreadsheet this way:
var group = [138, 139];
var links = ['https://docs.google.com/forms/idForm138','https://docs.google.com/forms/idForm139'];
function save_arrays_to_spreadsheet(group, links) {
var ss = SpreadsheetApp.openById(ss_id); // <-- put the spreadsheet ID here
var sheet = ss.getSheets()[0]; // let it be a first sheet
for (var i in group) sheet.appendRow([group[i], links[i]]); // add a row
}
And I don't understand what this function in your code is doing:
function generate_Form_links(group){
for (var group=0; group<=group.length ; group=i++){
createForm(group) //call our function for each value in list
}
}
It gets group (an array?) and converts it into zero var group = 0, and then there appears the variable i, etc. It all looks like an error to me.
Probably, I don't know, there should be:
function generate_Form_links(group) {
for (var i=0; i<=group.length; i++) { createForm(group[i]) }
}
Ok...not sure how to do this. Right now I 4 sheets and 4 scripts for each sheet producing 4 json feeds. What I am trying to experiment with is having one script that will produce 1 json that I can use in a web page and just call the type of class. They are all formatted the same with columns etc.
Here is the Google Script App code I have.
function doGet(e){
// Change Spread Sheet url
var ss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/SpreadsheetID/edit#gid=0");
// Sheet Name, Change Sheet to whatever name you used to name your sheet
var sheet = ss.getSheetByName("Class Sheet 1");
return getClasses(sheet);
}
function getClasses(sheet){
var dataObj = {};
var dataArray = [];
// collecting data starting from 2nd Row , 1st column to last row and last column
var rows = sheet.getRange(2,1,sheet.getLastRow()-1, sheet.getLastColumn()).sort([{column: 1, ascending: true}, 1]).getValues();
for(var i = 0, l= rows.length; i<l ; i++){
var dataRow = rows[i];
var record = {};
record['Name'] = dataRow[0];
record['Note'] = dataRow[1];
record['Address'] = dataRow[2];
record['StreetAddress'] = dataRow[3];
record['City'] = dataRow[4];
record['State'] = dataRow[5];
record['ZipCode'] = dataRow[6];
record['ContactName'] = dataRow[7];
record['EMailAddress'] = dataRow[8];
record['CustomerServicePhone'] = dataRow[9];
dataArray.push(record);
}
dataObj = dataArray;
var result = JSON.stringify(dataObj);
return ContentService.createTextOutput(result).setMimeType(ContentService.MimeType.JSON);
}
Scratching my head on this a little bit....I'm sure its something simple and I am probably over thinking things, but any help would be appreciated.
Possible Solution:
The e object in your doGet(e) provides a way to send parameters to your script. You can access different sheets with different url parameters. You can then easily get the requested SheetName through e.parameter. Use
https://script.google.com/.../exec?sheet=ClassSheet1 //for ClassSheet1
https://script.google.com/.../exec?sheet=ClassSheet2 //for ClassSheet2
Code.gs:
function doGet(e){
var ss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/SpreadsheetID/edit#gid=0");
var sheetName = e.parameter.sheet;
var sheet = ss.getSheetByName(sheetName);
return getClasses(sheet);
}
You can also provide UI in your web-app to select a sheet.
Hello stackoverflow community,
I want to create a script to search a google sheet by name, as this file will be deleted at the end of the script. A new file will be uploaded to google drive automatically every week. This will be the basis for the script that will be running weekly.
The code runs fine, but returns undefined in the 4 output cells.
Example Data from a row in the Spreadsheet "LocafoxInventoryData_Automatic":
1||5b8ff4fc3e578c005487dcd5|60.0000|38.6300|19.0000|||2.0000
I would like to retrieve the last number in the above string. (after the last " | " )
I hope someone can help me out. The strings being searched for are the ids of the products: In the above sample "5b8ff4fc3e578c005487dcd5". This id can only be found twice in the sheet. I want to always retrieve the first one. The differnce between the first and the second product IDs are the first number in the string. There are "1" and "2".
function getData() {
var files = DriveApp.getFilesByName('LocafoxInventoryData_Automatic');
while (files.hasNext()) {
var file = files.next();
var id = file.getId()
}
var sheetData = SpreadsheetApp.openById(id).getActiveSheet().getDataRange().getValues();
var sspre = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Vorlage");
var searchString1 = sspre.getRange('I7').getValue();
var searchString2 = sspre.getRange('I8').getValue();
var searchString3 = sspre.getRange('I9').getValue();
var searchString4 = sspre.getRange('I10').getValue();
for(var i=0;i<sheetData;i++)
{
//Column 1 should be searched
if(sheetData[i][0].search(searchString1)!=-1)
{
var rowData1 = sheetData[i];
return rowData1;
}
else if(sheetData[i][0].search(searchString2)!=-1)
{
var rowData2 = sheetData[i];
return rowData2;
}
else if(sheetData[i][0].search(searchString3)!=-1)
{
var rowData3 = sheetData[i];
return rowData3;
}
else if(sheetData[i][0].search(searchString4)!=-1)
{
var rowData4 = sheetData[i];
return rowData4;
}
}
sspre.getRange('D7').setValue(rowData1);
sspre.getRange('D8').setValue(rowData2);
sspre.getRange('D9').setValue(rowData3);
sspre.getRange('D10').setValue(rowData4);
file.setTrashed(true);
}
Returning Partial Row Data with Regex
Okay this is working for me. I have a file named 'LocafoxInventoryData_Automatic' which is a spreadsheet with one sheet. I look for files with that name and if more than one is found I throw error so that you can figure out which one you want.
I then open up the file as a SpreadSheet with openById. I get the product id from the Vorlage sheet column I7,8,9,10 and I wrap them with a regular expression that looks like this ^1\|\|cw8vtfxa5owglp03btv22g9d.\|\|\|(.)$ . Although in the code the backslashes \ have to be \\ double backslashed which took me a while to figure out.
So that get's the numbers at the end and I put them into Vorlage column D7,8,9,10. And then I set the file isTrashed to true. I don't know if you want to return the data so I left the object in there but commented them out. I also removed all of the else ifs.
function getData() {
var filename='LocafoxInventoryData_Automatic';
var files = DriveApp.getFilesByName(filename);
var n=0;
while (files.hasNext()) {
var file = files.next();
var id = file.getId();
n++;
}
if(n>1){throw(Utilities.formatString('Error: More than file named %s', filename));}//Will present an error if there is more than one file
if(id){
var sheetData = SpreadsheetApp.openById(id).getActiveSheet().getDataRange().getValues();//I assumed no headers in this file
var sspre = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Vorlage");
var re1 = new RegExp('^1\\|\\|' + sspre.getRange('I7').getValue() + '.*\\|\\|\\|(.*)$','i');
var re2 = new RegExp('^1\\|\\|' + sspre.getRange('I8').getValue() + '.*\\|\\|\\|(.*)$','i');
var re3 = new RegExp('^1\\|\\|' + sspre.getRange('I9').getValue() + '.*\\|\\|\\|(.*)$','i');
var re4 = new RegExp('^1\\|\\|' + sspre.getRange('I10').getValue() + '.*\\|\\|\\|(.*$)','i');
for(var i=0;i<sheetData.length;i++){
var rD1=re1.exec(sheetData[i][0]);
if(rD1) {
var rowData1 = rD1[1];
}
var rD2=re2.exec(sheetData[i][0]);
if(rD2) {
var rowData2 = rD2[1];
}
var rD3=re3.exec(sheetData[i][0]);
if(rD3) {
var rowData3 = rD3[1];
}
var rD4=re4.exec(sheetData[i][0]);
if(rD4) {
var rowData4 = rD4[1];
}
}
//var rObj={rowData1:rowData1,rowData2:rowData2,rowData3:rowData3,rowData4:rowData4};
sspre.getRange('D7').setValue(rowData1);
sspre.getRange('D8').setValue(rowData2);
sspre.getRange('D9').setValue(rowData3);
sspre.getRange('D10').setValue(rowData4);
file.setTrashed(true);
//return rObj;
}
}
Regular Expression exec method
RegExp
By the way it's quite helpful with sort of a problem to have your own regex tester written in the same language you happen to be developing in. I'm sorry it took me so long. If you run into additional problems let me know.
My objective/flow is as follows:
1) User enters name (Lead) on "output" sheet.
2) Formula takes lead name and checks against "Cleaned data" sheet to find all instances of name(Lead) in column 5 and returns all strings in the corresponding rows in column 2
3) These strings are matched to another sheet "Raw Data" and finally, any matches found in "Raw Data" are returned to row 1 on "output"
function producthierarchy(){
var leadSheet = SpreadsheetApp.openById("xxx").getSheetByName("[Output] Lead");
var alloSheet = SpreadsheetApp.openById("xxx").getSheetByName("[Cleaned Data] Teams w. Allocations");
var hierSheet = SpreadsheetApp.openById("xxx").getSheetByName("[Raw Data] Product Hierarchy");
var leadRange = leadSheet.getRange("D1");
var lead = leadRange.getValue(); //This should return the Lead's name entered in cell B1
Logger.log(lead)
var dataRange = alloSheet.getRange("A2:E")
var data = dataRange.getValues()
Logger.log(data);
for (i in data) {
var column = data[i]
var userName = column[0];
var productName = column[1];
var alloAdjusted = column[2];
var alloUnadjusted= column[3];
var managers = column[5];
if (managers.indexOf(managers)){
Logger.log("works");
}
}
}
Is it not possible to pass .indexOf a variable? That is my main blocker at the moment. I can find what the user has entered as "Lead" and My columns are right. However, I can't seem to find a way to find this entered data in my "Cleaned data" sheet
This is why I don't post here - I found that my code had an error (check the small things kids) and was referencing the wrong column. However, for any other people struggling, here is the code I used to match the strings:
for (i in data) {
var column = data[i]
var userName = column[0];
var productName = column[1];
var alloAdjusted = column[2];
var alloUnadjusted= column[3];
var managers = column[4];
var managersTest = new RegExp(Utilities.formatString('\|%s\|', lead))
if (managers.match(managersTest)){
//productName.getValue()
Logger.log("works");
}
}
}
I have a file that looks like so:
QUERY:1
DATABASE:geoquery
NL:What are the capitals of the states that border the most populated states?
SQL:something
QUERY:2
DATABASE:geoquery
NL:What are the capitals of the states bordering New York?
SQL:SELECT state.Capital FROM state JOIN borderinfo ON state.State_Name = borderinfo.State_Name
WHERE borderinfo.Border = 'New York'
QUERY:3
DATABASE:geoquery
NL:Show the state capitals and populations.
SQL:SELECT state.Capital, state.Population FROM state
etc...
The person generating this file refuses to give it to me in a usable format like say, XML or JSON. So I am parsing it a couple of times with REGEX to get results I want.
Strip off Databases to populate select list (works fine):
$.get('inputQueryExamples.txt',
function(data){
var string = data;
var dbDynamo ='';
dbExp = new RegExp('(DATABASE:.*)','gm');
dbDynamo = string.match(dbExp);
cleanBreaks = new RegExp('(\r?\n|\r)','gm');
stringNow = dbDynamo.toString();
//console.log(dbDynamo);
dbDynamo = dbDynamo.map(function(el){return el.replace('DATABASE:','');});
var outArray = [];
for(i=0; i < dbDynamo.length; i++){
if ($.inArray(dbDynamo[i],outArray)== -1){
outArray.push(dbDynamo[i]);
}
}
dbDynamo = outArray.sort();
var options = '';
for(i=0; i<dbDynamo.length; i++){
options += '<option value="' + dbDynamo[i] + '">' + dbDynamo[i] + '</option>';
};
$(select).append(options);
});
The problem comes when I parse a second time to get all of the strings associated with a specific database. I end up with a linebreak in front of every string so that when I fill a textarea with the autocomplete text it starts on the second line:
Array [ "
NL:Show company with complaint against Debt collection product.,DATABASE:consumer", "
NL:Show issues and dates of complaints about HSBC companies.,DATABASE:consumer", "
NL:Show companies, issues and dates with consumer concerns.,DATABASE:consumer", "
NL:Show issues and companies with complaints in MA state." ]
$(document).ready(function(){
$.get('inputQueryExamples.txt',function(data){
var queryString = data;
var cleanString = "";
var db = '';
$('#database-list').change(function(){
db = $('#database-list').val();
// /(^DATABASE:.*\r\n)(^NL.*)/gm
// http://regex101.com/r/mN4hS2
regex = new RegExp('(^DATABASE:'+ db +'\r\n)(^NL.*)' ,'gm');
cleanString = queryString.match(regex);
//console.log(cleanString);
//cleanBreaks = new RegExp('(\r\n|\r|\n)(^NL.*)','gm');
//stringNow = cleanString.toString();
//var dirtyString
//dirtyString = stringNow.match(cleanBreaks);
//console.log(dirtyString);
var nlString = cleanString.map(function(el) {return el.replace('DATABASE:' + db,'');});
nlString = nlString.map(function(el){return el.replace('NL:',''); });
//nlString = nlString.map(function(el){return el.replace('\\r','').replace('\\n','');});
console.log(nlString.pop());
$('#query-list').autocomplete({
source:nlString,
});
}); // end change
I have tried about everything I can think of to get rid of the linebreaks without success. Any ideas would be appreciated. Unfortunately the one where the server side just gives me data in a usable format is not viable. There is a lot of extra code in this just to give you an idea of what I have tried. I have commented out useless things. Thanks in advance.
It would make sense to use JavaScript to parse the data-structure you are given into a JavaScript object first, then you can more easily work with the data.
Here is a jsfiddle that demonstrates parsing your data into a JavaScript object. Below is the relevant code that does the parsing:
var datasources = {};
var parseData = function(block) {
var db = block.match(/DATABASE:(.*)/)[1];
var dbdata = {id: 0, nl: "", sql: ""};
if (!datasources[db]) {
datasources[db] = [];
}
dbdata.id = block.match(/QUERY:(.*)/)[1];
dbdata.nl = block.match(/NL:(.*)/)[1];
dbdata.sql = block.match(/SQL:(.*)/)[1];
datasources[db].push(dbdata);
};
var parseBlocks = function(data) {
var result = data.split('\n\n');
for(var i=0; i < result.length; i++) {
parseData(result[i]);
};
};
Thanks for the very thoughtful and elegant approach. I continued the brute force approach.
replace:
nlString = nlString.map(function(el){return el.replace('NL:',''); });
with:
nlString = nlString.map(function(el){return el.replace('NL:','').trim(); });