namespace SmartB2B.Enova.Contracts; public enum OrderSaveMode { Buffer, Approved } public sealed record EnovaConnectionOptions( string DatabaseName, string OperatorName, string Password); public sealed record EnovaAdapterConfiguration( EnovaConnectionOptions Connection, string DocumentDefinition, string? DefaultWarehouseCode, OrderSaveMode SaveMode); public sealed class OrderRequest { public string CustomerCode { get; init; } = string.Empty; public string? CustomerReference { get; init; } public string? Notes { get; init; } public string DocumentDefinition { get; init; } = "ZO"; public string? WarehouseCode { get; init; } public OrderSaveMode SaveMode { get; init; } = OrderSaveMode.Buffer; public IReadOnlyList Items { get; init; } = []; } public sealed class OrderLineRequest { public string ProductCode { get; init; } = string.Empty; public decimal Quantity { get; init; } public decimal UnitPrice { get; init; } public decimal Discount { get; init; } } public sealed record OrderResult( int Id, string Number, OrderSaveMode SaveMode, string CustomerCode, string WarehouseCode, string? CustomerReference, int LineCount, decimal Net, decimal Vat, decimal Gross, bool HasDiscount); public sealed record EnovaAdapterInfo( string AdapterVersion, string SonetaBusinessVersion, string SonetaHandelVersion, string DatabaseName); public interface IEnovaOrderAdapter { EnovaAdapterInfo Initialize(EnovaAdapterConfiguration configuration); OrderResult CreateOrder(OrderRequest request); } public sealed class EnovaOperationException : Exception { public EnovaOperationException( string errorUri, string message, IReadOnlyDictionary? details = null, Exception? innerException = null) : base(message, innerException) { ErrorUri = errorUri; Details = details ?? new Dictionary(); } public string ErrorUri { get; } public IReadOnlyDictionary Details { get; } } public static class OrderValidator { public static IReadOnlyList Validate(OrderRequest? request) { var errors = new List(); if (request is null) { errors.Add("Brak danych zamówienia."); return errors; } if (string.IsNullOrWhiteSpace(request.CustomerCode)) { errors.Add("Pole companyErpId jest wymagane."); } if (string.IsNullOrWhiteSpace(request.DocumentDefinition)) { errors.Add("Definicja dokumentu jest wymagana."); } if (request.Items is null || request.Items.Count == 0) { errors.Add("Zamówienie musi zawierać co najmniej jedną pozycję."); return errors; } for (var index = 0; index < request.Items.Count; index++) { var line = request.Items[index]; var prefix = $"lines[{index}]"; if (line is null) { errors.Add($"{prefix}: pozycja nie może być pusta."); continue; } if (string.IsNullOrWhiteSpace(line.ProductCode)) { errors.Add($"{prefix}.symbol jest wymagane."); } if (line.Quantity <= 0) { errors.Add($"{prefix}.quantity musi być większe od zera."); } if (line.UnitPrice < 0) { errors.Add($"{prefix}.price_netto nie może być ujemne."); } if (line.Discount is < 0 or > 100) { errors.Add($"{prefix}.discount musi mieścić się w zakresie 0-100."); } } return errors; } }