Google Sheets API Node.js Append Overwrite - api

I have a dumb question. I have a script running on google sheets. Every week, I would like to run a script and replace the data on a specific sheets.
I tried to do it through insertDataOption = OVERWRITE, but it does not work.
When I read the documentation, here what is written:
OVERWRITE The new data overwrites existing data in the areas it is written. (Note: adding data to the end of the sheet will still insert new rows or columns so the data can be written.)
Do you have any idea what I do wrong?

You are using the spreadsheets.values.append endpoint. From the documentation:
Appends values to a spreadsheet. The input range is used to search for existing data and find a "table" within that range. Values will be appended to the next row of the table, starting with the first column of the table.
If what you want, instead of appending data is to replace data in a range of your sheet, you should instead be using the spreadsheets.values.update endpoint. For your case, it can be used as follows:
function insertData(auth) {
const sheets = google.sheets({version: 'v4', auth});
var request = {
spreadsheetId: '###',
range: 'A1:D48',
valueInputOption: 'RAW',
resource: {
values: [[getting_company_name, duration_event, current_date, getting_profesional_service]]
}
};
sheets.spreadsheets.values.update(request,
(err, res) => {
if (err) return console.log('The API returned an error: ' + err);
});
}
You can find more information on creating a node js application for Sheets here

#Frenchcooc
var request = {
// The ID of the spreadsheet to update.
spreadsheetId: '###',
range: 'A1:D48',
valueInputOption: 'RAW',
insertDataOption: 'OVERWRITE',
resource: {
values: [[getting_company_name, duration_event, current_date, getting_profesional_service]]
},
auth: authClient,
};

Related

Suitescript: copying sublist data from one record to another

I have a before load user event function on an invoice record that create a button called 'create vendor bill'.
When this button is pressed, a new vendor bill record is opened. The UE script:
/**
*#NApiVersion 2.x
*#NScriptType UserEventScript
*/
define([
"N/url",
"N/record",
"N/runtime",
"N/ui/serverWidget",
"N/redirect",
], function (url, record, runtime, serverWidget, redirect) {
var exports = {};
/**
* #param {UserEventContext.beforeLoad} context
*/
function beforeLoad(context) {
if (
context.type == context.UserEventType.EDIT ||
context.type == context.UserEventType.VIEW
) {
var record = context.newRecord;
var recordId = record.id;
var recordType = record.type;
var customer = record.getValue({ fieldId: "entity" });
log.debug("entity", customer);
var scriptObj = runtime.getCurrentScript();
var customForm = scriptObj.getParameter({
name: "custscript_custom_form_vb",
});
var recordSublist = record.getSublist({ sublistId: "item" });
log.debug("item", recordSublist);
var form = context.form;
log.debug("form", form);
var userVarStr = record;
log.debug("uservarstr", userVarStr);
var userVarURL = url.resolveRecord({
recordType: "vendorbill",
params: {
entity: parseInt(customer),
supportcase: recordId,
cf: parseInt(customForm),
},
});
form.addButton({
id: "custpage_button_test",
label: "Create Vendor Bill",
functionName: "getDetails('" + userVarURL + "')",
});
}
}
exports.beforeLoad = beforeLoad;
return exports;
});
Once the page redirects to the vendor bill form, a client script (deployed on the form), sets the field values on the body of the vendor bill using the parameters passed in the url
This is working as expected.
Where I am getting stuck is trying to work out how to pass the 'item' sublist values to from the invoice to the vendor bill?
Would I pass this as an array?
From what I understand, there is a limit to the number of characters that can be passed via the url.
I can't find anything online or in the Netsuite documentation that deals with passing sublist values between records
For starters I would want to see the Client Script.
One option would be to only pass the Invoice Record ID and Type. Then you can create a Suitelet to be used as a proxy and get the sublist data by a saved search.
Something to keep in mind is that if the sublist is very very long you may reach a execution timeout so you may want to consider triggering a MapReduce script to populate the sublist again you would pass it the recType and ID of the invoice and vendor bill and then use a saved search to get the data.
There are other approaches but I would need to see the client script.

