From c0bd20304b9b2f8c2f59e88447a2b98654800af6 Mon Sep 17 00:00:00 2001 From: LuckShiba Date: Sat, 11 May 2024 19:13:21 -0300 Subject: [PATCH] add: cpf and cnpj validators in FluentValidator --- README.md | 18 +++-- .../Extensions/RuleBuilderExtension.cs | 79 +++++++++++++++++++ 2 files changed, 92 insertions(+), 5 deletions(-) create mode 100644 TakasakiStudio.Lina.Common/Extensions/RuleBuilderExtension.cs diff --git a/README.md b/README.md index a9125ed..51a2703 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ A framework to simplify application creation by improving dependency injection, - Fluent api - Reliable library - Easy usage + - CPF and CNPJ validators - Dependency Injection - Life time configurable - Easy manipulation @@ -139,6 +140,7 @@ public class UserConfiguration : IEntityTypeConfiguration ```csharp using FluentValidation; using TakasakiStudio.Lina.Common; +using TakasakiStudio.Lina.Common.Extensions; using TakasakiStudio.Lina.Database.Models; var user = new User() @@ -152,6 +154,8 @@ if (!await user.IsValid()) } user.Name = "Foo"; +user.Cpf = "349.306.930-80"; +user.Cnpj = "82.099.001/0001-08"; await user.Validate(); @@ -159,7 +163,9 @@ Console.WriteLine("Valid"); public class User : BaseEntityValidate { - public string Name { get; set; } = string.Empty; + public required string Name { get; set; } + public required string Cpf { get; set; } + public required string Cnpj { get; set; } } public class UserValidation : AbstractValidator @@ -167,19 +173,21 @@ public class UserValidation : AbstractValidator public UserValidation() { RuleFor(x => x.Name).NotEmpty(); + RuleFor(x => x.Cpf).ValidCpf(); + RuleFor(x => x.Cnpj).ValidCnpj(); } } -public record UserViewModel() : BaseValidationRecord -{ - public string Name { get; set; } = string.Empty; -} +public record UserViewModel(string Name, string Cpf, string Cnpj) + : BaseValidationRecord; public class UserViewModelValidation : AbstractValidator { public UserViewModelValidation() { RuleFor(x => x.Name).NotEmpty(); + RuleFor(x => x.Cpf).ValidCpf(); + RuleFor(x => x.Cnpj).ValidCnpj(); } } ``` diff --git a/TakasakiStudio.Lina.Common/Extensions/RuleBuilderExtension.cs b/TakasakiStudio.Lina.Common/Extensions/RuleBuilderExtension.cs new file mode 100644 index 0000000..ca2ae0f --- /dev/null +++ b/TakasakiStudio.Lina.Common/Extensions/RuleBuilderExtension.cs @@ -0,0 +1,79 @@ +using System.Text.RegularExpressions; +using FluentValidation; + +namespace TakasakiStudio.Lina.Common.Extensions; + +public static partial class RuleBuilderExtension +{ + public static IRuleBuilder ValidCpf(this IRuleBuilder ruleBuilder) + { + return ruleBuilder.Must(BeAValidCpf); + } + + public static IRuleBuilder ValidCnpj(this IRuleBuilder ruleBuilder) + { + return ruleBuilder.Must(BeAValidCnpj); + } + + private static bool BeAValidCpf(string input) + { + var numbers = ToNumbers(input); + if (numbers.Length != 11 || numbers.Distinct().Count() == 1) + return false; + + var v1 = 0; + var v2 = 0; + + for (var i = 0; i < 9; i++) { + var number = numbers[8 - i]; + v1 += number * (9 - i % 10); + v2 += number * (9 - (i + 1) % 10); + } + + v1 %= 11; + v1 %= 10; + + v2 += v1 * 9; + v2 %= 11; + v2 %= 10; + + return numbers[9] == v1 && numbers[10] == v2; + } + + private static bool BeAValidCnpj(string input) + { + var numbers = ToNumbers(input); + if (numbers.Length != 14) + return false; + + var v1 = 5 * numbers[0] + 4 * numbers[1] + 3 * numbers[2] + 2 * numbers[3] + + 9 * numbers[4] + 8 * numbers[5] + 7 * numbers[6] + 6 * numbers[7] + + 5 * numbers[8] + 4 * numbers[9] + 3 * numbers[10] + 2 * numbers[11]; + + var v2 = 6 * numbers[0] + 5 * numbers[1] + 4 * numbers[2] + 3 * numbers[3] + + 2 * numbers[4] + 9 * numbers[5] + 8 * numbers[6] + 7 * numbers[7] + + 6 * numbers[8] + 5 * numbers[9] + 4 * numbers[10] + 3 * numbers[11] + + 2 * numbers[12]; + + v1 = 11 - v1 % 11; + if (v1 >= 10) + v1 = 0; + + v2 = 11 - v2 % 11; + if (v2 >= 10) + v2 = 0; + + return numbers[12] == v1 && numbers[13] == v2; + } + + private static int[] ToNumbers(string input) + { + var clean = NotNumberRegex().Replace(input, string.Empty); + var numbers = clean.ToCharArray().Select(x => int.Parse(x.ToString())); + + return numbers.ToArray(); + } + + [GeneratedRegex(@"[^\d]")] + private static partial Regex NotNumberRegex(); +} \ No newline at end of file