Initial Enova365 sync service

This commit is contained in:
2026-07-15 08:27:32 +00:00
commit 605c6b7d2a
50 changed files with 2813 additions and 0 deletions

View File

@@ -0,0 +1,171 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using SmartB2B.Enova.Contracts;
namespace SmartB2B.Enova.Service.Configuration;
public sealed class ServiceSettings
{
public string Portal { get; init; } = string.Empty;
public WampSettings Wamp { get; init; } = new();
public EnovaSettings Enova { get; init; } = new();
public SqlSettings Sql { get; init; } = new();
public DiagnosticsSettings Diagnostics { get; init; } = new();
public static ServiceSettings Load(string path)
{
if (!File.Exists(path))
{
throw new ConfigurationException($"Nie znaleziono pliku konfiguracji: {path}");
}
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
ReadCommentHandling = JsonCommentHandling.Skip,
AllowTrailingCommas = true,
Converters = { new JsonStringEnumConverter() }
};
ServiceSettings settings;
try
{
settings = JsonSerializer.Deserialize<ServiceSettings>(File.ReadAllText(path), options)
?? throw new ConfigurationException("Plik konfiguracji jest pusty.");
}
catch (JsonException exception)
{
throw new ConfigurationException($"Niepoprawny JSON konfiguracji: {exception.Message}", exception);
}
settings.Validate();
return settings;
}
public RuntimeSettings ResolveRuntimeSettings()
{
var enovaPassword = Environment.GetEnvironmentVariable(Enova.PasswordEnvironmentVariable);
if (enovaPassword is null)
{
throw new ConfigurationException(
$"Brak zmiennej środowiskowej {Enova.PasswordEnvironmentVariable} z hasłem operatora Enovy.");
}
var connectionString = Environment.GetEnvironmentVariable(Sql.ConnectionStringEnvironmentVariable);
if (string.IsNullOrWhiteSpace(connectionString))
{
throw new ConfigurationException(
$"Brak zmiennej środowiskowej {Sql.ConnectionStringEnvironmentVariable} z connection stringiem SQL.");
}
var installationPath = Path.GetFullPath(
Environment.ExpandEnvironmentVariables(Enova.InstallationPath));
return new RuntimeSettings(
installationPath,
new EnovaAdapterConfiguration(
new EnovaConnectionOptions(Enova.Database, Enova.Operator, enovaPassword),
Enova.DocumentDefinition,
Enova.DefaultWarehouseCode,
Enova.SaveMode),
connectionString,
Sql.CommandTimeoutSeconds,
ResolvePath(Diagnostics.LogDirectory),
Diagnostics.LogPrefix);
}
private void Validate()
{
var errors = new List<string>();
Require(Portal, "portal", errors);
Require(Wamp.ServerUrl, "wamp.serverUrl", errors);
if (Wamp.ReconnectDelaySeconds <= 0)
{
errors.Add("wamp.reconnectDelaySeconds musi być większe od zera.");
}
Require(Enova.InstallationPath, "enova.installationPath", errors);
Require(Enova.Database, "enova.database", errors);
Require(Enova.Operator, "enova.operator", errors);
Require(Enova.PasswordEnvironmentVariable, "enova.passwordEnvironmentVariable", errors);
Require(Enova.DocumentDefinition, "enova.documentDefinition", errors);
Require(Sql.ConnectionStringEnvironmentVariable, "sql.connectionStringEnvironmentVariable", errors);
if (Sql.CommandTimeoutSeconds <= 0)
{
errors.Add("sql.commandTimeoutSeconds musi być większe od zera.");
}
if (errors.Count > 0)
{
throw new ConfigurationException(string.Join(Environment.NewLine, errors));
}
}
private static void Require(string? value, string name, ICollection<string> errors)
{
if (string.IsNullOrWhiteSpace(value))
{
errors.Add($"Parametr '{name}' jest wymagany.");
}
}
private static string ResolvePath(string path) =>
Path.IsPathRooted(path) ? Path.GetFullPath(path) : Path.GetFullPath(path, AppContext.BaseDirectory);
}
public sealed class WampSettings
{
public string ServerUrl { get; init; } = string.Empty;
public int ReconnectDelaySeconds { get; init; } = 10;
}
public sealed class EnovaSettings
{
public string InstallationPath { get; init; } = string.Empty;
public string Database { get; init; } = string.Empty;
public string Operator { get; init; } = "Administrator";
public string PasswordEnvironmentVariable { get; init; } = "SMARTB2B_ENOVA_PASSWORD";
public string DocumentDefinition { get; init; } = "ZO";
public string? DefaultWarehouseCode { get; init; }
public OrderSaveMode SaveMode { get; init; } = OrderSaveMode.Buffer;
}
public sealed class SqlSettings
{
public string ConnectionStringEnvironmentVariable { get; init; } = "SMARTB2B_SQL_CONNECTION_STRING";
public int CommandTimeoutSeconds { get; init; } = 30;
}
public sealed class DiagnosticsSettings
{
public string LogDirectory { get; init; } = "daemon";
public string LogPrefix { get; init; } = "smartb2bsync-enova";
}
public sealed record RuntimeSettings(
string EnovaInstallationPath,
EnovaAdapterConfiguration EnovaConfiguration,
string SqlConnectionString,
int SqlCommandTimeoutSeconds,
string LogDirectory,
string LogPrefix);
public sealed class ConfigurationException : Exception
{
public ConfigurationException(string message, Exception? innerException = null)
: base(message, innerException)
{
}
}