Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 5 additions & 5 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="10.0.14" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Tools" Version="10.0.14" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.11.0" />
<PackageVersion Include="Imposter" Version="1.0.7" />
<PackageVersion Include="SharpCompress" Version="0.50.7" />
<PackageVersion Include="Imposter" Version="1.0.10" />
<PackageVersion Include="SharpCompress" Version="0.50.8" />
<PackageVersion Include="Shouldly" Version="4.3.0" />
<PackageVersion Include="SSH.NET" Version="2026.0.0" />
<PackageVersion Include="System.Security.Cryptography.Pkcs" Version="10.0.14" />
<PackageVersion Include="TransactionProcessing.ApiDefaults" Version="2026.11.2" />
<PackageVersion Include="TransactionProcessor.Database" Version="2026.10.2.411" />
<PackageVersion Include="TransactionProcessor.Database" Version="2026.10.3.418" />
<PackageVersion Include="xunit.v3" Version="4.0.2" />
<PackageVersion Include="xunit.runner.visualstudio" Version="4.0.1" />
<PackageVersion Include="Microsoft.Testing.Extensions.CodeCoverage" Version="18.12.0" />
Expand Down Expand Up @@ -50,6 +50,6 @@
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.14" />
<PackageVersion Include="Ductus.FluentDocker" Version="2.85.0" />
<PackageVersion Include="NLog" Version="6.2.2" />
<PackageVersion Include="SecurityService.Client" Version="2026.10.3.204" />
<PackageVersion Include="SecurityService.Client" Version="2026.10.3.207" />
</ItemGroup>
</Project>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,26 @@ public sealed class ReportQueryValidationTests
public void ValidateDateRange_AllowsThirtyInclusiveDays()
{
ReportQueryValidation.ValidateDateRange(
new DateTime(2026, 9, 1),
new DateTime(2026, 9, 30))
new DateOnly(2026, 9, 1),
new DateOnly(2026, 9, 30))
.ShouldBeNull();
}

[Fact]
public void ValidateDateRange_RejectsMoreThanThirtyInclusiveDays()
{
ReportQueryValidation.ValidateDateRange(
new DateTime(2026, 9, 1),
new DateTime(2026, 10, 1))
new DateOnly(2026, 9, 1),
new DateOnly(2026, 10, 1))
.ShouldBe("date range must not exceed 30 inclusive calendar days.");
}

