mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 14:13:12 +00:00
161 lines
6.6 KiB
C#
161 lines
6.6 KiB
C#
|
|
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);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|