Update staffing management to enhance payroll and hiring functionalities
- Increased the `MonthlyPayrollCap` from 10,000 to 40,000, allowing for greater flexibility in hiring and subject assignments. - Revised payroll calculation logic to ensure that staff members are compensated based on their actual weekly hours, with a minimum payment reflecting one full rate. - Updated documentation to clarify the new payroll structure and its implications for hiring and subject assignments. - Enhanced tests to validate the new payroll cap and ensure proper functionality in staffing scenarios, including the handling of uncovered subjects. - Improved localization strings to reflect changes in staffing and payroll terminology.
This commit is contained in:
@@ -146,6 +146,50 @@ public class TimetablePlannerTests
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The four bans alone allowed a legal but unusable week. Taking the first free slot day by
|
||||
/// day gave a full school 77 lessons on Monday and 16 on Friday, with three foreign-language
|
||||
/// lessons back to back. These are the numbers a timetable is judged by, so they are asserted.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void AWeek_IsSpreadAcrossDaysAndSubjectsDoNotRunInBlocks()
|
||||
{
|
||||
var catalog = Fixtures.Catalog();
|
||||
var map = Fixtures.ClassroomsAndGym(11);
|
||||
var classes = Enumerable.Range(0, 11).Select(index => Fixtures.Class(index, index + 1, 16)).ToArray();
|
||||
var teachers = catalog.Subjects.Values
|
||||
.Where(subject => !subject.Abstract)
|
||||
.SelectMany(subject => Enumerable
|
||||
.Range(0, 3)
|
||||
.Select(copy => Fixtures.Teacher($"t{subject.DefName}{copy}", subject.DefName)))
|
||||
.ToArray();
|
||||
|
||||
var table = TimetablePlanner.Build(catalog, map, classes, teachers);
|
||||
|
||||
var perDay = Enumerable.Range(0, 5).Select(day => table.Lessons.Count(lesson => lesson.Day == day)).ToArray();
|
||||
Assert.All(perDay, count => Assert.True(count > 0, $"a school day is empty: {string.Join("/", perDay)}"));
|
||||
Assert.True(
|
||||
perDay.Max() <= perDay.Min() * 1.5,
|
||||
$"the week is lopsided: {string.Join("/", perDay)}");
|
||||
|
||||
// Spread as evenly as the curriculum allows, not "never twice a day": primary school is
|
||||
// twenty hours over five days, so four a day is the best that exists.
|
||||
foreach (var group in table.Lessons.GroupBy(lesson => (lesson.ClassId, lesson.Subject)))
|
||||
{
|
||||
var bySubjectDay = Enumerable
|
||||
.Range(0, 5)
|
||||
.Select(day => group.Count(lesson => lesson.Day == day))
|
||||
.ToArray();
|
||||
|
||||
// Two, not one: the day order is a preference, and a busy room or teacher can still
|
||||
// push an hour onto a day that already has the subject. Before the fix the same
|
||||
// measurement read 5/5/5/0/0.
|
||||
Assert.True(
|
||||
bySubjectDay.Max() - bySubjectDay.Min() <= 2,
|
||||
$"{group.Key.ClassId} has {group.Key.Subject} bunched into days: {string.Join("/", bySubjectDay)}");
|
||||
}
|
||||
}
|
||||
|
||||
private static string Snapshot(Timetable table) =>
|
||||
string.Join(
|
||||
'\n',
|
||||
|
||||
Reference in New Issue
Block a user