Enhance staffing management with uncovered teacher tracking
- Updated `protocol.md` to clarify the concept of uncovered subjects and the number of additional teachers required. - Introduced `teachersShort` property in the `StaffingSubject` interface to indicate how many more teachers are needed for a subject. - Enhanced localization strings to reflect the new uncovered teacher information in both English and Russian. - Updated the management panel UI to display the number of teachers short for each uncovered subject. - Revised the `Uncovered` method in the staffing logic to return detailed information about uncovered subjects, including the shortfall of teachers. - Added tests to validate the new uncovered teacher tracking functionality and ensure accurate reporting in the staffing API. - Marked related tasks as complete in the documentation for the golden fixtures phase.
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
namespace HSchool.People.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// One line per class and person, sorted, so a generator change shows up as the first
|
||||
/// mismatched line instead of "the snapshots differ".
|
||||
/// </summary>
|
||||
internal static class RosterFingerprint
|
||||
{
|
||||
public static string Format(Roster roster, int seed, string nameSet, string native)
|
||||
{
|
||||
var lines = new List<string>
|
||||
{
|
||||
$"# seed={seed} nameset={nameSet} native={native} people={roster.People.Count} classes={roster.Classes.Count}",
|
||||
};
|
||||
|
||||
foreach (var schoolClass in roster.Classes.OrderBy(row => row.Id, StringComparer.Ordinal))
|
||||
{
|
||||
var pupils = string.Join(',', schoolClass.PupilIds.Order(StringComparer.Ordinal));
|
||||
lines.Add(
|
||||
$"class {schoolClass.Id} year={schoolClass.Year} letter={schoolClass.Letter} room={schoolClass.RoomId} capacity={schoolClass.Capacity} pupils={pupils}");
|
||||
}
|
||||
|
||||
foreach (var person in roster.People.OrderBy(row => row.Id, StringComparer.Ordinal))
|
||||
{
|
||||
lines.Add(PersonLine(person));
|
||||
}
|
||||
|
||||
return string.Join('\n', lines) + '\n';
|
||||
}
|
||||
|
||||
public static void AssertEqual(string expected, string actual)
|
||||
{
|
||||
var left = expected.Replace("\r\n", "\n", StringComparison.Ordinal).Split('\n');
|
||||
var right = actual.Replace("\r\n", "\n", StringComparison.Ordinal).Split('\n');
|
||||
var count = Math.Min(left.Length, right.Length);
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
if (!string.Equals(left[i], right[i], StringComparison.Ordinal))
|
||||
{
|
||||
Assert.Fail($"first mismatch at line {i + 1}\nexpected: {left[i]}\nactual: {right[i]}");
|
||||
}
|
||||
}
|
||||
|
||||
if (left.Length != right.Length)
|
||||
{
|
||||
Assert.Fail($"line count {left.Length} vs {right.Length}");
|
||||
}
|
||||
}
|
||||
|
||||
private static string PersonLine(Person person)
|
||||
{
|
||||
var roles = string.Join(',', Roles(person));
|
||||
var traits = string.Join(',', person.Traits.Order(StringComparer.Ordinal));
|
||||
var skills = string.Join(
|
||||
',',
|
||||
person.Skills.OrderBy(pair => pair.Key, StringComparer.Ordinal).Select(pair => $"{pair.Key}={pair.Value}"));
|
||||
return
|
||||
$"person {person.Id} {person.Name.Full} female={person.Female} roles={roles} class={person.ClassId ?? "-"} born={person.BirthDate:yyyy-MM-dd} traits={traits} skills={skills}";
|
||||
}
|
||||
|
||||
private static IEnumerable<string> Roles(Person person)
|
||||
{
|
||||
if (person.IsStudent)
|
||||
{
|
||||
yield return "student";
|
||||
}
|
||||
|
||||
if (person.IsStaff)
|
||||
{
|
||||
yield return "staff";
|
||||
}
|
||||
|
||||
if (person.IsParent)
|
||||
{
|
||||
yield return "parent";
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user