refactor: move services and AITools to MoneyMap.Core
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
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."
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user