Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
6bc7962
PR - Configurando fontes do arquivo pdf
ArthurTorres1 Apr 22, 2025
13f0154
PR - Criando documento pdf e dando nome para ele, utilizando arquivo …
ArthurTorres1 Apr 22, 2025
66ec96f
PR - Criando cabeçalho com logo, adicionando paragrafo com o mes e va…
ArthurTorres1 Apr 23, 2025
84993a0
PR - Criando a tabela dos recibos e adicionando nome do cliente e tot…
ArthurTorres1 Apr 23, 2025
961c7a0
PR - Finalizando relatório de recibos mensal em pdf e adicionando cam…
ArthurTorres1 Apr 23, 2025
03b442d
Feat: Configuração de connection string para produção
ArthurTorres1 Apr 24, 2025
732dc48
subindo Dockerfile
ArthurTorres1 Apr 24, 2025
1b1382a
corrigindo regra de https no docker/prod
ArthurTorres1 Apr 24, 2025
2419cd1
separando banco de produção do banco de teste.
ArthurTorres1 Apr 24, 2025
7b76f07
Create README.md
ArthurTorres1 Apr 25, 2025
bdff6da
autorizando rotas do front no CORS
ArthurTorres1 Apr 25, 2025
8c4f6ec
Merge branch 'master' of https://github.com/ArthurTorres1/FrioAPI
ArthurTorres1 Apr 25, 2025
8d68d95
estilizando readme
ArthurTorres1 Apr 25, 2025
3f399d5
Add files via upload
ArthurTorres1 Apr 25, 2025
04b8f75
finalizando readme
ArthurTorres1 Apr 25, 2025
f6dc921
ajustando o idioma da data do recibo do cliente
ArthurTorres1 Apr 25, 2025
c998ebd
PR - ajustando o idioma da data do recibo do cliente
ArthurTorres1 Apr 25, 2025
60cac1a
Integrando a api do viaCEP, para facilitar o lado do cliente.
ArthurTorres1 Apr 29, 2025
c759bb3
PR - Integrando a api do viaCEP, para facilitar o lado do cliente.
ArthurTorres1 Apr 29, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -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"]
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# 🧾 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
![image](https://github.com/user-attachments/assets/9727aecc-3e28-40a8-b4d6-6ae2f7025230)


## 📖 Como Usar

### 📥 Clonar o Repositório
1. Clone o repositório:
```sh
git clone https://github.com/ArthurTorres1/FrioAPI.git
```
2. Preencha as informações `appsettings.Development.json`;
Binary file added images/image-recibo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 16 additions & 7 deletions src/FrioAPI.Api/Program.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
using FrioAPI.Api.Filters;
using FrioAPI.Application;
using FrioAPI.Application.UseCases.ViaCep;
using FrioAPI.Infrastructure;

var builder = WebApplication.CreateBuilder(args);

// Configura��o de CORS
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowAll", policy =>
{
policy.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
policy.WithOrigins(
"https://frio-front.vercel.app",
"http://localhost:3000"
)
.AllowAnyMethod()
.AllowAnyHeader();
});
});

Expand All @@ -19,9 +25,11 @@

builder.Services.AddMvc(options => options.Filters.Add(typeof(ExceptionFilter)));

//Inje��o de dependencias
// Inje��o de depend�ncias
builder.Services.AddInfrastructure(builder.Configuration);
builder.Services.AddApplication();
builder.Services.AddHttpClient<IBuscaEnderecoViaCep, BuscaEnderecoViaCep>();

var app = builder.Build();

app.UseCors("AllowAll");
Expand All @@ -30,15 +38,16 @@
{
app.UseSwagger();
app.UseSwaggerUI();
app.UseHttpsRedirection(); // HTTPS ativo apenas no ambiente de desenvolvimento
}

else
{
app.UseHttpsRedirection();
// Desabilitar HTTPS para ambientes Docker/produ��o
app.Urls.Add("http://0.0.0.0:5000"); // Aceita conex�es HTTP
}

app.UseAuthorization();

app.MapControllers();

app.Run();
app.Run();
3 changes: 1 addition & 2 deletions src/FrioAPI.Api/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"ConnectionStrings": {
"Connection-dev": "",
"Connection-prod": ""
"Connection-dev": "Server=localhost,1433;Database=friodatabase;User Id=sa;Password=12345;TrustServerCertificate=True;"
}
}
3 changes: 2 additions & 1 deletion src/FrioAPI.Application/DependencyInjectionExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -32,7 +33,7 @@ private static void AddUseCases(IServiceCollection services)
services.AddScoped<IDeleteReciboUseCase, DeleteReciboUseCase>();
services.AddScoped<IGenerateRecibosReportExcelUseCase, GenerateRecibosReportExcelUseCase>();
services.AddScoped<IGenerateRecibosReportPdfUseCase, GenerateRecibosReportPdfUseCase>();

services.AddScoped<IBuscaEnderecoViaCep, BuscaEnderecoViaCep>();
}
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<byte[]> 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<Recibo>(request);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -42,7 +43,9 @@ public async Task<byte[]> 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;

Expand Down
36 changes: 36 additions & 0 deletions src/FrioAPI.Application/UseCases/ViaCep/BuscaEnderecoViaCep.cs
Original file line number Diff line number Diff line change
@@ -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<ResponseViaCep?> 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<ResponseViaCep>(content, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });

if (endereco?.Erro == true)
{
var errorMessages = new List<string>{ ResourceErrorMessages.CEP_NAO_ENCONTRADO };
throw new ErrorOnValidationException(errorMessages);
}
return endereco;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using FrioAPI.Communication.Responses;

namespace FrioAPI.Application.UseCases.ViaCep
{
public interface IBuscaEnderecoViaCep
{
Task<ResponseViaCep?> BuscaCep(string cep);
}
}
11 changes: 11 additions & 0 deletions src/FrioAPI.Communication/Responses/ResponseViaCep.cs
Original file line number Diff line number Diff line change
@@ -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; }
}
}
9 changes: 9 additions & 0 deletions src/FrioAPI.Exception/ResourceErrorMessages.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/FrioAPI.Exception/ResourceErrorMessages.resx
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="CEP_NAO_ENCONTRADO" xml:space="preserve">
<value>O CEP não foi encontrado.</value>
</data>
<data name="CIDADE_OBRIGATORIO" xml:space="preserve">
<value>O campo (Cidade) é obrigatório.</value>
</data>
Expand Down
9 changes: 8 additions & 1 deletion src/FrioAPI.Infrastructure/DepedencyInjectionExtension.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<FrioApiDBContext>(options =>
options.UseSqlServer(connectionString));
Expand Down