AccountingNext/Schaad.Accounting.Services/SettingsService.cs
Claudio Schaad 9f11f6490b PR A: correctness fixes and improvement plan
- Add IMPROVEMENT_PLAN.md with phased plan for follow-up work
- Consolidate DI registrations into a single AddAccounting() extension;
  drop the duplicate service registrations and the PdfParsingService
  self-registration
- TrySetYear: capture this.year before overwriting so rollback actually
  restores the previous value
- DummyFxService: check toCurrency (was checking fromCurrency twice)
- TransactionRepository.GetTransaction: return a copy instead of mutating
  the loaded entity, and guard against unknown ids
- ViewService.GetTransactionViewList(accountId): flip the sign on a copy
  rather than mutating the entity returned by the repository
- FileService.GetTransactionListCsv: same treatment; use a local
  signedValue instead of mutating trx.Value
- ProfitLossReport: use ClassIds.Income/Expenses instead of magic 3/4
- CLAUDE.md: correct the ClassIds documentation (1/2/3/4, not
  1000/2000/3000/4000)

SettingsService lifetime is intentionally left as Singleton for now;
making it Scoped requires persisting year/mandator selection across
page reloads first (tracked in the plan).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-02 20:37:03 +02:00

131 lines
No EOL
3.7 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Schaad.Accounting.Datasets;
using Schaad.Accounting.Interfaces;
namespace Schaad.Accounting.Services
{
public class SettingsService : ISettingsService
{
private readonly SettingsDataset settingsDataset;
private string mandator = "Claudio Schaad";
private int year = DateTime.Now.Year;
public SettingsService(SettingsDataset settingsDataset)
{
this.settingsDataset = settingsDataset;
}
public int GetYear()
{
return year;
}
public void SetYear(int year)
{
this.year = year;
}
public bool TrySetYear(int year)
{
var oldYear = this.year;
SetYear(year);
if (Directory.GetFiles(GetDbPath()).Any() == false)
{
SetYear(oldYear);
return false;
}
return true;
}
public string GetMandator()
{
return mandator;
}
public IReadOnlyList<string> GetMandators(int year)
{
var path = Path.Combine(GetSettings().DataPath, year.ToString());
return Directory.GetDirectories(path).Select(Path.GetFileName).Where(d => !d.Equals("Backup", StringComparison.InvariantCultureIgnoreCase)).ToList();
}
public void SetMandator(string mandator)
{
this.mandator = mandator;
}
public string GetYearMandatorPath()
{
var path = Path.Combine(GetSettings().DataPath, year.ToString(), mandator);
if (Directory.Exists(path) == false)
{
Directory.CreateDirectory(path);
}
return path;
}
public string GetLastYearMandatorPath()
{
var path = Path.Combine(GetSettings().DataPath, (year - 1).ToString(), mandator);
return path;
}
public string GetBackupFilePath()
{
var backupPath = Path.Combine(GetSettings().DataPath, year.ToString(), "backup", mandator);
if (Directory.Exists(backupPath) == false)
{
Directory.CreateDirectory(backupPath);
}
var backupFilePath = Path.Combine(backupPath, DateTime.Now.ToString("yyyyMMddHHmmss") + ".zip");
return backupFilePath;
}
public string GetUploadPath()
{
var uploadPath = Path.Combine(GetYearMandatorPath(), "uploads");
if (Directory.Exists(uploadPath) == false)
{
Directory.CreateDirectory(uploadPath);
}
return uploadPath;
}
public string GetCreditCardStatementPath()
{
var path = Path.Combine(GetUploadPath(), "creditCard");
if (Directory.Exists(path) == false)
{
Directory.CreateDirectory(path);
}
return path;
}
public string GetDbPath()
{
var path = Path.Combine(GetYearMandatorPath(), "Data");
if (Directory.Exists(path) == false)
{
Directory.CreateDirectory(path);
}
return path;
}
public string GetLastYearDbPath()
{
var path = Path.Combine(GetLastYearMandatorPath(), "Data");
if (Directory.Exists(path) == false)
{
Directory.CreateDirectory(path);
}
return path;
}
public SettingsDataset GetSettings()
{
return settingsDataset;
}
}
}