Appscript setformula parsing error. but seems working - google-sheets-api

I'm trying to set formula in google spreadsheet cell using this code
function SetFormuleSettimana(row) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var Settimane = ss.getSheetByName("Settimane");
var cell = Settimane.getRange("I" + row);
cell.setFormulaR1C1('ArrayFormula(Indice(Gruppi!A:G;Confronta(1;(G' + row + '=Gruppi!A:A)*(H' + row + '=Gruppi!B:B);0);5))');
}
The cell seems correctly filled with the formuala =ArrayFormula(Indice(Gruppi!A:G;Confronta(1;(G2=Gruppi!A:A)*(H2=Gruppi!B:B);0);5))
but I get a "Parsing Error", analyzing the formula in spreadsheet the help give correct value.

There is a problem with setting formulas with Apps Script in a language other than English.
To set your formulas programmatically, for the meantime you need to use the corresponding English names of the formulas.

Related

Copy Excel OneDrive table to an specific cell on another Excel OneDrive table (Power Automate)

I need to copy data from one excel worksheet and paste (values only) on another worksheet using power automate + Office script
I started to creat a flow using the answer in the link bellow.
Power Automate: Copy Excel OneDrive table to the bottom of another Excel OneDrive table
The problem is I didnt understood the second script so I was not able to modify it to what I need ( that one paste on the end of the workbook)
SCRIPT on the link
For Run script I have
function main(workbook: ExcelScript.Workbook) {
const sheet = workbook.getWorksheets()[0];
let lastRow = sheet.getUsedRange(true).getLastCell().getRowIndex() + 1;
let rng = "A3:P" + lastRow
let tableTest = sheet.getRange(rng).getValues();
console.log(tableTest);
}
Then under Compose
#{outputs('Run_script')?['body']?['Logs'][0]}
Then Initialize the "RemoveString" variable
#{split(outputs('Compose'),' ')[0]}
Then Initialize the "NewString" variable
#{replace(outputs('Compose'),variables('RemoveString'),'')}
Then Run Script 2 and add "NewString" as the parameter.
function main(workbook: ExcelScript.Workbook, rangeTest: string) {
let table = workbook.getTable("BacklogTable");
let str = rangeTest;
let testerTest = JSON.parse(str);
table.addRows(null, testerTest);
}
The reason for RemoveString is to remove the Date & Time Stamp from the outputs
This requires a little different workflow.
Run Script
function main(workbook: ExcelScript.Workbook) {
const sheet = workbook.getWorksheets()[0];
let lastRow = sheet.getUsedRange(true).getLastCell().getRowIndex() + 1;
let rng = "A2:C" + lastRow
let tableTest = sheet.getRange(rng).getValues();
console.log(tableTest);
console.log(tableTest.length)
}
Compose
#{outputs('Run_script')?['body']?['Logs'][0]}
Compose 2
#{outputs('Run_script')?['body']?['Logs'][1]}
RemoveString
#{split(outputs('Compose'),' ')[0]}
NewString
#{replace(outputs('Compose'),variables('RemoveString'),'')}
RemoveString2
#{split(outputs('Compose_2'),' ')[0]}
NewString2
#{int(replace(outputs('Compose_2'),variables('RemoveString2'),''))}
Num
#{int(variables('NewString2'))}
Run Script 2
function main(workbook: ExcelScript.Workbook, rangeTest: string, length: number) {
let str = rangeTest;
const arr = JSON.parse(str);
let sheet = workbook.getWorksheet("Sheet2");
let rng = "A7:C" + (6 + length); //Change C to whichever column you want to end on
sheet.getRange(rng).setValues(arr);
sheet.getRange(rng).setNumberFormatLocal("0.00");
}
I may not be following this correctly, but you can also return values and pass them to another connector in Power Automate. Here is some documentation on how to return values with Office Scripts. Also, below is an example script with parameters and a number type return value. With returning values rather than console.logging them, you won't need to remove any output in your Flow steps. Let me know if you have any questions!
function main(
workbook: ExcelScript.Workbook,
issueId: string,
issueTitle: string): number {
// Get the "GitHub" worksheet.
let worksheet = workbook.getWorksheet("GitHub");
// Get the first table in this worksheet, which contains the table of GitHub issues.
let issueTable = worksheet.getTables()[0];
// Add the issue ID and issue title as a row.
issueTable.addRow(-1, [issueId, issueTitle]);
// Return the number of rows in the table, which represents how many issues are assigned to this user.
return issueTable.getRangeBetweenHeaderAndTotal().getRowCount();
}

How to get NPOI Excel RichStringCellValue?

