Get specific data from Salesbinder API JSON to a Google sheet - json

Hi what I'm trying to do is get the data from a Salesbinder invoice API (Invoice # is taken from Sheet2 Cell A1) output the data to a Google sheet (sheet Cell A2)
here's the code i'm using to get data from Salesbinder API
function fetching() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1');
var sheet2 = ss.getSheetByName('Sheet2');
var InvNumber = sheet2.getRange('A1').getValue();
var USERNAME = 'APIKey';
var PASSWORD = 'x';
var url = 'https://mydomain.salesbinder.com/api/2.0/documents.json?documentNumber='+InvNumber+'&contextId=5';
var headers = {
"Authorization": "Basic " + Utilities.base64Encode(USERNAME + ':' + PASSWORD)
};
let response = UrlFetchApp.fetch(url, { headers });
Logger.log(response.getContentText());
}
The result I get from the data is like this
{"document":[{"document_number":8542,"name":"VIOLET BEARINGS","context_id":5,"total_cost":7213.03,"total_tax":415.45,"total_tax2":0,"total_price":8309.08,"total_transactions":0,"issue_date":"2022-12-13T00:00:00+00:00","expiry_date":null,"shipping_address":"(Same as above)","date_sent":null,"shipped_percent":null,"status_id":9,"public_note":"","attention":"GLEN","payment_terms":"","id":"0b24e8d2-e7cc-4441-abd7-337c8a2c6cf1","customer_id":"5b0d881b-6a88-46e5-998c-06330a8e0006","user_id":"5b0d75b3-e9cc-4899-bf99-77610a8e0006","associated_document_id":"","created":"2022-12-13T21:21:43+00:00","modified":"2022-12-21T16:01:04+00:00","status":{"id":9,"name":"unpaid"},"context":{"id":5,"name":"invoice"},"customer":{"id":"5b0d881b-6a88-46e5-998c-06330a8e0006","name":"TestClient","customer_number":1889,"billing_address_1":"Add1","billing_address_2":"Add2","billing_city":"TestCity","billing_region":"TestLoc","billing_postal_code":"TestPost","billing_country":"CANADA","shipping_address_1":"Add1","shipping_address_2":"Add2","shipping_city":"TestCity","shipping_region":"TestLoc","shipping_postal_code":"TestPost","shipping_country":"CANADA"},"user":{"first_name":"test","last_name":"test"},"document_items":[{"id":"0ea11906-f197-4eb4-971e-715d4dc77ab2","name":"B-0832","document_id":"0b24e8d2-e7cc-4441-abd7-337c8a2c6cf1","item_id":null,"unit_id":4,"service_category_id":"5dc2f6d2-27e0-4dac-a2b7-39080a8e0008","description":"JGE/H/K DOOR GASKET","quantity":8,"quantity_partially_received":0,"quantity_partially_shipped":0,"tax":5,"tax2":0,"discount_percent":0,"cost":38.1,"price":43.81,"discounted_price":0,"weight":2,"modified":"2022-12-21T16:01:04+00:00","created":"2022-12-15T15:43:57+00:00","item_variations_location_id":null,"item_variation_data":null,"delete":false,"item":null},{"id":"2b7e9376-ed70-4e75-95c9-6237aad8cfc0","name":"B-0770","document_id":"0b24e8d2-e7cc-4441-abd7-337c8a2c6cf1","item_id":null,"unit_id":4,"service_category_id":"5dc2f6d2-27e0-4dac-a2b7-39080a8e0008","description":"MAIN BEARING JGE/H/K","quantity":8,"quantity_partially_received":0,"quantity_partially_shipped":0,"tax":5,"tax2":0,"discount_percent":0,"cost":282.73,"price":325.14,"discounted_price":0,"weight":6,"modified":"2022-12-21T16:01:04+00:00","created":"2022-12-15T15:43:57+00:00","item_variations_location_id":null,"item_variation_data":null,"delete":false,"item":null},{"id":"391c2ec1-e02d-4390-9a10-429c2ea460fc","name":"B-2082","document_id":"0b24e8d2-e7cc-4441-abd7-337c8a2c6cf1","item_id":null,"unit_id":4,"service_category_id":"5dc2f6d2-27e0-4dac-a2b7-39080a8e0008","description":"ROD BEARING JGE/H/K","quantity":8,"quantity_partially_received":0,"quantity_partially_shipped":0,"tax":5,"tax2":0,"discount_percent":0,"cost":282.73,"price":325.14,"discounted_price":0,"weight":5,"modified":"2022-12-21T16:01:04+00:00","created":"2022-12-15T15:43:57+00:00","item_variations_location_id":null,"item_variation_data":null,"delete":false,"item":null},{"id":"725fb97d-243f-44aa-98d0-50d903871ae4","name":"B-0776","document_id":"0b24e8d2-e7cc-4441-abd7-337c8a2c6cf1","item_id":null,"unit_id":4,"service_category_id":"5dc2f6d2-27e0-4dac-a2b7-39080a8e0008","description":"THRUST PLATE JGE/H/K","quantity":2,"quantity_partially_received":0,"quantity_partially_shipped":0,"tax":5,"tax2":0,"discount_percent":0,"cost":878.44,"price":1010.21,"discounted_price":0,"weight":7,"modified":"2022-12-21T16:01:04+00:00","created":"2022-12-15T15:43:57+00:00","item_variations_location_id":null,"item_variation_data":null,"delete":false,"item":null},{"id":"956cf37e-3921-4cad-94bf-670cdedd2d17","name":"B-1032","document_id":"0b24e8d2-e7cc-4441-abd7-337c8a2c6cf1","item_id":null,"unit_id":4,"service_category_id":"5dc2f6d2-27e0-4dac-a2b7-39080a8e0008","description":"JGK DOOR GASKET","quantity":8,"quantity_partially_received":0,"quantity_partially_shipped":0,"tax":5,"tax2":0,"discount_percent":0,"cost":17.21,"price":19.79,"discounted_price":0,"weight":3,"modified":"2022-12-21T16:01:04+00:00","created":"2022-12-15T15:43:57+00:00","item_variations_location_id":null,"item_variation_data":null,"delete":false,"item":null},{"id":"c2b74c55-465b-4bee-84a1-6c9e8e5bd102","name":"A-0661","document_id":"0b24e8d2-e7cc-4441-abd7-337c8a2c6cf1","item_id":null,"unit_id":4,"service_category_id":"5dc2f6d2-27e0-4dac-a2b7-39080a8e0008","description":"OIL FILTER","quantity":3,"quantity_partially_received":0,"quantity_partially_shipped":0,"tax":5,"tax2":0,"discount_percent":0,"cost":24.5,"price":28.18,"discounted_price":0,"weight":4,"modified":"2022-12-21T16:01:04+00:00","created":"2022-12-15T15:43:57+00:00","item_variations_location_id":null,"item_variation_data":null,"delete":false,"item":null},{"id":"de2c8695-9589-4856-be7a-d3979a776646","name":"FREIGHT CHARGE","document_id":"0b24e8d2-e7cc-4441-abd7-337c8a2c6cf1","item_id":null,"unit_id":1,"service_category_id":"5e6a78e2-cf6c-437c-ac52-0c3a0a8e000a","description":"RE:E2920103","quantity":1,"quantity_partially_received":0,"quantity_partially_shipped":0,"tax":5,"tax2":0,"discount_percent":0,"cost":70.64,"price":95.35,"discounted_price":0,"weight":8,"modified":"2022-12-21T16:01:04+00:00","created":"2022-12-21T15:34:51+00:00","item_variations_location_id":null,"item_variation_data":null,"delete":false,"item":null},{"id":"eab3c271-20ce-4c4e-af92-8553425eaa71","name":"C-6200","document_id":"0b24e8d2-e7cc-4441-abd7-337c8a2c6cf1","item_id":null,"unit_id":4,"service_category_id":"5dc2f6d2-27e0-4dac-a2b7-39080a8e0008","description":"TOP COVER GASKET","quantity":1,"quantity_partially_received":0,"quantity_partially_shipped":0,"tax":5,"tax2":0,"discount_percent":0,"cost":345.85,"price":397.73,"discounted_price":0,"weight":1,"modified":"2022-12-21T16:01:04+00:00","created":"2022-12-13T21:21:43+00:00","item_variations_location_id":null,"item_variation_data":null,"delete":false,"item":null}]}]}
I would like to output the JSON content to look like this on my google sheet
https://docs.google.com/spreadsheets/d/18x1cyztf5SgnKZHjqgWx2iP7SzQAksOzE_EVZoUOcy8/edit#gid=0
Any help would be greatly appreciated
Thanks

