diff --git a/server/AyaNova/biz/NotifyEventType.cs b/server/AyaNova/biz/NotifyEventType.cs index fa3e209d..b6c8845e 100644 --- a/server/AyaNova/biz/NotifyEventType.cs +++ b/server/AyaNova/biz/NotifyEventType.cs @@ -14,7 +14,7 @@ namespace AyaNova.Biz ObjectDeleted = 1,//* Deletion of any object of conditional specific AyaType and optionally conditional tags ObjectCreated = 2,//* creation of any object of conditional specific AyaType and optionally conditional tags ObjectModified = 3,//* Modification / update of any kind of any object of conditional specific AyaType and optionally conditional tags - WorkorderStatusChange = 4,//* Workorder object, any NEW status set. Conditions: specific status ID value, Workorder TAGS + WorkorderStatusChange = 4,//* Workorder object, any NEW status set. Conditions: specific status ID value only (no generic any status allowed), Workorder TAGS ContractExpiring = 5,//* Contract object, aged notification with optional advance notice for expiration date of contract. Customer version and User version deliveries possible. CSRAccepted = 6,//*CustomerServiceRequest object, saved with ACCEPTED status, delivered to Customer only CSRRejected = 7,//*CustomerServiceRequest object, saved with REJECTED status, delivered to Customer only @@ -25,7 +25,7 @@ namespace AyaNova.Biz ReminderImminent = 12,//*Reminder object, Advance notice setting tag conditional ScheduledOnWorkorder = 13,//*Workorder / WorkorderItemScheduledUser object, instant notification when current user is scheduled on a service workorder ScheduledOnWorkorderImminent = 14,//*Workorder / WorkorderItemScheduledUser object, advanced (settable) notification when current user's scheduled date/time is imminent - WorkorderFinishStatusOverdue = 15,//* Workorder object not set to a "Finished" flagged workorder status type in selected time span from creation of workorderWorkorderSetToFinishedStatus + WorkorderFinishStatusOverdue = 15,//* Workorder object not set to a "Completed" flagged workorder status type in selected time span from creation of workorder OutsideServiceOverdue = 16,//* Workorder object , WorkorderItemOutsideService created / updated, sets advance notice on due date tag filterable OutsideServiceReceived = 17,//* Workorder object , WorkorderItemOutsideService updated, instant notification when item received, tag filterable PartRequestReceived = 18,//* Workorder object / workorderitempartrequest updated, sent to person who requested when parts received back diff --git a/server/AyaNova/biz/WorkOrderBiz.cs b/server/AyaNova/biz/WorkOrderBiz.cs index 081dabf0..c3520e57 100644 --- a/server/AyaNova/biz/WorkOrderBiz.cs +++ b/server/AyaNova/biz/WorkOrderBiz.cs @@ -986,8 +986,47 @@ namespace AyaNova.Biz await NotifyEventHelper.ProcessStandardObjectEvents(ayaEvent, proposedObj, ct); //SPECIFIC EVENTS FOR THIS OBJECT + WorkOrder o = (WorkOrder)proposedObj; - if (ayaEvent == AyaEvent.Deleted) + + //OVERDUE TO COMPLETION + if (ayaEvent == AyaEvent.Created) + {// WorkorderFinishStatusOverdue Created here on workorder creation for any subscribers + // State notify event processor below has more notes and details and will remove this event if set to a completed state + + var subs = await ct.NotifySubscription.Where(z => z.EventType == NotifyEventType.WorkorderFinishStatusOverdue).ToListAsync(); + + foreach (var sub in subs) + { + //not for inactive users + if (!await UserBiz.UserIsActive(sub.UserId)) continue; + + //Tag match? (will be true if no sub tags so always safe to call this) + if (NotifyEventHelper.TagsMatch(o.Tags, sub.Tags)) + { + var OverdueDate = DateTime.UtcNow.Add(sub.AgeValue);//age value is how long the user wants to wait before workorder is considered overdue + NotifyEvent n = new NotifyEvent() + { + EventType = NotifyEventType.WorkorderFinishStatusOverdue, + UserId = sub.UserId, + AyaType = o.AyaType, + ObjectId = o.Id, + NotifySubscriptionId = sub.Id, + Name = o.Serial.ToString(), + EventDate = OverdueDate + }; + await ct.NotifyEvent.AddAsync(n); + log.LogDebug($"Adding NotifyEvent: [{n.ToString()}]"); + await ct.SaveChangesAsync(); + } + } + + }//overdue event + + + + + if (ayaEvent == AyaEvent.Deleted) { //remove any potential time delayed STATUS notifications for OVERDUE NOT CLOSED STATUS //NOTE: if the workorder is deleted the above process standard etc will automatically @@ -1090,7 +1129,7 @@ namespace AyaNova.Biz //no need to call this because it's only going to run this method if the workorder is deleted and //via process standard notifciation events for workorder deletion will remove any state delayed notifications anyway so //nothing to call or do here related to notification - // await StateHandlePotentialNotificationEvent(AyaEvent.Deleted, wostate); + // await StateHandlePotentialNotificationEvent(AyaEvent.Deleted, wostate); } } catch @@ -1156,35 +1195,37 @@ namespace AyaNova.Biz //NONE: state notifications are specific and not the same as for general objects so don't process standard events //SPECIFIC EVENTS FOR THIS OBJECT - //WorkorderStatusChange = 4,//* Workorder object, any *change* of status including from no status (new) to a specific conditional status ID value + //WorkorderStatusChange = 4,//*Workorder object, any NEW status set. Conditions: specific status ID value only (no generic any status allowed), Workorder TAGS //WorkorderFinishStatusOverdue = 15,//* Workorder object not set to a "Finished" flagged workorder status type in selected time span from creation of workorderWorkorderSetToFinishedStatus //WorkorderStatusAge = 24,//* Workorder object Created / Updated, conditional on exact status selected IdValue, Tags conditional, advance notice can be set + //NOTE: ID, state notifications are for the Workorder, not the state itself unlike other objects, so use the WO type and ID here for all notifications + WorkOrderState o = (WorkOrderState)proposedObj; + WorkOrderStatus wos = await ct.WorkOrderStatus.AsNoTracking().FirstOrDefaultAsync(x => x.Id == o.WorkOrderStatusId); + WorkOrder wo = await ct.WorkOrder.AsNoTracking().FirstOrDefaultAsync(x => x.Id == o.WorkOrderId); + var WorkorderName = wo.Serial.ToString(); //## DELETED EVENTS - //A state cannot be deleted so nothing to handle that is required - //a workorder CAN be deleted and it will automatically remove all events for it so also no need to remove time delayed status events either if wo is deleted. - //so in essence there is nothing to be done regarding deleted events with states + //A state cannot be deleted so nothing to handle that is required + //a workorder CAN be deleted and it will automatically remove all events for it so also no need to remove time delayed status events either if wo is deleted. + //so in essence there is nothing to be done regarding deleted events with states in a blanket way, however specific events below may remove them as appropriate - //NO, the above is not correct, time delayed ones should NOT be removed for example finished until appropriate or if wo deleted - //so there should be a deleted event here handled with delete of all notifications sitting and the blanket remove below should be more surgical - //and only apply to stuff that it is approriate to remove - //#NOTE: state can be deleted so this block will handle that - await NotifyEventHelper.ClearPriorEventsForObject(ct, proposedObj.AyaType, o.Id, NotifyEventType.WorkorderStatusChange); - await NotifyEventHelper.ClearPriorEventsForObject(ct, proposedObj.AyaType, o.Id, NotifyEventType.WorkorderFinishStatusOverdue); - await NotifyEventHelper.ClearPriorEventsForObject(ct, proposedObj.AyaType, o.Id, NotifyEventType.WorkorderStatusAge); + // await NotifyEventHelper.ClearPriorEventsForObject(ct, proposedObj.AyaType, o.Id, NotifyEventType.WorkorderStatusChange); + // await NotifyEventHelper.ClearPriorEventsForObject(ct, proposedObj.AyaType, o.Id, NotifyEventType.WorkorderFinishStatusOverdue); + // await NotifyEventHelper.ClearPriorEventsForObject(ct, proposedObj.AyaType, o.Id, NotifyEventType.WorkorderStatusAge); //## CREATED (this is the only possible notification CREATION ayaEvent type for a workorder state as they are create only) if (ayaEvent == AyaEvent.Created) { - //# STATUS CHANGE (create new status) { - var subs = await ct.NotifySubscription.Where(z => z.EventType == NotifyEventType.WorkorderStatusChange).ToListAsync(); + //Conditions: must match specific status id value and also tags below + //delivery is immediate so no need to remove old ones of this kind + var subs = await ct.NotifySubscription.Where(z => z.EventType == NotifyEventType.WorkorderStatusChange && z.IdValue == o.WorkOrderStatusId).ToListAsync(); foreach (var sub in subs) { //not for inactive users @@ -1197,10 +1238,10 @@ namespace AyaNova.Biz { EventType = NotifyEventType.WorkorderStatusChange, UserId = sub.UserId, - AyaType = o.AyaType, - ObjectId = o.Id, + AyaType = AyaType.WorkOrder, + ObjectId = o.WorkOrderId, NotifySubscriptionId = sub.Id, - Name = wo.Serial.ToString() + Name = WorkorderName }; await ct.NotifyEvent.AddAsync(n); log.LogDebug($"Adding NotifyEvent: [{n.ToString()}]"); @@ -1210,32 +1251,24 @@ namespace AyaNova.Biz }//workorder status change event - //# WorkorderFinishStatusOverdue - {//* Workorder object not set to a "Finished" flagged workorder status type in selected time span from creation of workorderWorkorderSetToFinishedStatus - var subs = await ct.NotifySubscription.Where(z => z.EventType == NotifyEventType.WorkorderStatusChange).ToListAsync(); - foreach (var sub in subs) - { - //not for inactive users - if (!await UserBiz.UserIsActive(sub.UserId)) continue; + //# OVERDUE TO COMPLETED + { + //NOTE: the initial notification is created by the Workorder Header notification as it's where this time delayed notification is first generated + //the only job here in state notification is to remove any prior finish overdue notifications waiting if a new state is selected that is a completed state - //Tag match? (will be true if no sub tags so always safe to call this) - if (NotifyEventHelper.TagsMatch(wo.Tags, sub.Tags)) - { - NotifyEvent n = new NotifyEvent() - { - EventType = NotifyEventType.WorkorderStatusChange, - UserId = sub.UserId, - AyaType = o.AyaType, - ObjectId = o.Id, - NotifySubscriptionId = sub.Id, - Name = wo.Serial.ToString() - }; - await ct.NotifyEvent.AddAsync(n); - log.LogDebug($"Adding NotifyEvent: [{n.ToString()}]"); - await ct.SaveChangesAsync(); - } + //NOTE ABOUT RE-OPEN DECISION ON HOW THIS WORKS: + + //what though if it's not a finished status, then I guess don't remove it, but what if it *was* a finished status and it's change to a non finished? + //that, in essence re-opens it so it's not finished at that point. + //My decision on this june 2021 is that a work order finished status notification is satisifed the moment it's saved with a finished status + //and nothing afterwards restarts that process so if a person sets closed status then sets open status again no new finished overdue notification will be generated + + if (wos.Completed) + { + //Workorder was just set to a completed status so remove any notify events lurking to deliver for overdue + await NotifyEventHelper.ClearPriorEventsForObject(ct, proposedObj.AyaType, o.WorkOrderId, NotifyEventType.WorkorderFinishStatusOverdue); } - }//workorder finish change event + }//workorder overdue change event } diff --git a/server/AyaNova/models/WorkOrderState.cs b/server/AyaNova/models/WorkOrderState.cs index dcf31572..c5f2271e 100644 --- a/server/AyaNova/models/WorkOrderState.cs +++ b/server/AyaNova/models/WorkOrderState.cs @@ -26,8 +26,8 @@ namespace AyaNova.Models //UTILITY FIELDS //related - [JsonIgnore]//internal only here at server not used by client - public WorkOrderStatus WorkOrderStatus { get; set; } + // [JsonIgnore]//internal only here at server not used by client + // public WorkOrderStatus WorkOrderStatus { get; set; } [NotMapped, JsonIgnore] public AyaType AyaType { get => AyaType.WorkOrderStatus; }