Register Enova database from SQL connection string

This commit is contained in:
2026-08-31 19:56:59 +00:00
parent 52c9d9b9e2
commit ee62a6253d
11 changed files with 48 additions and 17 deletions

View File

@@ -13,9 +13,9 @@ Dedykowana usługa Windows zastępująca proces Node na stanowiskach z enova365.
## Konfiguracja
Plik `config/enova.json` zawiera portal WAMP, ścieżkę instalacji, alias bazy, operatora wraz z hasłem, connection string SQL, definicję dokumentu, magazyn domyślny, tryb zapisu oraz DSN Sentry. Repozytorium oraz paczka zawierają tylko `config/enova.json.sample`. Skrypt instalacyjny kopiuje wzorzec do `config/enova.json` wyłącznie wtedy, gdy lokalna konfiguracja jeszcze nie istnieje.
Plik `config/enova.json` zawiera portal WAMP, ścieżkę instalacji, alias bazy używany wewnątrz procesu, operatora wraz z hasłem, connection string SQL, definicję dokumentu, magazyn domyślny, tryb zapisu oraz DSN Sentry. Repozytorium oraz paczka zawierają tylko `config/enova.json.sample`. Skrypt instalacyjny kopiuje wzorzec do `config/enova.json` wyłącznie wtedy, gdy lokalna konfiguracja jeszcze nie istnieje.
Uzupełnij pola `enova.operator`, `enova.password` i `sql.connectionString` bezpośrednio w lokalnym pliku `config/enova.json`. Parametr `sentry.dsn` wskazuje projekt Sentry; pusty lub pominięty DSN wyłącza wysyłanie błędów. Jeżeli operator lub hasło Enovy nie są podane, usługa nie loguje się do bazy Enovy i nie rejestruje endpointu `eu.smartb2b.place_order`; endpoint SQL oraz diagnostyka pozostają dostępne. Po zmianie konfiguracji trzeba zrestartować usługę. Connection string powinien używać konta SQL o możliwie najmniejszych uprawnieniach; `sql_raw` celowo dopuszcza również polecenia modyfikujące dane dla zgodności z obecną usługą.
Uzupełnij pola `enova.operator`, `enova.password` i `sql.connectionString` bezpośrednio w lokalnym pliku `config/enova.json`. Adapter rejestruje bazę Enovy tylko w pamięci procesu na podstawie `sql.connectionString`; baza nie musi być wcześniej dodana do listy baz w profilu użytkownika Windows, a dane połączenia nie są przez usługę zapisywane w plikach Enovy. Pole `enova.database` jest nazwą tego wpisu w procesie i może odpowiadać nazwie bazy z connection stringa. Parametr `sentry.dsn` wskazuje projekt Sentry; pusty lub pominięty DSN wyłącza wysyłanie błędów. Jeżeli operator lub hasło Enovy nie są podane, usługa nie loguje się do bazy Enovy i nie rejestruje endpointu `eu.smartb2b.place_order`; endpoint SQL oraz diagnostyka pozostają dostępne. Po zmianie konfiguracji trzeba zrestartować usługę. Konto z `sql.connectionString` musi mieć uprawnienia wymagane do pracy Enovy oraz do zapytań `sql_raw`; `sql_raw` celowo dopuszcza również polecenia modyfikujące dane dla zgodności z obecną usługą.
## Budowanie i testy
@@ -46,7 +46,7 @@ Skrypt odtwarza katalog `release` z hostem, adapterem, wzorcem konfiguracji i Wi
1. Skopiuj katalog `release` na komputer produkcyjny. Możesz skopiować `release/config/enova.json.sample` do `release/config/enova.json` i uzupełnić go przed instalacją; jeżeli tego nie zrobisz, `install.cmd` utworzy plik automatycznie.
2. Uzupełnij w `release/config/enova.json` hasło operatora i connection string SQL.
3. Zatrzymaj starą usługę Node dla tego samego portalu WAMP.
4. Skonfiguruj usługę do pracy pod dedykowanym kontem Windows, które potrafi uruchomić Enovę, widzi jej bazę i licencję.
4. Skonfiguruj usługę do pracy pod dedykowanym kontem Windows, które potrafi uruchomić Enovę i ma dostęp do jej licencji. Lista baz zapisana w profilu tego konta nie jest wymagana.
5. Jako administrator uruchom `release/daemon/install.cmd`.
Jeżeli usługa ma działać pod innym kontem niż `LocalSystem`, po instalacji ustaw je w `services.msc` albo poleceniem administracyjnym `sc.exe config smartb2bsync-enova obj= "DOMENA\\Użytkownik" password= "..."`, a następnie uruchom usługę ponownie.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -18,18 +18,14 @@ public sealed class EnovaOrderAdapter : IEnovaOrderAdapter
private static readonly object RuntimeLock = new();
private static bool _runtimeLoaded;
private EnovaAdapterConfiguration? _configuration;
private Database? _database;
public EnovaAdapterInfo Initialize(EnovaAdapterConfiguration configuration)
{
ValidateConfiguration(configuration);
EnsureRuntimeLoaded();
_ = BusApplication.Instance[configuration.Connection.DatabaseName]
?? throw new EnovaOperationException(
"eu.smartb2b.erp.database_not_found",
$"Nie znaleziono zarejestrowanej bazy enova365 '{configuration.Connection.DatabaseName}'.",
new Dictionary<string, object?> { ["database"] = configuration.Connection.DatabaseName });
_database = RegisterDatabase(configuration.Connection);
_configuration = configuration;
return new EnovaAdapterInfo(
@@ -43,6 +39,8 @@ public sealed class EnovaOrderAdapter : IEnovaOrderAdapter
{
var configuration = _configuration
?? throw new InvalidOperationException("Adapter Enovy nie został zainicjalizowany.");
var database = _database
?? throw new InvalidOperationException("Połączenie z bazą Enovy nie zostało zainicjalizowane.");
var errors = OrderValidator.Validate(request);
if (errors.Count > 0)
@@ -58,11 +56,6 @@ public sealed class EnovaOrderAdapter : IEnovaOrderAdapter
var sessionState = SessionState.Create();
using var attachedSessionState = sessionState.Attach();
var database = BusApplication.Instance[configuration.Connection.DatabaseName]
?? throw new EnovaOperationException(
"eu.smartb2b.erp.database_not_found",
$"Nie znaleziono zarejestrowanej bazy enova365 '{configuration.Connection.DatabaseName}'.");
using var login = database.Login(
winAuth: false,
user: configuration.Connection.OperatorName,
@@ -225,6 +218,26 @@ public sealed class EnovaOrderAdapter : IEnovaOrderAdapter
}
}
private static Database RegisterDatabase(EnovaConnectionOptions connection)
{
var application = BusApplication.Instance;
var existing = application[connection.DatabaseName, throwError: false];
if (existing is not null)
{
application.Remove(existing, save: false);
}
var database = new MsSqlDatabase
{
Name = connection.DatabaseName,
UseConnectionString = true,
ConnectionString = connection.SqlConnectionString
};
application.Add(database, save: false);
return database;
}
private static void ValidateConfiguration(EnovaAdapterConfiguration configuration)
{
var errors = new List<string>();
@@ -238,6 +251,11 @@ public sealed class EnovaOrderAdapter : IEnovaOrderAdapter
errors.Add("Nazwa operatora enova365 jest wymagana.");
}
if (string.IsNullOrWhiteSpace(configuration.Connection.SqlConnectionString))
{
errors.Add("Connection string SQL dla bazy Enovy jest wymagany.");
}
if (string.IsNullOrWhiteSpace(configuration.DocumentDefinition))
{
errors.Add("Definicja dokumentu jest wymagana.");

View File

@@ -9,7 +9,8 @@ public enum OrderSaveMode
public sealed record EnovaConnectionOptions(
string DatabaseName,
string OperatorName,
string Password);
string Password,
string SqlConnectionString);
public sealed record EnovaAdapterConfiguration(
EnovaConnectionOptions Connection,

View File

@@ -57,7 +57,11 @@ public sealed class ServiceSettings
if (!string.IsNullOrWhiteSpace(Enova.Operator) && Enova.Password is not null)
{
enovaConfiguration = new EnovaAdapterConfiguration(
new EnovaConnectionOptions(Enova.Database, Enova.Operator, Enova.Password),
new EnovaConnectionOptions(
Enova.Database,
Enova.Operator,
Enova.Password,
Sql.ConnectionString),
Enova.DocumentDefinition,
Enova.DefaultWarehouseCode,
Enova.SaveMode);

View File

@@ -255,6 +255,10 @@ static Task SecretsComeFromConfigurationFile()
"Server=db;Database=enova;User ID=user;Password=sql-z-pliku",
runtime.SqlConnectionString,
"connection string SQL");
AssertEqual(
runtime.SqlConnectionString,
runtime.EnovaConfiguration?.Connection.SqlConnectionString,
"connection string rejestracji bazy Enovy");
return Task.CompletedTask;
}
finally
@@ -321,7 +325,11 @@ static RpcInvocation CreateInvocation() => new(
});
static EnovaAdapterConfiguration CreateConfiguration() => new(
new EnovaConnectionOptions("Firma demo", "Administrator", ""),
new EnovaConnectionOptions(
"Firma demo",
"Administrator",
"",
"Server=localhost;Database=enova;Integrated Security=true;TrustServerCertificate=true"),
"ZO",
null,
OrderSaveMode.Buffer);