Skip to content

Commit

Permalink
feat(cli): refactor the code to use the KaluzaOnCallPaymentsCalculator
Browse files Browse the repository at this point in the history
- finally a working cli using some default dates.
- TODO: test error response from pagerduty api
- TODO: test CLI with custom date options
- TODO: allow CLI to accept just date in YYYYMMDD format
  - the script automatically creates the time range.
- TODO: add some colour to console output
- TODO: add file generation for output
  • Loading branch information
lonelydev committed Oct 14, 2024
1 parent 7e83cdf commit 1818def
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 47 deletions.
48 changes: 44 additions & 4 deletions src/CalOohPay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import { api } from '@pagerduty/pdjs';
import * as dotenv from 'dotenv';
import { hideBin } from 'yargs/helpers';
import yargs, { Argv, ArgumentsCamelCase } from "yargs";
import { OnCallUser } from './OnCallUser';
import { OnCallPeriod } from './OnCallPeriod';
import { FinalSchedule } from './FinalSchedule';
import { KaluzaOnCallPaymentsCalculator } from './KaluzaOnCallPaymentsCalculator';
import { ScheduleEntry } from './ScheduleEntry';

dotenv.config();

Expand Down Expand Up @@ -87,7 +92,7 @@ const argv: CommandLineOptions = yargsInstance
return true;
}).argv as CommandLineOptions;

calOohPay(argv);
calOohPay(argv);


