Skip to content

Commit

Permalink
Merge pull request #29 from armentanoc/23-criar-anlise-interna-pelo-s…
Browse files Browse the repository at this point in the history
…etor-financeiro

23 criar anlise interna pelo setor financeiro
  • Loading branch information
ig-nunes authored Mar 12, 2024
2 parents 33946a8 + ee6e6ac commit b51f73f
Show file tree
Hide file tree
Showing 13 changed files with 344 additions and 26 deletions.
16 changes: 16 additions & 0 deletions src/SmartRefund.Application/Interfaces/IInternalAnalyzerService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SmartRefund.Domain.Models;
using SmartRefund.ViewModels.Responses;

namespace SmartRefund.Application.Interfaces
{
public interface IInternalAnalyzerService
{
Task<IEnumerable<TranslatedReceiptResponse>> GetAllByStatus();
Task<TranslatedVisionReceipt> UpdateStatus(uint id, string newStatus);
}
}
89 changes: 89 additions & 0 deletions src/SmartRefund.Application/Services/InternalAnalyzerService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
using Microsoft.Extensions.Logging;
using SmartRefund.Application.Interfaces;
using SmartRefund.CustomExceptions;

using SmartRefund.Domain.Enums;
using SmartRefund.Domain.Models;
using SmartRefund.Infra.Interfaces;
using SmartRefund.ViewModels.Responses;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SmartRefund.Application.Services
{
public class InternalAnalyzerService : IInternalAnalyzerService
{
private readonly ITranslatedVisionReceiptRepository _receiptRepository;
private readonly ILogger<InternalAnalyzerService> _logger;

public InternalAnalyzerService(ITranslatedVisionReceiptRepository translatedVisionReceiptRepository, ILogger<InternalAnalyzerService> logger)
{
_receiptRepository = translatedVisionReceiptRepository;
_logger = logger;
}


public async Task<IEnumerable<TranslatedReceiptResponse>> GetAllByStatus()
{
try
{
var receipts = await _receiptRepository.GetAllByStatusAsync(TranslatedVisionReceiptStatusEnum.SUBMETIDO);
return this.ConvertToResponse(receipts);
}
catch
{
throw new InvalidOperationException("Ocorreu um erro ao buscar as notas fiscais!");
}
}

private IEnumerable<TranslatedReceiptResponse> ConvertToResponse(IEnumerable<TranslatedVisionReceipt> receipts)
{
return receipts.Select(receipt =>
new TranslatedReceiptResponse(
total: receipt.Total,
category: receipt.Category.ToString(),
status: receipt.Status.ToString(),
description: receipt.Description
)
);
}



public async Task<TranslatedVisionReceipt> UpdateStatus(uint id, string newStatus)
{
var translatedVisionReceipt = await GetById(id);

if (TryParseStatus(newStatus, out var result))
{
translatedVisionReceipt.SetStatus(result);
var updatedObject = await _receiptRepository.UpdateAsync(translatedVisionReceipt);

return updatedObject;
}

throw new InvalidOperationException("Status enviado inválido!");
}

public bool TryParseStatus(string newStatus, out TranslatedVisionReceiptStatusEnum result)
{
return Enum.TryParse<TranslatedVisionReceiptStatusEnum>(newStatus, true, out result);
}



private async Task<TranslatedVisionReceipt> GetById(uint id)
{
var translatedVisionReceipt = await _receiptRepository.GetAsync(id);

return translatedVisionReceipt;
}
}

}


Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
using SmartRefund.Domain.Models;
using SmartRefund.Domain.Enums;
using SmartRefund.Domain.Models;

namespace SmartRefund.Infra.Interfaces
{
public interface ITranslatedVisionReceiptRepository : IRepository<TranslatedVisionReceipt>
{
Task<IEnumerable<TranslatedVisionReceipt>> GetAllByStatusAsync(TranslatedVisionReceiptStatusEnum status);
}

}
2 changes: 1 addition & 1 deletion src/SmartRefund.Infra/Repositories/Repository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public async Task<T> GetAsync(uint id)
throw new EntityNotFoundException(_specificEntity, id);
}

