Skip to content

Instantly share code, notes, and snippets.

@cmcculloh-kr
Forked from scottw-kr/Autofill Oneview Timesheets.md
Last active April 3, 2023 13:23
Show Gist options
  • Save cmcculloh-kr/f5643f9d7a1b03a7bf09a6c1de3d21a6 to your computer and use it in GitHub Desktop.
Save cmcculloh-kr/f5643f9d7a1b03a7bf09a6c1de3d21a6 to your computer and use it in GitHub Desktop.

Auto-fill OneView Timesheets

Forked from Michael Bruno

Install

  1. Download a plugin called Tamper Monkey.
  2. Navigate to http://oneview.kroger.com/
  3. Add a new script.
  4. Paste the script into the function body.

Configure

  1. Update the task list with the tasks you have and the values you'd like to enter for them.
// ==UserScript==
// @name Autofill OneView Timesheet
// @namespace http://tampermonkey.net/
// @version 1.1.3
// @description Help you save some time filling out your timesheet
// @author mbruno-kr, scottw-kr, cmcculloh-kr
// @match http://oneview.kroger.com/niku/nu
// @icon https://www.google.com/s2/favicons?sz=64&domain=kroger.com
// @grant none
// ==/UserScript==
(function () {
("use strict");
const taskTypes = [
{
id: "work",
description: "Analytics Enablement",
guidance: "This is your primary billable category.",
},
{
id: "plan",
description: "OKR Discovery and Ceremonies",
guidance: "Product activities for planning and nuturing the delivery of work.",
},
{
id: "admin",
description: "General Admin",
guidance:
"Reading organizational emails/newsletters, Installing new PC applications/updating PC, On-boarding activities, Resource Manager miscellaneous tasks, Town Halls, Kroger sponsored meetings, Benefits sessions, Company Webinars, 1:1, Interviewing, Quarterly/Annual review, Time spent volunteering during normal business hours (pending manager approval), Time spent performing community service during normal business hours (pending manager approval), United Way, Arts Wave, Jury Duty, Travel between locations during the workday for non-project meetings, Travel time to conferences",
},
{
id: "train",
description: "Non Project Training",
guidance:
"Receiving/Delivering training, Annual training (KnowMe), General skills training (PM, Java), Mentoring, Career development/coaching",
},
{
id: "pto",
description: "PTO/ Vacation/ Approved Absences",
guidance:
"Health & Wellness days, Vacation, Approve Absence, Personal days, Bereavement.",
},
{
id: "hol",
description: "Holiday",
guidance: "Corporate Holidays",
},
];
// Fill in your default week here. "A" will be "Auto" assigned any remaining hours, assuming an 8 hour day.
const defaultWeek = {
work: ["A", "A", "A", "A", "A"],
plan: [1.0, 2.0, 2.0, 2.0, 2.0],
admin: [2.0, 2, 2, 2, 1],
train: [0, 0, 0, 0, 0],
pto: [0, 0, 0, 0, 0],
hol: [0, 0, 0, 0, 0],
};
const expectedOutcome = {
work: [3, 5.5, 5, 4.5, 0],
plan: [5, 1, 0, 3, 1],
admin: [0, 1.5, 1, 0.5, 1.5],
train: [0, 0, 0, 0, 0],
pto: [0, 0, 0, 0, 0],
hol: [0, 0, 0, 0, 6],
};
const appendGuidance = () => {
taskTypes.forEach((taskType) => {
const link = document.querySelector(`a[title*="${taskType.description}"]`);
if (link) {
link.innerHTML += ` - ${taskType.guidance}`;
}
});
}
const totalForDayAcrossCategories = (week, day) => {
let total = 0;
Object.keys(week).forEach((category) => {
console.log("week, category", category, day, week[category][day]);
total += +week[category][day] > 0 ? +week[category][day] : 0;
});
console.log("totalForDayAcrossCategories", total);
return total;
};
const doAutoCalculation = (week) => {
const autoWeek = {};
Object.keys(week).forEach(
(category, i) => {
autoWeek[category] = [];
for (let i = 0; i < week[category].length; i++) {
autoWeek[category][i] =
week[category][i] === "A"
? 8 - totalForDayAcrossCategories(week, i)
: week[category][i];
}
return autoWeek[category];
}
);
return autoWeek;
};
// UNIT TESTS
// console.log("expectedOutcome", expectedOutcome);
// console.assert(compareWeeks(finalizedWeek, expectedOutcome), "Weeks do not match");
// console.assert(totalForDayAcrossCategories(finalizedWeek, 0) === 5, "Total for day 0 is not 5");
// console.assert(false, "This is a test");
// const compareWeeks = (week1, week2) => {
// let result = true;
// Object.keys(week1).forEach((category) => {
// for (let i = 0; i < week1[category].length; i++) {
// if (week1[category][i] !== week2[category][i]) {
// console.log(
// "Weeks do not match at " +
// category +
// " " +
// i +
// " " +
// week1[category][i] +
// " " +
// week2[category][i]
// );
// result = false;
// }
// }
// });
// return result;
// };
function getDays() {
let days = [];
document.querySelectorAll('[data-columnid="day"]').forEach((e) => {
let content = e.innerText;
if (content.length > 0) {
days.push(content.replace(/\n/g, " ").trim().replace(" ", ", "));
}
});
return days;
}
const getCurrentValues = () => {
let days = getDays();
let weekDays = days.slice(1, 6);
// For each weekday, fill each task's values
let weekValues = {};
taskTypes.forEach((task) => {
weekValues[task.id] = [];
});
weekDays.forEach((dayOfWeek) => {
taskTypes.forEach((task) => {
let day = document.querySelector(
`input[alt*='${dayOfWeek}'][title*='${task.description}']`
);
weekValues[task.id].push(day.value);
});
});
console.log('weekValues', weekValues)
return weekValues;
}
const getWeekValues = () => {
const mergedWeek = getCurrentValues();
const finalizedWeek = doAutoCalculation(mergedWeek);
return finalizedWeek;
};
const autoFillWithDefaultValues = () => {
autoFill(defaultWeek);
};
const autoFillWithOverrides = () => {
const weekValues = getWeekValues();
autoFill(weekValues);
};
function autoFill(weekvalues) {
let days = getDays();
let weekDays = days.slice(1, 6);
// For each weekday, fill each task's values
weekDays.forEach((dayOfWeek) => {
taskTypes.forEach((task) => {
let day = document.querySelector(
`input[alt*='${dayOfWeek}'][title*='${task.description}']`
);
if (!day) {
const msg = `Cannot find activity "${task.description}" on ${dayOfWeek}`;
alert(msg);
throw Error(msg);
}
// Add weekvalues value for day & id
const newValueForDay = weekvalues[task.id][weekDays.indexOf(dayOfWeek)];
day.value = newValueForDay;
});
});
// submitForm("page", "timeadmin.saveTimesheet");
}
function addAutofillButton() {
let container = document.querySelector('div[class*="ppm_button_bar"]');
if (!container) {
setTimeout(main, 200);
return;
}
if (isEntryPage()) {
// if there is no button
if (!container.querySelector('button[id="auto-fill"]')) {
let button = document.createElement("button");
button.id = "auto-fill";
button.innerText = "Auto Fill";
button.className = "ppm_button";
button.style = "box-shadow: 0 0 15px 3px rgb(182 148 92, 1);";
button.onclick = autoFillWithOverrides;
container.appendChild(button);
} else {
const input = document.querySelectorAll('input[name="actuals_hours"]')[1];
// if the form is still empty
if (input && input.value === "") {
const xpath = "//button[text()='Auto Fill']";
const matchingElement = document.evaluate(
xpath,
document,
null,
XPathResult.FIRST_ORDERED_NODE_TYPE,
null
).singleNodeValue;
matchingElement.click();
}
}
}
}
const isEntryPage = () => document.querySelectorAll('img[title="Delete"]')[0] !== undefined;
function main() {
const onTimeSheetPage = window.location.hash.indexOf("editTimesheet") !== -1;
if (onTimeSheetPage) {
setTimeout(() => {
console.log("AutoFill Running");
setTimeout(appendGuidance, 100);
setTimeout(addAutofillButton, 100);
// autofill with default values
setTimeout(autoFillWithDefaultValues, 100);
}, 500);
}
}
main();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment