-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
merge 23-criar-anaalise-interna-pelo-setor-financeiro into main
- Loading branch information
Showing
36 changed files
with
1,103 additions
and
123 deletions.
There are no files selected for viewing
8 changes: 8 additions & 0 deletions
8
src/SmartRefund.Application/Interfaces/IFileValidatorService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,15 @@ | ||
| ||
using Microsoft.AspNetCore.Http; | ||
using SmartRefund.Domain.Models; | ||
|
||
namespace SmartRefund.Application.Interfaces | ||
{ | ||
public interface IFileValidatorService | ||
{ | ||
public Task<InternalReceipt?> Validate(IFormFile file, uint employeeId); | ||
|
||
public bool ValidateExtension(string fileName); | ||
|
||
public bool ValidateSize(long lenght); | ||
} | ||
} |
14 changes: 14 additions & 0 deletions
14
src/SmartRefund.Application/Interfaces/IVisionTranslatorService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
using SmartRefund.Domain.Enums; | ||
using SmartRefund.Domain.Models; | ||
|
||
namespace SmartRefund.Application.Interfaces | ||
{ | ||
public interface IVisionTranslatorService | ||
{ | ||
Task<TranslatedVisionReceipt> GetTranslatedVisionReceipt(RawVisionReceipt rawVisionReceipt); | ||
bool GetIsReceipt(string isReceipt); | ||
TranslatedVisionReceiptCategoryEnum GetCategory(string category); | ||
decimal GetTotal(string total); | ||
string GetDescription(string description); | ||
} | ||
} |
101 changes: 98 additions & 3 deletions
101
src/SmartRefund.Application/Services/FileValidatorService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,112 @@ | ||
using Microsoft.Extensions.Logging; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.Extensions.Logging; | ||
using SmartRefund.Application.Interfaces; | ||
using SmartRefund.Domain.Models; | ||
using SmartRefund.Infra.Interfaces; | ||
using System.Reflection.PortableExecutable; | ||
|
||
|
||
namespace SmartRefund.Application.Services | ||
{ | ||
public class FileValidatorService : IFileValidatorService | ||
{ | ||
private IRepositoryTeste _repository; | ||
private IInternalReceiptRepository _repository; | ||
private ILogger<FileValidatorService> _logger; | ||
public FileValidatorService(IRepositoryTeste repository, ILogger<FileValidatorService> logger) | ||
private string? _errormessage; | ||
public string? ErrorMessage | ||
{ | ||
get | ||
{ | ||
return _errormessage; | ||
} | ||
private set | ||
{ | ||
_errormessage = value; | ||
} | ||
} | ||
|
||
public FileValidatorService(IInternalReceiptRepository repository, ILogger<FileValidatorService> logger) | ||
{ | ||
_repository = repository; | ||
_logger = logger; | ||
} | ||
|
||
public async Task<InternalReceipt?> Validate(IFormFile file, uint employeeId) | ||
{ | ||
|
||
if (ValidateSize(file.Length) && ValidateType(file) && ValidateExtension(file.FileName)) //await | ||
{ | ||
byte[] imageBytes; | ||
using (var memoryStream = new MemoryStream()) | ||
{ | ||
await file.CopyToAsync(memoryStream); | ||
imageBytes = memoryStream.ToArray(); | ||
} | ||
|
||
InternalReceipt receipt = new InternalReceipt(employeeId, imageBytes); | ||
|
||
await _repository.AddAsync(receipt); | ||
|
||
return receipt; | ||
} | ||
|
||
return null; | ||
|
||
} | ||
|
||
public bool ValidateSize(long lenght) | ||
{ | ||
if (lenght >= 20 * 1024 * 1024) | ||
{ | ||
throw new ArgumentException("Arquivo é maior do que 20MB"); | ||
} | ||
return true; | ||
} | ||
|
||
public bool ValidateExtension(string fileName) | ||
{ | ||
var extension = Path.GetExtension(fileName); | ||
|
||
string[] possibleExtensions = [".png", ".jpg", ".jpeg"]; | ||
|
||
if(possibleExtensions.Contains(extension)) | ||
{ | ||
return true; | ||
} | ||
else | ||
{ | ||
throw new ArgumentException("Extensão não permitida"); | ||
} | ||
|
||
} | ||
|
||
public bool ValidateType(IFormFile file) //async Task<bool> | ||
{ | ||
//byte[] header = new byte[4]; | ||
//using (var memoryStream = new MemoryStream()) | ||
//{ | ||
// await file.CopyToAsync(memoryStream); | ||
// memoryStream.Read(header, 0, 4); | ||
//} | ||
|
||
//if (IsJpeg(header) || IsPng(header)) | ||
//{ | ||
return true; | ||
//} | ||
|
||
//throw new ArgumentException("Extensão não permitida"); | ||
} | ||
|
||
private static bool IsJpeg(byte[] header) | ||
{ | ||
// Verifica se os primeiros bytes correspondem ao header de um arquivo JPG | ||
return header[0] == 0xFF && header[1] == 0xD8 && header[2] == 0xFF; | ||
} | ||
|
||
private static bool IsPng(byte[] header) | ||
{ | ||
// Verifica se os primeiros bytes correspondem ao header de um arquivo PNG | ||
return header[0] == 0x89 && header[1] == 0x50 && header[2] == 0x4E && header[3] == 0x47; | ||
} | ||
} | ||
} |
173 changes: 173 additions & 0 deletions
173
src/SmartRefund.Application/Services/VisionTranslatorService.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
using Microsoft.Extensions.Logging; | ||
using SmartRefund.Application.Interfaces; | ||
using SmartRefund.CustomExceptions; | ||
using SmartRefund.Domain.Enums; | ||
using SmartRefund.Domain.Models; | ||
using SmartRefund.Infra.Interfaces; | ||
using System.Globalization; | ||
using System.Text; | ||
using System.Text.RegularExpressions; | ||
|
||
namespace SmartRefund.Application.Services | ||
{ | ||
public class VisionTranslatorService : IVisionTranslatorService | ||
{ | ||
private ITranslatedVisionReceiptRepository _translatorRepository; | ||
private IRawVisionReceiptRepository _rawRepository; | ||
private ILogger<VisionTranslatorService> _logger; | ||
|
||
public VisionTranslatorService(ITranslatedVisionReceiptRepository translatorRepository, IRawVisionReceiptRepository rawRepository, ILogger<VisionTranslatorService> logger) | ||
{ | ||
_translatorRepository = translatorRepository; | ||
_rawRepository = rawRepository; | ||
_logger = logger; | ||
} | ||
|
||
public async Task<TranslatedVisionReceipt> GetTranslatedVisionReceipt(RawVisionReceipt rawVisionReceipt) | ||
{ | ||
if(rawVisionReceipt.IsTranslated) | ||
throw new ReceiptAlreadyTranslatedException(rawVisionReceipt.Id); | ||
|
||
TranslatedVisionReceipt translatedVisionReceipt = | ||
|
||
new TranslatedVisionReceipt( | ||
rawVisionReceipt : rawVisionReceipt, | ||
isReceipt: GetIsReceipt(rawVisionReceipt.IsReceipt), | ||
category: GetCategory(rawVisionReceipt.Category), | ||
status: TranslatedVisionReceiptStatusEnum.SUBMETIDO, | ||
total: GetTotal(rawVisionReceipt.Total), | ||
description: GetDescription(rawVisionReceipt.Description) | ||
); | ||
|
||
var addedReceipt = await _translatorRepository.AddAsync(translatedVisionReceipt); | ||
rawVisionReceipt.SetIsTranslated(true); | ||
var updatedRawReceipt = await _rawRepository.UpdateAsync(rawVisionReceipt); | ||
|
||
LogSuccess(addedReceipt, updatedRawReceipt); | ||
|
||
return addedReceipt; | ||
} | ||
|
||
public bool GetIsReceipt(string isReceipt) | ||
{ | ||
if (string.IsNullOrWhiteSpace(isReceipt)) | ||
throw new FieldIsNullOrWhitespaceException("IsRecept", isReceipt); | ||
|
||
bool isYes = Regex.IsMatch(isReceipt, @"\bsim\b", RegexOptions.IgnoreCase); | ||
bool isNo = Regex.IsMatch(isReceipt, @"\bn(ã|a)o\b", RegexOptions.IgnoreCase); | ||
bool isReceiptBool; | ||
|
||
if (isYes && !isNo) | ||
isReceiptBool = true; | ||
else if (isNo) | ||
isReceiptBool = false; | ||
else | ||
throw new UnnableToTranslateException("IsReceipt", isReceipt); | ||
|
||
LogInformation("IsReceipt", isReceipt, isReceiptBool.ToString()); | ||
return isReceiptBool; | ||
} | ||
public TranslatedVisionReceiptCategoryEnum GetCategory(string category) | ||
{ | ||
if (string.IsNullOrWhiteSpace(category)) | ||
throw new FieldIsNullOrWhitespaceException("Category", category); | ||
|
||
string cleanCategory = RemoveDiacritics(category) | ||
.ToLower().Replace("ç", "c").Replace("ã", "a"); | ||
//por que é necessário se o RemoveDiacritics passa no teste??? | ||
|
||
string enumCandidate = GetMatchingCategory(cleanCategory); | ||
|
||
if (Enum.TryParse(enumCandidate, out TranslatedVisionReceiptCategoryEnum result)) | ||
{ | ||
LogInformation("Category", category, result.ToString()); | ||
return result; | ||
} | ||
|
||
throw new UnnableToTranslateException("Category", category); | ||
} | ||
public decimal GetTotal(string total) | ||
{ | ||
if (string.IsNullOrWhiteSpace(total)) | ||
throw new FieldIsNullOrWhitespaceException("Total", total); | ||
|
||
string numberPattern = @"[\d]+(?:[,.][\d]+)*"; | ||
Match match = Regex.Match(total, numberPattern); | ||
|
||
if (match.Success) | ||
{ | ||
string decimalString = match.Value; | ||
|
||
if (decimalString.Length >= 3 && decimalString[decimalString.Length - 3] == ',') | ||
decimalString = decimalString.Remove(decimalString.Length - 3, 1).Insert(decimalString.Length - 3, "."); | ||
|
||
for (int i = 0; i < decimalString.Length; i++) | ||
{ | ||
if (i != decimalString.Length - 3 && decimalString[i] == '.') | ||
decimalString = decimalString.Remove(i, 1); | ||
} | ||
|
||
if (decimal.TryParse(decimalString, NumberStyles.Any, CultureInfo.InvariantCulture, out decimal decimalValue)) | ||
{ | ||
LogInformation("Total", total, decimalValue.ToString()); | ||
return decimalValue; | ||
} | ||
else | ||
throw new UnnableToTranslateException("Total", $"couldn't parse to decimal - {total}"); | ||
} | ||
else | ||
{ | ||
throw new UnnableToTranslateException("Total", $"no number found at string - {total}"); | ||
} | ||
} | ||
public string GetDescription(string description) | ||
{ | ||
if (string.IsNullOrWhiteSpace(description)) | ||
throw new FieldIsNullOrWhitespaceException("Description", description); | ||
|
||
string cleanDescription = description.Replace("\n", "").Trim(); | ||
LogInformation("Description", description, cleanDescription); | ||
return cleanDescription; | ||
} | ||
|
||
#region Aux Category Methods | ||
public string GetMatchingCategory(string cleanCategory) | ||
{ | ||
var validCategories = Enum.GetNames(typeof(TranslatedVisionReceiptCategoryEnum)); | ||
|
||
return validCategories.FirstOrDefault(validCategory => | ||
cleanCategory.Contains(validCategory, StringComparison.OrdinalIgnoreCase)) | ||
?? "OUTROS"; | ||
} | ||
|
||
public string RemoveDiacritics(string text) | ||
{ | ||
string normalizedText = text.Normalize(NormalizationForm.FormD); | ||
StringBuilder result = new StringBuilder(); | ||
|
||
foreach (char c in normalizedText) | ||
{ | ||
if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark) | ||
result.Append(c); | ||
} | ||
|
||
return result.ToString(); | ||
} | ||
|
||
#endregion | ||
|
||
#region Log Aux | ||
private void LogSuccess(TranslatedVisionReceipt addedReceipt, RawVisionReceipt updatedRawReceipt) | ||
{ | ||
_logger.LogInformation($"Receipt translated and saved to database " + | ||
$"as TranslatedVisionReceipt (Id {addedReceipt.Id}) " + | ||
$"and RawVisionReceiptUpdated marked as translated (Id {updatedRawReceipt.Id})"); | ||
} | ||
private void LogInformation(string type, string raw, string clean) | ||
{ | ||
_logger.LogInformation($"Raw{type}: {raw}"); | ||
_logger.LogInformation($"Clean{type}: {clean}"); | ||
} | ||
#endregion | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
src/SmartRefund.CustomExceptions/FieldIsNullOrWhitespaceException.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
| ||
using System.Diagnostics.CodeAnalysis; | ||
|
||
namespace SmartRefund.CustomExceptions | ||
{ | ||
[ExcludeFromCodeCoverage] | ||
[Serializable] | ||
public class FieldIsNullOrWhitespaceException : Exception | ||
{ | ||
public string SpecificEntity { get; private set; } | ||
public string Field { get; private set; } | ||
public FieldIsNullOrWhitespaceException(string field, string specificEntity) | ||
: base($"{field} cannot be null or empty. We need to send it again to GPT ({specificEntity})") | ||
{ | ||
Field = field; | ||
SpecificEntity = specificEntity; | ||
} | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
src/SmartRefund.CustomExceptions/ReceiptAlreadyTranslatedException.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
| ||
using System.Diagnostics.CodeAnalysis; | ||
|
||
namespace SmartRefund.CustomExceptions | ||
{ | ||
[ExcludeFromCodeCoverage] | ||
[Serializable] | ||
public class ReceiptAlreadyTranslatedException : Exception | ||
{ | ||
public uint ReceiptId { get; private set; } | ||
public ReceiptAlreadyTranslatedException(uint receiptId) | ||
: base($"RawVisionReceipt is already translated. (Id {receiptId})") | ||
{ | ||
ReceiptId = receiptId; | ||
} | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
src/SmartRefund.CustomExceptions/UnnableToTranslateException.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
| ||
using System.Diagnostics.CodeAnalysis; | ||
|
||
namespace SmartRefund.CustomExceptions | ||
{ | ||
[ExcludeFromCodeCoverage] | ||
[Serializable] | ||
public class UnnableToTranslateException : Exception | ||
{ | ||
public string SpecificEntity { get; private set; } | ||
public string Field { get; private set; } | ||
public UnnableToTranslateException(string field, string specificEntity) | ||
: base($"{field} couldn't be translated. ({specificEntity})") | ||
{ | ||
SpecificEntity = specificEntity; | ||
Field = field; | ||
} | ||
} | ||
} |
Oops, something went wrong.