Skip to content

Commit 6956dd0

Browse files
feat(config): add database connection enable/disable flags and fix entity mappings
- Add SQL_CONNECTIONENABLE, MYSQL_CONNECTIONENABLE, POSTGRES_CONNECTIONENABLE env vars - Add DatabaseConnections section in appsettings.json for config-file based control - Fix websiteCode entity mapping from string to int (matches DB column type) - Fix TPartnerCode entity mapping from nullable to non-nullable (matches DB) - Add alert recipients: muhammad.zakir, yarik.sobanski, michael.sobanski - Update all unit and integration tests for corrected entity types Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0654212 commit 6956dd0

File tree

11 files changed

+130
-27
lines changed

11 files changed

+130
-27
lines changed

src/OrderMonitor.Api/appsettings.Development.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
{
2+
"DatabaseConnections": {
3+
"SqlConnectionEnable": true,
4+
"MySqlConnectionEnable": false,
5+
"PostgresConnectionEnable": false
6+
},
7+
28
"ConnectionStrings": {
39
"BackofficeDb": "Server=10.10.30.7,1433;Database=PrinterPix_BO_Live;User Id=db_PIX_BackOffice_Live;Password={ENCRYPTED};TrustServerCertificate=True;ApplicationIntent=ReadOnly;"
410
},
@@ -24,7 +30,12 @@
2430

2531
"Alerts": {
2632
"Enabled": true,
27-
"Recipients": ["ranganathan.e@syncoms.com"],
33+
"Recipients": [
34+
"ranganathan.e@syncoms.com",
35+
"muhammad.zakir@syncoms.co.uk",
36+
"yarik.sobanski@syncoms.co.uk",
37+
"michael.sobanski@syncoms.co.uk"
38+
],
2839
"SubjectPrefix": "[Order Monitor]"
2940
},
3041

src/OrderMonitor.Api/appsettings.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
{
2+
"DatabaseConnections": {
3+
"SqlConnectionEnable": true,
4+
"MySqlConnectionEnable": false,
5+
"PostgresConnectionEnable": false
6+
},
7+
28
"ConnectionStrings": {
39
"BackofficeDb": "Server=localhost;Database=Backoffice;Trusted_Connection=True;TrustServerCertificate=True;ApplicationIntent=ReadOnly;"
410
},
@@ -25,7 +31,10 @@
2531
"Alerts": {
2632
"Enabled": true,
2733
"Recipients": [
28-
"ranganathan.e@syncoms.com"
34+
"ranganathan.e@syncoms.com",
35+
"muhammad.zakir@syncoms.co.uk",
36+
"yarik.sobanski@syncoms.co.uk",
37+
"michael.sobanski@syncoms.co.uk"
2938
],
3039
"SubjectPrefix": "[Order Monitor]"
3140
},

src/OrderMonitor.Infrastructure/Data/EfCoreOrderRepository.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,9 @@ where opt.IsPrimaryComponent
7979
StuckSince = o.LastUpdatedDate!.Value,
8080
HoursStuck = (int)(utcNow - o.LastUpdatedDate!.Value).TotalHours,
8181
ThresholdHours = OrderStatusConfiguration.GetThresholdHours(o.Status),
82-
Region = o.WebsiteCode,
82+
Region = o.WebsiteCode.ToString(),
8383
CustomerEmail = null,
84-
FacilityCode = o.FacilityCode?.ToString(),
84+
FacilityCode = o.FacilityCode.ToString(),
8585
FacilityName = o.FacilityName ?? "Unknown"
8686
});
8787

src/OrderMonitor.Infrastructure/Data/Entities/ConsolidationOrderEntity.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ public class ConsolidationOrderEntity
1919
public string? OrderNumber { get; set; }
2020

2121
[Column("websiteCode")]
22-
[StringLength(20)]
23-
public string? WebsiteCode { get; set; }
22+
public int WebsiteCode { get; set; }
2423

