[ { "name": "a matter's time in 6-minute units, part units charged in full", "args": [ [ { "feeEarner": "PTN", "minutes": 20 }, { "feeEarner": "AST", "minutes": 61 }, { "feeEarner": "TRN", "minutes": 6 }, { "feeEarner": "PTN", "minutes": 7 } ], [ { "feeEarner": "PTN", "hourlyRate": { "minor": 35000, "currency": "GBP" } }, { "feeEarner": "AST", "hourlyRate": { "minor": 22000, "currency": "GBP" } }, { "feeEarner": "TRN", "hourlyRate": { "minor": 15000, "currency": "GBP" } } ], 6, "up" ], "expect": { "lines": [ { "feeEarner": "PTN", "minutes": 20, "billedMinutes": 24, "units": 4, "hourlyRate": { "minor": 35000, "currency": "GBP" }, "fee": { "minor": 14000, "currency": "GBP" } }, { "feeEarner": "AST", "minutes": 61, "billedMinutes": 66, "units": 11, "hourlyRate": { "minor": 22000, "currency": "GBP" }, "fee": { "minor": 24200, "currency": "GBP" } }, { "feeEarner": "TRN", "minutes": 6, "billedMinutes": 6, "units": 1, "hourlyRate": { "minor": 15000, "currency": "GBP" }, "fee": { "minor": 1500, "currency": "GBP" } }, { "feeEarner": "PTN", "minutes": 7, "billedMinutes": 12, "units": 2, "hourlyRate": { "minor": 35000, "currency": "GBP" }, "fee": { "minor": 7000, "currency": "GBP" } } ], "byFeeEarner": [ { "feeEarner": "PTN", "units": 6, "fee": { "minor": 21000, "currency": "GBP" } }, { "feeEarner": "AST", "units": 11, "fee": { "minor": 24200, "currency": "GBP" } }, { "feeEarner": "TRN", "units": 1, "fee": { "minor": 1500, "currency": "GBP" } } ], "units": 18, "billedMinutes": 108, "total": { "minor": 46700, "currency": "GBP" } } }, { "name": "the same time rounded to the nearest unit", "args": [ [ { "feeEarner": "PTN", "minutes": 20 }, { "feeEarner": "AST", "minutes": 61 }, { "feeEarner": "TRN", "minutes": 6 }, { "feeEarner": "PTN", "minutes": 7 } ], [ { "feeEarner": "PTN", "hourlyRate": { "minor": 35000, "currency": "GBP" } }, { "feeEarner": "AST", "hourlyRate": { "minor": 22000, "currency": "GBP" } }, { "feeEarner": "TRN", "hourlyRate": { "minor": 15000, "currency": "GBP" } } ], 6, "half-up" ], "expect": { "lines": [ { "feeEarner": "PTN", "minutes": 20, "billedMinutes": 18, "units": 3, "hourlyRate": { "minor": 35000, "currency": "GBP" }, "fee": { "minor": 10500, "currency": "GBP" } }, { "feeEarner": "AST", "minutes": 61, "billedMinutes": 60, "units": 10, "hourlyRate": { "minor": 22000, "currency": "GBP" }, "fee": { "minor": 22000, "currency": "GBP" } }, { "feeEarner": "TRN", "minutes": 6, "billedMinutes": 6, "units": 1, "hourlyRate": { "minor": 15000, "currency": "GBP" }, "fee": { "minor": 1500, "currency": "GBP" } }, { "feeEarner": "PTN", "minutes": 7, "billedMinutes": 6, "units": 1, "hourlyRate": { "minor": 35000, "currency": "GBP" }, "fee": { "minor": 3500, "currency": "GBP" } } ], "byFeeEarner": [ { "feeEarner": "PTN", "units": 4, "fee": { "minor": 14000, "currency": "GBP" } }, { "feeEarner": "AST", "units": 10, "fee": { "minor": 22000, "currency": "GBP" } }, { "feeEarner": "TRN", "units": 1, "fee": { "minor": 1500, "currency": "GBP" } } ], "units": 15, "billedMinutes": 90, "total": { "minor": 37500, "currency": "GBP" } } }, { "name": "seven 1-minute emails are seven units, not the two a rounded total gives", "args": [ [ { "feeEarner": "AST", "minutes": 1 }, { "feeEarner": "AST", "minutes": 1 }, { "feeEarner": "AST", "minutes": 1 }, { "feeEarner": "AST", "minutes": 1 }, { "feeEarner": "AST", "minutes": 1 }, { "feeEarner": "AST", "minutes": 1 }, { "feeEarner": "AST", "minutes": 1 } ], [ { "feeEarner": "PTN", "hourlyRate": { "minor": 35000, "currency": "GBP" } }, { "feeEarner": "AST", "hourlyRate": { "minor": 22000, "currency": "GBP" } }, { "feeEarner": "TRN", "hourlyRate": { "minor": 15000, "currency": "GBP" } } ], 6, "up" ], "expect": { "lines": [ { "feeEarner": "AST", "minutes": 1, "billedMinutes": 6, "units": 1, "hourlyRate": { "minor": 22000, "currency": "GBP" }, "fee": { "minor": 2200, "currency": "GBP" } }, { "feeEarner": "AST", "minutes": 1, "billedMinutes": 6, "units": 1, "hourlyRate": { "minor": 22000, "currency": "GBP" }, "fee": { "minor": 2200, "currency": "GBP" } }, { "feeEarner": "AST", "minutes": 1, "billedMinutes": 6, "units": 1, "hourlyRate": { "minor": 22000, "currency": "GBP" }, "fee": { "minor": 2200, "currency": "GBP" } }, { "feeEarner": "AST", "minutes": 1, "billedMinutes": 6, "units": 1, "hourlyRate": { "minor": 22000, "currency": "GBP" }, "fee": { "minor": 2200, "currency": "GBP" } }, { "feeEarner": "AST", "minutes": 1, "billedMinutes": 6, "units": 1, "hourlyRate": { "minor": 22000, "currency": "GBP" }, "fee": { "minor": 2200, "currency": "GBP" } }, { "feeEarner": "AST", "minutes": 1, "billedMinutes": 6, "units": 1, "hourlyRate": { "minor": 22000, "currency": "GBP" }, "fee": { "minor": 2200, "currency": "GBP" } }, { "feeEarner": "AST", "minutes": 1, "billedMinutes": 6, "units": 1, "hourlyRate": { "minor": 22000, "currency": "GBP" }, "fee": { "minor": 2200, "currency": "GBP" } } ], "byFeeEarner": [ { "feeEarner": "AST", "units": 7, "fee": { "minor": 15400, "currency": "GBP" } } ], "units": 7, "billedMinutes": 42, "total": { "minor": 15400, "currency": "GBP" } } }, { "name": "quarter-hour units", "args": [ [ { "feeEarner": "PTN", "minutes": 16 }, { "feeEarner": "PTN", "minutes": 45 } ], [ { "feeEarner": "PTN", "hourlyRate": { "minor": 35000, "currency": "GBP" } }, { "feeEarner": "AST", "hourlyRate": { "minor": 22000, "currency": "GBP" } }, { "feeEarner": "TRN", "hourlyRate": { "minor": 15000, "currency": "GBP" } } ], 15, "up" ], "expect": { "lines": [ { "feeEarner": "PTN", "minutes": 16, "billedMinutes": 30, "units": 2, "hourlyRate": { "minor": 35000, "currency": "GBP" }, "fee": { "minor": 17500, "currency": "GBP" } }, { "feeEarner": "PTN", "minutes": 45, "billedMinutes": 45, "units": 3, "hourlyRate": { "minor": 35000, "currency": "GBP" }, "fee": { "minor": 26250, "currency": "GBP" } } ], "byFeeEarner": [ { "feeEarner": "PTN", "units": 5, "fee": { "minor": 43750, "currency": "GBP" } } ], "units": 5, "billedMinutes": 75, "total": { "minor": 43750, "currency": "GBP" } } }, { "name": "a unit at an odd hourly rate rounds half-up to the penny: 177.77 an hour is 17.78 a unit", "args": [ [ { "feeEarner": "CON", "minutes": 6 }, { "feeEarner": "CON", "minutes": 5 } ], [ { "feeEarner": "CON", "hourlyRate": { "minor": 17777, "currency": "GBP" } } ], 6, "up" ], "expect": { "lines": [ { "feeEarner": "CON", "minutes": 6, "billedMinutes": 6, "units": 1, "hourlyRate": { "minor": 17777, "currency": "GBP" }, "fee": { "minor": 1778, "currency": "GBP" } }, { "feeEarner": "CON", "minutes": 5, "billedMinutes": 6, "units": 1, "hourlyRate": { "minor": 17777, "currency": "GBP" }, "fee": { "minor": 1778, "currency": "GBP" } } ], "byFeeEarner": [ { "feeEarner": "CON", "units": 2, "fee": { "minor": 3556, "currency": "GBP" } } ], "units": 2, "billedMinutes": 12, "total": { "minor": 3556, "currency": "GBP" } } }, { "name": "a zero-minute entry is kept as a nil line", "args": [ [ { "feeEarner": "TRN", "minutes": 0 } ], [ { "feeEarner": "PTN", "hourlyRate": { "minor": 35000, "currency": "GBP" } }, { "feeEarner": "AST", "hourlyRate": { "minor": 22000, "currency": "GBP" } }, { "feeEarner": "TRN", "hourlyRate": { "minor": 15000, "currency": "GBP" } } ], 6, "up" ], "expect": { "lines": [ { "feeEarner": "TRN", "minutes": 0, "billedMinutes": 0, "units": 0, "hourlyRate": { "minor": 15000, "currency": "GBP" }, "fee": { "minor": 0, "currency": "GBP" } } ], "byFeeEarner": [ { "feeEarner": "TRN", "units": 0, "fee": { "minor": 0, "currency": "GBP" } } ], "units": 0, "billedMinutes": 0, "total": { "minor": 0, "currency": "GBP" } } }, { "name": "no entries bill nothing, in the rate card's currency", "args": [ [], [ { "feeEarner": "PTN", "hourlyRate": { "minor": 40000, "currency": "EUR" } } ], 6, "up" ], "expect": { "lines": [], "byFeeEarner": [], "units": 0, "billedMinutes": 0, "total": { "minor": 0, "currency": "EUR" } } }, { "name": "a fee earner's summary follows their first entry", "args": [ [ { "feeEarner": "TRN", "minutes": 12 }, { "feeEarner": "PTN", "minutes": 6 }, { "feeEarner": "TRN", "minutes": 6 } ], [ { "feeEarner": "PTN", "hourlyRate": { "minor": 35000, "currency": "GBP" } }, { "feeEarner": "AST", "hourlyRate": { "minor": 22000, "currency": "GBP" } }, { "feeEarner": "TRN", "hourlyRate": { "minor": 15000, "currency": "GBP" } } ], 6, "up" ], "expect": { "lines": [ { "feeEarner": "TRN", "minutes": 12, "billedMinutes": 12, "units": 2, "hourlyRate": { "minor": 15000, "currency": "GBP" }, "fee": { "minor": 3000, "currency": "GBP" } }, { "feeEarner": "PTN", "minutes": 6, "billedMinutes": 6, "units": 1, "hourlyRate": { "minor": 35000, "currency": "GBP" }, "fee": { "minor": 3500, "currency": "GBP" } }, { "feeEarner": "TRN", "minutes": 6, "billedMinutes": 6, "units": 1, "hourlyRate": { "minor": 15000, "currency": "GBP" }, "fee": { "minor": 1500, "currency": "GBP" } } ], "byFeeEarner": [ { "feeEarner": "TRN", "units": 3, "fee": { "minor": 4500, "currency": "GBP" } }, { "feeEarner": "PTN", "units": 1, "fee": { "minor": 3500, "currency": "GBP" } } ], "units": 4, "billedMinutes": 24, "total": { "minor": 8000, "currency": "GBP" } } }, { "name": "an entry whose fee earner has no rate is an error", "args": [ [ { "feeEarner": "XYZ", "minutes": 6 } ], [ { "feeEarner": "PTN", "hourlyRate": { "minor": 35000, "currency": "GBP" } }, { "feeEarner": "AST", "hourlyRate": { "minor": 22000, "currency": "GBP" } }, { "feeEarner": "TRN", "hourlyRate": { "minor": 15000, "currency": "GBP" } } ], 6, "up" ], "expectError": "no rate for fee earner \"XYZ\"" }, { "name": "an empty rate card is an error", "args": [ [], [], 6, "up" ], "expectError": "rates must not be empty" }, { "name": "a fee earner twice on the rate card is an error", "args": [ [], [ { "feeEarner": "PTN", "hourlyRate": { "minor": 1, "currency": "GBP" } }, { "feeEarner": "PTN", "hourlyRate": { "minor": 2, "currency": "GBP" } } ], 6, "up" ], "expectError": "duplicate rate for fee earner \"PTN\"" }, { "name": "a rate card in two currencies is an error", "args": [ [], [ { "feeEarner": "PTN", "hourlyRate": { "minor": 1, "currency": "GBP" } }, { "feeEarner": "AST", "hourlyRate": { "minor": 2, "currency": "EUR" } } ], 6, "up" ], "expectError": "currency mismatch" }, { "name": "a negative hourly rate is an error", "args": [ [], [ { "feeEarner": "PTN", "hourlyRate": { "minor": -1, "currency": "GBP" } } ], 6, "up" ], "expectError": "hourly rates must not be negative" }, { "name": "negative minutes are an error", "args": [ [ { "feeEarner": "PTN", "minutes": -6 } ], [ { "feeEarner": "PTN", "hourlyRate": { "minor": 35000, "currency": "GBP" } }, { "feeEarner": "AST", "hourlyRate": { "minor": 22000, "currency": "GBP" } }, { "feeEarner": "TRN", "hourlyRate": { "minor": 15000, "currency": "GBP" } } ], 6, "up" ], "expectError": "minutes must be a non-negative integer" }, { "name": "a zero-minute unit is an error", "args": [ [ { "feeEarner": "PTN", "minutes": 6 } ], [ { "feeEarner": "PTN", "hourlyRate": { "minor": 35000, "currency": "GBP" } }, { "feeEarner": "AST", "hourlyRate": { "minor": 22000, "currency": "GBP" } }, { "feeEarner": "TRN", "hourlyRate": { "minor": 15000, "currency": "GBP" } } ], 0, "up" ], "expectError": "increment must be a positive integer" } ]