Each month, populate spreadsheet data to next column [script needed] - excel

I am developing a "Dashboard" [Sample Sheet Here] in which a number of data points are automatically calculated using formulas in Column C (NOTE: formulas not included in sample sheet).
I would like to create a monthly log of Column C data, in which cell values are copied to the next blank column of the corresponding Row
I have previously used the following script to log changes vertically, and could use a hand with repurposing for my desired outcome.
function onEdit(event) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = event.source.getActiveSheet();
var r = event.source.getActiveRange();
if(s.getName() == "Action Items" && r.getColumn() == 2 && r.getValue()) {
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Portion Tracking");
if(targetSheet.getLastRow() == targetSheet.getMaxRows()) {
targetSheet.insertRowAfter(targetSheet.getLastRow());
}
//Changes Start Here
var myRow = targetSheet.getLastRow()+1;
s.getRange(row, 1).copyTo(targetSheet.getRange(myRow,1));
s.getRange(row, 2).copyTo(targetSheet.getRange(myRow,2));
s.getRange(row, 3).copyTo(targetSheet.getRange(myRow,3));
}
}

AppendColumn()
I played around with this idea once and using a function I took from here and some of my own carving. I've comeup with an appendColumn() function.
Anyway it sounded like something you might want to have. You can take a look at it and in the meantime I'll take a look at your code.
function appendColumn(columnA)
{
var ss=SpreadsheetApp.getActive();
var sh=ss.getActiveSheet();
var rg=sh.getDataRange();
var vA=rg.getValues();
var vB=transpose(vA);
sh.clear();
sh.getRange(1,1,vB.length,vB[0].length).setValues(vB);
sh.appendRow(columnA);
vD=sh.getDataRange().getValues();
sh.clear();
vE=transpose(vD);
sh.getRange(1,1,vE.length,vE[0].length).setValues(vE);;
}
function transpose(a)
{
return Object.keys(a[0]).map(function (c) { return a.map(function (r) { return r[c]; }); });
}
To test it I just called it like this.
function testAppendColumn()
{
appendColumn(['',1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]);
}
I'd like to see the source data. But assuming it has not changed then I'm guessing that this technique will work for you.
function onEdit(event)
{
var ss = event.source;
var s = event.source.getActiveSheet();
var r = event.range;
if(s.getName() == "Action Items" && r.getColumn() == 2 && r.getValue())
{
var row = r.getRow();
var numColumns = s.getLastColumn();
var targetSheet = ss.getSheetByName("Portion Tracking");
if(targetSheet.getLastRow() == targetSheet.getMaxRows())
{
targetSheet.insertRowAfter(targetSheet.getLastRow());
}
//Changes Start Here
var myCol = targetSheet.getLastColumn()+1;
s.getRange(row, 1).copyTo(targetSheet.getRange(1,myCol));
s.getRange(row, 2).copyTo(targetSheet.getRange(2,myCol));
s.getRange(row, 3).copyTo(targetSheet.getRange(3,myCol));
}
}
I don't understand the logic of connecting this to onEdit trigger but I'll assume that you do.

Related

Tabulator - How to set value inside cellEdited function

I am using the Tabulator plugin and am using the editorParams function to select from a list of options. If a value isn't selected (eg: Cancelled) I want it to revert to the old (previous) cell value and do nothing, but calling cell.setValue() keeps retriggering the cellEdit function and it gets stuck in a loop.
table.on('cellEdited', function(cell) {
var cellOldValue = cell.getOldValue();
var cellNewValue = cell.getValue();
var row = cell.getRow();
var index = row.getIndex();
if (cellNewValue == 'none-selected') {
cell.setValue(cellOldValue);
} else {
if (confirm('Are you sure?')) {
// ok, do something
} else {
cell.setValue(cellOldValue);
}
}
});
This just keeps triggering the prompt. Any solutions, thank you?

Get data from cell and pass to app script and run API when cell gets update

