Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
c2f8c75
feat: add PostgreSQL persistence backend
jbuchbinder Aug 3, 2026
917ee8f
feat: add PostgreSQL schema DDL and Dockerfile support
jbuchbinder Aug 4, 2026
09b8971
fix: suppress NU1903 vulnerability warning (Microsoft.OpenApi 2.4.1)
jbuchbinder Aug 4, 2026
895faeb
fix: quote PostgreSQL reserved word 'End' in schema and stored proced…
jbuchbinder Aug 4, 2026
aebd6cf
fix: remove RETURN QUERY from PostgreSQL procedures
jbuchbinder Aug 4, 2026
340b52a
fix: normalize collation comparison for Alpine PostgreSQL
jbuchbinder Aug 4, 2026
726c71e
fix: use lowercase 'version' table name in DbContext query
jbuchbinder Aug 4, 2026
e56c185
fix: use lowercase column names in version query
jbuchbinder Aug 4, 2026
afe81f8
fix: quote all table names in PostgreSQL DDL and stored procedures
jbuchbinder Aug 4, 2026
6d4ba6c
fix: prevent double-quoting of already-quoted table names in SPs
jbuchbinder Aug 4, 2026
c91d073
fix: use quoted "Version" table name to match DDL case
jbuchbinder Aug 4, 2026
73c1c77
fix: lowercase identifiers in PostgreSQL INSERT/UPDATE SQL generation
jbuchbinder Aug 5, 2026
c54c898
fix: lowercase QuoteIdentifier for PostgreSQL — DDL has unquoted iden…
jbuchbinder Aug 5, 2026
7afa1e9
fix: remove DbType.DateTime2 from AddCreated/AddUpdated for PostgreSQL
jbuchbinder Aug 5, 2026
7fca8aa
fix: use DbType.DateTimeOffset for Created/Updated to force timestamptz
jbuchbinder Aug 5, 2026
131fbbd
fix: lowercase QuoteIdentifier — DDL columns are stored lowercase in DB
jbuchbinder Aug 5, 2026
5311723
fix: revert QuoteIdentifier to PascalCase — DDL now uses quoted ident…
jbuchbinder Aug 5, 2026
d218520
fix: quote column names in version query for PostgreSQL
jbuchbinder Aug 5, 2026
12c8d29
fix: enable Npgsql legacy timestamp behavior for timestamptz compatib…
jbuchbinder Aug 5, 2026
2df6447
feat: add GET /payruns/jobs/{id}/results endpoint for wage type results
jbuchbinder Aug 5, 2026
e9a55ed
fix: auto-create PostgreSQL stored procedures on startup
jbuchbinder Aug 6, 2026
3a5d276
fix: GetDerivedCollectors parameter order matches C# call
jbuchbinder Aug 6, 2026
db0ace7
fix: PostgreSQL stored procedure calls use CALL with explicit type casts
jbuchbinder Aug 6, 2026
8755063
fix: robust entrypoint.sh with retry, DeletePayrunJob uses quoted col…
jbuchbinder Aug 6, 2026
1c00418
fix: install postgresql-client in Docker image for entrypoint.sh
jbuchbinder Aug 6, 2026
5aa32d6
fix: CALL procedure without double-quoted name (PG folds to lowercase)
jbuchbinder Aug 6, 2026
316fa3e
fix: map DateTime2 to timestamp not timestamptz for PG procedures
jbuchbinder Aug 6, 2026
a3cacb8
fix: try parameter type lookup both with and without @ prefix
jbuchbinder Aug 6, 2026
2837fd5
fix: comprehensive PostgreSQL stored procedure port fixes
jbuchbinder Aug 6, 2026
44ccbc4
fix: quote parameter names to match Npgsql named-param CALL syntax
jbuchbinder Aug 6, 2026
f5710d9
fix: restrict BuildFunctionCallSql to Get* procs only
jbuchbinder Aug 6, 2026
4c23389
fix: restore original stored procedures, keep only 3 GetDerived funct…
jbuchbinder Aug 6, 2026
1bb698b
fix: bypass SqlKata for employee division queries, deduplicate Employ…
jbuchbinder Aug 6, 2026
b2b3527
fix: add PostgreSQL fallback for employee resolver
jbuchbinder Aug 6, 2026
1a22e0c
fix: catch PayrunException and fallback to direct employee query
jbuchbinder Aug 6, 2026
77a4fbd
fix: add missing using System.Collections.Generic
jbuchbinder Aug 6, 2026
c1c5d7f
fix: SqlKata ToTableColumn produces single identifiers breaking Postg…
jbuchbinder Aug 6, 2026
ea25e56
fix: replace SqlKata employee fallback with raw SQL in PayrunProcessor
jbuchbinder Aug 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions Api/Api.Controller/PayrunJobController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,32 @@ public virtual async Task<ActionResult<string>> GetPayrunJobStatusAsync(int tena
return Enum.GetName(typeof(PayrunJobStatus), payrunJob.JobStatus);
}