2524
public ICollection<OrderProductTrackingEntity> OrderProductTrackings { get; set; } = [];
2625
}

src/OrderMonitor.Infrastructure/Data/Entities/OrderProductTrackingEntity.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public class OrderProductTrackingEntity
2727
public bool IsPrimaryComponent { get; set; }
2828

2929
[Column("TPartnerCode")]
30-
public int? TPartnerCode { get; set; }
30+
public int TPartnerCode { get; set; }
3131

3232
[Column("OPT_SnSpId")]
3333
public int? OptSnSpId { get; set; }

src/OrderMonitor.Infrastructure/DependencyInjection.cs

Lines changed: 87 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Microsoft.Extensions.Configuration;
22
using Microsoft.Extensions.DependencyInjection;
3+
using Microsoft.Extensions.Logging;
34
using OrderMonitor.Core.Configuration;
45
using OrderMonitor.Core.Interfaces;
56
using OrderMonitor.Core.Services;
@@ -25,10 +26,10 @@ public static IServiceCollection AddInfrastructure(
2526
services.AddDbContext<OrderMonitorDbContext>((sp, options) =>
2627
{
2728
var config = sp.GetRequiredService<IConfiguration>();
29+
var logger = sp.GetRequiredService<ILoggerFactory>().CreateLogger("DatabaseSetup");
2830

29-
// Resolve database provider
30-
var providerString = config["Database:Provider"] ?? "SqlServer";
31-
var provider = DatabaseProviderFactory.ParseProvider(providerString);
31+
// Resolve database provider from connection enable flags
32+
var provider = ResolveProviderFromConnectionFlags(config, logger);
3233

3334
// Resolve connection string
3435
var connectionString = config["Database:ConnectionString"];
@@ -73,4 +74,87 @@ public static IServiceCollection AddInfrastructure(
7374

7475
return services;
7576
}
77+
78+
/// <summary>
79+
/// Resolves the database provider from connection enable flags.
80+
/// Checks environment variables first (SQL_CONNECTIONENABLE, MYSQL_CONNECTIONENABLE, POSTGRES_CONNECTIONENABLE),
81+
/// then falls back to configuration section (DatabaseConnections:SqlConnectionEnable, etc.),
82+
/// then falls back to Database:Provider setting.
83+
/// </summary>
84+
private static DatabaseProvider ResolveProviderFromConnectionFlags(
85+
IConfiguration config,
86+
ILogger logger)
87+
{
88+
// Check environment variables first, then configuration section
89+
var sqlEnabled = GetConnectionFlag("SQL_CONNECTIONENABLE", "DatabaseConnections:SqlConnectionEnable", config);
90+
var mysqlEnabled = GetConnectionFlag("MYSQL_CONNECTIONENABLE", "DatabaseConnections:MySqlConnectionEnable", config);
91+
var postgresEnabled = GetConnectionFlag("POSTGRES_CONNECTIONENABLE", "DatabaseConnections:PostgresConnectionEnable", config);
92+
93+
// If no connection flags are set at all, fall back to Database:Provider
94+
if (sqlEnabled is null && mysqlEnabled is null && postgresEnabled is null)
95+
{
96+
var providerString = config["Database:Provider"] ?? "SqlServer";
97+
logger.LogInformation("No connection enable flags found. Falling back to Database:Provider = {Provider}", providerString);
98+
return DatabaseProviderFactory.ParseProvider(providerString);
99+
}
100+
101+
// Default unset flags to false
102+
var sql = sqlEnabled ?? false;
103+
var mysql = mysqlEnabled ?? false;
104+
var postgres = postgresEnabled ?? false;
105+
106+
var enabledCount = (sql ? 1 : 0) + (mysql ? 1 : 0) + (postgres ? 1 : 0);
107+
108+
if (enabledCount == 0)
109+
{
110+
throw new InvalidOperationException(
111+
"No database connection is enabled. " +
112+
"Set one of: SQL_CONNECTIONENABLE=true, MYSQL_CONNECTIONENABLE=true, or POSTGRES_CONNECTIONENABLE=true.");
113+
}
114+
115+
if (enabledCount > 1)
116+
{
117+
throw new InvalidOperationException(
118+
"Multiple database connections are enabled. Only one can be active at a time. " +
119+
$"Current: SQL={sql}, MySQL={mysql}, PostgreSQL={postgres}.");
120+
}
121+
122+
if (sql)
123+
{
124+
logger.LogInformation("Database connection: SQL Server enabled");
125+
return DatabaseProvider.SqlServer;
126+
}
127+
128+
if (mysql)
129+
{
130+
logger.LogInformation("Database connection: MySQL enabled");
131+
return DatabaseProvider.MySql;
132+
}
133+
134+
logger.LogInformation("Database connection: PostgreSQL enabled");
135+
return DatabaseProvider.PostgreSql;
136+
}
137+
138+
/// <summary>
139+
/// Gets a connection enable flag value. Checks environment variable first, then configuration.
140+
/// Returns null if neither is set.
141+
/// </summary>
142+
private static bool? GetConnectionFlag(string envVarName, string configKey, IConfiguration config)
143+
{
144+
// Check environment variable first
145+
var envValue = Environment.GetEnvironmentVariable(envVarName);
146+
if (!string.IsNullOrWhiteSpace(envValue))
147+
{
148+
return string.Equals(envValue.Trim(), "true", StringComparison.OrdinalIgnoreCase);
149+
}
150+
151+
// Fall back to configuration section
152+
var configValue = config[configKey];
153+
if (!string.IsNullOrWhiteSpace(configValue))
154+
{
155+
return string.Equals(configValue.Trim(), "true", StringComparison.OrdinalIgnoreCase);
156+
}
157+
158+
return null;
159+
}
76160
}

tests/OrderMonitor.IntegrationTests/Providers/DatabaseProviderTestBase.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,10 @@ private async Task SeedTestDataAsync()
7272

7373
// Orders
7474
DbContext.ConsolidationOrders.AddRange(
75-
new ConsolidationOrderEntity { CONumber = "CO001", OrderNumber = "ORD001", WebsiteCode = "US" },
76-
new ConsolidationOrderEntity { CONumber = "CO002", OrderNumber = "ORD002", WebsiteCode = "UK" },
77-
new ConsolidationOrderEntity { CONumber = "CO003", OrderNumber = "ORD003", WebsiteCode = "DE" },
78-
new ConsolidationOrderEntity { CONumber = "CO004", OrderNumber = "ORD004", WebsiteCode = "US" }
75+
new ConsolidationOrderEntity { CONumber = "CO001", OrderNumber = "ORD001", WebsiteCode = 1 },
76+
new ConsolidationOrderEntity { CONumber = "CO002", OrderNumber = "ORD002", WebsiteCode = 2 },
77+
new ConsolidationOrderEntity { CONumber = "CO003", OrderNumber = "ORD003", WebsiteCode = 3 },
78+
new ConsolidationOrderEntity { CONumber = "CO004", OrderNumber = "ORD004", WebsiteCode = 1 }
7979
);
8080

8181
// Stuck prep order (>6h at status 3050)
@@ -164,7 +164,7 @@ public async Task GetStuckOrders_IncludesRelatedData()
164164
order.OrderNumber.Should().Be("ORD001");
165165
order.Status.Should().Be("PreparationStarted");
166166
order.ProductType.Should().Be("Photo Book");
167-
order.Region.Should().Be("US");
167+
order.Region.Should().Be("1");
168168
order.FacilityName.Should().Be("Facility Alpha");
169169
}
170170

tests/OrderMonitor.IntegrationTests/Providers/QueryPerformanceTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ private async Task SeedPerformanceDataAsync()
9898
var statusIds = new[] { 3050, 3060, 4001, 4200, 6400 };
9999
var specIds = new[] { 100, 200, 300, 400 };
100100
var partnerIds = new[] { 10, 20 };
101-
var websites = new[] { "US", "UK", "DE", "FR", "AU" };
101+
var websites = new[] { 1, 2, 3, 4, 5 };
102102
var random = new Random(42); // deterministic
103103

104104
long optId = 1;

tests/OrderMonitor.UnitTests/Data/EfCoreOrderRepositoryTests.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,10 @@ private void SeedTestData()
5555

5656
// Orders
5757
_dbContext.ConsolidationOrders.AddRange(
58-
new ConsolidationOrderEntity { CONumber = "CO001", OrderNumber = "ORD001", WebsiteCode = "US" },
59-
new ConsolidationOrderEntity { CONumber = "CO002", OrderNumber = "ORD002", WebsiteCode = "UK" },
60-
new ConsolidationOrderEntity { CONumber = "CO003", OrderNumber = "ORD003", WebsiteCode = "DE" },
61-
new ConsolidationOrderEntity { CONumber = "CO004", OrderNumber = "ORD004", WebsiteCode = "US" }
58+
new ConsolidationOrderEntity { CONumber = "CO001", OrderNumber = "ORD001", WebsiteCode = 1 },
59+
new ConsolidationOrderEntity { CONumber = "CO002", OrderNumber = "ORD002", WebsiteCode = 2 },
60+
new ConsolidationOrderEntity { CONumber = "CO003", OrderNumber = "ORD003", WebsiteCode = 3 },
61+
new ConsolidationOrderEntity { CONumber = "CO004", OrderNumber = "ORD004", WebsiteCode = 1 }
6262
);
6363

6464
// Order product trackings - stuck prep order (>6h at status 3050)
@@ -161,7 +161,7 @@ public async Task GetStuckOrdersAsync_IncludesRelatedData()
161161
order.OrderNumber.Should().Be("ORD001");
162162
order.Status.Should().Be("PreparationStarted");
163163
order.ProductType.Should().Be("Photo Book");
164-
order.Region.Should().Be("US");
164+
order.Region.Should().Be("1");
165165
order.FacilityName.Should().Be("Facility Alpha");
166166
}
167167

