Skip to content

rayzaisra/HumanReadableReports

Repository files navigation

📊 HumanReadableReports

A clean, production-ready report engine for .NET Framework 4.5.2+ that converts SQL result data into business-friendly Excel, HTML, and CSV reports with minimal code.

NuGet .NET Framework License


🎯 What Problem Does This Solve?

Enterprise developers often need to:

  • Convert SQL query results into formatted reports
  • Present data in a business-friendly way (not just raw tables)
  • Support multiple output formats (Excel, HTML, PDF, CSV)
  • Add grouping, subtotals, and grand totals
  • Format currencies correctly for different regions
  • Make reports understandable by non-technical stakeholders

Traditional approach: Write complex rendering code, handle formatting logic, manage EPPlus manually, repeat for each report.

With HumanReadableReports: Define your report in 5 lines of readable code. The library handles all the complexity.


✨ Key Features

  • 🎨 Fluent API - Readable, chainable code that looks like plain English
  • 📊 Multiple Formats - Excel (.xlsx), HTML, and CSV output
  • 📈 Smart Grouping - Group by day, month, year, or any value
  • 💰 Currency Formatting - Custom formatting for IDR, USD, EUR, GBP, and more
  • 🧮 Automatic Calculations - Subtotals and grand totals calculated automatically
  • 🎓 "Explain Like I'm Five" - Generate human-readable report summaries
  • 🏗️ Clean Architecture - Separation of concerns: Definition → Processing → Rendering
  • ✅ Production-Ready - Enterprise code quality, fully commented, unit-testable

🚀 Quick Start

Installation

Install-Package HumanReadableReports

Basic Example

using HumanReadableReports.Definition;
using HumanReadableReports.Models;

// Get your data
DataTable data = GetSalesDataFromDatabase();

// Define and generate report
var report = Report
    .From(data)
    .WithTitle("Monthly Sales Report")
    .Column("TransactionDate", "Date").AsDate("dd MMM yyyy")
    .Column("Product")
    .Column("Amount").AsCurrency("IDR")
    .GroupBy("TransactionDate", GroupingType.Month)
    .Total("Amount");
	
// columns auto-detected!
var report = Report
    .From(data)
    .WithTitle("Monthly Sales Report");

// Generate Excel file
byte[] excelFile = report.ToExcel();
File.WriteAllBytes("SalesReport.xlsx", excelFile);

That's it! You now have a professional Excel report with:

  • Formatted headers
  • Grouped data by month
  • Subtotals for each month
  • Grand total at the bottom
  • Professional styling (borders, alternating rows, frozen headers)

📖 Detailed Usage

1. Data Sources

The library supports two data sources:

DataTable (Most Common)

DataTable data = GetDataFromStoredProcedure();
var report = Report.From(data);

List<Dictionary<string, object>>

var data = new List<Dictionary<string, object>>
{
    new Dictionary<string, object>
    {
        { "Date", new DateTime(2024, 10, 15) },
        { "Customer", "PT Maju Jaya" },
        { "Amount", 25000000m }
    }
};
var report = Report.From(data);

2. Column Definitions

// Basic column
.Column("ColumnName")

// Column with display name
.Column("ColumnName", "Display Name")

// Date column with format
.Column("OrderDate").AsDate("dd MMM yyyy")

// Currency column
.Column("Amount").AsCurrency("IDR")  // Rp 1.000.000,00
.Column("Price").AsCurrency("USD")   // $1,000.00
.Column("Total").AsCurrency("EUR")   // €1,000.00

// Number column
.Column("Quantity").AsNumber()       // 1,234.56

// Percentage column
.Column("Growth").AsPercentage()     // 12.34%

3. Grouping

// Group by month
.GroupBy("TransactionDate", GroupingType.Month)

// Group by year
.GroupBy("TransactionDate", GroupingType.Year)

// Group by day
.GroupBy("TransactionDate", GroupingType.Day)

// Group by any value (e.g., Category, Department)
.GroupBy("Category", GroupingType.Value)

// No grouping (default)
// Just don't call GroupBy()

4. Totals

// Add totals for specific columns
.Total("Amount")
.Total("Quantity")
.Total("Revenue")

The library will automatically:

  • Calculate subtotals for each group
  • Calculate grand totals
  • Format totals using the column's format (currency, number, etc.)

5. Output Formats

// Excel (XLSX)
byte[] excelFile = report.ToExcel();

// HTML (standalone HTML file)
byte[] htmlFile = report.ToHtml();

// CSV
byte[] csvFile = report.ToCsv();

6. Explain Like I'm Five

string explanation = report.ExplainLikeImFive();
Console.WriteLine(explanation);

Output:

📊 Report Summary

This report shows 156 records organized into 12 groups.

💰 Total Amount: Rp 1.250.000.000,00

🏆 Highest group: December 2024 with Rp 150.000.000,00

📈 Trend: Growing by 15.3% from start to end.

✅ All calculations have been verified and formatted for easy reading.

🏢 Real-World Examples

MVC Controller Integration

using System.Web.Mvc;
using HumanReadableReports.Definition;

public class ReportController : Controller
{
    public ActionResult DownloadSalesReport(string format = "excel")
    {
        // Get data from database
        var data = GetSalesData();

        // Build report
        var report = Report
            .From(data)
            .WithTitle("Sales Report")
            .Column("Date").AsDate("dd MMM yyyy")
            .Column("Product")
            .Column("Amount").AsCurrency("IDR")
            .GroupBy("Date", GroupingType.Month)
            .Total("Amount");

        // Render based on requested format
        byte[] fileContent;
        string contentType;
        string fileName;

        switch (format.ToLower())
        {
            case "html":
                fileContent = report.ToHtml();
                contentType = "text/html";
                fileName = "SalesReport.html";
                break;
            case "csv":
                fileContent = report.ToCsv();
                contentType = "text/csv";
                fileName = "SalesReport.csv";
                break;
            default:
                fileContent = report.ToExcel();
                contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
                fileName = "SalesReport.xlsx";
                break;
        }

        return File(fileContent, contentType, fileName);
    }
}

