Private
Public Access
1
0
Files
Purrse/src/Purrse.Api/Services/AccountService.cs
T
Catherine Renelle 54a15cf3cf Fix account type not updating on edit
UpdateAccountRequest was missing the Type field, so changes to
account type were silently ignored. Add Type to the DTO and apply
it in the update service method.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 21:44:09 -05:00

137 lines
4.7 KiB
C#

using Microsoft.EntityFrameworkCore;
using Purrse.Core.DTOs;
using Purrse.Core.Interfaces.Services;
using Purrse.Core.Models;
using Purrse.Data;
namespace Purrse.Api.Services;
public class AccountService : IAccountService
{
private readonly PurrseDbContext _db;
public AccountService(PurrseDbContext db)
{
_db = db;
}
public async Task<List<AccountResponse>> GetAllAsync(Guid userId)
{
return await _db.Accounts
.Where(a => a.UserId == userId)
.OrderBy(a => a.SortOrder).ThenBy(a => a.Name)
.Select(a => MapToResponse(a))
.ToListAsync();
}
public async Task<AccountResponse?> GetByIdAsync(Guid userId, Guid accountId)
{
var account = await _db.Accounts
.Include(a => a.LoanDetail)
.FirstOrDefaultAsync(a => a.Id == accountId && a.UserId == userId);
return account == null ? null : MapToResponse(account);
}
public async Task<AccountResponse> CreateAsync(Guid userId, CreateAccountRequest request)
{
var account = new Account
{
Id = Guid.NewGuid(),
UserId = userId,
Name = request.Name,
Type = request.Type,
Institution = request.Institution,
AccountNumber = request.AccountNumber,
Balance = request.Balance,
CreditLimit = request.CreditLimit,
InterestRate = request.InterestRate,
Notes = request.Notes,
SortOrder = await _db.Accounts.CountAsync(a => a.UserId == userId)
};
_db.Accounts.Add(account);
await _db.SaveChangesAsync();
return MapToResponse(account);
}
public async Task<AccountResponse> UpdateAsync(Guid userId, Guid accountId, UpdateAccountRequest request)
{
var account = await _db.Accounts.FirstOrDefaultAsync(a => a.Id == accountId && a.UserId == userId)
?? throw new KeyNotFoundException("Account not found");
account.Name = request.Name;
account.Type = request.Type;
account.Institution = request.Institution;
account.AccountNumber = request.AccountNumber;
account.CreditLimit = request.CreditLimit;
account.InterestRate = request.InterestRate;
account.Notes = request.Notes;
account.IsActive = request.IsActive;
account.SortOrder = request.SortOrder;
account.UpdatedAt = DateTime.UtcNow;
await _db.SaveChangesAsync();
return MapToResponse(account);
}
public async Task DeleteAsync(Guid userId, Guid accountId)
{
var account = await _db.Accounts.FirstOrDefaultAsync(a => a.Id == accountId && a.UserId == userId)
?? throw new KeyNotFoundException("Account not found");
_db.Accounts.Remove(account);
await _db.SaveChangesAsync();
}
public async Task<List<BalanceHistoryEntry>> GetBalanceHistoryAsync(Guid userId, Guid accountId, DateTime startDate, DateTime endDate)
{
var account = await _db.Accounts.FirstOrDefaultAsync(a => a.Id == accountId && a.UserId == userId)
?? throw new KeyNotFoundException("Account not found");
var transactions = await _db.Transactions
.Where(t => t.AccountId == accountId && t.Date >= startDate && t.Date <= endDate && !t.IsVoid)
.OrderBy(t => t.Date)
.ToListAsync();
var balanceBefore = account.Balance - await _db.Transactions
.Where(t => t.AccountId == accountId && !t.IsVoid)
.SumAsync(t => t.Amount);
var priorSum = await _db.Transactions
.Where(t => t.AccountId == accountId && t.Date < startDate && !t.IsVoid)
.SumAsync(t => t.Amount);
var runningBalance = balanceBefore + priorSum;
var entries = new List<BalanceHistoryEntry>();
foreach (var group in transactions.GroupBy(t => t.Date.Date))
{
runningBalance += group.Sum(t => t.Amount);
entries.Add(new BalanceHistoryEntry(group.Key, runningBalance));
}
return entries;
}
public async Task RecalculateBalanceAsync(Guid accountId)
{
var account = await _db.Accounts.FindAsync(accountId);
if (account == null) return;
var sum = await _db.Transactions
.Where(t => t.AccountId == accountId && !t.IsVoid)
.SumAsync(t => t.Amount);
account.Balance = sum;
account.UpdatedAt = DateTime.UtcNow;
await _db.SaveChangesAsync();
}
private static AccountResponse MapToResponse(Account a) => new(
a.Id, a.Name, a.Type, a.Institution, a.AccountNumber,
a.Balance, a.CreditLimit, a.InterestRate,
a.IsActive, a.IsClosed, a.Notes, a.SortOrder, a.CreatedAt,
a.LoanDetail != null
);
}