case 4056
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user