Working with Stored Procedures

public byte[] GenerateFinancialReport(DateTime startDate, DateTime endDate)
{
    DataTable data;
    
    using (var conn = new SqlConnection(connectionString))
    {
        using (var cmd = new SqlCommand("sp_GetFinancialData", conn))
        {
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.AddWithValue("@StartDate", startDate);
            cmd.Parameters.AddWithValue("@EndDate", endDate);
            
            var adapter = new SqlDataAdapter(cmd);
            data = new DataTable();
            adapter.Fill(data);
        }
    }

    var report = Report
        .From(data)
        .WithTitle($"Financial Report {startDate:MMM yyyy} - {endDate:MMM yyyy}")
        .Column("TransactionDate", "Date").AsDate("dd MMM yyyy")
        .Column("Description")
        .Column("Debit").AsCurrency("IDR")
        .Column("Credit").AsCurrency("IDR")
        .Column("Balance").AsCurrency("IDR")
        .GroupBy("TransactionDate", GroupingType.Month)
        .Total("Debit")
        .Total("Credit");

    return report.ToExcel();
}

🏗️ Architecture

The library follows clean architecture principles:

HumanReadableReports/
├── Core/                    # Interfaces
│   ├── IReportDefinition
│   ├── IReportProcessor
│   └── IReportRenderer
├── Definition/              # Fluent API
│   ├── Report.cs
│   └── ReportDefinition.cs
├── Processing/              # Business Logic
│   ├── ReportProcessor.cs
│   └── GroupingEngine.cs
├── Rendering/               # Output Generation
│   ├── ExcelRenderer.cs
│   ├── HtmlRenderer.cs
│   └── CsvRenderer.cs
├── Models/                  # Data Models
│   ├── ProcessedReport.cs
│   ├── ReportGroup.cs
│   └── ColumnDefinition.cs
└── Explanation/             # Human Explanations
    └── ReportExplainer.cs

Design Principles

  1. Fluent API - Readable, chainable interface
  2. Separation of Concerns - Definition → Processing → Rendering
  3. Single Responsibility - Each class has one job
  4. Open/Closed Principle - Easy to extend with new renderers
  5. Dependency Inversion - Depends on abstractions, not implementations

🧪 Testing

The library is designed to be easily testable:

[TestClass]
public class ReportProcessorTests
{
    [TestMethod]
    public void Should_Calculate_Subtotals_Correctly()
    {
        // Arrange
        var data = CreateTestData();
        var definition = CreateTestDefinition(data);
        var processor = new ReportProcessor();

        // Act
        var result = processor.Process(definition);

        // Assert
        Assert.AreEqual(2, result.Groups.Count);
        Assert.AreEqual(150000m, result.Groups[0].Subtotals["Amount"]);
        Assert.AreEqual(250000m, result.Groups[1].Subtotals["Amount"]);
    }
}

📦 Dependencies

  • EPPlus 4.5.3.3 - Excel generation (LGPL license, free for .NET Framework)
  • .NET Framework 4.5.2+ - Target framework

That's it! Minimal dependencies keep the package small and maintainable.


🔧 Advanced Scenarios

Custom Currency Formatting

The library includes built-in formatters for IDR, USD, EUR, and GBP. To add more:

// Fork the library and modify ColumnDefinition.FormatCurrency()
case "JPY":
    return string.Format("¥{0:N0}", amount);  // Japanese Yen (no decimals)

Custom Renderers

Want to add PDF output? Implement IReportRenderer:

public class PdfRenderer : IReportRenderer
{
    public byte[] Render(ProcessedReport report)
    {
        // Use iTextSharp or similar
        // Process report.Groups, report.Columns, etc.
        return pdfBytes;
    }

    public string GetContentType() => "application/pdf";
    public string GetFileExtension() => ".pdf";
}

🤝 Contributing

We welcome contributions! Please follow these guidelines:

  1. Fork the repository
  2. Create a feature branch
  3. Follow existing code style (C# 7.3, .NET Framework 4.5.2)
  4. Add unit tests for new features
  5. Update documentation
  6. Submit a pull request

📄 License

This project is licensed under the MIT License - see the LICENSE.txt file for details.


🙋 FAQ

Q: Does this work with .NET Core?

A: Not currently. This library targets .NET Framework 4.5.2+. A .NET Standard version is planned for the future.

Q: Can I use this with Entity Framework?

A: Yes! Convert your query results to DataTable or List:

var data = context.Orders.ToList().ConvertToDataTable();
var report = Report.From(data);

Q: What about very large datasets?

A: The library loads all data into memory for processing. For datasets with 100k+ rows, consider:

  • Applying filters at the database level
  • Processing in batches
  • Using server-side pagination

Q: Can I customize Excel styling?

A: The library uses professional defaults. For custom styling, you can modify ExcelRenderer.cs in your fork.

Q: Is this thread-safe?

A: Yes. Each report generation creates new instances, so you can safely generate multiple reports concurrently.


📞 Support


🌟 Show Your Support

If this library helps you, please:

  • ⭐ Star the repository
  • 📢 Share with your team
  • 🐛 Report bugs
  • 💡 Suggest features

Built with ❤️ for enterprise .NET developers who value clean, readable code.

About

A clean, production-ready report engine for .NET Framework that converts SQL result data into business-friendly Excel, HTML, and CSV reports.

Resources

License

MIT, MIT licenses found

Licenses found

MIT
LICENSE
MIT
LICENSE.md

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors