- 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>
58 lines
2.2 KiB
C#
58 lines
2.2 KiB
C#
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);
|
||
}
|
||
}
|