Files
Geradores/GeradoresService/Generators/Financeiro/NibGenerator.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

76 lines
2.7 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.Financeiro;
/// <summary>
/// NIB: banco (4) + balcão (4) + conta (11) + controlo (2). Controlo = 98 - (NIB19 × 100 mod 97).
/// </summary>
public class NibGenerator : GeneratorBase
{
public static readonly IReadOnlyList<(string Code, string Name)> Banks =
[
("0007", "Novo Banco"),
("0010", "BPI"),
("0018", "Santander Totta"),
("0023", "Banco ActivoBank"),
("0033", "Millennium BCP"),
("0035", "Caixa Geral de Depósitos"),
("0036", "Banco Montepio"),
("0045", "Crédito Agrícola"),
("0079", "Banco BIC"),
("0193", "Banco CTT"),
("0269", "Bankinter"),
];
public override string Id => "nib";
public override string Name => "NIB";
public override string Category => Categories.Financeiro;
public override string Description => "Número de Identificação Bancária (21 dígitos).";
public override IReadOnlyList<GeneratorOption> Options =>
[
Option("banco", "Banco", "qualquer",
[("qualquer", "Qualquer"), .. Banks.Select(b => (b.Code, $"{b.Code} — {b.Name}"))]),
];
public override GeneratedItem Generate(GeneratorContext context) => new(BuildNib(context));
protected string BuildNib(GeneratorContext context)
{
var bank = context.Option(Options[0]);
if (bank == "qualquer")
bank = context.Pick(Banks).Code;
var body = bank + context.Digits(4) + context.Digits(11);
return body + NibCheck(body);
}
public static string NibCheck(string first19) =>
(98 - Checksums.Mod97(first19 + "00")).ToString("D2");
public static string? BankName(string nib) =>
Banks.FirstOrDefault(b => nib.StartsWith(b.Code)).Name;
public override ValidationResult Validate(string value)
{
var nib = Checksums.Clean(value);
if (nib.Length != 21 || !Checksums.AllDigits(nib))
return ValidationResult.WrongFormat("Um NIB tem 21 dígitos.");
return ValidateNib(nib, "NIB");
}
public static ValidationResult ValidateNib(string nib, string label)
{
var expected = NibCheck(nib[..19]);
var details = new List<string>
{
$"Banco: {nib[..4]}{(BankName(nib) is { } n ? $" ({n})" : "")}",
$"Balcão: {nib[4..8]}",
$"Conta: {nib[8..19]}",
$"Dígitos de controlo esperados: {expected} (módulo 97)",
};
return nib[19..] == expected
? ValidationResult.Valid(nib, $"{label} válido.", details)
: ValidationResult.BadChecksum($"Dígitos de controlo do NIB inválidos: esperado {expected}, encontrado {nib[19..]}.", details);
}
}