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; }