From 732dc48f0538e70b44d558643d4ba30ec8ea082a Mon Sep 17 00:00:00 2001 From: ArthurTorres1 Date: Thu, 24 Apr 2025 15:33:40 -0300 Subject: [PATCH 01/10] subindo Dockerfile --- Dockerfile | 26 ++++++++++++++++++++++++++ src/FrioAPI.Api/Program.cs | 2 ++ 2 files changed, 28 insertions(+) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..cc7cf24 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,26 @@ +# Etapa de build +FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build +WORKDIR /app + +# Copiar todos os arquivos do repositório para dentro do container +COPY . ./ + +# Restaurar as dependências a partir do arquivo de solução +RUN dotnet restore FrioAPI.sln + +# Buildar o projeto no modo Release +RUN dotnet publish FrioAPI.sln -c Release -o /publish + +# Etapa de runtime (imagem mais leve para executar) +FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime +WORKDIR /app + +# Copiar o conteúdo publicado da etapa anterior para o container +COPY --from=build /publish . + +# Expor as portas que serão usadas pela aplicação +EXPOSE 5000 +EXPOSE 5001 + +# Configurar o comando de entrada para iniciar sua API +ENTRYPOINT ["dotnet", "FrioAPI.Api.dll"] \ No newline at end of file diff --git a/src/FrioAPI.Api/Program.cs b/src/FrioAPI.Api/Program.cs index 9e34ad6..6650113 100644 --- a/src/FrioAPI.Api/Program.cs +++ b/src/FrioAPI.Api/Program.cs @@ -37,6 +37,8 @@ app.UseHttpsRedirection(); } +app.Urls.Add("https://0.0.0.0:5001"); // Aceita conexes HTTPS de qualquer host + app.UseAuthorization(); app.MapControllers(); From 1b1382ac7db6ecec9171f6c1b90691d4a4bfd1f0 Mon Sep 17 00:00:00 2001 From: ArthurTorres1 Date: Thu, 24 Apr 2025 16:30:39 -0300 Subject: [PATCH 02/10] corrigindo regra de https no docker/prod --- src/FrioAPI.Api/Program.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/FrioAPI.Api/Program.cs b/src/FrioAPI.Api/Program.cs index 6650113..93eeb29 100644 --- a/src/FrioAPI.Api/Program.cs +++ b/src/FrioAPI.Api/Program.cs @@ -3,6 +3,8 @@ using FrioAPI.Infrastructure; var builder = WebApplication.CreateBuilder(args); + +// Configurao de CORS builder.Services.AddCors(options => { options.AddPolicy("AllowAll", policy => @@ -19,9 +21,10 @@ builder.Services.AddMvc(options => options.Filters.Add(typeof(ExceptionFilter))); -//Injeo de dependencias +// Injeo de dependncias builder.Services.AddInfrastructure(builder.Configuration); builder.Services.AddApplication(); + var app = builder.Build(); app.UseCors("AllowAll"); @@ -30,17 +33,16 @@ { app.UseSwagger(); app.UseSwaggerUI(); + app.UseHttpsRedirection(); // HTTPS ativo apenas no ambiente de desenvolvimento } - else { - app.UseHttpsRedirection(); + // Desabilitar HTTPS para ambientes Docker/produo + app.Urls.Add("http://0.0.0.0:5000"); // Aceita conexes HTTP } -app.Urls.Add("https://0.0.0.0:5001"); // Aceita conexes HTTPS de qualquer host - app.UseAuthorization(); app.MapControllers(); -app.Run(); +app.Run(); \ No newline at end of file From 2419cd1dd322ff9607457cc65eedf0f7c41eb5fa Mon Sep 17 00:00:00 2001 From: ArthurTorres1 Date: Thu, 24 Apr 2025 17:19:07 -0300 Subject: [PATCH 03/10] =?UTF-8?q?separando=20banco=20de=20produ=C3=A7?= =?UTF-8?q?=C3=A3o=20do=20banco=20de=20teste.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/FrioAPI.Api/appsettings.Development.json | 3 +-- .../DepedencyInjectionExtension.cs | 9 ++++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/FrioAPI.Api/appsettings.Development.json b/src/FrioAPI.Api/appsettings.Development.json index 6b62bb5..d553b95 100644 --- a/src/FrioAPI.Api/appsettings.Development.json +++ b/src/FrioAPI.Api/appsettings.Development.json @@ -1,6 +1,5 @@ { "ConnectionStrings": { - "Connection-dev": "", - "Connection-prod": "" + "Connection-dev": "Server=localhost,1433;Database=friodatabase;User Id=sa;Password=12345;TrustServerCertificate=True;" } } \ No newline at end of file diff --git a/src/FrioAPI.Infrastructure/DepedencyInjectionExtension.cs b/src/FrioAPI.Infrastructure/DepedencyInjectionExtension.cs index 2357a2c..bb07d95 100644 --- a/src/FrioAPI.Infrastructure/DepedencyInjectionExtension.cs +++ b/src/FrioAPI.Infrastructure/DepedencyInjectionExtension.cs @@ -25,7 +25,14 @@ private static void AddRepostories(IServiceCollection services) } private static void AddDbContext(IServiceCollection services, IConfiguration configuration) { - var connectionString = configuration.GetConnectionString("Connection-prod"); + // Busca a connection string da variável de ambiente configurada no Render + var connectionString = Environment.GetEnvironmentVariable("CONNECTION_PROD") + ?? configuration.GetConnectionString("Connection-dev"); + + if (string.IsNullOrEmpty(connectionString)) + { + throw new InvalidOperationException("A Connection String não foi configurada."); + } services.AddDbContext(options => options.UseSqlServer(connectionString)); From 7b76f07da4d161abd08650f9b7fae31dfc425d9a Mon Sep 17 00:00:00 2001 From: Arthur Torres <149539835+ArthurTorres1@users.noreply.github.com> Date: Thu, 24 Apr 2025 21:57:14 -0300 Subject: [PATCH 04/10] Create README.md --- README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..4428e2b --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +### Sobre o Projeto From bdff6da853bed8bfea55f698c94c0d2ad07a2b4b Mon Sep 17 00:00:00 2001 From: ArthurTorres1 Date: Thu, 24 Apr 2025 22:34:22 -0300 Subject: [PATCH 05/10] autorizando rotas do front no CORS --- src/FrioAPI.Api/Program.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/FrioAPI.Api/Program.cs b/src/FrioAPI.Api/Program.cs index 93eeb29..86ff4e9 100644 --- a/src/FrioAPI.Api/Program.cs +++ b/src/FrioAPI.Api/Program.cs @@ -9,9 +9,12 @@ { options.AddPolicy("AllowAll", policy => { - policy.AllowAnyOrigin() - .AllowAnyMethod() - .AllowAnyHeader(); + policy.WithOrigins( + "https://frio-front.vercel.app", + "http://localhost:3000" + ) + .AllowAnyMethod() + .AllowAnyHeader(); }); }); From 8d68d95efcb1bddafa62ac4c3ea71823bc8878cf Mon Sep 17 00:00:00 2001 From: Arthur Torres <149539835+ArthurTorres1@users.noreply.github.com> Date: Thu, 24 Apr 2025 22:45:26 -0300 Subject: [PATCH 06/10] estilizando readme --- README.md | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 4428e2b..75cc537 100644 --- a/README.md +++ b/README.md @@ -1 +1,35 @@ -### Sobre o Projeto +# 🧾 Gerador de Relatórios e Recibos API + +[![.NET](https://img.shields.io/badge/.NET-8.0-blueviolet.svg)](https://dotnet.microsoft.com/) +[![Swagger](https://img.shields.io/badge/Swagger-API-green.svg)](https://swagger.io/) +[![SQL Server](https://img.shields.io/badge/SQL%20Server-MS%20SQL-blue.svg)](https://www.microsoft.com/pt-br/sql-server) + +Bem-vindo à API **FrioAPI**! Esta aplicação foi desenvolvida com **DDD (Domain-Driven Design)** e os **princípios SOLID** para garantir alta escalabilidade, manutenibilidade e qualidade. O objetivo principal é permitir que você gere relatórios mensais e recibos personalizados para clientes em formatos **PDF** e **Excel**, usando as bibliotecas **ClosedXML** e **PdfSharp-MigraDoc**. Além disso, a documentação da API está acessível através do **Swagger**. + +## 🛠️ Tecnologias Utilizadas +- **.NET 8.0** +- **ClosedXML** (para gerar relatórios em Excel) +- **PdfSharp-MigraDoc** (para relatórios e recibos em PDF) +- **MS SQL Server** (banco de dados) +- **Swagger** (para documentação da API) + +## 🚀 Principais Funcionalidades +- Geração de recibos de clientes em **PDF**. +- Relatórios mensais em **PDF** e **Excel**. +- Arquitetura robusta baseada em **DDD** e **SOLID**. + +## 🎨 Visual do Projeto + ![hero-images] + + +## 📖 Como Usar + +### 📥 Clonar o Repositório +1. Clone o repositório: + ```sh + git clone https://github.com/ArthurTorres1/CashFlow.git + ``` +2. Preencha as informações `appsettings.Development.json`; +3. + +[hero-images]: imagem/image.png From 3f399d54cf8411c016d1aefe11d6f6b24b97f655 Mon Sep 17 00:00:00 2001 From: Arthur Torres <149539835+ArthurTorres1@users.noreply.github.com> Date: Thu, 24 Apr 2025 22:54:05 -0300 Subject: [PATCH 07/10] Add files via upload --- images/image-recibo.png | Bin 0 -> 50750 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 images/image-recibo.png diff --git a/images/image-recibo.png b/images/image-recibo.png new file mode 100644 index 0000000000000000000000000000000000000000..5ec0327eee64fe934b473379c544a687c850a426 GIT binary patch literal 50750 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 Date: Thu, 24 Apr 2025 23:15:19 -0300 Subject: [PATCH 08/10] finalizando readme --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 75cc537..cc1ed9e 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Bem-vindo à API **FrioAPI**! Esta aplicação foi desenvolvida com **DDD (Domai - Arquitetura robusta baseada em **DDD** e **SOLID**. ## 🎨 Visual do Projeto - ![hero-images] + ![image](https://github.com/user-attachments/assets/9727aecc-3e28-40a8-b4d6-6ae2f7025230) ## 📖 Como Usar @@ -27,9 +27,6 @@ Bem-vindo à API **FrioAPI**! Esta aplicação foi desenvolvida com **DDD (Domai ### 📥 Clonar o Repositório 1. Clone o repositório: ```sh - git clone https://github.com/ArthurTorres1/CashFlow.git + git clone https://github.com/ArthurTorres1/FrioAPI.git ``` 2. Preencha as informações `appsettings.Development.json`; -3. - -[hero-images]: imagem/image.png From f6dc921118690fec9cfc86fb410e6bb620c48039 Mon Sep 17 00:00:00 2001 From: ArthurTorres1 Date: Thu, 24 Apr 2025 23:34:12 -0300 Subject: [PATCH 09/10] ajustando o idioma da data do recibo do cliente --- .../Recibos/Reports/Pdf/GenerateRecibosReportPdfUseCase.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/FrioAPI.Application/UseCases/Recibos/Reports/Pdf/GenerateRecibosReportPdfUseCase.cs b/src/FrioAPI.Application/UseCases/Recibos/Reports/Pdf/GenerateRecibosReportPdfUseCase.cs index dcc9bda..5d18fa7 100644 --- a/src/FrioAPI.Application/UseCases/Recibos/Reports/Pdf/GenerateRecibosReportPdfUseCase.cs +++ b/src/FrioAPI.Application/UseCases/Recibos/Reports/Pdf/GenerateRecibosReportPdfUseCase.cs @@ -8,6 +8,7 @@ using MigraDoc.DocumentObjectModel.Tables; using MigraDoc.Rendering; using PdfSharp.Fonts; +using System.Globalization; using System.Reflection; namespace FrioAPI.Application.UseCases.Recibos.Reports.Pdf @@ -42,7 +43,9 @@ public async Task ReciboClientePdf(Recibo recibo) row = table.AddRow(); row.Height = HEIGHT_ROW_TABLE_RECIBOS; - row.Cells[0].AddParagraph($"{recibo.Data:ddd dd MMM yyyy}"); + var cultura = new CultureInfo("pt-BR"); + row.Cells[0].AddParagraph($"{recibo.Data.ToString("ddd dd MMM yyyy", cultura)}"); + EstiloBaseParaInformacoesRecibo(row.Cells[0]); row.Cells[0].Format.LeftIndent = 10; From 60cac1a38b4c61e7288d283222ce3c0c8bce8eb2 Mon Sep 17 00:00:00 2001 From: ArthurTorres1 Date: Tue, 29 Apr 2025 01:10:52 -0300 Subject: [PATCH 10/10] Integrando a api do viaCEP, para facilitar o lado do cliente. --- src/FrioAPI.Api/Program.cs | 2 ++ .../DependencyInjectionExtension.cs | 3 +- .../Recibos/Register/RegisterReciboUseCase.cs | 22 +++++++++++- .../UseCases/ViaCep/BuscaEnderecoViaCep.cs | 36 +++++++++++++++++++ .../UseCases/ViaCep/IBuscaEnderecoViaCep.cs | 9 +++++ .../Responses/ResponseViaCep.cs | 11 ++++++ .../ResourceErrorMessages.Designer.cs | 9 +++++ .../ResourceErrorMessages.resx | 3 ++ 8 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 src/FrioAPI.Application/UseCases/ViaCep/BuscaEnderecoViaCep.cs create mode 100644 src/FrioAPI.Application/UseCases/ViaCep/IBuscaEnderecoViaCep.cs create mode 100644 src/FrioAPI.Communication/Responses/ResponseViaCep.cs diff --git a/src/FrioAPI.Api/Program.cs b/src/FrioAPI.Api/Program.cs index 86ff4e9..53f0bdf 100644 --- a/src/FrioAPI.Api/Program.cs +++ b/src/FrioAPI.Api/Program.cs @@ -1,5 +1,6 @@ using FrioAPI.Api.Filters; using FrioAPI.Application; +using FrioAPI.Application.UseCases.ViaCep; using FrioAPI.Infrastructure; var builder = WebApplication.CreateBuilder(args); @@ -27,6 +28,7 @@ // Injeo de dependncias builder.Services.AddInfrastructure(builder.Configuration); builder.Services.AddApplication(); +builder.Services.AddHttpClient(); var app = builder.Build(); diff --git a/src/FrioAPI.Application/DependencyInjectionExtension.cs b/src/FrioAPI.Application/DependencyInjectionExtension.cs index aaf0152..d2596c5 100644 --- a/src/FrioAPI.Application/DependencyInjectionExtension.cs +++ b/src/FrioAPI.Application/DependencyInjectionExtension.cs @@ -6,6 +6,7 @@ using FrioAPI.Application.UseCases.Recibos.Reports.Excel; using FrioAPI.Application.UseCases.Recibos.Reports.Pdf; using FrioAPI.Application.UseCases.Recibos.Update; +using FrioAPI.Application.UseCases.ViaCep; using Microsoft.Extensions.DependencyInjection; namespace FrioAPI.Application @@ -32,7 +33,7 @@ private static void AddUseCases(IServiceCollection services) services.AddScoped(); services.AddScoped(); services.AddScoped(); - + services.AddScoped(); } } } diff --git a/src/FrioAPI.Application/UseCases/Recibos/Register/RegisterReciboUseCase.cs b/src/FrioAPI.Application/UseCases/Recibos/Register/RegisterReciboUseCase.cs index ffe6f43..1fbdef0 100644 --- a/src/FrioAPI.Application/UseCases/Recibos/Register/RegisterReciboUseCase.cs +++ b/src/FrioAPI.Application/UseCases/Recibos/Register/RegisterReciboUseCase.cs @@ -1,6 +1,8 @@ using System.Linq; +using System.Runtime.ConstrainedExecution; using AutoMapper; using FrioAPI.Application.UseCases.Recibos.Reports.Pdf; +using FrioAPI.Application.UseCases.ViaCep; using FrioAPI.Communication.Requests; using FrioAPI.Communication.Responses; using FrioAPI.Domain.Entities; @@ -17,21 +19,39 @@ public class RegisterReciboUseCase : IRegisterReciboUseCase private readonly IUnidadeDeTrabalho _unidadeDeTrabalho; private readonly IMapper _mapper; private readonly IGenerateRecibosReportPdfUseCase _pdfRecibo; + private readonly IBuscaEnderecoViaCep _viacepUseCase; public RegisterReciboUseCase( IRecibosWriteOnlyRepository repository, IUnidadeDeTrabalho unidadeDeTrabalho, IMapper mapper, - IGenerateRecibosReportPdfUseCase pdfRecibo + IGenerateRecibosReportPdfUseCase pdfRecibo, + IBuscaEnderecoViaCep viaCepUseCase ) { _recibosRepository = repository; _unidadeDeTrabalho = unidadeDeTrabalho; _mapper = mapper; _pdfRecibo = pdfRecibo; + _viacepUseCase = viaCepUseCase; } public async Task Execute(RequestReciboJson request) { + if (!string.IsNullOrWhiteSpace(request.CEP)) + { + var cepLimpo = new string(request.CEP.Where(char.IsDigit).ToArray()); + var endereco = await _viacepUseCase.BuscaCep(cepLimpo); + + if (endereco == null) + throw new ArgumentException("CEP inválido ou não encontrado. Por favor, informe um CEP válido ou preencha os campos manualmente."); + + //preenche automaticamente apenas se os campos estiverem vazios + request.Logradouro = string.IsNullOrWhiteSpace(request.Logradouro) ? endereco.Logradouro : request.Logradouro; + request.Bairro = string.IsNullOrWhiteSpace(request.Bairro) ? endereco.Bairro : request.Bairro; + request.Cidade = string.IsNullOrWhiteSpace(request.Cidade) ? endereco.Localidade : request.Cidade; + request.UF = string.IsNullOrWhiteSpace(request.UF) ? endereco.Uf : request.UF; + } + Validate(request); var entity = _mapper.Map(request); diff --git a/src/FrioAPI.Application/UseCases/ViaCep/BuscaEnderecoViaCep.cs b/src/FrioAPI.Application/UseCases/ViaCep/BuscaEnderecoViaCep.cs new file mode 100644 index 0000000..6dd362d --- /dev/null +++ b/src/FrioAPI.Application/UseCases/ViaCep/BuscaEnderecoViaCep.cs @@ -0,0 +1,36 @@ +using FrioAPI.Communication.Responses; +using FrioAPI.Exception; +using FrioAPI.Exception.ExceptionsBase; +using System.Text.Json; + +namespace FrioAPI.Application.UseCases.ViaCep +{ + public class BuscaEnderecoViaCep : IBuscaEnderecoViaCep + { + private readonly HttpClient _httpClient; + + public BuscaEnderecoViaCep(HttpClient httpClient) + { + _httpClient = httpClient; + } + + public async Task BuscaCep(string cep) + { + var response = await _httpClient.GetAsync($"https://viacep.com.br/ws/{cep}/json/"); + + if (!response.IsSuccessStatusCode) + return null; + + var content = await response.Content.ReadAsStringAsync(); + + var endereco = JsonSerializer.Deserialize(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); + + if (endereco?.Erro == true) + { + var errorMessages = new List{ ResourceErrorMessages.CEP_NAO_ENCONTRADO }; + throw new ErrorOnValidationException(errorMessages); + } + return endereco; + } + } +} diff --git a/src/FrioAPI.Application/UseCases/ViaCep/IBuscaEnderecoViaCep.cs b/src/FrioAPI.Application/UseCases/ViaCep/IBuscaEnderecoViaCep.cs new file mode 100644 index 0000000..5ca23b4 --- /dev/null +++ b/src/FrioAPI.Application/UseCases/ViaCep/IBuscaEnderecoViaCep.cs @@ -0,0 +1,9 @@ +using FrioAPI.Communication.Responses; + +namespace FrioAPI.Application.UseCases.ViaCep +{ + public interface IBuscaEnderecoViaCep + { + Task BuscaCep(string cep); + } +} diff --git a/src/FrioAPI.Communication/Responses/ResponseViaCep.cs b/src/FrioAPI.Communication/Responses/ResponseViaCep.cs new file mode 100644 index 0000000..2111833 --- /dev/null +++ b/src/FrioAPI.Communication/Responses/ResponseViaCep.cs @@ -0,0 +1,11 @@ +namespace FrioAPI.Communication.Responses +{ + public class ResponseViaCep + { + public string Logradouro { get; set; } = string.Empty; + public string Bairro { get; set; } = string.Empty; + public string Localidade { get; set; } = string.Empty; + public string Uf { get; set; } = string.Empty; + public bool Erro { get; set; } + } +} diff --git a/src/FrioAPI.Exception/ResourceErrorMessages.Designer.cs b/src/FrioAPI.Exception/ResourceErrorMessages.Designer.cs index 75efe17..f51a7ed 100644 --- a/src/FrioAPI.Exception/ResourceErrorMessages.Designer.cs +++ b/src/FrioAPI.Exception/ResourceErrorMessages.Designer.cs @@ -60,6 +60,15 @@ internal ResourceErrorMessages() { } } + /// + /// Looks up a localized string similar to O CEP não foi encontrado.. + /// + public static string CEP_NAO_ENCONTRADO { + get { + return ResourceManager.GetString("CEP_NAO_ENCONTRADO", resourceCulture); + } + } + /// /// Looks up a localized string similar to O campo (Cidade) é obrigatório.. /// diff --git a/src/FrioAPI.Exception/ResourceErrorMessages.resx b/src/FrioAPI.Exception/ResourceErrorMessages.resx index 92a5263..ad48145 100644 --- a/src/FrioAPI.Exception/ResourceErrorMessages.resx +++ b/src/FrioAPI.Exception/ResourceErrorMessages.resx @@ -117,6 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + O CEP não foi encontrado. + O campo (Cidade) é obrigatório.