[Fact]
public void ValidateDateRange_RejectsReversedDates()
{
ReportQueryValidation.ValidateDateRange(
new DateTime(2026, 9, 2),
new DateTime(2026, 9, 1))
new DateOnly(2026, 9, 2),
new DateOnly(2026, 9, 1))
.ShouldBe("startDate must be less than or equal to endDate.");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ public void SettlementFiltersAndFeeGroupingsFilterAndAggregateRows()
ContractId = contractId,
ContractProductId = productId,
TransactionType = "Sale",
TransactionDate = new DateTime(2026, 9, 1),
TransactionDate = new DateOnly(2026, 9, 1),
TransactionDateTime = new DateTime(2026, 9, 1),
TransactionTime = TimeSpan.Zero,
TransactionAmount = 10m,
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ private static TransactionProcessor.Database.Entities.Calendar CreateCalendar(Da
{
return new TransactionProcessor.Database.Entities.Calendar
{
Date = date,
Date = DateOnly.FromDateTime(date),
Year = year,
DayOfWeek = "Monday",
DayOfWeekShort = "Mon",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public async Task SettlementRequestHandler_ForwardsRequestAndCancellationToken()
{
var manager = new ISettlementReportingServiceImposter();
var expected = Result.Success(new TodaysSettlement());
var request = new SettlementQueries.TodaysSettlementQuery(Guid.NewGuid(), DateTime.Today);
var request = new SettlementQueries.TodaysSettlementQuery(Guid.NewGuid(), DateOnly.FromDateTime(DateTime.Today));
var cancellationToken = new CancellationTokenSource().Token;
manager.GetTodaysSettlement(Arg<SettlementQueries.TodaysSettlementQuery>.Any(), Arg<CancellationToken>.Any())
.Returns(Task.FromResult(expected));
Expand Down Expand Up @@ -152,7 +152,7 @@ public async Task EstateRequestHandler_ForwardsEstateOperatorsRequest()
public async Task FileImportLogRequestHandler_ForwardsRequest()
{
var manager = new IFileImportReportingServiceImposter();
var request = new FileImportLogQueries.GetFileImportLogListQuery(Guid.NewGuid(), null, DateTime.Today, DateTime.Today);
var request = new FileImportLogQueries.GetFileImportLogListQuery(Guid.NewGuid(), null, DateOnly.FromDateTime(DateTime.Today), DateOnly.FromDateTime(DateTime.Today));
manager.GetFileImportLogList(Arg<FileImportLogQueries.GetFileImportLogListQuery>.Any(), Arg<CancellationToken>.Any())
.Returns(Task.FromResult(Result.Success(new List<FileImportLog>())));

Expand Down Expand Up @@ -334,7 +334,7 @@ public async Task OperatorRequestHandler_ForwardsOperatorRequest()
public async Task TransactionRequestHandler_ForwardsRequest()
{
var manager = new ITransactionReportingServiceImposter();
var request = new TransactionQueries.ProductPerformanceQuery(Guid.NewGuid(), DateTime.Today, DateTime.Today);
var request = new TransactionQueries.ProductPerformanceQuery(Guid.NewGuid(), DateOnly.FromDateTime(DateTime.Today), DateOnly.FromDateTime(DateTime.Today));
manager.GetProductPerformanceReport(Arg<TransactionQueries.ProductPerformanceQuery>.Any(), Arg<CancellationToken>.Any())
.Returns(Task.FromResult(Result.Success(new ProductPerformanceResponse())));

Expand Down
6 changes: 3 additions & 3 deletions EstateReportingAPI.BusinessLogic.UnitTests/UnitTest1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public async Task ReportingService_GetCalendarYears_YearsAreReturned(){
await context.Database.EnsureCreatedAsync();

await context.Calendar.AddRangeAsync(new Calendar{
Date = new DateTime(2023, 1, 1),
Date = new DateOnly(2023, 1, 1),
DayOfWeek = "Monday",
DayOfWeekShort = "Mon",
MonthNameLong = "January",
Expand All @@ -53,7 +53,7 @@ await context.Calendar.AddRangeAsync(new Calendar{
},
new Calendar
{
Date = new DateTime(2022, 1, 1),
Date = new DateOnly(2022, 1, 1),
DayOfWeek = "Monday",
DayOfWeekShort = "Mon",
MonthNameLong = "January",
Expand All @@ -64,7 +64,7 @@ await context.Calendar.AddRangeAsync(new Calendar{
},
new Calendar
{
Date = new DateTime(2021, 1, 1),
Date = new DateOnly(2021, 1, 1),
DayOfWeek = "Monday",
DayOfWeekShort = "Mon",
MonthNameLong = "January",
Expand Down
2 changes: 1 addition & 1 deletion EstateReportingAPI.BusinessLogic/DatabaseModels.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ internal sealed class MerchantData {
public Guid MerchantId { get; init; }
public int MerchantReportingId { get; init; }
public string? Name { get; init; }
public DateTime CreatedDateTime { get; init; }
public DateTimeOffset CreatedDateTime { get; init; }
public string? Reference { get; init; }
public int SettlementSchedule { get; init; }
public MerchantAddressData? AddressInfo { get; init; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace EstateReportingAPI.BusinessLogic.Queries;
[ExcludeFromCodeCoverage]
public record FileImportLogQueries
{
public record GetFileImportLogListQuery(Guid EstateId, Guid? MerchantId, DateTime StartDate, DateTime EndDate) : IRequest<Result<List<FileImportLog>>>;
public record GetFileImportLogListQuery(Guid EstateId, Guid? MerchantId, DateOnly StartDate, DateOnly EndDate) : IRequest<Result<List<FileImportLog>>>;
public record GetFileImportLogQuery(Guid EstateId, Guid? MerchantId, Guid FileImportLogId) : IRequest<Result<FileImportLog>>;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ namespace EstateReportingAPI.BusinessLogic.Queries;

[ExcludeFromCodeCoverage]
public record SettlementQueries {
public record TodaysSettlementQuery(Guid EstateId, DateTime ComparisonDate) : IRequest<Result<TodaysSettlement>>;
public record TodaysSettlementQuery(Guid EstateId, DateOnly ComparisonDate) : IRequest<Result<TodaysSettlement>>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public record TodaysFailedSales(Guid EstateId, DateTime ComparisonDate, String R
public record TransactionDetailReportQuery(Guid EstateId, TransactionDetailReportRequest Request) : IRequest<Result<TransactionDetailReportResponse>>;
public record TransactionSummaryByMerchantQuery(Guid EstateId, TransactionSummaryByMerchantRequest Request) : IRequest<Result<TransactionSummaryByMerchantResponse>>;
public record TransactionSummaryByOperatorQuery(Guid EstateId, TransactionSummaryByOperatorRequest Request) : IRequest<Result<TransactionSummaryByOperatorResponse>>;
public record ProductPerformanceQuery(Guid EstateId, DateTime StartDate, DateTime EndDate, int PageNumber = 1, int PageSize = 50) : IRequest<Result<ProductPerformanceResponse>>;
public record ProductPerformanceQuery(Guid EstateId, DateOnly StartDate, DateOnly EndDate, int PageNumber = 1, int PageSize = 50) : IRequest<Result<ProductPerformanceResponse>>;
public record TransactionMixSummaryQuery(Guid EstateId, TransactionMixSummaryRequest Request) : IRequest<Result<TransactionMixSummaryResponse>>;
public record GetRecentActivityReceiptReportQuery(Guid EstateId, GetRecentActivityReceiptReportRequest Request) : IRequest<Result<GetRecentActivityReceiptReportResponse>>;
public record TodaysSalesByHour(Guid estateId, DateTime comparisonDate) : IRequest<Result<List<Models.TodaysSalesByHour>>>;
Expand Down
9 changes: 3 additions & 6 deletions EstateReportingAPI.BusinessLogic/ReportQueryValidation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,12 @@ namespace EstateReportingAPI.BusinessLogic;

public static class ReportQueryValidation
{
public static string? ValidateDateRange(DateTime startDate, DateTime endDate)
public static string? ValidateDateRange(DateOnly startDate, DateOnly endDate)
{
DateTime start = startDate.Date;
DateTime end = endDate.Date;

if (start > end)
if (startDate > endDate)
return "startDate must be less than or equal to endDate.";

if ((end - start).TotalDays + 1 > ReportQueryLimits.MaxDateRangeDays)
if ((endDate.DayNumber - startDate.DayNumber) + 1 > ReportQueryLimits.MaxDateRangeDays)
return "date range must not exceed 30 inclusive calendar days.";

return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ public async Task<Result<List<Calendar>>> GetCalendarComparisonDates(CalendarQue
using ResolvedDbContext<EstateManagementContext>? resolvedContext = Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString());
await using EstateManagementContext context = resolvedContext.Context;

DateTime today = DatePolicy.Today.ToDateTime(TimeOnly.MinValue);
DateTime startDate = today.AddYears(-1);
DateTime endDate = today.AddDays(-1); // yesterday
DateOnly today = DatePolicy.Today;
DateOnly startDate = today.AddYears(-1);
DateOnly endDate = today.AddDays(-1); // yesterday

var result = await ReportingQueryExecutor.ToListAsync(context.Calendar.Where(c => c.Date >= startDate && c.Date <= endDate).OrderByDescending(c => c.Date), cancellationToken, "Error retrieving calendar comparison dates");

Expand Down Expand Up @@ -73,7 +73,7 @@ public async Task<Result<List<Calendar>>> GetCalendarDates(CalendarQueries.GetAl
await using EstateManagementContext context = resolvedContext.Context;


var result = await ReportingQueryExecutor.ToListAsync(context.Calendar.Where(c => c.Date <= DatePolicy.Today.ToDateTime(TimeOnly.MinValue)), cancellationToken, "Error retrieving calendar dates");
var result = await ReportingQueryExecutor.ToListAsync(context.Calendar.Where(c => c.Date <= DatePolicy.Today), cancellationToken, "Error retrieving calendar dates");

if (result.IsFailed)
return ResultHelpers.CreateFailure(result);
Expand Down Expand Up @@ -104,7 +104,7 @@ public async Task<Result<List<Int32>>> GetCalendarYears(CalendarQueries.GetYears
using ResolvedDbContext<EstateManagementContext>? resolvedContext = Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString());
await using EstateManagementContext context = resolvedContext.Context;

var result = await ReportingQueryExecutor.ToListAsync(context.Calendar.Where(c => c.Date <= DatePolicy.Today.ToDateTime(TimeOnly.MinValue)).GroupBy(c => c.Year).Select(y => y.Key), cancellationToken, "Error retrieving calendar years");
var result = await ReportingQueryExecutor.ToListAsync(context.Calendar.Where(c => c.Date <= DatePolicy.Today).GroupBy(c => c.Year).Select(y => y.Key), cancellationToken, "Error retrieving calendar years");

if (result.IsFailed)
return ResultHelpers.CreateFailure(result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ from esu in esuJoin.DefaultIfEmpty()
join m in context.Merchants on f.MerchantId equals m.MerchantId into mJoin
from m in mJoin.DefaultIfEmpty()
join fl in context.FileLines on f.FileId equals fl.FileId
where fil.ImportLogDate >= request.StartDate.Date && fil.ImportLogDate < request.EndDate.Date.AddDays(1)
where fil.ImportLogDate >= request.StartDate && fil.ImportLogDate < request.EndDate.AddDays(1)
&& (request.MerchantId == null || f.MerchantId == request.MerchantId)
select new FileImportFlatData {
FileImportLogId = fil.FileImportLogId,
Expand Down Expand Up @@ -186,11 +186,11 @@ join o in context.Operators on c.OperatorId equals o.OperatorId
}
private sealed class FileImportFlatData {
public Guid FileImportLogId { get; init; }
public DateTime ImportLogDateTime { get; init; }
public DateTimeOffset ImportLogDateTime { get; init; }
public Guid FileId { get; init; }
public string? FileName { get; init; }
public Guid? FileProfileId { get; init; }
public DateTime DateTimeUploaded { get; init; }
public DateTimeOffset DateTimeUploaded { get; init; }
public Guid UserId { get; init; }
public string? UploadedBy { get; init; }
public Guid MerchantId { get; init; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public async Task<Result<TodaysSettlement>> GetTodaysSettlement(SettlementQuerie
using ResolvedDbContext<EstateManagementContext>? resolvedContext = Resolver.Resolve(EstateManagementDatabaseName, request.EstateId.ToString());
await using EstateManagementContext context = resolvedContext.Context;

IQueryable<DatabaseProjections.TodaySettlementTransactionProjection> todaySettlementData = this.BuildTodaySettlementQuery(context, DatePolicy.Today.ToDateTime(TimeOnly.MinValue));
IQueryable<DatabaseProjections.TodaySettlementTransactionProjection> todaySettlementData = this.BuildTodaySettlementQuery(context, DatePolicy.Today);
IQueryable<DatabaseProjections.ComparisonSettlementTransactionProjection> comparisonSettlementData = this.BuildComparisonSettlementQuery(context, request.ComparisonDate);

DatabaseProjections.SettlementGroupProjection todaySettlement = await this.GetSettlementSummary(todaySettlementData, cancellationToken);
Expand Down Expand Up @@ -87,14 +87,14 @@ public async Task<Result<TodaysSettlement>> GetTodaysSettlement(SettlementQuerie
}

private IQueryable<DatabaseProjections.TodaySettlementTransactionProjection> BuildTodaySettlementQuery(EstateManagementContext context,
DateTime settlementDate) {
DateOnly settlementDate) {
IQueryable<DatabaseProjections.TodaySettlementTransactionProjection> settlementData = from s in context.Settlements join f in context.MerchantSettlementFees on s.SettlementId equals f.SettlementId join t in context.TodayTransactions on f.TransactionId equals t.TransactionId where s.SettlementDate == settlementDate select new DatabaseProjections.TodaySettlementTransactionProjection { Fee = f, Txn = t };
return settlementData;
}

private IQueryable<DatabaseProjections.ComparisonSettlementTransactionProjection> BuildComparisonSettlementQuery(EstateManagementContext context,
DateTime settlementDate) {
IQueryable<DatabaseProjections.ComparisonSettlementTransactionProjection> settlementData = from s in context.Settlements join f in context.MerchantSettlementFees on s.SettlementId equals f.SettlementId join t in context.TransactionHistory on f.TransactionId equals t.TransactionId where s.SettlementDate == settlementDate.Date select new DatabaseProjections.ComparisonSettlementTransactionProjection { Fee = f, Txn = t };
DateOnly settlementDate) {
IQueryable<DatabaseProjections.ComparisonSettlementTransactionProjection> settlementData = from s in context.Settlements join f in context.MerchantSettlementFees on s.SettlementId equals f.SettlementId join t in context.TransactionHistory on f.TransactionId equals t.TransactionId where s.SettlementDate == settlementDate select new DatabaseProjections.ComparisonSettlementTransactionProjection { Fee = f, Txn = t };
return settlementData;
}
}
Loading
Loading