style: format backend with dotnet format
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,8 +2,8 @@ namespace BigRegister.Domain.Diplomas;
|
||||
|
||||
public enum QuestionType
|
||||
{
|
||||
JaNee,
|
||||
Tekst,
|
||||
JaNee,
|
||||
Tekst,
|
||||
}
|
||||
|
||||
public sealed record PolicyQuestion(string Id, string Vraag, QuestionType Type);
|
||||
|
||||
@@ -8,61 +8,61 @@ namespace BigRegister.Domain.Diplomas;
|
||||
/// </summary>
|
||||
public static class DiplomaRules
|
||||
{
|
||||
// RULE: study program → BIG profession.
|
||||
private static readonly Dictionary<string, string> ProfessionByProgram = new(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
["geneeskunde"] = "Arts",
|
||||
["verpleegkunde"] = "Verpleegkundige",
|
||||
["fysiotherapie"] = "Fysiotherapeut",
|
||||
["farmacie"] = "Apotheker",
|
||||
["tandheelkunde"] = "Tandarts",
|
||||
};
|
||||
// RULE: study program → BIG profession.
|
||||
private static readonly Dictionary<string, string> ProfessionByProgram = new(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
["geneeskunde"] = "Arts",
|
||||
["verpleegkunde"] = "Verpleegkundige",
|
||||
["fysiotherapie"] = "Fysiotherapeut",
|
||||
["farmacie"] = "Apotheker",
|
||||
["tandheelkunde"] = "Tandarts",
|
||||
};
|
||||
|
||||
public static string ProfessionFor(Diploma d) =>
|
||||
ProfessionByProgram.TryGetValue(d.Opleiding, out var beroep) ? beroep : "Onbekend";
|
||||
public static string ProfessionFor(Diploma d) =>
|
||||
ProfessionByProgram.TryGetValue(d.Opleiding, out var beroep) ? beroep : "Onbekend";
|
||||
|
||||
/// <summary>Professions a user may declare for a manual (unlisted) diploma.</summary>
|
||||
public static IReadOnlyList<string> ManualProfessions() =>
|
||||
ProfessionByProgram.Values.Distinct().ToList();
|
||||
/// <summary>Professions a user may declare for a manual (unlisted) diploma.</summary>
|
||||
public static IReadOnlyList<string> ManualProfessions() =>
|
||||
ProfessionByProgram.Values.Distinct().ToList();
|
||||
|
||||
// --- Policy questions (geldigheidsvragen) ---
|
||||
// --- Policy questions (geldigheidsvragen) ---
|
||||
|
||||
private static readonly PolicyQuestion NlTaalEngelstalig = new(
|
||||
"nl-taalvaardigheid",
|
||||
"Uw opleiding was Engelstalig. Beheerst u de Nederlandse taal op het vereiste niveau (B2)?",
|
||||
QuestionType.JaNee);
|
||||
private static readonly PolicyQuestion NlTaalEngelstalig = new(
|
||||
"nl-taalvaardigheid",
|
||||
"Uw opleiding was Engelstalig. Beheerst u de Nederlandse taal op het vereiste niveau (B2)?",
|
||||
QuestionType.JaNee);
|
||||
|
||||
private static readonly PolicyQuestion NlTaalManual = new(
|
||||
"nl-taalvaardigheid",
|
||||
"Beheerst u de Nederlandse taal op het vereiste niveau (B2)?",
|
||||
QuestionType.JaNee);
|
||||
private static readonly PolicyQuestion NlTaalManual = new(
|
||||
"nl-taalvaardigheid",
|
||||
"Beheerst u de Nederlandse taal op het vereiste niveau (B2)?",
|
||||
QuestionType.JaNee);
|
||||
|
||||
private static readonly PolicyQuestion DiplomaErkend = new(
|
||||
"diploma-erkend",
|
||||
"Is uw diploma erkend door de Nederlandse overheid (bijv. via Nuffic)?",
|
||||
QuestionType.JaNee);
|
||||
private static readonly PolicyQuestion DiplomaErkend = new(
|
||||
"diploma-erkend",
|
||||
"Is uw diploma erkend door de Nederlandse overheid (bijv. via Nuffic)?",
|
||||
QuestionType.JaNee);
|
||||
|
||||
private static readonly PolicyQuestion Toelichting = new(
|
||||
"toelichting",
|
||||
"Geef een korte toelichting op uw diploma en opleiding.",
|
||||
QuestionType.Tekst);
|
||||
private static readonly PolicyQuestion Toelichting = new(
|
||||
"toelichting",
|
||||
"Geef een korte toelichting op uw diploma en opleiding.",
|
||||
QuestionType.Tekst);
|
||||
|
||||
/// <summary>
|
||||
/// RULE: an English-language diploma requires proof of Dutch proficiency (B2).
|
||||
/// Add a question here to apply it to a (set of) diploma(s) — a single backend
|
||||
/// change, no frontend change.
|
||||
/// </summary>
|
||||
public static IReadOnlyList<PolicyQuestion> QuestionsFor(Diploma d)
|
||||
{
|
||||
var questions = new List<PolicyQuestion>();
|
||||
if (d.Engelstalig)
|
||||
questions.Add(NlTaalEngelstalig);
|
||||
return questions;
|
||||
}
|
||||
/// <summary>
|
||||
/// RULE: an English-language diploma requires proof of Dutch proficiency (B2).
|
||||
/// Add a question here to apply it to a (set of) diploma(s) — a single backend
|
||||
/// change, no frontend change.
|
||||
/// </summary>
|
||||
public static IReadOnlyList<PolicyQuestion> QuestionsFor(Diploma d)
|
||||
{
|
||||
var questions = new List<PolicyQuestion>();
|
||||
if (d.Engelstalig)
|
||||
questions.Add(NlTaalEngelstalig);
|
||||
return questions;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RULE: a manual diploma is unverified, so the strictest (maximal) set applies.
|
||||
/// </summary>
|
||||
public static IReadOnlyList<PolicyQuestion> ManualQuestions() =>
|
||||
new[] { NlTaalManual, DiplomaErkend, Toelichting };
|
||||
/// <summary>
|
||||
/// RULE: a manual diploma is unverified, so the strictest (maximal) set applies.
|
||||
/// </summary>
|
||||
public static IReadOnlyList<PolicyQuestion> ManualQuestions() =>
|
||||
new[] { NlTaalManual, DiplomaErkend, Toelichting };
|
||||
}
|
||||
|
||||
@@ -17,67 +17,67 @@ public sealed record DocumentCategory(
|
||||
|
||||
public static class DocumentRules
|
||||
{
|
||||
private static readonly string[] Pdf = { "application/pdf" };
|
||||
private static readonly string[] PdfImage = { "application/pdf", "image/jpeg", "image/png" };
|
||||
private static readonly string[] Pdf = { "application/pdf" };
|
||||
private static readonly string[] PdfImage = { "application/pdf", "image/jpeg", "image/png" };
|
||||
|
||||
private static readonly DocumentCategory Diploma = new("diploma", "Diplomabewijs",
|
||||
"Upload uw diploma als PDF-bestand.", true, Pdf, 10, false, false);
|
||||
private static readonly DocumentCategory Identiteit = new("identiteit", "Identiteitsbewijs",
|
||||
"Upload een kopie van uw paspoort of ID-kaart.", true, PdfImage, 10, false, true);
|
||||
private static readonly DocumentCategory Taalvaardigheid = new("taalvaardigheid", "Bewijs Nederlandse taalvaardigheid",
|
||||
"Upload een bewijs van uw Nederlandse taalvaardigheid op het vereiste niveau (B2).", true, PdfImage, 10, false, true);
|
||||
private static readonly DocumentCategory Diploma = new("diploma", "Diplomabewijs",
|
||||
"Upload uw diploma als PDF-bestand.", true, Pdf, 10, false, false);
|
||||
private static readonly DocumentCategory Identiteit = new("identiteit", "Identiteitsbewijs",
|
||||
"Upload een kopie van uw paspoort of ID-kaart.", true, PdfImage, 10, false, true);
|
||||
private static readonly DocumentCategory Taalvaardigheid = new("taalvaardigheid", "Bewijs Nederlandse taalvaardigheid",
|
||||
"Upload een bewijs van uw Nederlandse taalvaardigheid op het vereiste niveau (B2).", true, PdfImage, 10, false, true);
|
||||
|
||||
/// <summary>
|
||||
/// The MAXIMAL set of categories a wizard can ever ask for. Used to validate an
|
||||
/// upload POST (any real category must resolve) — <see cref="CategoriesFor"/>
|
||||
/// decides which subset is actually presented for a given set of answers.
|
||||
/// </summary>
|
||||
public static IReadOnlyList<DocumentCategory> AllCategoriesFor(string wizardId) => wizardId switch
|
||||
/// <summary>
|
||||
/// The MAXIMAL set of categories a wizard can ever ask for. Used to validate an
|
||||
/// upload POST (any real category must resolve) — <see cref="CategoriesFor"/>
|
||||
/// decides which subset is actually presented for a given set of answers.
|
||||
/// </summary>
|
||||
public static IReadOnlyList<DocumentCategory> AllCategoriesFor(string wizardId) => wizardId switch
|
||||
{
|
||||
"registratie" => new[] { Diploma, Identiteit, Taalvaardigheid },
|
||||
"herregistratie" => new[]
|
||||
{
|
||||
"registratie" => new[] { Diploma, Identiteit, Taalvaardigheid },
|
||||
"herregistratie" => new[]
|
||||
{
|
||||
new DocumentCategory("werkervaring", "Bewijs van werkervaring",
|
||||
"Upload bewijs van uw gewerkte uren (bijv. een werkgeversverklaring).", true, Pdf, 10, true, true),
|
||||
new DocumentCategory("nascholing", "Nascholingscertificaten",
|
||||
"Upload uw nascholingscertificaten (optioneel).", false, PdfImage, 10, true, true),
|
||||
},
|
||||
_ => Array.Empty<DocumentCategory>(),
|
||||
};
|
||||
_ => Array.Empty<DocumentCategory>(),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The categories to PRESENT for a wizard, given the answers that affect required
|
||||
/// documents. RULES (registratie): a diploma upload is required ONLY for a manually
|
||||
/// entered diploma (a DUO diploma is verified digitally, and nothing is required
|
||||
/// before a diploma is chosen); proof of Dutch taalvaardigheid is required only when
|
||||
/// the applicant confirms ("ja") they meet the language requirement. Answer-agnostic
|
||||
/// wizards get their full set.
|
||||
/// </summary>
|
||||
public static IReadOnlyList<DocumentCategory> CategoriesFor(
|
||||
string wizardId, string? diplomaHerkomst = null, string? taalvaardigheid = null)
|
||||
{
|
||||
if (wizardId != "registratie") return AllCategoriesFor(wizardId);
|
||||
var result = new List<DocumentCategory>();
|
||||
if (diplomaHerkomst == "handmatig") result.Add(Diploma);
|
||||
result.Add(Identiteit);
|
||||
if (taalvaardigheid == "ja") result.Add(Taalvaardigheid);
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// The categories to PRESENT for a wizard, given the answers that affect required
|
||||
/// documents. RULES (registratie): a diploma upload is required ONLY for a manually
|
||||
/// entered diploma (a DUO diploma is verified digitally, and nothing is required
|
||||
/// before a diploma is chosen); proof of Dutch taalvaardigheid is required only when
|
||||
/// the applicant confirms ("ja") they meet the language requirement. Answer-agnostic
|
||||
/// wizards get their full set.
|
||||
/// </summary>
|
||||
public static IReadOnlyList<DocumentCategory> CategoriesFor(
|
||||
string wizardId, string? diplomaHerkomst = null, string? taalvaardigheid = null)
|
||||
{
|
||||
if (wizardId != "registratie") return AllCategoriesFor(wizardId);
|
||||
var result = new List<DocumentCategory>();
|
||||
if (diplomaHerkomst == "handmatig") result.Add(Diploma);
|
||||
result.Add(Identiteit);
|
||||
if (taalvaardigheid == "ja") result.Add(Taalvaardigheid);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static DocumentCategory? Find(string wizardId, string categoryId) =>
|
||||
AllCategoriesFor(wizardId).FirstOrDefault(c => c.CategoryId == categoryId);
|
||||
public static DocumentCategory? Find(string wizardId, string categoryId) =>
|
||||
AllCategoriesFor(wizardId).FirstOrDefault(c => c.CategoryId == categoryId);
|
||||
|
||||
/// <summary>
|
||||
/// Authoritative upload validation (the client check is UX-only). Returns a
|
||||
/// rejection reason, or null when the file is acceptable.
|
||||
/// </summary>
|
||||
public static string? RejectUpload(DocumentCategory? category, string contentType, long sizeBytes)
|
||||
{
|
||||
if (category is null) return "Onbekende documentcategorie.";
|
||||
if (!category.AcceptedTypes.Contains(contentType))
|
||||
return $"Bestandstype niet toegestaan voor {category.Label}.";
|
||||
if (sizeBytes > (long)category.MaxSizeMb * 1024 * 1024)
|
||||
return $"Bestand is groter dan {category.MaxSizeMb} MB.";
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
/// Authoritative upload validation (the client check is UX-only). Returns a
|
||||
/// rejection reason, or null when the file is acceptable.
|
||||
/// </summary>
|
||||
public static string? RejectUpload(DocumentCategory? category, string contentType, long sizeBytes)
|
||||
{
|
||||
if (category is null) return "Onbekende documentcategorie.";
|
||||
if (!category.AcceptedTypes.Contains(contentType))
|
||||
return $"Bestandstype niet toegestaan voor {category.Label}.";
|
||||
if (sizeBytes > (long)category.MaxSizeMb * 1024 * 1024)
|
||||
return $"Bestand is groter dan {category.MaxSizeMb} MB.";
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,5 +7,5 @@ namespace BigRegister.Domain.Intake;
|
||||
/// </summary>
|
||||
public static class IntakePolicy
|
||||
{
|
||||
public const int ScholingThreshold = 1000;
|
||||
public const int ScholingThreshold = 1000;
|
||||
}
|
||||
|
||||
@@ -8,25 +8,25 @@ namespace BigRegister.Domain.Registrations;
|
||||
/// </summary>
|
||||
public static class HerregistratieRule
|
||||
{
|
||||
public const int WindowMonths = 12;
|
||||
public const int WindowMonths = 12;
|
||||
|
||||
public static DateOnly? Deadline(Registration reg) =>
|
||||
reg.Status.Tag == StatusTag.Geregistreerd ? reg.Status.HerregistratieDatum : null;
|
||||
public static DateOnly? Deadline(Registration reg) =>
|
||||
reg.Status.Tag == StatusTag.Geregistreerd ? reg.Status.HerregistratieDatum : null;
|
||||
|
||||
public static (bool Eligible, string? Reason) Evaluate(
|
||||
Registration reg, DateOnly today, int windowMonths = WindowMonths)
|
||||
{
|
||||
var deadline = Deadline(reg);
|
||||
if (deadline is null)
|
||||
return (false, "Geen actieve registratie.");
|
||||
public static (bool Eligible, string? Reason) Evaluate(
|
||||
Registration reg, DateOnly today, int windowMonths = WindowMonths)
|
||||
{
|
||||
var deadline = Deadline(reg);
|
||||
if (deadline is null)
|
||||
return (false, "Geen actieve registratie.");
|
||||
|
||||
var windowStart = deadline.Value.AddMonths(-windowMonths);
|
||||
return today >= windowStart
|
||||
? (true, $"Registratie verloopt binnen {windowMonths} maanden ({deadline:yyyy-MM-dd}).")
|
||||
: (false, $"Herregistratie kan vanaf {windowStart:yyyy-MM-dd}.");
|
||||
}
|
||||
var windowStart = deadline.Value.AddMonths(-windowMonths);
|
||||
return today >= windowStart
|
||||
? (true, $"Registratie verloopt binnen {windowMonths} maanden ({deadline:yyyy-MM-dd}).")
|
||||
: (false, $"Herregistratie kan vanaf {windowStart:yyyy-MM-dd}.");
|
||||
}
|
||||
|
||||
/// <summary>Invariant: a non-active status must not carry a herregistratie date.</summary>
|
||||
public static bool IsStatusConsistent(RegistrationStatus s) =>
|
||||
s.Tag != StatusTag.Geregistreerd || s.HerregistratieDatum is not null;
|
||||
/// <summary>Invariant: a non-active status must not carry a herregistratie date.</summary>
|
||||
public static bool IsStatusConsistent(RegistrationStatus s) =>
|
||||
s.Tag != StatusTag.Geregistreerd || s.HerregistratieDatum is not null;
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@ namespace BigRegister.Domain.Registrations;
|
||||
/// <summary>The three states a BIG registration can be in.</summary>
|
||||
public enum StatusTag
|
||||
{
|
||||
Geregistreerd,
|
||||
Geschorst,
|
||||
Doorgehaald,
|
||||
Geregistreerd,
|
||||
Geschorst,
|
||||
Doorgehaald,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -9,29 +9,29 @@ namespace BigRegister.Domain.Submissions;
|
||||
/// </summary>
|
||||
public static class SubmissionRules
|
||||
{
|
||||
// RULE: a manually entered diploma cannot be auto-verified.
|
||||
public static string? RejectRegistratie(string diplomaHerkomst) =>
|
||||
diplomaHerkomst == "handmatig"
|
||||
? "Een handmatig ingevoerd diploma kan niet automatisch worden geverifieerd. Uw aanvraag is doorgestuurd voor handmatige beoordeling."
|
||||
: null;
|
||||
// RULE: a manually entered diploma cannot be auto-verified.
|
||||
public static string? RejectRegistratie(string diplomaHerkomst) =>
|
||||
diplomaHerkomst == "handmatig"
|
||||
? "Een handmatig ingevoerd diploma kan niet automatisch worden geverifieerd. Uw aanvraag is doorgestuurd voor handmatige beoordeling."
|
||||
: null;
|
||||
|
||||
// RULE: an application reporting zero worked hours is rejected.
|
||||
public static string? RejectZeroUren(int uren) =>
|
||||
uren == 0 ? "Aanvraag afgewezen: geen gewerkte uren geregistreerd." : null;
|
||||
// RULE: an application reporting zero worked hours is rejected.
|
||||
public static string? RejectZeroUren(int uren) =>
|
||||
uren == 0 ? "Aanvraag afgewezen: geen gewerkte uren geregistreerd." : null;
|
||||
|
||||
private static readonly Regex PostcodePattern =
|
||||
new(@"^[1-9]\d{3}\s?[A-Z]{2}$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
private static readonly Regex PostcodePattern =
|
||||
new(@"^[1-9]\d{3}\s?[A-Z]{2}$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
|
||||
|
||||
// RULE: a change request needs a street and a well-formed Dutch postcode. The
|
||||
// server re-validates format authoritatively (the FE check is UX-only).
|
||||
public static string? RejectChangeRequest(string straat, string postcode)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(straat)) return "Vul straat en huisnummer in.";
|
||||
if (!PostcodePattern.IsMatch(postcode?.Trim() ?? "")) return "Voer een geldige postcode in, bijv. 1234 AB.";
|
||||
return null;
|
||||
}
|
||||
// RULE: a change request needs a street and a well-formed Dutch postcode. The
|
||||
// server re-validates format authoritatively (the FE check is UX-only).
|
||||
public static string? RejectChangeRequest(string straat, string postcode)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(straat)) return "Vul straat en huisnummer in.";
|
||||
if (!PostcodePattern.IsMatch(postcode?.Trim() ?? "")) return "Voer een geldige postcode in, bijv. 1234 AB.";
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string NewReference() =>
|
||||
// ponytail: random reference is fine for a demo; a real system reserves it transactionally.
|
||||
"BIG-2026-" + Random.Shared.Next(100_000, 1_000_000);
|
||||
public static string NewReference() =>
|
||||
// ponytail: random reference is fine for a demo; a real system reserves it transactionally.
|
||||
"BIG-2026-" + Random.Shared.Next(100_000, 1_000_000);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user