Files
Geradores/GeradoresService/Generators/Identificacao/NissGenerator.cs
Marco Santos d7ea8a9b9e Reescrita dos geradores: biblioteca IGenerator, minimal API e novo frontend
- GeradoresService: cada tipo passa a ser um IGenerator (NIF, NIPC, NISS, CC,
  passaporte, IBAN, NIB, cartões, referência MB, pessoa, telefone, código postal,
  email, matrícula, EAN, UUID) registado em GeneratorRegistry; remove DAL/EF
- GeradoresWS: minimal APIs em /api/v1 com OpenAPI + Scalar e health check
- UnitTest: testes de ida e volta, valores conhecidos, detecção e API
- geradoresfe: UI construída a partir dos metadados da API, validador livre,
  exportação CSV/JSON/TXT, nginx com API_UPSTREAM configurável
- Docker, docker-compose e Jenkinsfile actualizados

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 23:51:39 +01:00

58 lines
2.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using GeradoresService.Core;
namespace GeradoresService.Generators.Identificacao;
/// <summary>
/// Número de Identificação da Segurança Social. 11 dígitos, começa por 1 (singular) ou 2 (colectiva).
/// Controlo: 9 - (Σ dígito × peso) mod 10, pesos 29, 23, 19, 17, 13, 11, 7, 5, 3, 2.
/// </summary>
public sealed class NissGenerator : GeneratorBase
{
private static readonly int[] Weights = [29, 23, 19, 17, 13, 11, 7, 5, 3, 2];
public override string Id => "niss";
public override string Name => "NISS";
public override string Category => Categories.Identificacao;
public override string Description => "Número de Identificação da Segurança Social.";
public override IReadOnlyList<GeneratorOption> Options =>
[
Option("tipo", "Tipo", "1", ("1", "1 — Pessoa singular"), ("2", "2 — Pessoa colectiva")),
];
public override GeneratedItem Generate(GeneratorContext context)
{
var body = context.Option(Options[0]) + context.Digits(9);
return new GeneratedItem(body + CheckDigit(body));
}
public static int CheckDigit(ReadOnlySpan<char> first10)
{
var sum = 0;
for (var i = 0; i < 10; i++)
sum += (first10[i] - '0') * Weights[i];
return 9 - sum % 10;
}
public override ValidationResult Validate(string value)
{
var niss = Checksums.Clean(value);
if (niss.Length != 11 || !Checksums.AllDigits(niss))
return ValidationResult.WrongFormat("Um NISS tem 11 dígitos.");
if (niss[0] is not ('1' or '2'))
return ValidationResult.WrongFormat("Um NISS começa por 1 (singular) ou 2 (colectiva).");
var expected = CheckDigit(niss);
var tipo = niss[0] == '1' ? "pessoa singular" : "pessoa colectiva";
var details = new List<string>
{
$"Tipo: {tipo}",
$"Dígito de controlo esperado: {expected}",
};
return expected == niss[10] - '0'
? ValidationResult.Valid(niss, $"NISS válido — {tipo}.", details)
: ValidationResult.BadChecksum($"Dígito de controlo inválido: esperado {expected}, encontrado {niss[10]}.", details);
}
}