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

185 lines
5.6 KiB
C#

using Microsoft.EntityFrameworkCore;
using MoneyMap.Data;
using MoneyMap.Models;
namespace MoneyMap.Services
{
public interface IMerchantService
{
Task<Merchant?> FindByNameAsync(string name);
Task<Merchant> GetOrCreateAsync(string name);
Task<int?> GetOrCreateIdAsync(string? name);
Task<Merchant?> GetMerchantByIdAsync(int id, bool includeRelated = false);
Task<List<MerchantWithStats>> GetAllMerchantsWithStatsAsync();
Task<MerchantUpdateResult> UpdateMerchantAsync(int id, string newName);
Task<MerchantDeleteResult> DeleteMerchantAsync(int id);
}
public class MerchantService : IMerchantService
{
private readonly MoneyMapContext _db;
public MerchantService(MoneyMapContext db)
{
_db = db;
}
public async Task<Merchant?> FindByNameAsync(string name)
{
if (string.IsNullOrWhiteSpace(name))
return null;
return await _db.Merchants
.FirstOrDefaultAsync(m => m.Name == name.Trim());
}
public async Task<Merchant> GetOrCreateAsync(string name)
{
var trimmedName = name.Trim();
var existing = await _db.Merchants
.FirstOrDefaultAsync(m => m.Name == trimmedName);
if (existing != null)
return existing;
var merchant = new Merchant { Name = trimmedName };
_db.Merchants.Add(merchant);
await _db.SaveChangesAsync();
return merchant;
}
public async Task<int?> GetOrCreateIdAsync(string? name)
{
if (string.IsNullOrWhiteSpace(name))
return null;
var merchant = await GetOrCreateAsync(name);
return merchant.Id;
}
public async Task<Merchant?> GetMerchantByIdAsync(int id, bool includeRelated = false)
{
var query = _db.Merchants.AsQueryable();
if (includeRelated)
{
query = query
.Include(m => m.Transactions)
.Include(m => m.CategoryMappings);
}
return await query.FirstOrDefaultAsync(m => m.Id == id);
}
public async Task<List<MerchantWithStats>> GetAllMerchantsWithStatsAsync()
{
var merchants = await _db.Merchants
.Include(m => m.Transactions)
.Include(m => m.CategoryMappings)
.OrderBy(m => m.Name)
.ToListAsync();
return merchants.Select(m => new MerchantWithStats
{
Id = m.Id,
Name = m.Name,
TransactionCount = m.Transactions.Count,
MappingCount = m.CategoryMappings.Count
}).ToList();
}
public async Task<MerchantUpdateResult> UpdateMerchantAsync(int id, string newName)
{
var merchant = await _db.Merchants.FindAsync(id);
if (merchant == null)
{
return new MerchantUpdateResult
{
Success = false,
Message = "Merchant not found."
};
}
var trimmedName = newName.Trim();
// Check if another merchant with the same name exists
var existing = await _db.Merchants
.FirstOrDefaultAsync(m => m.Name == trimmedName && m.Id != id);
if (existing != null)
{
return new MerchantUpdateResult
{
Success = false,
Message = $"Merchant '{trimmedName}' already exists."
};
}
merchant.Name = trimmedName;
await _db.SaveChangesAsync();
return new MerchantUpdateResult
{
Success = true,
Message = "Merchant updated successfully."
};
}
public async Task<MerchantDeleteResult> DeleteMerchantAsync(int id)
{
var merchant = await _db.Merchants
.Include(m => m.Transactions)
.Include(m => m.CategoryMappings)
.FirstOrDefaultAsync(m => m.Id == id);
if (merchant == null)
{
return new MerchantDeleteResult
{
Success = false,
Message = "Merchant not found."
};
}
var transactionCount = merchant.Transactions.Count;
var mappingCount = merchant.CategoryMappings.Count;
_db.Merchants.Remove(merchant);
await _db.SaveChangesAsync();
return new MerchantDeleteResult
{
Success = true,
Message = $"Deleted merchant '{merchant.Name}'. {transactionCount} transactions and {mappingCount} category mappings are now unlinked.",
TransactionCount = transactionCount,
MappingCount = mappingCount
};
}
}
// DTOs
public class MerchantWithStats
{
public int Id { get; set; }
public string Name { get; set; } = "";
public int TransactionCount { get; set; }
public int MappingCount { get; set; }
}
public class MerchantUpdateResult
{
public bool Success { get; set; }
public string Message { get; set; } = "";
}
public class MerchantDeleteResult
{
public bool Success { get; set; }
public string Message { get; set; } = "";
public int TransactionCount { get; set; }
public int MappingCount { get; set; }
}
}