I'm using an app script to get data from cells and pass that data to API. So whenever a color gets the change we have to take that value pass in APIs and store response in G Column. Can someone help
function callNumbers() {
// Call the Numbers API for random math fact
var response = UrlFetchApp.fetch("http://numbersapi.com/random/math");
Logger.log(response.getContentText());
var fact = response.getContentText();
var sheet = SpreadsheetApp.getActiveSheet();
sheet.getRange(sheet.getLastRow() + 1,1).setValue([fact]);
}
function onEdit(e) {
var row = e.range.getRow();
if (row > 1 && e.source.getActiveSheet().getName() === "Sheet1") {
e.source.getActiveSheet().getRange(row, 14).setValue(new Date());
} else {
if ((row > 1 && e.source.getActiveSheet().getName() === "Sheet2") || (row > 1 && e.source.getActiveSheet().getName() === "Sheet3")) {
e.source.getActiveSheet().getRange(row, 6).setValue(new Date());
}}}

How get Lot/Serial number in Netsuite SuiteScript 2.0 for Inventory Adjustment Transaction?

I'm trying to get the serial numbers from a inventory adjustment in a user event script. The following code works very well for me when the amount to adjust is positive, but not when it is negative.
var invDet = transaction.getSublistSubrecord({sublistId:'inventory',
fieldId:'inventorydetail',
line:x});
for(var y = 0; y = invDet.getLineCount('inventoryassignment'); y++) {
var lotNumber = invDet.getSublistValue({sublistId:'inventoryassignment',
fieldId:'receiptinventorynumber',
line:y});
log.debug('lotNumber', lotNumber);
}
When adjust quantity is negative, receiptinvetorynumber is empty
I have tried using field id equal to 'issueinventorynumber' or 'binnunber' but the returned value is empty.
I found the following comment in a NetsuiteHub forum...
In 2.0 the getValue call returns the internal ID of the serial/lot number and the getText equivalent does not work. Depending on the exact logic you need to execute for the obtained numbers you might need to call a subsequent saved search to obtain the actual serial/lot numbers and not internal IDs (an 'inventorynumber' search will do the trick).
I tried this...
try{
var internalId = invdet.getSublistValue({sublistId:'inventoryassignment',fieldId:'internalid', line:y});
search.create({type:'inventorynumber', filters:[
['internalid', 'is', internalId]
], columns:['inventorynumber']}).run().each(function (result) {
binText = result.getValue('inventorynumber');
log.debug('binText', binText);
});
} catch(e) {
log.debug('Error', e.message);
throw e.message;
}
I am too inexperienced to make this work. I appreciate any help you can give me.
Thanks.
The challenge is that this area of the NetSuite API is not well documented. However, I pushed through it through trial and error and search hours.
var invDet = transaction.getSublistSubrecord({sublistId:'inventory',
fieldId:'inventorydetail',
line:x});
for(var y = 0; y = invDet.getLineCount('inventoryassignment'); y++) {
var Qty = invdet.getSublistValue({sublistId:'inventoryassignment',
fieldId:'quantity',
line:y});
var lotNumber = '';
if(Qty < 0)
{
var ivnNumId = nvdet.getSublistValue({sublistId:'inventoryassignment',
fieldId:'issueinventorynumber',
line:y});
if(ivnNumId !== '')
{
var invNum = record.load({type: 'inventorynumber',id:ivnNumId});
lotNumber = invNum.getValue({fieldId: 'inventorynumber'});
}
}
else
{
lotNumber = invdet.getSublistValue({sublistId:'inventoryassignment',
fieldId:'receiptinventorynumber',
line:y});
}
log.debug('lotNumber', lotNumber);
}
This information was very helpful in ss1.0
I hope it is useful to someone

office.js code after context.sync not running

