AccountingNext/Schaad.Accounting.Db/Repositories/TransactionRepository.cs
Claudio Schaad 3a770af016 PR J: log repository save failures via ILogger
BaseRepository takes an ILogger via its constructor and logs the
failing file path and exception in Save's catch block before
rethrowing. Every concrete repository takes ILogger<ThisRepo> and
passes it up so failures are categorised by repository type.

Pulls Microsoft.Extensions.Logging.Abstractions into the Db project.
TransactionRepositoryTestShould and AccountRepositoryTestShould pass
NullLogger<T>.Instance.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-02 21:47:55 +02:00

98 lines
No EOL
3.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Logging;
using Schaad.Accounting.Interfaces;
using Schaad.Accounting.Models;
namespace Schaad.Accounting.Repositories
{
public class TransactionRepository : BaseRepository, ITransactionRepository
{
private readonly IAccountRepository accountRepository;
private readonly string TRANSACTIONS = "Transactions.xml";
public TransactionRepository(ISettingsService settingsService, RepositoryCache cache, IAccountRepository accountRepository, ILogger<TransactionRepository> logger)
: base(settingsService, cache, logger)
{
this.accountRepository = accountRepository;
}
/// <summary>
/// Get transaction list
/// </summary>
public List<Transaction> GetTransactionList() => LoadList<Transaction>(TRANSACTIONS);
/// <summary>
/// Save a transaction (insert/update)
/// </summary>
public void SaveTransaction(Transaction transaction)
{
transaction.Value = Math.Abs(transaction.Value);
var originIsFx = accountRepository.GetAccount(transaction.OriginAccountId).IsFxAccount;
var targetIsFx = accountRepository.GetAccount(transaction.TargetAccountId).IsFxAccount;
var isFxAccount = originIsFx || targetIsFx;
// user enters amount in the foreign account's currency -> convert to CHF for storage
if (isFxAccount && transaction.FxRate != 0)
{
transaction.Value = transaction.Value * transaction.FxRate.Value;
}
if (!isFxAccount)
{
transaction.FxRate = null;
}
var transactionList = GetTransactionList();
var existingTransaction = transactionList.FirstOrDefault(a => a.Id == transaction.Id);
if (existingTransaction == null)
{
existingTransaction = new Transaction();
transactionList.Add(existingTransaction);
transaction.Id = Guid.NewGuid().ToString();
}
transaction.Copy(existingTransaction);
Save(transactionList, TRANSACTIONS);
}
/// <summary>
/// Get transaction
/// </summary>
public Transaction GetTransaction(string id)
{
var transactions = GetTransactionList();
var stored = transactions.FirstOrDefault(t => t.Id == id);
if (stored == null)
{
return null;
}
var result = new Transaction();
stored.Copy(result);
// value is stored in CHF -> convert back to foreign currency for display/editing
var isFxAccount = accountRepository.GetAccount(result.OriginAccountId).IsFxAccount
|| accountRepository.GetAccount(result.TargetAccountId).IsFxAccount;
if (isFxAccount && result.FxRate != 0)
{
result.Value = result.Value / result.FxRate.Value;
}
return result;
}
/// <summary>
/// Delete transaction
/// </summary>
public void DeleteTransaction(string id)
{
var transactions = GetTransactionList();
transactions.RemoveAll(t => t.Id == id);
Save(transactions, TRANSACTIONS);
}
}
}