refactor: extract Models and Data into MoneyMap.Core shared library

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-20 18:16:33 -04:00
parent d831991ad0
commit 3deca29f05
23 changed files with 59 additions and 7 deletions
@@ -0,0 +1,28 @@
namespace MoneyMap.Models.Import
{
/// <summary>
/// Context for transaction import operations, containing payment selection mode and available options.
/// </summary>
public class ImportContext
{
public required PaymentSelectMode PaymentMode { get; init; }
public int? SelectedCardId { get; init; }
public int? SelectedAccountId { get; init; }
public required List<Card> AvailableCards { get; init; }
public required List<Account> AvailableAccounts { get; init; }
public required string FileName { get; init; }
}
/// <summary>
/// Specifies how to determine the payment method for imported transactions.
/// </summary>
public enum PaymentSelectMode
{
/// <summary>Auto-detect from memo or filename.</summary>
Auto,
/// <summary>Use a specific card for all transactions.</summary>
Card,
/// <summary>Use a specific account for all transactions.</summary>
Account
}
}
@@ -0,0 +1,69 @@
namespace MoneyMap.Models.Import
{
/// <summary>
/// Result of an import operation, showing counts of processed transactions.
/// </summary>
public record ImportResult(int Total, int Inserted, int Skipped, string? Last4FromFile);
/// <summary>
/// Wrapper for import operation result with success/failure state.
/// </summary>
public class ImportOperationResult
{
public bool IsSuccess { get; init; }
public ImportResult? Data { get; init; }
public string? ErrorMessage { get; init; }
public static ImportOperationResult Success(ImportResult data) =>
new() { IsSuccess = true, Data = data };
public static ImportOperationResult Failure(string error) =>
new() { IsSuccess = false, ErrorMessage = error };
}
/// <summary>
/// Wrapper for preview operation result with success/failure state.
/// </summary>
public class PreviewOperationResult
{
public bool IsSuccess { get; init; }
public List<TransactionPreview>? Data { get; init; }
public string? ErrorMessage { get; init; }
public static PreviewOperationResult Success(List<TransactionPreview> data) =>
new() { IsSuccess = true, Data = data };
public static PreviewOperationResult Failure(string error) =>
new() { IsSuccess = false, ErrorMessage = error };
}
/// <summary>
/// Preview of a transaction before import, with duplicate detection info.
/// </summary>
public class TransactionPreview
{
public required Transaction Transaction { get; init; }
public bool IsDuplicate { get; init; }
public required string PaymentMethodLabel { get; init; }
public string? SuggestedCategory { get; set; }
}
/// <summary>
/// User's selection for payment method during import confirmation.
/// </summary>
public class PaymentSelection
{
public int? AccountId { get; set; }
public int? CardId { get; set; }
public string? Category { get; set; }
}
/// <summary>
/// Key for detecting duplicate transactions.
/// </summary>
public record TransactionKey(DateTime Date, decimal Amount, string Name, string Memo, int AccountId, int? CardId)
{
public TransactionKey(Transaction txn)
: this(txn.Date, txn.Amount, txn.Name, txn.Memo, txn.AccountId, txn.CardId) { }
}
}
@@ -0,0 +1,32 @@
namespace MoneyMap.Models.Import
{
/// <summary>
/// Result of resolving a payment method (card or account) for a transaction.
/// </summary>
public class PaymentResolutionResult
{
public bool IsSuccess { get; init; }
public int? CardId { get; init; }
public int? AccountId { get; init; }
public string? Last4 { get; init; }
public string? ErrorMessage { get; init; }
/// <summary>
/// Creates a successful result when a card is used.
/// </summary>
public static PaymentResolutionResult SuccessCard(int cardId, int accountId, string last4) =>
new() { IsSuccess = true, CardId = cardId, AccountId = accountId, Last4 = last4 };
/// <summary>
/// Creates a successful result when a direct account transaction (no card).
/// </summary>
public static PaymentResolutionResult SuccessAccount(int accountId, string last4) =>
new() { IsSuccess = true, AccountId = accountId, Last4 = last4 };
/// <summary>
/// Creates a failure result with error message.
/// </summary>
public static PaymentResolutionResult Failure(string error) =>
new() { IsSuccess = false, ErrorMessage = error };
}
}
@@ -0,0 +1,11 @@
namespace MoneyMap.Models.Import;
public class TransactionCsvRow
{
public DateTime Date { get; set; }
public string Transaction { get; set; } = "";
public string Name { get; set; } = "";
public string Memo { get; set; } = "";
public decimal Amount { get; set; }
public string Category { get; set; } = "";
}
@@ -0,0 +1,32 @@
using CsvHelper.Configuration;
namespace MoneyMap.Models.Import;
public sealed class TransactionCsvRowMap : ClassMap<TransactionCsvRow>
{
public TransactionCsvRowMap(bool hasCategory)
{
Map(m => m.Date).Name("Date");
Map(m => m.Transaction).Name("Transaction");
Map(m => m.Name).Name("Name");
Map(m => m.Memo).Name("Memo");
Map(m => m.Amount).Name("Amount");
if (hasCategory)
{
Map(m => m.Category).Name("Category");
}
else
{
if (hasCategory)
{
Map(m => m.Category).Name("Category");
}
else
{
Map(m => m.Category).Constant(string.Empty).Optional();
}
}
}
}