Date format messed up while copying data from one spreadsheet to another using Google Sheets API batchUpdate

I am copying a dataset from one spreadsheet to another and all is fine except the dates.
In the source file the dates are like "2020-07-27", but after I run the script, the dates in the destination file are in completely different format like "Sun Jul 26 18:00:00 GMT-04:00 2020".
What should I do in order to copy the date as it is - YYYY-MM-DD?
My code:
function myFunction() {
var sheet_source_values = SpreadsheetApp.openById("1JfjXPPFj08p6cxjdsdcBhTMkl6yXLJkhASG0dv4").getSheetByName(Utilities.formatDate(now,"GMT+1", "dd.MM")).getRange('A:AD').getValues()
var sheet_destination = SpreadsheetApp.openById("GTjEfvjoTJ7U7ZXwYUEnSkKtfudXZuCP0dyq").getSheetByName("Updated_sheet")
var request = {
'responseValueRenderOption' : 'UNFORMATTED_VALUE',
'valueInputOption': 'RAW',
'responseDateTimeRenderOption' : 'SERIAL_NUMBER',
'data': [
{
'range': "'Updated_sheet'!" + sheet_destination.getRange(2,1,sheet_source_values.length,sheet_source_values[0].length).getA1Notation(),
'majorDimension': 'ROWS',
'values': sheet_source_values
}
]
};
Sheets.Spreadsheets.Values.batchUpdate(request, "GTjEfvjoTJ7U7ZXwYUEnSkKtfudXZuCP0dyq");
}
I tried changing "responseValueRenderOption" and "responseDateTimeRenderOption" but could find solution :(
The problem here is not with the Sheets API, but with the way you are retrieving the values from the source spreadsheet.
According to the getValues method documentation:
getValues - Returns a two-dimensional array of values, indexed by row, then by column. The values may be of type Number, Boolean, Date, or String, depending on the value of the cell.
In this way, the values will be retrieved as a Date type, but this type is the Google default one, hence the results you are getting on the destination sheet.
In order to fix this, I suggest you use getDisplayValues instead as this will return the displayed values from the source sheet. As for the Sheets API request, you can simply keep the 'valueInputOption': 'RAW' option only.
Modified sheet_source_values
var sheet_source_values = SpreadsheetApp.openById("1bGCXCUe6cgyLQRUQrOIAT2BruBH95ybAX7iG_pyk4Q0").getSheetByName("Sheet1").getRange('A1:A4').getDisplayValues();
Modified Sheets API request
var request = {
'valueInputOption': 'RAW',
'data': [{
'range': "'Updated_sheet'!" + sheet_destination.getRange(2, 1, sheet_source_values.length, sheet_source_values[0].length).getA1Notation(),
'majorDimension': 'ROWS',
'values': sheet_source_values
}]
};
Reference
Google Apps Script Range Class - getDisplayValues();
Google Apps Script Range Class - getValues().

columnSummary is not added

I am trying to add columnSummary to my table using Handsontable. But it seems that the function does not fire. The stretchH value gets set and is set properly. But it does not react to the columnSummary option:
this.$refs.hot.hotInstance.updateSettings({stretchH: 'all',columnSummary: [
{
destinationRow: 0,
destinationColumn: 2,
reversedRowCoords: true,
type: 'custom',
customFunction: function(endpoint) {
console.log("TEST");
}
}]
}, false);
I have also tried with type:'sum' without any luck.
Thanks for all help and guidance!
columnSummary cannot be changed with updateSettings: GH #3597
You can set columnSummary settings at the initialization of Handsontable.
One workaround would be to somehow manage your own column summary, since Handsontable one could give you some headeache. So you may try to add one additional row to put your arithmetic in, but it is messy (it needs fixed rows number and does not work with filtering and sorting operations. Still, it could work well under some circumstances.
In my humble opinion though, a summary column has to be fully functionnal. We then need to set our summary row out of the table data. What comes to mind is to take the above mentioned additional row and take it away from the table data "area" but it would force us to make that out of the table row always looks like it still was in the table.
So I thought that instead of having a new line we could just have to add our column summary within column header:
Here is a working JSFiddle example.
Once the Handsontable table is rendered, we need to iterate through the columns and set our column summary right in the table cell HTML content:
for(var i=0;i<tableConfig.columns.length;i++) {
var columnHeader = document.querySelectorAll('.ht_clone_top th')[i];
if(columnHeader) { // Just to be sure column header exists
var summaryColumnHeader = document.createElement('div');
summaryColumnHeader.className = 'custom-column-summary';
columnHeader.appendChild( summaryColumnHeader );
}
}
Now that our placeholders are set, we have to update them with some arithmetic results:
var printedData = hotInstance.getData();
for(var i=0;i<tableConfig.columns.length;i++) {
var summaryColumnHeader = document.querySelectorAll('.ht_clone_top th')[i].querySelector('.custom-column-summary'); // Get back our column summary for each column
if(summaryColumnHeader) {
var res = 0;
printedData.forEach(function(row) { res += row[i] }); // Count all data that are stored under that column
summaryColumnHeader.innerText = '= '+ res;
}
}
This piece of code function may be called anytime it should be:
var hotInstance = new Handsontable(/* ... */);
setMySummaryHeaderCalc(); // When Handsontable table is printed
Handsontable.hooks.add('afterFilter', function(conditionsStack) { // When Handsontable table is filtered
setMySummaryHeaderCalc();
}, hotInstance);
Feel free to comment, I could improve my answer.

Find if a range exists in a spreadsheet

How can I list the names of the worksheets in a Google SpreadSheet? I am trying to find if a worksheet exists using DataFilters
This is my function
public bool RangeExists(string sheet, string range)
{
BatchGetValuesByDataFilterRequest r = new BatchGetValuesByDataFilterRequest();
DataFilter filter = new DataFilter();
filter.A1Range = range;
r.DataFilters = new List<DataFilter>() { filter };
var a = service.Spreadsheets.Values.BatchGetByDataFilter(r, sheet).Execute();
return a.ValueRange.Count>0;
}
This code throws this exception when I try to find if my spreadsheet has a sheet called "Sheet":
Google.Apis.Requests.RequestError
Invalid dataFilter[0]: Unable to parse range: Sheet!A:ZZ [400]
Errors [
Message[Invalid dataFilter[0]: Unable to parse range: Sheet!A:ZZ] Location[ - ] Reason[badRequest] Domain[global]
]
Thank you.
If you check REST Resource: spreadsheets you'll notice that there's a sheets property that should display all the sheets within a spreadsheet.
"sheets": [
{
object(Sheet)
}
]
So, what you can do is to make a call to spreadsheets.get. This will return that sheets object which you're looking for. You can use the Try-it from that link and indicate '*' in the "fields" parameter to return all properties (that includes the sheets).

API returns array of JSON for only one result

Currently working on an API which given an address returns information about is. Some of the rows in our tables are duplicates, however being as there is over 15 million I cant go and find the duplicates. Instead I have opted to use
var query = `SELECT TOP 1 * from my_TABLE where..conditions`;
This ensures that only one row of the duplicates are returned.
The problem is when this is sent back as a JSON it comes as an array with one object.
In the Server.js file
// create Request object
var request = new sql.Request();
// query to the database
request.query(query, function (err, result) {
if (err) {
console.log("Error while querying database :- " + err);
res.send(err);
}
else {
res.send(result)
}
Returns this:
[{
Address:'our info'
}]
is there a way to have it respond with
{
Address:'our info'
}
Because from DB you've get list of object anyway, even there is only 1 item.
It works as you expected when you try to return json with the first element of your array.