diff --git a/OpenAdm.Api/Controllers/LojasParceirasController.cs b/OpenAdm.Api/Controllers/LojasParceirasController.cs new file mode 100644 index 0000000..e5a7fad --- /dev/null +++ b/OpenAdm.Api/Controllers/LojasParceirasController.cs @@ -0,0 +1,87 @@ +using Microsoft.AspNetCore.Mvc; +using OpenAdm.Application.Dtos.LojaParceira; +using OpenAdm.Application.Interfaces; +using OpenAdm.Infra.Paginacao; + +namespace OpenAdm.Api.Controllers; + +[ApiController] +[Route("lojas-parceiras")] +public class LojasParceirasController : ControllerBaseApi +{ + private readonly ILojasParceirasService _lojasParceirasService; + + public LojasParceirasController(ILojasParceirasService lojasParceirasService) + { + _lojasParceirasService = lojasParceirasService; + } + + [HttpGet("paginacao")] + public async Task Paginacao([FromQuery] PaginacaoLojasParceirasDto paginacaoLojasParceirasDto) + { + try + { + var paginacao = await _lojasParceirasService.GetPaginacaoAsync(paginacaoLojasParceirasDto); + return Ok(paginacao); + } + catch (Exception ex) + { + return await HandleErrorAsync(ex); + } + } + + [HttpPost("create")] + public async Task Create(CreateLojaParceiraDto createLojaParceiraDto) + { + try + { + var lojaParceiraViewModel = await _lojasParceirasService.CreateLojaParceiraAsync(createLojaParceiraDto); + return Ok(lojaParceiraViewModel); + } + catch (Exception ex) + { + return await HandleErrorAsync(ex); + } + } + + [HttpPut("update")] + public async Task Update(UpdateLojaParceiraDto updateLojaParceiraDto) + { + try + { + var lojaParceiraViewModel = await _lojasParceirasService.UpdateLojaParceiraAsync(updateLojaParceiraDto); + return Ok(lojaParceiraViewModel); + } + catch (Exception ex) + { + return await HandleErrorAsync(ex); + } + } + + [HttpGet("get-loja")] + public async Task GetLoja([FromQuery] Guid id) + { + try + { + var lojaParceiraViewModel = await _lojasParceirasService.GetLojasParceirasViewModelAsync(id); + return Ok(lojaParceiraViewModel); + } + catch (Exception ex) + { + return await HandleErrorAsync(ex); + } + } + [HttpDelete("delete")] + public async Task DeleteLoja([FromQuery] Guid id) + { + try + { + await _lojasParceirasService.DeleteLojaParceiraAsync(id); + return Ok(); + } + catch (Exception ex) + { + return await HandleErrorAsync(ex); + } + } +} diff --git a/OpenAdm.Application/Dtos/LojaParceira/CreateLojaParceiraDto.cs b/OpenAdm.Application/Dtos/LojaParceira/CreateLojaParceiraDto.cs new file mode 100644 index 0000000..3ec5ecd --- /dev/null +++ b/OpenAdm.Application/Dtos/LojaParceira/CreateLojaParceiraDto.cs @@ -0,0 +1,39 @@ +using Domain.Pkg.Entities; +using System.ComponentModel.DataAnnotations; + +namespace OpenAdm.Application.Dtos.LojaParceira; + +public class CreateLojaParceiraDto +{ + [Required] + [MaxLength(255)] + public string Nome { get; set; } = string.Empty; + + [MaxLength(500)] + public string? Instagram { get; set; } + [MaxLength(500)] + public string? Facebook { get; set; } + [MaxLength(500)] + public string? Endereco { get; set; } + [MaxLength(20)] + public string? Contato { get; set; } + public string? Foto { get; set; } + + public LojasParceiras ToEntity(string? nomeFoto) + { + var date = DateTime.Now; + + return new LojasParceiras( + Guid.NewGuid(), + date, + date, + 0, + Nome, + nomeFoto, + Foto, + Instagram, + Facebook, + Endereco, + Contato); + } +} diff --git a/OpenAdm.Application/Dtos/LojaParceira/UpdateLojaParceiraDto.cs b/OpenAdm.Application/Dtos/LojaParceira/UpdateLojaParceiraDto.cs new file mode 100644 index 0000000..2ff2660 --- /dev/null +++ b/OpenAdm.Application/Dtos/LojaParceira/UpdateLojaParceiraDto.cs @@ -0,0 +1,21 @@ +using System.ComponentModel.DataAnnotations; + +namespace OpenAdm.Application.Dtos.LojaParceira; + +public class UpdateLojaParceiraDto +{ + public Guid Id { get; set; } + [Required] + [MaxLength(255)] + public string Nome { get; set; } = string.Empty; + + [MaxLength(500)] + public string? Instagram { get; set; } + [MaxLength(500)] + public string? Facebook { get; set; } + [MaxLength(500)] + public string? Endereco { get; set; } + [MaxLength(20)] + public string? Contato { get; set; } + public string? Foto { get; set; } +} diff --git a/OpenAdm.Application/Interfaces/ILojasParceirasService.cs b/OpenAdm.Application/Interfaces/ILojasParceirasService.cs new file mode 100644 index 0000000..a408bf6 --- /dev/null +++ b/OpenAdm.Application/Interfaces/ILojasParceirasService.cs @@ -0,0 +1,15 @@ +using OpenAdm.Application.Dtos.LojaParceira; +using OpenAdm.Application.Models.LojasParceira; +using OpenAdm.Domain.Model; +using OpenAdm.Infra.Paginacao; + +namespace OpenAdm.Application.Interfaces; + +public interface ILojasParceirasService +{ + Task> GetPaginacaoAsync(PaginacaoLojasParceirasDto paginacaoLojasParceirasDto); + Task GetLojasParceirasViewModelAsync(Guid id); + Task CreateLojaParceiraAsync(CreateLojaParceiraDto createLojaParceiraDto); + Task UpdateLojaParceiraAsync(UpdateLojaParceiraDto updateLojaParceiraDto); + Task DeleteLojaParceiraAsync(Guid id); +} diff --git a/OpenAdm.Application/Models/LojasParceira/LojasParceirasViewModel.cs b/OpenAdm.Application/Models/LojasParceira/LojasParceirasViewModel.cs new file mode 100644 index 0000000..84b15a8 --- /dev/null +++ b/OpenAdm.Application/Models/LojasParceira/LojasParceirasViewModel.cs @@ -0,0 +1,29 @@ +using Domain.Pkg.Entities; + +namespace OpenAdm.Application.Models.LojasParceira; + +public class LojasParceirasViewModel : BaseModel +{ + public string Nome { get; set; } = string.Empty; + public string? Foto { get; set; } + public string? Instagram { get; set; } + public string? Facebook { get; set; } + public string? Endereco { get; set; } + public string? Contato { get; set; } + + public LojasParceirasViewModel ToModel(LojasParceiras lojasParceiras) + { + Id = lojasParceiras.Id; + DataDeAtualizacao = lojasParceiras.DataDeAtualizacao; + Numero = lojasParceiras.Numero; + DataDeCriacao = lojasParceiras.DataDeCriacao; + Foto = lojasParceiras.Foto; + Instagram = lojasParceiras.Instagram; + Facebook = lojasParceiras.Facebook; + Endereco = lojasParceiras.Endereco; + Contato = lojasParceiras.Contato; + Nome = lojasParceiras.Nome; + + return this; + } +} diff --git a/OpenAdm.Application/Services/LojasParceirasService.cs b/OpenAdm.Application/Services/LojasParceirasService.cs new file mode 100644 index 0000000..ecec9a1 --- /dev/null +++ b/OpenAdm.Application/Services/LojasParceirasService.cs @@ -0,0 +1,115 @@ +using Domain.Pkg.Entities; +using Domain.Pkg.Errors; +using Domain.Pkg.Exceptions; +using OpenAdm.Application.Dtos.LojaParceira; +using OpenAdm.Application.Interfaces; +using OpenAdm.Application.Models.LojasParceira; +using OpenAdm.Domain.Interfaces; +using OpenAdm.Domain.Model; +using OpenAdm.Infra.Azure.Interfaces; +using OpenAdm.Infra.Paginacao; + +namespace OpenAdm.Application.Services; + +public class LojasParceirasService : ILojasParceirasService +{ + private readonly ILojasParceirasRepository _lojasParceirasRepository; + private readonly IUploadImageBlobClient _uploadImageBlobClient; + + public LojasParceirasService(ILojasParceirasRepository lojasParceirasRepository, IUploadImageBlobClient uploadImageBlobClient) + { + _lojasParceirasRepository = lojasParceirasRepository; + _uploadImageBlobClient = uploadImageBlobClient; + } + + public async Task CreateLojaParceiraAsync(CreateLojaParceiraDto createLojaParceiraDto) + { + var nomeFoto = string.Empty; + if (!string.IsNullOrWhiteSpace(createLojaParceiraDto.Foto)) + { + nomeFoto = $"{Guid.NewGuid()}.jpg"; + createLojaParceiraDto.Foto = await _uploadImageBlobClient.UploadImageAsync(createLojaParceiraDto.Foto, nomeFoto); + } + + var lojaParceira = createLojaParceiraDto.ToEntity(nomeFoto); + + await _lojasParceirasRepository.AddAsync(lojaParceira); + + return new LojasParceirasViewModel().ToModel(lojaParceira); + } + + public async Task DeleteLojaParceiraAsync(Guid id) + { + var lojaParceira = await GetLojaAsync(id); + + if (!string.IsNullOrWhiteSpace(lojaParceira.NomeFoto)) + { + await _uploadImageBlobClient.DeleteImageAsync(lojaParceira.NomeFoto); + } + + await _lojasParceirasRepository.DeleteAsync(lojaParceira); + } + + public async Task GetLojasParceirasViewModelAsync(Guid id) + { + var lojaParceira = await GetLojaAsync(id); + + return new LojasParceirasViewModel().ToModel(lojaParceira); + } + + public async Task> GetPaginacaoAsync(PaginacaoLojasParceirasDto paginacaoLojasParceirasDto) + { + var paginacao = await _lojasParceirasRepository.GetPaginacaoLojasParceirasAsync(paginacaoLojasParceirasDto); + + return new PaginacaoViewModel() + { + TotalPage = paginacao.TotalPage, + Values = paginacao + .Values + .Select(x => + new LojasParceirasViewModel().ToModel(x)) + .ToList() + }; + } + + public async Task UpdateLojaParceiraAsync(UpdateLojaParceiraDto updateLojaParceiraDto) + { + var lojaParceira = await GetLojaAsync(updateLojaParceiraDto.Id); + + var foto = lojaParceira.Foto; + var nomeFoto = lojaParceira.NomeFoto; + + if(!string.IsNullOrWhiteSpace(updateLojaParceiraDto.Foto) && !updateLojaParceiraDto.Foto.StartsWith("https://")) + { + if (!string.IsNullOrWhiteSpace(nomeFoto)) + { + var resultDeleteFoto = await _uploadImageBlobClient.DeleteImageAsync(nomeFoto); + if (!resultDeleteFoto) + throw new ExceptionApi("Não foi possível excluir a foto da loja, tente novamente mais tarde, ou entre em contato com o suporte!"); + + nomeFoto = $"{Guid.NewGuid()}.jpg"; + + foto = await _uploadImageBlobClient.UploadImageAsync(updateLojaParceiraDto.Foto, nomeFoto); + } + } + + lojaParceira.Update( + updateLojaParceiraDto.Nome, + nomeFoto, + foto, + updateLojaParceiraDto.Instagram, + updateLojaParceiraDto.Facebook, + updateLojaParceiraDto.Endereco, + updateLojaParceiraDto.Contato); + + await _lojasParceirasRepository.UpdateAsync(lojaParceira); + + return new LojasParceirasViewModel().ToModel(lojaParceira); + } + + private async Task GetLojaAsync(Guid id) + { + return await _lojasParceirasRepository.GetLojaParceiraByIdAsync(id) + ?? throw new ExceptionApi(CodigoErrors.RegistroNotFound); + } +} diff --git a/OpenAdm.Domain/Interfaces/ILojasParceirasRepository.cs b/OpenAdm.Domain/Interfaces/ILojasParceirasRepository.cs new file mode 100644 index 0000000..bb2a79f --- /dev/null +++ b/OpenAdm.Domain/Interfaces/ILojasParceirasRepository.cs @@ -0,0 +1,10 @@ +using Domain.Pkg.Entities; +using OpenAdm.Domain.Model; + +namespace OpenAdm.Domain.Interfaces; + +public interface ILojasParceirasRepository : IGenericRepository +{ + Task> GetPaginacaoLojasParceirasAsync(FilterModel filterModel); + Task GetLojaParceiraByIdAsync(Guid id); +} diff --git a/OpenAdm.Domain/OpenAdm.Domain.csproj b/OpenAdm.Domain/OpenAdm.Domain.csproj index cc855ef..0914646 100644 --- a/OpenAdm.Domain/OpenAdm.Domain.csproj +++ b/OpenAdm.Domain/OpenAdm.Domain.csproj @@ -7,7 +7,7 @@ - + diff --git a/OpenAdm.Infra/Context/ParceiroContext.cs b/OpenAdm.Infra/Context/ParceiroContext.cs index 967497e..822c18a 100644 --- a/OpenAdm.Infra/Context/ParceiroContext.cs +++ b/OpenAdm.Infra/Context/ParceiroContext.cs @@ -30,6 +30,7 @@ public class ParceiroContext(DbContextOptions options, IDomainFactory domainFact public DbSet ConfiguracoesDePedidos { get; set; } public DbSet Estoques { get; set; } public DbSet MovimentacoesDeProdutos { get; set; } + public DbSet LojasParceiras { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { @@ -61,5 +62,6 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.ApplyConfiguration(new ConfiguracoesDePedidoConfiguration()); modelBuilder.ApplyConfiguration(new EstoqueConfiguration()); modelBuilder.ApplyConfiguration(new MovimentacaoDeProdutoConfiguration()); + modelBuilder.ApplyConfiguration(new LojasParceirasConfiguration()); } } diff --git a/OpenAdm.Infra/EntityConfiguration/LojasParceirasConfiguration.cs b/OpenAdm.Infra/EntityConfiguration/LojasParceirasConfiguration.cs new file mode 100644 index 0000000..c9a266b --- /dev/null +++ b/OpenAdm.Infra/EntityConfiguration/LojasParceirasConfiguration.cs @@ -0,0 +1,38 @@ +using Domain.Pkg.Entities; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Metadata.Builders; + +namespace OpenAdm.Infra.EntityConfiguration; + +public class LojasParceirasConfiguration : IEntityTypeConfiguration +{ + public void Configure(EntityTypeBuilder builder) + { + builder.HasKey(x => x.Id); + builder.Property(x => x.DataDeCriacao) + .IsRequired() + .ValueGeneratedOnAdd() + .HasDefaultValueSql("now()"); + builder.Property(x => x.DataDeAtualizacao) + .IsRequired() + .ValueGeneratedOnAddOrUpdate() + .HasDefaultValueSql("now()"); + builder.Property(x => x.Numero) + .ValueGeneratedOnAdd(); + builder.Property(x => x.NomeFoto) + .HasMaxLength(500); + builder.Property(x => x.Foto) + .HasMaxLength(500); + builder.Property(x => x.Instagram) + .HasMaxLength(500); + builder.Property(x => x.Facebook) + .HasMaxLength(500); + builder.Property(x => x.Endereco) + .HasMaxLength(500); + builder.Property(x => x.Contato) + .HasMaxLength(20); + builder.Property(x => x.Nome) + .IsRequired() + .HasMaxLength(255); + } +} diff --git a/OpenAdm.Infra/Paginacao/PaginacaoLojasParceirasDto.cs b/OpenAdm.Infra/Paginacao/PaginacaoLojasParceirasDto.cs new file mode 100644 index 0000000..532ea9a --- /dev/null +++ b/OpenAdm.Infra/Paginacao/PaginacaoLojasParceirasDto.cs @@ -0,0 +1,17 @@ +using Domain.Pkg.Entities; +using Microsoft.EntityFrameworkCore; +using OpenAdm.Domain.Model; +using System.Linq.Expressions; + +namespace OpenAdm.Infra.Paginacao; + +public class PaginacaoLojasParceirasDto : FilterModel +{ + public override Expression>? GetWhereBySearch() + { + if (string.IsNullOrWhiteSpace(Search)) + return null; + + return x => EF.Functions.ILike(EF.Functions.Unaccent(x.Nome), $"%{Search}%"); + } +} diff --git a/OpenAdm.Infra/Repositories/LojasParceirasRepository.cs b/OpenAdm.Infra/Repositories/LojasParceirasRepository.cs new file mode 100644 index 0000000..dd95f50 --- /dev/null +++ b/OpenAdm.Infra/Repositories/LojasParceirasRepository.cs @@ -0,0 +1,42 @@ +using Domain.Pkg.Entities; +using Microsoft.EntityFrameworkCore; +using OpenAdm.Domain.Interfaces; +using OpenAdm.Domain.Model; +using OpenAdm.Infra.Context; +using OpenAdm.Infra.Extensions.IQueryable; + +namespace OpenAdm.Infra.Repositories; + +public class LojasParceirasRepository : GenericRepository, ILojasParceirasRepository +{ + private readonly ParceiroContext _parceiroContext; + public LojasParceirasRepository(ParceiroContext parceiroContext) : base(parceiroContext) + { + _parceiroContext = parceiroContext; + } + + public async Task GetLojaParceiraByIdAsync(Guid id) + { + return await _parceiroContext + .LojasParceiras + .AsNoTracking() + .FirstOrDefaultAsync(x => x.Id == id); + } + + public async Task> GetPaginacaoLojasParceirasAsync(FilterModel filterModel) + { + var (total, values) = await _parceiroContext + .LojasParceiras + .AsNoTracking() + .AsQueryable() + .OrderByDescending(x => EF.Property(x, filterModel.OrderBy)) + .WhereIsNotNull(filterModel.GetWhereBySearch()) + .CustomFilterAsync(filterModel); + + return new() + { + TotalPage = total, + Values = values + }; + } +} diff --git a/OpenAdm.IoC/DependencyInjectRepositories.cs b/OpenAdm.IoC/DependencyInjectRepositories.cs index 2fb0b5b..1fa4892 100644 --- a/OpenAdm.IoC/DependencyInjectRepositories.cs +++ b/OpenAdm.IoC/DependencyInjectRepositories.cs @@ -70,5 +70,6 @@ public static void InjectRepositories(this IServiceCollection services, string c services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); } } diff --git a/OpenAdm.IoC/DependencyInjectyApplication.cs b/OpenAdm.IoC/DependencyInjectyApplication.cs index fd02e32..116c0dd 100644 --- a/OpenAdm.IoC/DependencyInjectyApplication.cs +++ b/OpenAdm.IoC/DependencyInjectyApplication.cs @@ -30,5 +30,6 @@ public static void InjectServices(this IServiceCollection services) services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); } }