|
|
|
|
@@ -903,27 +903,8 @@ namespace AyaNova.Biz
|
|
|
|
|
o.CustomerEmailAddressViz = vc.Get("custemail", o.CustomerId);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
// var custInfo = await ct.Customer.AsNoTracking().Where(x => x.Id == o.CustomerId).Select(x => new { x.AlertNotes, x.TechNotes, x.Name, x.Phone1, x.Phone2, x.Phone3, x.Phone4, x.Phone5, x.EmailAddress }).FirstOrDefaultAsync();
|
|
|
|
|
// if (!string.IsNullOrWhiteSpace(custInfo.AlertNotes))
|
|
|
|
|
// {
|
|
|
|
|
// o.AlertViz = $"{await Translate("Customer")} - {await Translate("AlertNotes")}\n{custInfo.AlertNotes}\n\n";
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// if (!string.IsNullOrWhiteSpace(custInfo.TechNotes))
|
|
|
|
|
// {
|
|
|
|
|
// o.CustomerTechNotesViz = $"{await Translate("CustomerTechNotes")}\n{custInfo.TechNotes}\n\n";
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// o.CustomerViz = custInfo.Name;
|
|
|
|
|
// o.CustomerPhone1Viz = custInfo.Phone1;
|
|
|
|
|
// o.CustomerPhone2Viz = custInfo.Phone2;
|
|
|
|
|
// o.CustomerPhone3Viz = custInfo.Phone3;
|
|
|
|
|
// o.CustomerPhone4Viz = custInfo.Phone4;
|
|
|
|
|
// o.CustomerPhone5Viz = custInfo.Phone5;
|
|
|
|
|
// o.CustomerEmailAddressViz = custInfo.EmailAddress;
|
|
|
|
|
|
|
|
|
|
// if (o.ProjectId != null)
|
|
|
|
|
// o.ProjectViz = await ct.Project.AsNoTracking().Where(x => x.Id == o.ProjectId).Select(x => x.Name).FirstOrDefaultAsync();
|
|
|
|
|
if (o.ProjectId != null)
|
|
|
|
|
{
|
|
|
|
|
string value = vc.Get("projname", o.ProjectId);
|
|
|
|
|
@@ -935,8 +916,7 @@ namespace AyaNova.Biz
|
|
|
|
|
o.ProjectViz = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if (o.PreparedById != null)
|
|
|
|
|
// o.PreparedByViz = await ct.User.AsNoTracking().Where(x => x.Id == o.PreparedById).Select(x => x.Name).FirstOrDefaultAsync();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (o.PreparedById != null)
|
|
|
|
|
{
|
|
|
|
|
@@ -947,17 +927,7 @@ namespace AyaNova.Biz
|
|
|
|
|
o.PreparedByViz = vc.Get("user", o.PreparedById);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if (o.ContractId != null)
|
|
|
|
|
// {
|
|
|
|
|
// var contractVizFields = await ct.Contract.AsNoTracking().Where(x => x.Id == o.ContractId).Select(x => new { Name = x.Name, AlertNotes = x.AlertNotes }).FirstOrDefaultAsync();
|
|
|
|
|
// o.ContractViz = contractVizFields.Name;
|
|
|
|
|
// if (!string.IsNullOrWhiteSpace(contractVizFields.AlertNotes))
|
|
|
|
|
// {
|
|
|
|
|
// o.AlertViz += $"{await Translate("Contract")}\n{contractVizFields.AlertNotes}\n\n";
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
// else
|
|
|
|
|
// o.ContractViz = "-";
|
|
|
|
|
|
|
|
|
|
if (o.ContractId != null)
|
|
|
|
|
{
|
|
|
|
|
if (vc.Get("ctrctname", o.ContractId) == null)
|
|
|
|
|
@@ -976,6 +946,16 @@ namespace AyaNova.Biz
|
|
|
|
|
else
|
|
|
|
|
o.ContractViz = "-";
|
|
|
|
|
|
|
|
|
|
if (o.LastStatusId != null)
|
|
|
|
|
{
|
|
|
|
|
var lastState = o.States[o.States.Count - 1];
|
|
|
|
|
o.LastStateColorViz = lastState.ColorViz;
|
|
|
|
|
o.LastStateCompletedViz = lastState.CompletedViz;
|
|
|
|
|
o.LastStateLockedViz = lastState.LockedViz;
|
|
|
|
|
o.LastStateNameViz = lastState.NameViz;
|
|
|
|
|
o.LastStateUserViz = lastState.UserViz;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1158,7 +1138,6 @@ namespace AyaNova.Biz
|
|
|
|
|
//
|
|
|
|
|
private async Task StatePopulateVizFields(QuoteState o)
|
|
|
|
|
{
|
|
|
|
|
// o.UserViz = await ct.User.AsNoTracking().Where(x => x.Id == o.UserId).Select(x => x.Name).FirstOrDefaultAsync();
|
|
|
|
|
|
|
|
|
|
if (o.UserId != 0)
|
|
|
|
|
{
|
|
|
|
|
@@ -1168,6 +1147,22 @@ namespace AyaNova.Biz
|
|
|
|
|
}
|
|
|
|
|
o.UserViz = vc.Get("user", o.UserId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QuoteStatus QStatus = null;
|
|
|
|
|
|
|
|
|
|
if (!oc.Has("quotestatus", o.QuoteStatusId))
|
|
|
|
|
{
|
|
|
|
|
QStatus = await ct.QuoteStatus.AsNoTracking().Where(x => x.Id == o.QuoteStatusId).FirstOrDefaultAsync();
|
|
|
|
|
oc.Add(QStatus, "quotestatus", o.QuoteStatusId);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
QStatus = (QuoteStatus)oc.Get("quotestatus", o.QuoteStatusId);
|
|
|
|
|
|
|
|
|
|
o.NameViz = QStatus.Name;
|
|
|
|
|
o.ColorViz = QStatus.Color;
|
|
|
|
|
o.CompletedViz = QStatus.Completed;
|
|
|
|
|
o.LockedViz = QStatus.Locked;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
@@ -1216,203 +1211,6 @@ namespace AyaNova.Biz
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// // NOTIFICATION PROCESSING
|
|
|
|
|
// //
|
|
|
|
|
// public async Task StateHandlePotentialNotificationEvent(AyaEvent ayaEvent, ICoreBizObjectModel proposedObj, ICoreBizObjectModel currentObj = null)
|
|
|
|
|
// {
|
|
|
|
|
|
|
|
|
|
// ILogger log = AyaNova.Util.ApplicationLogging.CreateLogger<QuoteBiz>();
|
|
|
|
|
// if(ServerBootConfig.SEEDING || ServerBootConfig.MIGRATING) return;
|
|
|
|
|
// log.LogDebug($"HandlePotentialNotificationEvent processing: [AyaType:{proposedObj.AyaType}, AyaEvent:{ayaEvent}]");
|
|
|
|
|
|
|
|
|
|
// bool isNew = currentObj == null;
|
|
|
|
|
|
|
|
|
|
// //currently no quote state notifications but may well be in future so this saves changing a bunch of shit if necessary later
|
|
|
|
|
// await Task.CompletedTask;
|
|
|
|
|
// // QuoteState oProposed = (QuoteState)proposedObj;
|
|
|
|
|
|
|
|
|
|
// // var WorkorderInfo = await ct.Quote.AsNoTracking().Where(x => x.Id == oProposed.QuoteId).Select(x => new { x.Serial, x.Tags, x.CustomerId }).FirstOrDefaultAsync();
|
|
|
|
|
// // QuoteStatus wos = await ct.QuoteStatus.AsNoTracking().FirstOrDefaultAsync(x => x.Id == oProposed.QuoteStatusId);
|
|
|
|
|
// // //for notification purposes because has no name / tags field itself
|
|
|
|
|
// // oProposed.Name = WorkorderInfo.Serial.ToString();
|
|
|
|
|
// // oProposed.Tags = WorkorderInfo.Tags;
|
|
|
|
|
|
|
|
|
|
// // //STANDARD EVENTS FOR ALL OBJECTS
|
|
|
|
|
// // //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 NEW status set. Conditions: specific status ID value only (no generic any status allowed), Workorder TAGS
|
|
|
|
|
// // //WorkorderCompletedStatusOverdue = 15,//* Workorder object not set to a "Completed" flagged quote status type in selected time span from creation of workorderWorkorderSetToCompletedStatus
|
|
|
|
|
// // //WorkorderStatusAge = 24,//* Workorder STATUS unchanged for set time (stuck in state), conditional on: Duration (how long stuck), exact status selected IdValue, Tags. Advance notice can NOT 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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// // //## DELETED EVENTS
|
|
|
|
|
// // //A state cannot be deleted so nothing to handle that is required
|
|
|
|
|
// // //a quote 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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// // // await NotifyEventHelper.ClearPriorEventsForObject(ct, proposedObj.AyaType, o.Id, NotifyEventType.WorkorderStatusChange);
|
|
|
|
|
// // // await NotifyEventHelper.ClearPriorEventsForObject(ct, proposedObj.AyaType, o.Id, NotifyEventType.WorkorderCompletedStatusOverdue);
|
|
|
|
|
// // // await NotifyEventHelper.ClearPriorEventsForObject(ct, proposedObj.AyaType, o.Id, NotifyEventType.WorkorderStatusAge);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// // //## CREATED (this is the only possible notification CREATION ayaEvent type for a quote state as they are create only)
|
|
|
|
|
// // if (ayaEvent == AyaEvent.Created)
|
|
|
|
|
// // {
|
|
|
|
|
// // //# STATUS CHANGE (create new status)
|
|
|
|
|
// // {
|
|
|
|
|
// // //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.AsNoTracking().Where(z => z.EventType == NotifyEventType.WorkorderStatusChange && z.IdValue == oProposed.QuoteStatusId).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.ObjectHasAllSubscriptionTags(WorkorderInfo.Tags, sub.Tags))
|
|
|
|
|
// // {
|
|
|
|
|
// // NotifyEvent n = new NotifyEvent()
|
|
|
|
|
// // {
|
|
|
|
|
// // EventType = NotifyEventType.WorkorderStatusChange,
|
|
|
|
|
// // UserId = sub.UserId,
|
|
|
|
|
// // AyaType = AyaType.Quote,
|
|
|
|
|
// // ObjectId = oProposed.QuoteId,
|
|
|
|
|
// // NotifySubscriptionId = sub.Id,
|
|
|
|
|
// // Name = $"{WorkorderInfo.Serial.ToString()} - {wos.Name}"
|
|
|
|
|
// // };
|
|
|
|
|
// // await ct.NotifyEvent.AddAsync(n);
|
|
|
|
|
// // log.LogDebug($"Adding NotifyEvent: [{n.ToString()}]");
|
|
|
|
|
// // await ct.SaveChangesAsync();
|
|
|
|
|
// // }
|
|
|
|
|
// // }
|
|
|
|
|
// // }//quote status change event
|
|
|
|
|
|
|
|
|
|
// // //# STATUS AGE
|
|
|
|
|
// // {
|
|
|
|
|
// // //WorkorderStatusAge = 24,//* Workorder STATUS unchanged for set time (stuck in state), conditional on: Duration (how long stuck), exact status selected IdValue, Tags. Advance notice can NOT be set
|
|
|
|
|
// // //Always clear any old ones for this object as they are all irrelevant the moment the state has changed:
|
|
|
|
|
// // await NotifyEventHelper.ClearPriorEventsForObject(ct, proposedObj.AyaType, proposedObj.Id, NotifyEventType.WorkorderStatusAge);
|
|
|
|
|
// // var subs = await ct.NotifySubscription.AsNoTracking().Where(z => z.EventType == NotifyEventType.WorkorderStatusAge && z.IdValue == oProposed.QuoteStatusId).ToListAsync();
|
|
|
|
|
// // foreach (var sub in subs)
|
|
|
|
|
// // {
|
|
|
|
|
// // //not for inactive users
|
|
|
|
|
// // if (!await UserBiz.UserIsActive(sub.UserId)) continue;
|
|
|
|
|
|
|
|
|
|
// // //Quote Tag match? (Not State, state has no tags, will be true if no sub tags so always safe to call this)
|
|
|
|
|
// // if (NotifyEventHelper.ObjectHasAllSubscriptionTags(WorkorderInfo.Tags, sub.Tags))
|
|
|
|
|
// // {
|
|
|
|
|
// // NotifyEvent n = new NotifyEvent()
|
|
|
|
|
// // {
|
|
|
|
|
// // EventType = NotifyEventType.WorkorderStatusAge,
|
|
|
|
|
// // UserId = sub.UserId,
|
|
|
|
|
// // AyaType = AyaType.Quote,
|
|
|
|
|
// // ObjectId = oProposed.QuoteId,
|
|
|
|
|
// // NotifySubscriptionId = sub.Id,
|
|
|
|
|
// // Name = $"{WorkorderInfo.Serial.ToString()} - {wos.Name}"
|
|
|
|
|
// // };
|
|
|
|
|
// // await ct.NotifyEvent.AddAsync(n);
|
|
|
|
|
// // log.LogDebug($"Adding NotifyEvent: [{n.ToString()}]");
|
|
|
|
|
// // await ct.SaveChangesAsync();
|
|
|
|
|
// // }
|
|
|
|
|
// // }
|
|
|
|
|
// // }//quote status change event
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// // //# COMPLETE BY OVERDUE
|
|
|
|
|
// // {
|
|
|
|
|
// // //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
|
|
|
|
|
|
|
|
|
|
// // //NOTE ABOUT RE-OPEN DECISION ON HOW THIS WORKS:
|
|
|
|
|
|
|
|
|
|
// // //what though if it's not a Completed status, then I guess don't remove it, but what if it *was* a Completed status and it's change to a non Completed?
|
|
|
|
|
// // //that, in essence re-opens it so it's not Completed at that point.
|
|
|
|
|
// // //My decision on this june 2021 is that a work order Completed status notification is satisifed the moment it's saved with a Completed status
|
|
|
|
|
// // //and nothing afterwards restarts that process so if a person sets closed status then sets open status again no new Completed 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, oProposed.QuoteId, NotifyEventType.WorkorderCompletedStatusOverdue);
|
|
|
|
|
// // }
|
|
|
|
|
// // }//quote complete by overdue change event
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// // //# WorkorderCompleted - Customer AND User but customer only notifies if it's their quote
|
|
|
|
|
// // {
|
|
|
|
|
// // if (wos.Completed)
|
|
|
|
|
// // {
|
|
|
|
|
// // //look for potential subscribers
|
|
|
|
|
// // var subs = await ct.NotifySubscription.AsNoTracking().Where(z => z.EventType == NotifyEventType.WorkorderCompleted).ToListAsync();
|
|
|
|
|
// // foreach (var sub in subs)
|
|
|
|
|
// // {
|
|
|
|
|
// // //not for inactive users
|
|
|
|
|
// // if (!await UserBiz.UserIsActive(sub.UserId)) continue;
|
|
|
|
|
|
|
|
|
|
// // //Customer User?
|
|
|
|
|
// // var UserInfo = await ct.User.AsNoTracking().Where(x => x.Id == sub.UserId).Select(x => new { x.CustomerId, x.UserType, x.HeadOfficeId }).FirstOrDefaultAsync();
|
|
|
|
|
// // if (UserInfo.UserType == UserType.Customer || UserInfo.UserType == UserType.HeadOffice)
|
|
|
|
|
// // {
|
|
|
|
|
// // //CUSTOMER USER
|
|
|
|
|
|
|
|
|
|
// // //Quick short circuit: if quote doesn't have a customer id then it's not going to match no matter what
|
|
|
|
|
// // if (WorkorderInfo.CustomerId == 0) continue;
|
|
|
|
|
|
|
|
|
|
// // var customerUserRights = await UserBiz.CustomerUserEffectiveRightsAsync(sub.UserId);
|
|
|
|
|
|
|
|
|
|
// // //Are they allowed right now to use this type of notification?
|
|
|
|
|
// // if (!customerUserRights.NotifyWOCompleted) continue;
|
|
|
|
|
|
|
|
|
|
// // //is this their related work order?
|
|
|
|
|
// // if (UserInfo.CustomerId != WorkorderInfo.CustomerId)
|
|
|
|
|
// // {
|
|
|
|
|
// // //not the same customer but might be a head office user and this is one of their customers so check for that
|
|
|
|
|
// // if (UserInfo.HeadOfficeId == null) continue;//can't match any head office so no need to go further
|
|
|
|
|
|
|
|
|
|
// // //see if quote customer's head office is the same id as the user's headofficeid (note that a customer user with the same head office as a *different* customer quote doesn't qualify)
|
|
|
|
|
// // var CustomerInfo = await ct.Customer.AsNoTracking().Where(x => x.Id == WorkorderInfo.CustomerId).Select(x => new { x.HeadOfficeId, x.BillHeadOffice }).FirstOrDefaultAsync();
|
|
|
|
|
// // if (!CustomerInfo.BillHeadOffice) continue;//can't possibly match so no need to go further
|
|
|
|
|
// // if (UserInfo.HeadOfficeId != CustomerInfo.HeadOfficeId) continue;
|
|
|
|
|
// // }
|
|
|
|
|
// // }
|
|
|
|
|
// // else
|
|
|
|
|
// // {
|
|
|
|
|
// // //INSIDE USER
|
|
|
|
|
// // //Tag match? (will be true if no sub tags so always safe to call this)
|
|
|
|
|
// // //check early to avoid cost of fetching and calculating total if unnecessary
|
|
|
|
|
// // if (!NotifyEventHelper.ObjectHasAllSubscriptionTags(WorkorderInfo.Tags, sub.Tags)) continue;
|
|
|
|
|
// // }
|
|
|
|
|
|
|
|
|
|
// // //Ok, we're here so it must be ok to notify user
|
|
|
|
|
// // NotifyEvent n = new NotifyEvent()
|
|
|
|
|
// // {
|
|
|
|
|
// // EventType = NotifyEventType.WorkorderCompleted,
|
|
|
|
|
// // UserId = sub.UserId,
|
|
|
|
|
// // AyaType = AyaType.Quote,
|
|
|
|
|
// // ObjectId = oProposed.QuoteId,
|
|
|
|
|
// // NotifySubscriptionId = sub.Id,
|
|
|
|
|
// // Name = $"{WorkorderInfo.Serial.ToString()}"
|
|
|
|
|
// // };
|
|
|
|
|
// // await ct.NotifyEvent.AddAsync(n);
|
|
|
|
|
// // log.LogDebug($"Adding NotifyEvent: [{n.ToString()}]");
|
|
|
|
|
// // await ct.SaveChangesAsync();
|
|
|
|
|
// // }
|
|
|
|
|
// // }
|
|
|
|
|
// // }//WorkorderCompleted
|
|
|
|
|
// // }
|
|
|
|
|
|
|
|
|
|
// }//end of process notifications
|
|
|
|
|
|
|
|
|
|
#endregion work order STATE level
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|