Skip to content

Commit

Permalink
feat(generalise): generalise the project to be public
Browse files Browse the repository at this point in the history
- There was nothing special about this script that made it specific
     to Kaluza. It was just a simple script that calculated on-call
     payments for engineers. So I decided to generalise it and make it
     public so that anyone can use it.
  • Loading branch information
lonelydev committed Oct 16, 2024
1 parent 6da61b3 commit 74fbc3e
Show file tree
Hide file tree
Showing 8 changed files with 25 additions and 23 deletions.
2 changes: 2 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{
}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

In some organisations, engineers get compensated for going *on-call outside of working hours*.

I have a couple of teams at Kaluza that I look after. Both with at least 4 people on the rota. Similarly, we have an *incident commander* rota. And every month, managers have to fill in a spreadsheet for payroll to account for our OOH (out of hours) on-call so that we all get compensated at the end of the month for on-call. This sounds like a simple thing, and it is. Just that it takes about 5 minutes of reconciliation per team's on-call rota.
I have a couple of teams at my current workplace that I look after. Both with at least 4 people on the rota. Similarly, we have an *incident commander* rota. And every month, managers have to fill in a spreadsheet for payroll to account for our OOH (out of hours) on-call so that we all get compensated at the end of the month for on-call. This sounds like a simple thing, and it is. Just that it takes about 5 minutes of reconciliation per team's on-call rota.
And if your team is geographically distributed, then you probably have more than one sheet to fill as each location might have a different payroll and could even have different on-call rates and maybe they even get compensated an additional amount every time they respond to an actual incident by the hour! Who knows?!

