diff --git a/Api.SeaHavenIndustries.Tests/WorkOrderDataServiceTimestampTests.cs b/Api.SeaHavenIndustries.Tests/WorkOrderDataServiceTimestampTests.cs new file mode 100644 index 0000000..512ad0e --- /dev/null +++ b/Api.SeaHavenIndustries.Tests/WorkOrderDataServiceTimestampTests.cs @@ -0,0 +1,68 @@ +using Data.SeaHavenIndustries; +using FluentAssertions; +using Microsoft.EntityFrameworkCore; +using SeaHaven.DataServices.Implementation; +using Xunit; + +namespace Api.SeaHavenIndustries.Tests; + +/// +/// The SLA clock and every "created"/"modified" display read these stamps as UTC, so the data layer +/// must never write local server time into them. +/// +public class WorkOrderDataServiceTimestampTests +{ + private static ApplicationDbContext NewContext() + { + var options = new DbContextOptionsBuilder() + .UseInMemoryDatabase(Guid.NewGuid().ToString()) + .Options; + return new ApplicationDbContext(options); + } + + private static WorkOrder NewWorkOrder() => + new() { InternalWONumber = "WO-1", WorkerOrderTitle = "Leak", LocationId = 100 }; + + [Fact] + public async Task AddAsync_KeepsTheCreationTimeTheCallerSet() + { + await using var context = NewContext(); + var createdAt = new DateTime(2026, 9, 25, 14, 0, 0, DateTimeKind.Utc); + var workOrder = NewWorkOrder(); + workOrder.CreatedDate = createdAt; + + var saved = await new WorkOrderDataService(context).AddAsync(workOrder); + + saved.CreatedDate.Should().Be(createdAt); + saved.CreatedDate!.Value.Kind.Should().Be(DateTimeKind.Utc); + (await context.workOrders.SingleAsync()).CreatedDate.Should().Be(createdAt); + } + + [Fact] + public async Task AddAsync_StampsUtcWhenTheCallerSetNoCreationTime() + { + await using var context = NewContext(); + var before = DateTime.UtcNow; + + var saved = await new WorkOrderDataService(context).AddAsync(NewWorkOrder()); + + saved.CreatedDate.Should().NotBeNull(); + saved.CreatedDate!.Value.Kind.Should().Be(DateTimeKind.Utc); + saved.CreatedDate.Value.Should().BeOnOrAfter(before).And.BeOnOrBefore(DateTime.UtcNow); + } + + [Fact] + public async Task UpdateAsync_StampsTheModificationTimeInUtc() + { + await using var context = NewContext(); + var service = new WorkOrderDataService(context); + var saved = await service.AddAsync(NewWorkOrder()); + var before = DateTime.UtcNow; + + await service.UpdateAsync(saved); + + saved.LastModificationTime.Should().NotBeNull(); + saved.LastModificationTime!.Value.Kind.Should().Be(DateTimeKind.Utc); + saved.LastModificationTime.Value.Should().BeOnOrAfter(before).And.BeOnOrBefore(DateTime.UtcNow); + } +} diff --git a/SeaHaven.DataServices/Implementation/AccountDataService.cs b/SeaHaven.DataServices/Implementation/AccountDataService.cs index 5b00af2..ec2f874 100644 --- a/SeaHaven.DataServices/Implementation/AccountDataService.cs +++ b/SeaHaven.DataServices/Implementation/AccountDataService.cs @@ -64,7 +64,7 @@ namespace SeaHaven.DataServices.Implementation public async Task AddAsync(Accounts account) { - account.CreatedDate = DateTime.Now; + account.CreatedDate = DateTime.UtcNow; await _context.Accounts.AddAsync(account); await _context.SaveChangesAsync(); return account; @@ -72,7 +72,7 @@ namespace SeaHaven.DataServices.Implementation public async Task UpdateAsync(Accounts account) { - account.LastModificationTime = DateTime.Now; + account.LastModificationTime = DateTime.UtcNow; _context.Accounts.Update(account); await _context.SaveChangesAsync(); } diff --git a/SeaHaven.DataServices/Implementation/AssetDataService.cs b/SeaHaven.DataServices/Implementation/AssetDataService.cs index 93a3f1e..1d60a7d 100644 --- a/SeaHaven.DataServices/Implementation/AssetDataService.cs +++ b/SeaHaven.DataServices/Implementation/AssetDataService.cs @@ -72,7 +72,7 @@ namespace SeaHaven.DataServices.Implementation public async Task AddAsync(Assets asset) { - asset.CreatedDate = DateTime.Now; + asset.CreatedDate = DateTime.UtcNow; await _context.Assets.AddAsync(asset); await _context.SaveChangesAsync(); return asset; @@ -80,7 +80,7 @@ namespace SeaHaven.DataServices.Implementation public async Task UpdateAsync(Assets asset) { - asset.LastModificationTime = DateTime.Now; + asset.LastModificationTime = DateTime.UtcNow; _context.Assets.Update(asset); await _context.SaveChangesAsync(); } diff --git a/SeaHaven.DataServices/Implementation/CategoryDataService.cs b/SeaHaven.DataServices/Implementation/CategoryDataService.cs index c5af096..994acc3 100644 --- a/SeaHaven.DataServices/Implementation/CategoryDataService.cs +++ b/SeaHaven.DataServices/Implementation/CategoryDataService.cs @@ -25,7 +25,7 @@ namespace SeaHaven.DataServices.Implementation public async Task AddAsync(Category category) { - category.CreatedDate = DateTime.Now; + category.CreatedDate = DateTime.UtcNow; await _context.Categories.AddAsync(category); await _context.SaveChangesAsync(); return category; @@ -33,7 +33,7 @@ namespace SeaHaven.DataServices.Implementation public async Task UpdateAsync(Category category) { - category.LastModificationTime = DateTime.Now; + category.LastModificationTime = DateTime.UtcNow; _context.Categories.Update(category); await _context.SaveChangesAsync(); } diff --git a/SeaHaven.DataServices/Implementation/ContactDataService.cs b/SeaHaven.DataServices/Implementation/ContactDataService.cs index 8196d2b..e4abf4f 100644 --- a/SeaHaven.DataServices/Implementation/ContactDataService.cs +++ b/SeaHaven.DataServices/Implementation/ContactDataService.cs @@ -100,7 +100,7 @@ namespace SeaHaven.DataServices.Implementation public async Task AddAsync(Contacts contact) { - contact.CreatedDate = DateTime.Now; + contact.CreatedDate = DateTime.UtcNow; await _context.Contacts.AddAsync(contact); await _context.SaveChangesAsync(); return contact; @@ -108,7 +108,7 @@ namespace SeaHaven.DataServices.Implementation public async Task UpdateAsync(Contacts contact) { - contact.LastModificationTime = DateTime.Now; + contact.LastModificationTime = DateTime.UtcNow; _context.Contacts.Update(contact); await _context.SaveChangesAsync(); } diff --git a/SeaHaven.DataServices/Implementation/DispatchDataService.cs b/SeaHaven.DataServices/Implementation/DispatchDataService.cs index 3274713..398051d 100644 --- a/SeaHaven.DataServices/Implementation/DispatchDataService.cs +++ b/SeaHaven.DataServices/Implementation/DispatchDataService.cs @@ -85,7 +85,7 @@ namespace SeaHaven.DataServices.Implementation public async Task AddAsync(Dispatch dispatch) { - dispatch.CreatedDate = DateTime.Now; + dispatch.CreatedDate = DateTime.UtcNow; await _context.Dispatches.AddAsync(dispatch); await _context.SaveChangesAsync(); return dispatch; @@ -93,7 +93,7 @@ namespace SeaHaven.DataServices.Implementation public async Task UpdateAsync(Dispatch dispatch) { - dispatch.LastModificationTime = DateTime.Now; + dispatch.LastModificationTime = DateTime.UtcNow; _context.Dispatches.Update(dispatch); await _context.SaveChangesAsync(); } diff --git a/SeaHaven.DataServices/Implementation/EmployeeDataService.cs b/SeaHaven.DataServices/Implementation/EmployeeDataService.cs index 4606d11..7b0b2c7 100644 --- a/SeaHaven.DataServices/Implementation/EmployeeDataService.cs +++ b/SeaHaven.DataServices/Implementation/EmployeeDataService.cs @@ -72,7 +72,7 @@ namespace SeaHaven.DataServices.Implementation public async Task AddAsync(Employee employee) { - employee.CreatedDate = DateTime.Now; + employee.CreatedDate = DateTime.UtcNow; await _context.Employees.AddAsync(employee); await _context.SaveChangesAsync(); return employee; @@ -80,7 +80,7 @@ namespace SeaHaven.DataServices.Implementation public async Task UpdateAsync(Employee employee) { - employee.LastModificationTime = DateTime.Now; + employee.LastModificationTime = DateTime.UtcNow; _context.Employees.Update(employee); await _context.SaveChangesAsync(); } diff --git a/SeaHaven.DataServices/Implementation/FollowUpDataService.cs b/SeaHaven.DataServices/Implementation/FollowUpDataService.cs index 4eebe82..72ef131 100644 --- a/SeaHaven.DataServices/Implementation/FollowUpDataService.cs +++ b/SeaHaven.DataServices/Implementation/FollowUpDataService.cs @@ -88,7 +88,7 @@ namespace SeaHaven.DataServices.Implementation public async Task AddAsync(FollowUps followUp) { - followUp.CreatedDate = DateTime.Now; + followUp.CreatedDate = DateTime.UtcNow; await _context.FollowUps.AddAsync(followUp); await _context.SaveChangesAsync(); return followUp; @@ -96,7 +96,7 @@ namespace SeaHaven.DataServices.Implementation public async Task UpdateAsync(FollowUps followUp) { - followUp.LastModificationTime = DateTime.Now; + followUp.LastModificationTime = DateTime.UtcNow; _context.FollowUps.Update(followUp); await _context.SaveChangesAsync(); } @@ -218,7 +218,7 @@ namespace SeaHaven.DataServices.Implementation public async Task AddAsync(FollowUps followUp, CancellationToken cancellationToken) { - followUp.CreatedDate = DateTime.Now; + followUp.CreatedDate = DateTime.UtcNow; await _context.FollowUps.AddAsync(followUp, cancellationToken); await _context.SaveChangesAsync(cancellationToken); return followUp; @@ -226,7 +226,7 @@ namespace SeaHaven.DataServices.Implementation public async Task UpdateAsync(FollowUps followUp, CancellationToken cancellationToken) { - followUp.LastModificationTime = DateTime.Now; + followUp.LastModificationTime = DateTime.UtcNow; _context.FollowUps.Update(followUp); await _context.SaveChangesAsync(cancellationToken); } @@ -238,7 +238,7 @@ namespace SeaHaven.DataServices.Implementation return false; entity.Status = status; - entity.LastModificationTime = DateTime.Now; + entity.LastModificationTime = DateTime.UtcNow; await _context.SaveChangesAsync(cancellationToken); return true; } diff --git a/SeaHaven.DataServices/Implementation/LocationDataService.cs b/SeaHaven.DataServices/Implementation/LocationDataService.cs index 11cb89e..b331a01 100644 --- a/SeaHaven.DataServices/Implementation/LocationDataService.cs +++ b/SeaHaven.DataServices/Implementation/LocationDataService.cs @@ -98,7 +98,7 @@ namespace SeaHaven.DataServices.Implementation public async Task AddAsync(Locations location) { - location.CreatedDate = DateTime.Now; + location.CreatedDate = DateTime.UtcNow; await _context.Locations.AddAsync(location); await _context.SaveChangesAsync(); return location; @@ -106,7 +106,7 @@ namespace SeaHaven.DataServices.Implementation public async Task UpdateAsync(Locations location) { - location.LastModificationTime = DateTime.Now; + location.LastModificationTime = DateTime.UtcNow; _context.Locations.Update(location); await _context.SaveChangesAsync(); } @@ -228,7 +228,7 @@ namespace SeaHaven.DataServices.Implementation public async Task AddAsync(Locations location, CancellationToken cancellationToken) { - location.CreatedDate = DateTime.Now; + location.CreatedDate = DateTime.UtcNow; await _context.Locations.AddAsync(location, cancellationToken); await _context.SaveChangesAsync(cancellationToken); return location; @@ -236,7 +236,7 @@ namespace SeaHaven.DataServices.Implementation public async Task UpdateAsync(Locations location, CancellationToken cancellationToken) { - location.LastModificationTime = DateTime.Now; + location.LastModificationTime = DateTime.UtcNow; _context.Locations.Update(location); await _context.SaveChangesAsync(cancellationToken); } @@ -249,7 +249,7 @@ namespace SeaHaven.DataServices.Implementation if (entity == null) return false; - var now = DateTime.Now; + var now = DateTime.UtcNow; foreach (var contact in entity.Contacts ?? Enumerable.Empty()) { if (contact.IsDeleted != true) diff --git a/SeaHaven.DataServices/Implementation/PMScheduleDataService.cs b/SeaHaven.DataServices/Implementation/PMScheduleDataService.cs index a2418ea..6bc925a 100644 --- a/SeaHaven.DataServices/Implementation/PMScheduleDataService.cs +++ b/SeaHaven.DataServices/Implementation/PMScheduleDataService.cs @@ -64,7 +64,7 @@ namespace SeaHaven.DataServices.Implementation public async Task AddAsync(PMSchedules schedule) { - schedule.CreatedDate = DateTime.Now; + schedule.CreatedDate = DateTime.UtcNow; await _context.PMSchedules.AddAsync(schedule); await _context.SaveChangesAsync(); return schedule; @@ -72,7 +72,7 @@ namespace SeaHaven.DataServices.Implementation public async Task UpdateAsync(PMSchedules schedule) { - schedule.LastModificationTime = DateTime.Now; + schedule.LastModificationTime = DateTime.UtcNow; _context.PMSchedules.Update(schedule); await _context.SaveChangesAsync(); } diff --git a/SeaHaven.DataServices/Implementation/WorkOrderDataService.cs b/SeaHaven.DataServices/Implementation/WorkOrderDataService.cs index d32b77b..b34db11 100644 --- a/SeaHaven.DataServices/Implementation/WorkOrderDataService.cs +++ b/SeaHaven.DataServices/Implementation/WorkOrderDataService.cs @@ -193,7 +193,7 @@ namespace SeaHaven.DataServices.Implementation public async Task AddAsync(WorkOrder workOrder) { - workOrder.CreatedDate = DateTime.Now; + workOrder.CreatedDate ??= DateTime.UtcNow; await _context.workOrders.AddAsync(workOrder); await _context.SaveChangesAsync(); return workOrder; @@ -201,7 +201,7 @@ namespace SeaHaven.DataServices.Implementation public async Task UpdateAsync(WorkOrder workOrder) { - workOrder.LastModificationTime = DateTime.Now; + workOrder.LastModificationTime = DateTime.UtcNow; _context.workOrders.Update(workOrder); await _context.SaveChangesAsync(); }