case 4056

This commit is contained in:
2021-12-31 18:33:05 +00:00
parent 2df3525b07
commit 88d6ad0e03
5 changed files with 77 additions and 238 deletions

View File

@@ -61,7 +61,7 @@ namespace AyaNova.Biz
}
private VizCache vc = new VizCache();
private ObjectCache oc = new ObjectCache();
@@ -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)
@@ -975,6 +945,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

View File

@@ -61,7 +61,7 @@ namespace AyaNova.Biz
UserType.Service);
}
private VizCache vc = new VizCache();
private ObjectCache oc = new ObjectCache();
@@ -938,7 +938,7 @@ namespace AyaNova.Biz
//REPORTING
//
public async Task<JArray> GetReportData(DataListSelectedRequest dataListSelectedRequest, Guid jobId)
{
{
//workorder reports for entire workorder or just sub parts all go through here
//if the ayatype is a descendant of the workorder then only the portion of the workorder from that descendant directly up to the header will be populated and returned
//however if the report template has includeWoItemDescendants=true then the woitems is fully populated
@@ -948,19 +948,19 @@ namespace AyaNova.Biz
List<WorkOrder> batchResults = new List<WorkOrder>();
while (idList.Any())
{
if (!ReportRenderManager.KeepGoing(jobId)) return null;
if (!ReportRenderManager.KeepGoing(jobId)) return null;
var batch = idList.Take(IReportAbleObject.REPORT_DATA_BATCH_SIZE);
idList = idList.Skip(IReportAbleObject.REPORT_DATA_BATCH_SIZE).ToArray();
batchResults.Clear();
foreach (long batchId in batch)
{
if (!ReportRenderManager.KeepGoing(jobId)) return null;
if (!ReportRenderManager.KeepGoing(jobId)) return null;
batchResults.Add(await WorkOrderGetPartialAsync(dataListSelectedRequest.AType, batchId, dataListSelectedRequest.IncludeWoItemDescendants, true));
}
foreach (WorkOrder w in batchResults)
{
if (!ReportRenderManager.KeepGoing(jobId)) return null;
if (!ReportRenderManager.KeepGoing(jobId)) return null;
var jo = JObject.FromObject(w);
//WorkOrder header custom fields
@@ -1102,6 +1102,17 @@ namespace AyaNova.Biz
o.FromPMViz = value;
}
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;
}
}
@@ -3111,14 +3122,14 @@ namespace AyaNova.Biz
////////////////////////////////////////////////////////////////////////////////////////////////
// GET
//
internal async Task<WorkOrderItemLoan> LoanGetAsync(long id, bool logTheGetEvent = true, bool populateViz=false)
internal async Task<WorkOrderItemLoan> LoanGetAsync(long id, bool logTheGetEvent = true, bool populateViz = false)
{
if (UserIsSubContractorRestricted) //no access allowed at all
return null;
var ret = await ct.WorkOrderItemLoan.AsNoTracking().SingleOrDefaultAsync(z => z.Id == id);
if (logTheGetEvent && ret != null)
await EventLogProcessor.LogEventToDatabaseAsync(new Event(UserId, id, ret.AyaType, AyaEvent.Retrieved), ct);
if(populateViz)
if (populateViz)
await LoanPopulateVizFields(ret);
return ret;
}

View File

@@ -97,6 +97,17 @@ namespace AyaNova.Models
[NotMapped]
public string AlertViz { get; set; } = null;
[NotMapped]
public string LastStateUserViz { get; set; }
[NotMapped]
public string LastStateNameViz { get; set; }
[NotMapped]
public string LastStateColorViz { get; set; }
[NotMapped]
public bool LastStateCompletedViz { get; set; }
[NotMapped]
public bool LastStateLockedViz { get; set; }
[NotMapped]
public bool IsCompleteRecord { get; set; } = true;//indicates if some items were removed due to user role / type restrictions (i.e. woitems they are not scheduled on)

View File

@@ -23,6 +23,14 @@ namespace AyaNova.Models
public long UserId { get; set; }
[NotMapped]
public string UserViz { get; set; }
[NotMapped]
public string NameViz { get; set; }
[NotMapped]
public string ColorViz { get; set; }
[NotMapped]
public bool CompletedViz { get; set; }
[NotMapped]
public bool LockedViz { get; set; }
//workaround for notification
[NotMapped, JsonIgnore]

View File

@@ -99,6 +99,17 @@ namespace AyaNova.Models
[NotMapped]
public string FromPMViz { get; set; }
[NotMapped]
public string LastStateUserViz { get; set; }
[NotMapped]
public string LastStateNameViz { get; set; }
[NotMapped]
public string LastStateColorViz { get; set; }
[NotMapped]
public bool LastStateCompletedViz { get; set; }
[NotMapped]
public bool LastStateLockedViz { get; set; }
[NotMapped]
public bool IsCompleteRecord { get; set; } = true;//indicates if some items were removed due to user role / type restrictions (i.e. woitems they are not scheduled on)