From e50573157882d42d14fb258ffcf827b141c765e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Cl=C3=A1udio=20Mandlate?= Date: Thu, 5 Jun 2025 14:58:32 +0200 Subject: [PATCH 01/15] =?UTF-8?q?Refatorar=20inicializa=C3=A7=C3=A3o=20de?= =?UTF-8?q?=20XLWorkbook?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Alterada a sintaxe de criação da instância de `XLWorkbook` para uma forma mais concisa e moderna, utilizando a inferência de tipo do C# 9.0. --- src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs b/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs index 0800e71..cf1a101 100644 --- a/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs +++ b/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs @@ -237,7 +237,7 @@ public byte[] GenerateBytesExcel(AuditFile auditFile) { try { - using var workbook = new XLWorkbook(); + using XLWorkbook workbook = new(); var worksheet = workbook.Worksheets.Add("Faturas"); // Cabeçalho From 162a0006c55eaf014dee3fccdc1ad0d7e7740299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Cl=C3=A1udio=20Mandlate?= Date: Thu, 5 Jun 2025 15:14:15 +0200 Subject: [PATCH 02/15] =?UTF-8?q?Adicionar=20suporte=20a=20novos=20formato?= =?UTF-8?q?s=20de=20sa=C3=ADda=20e=20pacotes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adicionado o valor `ExcelOld` ao enum `FormatoOutput` em `AuditFile.cs` para incluir mais opções de formato. Modificado o método `GenerateBytesExcel` em `MozambiqueSaftGenerator.cs` para aceitar um parâmetro `formatoOutput`, permitindo maior flexibilidade na geração de bytes. Incluída a referência ao pacote `NPOI` na versão `2.7.3` no projeto `SAF-T.Mozambique.csproj` para suporte adicional à manipulação de arquivos Excel. --- src/SAF-T.Core/Models/AuditFile.cs | 3 ++- src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs | 2 +- src/SAF-T.Mozambique/SAF-T.Mozambique.csproj | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/SAF-T.Core/Models/AuditFile.cs b/src/SAF-T.Core/Models/AuditFile.cs index 589d5e3..23a8d7a 100644 --- a/src/SAF-T.Core/Models/AuditFile.cs +++ b/src/SAF-T.Core/Models/AuditFile.cs @@ -8,7 +8,8 @@ public enum FormatoOutput { Xml, Json, - Excel + Excel, + ExcelOld } [JsonSerializable(typeof(AuditFile))] diff --git a/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs b/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs index cf1a101..db77496 100644 --- a/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs +++ b/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs @@ -233,7 +233,7 @@ public string GenerateXml(AuditFile auditFile) } } - public byte[] GenerateBytesExcel(AuditFile auditFile) + public byte[] GenerateBytesExcel(AuditFile auditFile, FormatoOutput formatoOutput = FormatoOutput.Excel) { try { diff --git a/src/SAF-T.Mozambique/SAF-T.Mozambique.csproj b/src/SAF-T.Mozambique/SAF-T.Mozambique.csproj index 9c950e6..aed388c 100644 --- a/src/SAF-T.Mozambique/SAF-T.Mozambique.csproj +++ b/src/SAF-T.Mozambique/SAF-T.Mozambique.csproj @@ -39,6 +39,7 @@ + From 1d7ff13a68be729130d8a9d0ef9658b17112f071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Cl=C3=A1udio=20Mandlate?= Date: Thu, 5 Jun 2025 16:37:10 +0200 Subject: [PATCH 03/15] =?UTF-8?q?Adiciona=20suporte=20a=20NPOI=20no=20m?= =?UTF-8?q?=C3=A9todo=20GenerateBytesExcel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Foi adicionada uma nova sobrecarga do método `GenerateBytesExcel` na interface `ISaftGenerator`, permitindo um parâmetro adicional `FormatoOutput` com valor padrão. O método foi reescrito para utilizar a biblioteca NPOI em vez de ClosedXML, alterando a lógica de criação e preenchimento do arquivo Excel. O cabeçalho da planilha agora é criado com `CreateRow` e `CreateCell`, e o tratamento de exceções foi atualizado para capturar `ArgumentNullException`, melhorando a robustez do código. --- src/SAF-T.Core/Interfaces/ISaftGenerator.cs | 1 + .../Generators/MozambiqueSaftGenerator.cs | 169 ++++++++++-------- 2 files changed, 98 insertions(+), 72 deletions(-) diff --git a/src/SAF-T.Core/Interfaces/ISaftGenerator.cs b/src/SAF-T.Core/Interfaces/ISaftGenerator.cs index 15cd5fc..92ab9a0 100644 --- a/src/SAF-T.Core/Interfaces/ISaftGenerator.cs +++ b/src/SAF-T.Core/Interfaces/ISaftGenerator.cs @@ -9,6 +9,7 @@ public interface ISaftGenerator string GenerateJson(AuditFile auditFile); string GenerateXml(AuditFile auditFile); byte[] GenerateBytesExcel(AuditFile auditFile); + byte[] GenerateBytesExcel(AuditFile auditFile, FormatoOutput formatoOutput = FormatoOutput.Excel); byte[] GenerateBytesXml(AuditFile auditFile); ValidationResult Validate(T saftData); // Validação integrada } diff --git a/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs b/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs index db77496..8acd5af 100644 --- a/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs +++ b/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs @@ -6,6 +6,9 @@ using System.Text.Json; using System.Xml; using ClosedXML.Excel; +using NPOI.HSSF.UserModel; +using NPOI.SS.UserModel; +using NPOI.XSSF.UserModel; namespace Simansoft.SAFT.Mozambique.Generators { @@ -233,101 +236,123 @@ public string GenerateXml(AuditFile auditFile) } } + public byte[] GenerateBytesExcel(AuditFile auditFile) + { + return GenerateBytesExcel(auditFile, FormatoOutput.Excel); + } + public byte[] GenerateBytesExcel(AuditFile auditFile, FormatoOutput formatoOutput = FormatoOutput.Excel) { try { - using XLWorkbook workbook = new(); - var worksheet = workbook.Worksheets.Add("Faturas"); + if (auditFile == null) + { + throw new ArgumentNullException(nameof(auditFile), "O objeto AuditFile não pode ser nulo."); + } + + IWorkbook workbook = formatoOutput switch + { + FormatoOutput.Excel => new XSSFWorkbook(),// XLSX + FormatoOutput.ExcelOld => new HSSFWorkbook(),// XLS + _ => throw new ArgumentException("Formato de saída não suportado.", nameof(formatoOutput)), + }; + ISheet sheet = workbook.CreateSheet("Faturas"); // Cabeçalho - worksheet.Cell(1, 1).Value = "Linha"; - worksheet.Cell(1, 2).Value = "NUIT"; - worksheet.Cell(1, 3).Value = "MÊS"; - worksheet.Cell(1, 4).Value = "ID Documento"; - worksheet.Cell(1, 5).Value = "Tipo"; - worksheet.Cell(1, 6).Value = "Série"; - worksheet.Cell(1, 7).Value = "Número"; - worksheet.Cell(1, 8).Value = "Série/Número"; - worksheet.Cell(1, 9).Value = "Estado"; - worksheet.Cell(1, 10).Value = "Referência a Documento de Origem"; - worksheet.Cell(1, 11).Value = "Referência a Factura"; - worksheet.Cell(1, 12).Value = "Data Emissão"; - worksheet.Cell(1, 13).Value = "Data Vencimento"; - worksheet.Cell(1, 14).Value = "NUIT Cliente"; - worksheet.Cell(1, 15).Value = "Nome do Cliente"; - worksheet.Cell(1, 16).Value = "Subtotal S/IVA"; - worksheet.Cell(1, 17).Value = "Outro S/IVA"; - worksheet.Cell(1, 18).Value = "IVA"; - worksheet.Cell(1, 19).Value = "Razão de Isenção de IVA"; - worksheet.Cell(1, 20).Value = "Total Retenção"; - worksheet.Cell(1, 21).Value = "Total Desconto"; - worksheet.Cell(1, 22).Value = "Total"; - worksheet.Cell(1, 23).Value = "Valor Recebido"; - worksheet.Cell(1, 24).Value = "IVA (%)"; - worksheet.Cell(1, 25).Value = "Valor do Imposto"; - worksheet.Cell(1, 26).Value = "Desconto"; - worksheet.Cell(1, 27).Value = "Valor Total sem Imposto"; - worksheet.Cell(1, 28).Value = "Total Incluindo Imposto"; - worksheet.Cell(1, 29).Value = "Moeda"; - worksheet.Cell(1, 30).Value = "Taxa Câmbio"; - worksheet.Range(1, 1, 1, 30).Style.Font.SetBold(); - - int numeroLinha = 2; + var headerRow = sheet.CreateRow(0); + headerRow.CreateCell(0).SetCellValue("Linha"); + headerRow.CreateCell(1).SetCellValue("NUIT"); + headerRow.CreateCell(2).SetCellValue("MÊS"); + headerRow.CreateCell(3).SetCellValue("ID Documento"); + headerRow.CreateCell(4).SetCellValue("Tipo"); + headerRow.CreateCell(5).SetCellValue("Série"); + headerRow.CreateCell(6).SetCellValue("Número"); + headerRow.CreateCell(7).SetCellValue("Série/Número"); + headerRow.CreateCell(8).SetCellValue("Estado"); + headerRow.CreateCell(9).SetCellValue("Referência a Documento de Origem"); + headerRow.CreateCell(10).SetCellValue("Referência a Factura"); + headerRow.CreateCell(11).SetCellValue("Data Emissão"); + headerRow.CreateCell(12).SetCellValue("Data Vencimento"); + headerRow.CreateCell(13).SetCellValue("NUIT Cliente"); + headerRow.CreateCell(14).SetCellValue("Nome do Cliente"); + headerRow.CreateCell(15).SetCellValue("Subtotal S/IVA"); + headerRow.CreateCell(16).SetCellValue("Outro S/IVA"); + headerRow.CreateCell(17).SetCellValue("IVA"); + headerRow.CreateCell(18).SetCellValue("Razão de Isenção de IVA"); + headerRow.CreateCell(19).SetCellValue("Total Retenção"); + headerRow.CreateCell(20).SetCellValue("Total Desconto"); + headerRow.CreateCell(21).SetCellValue("Total"); + headerRow.CreateCell(22).SetCellValue("Valor Recebido"); + headerRow.CreateCell(23).SetCellValue("IVA (%)"); + headerRow.CreateCell(24).SetCellValue("Valor do Imposto"); + headerRow.CreateCell(25).SetCellValue("Desconto"); + headerRow.CreateCell(26).SetCellValue("Valor Total sem Imposto"); + headerRow.CreateCell(27).SetCellValue("Total Incluindo Imposto"); + headerRow.CreateCell(28).SetCellValue("Moeda"); + headerRow.CreateCell(29).SetCellValue("Taxa Câmbio"); + + IFont font = workbook.CreateFont(); + font.IsBold = true; + for (int i = 0; i < 30; i++) + { + headerRow.GetCell(i).CellStyle = workbook.CreateCellStyle(); + headerRow.GetCell(i).CellStyle.SetFont(font); + } + + int numeroLinha = 1; auditFile.SourceDocuments?.SalesInvoices?.Invoices?.ForEach(factura => { - worksheet.Cell(numeroLinha, 1).Value = numeroLinha - 1; - worksheet.Cell(numeroLinha, 2).Value = auditFile.Header!.TaxRegistrationNumber; - worksheet.Cell(numeroLinha, 3).Value = factura.InvoiceDate!.Value.ToDateTime(new TimeOnly()).ToString("yyyy-MM"); - worksheet.Cell(numeroLinha, 4).Value = string.Concat(factura.TipoDocumentoAbreviado, factura.InvoiceNo!.Split('/')[1]); - worksheet.Cell(numeroLinha, 5).Value = factura.TipoDocumento; - worksheet.Cell(numeroLinha, 6).Value = factura.Serie; - worksheet.Cell(numeroLinha, 7).Value = factura.InvoiceNo!.Split('/')[1]; - worksheet.Cell(numeroLinha, 8).Value = string.Concat(factura.Serie, "/", factura.InvoiceNo!.Split('/')[1]); - worksheet.Cell(numeroLinha, 9).Value = factura.DocumentStatus!.EstadoDescricao; - //worksheet.Cell(numeroLinha, 10).Value = //factura.DocumentStatus!.ReferenciaDocumentoOrigem; - //worksheet.Cell(numeroLinha, 11).Value = //factura.DocumentStatus!.ReferenciaFactura; - worksheet.Cell(numeroLinha, 12).Value = factura.InvoiceDate!.Value.ToString("yyyy-MM-dd"); - //worksheet.Cell(numeroLinha, 13).Value = factura.DataVencimento?.ToString("yyyy-MM-dd"); - worksheet.Cell(numeroLinha, 14).Value = auditFile.MasterFiles? + var row = sheet.CreateRow(numeroLinha++); + row.CreateCell(0).SetCellValue(numeroLinha - 1); + row.CreateCell(1).SetCellValue(auditFile.Header!.TaxRegistrationNumber); + row.CreateCell(2).SetCellValue(factura.InvoiceDate!.Value.ToDateTime(new TimeOnly()).ToString("yyyy-MM")); + row.CreateCell(3).SetCellValue(string.Concat(factura.TipoDocumentoAbreviado, factura.InvoiceNo!.Split('/')[1])); + row.CreateCell(4).SetCellValue(factura.TipoDocumento); + row.CreateCell(5).SetCellValue(factura.Serie); + row.CreateCell(6).SetCellValue(factura.InvoiceNo!.Split('/')[1]); + row.CreateCell(7).SetCellValue(string.Concat(factura.Serie, "/", factura.InvoiceNo!.Split('/')[1])); + row.CreateCell(8).SetCellValue(factura.DocumentStatus!.EstadoDescricao); + //row.CreateCell(9).SetCellValue(factura.DocumentStatus!.ReferenciaDocumentoOrigem); + //row.CreateCell(10).SetCellValue(factura.DocumentStatus!.ReferenciaFactura); + row.CreateCell(11).SetCellValue(factura.InvoiceDate!.Value.ToString("yyyy-MM-dd")); + //row.CreateCell(12).SetCellValue(factura.DataVencimento?.ToString("yyyy-MM-dd")); + row.CreateCell(13).SetCellValue(auditFile.MasterFiles? .Customers.SingleOrDefault(w => (w.CustomerID ?? string.Empty).Equals(factura.CustomerID, StringComparison.OrdinalIgnoreCase))? - .CustomerTaxID ?? string.Empty; + .CustomerTaxID ?? string.Empty); - worksheet.Cell(numeroLinha, 15).Value = auditFile.MasterFiles? + row.CreateCell(14).SetCellValue(auditFile.MasterFiles? .Customers.SingleOrDefault(w => (w.CustomerID ?? string.Empty).Equals(factura.CustomerID, StringComparison.OrdinalIgnoreCase))? - .CompanyName ?? string.Empty; - worksheet.Cell(numeroLinha, 16).Value = factura.DocumentTotals?.TaxPayable; - worksheet.Cell(numeroLinha, 18).Value = factura.DocumentTotals?.NetTotal; - worksheet.Cell(numeroLinha, 21).Value = factura.Lines?.Sum(s => s.SettlementAmount) ?? 0m; - worksheet.Cell(numeroLinha, 22).Value = factura.DocumentTotals?.GrossTotal; - worksheet.Cell(numeroLinha, 23).Value = factura.DocumentTotals?.Payments.Sum(s => s.PaymentAmount); - + .CompanyName ?? string.Empty); + + row.CreateCell(15).SetCellValue(factura.DocumentTotals?.TaxPayable.ToString() ?? "0"); + row.CreateCell(17).SetCellValue(factura.DocumentTotals?.NetTotal.ToString() ?? "0"); + row.CreateCell(20).SetCellValue((factura.Lines?.Sum(s => s.SettlementAmount) ?? 0m).ToString()); + row.CreateCell(21).SetCellValue(factura.DocumentTotals?.GrossTotal.ToString() ?? "0"); + row.CreateCell(22).SetCellValue(factura.DocumentTotals?.Payments.Sum(s => s.PaymentAmount).ToString() ?? "0"); + decimal impostos = factura.Lines? .FirstOrDefault(w => w.Tax.Where(wh => wh.TaxPercentage != 0m).FirstOrDefault()?.TaxPercentage != 0m)? .Tax.FirstOrDefault(w => w.TaxPercentage != 0m)?.TaxPercentage ?? 0m; - worksheet.Cell(numeroLinha, 24).Value = factura.Lines? + row.CreateCell(23).SetCellValue(factura.Lines? .FirstOrDefault(w => w.Tax.Where(wh => wh.TaxPercentage != 0m).FirstOrDefault()?.TaxPercentage != 0m)? - .Tax.FirstOrDefault(w => w.TaxPercentage != 0m)?.TaxPercentage ?? 0m; - - worksheet.Cell(numeroLinha, 25).Value = factura.DocumentTotals?.NetTotal; - worksheet.Cell(numeroLinha, 26).Value = factura.Lines?.Sum(s => s.SettlementAmount) ?? 0m; - worksheet.Cell(numeroLinha, 27).Value = factura.DocumentTotals?.TaxPayable; - worksheet.Cell(numeroLinha, 28).Value = factura.DocumentTotals?.GrossTotal; - worksheet.Cell(numeroLinha, 29).Value = auditFile.Header?.CurrencyCode; - worksheet.Cell(numeroLinha, 30).Value = 1; - - numeroLinha++; + .Tax.FirstOrDefault(w => w.TaxPercentage != 0m)?.TaxPercentage.ToString() ?? "0"); + + row.CreateCell(24).SetCellValue(factura.DocumentTotals?.NetTotal.ToString() ?? "0"); + row.CreateCell(25).SetCellValue((factura.Lines?.Sum(s => s.SettlementAmount) ?? 0m).ToString()); + row.CreateCell(26).SetCellValue(factura.DocumentTotals?.TaxPayable.ToString() ?? "0"); + row.CreateCell(27).SetCellValue(factura.DocumentTotals?.GrossTotal.ToString() ?? "0"); + row.CreateCell(28).SetCellValue(auditFile.Header?.CurrencyCode ?? string.Empty); + row.CreateCell(29).SetCellValue("1"); // Taxa de Câmbio fixa como 1 }); using var stream = new MemoryStream(); - workbook.SaveAs(stream); - + workbook.Write(stream); return stream.ToArray(); } - catch (InvalidOperationException ex) + catch (ArgumentNullException ex) { throw new InvalidOperationException("Falha ao gerar o SAF-T em formato Excel", ex); } From 89f0474d0159065ebf1f46190d91f2b2fbae48fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Cl=C3=A1udio=20Mandlate?= Date: Thu, 5 Jun 2025 16:37:59 +0200 Subject: [PATCH 04/15] Gerar arquivos XLSX e XLS a partir de auditoria MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Atualiza o código para suportar a geração de arquivos XLSX e XLS a partir de um arquivo de auditoria. As mensagens de console foram ajustadas para indicar a criação de múltiplos arquivos, e a mensagem final foi modificada para refletir que vários arquivos foram criados com sucesso. --- .../MozambiqueDemo/BasicMozDemo.cs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/samples/SAF-T.Examples/MozambiqueDemo/BasicMozDemo.cs b/samples/SAF-T.Examples/MozambiqueDemo/BasicMozDemo.cs index 7960d0d..371c83b 100644 --- a/samples/SAF-T.Examples/MozambiqueDemo/BasicMozDemo.cs +++ b/samples/SAF-T.Examples/MozambiqueDemo/BasicMozDemo.cs @@ -47,18 +47,26 @@ public static void Run() //Console.WriteLine("=== XML ==="); Console.WriteLine(xml); - Console.WriteLine("Vou criar o ficheiro Excel..."); + Console.WriteLine("Vou criar os ficheiros..."); Console.ReadKey(true); - byte[] excel = gerador.GenerateBytesExcel(auditFile); - File.WriteAllBytes("saft_mozambique.xlsx", excel); + Console.WriteLine(""); + Console.WriteLine("A gerar o XLSX..."); + byte[] excelByte = gerador.GenerateBytesExcel(auditFile); + File.WriteAllBytes("saft_mozambique.xlsx", excelByte); + + Console.WriteLine("A gerar o XLS..."); + byte[] excelXLSByte = gerador.GenerateBytesExcel(auditFile, FormatoOutput.ExcelOld); + File.WriteAllBytes("saft_mozambique.xls", excelXLSByte); + + Console.WriteLine("A gerar o XML..."); byte[] xmlByte = gerador.GenerateBytesXml(auditFile); File.WriteAllBytes("saft_mozambique.xml", xmlByte); //File.WriteAllText("saft_mozambique.xml", xml); - Console.WriteLine("Ficheiro criado com sucesso!"); + Console.WriteLine("Ficheiros criados com sucesso!"); Console.ReadKey(true); Console.Clear(); From d7e914657f49d47e2ffb132b428aec2e077d5802 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alberto=20Cl=C3=A1udio=20Mandlate?= Date: Thu, 5 Jun 2025 16:44:05 +0200 Subject: [PATCH 05/15] =?UTF-8?q?Remover=20depend=C3=AAncias=20de=20Closed?= =?UTF-8?q?XML=20e=20NPOI?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Alterações no arquivo `MozambiqueSaftGenerator.cs` para remover as importações das bibliotecas `ClosedXML.Excel`, `NPOI.HSSF.UserModel`, `NPOI.SS.UserModel` e `NPOI.XSSF.UserModel`. Adicionada a importação de `Simansoft.SAFT.Mozambique.Models`. No arquivo `SAF-T.Mozambique.csproj`, removidas as referências aos pacotes `ClosedXML` e `NPOI`, indicando que essas bibliotecas não são mais necessárias no projeto. --- src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs | 1 - src/SAF-T.Mozambique/SAF-T.Mozambique.csproj | 1 - 2 files changed, 2 deletions(-) diff --git a/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs b/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs index 8acd5af..555338f 100644 --- a/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs +++ b/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs @@ -5,7 +5,6 @@ using System.Text; using System.Text.Json; using System.Xml; -using ClosedXML.Excel; using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; using NPOI.XSSF.UserModel; diff --git a/src/SAF-T.Mozambique/SAF-T.Mozambique.csproj b/src/SAF-T.Mozambique/SAF-T.Mozambique.csproj index aed388c..4eed5b3 100644 --- a/src/SAF-T.Mozambique/SAF-T.Mozambique.csproj +++ b/src/SAF-T.Mozambique/SAF-T.Mozambique.csproj @@ -38,7 +38,6 @@ - From 31923119642df4badde37c7a04832d4bfa15f49f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albero=20Cl=C3=A1udio=20Mandlate?= Date: Thu, 5 Jun 2025 17:02:36 +0200 Subject: [PATCH 06/15] Update src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs b/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs index 555338f..44c3f76 100644 --- a/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs +++ b/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs @@ -292,10 +292,11 @@ public byte[] GenerateBytesExcel(AuditFile auditFile, FormatoOutput formatoOutpu IFont font = workbook.CreateFont(); font.IsBold = true; + ICellStyle headerStyle = workbook.CreateCellStyle(); + headerStyle.SetFont(font); for (int i = 0; i < 30; i++) { - headerRow.GetCell(i).CellStyle = workbook.CreateCellStyle(); - headerRow.GetCell(i).CellStyle.SetFont(font); + headerRow.GetCell(i).CellStyle = headerStyle; } int numeroLinha = 1; From 35a8977da1e6f99919201896ea2e9638acf82fb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albero=20Cl=C3=A1udio=20Mandlate?= Date: Thu, 5 Jun 2025 17:03:02 +0200 Subject: [PATCH 07/15] Update src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs b/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs index 44c3f76..5dcbe80 100644 --- a/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs +++ b/src/SAF-T.Mozambique/Generators/MozambiqueSaftGenerator.cs @@ -253,7 +253,7 @@ public byte[] GenerateBytesExcel(AuditFile auditFile, FormatoOutput formatoOutpu { FormatoOutput.Excel => new XSSFWorkbook(),// XLSX FormatoOutput.ExcelOld => new HSSFWorkbook(),// XLS - _ => throw new ArgumentException("Formato de saída não suportado.", nameof(formatoOutput)), + _ => throw new ArgumentException($"Formato de saída '{formatoOutput}' não suportado.", nameof(formatoOutput)), }; ISheet sheet = workbook.CreateSheet("Faturas"); From a592a733d9542c5da5c95d3023029c848c53d17f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albero=20Cl=C3=A1udio=20Mandlate?= Date: Fri, 6 Jun 2025 10:43:51 +0200 Subject: [PATCH 08/15] Create auto-pr-aprovacao.yml --- .github/workflows/auto-pr-aprovacao.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/auto-pr-aprovacao.yml diff --git a/.github/workflows/auto-pr-aprovacao.yml b/.github/workflows/auto-pr-aprovacao.yml new file mode 100644 index 0000000..a5c5be3 --- /dev/null +++ b/.github/workflows/auto-pr-aprovacao.yml @@ -0,0 +1,24 @@ +name: Auto-PR com Aprovação + +on: + workflow_dispatch: # Disparo manual (opcional) + +jobs: + create-pr: + runs-on: ubuntu-latest + steps: + # Passos para criar o PR automaticamente... + - name: Create Pull Request + uses: peter-evans/create-pull-request@v4 + with: + token: ${{ secrets.AUTO_APPROVE_TOKEN }} + branch: develop + + auto-approve: + needs: create-pr + runs-on: ubuntu-latest + steps: + - name: Auto-Approve PR + uses: hmarr/auto-approve-action@v2 + with: + github-token: ${{ secrets.AUTO_APPROVE_TOKEN }} # Token personalizado From 2f1b578debd63185edc55232a00c33892d2728b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albero=20Cl=C3=A1udio=20Mandlate?= Date: Fri, 6 Jun 2025 11:18:30 +0200 Subject: [PATCH 09/15] Update codeql.yml --- .github/workflows/codeql.yml | 92 +++++++----------------------------- 1 file changed, 18 insertions(+), 74 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index e204aed..248c677 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,14 +1,3 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# name: "CodeQL Advanced" on: @@ -17,84 +6,39 @@ on: pull_request: branches: [ "main", "develop", "release-**" ] schedule: - - cron: '37 22 * * 5' + - cron: '* * * * 2' + +# Permissões globais para todo o workflow +permissions: + contents: read + security-events: write + statuses: write # ESSENCIAL para reportar status + actions: read + packages: read jobs: analyze: - name: Analisar (${{ matrix.language }}) - # Runner size impacts CodeQL analysis time. To learn more, please see: - # - https://gh.io/recommended-hardware-resources-for-running-codeql - # - https://gh.io/supported-runners-and-hardware-resources - # - https://gh.io/using-larger-runners (GitHub.com only) - # Consider using larger runners or machines with greater resources for possible analysis time improvements. - runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} - permissions: - # required for all workflows - security-events: write - - # required to fetch internal or private CodeQL packs - packages: read - - # only required for workflows in private repositories - actions: read - contents: read + name: Analisar + runs-on: ubuntu-latest # Simplificado strategy: fail-fast: false matrix: - include: - - language: actions - build-mode: none - - language: csharp - build-mode: none - # CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' - # Use `c-cpp` to analyze code written in C, C++ or both - # Use 'java-kotlin' to analyze code written in Java, Kotlin or both - # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both - # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, - # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. - # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how - # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages + language: ['actions', 'csharp'] # Formato simplificado + steps: - name: Checkout repository uses: actions/checkout@v4 + with: + fetch-depth: 2 # Necessário para análise precisa - # Add any setup steps before running the `github/codeql-action/init` action. - # This includes steps like installing compilers or runtimes (`actions/setup-node` - # or others). This is typically only required for manual builds. - # - name: Setup runtime (example) - # uses: actions/setup-example@v1 - - # Initializes the CodeQL tools for scanning. - name: Inicializar o CodeQL uses: github/codeql-action/init@v3 with: languages: ${{ matrix.language }} - build-mode: ${{ matrix.build-mode }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - - # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs - # queries: security-extended,security-and-quality - - # If the analyze step fails for one of the languages you are analyzing with - # "We were unable to automatically build your code", modify the matrix above - # to set the build mode to "manual" for that language. Then modify this step - # to build your code . - # ℹ️ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - if: matrix.build-mode == 'manual' - shell: bash - run: | - echo 'If you are using a "manual" build mode for one or more of the' \ - 'languages you are analyzing, replace this with the commands to build' \ - 'your code, for example:' - echo ' make bootstrap' - echo ' make release' - exit 1 + build-mode: none - - name: Fazendo analises com o CodeQL + - name: Fazendo análises com o CodeQL uses: github/codeql-action/analyze@v3 with: - category: "/language:${{matrix.language}}" + category: "language:${{ matrix.language }}" From a114c8d9edc956a53c7d678e7a20c3e3d9566c84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albero=20Cl=C3=A1udio=20Mandlate?= Date: Fri, 6 Jun 2025 11:37:14 +0200 Subject: [PATCH 10/15] Delete .github/workflows/auto-pr-aprovacao.yml --- .github/workflows/auto-pr-aprovacao.yml | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 .github/workflows/auto-pr-aprovacao.yml diff --git a/.github/workflows/auto-pr-aprovacao.yml b/.github/workflows/auto-pr-aprovacao.yml deleted file mode 100644 index a5c5be3..0000000 --- a/.github/workflows/auto-pr-aprovacao.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Auto-PR com Aprovação - -on: - workflow_dispatch: # Disparo manual (opcional) - -jobs: - create-pr: - runs-on: ubuntu-latest - steps: - # Passos para criar o PR automaticamente... - - name: Create Pull Request - uses: peter-evans/create-pull-request@v4 - with: - token: ${{ secrets.AUTO_APPROVE_TOKEN }} - branch: develop - - auto-approve: - needs: create-pr - runs-on: ubuntu-latest - steps: - - name: Auto-Approve PR - uses: hmarr/auto-approve-action@v2 - with: - github-token: ${{ secrets.AUTO_APPROVE_TOKEN }} # Token personalizado From 587ca6f108b9aa9545ee83487dfbd83da748a956 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albero=20Cl=C3=A1udio=20Mandlate?= Date: Fri, 6 Jun 2025 12:11:44 +0200 Subject: [PATCH 11/15] Create auto-aprove-pr-develop.yml --- .github/workflows/auto-aprove-pr-develop.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/auto-aprove-pr-develop.yml diff --git a/.github/workflows/auto-aprove-pr-develop.yml b/.github/workflows/auto-aprove-pr-develop.yml new file mode 100644 index 0000000..43fcbd0 --- /dev/null +++ b/.github/workflows/auto-aprove-pr-develop.yml @@ -0,0 +1,19 @@ +name: Auto Approve PRs + +on: + pull_request: + branches: [ develop ] + types: [ opened, reopened, synchronize ] + +jobs: + auto-approve: + runs-on: ubuntu-latest + permissions: + pull-requests: write + contents: read + steps: + - name: Auto-approve PR + uses: hmarr/auto-approve-action@v2 + with: + github-token: ${{ secrets.AM_AUTO_APROVE_TOKEN }} + label: "auto-approved" From 0d512ba49b421b3e5b6c7cc7d98ef700dcbb38f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albero=20Cl=C3=A1udio=20Mandlate?= Date: Fri, 6 Jun 2025 12:24:35 +0200 Subject: [PATCH 12/15] Create automated-pr-with-approval.yml --- .../workflows/automated-pr-with-approval.yml | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 .github/workflows/automated-pr-with-approval.yml diff --git a/.github/workflows/automated-pr-with-approval.yml b/.github/workflows/automated-pr-with-approval.yml new file mode 100644 index 0000000..0f7c56f --- /dev/null +++ b/.github/workflows/automated-pr-with-approval.yml @@ -0,0 +1,57 @@ +name: Automated PR with Approval + +on: + schedule: + - cron: '* * * * *' # Executa diariamente à meia-noite + workflow_dispatch: # Permite execução manual + +jobs: + prepare-changes: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Generate changes + run: | + # Comandos para gerar mudanças automáticas + echo "Automated update $(date)" >> auto-update.txt + + - name: Commit changes + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add . + git commit -m "Automated update: $(date)" + + create-pr: + runs-on: ubuntu-latest + needs: prepare-changes + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Pull changes from previous job + uses: actions/download-artifact@v3 + with: + name: auto-changes + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v4 + with: + token: ${{ secrets.AM_AUTO_APROVE_TOKEN }} + commit-message: "Automated changes" + title: "Auto Update: $(date +'%Y-%m-%d')" + body: "Automated changes generated by GitHub Actions" + branch: "auto-update-$(date +%s)" + base: develop + labels: automated + + auto-approve: + runs-on: ubuntu-latest + needs: create-pr + steps: + - name: Auto-approve PR + uses: hmarr/auto-approve-action@v2 + with: + github-token: ${{ secrets.AM_AUTO_APROVE_TOKEN }} From 9624373368f9ff55198e012fc8d5692979d126ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albero=20Cl=C3=A1udio=20Mandlate?= Date: Fri, 6 Jun 2025 12:27:44 +0200 Subject: [PATCH 13/15] Delete .github/workflows/auto-aprove-pr-develop.yml --- .github/workflows/auto-aprove-pr-develop.yml | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 .github/workflows/auto-aprove-pr-develop.yml diff --git a/.github/workflows/auto-aprove-pr-develop.yml b/.github/workflows/auto-aprove-pr-develop.yml deleted file mode 100644 index 43fcbd0..0000000 --- a/.github/workflows/auto-aprove-pr-develop.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Auto Approve PRs - -on: - pull_request: - branches: [ develop ] - types: [ opened, reopened, synchronize ] - -jobs: - auto-approve: - runs-on: ubuntu-latest - permissions: - pull-requests: write - contents: read - steps: - - name: Auto-approve PR - uses: hmarr/auto-approve-action@v2 - with: - github-token: ${{ secrets.AM_AUTO_APROVE_TOKEN }} - label: "auto-approved" From 7626b78076f3ed33452a592ef4e09f73494c493d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albero=20Cl=C3=A1udio=20Mandlate?= Date: Fri, 6 Jun 2025 12:28:00 +0200 Subject: [PATCH 14/15] Delete .github/workflows/automated-pr-with-approval.yml --- .../workflows/automated-pr-with-approval.yml | 57 ------------------- 1 file changed, 57 deletions(-) delete mode 100644 .github/workflows/automated-pr-with-approval.yml diff --git a/.github/workflows/automated-pr-with-approval.yml b/.github/workflows/automated-pr-with-approval.yml deleted file mode 100644 index 0f7c56f..0000000 --- a/.github/workflows/automated-pr-with-approval.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: Automated PR with Approval - -on: - schedule: - - cron: '* * * * *' # Executa diariamente à meia-noite - workflow_dispatch: # Permite execução manual - -jobs: - prepare-changes: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Generate changes - run: | - # Comandos para gerar mudanças automáticas - echo "Automated update $(date)" >> auto-update.txt - - - name: Commit changes - run: | - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add . - git commit -m "Automated update: $(date)" - - create-pr: - runs-on: ubuntu-latest - needs: prepare-changes - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Pull changes from previous job - uses: actions/download-artifact@v3 - with: - name: auto-changes - - - name: Create Pull Request - uses: peter-evans/create-pull-request@v4 - with: - token: ${{ secrets.AM_AUTO_APROVE_TOKEN }} - commit-message: "Automated changes" - title: "Auto Update: $(date +'%Y-%m-%d')" - body: "Automated changes generated by GitHub Actions" - branch: "auto-update-$(date +%s)" - base: develop - labels: automated - - auto-approve: - runs-on: ubuntu-latest - needs: create-pr - steps: - - name: Auto-approve PR - uses: hmarr/auto-approve-action@v2 - with: - github-token: ${{ secrets.AM_AUTO_APROVE_TOKEN }} From b01daff9a658147f235ade4f6eeffcdc1bef32f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albero=20Cl=C3=A1udio=20Mandlate?= Date: Sat, 7 Jun 2025 10:33:14 +0200 Subject: [PATCH 15/15] Update .github/workflows/codeql.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 248c677..3bf7b8e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -6,7 +6,7 @@ on: pull_request: branches: [ "main", "develop", "release-**" ] schedule: - - cron: '* * * * 2' + - cron: '0 * * * 2' # Permissões globais para todo o workflow permissions: