shoc-backend/SeaHaven.DataServices/Implementation/WorkOrderWebhookDataService.cs

161 lines
6.6 KiB
C#
Raw Normal View History

using Data.SeaHavenIndustries;
using Microsoft.EntityFrameworkCore;
using SeaHaven.DataServices.Interfaces;
namespace SeaHaven.DataServices.Implementation
{
public sealed class WorkOrderWebhookDataService : IWorkOrderWebhookDataService
{
private readonly ApplicationDbContext _context;
public WorkOrderWebhookDataService(ApplicationDbContext context)
{
_context = context;
}
public async Task<WorkOrderWebhookPersistenceResult> ApplyAsync(
WorkOrderWebhookMutation mutation,
CancellationToken cancellationToken)
{
var prior = await _context.WorkOrderWebhookDeliveries
.AsNoTracking()
.SingleOrDefaultAsync(d => d.DeliveryId == mutation.DeliveryId, cancellationToken);
if (prior != null)
return ExistingDeliveryResult(prior, mutation.BodySha256);
var workOrder = await _context.workOrders
.SingleOrDefaultAsync(
w => w.ExternalWorkOrderId == mutation.ExternalWorkOrderId,
cancellationToken);
if (workOrder == null)
{
var nextInternalNumber = Math.Max(
await _context.workOrders.MaxAsync(
w => (int?)w.Id,
cancellationToken) ?? 0,
0)
+ 1;
workOrder = new WorkOrder
{
ExternalWorkOrderId = mutation.ExternalWorkOrderId,
WorkerOrderNumber = mutation.WorkerOrderNumber,
InternalWONumber = nextInternalNumber.ToString("D11"),
WorkerOrderTitle = mutation.Title ?? mutation.Description
?? $"Imported work order {mutation.ExternalWorkOrderId}",
Description = mutation.Description,
Source = mutation.Source,
istemplate = false,
CreatedDate = mutation.CreatedAt ?? mutation.ProcessedAt.UtcDateTime
};
_context.workOrders.Add(workOrder);
}
var staleState = mutation.IsStateEvent
&& workOrder.ExternalLastOccurredAt.HasValue
&& mutation.OccurredAt < workOrder.ExternalLastOccurredAt.Value;
if (mutation.IsStateEvent && !staleState)
{
var locationKey = mutation.SiteCode ?? mutation.Building;
if (!string.IsNullOrWhiteSpace(locationKey))
{
var location = await _context.Locations
.FirstOrDefaultAsync(
l => l.Name == locationKey || l.Title == locationKey,
cancellationToken);
if (location == null)
{
location = new Locations
{
Name = locationKey,
Title = mutation.Building,
Address1 = mutation.Address,
Status = "Active"
};
_context.Locations.Add(location);
}
workOrder.Locations = location;
}
workOrder.WorkerOrderNumber = mutation.WorkerOrderNumber;
workOrder.WorkerOrderTitle = mutation.Title ?? mutation.Description;
workOrder.Description = mutation.Description;
workOrder.Status = mutation.IsCancelled ? "Cancelled" : mutation.Status;
workOrder.Severity = mutation.Severity;
workOrder.Priority = mutation.Priority;
workOrder.Customer = mutation.Customer;
workOrder.SiteCode = mutation.SiteCode;
workOrder.Building = mutation.Building;
workOrder.DueDate = mutation.DueDate;
workOrder.DateReported = mutation.DateReported;
workOrder.ScheduledStart = mutation.ScheduledStart;
workOrder.Source = mutation.Source;
workOrder.istemplate = false;
workOrder.ExternalLastOccurredAt = mutation.OccurredAt;
}
if (mutation.CommentId != null)
{
var commentExists = await _context.Comments
.AnyAsync(c => c.ExternalCommentId == mutation.CommentId, cancellationToken);
if (!commentExists)
{
_context.Comments.Add(new Comments
{
ExternalCommentId = mutation.CommentId,
Commenttext = mutation.CommentText,
Commenter = mutation.Commenter,
CommentType = mutation.CommentType,
RecordType = "WorkOrder",
WorkOrder = workOrder,
CreatedDate = mutation.OccurredAt.UtcDateTime
});
}
}
_context.WorkOrderWebhookDeliveries.Add(new WorkOrderWebhookDelivery
{
DeliveryId = mutation.DeliveryId,
EventType = mutation.EventType,
OccurredAt = mutation.OccurredAt,
ProcessedAt = mutation.ProcessedAt,
BodySha256 = mutation.BodySha256
});
try
{
await _context.SaveChangesAsync(cancellationToken);
return new WorkOrderWebhookPersistenceResult(
WorkOrderWebhookPersistenceStatus.Applied,
staleState);
}
catch (DbUpdateException)
{
_context.ChangeTracker.Clear();
var concurrent = await _context.WorkOrderWebhookDeliveries
.AsNoTracking()
.SingleOrDefaultAsync(d => d.DeliveryId == mutation.DeliveryId, cancellationToken);
if (concurrent == null)
throw;
return ExistingDeliveryResult(concurrent, mutation.BodySha256);
}
}
private static WorkOrderWebhookPersistenceResult ExistingDeliveryResult(
WorkOrderWebhookDelivery delivery,
string bodySha256)
{
return new WorkOrderWebhookPersistenceResult(
string.Equals(delivery.BodySha256, bodySha256, StringComparison.OrdinalIgnoreCase)
? WorkOrderWebhookPersistenceStatus.Duplicate
: WorkOrderWebhookPersistenceStatus.HashConflict);
}
}
}