Add shared ERP sync core and Optima adapter
This commit is contained in:
209
tests/SmartB2B.Optima.IntegrationTests/Program.cs
Normal file
209
tests/SmartB2B.Optima.IntegrationTests/Program.cs
Normal file
@@ -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 <optima.json> [--negative-tests] [--write-order [--approved]] " +
|
||||
"[--customer-id <ID> --product-code <KOD>]");
|
||||
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<string, object?>
|
||||
{
|
||||
["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<string, object> 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<string, object?>
|
||||
{
|
||||
["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<string, string?> ParseArguments(string[] arguments)
|
||||
{
|
||||
var result = new Dictionary<string, string?>(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;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="../../src/SmartB2B.Optima.Adapter/SmartB2B.Optima.Adapter.csproj" />
|
||||
<ProjectReference Include="../../src/SmartB2B.Optima.Service/SmartB2B.Optima.Service.csproj" />
|
||||
<ProjectReference Include="../../src/SmartB2B.Sync.Contracts/SmartB2B.Sync.Contracts.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user