In your script, when the value of response.getContentText() is your showing data, how about the following modification?
From:
Logger.log(response.getContentText());
To:
Logger.log(response.getContentText());
// I added the below script.
const value = JSON.parse(response.getContentText());
const addValues = [value.document[0].customer.name, value.document[0].issue_date, value.document[0].attention, value.document[0].name];
const res = value.document[0].document_items.map(o => [value.document[0].document_number, ...["name", "description", "quantity", "price", "discounted_price"].map(h => o[h]), ...addValues]);
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1");
sheet.getRange(sheet.getLastRow() + 1, 1, res.length, res[0].length).setValues(res);
Please set your sheet name to getSheetByName("Sheet1").
Unfortunately, I cannot find External PO# you expect from your data.

Suggestion: Clean and Extract the Required Data
The first thing I noticed is that your current script has already extracted a single JSON object from Salesbinder. However, the format returned is hard to read. You may use JSON beautify sites online to rearrange and analyze the JSON object you have produced like JSON Viewer (DISCLAIMER: I am not affiliated with the website, I just find it helpful to share it to others due to its helpful features).
Script
Afterwards, you may be able to access the data you wanted by accessing the JSON object. For your table, you may use the following:
var salesBinderInvoiceNumVal = object.document[0].document_number;
var itemNameVal = object.document[0].document_items[0].name;
var descriptionVal = object.document[0].document_items[0].description;
var quantityVal = object.document[0].document_items[0].quantity;
var priceVal = object.document[0].document_items[0].price;
var discountPercentVal = object.document[0].document_items[0].discount_percent;
var clientNameVal = object.document[0].customer.name;
var issueDateVal = object.document[0].issue_date;
var attentionVal = object.document[0].attention;
var nameVal = object.document[0].name;
Note: The External PO number can't be found since there are no given values in your sample table.
But before doing so, you may want to store the generated JSON object to a variable. Thus, you may change:
Logger.log(response.getContentText());
to:
var object = response.getContentText();
Afterwards, you may add the setValues() function to add the values to the last row of your table. Thus, your script should be somewhat like this:
function fetching() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Sheet1');
var sheet2 = ss.getSheetByName('Sheet2');
var InvNumber = sheet2.getRange('A1').getValue();
var USERNAME = 'APIKey';
var PASSWORD = 'x';
var url = 'https://mydomain.salesbinder.com/api/2.0/documents.json?documentNumber=' + InvNumber + '&contextId=5';
var headers = {
"Authorization": "Basic " + Utilities.base64Encode(USERNAME + ':' + PASSWORD)
};
let response = UrlFetchApp.fetch(url, { headers });
//Changes start here
var object = response.getContentText(); //Store the JSON object to this variable
var lastRow = sheet.getLastRow(); //get the last row
//required values
var salesBinderInvoiceNumVal = object.document[0].document_number;
var itemNameVal = object.document[0].document_items[0].name;
var descriptionVal = object.document[0].document_items[0].description;
var quantityVal = object.document[0].document_items[0].quantity;
var priceVal = object.document[0].document_items[0].price;
var discountPercentVal = object.document[0].document_items[0].discount_percent;
var clientNameVal = object.document[0].customer.name;
var issueDateVal = object.document[0].issue_date;
var attentionVal = object.document[0].attention;
var nameVal = object.document[0].name;
//add the required values to a 2d array
var output = [[salesBinderInvoiceNumVal, itemNameVal, descriptionVal, quantityVal, priceVal, discountPercentVal, clientNameVal, issueDateVal, attentionVal, nameVal]];
sheet.getRange(lastRow+1, 1, 1, output[0].length).setValues(output); //add the 2d array to the last row of your table
}
Output:
Since your script only gets the value of one cell, I assumed that it only fetches one item or one row to your table. NOTE: I only processed the given JSON object in your post since I have no access/account in Salesbinder. I did assume that it was the output of your current script.
Reference:
You may further study about accessing JSON objects date in this article: JSON Object Literals

