refactor: Simplify ArchiveAsync method signatures and update related implementations

This commit is contained in:
Giuliano Paschoalino 2025-06-25 16:09:56 -03:00
parent e6b2180c94
commit ad7dc587b2
13 changed files with 35 additions and 52 deletions

View File

@ -32,7 +32,7 @@ namespace ComplianceNFs.Core.Application
// Handles archiving of files
public interface IArchivingService
{
Task ArchiveAsync(EnergyInvoice invoice, byte[] rawFile);
Task ArchiveAsync(EnergyInvoice invoice);
}
// For streaming invoice status updates (for Monitor)

View File

@ -92,24 +92,15 @@ namespace ComplianceNFs.Core.Application.Services
}
// Handles matching logic for invoices
public class MatchingService : IMatchingService
public class MatchingService(IAccessDbRepository accessDbRepository, ILogger<MatchingService> logger) : IMatchingService
{
private readonly IAccessDbRepository _accessDbRepository;
private readonly ILogger<MatchingService> _logger;
public MatchingService(IAccessDbRepository accessDbRepository, ILogger<MatchingService> logger)
{
_accessDbRepository = accessDbRepository;
_logger = logger;
}
public Task MatchAsync(EnergyInvoice invoice)
{
try
{
_logger.LogInformation("Matching invoice {InvoiceId}", invoice.InvoiceId);
logger.LogInformation("Matching invoice {InvoiceId}", invoice.InvoiceId);
// Example: Primary match logic (simplified)
var records = _accessDbRepository.GetByCnpj(invoice.CnpjComp ?? throw new ArgumentNullException("CnpjComp is required"));
var records = accessDbRepository.GetByCnpj(invoice.CnpjComp ?? throw new ArgumentNullException(null, nameof(invoice.CnpjComp)));
if (records == null || records.ToList().Count == 0)
{
invoice.Status = InvoiceStatus.NotFound;
@ -164,7 +155,7 @@ namespace ComplianceNFs.Core.Application.Services
}
catch (Exception ex)
{
_logger.LogError(ex, "Error matching invoice {InvoiceId}", invoice.InvoiceId);
logger.LogError(ex, "Error matching invoice {InvoiceId}", invoice.InvoiceId);
throw;
}
return Task.CompletedTask;
@ -211,9 +202,10 @@ namespace ComplianceNFs.Core.Application.Services
{
private readonly IFileArchiver _fileArchiver = fileArchiver;
public Task ArchiveAsync(EnergyInvoice invoice, byte[] rawFile)
public Task ArchiveAsync(EnergyInvoice invoice)
{
return _fileArchiver.ArchiveAsync(invoice, rawFile);
_fileArchiver.ArchiveAsync(invoice);
return Task.CompletedTask;
}
}
}

View File

@ -38,6 +38,6 @@ namespace ComplianceNFs.Core.Ports
public interface IFileArchiver
{
Task ArchiveAsync(Entities.EnergyInvoice invoice, byte[] rawFile);
void ArchiveAsync(Entities.EnergyInvoice invoice);
}
}

View File

@ -14,7 +14,7 @@ namespace ComplianceNFs.Infrastructure.Tests
{
// Arrange
var expected = new List<BuyingRecord> {
new BuyingRecord { CodTE = 180310221018240701, CnpjComp = "06272575007403", CnpjVend = "13777004000122", MontLO = 24.72m, PrecLO = 147.29m }
new() { CodTE = 180310221018240701, CnpjComp = "06272575007403", CnpjVend = "13777004000122", MontLO = 24.72m, PrecLO = 147.29m }
};
var mockRepo = new Mock<IAccessDbRepository>();
mockRepo.Setup(r => r.GetByCnpj("06272575007403")).Returns(expected);

View File

@ -29,10 +29,10 @@ namespace ComplianceNFs.Infrastructure.Tests
var fileBytes = new byte[] { 1, 2, 3 };
// Act
await service.ArchiveAsync(invoice, fileBytes);
await service.ArchiveAsync(invoice);
// Assert
mockArchiver.Verify(a => a.ArchiveAsync(invoice, fileBytes), Times.Once);
mockArchiver.Verify(a => a.ArchiveAsync(invoice), Times.Once);
}
}
}

View File

@ -46,9 +46,8 @@ namespace ComplianceNFs.Infrastructure.Tests
}
// Expose protected method for test
private class TestableMailListener : MailListener
private class TestableMailListener(IConfiguration config, ILogger<MailListener> logger) : MailListener(config, logger)
{
public TestableMailListener(IConfiguration config, ILogger<MailListener> logger) : base(config, logger) { }
public new void RaiseNewMailReceivedForTest(MailMessage mail) => base.RaiseNewMailReceivedForTest(mail);
}
}

View File

@ -25,7 +25,7 @@ namespace ComplianceNFs.Infrastructure.Tests
Filename = "file.xml",
Status = InvoiceStatus.Validated
};
mockStream.Setup(s => s.GetRecent(It.IsAny<int>())).Returns(new[] { testInvoice });
mockStream.Setup(s => s.GetRecent(It.IsAny<int>())).Returns([testInvoice]);
var viewModel = new MonitorViewModel(mockStream.Object);
// Assert
@ -38,7 +38,7 @@ namespace ComplianceNFs.Infrastructure.Tests
{
// Arrange
var mockStream = new Mock<IInvoiceStatusStream>();
mockStream.Setup(s => s.GetRecent(It.IsAny<int>())).Returns(Array.Empty<EnergyInvoice>());
mockStream.Setup(s => s.GetRecent(It.IsAny<int>())).Returns([]);
var viewModel = new MonitorViewModel(mockStream.Object);
var newInvoice = new EnergyInvoice
{

View File

@ -55,8 +55,8 @@ namespace ComplianceNFs.Infrastructure.Tests
var mockLogger = new Mock<ILogger<MatchingService>>();
var invoice = new EnergyInvoice { CnpjComp = "123", CnpjVend = "456", MontNF = 300, PrecNF = 600, MailId = "m", ConversationId = "c", SupplierEmail = "s", ReceivedDate = DateTime.Now, InvoiceId = 1, Filename = "f.xml" };
var records = new List<BuyingRecord> {
new BuyingRecord { CnpjComp = "123", CnpjVend = "456", MontLO = 100, PrecLO = 200, CodTE = 1 },
new BuyingRecord { CnpjComp = "123", CnpjVend = "456", MontLO = 200, PrecLO = 400, CodTE = 2 }
new() { CnpjComp = "123", CnpjVend = "456", MontLO = 100, PrecLO = 200, CodTE = 1 },
new() { CnpjComp = "123", CnpjVend = "456", MontLO = 200, PrecLO = 400, CodTE = 2 }
};
mockRepo.Setup(r => r.GetByCnpj("123")).Returns(records);
var service = new MatchingService(mockRepo.Object, mockLogger.Object);
@ -87,8 +87,8 @@ namespace ComplianceNFs.Infrastructure.Tests
Filename = "f.xml"
};
var records = new List<BuyingRecord> {
new BuyingRecord { CnpjComp = "123", CnpjVend = "456", MontLO = 100, PrecLO = 200, CodTE = 1 },
new BuyingRecord { CnpjComp = "123", CnpjVend = "456", MontLO = 200, PrecLO = 400, CodTE = 2 }
new() { CnpjComp = "123", CnpjVend = "456", MontLO = 100, PrecLO = 200, CodTE = 1 },
new() { CnpjComp = "123", CnpjVend = "456", MontLO = 200, PrecLO = 400, CodTE = 2 }
};
mockRepo.Setup(r => r.GetByCnpj("123")).Returns(records);
var service = new MatchingService(mockRepo.Object, mockLogger.Object);

View File

@ -34,7 +34,7 @@ namespace ComplianceNFs.Infrastructure.Tests
};
var data = new byte[] { 1, 2, 3, 4 };
await archiver.ArchiveAsync(invoice, data);
archiver.ArchiveAsync(invoice);
var expectedFolder = Path.Combine(_testBasePath, "Validated");
var expectedFile = Path.Combine(expectedFolder, "testfile.txt");
@ -59,11 +59,10 @@ namespace ComplianceNFs.Infrastructure.Tests
ReceivedDate = DateTime.Now,
InvoiceId = 1
};
var data1 = new byte[] { 1, 2, 3 };
var data2 = new byte[] { 9, 8, 7 };
await archiver.ArchiveAsync(invoice, data1);
await archiver.ArchiveAsync(invoice, data2);
archiver.ArchiveAsync(invoice);
archiver.ArchiveAsync(invoice);
var expectedFile = Path.Combine(_testBasePath, "Validated", "testfile.txt");
var fileData = await File.ReadAllBytesAsync(expectedFile);
@ -74,6 +73,7 @@ namespace ComplianceNFs.Infrastructure.Tests
{
if (Directory.Exists(_testBasePath))
Directory.Delete(_testBasePath, true);
GC.SuppressFinalize(this);
}
}

View File

