I have the below script which was running but after adding the utilities.sleep and app flush function it isn't. Can anyone see what I did wrong? When the "nameofspreadsheet" runs it takes a few seconds for the script to run and put the correct sheetname in A2, taken from the workbook name. So this means the backup script runs but enters date 01/01/1970 in the archive sheet instead of the date the sheet was used (I make multiple copies maybe months in advance so only need it to backup on the day it is used).
function onOpen() { // This function adds a custom menu to the spreadsheet (Backup to archive) so you can run the script from there.
var ui = SpreadsheetApp.getUi();
ui.createMenu('Backup')
.addItem('Backup','dataBackup')
.addToUi();
}
function nameOfSpreadsheet()
{
var s=SpreadsheetApp.getActive().getName().replace(/(\d{1,2}\.\d{1,2}\.\d{1,2}).*/,
'$1');
return s;
}
function dataBackup() {
var inputSS = SpreadsheetApp.getActiveSpreadsheet();
var archiveSS = SpreadsheetApp.openById('146WU8RghfFqlCpCSX7n6kBAKOyxcpVKt14yhVfvYz-g');
var user = Session.getActiveUser().getEmail();
var sheetNames = ['AM trip', 'PM trip', 'Pool / Beach', 'Night Dive'];
for (var i = 0; i < sheetNames.length; i++) {
var inputSheet = inputSS.getSheetByName(sheetNames[i]);
var archiveSheet = archiveSS.getSheetByName(sheetNames[i]);
var date = inputSheet.getRange('A2').getValue(); // Changed to stop inadvertent cell changes, also made text white so not seen.
var data = inputSheet.getRange('E7:U37').getValues().filter(function(row) { return row[0] !== '' || row[1] !== ''});
for (var x = 0; x < data.length; x++) {
data[x].splice(0, 0, date);
}
var getDate = archiveSheet.getRange(archiveSheet.getLastRow(), 1).getValue();
var maxRowLength = data.reduce(function(length, row) { return Math.max(length, row.length); }, 0);
var date = new Date(date);
if (date.getDate() === "Loading Data...") {
Utilities.sleep(10000);
SpreadsheetApp.flush();
if (getDate.getDate() != date.getDate() || getDate.getMonth() != date.getMonth()) {
if (data.length != 0) {
archiveSheet.insertRowsAfter(archiveSheet.getLastRow(), data.length);
archiveSheet.getRange(archiveSheet.getLastRow() + 1, 1, data.length, maxRowLength).setValues(data);
} else {
archiveSheet.insertRowsAfter(archiveSheet.getLastRow(), 1);
archiveSheet.getRange(archiveSheet.getLastRow() + 1, 1, 1, 2).setValues([[date, 'No Data']]);
}
}
}
}
}
date.getDate() === "Loading Data..." always will be false and the true from if will never be executed because just above the script has the following line
var date = new Date(date);
This line assigns a datetime to date that so date.getDate(date) could return an integer if date is a valid argument. By the way, usually it's better to reuse variable names and to use variable names that they spelling / writing is similar to keywords because this could lead certain programmers to be confused.
date.getDate() will never return "Loading Data..." as this string it's not part of the JavaScript specification but it's from Google Sheets.
Considering the above the problem isn't Utilities.sleep().
If you fear that
var date = inputSheet.getRange('A2').getValue();
could return "Loading Data..." the Utilities.sleep(milliseconds) should be included before that line.
Regarding SpreadsheetApp.flush() it should be included after the script made important changes to the spreadsheet. Its place on your code could be at the end of the for block but maybe it could be better to rethink the logic of the OP script.
Related
I have the following script that needs to run at the end of the relevant day, I have tried to get it to run on a timer and I can't work it out. I have 5 sheets which are for different parts of the day to schedule the staff. At the end of the day I need to send it to a master sheet that tallies hours worked and various tasks worked on. My issues are:-
1) I have a blank Google Worksheet with 5 sheets inside it + 1 hidden sheet. This needs to be sent to the master copy on the day of its' name, automatically if possible.
2) They can be made up to 3 months in advance and don't want it sending a blank back up daily.
3) When I press "backup" button on any newly created sheet I have to authorise the script.
Is there any way to not have to authorise the script on the new spreadsheet. Does anyone have a better idea for automating this?
function onOpen() { // This function adds a custom menu to the spreadsheet (Backup to archive) so you can run the script from there.
var ui = SpreadsheetApp.getUi();
ui.createMenu('Backup')
.addItem('Backup','dataBackup')
.addItem('Name','nameOfSpreadsheet')
.addToUi();
}
function nameOfSpreadsheet() {
var s=SpreadsheetApp.getActive().getName().replace(/(\d{1,2}\.\d{1,2}\.\d{1,2}).*/,'$1');
return s;
}
function dataBackup() {
var inputSS = SpreadsheetApp.getActiveSpreadsheet();
var archiveSS = SpreadsheetApp.openById('146WU8RghfFqlCpCSX7n6kBAKOyxcpVKt14yhVfvYz-g');
var user = Session.getActiveUser().getEmail();
var sheetNames = ['AM trip', 'PM trip', 'Pool / Beach', 'Night Dive'];
for (var i = 0; i < sheetNames.length; i++) {
var inputSheet = inputSS.getSheetByName(sheetNames[i]);
var archiveSheet = archiveSS.getSheetByName(sheetNames[i]);
var date = inputSheet.getRange('A2').getValue(); // Changed to stop inadvertent cell changes, also made text white so not seen.
var data = inputSheet.getRange('E7:U37').getValues().filter(function(row) { return row[0] !== '' || row[1] !== ''});
for (var x = 0; x < data.length; x++) {
data[x].splice(0, 0, date);
}
var getDate = archiveSheet.getRange(archiveSheet.getLastRow(), 1).getValue();
var maxRowLength = data.reduce(function(length, row) { return Math.max(length, row.length); }, 0);
var date = new Date(date);
if (date.getDate() === "Loading Data...") {
Utilities.sleep(10000);
SpreadsheetApp.flush();
if (getDate.getDate() != date.getDate() || getDate.getMonth() != date.getMonth()) {
if (data.length != 0) {
archiveSheet.insertRowsAfter(archiveSheet.getLastRow(), data.length);
archiveSheet.getRange(archiveSheet.getLastRow() + 1, 1, data.length, maxRowLength).setValues(data);
} else {
archiveSheet.insertRowsAfter(archiveSheet.getLastRow(), 1);
archiveSheet.getRange(archiveSheet.getLastRow() + 1, 1, 1, 2).setValues([[date, 'No Data']]);
}}}}}
It doesn't make sense to me to put nameofSpreadsheet in the menu .addItem('Name','nameOfSpreadsheet'). It doesn't accomplish anything because there's no way to see the return.
I took a stab at rewriting your backup function.
function dataBackup()
{
var inputSS = SpreadsheetApp.getActiveSpreadsheet();
var archiveSS = SpreadsheetApp.openById('146WU8RghfFqlCpCSX7n6kBAKOyxcpVKt14yhVfvYz-g');
var sheetNames = ['AM trip', 'PM trip', 'Pool / Beach', 'Night Dive'];
for (var i=0; i<sheetNames.length; i++)
{
var inputSheet = inputSS.getSheetByName(sheetNames[i]);
var archiveSheet = archiveSS.getSheetByName(sheetNames[i]);
var date=new Date(inputSheet.getRange('A2').getValue());
var rng=inputSheet.getRange('E7:U37');
var dataA=rng.getValues();
var data=[];
for(var j=0;i<dataA.length;j++)
{
if(dataA[j][0] && dataA[j][1])
{
data.push([dataA[j].splice(0,0,date)]);
}
}
var dv=archiveSheet.getRange(archiveSheet.getLastRow(), 1).getValue();
date=(typeof(dv)!='undefined')?dv:'No Date Found';
if (data.length>0)
{
archiveSheet.insertRowsAfter(archiveSheet.getLastRow(), data.length);
archiveSheet.getRange(archiveSheet.getLastRow() + 1, 1, data.length, rng.getWidth()+1).setValues(data);
}
else
{
archiveSheet.insertRowsAfter(archiveSheet.getLastRow(), 1);
archiveSheet.getRange(archiveSheet.getLastRow() + 1, 1, 1, 2).setValues([[date, 'No Data']]);
}
}
}
I have an archiving script which is now working as it should (I have included it below). However I would like it to run only at 1 am on the date the sheet is in use for.I make the sheets and name them months in advance and they sit in drive until the day of use (maybe earlier if we get pre bookings) but i don't want them to run the script and archive every night at 2 AM! Is there any way to make the time driven trigger only once? At moment the time driven trigger doesn't copy over when i copy the blank sheet either. Any ideas or a better way of automating this? Thanks.
function dataBackup() {
var inputSS = SpreadsheetApp.getActiveSpreadsheet();
var archiveSS =
SpreadsheetApp.openById('146WU8RghfFqlCpCSX7n6kBAKOyxcpVKt14yhVfvYz-g');
var user = Session.getActiveUser().getEmail();
var sheetNames = ['AM trip', 'PM trip', 'Pool / Beach', 'Night Dive'];
for (var i = 0; i < sheetNames.length; i++) {
var inputSheet = inputSS.getSheetByName(sheetNames[i]);
var archiveSheet = archiveSS.getSheetByName(sheetNames[i]);
var date = inputSheet.getRange('A2').getValue(); // Changed to stop
inadvertent cell changes, also made text white so not seen.
var data =
inputSheet.getRange('E7:U37').getValues().filter(function(row) { return
row[0] !== '' || row[1] !== ''});
for (var x = 0; x < data.length; x++) {
data[x].splice(0, 0, date);
}
var getDate = archiveSheet.getRange(archiveSheet.getLastRow(),
1).getValue();
var maxRowLength = data.reduce(function(length, row) { return
Math.max(length, row.length); }, 0);
var date = new Date(date);
var getDate = new Date(getDate);
if (getDate.getDate() != date.getDate() || getDate.getMonth() !=
date.getMonth()) {
if (data.length != 0) {
archiveSheet.insertRowsAfter(archiveSheet.getLastRow(),
data.length);
archiveSheet.getRange(archiveSheet.getLastRow() + 1, 1,
data.length, maxRowLength).setValues(data);
} else {
archiveSheet.insertRowsAfter(archiveSheet.getLastRow(), 1);
archiveSheet.getRange(archiveSheet.getLastRow() + 1, 1, 1,
2).setValues([[date, 'No Data']]);
}
}
}
}
Set your trigger to only go off once monthly? E.g. Weekly or set date?
As for triggers copying over they won't due to the way Google have made their service. Doesn't take long to set them up.
My spreadsheet for containing the archived information
Sample of daily sheet that needs archiving
I have the code below that is used to insert a menu button so it can be manually backed up at end of day, see below.
When I copy this daily sheet using a script it keeps all the information but I have to authorise every sheet to run script.
My question is can I make the script run without any authorisation or is there another way to automate the sending of the data from 4 of the 6 sheets to the corresponding sheets on the archive sheet?
As it is a collaboration if I am away or off no-one else can authorise the script.
How would YOU handle this?
Thank you in advance.
function onOpen() { // This function adds a custom menu to the spreadsheet (Backup to archive) so you can run the script from there.
var ui = SpreadsheetApp.getUi();
ui.createMenu('Backup')
.addItem('Backup','dataBackup')
.addToUi();
}
function nameOfSpreadsheet() {
var s=SpreadsheetApp.getActive().getName().replace(/(\d{1,2}\.\d{1,2}\.\d{1,2}).*/,'$1');
return s;
}
function dataBackup() {
var inputSS = SpreadsheetApp.getActiveSpreadsheet();
var archiveSS = SpreadsheetApp.openById('146WU8RghfFqlCpCSX7n6kBAKOyxcpVKt14yhVfvYz-g');
var user = Session.getActiveUser().getEmail();
var sheetNames = ['AM trip', 'PM trip', 'Pool / Beach', 'Night Dive'];
for (var i = 0; i < sheetNames.length; i++) {
var inputSheet = inputSS.getSheetByName(sheetNames[i]);
var archiveSheet = archiveSS.getSheetByName(sheetNames[i]);
var date = inputSheet.getRange('A2').getValue(); // Changed to stop inadvertent cell changes, also made text white so not seen.
var data = inputSheet.getRange('E7:U37').getValues().filter(function(row) { return row[0] !== '' || row[1] !== ''});
for (var x = 0; x < data.length; x++) {
data[x].splice(0, 0, date);
}
var getDate = archiveSheet.getRange(archiveSheet.getLastRow(), 1).getValue();
var maxRowLength = data.reduce(function(length, row) { return Math.max(length, row.length); }, 0);
var date = new Date(date);
var getDate = new Date(getDate);
if (getDate.getDate() === "Loading Data...") {
Utilities.sleep(30000);
}
if (getDate.getDate() != date.getDate() || getDate.getMonth() != date.getMonth()) {
if (data.length != 0) {
archiveSheet.insertRowsAfter(archiveSheet.getLastRow(), data.length);
archiveSheet.getRange(archiveSheet.getLastRow() + 1, 1, data.length, maxRowLength).setValues(data);
} else {
archiveSheet.insertRowsAfter(archiveSheet.getLastRow(), 1);
archiveSheet.getRange(archiveSheet.getLastRow() + 1, 1, 1, 2).setValues([[date, 'No Data']]);
}
}
}
}
I have a daily worksheet titled 07.09.17 Thursday, there are 4 sheets inside that I would like to add 07.09.17 (or the day of the sheet) in cell A1? Obviously every day is dated accordingly but when running a back up script I want it to refer to cell A1 as the date to be entered into the archive sheet. I have everything else working except this. I can't us =Now() or =Today() as I make the sheets up to 3 months in advance as we have some bookings that far in advance, also they are not only accessed on that day but many days.However the day of the backup is the date of the sheet.With many staff I don't want to have to trust them to do (ctrl) +; to insert date for each sheet manually.
Thank you for your help.
function onOpen() { // This function adds a custom menu to the spreadsheet (Backup to archive) so you can run the script from there.
var ui = SpreadsheetApp.getUi();
ui.createMenu('Backup to archive')
.addItem('timeStamp','dataBackup')
.addToUi();
}
function timeStamp() {
SpreadsheetApp.getActiveSheet()
var sheetNames = ['AM trip', 'PM trip', 'Pool / Beach', 'Night Dive'];
.setActiveCell()
.setValue(new Date());
}
function dataBackup() {
var inputSS = SpreadsheetApp.getActiveSpreadsheet();
var archiveSS = SpreadsheetApp.openById('146WU8RghfFqlCpCSX7n6kBAKOyxcpVKt14yhVfvYz-g');
var user = Session.getActiveUser().getEmail();
var sheetNames = ['AM trip', 'PM trip', 'Pool / Beach', 'Night Dive'];
for (var i = 0; i < sheetNames.length; i++) {
var inputSheet = inputSS.getSheetByName(sheetNames[i]);
var archiveSheet = archiveSS.getSheetByName(sheetNames[i]);
var date = inputSheet.getRange('A1').getValue();
var data = inputSheet.getRange('E7:U37').getValues().filter(function(row) { return row[0] !== '' || row[1] !== ''});
for (var x = 0; x < data.length; x++) {
data[x].splice(0, 0, date);
}
var getDate = archiveSheet.getRange(archiveSheet.getLastRow(), 1).getValue();
var maxRowLength = data.reduce(function(length, row) { return Math.max(length, row.length); }, 0);
var date = new Date(date);
var getDate = new Date(getDate);
if (getDate.getDate() != date.getDate() || getDate.getMonth() != date.getMonth()) {
if (data.length != 0) {
archiveSheet.insertRowsAfter(archiveSheet.getLastRow(), data.length);
archiveSheet.getRange(archiveSheet.getLastRow() + 1, 1, data.length, maxRowLength).setValues(data);
} else {
archiveSheet.insertRowsAfter(archiveSheet.getLastRow(), 1);
archiveSheet.getRange(archiveSheet.getLastRow() + 1, 1, 1, 2).setValues([[date, 'No Data']]);
}
}
}
}
Assuming that the sheets that you want this in are in the same spreadsheet then all you have to do is go to A1 and enter this =nameOfSpreadsheet() Yes, I know it's customary to capitalize all of the letters but I generally swim against the currents of following customs. You may capitalize all of them if you wish.
function nameOfSpreadsheet()
{
return SpreadsheetApp.getActive().getName();
}
All of course you will have to put the function into a project in your script editor. I keep my custom functions like this in a separate project from other functions.
I didn't pay attention to removing the week day so I find that this will work for that and now you just get the date.
function nameOfSpreadsheet()
{
var s=SpreadsheetApp.getActive().getName().replace(/(\d{1,2}\.\d{1,2}\.\d{1,2}).*/,'$1');
return s;
}
This is the function in the code editor:
And this is how it's deployed:
The title of the spreadsheet is 09.09.17 Saturday
I have an archiving script which is now working as it should, however when backing up I did get correct date from cell A2 in first sheet but in the other 3 sheets I get 01/01/1970 in date stamp column on archive sheet. So I assume I need to pause script to allow new page to load date in A2 from sheet name. I have added a pause in line 33 but now i am getting 01/01/70 in all sheets! I have now let it run overnight and when I checked this am I have 01/0/1970 in ll 4 sheets so I am assuming the delay is either not enough or in the wrong place in the script, can anyone help please?
function onOpen() { // This function adds a custom menu to the
spreadsheet (Backup to archive) so you can run the script from there.
var ui = SpreadsheetApp.getUi();
ui.createMenu('Backup')
.addItem('Backup','dataBackup')
.addToUi();
}
function nameOfSpreadsheet()
{
var s= SpreadsheetApp.getActive().getName().replace(/(\d{1,2}\.\d{1,2}\.\d{1,2}).*/,'$1');
return s;
}
function dataBackup() {
var inputSS = SpreadsheetApp.getActiveSpreadsheet();
var archiveSS =
SpreadsheetApp.openById('146WU8RghfFqlCpCSX7n6kBAKOyxcpVKt14yhVfvYz-g');
var user = Session.getActiveUser().getEmail();
var sheetNames = ['AM trip', 'PM trip', 'Pool / Beach', 'Night Dive'];
for (var i = 0; i < sheetNames.length; i++) {
var inputSheet = inputSS.getSheetByName(sheetNames[i]);
var archiveSheet = archiveSS.getSheetByName(sheetNames[i]);
var date = inputSheet.getRange('A2').getValue(); // Changed to stop
inadvertent cell changes, also made text white so not seen.
var data =
inputSheet.getRange('E7:U37').getValues().filter(function(row) { return
row[0] !== '' || row[1] !== ''});
for (var x = 0; x < data.length; x++) {
data[x].splice(0, 0, date);
}
var getDate = archiveSheet.getRange(archiveSheet.getLastRow(),
1).getValue();
var maxRowLength = data.reduce(function(length, row) { return
Math.max(length, row.length); }, 0);
var date = new Date(date);
var getDate = new Date(getDate);
if (getDate.getDate() === "Loading Data...") {
Utilities.sleep(10000);
}
if (getDate.getDate() != date.getDate() || getDate.getMonth() !=
date.getMonth()) {
if (data.length != 0) {
archiveSheet.insertRowsAfter(archiveSheet.getLastRow(),
data.length);
archiveSheet.getRange(archiveSheet.getLastRow() + 1, 1,
data.length, maxRowLength).setValues(data);
} else {
archiveSheet.insertRowsAfter(archiveSheet.getLastRow(), 1);
archiveSheet.getRange(archiveSheet.getLastRow() + 1, 1, 1,
2).setValues([[date, 'No Data']]);
}
}
}
}