interface CommandLineOptions {
Expand All @@ -99,14 +104,36 @@ interface CommandLineOptions {
help: boolean;
}

function getOnCallUserFromScheduleEntry(scheduleEntry: ScheduleEntry): OnCallUser {
let onCallPeriod = new OnCallPeriod(scheduleEntry.start, scheduleEntry.end);
let onCallUser = new OnCallUser(
scheduleEntry.user?.id || "",
scheduleEntry.user?.summary || "", [onCallPeriod]);
return onCallUser
}

function extractOnCallUsersFromFinalSchedule(finalSchedule: FinalSchedule): Record<string,OnCallUser> {
let onCallUsers: Record<string,OnCallUser> = {};
if(finalSchedule.rendered_schedule_entries){
finalSchedule.rendered_schedule_entries.forEach(scheduleEntry => {
let onCallUser = getOnCallUserFromScheduleEntry(scheduleEntry);
if(onCallUser.id in onCallUsers){
onCallUsers[onCallUser.id].addOnCallPeriods(onCallUser.onCallPeriods);
} else {
onCallUsers[onCallUser.id] = onCallUser;
}
});
}
return onCallUsers;
}

function calOohPay(cliOptions: CommandLineOptions) {
const pagerDutyApi = api({ token: sanitisedEnvVars.API_TOKEN });
console.log("CLI Options: %s", JSON.stringify(cliOptions));
// invoke the pd api to get schedule data
// invoke the pd api to get schedule data
for (let rotaId of cliOptions.rotaIds.split(',')) {
console.log(`fetching schedule data for rotaId: ${rotaId}`);
pagerDutyApi
console.log(`Fetching schedule data for rotaId: ${rotaId} between ${cliOptions.since} and ${cliOptions.until}`);
pagerDutyApi
.get(`/schedules/${rotaId}`,
{
data: {
Expand All @@ -120,6 +147,19 @@ function calOohPay(cliOptions: CommandLineOptions) {
({ data, resource, response, next }) => {
console.log("Schedule name: %s", data.schedule.name);
console.log("Schedule URL: %s", data.schedule.html_url);
let onCallUsers = extractOnCallUsersFromFinalSchedule(data.schedule.final_schedule);
let listOfOnCallUsers = Object.values(onCallUsers);

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

for (const [userId, onCallCompensation] of Object.entries(auditableRecords)) {
console.log("%s, %d, %d, %d",
onCallCompensation.OnCallUser.name,
onCallCompensation.totalCompensation,
onCallCompensation.OnCallUser.getTotalOohWeekDays(),
onCallCompensation.OnCallUser.getTotalOohWeekendDays());
}
}
).catch(
(error) => {
Expand Down
1 change: 0 additions & 1 deletion src/IOnCallPaymentsCalculator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,4 @@ import { OnCallUser } from "./OnCallUser";
export interface IOnCallPaymentsCalculator {
calculateOnCallPayment(onCallUser: OnCallUser): number;
calculateOnCallPayments(onCallUsers: OnCallUser[]): Record<string, number>;
getAuditableOnCallPaymentRecords(onCallUsers: OnCallUser[]): Record<string, OnCallCompensation>;
}
33 changes: 11 additions & 22 deletions src/KaluzaOnCallPaymentsCalculator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,24 @@ import { IOnCallPaymentsCalculator } from "./IOnCallPaymentsCalculator";
import { OnCallCompensation } from "./OnCallCompensation";
import { OnCallUser } from "./OnCallUser";

function wasPersonOnCallOOH(dateToCheck: Date, onCallUntilDate: Date): boolean {
var dateToCheckEvening = new Date(dateToCheck);
dateToCheckEvening.setHours(18);
return (dateToCheckEvening > dateToCheck && dateToCheckEvening < onCallUntilDate)
}

export function dateDiffInHours(until: Date, since: Date): number {
return Math.round(Math.abs(until.getTime()) - Math.abs(since.getTime())) / (1000 * 60 * 60);
}

function validateOnCallUser(onCallUser: OnCallUser): void {
if (!onCallUser) {
throw new Error("User undefined!");
}
if (!onCallUser.onCallPeriods) {
throw new Error("No on call periods defined!");
}
}

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

static validateOnCallUser(onCallUser: OnCallUser): void {
if (!onCallUser) {
throw new Error("User undefined!");
}
if (!onCallUser.onCallPeriods) {
throw new Error("No on call periods defined!");
}
}
/**
* The calculator works on the assumption that the request was made with full date time format
* 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 {
validateOnCallUser(onCallUser);
KaluzaOnCallPaymentsCalculator.validateOnCallUser(onCallUser);
return (onCallUser.getTotalOohWeekDays() * KaluzaOnCallPaymentsCalculator.WeekDayRate) +
(onCallUser.getTotalOohWeekendDays() * KaluzaOnCallPaymentsCalculator.WeekEndRate);
}
Expand All @@ -43,14 +32,14 @@ export class KaluzaOnCallPaymentsCalculator implements IOnCallPaymentsCalculator
return payments;
}

getAuditableOnCallPaymentRecords(onCallUsers: OnCallUser[]): Record<string, OnCallCompensation> {
static getAuditableOnCallPaymentRecords(onCallUsers: OnCallUser[]): Record<string, OnCallCompensation> {
/**
* for every OnCallUser item, create an OnCallCompensation object
* calculate number of weekdays and weekends that the person was on call
*/
let onCallCompensations: Record<string, OnCallCompensation> = {};
for (let onCallUser of onCallUsers) {
validateOnCallUser(onCallUser);
KaluzaOnCallPaymentsCalculator.validateOnCallUser(onCallUser);
onCallCompensations[onCallUser.id] = {
OnCallUser: onCallUser,
totalCompensation:
Expand Down
3 changes: 1 addition & 2 deletions src/pgapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,9 @@ pd.get(`/schedules/${incidentCommanderScheduleId}`,
console.log("Schedule URL: %s", data.schedule.html_url);

let onCallUsers = extractOnCallUsersFromFinalSchedule(data.schedule.final_schedule);
let kOnCallPaymentsCalculator = new KaluzaOnCallPaymentsCalculator();
let listOfOnCallUsers = Object.values(onCallUsers);

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

for (const [userId, onCallCompensation] of Object.entries(auditableRecords)) {
Expand Down
20 changes: 2 additions & 18 deletions test/OnCallPaymentCalculator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,29 +122,13 @@ describe('should be able to audit the payment for an on call user', () => {
new OnCallPeriod(new Date('2024-08-16T10:00:00+01:00'),
new Date('2024-08-21T10:00:00+01:00'))
]
),
// new OnCallUser(
// 'PINI77A',
// 'EG Oncall',
// [
// new OnCallPeriod(new Date('2024-08-15T00:00:00+01:00'),
// new Date('2024-08-16T10:00:00+01:00'))
// ]
// ),
// new OnCallUser(
// 'PJXZDBT',
// 'CE Oncall',
// [
// new OnCallPeriod(new Date('2024-08-21T10:00:00+01:00'), new Date('2024-08-28T10:00:00+01:00'))
// ]
// )
)
];

const calculator = new KaluzaOnCallPaymentsCalculator();
expect(onCallUsers.length).toBe(2);
expect(onCallUsers[0].id).toBe('1PF7DNAV');
expect(onCallUsers[0].getTotalOohWeekDays()).toBe(4);
const audit = calculator.getAuditableOnCallPaymentRecords(onCallUsers);
const audit = KaluzaOnCallPaymentsCalculator.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 1818def

Please sign in to comment.