EKÁER: add warning/error distinction, status, and filters

- Validation now distinguishes blocking errors from warnings; only errors block submission, warnings are shown but allow progress.
- Introduced EkaerSeverity, EkaerValidationMessage, and severity-aware extensions for validation results.
- Extended EkaerHistory.Status with GeneratedWithWarning and SentWithMissingData; added EkaerStatusExtensions for status categorization.
- Added EkaerHistoryFilter for server-side filtering; updated SignalR and controller interfaces accordingly.
- UI now displays error/warning messages with color/icons, supports new status tabs/filters, and restricts XML copying to submittable records.
- Refactored validation and error handling to use new severity logic; updated comments and minor code for clarity.
This commit is contained in:
Loretta 2026-06-12 09:00:26 +02:00
parent 52541628f9
commit ad7d5813cb
3 changed files with 47 additions and 5 deletions

View File

@ -22,9 +22,10 @@ public sealed class EkaerSubmitService : IEkaerSubmitService
{ {
ArgumentNullException.ThrowIfNull(operations); ArgumentNullException.ThrowIfNull(operations);
// 1) Validáció — bármilyen hiba esetén NEM küldünk; a teljes hibalistát visszaadjuk. // 1) Validáció — csak BLOKKOLÓ (error) szintű hiba esetén NEM küldünk; a warning (pl. hiányzó rendszám,
// ami a felrakodásig pótolható) nem blokkol. A teljes üzenetlistát visszaadjuk (warningostul).
var errors = _validator.Validate(operations); var errors = _validator.Validate(operations);
if (errors.Count > 0) if (errors.HasErrors())
return EkaerSubmitResult.Invalid(errors); return EkaerSubmitResult.Invalid(errors);
// 2) Request összeállítás. A Header/User példányt itt kell létrehozni (a generált ctor csak a // 2) Request összeállítás. A Header/User példányt itt kell létrehozni (a generált ctor csak a

View File

@ -84,7 +84,9 @@ public sealed class EkaerTradeCardValidator : IEkaerTradeCardValidator
} }
// 3) Üzleti szabályok (az XSD nem jelöli [Required]-ként, de a NAV megköveteli). // 3) Üzleti szabályok (az XSD nem jelöli [Required]-ként, de a NAV megköveteli).
if (tradeCard.Vehicle is null) errors.Add(Error($"{path}.vehicle", "a vonó jármű (rendszám) kötelező — rendszám nélkül a NAV elutasítja a bejelentést")); // A rendszám a NAV-nál legkésőbb a felrakodás megkezdéséig pótolható — a bejelentéskor NEM kötelező,
// ezért hiánya WARNING (a bejelentés beküldhető), nem blokkoló error. Lásd EKAER_OPERATIONS.md (create→finalize).
if (tradeCard.Vehicle is null) errors.Add(Warning($"{path}.vehicle", "a vonó jármű (rendszám) hiányzik — legkésőbb a felrakodás megkezdéséig pótolandó"));
if (tradeCard.Items.Count == 0) errors.Add(Error($"{path}.items", "legalább egy tétel szükséges")); if (tradeCard.Items.Count == 0) errors.Add(Error($"{path}.items", "legalább egy tétel szükséges"));
RequireText(tradeCard.SellerName, $"{path}.sellerName", "a feladó (eladó) neve kötelező", errors); RequireText(tradeCard.SellerName, $"{path}.sellerName", "a feladó (eladó) neve kötelező", errors);
@ -117,7 +119,7 @@ public sealed class EkaerTradeCardValidator : IEkaerTradeCardValidator
Validator.TryValidateProperty(property.GetValue(instance), context, local); Validator.TryValidateProperty(property.GetValue(instance), context, local);
foreach (var result in local) foreach (var result in local)
errors.Add(new ValidationResult($"{path}.{property.Name}: {result.ErrorMessage}", result.MemberNames)); errors.Add(new EkaerValidationMessage(EkaerSeverity.Error, $"{path}.{property.Name}: {result.ErrorMessage}"));
} }
} }
@ -127,5 +129,7 @@ public sealed class EkaerTradeCardValidator : IEkaerTradeCardValidator
errors.Add(Error(path, message)); errors.Add(Error(path, message));
} }
private static ValidationResult Error(string path, string message) => new($"{path}: {message}"); private static EkaerValidationMessage Error(string path, string message) => new(EkaerSeverity.Error, $"{path}: {message}");
private static EkaerValidationMessage Warning(string path, string message) => new(EkaerSeverity.Warning, $"{path}: {message}");
} }

View File

@ -0,0 +1,37 @@
using System.ComponentModel.DataAnnotations;
namespace AyCode.Services.Nav.Ekaer;
/// <summary>Az EKÁER validációs üzenet súlyossága.</summary>
public enum EkaerSeverity
{
/// <summary>Nem blokkoló — a bejelentés beküldhető, de valamit pótolni kell (pl. a rendszám a felrakodásig).</summary>
Warning,
/// <summary>Blokkoló — a NAV elutasítaná; beküldés előtt javítandó.</summary>
Error,
}
/// <summary>
/// Súlyossággal (warning/error) bővített validációs eredmény. A <see cref="ValidationResult"/>-ból származik,
/// így a meglévő fogyasztók (akik csak az <c>ErrorMessage</c>-et használják) változatlanul működnek; aki a
/// szintet is akarja, a <see cref="Severity"/>-t / a <c>GetSeverity()</c> kiterjesztést használja.
/// </summary>
public sealed class EkaerValidationMessage(EkaerSeverity severity, string message) : ValidationResult(message)
{
public EkaerSeverity Severity { get; } = severity;
}
/// <summary>Súlyosság-segédek a validációs eredmény-listához.</summary>
public static class EkaerValidationExtensions
{
/// <summary>A súlyosság; egy sima (nem <see cref="EkaerValidationMessage"/>) eredmény konzervatívan <see cref="EkaerSeverity.Error"/>.</summary>
public static EkaerSeverity GetSeverity(this ValidationResult result)
=> result is EkaerValidationMessage m ? m.Severity : EkaerSeverity.Error;
/// <summary>Van-e blokkoló (error) szintű üzenet — ennek alapján NEM küldhető a bejelentés.</summary>
public static bool HasErrors(this IEnumerable<ValidationResult> results) => results.Any(r => r.GetSeverity() == EkaerSeverity.Error);
/// <summary>Van-e warning szintű üzenet (a beküldést nem blokkolja, de pótlandó).</summary>
public static bool HasWarnings(this IEnumerable<ValidationResult> results) => results.Any(r => r.GetSeverity() == EkaerSeverity.Warning);
}