I'm having trouble to extract values from an excel file with the office.js add in I'm writing.
The add in shall help my colleagues to prepare report sheets for each teacher.
It is supposed to filter the corresponding courses from the master table and send the data to the next processing step (create word files for each teacher).
I've tried filtering ranges with autofilter and creating a table with the data, but it seems that no code is executed after return context.sync()
I've read the official tutorial and some of the code on buildingofficeaddins.com but my function never executes the code after "return context.sync()"
function mselectTeacher(teachers) {
Excel.run(function (context) {
var sheet = context.workbook.worksheets.getActiveWorksheet();
var lfv = sheet.tables.add("A1:M211", true);
var wsy = lfv.columns.getItem("WS/SS");
var studium = lfv.columns.getItem("Studium");
// some more colums
wsy.load("values");
studium.load("values");
return context.sync()
.then(function () {
//I actually want to filter the rows by teacher,
//this is only for testing
for (var i = 1; i < 20; i++) {
console.log(wsy[i] + "," + studium[i]);
}
});
});
}
Is the problem, that I'm calling Excel.run from within another function?
Could you try this?
function mselectTeacher(teachers) {
Excel.run(function (context) {
var sheet = context.workbook.worksheets.getActiveWorksheet();
var lfv = sheet.tables.add("A1:M211", true);
var wsy = lfv.columns.getItem("WS/SS");
var studium = lfv.columns.getItem("Studium");
// some more colums
wsy.load("values");
studium.load("values");
context.sync()
//I actually want to filter the rows by teacher,
//this is only for testing
for (var i = 1; i < 20; i++) {
console.log(wsy[i] + "," + studium[i]);
}
});
}
I tried your code in ScriptLab on excel web and saw "The requested resource doesn't exist"error in F12
I think it's due to no columns named "WS/SS" "Studium" in your new added table. It works after i changed the columns name with "WS/SS" "Studium"

Google Apps Script - Exporting events from Google Sheets to Google Calendar - how can I stop it from removing my spreadsheet formulas?