tests/OrderMonitor.UnitTests/Data/EntityModelTests.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public void ConsolidationOrderEntity_DefaultValues()
1111
var entity = new ConsolidationOrderEntity();
1212
entity.CONumber.Should().Be(string.Empty);
1313
entity.OrderNumber.Should().BeNull();
14-
entity.WebsiteCode.Should().BeNull();
14+
entity.WebsiteCode.Should().Be(0);
1515
entity.OrderProductTrackings.Should().BeEmpty();
1616
}
1717

@@ -24,7 +24,7 @@ public void OrderProductTrackingEntity_DefaultValues()
2424
entity.Status.Should().Be(0);
2525
entity.LastUpdatedDate.Should().BeNull();
2626
entity.IsPrimaryComponent.Should().BeFalse();
27-
entity.TPartnerCode.Should().BeNull();
27+
entity.TPartnerCode.Should().Be(0);
2828
entity.OptSnSpId.Should().BeNull();
2929
entity.OrderDate.Should().BeNull();
3030
}
@@ -70,12 +70,12 @@ public void ConsolidationOrderEntity_CanSetProperties()
7070
{
7171
CONumber = "CO12345",
7272
OrderNumber = "12345",
73-
WebsiteCode = "US"
73+
WebsiteCode = 1
7474
};
7575

7676
entity.CONumber.Should().Be("CO12345");
7777
entity.OrderNumber.Should().Be("12345");
78-
entity.WebsiteCode.Should().Be("US");
78+
entity.WebsiteCode.Should().Be(1);
7979
}
8080

8181
[Fact]

0 commit comments

Comments
 (0)