Revert "Merge pull request 'Dev' (#58) from Dev into production"
This reverts commit821e96e011, reversing changes made to0ff39e9e58.
This commit is contained in:
@@ -18,11 +18,6 @@ public sealed class GeneralLedgerClient(HttpClient http, IConfiguration configur
|
||||
public async Task<GeneralLedgerResponse> SendAsync(
|
||||
HttpMethod method, string path, string? queryString, string? contentType, Stream? body, CancellationToken ct)
|
||||
{
|
||||
// The base appsettings.json ships the key blank; name it here rather than forward GL's 401
|
||||
// for an empty X-Api-Key (deployed environments already refuse to start without it).
|
||||
if (string.IsNullOrWhiteSpace(_apiKey))
|
||||
throw new DomainException(ErrorCodes.GlServiceUnavailable, "GeneralLedgerService:ApiKey is not configured.", 503);
|
||||
|
||||
var relativeUri = path.TrimStart('/') + queryString;
|
||||
using var request = new HttpRequestMessage(method, relativeUri);
|
||||
request.Headers.TryAddWithoutValidation("X-Api-Key", _apiKey);
|
||||
|
||||
@@ -39,29 +39,17 @@ public static class DataSeeder
|
||||
("PRD-REWORK-LOSS", "Production Rework Loss", ReasonContext.Production),
|
||||
];
|
||||
|
||||
/// <param name="includeDemoData">
|
||||
/// Also seed demo rows — sample warehouses/UOMs/category/items, an on-hand stock layer,
|
||||
/// customers, bundle and draft sales documents (<c>Seed:DemoData</c>). On for Development
|
||||
/// and the test deployment (the E2E suite relies on MAIN/SHOP, PCS/BOX, General Goods);
|
||||
/// never for release, which gets reference data only (docs/40-DEPLOYMENT.md).
|
||||
/// </param>
|
||||
public static async Task SeedAsync(ErpDbContext db, bool includeDemoData, CancellationToken ct = default)
|
||||
public static async Task SeedAsync(ErpDbContext db, CancellationToken ct = default)
|
||||
{
|
||||
// Reference data — every environment.
|
||||
var dirty = await SeedReasonCodesAsync(db, ct);
|
||||
dirty |= await SeedItemTypesAsync(db, ct);
|
||||
// dirty |= await SeedCompanyProfileAsync(db, ct);
|
||||
dirty |= await SeedProductConfigAsync(db, ct);
|
||||
dirty |= await SeedBranchConfigAsync(db, ct);
|
||||
dirty |= await SeedNotificationConfigAsync(db, ct);
|
||||
dirty |= await SeedSalesSequencesAsync(db, ct);
|
||||
|
||||
if (includeDemoData)
|
||||
{
|
||||
dirty |= await SeedSalesMastersAsync(db, ct);
|
||||
dirty |= await SeedSalesStockAsync(db, ct);
|
||||
dirty |= await SeedSalesAsync(db, ct);
|
||||
}
|
||||
dirty |= await SeedSalesMastersAsync(db, ct);
|
||||
dirty |= await SeedSalesStockAsync(db, ct);
|
||||
dirty |= await SeedSalesAsync(db, ct);
|
||||
|
||||
if (dirty) await db.SaveChangesAsync(ct);
|
||||
}
|
||||
@@ -356,9 +344,9 @@ public static class DataSeeder
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Seeds the demo sales data used for UI/backend development: a couple of customer
|
||||
/// rows and a few draft invoice/slip samples when the required master data already
|
||||
/// exists. (Current-year document counters are reference data, seeded in SeedAsync.)
|
||||
/// Seeds the minimum sales bootstrap data needed for UI/backend development:
|
||||
/// a couple of customer rows, current-year document counters, and a few draft
|
||||
/// invoice/slip samples when the required master data already exists.
|
||||
/// This intentionally never clears or rewrites any existing rows.
|
||||
/// </summary>
|
||||
private static async Task<bool> SeedSalesAsync(ErpDbContext db, CancellationToken ct)
|
||||
@@ -366,6 +354,7 @@ public static class DataSeeder
|
||||
var dirty = false;
|
||||
|
||||
dirty |= await SeedSalesCustomersAsync(db, ct);
|
||||
dirty |= await SeedSalesSequencesAsync(db, ct);
|
||||
dirty |= await SeedSampleSalesDocsAsync(db, ct);
|
||||
|
||||
try
|
||||
|
||||
@@ -15,7 +15,6 @@ using ERPCore.Services.Production;
|
||||
using ERPCore.Services.Stock;
|
||||
using ERPCore.System.Errors;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.HttpOverrides;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||
using Microsoft.OpenApi;
|
||||
@@ -24,32 +23,10 @@ using Serilog;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Fail fast on missing deployment config. Outside Development these arrive as environment
|
||||
// variables (docs/40-DEPLOYMENT.md §5); a blank value would otherwise surface later as an
|
||||
// unrelated crash (e.g. `new Uri("")` for AuthHex:BaseUrl) instead of naming the key.
|
||||
if (!builder.Environment.IsDevelopment())
|
||||
{
|
||||
string[] requiredKeys =
|
||||
[
|
||||
"ConnectionStrings:DefaultConnection",
|
||||
"AuthHex:BaseUrl",
|
||||
"GeneralLedgerService:BaseUrl",
|
||||
"GeneralLedgerService:ApiKey",
|
||||
"Auth:RsaPublicKeyXml",
|
||||
];
|
||||
var missing = requiredKeys.Where(k => string.IsNullOrWhiteSpace(builder.Configuration[k])).ToArray();
|
||||
if (missing.Length > 0)
|
||||
throw new InvalidOperationException(
|
||||
$"Missing required configuration for environment '{builder.Environment.EnvironmentName}': " +
|
||||
$"{string.Join(", ", missing)}. Set them as environment variables (':' becomes '__', " +
|
||||
"e.g. ConnectionStrings__DefaultConnection).");
|
||||
}
|
||||
|
||||
// Serilog (file sink) — reads levels from configuration, plus a rolling daily file. The path is
|
||||
// configurable so deployed instances log outside their release folder (LogFile:Path).
|
||||
// Serilog (file sink) — reads levels from configuration, plus a rolling daily file.
|
||||
builder.Host.UseSerilog((ctx, cfg) => cfg
|
||||
.ReadFrom.Configuration(ctx.Configuration)
|
||||
.WriteTo.File(ctx.Configuration["LogFile:Path"] ?? "logs/erpcore-.log", rollingInterval: RollingInterval.Day));
|
||||
.WriteTo.File("logs/erpcore-.log", rollingInterval: RollingInterval.Day));
|
||||
|
||||
// Controllers + JSON: serialize enums as their string names (docs/11 §8, camelCase).
|
||||
builder.Services.AddControllers()
|
||||
@@ -72,10 +49,8 @@ builder.Services.AddErpJwtAuth(builder.Configuration);
|
||||
// AuthController proxy → AuthHex (docs/11 §2.0)
|
||||
builder.Services.AddHttpClient<IAuthHexClient, AuthHexClient>(c =>
|
||||
{
|
||||
// Blank counts as missing: the base appsettings.json ships these keys empty on purpose.
|
||||
var baseUrl = builder.Configuration["AuthHex:BaseUrl"];
|
||||
if (string.IsNullOrWhiteSpace(baseUrl))
|
||||
throw new InvalidOperationException("AuthHex:BaseUrl is not configured (set it in appsettings.Development.json locally).");
|
||||
var baseUrl = builder.Configuration["AuthHex:BaseUrl"]
|
||||
?? throw new InvalidOperationException("AuthHex:BaseUrl is not configured.");
|
||||
c.BaseAddress = new Uri(baseUrl);
|
||||
});
|
||||
builder.Services.AddScoped<IAuthUserService, AuthUserService>();
|
||||
@@ -85,9 +60,8 @@ builder.Services.AddScoped<IAuthAltService, AuthAltService>();
|
||||
// General Ledger service proxy → external GL microservice (docs/12-GENERAL-LEDGER-INTEGRATION.md)
|
||||
builder.Services.AddHttpClient<IGeneralLedgerClient, GeneralLedgerClient>(c =>
|
||||
{
|
||||
var baseUrl = builder.Configuration["GeneralLedgerService:BaseUrl"];
|
||||
if (string.IsNullOrWhiteSpace(baseUrl))
|
||||
throw new InvalidOperationException("GeneralLedgerService:BaseUrl is not configured (set it in appsettings.Development.json locally).");
|
||||
var baseUrl = builder.Configuration["GeneralLedgerService:BaseUrl"]
|
||||
?? throw new InvalidOperationException("GeneralLedgerService:BaseUrl is not configured.");
|
||||
c.BaseAddress = new Uri(baseUrl);
|
||||
});
|
||||
builder.Services.AddScoped<IGeneralLedgerService, GeneralLedgerService>();
|
||||
@@ -231,10 +205,7 @@ using (var scope = app.Services.CreateScope())
|
||||
await db.Database.MigrateAsync();
|
||||
try
|
||||
{
|
||||
// Demo rows (sample catalog, stock, customers, sales docs) default on only in Development;
|
||||
// the test deployment opts in with Seed__DemoData=true, release never does.
|
||||
var includeDemoData = app.Configuration.GetValue("Seed:DemoData", app.Environment.IsDevelopment());
|
||||
await DataSeeder.SeedAsync(db, includeDemoData);
|
||||
await DataSeeder.SeedAsync(db);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -242,18 +213,9 @@ using (var scope = app.Services.CreateScope())
|
||||
}
|
||||
}
|
||||
|
||||
// Behind the co-located Apache reverse proxy (docs/40-DEPLOYMENT.md): take the client IP and
|
||||
// scheme from X-Forwarded-*. Only loopback proxies are trusted by default, which is exactly it.
|
||||
app.UseForwardedHeaders(new ForwardedHeadersOptions
|
||||
{
|
||||
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
|
||||
});
|
||||
|
||||
app.UseSerilogRequestLogging();
|
||||
|
||||
// Off in Production only. The test deployment (Staging) keeps it; it is still not public there
|
||||
// because Apache proxies only /api/ — reach it through an SSH tunnel to the backend port.
|
||||
if (!app.Environment.IsProduction())
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "Host=127.0.0.1;Port=5433;Database=ERPCoreTest;Username=postgres;Password=post@hexdive"
|
||||
},
|
||||
"AuthHex": {
|
||||
"BaseUrl": "http://localhost:5011"
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "Host=127.0.0.1;Port=5432;Database=ERPCore;Username=postgres;Password=CHANGE_ME"
|
||||
},
|
||||
"AuthHex": {
|
||||
"BaseUrl": "http://localhost:5011"
|
||||
},
|
||||
"GeneralLedgerService": {
|
||||
"BaseUrl": "https://localhost:7024/api/v1/",
|
||||
"ApiKey": "ask-the-team-for-the-dev-key"
|
||||
},
|
||||
"Seed": {
|
||||
"DemoData": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": ""
|
||||
},
|
||||
"Jwt": {
|
||||
"SigningKey": ""
|
||||
},
|
||||
"AuthHex": {
|
||||
"BaseUrl": ""
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": ""
|
||||
"DefaultConnection": "Host=localhost;Port=5432;Database=ERPCore;Username=root;Password=root"
|
||||
},
|
||||
"Auth": {
|
||||
"Issuer": "AuthHex",
|
||||
@@ -16,18 +16,15 @@
|
||||
"RequiredRoleCode": ""
|
||||
},
|
||||
"AuthHex": {
|
||||
"BaseUrl": ""
|
||||
"BaseUrl": "http://localhost:5602"
|
||||
},
|
||||
"FileStorage": {
|
||||
"RootPath": "App_Data/hr-documents",
|
||||
"MaxSizeBytes": 10485760
|
||||
},
|
||||
"LogFile": {
|
||||
"Path": "logs/erpcore-.log"
|
||||
},
|
||||
"GeneralLedgerService": {
|
||||
"BaseUrl": "",
|
||||
"ApiKey": ""
|
||||
"BaseUrl": "https://localhost:7024/api/v1/",
|
||||
"ApiKey": "1A5FE0E389C029B1FBCD2A94650CEBF0656083BF06FF48E5E11987040ABA262D"
|
||||
},
|
||||
"Grn": {
|
||||
"GlInventoryAccountCode": "1100",
|
||||
|
||||
Reference in New Issue
Block a user