mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-10-04 13:42:14 +00:00
fix(work-orders): persist empty apptTime as null scheduled instants
EOF
This commit is contained in:
parent
b605d5be02
commit
dcb757b404
6 changed files with 114 additions and 6 deletions
|
|
@ -53,5 +53,8 @@ namespace SeaHaven.Services.Helpers
|
||||||
|
|
||||||
return date.Value.Date.Add(time.Value);
|
return date.Value.Date.Add(time.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static DateTime? ToScheduledInstant(DateTime? date, TimeSpan? time)
|
||||||
|
=> time.HasValue ? CombineDateAndTime(date, time) : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -87,8 +87,8 @@ namespace SeaHaven.Services.Helpers
|
||||||
var oldStart = FormatDateTime(workOrder.ScheduledStart);
|
var oldStart = FormatDateTime(workOrder.ScheduledStart);
|
||||||
var oldEnd = FormatDateTime(workOrder.ScheduledEnd);
|
var oldEnd = FormatDateTime(workOrder.ScheduledEnd);
|
||||||
|
|
||||||
workOrder.ScheduledStart = WorkOrderBoardApptTimeParser.CombineDateAndTime(apptDate, start);
|
workOrder.ScheduledStart = WorkOrderBoardApptTimeParser.ToScheduledInstant(apptDate, start);
|
||||||
workOrder.ScheduledEnd = WorkOrderBoardApptTimeParser.CombineDateAndTime(apptDate, end);
|
workOrder.ScheduledEnd = WorkOrderBoardApptTimeParser.ToScheduledInstant(apptDate, end);
|
||||||
|
|
||||||
var newStart = FormatDateTime(workOrder.ScheduledStart);
|
var newStart = FormatDateTime(workOrder.ScheduledStart);
|
||||||
var newEnd = FormatDateTime(workOrder.ScheduledEnd);
|
var newEnd = FormatDateTime(workOrder.ScheduledEnd);
|
||||||
|
|
|
||||||
|
|
@ -85,8 +85,10 @@ namespace SeaHaven.Services.Implementation
|
||||||
public static WorkOrderBoardRowDto MapRawRow(WorkOrderBoardRawRow row, DateTime utcNow)
|
public static WorkOrderBoardRowDto MapRawRow(WorkOrderBoardRawRow row, DateTime utcNow)
|
||||||
{
|
{
|
||||||
// Appt column: date prefers dispatch appointment (vendor slot), then WO ScheduledDate.
|
// Appt column: date prefers dispatch appointment (vendor slot), then WO ScheduledDate.
|
||||||
// Time prefers WO ScheduledStart/End (dispatcher window), then dispatch datetime.
|
// Time uses WO ScheduledStart/End only. Do not fall back to a date-only dispatch
|
||||||
var apptStart = row.ScheduledStart ?? row.DispatchApptDate;
|
// instant (midnight), or clearing apptTime still renders 00:00.
|
||||||
|
var apptStart = row.ScheduledStart
|
||||||
|
?? (HasClockTime(row.DispatchApptDate) ? row.DispatchApptDate : null);
|
||||||
var apptEnd = row.ScheduledEnd;
|
var apptEnd = row.ScheduledEnd;
|
||||||
var (vendorId, vendorName) = WorkOrderBoardDispatchAssignment.LiveVendor(
|
var (vendorId, vendorName) = WorkOrderBoardDispatchAssignment.LiveVendor(
|
||||||
row.VendorId,
|
row.VendorId,
|
||||||
|
|
@ -145,6 +147,9 @@ namespace SeaHaven.Services.Implementation
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool HasClockTime(DateTime? value)
|
||||||
|
=> value.HasValue && value.Value.TimeOfDay != TimeSpan.Zero;
|
||||||
|
|
||||||
private static string FormatName(string? firstName, string? lastName)
|
private static string FormatName(string? firstName, string? lastName)
|
||||||
=> $"{firstName ?? ""} {lastName ?? ""}".Trim();
|
=> $"{firstName ?? ""} {lastName ?? ""}".Trim();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -651,8 +651,8 @@ namespace SeaHaven.Services.Implementation
|
||||||
var oldEnd = FormatDateTime(workOrder.ScheduledEnd);
|
var oldEnd = FormatDateTime(workOrder.ScheduledEnd);
|
||||||
var dispatchId = ResolveDispatchIdForAudit(dispatch);
|
var dispatchId = ResolveDispatchIdForAudit(dispatch);
|
||||||
|
|
||||||
workOrder.ScheduledStart = WorkOrderBoardApptTimeParser.CombineDateAndTime(apptDate, start);
|
workOrder.ScheduledStart = WorkOrderBoardApptTimeParser.ToScheduledInstant(apptDate, start);
|
||||||
workOrder.ScheduledEnd = WorkOrderBoardApptTimeParser.CombineDateAndTime(apptDate, end);
|
workOrder.ScheduledEnd = WorkOrderBoardApptTimeParser.ToScheduledInstant(apptDate, end);
|
||||||
|
|
||||||
var newStart = FormatDateTime(workOrder.ScheduledStart);
|
var newStart = FormatDateTime(workOrder.ScheduledStart);
|
||||||
var newEnd = FormatDateTime(workOrder.ScheduledEnd);
|
var newEnd = FormatDateTime(workOrder.ScheduledEnd);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
using Data.SeaHavenIndustries;
|
||||||
|
using SeaHaven.Services.Helpers;
|
||||||
|
|
||||||
|
namespace SeaHavenIndustries.Tests;
|
||||||
|
|
||||||
|
public class WorkOrderBoardFieldMutationsTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void ApplyApptTime_EmptyValue_ClearsStartAndEnd_KeepsDates()
|
||||||
|
{
|
||||||
|
var appointmentDate = new DateTime(2026, 6, 25);
|
||||||
|
var workOrder = new WorkOrder
|
||||||
|
{
|
||||||
|
ScheduledDate = appointmentDate,
|
||||||
|
ScheduledStart = new DateTime(2026, 6, 25, 9, 0, 0),
|
||||||
|
ScheduledEnd = new DateTime(2026, 6, 25, 11, 0, 0)
|
||||||
|
};
|
||||||
|
var dispatch = new Dispatch { Id = 10, ScheduledDate = appointmentDate };
|
||||||
|
|
||||||
|
WorkOrderBoardFieldMutations.ApplyApptTime(workOrder, dispatch, "");
|
||||||
|
|
||||||
|
Assert.Null(workOrder.ScheduledStart);
|
||||||
|
Assert.Null(workOrder.ScheduledEnd);
|
||||||
|
Assert.Equal(appointmentDate, workOrder.ScheduledDate);
|
||||||
|
Assert.Equal(appointmentDate, dispatch.ScheduledDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplyApptTime_StartOnly_LeavesEndNull()
|
||||||
|
{
|
||||||
|
var appointmentDate = new DateTime(2026, 6, 25);
|
||||||
|
var workOrder = new WorkOrder { ScheduledDate = appointmentDate };
|
||||||
|
var dispatch = new Dispatch { Id = 10, ScheduledDate = appointmentDate };
|
||||||
|
|
||||||
|
WorkOrderBoardFieldMutations.ApplyApptTime(workOrder, dispatch, "09:00");
|
||||||
|
|
||||||
|
Assert.Equal(new DateTime(2026, 6, 25, 9, 0, 0), workOrder.ScheduledStart);
|
||||||
|
Assert.Null(workOrder.ScheduledEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ApplyApptTime_Range_SetsStartAndEnd()
|
||||||
|
{
|
||||||
|
var appointmentDate = new DateTime(2026, 6, 25);
|
||||||
|
var workOrder = new WorkOrder { ScheduledDate = appointmentDate };
|
||||||
|
var dispatch = new Dispatch { Id = 10, ScheduledDate = appointmentDate };
|
||||||
|
|
||||||
|
WorkOrderBoardFieldMutations.ApplyApptTime(workOrder, dispatch, "09:00 – 11:00");
|
||||||
|
|
||||||
|
Assert.Equal(new DateTime(2026, 6, 25, 9, 0, 0), workOrder.ScheduledStart);
|
||||||
|
Assert.Equal(new DateTime(2026, 6, 25, 11, 0, 0), workOrder.ScheduledEnd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1070,6 +1070,53 @@ public class WorkOrderBoardUpdateServiceTests
|
||||||
Assert.Equal(new DateTime(2026, 6, 25, 10, 0, 0), reloaded.ScheduledEnd);
|
Assert.Equal(new DateTime(2026, 6, 25, 10, 0, 0), reloaded.ScheduledEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task PatchField_ApptTime_EmptyClearsStartAndEnd_KeepsAppointmentDate()
|
||||||
|
{
|
||||||
|
var (context, service) = CreateSut();
|
||||||
|
var appointmentDate = new DateTime(2026, 6, 25);
|
||||||
|
var dispatch = new Dispatch
|
||||||
|
{
|
||||||
|
Id = 10,
|
||||||
|
WorkOrderId = 1,
|
||||||
|
VendorId = 1,
|
||||||
|
ScheduledDate = appointmentDate,
|
||||||
|
RowVersion = new byte[] { 1, 0, 0, 0, 0, 0, 0, 2 }
|
||||||
|
};
|
||||||
|
var wo = new WorkOrder
|
||||||
|
{
|
||||||
|
Id = 1,
|
||||||
|
LifecycleStatus = LifecycleStatus.Scheduled,
|
||||||
|
PrimaryDispatchId = 10,
|
||||||
|
ScheduledDate = appointmentDate,
|
||||||
|
ScheduledStart = new DateTime(2026, 6, 25, 9, 0, 0),
|
||||||
|
ScheduledEnd = new DateTime(2026, 6, 25, 11, 0, 0),
|
||||||
|
RowVersion = new byte[] { 1, 0, 0, 0, 0, 0, 0, 1 }
|
||||||
|
};
|
||||||
|
context.Vendors.Add(new Vendor { Id = 1, CompanyName = "Vendor A" });
|
||||||
|
context.Dispatches.Add(dispatch);
|
||||||
|
context.workOrders.Add(wo);
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
|
||||||
|
var result = await service.PatchFieldAsync(1, new WorkOrderBoardPatchRequestDto
|
||||||
|
{
|
||||||
|
Field = WorkOrderBoardFieldNames.ApptTime,
|
||||||
|
Value = "",
|
||||||
|
WorkOrderVersion = ToVersion(wo),
|
||||||
|
DispatchVersion = ToVersion(dispatch),
|
||||||
|
PrimaryDispatchId = 10
|
||||||
|
}, "actor-1");
|
||||||
|
|
||||||
|
Assert.True(string.IsNullOrEmpty(result.ApptTime));
|
||||||
|
Assert.Equal(appointmentDate, result.ScheduledDate);
|
||||||
|
var reloaded = await context.workOrders.FindAsync(1);
|
||||||
|
Assert.Null(reloaded!.ScheduledStart);
|
||||||
|
Assert.Null(reloaded.ScheduledEnd);
|
||||||
|
Assert.Equal(appointmentDate, reloaded.ScheduledDate);
|
||||||
|
var reloadedDispatch = await context.Dispatches.FindAsync(10);
|
||||||
|
Assert.Equal(appointmentDate, reloadedDispatch!.ScheduledDate);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task PatchField_ApptTime_DashPrefixedToken_TreatedAsSingleStart()
|
public async Task PatchField_ApptTime_DashPrefixedToken_TreatedAsSingleStart()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue