diff --git a/.gitignore b/.gitignore index 6911a0c..ab88c6f 100644 --- a/.gitignore +++ b/.gitignore @@ -8,5 +8,7 @@ NuGet/ # Lokalne konfiguracje wdrożeniowe; repozytorium zawiera wyłącznie wzorzec. src/SmartB2B.Enova.Service/config/enova.json -release/config/enova.json -release/config/enova.local.json +release-enova/config/enova.json +release-enova/config/enova.local.json +src/SmartB2B.Optima.Service/config/optima.json +release-optima/config/optima.json diff --git a/OPTIMA-INTEGRATION-TESTS.md b/OPTIMA-INTEGRATION-TESTS.md new file mode 100644 index 0000000..ebb81e2 --- /dev/null +++ b/OPTIMA-INTEGRATION-TESTS.md @@ -0,0 +1,48 @@ +# Testy integracyjne Comarch ERP Optima + +Testy z bazą są celowo wykonywane dopiero po ręcznym przygotowaniu i zarejestrowaniu firmy w Optimie. Narzędzia w tym repozytorium nie odtwarzają, nie tworzą ani nie modyfikują konfiguracji baz Optimy. + +## Przygotowanie + +1. Skopiuj `src/SmartB2B.Optima.Service/config/optima.json.sample` do lokalnego, ignorowanego przez Git pliku `src/SmartB2B.Optima.Service/config/optima.json`. +2. Uzupełnij nazwę firmy widoczną podczas logowania, operatora, hasło, identyfikator magazynu i connection string SQL. +3. Nie dodawaj pliku `optima.json` do repozytorium ani paczki wdrożeniowej. +4. W przygotowanej firmie zapewnij kontrolowane dane testowe: kontrahenta, towar, magazyn, walutę oraz definicje RO liczone netto i brutto. + +## Kontrola bez zapisu + +Uruchom opublikowaną wersję x64: + +```powershell +.\release-optima\SmartB2B.Optima.Service.exe --config .\src\SmartB2B.Optima.Service\config\optima.json --check-config +``` + +Polecenie sprawdza JSON, zgodność architektury procesu z `op_base.dll`, rejestrację COM, wersję Optimy, połączenie SQL, logowanie operatora i utworzenie sesji. Nie zapisuje dokumentu. + +## Scenariusze zapisu przez WAMP + +Pierwszy kontrolowany zapis adaptera można wykonać runnerem, który wymaga jawnego +parametru `--write-order` i domyślnie zapisuje wyłącznie w trybie `Buffer`: + +```powershell +dotnet run --project .\tests\SmartB2B.Optima.IntegrationTests -- --config .\src\SmartB2B.Optima.Service\config\optima.json --negative-tests --write-order --customer-id 2 --product-code SMARTB2B_TEST_TWR +``` + +Zatwierdzenie dokumentu wymaga dodatkowej flagi `--approved` i powinno być wykonywane +wyłącznie w firmie testowej: + +```powershell +dotnet run --project .\tests\SmartB2B.Optima.IntegrationTests -- --config .\src\SmartB2B.Optima.Service\config\optima.json --write-order --approved --customer-id 2 --product-code SMARTB2B_TEST_TWR +``` + +Po pomyślnym `--check-config` uruchom usługę z tym samym plikiem konfiguracji i sprawdź kolejno: + +- RO w buforze (`saveMode: Buffer`) i zatwierdzone (`saveMode: Approved`); +- definicję liczoną netto z `price_netto` i brutto z `price_brutto`; +- rabat, uwagi, numer obcy, magazyn oraz walutę; +- zgodność `order_erp_id`, `order_erp_symbol`, `value_netto` i `value_brutto` z dokumentem zapisanym w Optimie; +- błędy dla brakującego kontrahenta, produktu, magazynu, waluty i wymaganej ceny; +- parametryzowane `sql_raw`, wiele recordsetów, dane binarne oraz błąd SQL; +- dwa równoczesne wywołania `place_order` — dokumenty mają zostać utworzone kolejno na jednym wątku COM. + +Przed testami trybu `Approved` wykonaj kopię bezpieczeństwa bazy lub użyj firmy przeznaczonej wyłącznie do testów. diff --git a/README.md b/README.md index c43bd45..ecb2b85 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,13 @@ -# SmartB2B SYNC dla enova365 +# SmartB2B SYNC dla enova365 i Comarch ERP Optima -Dedykowana usługa Windows zastępująca proces Node na stanowiskach z enova365. Utrzymuje połączenie WAMP, dodaje zamówienia przez oficjalne API Enovy i wykonuje `eu.smartb2b.sql_raw` na osobnym połączeniu SQL. +Dedykowane usługi Windows zastępujące proces Node na stanowiskach z enova365 albo +Comarch ERP Optima. Wspólny rdzeń utrzymuje połączenie WAMP, udostępnia diagnostykę +i wykonuje `eu.smartb2b.sql_raw`. Osobne adaptery zapisują zamówienia przez API ERP. + +Rozwiązanie składa się z bibliotek `SmartB2B.Sync.Contracts` i +`SmartB2B.Sync.Service` oraz osobnych hostów i adapterów Enovy i Optimy. Usług dla +tego samego portalu nie należy uruchamiać jednocześnie, ponieważ rejestrują te same +procedury WAMP. ## Najważniejsze właściwości @@ -15,6 +22,13 @@ Dedykowana usługa Windows zastępująca proces Node na stanowiskach z enova365. 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. +Dla Optimy odpowiednikiem jest `config/optima.json`. Sekcja `optima` zawiera +ścieżkę instalacji, nazwę firmy widoczną podczas logowania, operatora, hasło, +symbol definicji dokumentu (domyślnie `RO`), liczbowy identyfikator magazynu i tryb +`Buffer` albo `Approved`. `companyErpId` jest liczbowym `Knt_KntId`, a +`warehouseErpId` liczbowym identyfikatorem magazynu. Paczka zawiera wyłącznie +`optima.json.sample`. + 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 @@ -22,9 +36,10 @@ Uzupełnij pola `enova.operator`, `enova.password` i `sql.connectionString` bezp Z katalogu głównego repozytorium, przy zainstalowanym SDK .NET 8: ```powershell -dotnet restore .\SmartB2B.EnovaSync.sln --configfile .\NuGet.Config -dotnet build .\SmartB2B.EnovaSync.sln --no-restore +dotnet restore .\SmartB2B.Sync.sln --configfile .\NuGet.Config +dotnet build .\SmartB2B.Sync.sln --no-restore dotnet run --project .\tests\SmartB2B.Enova.Tests --no-build --no-restore +dotnet run --project .\tests\SmartB2B.Optima.Tests --no-build --no-restore ``` Ostrzeżenie `NU1603` dotyczące `Soneta.Generator` jest takie samo jak w działającym prototypie `test1` i nie blokuje kompilacji. @@ -35,11 +50,20 @@ Kontrola konfiguracji i dynamicznego ładowania, bez zapisu do bazy: .\src\SmartB2B.Enova.Service\bin\Debug\net8.0\SmartB2B.Enova.Service.exe --config .\src\SmartB2B.Enova.Service\bin\Debug\net8.0\config\enova.json.sample --check-config ``` +Dla Optimy `--check-config` sprawdza zgodność architektury procesu z `op_base.dll`, rejestrację COM +`CDNBase.Application`, wersję instalacji, połączenie SQL oraz logowanie i utworzenie +sesji. Nie zapisuje dokumentu. Pełne sprawdzenie wymaga gotowej bazy i prawdziwego +operatora: + +```powershell +.\release-optima\SmartB2B.Optima.Service.exe --config .\release-optima\config\optima.json --check-config +``` + Szczegółowe logowanie włącza parametr `/debug` albo `/verbose` (obsługiwane są też warianty `--debug` i `--verbose`). Wyłącza je brak parametru lub jawny parametr `/nodebug` albo `/noverbose`. Błędy są zapisywane do `stderr` niezależnie od tego ustawienia. W usłudze Windows parametr można włączyć przez odkomentowanie elementu -`/verbose` w `daemon/smartb2bsync-enova.xml` i restart usługi. +`/verbose` w `daemon-enova/smartb2bsync-enova.xml` i restart usługi. W trybie szczegółowym zapis ZO raportuje kolejne etapy: walidację żądania, logowanie do Enovy, wyszukanie definicji, kontrahenta, magazynu i towarów, commit transakcji @@ -52,24 +76,35 @@ nie kopiuje tej wartości automatycznie z `enova.json.sample` do istniejącej ko ## Publikacja i instalacja ```powershell -.\publish.ps1 +.\publish-enova.ps1 ``` -Skrypt odtwarza katalog `release` z hostem, adapterem, wzorcem konfiguracji i WinSW. Repozytorium zawiera również gotowy, skompilowany katalog `release`, więc na komputerze produkcyjnym nie trzeba instalować SDK. Przed instalacją: +Paczka Optimy jest samodzielnym buildem `win-x64`, zgodnym z Optimą 2026.5.1, +i nie wymaga instalowania runtime .NET x64. Nie zawiera bibliotek ani licencji Comarch: -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. +```powershell +.\publish-optima.ps1 +``` + +Wynik trafia do `release-optima`. Po uzupełnieniu `config/optima.json` instalację +wykonuje `release-optima/daemon/install.cmd`. Usługa ma identyfikator +`smartb2bsync-optima`. + +Skrypt odtwarza katalog `release-enova` z hostem, adapterem, wzorcem konfiguracji i WinSW. Repozytorium zawiera również gotowy, skompilowany katalog `release-enova`, więc na komputerze produkcyjnym nie trzeba instalować SDK. Przed instalacją: + +1. Skopiuj katalog `release-enova` na komputer produkcyjny. Możesz skopiować `release-enova/config/enova.json.sample` do `release-enova/config/enova.json` i uzupełnić go przed instalacją; jeżeli tego nie zrobisz, `install.cmd` utworzy plik automatycznie. +2. Uzupełnij w `release-enova/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ę 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`. +5. Jako administrator uruchom `release-enova/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. -Wycofanie polega na uruchomieniu `daemon/uninstall.cmd` i ponownym uruchomieniu dotychczasowej usługi Node. Nie ma migracji schematu bazy. +Wycofanie polega na uruchomieniu `release-enova/daemon/uninstall.cmd` i ponownym uruchomieniu dotychczasowej usługi Node. Nie ma migracji schematu bazy. ## Procedury WAMP -- `eu.smartb2b.place_order` przyjmuje `currency_iso`, `companyErpId`, `warehouseErpId`, `purchase_order_number`, `notes` i `lines[]` z polami `symbol`, `quantity`, `price_netto`, `discount`. Wynik jest zwracany jako kwargs: `order_erp_id`, `order_erp_symbol`, `value_netto`, `value_brutto`, `stocks`. +- `eu.smartb2b.place_order` przyjmuje `currency_iso`, `companyErpId`, `warehouseErpId`, `purchase_order_number`, `notes` i `lines[]` z polami `symbol`, `quantity`, opcjonalnymi `price_netto` i `price_brutto` oraz `discount`. Enova wymaga `price_netto`; Optima wybiera cenę zgodnie z `TypNB` definicji dokumentu. Wynik jest zwracany jako kwargs: `order_erp_id`, `order_erp_symbol`, `value_netto`, `value_brutto`, `stocks`. - `eu.smartb2b.sql_raw` przyjmuje `query` i opcjonalne `params`; parametry odpowiadają kolejno `@1`, `@2`, itd. Wynik ma pola `recordsets`, `recordset`, `output`, `rowsAffected`. - Diagnostyka: `eu.smartb2b.sync.get_version`, `get_info`, `get_log`, `get_error_log`. @@ -77,4 +112,4 @@ Kod produkcyjny, testy oraz gotowa wersja instalacyjna znajdują się w tym repo ## Automatyczne aktualizacje -Przy starcie WinSW pobiera pliki aplikacji z `https://demo.smartb2b.eu/files/smartb2b-sync-enova/` zgodnie z listą `` w `daemon/smartb2bsync-enova.xml`. Aktualizowane są program, biblioteki, adapter Enovy, skrypty, manifest usługi i `config/enova.json.sample`. Lokalny `config/enova.json` nie występuje na liście i nie jest nadpisywany. Sam `smartb2bsync-enova.exe` jest programem rozruchowym WinSW, dlatego nie aktualizuje samego siebie podczas pracy. `publish.ps1` porównuje zawartość gotowej paczki z manifestem i przerywa publikowanie, jeżeli którejkolwiek pozycji brakuje po jednej ze stron. +Przy starcie WinSW pobiera pliki aplikacji z `https://demo.smartb2b.eu/files/smartb2b-sync-enova/` zgodnie z listą `` w `daemon-enova/smartb2bsync-enova.xml`. Aktualizowane są program, biblioteki, adapter Enovy, skrypty, manifest usługi i `config/enova.json.sample`. Lokalny `config/enova.json` nie występuje na liście i nie jest nadpisywany. Sam `smartb2bsync-enova.exe` jest programem rozruchowym WinSW, dlatego nie aktualizuje samego siebie podczas pracy. `publish-enova.ps1` porównuje zawartość gotowej paczki z manifestem i przerywa publikowanie, jeżeli którejkolwiek pozycji brakuje po jednej ze stron. diff --git a/SmartB2B.EnovaSync.sln b/SmartB2B.EnovaSync.sln deleted file mode 100644 index f56a7b0..0000000 --- a/SmartB2B.EnovaSync.sln +++ /dev/null @@ -1,36 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.11.35327.3 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartB2B.Enova.Contracts", "src\SmartB2B.Enova.Contracts\SmartB2B.Enova.Contracts.csproj", "{83EEA218-71A0-4E45-9572-B53767A3BC26}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartB2B.Enova.Adapter", "src\SmartB2B.Enova.Adapter\SmartB2B.Enova.Adapter.csproj", "{64C5439F-00AA-48F9-9A9B-DAE69DB0BC57}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartB2B.Enova.Service", "src\SmartB2B.Enova.Service\SmartB2B.Enova.Service.csproj", "{3473BD53-A2B9-46A8-AEE8-F087F373DF2B}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartB2B.Enova.Tests", "tests\SmartB2B.Enova.Tests\SmartB2B.Enova.Tests.csproj", "{842D10FD-D5FC-4AF9-8D72-619BF6EE10C2}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {83EEA218-71A0-4E45-9572-B53767A3BC26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {83EEA218-71A0-4E45-9572-B53767A3BC26}.Debug|Any CPU.Build.0 = Debug|Any CPU - {83EEA218-71A0-4E45-9572-B53767A3BC26}.Release|Any CPU.ActiveCfg = Release|Any CPU - {83EEA218-71A0-4E45-9572-B53767A3BC26}.Release|Any CPU.Build.0 = Release|Any CPU - {64C5439F-00AA-48F9-9A9B-DAE69DB0BC57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {64C5439F-00AA-48F9-9A9B-DAE69DB0BC57}.Debug|Any CPU.Build.0 = Debug|Any CPU - {64C5439F-00AA-48F9-9A9B-DAE69DB0BC57}.Release|Any CPU.ActiveCfg = Release|Any CPU - {64C5439F-00AA-48F9-9A9B-DAE69DB0BC57}.Release|Any CPU.Build.0 = Release|Any CPU - {3473BD53-A2B9-46A8-AEE8-F087F373DF2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3473BD53-A2B9-46A8-AEE8-F087F373DF2B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3473BD53-A2B9-46A8-AEE8-F087F373DF2B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3473BD53-A2B9-46A8-AEE8-F087F373DF2B}.Release|Any CPU.Build.0 = Release|Any CPU - {842D10FD-D5FC-4AF9-8D72-619BF6EE10C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {842D10FD-D5FC-4AF9-8D72-619BF6EE10C2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {842D10FD-D5FC-4AF9-8D72-619BF6EE10C2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {842D10FD-D5FC-4AF9-8D72-619BF6EE10C2}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection -EndGlobal diff --git a/SmartB2B.Sync.sln b/SmartB2B.Sync.sln new file mode 100644 index 0000000..aa29861 --- /dev/null +++ b/SmartB2B.Sync.sln @@ -0,0 +1,71 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35327.3 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartB2B.Sync.Contracts", "src\SmartB2B.Sync.Contracts\SmartB2B.Sync.Contracts.csproj", "{83EEA218-71A0-4E45-9572-B53767A3BC26}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartB2B.Sync.Service", "src\SmartB2B.Sync.Service\SmartB2B.Sync.Service.csproj", "{D52B9C80-C6F4-4E0B-B3B8-17F6A8FD88E5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartB2B.Enova.Adapter", "src\SmartB2B.Enova.Adapter\SmartB2B.Enova.Adapter.csproj", "{64C5439F-00AA-48F9-9A9B-DAE69DB0BC57}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartB2B.Enova.Service", "src\SmartB2B.Enova.Service\SmartB2B.Enova.Service.csproj", "{3473BD53-A2B9-46A8-AEE8-F087F373DF2B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartB2B.Optima.Adapter", "src\SmartB2B.Optima.Adapter\SmartB2B.Optima.Adapter.csproj", "{7C9A4077-0EB1-4E87-A202-99219EBE9BDF}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartB2B.Optima.Service", "src\SmartB2B.Optima.Service\SmartB2B.Optima.Service.csproj", "{A0DA9C63-98D1-47AA-B491-E101D6131B0B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartB2B.Enova.Tests", "tests\SmartB2B.Enova.Tests\SmartB2B.Enova.Tests.csproj", "{842D10FD-D5FC-4AF9-8D72-619BF6EE10C2}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartB2B.Optima.Tests", "tests\SmartB2B.Optima.Tests\SmartB2B.Optima.Tests.csproj", "{1F6B3CB3-141D-4438-B43B-B3B6CA80A483}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{83B01DA9-7F49-48C8-AB20-E9814B7093DA}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SmartB2B.Optima.IntegrationTests", "tests\SmartB2B.Optima.IntegrationTests\SmartB2B.Optima.IntegrationTests.csproj", "{9BDCCB4C-12DD-4CCF-A628-F30721ACC2C9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {83EEA218-71A0-4E45-9572-B53767A3BC26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {83EEA218-71A0-4E45-9572-B53767A3BC26}.Debug|Any CPU.Build.0 = Debug|Any CPU + {83EEA218-71A0-4E45-9572-B53767A3BC26}.Release|Any CPU.ActiveCfg = Release|Any CPU + {83EEA218-71A0-4E45-9572-B53767A3BC26}.Release|Any CPU.Build.0 = Release|Any CPU + {D52B9C80-C6F4-4E0B-B3B8-17F6A8FD88E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D52B9C80-C6F4-4E0B-B3B8-17F6A8FD88E5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D52B9C80-C6F4-4E0B-B3B8-17F6A8FD88E5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D52B9C80-C6F4-4E0B-B3B8-17F6A8FD88E5}.Release|Any CPU.Build.0 = Release|Any CPU + {64C5439F-00AA-48F9-9A9B-DAE69DB0BC57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {64C5439F-00AA-48F9-9A9B-DAE69DB0BC57}.Debug|Any CPU.Build.0 = Debug|Any CPU + {64C5439F-00AA-48F9-9A9B-DAE69DB0BC57}.Release|Any CPU.ActiveCfg = Release|Any CPU + {64C5439F-00AA-48F9-9A9B-DAE69DB0BC57}.Release|Any CPU.Build.0 = Release|Any CPU + {3473BD53-A2B9-46A8-AEE8-F087F373DF2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3473BD53-A2B9-46A8-AEE8-F087F373DF2B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3473BD53-A2B9-46A8-AEE8-F087F373DF2B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3473BD53-A2B9-46A8-AEE8-F087F373DF2B}.Release|Any CPU.Build.0 = Release|Any CPU + {7C9A4077-0EB1-4E87-A202-99219EBE9BDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7C9A4077-0EB1-4E87-A202-99219EBE9BDF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7C9A4077-0EB1-4E87-A202-99219EBE9BDF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7C9A4077-0EB1-4E87-A202-99219EBE9BDF}.Release|Any CPU.Build.0 = Release|Any CPU + {A0DA9C63-98D1-47AA-B491-E101D6131B0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A0DA9C63-98D1-47AA-B491-E101D6131B0B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A0DA9C63-98D1-47AA-B491-E101D6131B0B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A0DA9C63-98D1-47AA-B491-E101D6131B0B}.Release|Any CPU.Build.0 = Release|Any CPU + {842D10FD-D5FC-4AF9-8D72-619BF6EE10C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {842D10FD-D5FC-4AF9-8D72-619BF6EE10C2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {842D10FD-D5FC-4AF9-8D72-619BF6EE10C2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {842D10FD-D5FC-4AF9-8D72-619BF6EE10C2}.Release|Any CPU.Build.0 = Release|Any CPU + {1F6B3CB3-141D-4438-B43B-B3B6CA80A483}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1F6B3CB3-141D-4438-B43B-B3B6CA80A483}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1F6B3CB3-141D-4438-B43B-B3B6CA80A483}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1F6B3CB3-141D-4438-B43B-B3B6CA80A483}.Release|Any CPU.Build.0 = Release|Any CPU + {9BDCCB4C-12DD-4CCF-A628-F30721ACC2C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9BDCCB4C-12DD-4CCF-A628-F30721ACC2C9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9BDCCB4C-12DD-4CCF-A628-F30721ACC2C9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9BDCCB4C-12DD-4CCF-A628-F30721ACC2C9}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {9BDCCB4C-12DD-4CCF-A628-F30721ACC2C9} = {83B01DA9-7F49-48C8-AB20-E9814B7093DA} + EndGlobalSection +EndGlobal diff --git a/release/daemon/install.cmd b/daemon-enova/install.cmd similarity index 88% rename from release/daemon/install.cmd rename to daemon-enova/install.cmd index be98290..978b056 100644 --- a/release/daemon/install.cmd +++ b/daemon-enova/install.cmd @@ -3,7 +3,7 @@ setlocal cd /d "%~dp0" if not exist "smartb2bsync-enova.exe" ( - echo Brak smartb2bsync-enova.exe. Najpierw uruchom publish.ps1. + echo Brak smartb2bsync-enova.exe. Najpierw uruchom publish-enova.ps1. exit /b 1 ) diff --git a/daemon/smartb2bsync-enova.exe b/daemon-enova/smartb2bsync-enova.exe similarity index 100% rename from daemon/smartb2bsync-enova.exe rename to daemon-enova/smartb2bsync-enova.exe diff --git a/daemon/smartb2bsync-enova.xml b/daemon-enova/smartb2bsync-enova.xml similarity index 95% rename from daemon/smartb2bsync-enova.xml rename to daemon-enova/smartb2bsync-enova.xml index da3589a..ab5e5e3 100644 --- a/daemon/smartb2bsync-enova.xml +++ b/daemon-enova/smartb2bsync-enova.xml @@ -28,8 +28,10 @@ - - + + + + diff --git a/daemon/uninstall.cmd b/daemon-enova/uninstall.cmd similarity index 100% rename from daemon/uninstall.cmd rename to daemon-enova/uninstall.cmd diff --git a/daemon-optima/install.cmd b/daemon-optima/install.cmd new file mode 100644 index 0000000..c5a8fb8 --- /dev/null +++ b/daemon-optima/install.cmd @@ -0,0 +1,24 @@ +@echo off +setlocal +cd /d "%~dp0" + +if not exist "smartb2bsync-optima.exe" ( + echo Brak smartb2bsync-optima.exe. Najpierw uruchom publish-optima.ps1. + exit /b 1 +) + +if not exist "..\config" mkdir "..\config" +if not exist "..\config\optima.json" ( + if not exist "..\config\optima.json.sample" ( + echo Brak ..\config\optima.json.sample. + exit /b 1 + ) + copy /Y "..\config\optima.json.sample" "..\config\optima.json" >nul + echo Utworzono lokalna konfiguracje ..\config\optima.json. +) + +smartb2bsync-optima.exe install +if errorlevel 1 exit /b %errorlevel% + +smartb2bsync-optima.exe start +exit /b %errorlevel% diff --git a/release/daemon/smartb2bsync-enova.exe b/daemon-optima/smartb2bsync-optima.exe similarity index 100% rename from release/daemon/smartb2bsync-enova.exe rename to daemon-optima/smartb2bsync-optima.exe diff --git a/daemon-optima/smartb2bsync-optima.xml b/daemon-optima/smartb2bsync-optima.xml new file mode 100644 index 0000000..eaed520 --- /dev/null +++ b/daemon-optima/smartb2bsync-optima.xml @@ -0,0 +1,14 @@ + + smartb2bsync-optima + SmartB2B SYNC - Comarch ERP Optima + Synchronizuje Comarch ERP Optima z portalem SmartB2B. + %BASE%\..\SmartB2B.Optima.Service.exe + %BASE%\.. + + 45sec + + yyyyMMdd + + + + diff --git a/daemon-optima/uninstall.cmd b/daemon-optima/uninstall.cmd new file mode 100644 index 0000000..f1e1d45 --- /dev/null +++ b/daemon-optima/uninstall.cmd @@ -0,0 +1,7 @@ +@echo off +setlocal +cd /d "%~dp0" + +smartb2bsync-optima.exe stop +smartb2bsync-optima.exe uninstall +exit /b %errorlevel% diff --git a/publish.ps1 b/publish-enova.ps1 similarity index 75% rename from publish.ps1 rename to publish-enova.ps1 index 15690f5..45d8949 100644 --- a/publish.ps1 +++ b/publish-enova.ps1 @@ -1,5 +1,5 @@ param( - [string]$OutputPath = (Join-Path $PSScriptRoot "release"), + [string]$OutputPath = (Join-Path $PSScriptRoot "release-enova"), [ValidateSet("Debug", "Release")] [string]$Configuration = "Release" ) @@ -10,19 +10,18 @@ $env:APPDATA = $PSScriptRoot $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = "1" $env:DOTNET_CLI_TELEMETRY_OPTOUT = "1" -$bundledDotnet = Join-Path $PSScriptRoot "..\..\..\test1\.dotnet\dotnet.exe" -$dotnet = if (Test-Path -LiteralPath $bundledDotnet) { - (Resolve-Path $bundledDotnet).Path -} else { - (Get-Command dotnet -ErrorAction Stop).Source -} +$dotnet = (Get-Command dotnet -ErrorAction Stop).Source $project = Join-Path $PSScriptRoot "src\SmartB2B.Enova.Service\SmartB2B.Enova.Service.csproj" -$daemonSource = Join-Path $PSScriptRoot "daemon" +$adapterProject = Join-Path $PSScriptRoot "src\SmartB2B.Enova.Adapter\SmartB2B.Enova.Adapter.csproj" +$daemonSource = Join-Path $PSScriptRoot "daemon-enova" $winSwSource = Resolve-Path (Join-Path $daemonSource "smartb2bsync-enova.exe") $output = [System.IO.Path]::GetFullPath($OutputPath) +$workspace = [System.IO.Path]::GetFullPath($PSScriptRoot) $daemonOutput = Join-Path $output "daemon" -if ($output -eq [System.IO.Path]::GetPathRoot($output) -or $output.Length -lt 10) { +if (-not $output.StartsWith($workspace, [StringComparison]::OrdinalIgnoreCase) -or + $output -eq $workspace -or + $output.Length -lt 10) { throw "Niebezpieczna ścieżka wyjściowa: $output" } @@ -33,7 +32,12 @@ if (Test-Path -LiteralPath $output) { New-Item -ItemType Directory -Force -Path $output | Out-Null New-Item -ItemType Directory -Force -Path $daemonOutput | Out-Null -& $dotnet publish $project -c $Configuration --no-restore -o $output +& $dotnet restore $adapterProject +if ($LASTEXITCODE -ne 0) { + throw "Przywracanie pakietów adaptera Enovy nie powiodło się." +} + +& $dotnet publish $project -c $Configuration -o $output if ($LASTEXITCODE -ne 0) { throw "Publikowanie usługi nie powiodło się." } diff --git a/publish-optima.ps1 b/publish-optima.ps1 new file mode 100644 index 0000000..d8ad1b7 --- /dev/null +++ b/publish-optima.ps1 @@ -0,0 +1,79 @@ +param( + [string]$OutputPath = (Join-Path $PSScriptRoot "release-optima"), + [ValidateSet("Debug", "Release")] + [string]$Configuration = "Release" +) + +$ErrorActionPreference = "Stop" +$env:DOTNET_CLI_HOME = $PSScriptRoot +$env:APPDATA = $PSScriptRoot +$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = "1" +$env:DOTNET_CLI_TELEMETRY_OPTOUT = "1" + +$dotnet = (Get-Command dotnet -ErrorAction Stop).Source + +$project = Join-Path $PSScriptRoot "src\SmartB2B.Optima.Service\SmartB2B.Optima.Service.csproj" +$daemonSource = Join-Path $PSScriptRoot "daemon-optima" +$winSwSource = Resolve-Path (Join-Path $daemonSource "smartb2bsync-optima.exe") +$output = [System.IO.Path]::GetFullPath($OutputPath) +$workspace = [System.IO.Path]::GetFullPath($PSScriptRoot) +$daemonOutput = Join-Path $output "daemon" + +if (-not $output.StartsWith($workspace, [StringComparison]::OrdinalIgnoreCase) -or + $output -eq $workspace -or + $output.Length -lt 10) { + throw "Niebezpieczna ścieżka wyjściowa: $output" +} + +if (Test-Path -LiteralPath $output) { + Remove-Item -LiteralPath $output -Recurse -Force +} + +New-Item -ItemType Directory -Force -Path $output | Out-Null +New-Item -ItemType Directory -Force -Path $daemonOutput | Out-Null + +& $dotnet publish $project -c $Configuration -r win-x64 --self-contained true -o $output +if ($LASTEXITCODE -ne 0) { + throw "Publikowanie usługi Optimy nie powiodło się." +} + +Copy-Item $winSwSource (Join-Path $daemonOutput "smartb2bsync-optima.exe") -Force +Copy-Item (Join-Path $daemonSource "smartb2bsync-optima.xml") $daemonOutput -Force +Copy-Item (Join-Path $daemonSource "install.cmd") $daemonOutput -Force +Copy-Item (Join-Path $daemonSource "uninstall.cmd") $daemonOutput -Force + +$downloadBaseUrl = "https://demo.smartb2b.eu/files/smartb2b-sync-optima/" +$manifestPath = Join-Path $daemonOutput "smartb2bsync-optima.xml" +[xml]$manifest = Get-Content -Raw $manifestPath +$packagedFiles = @( + Get-ChildItem -Recurse -File $output | + ForEach-Object { $_.FullName.Substring($output.Length).TrimStart('\') } | + Where-Object { $_ -ne "daemon\smartb2bsync-optima.exe" } | + Sort-Object +) + +foreach ($relativePath in $packagedFiles) { + $download = $manifest.CreateElement("download") + $urlPath = $relativePath.Replace('\', '/') + $destination = if ($relativePath.StartsWith("daemon\", [StringComparison]::OrdinalIgnoreCase)) { + "%BASE%\" + $relativePath.Substring("daemon\".Length) + } else { + "%BASE%\..\" + $relativePath + } + $download.SetAttribute("from", $downloadBaseUrl + $urlPath) + $download.SetAttribute("to", $destination) + $download.SetAttribute("failOnError", "false") + [void]$manifest.service.AppendChild($download) +} + +$settings = [System.Xml.XmlWriterSettings]::new() +$settings.Indent = $true +$settings.Encoding = [System.Text.UTF8Encoding]::new($false) +$writer = [System.Xml.XmlWriter]::Create($manifestPath, $settings) +try { + $manifest.Save($writer) +} finally { + $writer.Dispose() +} + +Write-Host "Gotowa usługa Optimy (self-contained win-x64): $output" diff --git a/release/Azure.Core.dll b/release-enova/Azure.Core.dll similarity index 100% rename from release/Azure.Core.dll rename to release-enova/Azure.Core.dll diff --git a/release/Azure.Identity.dll b/release-enova/Azure.Identity.dll similarity index 100% rename from release/Azure.Identity.dll rename to release-enova/Azure.Identity.dll diff --git a/release/Microsoft.Bcl.AsyncInterfaces.dll b/release-enova/Microsoft.Bcl.AsyncInterfaces.dll similarity index 100% rename from release/Microsoft.Bcl.AsyncInterfaces.dll rename to release-enova/Microsoft.Bcl.AsyncInterfaces.dll diff --git a/release/Microsoft.Bcl.Memory.dll b/release-enova/Microsoft.Bcl.Memory.dll similarity index 100% rename from release/Microsoft.Bcl.Memory.dll rename to release-enova/Microsoft.Bcl.Memory.dll diff --git a/release/Microsoft.Data.SqlClient.dll b/release-enova/Microsoft.Data.SqlClient.dll similarity index 100% rename from release/Microsoft.Data.SqlClient.dll rename to release-enova/Microsoft.Data.SqlClient.dll diff --git a/release-enova/Microsoft.Extensions.DependencyInjection.Abstractions.dll b/release-enova/Microsoft.Extensions.DependencyInjection.Abstractions.dll new file mode 100644 index 0000000..0b3c8e9 Binary files /dev/null and b/release-enova/Microsoft.Extensions.DependencyInjection.Abstractions.dll differ diff --git a/release/Microsoft.Extensions.Logging.Abstractions.dll b/release-enova/Microsoft.Extensions.Logging.Abstractions.dll similarity index 75% rename from release/Microsoft.Extensions.Logging.Abstractions.dll rename to release-enova/Microsoft.Extensions.Logging.Abstractions.dll index f9d1dc6..085f415 100644 Binary files a/release/Microsoft.Extensions.Logging.Abstractions.dll and b/release-enova/Microsoft.Extensions.Logging.Abstractions.dll differ diff --git a/release/Microsoft.Identity.Client.Extensions.Msal.dll b/release-enova/Microsoft.Identity.Client.Extensions.Msal.dll similarity index 100% rename from release/Microsoft.Identity.Client.Extensions.Msal.dll rename to release-enova/Microsoft.Identity.Client.Extensions.Msal.dll diff --git a/release/Microsoft.Identity.Client.dll b/release-enova/Microsoft.Identity.Client.dll similarity index 100% rename from release/Microsoft.Identity.Client.dll rename to release-enova/Microsoft.Identity.Client.dll diff --git a/release/Microsoft.IdentityModel.Abstractions.dll b/release-enova/Microsoft.IdentityModel.Abstractions.dll similarity index 100% rename from release/Microsoft.IdentityModel.Abstractions.dll rename to release-enova/Microsoft.IdentityModel.Abstractions.dll diff --git a/release/Microsoft.IdentityModel.JsonWebTokens.dll b/release-enova/Microsoft.IdentityModel.JsonWebTokens.dll similarity index 100% rename from release/Microsoft.IdentityModel.JsonWebTokens.dll rename to release-enova/Microsoft.IdentityModel.JsonWebTokens.dll diff --git a/release/Microsoft.IdentityModel.Logging.dll b/release-enova/Microsoft.IdentityModel.Logging.dll similarity index 100% rename from release/Microsoft.IdentityModel.Logging.dll rename to release-enova/Microsoft.IdentityModel.Logging.dll diff --git a/release/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll b/release-enova/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll similarity index 100% rename from release/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll rename to release-enova/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll diff --git a/release/Microsoft.IdentityModel.Protocols.dll b/release-enova/Microsoft.IdentityModel.Protocols.dll similarity index 100% rename from release/Microsoft.IdentityModel.Protocols.dll rename to release-enova/Microsoft.IdentityModel.Protocols.dll diff --git a/release/Microsoft.IdentityModel.Tokens.dll b/release-enova/Microsoft.IdentityModel.Tokens.dll similarity index 100% rename from release/Microsoft.IdentityModel.Tokens.dll rename to release-enova/Microsoft.IdentityModel.Tokens.dll diff --git a/release/Microsoft.SqlServer.Server.dll b/release-enova/Microsoft.SqlServer.Server.dll similarity index 100% rename from release/Microsoft.SqlServer.Server.dll rename to release-enova/Microsoft.SqlServer.Server.dll diff --git a/release/Newtonsoft.Json.dll b/release-enova/Newtonsoft.Json.dll similarity index 100% rename from release/Newtonsoft.Json.dll rename to release-enova/Newtonsoft.Json.dll diff --git a/release/NewtonsoftMessagePack.dll b/release-enova/NewtonsoftMessagePack.dll similarity index 100% rename from release/NewtonsoftMessagePack.dll rename to release-enova/NewtonsoftMessagePack.dll diff --git a/release/Sentry.dll b/release-enova/Sentry.dll similarity index 100% rename from release/Sentry.dll rename to release-enova/Sentry.dll diff --git a/release/SmartB2B.Enova.Service.deps.json b/release-enova/SmartB2B.Enova.Service.deps.json similarity index 97% rename from release/SmartB2B.Enova.Service.deps.json rename to release-enova/SmartB2B.Enova.Service.deps.json index 55a1a3b..32bafca 100644 --- a/release/SmartB2B.Enova.Service.deps.json +++ b/release-enova/SmartB2B.Enova.Service.deps.json @@ -8,14 +8,8 @@ ".NETCoreApp,Version=v8.0": { "SmartB2B.Enova.Service/1.0.0": { "dependencies": { - "Microsoft.Bcl.AsyncInterfaces": "8.0.0", - "Microsoft.Data.SqlClient": "5.2.2", - "Microsoft.Identity.Client": "4.73.1", - "Newtonsoft.Json": "13.0.3", - "Sentry": "6.9.0", - "SmartB2B.Enova.Contracts": "1.0.0", - "System.IdentityModel.Tokens.Jwt": "8.3.1", - "WampSharp.Default.Client": "23.8.1" + "SmartB2B.Sync.Contracts": "1.0.0", + "SmartB2B.Sync.Service": "1.0.0" }, "runtime": { "SmartB2B.Enova.Service.dll": {} @@ -180,22 +174,22 @@ } } }, - "Microsoft.Extensions.DependencyInjection.Abstractions/8.0.2": { + "Microsoft.Extensions.DependencyInjection.Abstractions/8.0.0": { "runtime": { "lib/net8.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": { "assemblyVersion": "8.0.0.0", - "fileVersion": "8.0.1024.46610" + "fileVersion": "8.0.23.53103" } } }, - "Microsoft.Extensions.Logging.Abstractions/8.0.2": { + "Microsoft.Extensions.Logging.Abstractions/8.0.0": { "dependencies": { - "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2" + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" }, "runtime": { "lib/net8.0/Microsoft.Extensions.Logging.Abstractions.dll": { "assemblyVersion": "8.0.0.0", - "fileVersion": "8.0.1024.46610" + "fileVersion": "8.0.23.53103" } } }, @@ -280,7 +274,7 @@ "Microsoft.IdentityModel.Tokens/8.3.1": { "dependencies": { "Microsoft.Bcl.Memory": "9.0.0", - "Microsoft.Extensions.Logging.Abstractions": "8.0.2", + "Microsoft.Extensions.Logging.Abstractions": "8.0.0", "Microsoft.IdentityModel.Logging": "8.3.1" }, "runtime": { @@ -722,9 +716,27 @@ } } }, - "SmartB2B.Enova.Contracts/1.0.0": { + "SmartB2B.Sync.Contracts/1.0.0": { "runtime": { - "SmartB2B.Enova.Contracts.dll": { + "SmartB2B.Sync.Contracts.dll": { + "assemblyVersion": "1.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "SmartB2B.Sync.Service/1.0.0": { + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "8.0.0", + "Microsoft.Data.SqlClient": "5.2.2", + "Microsoft.Identity.Client": "4.73.1", + "Newtonsoft.Json": "13.0.3", + "Sentry": "6.9.0", + "SmartB2B.Sync.Contracts": "1.0.0", + "System.IdentityModel.Tokens.Jwt": "8.3.1", + "WampSharp.Default.Client": "23.8.1" + }, + "runtime": { + "SmartB2B.Sync.Service.dll": { "assemblyVersion": "1.0.0", "fileVersion": "1.0.0.0" } @@ -787,19 +799,19 @@ "path": "microsoft.data.sqlclient.sni.runtime/5.2.0", "hashPath": "microsoft.data.sqlclient.sni.runtime.5.2.0.nupkg.sha512" }, - "Microsoft.Extensions.DependencyInjection.Abstractions/8.0.2": { + "Microsoft.Extensions.DependencyInjection.Abstractions/8.0.0": { "type": "package", "serviceable": true, - "sha512": "sha512-3iE7UF7MQkCv1cxzCahz+Y/guQbTqieyxyaWKhrRO91itI9cOKO76OHeQDahqG4MmW5umr3CcCvGmK92lWNlbg==", - "path": "microsoft.extensions.dependencyinjection.abstractions/8.0.2", - "hashPath": "microsoft.extensions.dependencyinjection.abstractions.8.0.2.nupkg.sha512" + "sha512": "sha512-cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==", + "path": "microsoft.extensions.dependencyinjection.abstractions/8.0.0", + "hashPath": "microsoft.extensions.dependencyinjection.abstractions.8.0.0.nupkg.sha512" }, - "Microsoft.Extensions.Logging.Abstractions/8.0.2": { + "Microsoft.Extensions.Logging.Abstractions/8.0.0": { "type": "package", "serviceable": true, - "sha512": "sha512-nroMDjS7hNBPtkZqVBbSiQaQjWRDxITI8Y7XnDs97rqG3EbzVTNLZQf7bIeUJcaHOV8bca47s1Uxq94+2oGdxA==", - "path": "microsoft.extensions.logging.abstractions/8.0.2", - "hashPath": "microsoft.extensions.logging.abstractions.8.0.2.nupkg.sha512" + "sha512": "sha512-arDBqTgFCyS0EvRV7O3MZturChstm50OJ0y9bDJvAcmEPJm0FFpFyjU/JLYyStNGGey081DvnQYlncNX5SJJGA==", + "path": "microsoft.extensions.logging.abstractions/8.0.0", + "hashPath": "microsoft.extensions.logging.abstractions.8.0.0.nupkg.sha512" }, "Microsoft.Identity.Client/4.73.1": { "type": "package", @@ -1221,7 +1233,12 @@ "path": "wampsharp.websockets/23.8.1", "hashPath": "wampsharp.websockets.23.8.1.nupkg.sha512" }, - "SmartB2B.Enova.Contracts/1.0.0": { + "SmartB2B.Sync.Contracts/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "SmartB2B.Sync.Service/1.0.0": { "type": "project", "serviceable": false, "sha512": "" diff --git a/release-enova/SmartB2B.Enova.Service.dll b/release-enova/SmartB2B.Enova.Service.dll new file mode 100644 index 0000000..7f7441d Binary files /dev/null and b/release-enova/SmartB2B.Enova.Service.dll differ diff --git a/release/SmartB2B.Enova.Service.exe b/release-enova/SmartB2B.Enova.Service.exe similarity index 99% rename from release/SmartB2B.Enova.Service.exe rename to release-enova/SmartB2B.Enova.Service.exe index b455cce..80dcfbd 100644 Binary files a/release/SmartB2B.Enova.Service.exe and b/release-enova/SmartB2B.Enova.Service.exe differ diff --git a/release-enova/SmartB2B.Enova.Service.pdb b/release-enova/SmartB2B.Enova.Service.pdb new file mode 100644 index 0000000..1721db1 Binary files /dev/null and b/release-enova/SmartB2B.Enova.Service.pdb differ diff --git a/release/SmartB2B.Enova.Service.runtimeconfig.json b/release-enova/SmartB2B.Enova.Service.runtimeconfig.json similarity index 100% rename from release/SmartB2B.Enova.Service.runtimeconfig.json rename to release-enova/SmartB2B.Enova.Service.runtimeconfig.json diff --git a/release-enova/SmartB2B.Sync.Contracts.dll b/release-enova/SmartB2B.Sync.Contracts.dll new file mode 100644 index 0000000..e8cb390 Binary files /dev/null and b/release-enova/SmartB2B.Sync.Contracts.dll differ diff --git a/release/SmartB2B.Enova.Contracts.pdb b/release-enova/SmartB2B.Sync.Contracts.pdb similarity index 72% rename from release/SmartB2B.Enova.Contracts.pdb rename to release-enova/SmartB2B.Sync.Contracts.pdb index 8da68a0..16a3f29 100644 Binary files a/release/SmartB2B.Enova.Contracts.pdb and b/release-enova/SmartB2B.Sync.Contracts.pdb differ diff --git a/release-enova/SmartB2B.Sync.Service.dll b/release-enova/SmartB2B.Sync.Service.dll new file mode 100644 index 0000000..d928549 Binary files /dev/null and b/release-enova/SmartB2B.Sync.Service.dll differ diff --git a/release-enova/SmartB2B.Sync.Service.pdb b/release-enova/SmartB2B.Sync.Service.pdb new file mode 100644 index 0000000..1afdf80 Binary files /dev/null and b/release-enova/SmartB2B.Sync.Service.pdb differ diff --git a/release/System.ClientModel.dll b/release-enova/System.ClientModel.dll similarity index 100% rename from release/System.ClientModel.dll rename to release-enova/System.ClientModel.dll diff --git a/release/System.Configuration.ConfigurationManager.dll b/release-enova/System.Configuration.ConfigurationManager.dll similarity index 100% rename from release/System.Configuration.ConfigurationManager.dll rename to release-enova/System.Configuration.ConfigurationManager.dll diff --git a/release/System.Diagnostics.EventLog.dll b/release-enova/System.Diagnostics.EventLog.dll similarity index 100% rename from release/System.Diagnostics.EventLog.dll rename to release-enova/System.Diagnostics.EventLog.dll diff --git a/release/System.IdentityModel.Tokens.Jwt.dll b/release-enova/System.IdentityModel.Tokens.Jwt.dll similarity index 100% rename from release/System.IdentityModel.Tokens.Jwt.dll rename to release-enova/System.IdentityModel.Tokens.Jwt.dll diff --git a/release/System.Memory.Data.dll b/release-enova/System.Memory.Data.dll similarity index 100% rename from release/System.Memory.Data.dll rename to release-enova/System.Memory.Data.dll diff --git a/release/System.Reactive.dll b/release-enova/System.Reactive.dll similarity index 100% rename from release/System.Reactive.dll rename to release-enova/System.Reactive.dll diff --git a/release/System.Runtime.Caching.dll b/release-enova/System.Runtime.Caching.dll similarity index 100% rename from release/System.Runtime.Caching.dll rename to release-enova/System.Runtime.Caching.dll diff --git a/release/System.Runtime.InteropServices.WindowsRuntime.dll b/release-enova/System.Runtime.InteropServices.WindowsRuntime.dll similarity index 100% rename from release/System.Runtime.InteropServices.WindowsRuntime.dll rename to release-enova/System.Runtime.InteropServices.WindowsRuntime.dll diff --git a/release/System.Security.Cryptography.ProtectedData.dll b/release-enova/System.Security.Cryptography.ProtectedData.dll similarity index 100% rename from release/System.Security.Cryptography.ProtectedData.dll rename to release-enova/System.Security.Cryptography.ProtectedData.dll diff --git a/release/WampSharp.Default.Client.dll b/release-enova/WampSharp.Default.Client.dll similarity index 100% rename from release/WampSharp.Default.Client.dll rename to release-enova/WampSharp.Default.Client.dll diff --git a/release/WampSharp.NewtonsoftJson.dll b/release-enova/WampSharp.NewtonsoftJson.dll similarity index 100% rename from release/WampSharp.NewtonsoftJson.dll rename to release-enova/WampSharp.NewtonsoftJson.dll diff --git a/release/WampSharp.NewtonsoftMessagePack.dll b/release-enova/WampSharp.NewtonsoftMessagePack.dll similarity index 100% rename from release/WampSharp.NewtonsoftMessagePack.dll rename to release-enova/WampSharp.NewtonsoftMessagePack.dll diff --git a/release/WampSharp.WebSockets.dll b/release-enova/WampSharp.WebSockets.dll similarity index 100% rename from release/WampSharp.WebSockets.dll rename to release-enova/WampSharp.WebSockets.dll diff --git a/release/WampSharp.dll b/release-enova/WampSharp.dll similarity index 100% rename from release/WampSharp.dll rename to release-enova/WampSharp.dll diff --git a/release-enova/adapters/SmartB2B.Enova.Adapter.dll b/release-enova/adapters/SmartB2B.Enova.Adapter.dll new file mode 100644 index 0000000..391f81e Binary files /dev/null and b/release-enova/adapters/SmartB2B.Enova.Adapter.dll differ diff --git a/release/config/enova.json.sample b/release-enova/config/enova.json.sample similarity index 100% rename from release/config/enova.json.sample rename to release-enova/config/enova.json.sample diff --git a/daemon/install.cmd b/release-enova/daemon/install.cmd similarity index 88% rename from daemon/install.cmd rename to release-enova/daemon/install.cmd index be98290..978b056 100644 --- a/daemon/install.cmd +++ b/release-enova/daemon/install.cmd @@ -3,7 +3,7 @@ setlocal cd /d "%~dp0" if not exist "smartb2bsync-enova.exe" ( - echo Brak smartb2bsync-enova.exe. Najpierw uruchom publish.ps1. + echo Brak smartb2bsync-enova.exe. Najpierw uruchom publish-enova.ps1. exit /b 1 ) diff --git a/release-enova/daemon/smartb2bsync-enova.exe b/release-enova/daemon/smartb2bsync-enova.exe new file mode 100644 index 0000000..a27a1bc Binary files /dev/null and b/release-enova/daemon/smartb2bsync-enova.exe differ diff --git a/release/daemon/smartb2bsync-enova.xml b/release-enova/daemon/smartb2bsync-enova.xml similarity index 95% rename from release/daemon/smartb2bsync-enova.xml rename to release-enova/daemon/smartb2bsync-enova.xml index da3589a..ab5e5e3 100644 --- a/release/daemon/smartb2bsync-enova.xml +++ b/release-enova/daemon/smartb2bsync-enova.xml @@ -28,8 +28,10 @@ - - + + + + diff --git a/release/daemon/uninstall.cmd b/release-enova/daemon/uninstall.cmd similarity index 100% rename from release/daemon/uninstall.cmd rename to release-enova/daemon/uninstall.cmd diff --git a/release/de/Microsoft.Data.SqlClient.resources.dll b/release-enova/de/Microsoft.Data.SqlClient.resources.dll similarity index 100% rename from release/de/Microsoft.Data.SqlClient.resources.dll rename to release-enova/de/Microsoft.Data.SqlClient.resources.dll diff --git a/release/es/Microsoft.Data.SqlClient.resources.dll b/release-enova/es/Microsoft.Data.SqlClient.resources.dll similarity index 100% rename from release/es/Microsoft.Data.SqlClient.resources.dll rename to release-enova/es/Microsoft.Data.SqlClient.resources.dll diff --git a/release/fr/Microsoft.Data.SqlClient.resources.dll b/release-enova/fr/Microsoft.Data.SqlClient.resources.dll similarity index 100% rename from release/fr/Microsoft.Data.SqlClient.resources.dll rename to release-enova/fr/Microsoft.Data.SqlClient.resources.dll diff --git a/release/it/Microsoft.Data.SqlClient.resources.dll b/release-enova/it/Microsoft.Data.SqlClient.resources.dll similarity index 100% rename from release/it/Microsoft.Data.SqlClient.resources.dll rename to release-enova/it/Microsoft.Data.SqlClient.resources.dll diff --git a/release/ja/Microsoft.Data.SqlClient.resources.dll b/release-enova/ja/Microsoft.Data.SqlClient.resources.dll similarity index 100% rename from release/ja/Microsoft.Data.SqlClient.resources.dll rename to release-enova/ja/Microsoft.Data.SqlClient.resources.dll diff --git a/release/ko/Microsoft.Data.SqlClient.resources.dll b/release-enova/ko/Microsoft.Data.SqlClient.resources.dll similarity index 100% rename from release/ko/Microsoft.Data.SqlClient.resources.dll rename to release-enova/ko/Microsoft.Data.SqlClient.resources.dll diff --git a/release/pt-BR/Microsoft.Data.SqlClient.resources.dll b/release-enova/pt-BR/Microsoft.Data.SqlClient.resources.dll similarity index 100% rename from release/pt-BR/Microsoft.Data.SqlClient.resources.dll rename to release-enova/pt-BR/Microsoft.Data.SqlClient.resources.dll diff --git a/release/ru/Microsoft.Data.SqlClient.resources.dll b/release-enova/ru/Microsoft.Data.SqlClient.resources.dll similarity index 100% rename from release/ru/Microsoft.Data.SqlClient.resources.dll rename to release-enova/ru/Microsoft.Data.SqlClient.resources.dll diff --git a/release/runtimes/unix/lib/net8.0/Microsoft.Data.SqlClient.dll b/release-enova/runtimes/unix/lib/net8.0/Microsoft.Data.SqlClient.dll similarity index 100% rename from release/runtimes/unix/lib/net8.0/Microsoft.Data.SqlClient.dll rename to release-enova/runtimes/unix/lib/net8.0/Microsoft.Data.SqlClient.dll diff --git a/release/runtimes/win-arm/native/Microsoft.Data.SqlClient.SNI.dll b/release-enova/runtimes/win-arm/native/Microsoft.Data.SqlClient.SNI.dll similarity index 100% rename from release/runtimes/win-arm/native/Microsoft.Data.SqlClient.SNI.dll rename to release-enova/runtimes/win-arm/native/Microsoft.Data.SqlClient.SNI.dll diff --git a/release/runtimes/win-arm64/native/Microsoft.Data.SqlClient.SNI.dll b/release-enova/runtimes/win-arm64/native/Microsoft.Data.SqlClient.SNI.dll similarity index 100% rename from release/runtimes/win-arm64/native/Microsoft.Data.SqlClient.SNI.dll rename to release-enova/runtimes/win-arm64/native/Microsoft.Data.SqlClient.SNI.dll diff --git a/release/runtimes/win-x64/native/Microsoft.Data.SqlClient.SNI.dll b/release-enova/runtimes/win-x64/native/Microsoft.Data.SqlClient.SNI.dll similarity index 100% rename from release/runtimes/win-x64/native/Microsoft.Data.SqlClient.SNI.dll rename to release-enova/runtimes/win-x64/native/Microsoft.Data.SqlClient.SNI.dll diff --git a/release/runtimes/win-x86/native/Microsoft.Data.SqlClient.SNI.dll b/release-enova/runtimes/win-x86/native/Microsoft.Data.SqlClient.SNI.dll similarity index 100% rename from release/runtimes/win-x86/native/Microsoft.Data.SqlClient.SNI.dll rename to release-enova/runtimes/win-x86/native/Microsoft.Data.SqlClient.SNI.dll diff --git a/release/runtimes/win/lib/net8.0/Microsoft.Data.SqlClient.dll b/release-enova/runtimes/win/lib/net8.0/Microsoft.Data.SqlClient.dll similarity index 100% rename from release/runtimes/win/lib/net8.0/Microsoft.Data.SqlClient.dll rename to release-enova/runtimes/win/lib/net8.0/Microsoft.Data.SqlClient.dll diff --git a/release/runtimes/win/lib/net8.0/System.Diagnostics.EventLog.Messages.dll b/release-enova/runtimes/win/lib/net8.0/System.Diagnostics.EventLog.Messages.dll similarity index 100% rename from release/runtimes/win/lib/net8.0/System.Diagnostics.EventLog.Messages.dll rename to release-enova/runtimes/win/lib/net8.0/System.Diagnostics.EventLog.Messages.dll diff --git a/release/runtimes/win/lib/net8.0/System.Diagnostics.EventLog.dll b/release-enova/runtimes/win/lib/net8.0/System.Diagnostics.EventLog.dll similarity index 100% rename from release/runtimes/win/lib/net8.0/System.Diagnostics.EventLog.dll rename to release-enova/runtimes/win/lib/net8.0/System.Diagnostics.EventLog.dll diff --git a/release/runtimes/win/lib/net8.0/System.Runtime.Caching.dll b/release-enova/runtimes/win/lib/net8.0/System.Runtime.Caching.dll similarity index 100% rename from release/runtimes/win/lib/net8.0/System.Runtime.Caching.dll rename to release-enova/runtimes/win/lib/net8.0/System.Runtime.Caching.dll diff --git a/release/zh-Hans/Microsoft.Data.SqlClient.resources.dll b/release-enova/zh-Hans/Microsoft.Data.SqlClient.resources.dll similarity index 100% rename from release/zh-Hans/Microsoft.Data.SqlClient.resources.dll rename to release-enova/zh-Hans/Microsoft.Data.SqlClient.resources.dll diff --git a/release/zh-Hant/Microsoft.Data.SqlClient.resources.dll b/release-enova/zh-Hant/Microsoft.Data.SqlClient.resources.dll similarity index 100% rename from release/zh-Hant/Microsoft.Data.SqlClient.resources.dll rename to release-enova/zh-Hant/Microsoft.Data.SqlClient.resources.dll diff --git a/release-optima/Azure.Core.dll b/release-optima/Azure.Core.dll new file mode 100644 index 0000000..d3fa20b Binary files /dev/null and b/release-optima/Azure.Core.dll differ diff --git a/release-optima/Azure.Identity.dll b/release-optima/Azure.Identity.dll new file mode 100644 index 0000000..aab6832 Binary files /dev/null and b/release-optima/Azure.Identity.dll differ diff --git a/release-optima/Microsoft.Bcl.AsyncInterfaces.dll b/release-optima/Microsoft.Bcl.AsyncInterfaces.dll new file mode 100644 index 0000000..421e812 Binary files /dev/null and b/release-optima/Microsoft.Bcl.AsyncInterfaces.dll differ diff --git a/release-optima/Microsoft.Bcl.Memory.dll b/release-optima/Microsoft.Bcl.Memory.dll new file mode 100644 index 0000000..84f76cb Binary files /dev/null and b/release-optima/Microsoft.Bcl.Memory.dll differ diff --git a/release-optima/Microsoft.CSharp.dll b/release-optima/Microsoft.CSharp.dll new file mode 100644 index 0000000..3605d6d Binary files /dev/null and b/release-optima/Microsoft.CSharp.dll differ diff --git a/release-optima/Microsoft.Data.SqlClient.SNI.dll b/release-optima/Microsoft.Data.SqlClient.SNI.dll new file mode 100644 index 0000000..12b8900 Binary files /dev/null and b/release-optima/Microsoft.Data.SqlClient.SNI.dll differ diff --git a/release-optima/Microsoft.Data.SqlClient.dll b/release-optima/Microsoft.Data.SqlClient.dll new file mode 100644 index 0000000..7a5eedb Binary files /dev/null and b/release-optima/Microsoft.Data.SqlClient.dll differ diff --git a/release-optima/Microsoft.DiaSymReader.Native.amd64.dll b/release-optima/Microsoft.DiaSymReader.Native.amd64.dll new file mode 100644 index 0000000..92b355b Binary files /dev/null and b/release-optima/Microsoft.DiaSymReader.Native.amd64.dll differ diff --git a/release-optima/Microsoft.Extensions.DependencyInjection.Abstractions.dll b/release-optima/Microsoft.Extensions.DependencyInjection.Abstractions.dll new file mode 100644 index 0000000..0b3c8e9 Binary files /dev/null and b/release-optima/Microsoft.Extensions.DependencyInjection.Abstractions.dll differ diff --git a/release-optima/Microsoft.Extensions.Logging.Abstractions.dll b/release-optima/Microsoft.Extensions.Logging.Abstractions.dll new file mode 100644 index 0000000..085f415 Binary files /dev/null and b/release-optima/Microsoft.Extensions.Logging.Abstractions.dll differ diff --git a/release-optima/Microsoft.Identity.Client.Extensions.Msal.dll b/release-optima/Microsoft.Identity.Client.Extensions.Msal.dll new file mode 100644 index 0000000..9a7cadb Binary files /dev/null and b/release-optima/Microsoft.Identity.Client.Extensions.Msal.dll differ diff --git a/release-optima/Microsoft.Identity.Client.dll b/release-optima/Microsoft.Identity.Client.dll new file mode 100644 index 0000000..aa7367f Binary files /dev/null and b/release-optima/Microsoft.Identity.Client.dll differ diff --git a/release-optima/Microsoft.IdentityModel.Abstractions.dll b/release-optima/Microsoft.IdentityModel.Abstractions.dll new file mode 100644 index 0000000..a34e976 Binary files /dev/null and b/release-optima/Microsoft.IdentityModel.Abstractions.dll differ diff --git a/release-optima/Microsoft.IdentityModel.JsonWebTokens.dll b/release-optima/Microsoft.IdentityModel.JsonWebTokens.dll new file mode 100644 index 0000000..bef1e02 Binary files /dev/null and b/release-optima/Microsoft.IdentityModel.JsonWebTokens.dll differ diff --git a/release-optima/Microsoft.IdentityModel.Logging.dll b/release-optima/Microsoft.IdentityModel.Logging.dll new file mode 100644 index 0000000..a533925 Binary files /dev/null and b/release-optima/Microsoft.IdentityModel.Logging.dll differ diff --git a/release-optima/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll b/release-optima/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll new file mode 100644 index 0000000..57a9536 Binary files /dev/null and b/release-optima/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll differ diff --git a/release-optima/Microsoft.IdentityModel.Protocols.dll b/release-optima/Microsoft.IdentityModel.Protocols.dll new file mode 100644 index 0000000..9fd9ebf Binary files /dev/null and b/release-optima/Microsoft.IdentityModel.Protocols.dll differ diff --git a/release-optima/Microsoft.IdentityModel.Tokens.dll b/release-optima/Microsoft.IdentityModel.Tokens.dll new file mode 100644 index 0000000..2f55b44 Binary files /dev/null and b/release-optima/Microsoft.IdentityModel.Tokens.dll differ diff --git a/release-optima/Microsoft.SqlServer.Server.dll b/release-optima/Microsoft.SqlServer.Server.dll new file mode 100644 index 0000000..ddeaa86 Binary files /dev/null and b/release-optima/Microsoft.SqlServer.Server.dll differ diff --git a/release-optima/Microsoft.VisualBasic.Core.dll b/release-optima/Microsoft.VisualBasic.Core.dll new file mode 100644 index 0000000..fe94e85 Binary files /dev/null and b/release-optima/Microsoft.VisualBasic.Core.dll differ diff --git a/release-optima/Microsoft.VisualBasic.dll b/release-optima/Microsoft.VisualBasic.dll new file mode 100644 index 0000000..fc2b384 Binary files /dev/null and b/release-optima/Microsoft.VisualBasic.dll differ diff --git a/release-optima/Microsoft.Win32.Primitives.dll b/release-optima/Microsoft.Win32.Primitives.dll new file mode 100644 index 0000000..418fd78 Binary files /dev/null and b/release-optima/Microsoft.Win32.Primitives.dll differ diff --git a/release-optima/Microsoft.Win32.Registry.dll b/release-optima/Microsoft.Win32.Registry.dll new file mode 100644 index 0000000..77a73b4 Binary files /dev/null and b/release-optima/Microsoft.Win32.Registry.dll differ diff --git a/release-optima/Newtonsoft.Json.dll b/release-optima/Newtonsoft.Json.dll new file mode 100644 index 0000000..d035c38 Binary files /dev/null and b/release-optima/Newtonsoft.Json.dll differ diff --git a/release-optima/NewtonsoftMessagePack.dll b/release-optima/NewtonsoftMessagePack.dll new file mode 100644 index 0000000..4a02789 Binary files /dev/null and b/release-optima/NewtonsoftMessagePack.dll differ diff --git a/release-optima/Sentry.dll b/release-optima/Sentry.dll new file mode 100644 index 0000000..1671d8b Binary files /dev/null and b/release-optima/Sentry.dll differ diff --git a/release-optima/SmartB2B.Optima.Adapter.dll b/release-optima/SmartB2B.Optima.Adapter.dll new file mode 100644 index 0000000..7ad711f Binary files /dev/null and b/release-optima/SmartB2B.Optima.Adapter.dll differ diff --git a/release-optima/SmartB2B.Optima.Adapter.pdb b/release-optima/SmartB2B.Optima.Adapter.pdb new file mode 100644 index 0000000..f615cc7 Binary files /dev/null and b/release-optima/SmartB2B.Optima.Adapter.pdb differ diff --git a/release-optima/SmartB2B.Optima.Service.deps.json b/release-optima/SmartB2B.Optima.Service.deps.json new file mode 100644 index 0000000..1c6480c --- /dev/null +++ b/release-optima/SmartB2B.Optima.Service.deps.json @@ -0,0 +1,2100 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0/win-x64", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": {}, + ".NETCoreApp,Version=v8.0/win-x64": { + "SmartB2B.Optima.Service/1.0.0": { + "dependencies": { + "SmartB2B.Optima.Adapter": "1.0.0", + "SmartB2B.Sync.Contracts": "1.0.0", + "SmartB2B.Sync.Service": "1.0.0", + "runtimepack.Microsoft.NETCore.App.Runtime.win-x64": "8.0.24" + }, + "runtime": { + "SmartB2B.Optima.Service.dll": {} + } + }, + "runtimepack.Microsoft.NETCore.App.Runtime.win-x64/8.0.24": { + "runtime": { + "Microsoft.CSharp.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "Microsoft.VisualBasic.Core.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.2426.7010" + }, + "Microsoft.VisualBasic.dll": { + "assemblyVersion": "10.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "Microsoft.Win32.Primitives.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "Microsoft.Win32.Registry.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.AppContext.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Buffers.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Collections.Concurrent.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Collections.Immutable.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Collections.NonGeneric.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Collections.Specialized.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Collections.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.ComponentModel.Annotations.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.ComponentModel.DataAnnotations.dll": { + "assemblyVersion": "4.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.ComponentModel.EventBasedAsync.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.ComponentModel.Primitives.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.ComponentModel.TypeConverter.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.ComponentModel.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Configuration.dll": { + "assemblyVersion": "4.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Console.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Core.dll": { + "assemblyVersion": "4.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Data.Common.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Data.DataSetExtensions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Data.dll": { + "assemblyVersion": "4.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Diagnostics.Contracts.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Diagnostics.Debug.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Diagnostics.DiagnosticSource.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Diagnostics.FileVersionInfo.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Diagnostics.Process.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Diagnostics.StackTrace.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Diagnostics.TextWriterTraceListener.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Diagnostics.Tools.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Diagnostics.TraceSource.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Diagnostics.Tracing.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Drawing.Primitives.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Drawing.dll": { + "assemblyVersion": "4.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Dynamic.Runtime.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Formats.Asn1.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Formats.Tar.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Globalization.Calendars.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Globalization.Extensions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Globalization.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.IO.Compression.Brotli.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.IO.Compression.FileSystem.dll": { + "assemblyVersion": "4.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.IO.Compression.ZipFile.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.IO.Compression.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.IO.FileSystem.AccessControl.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.IO.FileSystem.DriveInfo.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.IO.FileSystem.Primitives.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.IO.FileSystem.Watcher.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.IO.FileSystem.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.IO.IsolatedStorage.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.IO.MemoryMappedFiles.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.IO.Pipes.AccessControl.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.IO.Pipes.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.IO.UnmanagedMemoryStream.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.IO.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Linq.Expressions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Linq.Parallel.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Linq.Queryable.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Linq.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Memory.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Net.Http.Json.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Net.Http.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Net.HttpListener.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Net.Mail.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Net.NameResolution.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Net.NetworkInformation.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Net.Ping.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Net.Primitives.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Net.Quic.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Net.Requests.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Net.Security.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Net.ServicePoint.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Net.Sockets.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Net.WebClient.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Net.WebHeaderCollection.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Net.WebProxy.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Net.WebSockets.Client.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Net.WebSockets.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Net.dll": { + "assemblyVersion": "4.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Numerics.Vectors.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Numerics.dll": { + "assemblyVersion": "4.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.ObjectModel.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Private.CoreLib.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Private.DataContractSerialization.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Private.Uri.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Private.Xml.Linq.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Private.Xml.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Reflection.DispatchProxy.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Reflection.Emit.ILGeneration.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Reflection.Emit.Lightweight.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Reflection.Emit.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Reflection.Extensions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Reflection.Metadata.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Reflection.Primitives.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Reflection.TypeExtensions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Reflection.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Resources.Reader.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Resources.ResourceManager.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Resources.Writer.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Runtime.CompilerServices.Unsafe.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Runtime.CompilerServices.VisualC.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Runtime.Extensions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Runtime.Handles.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Runtime.InteropServices.JavaScript.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Runtime.InteropServices.RuntimeInformation.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Runtime.InteropServices.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Runtime.Intrinsics.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Runtime.Loader.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Runtime.Numerics.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Runtime.Serialization.Formatters.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Runtime.Serialization.Json.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Runtime.Serialization.Primitives.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Runtime.Serialization.Xml.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Runtime.Serialization.dll": { + "assemblyVersion": "4.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Runtime.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Security.AccessControl.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Security.Claims.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Security.Cryptography.Algorithms.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Security.Cryptography.Cng.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Security.Cryptography.Csp.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Security.Cryptography.Encoding.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Security.Cryptography.OpenSsl.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Security.Cryptography.Primitives.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Security.Cryptography.X509Certificates.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Security.Cryptography.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Security.Principal.Windows.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Security.Principal.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Security.SecureString.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Security.dll": { + "assemblyVersion": "4.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.ServiceModel.Web.dll": { + "assemblyVersion": "4.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.ServiceProcess.dll": { + "assemblyVersion": "4.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Text.Encoding.CodePages.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Text.Encoding.Extensions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Text.Encoding.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Text.Encodings.Web.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Text.Json.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Text.RegularExpressions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Threading.Channels.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Threading.Overlapped.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Threading.Tasks.Dataflow.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Threading.Tasks.Extensions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Threading.Tasks.Parallel.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Threading.Tasks.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Threading.Thread.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Threading.ThreadPool.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Threading.Timer.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Threading.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Transactions.Local.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Transactions.dll": { + "assemblyVersion": "4.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.ValueTuple.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Web.HttpUtility.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Web.dll": { + "assemblyVersion": "4.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Windows.dll": { + "assemblyVersion": "4.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Xml.Linq.dll": { + "assemblyVersion": "4.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Xml.ReaderWriter.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Xml.Serialization.dll": { + "assemblyVersion": "4.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Xml.XDocument.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Xml.XPath.XDocument.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Xml.XPath.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Xml.XmlDocument.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Xml.XmlSerializer.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.Xml.dll": { + "assemblyVersion": "4.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "System.dll": { + "assemblyVersion": "4.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "WindowsBase.dll": { + "assemblyVersion": "4.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "mscorlib.dll": { + "assemblyVersion": "4.0.0.0", + "fileVersion": "8.0.2426.7010" + }, + "netstandard.dll": { + "assemblyVersion": "2.1.0.0", + "fileVersion": "8.0.2426.7010" + } + }, + "native": { + "Microsoft.DiaSymReader.Native.amd64.dll": { + "fileVersion": "14.42.34436.0" + }, + "System.IO.Compression.Native.dll": { + "fileVersion": "8.0.2426.7010" + }, + "clretwrc.dll": { + "fileVersion": "8.0.2426.7010" + }, + "clrgc.dll": { + "fileVersion": "8.0.2426.7010" + }, + "clrjit.dll": { + "fileVersion": "8.0.2426.7010" + }, + "coreclr.dll": { + "fileVersion": "8.0.2426.7010" + }, + "createdump.exe": { + "fileVersion": "8.0.2426.7010" + }, + "hostfxr.dll": { + "fileVersion": "8.0.2426.7010" + }, + "hostpolicy.dll": { + "fileVersion": "8.0.2426.7010" + }, + "mscordaccore.dll": { + "fileVersion": "8.0.2426.7010" + }, + "mscordaccore_amd64_amd64_8.0.2426.7010.dll": { + "fileVersion": "8.0.2426.7010" + }, + "mscordbi.dll": { + "fileVersion": "8.0.2426.7010" + }, + "mscorrc.dll": { + "fileVersion": "8.0.2426.7010" + }, + "msquic.dll": { + "fileVersion": "2.4.8.0" + } + } + }, + "Azure.Core/1.38.0": { + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "8.0.0", + "System.ClientModel": "1.0.0", + "System.Diagnostics.DiagnosticSource": "6.0.1", + "System.Memory.Data": "1.0.2", + "System.Numerics.Vectors": "4.5.0", + "System.Text.Encodings.Web": "4.7.2", + "System.Text.Json": "4.7.2", + "System.Threading.Tasks.Extensions": "4.5.4" + }, + "runtime": { + "lib/net6.0/Azure.Core.dll": { + "assemblyVersion": "1.38.0.0", + "fileVersion": "1.3800.24.12602" + } + } + }, + "Azure.Identity/1.11.4": { + "dependencies": { + "Azure.Core": "1.38.0", + "Microsoft.Identity.Client": "4.73.1", + "Microsoft.Identity.Client.Extensions.Msal": "4.61.3", + "System.Memory": "4.5.4", + "System.Security.Cryptography.ProtectedData": "8.0.0", + "System.Text.Json": "4.7.2", + "System.Threading.Tasks.Extensions": "4.5.4" + }, + "runtime": { + "lib/netstandard2.0/Azure.Identity.dll": { + "assemblyVersion": "1.11.4.0", + "fileVersion": "1.1100.424.31005" + } + } + }, + "Microsoft.Bcl.AsyncInterfaces/8.0.0": { + "runtime": { + "lib/netstandard2.1/Microsoft.Bcl.AsyncInterfaces.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Bcl.Memory/9.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Bcl.Memory.dll": { + "assemblyVersion": "9.0.0.0", + "fileVersion": "9.0.24.52809" + } + } + }, + "Microsoft.CSharp/4.3.0": { + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Dynamic.Runtime": "4.3.0", + "System.Globalization": "4.3.0", + "System.Linq": "4.3.0", + "System.Linq.Expressions": "4.3.0", + "System.ObjectModel": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Extensions": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Reflection.TypeExtensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Runtime.InteropServices": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "Microsoft.Data.SqlClient/5.2.2": { + "dependencies": { + "Azure.Identity": "1.11.4", + "Microsoft.Data.SqlClient.SNI.runtime": "5.2.0", + "Microsoft.Identity.Client": "4.73.1", + "Microsoft.IdentityModel.JsonWebTokens": "8.3.1", + "Microsoft.IdentityModel.Protocols.OpenIdConnect": "6.35.0", + "Microsoft.SqlServer.Server": "1.0.0", + "System.Configuration.ConfigurationManager": "8.0.0", + "System.Runtime.Caching": "8.0.0" + }, + "runtime": { + "runtimes/win/lib/net8.0/Microsoft.Data.SqlClient.dll": { + "assemblyVersion": "5.0.0.0", + "fileVersion": "5.22.24240.6" + } + }, + "resources": { + "lib/net8.0/de/Microsoft.Data.SqlClient.resources.dll": { + "locale": "de" + }, + "lib/net8.0/es/Microsoft.Data.SqlClient.resources.dll": { + "locale": "es" + }, + "lib/net8.0/fr/Microsoft.Data.SqlClient.resources.dll": { + "locale": "fr" + }, + "lib/net8.0/it/Microsoft.Data.SqlClient.resources.dll": { + "locale": "it" + }, + "lib/net8.0/ja/Microsoft.Data.SqlClient.resources.dll": { + "locale": "ja" + }, + "lib/net8.0/ko/Microsoft.Data.SqlClient.resources.dll": { + "locale": "ko" + }, + "lib/net8.0/pt-BR/Microsoft.Data.SqlClient.resources.dll": { + "locale": "pt-BR" + }, + "lib/net8.0/ru/Microsoft.Data.SqlClient.resources.dll": { + "locale": "ru" + }, + "lib/net8.0/zh-Hans/Microsoft.Data.SqlClient.resources.dll": { + "locale": "zh-Hans" + }, + "lib/net8.0/zh-Hant/Microsoft.Data.SqlClient.resources.dll": { + "locale": "zh-Hant" + } + } + }, + "Microsoft.Data.SqlClient.SNI.runtime/5.2.0": { + "native": { + "runtimes/win-x64/native/Microsoft.Data.SqlClient.SNI.dll": { + "fileVersion": "5.2.0.0" + } + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/8.0.0": { + "runtime": { + "lib/net8.0/Microsoft.Extensions.DependencyInjection.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Extensions.Logging.Abstractions/8.0.0": { + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0" + }, + "runtime": { + "lib/net8.0/Microsoft.Extensions.Logging.Abstractions.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "Microsoft.Identity.Client/4.73.1": { + "dependencies": { + "Microsoft.IdentityModel.Abstractions": "8.3.1", + "System.Diagnostics.DiagnosticSource": "6.0.1" + }, + "runtime": { + "lib/net8.0/Microsoft.Identity.Client.dll": { + "assemblyVersion": "4.73.1.0", + "fileVersion": "4.73.1.0" + } + } + }, + "Microsoft.Identity.Client.Extensions.Msal/4.61.3": { + "dependencies": { + "Microsoft.Identity.Client": "4.73.1", + "System.Security.Cryptography.ProtectedData": "8.0.0" + }, + "runtime": { + "lib/net6.0/Microsoft.Identity.Client.Extensions.Msal.dll": { + "assemblyVersion": "4.61.3.0", + "fileVersion": "4.61.3.0" + } + } + }, + "Microsoft.IdentityModel.Abstractions/8.3.1": { + "runtime": { + "lib/net8.0/Microsoft.IdentityModel.Abstractions.dll": { + "assemblyVersion": "8.3.1.0", + "fileVersion": "8.3.1.60117" + } + } + }, + "Microsoft.IdentityModel.JsonWebTokens/8.3.1": { + "dependencies": { + "Microsoft.IdentityModel.Tokens": "8.3.1" + }, + "runtime": { + "lib/net8.0/Microsoft.IdentityModel.JsonWebTokens.dll": { + "assemblyVersion": "8.3.1.0", + "fileVersion": "8.3.1.60117" + } + } + }, + "Microsoft.IdentityModel.Logging/8.3.1": { + "dependencies": { + "Microsoft.IdentityModel.Abstractions": "8.3.1" + }, + "runtime": { + "lib/net8.0/Microsoft.IdentityModel.Logging.dll": { + "assemblyVersion": "8.3.1.0", + "fileVersion": "8.3.1.60117" + } + } + }, + "Microsoft.IdentityModel.Protocols/6.35.0": { + "dependencies": { + "Microsoft.IdentityModel.Logging": "8.3.1", + "Microsoft.IdentityModel.Tokens": "8.3.1" + }, + "runtime": { + "lib/net6.0/Microsoft.IdentityModel.Protocols.dll": { + "assemblyVersion": "6.35.0.0", + "fileVersion": "6.35.0.41201" + } + } + }, + "Microsoft.IdentityModel.Protocols.OpenIdConnect/6.35.0": { + "dependencies": { + "Microsoft.IdentityModel.Protocols": "6.35.0", + "System.IdentityModel.Tokens.Jwt": "8.3.1" + }, + "runtime": { + "lib/net6.0/Microsoft.IdentityModel.Protocols.OpenIdConnect.dll": { + "assemblyVersion": "6.35.0.0", + "fileVersion": "6.35.0.41201" + } + } + }, + "Microsoft.IdentityModel.Tokens/8.3.1": { + "dependencies": { + "Microsoft.Bcl.Memory": "9.0.0", + "Microsoft.Extensions.Logging.Abstractions": "8.0.0", + "Microsoft.IdentityModel.Logging": "8.3.1" + }, + "runtime": { + "lib/net8.0/Microsoft.IdentityModel.Tokens.dll": { + "assemblyVersion": "8.3.1.0", + "fileVersion": "8.3.1.60117" + } + } + }, + "Microsoft.NETCore.Platforms/1.1.0": {}, + "Microsoft.NETCore.Targets/1.1.0": {}, + "Microsoft.SqlServer.Server/1.0.0": { + "runtime": { + "lib/netstandard2.0/Microsoft.SqlServer.Server.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "Newtonsoft.Json/13.0.3": { + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "assemblyVersion": "13.0.0.0", + "fileVersion": "13.0.3.27908" + } + } + }, + "NewtonsoftMessagePack/0.1.11": { + "dependencies": { + "Newtonsoft.Json": "13.0.3" + }, + "runtime": { + "lib/netstandard2.0/NewtonsoftMessagePack.dll": { + "assemblyVersion": "0.0.0.0", + "fileVersion": "0.0.0.0" + } + } + }, + "runtime.any.System.Collections/4.3.0": { + "dependencies": { + "System.Runtime": "4.3.0" + } + }, + "runtime.any.System.Globalization/4.3.0": {}, + "runtime.any.System.IO/4.3.0": {}, + "runtime.any.System.Reflection/4.3.0": {}, + "runtime.any.System.Reflection.Extensions/4.3.0": {}, + "runtime.any.System.Reflection.Primitives/4.3.0": {}, + "runtime.any.System.Resources.ResourceManager/4.3.0": {}, + "runtime.any.System.Runtime/4.3.0": { + "dependencies": { + "System.Private.Uri": "4.3.0" + } + }, + "runtime.any.System.Runtime.Handles/4.3.0": {}, + "runtime.any.System.Runtime.InteropServices/4.3.0": {}, + "runtime.any.System.Text.Encoding/4.3.0": {}, + "runtime.any.System.Threading.Tasks/4.3.0": {}, + "runtime.win.System.Diagnostics.Debug/4.3.0": {}, + "runtime.win.System.Runtime.Extensions/4.3.0": { + "dependencies": { + "System.Private.Uri": "4.3.0" + } + }, + "Sentry/6.9.0": { + "runtime": { + "lib/net8.0/Sentry.dll": { + "assemblyVersion": "6.9.0.0", + "fileVersion": "6.9.0.0" + } + } + }, + "System.ClientModel/1.0.0": { + "dependencies": { + "System.Memory.Data": "1.0.2", + "System.Text.Json": "4.7.2" + }, + "runtime": { + "lib/net6.0/System.ClientModel.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.24.5302" + } + } + }, + "System.Collections/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "runtime.any.System.Collections": "4.3.0" + } + }, + "System.Collections.Immutable/1.5.0": {}, + "System.Configuration.ConfigurationManager/8.0.0": { + "dependencies": { + "System.Diagnostics.EventLog": "8.0.0", + "System.Security.Cryptography.ProtectedData": "8.0.0" + }, + "runtime": { + "lib/net8.0/System.Configuration.ConfigurationManager.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "System.Diagnostics.Debug/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "runtime.win.System.Diagnostics.Debug": "4.3.0" + } + }, + "System.Diagnostics.DiagnosticSource/6.0.1": { + "dependencies": { + "System.Runtime.CompilerServices.Unsafe": "6.0.0" + } + }, + "System.Diagnostics.EventLog/8.0.0": { + "runtime": { + "runtimes/win/lib/net8.0/System.Diagnostics.EventLog.Messages.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "0.0.0.0" + }, + "runtimes/win/lib/net8.0/System.Diagnostics.EventLog.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "System.Dynamic.Runtime/4.3.0": { + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Linq": "4.3.0", + "System.Linq.Expressions": "4.3.0", + "System.ObjectModel": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Emit": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Reflection.TypeExtensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Globalization/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "runtime.any.System.Globalization": "4.3.0" + } + }, + "System.IdentityModel.Tokens.Jwt/8.3.1": { + "dependencies": { + "Microsoft.IdentityModel.JsonWebTokens": "8.3.1", + "Microsoft.IdentityModel.Tokens": "8.3.1" + }, + "runtime": { + "lib/net8.0/System.IdentityModel.Tokens.Jwt.dll": { + "assemblyVersion": "8.3.1.0", + "fileVersion": "8.3.1.60117" + } + } + }, + "System.IO/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "System.Text.Encoding": "4.3.0", + "System.Threading.Tasks": "4.3.0", + "runtime.any.System.IO": "4.3.0" + } + }, + "System.Linq/4.3.0": { + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0" + } + }, + "System.Linq.Expressions/4.3.0": { + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Globalization": "4.3.0", + "System.IO": "4.3.0", + "System.Linq": "4.3.0", + "System.ObjectModel": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Emit": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Emit.Lightweight": "4.3.0", + "System.Reflection.Extensions": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Reflection.TypeExtensions": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Extensions": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Memory/4.5.4": {}, + "System.Memory.Data/1.0.2": { + "dependencies": { + "System.Text.Encodings.Web": "4.7.2", + "System.Text.Json": "4.7.2" + }, + "runtime": { + "lib/netstandard2.0/System.Memory.Data.dll": { + "assemblyVersion": "1.0.2.0", + "fileVersion": "1.0.221.20802" + } + } + }, + "System.Numerics.Vectors/4.5.0": {}, + "System.ObjectModel/4.3.0": { + "dependencies": { + "System.Collections": "4.3.0", + "System.Diagnostics.Debug": "4.3.0", + "System.Resources.ResourceManager": "4.3.0", + "System.Runtime": "4.3.0", + "System.Threading": "4.3.0" + } + }, + "System.Private.Uri/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0" + } + }, + "System.Reactive/4.1.6": { + "dependencies": { + "System.Runtime.InteropServices.WindowsRuntime": "4.3.0", + "System.Threading.Tasks.Extensions": "4.5.4" + }, + "runtime": { + "lib/netstandard2.0/System.Reactive.dll": { + "assemblyVersion": "4.1.0.0", + "fileVersion": "4.1.6.362" + } + } + }, + "System.Reflection/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.IO": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0", + "runtime.any.System.Reflection": "4.3.0" + } + }, + "System.Reflection.Emit/4.3.0": { + "dependencies": { + "System.IO": "4.3.0", + "System.Reflection": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Emit.ILGeneration/4.3.0": { + "dependencies": { + "System.Reflection": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Emit.Lightweight/4.3.0": { + "dependencies": { + "System.Reflection": "4.3.0", + "System.Reflection.Emit.ILGeneration": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Reflection.Extensions/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0", + "runtime.any.System.Reflection.Extensions": "4.3.0" + } + }, + "System.Reflection.Primitives/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "runtime.any.System.Reflection.Primitives": "4.3.0" + } + }, + "System.Reflection.TypeExtensions/4.3.0": { + "dependencies": { + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0" + } + }, + "System.Resources.ResourceManager/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Globalization": "4.3.0", + "System.Reflection": "4.3.0", + "System.Runtime": "4.3.0", + "runtime.any.System.Resources.ResourceManager": "4.3.0" + } + }, + "System.Runtime/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "runtime.any.System.Runtime": "4.3.0" + } + }, + "System.Runtime.Caching/8.0.0": { + "dependencies": { + "System.Configuration.ConfigurationManager": "8.0.0" + }, + "runtime": { + "runtimes/win/lib/net8.0/System.Runtime.Caching.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "System.Runtime.CompilerServices.Unsafe/6.0.0": {}, + "System.Runtime.Extensions/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "runtime.win.System.Runtime.Extensions": "4.3.0" + } + }, + "System.Runtime.Handles/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "runtime.any.System.Runtime.Handles": "4.3.0" + } + }, + "System.Runtime.InteropServices/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Reflection": "4.3.0", + "System.Reflection.Primitives": "4.3.0", + "System.Runtime": "4.3.0", + "System.Runtime.Handles": "4.3.0", + "runtime.any.System.Runtime.InteropServices": "4.3.0" + } + }, + "System.Runtime.InteropServices.WindowsRuntime/4.3.0": { + "dependencies": { + "System.Runtime": "4.3.0" + }, + "runtime": { + "lib/netstandard1.3/System.Runtime.InteropServices.WindowsRuntime.dll": { + "assemblyVersion": "4.0.2.0", + "fileVersion": "4.6.24705.1" + } + } + }, + "System.Security.Cryptography.ProtectedData/8.0.0": { + "runtime": { + "lib/net8.0/System.Security.Cryptography.ProtectedData.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + }, + "System.Text.Encoding/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "runtime.any.System.Text.Encoding": "4.3.0" + } + }, + "System.Text.Encodings.Web/4.7.2": {}, + "System.Text.Json/4.7.2": {}, + "System.Threading/4.3.0": { + "dependencies": { + "System.Runtime": "4.3.0", + "System.Threading.Tasks": "4.3.0" + } + }, + "System.Threading.Tasks/4.3.0": { + "dependencies": { + "Microsoft.NETCore.Platforms": "1.1.0", + "Microsoft.NETCore.Targets": "1.1.0", + "System.Runtime": "4.3.0", + "runtime.any.System.Threading.Tasks": "4.3.0" + } + }, + "System.Threading.Tasks.Dataflow/4.9.0": {}, + "System.Threading.Tasks.Extensions/4.5.4": {}, + "WampSharp/23.8.1": { + "dependencies": { + "Microsoft.CSharp": "4.3.0", + "System.Collections.Immutable": "1.5.0", + "System.Reactive": "4.1.6", + "System.Threading.Tasks.Dataflow": "4.9.0" + }, + "runtime": { + "lib/netstandard2.1/WampSharp.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "WampSharp.Default.Client/23.8.1": { + "dependencies": { + "WampSharp.NewtonsoftJson": "23.8.1", + "WampSharp.NewtonsoftMessagePack": "23.8.1", + "WampSharp.WebSockets": "23.8.1" + }, + "runtime": { + "lib/netstandard2.1/WampSharp.Default.Client.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "WampSharp.NewtonsoftJson/23.8.1": { + "dependencies": { + "Newtonsoft.Json": "13.0.3", + "WampSharp": "23.8.1" + }, + "runtime": { + "lib/netstandard2.1/WampSharp.NewtonsoftJson.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "WampSharp.NewtonsoftMessagePack/23.8.1": { + "dependencies": { + "NewtonsoftMessagePack": "0.1.11", + "WampSharp.NewtonsoftJson": "23.8.1" + }, + "runtime": { + "lib/netstandard2.1/WampSharp.NewtonsoftMessagePack.dll": { + "assemblyVersion": "0.0.0.0", + "fileVersion": "0.0.0.0" + } + } + }, + "WampSharp.WebSockets/23.8.1": { + "dependencies": { + "WampSharp": "23.8.1" + }, + "runtime": { + "lib/netstandard2.1/WampSharp.WebSockets.dll": { + "assemblyVersion": "1.0.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "SmartB2B.Optima.Adapter/1.0.0": { + "dependencies": { + "SmartB2B.Sync.Contracts": "1.0.0" + }, + "runtime": { + "SmartB2B.Optima.Adapter.dll": { + "assemblyVersion": "1.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "SmartB2B.Sync.Contracts/1.0.0": { + "runtime": { + "SmartB2B.Sync.Contracts.dll": { + "assemblyVersion": "1.0.0", + "fileVersion": "1.0.0.0" + } + } + }, + "SmartB2B.Sync.Service/1.0.0": { + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "8.0.0", + "Microsoft.Data.SqlClient": "5.2.2", + "Microsoft.Identity.Client": "4.73.1", + "Newtonsoft.Json": "13.0.3", + "Sentry": "6.9.0", + "SmartB2B.Sync.Contracts": "1.0.0", + "System.IdentityModel.Tokens.Jwt": "8.3.1", + "WampSharp.Default.Client": "23.8.1" + }, + "runtime": { + "SmartB2B.Sync.Service.dll": { + "assemblyVersion": "1.0.0", + "fileVersion": "1.0.0.0" + } + } + } + } + }, + "libraries": { + "SmartB2B.Optima.Service/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "runtimepack.Microsoft.NETCore.App.Runtime.win-x64/8.0.24": { + "type": "runtimepack", + "serviceable": false, + "sha512": "" + }, + "Azure.Core/1.38.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-IuEgCoVA0ef7E4pQtpC3+TkPbzaoQfa77HlfJDmfuaJUCVJmn7fT0izamZiryW5sYUFKizsftIxMkXKbgIcPMQ==", + "path": "azure.core/1.38.0", + "hashPath": "azure.core.1.38.0.nupkg.sha512" + }, + "Azure.Identity/1.11.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Sf4BoE6Q3jTgFkgBkx7qztYOFELBCo+wQgpYDwal/qJ1unBH73ywPztIJKXBXORRzAeNijsuxhk94h0TIMvfYg==", + "path": "azure.identity/1.11.4", + "hashPath": "azure.identity.1.11.4.nupkg.sha512" + }, + "Microsoft.Bcl.AsyncInterfaces/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3WA9q9yVqJp222P3x1wYIGDAkpjAku0TMUaaQV22g6L67AI0LdOIrVS7Ht2vJfLHGSPVuqN94vIr15qn+HEkHw==", + "path": "microsoft.bcl.asyncinterfaces/8.0.0", + "hashPath": "microsoft.bcl.asyncinterfaces.8.0.0.nupkg.sha512" + }, + "Microsoft.Bcl.Memory/9.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bTUtGfpGyJnohQzjdXbtc7MqNzkv7CWUSRz54+ucNm0i32rZiIU0VdVPHDBShOl1qhVKRjW8mnEBz3d2vH93tQ==", + "path": "microsoft.bcl.memory/9.0.0", + "hashPath": "microsoft.bcl.memory.9.0.0.nupkg.sha512" + }, + "Microsoft.CSharp/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-P+MBhIM0YX+JqROuf7i306ZLJEjQYA9uUyRDE+OqwUI5sh41e2ZbPQV3LfAPh+29cmceE1pUffXsGfR4eMY3KA==", + "path": "microsoft.csharp/4.3.0", + "hashPath": "microsoft.csharp.4.3.0.nupkg.sha512" + }, + "Microsoft.Data.SqlClient/5.2.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-mtoeRMh7F/OA536c/Cnh8L4H0uLSKB5kSmoi54oN7Fp0hNJDy22IqyMhaMH4PkDCqI7xL//Fvg9ldtuPHG0h5g==", + "path": "microsoft.data.sqlclient/5.2.2", + "hashPath": "microsoft.data.sqlclient.5.2.2.nupkg.sha512" + }, + "Microsoft.Data.SqlClient.SNI.runtime/5.2.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-po1jhvFd+8pbfvJR/puh+fkHi0GRanAdvayh/0e47yaM6CXWZ6opUjCMFuYlAnD2LcbyvQE7fPJKvogmaUcN+w==", + "path": "microsoft.data.sqlclient.sni.runtime/5.2.0", + "hashPath": "microsoft.data.sqlclient.sni.runtime.5.2.0.nupkg.sha512" + }, + "Microsoft.Extensions.DependencyInjection.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg==", + "path": "microsoft.extensions.dependencyinjection.abstractions/8.0.0", + "hashPath": "microsoft.extensions.dependencyinjection.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Extensions.Logging.Abstractions/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-arDBqTgFCyS0EvRV7O3MZturChstm50OJ0y9bDJvAcmEPJm0FFpFyjU/JLYyStNGGey081DvnQYlncNX5SJJGA==", + "path": "microsoft.extensions.logging.abstractions/8.0.0", + "hashPath": "microsoft.extensions.logging.abstractions.8.0.0.nupkg.sha512" + }, + "Microsoft.Identity.Client/4.73.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-NnDLS8QwYqO5ZZecL2oioi1LUqjh5Ewk4bMLzbgiXJbQmZhDLtKwLxL3DpGMlQAJ2G4KgEnvGPKa+OOgffeJbw==", + "path": "microsoft.identity.client/4.73.1", + "hashPath": "microsoft.identity.client.4.73.1.nupkg.sha512" + }, + "Microsoft.Identity.Client.Extensions.Msal/4.61.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-PWnJcznrSGr25MN8ajlc2XIDW4zCFu0U6FkpaNLEWLgd1NgFCp5uDY3mqLDgM8zCN8hqj8yo5wHYfLB2HjcdGw==", + "path": "microsoft.identity.client.extensions.msal/4.61.3", + "hashPath": "microsoft.identity.client.extensions.msal.4.61.3.nupkg.sha512" + }, + "Microsoft.IdentityModel.Abstractions/8.3.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-oXYKRcTS0DTIB5vZenGy9oceD8awhjnXFFabc/IWBwluMA03SGvazCFyUIQ2mJOIOSf9lLyM971nbTj9qZgEJg==", + "path": "microsoft.identitymodel.abstractions/8.3.1", + "hashPath": "microsoft.identitymodel.abstractions.8.3.1.nupkg.sha512" + }, + "Microsoft.IdentityModel.JsonWebTokens/8.3.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-cA622rrXYdaO7inNZ8KY5leZpP6889wT+gHPgvy62PYlAITyxF9PxP5u+ecNBOsPx2PagBH7ZNr39yU/MOPn+w==", + "path": "microsoft.identitymodel.jsonwebtokens/8.3.1", + "hashPath": "microsoft.identitymodel.jsonwebtokens.8.3.1.nupkg.sha512" + }, + "Microsoft.IdentityModel.Logging/8.3.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-XCwbK7ErgZdrwl4ph+i8X5SCGwAepBFbsNIEceozGzrBFVvZbKKJE1WQOft9QyglP4me+DECdVVL8UnI6OO+sg==", + "path": "microsoft.identitymodel.logging/8.3.1", + "hashPath": "microsoft.identitymodel.logging.8.3.1.nupkg.sha512" + }, + "Microsoft.IdentityModel.Protocols/6.35.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-BPQhlDzdFvv1PzaUxNSk+VEPwezlDEVADIKmyxubw7IiELK18uJ06RQ9QKKkds30XI+gDu9n8j24XQ8w7fjWcg==", + "path": "microsoft.identitymodel.protocols/6.35.0", + "hashPath": "microsoft.identitymodel.protocols.6.35.0.nupkg.sha512" + }, + "Microsoft.IdentityModel.Protocols.OpenIdConnect/6.35.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-LMtVqnECCCdSmyFoCOxIE5tXQqkOLrvGrL7OxHg41DIm1bpWtaCdGyVcTAfOQpJXvzND9zUKIN/lhngPkYR8vg==", + "path": "microsoft.identitymodel.protocols.openidconnect/6.35.0", + "hashPath": "microsoft.identitymodel.protocols.openidconnect.6.35.0.nupkg.sha512" + }, + "Microsoft.IdentityModel.Tokens/8.3.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-77GXREJzIDiKAc/RR8YE267bwzrxM4cjMRCzMQa0Xk1MUUdjx/JwjDJpUh00vT4oxcX5rjsMP0KLd8YjgR3N3w==", + "path": "microsoft.identitymodel.tokens/8.3.1", + "hashPath": "microsoft.identitymodel.tokens.8.3.1.nupkg.sha512" + }, + "Microsoft.NETCore.Platforms/1.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==", + "path": "microsoft.netcore.platforms/1.1.0", + "hashPath": "microsoft.netcore.platforms.1.1.0.nupkg.sha512" + }, + "Microsoft.NETCore.Targets/1.1.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-aOZA3BWfz9RXjpzt0sRJJMjAscAUm3Hoa4UWAfceV9UTYxgwZ1lZt5nO2myFf+/jetYQo4uTP7zS8sJY67BBxg==", + "path": "microsoft.netcore.targets/1.1.0", + "hashPath": "microsoft.netcore.targets.1.1.0.nupkg.sha512" + }, + "Microsoft.SqlServer.Server/1.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-N4KeF3cpcm1PUHym1RmakkzfkEv3GRMyofVv40uXsQhCQeglr2OHNcUk2WOG51AKpGO8ynGpo9M/kFXSzghwug==", + "path": "microsoft.sqlserver.server/1.0.0", + "hashPath": "microsoft.sqlserver.server.1.0.0.nupkg.sha512" + }, + "Newtonsoft.Json/13.0.3": { + "type": "package", + "serviceable": true, + "sha512": "sha512-HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "path": "newtonsoft.json/13.0.3", + "hashPath": "newtonsoft.json.13.0.3.nupkg.sha512" + }, + "NewtonsoftMessagePack/0.1.11": { + "type": "package", + "serviceable": true, + "sha512": "sha512-CuwKoxWUFRQewUXS0FH2V3hZFrati69OtveyX3GwlDGp6VuvkzaSzSXw7Hi5OiFR3X4QYULlWkwV/jxYYEPacA==", + "path": "newtonsoftmessagepack/0.1.11", + "hashPath": "newtonsoftmessagepack.0.1.11.nupkg.sha512" + }, + "runtime.any.System.Collections/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-23g6rqftKmovn2cLeGsuHUYm0FD7pdutb0uQMJpZ3qTvq+zHkgmt6J65VtRry4WDGYlmkMa4xDACtaQ94alNag==", + "path": "runtime.any.system.collections/4.3.0", + "hashPath": "runtime.any.system.collections.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Globalization/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-sMDBnad4rp4t7GY442Jux0MCUuKL4otn5BK6Ni0ARTXTSpRNBzZ7hpMfKSvnVSED5kYJm96YOWsqV0JH0d2uuw==", + "path": "runtime.any.system.globalization/4.3.0", + "hashPath": "runtime.any.system.globalization.4.3.0.nupkg.sha512" + }, + "runtime.any.System.IO/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-SDZ5AD1DtyRoxYtEcqQ3HDlcrorMYXZeCt7ZhG9US9I5Vva+gpIWDGMkcwa5XiKL0ceQKRZIX2x0XEjLX7PDzQ==", + "path": "runtime.any.system.io/4.3.0", + "hashPath": "runtime.any.system.io.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Reflection/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-hLC3A3rI8jipR5d9k7+f0MgRCW6texsAp0MWkN/ci18FMtQ9KH7E2vDn/DH2LkxsszlpJpOn9qy6Z6/69rH6eQ==", + "path": "runtime.any.system.reflection/4.3.0", + "hashPath": "runtime.any.system.reflection.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Reflection.Extensions/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-cPhT+Vqu52+cQQrDai/V91gubXUnDKNRvlBnH+hOgtGyHdC17aQIU64EaehwAQymd7kJA5rSrVRNfDYrbhnzyA==", + "path": "runtime.any.system.reflection.extensions/4.3.0", + "hashPath": "runtime.any.system.reflection.extensions.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Reflection.Primitives/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Nrm1p3armp6TTf2xuvaa+jGTTmncALWFq22CpmwRvhDf6dE9ZmH40EbOswD4GnFLrMRS0Ki6Kx5aUPmKK/hZBg==", + "path": "runtime.any.system.reflection.primitives/4.3.0", + "hashPath": "runtime.any.system.reflection.primitives.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Resources.ResourceManager/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-Lxb89SMvf8w9p9+keBLyL6H6x/TEmc6QVsIIA0T36IuyOY3kNvIdyGddA2qt35cRamzxF8K5p0Opq4G4HjNbhQ==", + "path": "runtime.any.system.resources.resourcemanager/4.3.0", + "hashPath": "runtime.any.system.resources.resourcemanager.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Runtime/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-fRS7zJgaG9NkifaAxGGclDDoRn9HC7hXACl52Or06a/fxdzDajWb5wov3c6a+gVSlekRoexfjwQSK9sh5um5LQ==", + "path": "runtime.any.system.runtime/4.3.0", + "hashPath": "runtime.any.system.runtime.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Runtime.Handles/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-GG84X6vufoEzqx8PbeBKheE4srOhimv+yLtGb/JkR3Y2FmoqmueLNFU4Xx8Y67plFpltQSdK74x0qlEhIpv/CQ==", + "path": "runtime.any.system.runtime.handles/4.3.0", + "hashPath": "runtime.any.system.runtime.handles.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Runtime.InteropServices/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-lBoFeQfxe/4eqjPi46E0LU/YaCMdNkQ8B4MZu/mkzdIAZh8RQ1NYZSj0egrQKdgdvlPFtP4STtob40r4o2DBAw==", + "path": "runtime.any.system.runtime.interopservices/4.3.0", + "hashPath": "runtime.any.system.runtime.interopservices.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Text.Encoding/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-+ihI5VaXFCMVPJNstG4O4eo1CfbrByLxRrQQTqOTp1ttK0kUKDqOdBSTaCB2IBk/QtjDrs6+x4xuezyMXdm0HQ==", + "path": "runtime.any.system.text.encoding/4.3.0", + "hashPath": "runtime.any.system.text.encoding.4.3.0.nupkg.sha512" + }, + "runtime.any.System.Threading.Tasks/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OhBAVBQG5kFj1S+hCEQ3TUHBAEtZ3fbEMgZMRNdN8A0Pj4x+5nTELEqL59DU0TjKVE6II3dqKw4Dklb3szT65w==", + "path": "runtime.any.system.threading.tasks/4.3.0", + "hashPath": "runtime.any.system.threading.tasks.4.3.0.nupkg.sha512" + }, + "runtime.win.System.Diagnostics.Debug/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-hHHP0WCStene2jjeYcuDkETozUYF/3sHVRHAEOgS3L15hlip24ssqCTnJC28Z03Wpo078oMcJd0H4egD2aJI8g==", + "path": "runtime.win.system.diagnostics.debug/4.3.0", + "hashPath": "runtime.win.system.diagnostics.debug.4.3.0.nupkg.sha512" + }, + "runtime.win.System.Runtime.Extensions/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-RkgHVhUPvzZxuUubiZe8yr/6CypRVXj0VBzaR8hsqQ8f+rUo7e4PWrHTLOCjd8fBMGWCrY//fi7Ku3qXD7oHRw==", + "path": "runtime.win.system.runtime.extensions/4.3.0", + "hashPath": "runtime.win.system.runtime.extensions.4.3.0.nupkg.sha512" + }, + "Sentry/6.9.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-qQIvEwuvjAB6fDLVLLcDj/5f8n5jOyPyHjj3a/GQ1ogTLLQqsSxgQj1fEEquNT9HQuj4ZTyCg3c1DCBMUIvJGQ==", + "path": "sentry/6.9.0", + "hashPath": "sentry.6.9.0.nupkg.sha512" + }, + "System.ClientModel/1.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-I3CVkvxeqFYjIVEP59DnjbeoGNfo/+SZrCLpRz2v/g0gpCHaEMPtWSY0s9k/7jR1rAsLNg2z2u1JRB76tPjnIw==", + "path": "system.clientmodel/1.0.0", + "hashPath": "system.clientmodel.1.0.0.nupkg.sha512" + }, + "System.Collections/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3Dcj85/TBdVpL5Zr+gEEBUuFe2icOnLalmEh9hfck1PTYbbyWuZgh4fmm2ysCLTrqLQw6t3TgTyJ+VLp+Qb+Lw==", + "path": "system.collections/4.3.0", + "hashPath": "system.collections.4.3.0.nupkg.sha512" + }, + "System.Collections.Immutable/1.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-EXKiDFsChZW0RjrZ4FYHu9aW6+P4MCgEDCklsVseRfhoO0F+dXeMSsMRAlVXIo06kGJ/zv+2w1a2uc2+kxxSaQ==", + "path": "system.collections.immutable/1.5.0", + "hashPath": "system.collections.immutable.1.5.0.nupkg.sha512" + }, + "System.Configuration.ConfigurationManager/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-JlYi9XVvIREURRUlGMr1F6vOFLk7YSY4p1vHo4kX3tQ0AGrjqlRWHDi66ImHhy6qwXBG3BJ6Y1QlYQ+Qz6Xgww==", + "path": "system.configuration.configurationmanager/8.0.0", + "hashPath": "system.configuration.configurationmanager.8.0.0.nupkg.sha512" + }, + "System.Diagnostics.Debug/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-ZUhUOdqmaG5Jk3Xdb8xi5kIyQYAA4PnTNlHx1mu9ZY3qv4ELIdKbnL/akbGaKi2RnNUWaZsAs31rvzFdewTj2g==", + "path": "system.diagnostics.debug/4.3.0", + "hashPath": "system.diagnostics.debug.4.3.0.nupkg.sha512" + }, + "System.Diagnostics.DiagnosticSource/6.0.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-KiLYDu2k2J82Q9BJpWiuQqCkFjRBWVq4jDzKKWawVi9KWzyD0XG3cmfX0vqTQlL14Wi9EufJrbL0+KCLTbqWiQ==", + "path": "system.diagnostics.diagnosticsource/6.0.1", + "hashPath": "system.diagnostics.diagnosticsource.6.0.1.nupkg.sha512" + }, + "System.Diagnostics.EventLog/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-fdYxcRjQqTTacKId/2IECojlDSFvp7LP5N78+0z/xH7v/Tuw5ZAxu23Y6PTCRinqyu2ePx+Gn1098NC6jM6d+A==", + "path": "system.diagnostics.eventlog/8.0.0", + "hashPath": "system.diagnostics.eventlog.8.0.0.nupkg.sha512" + }, + "System.Dynamic.Runtime/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-SNVi1E/vfWUAs/WYKhE9+qlS6KqK0YVhnlT0HQtr8pMIA8YX3lwy3uPMownDwdYISBdmAF/2holEIldVp85Wag==", + "path": "system.dynamic.runtime/4.3.0", + "hashPath": "system.dynamic.runtime.4.3.0.nupkg.sha512" + }, + "System.Globalization/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-kYdVd2f2PAdFGblzFswE4hkNANJBKRmsfa2X5LG2AcWE1c7/4t0pYae1L8vfZ5xvE2nK/R9JprtToA61OSHWIg==", + "path": "system.globalization/4.3.0", + "hashPath": "system.globalization.4.3.0.nupkg.sha512" + }, + "System.IdentityModel.Tokens.Jwt/8.3.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-SxdCv+SmnKOhUvryKvrpWJnkuVHj3hU8pUwj7R8zthi73TlBUlMyavon9qfuJsjnqY+L7jusp3Zo0fWFX6mwtw==", + "path": "system.identitymodel.tokens.jwt/8.3.1", + "hashPath": "system.identitymodel.tokens.jwt.8.3.1.nupkg.sha512" + }, + "System.IO/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-3qjaHvxQPDpSOYICjUoTsmoq5u6QJAFRUITgeT/4gqkF1bajbSmb1kwSxEA8AHlofqgcKJcM8udgieRNhaJ5Cg==", + "path": "system.io/4.3.0", + "hashPath": "system.io.4.3.0.nupkg.sha512" + }, + "System.Linq/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-5DbqIUpsDp0dFftytzuMmc0oeMdQwjcP/EWxsksIz/w1TcFRkZ3yKKz0PqiYFMmEwPSWw+qNVqD7PJ889JzHbw==", + "path": "system.linq/4.3.0", + "hashPath": "system.linq.4.3.0.nupkg.sha512" + }, + "System.Linq.Expressions/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-PGKkrd2khG4CnlyJwxwwaWWiSiWFNBGlgXvJpeO0xCXrZ89ODrQ6tjEWS/kOqZ8GwEOUATtKtzp1eRgmYNfclg==", + "path": "system.linq.expressions/4.3.0", + "hashPath": "system.linq.expressions.4.3.0.nupkg.sha512" + }, + "System.Memory/4.5.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-1MbJTHS1lZ4bS4FmsJjnuGJOu88ZzTT2rLvrhW7Ygic+pC0NWA+3hgAen0HRdsocuQXCkUTdFn9yHJJhsijDXw==", + "path": "system.memory/4.5.4", + "hashPath": "system.memory.4.5.4.nupkg.sha512" + }, + "System.Memory.Data/1.0.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-JGkzeqgBsiZwKJZ1IxPNsDFZDhUvuEdX8L8BDC8N3KOj+6zMcNU28CNN59TpZE/VJYy9cP+5M+sbxtWJx3/xtw==", + "path": "system.memory.data/1.0.2", + "hashPath": "system.memory.data.1.0.2.nupkg.sha512" + }, + "System.Numerics.Vectors/4.5.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-QQTlPTl06J/iiDbJCiepZ4H//BVraReU4O4EoRw1U02H5TLUIT7xn3GnDp9AXPSlJUDyFs4uWjWafNX6WrAojQ==", + "path": "system.numerics.vectors/4.5.0", + "hashPath": "system.numerics.vectors.4.5.0.nupkg.sha512" + }, + "System.ObjectModel/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-bdX+80eKv9bN6K4N+d77OankKHGn6CH711a6fcOpMQu2Fckp/Ft4L/kW9WznHpyR0NRAvJutzOMHNNlBGvxQzQ==", + "path": "system.objectmodel/4.3.0", + "hashPath": "system.objectmodel.4.3.0.nupkg.sha512" + }, + "System.Private.Uri/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-I4SwANiUGho1esj4V4oSlPllXjzCZDE+5XXso2P03LW2vOda2Enzh8DWOxwN6hnrJyp314c7KuVu31QYhRzOGg==", + "path": "system.private.uri/4.3.0", + "hashPath": "system.private.uri.4.3.0.nupkg.sha512" + }, + "System.Reactive/4.1.6": { + "type": "package", + "serviceable": true, + "sha512": "sha512-mPLRPf2tql0Af4RcJRVPWiGxhJCbPQFNr74Qq0rDf+QXt8KV/SzYl9/NK604zf0s8Yu3hwelmCsDCjqp5SJoJA==", + "path": "system.reactive/4.1.6", + "hashPath": "system.reactive.4.1.6.nupkg.sha512" + }, + "System.Reflection/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-KMiAFoW7MfJGa9nDFNcfu+FpEdiHpWgTcS2HdMpDvt9saK3y/G4GwprPyzqjFH9NTaGPQeWNHU+iDlDILj96aQ==", + "path": "system.reflection/4.3.0", + "hashPath": "system.reflection.4.3.0.nupkg.sha512" + }, + "System.Reflection.Emit/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-228FG0jLcIwTVJyz8CLFKueVqQK36ANazUManGaJHkO0icjiIypKW7YLWLIWahyIkdh5M7mV2dJepllLyA1SKg==", + "path": "system.reflection.emit/4.3.0", + "hashPath": "system.reflection.emit.4.3.0.nupkg.sha512" + }, + "System.Reflection.Emit.ILGeneration/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-59tBslAk9733NXLrUJrwNZEzbMAcu8k344OYo+wfSVygcgZ9lgBdGIzH/nrg3LYhXceynyvTc8t5/GD4Ri0/ng==", + "path": "system.reflection.emit.ilgeneration/4.3.0", + "hashPath": "system.reflection.emit.ilgeneration.4.3.0.nupkg.sha512" + }, + "System.Reflection.Emit.Lightweight/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-oadVHGSMsTmZsAF864QYN1t1QzZjIcuKU3l2S9cZOwDdDueNTrqq1yRj7koFfIGEnKpt6NjpL3rOzRhs4ryOgA==", + "path": "system.reflection.emit.lightweight/4.3.0", + "hashPath": "system.reflection.emit.lightweight.4.3.0.nupkg.sha512" + }, + "System.Reflection.Extensions/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-rJkrJD3kBI5B712aRu4DpSIiHRtr6QlfZSQsb0hYHrDCZORXCFjQfoipo2LaMUHoT9i1B7j7MnfaEKWDFmFQNQ==", + "path": "system.reflection.extensions/4.3.0", + "hashPath": "system.reflection.extensions.4.3.0.nupkg.sha512" + }, + "System.Reflection.Primitives/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-5RXItQz5As4xN2/YUDxdpsEkMhvw3e6aNveFXUn4Hl/udNTCNhnKp8lT9fnc3MhvGKh1baak5CovpuQUXHAlIA==", + "path": "system.reflection.primitives/4.3.0", + "hashPath": "system.reflection.primitives.4.3.0.nupkg.sha512" + }, + "System.Reflection.TypeExtensions/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-7u6ulLcZbyxB5Gq0nMkQttcdBTx57ibzw+4IOXEfR+sXYQoHvjW5LTLyNr8O22UIMrqYbchJQJnos4eooYzYJA==", + "path": "system.reflection.typeextensions/4.3.0", + "hashPath": "system.reflection.typeextensions.4.3.0.nupkg.sha512" + }, + "System.Resources.ResourceManager/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-/zrcPkkWdZmI4F92gL/TPumP98AVDu/Wxr3CSJGQQ+XN6wbRZcyfSKVoPo17ilb3iOr0cCRqJInGwNMolqhS8A==", + "path": "system.resources.resourcemanager/4.3.0", + "hashPath": "system.resources.resourcemanager.4.3.0.nupkg.sha512" + }, + "System.Runtime/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-JufQi0vPQ0xGnAczR13AUFglDyVYt4Kqnz1AZaiKZ5+GICq0/1MH/mO/eAJHt/mHW1zjKBJd7kV26SrxddAhiw==", + "path": "system.runtime/4.3.0", + "hashPath": "system.runtime.4.3.0.nupkg.sha512" + }, + "System.Runtime.Caching/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-4TmlmvGp4kzZomm7J2HJn6IIx0UUrQyhBDyb5O1XiunZlQImXW+B8b7W/sTPcXhSf9rp5NR5aDtQllwbB5elOQ==", + "path": "system.runtime.caching/8.0.0", + "hashPath": "system.runtime.caching.8.0.0.nupkg.sha512" + }, + "System.Runtime.CompilerServices.Unsafe/6.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg==", + "path": "system.runtime.compilerservices.unsafe/6.0.0", + "hashPath": "system.runtime.compilerservices.unsafe.6.0.0.nupkg.sha512" + }, + "System.Runtime.Extensions/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-guW0uK0fn5fcJJ1tJVXYd7/1h5F+pea1r7FLSOz/f8vPEqbR2ZAknuRDvTQ8PzAilDveOxNjSfr0CHfIQfFk8g==", + "path": "system.runtime.extensions/4.3.0", + "hashPath": "system.runtime.extensions.4.3.0.nupkg.sha512" + }, + "System.Runtime.Handles/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-OKiSUN7DmTWeYb3l51A7EYaeNMnvxwE249YtZz7yooT4gOZhmTjIn48KgSsw2k2lYdLgTKNJw/ZIfSElwDRVgg==", + "path": "system.runtime.handles/4.3.0", + "hashPath": "system.runtime.handles.4.3.0.nupkg.sha512" + }, + "System.Runtime.InteropServices/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-uv1ynXqiMK8mp1GM3jDqPCFN66eJ5w5XNomaK2XD+TuCroNTLFGeZ+WCmBMcBDyTFKou3P6cR6J/QsaqDp7fGQ==", + "path": "system.runtime.interopservices/4.3.0", + "hashPath": "system.runtime.interopservices.4.3.0.nupkg.sha512" + }, + "System.Runtime.InteropServices.WindowsRuntime/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-J4GUi3xZQLUBasNwZnjrffN8i5wpHrBtZoLG+OhRyGo/+YunMRWWtwoMDlUAIdmX0uRfpHIBDSV6zyr3yf00TA==", + "path": "system.runtime.interopservices.windowsruntime/4.3.0", + "hashPath": "system.runtime.interopservices.windowsruntime.4.3.0.nupkg.sha512" + }, + "System.Security.Cryptography.ProtectedData/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-+TUFINV2q2ifyXauQXRwy4CiBhqvDEDZeVJU7qfxya4aRYOKzVBpN+4acx25VcPB9ywUN6C0n8drWl110PhZEg==", + "path": "system.security.cryptography.protecteddata/8.0.0", + "hashPath": "system.security.cryptography.protecteddata.8.0.0.nupkg.sha512" + }, + "System.Text.Encoding/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-BiIg+KWaSDOITze6jGQynxg64naAPtqGHBwDrLaCtixsa5bKiR8dpPOHA7ge3C0JJQizJE+sfkz1wV+BAKAYZw==", + "path": "system.text.encoding/4.3.0", + "hashPath": "system.text.encoding.4.3.0.nupkg.sha512" + }, + "System.Text.Encodings.Web/4.7.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-iTUgB/WtrZ1sWZs84F2hwyQhiRH6QNjQv2DkwrH+WP6RoFga2Q1m3f9/Q7FG8cck8AdHitQkmkXSY8qylcDmuA==", + "path": "system.text.encodings.web/4.7.2", + "hashPath": "system.text.encodings.web.4.7.2.nupkg.sha512" + }, + "System.Text.Json/4.7.2": { + "type": "package", + "serviceable": true, + "sha512": "sha512-TcMd95wcrubm9nHvJEQs70rC0H/8omiSGGpU4FQ/ZA1URIqD4pjmFJh2Mfv1yH1eHgJDWTi2hMDXwTET+zOOyg==", + "path": "system.text.json/4.7.2", + "hashPath": "system.text.json.4.7.2.nupkg.sha512" + }, + "System.Threading/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-VkUS0kOBcUf3Wwm0TSbrevDDZ6BlM+b/HRiapRFWjM5O0NS0LviG0glKmFK+hhPDd1XFeSdU1GmlLhb2CoVpIw==", + "path": "system.threading/4.3.0", + "hashPath": "system.threading.4.3.0.nupkg.sha512" + }, + "System.Threading.Tasks/4.3.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-LbSxKEdOUhVe8BezB/9uOGGppt+nZf6e1VFyw6v3DN6lqitm0OSn2uXMOdtP0M3W4iMcqcivm2J6UgqiwwnXiA==", + "path": "system.threading.tasks/4.3.0", + "hashPath": "system.threading.tasks.4.3.0.nupkg.sha512" + }, + "System.Threading.Tasks.Dataflow/4.9.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-dTS+3D/GtG2/Pvc3E5YzVvAa7aQJgLDlZDIzukMOJjYudVOQOUXEU68y6Zi3Nn/jqIeB5kOCwrGbQFAKHVzXEQ==", + "path": "system.threading.tasks.dataflow/4.9.0", + "hashPath": "system.threading.tasks.dataflow.4.9.0.nupkg.sha512" + }, + "System.Threading.Tasks.Extensions/4.5.4": { + "type": "package", + "serviceable": true, + "sha512": "sha512-zteT+G8xuGu6mS+mzDzYXbzS7rd3K6Fjb9RiZlYlJPam2/hU7JCBZBVEcywNuR+oZ1ncTvc/cq0faRr3P01OVg==", + "path": "system.threading.tasks.extensions/4.5.4", + "hashPath": "system.threading.tasks.extensions.4.5.4.nupkg.sha512" + }, + "WampSharp/23.8.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-khUXgLMNv5KQ9Xzq5HkxGP9kb/5r19UMS7RW8kY+5ua3ev6ZtX1zGUaMUHwTiXVWkb+1wz4B35oHqx/F38sicQ==", + "path": "wampsharp/23.8.1", + "hashPath": "wampsharp.23.8.1.nupkg.sha512" + }, + "WampSharp.Default.Client/23.8.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-RZD8/SOQb/6KOhpxk2Z5IyVh06AJU/v431En2t14VCLD++RU7nSE4fJzNbQTlirbq/tYEVmTiYHILWX9HIEGUg==", + "path": "wampsharp.default.client/23.8.1", + "hashPath": "wampsharp.default.client.23.8.1.nupkg.sha512" + }, + "WampSharp.NewtonsoftJson/23.8.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-4JMyyf5ojLivoZusJ0eTL73p2tDrKR4pS8fy7iiZ4IxNV3D+ZzuVQc8uh6y9qtwXEx9IImrjvRejbphiBw3ERA==", + "path": "wampsharp.newtonsoftjson/23.8.1", + "hashPath": "wampsharp.newtonsoftjson.23.8.1.nupkg.sha512" + }, + "WampSharp.NewtonsoftMessagePack/23.8.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-wD/7AD6ZHyQOMcHuCn69pm4PMRHJL6LAvqAXZuL6/yxP4ASk8qaDf088sL1gjWmxiHSAHFnBsXDSZJzRncDfUA==", + "path": "wampsharp.newtonsoftmessagepack/23.8.1", + "hashPath": "wampsharp.newtonsoftmessagepack.23.8.1.nupkg.sha512" + }, + "WampSharp.WebSockets/23.8.1": { + "type": "package", + "serviceable": true, + "sha512": "sha512-sPdCJhkNS7AzQB62/DeG2EjQGud2VmJ5Hd4l1OOn2NmEqHx5bTyUcUUXaiRc4F4JtgRwiBU1Le3kd5SjpUfZsg==", + "path": "wampsharp.websockets/23.8.1", + "hashPath": "wampsharp.websockets.23.8.1.nupkg.sha512" + }, + "SmartB2B.Optima.Adapter/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "SmartB2B.Sync.Contracts/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "SmartB2B.Sync.Service/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + } + }, + "runtimes": { + "win-x64": [ + "win", + "any", + "base" + ] + } +} \ No newline at end of file diff --git a/release-optima/SmartB2B.Optima.Service.dll b/release-optima/SmartB2B.Optima.Service.dll new file mode 100644 index 0000000..b6d0625 Binary files /dev/null and b/release-optima/SmartB2B.Optima.Service.dll differ diff --git a/release-optima/SmartB2B.Optima.Service.exe b/release-optima/SmartB2B.Optima.Service.exe new file mode 100644 index 0000000..151e7da Binary files /dev/null and b/release-optima/SmartB2B.Optima.Service.exe differ diff --git a/release-optima/SmartB2B.Optima.Service.pdb b/release-optima/SmartB2B.Optima.Service.pdb new file mode 100644 index 0000000..24e6ccd Binary files /dev/null and b/release-optima/SmartB2B.Optima.Service.pdb differ diff --git a/release-optima/SmartB2B.Optima.Service.runtimeconfig.json b/release-optima/SmartB2B.Optima.Service.runtimeconfig.json new file mode 100644 index 0000000..333b515 --- /dev/null +++ b/release-optima/SmartB2B.Optima.Service.runtimeconfig.json @@ -0,0 +1,16 @@ +{ + "runtimeOptions": { + "tfm": "net8.0", + "includedFrameworks": [ + { + "name": "Microsoft.NETCore.App", + "version": "8.0.24" + } + ], + "configProperties": { + "Sentry.Native.IsEnabled": true, + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false + } + } +} \ No newline at end of file diff --git a/release-optima/SmartB2B.Sync.Contracts.dll b/release-optima/SmartB2B.Sync.Contracts.dll new file mode 100644 index 0000000..e8cb390 Binary files /dev/null and b/release-optima/SmartB2B.Sync.Contracts.dll differ diff --git a/release-optima/SmartB2B.Sync.Contracts.pdb b/release-optima/SmartB2B.Sync.Contracts.pdb new file mode 100644 index 0000000..16a3f29 Binary files /dev/null and b/release-optima/SmartB2B.Sync.Contracts.pdb differ diff --git a/release-optima/SmartB2B.Sync.Service.dll b/release-optima/SmartB2B.Sync.Service.dll new file mode 100644 index 0000000..d928549 Binary files /dev/null and b/release-optima/SmartB2B.Sync.Service.dll differ diff --git a/release-optima/SmartB2B.Sync.Service.pdb b/release-optima/SmartB2B.Sync.Service.pdb new file mode 100644 index 0000000..1afdf80 Binary files /dev/null and b/release-optima/SmartB2B.Sync.Service.pdb differ diff --git a/release-optima/System.AppContext.dll b/release-optima/System.AppContext.dll new file mode 100644 index 0000000..2a7c0d7 Binary files /dev/null and b/release-optima/System.AppContext.dll differ diff --git a/release-optima/System.Buffers.dll b/release-optima/System.Buffers.dll new file mode 100644 index 0000000..87a7701 Binary files /dev/null and b/release-optima/System.Buffers.dll differ diff --git a/release-optima/System.ClientModel.dll b/release-optima/System.ClientModel.dll new file mode 100644 index 0000000..00a3380 Binary files /dev/null and b/release-optima/System.ClientModel.dll differ diff --git a/release-optima/System.Collections.Concurrent.dll b/release-optima/System.Collections.Concurrent.dll new file mode 100644 index 0000000..fc91586 Binary files /dev/null and b/release-optima/System.Collections.Concurrent.dll differ diff --git a/release-optima/System.Collections.Immutable.dll b/release-optima/System.Collections.Immutable.dll new file mode 100644 index 0000000..85501d6 Binary files /dev/null and b/release-optima/System.Collections.Immutable.dll differ diff --git a/release-optima/System.Collections.NonGeneric.dll b/release-optima/System.Collections.NonGeneric.dll new file mode 100644 index 0000000..991c85f Binary files /dev/null and b/release-optima/System.Collections.NonGeneric.dll differ diff --git a/release-optima/System.Collections.Specialized.dll b/release-optima/System.Collections.Specialized.dll new file mode 100644 index 0000000..26e21cc Binary files /dev/null and b/release-optima/System.Collections.Specialized.dll differ diff --git a/release-optima/System.Collections.dll b/release-optima/System.Collections.dll new file mode 100644 index 0000000..af3641a Binary files /dev/null and b/release-optima/System.Collections.dll differ diff --git a/release-optima/System.ComponentModel.Annotations.dll b/release-optima/System.ComponentModel.Annotations.dll new file mode 100644 index 0000000..ff7c611 Binary files /dev/null and b/release-optima/System.ComponentModel.Annotations.dll differ diff --git a/release-optima/System.ComponentModel.DataAnnotations.dll b/release-optima/System.ComponentModel.DataAnnotations.dll new file mode 100644 index 0000000..091efb6 Binary files /dev/null and b/release-optima/System.ComponentModel.DataAnnotations.dll differ diff --git a/release-optima/System.ComponentModel.EventBasedAsync.dll b/release-optima/System.ComponentModel.EventBasedAsync.dll new file mode 100644 index 0000000..79e74b0 Binary files /dev/null and b/release-optima/System.ComponentModel.EventBasedAsync.dll differ diff --git a/release-optima/System.ComponentModel.Primitives.dll b/release-optima/System.ComponentModel.Primitives.dll new file mode 100644 index 0000000..dd4b66d Binary files /dev/null and b/release-optima/System.ComponentModel.Primitives.dll differ diff --git a/release-optima/System.ComponentModel.TypeConverter.dll b/release-optima/System.ComponentModel.TypeConverter.dll new file mode 100644 index 0000000..b94cdd8 Binary files /dev/null and b/release-optima/System.ComponentModel.TypeConverter.dll differ diff --git a/release-optima/System.ComponentModel.dll b/release-optima/System.ComponentModel.dll new file mode 100644 index 0000000..76fcd71 Binary files /dev/null and b/release-optima/System.ComponentModel.dll differ diff --git a/release-optima/System.Configuration.ConfigurationManager.dll b/release-optima/System.Configuration.ConfigurationManager.dll new file mode 100644 index 0000000..accdffe Binary files /dev/null and b/release-optima/System.Configuration.ConfigurationManager.dll differ diff --git a/release-optima/System.Configuration.dll b/release-optima/System.Configuration.dll new file mode 100644 index 0000000..72e8a7b Binary files /dev/null and b/release-optima/System.Configuration.dll differ diff --git a/release-optima/System.Console.dll b/release-optima/System.Console.dll new file mode 100644 index 0000000..b691f6b Binary files /dev/null and b/release-optima/System.Console.dll differ diff --git a/release-optima/System.Core.dll b/release-optima/System.Core.dll new file mode 100644 index 0000000..e0834c6 Binary files /dev/null and b/release-optima/System.Core.dll differ diff --git a/release-optima/System.Data.Common.dll b/release-optima/System.Data.Common.dll new file mode 100644 index 0000000..22aea96 Binary files /dev/null and b/release-optima/System.Data.Common.dll differ diff --git a/release-optima/System.Data.DataSetExtensions.dll b/release-optima/System.Data.DataSetExtensions.dll new file mode 100644 index 0000000..bbd427c Binary files /dev/null and b/release-optima/System.Data.DataSetExtensions.dll differ diff --git a/release-optima/System.Data.dll b/release-optima/System.Data.dll new file mode 100644 index 0000000..22aab4e Binary files /dev/null and b/release-optima/System.Data.dll differ diff --git a/release-optima/System.Diagnostics.Contracts.dll b/release-optima/System.Diagnostics.Contracts.dll new file mode 100644 index 0000000..62ef27e Binary files /dev/null and b/release-optima/System.Diagnostics.Contracts.dll differ diff --git a/release-optima/System.Diagnostics.Debug.dll b/release-optima/System.Diagnostics.Debug.dll new file mode 100644 index 0000000..2d7d501 Binary files /dev/null and b/release-optima/System.Diagnostics.Debug.dll differ diff --git a/release-optima/System.Diagnostics.DiagnosticSource.dll b/release-optima/System.Diagnostics.DiagnosticSource.dll new file mode 100644 index 0000000..31ac371 Binary files /dev/null and b/release-optima/System.Diagnostics.DiagnosticSource.dll differ diff --git a/release-optima/System.Diagnostics.EventLog.Messages.dll b/release-optima/System.Diagnostics.EventLog.Messages.dll new file mode 100644 index 0000000..a8d91f3 Binary files /dev/null and b/release-optima/System.Diagnostics.EventLog.Messages.dll differ diff --git a/release-optima/System.Diagnostics.EventLog.dll b/release-optima/System.Diagnostics.EventLog.dll new file mode 100644 index 0000000..33066bd Binary files /dev/null and b/release-optima/System.Diagnostics.EventLog.dll differ diff --git a/release-optima/System.Diagnostics.FileVersionInfo.dll b/release-optima/System.Diagnostics.FileVersionInfo.dll new file mode 100644 index 0000000..5fe0cf2 Binary files /dev/null and b/release-optima/System.Diagnostics.FileVersionInfo.dll differ diff --git a/release-optima/System.Diagnostics.Process.dll b/release-optima/System.Diagnostics.Process.dll new file mode 100644 index 0000000..cfa116f Binary files /dev/null and b/release-optima/System.Diagnostics.Process.dll differ diff --git a/release-optima/System.Diagnostics.StackTrace.dll b/release-optima/System.Diagnostics.StackTrace.dll new file mode 100644 index 0000000..210d912 Binary files /dev/null and b/release-optima/System.Diagnostics.StackTrace.dll differ diff --git a/release-optima/System.Diagnostics.TextWriterTraceListener.dll b/release-optima/System.Diagnostics.TextWriterTraceListener.dll new file mode 100644 index 0000000..10d7b8f Binary files /dev/null and b/release-optima/System.Diagnostics.TextWriterTraceListener.dll differ diff --git a/release-optima/System.Diagnostics.Tools.dll b/release-optima/System.Diagnostics.Tools.dll new file mode 100644 index 0000000..017a5d0 Binary files /dev/null and b/release-optima/System.Diagnostics.Tools.dll differ diff --git a/release-optima/System.Diagnostics.TraceSource.dll b/release-optima/System.Diagnostics.TraceSource.dll new file mode 100644 index 0000000..5a40515 Binary files /dev/null and b/release-optima/System.Diagnostics.TraceSource.dll differ diff --git a/release-optima/System.Diagnostics.Tracing.dll b/release-optima/System.Diagnostics.Tracing.dll new file mode 100644 index 0000000..809baf4 Binary files /dev/null and b/release-optima/System.Diagnostics.Tracing.dll differ diff --git a/release-optima/System.Drawing.Primitives.dll b/release-optima/System.Drawing.Primitives.dll new file mode 100644 index 0000000..ccbffe6 Binary files /dev/null and b/release-optima/System.Drawing.Primitives.dll differ diff --git a/release-optima/System.Drawing.dll b/release-optima/System.Drawing.dll new file mode 100644 index 0000000..78bbd7a Binary files /dev/null and b/release-optima/System.Drawing.dll differ diff --git a/release-optima/System.Dynamic.Runtime.dll b/release-optima/System.Dynamic.Runtime.dll new file mode 100644 index 0000000..282adc8 Binary files /dev/null and b/release-optima/System.Dynamic.Runtime.dll differ diff --git a/release-optima/System.Formats.Asn1.dll b/release-optima/System.Formats.Asn1.dll new file mode 100644 index 0000000..b5ef22a Binary files /dev/null and b/release-optima/System.Formats.Asn1.dll differ diff --git a/release-optima/System.Formats.Tar.dll b/release-optima/System.Formats.Tar.dll new file mode 100644 index 0000000..97402d0 Binary files /dev/null and b/release-optima/System.Formats.Tar.dll differ diff --git a/release-optima/System.Globalization.Calendars.dll b/release-optima/System.Globalization.Calendars.dll new file mode 100644 index 0000000..de979c9 Binary files /dev/null and b/release-optima/System.Globalization.Calendars.dll differ diff --git a/release-optima/System.Globalization.Extensions.dll b/release-optima/System.Globalization.Extensions.dll new file mode 100644 index 0000000..fcb6e6e Binary files /dev/null and b/release-optima/System.Globalization.Extensions.dll differ diff --git a/release-optima/System.Globalization.dll b/release-optima/System.Globalization.dll new file mode 100644 index 0000000..5adf70e Binary files /dev/null and b/release-optima/System.Globalization.dll differ diff --git a/release-optima/System.IO.Compression.Brotli.dll b/release-optima/System.IO.Compression.Brotli.dll new file mode 100644 index 0000000..4ac5695 Binary files /dev/null and b/release-optima/System.IO.Compression.Brotli.dll differ diff --git a/release-optima/System.IO.Compression.FileSystem.dll b/release-optima/System.IO.Compression.FileSystem.dll new file mode 100644 index 0000000..d5341b1 Binary files /dev/null and b/release-optima/System.IO.Compression.FileSystem.dll differ diff --git a/release-optima/System.IO.Compression.Native.dll b/release-optima/System.IO.Compression.Native.dll new file mode 100644 index 0000000..5512995 Binary files /dev/null and b/release-optima/System.IO.Compression.Native.dll differ diff --git a/release-optima/System.IO.Compression.ZipFile.dll b/release-optima/System.IO.Compression.ZipFile.dll new file mode 100644 index 0000000..585bc61 Binary files /dev/null and b/release-optima/System.IO.Compression.ZipFile.dll differ diff --git a/release-optima/System.IO.Compression.dll b/release-optima/System.IO.Compression.dll new file mode 100644 index 0000000..890a4d9 Binary files /dev/null and b/release-optima/System.IO.Compression.dll differ diff --git a/release-optima/System.IO.FileSystem.AccessControl.dll b/release-optima/System.IO.FileSystem.AccessControl.dll new file mode 100644 index 0000000..93392b8 Binary files /dev/null and b/release-optima/System.IO.FileSystem.AccessControl.dll differ diff --git a/release-optima/System.IO.FileSystem.DriveInfo.dll b/release-optima/System.IO.FileSystem.DriveInfo.dll new file mode 100644 index 0000000..b58f06c Binary files /dev/null and b/release-optima/System.IO.FileSystem.DriveInfo.dll differ diff --git a/release-optima/System.IO.FileSystem.Primitives.dll b/release-optima/System.IO.FileSystem.Primitives.dll new file mode 100644 index 0000000..e69c39b Binary files /dev/null and b/release-optima/System.IO.FileSystem.Primitives.dll differ diff --git a/release-optima/System.IO.FileSystem.Watcher.dll b/release-optima/System.IO.FileSystem.Watcher.dll new file mode 100644 index 0000000..d003a79 Binary files /dev/null and b/release-optima/System.IO.FileSystem.Watcher.dll differ diff --git a/release-optima/System.IO.FileSystem.dll b/release-optima/System.IO.FileSystem.dll new file mode 100644 index 0000000..f4cd888 Binary files /dev/null and b/release-optima/System.IO.FileSystem.dll differ diff --git a/release-optima/System.IO.IsolatedStorage.dll b/release-optima/System.IO.IsolatedStorage.dll new file mode 100644 index 0000000..dabed20 Binary files /dev/null and b/release-optima/System.IO.IsolatedStorage.dll differ diff --git a/release-optima/System.IO.MemoryMappedFiles.dll b/release-optima/System.IO.MemoryMappedFiles.dll new file mode 100644 index 0000000..e0c1878 Binary files /dev/null and b/release-optima/System.IO.MemoryMappedFiles.dll differ diff --git a/release-optima/System.IO.Pipes.AccessControl.dll b/release-optima/System.IO.Pipes.AccessControl.dll new file mode 100644 index 0000000..5315695 Binary files /dev/null and b/release-optima/System.IO.Pipes.AccessControl.dll differ diff --git a/release-optima/System.IO.Pipes.dll b/release-optima/System.IO.Pipes.dll new file mode 100644 index 0000000..a799668 Binary files /dev/null and b/release-optima/System.IO.Pipes.dll differ diff --git a/release-optima/System.IO.UnmanagedMemoryStream.dll b/release-optima/System.IO.UnmanagedMemoryStream.dll new file mode 100644 index 0000000..791f4d4 Binary files /dev/null and b/release-optima/System.IO.UnmanagedMemoryStream.dll differ diff --git a/release-optima/System.IO.dll b/release-optima/System.IO.dll new file mode 100644 index 0000000..23eff45 Binary files /dev/null and b/release-optima/System.IO.dll differ diff --git a/release-optima/System.IdentityModel.Tokens.Jwt.dll b/release-optima/System.IdentityModel.Tokens.Jwt.dll new file mode 100644 index 0000000..b99fef3 Binary files /dev/null and b/release-optima/System.IdentityModel.Tokens.Jwt.dll differ diff --git a/release-optima/System.Linq.Expressions.dll b/release-optima/System.Linq.Expressions.dll new file mode 100644 index 0000000..8fa79c4 Binary files /dev/null and b/release-optima/System.Linq.Expressions.dll differ diff --git a/release-optima/System.Linq.Parallel.dll b/release-optima/System.Linq.Parallel.dll new file mode 100644 index 0000000..1e557c0 Binary files /dev/null and b/release-optima/System.Linq.Parallel.dll differ diff --git a/release-optima/System.Linq.Queryable.dll b/release-optima/System.Linq.Queryable.dll new file mode 100644 index 0000000..74ff41f Binary files /dev/null and b/release-optima/System.Linq.Queryable.dll differ diff --git a/release-optima/System.Linq.dll b/release-optima/System.Linq.dll new file mode 100644 index 0000000..5f4ad2d Binary files /dev/null and b/release-optima/System.Linq.dll differ diff --git a/release-optima/System.Memory.Data.dll b/release-optima/System.Memory.Data.dll new file mode 100644 index 0000000..6f2a3e0 Binary files /dev/null and b/release-optima/System.Memory.Data.dll differ diff --git a/release-optima/System.Memory.dll b/release-optima/System.Memory.dll new file mode 100644 index 0000000..69997c4 Binary files /dev/null and b/release-optima/System.Memory.dll differ diff --git a/release-optima/System.Net.Http.Json.dll b/release-optima/System.Net.Http.Json.dll new file mode 100644 index 0000000..fdfbda4 Binary files /dev/null and b/release-optima/System.Net.Http.Json.dll differ diff --git a/release-optima/System.Net.Http.dll b/release-optima/System.Net.Http.dll new file mode 100644 index 0000000..f1e0771 Binary files /dev/null and b/release-optima/System.Net.Http.dll differ diff --git a/release-optima/System.Net.HttpListener.dll b/release-optima/System.Net.HttpListener.dll new file mode 100644 index 0000000..2e4c9d0 Binary files /dev/null and b/release-optima/System.Net.HttpListener.dll differ diff --git a/release-optima/System.Net.Mail.dll b/release-optima/System.Net.Mail.dll new file mode 100644 index 0000000..daa422c Binary files /dev/null and b/release-optima/System.Net.Mail.dll differ diff --git a/release-optima/System.Net.NameResolution.dll b/release-optima/System.Net.NameResolution.dll new file mode 100644 index 0000000..0159422 Binary files /dev/null and b/release-optima/System.Net.NameResolution.dll differ diff --git a/release-optima/System.Net.NetworkInformation.dll b/release-optima/System.Net.NetworkInformation.dll new file mode 100644 index 0000000..752287c Binary files /dev/null and b/release-optima/System.Net.NetworkInformation.dll differ diff --git a/release-optima/System.Net.Ping.dll b/release-optima/System.Net.Ping.dll new file mode 100644 index 0000000..cd6dbf8 Binary files /dev/null and b/release-optima/System.Net.Ping.dll differ diff --git a/release-optima/System.Net.Primitives.dll b/release-optima/System.Net.Primitives.dll new file mode 100644 index 0000000..5781163 Binary files /dev/null and b/release-optima/System.Net.Primitives.dll differ diff --git a/release-optima/System.Net.Quic.dll b/release-optima/System.Net.Quic.dll new file mode 100644 index 0000000..85772de Binary files /dev/null and b/release-optima/System.Net.Quic.dll differ diff --git a/release-optima/System.Net.Requests.dll b/release-optima/System.Net.Requests.dll new file mode 100644 index 0000000..3643521 Binary files /dev/null and b/release-optima/System.Net.Requests.dll differ diff --git a/release-optima/System.Net.Security.dll b/release-optima/System.Net.Security.dll new file mode 100644 index 0000000..b379b31 Binary files /dev/null and b/release-optima/System.Net.Security.dll differ diff --git a/release-optima/System.Net.ServicePoint.dll b/release-optima/System.Net.ServicePoint.dll new file mode 100644 index 0000000..841ec02 Binary files /dev/null and b/release-optima/System.Net.ServicePoint.dll differ diff --git a/release-optima/System.Net.Sockets.dll b/release-optima/System.Net.Sockets.dll new file mode 100644 index 0000000..cadd006 Binary files /dev/null and b/release-optima/System.Net.Sockets.dll differ diff --git a/release-optima/System.Net.WebClient.dll b/release-optima/System.Net.WebClient.dll new file mode 100644 index 0000000..ddb549b Binary files /dev/null and b/release-optima/System.Net.WebClient.dll differ diff --git a/release-optima/System.Net.WebHeaderCollection.dll b/release-optima/System.Net.WebHeaderCollection.dll new file mode 100644 index 0000000..ffdf6e3 Binary files /dev/null and b/release-optima/System.Net.WebHeaderCollection.dll differ diff --git a/release-optima/System.Net.WebProxy.dll b/release-optima/System.Net.WebProxy.dll new file mode 100644 index 0000000..c03d947 Binary files /dev/null and b/release-optima/System.Net.WebProxy.dll differ diff --git a/release-optima/System.Net.WebSockets.Client.dll b/release-optima/System.Net.WebSockets.Client.dll new file mode 100644 index 0000000..d8f5ace Binary files /dev/null and b/release-optima/System.Net.WebSockets.Client.dll differ diff --git a/release-optima/System.Net.WebSockets.dll b/release-optima/System.Net.WebSockets.dll new file mode 100644 index 0000000..5f5f296 Binary files /dev/null and b/release-optima/System.Net.WebSockets.dll differ diff --git a/release-optima/System.Net.dll b/release-optima/System.Net.dll new file mode 100644 index 0000000..3fe5a6e Binary files /dev/null and b/release-optima/System.Net.dll differ diff --git a/release-optima/System.Numerics.Vectors.dll b/release-optima/System.Numerics.Vectors.dll new file mode 100644 index 0000000..cdf9249 Binary files /dev/null and b/release-optima/System.Numerics.Vectors.dll differ diff --git a/release-optima/System.Numerics.dll b/release-optima/System.Numerics.dll new file mode 100644 index 0000000..2b12dd1 Binary files /dev/null and b/release-optima/System.Numerics.dll differ diff --git a/release-optima/System.ObjectModel.dll b/release-optima/System.ObjectModel.dll new file mode 100644 index 0000000..b8563c6 Binary files /dev/null and b/release-optima/System.ObjectModel.dll differ diff --git a/release-optima/System.Private.CoreLib.dll b/release-optima/System.Private.CoreLib.dll new file mode 100644 index 0000000..e405a87 Binary files /dev/null and b/release-optima/System.Private.CoreLib.dll differ diff --git a/release-optima/System.Private.DataContractSerialization.dll b/release-optima/System.Private.DataContractSerialization.dll new file mode 100644 index 0000000..4e401e4 Binary files /dev/null and b/release-optima/System.Private.DataContractSerialization.dll differ diff --git a/release-optima/System.Private.Uri.dll b/release-optima/System.Private.Uri.dll new file mode 100644 index 0000000..11d5d70 Binary files /dev/null and b/release-optima/System.Private.Uri.dll differ diff --git a/release-optima/System.Private.Xml.Linq.dll b/release-optima/System.Private.Xml.Linq.dll new file mode 100644 index 0000000..8d19450 Binary files /dev/null and b/release-optima/System.Private.Xml.Linq.dll differ diff --git a/release-optima/System.Private.Xml.dll b/release-optima/System.Private.Xml.dll new file mode 100644 index 0000000..3b45bf4 Binary files /dev/null and b/release-optima/System.Private.Xml.dll differ diff --git a/release-optima/System.Reactive.dll b/release-optima/System.Reactive.dll new file mode 100644 index 0000000..d2fef33 Binary files /dev/null and b/release-optima/System.Reactive.dll differ diff --git a/release-optima/System.Reflection.DispatchProxy.dll b/release-optima/System.Reflection.DispatchProxy.dll new file mode 100644 index 0000000..7188149 Binary files /dev/null and b/release-optima/System.Reflection.DispatchProxy.dll differ diff --git a/release-optima/System.Reflection.Emit.ILGeneration.dll b/release-optima/System.Reflection.Emit.ILGeneration.dll new file mode 100644 index 0000000..62ac8b0 Binary files /dev/null and b/release-optima/System.Reflection.Emit.ILGeneration.dll differ diff --git a/release-optima/System.Reflection.Emit.Lightweight.dll b/release-optima/System.Reflection.Emit.Lightweight.dll new file mode 100644 index 0000000..e8a7324 Binary files /dev/null and b/release-optima/System.Reflection.Emit.Lightweight.dll differ diff --git a/release-optima/System.Reflection.Emit.dll b/release-optima/System.Reflection.Emit.dll new file mode 100644 index 0000000..9046d28 Binary files /dev/null and b/release-optima/System.Reflection.Emit.dll differ diff --git a/release-optima/System.Reflection.Extensions.dll b/release-optima/System.Reflection.Extensions.dll new file mode 100644 index 0000000..afa9ce9 Binary files /dev/null and b/release-optima/System.Reflection.Extensions.dll differ diff --git a/release-optima/System.Reflection.Metadata.dll b/release-optima/System.Reflection.Metadata.dll new file mode 100644 index 0000000..0daab5d Binary files /dev/null and b/release-optima/System.Reflection.Metadata.dll differ diff --git a/release-optima/System.Reflection.Primitives.dll b/release-optima/System.Reflection.Primitives.dll new file mode 100644 index 0000000..9060bbb Binary files /dev/null and b/release-optima/System.Reflection.Primitives.dll differ diff --git a/release-optima/System.Reflection.TypeExtensions.dll b/release-optima/System.Reflection.TypeExtensions.dll new file mode 100644 index 0000000..9e25ade Binary files /dev/null and b/release-optima/System.Reflection.TypeExtensions.dll differ diff --git a/release-optima/System.Reflection.dll b/release-optima/System.Reflection.dll new file mode 100644 index 0000000..0892ba7 Binary files /dev/null and b/release-optima/System.Reflection.dll differ diff --git a/release-optima/System.Resources.Reader.dll b/release-optima/System.Resources.Reader.dll new file mode 100644 index 0000000..b3bd8ce Binary files /dev/null and b/release-optima/System.Resources.Reader.dll differ diff --git a/release-optima/System.Resources.ResourceManager.dll b/release-optima/System.Resources.ResourceManager.dll new file mode 100644 index 0000000..8a2c2bd Binary files /dev/null and b/release-optima/System.Resources.ResourceManager.dll differ diff --git a/release-optima/System.Resources.Writer.dll b/release-optima/System.Resources.Writer.dll new file mode 100644 index 0000000..6eb95b9 Binary files /dev/null and b/release-optima/System.Resources.Writer.dll differ diff --git a/release-optima/System.Runtime.Caching.dll b/release-optima/System.Runtime.Caching.dll new file mode 100644 index 0000000..38b97a2 Binary files /dev/null and b/release-optima/System.Runtime.Caching.dll differ diff --git a/release-optima/System.Runtime.CompilerServices.Unsafe.dll b/release-optima/System.Runtime.CompilerServices.Unsafe.dll new file mode 100644 index 0000000..1a58b5a Binary files /dev/null and b/release-optima/System.Runtime.CompilerServices.Unsafe.dll differ diff --git a/release-optima/System.Runtime.CompilerServices.VisualC.dll b/release-optima/System.Runtime.CompilerServices.VisualC.dll new file mode 100644 index 0000000..794d40d Binary files /dev/null and b/release-optima/System.Runtime.CompilerServices.VisualC.dll differ diff --git a/release-optima/System.Runtime.Extensions.dll b/release-optima/System.Runtime.Extensions.dll new file mode 100644 index 0000000..85e9712 Binary files /dev/null and b/release-optima/System.Runtime.Extensions.dll differ diff --git a/release-optima/System.Runtime.Handles.dll b/release-optima/System.Runtime.Handles.dll new file mode 100644 index 0000000..fb28bfe Binary files /dev/null and b/release-optima/System.Runtime.Handles.dll differ diff --git a/release-optima/System.Runtime.InteropServices.JavaScript.dll b/release-optima/System.Runtime.InteropServices.JavaScript.dll new file mode 100644 index 0000000..8ba827e Binary files /dev/null and b/release-optima/System.Runtime.InteropServices.JavaScript.dll differ diff --git a/release-optima/System.Runtime.InteropServices.RuntimeInformation.dll b/release-optima/System.Runtime.InteropServices.RuntimeInformation.dll new file mode 100644 index 0000000..63befe9 Binary files /dev/null and b/release-optima/System.Runtime.InteropServices.RuntimeInformation.dll differ diff --git a/release-optima/System.Runtime.InteropServices.WindowsRuntime.dll b/release-optima/System.Runtime.InteropServices.WindowsRuntime.dll new file mode 100644 index 0000000..cc35b34 Binary files /dev/null and b/release-optima/System.Runtime.InteropServices.WindowsRuntime.dll differ diff --git a/release-optima/System.Runtime.InteropServices.dll b/release-optima/System.Runtime.InteropServices.dll new file mode 100644 index 0000000..cdc28e2 Binary files /dev/null and b/release-optima/System.Runtime.InteropServices.dll differ diff --git a/release-optima/System.Runtime.Intrinsics.dll b/release-optima/System.Runtime.Intrinsics.dll new file mode 100644 index 0000000..50195c1 Binary files /dev/null and b/release-optima/System.Runtime.Intrinsics.dll differ diff --git a/release-optima/System.Runtime.Loader.dll b/release-optima/System.Runtime.Loader.dll new file mode 100644 index 0000000..a833ec7 Binary files /dev/null and b/release-optima/System.Runtime.Loader.dll differ diff --git a/release-optima/System.Runtime.Numerics.dll b/release-optima/System.Runtime.Numerics.dll new file mode 100644 index 0000000..0659dbf Binary files /dev/null and b/release-optima/System.Runtime.Numerics.dll differ diff --git a/release-optima/System.Runtime.Serialization.Formatters.dll b/release-optima/System.Runtime.Serialization.Formatters.dll new file mode 100644 index 0000000..97fc9f1 Binary files /dev/null and b/release-optima/System.Runtime.Serialization.Formatters.dll differ diff --git a/release-optima/System.Runtime.Serialization.Json.dll b/release-optima/System.Runtime.Serialization.Json.dll new file mode 100644 index 0000000..5477eb7 Binary files /dev/null and b/release-optima/System.Runtime.Serialization.Json.dll differ diff --git a/release-optima/System.Runtime.Serialization.Primitives.dll b/release-optima/System.Runtime.Serialization.Primitives.dll new file mode 100644 index 0000000..7567dd9 Binary files /dev/null and b/release-optima/System.Runtime.Serialization.Primitives.dll differ diff --git a/release-optima/System.Runtime.Serialization.Xml.dll b/release-optima/System.Runtime.Serialization.Xml.dll new file mode 100644 index 0000000..43f61e4 Binary files /dev/null and b/release-optima/System.Runtime.Serialization.Xml.dll differ diff --git a/release-optima/System.Runtime.Serialization.dll b/release-optima/System.Runtime.Serialization.dll new file mode 100644 index 0000000..96531e4 Binary files /dev/null and b/release-optima/System.Runtime.Serialization.dll differ diff --git a/release-optima/System.Runtime.dll b/release-optima/System.Runtime.dll new file mode 100644 index 0000000..26cb1a3 Binary files /dev/null and b/release-optima/System.Runtime.dll differ diff --git a/release-optima/System.Security.AccessControl.dll b/release-optima/System.Security.AccessControl.dll new file mode 100644 index 0000000..6b17343 Binary files /dev/null and b/release-optima/System.Security.AccessControl.dll differ diff --git a/release-optima/System.Security.Claims.dll b/release-optima/System.Security.Claims.dll new file mode 100644 index 0000000..721b7dc Binary files /dev/null and b/release-optima/System.Security.Claims.dll differ diff --git a/release-optima/System.Security.Cryptography.Algorithms.dll b/release-optima/System.Security.Cryptography.Algorithms.dll new file mode 100644 index 0000000..7198db5 Binary files /dev/null and b/release-optima/System.Security.Cryptography.Algorithms.dll differ diff --git a/release-optima/System.Security.Cryptography.Cng.dll b/release-optima/System.Security.Cryptography.Cng.dll new file mode 100644 index 0000000..749a231 Binary files /dev/null and b/release-optima/System.Security.Cryptography.Cng.dll differ diff --git a/release-optima/System.Security.Cryptography.Csp.dll b/release-optima/System.Security.Cryptography.Csp.dll new file mode 100644 index 0000000..abd1152 Binary files /dev/null and b/release-optima/System.Security.Cryptography.Csp.dll differ diff --git a/release-optima/System.Security.Cryptography.Encoding.dll b/release-optima/System.Security.Cryptography.Encoding.dll new file mode 100644 index 0000000..ce3cdfb Binary files /dev/null and b/release-optima/System.Security.Cryptography.Encoding.dll differ diff --git a/release-optima/System.Security.Cryptography.OpenSsl.dll b/release-optima/System.Security.Cryptography.OpenSsl.dll new file mode 100644 index 0000000..d1dd969 Binary files /dev/null and b/release-optima/System.Security.Cryptography.OpenSsl.dll differ diff --git a/release-optima/System.Security.Cryptography.Primitives.dll b/release-optima/System.Security.Cryptography.Primitives.dll new file mode 100644 index 0000000..55e4897 Binary files /dev/null and b/release-optima/System.Security.Cryptography.Primitives.dll differ diff --git a/release-optima/System.Security.Cryptography.ProtectedData.dll b/release-optima/System.Security.Cryptography.ProtectedData.dll new file mode 100644 index 0000000..40f1b5a Binary files /dev/null and b/release-optima/System.Security.Cryptography.ProtectedData.dll differ diff --git a/release-optima/System.Security.Cryptography.X509Certificates.dll b/release-optima/System.Security.Cryptography.X509Certificates.dll new file mode 100644 index 0000000..086284e Binary files /dev/null and b/release-optima/System.Security.Cryptography.X509Certificates.dll differ diff --git a/release-optima/System.Security.Cryptography.dll b/release-optima/System.Security.Cryptography.dll new file mode 100644 index 0000000..687b75f Binary files /dev/null and b/release-optima/System.Security.Cryptography.dll differ diff --git a/release-optima/System.Security.Principal.Windows.dll b/release-optima/System.Security.Principal.Windows.dll new file mode 100644 index 0000000..227ca59 Binary files /dev/null and b/release-optima/System.Security.Principal.Windows.dll differ diff --git a/release-optima/System.Security.Principal.dll b/release-optima/System.Security.Principal.dll new file mode 100644 index 0000000..4db5cef Binary files /dev/null and b/release-optima/System.Security.Principal.dll differ diff --git a/release-optima/System.Security.SecureString.dll b/release-optima/System.Security.SecureString.dll new file mode 100644 index 0000000..ae50c21 Binary files /dev/null and b/release-optima/System.Security.SecureString.dll differ diff --git a/release-optima/System.Security.dll b/release-optima/System.Security.dll new file mode 100644 index 0000000..ddfa9de Binary files /dev/null and b/release-optima/System.Security.dll differ diff --git a/release-optima/System.ServiceModel.Web.dll b/release-optima/System.ServiceModel.Web.dll new file mode 100644 index 0000000..4d395f8 Binary files /dev/null and b/release-optima/System.ServiceModel.Web.dll differ diff --git a/release-optima/System.ServiceProcess.dll b/release-optima/System.ServiceProcess.dll new file mode 100644 index 0000000..68e9851 Binary files /dev/null and b/release-optima/System.ServiceProcess.dll differ diff --git a/release-optima/System.Text.Encoding.CodePages.dll b/release-optima/System.Text.Encoding.CodePages.dll new file mode 100644 index 0000000..d2357f1 Binary files /dev/null and b/release-optima/System.Text.Encoding.CodePages.dll differ diff --git a/release-optima/System.Text.Encoding.Extensions.dll b/release-optima/System.Text.Encoding.Extensions.dll new file mode 100644 index 0000000..20d2d23 Binary files /dev/null and b/release-optima/System.Text.Encoding.Extensions.dll differ diff --git a/release-optima/System.Text.Encoding.dll b/release-optima/System.Text.Encoding.dll new file mode 100644 index 0000000..47dfd5e Binary files /dev/null and b/release-optima/System.Text.Encoding.dll differ diff --git a/release-optima/System.Text.Encodings.Web.dll b/release-optima/System.Text.Encodings.Web.dll new file mode 100644 index 0000000..a2ca428 Binary files /dev/null and b/release-optima/System.Text.Encodings.Web.dll differ diff --git a/release-optima/System.Text.Json.dll b/release-optima/System.Text.Json.dll new file mode 100644 index 0000000..8bb6aca Binary files /dev/null and b/release-optima/System.Text.Json.dll differ diff --git a/release-optima/System.Text.RegularExpressions.dll b/release-optima/System.Text.RegularExpressions.dll new file mode 100644 index 0000000..af38846 Binary files /dev/null and b/release-optima/System.Text.RegularExpressions.dll differ diff --git a/release-optima/System.Threading.Channels.dll b/release-optima/System.Threading.Channels.dll new file mode 100644 index 0000000..253ab0f Binary files /dev/null and b/release-optima/System.Threading.Channels.dll differ diff --git a/release-optima/System.Threading.Overlapped.dll b/release-optima/System.Threading.Overlapped.dll new file mode 100644 index 0000000..9fd3b3d Binary files /dev/null and b/release-optima/System.Threading.Overlapped.dll differ diff --git a/release-optima/System.Threading.Tasks.Dataflow.dll b/release-optima/System.Threading.Tasks.Dataflow.dll new file mode 100644 index 0000000..ac5a009 Binary files /dev/null and b/release-optima/System.Threading.Tasks.Dataflow.dll differ diff --git a/release-optima/System.Threading.Tasks.Extensions.dll b/release-optima/System.Threading.Tasks.Extensions.dll new file mode 100644 index 0000000..9accac6 Binary files /dev/null and b/release-optima/System.Threading.Tasks.Extensions.dll differ diff --git a/release-optima/System.Threading.Tasks.Parallel.dll b/release-optima/System.Threading.Tasks.Parallel.dll new file mode 100644 index 0000000..cd76a2c Binary files /dev/null and b/release-optima/System.Threading.Tasks.Parallel.dll differ diff --git a/release-optima/System.Threading.Tasks.dll b/release-optima/System.Threading.Tasks.dll new file mode 100644 index 0000000..6637e26 Binary files /dev/null and b/release-optima/System.Threading.Tasks.dll differ diff --git a/release-optima/System.Threading.Thread.dll b/release-optima/System.Threading.Thread.dll new file mode 100644 index 0000000..106c3f1 Binary files /dev/null and b/release-optima/System.Threading.Thread.dll differ diff --git a/release-optima/System.Threading.ThreadPool.dll b/release-optima/System.Threading.ThreadPool.dll new file mode 100644 index 0000000..bc45c91 Binary files /dev/null and b/release-optima/System.Threading.ThreadPool.dll differ diff --git a/release-optima/System.Threading.Timer.dll b/release-optima/System.Threading.Timer.dll new file mode 100644 index 0000000..e2ce89f Binary files /dev/null and b/release-optima/System.Threading.Timer.dll differ diff --git a/release-optima/System.Threading.dll b/release-optima/System.Threading.dll new file mode 100644 index 0000000..3d347e7 Binary files /dev/null and b/release-optima/System.Threading.dll differ diff --git a/release-optima/System.Transactions.Local.dll b/release-optima/System.Transactions.Local.dll new file mode 100644 index 0000000..a4b14f8 Binary files /dev/null and b/release-optima/System.Transactions.Local.dll differ diff --git a/release-optima/System.Transactions.dll b/release-optima/System.Transactions.dll new file mode 100644 index 0000000..32d3a02 Binary files /dev/null and b/release-optima/System.Transactions.dll differ diff --git a/release-optima/System.ValueTuple.dll b/release-optima/System.ValueTuple.dll new file mode 100644 index 0000000..06b5ad4 Binary files /dev/null and b/release-optima/System.ValueTuple.dll differ diff --git a/release-optima/System.Web.HttpUtility.dll b/release-optima/System.Web.HttpUtility.dll new file mode 100644 index 0000000..f55e8dc Binary files /dev/null and b/release-optima/System.Web.HttpUtility.dll differ diff --git a/release-optima/System.Web.dll b/release-optima/System.Web.dll new file mode 100644 index 0000000..1958ad8 Binary files /dev/null and b/release-optima/System.Web.dll differ diff --git a/release-optima/System.Windows.dll b/release-optima/System.Windows.dll new file mode 100644 index 0000000..7243354 Binary files /dev/null and b/release-optima/System.Windows.dll differ diff --git a/release-optima/System.Xml.Linq.dll b/release-optima/System.Xml.Linq.dll new file mode 100644 index 0000000..738169e Binary files /dev/null and b/release-optima/System.Xml.Linq.dll differ diff --git a/release-optima/System.Xml.ReaderWriter.dll b/release-optima/System.Xml.ReaderWriter.dll new file mode 100644 index 0000000..77303b4 Binary files /dev/null and b/release-optima/System.Xml.ReaderWriter.dll differ diff --git a/release-optima/System.Xml.Serialization.dll b/release-optima/System.Xml.Serialization.dll new file mode 100644 index 0000000..f266e92 Binary files /dev/null and b/release-optima/System.Xml.Serialization.dll differ diff --git a/release-optima/System.Xml.XDocument.dll b/release-optima/System.Xml.XDocument.dll new file mode 100644 index 0000000..3c7fc73 Binary files /dev/null and b/release-optima/System.Xml.XDocument.dll differ diff --git a/release-optima/System.Xml.XPath.XDocument.dll b/release-optima/System.Xml.XPath.XDocument.dll new file mode 100644 index 0000000..2a995d9 Binary files /dev/null and b/release-optima/System.Xml.XPath.XDocument.dll differ diff --git a/release-optima/System.Xml.XPath.dll b/release-optima/System.Xml.XPath.dll new file mode 100644 index 0000000..101634f Binary files /dev/null and b/release-optima/System.Xml.XPath.dll differ diff --git a/release-optima/System.Xml.XmlDocument.dll b/release-optima/System.Xml.XmlDocument.dll new file mode 100644 index 0000000..9943ef3 Binary files /dev/null and b/release-optima/System.Xml.XmlDocument.dll differ diff --git a/release-optima/System.Xml.XmlSerializer.dll b/release-optima/System.Xml.XmlSerializer.dll new file mode 100644 index 0000000..cfdb67a Binary files /dev/null and b/release-optima/System.Xml.XmlSerializer.dll differ diff --git a/release-optima/System.Xml.dll b/release-optima/System.Xml.dll new file mode 100644 index 0000000..a946168 Binary files /dev/null and b/release-optima/System.Xml.dll differ diff --git a/release-optima/System.dll b/release-optima/System.dll new file mode 100644 index 0000000..f7a3c25 Binary files /dev/null and b/release-optima/System.dll differ diff --git a/release-optima/WampSharp.Default.Client.dll b/release-optima/WampSharp.Default.Client.dll new file mode 100644 index 0000000..342f23b Binary files /dev/null and b/release-optima/WampSharp.Default.Client.dll differ diff --git a/release-optima/WampSharp.NewtonsoftJson.dll b/release-optima/WampSharp.NewtonsoftJson.dll new file mode 100644 index 0000000..06cef8f Binary files /dev/null and b/release-optima/WampSharp.NewtonsoftJson.dll differ diff --git a/release-optima/WampSharp.NewtonsoftMessagePack.dll b/release-optima/WampSharp.NewtonsoftMessagePack.dll new file mode 100644 index 0000000..62f93cb Binary files /dev/null and b/release-optima/WampSharp.NewtonsoftMessagePack.dll differ diff --git a/release-optima/WampSharp.WebSockets.dll b/release-optima/WampSharp.WebSockets.dll new file mode 100644 index 0000000..3e7c902 Binary files /dev/null and b/release-optima/WampSharp.WebSockets.dll differ diff --git a/release-optima/WampSharp.dll b/release-optima/WampSharp.dll new file mode 100644 index 0000000..b6fe2b4 Binary files /dev/null and b/release-optima/WampSharp.dll differ diff --git a/release-optima/WindowsBase.dll b/release-optima/WindowsBase.dll new file mode 100644 index 0000000..b05d2f8 Binary files /dev/null and b/release-optima/WindowsBase.dll differ diff --git a/release-optima/clretwrc.dll b/release-optima/clretwrc.dll new file mode 100644 index 0000000..0eb8ca5 Binary files /dev/null and b/release-optima/clretwrc.dll differ diff --git a/release-optima/clrgc.dll b/release-optima/clrgc.dll new file mode 100644 index 0000000..a312827 Binary files /dev/null and b/release-optima/clrgc.dll differ diff --git a/release-optima/clrjit.dll b/release-optima/clrjit.dll new file mode 100644 index 0000000..a858654 Binary files /dev/null and b/release-optima/clrjit.dll differ diff --git a/release-optima/config/optima.json.sample b/release-optima/config/optima.json.sample new file mode 100644 index 0000000..408ccf8 --- /dev/null +++ b/release-optima/config/optima.json.sample @@ -0,0 +1,27 @@ +{ + "portal": "demo", + "wamp": { + "serverUrl": "ws://wamp.smartb2b.eu:8080/", + "reconnectDelaySeconds": 10 + }, + "optima": { + "installationPath": "C:\\Program Files (x86)\\Comarch ERP Optima", + "database": "", + "operator": "", + "password": "", + "documentDefinition": "RO", + "defaultWarehouseId": 1, + "saveMode": "Buffer" + }, + "sql": { + "connectionString": "Server=.\\OPTIMA;Database=...;User ID=...;Password=...;TrustServerCertificate=True", + "commandTimeoutSeconds": 30 + }, + "sentry": { + "dsn": null + }, + "diagnostics": { + "logDirectory": "daemon", + "logPrefix": "smartb2bsync-optima" + } +} diff --git a/release-optima/coreclr.dll b/release-optima/coreclr.dll new file mode 100644 index 0000000..a22164d Binary files /dev/null and b/release-optima/coreclr.dll differ diff --git a/release-optima/createdump.exe b/release-optima/createdump.exe new file mode 100644 index 0000000..730ef4f Binary files /dev/null and b/release-optima/createdump.exe differ diff --git a/release-optima/daemon/install.cmd b/release-optima/daemon/install.cmd new file mode 100644 index 0000000..c5a8fb8 --- /dev/null +++ b/release-optima/daemon/install.cmd @@ -0,0 +1,24 @@ +@echo off +setlocal +cd /d "%~dp0" + +if not exist "smartb2bsync-optima.exe" ( + echo Brak smartb2bsync-optima.exe. Najpierw uruchom publish-optima.ps1. + exit /b 1 +) + +if not exist "..\config" mkdir "..\config" +if not exist "..\config\optima.json" ( + if not exist "..\config\optima.json.sample" ( + echo Brak ..\config\optima.json.sample. + exit /b 1 + ) + copy /Y "..\config\optima.json.sample" "..\config\optima.json" >nul + echo Utworzono lokalna konfiguracje ..\config\optima.json. +) + +smartb2bsync-optima.exe install +if errorlevel 1 exit /b %errorlevel% + +smartb2bsync-optima.exe start +exit /b %errorlevel% diff --git a/release-optima/daemon/smartb2bsync-optima.exe b/release-optima/daemon/smartb2bsync-optima.exe new file mode 100644 index 0000000..a27a1bc Binary files /dev/null and b/release-optima/daemon/smartb2bsync-optima.exe differ diff --git a/release-optima/daemon/smartb2bsync-optima.xml b/release-optima/daemon/smartb2bsync-optima.xml new file mode 100644 index 0000000..1062fe5 --- /dev/null +++ b/release-optima/daemon/smartb2bsync-optima.xml @@ -0,0 +1,257 @@ + + + smartb2bsync-optima + SmartB2B SYNC - Comarch ERP Optima + Synchronizuje Comarch ERP Optima z portalem SmartB2B. + %BASE%\..\SmartB2B.Optima.Service.exe + %BASE%\.. + + 45sec + + yyyyMMdd + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/release-optima/daemon/uninstall.cmd b/release-optima/daemon/uninstall.cmd new file mode 100644 index 0000000..f1e1d45 --- /dev/null +++ b/release-optima/daemon/uninstall.cmd @@ -0,0 +1,7 @@ +@echo off +setlocal +cd /d "%~dp0" + +smartb2bsync-optima.exe stop +smartb2bsync-optima.exe uninstall +exit /b %errorlevel% diff --git a/release-optima/de/Microsoft.Data.SqlClient.resources.dll b/release-optima/de/Microsoft.Data.SqlClient.resources.dll new file mode 100644 index 0000000..3b4c5a7 Binary files /dev/null and b/release-optima/de/Microsoft.Data.SqlClient.resources.dll differ diff --git a/release-optima/es/Microsoft.Data.SqlClient.resources.dll b/release-optima/es/Microsoft.Data.SqlClient.resources.dll new file mode 100644 index 0000000..e8b7bb5 Binary files /dev/null and b/release-optima/es/Microsoft.Data.SqlClient.resources.dll differ diff --git a/release-optima/fr/Microsoft.Data.SqlClient.resources.dll b/release-optima/fr/Microsoft.Data.SqlClient.resources.dll new file mode 100644 index 0000000..eae9818 Binary files /dev/null and b/release-optima/fr/Microsoft.Data.SqlClient.resources.dll differ diff --git a/release-optima/hostfxr.dll b/release-optima/hostfxr.dll new file mode 100644 index 0000000..c4ce04e Binary files /dev/null and b/release-optima/hostfxr.dll differ diff --git a/release-optima/hostpolicy.dll b/release-optima/hostpolicy.dll new file mode 100644 index 0000000..53f778a Binary files /dev/null and b/release-optima/hostpolicy.dll differ diff --git a/release-optima/it/Microsoft.Data.SqlClient.resources.dll b/release-optima/it/Microsoft.Data.SqlClient.resources.dll new file mode 100644 index 0000000..c58dbce Binary files /dev/null and b/release-optima/it/Microsoft.Data.SqlClient.resources.dll differ diff --git a/release-optima/ja/Microsoft.Data.SqlClient.resources.dll b/release-optima/ja/Microsoft.Data.SqlClient.resources.dll new file mode 100644 index 0000000..aa9c299 Binary files /dev/null and b/release-optima/ja/Microsoft.Data.SqlClient.resources.dll differ diff --git a/release-optima/ko/Microsoft.Data.SqlClient.resources.dll b/release-optima/ko/Microsoft.Data.SqlClient.resources.dll new file mode 100644 index 0000000..e6c8ce4 Binary files /dev/null and b/release-optima/ko/Microsoft.Data.SqlClient.resources.dll differ diff --git a/release-optima/mscordaccore.dll b/release-optima/mscordaccore.dll new file mode 100644 index 0000000..75db57d Binary files /dev/null and b/release-optima/mscordaccore.dll differ diff --git a/release-optima/mscordaccore_amd64_amd64_8.0.2426.7010.dll b/release-optima/mscordaccore_amd64_amd64_8.0.2426.7010.dll new file mode 100644 index 0000000..75db57d Binary files /dev/null and b/release-optima/mscordaccore_amd64_amd64_8.0.2426.7010.dll differ diff --git a/release-optima/mscordbi.dll b/release-optima/mscordbi.dll new file mode 100644 index 0000000..f7e78d2 Binary files /dev/null and b/release-optima/mscordbi.dll differ diff --git a/release-optima/mscorlib.dll b/release-optima/mscorlib.dll new file mode 100644 index 0000000..faf8dfb Binary files /dev/null and b/release-optima/mscorlib.dll differ diff --git a/release-optima/mscorrc.dll b/release-optima/mscorrc.dll new file mode 100644 index 0000000..f6c4e58 Binary files /dev/null and b/release-optima/mscorrc.dll differ diff --git a/release-optima/msquic.dll b/release-optima/msquic.dll new file mode 100644 index 0000000..2a1350a Binary files /dev/null and b/release-optima/msquic.dll differ diff --git a/release-optima/netstandard.dll b/release-optima/netstandard.dll new file mode 100644 index 0000000..1930fbd Binary files /dev/null and b/release-optima/netstandard.dll differ diff --git a/release-optima/pt-BR/Microsoft.Data.SqlClient.resources.dll b/release-optima/pt-BR/Microsoft.Data.SqlClient.resources.dll new file mode 100644 index 0000000..2c9fb3b Binary files /dev/null and b/release-optima/pt-BR/Microsoft.Data.SqlClient.resources.dll differ diff --git a/release-optima/ru/Microsoft.Data.SqlClient.resources.dll b/release-optima/ru/Microsoft.Data.SqlClient.resources.dll new file mode 100644 index 0000000..dc24913 Binary files /dev/null and b/release-optima/ru/Microsoft.Data.SqlClient.resources.dll differ diff --git a/release-optima/zh-Hans/Microsoft.Data.SqlClient.resources.dll b/release-optima/zh-Hans/Microsoft.Data.SqlClient.resources.dll new file mode 100644 index 0000000..2744bb8 Binary files /dev/null and b/release-optima/zh-Hans/Microsoft.Data.SqlClient.resources.dll differ diff --git a/release-optima/zh-Hant/Microsoft.Data.SqlClient.resources.dll b/release-optima/zh-Hant/Microsoft.Data.SqlClient.resources.dll new file mode 100644 index 0000000..6586061 Binary files /dev/null and b/release-optima/zh-Hant/Microsoft.Data.SqlClient.resources.dll differ diff --git a/release/Microsoft.Extensions.DependencyInjection.Abstractions.dll b/release/Microsoft.Extensions.DependencyInjection.Abstractions.dll deleted file mode 100644 index 81ed3de..0000000 Binary files a/release/Microsoft.Extensions.DependencyInjection.Abstractions.dll and /dev/null differ diff --git a/release/SmartB2B.Enova.Contracts.dll b/release/SmartB2B.Enova.Contracts.dll deleted file mode 100644 index f89ef72..0000000 Binary files a/release/SmartB2B.Enova.Contracts.dll and /dev/null differ diff --git a/release/SmartB2B.Enova.Service.dll b/release/SmartB2B.Enova.Service.dll deleted file mode 100644 index 3165265..0000000 Binary files a/release/SmartB2B.Enova.Service.dll and /dev/null differ diff --git a/release/SmartB2B.Enova.Service.pdb b/release/SmartB2B.Enova.Service.pdb deleted file mode 100644 index 7de2902..0000000 Binary files a/release/SmartB2B.Enova.Service.pdb and /dev/null differ diff --git a/release/adapters/SmartB2B.Enova.Adapter.dll b/release/adapters/SmartB2B.Enova.Adapter.dll deleted file mode 100644 index e96d647..0000000 Binary files a/release/adapters/SmartB2B.Enova.Adapter.dll and /dev/null differ diff --git a/src/SmartB2B.Enova.Adapter/EnovaOrderAdapter.cs b/src/SmartB2B.Enova.Adapter/EnovaOrderAdapter.cs index 5a0e4d7..1b2c0d9 100644 --- a/src/SmartB2B.Enova.Adapter/EnovaOrderAdapter.cs +++ b/src/SmartB2B.Enova.Adapter/EnovaOrderAdapter.cs @@ -1,6 +1,6 @@ using System.Reflection; using Microsoft.Data.SqlClient; -using SmartB2B.Enova.Contracts; +using SmartB2B.Sync.Contracts; using Soneta.Business; using Soneta.Business.App; using Soneta.CRM; @@ -13,15 +13,15 @@ using Soneta.Types; namespace SmartB2B.Enova.Adapter; -public sealed class EnovaOrderAdapter : IEnovaOrderAdapter +public sealed class EnovaOrderAdapter : IErpOrderAdapter { private const string CurrencySymbol = "PLN"; private static readonly object RuntimeLock = new(); private static bool _runtimeLoaded; - private EnovaAdapterConfiguration? _configuration; + private ErpAdapterConfiguration? _configuration; private Database? _database; - public EnovaAdapterInfo Initialize(EnovaAdapterConfiguration configuration) + public ErpAdapterInfo Initialize(ErpAdapterConfiguration configuration) { ValidateConfiguration(configuration); EnsureRuntimeLoaded(); @@ -29,11 +29,48 @@ public sealed class EnovaOrderAdapter : IEnovaOrderAdapter _database = RegisterDatabase(configuration.Connection); _configuration = configuration; - return new EnovaAdapterInfo( + return new ErpAdapterInfo( GetAssemblyVersion(typeof(EnovaOrderAdapter).Assembly), + "enova365", GetAssemblyVersion(typeof(Session).Assembly), - GetAssemblyVersion(typeof(HandelModule).Assembly), - configuration.Connection.DatabaseName); + configuration.Connection.DatabaseName, + ["PLN", "price_netto", "Buffer", "Approved"], + new Dictionary + { + ["Soneta.Business version"] = GetAssemblyVersion(typeof(Session).Assembly), + ["Soneta.Handel version"] = GetAssemblyVersion(typeof(HandelModule).Assembly), + ["Save mode"] = configuration.SaveMode.ToString() + }); + } + + public void CheckConnection() + { + 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."); + + try + { + var sessionState = SessionState.Create(); + using var attachedSessionState = sessionState.Attach(); + using var login = database.Login( + winAuth: false, + user: configuration.Connection.OperatorName, + password: configuration.Connection.Password); + using var session = login.CreateSession(readOnly: true, config: false, name: "SmartB2B Enova Sync check"); + } + catch (Exception exception) + { + throw new ErpOperationException( + "eu.smartb2b.erp.connection_error", + $"Nie udało się zalogować do bazy '{configuration.Connection.DatabaseName}': {exception.Message}", + innerException: exception); + } + } + + public void Dispose() + { } public OrderResult CreateOrder(OrderRequest request) @@ -43,10 +80,18 @@ public sealed class EnovaOrderAdapter : IEnovaOrderAdapter var database = _database ?? throw new InvalidOperationException("Połączenie z bazą Enovy nie zostało zainicjalizowane."); + if (!string.Equals(request.CurrencyIso, CurrencySymbol, StringComparison.OrdinalIgnoreCase)) + { + throw new ErpOperationException( + "eu.smartb2b.erp.currency_not_supported", + $"Waluta '{request.CurrencyIso}' nie jest obsługiwana. Wymagana waluta: {CurrencySymbol}.", + new Dictionary { ["currency_iso"] = request.CurrencyIso }); + } + var errors = OrderValidator.Validate(request); if (errors.Count > 0) { - throw new EnovaOperationException( + throw new ErpOperationException( "eu.smartb2b.erp.invalid_order_lines", string.Join(" | ", errors), new Dictionary { ["errors"] = errors }); @@ -74,13 +119,13 @@ public sealed class EnovaOrderAdapter : IEnovaOrderAdapter return CreateOrderInSession(session, request, configuration.VerboseLogging); } - catch (EnovaOperationException) + catch (ErpOperationException) { throw; } catch (Exception exception) { - throw new EnovaOperationException( + throw new ErpOperationException( "eu.smartb2b.erp.error", $"Nie udało się utworzyć zamówienia w bazie '{configuration.Connection.DatabaseName}': {exception.Message}", new Dictionary { ["message"] = exception.Message }, @@ -100,13 +145,13 @@ public sealed class EnovaOrderAdapter : IEnovaOrderAdapter var warehouses = MagazynyModule.GetInstance(session).Magazyny; var definition = handel.DefDokHandlowych.WgSymbolu[request.DocumentDefinition] - ?? throw new EnovaOperationException( + ?? throw new ErpOperationException( "eu.smartb2b.erp.document_definition_not_found", $"Nie znaleziono definicji dokumentu '{request.DocumentDefinition}'.", new Dictionary { ["documentDefinition"] = request.DocumentDefinition }); Verbose(verboseLogging, $"Enova: znaleziono definicję dokumentu '{definition.Symbol}'."); var customer = crm.Kontrahenci.WgKodu[request.CustomerCode] - ?? throw new EnovaOperationException( + ?? throw new ErpOperationException( "eu.smartb2b.company_not_found", $"Nie znaleziono kontrahenta o kodzie '{request.CustomerCode}'.", new Dictionary { ["companyErpId"] = request.CustomerCode }); @@ -122,7 +167,7 @@ public sealed class EnovaOrderAdapter : IEnovaOrderAdapter if (warehouse is null) { - throw new EnovaOperationException( + throw new ErpOperationException( "eu.smartb2b.erp.warehouse_not_found", string.IsNullOrWhiteSpace(request.WarehouseCode) ? "Nie znaleziono standardowego magazynu firmy." @@ -160,7 +205,7 @@ public sealed class EnovaOrderAdapter : IEnovaOrderAdapter verboseLogging, $"Enova: pozycja {index + 1}/{request.Items.Count}, wyszukiwanie towaru '{line.ProductCode}'."); var product = towary.Towary.WgKodu[line.ProductCode] - ?? throw new EnovaOperationException( + ?? throw new ErpOperationException( "eu.smartb2b.product_not_found", $"Nie znaleziono towaru o kodzie '{line.ProductCode}'.", new Dictionary { ["symbol"] = line.ProductCode }); @@ -168,7 +213,11 @@ public sealed class EnovaOrderAdapter : IEnovaOrderAdapter var position = session.AddRow(new PozycjaDokHandlowego(document)); position.Towar = product; position.Ilosc = new Quantity((double)line.Quantity); - position.Cena = new DoubleCy(line.UnitPrice, CurrencySymbol); + position.Cena = new DoubleCy( + line.UnitPriceNet ?? throw new ErpOperationException( + "eu.smartb2b.erp.invalid_order_lines", + $"lines[{index}].price_netto jest wymagane przez enova365."), + CurrencySymbol); position.UstawRabat(new Percent(line.Discount / 100m), ręcznie: true); Verbose(verboseLogging, $"Enova: dodano pozycję {index + 1}."); } @@ -177,7 +226,7 @@ public sealed class EnovaOrderAdapter : IEnovaOrderAdapter { OrderSaveMode.Buffer => StanDokumentuHandlowego.Bufor, OrderSaveMode.Approved => StanDokumentuHandlowego.Zatwierdzony, - _ => throw new EnovaOperationException( + _ => throw new ErpOperationException( "eu.smartb2b.erp.invalid_order", $"Nieobsługiwany tryb zapisu: {request.SaveMode}.") }; @@ -236,7 +285,7 @@ public sealed class EnovaOrderAdapter : IEnovaOrderAdapter var errors = Loader.GetListOfErrors(); if (errors.Count > 0) { - throw new EnovaOperationException( + throw new ErpOperationException( "eu.smartb2b.erp.runtime_error", $"Loader enova365 zgłosił błędy: {string.Join(" | ", errors)}"); } @@ -245,7 +294,7 @@ public sealed class EnovaOrderAdapter : IEnovaOrderAdapter } } - private static Database RegisterDatabase(EnovaConnectionOptions connection) + private static Database RegisterDatabase(ErpConnectionOptions connection) { var application = BusApplication.Instance; var existing = application[connection.DatabaseName, throwError: false]; @@ -260,7 +309,7 @@ public sealed class EnovaOrderAdapter : IEnovaOrderAdapter return database; } - private static MsSqlDatabase CreateDatabase(EnovaConnectionOptions connection) + private static MsSqlDatabase CreateDatabase(ErpConnectionOptions connection) { var sqlConnection = ParseSqlConnectionString(connection.SqlConnectionString); return new MsSqlDatabase @@ -298,7 +347,7 @@ public sealed class EnovaOrderAdapter : IEnovaOrderAdapter bool IntegratedSecurity, bool TrustServerCertificate); - private static void ValidateConfiguration(EnovaAdapterConfiguration configuration) + private static void ValidateConfiguration(ErpAdapterConfiguration configuration) { var errors = new List(); if (string.IsNullOrWhiteSpace(configuration.Connection.DatabaseName)) @@ -323,7 +372,7 @@ public sealed class EnovaOrderAdapter : IEnovaOrderAdapter if (errors.Count > 0) { - throw new EnovaOperationException( + throw new ErpOperationException( "eu.smartb2b.erp.configuration_error", string.Join(" | ", errors)); } diff --git a/src/SmartB2B.Enova.Adapter/SmartB2B.Enova.Adapter.csproj b/src/SmartB2B.Enova.Adapter/SmartB2B.Enova.Adapter.csproj index 8b94de3..089c735 100644 --- a/src/SmartB2B.Enova.Adapter/SmartB2B.Enova.Adapter.csproj +++ b/src/SmartB2B.Enova.Adapter/SmartB2B.Enova.Adapter.csproj @@ -6,7 +6,7 @@ true - + diff --git a/src/SmartB2B.Enova.Service/Configuration/ServiceSettings.cs b/src/SmartB2B.Enova.Service/Configuration/ServiceSettings.cs index 2fdbea2..9eeb337 100644 --- a/src/SmartB2B.Enova.Service/Configuration/ServiceSettings.cs +++ b/src/SmartB2B.Enova.Service/Configuration/ServiceSettings.cs @@ -1,6 +1,7 @@ using System.Text.Json; using System.Text.Json.Serialization; -using SmartB2B.Enova.Contracts; +using SmartB2B.Sync.Contracts; +using SmartB2B.Sync.Service; namespace SmartB2B.Enova.Service.Configuration; @@ -53,11 +54,11 @@ public sealed class ServiceSettings var installationPath = Path.GetFullPath( Environment.ExpandEnvironmentVariables(Enova.InstallationPath)); - EnovaAdapterConfiguration? enovaConfiguration = null; + ErpAdapterConfiguration? enovaConfiguration = null; if (!string.IsNullOrWhiteSpace(Enova.Operator) && Enova.Password is not null) { - enovaConfiguration = new EnovaAdapterConfiguration( - new EnovaConnectionOptions( + enovaConfiguration = new ErpAdapterConfiguration( + new ErpConnectionOptions( Enova.Database, Enova.Operator, Enova.Password, @@ -158,13 +159,13 @@ public sealed class DiagnosticsSettings public sealed record RuntimeSettings( string EnovaInstallationPath, - EnovaAdapterConfiguration? EnovaConfiguration, + ErpAdapterConfiguration? EnovaConfiguration, string SqlConnectionString, int SqlCommandTimeoutSeconds, string LogDirectory, string LogPrefix); -public sealed class ConfigurationException : Exception +public sealed class ConfigurationException : ServiceConfigurationException { public ConfigurationException(string message, Exception? innerException = null) : base(message, innerException) diff --git a/src/SmartB2B.Enova.Service/Program.cs b/src/SmartB2B.Enova.Service/Program.cs index 5084133..231300d 100644 --- a/src/SmartB2B.Enova.Service/Program.cs +++ b/src/SmartB2B.Enova.Service/Program.cs @@ -1,13 +1,9 @@ -using SmartB2B.Enova.Contracts; using SmartB2B.Enova.Service.Configuration; -using SmartB2B.Enova.Service.Diagnostics; -using SmartB2B.Enova.Service.Orders; -using SmartB2B.Enova.Service.Rpc; using SmartB2B.Enova.Service.Runtime; -using SmartB2B.Enova.Service.Sql; -using Sentry; -using Sentry.Infrastructure; -using WampSharp.V2.Rpc; +using SmartB2B.Sync.Contracts; +using SmartB2B.Sync.Service; +using SmartB2B.Sync.Service.Diagnostics; +using SmartB2B.Sync.Service.Sql; namespace SmartB2B.Enova.Service; @@ -16,6 +12,7 @@ internal static class Program public static async Task Main(string[] args) { IDisposable? sentry = null; + IErpOrderAdapter? adapter = null; var cancellation = new CancellationTokenSource(); Console.CancelKeyPress += (_, eventArgs) => { @@ -26,79 +23,72 @@ internal static class Program try { - var commandLine = CommandLineOptions.Parse(args); + var commandLine = ServiceCommandLine.Parse(args, "enova.json"); ConsoleLogger.Configure(commandLine.VerboseLogging); - ConsoleLogger.Verbose( - $"Włączono szczegółowe logowanie; konfiguracja: '{commandLine.ConfigurationPath}'."); var settings = ServiceSettings.Load(commandLine.ConfigurationPath); - ConsoleLogger.Verbose("Wczytano i zweryfikowano konfigurację usługi."); - sentry = InitializeSentry(settings, commandLine.ConfigurationPath, commandLine.VerboseLogging); var runtime = settings.ResolveRuntimeSettings(commandLine.VerboseLogging); + var serviceVersion = typeof(Program).Assembly.GetName().Version?.ToString(3) ?? "unknown"; + sentry = SentryBootstrap.Initialize( + settings.Sentry.Dsn, + settings.Portal, + "enova365", + serviceVersion, + commandLine.ConfigurationPath, + commandLine.VerboseLogging); - using var adapterLoader = new EnovaAdapterLoader(runtime.EnovaInstallationPath); - var adapter = adapterLoader.Load(); - EnovaAdapterInfo? adapterInfo = null; + using var loader = new EnovaAdapterLoader(runtime.EnovaInstallationPath); + adapter = loader.Load(); + ErpAdapterInfo? adapterInfo = null; if (runtime.EnovaConfiguration is not null) { adapterInfo = adapter.Initialize(runtime.EnovaConfiguration); - Console.WriteLine( - $"Załadowano Enovę {adapterInfo.SonetaBusinessVersion} z '{runtime.EnovaInstallationPath}'."); + $"Załadowano {adapterInfo.ErpName} {adapterInfo.ErpVersion} z '{runtime.EnovaInstallationPath}'."); Console.WriteLine($"Baza: {adapterInfo.DatabaseName}; portal WAMP: {settings.Portal}."); } else { - Console.WriteLine( - "Nie podano enova.operator lub enova.password; endpoint eu.smartb2b.place_order jest wyłączony."); - Console.WriteLine($"Portal WAMP: {settings.Portal}."); + Console.WriteLine("Nie podano enova.operator lub enova.password; endpoint eu.smartb2b.place_order jest wyłączony."); } - _ = new System.Data.Common.DbConnectionStringBuilder - { - ConnectionString = runtime.SqlConnectionString - }; - var sql = new SqlRawHandler( - runtime.SqlConnectionString, - runtime.SqlCommandTimeoutSeconds); - if (commandLine.CheckConfigurationOnly) { + var sql = new SqlRawHandler(runtime.SqlConnectionString, runtime.SqlCommandTimeoutSeconds); + await sql.CheckConnectionAsync(cancellation.Token).ConfigureAwait(false); + if (runtime.EnovaConfiguration is not null) + { + adapter.CheckConnection(); + } + Console.WriteLine(runtime.EnovaConfiguration is null - ? "Konfiguracja jest poprawna; endpoint place_order pozostaje wyłączony." - : "Konfiguracja i adapter Enovy są poprawne."); + ? "Konfiguracja i połączenie SQL są poprawne; place_order pozostaje wyłączony." + : "Konfiguracja, połączenie SQL i adapter Enovy są poprawne."); return 0; } - var diagnostics = new DiagnosticsHandler( - adapterInfo, + var options = new SyncServiceOptions( + "SmartB2B Enova Sync", + serviceVersion, + "Enova path", runtime.EnovaInstallationPath, + settings.Portal, + settings.Wamp.ServerUrl, + settings.Wamp.ReconnectDelaySeconds, + runtime.SqlConnectionString, + runtime.SqlCommandTimeoutSeconds, runtime.LogDirectory, runtime.LogPrefix); - - var operations = new List(); - if (runtime.EnovaConfiguration is not null) - { - var orders = new PlaceOrderHandler(adapter, runtime.EnovaConfiguration); - operations.Add(new DelegateRpcOperation("eu.smartb2b.place_order", orders.HandleAsync)); - } - - operations.Add(new DelegateRpcOperation("eu.smartb2b.sql_raw", sql.HandleAsync)); - operations.Add(new DelegateRpcOperation("eu.smartb2b.sync.get_version", diagnostics.GetVersionAsync)); - operations.Add(new DelegateRpcOperation("eu.smartb2b.sync.get_info", diagnostics.GetInfoAsync)); - operations.Add(new DelegateRpcOperation("eu.smartb2b.sync.get_log", diagnostics.GetLogAsync)); - operations.Add(new DelegateRpcOperation("eu.smartb2b.sync.get_error_log", diagnostics.GetErrorLogAsync)); - - var wampClient = new WampServiceClient( - settings.Wamp.ServerUrl, - settings.Portal, - TimeSpan.FromSeconds(settings.Wamp.ReconnectDelaySeconds), - operations); - - await wampClient.RunAsync(cancellation.Token).ConfigureAwait(false); + await SyncServiceRunner.RunAsync( + options, + runtime.EnovaConfiguration is null ? null : adapter, + runtime.EnovaConfiguration, + adapterInfo, + cancellation.Token) + .ConfigureAwait(false); Console.WriteLine("SmartB2B Enova Sync zatrzymany."); return 0; } - catch (ConfigurationException exception) + catch (ServiceConfigurationException exception) { Console.Error.WriteLine($"Błąd konfiguracji: {exception.Message}"); return 2; @@ -111,95 +101,8 @@ internal static class Program } finally { + adapter?.Dispose(); sentry?.Dispose(); } } - - private static IDisposable? InitializeSentry( - ServiceSettings settings, - string configurationPath, - bool verboseLogging) - { - if (string.IsNullOrWhiteSpace(settings.Sentry.Dsn)) - { - Console.WriteLine( - $"Sentry wyłączone: brak parametru sentry.dsn w używanym pliku '{configurationPath}'."); - return null; - } - - var sentry = SentrySdk.Init(options => - { - options.Dsn = settings.Sentry.Dsn; - options.IsGlobalModeEnabled = true; - options.Release = typeof(Program).Assembly.GetName().Version?.ToString(); - // Diagnostyka na poziomie Error pozostaje aktywna także bez /verbose, - // aby problemy transportu Sentry nie znikały bez śladu w usłudze Windows. - options.DiagnosticLevel = verboseLogging ? SentryLevel.Debug : SentryLevel.Error; - options.DiagnosticLogger = new ConsoleDiagnosticLogger(options.DiagnosticLevel); - options.ShutdownTimeout = TimeSpan.FromSeconds(5); - }); - - SentrySdk.ConfigureScope(scope => scope.SetTag("portal", settings.Portal)); - Console.WriteLine($"Raportowanie błędów do Sentry włączone; cel: {DescribeSentryTarget(settings.Sentry.Dsn)}."); - return sentry; - } - - private static string DescribeSentryTarget(string dsn) - { - if (!Uri.TryCreate(dsn, UriKind.Absolute, out var uri)) - { - return "niepoprawny DSN"; - } - - var port = uri.IsDefaultPort ? string.Empty : $":{uri.Port}"; - var project = uri.AbsolutePath.Trim('/').Split('/').LastOrDefault() ?? "?"; - return $"{uri.Scheme}://{uri.Host}{port}, projekt {project}"; - } -} - -public sealed record CommandLineOptions( - string ConfigurationPath, - bool CheckConfigurationOnly, - bool VerboseLogging) -{ - public static CommandLineOptions Parse(string[] args) - { - var path = Path.Combine(AppContext.BaseDirectory, "config", "enova.json"); - var checkOnly = false; - var verbose = false; - - for (var index = 0; index < args.Length; index++) - { - switch (args[index]) - { - case "--config": - if (++index >= args.Length || string.IsNullOrWhiteSpace(args[index])) - { - throw new ConfigurationException("Argument --config wymaga ścieżki."); - } - - path = Path.GetFullPath(args[index]); - break; - case "--check-config": - checkOnly = true; - break; - case "/debug": - case "/verbose": - case "--debug": - case "--verbose": - verbose = true; - break; - case "/nodebug": - case "/noverbose": - case "--no-debug": - case "--no-verbose": - verbose = false; - break; - default: - throw new ConfigurationException($"Nieznany argument: {args[index]}"); - } - } - - return new CommandLineOptions(path, checkOnly, verbose); - } } diff --git a/src/SmartB2B.Enova.Service/Runtime/EnovaAdapterLoader.cs b/src/SmartB2B.Enova.Service/Runtime/EnovaAdapterLoader.cs index 4e48e6b..fd39cd4 100644 --- a/src/SmartB2B.Enova.Service/Runtime/EnovaAdapterLoader.cs +++ b/src/SmartB2B.Enova.Service/Runtime/EnovaAdapterLoader.cs @@ -1,6 +1,6 @@ using System.Reflection; using System.Runtime.Loader; -using SmartB2B.Enova.Contracts; +using SmartB2B.Sync.Contracts; namespace SmartB2B.Enova.Service.Runtime; @@ -37,19 +37,19 @@ public sealed class EnovaAdapterLoader : IDisposable } } - public IEnovaOrderAdapter Load() + public IErpOrderAdapter Load() { var assembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(_adapterPath); var adapterType = assembly.GetExportedTypes().SingleOrDefault(type => - !type.IsAbstract && typeof(IEnovaOrderAdapter).IsAssignableFrom(type)); + !type.IsAbstract && typeof(IErpOrderAdapter).IsAssignableFrom(type)); if (adapterType is null) { throw new InvalidOperationException( - $"W module '{_adapterPath}' nie znaleziono implementacji {nameof(IEnovaOrderAdapter)}."); + $"W module '{_adapterPath}' nie znaleziono implementacji {nameof(IErpOrderAdapter)}."); } - return (IEnovaOrderAdapter)(Activator.CreateInstance(adapterType) + return (IErpOrderAdapter)(Activator.CreateInstance(adapterType) ?? throw new InvalidOperationException($"Nie można utworzyć adaptera '{adapterType.FullName}'.")); } diff --git a/src/SmartB2B.Enova.Service/SmartB2B.Enova.Service.csproj b/src/SmartB2B.Enova.Service/SmartB2B.Enova.Service.csproj index 40f814e..ed084c3 100644 --- a/src/SmartB2B.Enova.Service/SmartB2B.Enova.Service.csproj +++ b/src/SmartB2B.Enova.Service/SmartB2B.Enova.Service.csproj @@ -8,14 +8,8 @@ 1.0.0 - - - - - - - - + + diff --git a/src/SmartB2B.Optima.Adapter/IOptimaComFacade.cs b/src/SmartB2B.Optima.Adapter/IOptimaComFacade.cs new file mode 100644 index 0000000..8b60575 --- /dev/null +++ b/src/SmartB2B.Optima.Adapter/IOptimaComFacade.cs @@ -0,0 +1,17 @@ +using SmartB2B.Sync.Contracts; + +namespace SmartB2B.Optima.Adapter; + +public sealed record OptimaRuntimeInfo( + string ErpVersion, + string ComProgId, + string ProcessArchitecture); + +public interface IOptimaComFacade +{ + OptimaRuntimeInfo InspectRuntime(string installationPath); + + void CheckConnection(ErpAdapterConfiguration configuration); + + OrderResult CreateOrder(ErpAdapterConfiguration configuration, OrderRequest request); +} diff --git a/src/SmartB2B.Optima.Adapter/LateBoundOptimaComFacade.cs b/src/SmartB2B.Optima.Adapter/LateBoundOptimaComFacade.cs new file mode 100644 index 0000000..97826fc --- /dev/null +++ b/src/SmartB2B.Optima.Adapter/LateBoundOptimaComFacade.cs @@ -0,0 +1,343 @@ +using System.Diagnostics; +using System.Runtime.InteropServices; +using SmartB2B.Sync.Contracts; + +namespace SmartB2B.Optima.Adapter; + +internal sealed class LateBoundOptimaComFacade : IOptimaComFacade +{ + private const string ApplicationProgId = "CDNBase.Application"; + + public OptimaRuntimeInfo InspectRuntime(string installationPath) + { + ValidateRuntime(installationPath); + AddInstallationPathToEnvironment(installationPath); + var executable = Path.Combine(installationPath, "Comarch OPT!MA.exe"); + var version = FileVersionInfo.GetVersionInfo(executable).FileVersion ?? "unknown"; + return new OptimaRuntimeInfo( + version, + ApplicationProgId, + Environment.Is64BitProcess ? "x64" : "x86"); + } + + public void CheckConnection(ErpAdapterConfiguration configuration) => + RunWithSession(configuration, _ => true); + + public OrderResult CreateOrder(ErpAdapterConfiguration configuration, OrderRequest request) => + RunWithSession( + configuration, + session => CreateOrderInSession(session, request, configuration.VerboseLogging)); + + private static T RunWithSession(ErpAdapterConfiguration configuration, Func action) + { + object? application = null; + object? login = null; + object? session = null; + var locked = false; + try + { + var applicationType = Type.GetTypeFromProgID(ApplicationProgId, throwOnError: true) + ?? throw new InvalidOperationException($"Nie znaleziono COM {ApplicationProgId}."); + application = Activator.CreateInstance(applicationType) + ?? throw new InvalidOperationException($"Nie można utworzyć COM {ApplicationProgId}."); + dynamic app = application; + app.LockApp(1); + locked = true; + login = app.Login( + configuration.Connection.OperatorName, + configuration.Connection.Password, + configuration.Connection.DatabaseName, + 0, 0, 0, 0, 0, null, + 0, 0, 0, 0, 0, 0, 0, 0, + null, null, null, + 0); + session = ((dynamic)login).CreateSession(); + return action(session); + } + catch (ErpOperationException) + { + throw; + } + catch (COMException exception) + { + throw new ErpOperationException( + "eu.smartb2b.erp.com_error", + "Komunikacja z Comarch ERP Optima nie powiodła się. Szczegóły zapisano w logu diagnostycznym.", + innerException: exception); + } + catch (Exception exception) + { + throw new ErpOperationException( + "eu.smartb2b.erp.error", + "Nie udało się wykonać operacji w Comarch ERP Optima. Szczegóły zapisano w logu diagnostycznym.", + innerException: exception); + } + finally + { + ReleaseComObject(session); + ReleaseComObject(login); + if (locked && application is not null) + { + try { ((dynamic)application).UnlockApp(); } catch { } + } + + ReleaseComObject(application); + } + } + + private static OrderResult CreateOrderInSession(object session, OrderRequest request, bool verboseLogging) + { + object? documents = null; + object? document = null; + object? definition = null; + object? customer = null; + object? warehouse = null; + object? currency = null; + object? elements = null; + try + { + dynamic comSession = session; + definition = FindRequired( + comSession, + "CDN.DefinicjeDokumentow", + $"DDf_Symbol='{EscapeFilter(request.DocumentDefinition)}'", + "eu.smartb2b.erp.document_definition_not_found", + $"Nie znaleziono definicji dokumentu '{request.DocumentDefinition}'."); + + if (!int.TryParse(request.CustomerCode, out var customerId) || customerId <= 0) + { + throw new ErpOperationException( + "eu.smartb2b.company_not_found", + $"companyErpId '{request.CustomerCode}' nie jest poprawnym identyfikatorem Knt_KntId."); + } + + customer = FindRequired( + comSession, + "CDN.Kontrahenci", + $"Knt_KntId={customerId}", + "eu.smartb2b.company_not_found", + $"Nie znaleziono kontrahenta o ID '{customerId}'."); + + if (!int.TryParse(request.WarehouseCode, out var warehouseId) || warehouseId <= 0) + { + throw new ErpOperationException( + "eu.smartb2b.erp.warehouse_not_found", + $"warehouseErpId '{request.WarehouseCode}' nie jest poprawnym identyfikatorem magazynu."); + } + + warehouse = FindRequired( + comSession, + "CDN.Magazyny", + $"Mag_MagId={warehouseId}", + "eu.smartb2b.erp.warehouse_not_found", + $"Nie znaleziono magazynu o ID '{warehouseId}'."); + currency = FindRequired( + comSession, + "CDN.Waluty", + $"WNa_Symbol='{EscapeFilter(request.CurrencyIso)}'", + "eu.smartb2b.erp.currency_not_found", + $"Nie znaleziono waluty '{request.CurrencyIso}'."); + + documents = comSession.CreateObject("CDN.DokumentyHaMag"); + document = ((dynamic)documents).AddNew(); + dynamic doc = document; + dynamic def = definition; + doc.Rodzaj = def.Klasa * 1000; + doc.TypDokumentu = def.Klasa; + doc.Podmiot = customer; + doc.Bufor = request.SaveMode == OrderSaveMode.Buffer ? 1 : 0; + doc.MagazynZrodlowyID = warehouseId; + doc.NumerObcy = request.CustomerReference?.Trim() ?? string.Empty; + doc.Uwagi = request.Notes?.Trim() ?? string.Empty; + doc.WalutaSymbol = request.CurrencyIso; + doc.Export = 0; + elements = doc.Elementy; + + var calculationMode = Convert.ToInt32(doc.TypNB); + var prices = request.Items.Select((line, index) => + OptimaOrderAdapter.SelectUnitPrice(calculationMode, line, index)).ToArray(); + for (var index = 0; index < request.Items.Count; index++) + { + var line = request.Items[index]; + object? product = null; + object? position = null; + try + { + product = FindRequired( + comSession, + "CDN.Towary", + $"Twr_Kod='{EscapeFilter(line.ProductCode)}'", + "eu.smartb2b.product_not_found", + $"Nie znaleziono towaru o kodzie '{line.ProductCode}'."); + position = ((dynamic)elements).AddNew(); + dynamic item = position; + item.Towar = product; + item.Ilosc = Convert.ToDouble(line.Quantity); + item.Cena0 = prices[index]; + item.Rabat = Convert.ToDouble(line.Discount); + } + finally + { + ReleaseComObject(position); + ReleaseComObject(product); + } + } + + Verbose(verboseLogging, "Optima: zapis dokumentu przez session.Save()."); + comSession.Save(); + var net = Convert.ToDecimal(doc.RazemNettoWal); + var gross = Convert.ToDecimal(doc.RazemBruttoWal); + return new OrderResult( + Convert.ToInt32(doc.ID), + Convert.ToString(doc.NumerPelny) ?? string.Empty, + request.SaveMode, + request.CustomerCode, + warehouseId.ToString(), + request.CustomerReference, + request.Items.Count, + net, + gross - net, + gross, + request.Items.Any(line => line.Discount > 0)); + } + finally + { + ReleaseComObject(elements); + ReleaseComObject(document); + ReleaseComObject(documents); + ReleaseComObject(currency); + ReleaseComObject(warehouse); + ReleaseComObject(customer); + ReleaseComObject(definition); + } + } + + private static object FindRequired( + dynamic session, + string collectionName, + string filter, + string errorUri, + string errorMessage) + { + object? collection = null; + try + { + collection = session.CreateObject(collectionName); + var value = ((dynamic)collection).Item(filter); + return value ?? throw new ErpOperationException(errorUri, errorMessage); + } + catch (ErpOperationException) + { + throw; + } + catch (Exception exception) + { + throw new ErpOperationException(errorUri, errorMessage, innerException: exception); + } + finally + { + ReleaseComObject(collection); + } + } + + private static void ValidateRuntime(string installationPath) + { + if (!OperatingSystem.IsWindows()) + { + throw new ErpOperationException("eu.smartb2b.erp.runtime_error", "Adapter Optimy wymaga systemu Windows."); + } + + if (!Directory.Exists(installationPath)) + { + throw new ErpOperationException( + "eu.smartb2b.erp.runtime_error", + $"Nie znaleziono katalogu instalacji Optimy: {installationPath}"); + } + + var executable = Path.Combine(installationPath, "Comarch OPT!MA.exe"); + if (!File.Exists(executable)) + { + throw new ErpOperationException( + "eu.smartb2b.erp.runtime_error", + $"Nie znaleziono pliku Optimy: {executable}"); + } + + var comServer = Path.Combine(installationPath, "op_base.dll"); + if (!File.Exists(comServer)) + { + throw new ErpOperationException( + "eu.smartb2b.erp.runtime_error", + $"Nie znaleziono biblioteki COM Optimy: {comServer}"); + } + + var requiredArchitecture = ReadPeArchitecture(comServer); + var processArchitecture = Environment.Is64BitProcess ? "x64" : "x86"; + if (!string.Equals(requiredArchitecture, processArchitecture, StringComparison.Ordinal)) + { + throw new ErpOperationException( + "eu.smartb2b.erp.runtime_error", + $"Biblioteka COM Optimy wymaga procesu {requiredArchitecture}, a usługa działa jako {processArchitecture}."); + } + + if (Type.GetTypeFromProgID(ApplicationProgId, throwOnError: false) is null) + { + throw new ErpOperationException( + "eu.smartb2b.erp.runtime_error", + $"Komponent COM {ApplicationProgId} nie jest zarejestrowany dla procesu {processArchitecture}."); + } + } + + private static string ReadPeArchitecture(string path) + { + try + { + using var stream = File.OpenRead(path); + using var reader = new BinaryReader(stream); + stream.Position = 0x3c; + var peOffset = reader.ReadInt32(); + stream.Position = peOffset; + if (reader.ReadUInt32() != 0x00004550) + { + throw new InvalidDataException("Brak sygnatury PE."); + } + + return reader.ReadUInt16() switch + { + 0x014c => "x86", + 0x8664 => "x64", + var machine => throw new InvalidDataException($"Nieobsługiwana architektura PE 0x{machine:X4}.") + }; + } + catch (Exception exception) when (exception is IOException or UnauthorizedAccessException or InvalidDataException) + { + throw new ErpOperationException( + "eu.smartb2b.erp.runtime_error", + $"Nie można ustalić architektury biblioteki COM Optimy '{path}': {exception.Message}", + innerException: exception); + } + } + + private static void AddInstallationPathToEnvironment(string installationPath) + { + var currentPath = Environment.GetEnvironmentVariable("PATH") ?? string.Empty; + if (!currentPath.Split(Path.PathSeparator).Contains(installationPath, StringComparer.OrdinalIgnoreCase)) + { + Environment.SetEnvironmentVariable("PATH", installationPath + Path.PathSeparator + currentPath); + } + } + + private static string EscapeFilter(string value) => value.Trim().Replace("'", "''", StringComparison.Ordinal); + + private static void ReleaseComObject(object? value) + { + if (value is not null && Marshal.IsComObject(value)) + { + try { Marshal.FinalReleaseComObject(value); } catch { } + } + } + + private static void Verbose(bool enabled, string message) + { + if (enabled) Console.WriteLine($"[verbose] {message}"); + } +} diff --git a/src/SmartB2B.Optima.Adapter/OptimaOrderAdapter.cs b/src/SmartB2B.Optima.Adapter/OptimaOrderAdapter.cs new file mode 100644 index 0000000..b9112b5 --- /dev/null +++ b/src/SmartB2B.Optima.Adapter/OptimaOrderAdapter.cs @@ -0,0 +1,124 @@ +using System.Reflection; +using SmartB2B.Sync.Contracts; + +namespace SmartB2B.Optima.Adapter; + +public sealed class OptimaOrderAdapter : IErpOrderAdapter +{ + private readonly string _installationPath; + private readonly IOptimaComFacade _comFacade; + private ErpAdapterConfiguration? _configuration; + private StaWorker? _worker; + private bool _disposed; + + public OptimaOrderAdapter(string installationPath) + : this(installationPath, new LateBoundOptimaComFacade()) + { + } + + public OptimaOrderAdapter(string installationPath, IOptimaComFacade comFacade) + { + ArgumentNullException.ThrowIfNull(comFacade); + _installationPath = Path.GetFullPath(installationPath); + _comFacade = comFacade; + } + + public ErpAdapterInfo Initialize(ErpAdapterConfiguration configuration) + { + ObjectDisposedException.ThrowIf(_disposed, this); + if (_worker is not null) + { + throw new InvalidOperationException("Adapter Optimy został już zainicjalizowany."); + } + + ValidateConfiguration(configuration); + var runtime = _comFacade.InspectRuntime(_installationPath); + _configuration = configuration; + _worker = new StaWorker(); + + return new ErpAdapterInfo( + GetAssemblyVersion(typeof(OptimaOrderAdapter).Assembly), + "Comarch ERP Optima", + runtime.ErpVersion, + configuration.Connection.DatabaseName, + ["price_netto", "price_brutto", "multi_currency", "Buffer", "Approved", "COM STA"], + new Dictionary + { + ["COM ProgID"] = runtime.ComProgId, + ["Process bitness"] = runtime.ProcessArchitecture, + ["Save mode"] = configuration.SaveMode.ToString() + }); + } + + public void CheckConnection() + { + var configuration = GetConfiguration(); + GetWorker().Invoke(() => + { + _comFacade.CheckConnection(configuration); + return true; + }); + } + + public OrderResult CreateOrder(OrderRequest request) + { + var configuration = GetConfiguration(); + var errors = OrderValidator.Validate(request); + if (errors.Count > 0) + { + throw new ErpOperationException( + "eu.smartb2b.erp.invalid_order_lines", + string.Join(" | ", errors), + new Dictionary { ["errors"] = errors }); + } + + return GetWorker().Invoke(() => _comFacade.CreateOrder(configuration, request)); + } + + public void Dispose() + { + if (_disposed) + { + return; + } + + _disposed = true; + _worker?.Dispose(); + _worker = null; + } + + public static decimal SelectUnitPrice(int documentCalculationMode, OrderLineRequest line, int index) + { + var price = documentCalculationMode == 2 ? line.UnitPriceGross : line.UnitPriceNet; + var field = documentCalculationMode == 2 ? "price_brutto" : "price_netto"; + return price ?? throw new ErpOperationException( + "eu.smartb2b.erp.invalid_order_lines", + $"lines[{index}].{field} jest wymagane przez wybraną definicję dokumentu.", + new Dictionary { ["line"] = index, ["requiredField"] = field }); + } + + private static void ValidateConfiguration(ErpAdapterConfiguration configuration) + { + var errors = new List(); + if (string.IsNullOrWhiteSpace(configuration.Connection.DatabaseName)) errors.Add("Nazwa firmy/bazy Optimy jest wymagana."); + if (string.IsNullOrWhiteSpace(configuration.Connection.OperatorName)) errors.Add("Operator Optimy jest wymagany."); + if (string.IsNullOrWhiteSpace(configuration.DocumentDefinition)) errors.Add("Definicja dokumentu Optimy jest wymagana."); + if (!int.TryParse(configuration.DefaultWarehouseCode, out var warehouseId) || warehouseId <= 0) + { + errors.Add("optima.defaultWarehouseId musi być dodatnim identyfikatorem liczbowym."); + } + + if (errors.Count > 0) + { + throw new ErpOperationException("eu.smartb2b.erp.configuration_error", string.Join(" | ", errors)); + } + } + + private ErpAdapterConfiguration GetConfiguration() => + _configuration ?? throw new InvalidOperationException("Adapter Optimy nie został zainicjalizowany."); + + private StaWorker GetWorker() => + _worker ?? throw new InvalidOperationException("Wątek COM Optimy nie został uruchomiony."); + + private static string GetAssemblyVersion(Assembly assembly) => assembly.GetName().Version?.ToString() ?? "unknown"; +} diff --git a/src/SmartB2B.Optima.Adapter/SmartB2B.Optima.Adapter.csproj b/src/SmartB2B.Optima.Adapter/SmartB2B.Optima.Adapter.csproj new file mode 100644 index 0000000..457bf4d --- /dev/null +++ b/src/SmartB2B.Optima.Adapter/SmartB2B.Optima.Adapter.csproj @@ -0,0 +1,11 @@ + + + net8.0-windows + enable + enable + true + + + + + diff --git a/src/SmartB2B.Optima.Adapter/StaWorker.cs b/src/SmartB2B.Optima.Adapter/StaWorker.cs new file mode 100644 index 0000000..437a8d2 --- /dev/null +++ b/src/SmartB2B.Optima.Adapter/StaWorker.cs @@ -0,0 +1,79 @@ +using System.Collections.Concurrent; + +namespace SmartB2B.Optima.Adapter; + +internal sealed class StaWorker : IDisposable +{ + private readonly BlockingCollection _queue = new(); + private readonly Thread _thread; + private bool _disposed; + + public StaWorker() + { + _thread = new Thread(Run) + { + IsBackground = true, + Name = "SmartB2B Optima COM STA" + }; + _thread.SetApartmentState(ApartmentState.STA); + _thread.Start(); + } + + public T Invoke(Func action) + { + ObjectDisposedException.ThrowIf(_disposed, this); + var item = new WorkItem(action); + _queue.Add(item); + return item.Task.GetAwaiter().GetResult(); + } + + public void Dispose() + { + if (_disposed) + { + return; + } + + _disposed = true; + _queue.CompleteAdding(); + if (_thread.Join(TimeSpan.FromSeconds(30))) + { + _queue.Dispose(); + } + } + + private void Run() + { + foreach (var item in _queue.GetConsumingEnumerable()) + { + item.Execute(); + } + } + + private interface IWorkItem + { + void Execute(); + } + + private sealed class WorkItem : IWorkItem + { + private readonly Func _action; + private readonly TaskCompletionSource _completion = new(TaskCreationOptions.RunContinuationsAsynchronously); + + public WorkItem(Func action) => _action = action; + + public Task Task => _completion.Task; + + public void Execute() + { + try + { + _completion.SetResult(_action()); + } + catch (Exception exception) + { + _completion.SetException(exception); + } + } + } +} diff --git a/src/SmartB2B.Optima.Service/Configuration/OptimaServiceSettings.cs b/src/SmartB2B.Optima.Service/Configuration/OptimaServiceSettings.cs new file mode 100644 index 0000000..6d2353c --- /dev/null +++ b/src/SmartB2B.Optima.Service/Configuration/OptimaServiceSettings.cs @@ -0,0 +1,129 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using SmartB2B.Sync.Contracts; +using SmartB2B.Sync.Service; + +namespace SmartB2B.Optima.Service.Configuration; + +public sealed class OptimaServiceSettings +{ + public string Portal { get; init; } = string.Empty; + public WampSettings Wamp { get; init; } = new(); + public OptimaSettings Optima { get; init; } = new(); + public SqlSettings Sql { get; init; } = new(); + public SentrySettings Sentry { get; init; } = new(); + public DiagnosticsSettings Diagnostics { get; init; } = new(); + + public static OptimaServiceSettings Load(string path) + { + if (!File.Exists(path)) + { + throw new ServiceConfigurationException($"Nie znaleziono pliku konfiguracji: {path}"); + } + + var options = new JsonSerializerOptions + { + PropertyNameCaseInsensitive = true, + ReadCommentHandling = JsonCommentHandling.Skip, + AllowTrailingCommas = true, + Converters = { new JsonStringEnumConverter() } + }; + + try + { + var settings = JsonSerializer.Deserialize(File.ReadAllText(path), options) + ?? throw new ServiceConfigurationException("Plik konfiguracji jest pusty."); + settings.Validate(); + return settings; + } + catch (JsonException exception) + { + throw new ServiceConfigurationException($"Niepoprawny JSON konfiguracji: {exception.Message}", exception); + } + } + + public OptimaRuntimeSettings ResolveRuntimeSettings(bool verboseLogging) + { + var installationPath = Path.GetFullPath(Environment.ExpandEnvironmentVariables(Optima.InstallationPath)); + var configuration = new ErpAdapterConfiguration( + new ErpConnectionOptions(Optima.Database, Optima.Operator, Optima.Password!, Sql.ConnectionString), + Optima.DocumentDefinition, + Optima.DefaultWarehouseId.ToString(), + Optima.SaveMode, + verboseLogging); + return new OptimaRuntimeSettings( + installationPath, + configuration, + Sql.ConnectionString, + Sql.CommandTimeoutSeconds, + ResolvePath(Diagnostics.LogDirectory), + Diagnostics.LogPrefix); + } + + private void Validate() + { + var errors = new List(); + Require(Portal, "portal", errors); + Require(Wamp.ServerUrl, "wamp.serverUrl", errors); + Require(Optima.InstallationPath, "optima.installationPath", errors); + Require(Optima.Database, "optima.database", errors); + Require(Optima.Operator, "optima.operator", errors); + if (Optima.Password is null) errors.Add("Parametr 'optima.password' jest wymagany."); + Require(Optima.DocumentDefinition, "optima.documentDefinition", errors); + if (Optima.DefaultWarehouseId <= 0) errors.Add("optima.defaultWarehouseId musi być większe od zera."); + Require(Sql.ConnectionString, "sql.connectionString", errors); + if (Sql.CommandTimeoutSeconds <= 0) errors.Add("sql.commandTimeoutSeconds musi być większe od zera."); + if (Wamp.ReconnectDelaySeconds <= 0) errors.Add("wamp.reconnectDelaySeconds musi być większe od zera."); + if (errors.Count > 0) throw new ServiceConfigurationException(string.Join(Environment.NewLine, errors)); + } + + private static void Require(string? value, string name, ICollection 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 OptimaSettings +{ + public string InstallationPath { get; init; } = string.Empty; + public string Database { get; init; } = string.Empty; + public string Operator { get; init; } = string.Empty; + public string? Password { get; init; } + public string DocumentDefinition { get; init; } = "RO"; + public int DefaultWarehouseId { get; init; } = 1; + public OrderSaveMode SaveMode { get; init; } = OrderSaveMode.Buffer; +} + +public sealed class SqlSettings +{ + public string ConnectionString { get; init; } = string.Empty; + public int CommandTimeoutSeconds { get; init; } = 30; +} + +public sealed class SentrySettings +{ + public string? Dsn { get; init; } +} + +public sealed class DiagnosticsSettings +{ + public string LogDirectory { get; init; } = "daemon"; + public string LogPrefix { get; init; } = "smartb2bsync-optima"; +} + +public sealed record OptimaRuntimeSettings( + string InstallationPath, + ErpAdapterConfiguration AdapterConfiguration, + string SqlConnectionString, + int SqlCommandTimeoutSeconds, + string LogDirectory, + string LogPrefix); diff --git a/src/SmartB2B.Optima.Service/Program.cs b/src/SmartB2B.Optima.Service/Program.cs new file mode 100644 index 0000000..f04b670 --- /dev/null +++ b/src/SmartB2B.Optima.Service/Program.cs @@ -0,0 +1,92 @@ +using SmartB2B.Optima.Adapter; +using SmartB2B.Optima.Service.Configuration; +using SmartB2B.Sync.Contracts; +using SmartB2B.Sync.Service; +using SmartB2B.Sync.Service.Diagnostics; +using SmartB2B.Sync.Service.Sql; + +namespace SmartB2B.Optima.Service; + +internal static class Program +{ + public static async Task Main(string[] args) + { + IDisposable? sentry = null; + IErpOrderAdapter? adapter = null; + var cancellation = new CancellationTokenSource(); + Console.CancelKeyPress += (_, eventArgs) => + { + eventArgs.Cancel = true; + cancellation.Cancel(); + }; + AppDomain.CurrentDomain.ProcessExit += (_, _) => cancellation.Cancel(); + + try + { + var commandLine = ServiceCommandLine.Parse(args, "optima.json"); + ConsoleLogger.Configure(commandLine.VerboseLogging); + var settings = OptimaServiceSettings.Load(commandLine.ConfigurationPath); + var runtime = settings.ResolveRuntimeSettings(commandLine.VerboseLogging); + var serviceVersion = typeof(Program).Assembly.GetName().Version?.ToString(3) ?? "unknown"; + sentry = SentryBootstrap.Initialize( + settings.Sentry.Dsn, + settings.Portal, + "optima", + serviceVersion, + commandLine.ConfigurationPath, + commandLine.VerboseLogging); + + adapter = new OptimaOrderAdapter(runtime.InstallationPath); + var adapterInfo = adapter.Initialize(runtime.AdapterConfiguration); + Console.WriteLine($"Załadowano {adapterInfo.ErpName} {adapterInfo.ErpVersion} z '{runtime.InstallationPath}'."); + Console.WriteLine($"Firma/baza: {adapterInfo.DatabaseName}; portal WAMP: {settings.Portal}."); + + if (commandLine.CheckConfigurationOnly) + { + var sql = new SqlRawHandler(runtime.SqlConnectionString, runtime.SqlCommandTimeoutSeconds); + await sql.CheckConnectionAsync(cancellation.Token).ConfigureAwait(false); + adapter.CheckConnection(); + Console.WriteLine("Konfiguracja, połączenie SQL i logowanie COM Optimy są poprawne."); + return 0; + } + + var options = new SyncServiceOptions( + "SmartB2B Optima Sync", + serviceVersion, + "Optima path", + runtime.InstallationPath, + settings.Portal, + settings.Wamp.ServerUrl, + settings.Wamp.ReconnectDelaySeconds, + runtime.SqlConnectionString, + runtime.SqlCommandTimeoutSeconds, + runtime.LogDirectory, + runtime.LogPrefix); + await SyncServiceRunner.RunAsync( + options, + adapter, + runtime.AdapterConfiguration, + adapterInfo, + cancellation.Token) + .ConfigureAwait(false); + Console.WriteLine("SmartB2B Optima Sync zatrzymany."); + return 0; + } + catch (ServiceConfigurationException exception) + { + Console.Error.WriteLine($"Błąd konfiguracji: {exception.Message}"); + return 2; + } + catch (Exception exception) + { + Console.Error.WriteLine($"Błąd krytyczny: {exception}"); + await SentryReporter.CaptureAsync(exception).ConfigureAwait(false); + return 1; + } + finally + { + adapter?.Dispose(); + sentry?.Dispose(); + } + } +} diff --git a/src/SmartB2B.Optima.Service/SmartB2B.Optima.Service.csproj b/src/SmartB2B.Optima.Service/SmartB2B.Optima.Service.csproj new file mode 100644 index 0000000..8928904 --- /dev/null +++ b/src/SmartB2B.Optima.Service/SmartB2B.Optima.Service.csproj @@ -0,0 +1,19 @@ + + + Exe + net8.0-windows + enable + enable + SmartB2B.Optima.Service + 1.0.0 + x64 + + + + + + + + + + diff --git a/src/SmartB2B.Optima.Service/config/optima.json.sample b/src/SmartB2B.Optima.Service/config/optima.json.sample new file mode 100644 index 0000000..408ccf8 --- /dev/null +++ b/src/SmartB2B.Optima.Service/config/optima.json.sample @@ -0,0 +1,27 @@ +{ + "portal": "demo", + "wamp": { + "serverUrl": "ws://wamp.smartb2b.eu:8080/", + "reconnectDelaySeconds": 10 + }, + "optima": { + "installationPath": "C:\\Program Files (x86)\\Comarch ERP Optima", + "database": "", + "operator": "", + "password": "", + "documentDefinition": "RO", + "defaultWarehouseId": 1, + "saveMode": "Buffer" + }, + "sql": { + "connectionString": "Server=.\\OPTIMA;Database=...;User ID=...;Password=...;TrustServerCertificate=True", + "commandTimeoutSeconds": 30 + }, + "sentry": { + "dsn": null + }, + "diagnostics": { + "logDirectory": "daemon", + "logPrefix": "smartb2bsync-optima" + } +} diff --git a/src/SmartB2B.Enova.Contracts/SmartB2B.Enova.Contracts.csproj b/src/SmartB2B.Sync.Contracts/SmartB2B.Sync.Contracts.csproj similarity index 100% rename from src/SmartB2B.Enova.Contracts/SmartB2B.Enova.Contracts.csproj rename to src/SmartB2B.Sync.Contracts/SmartB2B.Sync.Contracts.csproj diff --git a/src/SmartB2B.Enova.Contracts/EnovaContracts.cs b/src/SmartB2B.Sync.Contracts/SyncContracts.cs similarity index 71% rename from src/SmartB2B.Enova.Contracts/EnovaContracts.cs rename to src/SmartB2B.Sync.Contracts/SyncContracts.cs index 289a803..963c835 100644 --- a/src/SmartB2B.Enova.Contracts/EnovaContracts.cs +++ b/src/SmartB2B.Sync.Contracts/SyncContracts.cs @@ -1,4 +1,4 @@ -namespace SmartB2B.Enova.Contracts; +namespace SmartB2B.Sync.Contracts; public enum OrderSaveMode { @@ -6,14 +6,14 @@ public enum OrderSaveMode Approved } -public sealed record EnovaConnectionOptions( +public sealed record ErpConnectionOptions( string DatabaseName, string OperatorName, string Password, string SqlConnectionString); -public sealed record EnovaAdapterConfiguration( - EnovaConnectionOptions Connection, +public sealed record ErpAdapterConfiguration( + ErpConnectionOptions Connection, string DocumentDefinition, string? DefaultWarehouseCode, OrderSaveMode SaveMode, @@ -21,13 +21,15 @@ public sealed record EnovaAdapterConfiguration( public sealed class OrderRequest { + public string CurrencyIso { get; init; } = string.Empty; + 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 DocumentDefinition { get; init; } = string.Empty; public string? WarehouseCode { get; init; } @@ -42,7 +44,9 @@ public sealed class OrderLineRequest public decimal Quantity { get; init; } - public decimal UnitPrice { get; init; } + public decimal? UnitPriceNet { get; init; } + + public decimal? UnitPriceGross { get; init; } public decimal Discount { get; init; } } @@ -60,22 +64,26 @@ public sealed record OrderResult( decimal Gross, bool HasDiscount); -public sealed record EnovaAdapterInfo( +public sealed record ErpAdapterInfo( string AdapterVersion, - string SonetaBusinessVersion, - string SonetaHandelVersion, - string DatabaseName); + string ErpName, + string ErpVersion, + string DatabaseName, + IReadOnlyList Capabilities, + IReadOnlyDictionary? Details = null); -public interface IEnovaOrderAdapter +public interface IErpOrderAdapter : IDisposable { - EnovaAdapterInfo Initialize(EnovaAdapterConfiguration configuration); + ErpAdapterInfo Initialize(ErpAdapterConfiguration configuration); + + void CheckConnection(); OrderResult CreateOrder(OrderRequest request); } -public sealed class EnovaOperationException : Exception +public class ErpOperationException : Exception { - public EnovaOperationException( + public ErpOperationException( string errorUri, string message, IReadOnlyDictionary? details = null, @@ -103,6 +111,11 @@ public static class OrderValidator return errors; } + if (string.IsNullOrWhiteSpace(request.CurrencyIso)) + { + errors.Add("Pole currency_iso jest wymagane."); + } + if (string.IsNullOrWhiteSpace(request.CustomerCode)) { errors.Add("Pole companyErpId jest wymagane."); @@ -140,11 +153,21 @@ public static class OrderValidator errors.Add($"{prefix}.quantity musi być większe od zera."); } - if (line.UnitPrice < 0) + if (line.UnitPriceNet is null && line.UnitPriceGross is null) + { + errors.Add($"{prefix}: wymagane jest price_netto lub price_brutto."); + } + + if (line.UnitPriceNet < 0) { errors.Add($"{prefix}.price_netto nie może być ujemne."); } + if (line.UnitPriceGross < 0) + { + errors.Add($"{prefix}.price_brutto nie może być ujemne."); + } + if (line.Discount is < 0 or > 100) { errors.Add($"{prefix}.discount musi mieścić się w zakresie 0-100."); diff --git a/src/SmartB2B.Enova.Service/Diagnostics/ConsoleLogger.cs b/src/SmartB2B.Sync.Service/Diagnostics/ConsoleLogger.cs similarity index 71% rename from src/SmartB2B.Enova.Service/Diagnostics/ConsoleLogger.cs rename to src/SmartB2B.Sync.Service/Diagnostics/ConsoleLogger.cs index be192d6..ef5a16f 100644 --- a/src/SmartB2B.Enova.Service/Diagnostics/ConsoleLogger.cs +++ b/src/SmartB2B.Sync.Service/Diagnostics/ConsoleLogger.cs @@ -1,13 +1,10 @@ -namespace SmartB2B.Enova.Service.Diagnostics; +namespace SmartB2B.Sync.Service.Diagnostics; -internal static class ConsoleLogger +public static class ConsoleLogger { public static bool VerboseEnabled { get; private set; } - public static void Configure(bool verboseEnabled) - { - VerboseEnabled = verboseEnabled; - } + public static void Configure(bool verboseEnabled) => VerboseEnabled = verboseEnabled; public static void Verbose(string message) { diff --git a/src/SmartB2B.Enova.Service/Diagnostics/DiagnosticsHandler.cs b/src/SmartB2B.Sync.Service/Diagnostics/DiagnosticsHandler.cs similarity index 56% rename from src/SmartB2B.Enova.Service/Diagnostics/DiagnosticsHandler.cs rename to src/SmartB2B.Sync.Service/Diagnostics/DiagnosticsHandler.cs index c067288..6395920 100644 --- a/src/SmartB2B.Enova.Service/Diagnostics/DiagnosticsHandler.cs +++ b/src/SmartB2B.Sync.Service/Diagnostics/DiagnosticsHandler.cs @@ -1,25 +1,33 @@ -using System.Reflection; using System.Text.RegularExpressions; -using SmartB2B.Enova.Contracts; -using SmartB2B.Enova.Service.Rpc; +using SmartB2B.Sync.Contracts; +using SmartB2B.Sync.Service.Rpc; -namespace SmartB2B.Enova.Service.Diagnostics; +namespace SmartB2B.Sync.Service.Diagnostics; public sealed partial class DiagnosticsHandler { - private readonly EnovaAdapterInfo? _adapterInfo; - private readonly string _enovaPath; + private readonly string _serviceName; + private readonly string _serviceVersion; + private readonly string _runtimeLabel; + private readonly string _runtimePath; + private readonly ErpAdapterInfo? _adapterInfo; private readonly string _logDirectory; private readonly string _logPrefix; public DiagnosticsHandler( - EnovaAdapterInfo? adapterInfo, - string enovaPath, + string serviceName, + string serviceVersion, + string runtimeLabel, + string runtimePath, + ErpAdapterInfo? adapterInfo, string logDirectory, string logPrefix) { + _serviceName = serviceName; + _serviceVersion = serviceVersion; + _runtimeLabel = runtimeLabel; + _runtimePath = runtimePath; _adapterInfo = adapterInfo; - _enovaPath = enovaPath; _logDirectory = logDirectory; _logPrefix = logPrefix; } @@ -27,31 +35,35 @@ public sealed partial class DiagnosticsHandler public Task GetVersionAsync(RpcInvocation _, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - var version = Assembly.GetExecutingAssembly().GetName().Version?.ToString(3) ?? "unknown"; - return Task.FromResult(version); + return Task.FromResult(_serviceVersion); } public Task GetInfoAsync(RpcInvocation _, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - var serviceVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString(3) ?? "unknown"; var lines = new List { - $"SmartB2B Enova Sync version: {serviceVersion}", + $"{_serviceName} version: {_serviceVersion}", $".NET version: {Environment.Version}", - $"Enova path: {_enovaPath}" + $"Process architecture: {System.Runtime.InteropServices.RuntimeInformation.ProcessArchitecture}", + $"{_runtimeLabel}: {_runtimePath}" }; if (_adapterInfo is null) { - lines.Add("Adapter Enovy: nie zainicjalizowano (place_order jest wyłączony)"); + lines.Add("Adapter ERP: nie zainicjalizowano (place_order jest wyłączony)"); } else { + lines.Add($"ERP: {_adapterInfo.ErpName}"); lines.Add($"Adapter version: {_adapterInfo.AdapterVersion}"); - lines.Add($"Soneta.Business version: {_adapterInfo.SonetaBusinessVersion}"); - lines.Add($"Soneta.Handel version: {_adapterInfo.SonetaHandelVersion}"); + lines.Add($"ERP version: {_adapterInfo.ErpVersion}"); lines.Add($"Database: {_adapterInfo.DatabaseName}"); + lines.Add($"Capabilities: {string.Join(", ", _adapterInfo.Capabilities)}"); + if (_adapterInfo.Details is not null) + { + lines.AddRange(_adapterInfo.Details.Select(pair => $"{pair.Key}: {pair.Value}")); + } } return Task.FromResult(string.Join(Environment.NewLine, lines)); @@ -63,10 +75,7 @@ public sealed partial class DiagnosticsHandler public Task GetErrorLogAsync(RpcInvocation invocation, CancellationToken cancellationToken) => ReadLogAsync(invocation, "err", cancellationToken); - private async Task ReadLogAsync( - RpcInvocation invocation, - string stream, - CancellationToken cancellationToken) + private async Task ReadLogAsync(RpcInvocation invocation, string stream, CancellationToken cancellationToken) { var date = invocation.Get("date") ?? DateTime.UtcNow.ToString("yyyy-MM-dd"); if (!DatePattern().IsMatch(date)) @@ -79,12 +88,9 @@ public sealed partial class DiagnosticsHandler var compactDate = date.Replace("-", string.Empty, StringComparison.Ordinal); var path = Path.Combine(_logDirectory, $"{_logPrefix}_{compactDate}.{stream}.log"); - if (!File.Exists(path)) - { - return null; - } - - return await File.ReadAllTextAsync(path, cancellationToken).ConfigureAwait(false); + return File.Exists(path) + ? await File.ReadAllTextAsync(path, cancellationToken).ConfigureAwait(false) + : null; } [GeneratedRegex("^\\d{4}-\\d{2}-\\d{2}$", RegexOptions.CultureInvariant)] diff --git a/src/SmartB2B.Sync.Service/Diagnostics/SentryBootstrap.cs b/src/SmartB2B.Sync.Service/Diagnostics/SentryBootstrap.cs new file mode 100644 index 0000000..2563a43 --- /dev/null +++ b/src/SmartB2B.Sync.Service/Diagnostics/SentryBootstrap.cs @@ -0,0 +1,52 @@ +using Sentry; +using Sentry.Infrastructure; + +namespace SmartB2B.Sync.Service.Diagnostics; + +public static class SentryBootstrap +{ + public static IDisposable? Initialize( + string? dsn, + string portal, + string erpName, + string release, + string configurationPath, + bool verboseLogging) + { + if (string.IsNullOrWhiteSpace(dsn)) + { + Console.WriteLine($"Sentry wyłączone: brak parametru sentry.dsn w używanym pliku '{configurationPath}'."); + return null; + } + + var sentry = SentrySdk.Init(options => + { + options.Dsn = dsn; + options.IsGlobalModeEnabled = true; + options.Release = release; + options.DiagnosticLevel = verboseLogging ? SentryLevel.Debug : SentryLevel.Error; + options.DiagnosticLogger = new ConsoleDiagnosticLogger(options.DiagnosticLevel); + options.ShutdownTimeout = TimeSpan.FromSeconds(5); + }); + + SentrySdk.ConfigureScope(scope => + { + scope.SetTag("portal", portal); + scope.SetTag("erp", erpName); + }); + Console.WriteLine($"Raportowanie błędów do Sentry włączone; cel: {DescribeTarget(dsn)}."); + return sentry; + } + + private static string DescribeTarget(string dsn) + { + if (!Uri.TryCreate(dsn, UriKind.Absolute, out var uri)) + { + return "niepoprawny DSN"; + } + + var port = uri.IsDefaultPort ? string.Empty : $":{uri.Port}"; + var project = uri.AbsolutePath.Trim('/').Split('/').LastOrDefault() ?? "?"; + return $"{uri.Scheme}://{uri.Host}{port}, projekt {project}"; + } +} diff --git a/src/SmartB2B.Enova.Service/Diagnostics/SentryReporter.cs b/src/SmartB2B.Sync.Service/Diagnostics/SentryReporter.cs similarity index 76% rename from src/SmartB2B.Enova.Service/Diagnostics/SentryReporter.cs rename to src/SmartB2B.Sync.Service/Diagnostics/SentryReporter.cs index 1d92bbf..59ab100 100644 --- a/src/SmartB2B.Enova.Service/Diagnostics/SentryReporter.cs +++ b/src/SmartB2B.Sync.Service/Diagnostics/SentryReporter.cs @@ -1,8 +1,8 @@ using Sentry; -namespace SmartB2B.Enova.Service.Diagnostics; +namespace SmartB2B.Sync.Service.Diagnostics; -internal static class SentryReporter +public static class SentryReporter { private static readonly TimeSpan FlushTimeout = TimeSpan.FromSeconds(5); @@ -20,9 +20,7 @@ internal static class SentryReporter } catch (Exception sentryException) { - ConsoleLogger.Error( - $"Błąd raportowania do Sentry: {sentryException.Message}", - sentryException); + ConsoleLogger.Error($"Błąd raportowania do Sentry: {sentryException.Message}", sentryException); } } } diff --git a/src/SmartB2B.Enova.Service/Orders/PlaceOrderHandler.cs b/src/SmartB2B.Sync.Service/Orders/PlaceOrderHandler.cs similarity index 52% rename from src/SmartB2B.Enova.Service/Orders/PlaceOrderHandler.cs rename to src/SmartB2B.Sync.Service/Orders/PlaceOrderHandler.cs index d63ca2b..a50401f 100644 --- a/src/SmartB2B.Enova.Service/Orders/PlaceOrderHandler.cs +++ b/src/SmartB2B.Sync.Service/Orders/PlaceOrderHandler.cs @@ -1,17 +1,17 @@ using Newtonsoft.Json; -using SmartB2B.Enova.Contracts; -using SmartB2B.Enova.Service.Diagnostics; -using SmartB2B.Enova.Service.Rpc; +using SmartB2B.Sync.Contracts; +using SmartB2B.Sync.Service.Diagnostics; +using SmartB2B.Sync.Service.Rpc; -namespace SmartB2B.Enova.Service.Orders; +namespace SmartB2B.Sync.Service.Orders; public sealed class PlaceOrderHandler { - private readonly IEnovaOrderAdapter _adapter; - private readonly EnovaAdapterConfiguration _configuration; + private readonly IErpOrderAdapter _adapter; + private readonly ErpAdapterConfiguration _configuration; private readonly SemaphoreSlim _orderLock = new(1, 1); - public PlaceOrderHandler(IEnovaOrderAdapter adapter, EnovaAdapterConfiguration configuration) + public PlaceOrderHandler(IErpOrderAdapter adapter, ErpAdapterConfiguration configuration) { _adapter = adapter; _configuration = configuration; @@ -24,18 +24,10 @@ public sealed class PlaceOrderHandler throw WampErrorFactory.Create("eu.smartb2b.missing_currency", "Pole currency_iso jest wymagane."); } - var currency = invocation.Get("currency_iso")?.Trim(); - if (!string.Equals(currency, "PLN", StringComparison.OrdinalIgnoreCase)) - { - throw WampErrorFactory.Create( - "eu.smartb2b.erp.currency_not_supported", - $"Waluta '{currency}' nie jest obsługiwana. Wymagana waluta: PLN.", - new Dictionary { ["currency_iso"] = currency }); - } - var inputLines = invocation.Get("lines", []) ?? []; var request = new OrderRequest { + CurrencyIso = invocation.Get("currency_iso")?.Trim().ToUpperInvariant() ?? string.Empty, CustomerCode = invocation.Get("companyErpId") ?? string.Empty, CustomerReference = invocation.Get("purchase_order_number"), Notes = invocation.Get("notes"), @@ -46,7 +38,8 @@ public sealed class PlaceOrderHandler { ProductCode = line.Symbol ?? string.Empty, Quantity = line.Quantity, - UnitPrice = line.PriceNetto, + UnitPriceNet = line.PriceNetto, + UnitPriceGross = line.PriceBrutto, Discount = line.Discount }).ToArray() }; @@ -61,53 +54,43 @@ public sealed class PlaceOrderHandler } ConsoleLogger.Verbose( - $"ZO: żądanie zweryfikowane; definicja={request.DocumentDefinition}, " + + $"Zamówienie: zweryfikowano żądanie; definicja={request.DocumentDefinition}, " + $"magazyn={request.WarehouseCode ?? "(standardowy)"}, tryb={request.SaveMode}."); - ConsoleLogger.Verbose("ZO: oczekiwanie na wyłączną sekcję operacji Enovy."); await _orderLock.WaitAsync(cancellationToken).ConfigureAwait(false); try { Console.WriteLine( - $"Tworzenie ZO: kontrahent={request.CustomerCode}, pozycje={request.Items.Count}, referencja={request.CustomerReference ?? "(brak)"}."); - - OrderResult result; + $"Tworzenie zamówienia: kontrahent={request.CustomerCode}, pozycje={request.Items.Count}, " + + $"referencja={request.CustomerReference ?? "(brak)"}."); try { - ConsoleLogger.Verbose("ZO: przekazanie żądania do adaptera Enovy."); - result = await Task.Run(() => _adapter.CreateOrder(request), cancellationToken) + var result = await Task.Run(() => _adapter.CreateOrder(request), cancellationToken) .ConfigureAwait(false); + Console.WriteLine($"Utworzono zamówienie {result.Number} (ID: {result.Id})."); + return new KeywordResult(new Dictionary + { + ["order_erp_id"] = result.Id, + ["order_erp_symbol"] = result.Number, + ["value_netto"] = result.Net, + ["value_brutto"] = result.Gross, + ["stocks"] = Array.Empty() + }); } - catch (EnovaOperationException exception) + catch (ErpOperationException exception) { - ConsoleLogger.Error( - $"Błąd tworzenia ZO [{exception.ErrorUri}]: {exception.Message}", - exception); + ConsoleLogger.Error($"Błąd tworzenia zamówienia [{exception.ErrorUri}]: {exception.Message}", exception); await SentryReporter.CaptureAsync(exception, scope => { scope.SetTag("rpc.procedure", "eu.smartb2b.place_order"); scope.SetTag("wamp.error_uri", exception.ErrorUri); }) .ConfigureAwait(false); - throw WampErrorFactory.FromEnova(exception); + throw WampErrorFactory.FromErp(exception); } - - Console.WriteLine($"Utworzono ZO {result.Number} (ID: {result.Id})."); - ConsoleLogger.Verbose( - $"ZO: zapis zakończony; stan={result.SaveMode}, magazyn={result.WarehouseCode}, " + - $"netto={result.Net}, VAT={result.Vat}, brutto={result.Gross}."); - return new KeywordResult(new Dictionary - { - ["order_erp_id"] = result.Id, - ["order_erp_symbol"] = result.Number, - ["value_netto"] = result.Net, - ["value_brutto"] = result.Gross, - ["stocks"] = Array.Empty() - }); } finally { _orderLock.Release(); - ConsoleLogger.Verbose("ZO: zwolniono wyłączną sekcję operacji Enovy."); } } } @@ -121,7 +104,10 @@ public sealed class PlaceOrderLine public decimal Quantity { get; init; } [JsonProperty("price_netto")] - public decimal PriceNetto { get; init; } + public decimal? PriceNetto { get; init; } + + [JsonProperty("price_brutto")] + public decimal? PriceBrutto { get; init; } [JsonProperty("discount")] public decimal Discount { get; init; } diff --git a/src/SmartB2B.Enova.Service/Rpc/DelegateRpcOperation.cs b/src/SmartB2B.Sync.Service/Rpc/DelegateRpcOperation.cs similarity index 70% rename from src/SmartB2B.Enova.Service/Rpc/DelegateRpcOperation.cs rename to src/SmartB2B.Sync.Service/Rpc/DelegateRpcOperation.cs index c19252f..54b005e 100644 --- a/src/SmartB2B.Enova.Service/Rpc/DelegateRpcOperation.cs +++ b/src/SmartB2B.Sync.Service/Rpc/DelegateRpcOperation.cs @@ -1,17 +1,15 @@ +using SmartB2B.Sync.Service.Diagnostics; using WampSharp.Core.Serialization; using WampSharp.V2.Core.Contracts; using WampSharp.V2.Rpc; -using SmartB2B.Enova.Service.Diagnostics; -namespace SmartB2B.Enova.Service.Rpc; +namespace SmartB2B.Sync.Service.Rpc; public sealed class DelegateRpcOperation : IWampRpcOperation { private readonly Func> _handler; - public DelegateRpcOperation( - string procedure, - Func> handler) + public DelegateRpcOperation(string procedure, Func> handler) { Procedure = procedure; _handler = handler; @@ -63,7 +61,6 @@ public sealed class DelegateRpcOperation : IWampRpcOperation pair => pair.Key, pair => (object?)formatter.Deserialize(pair.Value), StringComparer.OrdinalIgnoreCase); - var result = await _handler(new RpcInvocation(positional, keywords), cancellationToken) .ConfigureAwait(false); var yieldOptions = new YieldOptions(); @@ -90,40 +87,30 @@ public sealed class DelegateRpcOperation : IWampRpcOperation var message = exception.ArgumentsKeywords.TryGetValue("message", out var value) ? Convert.ToString(value) : exception.Message; - ConsoleLogger.Error( - $"Błąd procedury {Procedure} [{exception.ErrorUri}]: {message}", - exception); - var details = formatter.Serialize(exception.Details); - var errorArguments = exception.Arguments.Select(formatter.Serialize).ToArray(); - var keywordArguments = formatter.Serialize(exception.ArgumentsKeywords); - caller.Error(formatter, details, exception.ErrorUri, errorArguments, keywordArguments); + ConsoleLogger.Error($"Błąd procedury {Procedure} [{exception.ErrorUri}]: {message}", exception); + caller.Error( + formatter, + formatter.Serialize(exception.Details), + exception.ErrorUri, + exception.Arguments.Select(formatter.Serialize).ToArray(), + formatter.Serialize(exception.ArgumentsKeywords)); } catch (OperationCanceledException) { ConsoleLogger.Error($"Anulowano wykonanie procedury {Procedure}."); - var details = formatter.Serialize(new Dictionary()); - caller.Error(formatter, details, "wamp.error.canceled"); + caller.Error(formatter, formatter.Serialize(new Dictionary()), "wamp.error.canceled"); } catch (Exception exception) { - ConsoleLogger.Error( - $"Nieobsłużony błąd procedury {Procedure}: {exception.Message}", - exception); - await SentryReporter.CaptureAsync( - exception, - scope => scope.SetTag("rpc.procedure", Procedure)) + ConsoleLogger.Error($"Nieobsłużony błąd procedury {Procedure}: {exception.Message}", exception); + await SentryReporter.CaptureAsync(exception, scope => scope.SetTag("rpc.procedure", Procedure)) .ConfigureAwait(false); - var details = formatter.Serialize(new Dictionary()); - var keywordArguments = formatter.Serialize(new Dictionary - { - ["message"] = exception.Message - }); caller.Error( formatter, - details, + formatter.Serialize(new Dictionary()), "eu.smartb2b.error", Array.Empty(), - keywordArguments); + formatter.Serialize(new Dictionary { ["message"] = exception.Message })); } } @@ -131,14 +118,8 @@ public sealed class DelegateRpcOperation : IWampRpcOperation { private readonly CancellationTokenSource _cancellation; - public CancellableInvocation(CancellationTokenSource cancellation) - { - _cancellation = cancellation; - } + public CancellableInvocation(CancellationTokenSource cancellation) => _cancellation = cancellation; - public void Cancel(InterruptDetails details) - { - _cancellation.Cancel(); - } + public void Cancel(InterruptDetails details) => _cancellation.Cancel(); } } diff --git a/src/SmartB2B.Enova.Service/Rpc/RpcInvocation.cs b/src/SmartB2B.Sync.Service/Rpc/RpcInvocation.cs similarity index 96% rename from src/SmartB2B.Enova.Service/Rpc/RpcInvocation.cs rename to src/SmartB2B.Sync.Service/Rpc/RpcInvocation.cs index 5ef8046..902b276 100644 --- a/src/SmartB2B.Enova.Service/Rpc/RpcInvocation.cs +++ b/src/SmartB2B.Sync.Service/Rpc/RpcInvocation.cs @@ -1,6 +1,6 @@ using Newtonsoft.Json.Linq; -namespace SmartB2B.Enova.Service.Rpc; +namespace SmartB2B.Sync.Service.Rpc; public sealed class RpcInvocation { diff --git a/src/SmartB2B.Enova.Service/Rpc/WampErrorFactory.cs b/src/SmartB2B.Sync.Service/Rpc/WampErrorFactory.cs similarity index 79% rename from src/SmartB2B.Enova.Service/Rpc/WampErrorFactory.cs rename to src/SmartB2B.Sync.Service/Rpc/WampErrorFactory.cs index 23d0bee..000d919 100644 --- a/src/SmartB2B.Enova.Service/Rpc/WampErrorFactory.cs +++ b/src/SmartB2B.Sync.Service/Rpc/WampErrorFactory.cs @@ -1,11 +1,11 @@ -using SmartB2B.Enova.Contracts; +using SmartB2B.Sync.Contracts; using WampSharp.V2.Core.Contracts; -namespace SmartB2B.Enova.Service.Rpc; +namespace SmartB2B.Sync.Service.Rpc; public static class WampErrorFactory { - public static WampException FromEnova(EnovaOperationException exception) => + public static WampException FromErp(ErpOperationException exception) => Create(exception.ErrorUri, exception.Message, exception.Details); public static WampException Create( @@ -16,7 +16,6 @@ public static class WampErrorFactory var keywordArguments = (details ?? new Dictionary()) .ToDictionary(pair => pair.Key, pair => pair.Value!, StringComparer.Ordinal); keywordArguments["message"] = message; - return new WampException(errorUri, [], keywordArguments); } } diff --git a/src/SmartB2B.Enova.Service/Rpc/WampServiceClient.cs b/src/SmartB2B.Sync.Service/Rpc/WampServiceClient.cs similarity index 73% rename from src/SmartB2B.Enova.Service/Rpc/WampServiceClient.cs rename to src/SmartB2B.Sync.Service/Rpc/WampServiceClient.cs index a7b0819..aaf51b8 100644 --- a/src/SmartB2B.Enova.Service/Rpc/WampServiceClient.cs +++ b/src/SmartB2B.Sync.Service/Rpc/WampServiceClient.cs @@ -1,10 +1,10 @@ +using SmartB2B.Sync.Service.Diagnostics; using WampSharp.V2; using WampSharp.V2.Client; using WampSharp.V2.Core.Contracts; using WampSharp.V2.Rpc; -using SmartB2B.Enova.Service.Diagnostics; -namespace SmartB2B.Enova.Service.Rpc; +namespace SmartB2B.Sync.Service.Rpc; public sealed class WampServiceClient { @@ -35,18 +35,14 @@ public sealed class WampServiceClient { var channelFactory = new DefaultWampChannelFactory(); channel = channelFactory.CreateJsonChannel(_serverUrl, _realmName); - var disconnected = new TaskCompletionSource( - TaskCreationOptions.RunContinuationsAsynchronously); - + var disconnected = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); channel.RealmProxy.Monitor.ConnectionBroken += (_, _) => disconnected.TrySetResult(); channel.RealmProxy.Monitor.ConnectionError += (_, _) => disconnected.TrySetResult(); Console.WriteLine($"Łączenie z WAMP: realm={_realmName}, url={_serverUrl}."); await channel.Open().WaitAsync(cancellationToken).ConfigureAwait(false); - foreach (var operation in _operations) { - ConsoleLogger.Verbose($"WAMP: rejestracja procedury {operation.Procedure}."); var registration = await channel.RealmProxy.RpcCatalog.Register( operation, new RegisterOptions { Invoke = "last" }) @@ -55,8 +51,7 @@ public sealed class WampServiceClient registrations.Add(registration); } - Console.WriteLine( - $"Połączono z WAMP; zarejestrowano {_operations.Count} procedur."); + Console.WriteLine($"Połączono z WAMP; zarejestrowano {_operations.Count} procedur."); await disconnected.Task.WaitAsync(cancellationToken).ConfigureAwait(false); ConsoleLogger.Error("Połączenie WAMP zostało przerwane."); } @@ -72,24 +67,10 @@ public sealed class WampServiceClient { foreach (var registration in registrations) { - try - { - await registration.DisposeAsync().ConfigureAwait(false); - } - catch - { - // Sesja może już nie istnieć po zerwaniu połączenia. - } + try { await registration.DisposeAsync().ConfigureAwait(false); } catch { } } - try - { - channel?.Close(); - } - catch - { - // Zamknięcie uszkodzonego kanału nie może zatrzymać pętli ponownego łączenia. - } + try { channel?.Close(); } catch { } } if (!cancellationToken.IsCancellationRequested) diff --git a/src/SmartB2B.Sync.Service/ServiceCommandLine.cs b/src/SmartB2B.Sync.Service/ServiceCommandLine.cs new file mode 100644 index 0000000..1912c45 --- /dev/null +++ b/src/SmartB2B.Sync.Service/ServiceCommandLine.cs @@ -0,0 +1,56 @@ +namespace SmartB2B.Sync.Service; + +public sealed record ServiceCommandLine( + string ConfigurationPath, + bool CheckConfigurationOnly, + bool VerboseLogging) +{ + public static ServiceCommandLine Parse(string[] args, string defaultConfigurationFile) + { + var path = Path.Combine(AppContext.BaseDirectory, "config", defaultConfigurationFile); + var checkOnly = false; + var verbose = false; + + for (var index = 0; index < args.Length; index++) + { + switch (args[index]) + { + case "--config": + if (++index >= args.Length || string.IsNullOrWhiteSpace(args[index])) + { + throw new ServiceConfigurationException("Argument --config wymaga ścieżki."); + } + + path = Path.GetFullPath(args[index]); + break; + case "--check-config": + checkOnly = true; + break; + case "/debug": + case "/verbose": + case "--debug": + case "--verbose": + verbose = true; + break; + case "/nodebug": + case "/noverbose": + case "--no-debug": + case "--no-verbose": + verbose = false; + break; + default: + throw new ServiceConfigurationException($"Nieznany argument: {args[index]}"); + } + } + + return new ServiceCommandLine(path, checkOnly, verbose); + } +} + +public class ServiceConfigurationException : Exception +{ + public ServiceConfigurationException(string message, Exception? innerException = null) + : base(message, innerException) + { + } +} diff --git a/src/SmartB2B.Sync.Service/SmartB2B.Sync.Service.csproj b/src/SmartB2B.Sync.Service/SmartB2B.Sync.Service.csproj new file mode 100644 index 0000000..836fc76 --- /dev/null +++ b/src/SmartB2B.Sync.Service/SmartB2B.Sync.Service.csproj @@ -0,0 +1,17 @@ + + + net8.0 + enable + enable + + + + + + + + + + + + diff --git a/src/SmartB2B.Enova.Service/Sql/SqlRawHandler.cs b/src/SmartB2B.Sync.Service/Sql/SqlRawHandler.cs similarity index 89% rename from src/SmartB2B.Enova.Service/Sql/SqlRawHandler.cs rename to src/SmartB2B.Sync.Service/Sql/SqlRawHandler.cs index a808ec9..caccee5 100644 --- a/src/SmartB2B.Enova.Service/Sql/SqlRawHandler.cs +++ b/src/SmartB2B.Sync.Service/Sql/SqlRawHandler.cs @@ -1,10 +1,10 @@ using System.Data.Common; using Microsoft.Data.SqlClient; using Newtonsoft.Json; -using SmartB2B.Enova.Service.Diagnostics; -using SmartB2B.Enova.Service.Rpc; +using SmartB2B.Sync.Service.Diagnostics; +using SmartB2B.Sync.Service.Rpc; -namespace SmartB2B.Enova.Service.Sql; +namespace SmartB2B.Sync.Service.Sql; public sealed class SqlRawHandler { @@ -18,6 +18,16 @@ public sealed class SqlRawHandler _commandTimeoutSeconds = commandTimeoutSeconds; } + public async Task CheckConnectionAsync(CancellationToken cancellationToken = default) + { + await using var connection = CreateConnection(); + await connection.OpenAsync(cancellationToken).ConfigureAwait(false); + await using var command = connection.CreateCommand(); + command.CommandText = "SELECT 1"; + command.CommandTimeout = _commandTimeoutSeconds; + _ = await command.ExecuteScalarAsync(cancellationToken).ConfigureAwait(false); + } + public async Task HandleAsync(RpcInvocation invocation, CancellationToken cancellationToken) { var query = invocation.Get("query"); @@ -27,12 +37,10 @@ public sealed class SqlRawHandler } var parameters = invocation.Get("params", []) ?? []; - try { await using var connection = CreateConnection(); await connection.OpenAsync(cancellationToken).ConfigureAwait(false); - await using var command = connection.CreateCommand(); command.CommandText = query; command.CommandTimeout = _commandTimeoutSeconds; @@ -45,9 +53,8 @@ public sealed class SqlRawHandler command.Parameters.Add(parameter); } - var rowsAffected = new List(); - var recordsets = new List>>(); + var rowsAffected = new List(); await using var reader = await command.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false); do { @@ -95,8 +102,7 @@ public sealed class SqlRawHandler } catch (DbException exception) { - var code = exception.GetType().GetProperty("Number")?.GetValue(exception) - ?? exception.ErrorCode; + var code = exception.GetType().GetProperty("Number")?.GetValue(exception) ?? exception.ErrorCode; ConsoleLogger.Error($"Błąd SQL {code}: {exception.Message}", exception); await SentryReporter.CaptureAsync(exception, scope => { diff --git a/src/SmartB2B.Sync.Service/SyncServiceRunner.cs b/src/SmartB2B.Sync.Service/SyncServiceRunner.cs new file mode 100644 index 0000000..29cbb35 --- /dev/null +++ b/src/SmartB2B.Sync.Service/SyncServiceRunner.cs @@ -0,0 +1,62 @@ +using SmartB2B.Sync.Contracts; +using SmartB2B.Sync.Service.Diagnostics; +using SmartB2B.Sync.Service.Orders; +using SmartB2B.Sync.Service.Rpc; +using SmartB2B.Sync.Service.Sql; +using WampSharp.V2.Rpc; + +namespace SmartB2B.Sync.Service; + +public sealed record SyncServiceOptions( + string ServiceName, + string ServiceVersion, + string RuntimeLabel, + string RuntimePath, + string Portal, + string WampServerUrl, + int ReconnectDelaySeconds, + string SqlConnectionString, + int SqlCommandTimeoutSeconds, + string LogDirectory, + string LogPrefix); + +public static class SyncServiceRunner +{ + public static async Task RunAsync( + SyncServiceOptions options, + IErpOrderAdapter? adapter, + ErpAdapterConfiguration? adapterConfiguration, + ErpAdapterInfo? adapterInfo, + CancellationToken cancellationToken) + { + var sql = new SqlRawHandler(options.SqlConnectionString, options.SqlCommandTimeoutSeconds); + var diagnostics = new DiagnosticsHandler( + options.ServiceName, + options.ServiceVersion, + options.RuntimeLabel, + options.RuntimePath, + adapterInfo, + options.LogDirectory, + options.LogPrefix); + + var operations = new List(); + if (adapter is not null && adapterConfiguration is not null) + { + var orders = new PlaceOrderHandler(adapter, adapterConfiguration); + operations.Add(new DelegateRpcOperation("eu.smartb2b.place_order", orders.HandleAsync)); + } + + operations.Add(new DelegateRpcOperation("eu.smartb2b.sql_raw", sql.HandleAsync)); + operations.Add(new DelegateRpcOperation("eu.smartb2b.sync.get_version", diagnostics.GetVersionAsync)); + operations.Add(new DelegateRpcOperation("eu.smartb2b.sync.get_info", diagnostics.GetInfoAsync)); + operations.Add(new DelegateRpcOperation("eu.smartb2b.sync.get_log", diagnostics.GetLogAsync)); + operations.Add(new DelegateRpcOperation("eu.smartb2b.sync.get_error_log", diagnostics.GetErrorLogAsync)); + + var client = new WampServiceClient( + options.WampServerUrl, + options.Portal, + TimeSpan.FromSeconds(options.ReconnectDelaySeconds), + operations); + await client.RunAsync(cancellationToken).ConfigureAwait(false); + } +} diff --git a/tests/SmartB2B.Enova.Tests/Program.cs b/tests/SmartB2B.Enova.Tests/Program.cs index b75d5d1..af22ce2 100644 --- a/tests/SmartB2B.Enova.Tests/Program.cs +++ b/tests/SmartB2B.Enova.Tests/Program.cs @@ -1,13 +1,14 @@ using System.Data.Common; using System.Reflection; using System.Runtime.Loader; -using SmartB2B.Enova.Contracts; +using SmartB2B.Sync.Contracts; +using SmartB2B.Sync.Service; using SmartB2B.Enova.Service; using SmartB2B.Enova.Service.Configuration; -using SmartB2B.Enova.Service.Orders; -using SmartB2B.Enova.Service.Rpc; +using SmartB2B.Sync.Service.Orders; +using SmartB2B.Sync.Service.Rpc; using SmartB2B.Enova.Service.Runtime; -using SmartB2B.Enova.Service.Sql; +using SmartB2B.Sync.Service.Sql; using WampSharp.Core.Serialization; using WampSharp.V2.Core; using WampSharp.V2.Core.Contracts; @@ -84,19 +85,25 @@ static Task SqlProviderIsSupported() static Task DatabaseRegistrationUsesConnectionString() { var directory = new DirectoryInfo(AppContext.BaseDirectory); - string? installationPath = null; + var installationCandidates = new List(); while (directory is not null) { - var candidate = Path.Combine(directory.FullName, "enova365 2604.4.4"); - if (File.Exists(Path.Combine(candidate, "Soneta.Business.dll"))) - { - installationPath = candidate; - break; - } - + installationCandidates.Add(Path.Combine(directory.FullName, "enova365 2604.4.4")); directory = directory.Parent; } + installationCandidates.Add(Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), + "Soneta", + "enova365 2604.4.4")); + installationCandidates.Add(Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), + "Soneta", + "enova365 2604.4.4")); + + var installationPath = installationCandidates.FirstOrDefault( + candidate => File.Exists(Path.Combine(candidate, "Soneta.Business.dll"))); + if (installationPath is null) { throw new InvalidOperationException("Nie znaleziono lokalnej instalacji enova365 do testu adaptera."); @@ -188,7 +195,7 @@ static Task MissingProduct() static Task MissingItems() { - var request = new OrderRequest { CustomerCode = "Abc", Items = [] }; + var request = new OrderRequest { CurrencyIso = "PLN", CustomerCode = "Abc", Items = [] }; AssertHasError(request, "co najmniej jedną"); return Task.CompletedTask; } @@ -214,7 +221,7 @@ static async Task PlaceOrderMapping() AssertEqual("PO/1", request.CustomerReference, "purchase_order_number"); AssertEqual(2, request.Items.Count, "liczba pozycji"); AssertEqual(12.5m, request.Items[0].Discount, "rabat"); - AssertEqual(120m, request.Items[0].UnitPrice, "cena netto"); + AssertEqual(120m, request.Items[0].UnitPriceNet, "cena netto"); } static async Task PlaceOrderKeywordResult() @@ -259,7 +266,7 @@ static async Task MissingCurrency() static async Task UnsupportedCurrency() { var handler = new PlaceOrderHandler(new FakeAdapter(), CreateConfiguration()); - var invocation = new RpcInvocation([], new Dictionary { ["currency_iso"] = "EUR" }); + var invocation = CreateInvocation("EUR"); await AssertWampError( handler.HandleAsync(invocation, CancellationToken.None), "eu.smartb2b.erp.currency_not_supported"); @@ -376,14 +383,14 @@ static Task PartialCredentialsDisablePlaceOrder() static Task DebugSwitchEnablesVerboseLogging() { - var options = CommandLineOptions.Parse(["/debug"]); + var options = ServiceCommandLine.Parse(["/debug"], "enova.json"); AssertEqual(true, options.VerboseLogging, "tryb szczegółowy"); return Task.CompletedTask; } static Task VerboseSwitchCanBeDisabled() { - var options = CommandLineOptions.Parse(["/verbose", "/noverbose"]); + var options = ServiceCommandLine.Parse(["/verbose", "/noverbose"], "enova.json"); AssertEqual(false, options.VerboseLogging, "wyłączony tryb szczegółowy"); return Task.CompletedTask; } @@ -424,11 +431,11 @@ static RuntimeSettings LoadRuntimeSettings(string credentialsJson, bool verboseL } } -static RpcInvocation CreateInvocation() => new( +static RpcInvocation CreateInvocation(string currency = "PLN") => new( [], new Dictionary { - ["currency_iso"] = "PLN", + ["currency_iso"] = currency, ["companyErpId"] = "ABC", ["warehouseErpId"] = "MAG", ["purchase_order_number"] = "PO/1", @@ -440,8 +447,8 @@ static RpcInvocation CreateInvocation() => new( } }); -static EnovaAdapterConfiguration CreateConfiguration() => new( - new EnovaConnectionOptions( +static ErpAdapterConfiguration CreateConfiguration() => new( + new ErpConnectionOptions( "Firma demo", "Administrator", "", @@ -457,6 +464,7 @@ static OrderRequest CreateValidRequest( string productCode = "BIKINI") => new() { + CurrencyIso = "PLN", CustomerCode = "Abc", CustomerReference = "KLIENT/TEST/1", Notes = "Test", @@ -468,7 +476,7 @@ static OrderRequest CreateValidRequest( { ProductCode = productCode, Quantity = quantity, - UnitPrice = unitPrice, + UnitPriceNet = unitPrice, Discount = discount } ] @@ -514,15 +522,24 @@ static void AssertEqual(object? expected, object? actual, string name) } } -file sealed class FakeAdapter : IEnovaOrderAdapter +file sealed class FakeAdapter : IErpOrderAdapter { public OrderRequest? LastRequest { get; private set; } - public EnovaAdapterInfo Initialize(EnovaAdapterConfiguration configuration) => - new("1.0.0", "2604.4.4.0", "2604.4.4.0", configuration.Connection.DatabaseName); + public ErpAdapterInfo Initialize(ErpAdapterConfiguration configuration) => + new("1.0.0", "enova365", "2604.4.4.0", configuration.Connection.DatabaseName, ["PLN"]); + + public void CheckConnection() { } + + public void Dispose() { } public OrderResult CreateOrder(OrderRequest request) { + if (!string.Equals(request.CurrencyIso, "PLN", StringComparison.OrdinalIgnoreCase)) + { + throw new ErpOperationException("eu.smartb2b.erp.currency_not_supported", "Waluta nie jest obsługiwana."); + } + LastRequest = request; return new OrderResult( 1, @@ -539,13 +556,17 @@ file sealed class FakeAdapter : IEnovaOrderAdapter } } -file sealed class FailingAdapter : IEnovaOrderAdapter +file sealed class FailingAdapter : IErpOrderAdapter { - public EnovaAdapterInfo Initialize(EnovaAdapterConfiguration configuration) => - new("1.0.0", "2604.4.4.0", "2604.4.4.0", configuration.Connection.DatabaseName); + public ErpAdapterInfo Initialize(ErpAdapterConfiguration configuration) => + new("1.0.0", "enova365", "2604.4.4.0", configuration.Connection.DatabaseName, ["PLN"]); + + public void CheckConnection() { } + + public void Dispose() { } public OrderResult CreateOrder(OrderRequest request) => - throw new EnovaOperationException( + throw new ErpOperationException( "eu.smartb2b.company_not_found", $"Nie znaleziono kontrahenta o kodzie '{request.CustomerCode}'."); } diff --git a/tests/SmartB2B.Enova.Tests/SmartB2B.Enova.Tests.csproj b/tests/SmartB2B.Enova.Tests/SmartB2B.Enova.Tests.csproj index f2f3386..5f51467 100644 --- a/tests/SmartB2B.Enova.Tests/SmartB2B.Enova.Tests.csproj +++ b/tests/SmartB2B.Enova.Tests/SmartB2B.Enova.Tests.csproj @@ -7,7 +7,8 @@ - + + diff --git a/tests/SmartB2B.Optima.IntegrationTests/Program.cs b/tests/SmartB2B.Optima.IntegrationTests/Program.cs new file mode 100644 index 0000000..5b393e4 --- /dev/null +++ b/tests/SmartB2B.Optima.IntegrationTests/Program.cs @@ -0,0 +1,209 @@ +using System.Text.Json; +using SmartB2B.Optima.Adapter; +using SmartB2B.Optima.Service.Configuration; +using SmartB2B.Sync.Contracts; +using SmartB2B.Sync.Service.Rpc; +using SmartB2B.Sync.Service.Sql; +using WampSharp.V2.Core.Contracts; + +var options = ParseArguments(args); +if (!options.TryGetValue("config", out var configPath) || string.IsNullOrWhiteSpace(configPath)) +{ + Console.Error.WriteLine( + "Użycie: --config [--negative-tests] [--write-order [--approved]] " + + "[--customer-id --product-code ]"); + return 2; +} + +var settings = OptimaServiceSettings.Load(Path.GetFullPath(configPath)); +var runtime = settings.ResolveRuntimeSettings(verboseLogging: true); +using var adapter = new OptimaOrderAdapter(runtime.InstallationPath); +var info = adapter.Initialize(runtime.AdapterConfiguration); +adapter.CheckConnection(); +Console.WriteLine( + $"PASS check-config: {info.ErpName} {info.ErpVersion}, baza {info.DatabaseName}, " + + $"architektura {info.Details?["Process bitness"]}."); + +var sql = new SqlRawHandler(runtime.SqlConnectionString, runtime.SqlCommandTimeoutSeconds); +var sqlResult = (SqlRawResult?)await sql.HandleAsync( + new RpcInvocation( + [], + new Dictionary + { + ["query"] = "SELECT @1 AS parameter_value; SELECT CAST(0x0102 AS varbinary(2)) AS binary_value;", + ["params"] = new object?[] { 123 } + }), + CancellationToken.None); +if (sqlResult?.Recordsets.Count != 2 || + sqlResult.Recordsets[0].Count != 1 || + sqlResult.Recordsets[1].Count != 1 || + Convert.ToInt32(sqlResult.Recordsets[0][0]["parameter_value"]) != 123 || + sqlResult.Recordsets[1][0]["binary_value"] is not IReadOnlyDictionary binary || + !string.Equals(Convert.ToString(binary["type"]), "Buffer", StringComparison.Ordinal) || + binary["data"] is not int[] { Length: 2 } bytes || + bytes[0] != 1 || + bytes[1] != 2) +{ + throw new InvalidOperationException("sql_raw nie zwrócił oczekiwanych parametrów, recordsetów lub danych binarnych."); +} +await ExpectSqlErrorAsync(sql); +Console.WriteLine("PASS sql_raw: parametry, dwa recordsety, wartość binarna i stabilny błąd SQL."); + +var needsTestData = options.ContainsKey("negative-tests") || options.ContainsKey("write-order"); +options.TryGetValue("customer-id", out var customerId); +options.TryGetValue("product-code", out var productCode); +if (needsTestData && (string.IsNullOrWhiteSpace(customerId) || string.IsNullOrWhiteSpace(productCode))) +{ + Console.Error.WriteLine("Przy --negative-tests lub --write-order wymagane są --customer-id i --product-code."); + return 2; +} + +if (options.ContainsKey("negative-tests")) +{ + RunNegativeTests(adapter, runtime.AdapterConfiguration, customerId!, productCode!); + Console.WriteLine("PASS błędy ERP: kontrahent, magazyn, waluta i towar."); +} + +if (!options.ContainsKey("write-order")) +{ + Console.WriteLine("Test zakończony bez zapisu. Dodaj --write-order, aby utworzyć RO w buforze."); + return 0; +} + +var saveMode = options.ContainsKey("approved") ? OrderSaveMode.Approved : OrderSaveMode.Buffer; +if (saveMode == OrderSaveMode.Buffer && runtime.AdapterConfiguration.SaveMode != OrderSaveMode.Buffer) +{ + Console.Error.WriteLine("Runner integracyjny zezwala na zapis wyłącznie przy optima.saveMode=Buffer."); + return 2; +} + +var reference = $"SMARTB2B-IT-{DateTime.UtcNow:yyyyMMdd-HHmmss}"; +var request = CreateRequest(runtime.AdapterConfiguration, customerId!, productCode!, "PLN", reference, saveMode); + +var result = adapter.CreateOrder(request); +Console.WriteLine("PASS place_order:"); +Console.WriteLine(JsonSerializer.Serialize(new +{ + order_erp_id = result.Id, + order_erp_symbol = result.Number, + value_netto = result.Net, + value_brutto = result.Gross, + reference, + save_mode = result.SaveMode.ToString() +}, new JsonSerializerOptions { WriteIndented = true })); +return 0; + +static void RunNegativeTests( + OptimaOrderAdapter adapter, + ErpAdapterConfiguration configuration, + string customerId, + string productCode) +{ + ExpectError( + () => adapter.CreateOrder(CreateRequest(configuration, "2147483647", productCode, "PLN", "SMARTB2B-ERR-KNT")), + "eu.smartb2b.company_not_found"); + ExpectError( + () => adapter.CreateOrder(CreateRequest( + configuration with { DefaultWarehouseCode = "2147483647" }, + customerId, + productCode, + "PLN", + "SMARTB2B-ERR-MAG")), + "eu.smartb2b.erp.warehouse_not_found"); + ExpectError( + () => adapter.CreateOrder(CreateRequest(configuration, customerId, productCode, "ZZZ", "SMARTB2B-ERR-WAL")), + "eu.smartb2b.erp.currency_not_found"); + ExpectError( + () => adapter.CreateOrder(CreateRequest(configuration, customerId, "SMARTB2B_MISSING", "PLN", "SMARTB2B-ERR-TWR")), + "eu.smartb2b.product_not_found"); +} + +static OrderRequest CreateRequest( + ErpAdapterConfiguration configuration, + string customerId, + string productCode, + string currency, + string reference, + OrderSaveMode saveMode = OrderSaveMode.Buffer) => new() +{ + CurrencyIso = currency, + CustomerCode = customerId, + CustomerReference = reference, + Notes = "Automatyczny test integracyjny SmartB2B", + DocumentDefinition = configuration.DocumentDefinition, + WarehouseCode = configuration.DefaultWarehouseCode, + SaveMode = saveMode, + Items = + [ + new OrderLineRequest + { + ProductCode = productCode, + Quantity = 2m, + UnitPriceNet = 10m, + UnitPriceGross = 10m, + Discount = 5m + } + ] +}; + +static void ExpectError(Action action, string expectedUri) +{ + try + { + action(); + throw new InvalidOperationException($"Oczekiwano błędu {expectedUri}."); + } + catch (ErpOperationException exception) when (exception.ErrorUri == expectedUri) + { + } +} + +static async Task ExpectSqlErrorAsync(SqlRawHandler sql) +{ + try + { + _ = await sql.HandleAsync( + new RpcInvocation( + [], + new Dictionary + { + ["query"] = "SELECT * FROM CDN.__SMARTB2B_MISSING_TABLE__" + }), + CancellationToken.None); + throw new InvalidOperationException("Oczekiwano błędu eu.smartb2b.sql_error."); + } + catch (WampException exception) when (exception.ErrorUri == "eu.smartb2b.sql_error") + { + } +} + +static Dictionary ParseArguments(string[] arguments) +{ + var result = new Dictionary(StringComparer.OrdinalIgnoreCase); + for (var index = 0; index < arguments.Length; index++) + { + var argument = arguments[index]; + if (!argument.StartsWith("--", StringComparison.Ordinal)) + { + throw new ArgumentException($"Nieznany argument: {argument}"); + } + + var name = argument[2..]; + if (string.Equals(name, "write-order", StringComparison.OrdinalIgnoreCase) || + string.Equals(name, "approved", StringComparison.OrdinalIgnoreCase) || + string.Equals(name, "negative-tests", StringComparison.OrdinalIgnoreCase)) + { + result[name] = null; + continue; + } + + if (++index >= arguments.Length) + { + throw new ArgumentException($"Brak wartości argumentu {argument}."); + } + + result[name] = arguments[index]; + } + + return result; +} diff --git a/tests/SmartB2B.Optima.IntegrationTests/SmartB2B.Optima.IntegrationTests.csproj b/tests/SmartB2B.Optima.IntegrationTests/SmartB2B.Optima.IntegrationTests.csproj new file mode 100644 index 0000000..1046dd2 --- /dev/null +++ b/tests/SmartB2B.Optima.IntegrationTests/SmartB2B.Optima.IntegrationTests.csproj @@ -0,0 +1,14 @@ + + + Exe + net8.0-windows + enable + enable + x64 + + + + + + + diff --git a/tests/SmartB2B.Optima.Tests/Program.cs b/tests/SmartB2B.Optima.Tests/Program.cs new file mode 100644 index 0000000..30fc72f --- /dev/null +++ b/tests/SmartB2B.Optima.Tests/Program.cs @@ -0,0 +1,319 @@ +using System.Collections.Concurrent; +using SmartB2B.Optima.Adapter; +using SmartB2B.Sync.Contracts; +using SmartB2B.Sync.Service.Orders; +using SmartB2B.Sync.Service.Rpc; + +var tests = new (string Name, Func Run)[] +{ + ("Cena netto pozostaje zgodna wstecznie", NetPriceIsBackwardCompatible), + ("Cena brutto jest obsługiwana addytywnie", GrossPriceIsAccepted), + ("Brak obu cen jest odrzucany", MissingPricesAreRejected), + ("Ujemna cena brutto jest odrzucana", NegativeGrossPriceIsRejected), + ("Tryb netto wybiera price_netto", NetDocumentSelectsNetPrice), + ("Tryb brutto wybiera price_brutto", GrossDocumentSelectsGrossPrice), + ("Brak ceny wymaganej przez definicję jest stabilnym błędem", RequiredPriceIsEnforced), + ("Handler przekazuje pełny kontrakt do Optimy", HandlerMapsOptimaContract), + ("Wynik Optimy zachowuje kwargs WAMP", HandlerReturnsKeywordResult), + ("Operacje zamówień są serializowane", ConcurrentOrdersAreSerialized), + ("Fasada COM działa na jednym wątku STA", FacadeRunsOnSingleStaThread), + ("Adapter serializuje bezpośrednie wywołania COM", AdapterSerializesComCalls) +}; + +var failures = 0; +foreach (var test in tests) +{ + try + { + await test.Run(); + Console.WriteLine($"PASS: {test.Name}"); + } + catch (Exception exception) + { + failures++; + Console.Error.WriteLine($"FAIL: {test.Name}: {exception.Message}"); + } +} + +Console.WriteLine($"Wynik: {tests.Length - failures}/{tests.Length} testów zaliczonych."); +return failures == 0 ? 0 : 1; + +static Task NetPriceIsBackwardCompatible() +{ + AssertNoErrors(CreateRequest(net: 10m, gross: null)); + return Task.CompletedTask; +} + +static Task GrossPriceIsAccepted() +{ + AssertNoErrors(CreateRequest(net: null, gross: 12.30m)); + return Task.CompletedTask; +} + +static Task MissingPricesAreRejected() +{ + AssertHasError(CreateRequest(net: null, gross: null), "price_netto lub price_brutto"); + return Task.CompletedTask; +} + +static Task NegativeGrossPriceIsRejected() +{ + AssertHasError(CreateRequest(net: null, gross: -0.01m), "price_brutto"); + return Task.CompletedTask; +} + +static Task NetDocumentSelectsNetPrice() +{ + AssertEqual(10m, OptimaOrderAdapter.SelectUnitPrice(1, CreateLine(10m, 12.30m), 0), "cena netto"); + return Task.CompletedTask; +} + +static Task GrossDocumentSelectsGrossPrice() +{ + AssertEqual(12.30m, OptimaOrderAdapter.SelectUnitPrice(2, CreateLine(10m, 12.30m), 0), "cena brutto"); + return Task.CompletedTask; +} + +static Task RequiredPriceIsEnforced() +{ + try + { + _ = OptimaOrderAdapter.SelectUnitPrice(2, CreateLine(10m, null), 3); + throw new InvalidOperationException("Oczekiwano błędu wymaganej ceny brutto."); + } + catch (ErpOperationException exception) when ( + exception.ErrorUri == "eu.smartb2b.erp.invalid_order_lines" && + exception.Message.Contains("lines[3].price_brutto", StringComparison.Ordinal)) + { + return Task.CompletedTask; + } +} + +static async Task HandlerMapsOptimaContract() +{ + using var adapter = new CapturingAdapter(); + var handler = new PlaceOrderHandler(adapter, CreateConfiguration()); + await handler.HandleAsync(CreateInvocation(), CancellationToken.None); + var request = adapter.LastRequest ?? throw new InvalidOperationException("Adapter nie otrzymał zamówienia."); + AssertEqual("EUR", request.CurrencyIso, "waluta"); + AssertEqual("123", request.CustomerCode, "kontrahent"); + AssertEqual("7", request.WarehouseCode, "magazyn"); + AssertEqual(100m, request.Items[0].UnitPriceNet, "netto"); + AssertEqual(123m, request.Items[0].UnitPriceGross, "brutto"); +} + +static async Task HandlerReturnsKeywordResult() +{ + using var adapter = new CapturingAdapter(); + var handler = new PlaceOrderHandler(adapter, CreateConfiguration()); + var result = await handler.HandleAsync(CreateInvocation(), CancellationToken.None) as KeywordResult + ?? throw new InvalidOperationException("Brak wyniku kwargs."); + AssertEqual(42, result.Values["order_erp_id"], "ID"); + AssertEqual("RO/1/2026", result.Values["order_erp_symbol"], "numer"); + AssertEqual(100m, result.Values["value_netto"], "netto"); + AssertEqual(123m, result.Values["value_brutto"], "brutto"); +} + +static async Task ConcurrentOrdersAreSerialized() +{ + using var adapter = new CapturingAdapter(delayMilliseconds: 100); + var handler = new PlaceOrderHandler(adapter, CreateConfiguration()); + await Task.WhenAll( + handler.HandleAsync(CreateInvocation(), CancellationToken.None), + handler.HandleAsync(CreateInvocation(), CancellationToken.None)); + AssertEqual(1, adapter.MaximumConcurrency, "maksymalna równoległość adaptera"); +} + +static Task FacadeRunsOnSingleStaThread() +{ + var facade = new CapturingComFacade(); + using var adapter = new OptimaOrderAdapter("C:\\Optima-Test", facade); + var info = adapter.Initialize(CreateConfiguration()); + adapter.CheckConnection(); + _ = adapter.CreateOrder(CreateRequest(10m, 12.30m)); + + AssertEqual(1, facade.ThreadIds.Distinct().Count(), "liczba wątków COM"); + AssertEqual(ApartmentState.STA, facade.ApartmentStates.Distinct().Single(), "apartment COM"); + AssertEqual("Buffer", info.Details?["Save mode"], "tryb zapisu w diagnostyce"); + return Task.CompletedTask; +} + +static async Task AdapterSerializesComCalls() +{ + var facade = new CapturingComFacade(delayMilliseconds: 100); + using var adapter = new OptimaOrderAdapter("C:\\Optima-Test", facade); + adapter.Initialize(CreateConfiguration()); + var request = CreateRequest(10m, 12.30m); + + await Task.WhenAll( + Task.Run(() => adapter.CreateOrder(request)), + Task.Run(() => adapter.CreateOrder(request))); + + AssertEqual(1, facade.MaximumConcurrency, "maksymalna równoległość fasady COM"); +} + +static RpcInvocation CreateInvocation() => new( + [], + new Dictionary + { + ["currency_iso"] = "eur", + ["companyErpId"] = "123", + ["warehouseErpId"] = "7", + ["purchase_order_number"] = "PO/OPTIMA/1", + ["notes"] = "Test", + ["lines"] = new[] + { + new PlaceOrderLine + { + Symbol = "TOWAR", + Quantity = 2m, + PriceNetto = 100m, + PriceBrutto = 123m, + Discount = 12.5m + } + } + }); + +static ErpAdapterConfiguration CreateConfiguration() => new( + new ErpConnectionOptions("Firma demo", "ADMIN", "", "Server=.;Database=demo"), + "RO", + "1", + OrderSaveMode.Buffer); + +static OrderRequest CreateRequest(decimal? net, decimal? gross) => new() +{ + CurrencyIso = "PLN", + CustomerCode = "123", + DocumentDefinition = "RO", + WarehouseCode = "1", + Items = [CreateLine(net, gross)] +}; + +static OrderLineRequest CreateLine(decimal? net, decimal? gross) => new() +{ + ProductCode = "TOWAR", + Quantity = 1m, + UnitPriceNet = net, + UnitPriceGross = gross, + Discount = 0m +}; + +static void AssertNoErrors(OrderRequest request) +{ + var errors = OrderValidator.Validate(request); + if (errors.Count > 0) throw new InvalidOperationException(string.Join(" | ", errors)); +} + +static void AssertHasError(OrderRequest request, string text) +{ + var errors = OrderValidator.Validate(request); + if (!errors.Any(error => error.Contains(text, StringComparison.OrdinalIgnoreCase))) + { + throw new InvalidOperationException($"Oczekiwano '{text}', otrzymano: {string.Join(" | ", errors)}"); + } +} + +static void AssertEqual(object? expected, object? actual, string name) +{ + if (!Equals(expected, actual)) + { + throw new InvalidOperationException($"{name}: oczekiwano '{expected}', otrzymano '{actual}'."); + } +} + +file sealed class CapturingAdapter : IErpOrderAdapter +{ + private readonly int _delayMilliseconds; + private int _concurrency; + private int _maximumConcurrency; + + public CapturingAdapter(int delayMilliseconds = 0) => _delayMilliseconds = delayMilliseconds; + + public OrderRequest? LastRequest { get; private set; } + public int MaximumConcurrency => _maximumConcurrency; + + public ErpAdapterInfo Initialize(ErpAdapterConfiguration configuration) => + new("1.0", "Comarch ERP Optima", "2026.5.1", configuration.Connection.DatabaseName, []); + + public void CheckConnection() { } + + public OrderResult CreateOrder(OrderRequest request) + { + var active = Interlocked.Increment(ref _concurrency); + InterlockedExtensions.Max(ref _maximumConcurrency, active); + try + { + LastRequest = request; + if (_delayMilliseconds > 0) Thread.Sleep(_delayMilliseconds); + return new OrderResult( + 42, "RO/1/2026", request.SaveMode, request.CustomerCode, + request.WarehouseCode ?? "1", request.CustomerReference, request.Items.Count, + 100m, 23m, 123m, request.Items.Any(line => line.Discount > 0)); + } + finally + { + Interlocked.Decrement(ref _concurrency); + } + } + + public void Dispose() { } +} + +file static class InterlockedExtensions +{ + public static void Max(ref int target, int value) + { + while (true) + { + var current = Volatile.Read(ref target); + if (current >= value || Interlocked.CompareExchange(ref target, value, current) == current) return; + } + } +} + +file sealed class CapturingComFacade : IOptimaComFacade +{ + private readonly int _delayMilliseconds; + private int _concurrency; + private int _maximumConcurrency; + + public CapturingComFacade(int delayMilliseconds = 0) => _delayMilliseconds = delayMilliseconds; + + public ConcurrentBag ThreadIds { get; } = []; + public ConcurrentBag ApartmentStates { get; } = []; + public int MaximumConcurrency => _maximumConcurrency; + + public OptimaRuntimeInfo InspectRuntime(string installationPath) => + new("2026.5.1.6382", "CDNBase.Application", "x64"); + + public void CheckConnection(ErpAdapterConfiguration configuration) => Capture(() => { }); + + public OrderResult CreateOrder(ErpAdapterConfiguration configuration, OrderRequest request) => Capture(() => + new OrderResult( + 84, "RO/2/2026", request.SaveMode, request.CustomerCode, + request.WarehouseCode ?? "1", request.CustomerReference, request.Items.Count, + 10m, 2.30m, 12.30m, false)); + + private T Capture(Func action) + { + var active = Interlocked.Increment(ref _concurrency); + InterlockedExtensions.Max(ref _maximumConcurrency, active); + try + { + ThreadIds.Add(Environment.CurrentManagedThreadId); + ApartmentStates.Add(Thread.CurrentThread.GetApartmentState()); + if (_delayMilliseconds > 0) Thread.Sleep(_delayMilliseconds); + return action(); + } + finally + { + Interlocked.Decrement(ref _concurrency); + } + } + + private void Capture(Action action) => Capture(() => + { + action(); + return true; + }); +} diff --git a/tests/SmartB2B.Optima.Tests/SmartB2B.Optima.Tests.csproj b/tests/SmartB2B.Optima.Tests/SmartB2B.Optima.Tests.csproj new file mode 100644 index 0000000..3b4595e --- /dev/null +++ b/tests/SmartB2B.Optima.Tests/SmartB2B.Optima.Tests.csproj @@ -0,0 +1,13 @@ + + + Exe + net8.0-windows + enable + enable + + + + + + +