diff --git a/src/KArtSell.Host/KArtSell.Host.csproj b/src/KArtSell.Host/KArtSell.Host.csproj
index 2e8d1492..e5b986a8 100644
--- a/src/KArtSell.Host/KArtSell.Host.csproj
+++ b/src/KArtSell.Host/KArtSell.Host.csproj
@@ -4,16 +4,18 @@
+
+
+
+
-
-
-
-
diff --git a/src/KArtSell.Modules.ModelOperations/ApprovalWorkflow/ApprovalSql.cs b/src/KArtSell.Modules.ModelOperations/ApprovalWorkflow/ApprovalSql.cs
index 897d2008..62ed678c 100644
--- a/src/KArtSell.Modules.ModelOperations/ApprovalWorkflow/ApprovalSql.cs
+++ b/src/KArtSell.Modules.ModelOperations/ApprovalWorkflow/ApprovalSql.cs
@@ -69,7 +69,7 @@ public class ApprovalSql
const string sql = """
INSERT INTO model_operations.approval_proposals
(id, model_id, status, created_by, created_at, justification, effective_at, published_at, revision, correlation_id)
- VALUES (@id, @modelId, @status, @createdBy, @createdAt, @justification, @effectiveAt, @publishedAt, 1, @correlationId)
+ VALUES (@id, @modelId, @status, @createdBy, @createdAt, @justification, @effectiveAt::date, @publishedAt, 1, @correlationId)
""";
await conn.ExecuteAsync(sql, new
@@ -80,7 +80,7 @@ public class ApprovalSql
createdBy,
createdAt = _clock.UtcNow,
justification,
- effectiveAt,
+ effectiveAt = effectiveAt.ToString("yyyy-MM-dd"), // Dapper: DateOnly cannot be used as a parameter value directly
publishedAt,
correlationId
});
diff --git a/src/KArtSell.Modules.ModelOperations/Compliance/AuditSql.cs b/src/KArtSell.Modules.ModelOperations/Compliance/AuditSql.cs
index bebdad94..f7d69e1c 100644
--- a/src/KArtSell.Modules.ModelOperations/Compliance/AuditSql.cs
+++ b/src/KArtSell.Modules.ModelOperations/Compliance/AuditSql.cs
@@ -135,7 +135,7 @@ public class AuditSql
// Get paginated results
var sql = $"""
SELECT id, event_type, entity_type, entity_id, actor_email, actor_role, event_at,
- result, error_message, details, evidence_links, ip_address, user_agent,
+ result, error_message, details, evidence_links, ip_address::text as ip_address, user_agent,
published_at, correlation_id, revision
FROM compliance.audit_events
WHERE {whereClause}
@@ -162,7 +162,7 @@ public class AuditSql
{
const string sql = """
SELECT id, event_type, entity_type, entity_id, actor_email, actor_role, event_at,
- result, error_message, details, evidence_links, ip_address, user_agent,
+ result, error_message, details, evidence_links, ip_address::text as ip_address, user_agent,
published_at, correlation_id, revision
FROM compliance.audit_events
WHERE id = @EventId
diff --git a/src/KArtSell.Modules.ModelOperations/Compliance/GdprRetention.cs b/src/KArtSell.Modules.ModelOperations/Compliance/GdprRetention.cs
index e2d7b884..0adccb22 100644
--- a/src/KArtSell.Modules.ModelOperations/Compliance/GdprRetention.cs
+++ b/src/KArtSell.Modules.ModelOperations/Compliance/GdprRetention.cs
@@ -10,7 +10,7 @@ public class GdprRetention
public Guid EventId { get; set; }
public Guid? CustomerId { get; set; }
public string[]? DataCategories { get; set; } // PII, EMAIL, TRADING_HISTORY, PORTFOLIO_DATA, etc.
- public DateTime RetentionEndsAt { get; set; }
+ public DateOnly RetentionEndsAt { get; set; }
public required string PurgeStatus { get; set; } // PENDING, PURGED, EXCEPTION
public DateTime? PurgedAt { get; set; }
public string? ExceptionReason { get; set; }
diff --git a/src/KArtSell.Modules.ModelOperations/TradeExecution/Trade.cs b/src/KArtSell.Modules.ModelOperations/TradeExecution/Trade.cs
index d7ce3783..49a73361 100644
--- a/src/KArtSell.Modules.ModelOperations/TradeExecution/Trade.cs
+++ b/src/KArtSell.Modules.ModelOperations/TradeExecution/Trade.cs
@@ -26,7 +26,7 @@ public class Trade
public decimal? Commission { get; set; }
public decimal? NetProceeds { get; set; }
public string? ErrorMessage { get; set; }
- public JsonElement? KisResponse { get; set; }
+ public string? KisResponse { get; set; }
public DateTime? ExecutionTimestamp { get; set; }
public DateTime? SettlementTimestamp { get; set; }
public DateTime PublishedAt { get; set; }
@@ -55,14 +55,14 @@ public class Trade
{
Status = TradeStatus.Submitted;
KisOrderId = kisOrderId;
- KisResponse = response;
+ KisResponse = response.ToString();
Revision++;
}
public void MarkAccepted(JsonElement response)
{
Status = TradeStatus.Accepted;
- KisResponse = response;
+ KisResponse = response.ToString();
Revision++;
}
@@ -73,7 +73,7 @@ public class Trade
TotalAmount = executedQty * unitPrice;
Status = executedQty >= Quantity ? TradeStatus.FullyFilled : TradeStatus.PartiallyFilled;
ExecutionTimestamp = now;
- KisResponse = response;
+ KisResponse = response.ToString();
Revision++;
}
@@ -98,7 +98,7 @@ public class Trade
public void MarkErrored(KisTradeExecutionException exception)
{
ErrorMessage = exception.Message;
- KisResponse = exception.KisResponse;
+ KisResponse = exception.KisResponse?.ToString();
Revision++;
}
}
diff --git a/src/KArtSell.Modules.ModelOperations/TradeExecution/TradeHandlers.cs b/src/KArtSell.Modules.ModelOperations/TradeExecution/TradeHandlers.cs
index 1179e413..21aa73b3 100644
--- a/src/KArtSell.Modules.ModelOperations/TradeExecution/TradeHandlers.cs
+++ b/src/KArtSell.Modules.ModelOperations/TradeExecution/TradeHandlers.cs
@@ -57,14 +57,7 @@ public class SubmitTradeHandler
);
trade.MarkSubmitted(orderId, response);
- await _sql.UpdateTradeStatusAsync(
- trade.Id,
- TradeStatus.Submitted,
- response,
- null,
- command.CorrelationId,
- ct
- );
+ await _sql.UpdateTradeStatusAsync(trade, response, null, ct);
await PublishEventAsync(
"TradeSubmitted",
@@ -84,14 +77,7 @@ public class SubmitTradeHandler
catch (KisTradeExecutionException ex)
{
trade.MarkErrored(ex);
- await _sql.UpdateTradeStatusAsync(
- trade.Id,
- trade.Status,
- ex.KisResponse,
- ex.Message,
- command.CorrelationId,
- ct
- );
+ await _sql.UpdateTradeStatusAsync(trade, ex.KisResponse, ex.Message, ct);
_logger.LogError(
"Trade submission failed: {TradeId} {Classification}",
@@ -163,14 +149,7 @@ public class PollTradeStatusHandler
trade.MarkFilled(executedQty, unitPrice, response, _clock.UtcNow.UtcDateTime);
}
- await _sql.UpdateTradeStatusAsync(
- trade.Id,
- trade.Status,
- response,
- null,
- command.CorrelationId,
- ct
- );
+ await _sql.UpdateTradeStatusAsync(trade, response, null, ct);
if (trade.Status is TradeStatus.FullyFilled)
{
@@ -195,14 +174,7 @@ public class PollTradeStatusHandler
}
catch (KisTradeExecutionException ex)
{
- await _sql.UpdateTradeStatusAsync(
- trade.Id,
- trade.Status,
- ex.KisResponse,
- ex.Message,
- command.CorrelationId,
- ct
- );
+ await _sql.UpdateTradeStatusAsync(trade, ex.KisResponse, ex.Message, ct);
_logger.LogError("Failed to poll trade status: {TradeId}", trade.Id);
}
@@ -262,14 +234,7 @@ public class ConfirmSettlementHandler
if (success)
{
trade.MarkConfirmed(_clock.UtcNow.UtcDateTime, command.Commission);
- await _sql.UpdateTradeStatusAsync(
- trade.Id,
- TradeStatus.Confirmed,
- response,
- null,
- command.CorrelationId,
- ct
- );
+ await _sql.UpdateTradeStatusAsync(trade, response, null, ct);
await TradeOutboxPublisher.PublishAsync(
_connectionFactory,
@@ -290,14 +255,7 @@ public class ConfirmSettlementHandler
}
catch (KisTradeExecutionException ex)
{
- await _sql.UpdateTradeStatusAsync(
- trade.Id,
- trade.Status,
- ex.KisResponse,
- ex.Message,
- command.CorrelationId,
- ct
- );
+ await _sql.UpdateTradeStatusAsync(trade, ex.KisResponse, ex.Message, ct);
_logger.LogError("Failed to confirm settlement: {TradeId}", trade.Id);
}
diff --git a/src/KArtSell.Modules.ModelOperations/TradeExecution/TradeSql.cs b/src/KArtSell.Modules.ModelOperations/TradeExecution/TradeSql.cs
index 542ec168..b1df1a00 100644
--- a/src/KArtSell.Modules.ModelOperations/TradeExecution/TradeSql.cs
+++ b/src/KArtSell.Modules.ModelOperations/TradeExecution/TradeSql.cs
@@ -12,7 +12,7 @@ public interface ITradeSql
Task> GetTradesByStatusAsync(TradeStatus status, Guid correlationId, CancellationToken ct = default);
Task> GetTradesByDecisionIdAsync(Guid sellDecisionId, Guid correlationId, CancellationToken ct = default);
Task InsertTradeAsync(Trade trade, CancellationToken ct = default);
- Task UpdateTradeStatusAsync(Guid tradeId, TradeStatus newStatus, JsonElement? kisResponse, string? errorMessage, Guid correlationId, CancellationToken ct = default);
+ Task UpdateTradeStatusAsync(Trade trade, JsonElement? kisResponse, string? errorMessage, CancellationToken ct = default);
Task CountTradesByStatusAsync(TradeStatus status, CancellationToken ct = default);
}
@@ -21,6 +21,16 @@ public class TradeSql : ITradeSql
private readonly NpgsqlDataSource _dataSource;
private readonly ILogger _logger;
+ static TradeSql()
+ {
+ // KArtSell.BuildingBlocks.Data.DapperBootstrap sets this via [ModuleInitializer], but that
+ // only fires once its assembly is actually loaded into the process. Nothing in this class
+ // references a BuildingBlocks type, so under test isolation (or any host that queries Trade
+ // before touching BuildingBlocks) that assembly load - and the mapping - can be skipped,
+ // silently nulling out every snake_case column (kis_order_id, sell_decision_id, ...).
+ Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true;
+ }
+
public TradeSql(NpgsqlDataSource dataSource, ILogger logger)
{
_dataSource = dataSource;
@@ -33,7 +43,7 @@ public class TradeSql : ITradeSql
const string sql = """
SELECT id, sell_decision_id, kis_order_id, status, quantity, executed_quantity,
- unit_price, total_amount, commission, net_proceeds, error_message, kis_response,
+ unit_price, total_amount, commission, net_proceeds, error_message, kis_response::text as kis_response,
execution_timestamp, settlement_timestamp, published_at, correlation_id, revision
FROM model_operations.trades
WHERE id = @tradeId
@@ -61,7 +71,7 @@ public class TradeSql : ITradeSql
const string sql = """
SELECT id, sell_decision_id, kis_order_id, status, quantity, executed_quantity,
- unit_price, total_amount, commission, net_proceeds, error_message, kis_response,
+ unit_price, total_amount, commission, net_proceeds, error_message, kis_response::text as kis_response,
execution_timestamp, settlement_timestamp, published_at, correlation_id, revision
FROM model_operations.trades
WHERE kis_order_id = @kisOrderId
@@ -82,7 +92,7 @@ public class TradeSql : ITradeSql
const string sql = """
SELECT id, sell_decision_id, kis_order_id, status, quantity, executed_quantity,
- unit_price, total_amount, commission, net_proceeds, error_message, kis_response,
+ unit_price, total_amount, commission, net_proceeds, error_message, kis_response::text as kis_response,
execution_timestamp, settlement_timestamp, published_at, correlation_id, revision
FROM model_operations.trades
WHERE status = @status
@@ -102,7 +112,7 @@ public class TradeSql : ITradeSql
const string sql = """
SELECT id, sell_decision_id, kis_order_id, status, quantity, executed_quantity,
- unit_price, total_amount, commission, net_proceeds, error_message, kis_response,
+ unit_price, total_amount, commission, net_proceeds, error_message, kis_response::text as kis_response,
execution_timestamp, settlement_timestamp, published_at, correlation_id, revision
FROM model_operations.trades
WHERE sell_decision_id = @sellDecisionId
@@ -143,7 +153,7 @@ public class TradeSql : ITradeSql
trade.Commission,
trade.NetProceeds,
trade.ErrorMessage,
- kisResponse = trade.KisResponse?.ToString(),
+ trade.KisResponse,
trade.ExecutionTimestamp,
trade.SettlementTimestamp,
trade.PublishedAt,
@@ -155,11 +165,9 @@ public class TradeSql : ITradeSql
}
public async Task UpdateTradeStatusAsync(
- Guid tradeId,
- TradeStatus newStatus,
+ Trade trade,
JsonElement? kisResponse,
string? errorMessage,
- Guid correlationId,
CancellationToken ct = default)
{
using var connection = await _dataSource.OpenConnectionAsync(ct);
@@ -173,6 +181,14 @@ public class TradeSql : ITradeSql
UPDATE model_operations.trades
SET status = @newStatus,
+ kis_order_id = COALESCE(@kisOrderId, kis_order_id),
+ executed_quantity = COALESCE(@executedQuantity, executed_quantity),
+ unit_price = COALESCE(@unitPrice, unit_price),
+ total_amount = COALESCE(@totalAmount, total_amount),
+ commission = COALESCE(@commission, commission),
+ net_proceeds = COALESCE(@netProceeds, net_proceeds),
+ execution_timestamp = COALESCE(@executionTimestamp, execution_timestamp),
+ settlement_timestamp = COALESCE(@settlementTimestamp, settlement_timestamp),
kis_response = COALESCE(@kisResponse::jsonb, kis_response),
error_message = COALESCE(@errorMessage, error_message),
revision = revision + 1
@@ -182,14 +198,22 @@ public class TradeSql : ITradeSql
await connection.ExecuteAsync(sql, new
{
id = Guid.NewGuid(),
- tradeId,
- newStatus = newStatus.ToString(),
+ tradeId = trade.Id,
+ newStatus = trade.Status.ToString(),
+ kisOrderId = trade.KisOrderId,
+ executedQuantity = trade.ExecutedQuantity,
+ unitPrice = trade.UnitPrice,
+ totalAmount = trade.TotalAmount,
+ commission = trade.Commission,
+ netProceeds = trade.NetProceeds,
+ executionTimestamp = trade.ExecutionTimestamp,
+ settlementTimestamp = trade.SettlementTimestamp,
kisResponse = kisResponse?.ToString(),
errorMessage,
- correlationId
+ correlationId = trade.CorrelationId
});
- _logger.LogInformation("Updated trade {TradeId} status to {Status}", tradeId, newStatus);
+ _logger.LogInformation("Updated trade {TradeId} status to {Status}", trade.Id, trade.Status);
}
public async Task CountTradesByStatusAsync(TradeStatus status, CancellationToken ct = default)
diff --git a/tests/KArtSell.Integration.Tests/ApprovalWorkflow/ApprovalWorkflowTests.cs b/tests/KArtSell.Integration.Tests/ApprovalWorkflow/ApprovalWorkflowTests.cs
index 791498f2..ee9440fb 100644
--- a/tests/KArtSell.Integration.Tests/ApprovalWorkflow/ApprovalWorkflowTests.cs
+++ b/tests/KArtSell.Integration.Tests/ApprovalWorkflow/ApprovalWorkflowTests.cs
@@ -3,6 +3,7 @@ namespace KArtSell.Integration.Tests.ApprovalWorkflow;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
+using Dapper;
using Xunit;
using KArtSell.BuildingBlocks.Time;
using KArtSell.Modules.ModelOperations.ApprovalWorkflow;
@@ -165,6 +166,7 @@ public class ApprovalWorkflowTests : IAsyncLifetime
var id = Guid.NewGuid();
var modelId = Guid.NewGuid();
var correlationId = Guid.NewGuid();
+ await SeedModelAsync(modelId);
// Act
await _sql.InsertProposalAsync(
@@ -185,6 +187,15 @@ public class ApprovalWorkflowTests : IAsyncLifetime
Assert.Equal(modelId, retrieved.ModelId);
Assert.Equal(correlationId, retrieved.CorrelationId);
}
+
+ private async Task SeedModelAsync(Guid modelId)
+ {
+ await using var conn = new Npgsql.NpgsqlConnection(_connectionString);
+ await conn.OpenAsync();
+ await conn.ExecuteAsync(
+ "INSERT INTO model_operations.models (id, ticker, correlation_id) VALUES (@Id, @Ticker, @CorrelationId)",
+ new { Id = modelId, Ticker = "TEST", CorrelationId = Guid.NewGuid() });
+ }
}
public class InMemoryOutbox : IOutbox
diff --git a/tests/KArtSell.Integration.Tests/Compliance/AuditTrailTests.cs b/tests/KArtSell.Integration.Tests/Compliance/AuditTrailTests.cs
index ea22d52e..bf1fdc2a 100644
--- a/tests/KArtSell.Integration.Tests/Compliance/AuditTrailTests.cs
+++ b/tests/KArtSell.Integration.Tests/Compliance/AuditTrailTests.cs
@@ -106,6 +106,11 @@ public class AuditTrailTests : IAsyncLifetime
var customerId = Guid.NewGuid();
var retentionId = Guid.NewGuid();
+ await _sql.InsertAuditEventAsync(
+ _db, eventId, AuditEventTypes.ModelActivated, AuditEntityTypes.Model,
+ Guid.NewGuid(), "customer@company.com", null, DateTime.UtcNow, "SUCCESS", null,
+ null, null, null, null, Guid.NewGuid(), CancellationToken.None);
+
// Act
await _sql.InsertGdprRetentionAsync(
_db, retentionId, eventId, customerId,
@@ -175,7 +180,8 @@ public class AuditTrailTests : IAsyncLifetime
// Assert
var @event = await _sql.GetAuditEventByIdAsync(_db, eventId, CancellationToken.None);
Assert.NotNull(@event);
- Assert.Contains("", @event.Details?.ToString() ?? "");
+ Assert.Equal("", @event.Details?["actor_email"].ToString());
+ Assert.Equal("", @event.Details?["customer_id"].ToString());
}
private const string TestConnectionString =
diff --git a/tests/KArtSell.Integration.Tests/SellDecision/SellDecisionTests.cs b/tests/KArtSell.Integration.Tests/SellDecision/SellDecisionTests.cs
index 67451a26..a9bb2fdb 100644
--- a/tests/KArtSell.Integration.Tests/SellDecision/SellDecisionTests.cs
+++ b/tests/KArtSell.Integration.Tests/SellDecision/SellDecisionTests.cs
@@ -118,8 +118,8 @@ public class SellPriorityRankerTests
[Fact]
public void CalculateScore_HardImpairment_ReturnsLowestScore()
{
- var score = _ranker.CalculateScore(SellPriority.HardImpairment, fundAgeDays: 200, liquidityPercent: 0.5m);
- Assert.Equal(950m, score); // 1000 - 50 (age boost)
+ var score = _ranker.CalculateScore(SellPriority.HardImpairment, fundAgeDays: 400, liquidityPercent: 0.5m);
+ Assert.Equal(950m, score); // 1000 - 50 (age boost, fundAgeDays > 365 per VS-10-SLICE_SPEC.md)
}
[Fact]
diff --git a/tests/KArtSell.Integration.Tests/TradeExecution/TradeExecutionTests.cs b/tests/KArtSell.Integration.Tests/TradeExecution/TradeExecutionTests.cs
index b8d4e011..20e44a38 100644
--- a/tests/KArtSell.Integration.Tests/TradeExecution/TradeExecutionTests.cs
+++ b/tests/KArtSell.Integration.Tests/TradeExecution/TradeExecutionTests.cs
@@ -1,4 +1,5 @@
using System.Text.Json;
+using Dapper;
using KArtSell.Modules.ModelOperations.TradeExecution;
using Microsoft.Extensions.Logging;
using Npgsql;
@@ -31,11 +32,31 @@ public class TradeExecutionTests : IAsyncLifetime
await _dataSource.DisposeAsync();
}
+ private async Task SeedSellDecisionAsync()
+ {
+ await using var connection = await _dataSource.OpenConnectionAsync();
+ var modelId = Guid.NewGuid();
+ await connection.ExecuteAsync(
+ "INSERT INTO model_operations.models (id, ticker, correlation_id) VALUES (@Id, @Ticker, @CorrelationId)",
+ new { Id = modelId, Ticker = "TEST", CorrelationId = Guid.NewGuid() });
+
+ var sellDecisionId = Guid.NewGuid();
+ await connection.ExecuteAsync(
+ """
+ INSERT INTO model_operations.sell_decisions
+ (id, model_id, status, created_by, published_at, correlation_id)
+ VALUES (@Id, @ModelId, 'PENDING', 'test@company.com', NOW(), @CorrelationId)
+ """,
+ new { Id = sellDecisionId, ModelId = modelId, CorrelationId = Guid.NewGuid() });
+
+ return sellDecisionId;
+ }
+
[Fact]
public async Task CreateTrade_WithValidData_ShouldInsertSuccessfully()
{
var sql = new TradeSql(_dataSource, _logger);
- var sellDecisionId = Guid.NewGuid();
+ var sellDecisionId = await SeedSellDecisionAsync();
var correlationId = Guid.NewGuid();
var trade = Trade.Create(sellDecisionId, 1000, correlationId, DateTime.UtcNow);
@@ -55,14 +76,14 @@ public class TradeExecutionTests : IAsyncLifetime
{
var sql = new TradeSql(_dataSource, _logger);
var correlationId = Guid.NewGuid();
- var trade = Trade.Create(Guid.NewGuid(), 1000, correlationId, DateTime.UtcNow);
+ var trade = Trade.Create(await SeedSellDecisionAsync(), 1000, correlationId, DateTime.UtcNow);
await sql.InsertTradeAsync(trade);
var response = JsonDocument.Parse("{}").RootElement;
trade.MarkSubmitted("KIS-ORDER-123", response);
- await sql.UpdateTradeStatusAsync(trade.Id, TradeStatus.Submitted, response, null, correlationId);
+ await sql.UpdateTradeStatusAsync(trade, response, null);
var retrieved = await sql.GetTradeByIdAsync(trade.Id, correlationId);
@@ -76,14 +97,14 @@ public class TradeExecutionTests : IAsyncLifetime
{
var sql = new TradeSql(_dataSource, _logger);
var correlationId = Guid.NewGuid();
- var trade = Trade.Create(Guid.NewGuid(), 1000, correlationId, DateTime.UtcNow);
+ var trade = Trade.Create(await SeedSellDecisionAsync(), 1000, correlationId, DateTime.UtcNow);
await sql.InsertTradeAsync(trade);
var response = JsonDocument.Parse("{}").RootElement;
trade.MarkFilled(1000, 49.95m, response, DateTime.UtcNow);
- await sql.UpdateTradeStatusAsync(trade.Id, TradeStatus.FullyFilled, response, null, correlationId);
+ await sql.UpdateTradeStatusAsync(trade, response, null);
var retrieved = await sql.GetTradeByIdAsync(trade.Id, correlationId);
@@ -100,8 +121,8 @@ public class TradeExecutionTests : IAsyncLifetime
var sql = new TradeSql(_dataSource, _logger);
var correlationId = Guid.NewGuid();
- var trade1 = Trade.Create(Guid.NewGuid(), 1000, correlationId, DateTime.UtcNow);
- var trade2 = Trade.Create(Guid.NewGuid(), 2000, correlationId, DateTime.UtcNow);
+ var trade1 = Trade.Create(await SeedSellDecisionAsync(), 1000, correlationId, DateTime.UtcNow);
+ var trade2 = Trade.Create(await SeedSellDecisionAsync(), 2000, correlationId, DateTime.UtcNow);
await sql.InsertTradeAsync(trade1);
await sql.InsertTradeAsync(trade2);
@@ -118,14 +139,14 @@ public class TradeExecutionTests : IAsyncLifetime
{
var sql = new TradeSql(_dataSource, _logger);
var correlationId = Guid.NewGuid();
- var trade = Trade.Create(Guid.NewGuid(), 1000, correlationId, DateTime.UtcNow);
+ var trade = Trade.Create(await SeedSellDecisionAsync(), 1000, correlationId, DateTime.UtcNow);
await sql.InsertTradeAsync(trade);
trade.TotalAmount = 49950m;
trade.MarkConfirmed(DateTime.UtcNow, 50m);
- await sql.UpdateTradeStatusAsync(trade.Id, TradeStatus.Confirmed, null, null, correlationId);
+ await sql.UpdateTradeStatusAsync(trade, null, null);
var retrieved = await sql.GetTradeByIdAsync(trade.Id, correlationId);
@@ -140,11 +161,16 @@ public class TradeExecutionTests : IAsyncLifetime
{
var sql = new TradeSql(_dataSource, _logger);
var correlationId = Guid.NewGuid();
- var trade = Trade.Create(Guid.NewGuid(), 1000, correlationId, DateTime.UtcNow);
+ var trade = Trade.Create(await SeedSellDecisionAsync(), 1000, correlationId, DateTime.UtcNow);
await sql.InsertTradeAsync(trade);
- await sql.UpdateTradeStatusAsync(trade.Id, TradeStatus.Submitted, null, null, correlationId);
- await sql.UpdateTradeStatusAsync(trade.Id, TradeStatus.Accepted, null, null, correlationId);
+
+ var response = JsonDocument.Parse("{}").RootElement;
+ trade.MarkSubmitted("KIS-1", response);
+ await sql.UpdateTradeStatusAsync(trade, response, null);
+
+ trade.MarkAccepted(response);
+ await sql.UpdateTradeStatusAsync(trade, response, null);
var retrieved = await sql.GetTradeByIdAsync(trade.Id, correlationId);
@@ -158,8 +184,8 @@ public class TradeExecutionTests : IAsyncLifetime
var sql = new TradeSql(_dataSource, _logger);
var correlationId = Guid.NewGuid();
- var trade1 = Trade.Create(Guid.NewGuid(), 1000, correlationId, DateTime.UtcNow);
- var trade2 = Trade.Create(Guid.NewGuid(), 2000, correlationId, DateTime.UtcNow);
+ var trade1 = Trade.Create(await SeedSellDecisionAsync(), 1000, correlationId, DateTime.UtcNow);
+ var trade2 = Trade.Create(await SeedSellDecisionAsync(), 2000, correlationId, DateTime.UtcNow);
await sql.InsertTradeAsync(trade1);
await sql.InsertTradeAsync(trade2);