public async Task<IEnumerable<T>> GetAllAsync()
public async Task<IEnumerable<T>> GetAllAsync()
{
return await _context.Set<T>().ToListAsync();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using SmartRefund.Domain.Models;
using Microsoft.EntityFrameworkCore;
using SmartRefund.Domain.Enums;
using SmartRefund.Domain.Models;
using SmartRefund.Infra.Context;
using SmartRefund.Infra.Interfaces;

Expand All @@ -8,6 +10,13 @@ public class TranslatedVisionReceiptRepository : Repository<TranslatedVisionRece
{
public TranslatedVisionReceiptRepository(AppDbContext context) : base(context)
{

}
public async Task<IEnumerable<TranslatedVisionReceipt>> GetAllByStatusAsync(TranslatedVisionReceiptStatusEnum status)
{
return await _context.Set<TranslatedVisionReceipt>()
.Where(receipt => receipt.Status == status)
.ToListAsync();
}
}
}
124 changes: 124 additions & 0 deletions src/SmartRefund.Tests/ApplicationTests/InternalAnalyzerServiceTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
using System;
using System.Reflection;
using FluentAssertions;
using Microsoft.Extensions.Logging;
using NSubstitute;
using SmartRefund.Application.Services;
using SmartRefund.Domain.Enums;
using SmartRefund.Domain.Models;
using SmartRefund.Infra.Interfaces;
using SmartRefund.ViewModels.Responses;