/// <summary>
/// Get wage type results for a completed payrun job
/// </summary>
/// <param name="tenantId">The tenant id</param>
/// <param name="payrunJobId">The payrun job id</param>
/// <returns>The wage type results for the payrun job</returns>
public virtual async Task<ActionResult<ApiObject.WageTypeResult[]>> GetPayrunJobResultsAsync(int tenantId, int payrunJobId)
{
// tenant
var tenant = await ParentService.GetAsync(Runtime.DbContext, tenantId);
if (tenant == null)
{
return BadRequest($"Unknown tenant with id {tenantId}");
}

// payrun job
var payrunJob = await Service.GetAsync(Runtime.DbContext, tenantId, payrunJobId);
if (payrunJob == null)
{
return BadRequest($"Unknown payrun job with id {payrunJobId}");
}

var results = await Service.GetWageTypeResultsByJobAsync(Runtime.DbContext, tenantId, payrunJobId);
return new WageTypeResultMap().ToApi(results);
}

/// <summary>
/// Change the status of a payrun job
/// </summary>
Expand Down
3 changes: 2 additions & 1 deletion Api/Api.Core/ApiServiceFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,8 @@ private static IPayrunJobService NewPayrunJobService(IServiceProvider servicePro
PayrollRepository = serviceProvider.GetRequiredService<IPayrollRepository>(),
PayrollResultSetRepository = serviceProvider.GetRequiredService<IPayrollResultSetRepository>(),
EmployeeRepository = serviceProvider.GetRequiredService<IEmployeeRepository>(),
PayrollCalculatorProvider = serviceProvider.GetRequiredService<IPayrollCalculatorProvider>()
PayrollCalculatorProvider = serviceProvider.GetRequiredService<IPayrollCalculatorProvider>(),
WageTypeResultRepository = serviceProvider.GetRequiredService<IWageTypeResultRepository>()
});

private static IPayrollResultService NewPayrollResultService(IServiceProvider serviceProvider) =>
Expand Down
14 changes: 14 additions & 0 deletions Backend.Controller/PayrunJobController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,20 @@ public override async Task<ActionResult<string>> GetPayrunJobStatusAsync(
int tenantId, int payrunJobId) =>
await base.GetPayrunJobStatusAsync(tenantId, payrunJobId);

/// <summary>
/// Get wage type results for a completed payrun job
/// </summary>
/// <param name="tenantId">The tenant id</param>
/// <param name="payrunJobId">The payrun job id</param>
/// <returns>The wage type results for the payrun job</returns>
[HttpGet("{payrunJobId}/results")]
[OkResponse]
[NotFoundResponse]
[ApiOperationId("GetPayrunJobResults")]
public override async Task<ActionResult<ApiObject.WageTypeResult[]>> GetPayrunJobResultsAsync(
int tenantId, int payrunJobId) =>
await base.GetPayrunJobResultsAsync(tenantId, payrunJobId);

/// <summary>
/// Change the status of a payrun job
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions Backend.Server/PayrollEngine.Backend.Server.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
<ProjectReference Include="..\Backend.Controller\PayrollEngine.Backend.Controller.csproj" />
<ProjectReference Include="..\Persistence\Persistence.SqlServer\PayrollEngine.Persistence.SqlServer.csproj" />
<ProjectReference Include="..\Persistence\Persistence.MySql\PayrollEngine.Persistence.MySql.csproj" />
<ProjectReference Include="..\Persistence\Persistence.Postgres\PayrollEngine.Persistence.Postgres.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
3 changes: 3 additions & 0 deletions Backend.Server/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ public static class Program
/// </summary>
public static void Main(string[] args)
{
// Npgsql: write DateTime values as timestamptz to match PostgreSQL DDL
AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);

// Bootstrap logger: active before Host.Build() so that startup exceptions
// (e.g. DB version mismatch, missing connection string) are written to the
// log file. Replaced by the full Serilog configuration from appsettings.json
Expand Down
4 changes: 4 additions & 0 deletions Backend.Server/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ public void ConfigureServices(IServiceCollection services)
"mysql" => new Persistence.MySql.DbContext(
connectionString: connectionString,
defaultCommendTimeout: Convert.ToInt32(serverConfiguration.DbCommandTimeout.TotalSeconds)),
"postgres" => new Persistence.Postgres.DbContext(
connectionString: connectionString,
defaultCommendTimeout: Convert.ToInt32(serverConfiguration.DbCommandTimeout.TotalSeconds),
collation: serverConfiguration.DbCollation),
_ => new Persistence.SqlServer.DbContext(
connectionString: connectionString,
defaultCommendTimeout: Convert.ToInt32(serverConfiguration.DbCommandTimeout.TotalSeconds),
Expand Down
Loading