[
{
"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"
}
]