Google Sheets - Delete Row After One Year - javascript

I apologise in advance, I'm new at using script with google sheets and after checking for an applicable script for my issue I can't seem to get any of them to work correctly for the sheet I'm working on. Im attempting to replace a paper document that our plant supervisors have for each of their employees. The plant workers have a points based attendance system where infractions drop off one year from the date of infraction.
Ideally the row would delete on its expiration date, thusly removing the points from the employee's total sum. If anyone would care to lend me a hand I would be more than grateful, thanks in advance.

get all values of D1:O13,
check if today > expirDate,
if true, skip the line,
otherwise push the row into result array.
At last, set the results back to the sheet.
function removeExpired() {
const sheet = SpreadsheetApp.getActiveSheet();
const range = sheet.getRange("D1:O13");
const values = range.getValues();
const hearders = values.shift();
const today = new Date().setHours(0,0,0,0);
const results = [hearders];
for (const row of values) {
const expireDate = new Date(row[2]).setHours(0,0,0,0);
const expired = today > expireDate;
if (expired) continue;
results.push(row);
}
range.clear();
sheet.getRange(1,1,results.length,results[0].length).setValues(results);
}

Related

Compare ID columns and update Dates if changed

I have 2 sheets viz., Sht1 & Sht2. I am looping through the ID column in Sht1 and trying to match it with ID column in Sht2. If there is a match, then check if the Date in Sht2 is different than the Date in Sht1. If it is, then update the Date in Sht1 with this new Date.
Sht1:
Sht2:
for e.g.:
From the above screenshots, the Sht1 matching ID's in Sht2 are 10001,10003,10006,10010,10011.
Of these, only 10001,10006,10011 have new Dates. So only for these ID's, these new Dates should get copied to Sht1.
As the Data is large, looping through the ID columns, matching them and then checking if the dates are different and finally updating new dates back to Sht1, is taking a lot of time. Is there an eloquent way to do this without looping and reading/writing to sheet - like picking up the Data in the 2 Sheets as JSON Objects viz., ObjSht1 & ObjSht2, updating the Dates for the matching ID's in ObjSht1, then transferring this JSON Object ObjSht1 to Sht1 in one go?
Edit:
#TheMaster the modified script is :
function myFunction() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sht1 = ss.getSheetByName("Sht1");
const sht2 = ss.getSheetByName("Sht2");
const idMap = sht2.getDataRange().getValues().reduce( (mp,[,id,,date]) => mp.set(id, date), new Map );
console.log(idMap);
const rg1 = sht1.getDataRange();
const values1 = rg1.getValues();
values1.forEach(row => row[2] = idMap.get(row[0]));
rg1.setValues(values1);
}
#TheMaster, This time it replaces the dates in Sht1 with the dates from Sht2 where the ID's match. But it also wipes out the other dates from Sht1 where the ID's do not match.
Also, I think the code is not comparing if dates have changed, but just dumping the dates from Sht2 to Sht1.
See updated Screenshots:
Create a map of {id => date} of the second sheet using reduce
Modify the first sheet values in place using forEach
Sample script:
function datesFromSht2ToSht1() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sht1 = ss.getSheetByName("Sht1");
const sht2 = ss.getSheetByName("Sht2");
const idMap = sht2.getDataRange().getValues().reduce( (mp,[,id,,date]) => mp.set(id, date), new Map );
const rg1 = sht1.getDataRange();
const values1 = rg1.getValues();
values1.forEach(row => row[2] = idMap.get(row[0]) || row[2]);
rg1.setValues(values1);
}

Google Sheets Calendar

I would like some help in pulling certain data from a google form linked to a spreadsheet and set a certain value in the date of a certain employee. For example if he/she marked as Vacation Leave then the letter V will be marked under the Date. I have attached the link to my calendar to give an example, I have tried searching the net and this is my second time posting here.
I started the Code but I am stuck in actually finding the Cell for a certain date and inserting the letter.
https://docs.google.com/spreadsheets/d/1uFTR2_B7T0QBr7fTflByFffmmiszbNj_RaCvLEfYRCA/edit?usp=sharing
function setData(){
//Spreadsheets
var ss = SpreadsheetApp;
var data = ss.getActiveSpreadsheet().getSheetByName("Data");
var calendar = ss.getActiveSpreadsheet().getSheetByName("Calendar");
//Get last row / Individual Cells from Form
var lRow = data.getLastRow();
var lRowData = data.getRange(lRow,1,1,17).getValues();
var approval = data.getRange(lRow,17,1,1).getValue();
var leave = data.getRange(lRow,9,1,1).getValue();
var agentName = data.getRange(lRow, 5,1,1).getValue();
var dateBefore = data.getRange(lRow, 10,1,1).getValue();
var dateAfter = data.getRange(lRow, 11,1,1).getValue();
//Calander Variable Arrays
var allDates = calendar.getRange("LA1:NJ1").getValues();
var allNames = calendar.getRange("A4:A160").getValues();
for(var i = 0; i<allNames.length; i++){
if (approval === "Approved" && allNames[i][0] === agentName){
//Here I need it to insert the dates under the correct name and date with a value of V H S M U T.
};
};
};
You are building a spreadsheet-based Leave Calendar based on information from a form response. Based on your existing Calendar, you are having problems identifying the relevant leave dates, and then filling calendar cells to indicate proposed leave.
The problem is there are no fields in rows 1,2 or 3 of Calendar that have the same date format as the Start Date and End Date fields on Form. As a result, there's no easy way to search for a match of the form data fields.
The solution, in my view, is to change the format of the date fields in rows 2 and 3 and enable a search to be match.
Row 2
the existing format is "d" - day of the month (Numeric)
change the format to match the Form Start/End dates: "d-MMM-yyyy".
the font colour for this field can be used to "hide" these dates, and the column width reduced also.
Row 3
the existing format is "E" - day of the week (Name)
change the format to combine the existing formats of rows #2 and #3 - "E-d"
Aspects of the script
the form data is retrieved as getDisplayValues(). The purpose of this is to get the date as a string to facilitate the search.
Two sets of Calendar data are obtained
1) the dates row (Row#2)
2) the names column (Col #1). The Javascript map method is used to convert names from a 2D array to a 1D array. This creates an array that can be easily searched.
the Javascript indexOf method is used to find the Column match for the start and end dates, and to match the name in the Calendar Column (which yields the Row)
the script loops through the number of days leave to create a temporary array of "V" values.
using the row number and the start and end column numbers, a range can be defined on calendar and then updated from the values in the temporary array.
Presumably your function would be triggered by onFormSubmit(e).
Form data
Calendar - Before
Calendar - After
function so5871726503(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var form = ss.getSheetByName("Form");
var calendar = ss.getSheetByName("Calander");
//get form data
var formdataRange = form.getRange(6,1,1,9);// test data
var formData = formdataRange.getDisplayValues(); // display values to format date as string
//get the employee name, start date and end date
var formName = formData[0][1];
var formSD = formData[0][3];
var formED = formData[0][4];
// Logger.log("DEBUG: name = "+formName+", start date = "+formSD+", end date = "+formED);
//get Calendar variables
var calLR = calendar.getLastRow();
var calLC = calendar.getLastColumn();
var caldateStart = 9;
var calnameStart=4;
// get Calendar dates
var calDateRange = calendar.getRange(2,caldateStart,1,calLC-caldateStart+1);
var calDateValues = calDateRange.getDisplayValues();
// get Calendar names
var calNameRange = calendar.getRange(calnameStart,1,calLR-calnameStart+1);
var calNameValues = calNameRange.getValues();
var calNames = calNameValues.map(function(e){return e[0];});//[[e],[e],[e]]=>[e,e,e]
// there should be some error checking on indexof results = -1 in case there is a mismatch.
// find form start date in calender
var startdateresult = calDateValues[0].indexOf(formSD);
var startdateresultcol = startdateresult+caldateStart;
// Logger.log("DEBUG: start date result = "+startdateresult+", column = "+startdateresultcol);
// find form end date in calender
var enddateresult = calDateValues[0].indexOf(formED);
var enddateresultcol = enddateresult+caldateStart;
// Logger.log("DEBUG: end date result = "+enddateresult+", column = "+enddateresultcol);
// find form name in calender
var nameresult = calNames.indexOf(formName);
var nameresultrow = nameresult+calnameStart;
// Logger.log("DEBUG: name result = "+nameresult+", row = "+nameresultrow)
// calculate number of days leave
var daysleave = enddateresultcol-startdateresultcol+1
// Logger.log("DEBUG: days leave = "+daysleave)
// create array variable to hold leave data
var leave=[];
// loop to create data to fill Calendar
for (i=0;i<daysleave;i++){
leave.push("V");
}
// Logger.log(leave); // DEBUG
// build leave range
var calLeave = calendar.getRange(nameresultrow,startdateresultcol,1,daysleave);
//Logger.log(calLeave.getA1Notation()); //DEBUG
// Update the leave range
calLeave.setValues([leave]);
}

Google Spreadsheet + Apps: Get max value of column, it gives me date format

I'm trying to use HTML and JS to write into a Spreadsheet and I found some useful code to do that. I had to add a column to insert an ID for each entry and I did it like this:
var sheet = SpreadsheetApp.openById("myKey").getSheetByName('Richieste');
var column = 1;
var colArray = sheet.getRange(2, column, sheet.getLastRow()).getValues();
var maxi = Math.max.apply(Math, colArray);
var id = maxi+1;
// set other params
var vals = [id, date, name, surname, serial, eMail, area, text, ans, flag];
var sheetObj = sheet.appendRow(vals);
Now, if I have an empty sheet, it works for the first two entries: the third ID is set such as 02/01/1900 0.00.00 and you can see a screenshot here.
I cannot understand what's going on... do you know something about this?
Thanks a lot for your help!
S.
It is hard to tell from the information you provided, but it looks like your cell format is set to date time, not a number.

Automatically locking a range (column) as each date passes?

I have a sheet that employees will update daily with information about tasks done that day. Each column has a date in the header row (row 3 in this case), and after the end of the following day I want that column to lock so it cannot be edited further except by myself and one other. This is to prevent people from covering up mistakes or accidentally changing or deleting data.
I am looking for a script or something that will accomplish this. This sheet has about 45 tabs and I need the same thing applied to all of them.
My idea is possibly a script that triggers at a certain time based off the date in the header row, so if the date is May 5th 2017, the respective column would lock itself at midnight on the 6th.
A link to a copy of my sheet, minus data is here.
Alternatively, if there is a way to simply lock any cell 24 hours after the most recent data is entered into it, and prevent further editing by everyone except select people, that could work too if the ideal method isn't doable.
Yes, there is a way to do this.
I will briefly describe the solution:
Let's say that the first row has 1:1 contains consecutive dates.
Create function lockColumns which would create new protected range.
Add function lockColumns to time trigger, which triggers every day between 0:01 and 1:00 am.
And now some code:
function lockColumns() {
var ss = SpreadsheetApp.getActive().getSheetByName('Sheet 1')
var range = ss.getRange('1:1').getValues()[0];
var today = new Date();
var todayCol = null;
for (var i=0; i<range.length; i++) {
if (today.isSameDateAs(range[i])) {
todayCol = i;
break;
}
}
var rangeToProtect = ss.getRange(1, todayCol +1, ss.getMaxRows(), 1)
var protection = rangeToProtect.protect().setDescription('Protected range');
// Ensure the current user is an editor before removing others. Otherwise, if the user's edit
// permission comes from a group, the script will throw an exception upon removing the group.
var me = Session.getEffectiveUser();
protection.addEditor(me);
protection.removeEditors(protection.getEditors());
if (protection.canDomainEdit()) {
protection.setDomainEdit(false);
}
protection.addEditor('email#gmail.com'); // second person with edit permissions
}
/*
http://stackoverflow.com/a/4428396/2351523
*/
Date.prototype.isSameDateAs = function(pDate) {
return (
this.getFullYear() === pDate.getFullYear() &&
this.getMonth() === pDate.getMonth() &&
this.getDate() === pDate.getDate()
);
}

Hide all but today's columns on four sheets (Google Spreadsheets script)

Goal: I'm trying to create a behavior tracker for four classes in Google Spreadsheets. The tracker has nine sheets: Class7A, Class7B, Class8A, Class8B, and Mon-Fri summary sheets. The goal was for each ClassXX sheet to have behavior tracking information for an entire week, but for the default view to show only the current day's information.
Attempts: During initial workup (with only the Class7A sheet created), I got this to work using a modification of the script found here (Thank you Jacob Jan Tuinstra!): Optimize Google Script for Hiding Columns
I modified it to check the value in the third row of each column (which held a 1 for Monday, 2 for Tuesday, etc), and if it did not match the numerical equivalent for the day of the week (var d = new Date(); var n = d.getDay();), then it would hide that column. This process was somewhat slow - I'm assuming because of the iterating through each column - but it worked.
Quite excited, I went ahead and added the rest of the sheets, and tried again - but the code as written, seems to affect only the current sheet. I tried modifying it by replacing var sheet = ss.getSheets()[0]; with for script that iterated through the columns, until i>4 (I've since lost that piece of code), with no luck.
Deciding to go back and try adapting the original version of the script to instead explicitly run multiple times for each named sheet, I found the that script no longer seems to work at all. I get various version of "cannot find XX function in sheet" or "cannot find XX function in Range."
Source: A shared version (with student info scrubbed) can be found here: https://docs.google.com/spreadsheets/d/1OMq4a4_Gh_xyNk_IRy-mwJn5Hq36RXmdAzTzx7dGii0/edit?usp=sharing (editing is on).
Stretch Goal: Ultimately, I need to get this to reliably show only the current day's columns (either through preset ranges (same for each sheet), or the 1-5 values), and I need it to do so for all four ClassXX sheets, but not the summary pages (and preferably more quickly than the iterations). If necessary, I can remove the summary pages and set them up externally, but that's not my first preference. I would deeply appreciate any help with this; so far my attempts have seemed to only take me backwards.
Thanks!
Current code:
function onOpen() {
// get active spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// create menu
var menu = [
{name: "Show Today Only", functionName: "hideColumn"},
{name: "Show All Days", functionName: "showColumn"},
{name: "Clear Week - WARNING will delete all data", functionName: "clearWeek"}
];
// add to menu
ss.addMenu("Show Days", menu);
}
var d = new Date();
var n = d.getDay();
function hideColumn() {
// get active spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// get first sheet
var sheet = ss.getSheets()[0];
// get data
var data = sheet.getDataRange();
// get number of columns
var lastCol = data.getLastColumn()+1;
Logger.log(lastCol);
// itterate through columns
for(var i=1; i<lastCol; i++) {
if(data.getCell(2, i).getValue() != n) {
sheet.hideColumns(i);
}
}
}
function showColumn() {
// get active spreadsheet
var ss = SpreadsheetApp.getActiveSpreadsheet();
// get first sheet
var sheet = ss.getSheets()[0];
// get data
var data = sheet.getDataRange();
// get number of columns
var lastCol = data.getLastColumn();
// show all columns
sheet.showColumns(1, lastCol);
}
I cannot recreate the problem of the script not working at all, it's working fine for Class7A so that part is working fine.
So let's look at the two other problems:
Applying this to all Sheets
Speeding up the script
First let's create some globals we use in both functions
var d = new Date();
var n = d.getDay();
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetNames = ss.getSheets().map(function(sheet) {return sheet.getName();});
var classSheets = sheetNames.filter(function(sheetName) {return sheetName.match("Class")});
Now we can iterate over classSheets and get the sheet by name and hide columns in each.
However hiding each individual column is very slow.
The sheet is built very structured, every week has 12 columns (except for friday which doesn't have the grey bar), so we can just calculate the ranges we want to hide.
function hideColumn() {
classSheets.map(function(sheetName){
var sheet = ss.getSheetByName(sheetName);
if (n == 1) {
// Hide everything after the first three columns + Monday
sheet.hideColumns(3 + 11, 12 * 4);
} else if (n == 5) {
// Hide everything to the left except the leftmost three columns
sheet.hideColumns(3, 4 * 12);
} else {
// Hide everything left of the current day
sheet.hideColumns(3, (n - 1) * 12);
// Hide everything after the current day
sheet.hideColumns(3 + n * 12, (5 - n) * 12 - 1);
}
});
}
Lastly we can shorten showColumn
function showColumn() {
classSheets.map(function(sheetName){
var sheet = ss.getSheetByName(sheetName);
var lastCol = sheet.getLastColumn();
sheet.showColumns(1, lastCol);
});
}

Categories