namespace SmartRefund.Tests.ApplicationTests
{
public class InternalAnalyzerServiceTests
{

[Theory]
[MemberData(nameof(ReceiptData))]
public void ConvertToResponse_Converts_Receipts_To_Response(decimal total, TranslatedVisionReceiptCategoryEnum category, TranslatedVisionReceiptStatusEnum status, string description, decimal expectedTotal, string expectedCategory, string expectedStatus, string expectedDescription)
{
// Arrange
var receipt = new TranslatedVisionReceipt(new RawVisionReceipt(), true, category, status, total, description);
var service = new InternalAnalyzerService(null, null);

MethodInfo methodInfo = typeof(InternalAnalyzerService).GetMethod("ConvertToResponse", BindingFlags.NonPublic | BindingFlags.Instance);
if (methodInfo == null)
{
throw new InvalidOperationException("Método ConvertToResponse não encontrado.");
}
//Act
var result = (IEnumerable<TranslatedReceiptResponse>)methodInfo.Invoke(service, new object[] { new List<TranslatedVisionReceipt> { receipt } });

// Assert
result.Should().NotBeNull();
result.Should().HaveCount(1);
result.First().Total.Should().Be(expectedTotal);
result.First().Category.Should().Be(expectedCategory);
result.First().Status.Should().Be(expectedStatus);
result.First().Description.Should().Be(expectedDescription);
}

public static TheoryData<decimal, TranslatedVisionReceiptCategoryEnum, TranslatedVisionReceiptStatusEnum, string, decimal, string, string, string> ReceiptData()
{
return new TheoryData<decimal, TranslatedVisionReceiptCategoryEnum, TranslatedVisionReceiptStatusEnum, string, decimal, string, string, string>
{
{ 100, TranslatedVisionReceiptCategoryEnum.ALIMENTACAO, TranslatedVisionReceiptStatusEnum.SUBMETIDO, "Receipt description 1", 100, "ALIMENTACAO", "SUBMETIDO", "Receipt description 1" },
{ 200, TranslatedVisionReceiptCategoryEnum.TRANSPORTE, TranslatedVisionReceiptStatusEnum.PAGA, "Receipt description 2", 200, "TRANSPORTE", "PAGA", "Receipt description 2" },
{ 150, TranslatedVisionReceiptCategoryEnum.HOSPEDAGEM, TranslatedVisionReceiptStatusEnum.SUBMETIDO, "Receipt description 3", 150, "HOSPEDAGEM", "SUBMETIDO", "Receipt description 3" }
};
}


[Theory]
[InlineData(1, "SUBMETIDO", TranslatedVisionReceiptStatusEnum.SUBMETIDO)]
[InlineData(1, "PAGA", TranslatedVisionReceiptStatusEnum.PAGA)]
[InlineData(1, "RECUSADA", TranslatedVisionReceiptStatusEnum.RECUSADA)]
public async Task UpdateStatus_Should_Update_TranslatedVisionReceipt_Status(uint id, string newStatus, TranslatedVisionReceiptStatusEnum expectedStatus)
{
// Arrange
var receipt = new TranslatedVisionReceipt(
new RawVisionReceipt(),
true,
TranslatedVisionReceiptCategoryEnum.ALIMENTACAO,
TranslatedVisionReceiptStatusEnum.SUBMETIDO,
100,
"Receipt description 1");
var updatedReceipt = new TranslatedVisionReceipt(
new RawVisionReceipt(),
true,
TranslatedVisionReceiptCategoryEnum.ALIMENTACAO,
expectedStatus,
100,
"Receipt description 1");
receipt.SetId(id);
updatedReceipt.SetId(id);

var repository = Substitute.For<ITranslatedVisionReceiptRepository>();
repository.GetAsync(1).Returns(receipt);
repository.UpdateAsync(Arg.Is<TranslatedVisionReceipt>(r => r.Id == id)).Returns(updatedReceipt);

var logger = Substitute.For<ILogger<InternalAnalyzerService>>();
var service = new InternalAnalyzerService(repository, logger);

// Act
var result = await service.UpdateStatus(1, newStatus);

// Assert
result.Status.Should().Be(expectedStatus);
}


[Theory]
[InlineData("SUBMETIDo", TranslatedVisionReceiptStatusEnum.SUBMETIDO)]
[InlineData("PaGA", TranslatedVisionReceiptStatusEnum.PAGA)]
[InlineData("REcUSADA", TranslatedVisionReceiptStatusEnum.RECUSADA)]
public void TryParseStatus_Should_Parse_Valid_Status(string statusString, TranslatedVisionReceiptStatusEnum expectedStatus)
{
// Arrange
var service = new InternalAnalyzerService(null, null);

// Act
var result = service.TryParseStatus(statusString, out var parsedStatus);

// Assert
result.Should().BeTrue();
parsedStatus.Should().Be(expectedStatus);
}

[Fact]
public void TryParseStatus_Should_Return_False_For_Invalid_Status()
{
// Arrange
var service = new InternalAnalyzerService(null, null);

// Act
var result = service.TryParseStatus("INVALID_STATUS", out var parsedStatus);

// Assert
result.Should().BeFalse();
}

}

}
24 changes: 24 additions & 0 deletions src/SmartRefund.ViewModels/Requests/UpdateTVRStatusRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SmartRefund.ViewModels.Requests
{
public class UpdateTVRStatusRequest
{
[Required(ErrorMessage = "Id is required.")]
public uint Id { get; init; }

[Required(ErrorMessage = "New status is required.")]
public string NewStatus { get; init; }

public UpdateTVRStatusRequest(string newStatus, uint id)
{
NewStatus = newStatus;
Id = id;
}
}
}
28 changes: 28 additions & 0 deletions src/SmartRefund.ViewModels/Responses/TranslatedReceiptResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SmartRefund.ViewModels.Responses
{
public class TranslatedReceiptResponse
{
public decimal Total { get; set; }
public string Category { get; set; }
public string Status { get; set; }
public string Description { get; set; }

public TranslatedReceiptResponse()

Check warning on line 16 in src/SmartRefund.ViewModels/Responses/TranslatedReceiptResponse.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Category' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 16 in src/SmartRefund.ViewModels/Responses/TranslatedReceiptResponse.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Status' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
{

}
public TranslatedReceiptResponse(decimal total, string category, string status, string description)
{
Total = total;
Category = category;
Status = status;
Description = description;
}
}
}
42 changes: 42 additions & 0 deletions src/SmartRefund.WebAPI/Controllers/ManagementController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using Microsoft.AspNetCore.Mvc;
using SmartRefund.Application.Interfaces;
using SmartRefund.Application.Services;
using SmartRefund.Domain.Enums;
using SmartRefund.Infra.Interfaces;
using SmartRefund.ViewModels.Requests;
using Swashbuckle.AspNetCore.Annotations;

namespace SmartRefund.WebAPI.Controllers
{
[ApiController]
[Route("[controller]")]
public class ManagementController : Controller
{
private readonly IInternalAnalyzerService _analyzerService;

public ManagementController(IInternalAnalyzerService analyzerService)
{
_analyzerService = analyzerService;
}

[HttpGet("receipts/submitted")]
public async Task<IActionResult> GetAllByStatus()
{
var receipts = await _analyzerService.GetAllByStatus();
if (receipts != null && receipts.Count() != 0)
return Ok(receipts);

return NotFound();
}

[HttpPatch]
[Route("update-status")]
[SwaggerOperation("Update TranslatedVisionReceipt's Status.")]
public async Task<IActionResult> UpdateStatus([FromBody] UpdateTVRStatusRequest updateRequest)
{
var UpdatedObject = await _analyzerService.UpdateStatus(updateRequest.Id, updateRequest.NewStatus);
return Ok(UpdatedObject);
}

}
}
21 changes: 0 additions & 21 deletions src/SmartRefund.WebAPI/Controllers/WeatherForecastController.cs

This file was deleted.

Loading

0 comments on commit b51f73f

Please sign in to comment.