I am using DotNetCore.NPOI (1.2.1) in order to read an MS Excel file.
Some of the cells are of type text and contain formatted strings (e.g. some words in bold).
How do I get the formatted cell value? My final goal: Retrieve the cell text as HTML.
I tried
var cell = row.GetCell(1);
var richStringCellValue = cell.RichStringCellValue;
But this won't let me access the formatted string (just the plain string without formattings).
Does anybody have an idea or solution?
I think you'll have to take longer route in this case. First you'll have to maintain the formatting of cell value like date, currency etc and then extract the style from cell value and embed the cell value under that style.
best option is to write extenstion method to get format and style value.
To get the fomat Please see this link How to get the value of cell containing a date and keep the original formatting using NPOI
For styling first you'll have to check and find the exact style of running text and then return the value inside the html tag , below method will give you idea to extract styling from cell value. Code is untested , you may have to include missing library.
public void GetStyleOfCellValue()
{
XSSFWorkbook wb = new XSSFWorkbook("YourFile.xlsx");
ISheet sheet = wb.GetSheetAt(0);
ICell cell = sheet.GetRow(0).GetCell(0);
XSSFRichTextString richText = (XSSFRichTextString)cell.RichStringCellValue;
int formattingRuns = cell.RichStringCellValue.NumFormattingRuns;
for (int i = 0; i < formattingRuns; i++)
{
int startIdx = richText.GetIndexOfFormattingRun(i);
int length = richText.GetLengthOfFormattingRun(i);
Console.WriteLine("Text: " + richText.String.Substring(startIdx, startIdx + length));
if (i == 0)
{
short fontIndex = cell.CellStyle.FontIndex;
IFont font = wb.GetFontAt(fontIndex);
Console.WriteLine("Bold: " + (font.IsBold)); // return string <b>my string</b>.
Console.WriteLine("Italics: " + font.IsItalic + "\n"); // return string <i>my string</i>.
Console.WriteLine("UnderLine: " + font.Underline + "\n"); // return string <u>my string</u>.
}
else
{
IFont fontFormat = richText.GetFontOfFormattingRun(i);
Console.WriteLine("Bold: " + (fontFormat.IsBold)); // return string <b>my string</b>.
Console.WriteLine("Italics: " + fontFormat.IsItalic + "\n");// return string <i>my string</i>.
}
}
}
Font formatting in XLSX files are stored according to schema http://schemas.openxmlformats.org/spreadsheetml/2006/main which has no direct relationship to HTML tags. Therefore your task is not that much straight forward.
style = cell.getCellStyle();
font = style.getFont(); // or style.getFont(workBook);
// use Font object to query font attributes. E.g. font.IsItalic
Then you will have to build the HTML by appending relevant HTML tags.

How to write into a particular cell using xlsx npm package

I have to write a value to a particular cell (say the D4 cell) in my xlsm file. I can see the option of
XLSX.writeFile(workbook, 'out.xlsx');
in the XLSX package documentation (writing functions)
But I am not seeing anything to write a value to a particular cell (where should the values which needs to be written passed?). Or, it is not as clear as the example provided to read a particular cell value.
Would be glad if someone could provide me a simple example of snippet.
This is how I read a particular cell value:
if(typeof require !== 'undefined') XLSX = require('C:\\Program Files\\nodejs\\node_modules\\npm\\node_modules\\xlsx');
var workbook = XLSX.readFile('xlsm');
var first_sheet_name = workbook.SheetNames[0];
var address_of_cell = 'D5';
var worksheet = workbook.Sheets[first_sheet_name];
var desired_cell = worksheet[address_of_cell];
desired_value = (desired_cell ? desired_cell.v : undefined);
console.log('Cell Value is: '+ desired_value);
So to write to a specific cell in a defined sheet - lets say first sheet, you can do:
const XLSX = require('xlsx');
// read from a XLS file
let workbook = XLSX.readFile('test.xls');
// get first sheet
let first_sheet_name = workbook.SheetNames[0];
let worksheet = workbook.Sheets[first_sheet_name];
// read value in D4
let cell = worksheet['D4'].v;
console.log(cell)
// modify value in D4
worksheet['D4'].v = 'NEW VALUE from NODE';
// modify value if D4 is undefined / does not exists
XLSX.utils.sheet_add_aoa(worksheet, [['NEW VALUE from NODE']], {origin: 'D4'});
// write to new file
// formatting from OLD file will be lost!
XLSX.writeFile(workbook, 'test2.xls');
Hope that helps
Modify value in D4
worksheet['D4'].v = 'NEW VALUE from NODE';
This will work only if the cell already defined in the file, but sometimes you will want to write to a new undefined cell.
so, the solution I found for that is:
modify value in new cell- D4
XLSX.utils.sheet_add_aoa(worksheet, [['NEW VALUE from NODE']], {origin: 'D4'});

Need a more efficient solution than looping