Related

Apps Script - Export JSON properly into Google Sheet

I'm quite beginner with Apps Script / Javascript. I have some JSON data that I'm exporting using an API.
Below is what I get when I do: console.log(jsonData);
I'm trying to:
Transform this JSON data into CSV.
Put the data in the first sheet of my active spreadsheet
Basically it should look like this:
However I'm stuck at this step and I cannot get the next piece of code right ... (how to transform into CSV and putting the data in a Google sheet).
Below is the beginning of my script:
function myFunction() {
var apiKey = "MyApiKEY";
var now = new Date();
var startDate = new Date(now.setDate(now.getDate()-2))
var endDate = startDate
var startDateFormatted = Utilities.formatDate(new Date(startDate), "GMT+7", "yyyy-MM-dd");
var endDateFormatted = Utilities.formatDate(new Date(endDate), "GMT+7", "yyyy-MM-dd");
var url = 'https://public-api.vendor.com/v1/clicks?start_date='+ startDateFormatted + '&end_date=' + endDateFormatted;
var options1 = {
"method": "get",
"headers": {
"accept": "application/json",
"Authorization": apiKey
}
}
var response = UrlFetchApp.fetch(url, options1);
var jsonData = JSON.parse(response.getContentText());
// console.log(jsonData);
}
I would appreciate any help in getting those data into a Google Sheet.
Also feel free to modify anything in the beginning of my script if you think something is wrong or unnecessary.
I believe your goal is as follows.
You want to convert your sample data to CSV data.
You want to put your sample data on the 1st sheet of the active Spreadsheet.
From your showing sample data, if jsonData is your showing sample data, how about the following modification?
From:
var jsonData = JSON.parse(response.getContentText());
To:
var jsonData = JSON.parse(response.getContentText());
// I added the below script.
const headers = ["date_of_report", "vendor_name", "product_name", "category", "avg_cpc", "avg_position", "clicks", "conversions", "conversion_rate", "cost", "cpl", "channel", "country", "email", "vendor_id"];
const values = [headers, ...jsonData.data.map(e => headers.map(h => e[h] || ""))];
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0];
sheet.getRange(1, 1, values.length, values[0].length).setValues(values);
// If you want to retrieve the values as CSV data. You can use the following script.
const csv = values.map(r => r.join(",")).join("\n");