@ -12,8 +12,9 @@ namespace ComplianceNFs.Infrastructure.Archiving
{
private readonly string _basePath = basePath;
public async Task ArchiveAsync(EnergyInvoice invoice, byte[] rawFile)
public void ArchiveAsync(EnergyInvoice invoice)
{
var sourceFile = Path.Combine(_basePath, invoice.Filename);
// Create subfolder for invoice.Status
var statusFolder = Path.Combine(_basePath, invoice.Status.ToString());
if (!Directory.Exists(statusFolder))
@ -23,7 +24,7 @@ namespace ComplianceNFs.Infrastructure.Archiving
// Build file path
var filePath = Path.Combine(statusFolder, invoice.Filename);
// Write file (overwrite if exists)
await File.WriteAllBytesAsync(filePath, rawFile);
File.Move(sourceFile, filePath);
}
}
}

View File

@ -10,22 +10,13 @@ using Microsoft.Extensions.Logging;
namespace ComplianceNFs.Infrastructure.Repositories
{
// Placeholder: fill in actual SQL and mapping logic
public class AttachmentRepository : IAttachmentRepository
public class AttachmentRepository(string connectionString, ILogger<AttachmentRepository> logger) : IAttachmentRepository
{
private readonly string _connectionString;
private readonly ILogger<AttachmentRepository> _logger;
public AttachmentRepository(string connectionString, ILogger<AttachmentRepository> logger)
{
_connectionString = connectionString;
_logger = logger;
}
public async Task SaveRawAsync(EnergyInvoice invoice)
{
try
{
using var conn = new NpgsqlConnection(_connectionString);
using var conn = new NpgsqlConnection(connectionString);
await conn.OpenAsync();
var cmd = conn.CreateCommand();
cmd.CommandText = @"INSERT INTO attachments (
@ -55,11 +46,11 @@ namespace ComplianceNFs.Infrastructure.Repositories
cmd.Parameters.AddWithValue("@discrepancy", (object?)invoice.DiscrepancyNotes ?? DBNull.Value);
cmd.Parameters.AddWithValue("@metadata", Newtonsoft.Json.JsonConvert.SerializeObject(invoice));
await cmd.ExecuteNonQueryAsync();
_logger.LogInformation("Saved raw invoice {InvoiceId} to attachments table.", invoice.InvoiceId);
logger.LogInformation("Saved raw invoice {InvoiceId} to attachments table.", invoice.InvoiceId);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error saving raw invoice {InvoiceId} to attachments table.", invoice.InvoiceId);
logger.LogError(ex, "Error saving raw invoice {InvoiceId} to attachments table.", invoice.InvoiceId);
throw;
}
}
@ -68,7 +59,7 @@ namespace ComplianceNFs.Infrastructure.Repositories
{
try
{
using var conn = new NpgsqlConnection(_connectionString);
using var conn = new NpgsqlConnection(connectionString);
await conn.OpenAsync();
var cmd = conn.CreateCommand();
cmd.CommandText = @"UPDATE attachments SET matched_cod_te = @matched_cod_te, status = @status, discrepancy = @discrepancy WHERE invoice_id = @invoice_id";
@ -77,11 +68,11 @@ namespace ComplianceNFs.Infrastructure.Repositories
cmd.Parameters.AddWithValue("@discrepancy", (object?)notes ?? DBNull.Value);
cmd.Parameters.AddWithValue("@invoice_id", invoiceId);
await cmd.ExecuteNonQueryAsync();
_logger.LogInformation("Updated match for invoice {InvoiceId}.", invoiceId);
logger.LogInformation("Updated match for invoice {InvoiceId}.", invoiceId);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error updating match for invoice {InvoiceId}.", invoiceId);
logger.LogError(ex, "Error updating match for invoice {InvoiceId}.", invoiceId);
throw;
}
}

View File

@ -32,6 +32,6 @@ namespace ComplianceNFs.Monitor
public class DummyStatusStream : IInvoiceStatusStream
{
public event Action<Core.Entities.EnergyInvoice>? StatusUpdated { add { } remove { } }
public IEnumerable<Core.Entities.EnergyInvoice> GetRecent(int count = 100) => Array.Empty<Core.Entities.EnergyInvoice>();
public IEnumerable<Core.Entities.EnergyInvoice> GetRecent(int count = 100) => [];
}
}

View File

@ -44,7 +44,7 @@ public class Worker(ILogger<Worker> logger,
}
// 4. Archive
// (Assume raw file is available or can be loaded if needed)
// await _archivingService.ArchiveAsync(invoice, rawFile);
await _archivingService.ArchiveAsync(invoice);
_logger.LogInformation("Invoice {NumeroNF} processed with status: {Status}", invoice.NumeroNF, invoice.Status);
}
catch (Exception ex)