85 lines
2.8 KiB
C#
85 lines
2.8 KiB
C#
using Asentrafin.Api.Contracts.Transactions;
|
|
using Asentrafin.Api.Data;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace Asentrafin.Api.Controllers;
|
|
|
|
[ApiController]
|
|
[Route("api/transactions")]
|
|
public class TransactionAnalyticsController(AppDbContext dbContext) : ControllerBase
|
|
{
|
|
[HttpGet("categories")]
|
|
public async Task<ActionResult<IReadOnlyList<TransactionCategoryResponse>>> GetCategories(
|
|
CancellationToken cancellationToken)
|
|
{
|
|
var categories = await dbContext.TransactionCategories
|
|
.OrderBy(category => category.SortOrder)
|
|
.ThenBy(category => category.Name)
|
|
.Select(category => new TransactionCategoryResponse(
|
|
category.Id,
|
|
category.ParentId,
|
|
category.Name,
|
|
category.Slug,
|
|
category.PlaidPrimary,
|
|
category.PlaidDetailed,
|
|
category.IsSystem))
|
|
.ToListAsync(cancellationToken);
|
|
|
|
return Ok(categories);
|
|
}
|
|
|
|
[HttpGet("category-summaries")]
|
|
public async Task<ActionResult<IReadOnlyList<CategorySummaryResponse>>> GetCategorySummaries(
|
|
[FromQuery] DateOnly? startDate,
|
|
[FromQuery] DateOnly? endDate,
|
|
[FromQuery] Guid? accountId,
|
|
[FromQuery] bool includePending = false,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var query = dbContext.PlaidTransactions
|
|
.AsNoTracking()
|
|
.Where(transaction => transaction.RemovedAt == null);
|
|
|
|
if (!includePending)
|
|
{
|
|
query = query.Where(transaction => !transaction.Pending);
|
|
}
|
|
|
|
if (startDate is not null)
|
|
{
|
|
query = query.Where(transaction => transaction.Date >= startDate.Value);
|
|
}
|
|
|
|
if (endDate is not null)
|
|
{
|
|
query = query.Where(transaction => transaction.Date <= endDate.Value);
|
|
}
|
|
|
|
if (accountId is not null)
|
|
{
|
|
query = query.Where(transaction => transaction.PlaidAccountId == accountId.Value);
|
|
}
|
|
|
|
var summaries = await query
|
|
.Where(transaction => transaction.Classification != null)
|
|
.GroupBy(transaction => new
|
|
{
|
|
transaction.Classification!.Category.Id,
|
|
transaction.Classification.Category.Name,
|
|
transaction.Classification.Category.Slug
|
|
})
|
|
.Select(group => new CategorySummaryResponse(
|
|
group.Key.Id,
|
|
group.Key.Name,
|
|
group.Key.Slug,
|
|
group.Count(),
|
|
group.Sum(transaction => transaction.Amount)))
|
|
.OrderByDescending(summary => Math.Abs(summary.TotalAmount))
|
|
.ThenBy(summary => summary.CategoryName)
|
|
.ToListAsync(cancellationToken);
|
|
|
|
return Ok(summaries);
|
|
}
|
|
}
|