Script returning set value error despite working in logger. The parameters (number[]) don't match [duplicate]

This question already has answers here:
How do you resolve a "The parameters (number[]) don't match the method signature for SpreadsheetApp.Range.setValues" error
(2 answers)
Closed last year.
I am quite literally at my wits end. I have this code that I put together to manage files that will be submitted through a Google form. The files are XLS and the conversion to sheets works perfectly.
The bottom function is to pull in the last 9 columns and the 1st column from each file. This seems to also work according to logger.log
However when I go to consolidate the data into a single file it all falls apart with the error:
Error
Exception: The parameters (number[]) don't match the method signature for SpreadsheetApp.Range.setValues.
I cannot figure out what is wrong....
function myFunction() {
//fileID
var folder = DriveApp.getFolderById("fileID");
var filesToConvert = DriveApp.getFolderById("fileID").getFilesByType(MimeType.MICROSOFT_EXCEL);
while (filesToConvert.hasNext()){ Drive.Files.copy({mimeType: MimeType.GOOGLE_SHEETS, parents: [{id: "FileID"}]}, filesToConvert.next().getId());}
var filesIterator = folder.getFiles();
var file;
var filetype;
var ssID;
var combinedData = [];
var data;
while(filesIterator.hasNext()){
file = filesIterator.next();
filetype = file.getMimeType();
if (filetype === "application/vnd.google-apps.spreadsheet"){
ssID = file.getId();
data = getDataFromSpreadsheet(ssID)
combinedData = combinedData.concat(data);
}//if ends here
}//while ends here
var ws = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Combined");
ws.getRange(2, 1, combinedData.length, combinedData[0].length).setValues(combinedData);
}
function getDataFromSpreadsheet(ssID) {
var ss = SpreadsheetApp.openById(ssID);
var ws = ss.getSheets()[0];
var data = ws.getRange(4, ws.getLastColumn()-9, ws.getLastRow(), 10).getValues();
var dataTwo = ws.getRange(4, 1, ws.getLastRow(), 1).getValues();
var dataThree = [];
for (let i in dataTwo) {
let dataIndex = i;
let startTime = data[dataIndex]
dataThree.push( [dataTwo[i], startTime].join(','))
};
return dataThree;
}
It seems that combinedData is a single 1D array but setValues accept a 2D array.
Replace:
dataThree.push( [dataTwo[i], startTime].join(','))
with:
dataThree.push( [[dataTwo[i], startTime].join(',')])
since you want to get an array of arrays.