That is a lot of productive minutes lost doing the same thing every month. 1 manager with two teams, could take 10 minutes. So imagine having 24 of them do this monthly! 240 minutes of doing mundane things for the company when that could have been invested in more useful, creative work, like building the next big thing!
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{
"name": "pagerduty-schedules",
"name": "caloohpay",
"bin": {
"caloohpay": "./dist/src/CalOohPay.js"
},
"version": "1.0.0",
"main": "CalOohPay.js",
"scripts": {
"dev": "tsc -w",
"start": "node dist/src/pgapi.js",
"start": "node dist/src/CalOohPay.js",
"build": "tsc",
"test": "jest",
"prepare": "husky",
Expand Down
4 changes: 2 additions & 2 deletions src/CalOohPay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import yargs from "yargs";
import { OnCallUser } from './OnCallUser';
import { OnCallPeriod } from './OnCallPeriod';
import { FinalSchedule } from './FinalSchedule';
import { KaluzaOnCallPaymentsCalculator } from './KaluzaOnCallPaymentsCalculator';
import { OnCallPaymentsCalculator } from './OnCallPaymentsCalculator';
import { ScheduleEntry } from './ScheduleEntry';
import { CommandLineOptions } from './CommandLineOptions.js';

Expand Down Expand Up @@ -167,7 +167,7 @@ function calOohPay(cliOptions: CommandLineOptions) {
let onCallUsers = extractOnCallUsersFromFinalSchedule(data.schedule.final_schedule);
let listOfOnCallUsers = Object.values(onCallUsers);

let auditableRecords = KaluzaOnCallPaymentsCalculator.getAuditableOnCallPaymentRecords(listOfOnCallUsers);
let auditableRecords = OnCallPaymentsCalculator.getAuditableOnCallPaymentRecords(listOfOnCallUsers);
console.log("User, TotalComp, Mon-Thu, Fri-Sun");

for (const [userId, onCallCompensation] of Object.entries(auditableRecords)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { IOnCallPaymentsCalculator } from "./IOnCallPaymentsCalculator";
import { OnCallCompensation } from "./OnCallCompensation";
import { OnCallUser } from "./OnCallUser";

export class KaluzaOnCallPaymentsCalculator implements IOnCallPaymentsCalculator {
export class OnCallPaymentsCalculator implements IOnCallPaymentsCalculator {
public static WeekDayRate: number = 50;
public static WeekEndRate: number = 75;

Expand All @@ -19,9 +19,9 @@ export class KaluzaOnCallPaymentsCalculator implements IOnCallPaymentsCalculator
* i.e. since is YYYY-MM-DDT00:00:00+01:00 AND until is YYYY-MM-DDT23:59:59+01:00
*/
calculateOnCallPayment(onCallUser: OnCallUser): number {
KaluzaOnCallPaymentsCalculator.validateOnCallUser(onCallUser);
return (onCallUser.getTotalOohWeekDays() * KaluzaOnCallPaymentsCalculator.WeekDayRate) +
(onCallUser.getTotalOohWeekendDays() * KaluzaOnCallPaymentsCalculator.WeekEndRate);
OnCallPaymentsCalculator.validateOnCallUser(onCallUser);
return (onCallUser.getTotalOohWeekDays() * OnCallPaymentsCalculator.WeekDayRate) +
(onCallUser.getTotalOohWeekendDays() * OnCallPaymentsCalculator.WeekEndRate);
}

calculateOnCallPayments(onCallUsers: OnCallUser[]): Record<string, number> {
Expand All @@ -39,12 +39,12 @@ export class KaluzaOnCallPaymentsCalculator implements IOnCallPaymentsCalculator
*/
let onCallCompensations: Record<string, OnCallCompensation> = {};
for (let onCallUser of onCallUsers) {
KaluzaOnCallPaymentsCalculator.validateOnCallUser(onCallUser);
OnCallPaymentsCalculator.validateOnCallUser(onCallUser);
onCallCompensations[onCallUser.id] = {
OnCallUser: onCallUser,
totalCompensation:
(onCallUser.getTotalOohWeekDays() * KaluzaOnCallPaymentsCalculator.WeekDayRate) +
(onCallUser.getTotalOohWeekendDays() * KaluzaOnCallPaymentsCalculator.WeekEndRate)
(onCallUser.getTotalOohWeekDays() * OnCallPaymentsCalculator.WeekDayRate) +
(onCallUser.getTotalOohWeekendDays() * OnCallPaymentsCalculator.WeekEndRate)
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/pgapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {api} from '@pagerduty/pdjs';
import * as dotenv from 'dotenv';
import { OnCallUser } from './OnCallUser';
import { OnCallPeriod } from './OnCallPeriod';
import { KaluzaOnCallPaymentsCalculator } from './KaluzaOnCallPaymentsCalculator';
import { OnCallPaymentsCalculator } from './OnCallPaymentsCalculator';
import { ScheduleEntry } from './ScheduleEntry';
import { FinalSchedule } from './FinalSchedule';

Expand Down Expand Up @@ -47,7 +47,7 @@ pd.get(`/schedules/${incidentCommanderScheduleId}`,
let onCallUsers = extractOnCallUsersFromFinalSchedule(data.schedule.final_schedule);
let listOfOnCallUsers = Object.values(onCallUsers);

let auditableRecords = KaluzaOnCallPaymentsCalculator.getAuditableOnCallPaymentRecords(listOfOnCallUsers);
let auditableRecords = OnCallPaymentsCalculator.getAuditableOnCallPaymentRecords(listOfOnCallUsers);
console.log("User, TotalComp, Mon-Thu, Fri-Sun");

for (const [userId, onCallCompensation] of Object.entries(auditableRecords)) {
Expand Down
14 changes: 7 additions & 7 deletions test/OnCallPaymentCalculator.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {describe, expect, test} from '@jest/globals';
import { KaluzaOnCallPaymentsCalculator } from "../src/KaluzaOnCallPaymentsCalculator";
import { OnCallPaymentsCalculator } from "../src/OnCallPaymentsCalculator";
import { OnCallPeriod } from '../src/OnCallPeriod';
import { OnCallUser } from '../src/OnCallUser';

Expand Down Expand Up @@ -62,7 +62,7 @@ describe('should calculate the payment for an on call user', () => {
]
);

const calculator = new KaluzaOnCallPaymentsCalculator();
const calculator = new OnCallPaymentsCalculator();
expect(onCallUser.onCallPeriods).toBeDefined();
expect(onCallUser.onCallPeriods.length).toBe(1);
expect(onCallUser.onCallPeriods[0].since).toEqual(since);
Expand All @@ -83,7 +83,7 @@ describe('should calculate the payment for an on call user', () => {
]
);

const calculator = new KaluzaOnCallPaymentsCalculator();
const calculator = new OnCallPaymentsCalculator();
expect(onCallUser.onCallPeriods).toBeDefined();
expect(onCallUser.onCallPeriods.length).toBe(1);
expect(onCallUser.onCallPeriods[0].since).toEqual(since);
Expand All @@ -104,7 +104,7 @@ describe('should calculate the payment for an on call user', () => {
]
);

const calculator = new KaluzaOnCallPaymentsCalculator();
const calculator = new OnCallPaymentsCalculator();
expect(onCallUser.onCallPeriods).toBeDefined();
expect(onCallUser.onCallPeriods.length).toBe(1);
expect(onCallUser.onCallPeriods[0].since).toEqual(since);
Expand All @@ -125,7 +125,7 @@ describe('should calculate the payment for an on call user', () => {
]
);

const calculator = new KaluzaOnCallPaymentsCalculator();
const calculator = new OnCallPaymentsCalculator();
expect(onCallUser.onCallPeriods).toBeDefined();
expect(onCallUser.onCallPeriods.length).toBe(1);
expect(onCallUser.onCallPeriods[0].since).toEqual(since);
Expand Down Expand Up @@ -172,7 +172,7 @@ describe('should calculate the payment for an on call user', () => {
)
];

const calculator = new KaluzaOnCallPaymentsCalculator();
const calculator = new OnCallPaymentsCalculator();
expect(calculator.calculateOnCallPayments(onCallUsers)).toStrictEqual({
"1PF7DNAV": 575,
"PGO3DTM": 850,
Expand Down Expand Up @@ -208,7 +208,7 @@ describe('should be able to audit the payment for an on call user', () => {
expect(onCallUsers.length).toBe(2);
expect(onCallUsers[0].id).toBe('1PF7DNAV');
expect(onCallUsers[0].getTotalOohWeekDays()).toBe(4);
const audit = KaluzaOnCallPaymentsCalculator.getAuditableOnCallPaymentRecords(onCallUsers);
const audit = OnCallPaymentsCalculator.getAuditableOnCallPaymentRecords(onCallUsers);
expect(audit['1PF7DNAV'].OnCallUser.getTotalOohWeekDays()).toBe(4);
expect(audit['1PF7DNAV'].OnCallUser.getTotalOohWeekendDays()).toBe(5);
expect(audit['1PF7DNAV'].totalCompensation).toBe(575);
Expand Down

0 comments on commit 74fbc3e

Please sign in to comment.