mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 07:13:12 +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);
|
||||
}
|
||||
|
||||
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 oldEnd = FormatDateTime(workOrder.ScheduledEnd);
|
||||
|
||||
workOrder.ScheduledStart = WorkOrderBoardApptTimeParser.CombineDateAndTime(apptDate, start);
|
||||
workOrder.ScheduledEnd = WorkOrderBoardApptTimeParser.CombineDateAndTime(apptDate, end);
|
||||
workOrder.ScheduledStart = WorkOrderBoardApptTimeParser.ToScheduledInstant(apptDate, start);
|
||||
workOrder.ScheduledEnd = WorkOrderBoardApptTimeParser.ToScheduledInstant(apptDate, end);
|
||||
|
||||
var newStart = FormatDateTime(workOrder.ScheduledStart);
|
||||
var newEnd = FormatDateTime(workOrder.ScheduledEnd);
|
||||
|
|
|
|||
|
|
@ -85,8 +85,10 @@ namespace SeaHaven.Services.Implementation
|
|||
public static WorkOrderBoardRowDto MapRawRow(WorkOrderBoardRawRow row, DateTime utcNow)
|
||||
{
|
||||
// Appt column: date prefers dispatch appointment (vendor slot), then WO ScheduledDate.
|
||||
// Time prefers WO ScheduledStart/End (dispatcher window), then dispatch datetime.
|
||||
var apptStart = row.ScheduledStart ?? row.DispatchApptDate;
|
||||
// Time uses WO ScheduledStart/End only. Do not fall back to a date-only dispatch
|
||||
// instant (midnight), or clearing apptTime still renders 00:00.
|
||||
var apptStart = row.ScheduledStart
|
||||
?? (HasClockTime(row.DispatchApptDate) ? row.DispatchApptDate : null);
|
||||
var apptEnd = row.ScheduledEnd;
|
||||
var (vendorId, vendorName) = WorkOrderBoardDispatchAssignment.LiveVendor(
|
||||
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)
|
||||
=> $"{firstName ?? ""} {lastName ?? ""}".Trim();
|
||||
|
||||
|
|
|
|||
|
|
@ -651,8 +651,8 @@ namespace SeaHaven.Services.Implementation
|
|||
var oldEnd = FormatDateTime(workOrder.ScheduledEnd);
|
||||
var dispatchId = ResolveDispatchIdForAudit(dispatch);
|
||||
|
||||
workOrder.ScheduledStart = WorkOrderBoardApptTimeParser.CombineDateAndTime(apptDate, start);
|
||||
workOrder.ScheduledEnd = WorkOrderBoardApptTimeParser.CombineDateAndTime(apptDate, end);
|
||||
workOrder.ScheduledStart = WorkOrderBoardApptTimeParser.ToScheduledInstant(apptDate, start);
|
||||
workOrder.ScheduledEnd = WorkOrderBoardApptTimeParser.ToScheduledInstant(apptDate, end);
|
||||
|
||||
var newStart = FormatDateTime(workOrder.ScheduledStart);
|
||||
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);
|
||||
}
|
||||
|
||||
[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]
|
||||
public async Task PatchField_ApptTime_DashPrefixedToken_TreatedAsSingleStart()
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue