I am writing a function that will search a spreadsheet for days an employee has worked hours, create an array with the values for job number, job name, employee name, hours, and date, and then put them onto another spreadsheet. It also only shows hours that were within the past 8 days so that time can be worked out for the week when we have to report hours (I'm scheduling it to run the day time is due). I also have been filtering out days with blank hours, which limits the amount of data that gets copied over.
I am encountering an issue where on one employee the function to skip the blank hours does not work. For other employees I have been able to use "" to indicate an empty cell. I have also tried to use (null) as a value, but that only ignores 6 of 7 days (It still logs days with no hours that are adjacent to cells that calculate hours in the week).
What I can't figure out is why this doesn't work on just one sheet out of the whole Google Sheets document. I have simplified my spreadsheet to reduce personal information, and to make it easier to parse the script, but in my original document I track 6 employees with similar code, and only one is showing this issue.
https://docs.google.com/spreadsheets/d/1ve0EPVQJ2vmWG1NYHMncw1ZljP3yXd28dMeNC38Jiy4/edit?usp=sharing
Is a link to the spreadsheet. Code is below.
function shoptime(){
var ss = SpreadsheetApp.getActive().getId();
var stephensheet = Sheets.Spreadsheets.Values.get(ss, 'Stephen!A2:G');
var tiffanysheet = Sheets.Spreadsheets.Values.get(ss, 'Tiffany!A2:G');
var scripts = SpreadsheetApp.getActive().getSheetByName("Scripts");
var currentDate = new Date();
var pastweek = new Date();
pastweek.setDate(currentDate.getDate() -8);
var array=[];
for (var a = 0; a < stephensheet.values.length; a++){
var jobdate = stephensheet.values[a][1];
var intime = stephensheet.values[a][2];
var outtime = stephensheet.values[a][3];
var dailyhours = stephensheet.values[a][4];
if (new Date(jobdate) > pastweek){
if (dailyhours != (null)){
array.push(["NA","Office","Stephen",dailyhours,jobdate]);
}
}
}
for (var a = 0; a < tiffanysheet.values.length; a++){
var jobdate = tiffanysheet.values[a][1];
var intime = tiffanysheet.values[a][2];
var outtime = tiffanysheet.values[a][3];
var dailyhours = tiffanysheet.values[a][4];
if (new Date(jobdate) > pastweek){
if (dailyhours != ("")){
array.push(["NA","Office","Tiffany",dailyhours,jobdate]);
}
}
}
if(array[0]){
scripts.getRange(scripts.getLastRow()+1,1,array.length,5).setValues(array);
}
SpreadsheetApp.flush();
}
I'm not sure of the exact issue but checking for cells that have a value rather than cells that are not null should work for you.
function shoptime(){
var ss = SpreadsheetApp.getActive().getId();
var stephensheet = Sheets.Spreadsheets.Values.get(ss, 'Stephen!A2:G');
var tiffanysheet = Sheets.Spreadsheets.Values.get(ss, 'Tiffany!A2:G');
var scripts = SpreadsheetApp.getActive().getSheetByName("Scripts");
var currentDate = new Date();
var pastweek = new Date();
pastweek.setDate(currentDate.getDate() -8);
var array=[];
for (var a = 0; a < stephensheet.values.length; a++){
var jobdate = stephensheet.values[a][1];
var intime = stephensheet.values[a][2];
var outtime = stephensheet.values[a][3];
var dailyhours = stephensheet.values[a][4];
if (new Date(jobdate) > pastweek){
if (dailyhours){
array.push(["NA","Office","Stephen",dailyhours,jobdate]);
}
}
}
for (var a = 0; a < tiffanysheet.values.length; a++){
var jobdate = tiffanysheet.values[a][1];
var intime = tiffanysheet.values[a][2];
var outtime = tiffanysheet.values[a][3];
var dailyhours = tiffanysheet.values[a][4];
if (new Date(jobdate) > pastweek){
if (dailyhours){
array.push(["NA","Office","Tiffany",dailyhours,jobdate]);
}
}
}
if(array[0]){
scripts.getRange(scripts.getLastRow()+1,1,array.length,5).setValues(array);
}
SpreadsheetApp.flush();
}
And to modify the code to use the built-in service with is much more straight forward in this case;
function shoptime(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var stephensheet = ss.getSheetByName('Stephen').getDataRange().getValues();
var tiffanysheet = ss.getSheetByName('Tiffany').getDataRange().getValues();
var scripts = ss.getSheetByName("Scripts");
var currentDate = new Date();
var pastweek = new Date();
pastweek.setDate(currentDate.getDate() -8);
var array=[];
for (var a = 0; a < stephensheet.length; a++){
var jobdate = stephensheet[a][1];
var intime = stephensheet[a][2];
var outtime = stephensheet[a][3];
var dailyhours = stephensheet[a][4];
if (new Date(jobdate) > pastweek){
if (dailyhours != ""){
array.push(["NA","Office","Stephen",dailyhours,jobdate]);
}
}
}
for (var a = 0; a < tiffanysheet.length; a++){
var jobdate = tiffanysheet[a][1];
var intime = tiffanysheet[a][2];
var outtime = tiffanysheet[a][3];
var dailyhours = tiffanysheet[a][4];
if (new Date(jobdate) > pastweek){
if (dailyhours != ""){
array.push(["NA","Office","Tiffany",dailyhours,jobdate]);
}
}
}
if(array[0]){
scripts.getRange(scripts.getLastRow()+1,1,array.length,5).setValues(array);
}
SpreadsheetApp.flush();
}
Finally, if you are scraping data from 6 sheets in the exact same format then a another loop and an array of the sheet names will save on repetition of code
function shoptime() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheets = ['Stephen', 'Tiffany'] // add the aditional sheet names here
var scripts = SpreadsheetApp.getActive().getSheetByName("Scripts");
var currentDate = new Date();
var pastweek = new Date();
pastweek.setDate(currentDate.getDate() - 8);
var array = [];
for (var i = 0; i < sheets.length; i++) {
var sheet = ss.getSheetByName(sheets[i]);
var data = sheet.getDataRange().getValues();
for (var a = 0; a < data.length; a++) {
var jobdate = data[a][1];
var intime = data[a][2];
var outtime = data[a][3];
var dailyhours = data[a][4];
if (new Date(jobdate) > pastweek) {
if (dailyhours) {
array.push(["NA", "Office", sheets[i], dailyhours, jobdate]);
}
}
}
}
if (array[0]) {
scripts.getRange(scripts.getLastRow() + 1, 1, array.length, 5).setValues(array);
}
SpreadsheetApp.flush();
}
Related
Trying to replace text + date just by date using regex, but it not works:
function myfunction() {
var SourceFolder = DriveApp.getFolderById("");
var Files = SourceFolder.getFiles()
var body = DocumentApp.getActiveDocument().getBody();
while(Files.hasNext()) {
var file = Files.next();
body.replaceText("Date: \d{2}.\d{2}.\d{4}", "31.10.2020")
}
}
Thanks
In your code, var body = DocumentApp.getActiveDocument().getBody(); is declared outside of the loop, so you always refer to the active document body in your while loop.
You may use
while(Files.hasNext()) {
var file = Files.next();
var doc = DocumentApp.openById(file.getId());
var body = doc.getBody();
body.replaceText("Date: \\d{2}\\.\\d{2}\\.\\d{4}", "31.10.2020")
}
The point here is to use double backslashes in the pattern, and escape the dot chars since otherwise a . matches any char but a line break char.
function replace_text() {
// Get speadshhet with ID
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
// Returns cell with ID (User will insert his or her folder ID in cell B3)
var range = sheet.getRange(3, 2);
var values = range.getDisplayValue();
// Get folder by ID - insert your folder ID
var SourceFolder = DriveApp.getFolderById(values);
// Iterate throw all files in folder
var Files = SourceFolder.getFiles();
while(Files.hasNext()) {
var file = Files.next();
// Get all documents ID
var doc = DocumentApp.openById(file.getId());
// Get text body to replace
var body = doc.getBody();
// Insert header in document + alignment
var header = body.insertParagraph(0, 'TEXT');
header.setAlignment(DocumentApp.HorizontalAlignment.RIGHT)
// Text style
var style = {};
//style[DocumentApp.Attribute.HORIZONTAL_ALIGNMENT] = DocumentApp.HorizontalAlignment.RIGHT;
style[DocumentApp.Attribute.FONT_FAMILY] = 'Arial';
style[DocumentApp.Attribute.FONT_SIZE] = 9;
style[DocumentApp.Attribute.FOREGROUND_COLOR] = '#000000';
body.setAttributes(style)
Logger.log(body)
// Replacing text
body.replaceText("Text", " ");
body.replaceText("Date:\\s*\\d{2}\\.\\d{2}\\.\\d{4}", "31.10.2020")
var paragraphs = body.getParagraphs();
for (var i = 7; i < paragraphs.length; i++) {
var paragraph = paragraphs[i];
paragraph.setAlignment(DocumentApp.Horizontal`enter code here`Alignment.LEFT)
}
}
}
I'm using the below code in order to display a photo in slide show, i need to display: name,job and quote for each person, but actually only photos change on time interval specified ...can anyone help?
var img1 = document.getElementById("img1");
var testname = document.getElementById("testname");
var testjob = document.getElementById("testjob");
var testpa = document.getElementById("testpa");
var currentPos = 0;
var images = ["ch1.jpg", "ch2.jpg", "ch3.jpg"]
var testname = [“John Smith” ,”Jan Rosso”,”Raphael Matthew”]
var testjob = [“Manager” ,”Director”,”Supervisor”]
var testpa = [“I like this company”,”It’s amazing”,”Wondeful atmospher”]
function volgendefoto() {
if (++currentPos >= images.length)
currentPos = 0;
img1.src = images[currentPos];
testname.value = testname[currentPos];
testjob.value = testjob[currentPos];
testpa.value = testpa[currentPos];
}
setInterval(volgendefoto, 3000);
function test(){
document.getElementById('text').value=document.getElementById('testname').value
}
testName and the others may need to be updated via innerHTML
function volgendefoto() {
if (++currentPos >= images.length)
currentPos = 0;
img1.src = images[currentPos];
testname.innerHtml = testname[currentPos];
testjob.innerHtml = testjob[currentPos];
testpa.innerHtml = testpa[currentPos];
}
Someone please help.
I am trying to create a simple script which records button presses in order.
I have:
function P1Buzzer() {
var sheet = SpreadsheetApp.getActiveSheet();
var row = 6;
var col = 1;
var Name = sheet.getRange(row, col).getValue();
var sheet = SpreadsheetApp.getActiveSheet();
var row = 192;
var col = 1;
var AnswerPosition = sheet.getRange(row, col).getValue();
if (AnswerPosition = 1) {
sheet.getRange(199, 1).setValue(Name);
var AnswerPosition = AnswerPosition + 1
sheet.getRange(192, 1).setValue(AnswerPosition);
}
if (AnswerPosition = 2) {
sheet.getRange(200, 1).setValue(Name);
var AnswerPosition = AnswerPosition + 1
sheet.getRange(192, 1).setValue(AnswerPosition);
}
}
The problem I have is that when I run the script it does both the commands, ignoring the if command.
Any ideas?
First, you are setting the value to 1 by using = instead of ==. Second, if it was 1, you add one to it and then check to see if it is 2. I'll bet it is!
if (AnswerPosition == 1) {
sheet.getRange(199, 1).setValue(Name);
var AnswerPosition = AnswerPosition + 1
sheet.getRange(192, 1).setValue(AnswerPosition);
} else if (AnswerPosition == 2) {
...
I have a spreadsheet where there are a large number of sheets detailing information for each "job" the person filling out the sheet can have. To clean this up, I wrote a script to hide or show the sheets based on which jobs they chose on the first page of the sheet - they can choose up to 3.
The script... works, but I've gotten errors saying it's trying to do too much at once and failed. I'm not exactly a great programmer so how to clean this up is, as of yet, fairly beyond me. I'm not looking for the most efficient, I'm just looking for something that works easily enough.
I googled the problem a few times, but a lot of the solutions I saw didn't seem to exactly fit what I was doing, and involved things like arrays and dictionaries?
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet1 = ss.getSheetByName("Character Sheet");
var sheet2 = ss.getSheetByName("Marauder Abilities");
var sheet3 = ss.getSheetByName("Warrior Abilities");
var sheet4 = ss.getSheetByName("Dark Knight");
var sheet5 = ss.getSheetByName("Gladiator");
var sheet6 = ss.getSheetByName("Paladin");
var sheet7 = ss.getSheetByName("Conjurer");
var sheet8 = ss.getSheetByName("White Mage");
var sheet9 = ss.getSheetByName("Arcanist");
var sheet10 = ss.getSheetByName("Scholar");
var sheet11 = ss.getSheetByName("Astrologian");
var sheet12 = ss.getSheetByName("Pugilist");
var sheet13 = ss.getSheetByName("Monk");
var sheet14 = ss.getSheetByName("Lancer");
var sheet15 = ss.getSheetByName("Dragoon");
var sheet16 = ss.getSheetByName("Rogue");
var sheet17 = ss.getSheetByName("Ninja");
var sheet18 = ss.getSheetByName("Samurai");
var sheet19 = ss.getSheetByName("Archer");
var sheet20 = ss.getSheetByName("Bard");
var sheet21 = ss.getSheetByName("Machinist");
var sheet22 = ss.getSheetByName("Summoner");
var sheet23 = ss.getSheetByName("Thaumaturge");
var sheet24 = ss.getSheetByName("Black Mage");
var sheet25 = ss.getSheetByName("Red Mage");
var sheet26 = ss.getSheetByName("Garlean Pureblood");
var cell1 = sheet1.getRange('B5');
var cell2 = sheet1.getRange('C5');
var cell3 = sheet1.getRange('D5');
if (cell1.getValue() != "Marauder"||cell2.getValue() != "Marauder"||cell3.getValue() != "Marauder") {
sheet2.hideSheet();
}
if (cell1.getValue() == "Marauder"||cell2.getValue() == "Marauder"||cell3.getValue() == "Marauder") {
sheet2.showSheet();
}
if (cell1.getValue() != "Warrior"||cell2.getValue() != "Warrior"||cell3.getValue() != "Warrior") {
sheet3.hideSheet();
}
if (cell1.getValue() == "Warrior"||cell2.getValue() == "Warrior"||cell3.getValue() == "Warrior") {
sheet3.showSheet();
}
if (cell1.getValue() != "Dark Knight"||cell2.getValue() != "Dark Knight"||cell3.getValue() != "Dark Knight") {
sheet4.hideSheet();
}
if (cell1.getValue() == "Dark Knight"||cell2.getValue() == "Dark Knight"||cell3.getValue() == "Dark Knight") {
sheet4.showSheet();
}
It goes on from there for all 26 sheets.
Is there an easier way to write this massive thing out?
Could I maybe do
if (cell1.getValue() == "Marauder"||cell2.getValue() == "Marauder"||cell3.getValue() == "Marauder")
{
sheet2.showSheet();
}
else
{
sheet2.hideSheet();
}
I think this does it:
function myFunction() {
var sA=["Marauder Abilities","Warrior Abilities","Dark Knight","Gladiator","Paladin","Conjurer","White Mage","Arcanist","Scholar","Astrologian","Pugilist","Monk","Lancer","Dragoon","Rogue","Ninja","Samurai","Archer","Bard","Machinist","Summoner","Thaumaturge","Black Mage","Red Mage","Garlean Pureblood"];
var cA=["Marauder","Warrior","Dark Knight","Gladiator","Paladin","Conjurer","White Mage","Arcanist","Scholar","Astrologian","Pugilist","Monk","Lancer","Dragoon","Rogue","Ninja","Samurai","Archer","Bard","Machinist","Summoner","Thaumaturge","Black Mage","Red Mage","Garlean Pureblood"];
var ss=SpreadsheetApp.getActive();
var sheet1=ss.getSheetByName("Character Sheet");
var cells=sheet1.getRange('B5:D5').getValues()[0];
var shts=ss.getSheets();
for(var i=0;i<shts.length;i++) {
var index=sA.indexOf(shts[i].getName());
if(index>-1) {
if(cells[0]!=cA[index] || cells[1]!=cA[index] || cells[2]!=cA[index]) {
shts[i].hideSheet();
}
if(cells[0]==cA[index] || cells[1]==cA[index] || cells[2]==cA[index]) {
shts[i].showSheet()
}
}
}
}
I'm using Sharepoint to develop an open issues list for my company that will automatically track if an issue is about to be due or overdue based on the color of the row. I have a way to override the default Sharepoint list features and edit the rows, but I think my date comparisons aren't functioning correctly. Here is my code so far:
SP.SOD.executeFunc("clienttemplates.js", "SPClientTemplates", function() {
SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
OnPostRender: function(ctx) {
var statusColors = {
'Almost Due' : '#FFFF00',
'Overdue' : '#FF0000',
};
var rows = ctx.ListData.Row;
for (var i=0;i<rows.length;i++)
{
var due = rows[i]["Due Date"];
var duedate = new Date(due);
var rowId = GenerateIIDForListItem(ctx, rows[i]);
var row = document.getElementById(rowId);
var today = new Date();
if(duedate <= today) {
var status = 'Overdue';
}
Else if (due.toDateString - today.toDateString <= 7 && due.toDateString - today.toDateString >= 0){
var status = 'Almost Due';
}
row.style.backgroundColor = statusColors[status];
}
}
});
});
I need the row to change red if the issue is past due and the issue to change yellow if the issue is due within one week.
Modified example:
SP.SOD.executeFunc("clienttemplates.js", "SPClientTemplates", function() {
SPClientTemplates.TemplateManager.RegisterTemplateOverrides({
OnPostRender: function(ctx) {
var statusColors = {
'Almost Due' : '#FFFF00',
'Overdue' : '#FF0000',
};
var rows = ctx.ListData.Row;
for (var i=0;i<rows.length;i++)
{
var dueDate = new Date(rows[i]["DueDate"]);
var today = new Date();
var status = null;
if(dueDate <= today) {
status = 'Overdue';
}
else if (daysBetween(today,dueDate) <= 7 && daysBetween(today,dueDate) >= 0){
status = 'Almost Due';
}
if (status != null){
var rowId = GenerateIIDForListItem(ctx, rows[i]);
var row = document.getElementById(rowId);
row.style.backgroundColor = statusColors[status];
}
}
}
});
});
function daysBetween(startDate, endDate) {
var timeDiff = Math.abs(endDate.getTime() - startDate.getTime());
var diffDays = Math.ceil(timeDiff / (1000 * 3600 * 24));
return diffDays;
}
The list of changes:
Fixed some typos like Else keyword
Introduced daysBetween function for getting dates difference in
days
due.toDateString - today.toDateString ...
I suspect that due.toDateString is returning a function definition. If you want your code to actually run that function, you'd want due.toDateString().
That said, since you're trying to do math with these dates, it's best to keep them as datetime objects or numbers rather than convert them to strings. Otherwise your subtraction is going to surprise you with NaN and your comparisons are going to be perpetually false.
If you subtract a date object from another date object in JavaScript, you'll get the difference between the dates in milliseconds. Convert that to days and you'll be good to go!