How can I make my function run only if there is no fetched data?

I have a Google Apps Script project where I am able to enter the name of a location in Column A of a Google Sheet and have several aspects fetched using the Google Places API. I have been working on this for a bit, and my most recent revision seeks to solve an issue where my function was making too many requests, causing me to burn through the free $200 in credit on the Google Cloud platform.
I noted that every time I opened my Google Sheet, it would have to fetch all of the data again, burning through even more requests just to find information it had already located.
What would be my best bet in order to fetch all of the information and keep it in my Sheet so that it does not make a new request for information every time the Sheet gets opened? Just an If statement to check if there is a value already in one of the cells which gets filled in once the function gets run?
Below is my code. Right now, I just run =COMINED2(A2) in Cell B2 to fetch the information for the place in A2 and that gets placed in B2, C2, D2, E2, etc. Happy to reconfigure things if people have other suggestions?
function COMBINED2(text) {
var API_KEY = 'AIzaSyvxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxQ';
var baseUrl = 'https://maps.googleapis.com/maps/api/place/findplacefromtext/json';
var queryUrl = baseUrl + '?input=' + text + '&inputtype=textquery&key=' + API_KEY + "&locationbias=point:" + LOC_BASIS_LAT_LON;
var response = UrlFetchApp.fetch(queryUrl);
var json = response.getContentText();
var placeId = JSON.parse(json);
var ID = placeId.candidates[0].place_id;
var fields = 'name,geometry,formatted_address,formatted_phone_number,website,url,types,opening_hours';
var baseUrl2 = 'https://maps.googleapis.com/maps/api/place/details/json?placeid=';
var queryUrl2 = baseUrl2 + ID + '&fields=' + fields + '&key='+ API_KEY + "&locationbias=point:" + LOC_BASIS_LAT_LON;
if (ID == '') {
return 'Give me a Google Places URL...';
}
var response2 = UrlFetchApp.fetch(queryUrl2);
var json2 = response2.getContentText();
var place = JSON.parse(json2).result;
var placeName = place.name;
var placeAddress = place.formatted_address;
var placePhoneNumber = place.formatted_phone_number;
var placeWebsite = place.website;
var placeURL = place.url;
var weekdays = '';
place.opening_hours.weekday_text.forEach((weekdayText) => {
weekdays += ( weekdayText + '\r\n' );
} );
var data = [ [
place.name,
place.formatted_address,
place.formatted_phone_number,
place.website,
place.url,
weekdays.trim(),
] ];
return data;
}
I don't think a custom formula will work in your case since custom formulas are supposed to be independent of range, i.e, it should not check a specific cell or range whether it has value or not.
You would be better off creating a regular Apps Script function that calls COMBINED2, and either triggering it manually using the script UI, or probably assigning it to a button.
// this function calls COMBINED2()
function call_COMBINED2() {
var ss = SpreadsheetApp.getActiveSheet();
var text = ss.getRange("A2").getValue();
var data = COMBINED2(text);
var dest = ss.getRange("B2:G2");
dest.setValues(data);
}

