PR C: mechanical cleanup (typos, packages, formatting, culture)
- Consolidate decimal.ToFormattedString into Schaad.Accounting.Formatting - Rename EnsureFileExisits -> EnsureFileExists and SplitPredefiniton* -> SplitPredefinition* (class, interface, files, DI reg) - AccountRepository: single-save year-rollover start-balance seed - Drop legacy .NET Standard packages redundant on net9.0 and the stale Interfaces\Extensions\ folder entry - Set culture via RequestLocalizationOptions middleware - Plan: item 9 (unit of work) split off into a dedicated PR D Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
152d4c3d57
commit
8961bb234c
15 changed files with 82 additions and 80 deletions
|
|
@ -97,6 +97,7 @@ Analysis and phased plan produced 2026-07-02. See conversation history for full
|
|||
|
||||
- **PR A** — Phase 1 items 1–7 + CLAUDE.md fix.
|
||||
- **PR B** — Phase 1 item 8 (atomic writes + lock).
|
||||
- **PR C** — Phase 2 items 9 + 11 + 13 + 15 + 16 + 17.
|
||||
- **PR D** — Phase 3 (async).
|
||||
- **PR E** — Phase 4 (tests) — done alongside PR C to lock in behavior.
|
||||
- **PR C** — Phase 2 mechanical cleanup: items 11, 13, 15, 16, 17.
|
||||
- **PR D** — Phase 2 item 9: per-request unit of work / cache. Split off from PR C because it is invasive enough to warrant its own review.
|
||||
- **PR E** — Phase 3 (async).
|
||||
- **PR F** — Phase 4 (tests) — done alongside PR D to lock in behavior.
|
||||
|
|
|
|||
19
Schaad.Accounting.Common/Formatting.cs
Normal file
19
Schaad.Accounting.Common/Formatting.cs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
using System.Globalization;
|
||||
|
||||
namespace Schaad.Accounting
|
||||
{
|
||||
public static class Formatting
|
||||
{
|
||||
private static readonly CultureInfo SwissCulture = CreateSwissCulture();
|
||||
|
||||
public static string ToFormattedString(this decimal value)
|
||||
=> value.ToString("#,0.00", SwissCulture);
|
||||
|
||||
private static CultureInfo CreateSwissCulture()
|
||||
{
|
||||
var culture = new CultureInfo("de-CH");
|
||||
culture.NumberFormat.NumberGroupSeparator = "'";
|
||||
return culture;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using Schaad.Accounting.Models;
|
||||
|
||||
namespace Schaad.Accounting.Interfaces
|
||||
{
|
||||
public interface ISplitPredefinitonRepository
|
||||
public interface ISplitPredefinitionRepository
|
||||
{
|
||||
List<SplitPredefinition> GetSplitPredefinitionList();
|
||||
|
||||
void SaveSplitPredefinition(SplitPredefinition splitPredefinition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,17 +4,9 @@
|
|||
<TargetFramework>net9.0</TargetFramework>
|
||||
<RootNamespace>Schaad.Accounting</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
|
||||
<PackageReference Include="System.Xml.XmlSerializer" Version="4.3.0" />
|
||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Schaad.Finance.Api">
|
||||
<HintPath>..\dlls\Schaad.Finance.Api.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Interfaces\Extensions\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -13,7 +13,7 @@ namespace Schaad.Accounting.Repositories
|
|||
|
||||
public AccountRepository(ISettingsService settingsService) : base(settingsService)
|
||||
{
|
||||
EnsureFileExisits(ACCOUNTS);
|
||||
EnsureAccountsFile();
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -79,35 +79,40 @@ namespace Schaad.Accounting.Repositories
|
|||
SaveAccount(account);
|
||||
}
|
||||
|
||||
private new void EnsureFileExisits(string file)
|
||||
private void EnsureAccountsFile()
|
||||
{
|
||||
string filePath = Path.Combine(settingsService.GetDbPath(), file);
|
||||
if (File.Exists(filePath) == false)
|
||||
string filePath = Path.Combine(settingsService.GetDbPath(), ACCOUNTS);
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
var lastYearFile = Path.Combine(settingsService.GetLastYearDbPath(), file);
|
||||
if (File.Exists(lastYearFile))
|
||||
File.Copy(lastYearFile, filePath);
|
||||
return;
|
||||
}
|
||||
|
||||
// set start balance to last bank balance
|
||||
if (file.IndexOf("Accounts") > -1)
|
||||
var lastYearFile = Path.Combine(settingsService.GetLastYearDbPath(), ACCOUNTS);
|
||||
if (File.Exists(lastYearFile))
|
||||
{
|
||||
File.Copy(lastYearFile, filePath);
|
||||
}
|
||||
|
||||
// Year rollover: seed start balances from the previous year's closing values.
|
||||
// Bank accounts start at the last known bank balance; cash accounts start at zero.
|
||||
var accounts = GetAccountList();
|
||||
var modified = false;
|
||||
foreach (var account in accounts.Where(a => a.Class == ClassIds.Activa))
|
||||
{
|
||||
if (account.LastBankBalance > 0)
|
||||
{
|
||||
var accounts = GetAccountList();
|
||||
foreach (var account in accounts.Where(a => a.Class == ClassIds.Activa))
|
||||
{
|
||||
// bank accounts
|
||||
if (account.LastBankBalance > 0)
|
||||
{
|
||||
account.StartBalance = account.LastBankBalance;
|
||||
SaveAccount(account);
|
||||
}
|
||||
// cash accounts
|
||||
else if (account.Number < 1010)
|
||||
{
|
||||
account.StartBalance = 0;
|
||||
SaveAccount(account);
|
||||
}
|
||||
}
|
||||
account.StartBalance = account.LastBankBalance;
|
||||
modified = true;
|
||||
}
|
||||
else if (account.Number < 1010)
|
||||
{
|
||||
account.StartBalance = 0;
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
if (modified)
|
||||
{
|
||||
Save(accounts, ACCOUNTS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace Schaad.Accounting.Repositories
|
|||
this.settingsService = settingsService;
|
||||
}
|
||||
|
||||
protected void EnsureFileExisits(string fileName)
|
||||
protected void EnsureFileExists(string fileName)
|
||||
{
|
||||
string filePath = Path.Combine(settingsService.GetDbPath(), fileName);
|
||||
lock (GetLock(filePath))
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ namespace Schaad.Accounting.Repositories
|
|||
|
||||
public BookingRuleRepository(ISettingsService settingsService) : base(settingsService)
|
||||
{
|
||||
EnsureFileExisits(BOOKING_RULES);
|
||||
EnsureFileExists(BOOKING_RULES);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ namespace Schaad.Accounting.Repositories
|
|||
|
||||
public BookingTextRepository(ISettingsService settingsService) : base(settingsService)
|
||||
{
|
||||
EnsureFileExisits(BOOKING_TEXTS);
|
||||
EnsureFileExists(BOOKING_TEXTS);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Schaad.Accounting.Interfaces;
|
||||
|
|
@ -6,17 +6,17 @@ using Schaad.Accounting.Models;
|
|||
|
||||
namespace Schaad.Accounting.Repositories
|
||||
{
|
||||
public class SplitPredefinitonRepository : BaseRepository, ISplitPredefinitonRepository
|
||||
public class SplitPredefinitionRepository : BaseRepository, ISplitPredefinitionRepository
|
||||
{
|
||||
private readonly string SPLIT_PREDEFINITION = "SplitPredefinitions.xml";
|
||||
|
||||
public SplitPredefinitonRepository(ISettingsService settingsService) : base(settingsService)
|
||||
public SplitPredefinitionRepository(ISettingsService settingsService) : base(settingsService)
|
||||
{
|
||||
EnsureFileExisits(SPLIT_PREDEFINITION);
|
||||
EnsureFileExists(SPLIT_PREDEFINITION);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load booking rules
|
||||
/// Load split predefinitions
|
||||
/// </summary>
|
||||
public List<SplitPredefinition> GetSplitPredefinitionList()
|
||||
{
|
||||
|
|
@ -25,7 +25,7 @@ namespace Schaad.Accounting.Repositories
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save a booking rule (insert/update)
|
||||
/// Save a split predefinition (insert/update)
|
||||
/// </summary>
|
||||
public void SaveSplitPredefinition(SplitPredefinition splitPredefinition)
|
||||
{
|
||||
|
|
@ -42,4 +42,4 @@ namespace Schaad.Accounting.Repositories
|
|||
Save(definitions, SPLIT_PREDEFINITION);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ namespace Schaad.Accounting.Repositories
|
|||
|
||||
public SubclassRepository(ISettingsService settingsService) : base(settingsService)
|
||||
{
|
||||
EnsureFileExisits(SUBCLASSES);
|
||||
EnsureFileExists(SUBCLASSES);
|
||||
|
||||
classes.Add(ClassIds.Activa, "Aktiven");
|
||||
classes.Add(ClassIds.Passiva, "Passiven");
|
||||
|
|
|
|||
|
|
@ -4,9 +4,6 @@
|
|||
<TargetFramework>net9.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Schaad.Accounting.Common\Schaad.Accounting.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
|
@ -134,25 +133,18 @@ namespace Schaad.Accounting.Services
|
|||
|
||||
if (trx.OriginAccountId == accountId)
|
||||
{
|
||||
debit = ToFormattedString(trx.Value);
|
||||
debit = trx.Value.ToFormattedString();
|
||||
signedValue = -trx.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
credit = ToFormattedString(trx.Value);
|
||||
credit = trx.Value.ToFormattedString();
|
||||
}
|
||||
balance += signedValue;
|
||||
sb.AppendLine($"{trx.BookingDate:dd.MM.yyyy};{trx.ValueDate:dd.MM.yyyy};{trx.Text};{debit};{credit};{ToFormattedString(balance)}");
|
||||
sb.AppendLine($"{trx.BookingDate:dd.MM.yyyy};{trx.ValueDate:dd.MM.yyyy};{trx.Text};{debit};{credit};{balance.ToFormattedString()}");
|
||||
}
|
||||
var fileBytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(sb.ToString());
|
||||
return fileBytes;
|
||||
}
|
||||
|
||||
private string ToFormattedString(decimal value)
|
||||
{
|
||||
var culture = new CultureInfo("de-CH");
|
||||
culture.NumberFormat.NumberGroupSeparator = "'";
|
||||
return value.ToString("#,0.00", culture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="FreeSpire.PDF" Version="10.2.0" />
|
||||
<PackageReference Include="System.Text.RegularExpressions" Version="4.3.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Schaad.Accounting.Common\Schaad.Accounting.Common.csproj" />
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using System.Globalization;
|
||||
using Schaad.Accounting.Interfaces;
|
||||
using Schaad.Accounting.Interfaces;
|
||||
using Schaad.Accounting.Repositories;
|
||||
using Schaad.Accounting.Services;
|
||||
using Schaad.Finance.Api;
|
||||
|
|
@ -9,13 +8,6 @@ namespace Schaad.Accounting.UI
|
|||
{
|
||||
public static class Extensions
|
||||
{
|
||||
public static string ToFormattedString(this decimal value)
|
||||
{
|
||||
var culture = new CultureInfo("de-CH");
|
||||
culture.NumberFormat.NumberGroupSeparator = "'";
|
||||
return value.ToString("#,0.00", culture);
|
||||
}
|
||||
|
||||
public static IServiceCollection AddAccounting(this IServiceCollection services)
|
||||
{
|
||||
// Singleton because MyHeader triggers a full page reload (forceLoad: true) after
|
||||
|
|
@ -28,7 +20,7 @@ namespace Schaad.Accounting.UI
|
|||
services.AddScoped<IBankTransactionRepository, BankTransactionRepository>();
|
||||
services.AddScoped<IBookingRuleRepository, BookingRuleRepository>();
|
||||
services.AddScoped<IBookingTextRepository, BookingTextRepository>();
|
||||
services.AddScoped<ISplitPredefinitonRepository, SplitPredefinitonRepository>();
|
||||
services.AddScoped<ISplitPredefinitionRepository, SplitPredefinitionRepository>();
|
||||
services.AddScoped<ISubclassRepository, SubclassRepository>();
|
||||
services.AddScoped<ITransactionRepository, TransactionRepository>();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using System.Globalization;
|
||||
using Microsoft.AspNetCore.Localization;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.FluentUI.AspNetCore.Components;
|
||||
using Schaad.Accounting.Datasets;
|
||||
|
|
@ -38,15 +39,19 @@ namespace Schaad.Accounting.UI
|
|||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
var supportedCultures = new[] { new CultureInfo("de-CH") };
|
||||
app.UseRequestLocalization(new RequestLocalizationOptions
|
||||
{
|
||||
DefaultRequestCulture = new RequestCulture(supportedCultures[0]),
|
||||
SupportedCultures = supportedCultures,
|
||||
SupportedUICultures = supportedCultures
|
||||
});
|
||||
|
||||
app.UseAntiforgery();
|
||||
app.MapStaticAssets();
|
||||
app.MapRazorComponents<App>()
|
||||
.AddInteractiveServerRenderMode();
|
||||
|
||||
var culture = new CultureInfo("de-CH");
|
||||
CultureInfo.DefaultThreadCurrentCulture = culture;
|
||||
CultureInfo.DefaultThreadCurrentUICulture = culture;
|
||||
|
||||
|
||||
app.Run();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue