Files
MoneyMap/MoneyMap.Core/Services/CardService.cs
T
2026-04-20 18:18:20 -04:00

124 lines
3.3 KiB
C#

using Microsoft.EntityFrameworkCore;
using MoneyMap.Data;
using MoneyMap.Models;
namespace MoneyMap.Services;
/// <summary>
/// Service for card management including retrieval, validation, and deletion.
/// </summary>
public interface ICardService
{
/// <summary>
/// Gets a card by ID with optional related data.
/// </summary>
Task<Card?> GetCardByIdAsync(int id, bool includeRelated = false);
/// <summary>
/// Gets all cards with transaction statistics.
/// </summary>
Task<List<CardWithStats>> GetAllCardsWithStatsAsync();
/// <summary>
/// Checks if a card can be deleted (no transactions exist).
/// </summary>
Task<DeleteValidationResult> CanDeleteCardAsync(int id);
/// <summary>
/// Deletes a card if it has no associated transactions.
/// </summary>
Task<DeleteResult> DeleteCardAsync(int id);
}
public class CardService : ICardService
{
private readonly MoneyMapContext _db;
public CardService(MoneyMapContext db)
{
_db = db;
}
public async Task<Card?> GetCardByIdAsync(int id, bool includeRelated = false)
{
var query = _db.Cards.AsQueryable();
if (includeRelated)
{
query = query
.Include(c => c.Account)
.Include(c => c.Transactions);
}
return await query.FirstOrDefaultAsync(c => c.Id == id);
}
public async Task<List<CardWithStats>> GetAllCardsWithStatsAsync()
{
// Single query with projection to avoid N+1
return await _db.Cards
.Include(c => c.Account)
.OrderBy(c => c.Owner)
.ThenBy(c => c.Last4)
.Select(c => new CardWithStats
{
Card = c,
TransactionCount = c.Transactions.Count
})
.ToListAsync();
}
public async Task<DeleteValidationResult> CanDeleteCardAsync(int id)
{
var card = await _db.Cards.FindAsync(id);
if (card == null)
return new DeleteValidationResult
{
CanDelete = false,
Reason = "Card not found."
};
var transactionCount = await _db.Transactions.CountAsync(t => t.CardId == id);
if (transactionCount > 0)
return new DeleteValidationResult
{
CanDelete = false,
Reason = $"Cannot delete card. It has {transactionCount} transaction(s) associated with it."
};
return new DeleteValidationResult { CanDelete = true };
}
public async Task<DeleteResult> DeleteCardAsync(int id)
{
var validation = await CanDeleteCardAsync(id);
if (!validation.CanDelete)
{
return new DeleteResult
{
Success = false,
Message = validation.Reason ?? "Cannot delete card."
};
}
var card = await _db.Cards.FindAsync(id);
if (card == null)
{
return new DeleteResult
{
Success = false,
Message = "Card not found."
};
}
_db.Cards.Remove(card);
await _db.SaveChangesAsync();
return new DeleteResult
{
Success = true,
Message = "Card deleted successfully."
};
}
}