Need to get permanent timestamps for a Google Sheets Dashboard - google-apps-script

I'm trying to build a dashboard for activities in google sheets, for this i have a page where the students can input the activity name and it status:
Activities page
And i need to get the timestamp for when the activity status has been modified, witch happens in this other page:
dashboard page
Where i'am using the flag to lock the time and date that a get with the now() function.
The problems is: every time the page updates, i lose the timestamp. How can I get it permanently?

You can use Apps Script to achieve your goal:
Use the onEdit
trigger
to check when a certain cell is manually changed.
Check if the cell is from Column Status and get the Row.
Write the TimeStamp in the other Sheet depending on the value of Status
For example:
function onEdit(event){
var editedSheet = event.source.getActiveSheet();
var eRange = event.range;
// If the name is Activities and the column edited is A
if (editedSheet.getName() == "Activities" && eRange.getColumn() == 1){
var sprsheet = SpreadsheetApp.getActiveSpreadsheet();
var dashboard = sprsheet.getSheetByName("Dashboard");
var dshbValues = dashboard.getRange("B1:L1").getValues(); //Values in Dashboard
//Compare the value introduced with the Values in Dashboard
for (var i = 0; i < dshbValues[0].length; i++){
//If they coincide, write the timestamp in the row edited, correspondent column
if (eRange.getValue() == dshbValues[0][i]){
var timestamp = new Date();
dashboard.getRange(eRange.getRow(), i + 2).setValue(timestamp);
}
}
}
}
Take into account that the first time you will need to manually run the script to give the needed permissions. Also, the values in Activities Column C and Dashboard Column A need to be in the same order for coherence purposes.
References:
Range Class
Get Values
Set values
Date()

Related

Edit a column in google sheets based on a condition

I've a Google sheet which contains two columns first is "Status" column and second is "RegDate" column. I want to update values in the "Status" column if Today's date matches with the RegDate column. Here, I am attaching a sample google sheet for reference.
Basically, I want to write an automated script which will run daily at a certain time and check if the date on which script is running matches with the date present in RegDate column then it should change the corresponding values in "Status" column.
For Eg. If the script is running on 3 Aug 2022 then the row where RegDate is 03-08-2022 should be considered and then "Inactive" value in Status column should be updated to "Active".
I do not have any idea how to automate this, as far as I've researched I need to write a Google AppScript for the same and use a time-driven trigger to run the script daily (Correct me if I am wrong here).
I want to know how can I proceed with this code any help on this would be appreciated. Please also mention any threads which can help me in solving this.
Solution:
Create a daily trigger. You can do this manually (following these steps), or programmatically (executing the function installTrigger below once).
The daily trigger will cause a specific function to execute once daily. On this function, iterate through your range, and for each row, check whether column B date is the same one as today. If that's the case, change column A value to Active.
function updateStatus() {
const now = new Date();
const day = now.getDate();
const month = now.getMonth();
const year = now.getFullYear();
const sheet = SpreadsheetApp.getActive().getSheetByName("Sheet1"); // Change according to your preferences
const range = sheet.getRange("A2:B" + sheet.getLastRow());
const updatedVals = range.getValues().map(row => {
const date = row[1];
if (typeof date.getMonth === 'function' && date.getDate() === day && date.getMonth() === month && date.getFullYear() === year) {
row[0] = "Active";
} else {
// row[0] = "Inactive"; // Uncomment if you want to change status from 'Active' to 'Inactive' if date is not today
}
return row;
});
range.setValues(updatedVals);
}
function installTrigger() {
ScriptApp.newTrigger("updateStatus")
.timeBased()
.everyDays(1)
.create();
}
Note:
I'm unsure whether you want to change status from Active to Inactive if the row date is not today (this was not made explicit on your question). If that's the case, uncomment the corresponding line (row[0] = "Inactive") on the sample above.
Reference:
everyDays(n)

Insert the date/time an individual tab was last updated (google sheets)

I have a data dashboard in Google Sheets that synthesizes data from several different data sources. These data sources are dropped into the same Google Sheet file, each on separate tabs. Different team members are responsible for updating each of the individual data tabs, which is done by pulling reports from various programs and pasting the new data into their respective data tab.
Note: I realize this process of pasting in data from reports from different programs is inefficient. Unfortunately the systems we use don't all speak to one another, so this is the best way we've found so far to analyze data across our systems.
The goal: I would like to have a cell on each data tab where it lists the last date and time that individual tab (sheet) was updated. For example, if I update the data on Tab 1, I would like the date/time stamp to update on Tab 1 but not on Tab 2. The date/time stamp on Tab 2 should only update when I add new data to Tab 2.
I have tried the script pasted below (from the Question/Answer linked here), and it does update the date/time on the tab:
function onEdit(e) {
var s = e.source.getActiveSheet();
var sName = s.getName();
var ar = e.range;
var row = ar.getRow();
var arRows = ar.getNumRows()
if( ar.getColumn() == 3 && sName == 'Sheet1') {
s.getRange(row,6,arRows).setValue(new Date()).setNumberFormat("MM/dd/yyyy hh:mm");
}
}
The problem is that it also updates the date/time on Tab 1 when I update the data on Tab 2.
What script do I use so that it updates the date/time on Tab 1 only when the data on Tab 1 is updated? And would update the date/time on Tab 2 when the data on Tab 2 is updated?
Change date cell A1 in every Sheet that is edit by a user
function onEdit(e) {
var sh = e.range.getSheet();
sh.getRange(1,1).setValue(new Date()).setNumberFormat("MM/dd/yyyy hh:mm");
}
If you wish to exclude some sheets:
function onEdit(e) {
const excl = ['Sheet1','Sheet2'];
var sh = e.range.getSheet();
if(~excl.indexOf(sh.getName()))return;//this could allow you to exclude some sheets
sh.getRange(1,1).setValue(new Date()).setNumberFormat("MM/dd/yyyy hh:mm");
}
I chose A1 in this case

Google Sheets - Identify duplicates and overwriting data

I've heavily edited the original question I posted, as i have solved some of the issue myself. I'm now stuck on just one thing.
function payINVOICE() {
var ss = SpreadsheetApp.getActive();
var ds = SpreadsheetApp.openById("14imcEob2qIZbH6AjGYtf16MJxbnfkhQn1ae4jR-Nzq4");
var srcSheet = ss.getSheetByName("INVOICE_ENTRY");
var dstSheet = ds.getSheetByName("INVOICE_ENTRY");
var data_range = srcSheet.getRange('B4:J100');
var data_data = data_range.getValues();
var data_clean = data_data.filter(function (r) {return r[1]});
var clear_range = srcSheet.getRange('B4:I100');
var lr = dstSheet.getLastRow();
dstSheet.getRange(lr+1, 2,data_clean.length,9).setValues(data_clean);
clear_range.clear();
}
This code checks the range B4:J100 for a value in Column B.
If there is a value and the script is run, it copies those rows onto dstSheet.
My role is marking invoices as paid or not.
The dstSheet will already contain the data, which is pulled back into the srcSheet with a query. Column K is not part of the original query.
If I mark a row as "PAID" in column K on the srcSheet, I want the code to take the data_data variable and overwrite what is already in the dstSheet, so that the query then pulls the data back into srcSheet with column J then showing "PAID".
It means I can then change column K to "NOT PAID", run the script again and it will over-write the "PAID".
This makes better sense than my last post and I am so close to achieving what I need, just stuck on this last bit.
If you simply want to monitor the changes between the two mentioned sheets, it would be much easier to use an onEdit(e) trigger which will tell you which cell has been edited.
Snippet
function payINVOICE(e) {
var srcSheet = SpreadsheetApp.getActiveSheet(); //gets the active sheet which is supposed to be source sheet
var dstSheet = SpreadsheetApp.openById('DEST_SHEET_ID').getSheetByName('INVOICE_ENTRY'); //gets the destination sheet
if (e.range.getSheet().getName() == 'INVOICE_ENTRY' && e.range.getColumn() == 11) { //e specifies where the edit has been made - therefore this if condition checks if the edit is in the INVOICE ENTRY sheet and if the column is the K column
var row =e.range.getRow(); //this gathers the row at which the edit has been made
var data = srcSheet.getRange(row, 2, 1, 10).getValues(); //this gathers the data corresponding to the row at which the edit has been made
dstSheet.getRange(row, 2, 1, 10).setValues(data); //this sets the data into the corresponding row in the destination sheet
}
Explanation
The above code uses the onEdit(e) installable trigger and the e event object. In this way, when an edit is being made on the srcSheet on the 11th column (aka K column) and the sheet name is "INVOICE_ENTRY", then the row at which the change has been made is kept in the row variable. Afterwards, the corresponding row of data is kept in the data variable; the getRange(row, 2, 1, 10) references the range for the row at which the change on the K column has been made. In order to update the dstSheet, the data value is set to the according range using setValues(data).
Installing the trigger
To make the payINVOICE(e) function trigger on an edit action, you need to install an onEdit trigger.
This is being done by accessing the project's triggers by clicking this icon:
After that, you just need to create a new trigger by clicking the Add trigger button and create a trigger with the following settings:
Trying the function
In order to try the behavior for this, you just need to make an edit on the srcSheet on the K column and this change will be reflected in the destSheet.
Note
The ranges that have been used in this script are chosen considering the fact that:
K column consists of the PAID/NOT PAID text;
The srcSheet and the dstSheet have the data wanted in the same ranges.
You might need to customize these according to your sheet and add the needed formulas/filters you have mentioned.
Reference
Apps Script Installable Triggers;
Apps Script Event Objects.

Google apps script: reliability issue.. setValue onformsubmit less than consistent

Hopefully this is a reasonably straight forward question.
Firstly, some context information:
I collect information from a form into a google spreadsheet to record entries to cycle races.
I use the onformsubmit trigger to run some code to do the following;
1) I check how many entries I have by rider Grade and compare these to some pre-set limits
2) Based on the pre-set limits, I work out whether the rider's entry is "provisionally entered" or "waitlisted" (I call this EntryType eg EntryType = 'waitlisted')
3) I populate some variables so as to send a confirmation email, quoting back entry details submitted by the user and advise them whether their entry is waitlisted or not.
4) I write the EntryType alongside the form submitted data in the spreadsheet so I have a record of what EntryType each rider was advised by email.
The code works fine apart from one little issue with step 4 above. Most of the time this works fine but if entries come in close together - eg a couple of seconds apart - step 4 may be left blank. The confirmation email will send, the form data will write to the spreadsheet, just that the "EntryType" will not be written to the spreadsheet alongside the form data.
I suspect that the data from the form for the next record coming in takes precedence and the write function fails without erroring? Just a guess.
Could someone offer some suggestions? I believe this code is very close, unfortunately not bullet proof as yet.
Regards, Colin
function onFormSubmit(e) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var oGradeSubmitted = e.values[13];
var oGradeLevelSubmitted = e.values[14];
// Get the Type of Entry Limits to Apply (Handicap, Scratch or None)
var oRangeLT = ss.getRangeByName("oLimitType");
var oLimitType = oRangeLT.getValue();
//== start ===G R A D E L I M I T =================================================================================
if (oLimitType == 'Scratch') {
// Concatenate Generic Range Name & Grade Submitted to get Specific Ranges Names
var oLimitVar = "oLimit" + oGradeSubmitted; //These are now the LOWER waitlist limits
var oLimitUpper = "oLimitUpper" + oGradeSubmitted; //These are the UPPER waitlist limits
var oCountVar = "oCount" + oGradeSubmitted; //The count is based on grade submitted, not handicapping grade so as to not upset waitlist order
// Get Data from Specific Ranges
// 1) Grade Limit Data
//lower waitlist limits
var oRangeLV = ss.getRangeByName(oLimitVar);
var oLimitData = oRangeLV.getValues();
//upper waitlist limits
var oRangeLVU = ss.getRangeByName(oLimitUpper);
var oLimitDataUpper = oRangeLVU.getValues();
// 2) Grade Count Data
var oRangeCV = ss.getRangeByName(oCountVar);
var oCountData = oRangeCV.getValues();
// Write some Data into the same row as the current form submission data
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Form Responses");
var row = sheet.getLastRow();
if (+oCountData >= +oLimitData && +oCountData <= +oLimitDataUpper) {
sheet.getRange(row,18).setValue("Waitlisted");
var oEntryStatus = "Waitlisted";
} else {};
if (+oCountData > +oLimitDataUpper) {
sheet.getRange(row,18).setValue("Waitlisted but doubtful");
var oEntryStatus = "Waitlisted but doubtful";
} else {};
}
}
To get around the concurrency issue you could use the e.range parameter that is passed rather than getLastRow():
var row = e.range.getRow();
https://developers.google.com/apps-script/understanding_events (scroll to bottom)