Google sheets export to txt

Hello I made this script to export the data from a column to a .txt on my google drive
function createOrAppendFile() {
var ss = SpreadsheetApp.getActive();
var sheet = ss.getActiveSheet();
var range = sheet.getRange('G3:G50');
var rows = range.getValues();
var fileName="test.txt";
var folderName="Videos";
var data = rows.splice(0);
var str = data.map(function(e) {return e.join()}).join("\n");
var content = str;
// get list of folders with matching name
var folderList = DriveApp.getFoldersByName(folderName);
if (folderList.hasNext()) {
// found matching folder
var folder = folderList.next();
// search for files with matching name
var fileList = folder.getFilesByName(fileName);
if (fileList.hasNext()) {
// found matching file - append text
var file = fileList.next();
var combinedContent = content;
file.setContent(combinedContent);
}
else {
// file not found - create new
folder.createFile(fileName, content);
}
}
}
The problem is that when I export the data its exporting with the empty lines and on the .txt shows up empty lines that i dont want to have, how i can make it? So I only export the lines that have content.
This is what the .txt looks like https://i.stack.imgur.com/wplZL.png
I think that the reason of your issue might be due to sheet.getRange('G3:G50'). In this case, even when the empty rows are included below the data range in the range of G3:G50, range.getValues() retrieves all rows of G3:G50. If you want to retrieve the values with the data range, how about the following modification?
From:
var range = sheet.getRange('G3:G50');
To:
var range = sheet.getRange('G3:G' + sheet.getLastRow());
And, when you want to remove all empty rows of the column "G", you can also use the following modification.
From:
var range = sheet.getRange('G3:G50');
var rows = range.getValues();
To:
var range = sheet.getRange('G3:G' + sheet.getLastRow());
var values = range.getValues().filter(([g]) => g.toString() != "");
References:
getLastRow()
filter()

Google Script to use a cell array and return a list of value from Json API

I want to use a list of cell on the same column to build a custom url and fetch API data. I wrote the code for a single cell (and single value return) but don't know how to extend to the entire column:
function checkAddress() {
var addresses = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Addresses");
var baseUrl = 'https://my.api.website/xxxxx&address=';
var address = addresses.getRange(1, 1);
var addrID = address.getValue();
var url = baseUrl.concat(addrID);
var responseAPI = UrlFetchApp.fetch(url);
var json = JSON.parse(responseAPI.getContentText());
var data = [[json.result]];
var dataRange = addresses.getRange(1, 2, 1, 1);
dataRange.setValue(data);
}
The var addrID is the one that change, and all of them are in the A column; I would like to return the result to the B column on the same row.
Any help would be appreciated, thank you
You just need to loop through Col A. Try the below Code.
function checkAddress() {
var addresses = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Addresses");
var baseUrl = 'https://my.api.website/xxxxx&address=';
var data = addresses.getRange(1, 1,addresses.getLastRow()).getValues();
for(var i=0;i<data.length;i++){
var addrID = data[i][0];
var url = baseUrl.concat(addrID);
var responseAPI = UrlFetchApp.fetch(url);
var json = JSON.parse(responseAPI.getContentText());
var data1 = [[json.result]];
var dataRange = addresses.getRange(i+1,2,1).setValue(data1);
}
}