Regelsteuerung grafisch und per C# Templates

This commit is contained in:
2026-04-16 08:47:13 +02:00
parent d02f4abb57
commit a25e5900c7
11 changed files with 205 additions and 14 deletions
@@ -3,18 +3,24 @@
@using System.Reflection @using System.Reflection
@using TrafagSalesExporter.Data @using TrafagSalesExporter.Data
@using TrafagSalesExporter.Models @using TrafagSalesExporter.Models
@using TrafagSalesExporter.Services
@inject IDbContextFactory<AppDbContext> DbFactory @inject IDbContextFactory<AppDbContext> DbFactory
@inject ITransformationCatalog TransformationCatalog
@inject ISnackbar Snackbar @inject ISnackbar Snackbar
<PageTitle>Transformationen</PageTitle> <PageTitle>Transformationen</PageTitle>
<MudText Typo="Typo.h4" Class="mb-4">Transformer Ansicht</MudText> <MudText Typo="Typo.h4" Class="mb-4">Transformer Ansicht</MudText>
<MudText Typo="Typo.body1" Class="mb-4">Definiere pro Quellsystem (SAP, BI1, SAGE) Feld-Remapping und Transformationen.</MudText> <MudText Typo="Typo.body1" Class="mb-4">Definiere pro Quellsystem einfache Feldregeln und komplexe record-basierte Strategien.</MudText>
<MudPaper Class="pa-4" Elevation="1"> <MudPaper Class="pa-4" Elevation="1">
<MudAlert Severity="Severity.Info" Dense="true" Variant="Variant.Outlined" Class="mb-3">
`Value`-Regeln arbeiten feldweise. `Record`-Regeln rufen eine registrierte C#-Strategie auf und koennen mehrere Felder eines Datensatzes verwenden.
</MudAlert>
<MudStack Row="true" Spacing="2" Class="mb-3"> <MudStack Row="true" Spacing="2" Class="mb-3">
<MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Add" OnClick="AddRule"> <MudButton Variant="Variant.Filled" Color="Color.Primary" StartIcon="@Icons.Material.Filled.Add" OnClick="AddRule">
Regel hinzufügen Regel hinzufuegen
</MudButton> </MudButton>
<MudButton Variant="Variant.Outlined" Color="Color.Secondary" StartIcon="@Icons.Material.Filled.Save" OnClick="SaveAllAsync"> <MudButton Variant="Variant.Outlined" Color="Color.Secondary" StartIcon="@Icons.Material.Filled.Save" OnClick="SaveAllAsync">
Alle speichern Alle speichern
@@ -25,6 +31,7 @@
<HeaderContent> <HeaderContent>
<MudTh>Aktiv</MudTh> <MudTh>Aktiv</MudTh>
<MudTh>System</MudTh> <MudTh>System</MudTh>
<MudTh>Scope</MudTh>
<MudTh>Source</MudTh> <MudTh>Source</MudTh>
<MudTh>Target</MudTh> <MudTh>Target</MudTh>
<MudTh>Typ</MudTh> <MudTh>Typ</MudTh>
@@ -38,15 +45,23 @@
<MudSelect T="string" Value="@context.SourceSystem" ValueChanged="@(v => context.SourceSystem = v)" Dense> <MudSelect T="string" Value="@context.SourceSystem" ValueChanged="@(v => context.SourceSystem = v)" Dense>
@foreach (var system in _systems) @foreach (var system in _systems)
{ {
<MudSelectItem Value="system">@system</MudSelectItem> <MudSelectItem Value="@system">@system</MudSelectItem>
} }
</MudSelect> </MudSelect>
</MudTd> </MudTd>
<MudTd> <MudTd>
<MudSelect T="string" Value="@context.SourceField" ValueChanged="@(v => context.SourceField = v)" Dense> <MudSelect T="string" Value="@context.RuleScope" ValueChanged="@(v => ChangeRuleScope(context, v))" Dense>
@foreach (var scope in _ruleScopes)
{
<MudSelectItem Value="@scope">@scope</MudSelectItem>
}
</MudSelect>
</MudTd>
<MudTd>
<MudSelect T="string" Value="@context.SourceField" ValueChanged="@(v => context.SourceField = v)" Dense Disabled="@IsRecordScope(context)">
@foreach (var field in _recordFields) @foreach (var field in _recordFields)
{ {
<MudSelectItem Value="field">@field</MudSelectItem> <MudSelectItem Value="@field">@field</MudSelectItem>
} }
</MudSelect> </MudSelect>
</MudTd> </MudTd>
@@ -54,21 +69,21 @@
<MudSelect T="string" Value="@context.TargetField" ValueChanged="@(v => context.TargetField = v)" Dense> <MudSelect T="string" Value="@context.TargetField" ValueChanged="@(v => context.TargetField = v)" Dense>
@foreach (var field in _recordFields) @foreach (var field in _recordFields)
{ {
<MudSelectItem Value="field">@field</MudSelectItem> <MudSelectItem Value="@field">@field</MudSelectItem>
} }
</MudSelect> </MudSelect>
</MudTd> </MudTd>
<MudTd> <MudTd>
<MudSelect T="string" Value="@context.TransformationType" ValueChanged="@(v => context.TransformationType = v)" Dense> <MudSelect T="string" Value="@context.TransformationType" ValueChanged="@(v => context.TransformationType = v)" Dense>
@foreach (var type in _types) @foreach (var type in GetTypesForScope(context.RuleScope))
{ {
<MudSelectItem Value="type">@type</MudSelectItem> <MudSelectItem Value="@type.Key">@type.Key</MudSelectItem>
} }
</MudSelect> </MudSelect>
</MudTd> </MudTd>
<MudTd> <MudTd>
<MudTextField T="string" Value="@context.Argument" ValueChanged="@(v => context.Argument = v)" <MudTextField T="string" Value="@context.Argument" ValueChanged="@(v => context.Argument = v)"
HelperText="Replace: alt=>neu" /> HelperText="@GetArgumentHelperText(context)" />
</MudTd> </MudTd>
<MudTd> <MudTd>
<MudNumericField T="int" Value="@context.SortOrder" ValueChanged="@(v => context.SortOrder = v)" Dense /> <MudNumericField T="int" Value="@context.SortOrder" ValueChanged="@(v => context.SortOrder = v)" Dense />
@@ -82,8 +97,8 @@
</MudPaper> </MudPaper>
@code { @code {
private readonly string[] _systems = ["SAP", "BI1", "SAGE"]; private readonly string[] _systems = ["SAP", "BI1", "SAGE", "MANUAL_EXCEL"];
private readonly string[] _types = ["Copy", "Uppercase", "Lowercase", "Prefix", "Suffix", "Replace", "Constant"]; private readonly string[] _ruleScopes = ["Value", "Record"];
private readonly string[] _recordFields = typeof(SalesRecord) private readonly string[] _recordFields = typeof(SalesRecord)
.GetProperties(BindingFlags.Public | BindingFlags.Instance) .GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Select(p => p.Name) .Select(p => p.Name)
@@ -91,9 +106,11 @@
.ToArray(); .ToArray();
private List<FieldTransformationRule> _rules = new(); private List<FieldTransformationRule> _rules = new();
private IReadOnlyList<TransformationCatalogItem> _catalogItems = [];
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
_catalogItems = TransformationCatalog.GetAll();
await LoadAsync(); await LoadAsync();
} }
@@ -101,6 +118,15 @@
{ {
using var db = await DbFactory.CreateDbContextAsync(); using var db = await DbFactory.CreateDbContextAsync();
_rules = await db.FieldTransformationRules.OrderBy(r => r.SortOrder).ThenBy(r => r.Id).ToListAsync(); _rules = await db.FieldTransformationRules.OrderBy(r => r.SortOrder).ThenBy(r => r.Id).ToListAsync();
foreach (var rule in _rules)
{
rule.RuleScope = string.IsNullOrWhiteSpace(rule.RuleScope) ? "Value" : rule.RuleScope;
if (!GetTypesForScope(rule.RuleScope).Any(x => string.Equals(x.Key, rule.TransformationType, StringComparison.OrdinalIgnoreCase)))
{
rule.TransformationType = GetTypesForScope(rule.RuleScope).FirstOrDefault()?.Key ?? "Copy";
}
}
} }
private void AddRule() private void AddRule()
@@ -109,6 +135,7 @@
_rules.Add(new FieldTransformationRule _rules.Add(new FieldTransformationRule
{ {
SourceSystem = "SAP", SourceSystem = "SAP",
RuleScope = "Value",
SourceField = nameof(SalesRecord.Material), SourceField = nameof(SalesRecord.Material),
TargetField = nameof(SalesRecord.Material), TargetField = nameof(SalesRecord.Material),
TransformationType = "Copy", TransformationType = "Copy",
@@ -134,4 +161,35 @@
Snackbar.Add("Transformationsregeln gespeichert.", Severity.Success); Snackbar.Add("Transformationsregeln gespeichert.", Severity.Success);
await LoadAsync(); await LoadAsync();
} }
private IReadOnlyList<TransformationCatalogItem> GetTypesForScope(string? ruleScope)
{
var scope = string.IsNullOrWhiteSpace(ruleScope) ? "Value" : ruleScope;
return TransformationCatalog.GetByScope(scope);
}
private static bool IsRecordScope(FieldTransformationRule rule)
=> string.Equals(rule.RuleScope, "Record", StringComparison.OrdinalIgnoreCase);
private void ChangeRuleScope(FieldTransformationRule rule, string scope)
{
rule.RuleScope = scope;
var firstType = GetTypesForScope(scope).FirstOrDefault()?.Key;
if (!string.IsNullOrWhiteSpace(firstType))
rule.TransformationType = firstType;
if (IsRecordScope(rule))
rule.SourceField = string.Empty;
else if (string.IsNullOrWhiteSpace(rule.SourceField))
rule.SourceField = nameof(SalesRecord.Material);
}
private string GetArgumentHelperText(FieldTransformationRule rule)
{
var item = _catalogItems.FirstOrDefault(x =>
string.Equals(x.RuleScope, rule.RuleScope, StringComparison.OrdinalIgnoreCase) &&
string.Equals(x.Key, rule.TransformationType, StringComparison.OrdinalIgnoreCase));
return item?.Description ?? "Optionales Argument.";
}
} }
@@ -18,6 +18,9 @@ public class FieldTransformationRule
[Required] [Required]
public string TransformationType { get; set; } = "Copy"; public string TransformationType { get; set; } = "Copy";
[Required]
public string RuleScope { get; set; } = "Value";
public string Argument { get; set; } = string.Empty; public string Argument { get; set; } = string.Empty;
public int SortOrder { get; set; } public int SortOrder { get; set; }
+2
View File
@@ -25,6 +25,8 @@ builder.Services.AddSingleton<ITransformationStrategy, PrefixTransformationStrat
builder.Services.AddSingleton<ITransformationStrategy, SuffixTransformationStrategy>(); builder.Services.AddSingleton<ITransformationStrategy, SuffixTransformationStrategy>();
builder.Services.AddSingleton<ITransformationStrategy, ReplaceTransformationStrategy>(); builder.Services.AddSingleton<ITransformationStrategy, ReplaceTransformationStrategy>();
builder.Services.AddSingleton<ITransformationStrategy, ConstantTransformationStrategy>(); builder.Services.AddSingleton<ITransformationStrategy, ConstantTransformationStrategy>();
builder.Services.AddSingleton<IRecordTransformationStrategy, FirstNonEmptyRecordTransformationStrategy>();
builder.Services.AddSingleton<ITransformationCatalog, TransformationCatalog>();
builder.Services.AddSingleton<IRecordTransformationService, RecordTransformationService>(); builder.Services.AddSingleton<IRecordTransformationService, RecordTransformationService>();
builder.Services.AddSingleton<IAppEventLogService, AppEventLogService>(); builder.Services.AddSingleton<IAppEventLogService, AppEventLogService>();
builder.Services.AddSingleton<IManagementCockpitService, ManagementCockpitService>(); builder.Services.AddSingleton<IManagementCockpitService, ManagementCockpitService>();
@@ -95,6 +95,7 @@ public class ConfigTransferService : IConfigTransferService
SourceField = r.SourceField, SourceField = r.SourceField,
TargetField = r.TargetField, TargetField = r.TargetField,
TransformationType = r.TransformationType, TransformationType = r.TransformationType,
RuleScope = r.RuleScope,
Argument = r.Argument, Argument = r.Argument,
SortOrder = r.SortOrder, SortOrder = r.SortOrder,
IsActive = r.IsActive IsActive = r.IsActive
@@ -265,6 +266,7 @@ public class ConfigTransferService : IConfigTransferService
SourceField = r.SourceField, SourceField = r.SourceField,
TargetField = r.TargetField, TargetField = r.TargetField,
TransformationType = r.TransformationType, TransformationType = r.TransformationType,
RuleScope = r.RuleScope,
Argument = r.Argument, Argument = r.Argument,
SortOrder = r.SortOrder, SortOrder = r.SortOrder,
IsActive = r.IsActive IsActive = r.IsActive
@@ -71,6 +71,7 @@ public class DatabaseInitializationService : IDatabaseInitializationService
AddColumnIfMissing(db, "ExportSettings", "LocalConsolidatedExportFolder", "TEXT NOT NULL DEFAULT ''"); AddColumnIfMissing(db, "ExportSettings", "LocalConsolidatedExportFolder", "TEXT NOT NULL DEFAULT ''");
AddColumnIfMissing(db, "ExportLogs", "FilePath", "TEXT NOT NULL DEFAULT ''"); AddColumnIfMissing(db, "ExportLogs", "FilePath", "TEXT NOT NULL DEFAULT ''");
EnsureTransformationTable(db); EnsureTransformationTable(db);
AddColumnIfMissing(db, "FieldTransformationRules", "RuleScope", "TEXT NOT NULL DEFAULT 'Value'");
EnsureSapSourceTable(db); EnsureSapSourceTable(db);
EnsureSapJoinTable(db); EnsureSapJoinTable(db);
EnsureSapFieldMappingTable(db); EnsureSapFieldMappingTable(db);
@@ -440,6 +441,7 @@ CREATE TABLE IF NOT EXISTS FieldTransformationRules (
SourceField TEXT NOT NULL, SourceField TEXT NOT NULL,
TargetField TEXT NOT NULL, TargetField TEXT NOT NULL,
TransformationType TEXT NOT NULL, TransformationType TEXT NOT NULL,
RuleScope TEXT NOT NULL DEFAULT 'Value',
Argument TEXT NOT NULL DEFAULT '', Argument TEXT NOT NULL DEFAULT '',
SortOrder INTEGER NOT NULL DEFAULT 0, SortOrder INTEGER NOT NULL DEFAULT 0,
IsActive INTEGER NOT NULL DEFAULT 1 IsActive INTEGER NOT NULL DEFAULT 1
@@ -0,0 +1,10 @@
using TrafagSalesExporter.Models;
namespace TrafagSalesExporter.Services;
public interface IRecordTransformationStrategy
{
string TransformationType { get; }
string Description => string.Empty;
void Transform(SalesRecord record, FieldTransformationRule rule);
}
@@ -0,0 +1,14 @@
namespace TrafagSalesExporter.Services;
public interface ITransformationCatalog
{
IReadOnlyList<TransformationCatalogItem> GetAll();
IReadOnlyList<TransformationCatalogItem> GetByScope(string ruleScope);
}
public sealed class TransformationCatalogItem
{
public string Key { get; init; } = string.Empty;
public string RuleScope { get; init; } = string.Empty;
public string Description { get; init; } = string.Empty;
}
@@ -3,5 +3,6 @@ namespace TrafagSalesExporter.Services;
public interface ITransformationStrategy public interface ITransformationStrategy
{ {
string TransformationType { get; } string TransformationType { get; }
string Description => string.Empty;
object? Transform(object? sourceValue, string? argument); object? Transform(object? sourceValue, string? argument);
} }
@@ -5,15 +5,17 @@ namespace TrafagSalesExporter.Services;
public class RecordTransformationService : IRecordTransformationService public class RecordTransformationService : IRecordTransformationService
{ {
private static readonly Dictionary<string, PropertyInfo> PropertyMap = typeof(SalesRecord) internal static readonly Dictionary<string, PropertyInfo> PropertyMap = typeof(SalesRecord)
.GetProperties(BindingFlags.Public | BindingFlags.Instance) .GetProperties(BindingFlags.Public | BindingFlags.Instance)
.ToDictionary(p => p.Name, p => p, StringComparer.OrdinalIgnoreCase); .ToDictionary(p => p.Name, p => p, StringComparer.OrdinalIgnoreCase);
private readonly IReadOnlyDictionary<string, ITransformationStrategy> _strategies; private readonly IReadOnlyDictionary<string, ITransformationStrategy> _strategies;
private readonly IReadOnlyDictionary<string, IRecordTransformationStrategy> _recordStrategies;
public RecordTransformationService(IEnumerable<ITransformationStrategy> strategies) public RecordTransformationService(IEnumerable<ITransformationStrategy> strategies, IEnumerable<IRecordTransformationStrategy> recordStrategies)
{ {
_strategies = strategies.ToDictionary(s => s.TransformationType, StringComparer.OrdinalIgnoreCase); _strategies = strategies.ToDictionary(s => s.TransformationType, StringComparer.OrdinalIgnoreCase);
_recordStrategies = recordStrategies.ToDictionary(s => s.TransformationType, StringComparer.OrdinalIgnoreCase);
} }
public void Apply(List<SalesRecord> records, IEnumerable<FieldTransformationRule> rules) public void Apply(List<SalesRecord> records, IEnumerable<FieldTransformationRule> rules)
@@ -32,6 +34,13 @@ public class RecordTransformationService : IRecordTransformationService
private void ApplyRule(SalesRecord record, FieldTransformationRule rule) private void ApplyRule(SalesRecord record, FieldTransformationRule rule)
{ {
if (string.Equals(rule.RuleScope, "Record", StringComparison.OrdinalIgnoreCase))
{
if (_recordStrategies.TryGetValue(rule.TransformationType, out var recordStrategy))
recordStrategy.Transform(record, rule);
return;
}
if (!PropertyMap.TryGetValue(rule.SourceField, out var sourceProp)) return; if (!PropertyMap.TryGetValue(rule.SourceField, out var sourceProp)) return;
if (!PropertyMap.TryGetValue(rule.TargetField, out var targetProp)) return; if (!PropertyMap.TryGetValue(rule.TargetField, out var targetProp)) return;
@@ -43,7 +52,7 @@ public class RecordTransformationService : IRecordTransformationService
SetPropertyValue(record, targetProp, result); SetPropertyValue(record, targetProp, result);
} }
private static void SetPropertyValue(SalesRecord record, PropertyInfo property, object? value) internal static void SetPropertyValue(SalesRecord record, PropertyInfo property, object? value)
{ {
try try
{ {
@@ -0,0 +1,33 @@
namespace TrafagSalesExporter.Services;
public class TransformationCatalog : ITransformationCatalog
{
private readonly IReadOnlyList<TransformationCatalogItem> _items;
public TransformationCatalog(IEnumerable<ITransformationStrategy> valueStrategies, IEnumerable<IRecordTransformationStrategy> recordStrategies)
{
_items = valueStrategies
.Select(x => new TransformationCatalogItem
{
Key = x.TransformationType,
RuleScope = "Value",
Description = x.Description
})
.Concat(recordStrategies.Select(x => new TransformationCatalogItem
{
Key = x.TransformationType,
RuleScope = "Record",
Description = x.Description
}))
.OrderBy(x => x.RuleScope, StringComparer.OrdinalIgnoreCase)
.ThenBy(x => x.Key, StringComparer.OrdinalIgnoreCase)
.ToList();
}
public IReadOnlyList<TransformationCatalogItem> GetAll() => _items;
public IReadOnlyList<TransformationCatalogItem> GetByScope(string ruleScope)
=> _items
.Where(x => string.Equals(x.RuleScope, ruleScope, StringComparison.OrdinalIgnoreCase))
.ToList();
}
@@ -1,38 +1,46 @@
using TrafagSalesExporter.Models;
namespace TrafagSalesExporter.Services; namespace TrafagSalesExporter.Services;
public sealed class CopyTransformationStrategy : ITransformationStrategy public sealed class CopyTransformationStrategy : ITransformationStrategy
{ {
public string TransformationType => "Copy"; public string TransformationType => "Copy";
public string Description => "Kopiert Source nach Target.";
public object? Transform(object? sourceValue, string? argument) => sourceValue; public object? Transform(object? sourceValue, string? argument) => sourceValue;
} }
public sealed class UppercaseTransformationStrategy : ITransformationStrategy public sealed class UppercaseTransformationStrategy : ITransformationStrategy
{ {
public string TransformationType => "Uppercase"; public string TransformationType => "Uppercase";
public string Description => "Wandelt Text in Grossbuchstaben.";
public object? Transform(object? sourceValue, string? argument) => sourceValue?.ToString()?.ToUpperInvariant(); public object? Transform(object? sourceValue, string? argument) => sourceValue?.ToString()?.ToUpperInvariant();
} }
public sealed class LowercaseTransformationStrategy : ITransformationStrategy public sealed class LowercaseTransformationStrategy : ITransformationStrategy
{ {
public string TransformationType => "Lowercase"; public string TransformationType => "Lowercase";
public string Description => "Wandelt Text in Kleinbuchstaben.";
public object? Transform(object? sourceValue, string? argument) => sourceValue?.ToString()?.ToLowerInvariant(); public object? Transform(object? sourceValue, string? argument) => sourceValue?.ToString()?.ToLowerInvariant();
} }
public sealed class PrefixTransformationStrategy : ITransformationStrategy public sealed class PrefixTransformationStrategy : ITransformationStrategy
{ {
public string TransformationType => "Prefix"; public string TransformationType => "Prefix";
public string Description => "Stellt Argument vor den Source-Wert.";
public object? Transform(object? sourceValue, string? argument) => $"{argument}{sourceValue}"; public object? Transform(object? sourceValue, string? argument) => $"{argument}{sourceValue}";
} }
public sealed class SuffixTransformationStrategy : ITransformationStrategy public sealed class SuffixTransformationStrategy : ITransformationStrategy
{ {
public string TransformationType => "Suffix"; public string TransformationType => "Suffix";
public string Description => "Haengt Argument an den Source-Wert.";
public object? Transform(object? sourceValue, string? argument) => $"{sourceValue}{argument}"; public object? Transform(object? sourceValue, string? argument) => $"{sourceValue}{argument}";
} }
public sealed class ReplaceTransformationStrategy : ITransformationStrategy public sealed class ReplaceTransformationStrategy : ITransformationStrategy
{ {
public string TransformationType => "Replace"; public string TransformationType => "Replace";
public string Description => "Ersetzt in Text mit Syntax alt=>neu.";
public object? Transform(object? sourceValue, string? argument) public object? Transform(object? sourceValue, string? argument)
{ {
@@ -54,5 +62,54 @@ public sealed class ReplaceTransformationStrategy : ITransformationStrategy
public sealed class ConstantTransformationStrategy : ITransformationStrategy public sealed class ConstantTransformationStrategy : ITransformationStrategy
{ {
public string TransformationType => "Constant"; public string TransformationType => "Constant";
public string Description => "Setzt das Target auf einen konstanten Wert aus Argument.";
public object? Transform(object? sourceValue, string? argument) => argument; public object? Transform(object? sourceValue, string? argument) => argument;
} }
public sealed class FirstNonEmptyRecordTransformationStrategy : IRecordTransformationStrategy
{
public string TransformationType => "FirstNonEmpty";
public string Description => "Record-Strategie: setzt Target aus dem ersten nicht-leeren Feld aus Argument, z.B. CustomerName|SupplierName|Name.";
public void Transform(SalesRecord record, FieldTransformationRule rule)
{
if (string.IsNullOrWhiteSpace(rule.TargetField) || string.IsNullOrWhiteSpace(rule.Argument))
return;
var propertyMap = RecordTransformationService.PropertyMap;
if (!propertyMap.TryGetValue(rule.TargetField, out var targetProperty))
return;
var sourceFields = rule.Argument
.Split(['|', ',', ';'], StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
foreach (var sourceField in sourceFields)
{
if (!propertyMap.TryGetValue(sourceField, out var sourceProperty))
continue;
var value = sourceProperty.GetValue(record);
if (IsMeaningfulValue(value))
{
RecordTransformationService.SetPropertyValue(record, targetProperty, value);
return;
}
}
}
private static bool IsMeaningfulValue(object? value)
{
if (value is null)
return false;
if (value is string text)
return !string.IsNullOrWhiteSpace(text);
if (value is DateTime date)
return date != default;
if (value is decimal decimalNumber)
return decimalNumber != 0m;
if (value is int intNumber)
return intNumber != 0;
return true;
}
}