I am building a spreadsheet that tracks work in progress as it moves through steps of a manufacturing process.
Each step of the process has a column with the total parts moved to each stage. To the left of this column is a column for number of parts moved to the stage (parts move through a few at a time).
My scrpit then takes the values in the "add" column, adds them to the "total" column, then reset the "add" column to "".
Here's the code:
function addColumns() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
// ss is now the spreadsheet the script is associated with
var sheet = ss.getSheets()[0]; // sheets are counted starting from 0
// sheet is the first worksheet in the spreadsheet
for (var i=4; i<500; i++ ) {
if(sheet.getRange(i,1).getValue()>0){ //Only run if order number not empty
//Breakout Column
var add = sheet.getRange(i,6);
var total = sheet.getRange(i,7);
total.setValue(total.getValue() + add.getValue());
add.setValue("");
//CNC Column
var add = sheet.getRange(i,8);
var total = sheet.getRange(i,9);
total.setValue(total.getValue() + add.getValue());
add.setValue("");
//CutSand Column
var add = sheet.getRange(i,10);
var total = sheet.getRange(i,11);
total.setValue(total.getValue() + add.getValue());
add.setValue("");
//Lasered Column
var add = sheet.getRange(i,12);
var total = sheet.getRange(i,13);
total.setValue(total.getValue() + add.getValue());
add.setValue("");
//To Finishing Column
var add = sheet.getRange(i,14);
var total = sheet.getRange(i,15);
total.setValue(total.getValue() + add.getValue());
add.setValue("");
// Defective Column
var add = sheet.getRange(i,17);
var total = sheet.getRange(i,18);
total.setValue(total.getValue() + add.getValue());
add.setValue("");
//Etsy Column
var add = sheet.getRange(i,20);
var total = sheet.getRange(i,21);
total.setValue(total.getValue() + add.getValue());
add.setValue("");
}
if(sheet.getRange(i,4).getValue()<1){i=500} //Once you find a blank order exit the loop
}
}
My code as written does accomplish this; it does exactly what I need. The problem is that since the code is accessing the spreadsheet on each loop it takes almost a full second per cell to run, and with 7 steps per order it can take minutes at a time to run through with lots of orders...
This is a pretty simple mathematical task, so there has to be a more efficient way of doing it, I just haven't been able to find the right keywords to describe what I need to do.
I am quite happy to learn whatever needs to be done, just need to know what direction to head.
Thanks in advance!
I would suggest to do something like this: (not tested)
function addColumns() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheets()[0]; // Refers to the first worksheet in the spreadsheet
var data = sheet.getDataRange().getValues(); // Acquires all values of the sheet
for (var i = 3; i < data.length; i++) { // Loop over every row
if (data[i][0].length > 0) { // Check if first column has a value
// Breakout
sheet.getRange(i+1,7).setValue(parseFloat(data[i][6]) + parseFloat(data[i][5]));
sheet.getRange(i+1,6).clear();
// Repeat code above for other columns
}
}
}
This code acquires all the data from the sheet instead of looping over a fixed amount of 500 rows. Assuming that your data starts at row 4, I've implemented this in the code above as well.
Variable data acquires all the data at one moment instead of trying to fetch values of every range (cell) all the time. I expect that this will save your script quite some time.
Because we acquire the data at once, the script sees the value as a string. Before we calculate the new value of the total column, we parse the value as a float (a number with decimals).
The code above is not tested as I don't have a sheet ready in the same format as you do but I think the logic is clear and if it doesn't work I suppose you should be able to adjust it to work for your sheet.

Apache POI - DROP DOWN value removing '00000' from data

I am building dynamic drop down through java code and it is working perfectly fine.
The code I am running is:
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = workbook.createSheet("Data Validation");
XSSFDataValidationHelper dvHelper = new XSSFDataValidationHelper(sheet);
XSSFDataValidationConstraint dvConstraint = (XSSFDataValidationConstraint)
dvHelper.createExplicitListConstraint(new String[]{"0000011", "0000021", "0000031"});
CellRangeAddressList addressList = new CellRangeAddressList(0, 0, 0, 0);
XSSFDataValidation validation = (XSSFDataValidation)dvHelper.createValidation(
dvConstraint, addressList);
validation.setShowErrorBox(true);
validation.setSuppressDropDownArrow(true);
sheet.addValidationData(validation);
Drop down are coming properly but when I select any one of the value from drop-down 00000 are automatically removed and only 11 is getting displayed, but I want value to be 0000011 to be selected from drop down.
drop value is showing as 0000011 but after selection it display 11. Might be if we can change cell type to text it will help or some other way but how to do it?
I solved this on my own after lot of research. so I thought to post answer to help others.
// setting cell type as string to avoid removing 00000 from drop down
CellStyle textStyle = workbook.createCellStyle();
textStyle.setDataFormat((short)BuiltinFormats.getBuiltinFormat("text"));
sheet.setDefaultColumnStyle(0, textStyle);