I've been trying to create a code that takes info from a Google Spreadsheet, and creates Google Calendar events. I'm new to this, so bear with my lack of in-depth coding knowledge!
I initially used this post to create a code:
Create Google Calendar Events from Spreadsheet but prevent duplicates
I then worked out that it was timing out due to the number of rows on the spreadsheet, and wasn't creating eventIDs to avoid the duplicates. I got an answer here to work that out!
Google Script that creates Google Calendar events from a Google Spreadsheet - "Exceeded maximum execution time"
And now I've realised that it's over-writing the formulas, I have in the spreadsheet, auto-completing into each row, as follows:
Row 12 - =if(E4="","",E4+1) // Row 13 - =if(C4="","",C4+1) // Row 18 - =if(B4="","","WHC - "&B4) // Row 19 - =if(B4="","","Docs - "&B4)
Does anyone have any idea how I can stop it doing this?
/**
* Adds a custom menu to the active spreadsheet, containing a single menu item
* for invoking the exportEvents() function.
* The onOpen() function, when defined, is automatically invoked whenever the
* spreadsheet is opened.
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
*/
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Export WHCs",
functionName : "exportWHCs"
},
{
name : "Export Docs",
functionName : "exportDocs"
}];
sheet.addMenu("Calendar Actions", entries);
};
/**
* Export events from spreadsheet to calendar
*/
function exportWHCs() {
// check if the script runs for the first time or not,
// if so, create the trigger and PropertiesService.getScriptProperties() the script will use
// a start index and a total counter for processed items
// else continue the task
if(PropertiesService.getScriptProperties().getKeys().length==0){
PropertiesService.getScriptProperties().setProperties({'itemsprocessed':0});
ScriptApp.newTrigger('exportWHCs').timeBased().everyMinutes(5).create();
}
// initialize all variables when we start a new task, "notFinished" is the main loop condition
var itemsProcessed = Number(PropertiesService.getScriptProperties().getProperty('itemsprocessed'));
var startTime = new Date().getTime();
var sheet = SpreadsheetApp.getActiveSheet();
var headerRows = 4; // Number of rows of header info (to skip)
var range = sheet.getDataRange();
var data = range.getValues();
var calId = "flightcentre.com.au_pma5g2rd5cft4lird345j7pke8#group.calendar.google.com";
var cal = CalendarApp.getCalendarById(calId);
for (i in data) {
if (i < headerRows) continue; // Skip header row(s)
var row = data[i];
var date = new Date(row[12]); // First column
var title = row[18]; // Second column
var tstart = new Date(row[15]);
tstart.setDate(date.getDate());
tstart.setMonth(date.getMonth());
tstart.setYear(date.getYear());
var tstop = new Date(row[16]);
tstop.setDate(date.getDate());
tstop.setMonth(date.getMonth());
tstop.setYear(date.getYear());
var id = row[17]; // Sixth column == eventId
// Check if event already exists, update it if it does
try {
var event = cal.getEventSeriesById(id);
}
catch (e) {
// do nothing - we just want to avoid the exception when event doesn't exist
}
if (!event) {
//cal.createEvent(title, new Date("March 3, 2010 08:00:00"), new Date("March 3, 2010 09:00:00"));
var newEvent = cal.createEvent(title, tstart, tstop).addEmailReminder(5).getId();
row[17] = newEvent; // Update the data array with event ID
}
else {
event.setTitle(title);
}
if(new Date().getTime()-startTime > 240000){ // if > 4 minutes
var processed = i+1;// save usefull variable
PropertiesService.getScriptProperties().setProperties({'itemsprocessed':processed});
range.setValues(data);
MailApp.sendEmail(Session.getEffectiveUser().getEmail(),'progress sheet to cal','item processed : '+processed);
return;
}
debugger;
}
// Record all event IDs to spreadsheet
range.setValues(data);
}
/**
* Export events from spreadsheet to calendar
*/
function exportDocs() {
// check if the script runs for the first time or not,
// if so, create the trigger and PropertiesService.getScriptProperties() the script will use
// a start index and a total counter for processed items
// else continue the task
if(PropertiesService.getScriptProperties().getKeys().length==0){
PropertiesService.getScriptProperties().setProperties({'itemsprocessed':0});
ScriptApp.newTrigger('exportDocs').timeBased().everyMinutes(5).create();
}
// initialize all variables when we start a new task, "notFinished" is the main loop condition
var itemsProcessed = Number(PropertiesService.getScriptProperties().getProperty('itemsprocessed'));
var startTime = new Date().getTime();
var sheet = SpreadsheetApp.getActiveSheet();
var headerRows = 4; // Number of rows of header info (to skip)
var range = sheet.getDataRange();
var data = range.getValues();
var calId = "flightcentre.com.au_pma5g2rd5cft4lird345j7pke8#group.calendar.google.com";
var cal = CalendarApp.getCalendarById(calId);
for (i in data) {
if (i < headerRows) continue; // Skip header row(s)
var row = data[i];
var date = new Date(row[13]); // First column
var title = row[19]; // Second column
var tstart = new Date(row[15]);
tstart.setDate(date.getDate());
tstart.setMonth(date.getMonth());
tstart.setYear(date.getYear());
var tstop = new Date(row[16]);
tstop.setDate(date.getDate());
tstop.setMonth(date.getMonth());
tstop.setYear(date.getYear());
var id = row[20]; // Sixth column == eventId
// Check if event already exists, update it if it does
try {
var event = cal.getEventSeriesById(id);
}
catch (e) {
// do nothing - we just want to avoid the exception when event doesn't exist
}
if (!event) {
//cal.createEvent(title, new Date("March 3, 2010 08:00:00"), new Date("March 3, 2010 09:00:00"));
var newEvent = cal.createEvent(title, tstart, tstop).addEmailReminder(5).getId();
row[20] = newEvent; // Update the data array with event ID
}
else {
event.setTitle(title);
}
if(new Date().getTime()-startTime > 240000){ // if > 4 minutes
var processed = i+1;// save usefull variable
PropertiesService.getScriptProperties().setProperties({'itemsprocessed':processed});
range.setValues(data);
MailApp.sendEmail(Session.getEffectiveUser().getEmail(),'progress sheet to cal','item processed : '+processed);
return;
}
debugger;
}
// Record all event IDs to spreadsheet
range.setValues(data);
}
You have to ways to solve that problem.
First possibility : update your sheet with array data only on columns that have no formulas, proceeding as in this other post but in your case (with multiple columns to skip) it will rapidly become tricky
Second possibility : (the one I would personally choose because I 'm not a "formula fan") is to do what your formulas do in the script itself, ie translate the formulas into array level operations.
following your example =if(E4="","",E4+1) would become something like data[n][4]=data[n][4]==''?'':data[n+1][4]; if I understood the logic (but I'm not so sure...).
EDIT
There is actually a third solution that is even simpler (go figure why I didn't think about it in the first place...) You could save the ranges that have formulas, for example if col M has formulas you want to keep use :
var formulM = sheet.getRange('G1:G').getFormulas();
and then, at the end of the function (after the global setValues()) rewrite the formulas using :
sheet.getRange('G1:G').setFormulas(formulM);
to restore all the previous formulas... as simple as that, repeat for every column where you need to keep the formulas.

Resources