Google Apps Script copy from cell to new row

I have two sheets in My Google Spreadsheet.
Master Tracking
Daily Tracking
Master Tracking pulls in information from other tracking sheets and updates the number of miles driven by each driver in cell M7.
I want to set up Daily Tracking with Date (Column A) and Number of Miles Traveled (Column B).
I want to write a Google Apps script which will copy the data from Master Tracking!M7 to Daily Tracking (column B) but into a NEW ROW every time the script is run. I'm planning on using a trigger for it to run at the end of every work day.
I have this till now but it doesn't work.
function copyFunction() {
var inputRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Master Tracking").getRange("M7:M7");
var inputValues = inputRange.getValues();
var outputRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Daily Tracking").getRange("B:B").getLastRow();
outputRange.setValue(inputValues);
}
I can't figure it out. I can get it to paste in one specific cell but I can't figure out how to paste it into a new row. Maybe getLastRow would work. I don't know.
Also, how to have a timestamp put in Column A of Daily Tracking?
Please help!
Didn't test it but should work : (see comments in code)
function copyFunction() {
var inputRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Master Tracking").getRange("M7");
var inputValue = inputRange.getValue();// use simple getValue without S, get a simple value
var last = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Daily Tracking").getLastRow();// get the last row on this sheet
var outputRange = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Daily Tracking").getRange(last+1,1,1,2);// getRange col A & B +1 after last row
outputRange.setValues([[Utilities.formatDate(new Date(), Session.getTimeZone(), 'MM-dd-yyyy'),inputValue]]);// date string in col A and value in col B in a 2D array (note the S in setValues) -
}