diff --git a/Controllers/PdfController.cs b/Controllers/PdfController.cs index b9a7229..7232d94 100644 --- a/Controllers/PdfController.cs +++ b/Controllers/PdfController.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using FirmTracker_Server.nHibernate; using FirmTracker_Server.nHibernate.Expenses; +using FirmTracker_Server.nHibernate.Transactions; using Microsoft.AspNetCore.Mvc; using QuestPDF.Fluent; using QuestPDF.Helpers; @@ -16,36 +17,86 @@ namespace FirmTracker_Server.Controllers public class PdfController : ControllerBase { private readonly IExpenseRepository _expenseRepository; + private readonly ITransactionRepository _transactionRepository; - public PdfController(IExpenseRepository expenseRepository) + public PdfController(IExpenseRepository expenseRepository, ITransactionRepository transactionRepository) { _expenseRepository = expenseRepository; + _transactionRepository = transactionRepository; } [HttpGet("download")] - public IActionResult DownloadExpenseReport() + public IActionResult DownloadReport( + [FromQuery] string reportType, // "expenses" or "transactions" + [FromQuery] DateTime? startDate, + [FromQuery] DateTime? endDate) { - // Fetch expense data from the repository - List expenses = _expenseRepository.GetAllExpenses(); + try + { + // Validate date inputs and set default values + DateTime start = startDate ?? DateTime.MinValue; + DateTime end = endDate ?? DateTime.MaxValue; - // Generate the PDF file - byte[] pdfBytes = GeneratePdf(expenses); - string date = DateTime.Now.ToString("yyyy-MM-dd"); - string fileName = $"ExpenseReport_{date}.pdf"; + // Validate report type + if (string.IsNullOrEmpty(reportType) || + (reportType.ToLower() != "expenses" && reportType.ToLower() != "transactions")) + { + return BadRequest("Invalid report type. Please specify 'expenses' or 'transactions'."); + } - // Return the PDF as a downloadable file + if (reportType.ToLower() == "expenses") + { + return GenerateExpenseReport(start, end); + } + else + { + return GenerateTransactionReport(start, end); + } + } + catch (Exception ex) + { + return StatusCode(500, $"Internal server error: {ex.Message}"); + } + } + + private IActionResult GenerateExpenseReport(DateTime start, DateTime end) + { + var expenses = _expenseRepository.GetAllExpenses() + .Where(e => e.Date >= start && e.Date <= end) + .ToList(); + + if (!expenses.Any()) + { + return BadRequest($"No expenses found between {start:yyyy-MM-dd} and {end:yyyy-MM-dd}."); + } + + var pdfBytes = GenerateExpensePdf(expenses, start, end); + string fileName = $"ExpenseReport_{start:yyyy-MM-dd}_to_{end:yyyy-MM-dd}.pdf"; return File(pdfBytes, "application/pdf", fileName); } - private byte[] GeneratePdf(List expenses) + private IActionResult GenerateTransactionReport(DateTime start, DateTime end) + { + var transactions = _transactionRepository.GetTransactionsByDateRange(start, end); + + if (!transactions.Any()) + { + return BadRequest($"No transactions found between {start:yyyy-MM-dd} and {end:yyyy-MM-dd}."); + } + + // Fetch transaction products for all transactions in one query + var transactionIds = transactions.Select(t => t.Id).ToList(); + var transactionProducts = _transactionRepository.GetTransactionProductsForTransactions(transactionIds); + + var pdfBytes = GenerateTransactionPdf(transactions, transactionProducts, start, end); + string fileName = $"TransactionReport_{start:yyyy-MM-dd}_to_{end:yyyy-MM-dd}.pdf"; + return File(pdfBytes, "application/pdf", fileName); + } + + private byte[] GenerateTransactionPdf(List transactions, List transactionProducts, DateTime startDate, DateTime endDate) { using (var ms = new MemoryStream()) { - // Calculate total and average expenses - decimal totalExpenses = expenses.Sum(e => e.Value); - decimal averageExpense = expenses.Count > 0 ? totalExpenses / expenses.Count : 0; - - // Define the document using QuestPDF Document.Create(container => { container.Page(page => @@ -57,7 +108,95 @@ namespace FirmTracker_Server.Controllers // Main header page.Header() - .Text("Expense Report") + .Text("Raport transakcji") + .FontSize(20) + .SemiBold() + .AlignCenter(); + + // Summary section + page.Content().PaddingVertical(1, Unit.Centimetre).Column(column => + { + column.Spacing(10); + + column.Item().Text($"Transakcje od ({startDate:yyyy-MM-dd} do {endDate:yyyy-MM-dd})") + .FontSize(16).Underline(); + + // Add table header + column.Item().Row(row => + { + row.RelativeItem().Text("Data").SemiBold(); + row.RelativeItem().Text("Typ płatności").SemiBold(); + row.RelativeItem().Text("Kwota razem").SemiBold(); + row.RelativeItem().Text("Rabat").SemiBold(); + row.RelativeItem().Text("Opis").SemiBold(); + }); + + // Populate table rows with transaction data + foreach (var transaction in transactions) + { + column.Item().Row(row => + { + row.RelativeItem().Text(transaction.Date.ToString("yyyy-MM-dd")); + row.RelativeItem().Text(transaction.PaymentType); + row.RelativeItem().Text(transaction.TotalPrice.ToString("C")); + row.RelativeItem().Text(transaction.Discount.ToString("C")); + row.RelativeItem().Text(transaction.Description); + }); + + // Fetch and display transaction products for this transaction + var products = transactionProducts + .Where(tp => tp.TransactionId == transaction.Id) + .ToList(); + + if (products.Any()) + { + column.Item().Text("Produkty:").SemiBold(); + foreach (var product in products) + { + column.Item().Row(productRow => + { + productRow.RelativeItem().Text($"Nazwa produktu: {product.ProductName}"); + productRow.RelativeItem().Text($"Ilość: {product.Quantity}"); + }); + } + } + } + }); + + // Footer with generation date + page.Footer() + .AlignCenter() + .Text(text => + { + text.Span("Wygenerowano przez automat FT: "); + text.Span(DateTime.Now.ToString("yyyy-MM-dd")).SemiBold(); + }); + }); + }).GeneratePdf(ms); + + return ms.ToArray(); + } + } + + private byte[] GenerateExpensePdf(List expenses, DateTime startDate, DateTime endDate) + { + using (var ms = new MemoryStream()) + { + decimal totalExpenses = expenses.Sum(e => e.Value); + decimal averageExpense = expenses.Any() ? totalExpenses / expenses.Count : 0; + + Document.Create(container => + { + container.Page(page => + { + page.Size(PageSizes.A4); + page.Margin(2, Unit.Centimetre); + page.PageColor(Colors.White); + page.DefaultTextStyle(x => x.FontSize(12)); + + // Main header + page.Header() + .Text("Raport wydatków") .FontSize(20) .SemiBold() .AlignCenter(); @@ -69,21 +208,20 @@ namespace FirmTracker_Server.Controllers column.Item().Row(row => { - row.RelativeItem().Text($"Total Expenses: {totalExpenses:C}").FontSize(14).Bold(); - row.RelativeItem().Text($"Average Expense: {averageExpense:C}").FontSize(14).Bold(); + row.RelativeItem().Text($"Łączne wydatki: {totalExpenses:C}").FontSize(14).Bold(); + row.RelativeItem().Text($"Średnie wydatki dzienne: {averageExpense:C}").FontSize(14).Bold(); }); - column.Item().Text("Expense Details").FontSize(16).Underline(); + column.Item().Text($"Szczegóły wydatków od ({startDate:yyyy-MM-dd} do {endDate:yyyy-MM-dd})") + .FontSize(16).Underline(); - // Add a table header column.Item().Row(row => { - row.RelativeItem().Text("Date").SemiBold(); - row.RelativeItem().Text("Value").SemiBold(); - row.RelativeItem().Text("Description").SemiBold(); + row.RelativeItem().Text("Data").SemiBold(); + row.RelativeItem().Text("Kwota").SemiBold(); + row.RelativeItem().Text("Opis").SemiBold(); }); - // Populate table rows with expense data foreach (var expense in expenses) { column.Item().Row(row => @@ -95,12 +233,11 @@ namespace FirmTracker_Server.Controllers } }); - // Footer with generation date page.Footer() .AlignCenter() .Text(text => { - text.Span("Generated on "); + text.Span("Wygenerowano przez automat FT: "); text.Span(DateTime.Now.ToString("yyyy-MM-dd")).SemiBold(); }); }); diff --git a/Program.cs b/Program.cs index 4c75fbc..4a73767 100644 --- a/Program.cs +++ b/Program.cs @@ -177,6 +177,7 @@ namespace FirmTracker_Server services.AddScoped(); services.AddScoped, PasswordHasher>(); services.AddScoped(); + services.AddScoped(); // services.AddScoped(); services.AddMvc(); } diff --git a/TestClass.cs b/TestClass.cs index 02cd16a..5cb4440 100644 --- a/TestClass.cs +++ b/TestClass.cs @@ -157,7 +157,7 @@ namespace FirmTracker_Server }; var expense2 = new Expense { - Date = DateTime.Now, + Date = DateTime.Parse("2024-09-10 16:11:17.6232408"), Value = 990.99m, Description = "naprawa pieca - 25.05.2024" }; diff --git a/nHIbernate/PdfData.cs b/nHIbernate/PdfData.cs index 3028bf4..d18d025 100644 --- a/nHIbernate/PdfData.cs +++ b/nHIbernate/PdfData.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Linq; using FirmTracker_Server.nHibernate.Expenses; +using FirmTracker_Server.nHibernate.Transactions; using NHibernate; namespace FirmTracker_Server.nHibernate @@ -13,7 +14,128 @@ namespace FirmTracker_Server.nHibernate void UpdateExpense(Expense expense); void DeleteExpense(int expenseId); } + public interface ITransactionRepository + { + List GetAllTransactions(); + Transaction GetTransaction(int transactionId); + List GetTransactionsByDateRange(DateTime startDate, DateTime endDate); + List GetTransactionProducts(int transactionId); + void AddTransaction(Transaction transaction); + void UpdateTransaction(Transaction transaction); + void DeleteTransaction(int transactionId); + List GetTransactionProductsForTransactions(List transactionIds); + } + public class TransactionRepository : ITransactionRepository + { + // Retrieve all transactions + public List GetAllTransactions() + { + using (var session = SessionFactory.OpenSession()) + { + return session.Query().ToList(); + } + } + public List GetTransactionProductsForTransactions(List transactionIds) + { + using (var session = SessionFactory.OpenSession()) + { + return session.Query() + .Where(tp => transactionIds.Contains(tp.TransactionId)) + .ToList(); + } + } + // Retrieve a specific transaction by ID + public Transaction GetTransaction(int transactionId) + { + using (var session = SessionFactory.OpenSession()) + { + return session.Get(transactionId); + } + } + // Retrieve transactions within a specific date range + public List GetTransactionsByDateRange(DateTime startDate, DateTime endDate) + { + using (var session = SessionFactory.OpenSession()) + { + return session.Query() + .Where(t => t.Date >= startDate && t.Date <= endDate) + .ToList(); + } + } + + // Retrieve all products for a specific transaction + public List GetTransactionProducts(int transactionId) + { + using (var session = SessionFactory.OpenSession()) + { + return session.Query() + .Where(tp => tp.TransactionId == transactionId) + .ToList(); + } + } + + // Add a new transaction + public void AddTransaction(Transaction transaction) + { + using (var session = SessionFactory.OpenSession()) + using (var transactionScope = session.BeginTransaction()) + { + try + { + session.Save(transaction); + transactionScope.Commit(); + } + catch + { + transactionScope.Rollback(); + throw; + } + } + } + + // Update an existing transaction + public void UpdateTransaction(Transaction transaction) + { + using (var session = SessionFactory.OpenSession()) + using (var transactionScope = session.BeginTransaction()) + { + try + { + session.Update(transaction); + transactionScope.Commit(); + } + catch + { + transactionScope.Rollback(); + throw; + } + } + } + + // Delete a transaction by ID + public void DeleteTransaction(int transactionId) + { + using (var session = SessionFactory.OpenSession()) + using (var transactionScope = session.BeginTransaction()) + { + try + { + var transaction = session.Get(transactionId); + if (transaction != null) + { + session.Delete(transaction); + } + transactionScope.Commit(); + } + catch + { + transactionScope.Rollback(); + throw; + } + } + } + } public class ExpenseRepository : IExpenseRepository { // Retrieve all expenses