@page "/finance-rules"
@rendermode @(Microsoft.AspNetCore.Components.Web.RenderMode.InteractiveServer)
@attribute [Authorize(Policy = TrafagSalesExporter.Security.SecurityPolicies.AdminOnly)]
@using System.Reflection
@using TrafagSalesExporter.Models
@using TrafagSalesExporter.Services
@inject IFinanceRulesPageService FinanceRulesPageActions
@inject ISnackbar Snackbar
@inject IUiTextService UiText
@T("Finance Regeln", "Finance rules")
@T("Finance Regeln", "Finance rules")
@T("Diese Regeln wirken nur auf die Finance-Sicht im zentralen Excel und im Abgleich. Rohdaten und Spaltenmapping bleiben unveraendert.",
"These rules only affect the finance view in the central Excel and reconciliation. Raw data and column mappings remain unchanged.")
@T("Regel hinzufuegen", "Add rule")
@T("Alle speichern", "Save all")
@T("Default-Regeln laden", "Load default rules")
Aktiv
Land
Jahr
Regeltyp
Feld
Vergleich
Wert
Sort
Notiz
@foreach (var type in FinanceRuleTypes.All)
{
@GetRuleTypeLabel(type)
}
-
@foreach (var field in _recordFields)
{
@field
}
@foreach (var type in FinanceRuleMatchTypes.All)
{
@GetMatchTypeLabel(type)
}
@code {
private readonly string[] _recordFields = typeof(SalesRecord)
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Select(property => property.Name)
.OrderBy(name => name, StringComparer.OrdinalIgnoreCase)
.ToArray();
private List _rules = [];
protected override async Task OnInitializedAsync()
{
_rules = await FinanceRulesPageActions.LoadAsync();
}
private void AddRule()
{
_rules.Add(new FinanceRule
{
ScopeKey = "DE",
RuleType = FinanceRuleTypes.Exclude,
FieldName = nameof(SalesRecord.CustomerName),
MatchType = FinanceRuleMatchTypes.Contains,
SortOrder = _rules.Count == 0 ? 100 : _rules.Max(rule => rule.SortOrder) + 10,
IsActive = true
});
}
private void RemoveRule(FinanceRule rule) => _rules.Remove(rule);
private void LoadDefaults()
{
_rules = FinanceRuleEngine.CreateDefaultRules()
.Select(rule => new FinanceRule
{
ScopeKey = rule.ScopeKey,
Year = rule.Year,
RuleType = rule.RuleType,
FieldName = rule.FieldName,
MatchType = rule.MatchType,
MatchValue = rule.MatchValue,
Notes = rule.Notes,
SortOrder = rule.SortOrder,
IsActive = rule.IsActive
})
.ToList();
}
private async Task SaveAllAsync()
{
_rules = await FinanceRulesPageActions.SaveAllAsync(_rules);
Snackbar.Add(T("Finance-Regeln gespeichert.", "Finance rules saved."), Severity.Success);
}
private static bool UsesNoField(FinanceRule rule)
=> rule.RuleType == FinanceRuleTypes.ForceYear ||
rule.MatchType == FinanceRuleMatchTypes.Always;
private static bool UsesNoMatchValue(FinanceRule rule)
=> rule.MatchType is FinanceRuleMatchTypes.Always or FinanceRuleMatchTypes.IsBlank;
private string GetRuleTypeLabel(string type)
=> type switch
{
FinanceRuleTypes.Exclude => T("Ausschliessen", "Exclude"),
FinanceRuleTypes.NegateAmount => T("Betrag negativ", "Negate amount"),
FinanceRuleTypes.ForceYear => T("Jahr erzwingen", "Force year"),
FinanceRuleTypes.DeduplicateBlankSupplierCountry => T("Duplikate ohne Supplier Country", "Deduplicate blank supplier country"),
_ => type
};
private string GetMatchTypeLabel(string type)
=> type switch
{
FinanceRuleMatchTypes.Always => T("Immer", "Always"),
FinanceRuleMatchTypes.Equal => T("gleich", "equals"),
FinanceRuleMatchTypes.Contains => T("enthaelt", "contains"),
FinanceRuleMatchTypes.StartsWith => T("beginnt mit", "starts with"),
FinanceRuleMatchTypes.IsBlank => T("ist leer", "is blank"),
_ => type
};
private string T(string german, string english) => UiText.Text(german, english);
}