Fix the bugs in an Express REST API that calculates weekly payroll for a senior citizen staffing agency.
A boutique elder-care staffing agency employs senior citizen part-time workers who receive special payroll treatment. Workers who log more than 20 hours per week earn a 15% "wisdom bonus" on the overtime hours beyond that threshold. Additionally, a local ordinance requires all wage amounts to be rounded to the nearest nickel ($0.05).
The API has been built but contains several bugs that cause incorrect pay calculations, missing validations, and inaccurate batch totals. Your task is to find and fix these bugs so that all tests pass.
-
Overtime Bonus Calculation: When a worker logs more than 20 hours in a week, the first 20 hours are paid at the flat hourly rate (base pay). Only the hours beyond 20 receive the 15% wisdom bonus (bonus pay = overtime_hours × hourly_rate × 1.15). Workers with 20 or fewer hours receive only base pay with no bonus.
-
Minimum Wage Validation: The agency enforces a senior minimum wage of $16.50/hour. Any payroll calculation request with an hourly rate below $16.50 must be rejected with a
400status and a clear error message. The validation logic should be applied before any calculation occurs. -
Nickel Rounding: All gross pay amounts must be rounded to the nearest $0.05 (nickel) per local ordinance. This means standard rounding — $412.37 becomes $412.35, and $412.38 becomes $412.40. Truncation is not acceptable.
-
Batch Total Accuracy: When processing multiple workers in a batch, the reported
total_gross_paymust equal the sum of each individual worker's rounded gross pay, not the sum of unrounded values.
| Field | Type | Description |
|---|---|---|
| worker_name | string | Non-empty string identifying the senior worker (required) |
| hourly_rate | number | Hourly pay rate, must be ≥ 16.50 (required) |
| hours_worked | number | Weekly hours, must be ≥ 0 and ≤ 60 (required) |
| base_pay | number | Computed: min(hours_worked, 20) × hourly_rate |
| bonus_pay | number | Computed: max(hours_worked − 20, 0) × hourly_rate × 1.15 |
| gross_pay | number | Computed: base_pay + bonus_pay, rounded to nearest $0.05 |
POST /payroll/calculate
Body: { "worker_name": "Margaret", "hourly_rate": 20.00, "hours_worked": 25 }
Response (200):
{
"data": {
"worker_name": "Margaret",
"hourly_rate": 20.00,
"hours_worked": 25,
"base_pay": 400.00,
"bonus_pay": 115.00,
"gross_pay": 515.00
}
}
POST /payroll/calculate
Body: { "worker_name": "Harold", "hourly_rate": 15.00, "hours_worked": 10 }
Response (400):
{
"error": "Hourly rate must be at least $16.50 (senior minimum wage)"
}
POST /payroll/batch
Body: {
"workers": [
{ "worker_name": "Margaret", "hourly_rate": 18.75, "hours_worked": 22 },
{ "worker_name": "Gerald", "hourly_rate": 21.30, "hours_worked": 15 }
]
}
Response (200):
{
"data": {
"pay_stubs": [
{
"worker_name": "Margaret",
"hourly_rate": 18.75,
"hours_worked": 22,
"base_pay": 375.00,
"bonus_pay": 43.125,
"gross_pay": 418.15
},
{
"worker_name": "Gerald",
"hourly_rate": 21.30,
"hours_worked": 15,
"base_pay": 319.50,
"bonus_pay": 0,
"gross_pay": 319.50
}
],
"total_gross_pay": 737.65
}
}
GET /payroll/policy
Response (200):
{
"data": {
"senior_minimum_wage": 16.50,
"wisdom_bonus_rate": 0.15,
"overtime_threshold": 20,
"rounding_increment": 0.05
}
}
npm install && npm test
- Handle all edge cases covered in
tests/payroll.test.js - All data is stored in-memory; no database is required
- Pay careful attention to how different parts of the codebase interact
- The application uses Express with standard JSON middleware