case 4132
This commit is contained in:
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@@ -48,7 +48,7 @@
|
|||||||
"AYANOVA_DATA_PATH": "c:\\temp\\ravendata",
|
"AYANOVA_DATA_PATH": "c:\\temp\\ravendata",
|
||||||
"AYANOVA_USE_URLS": "http://*:7575;",
|
"AYANOVA_USE_URLS": "http://*:7575;",
|
||||||
//"AYANOVA_PERMANENTLY_ERASE_DATABASE":"true",
|
//"AYANOVA_PERMANENTLY_ERASE_DATABASE":"true",
|
||||||
"AYANOVA_SERVER_TEST_MODE": "true",
|
"AYANOVA_SERVER_TEST_MODE": "false",
|
||||||
"AYANOVA_SERVER_TEST_MODE_TZ_OFFSET": "-8",
|
"AYANOVA_SERVER_TEST_MODE_TZ_OFFSET": "-8",
|
||||||
//"AYANOVA_REPORT_RENDERING_TIMEOUT":"1",
|
//"AYANOVA_REPORT_RENDERING_TIMEOUT":"1",
|
||||||
"AYANOVA_SERVER_TEST_MODE_SEEDLEVEL": "small",
|
"AYANOVA_SERVER_TEST_MODE_SEEDLEVEL": "small",
|
||||||
|
|||||||
@@ -1317,7 +1317,7 @@ namespace AyaNova.Biz
|
|||||||
{
|
{
|
||||||
//QuoteStatusAge = 29,//* Quote 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
|
//QuoteStatusAge = 29,//* Quote 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:
|
//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.QuoteStatusAge);
|
await NotifyEventHelper.ClearPriorEventsForObject(ct, AyaType.Quote, proposedObj.Id, NotifyEventType.QuoteStatusAge);
|
||||||
var subs = await ct.NotifySubscription.AsNoTracking().Where(z => z.EventType == NotifyEventType.QuoteStatusAge && z.IdValue == oProposed.QuoteStatusId).ToListAsync();
|
var subs = await ct.NotifySubscription.AsNoTracking().Where(z => z.EventType == NotifyEventType.QuoteStatusAge && z.IdValue == oProposed.QuoteStatusId).ToListAsync();
|
||||||
foreach (var sub in subs)
|
foreach (var sub in subs)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1779,304 +1779,303 @@ namespace AyaNova.Biz
|
|||||||
|
|
||||||
|
|
||||||
//## CREATED (this is the only possible notification CREATION ayaEvent type for a workorder state as they are create only)
|
//## 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)
|
||||||
{
|
{
|
||||||
//# 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.WorkOrderStatusId).ToListAsync();
|
||||||
|
foreach (var sub in subs)
|
||||||
{
|
{
|
||||||
//Conditions: must match specific status id value and also tags below
|
//not for inactive users
|
||||||
//delivery is immediate so no need to remove old ones of this kind
|
if (!await UserBiz.UserIsActive(sub.UserId)) continue;
|
||||||
var subs = await ct.NotifySubscription.AsNoTracking().Where(z => z.EventType == NotifyEventType.WorkorderStatusChange && z.IdValue == oProposed.WorkOrderStatusId).ToListAsync();
|
|
||||||
|
//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.WorkOrder,
|
||||||
|
ObjectId = oProposed.WorkOrderId,
|
||||||
|
NotifySubscriptionId = sub.Id,
|
||||||
|
Name = $"{WorkorderInfo.Serial.ToString()} - {wos.Name}"
|
||||||
|
};
|
||||||
|
await ct.NotifyEvent.AddAsync(n);
|
||||||
|
log.LogDebug($"Adding NotifyEvent: [{n.ToString()}]");
|
||||||
|
await ct.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}//workorder 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, AyaType.WorkOrder, proposedObj.Id, NotifyEventType.WorkorderStatusAge);
|
||||||
|
var subs = await ct.NotifySubscription.AsNoTracking().Where(z => z.EventType == NotifyEventType.WorkorderStatusAge && z.IdValue == oProposed.WorkOrderStatusId).ToListAsync();
|
||||||
|
foreach (var sub in subs)
|
||||||
|
{
|
||||||
|
//not for inactive users
|
||||||
|
if (!await UserBiz.UserIsActive(sub.UserId)) continue;
|
||||||
|
|
||||||
|
//WorkOrder 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.WorkOrder,
|
||||||
|
ObjectId = oProposed.WorkOrderId,
|
||||||
|
NotifySubscriptionId = sub.Id,
|
||||||
|
Name = $"{WorkorderInfo.Serial.ToString()} - {wos.Name}"
|
||||||
|
};
|
||||||
|
await ct.NotifyEvent.AddAsync(n);
|
||||||
|
log.LogDebug($"Adding NotifyEvent: [{n.ToString()}]");
|
||||||
|
await ct.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}//workorder status age 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, AyaType.WorkOrder, oProposed.WorkOrderId, NotifyEventType.WorkorderCompletedStatusOverdue);
|
||||||
|
}
|
||||||
|
}//workorder complete by overdue change event
|
||||||
|
|
||||||
|
|
||||||
|
//# WorkorderTotalExceedsThreshold / "The Andy"
|
||||||
|
{
|
||||||
|
if (wos.Completed)
|
||||||
|
{
|
||||||
|
|
||||||
|
//see if any subscribers to the workorder total exceeds notification
|
||||||
|
//that are active then proceed to fetch billed woitem children and total workorder and send notification if necessary
|
||||||
|
|
||||||
|
bool haveTotal = false;
|
||||||
|
decimal GrandTotal = 0m;
|
||||||
|
|
||||||
|
//look for potential subscribers
|
||||||
|
var subs = await ct.NotifySubscription.AsNoTracking().Where(z => z.EventType == NotifyEventType.WorkorderTotalExceedsThreshold).ToListAsync();
|
||||||
foreach (var sub in subs)
|
foreach (var sub in subs)
|
||||||
{
|
{
|
||||||
//not for inactive users
|
//not for inactive users
|
||||||
if (!await UserBiz.UserIsActive(sub.UserId)) continue;
|
if (!await UserBiz.UserIsActive(sub.UserId)) continue;
|
||||||
|
|
||||||
//Tag match? (will be true if no sub tags so always safe to call this)
|
//Tag match? (will be true if no sub tags so always safe to call this)
|
||||||
if (NotifyEventHelper.ObjectHasAllSubscriptionTags(WorkorderInfo.Tags, sub.Tags))
|
//check early to avoid cost of fetching and calculating total if unnecessary
|
||||||
|
if (!NotifyEventHelper.ObjectHasAllSubscriptionTags(WorkorderInfo.Tags, sub.Tags)) continue;
|
||||||
|
|
||||||
|
//get the total because we have at least one subscriber and matching tags
|
||||||
|
if (haveTotal == false)
|
||||||
{
|
{
|
||||||
|
GrandTotal = await WorkorderGrandTotalAsync(oProposed.WorkOrderId, ct);
|
||||||
|
haveTotal = true;
|
||||||
|
|
||||||
|
//Note: not a time delayed notification, however user could be flipping states quickly triggering multiple notifications that are in queue temporarily
|
||||||
|
//so this will prevent that:
|
||||||
|
await NotifyEventHelper.ClearPriorEventsForObject(ct, AyaType.WorkOrder, oProposed.WorkOrderId, NotifyEventType.WorkorderTotalExceedsThreshold);
|
||||||
|
}
|
||||||
|
//Ok, we're here because there is a subscriber who is active and tags match so only check left is total against decvalue
|
||||||
|
if (sub.DecValue < GrandTotal)
|
||||||
|
{
|
||||||
|
//notification is a go
|
||||||
NotifyEvent n = new NotifyEvent()
|
NotifyEvent n = new NotifyEvent()
|
||||||
{
|
{
|
||||||
EventType = NotifyEventType.WorkorderStatusChange,
|
EventType = NotifyEventType.WorkorderTotalExceedsThreshold,
|
||||||
UserId = sub.UserId,
|
UserId = sub.UserId,
|
||||||
AyaType = AyaType.WorkOrder,
|
AyaType = AyaType.WorkOrder,
|
||||||
ObjectId = oProposed.WorkOrderId,
|
ObjectId = oProposed.WorkOrderId,
|
||||||
NotifySubscriptionId = sub.Id,
|
NotifySubscriptionId = sub.Id,
|
||||||
Name = $"{WorkorderInfo.Serial.ToString()} - {wos.Name}"
|
Name = $"{WorkorderInfo.Serial.ToString()}",
|
||||||
|
DecValue = GrandTotal
|
||||||
};
|
};
|
||||||
await ct.NotifyEvent.AddAsync(n);
|
await ct.NotifyEvent.AddAsync(n);
|
||||||
log.LogDebug($"Adding NotifyEvent: [{n.ToString()}]");
|
log.LogDebug($"Adding NotifyEvent: [{n.ToString()}]");
|
||||||
await ct.SaveChangesAsync();
|
await ct.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}//workorder status change event
|
}
|
||||||
|
}//"The Andy" for Dynamic Dental corp. notification
|
||||||
|
|
||||||
//# STATUS AGE
|
|
||||||
|
//# WorkorderCompleted - Customer AND User but customer only notifies if it's their workorder
|
||||||
|
{
|
||||||
|
if (wos.Completed)
|
||||||
{
|
{
|
||||||
//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
|
//look for potential subscribers
|
||||||
//Always clear any old ones for this object as they are all irrelevant the moment the state has changed:
|
var subs = await ct.NotifySubscription.AsNoTracking().Where(z => z.EventType == NotifyEventType.WorkorderCompleted).ToListAsync();
|
||||||
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.WorkOrderStatusId).ToListAsync();
|
|
||||||
foreach (var sub in subs)
|
foreach (var sub in subs)
|
||||||
{
|
{
|
||||||
//not for inactive users
|
//not for inactive users
|
||||||
if (!await UserBiz.UserIsActive(sub.UserId)) continue;
|
if (!await UserBiz.UserIsActive(sub.UserId)) continue;
|
||||||
|
|
||||||
//WorkOrder Tag match? (Not State, state has no tags, will be true if no sub tags so always safe to call this)
|
//Customer User?
|
||||||
if (NotifyEventHelper.ObjectHasAllSubscriptionTags(WorkorderInfo.Tags, sub.Tags))
|
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)
|
||||||
{
|
{
|
||||||
NotifyEvent n = new NotifyEvent()
|
//CUSTOMER USER
|
||||||
|
|
||||||
|
//Quick short circuit: if workorder 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)
|
||||||
{
|
{
|
||||||
EventType = NotifyEventType.WorkorderStatusAge,
|
//not the same customer but might be a head office user and this is one of their customers so check for that
|
||||||
UserId = sub.UserId,
|
if (UserInfo.HeadOfficeId == null) continue;//can't match any head office so no need to go further
|
||||||
|
|
||||||
|
//see if workorder 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 workorder 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.WorkOrder,
|
||||||
|
ObjectId = oProposed.WorkOrderId,
|
||||||
|
NotifySubscriptionId = sub.Id,
|
||||||
|
Name = $"{WorkorderInfo.Serial.ToString()}"
|
||||||
|
};
|
||||||
|
await ct.NotifyEvent.AddAsync(n);
|
||||||
|
log.LogDebug($"Adding NotifyEvent: [{n.ToString()}]");
|
||||||
|
await ct.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}//WorkorderCompleted
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//## CUSTOMER "PROXY" NOTIFICATIONS
|
||||||
|
var custInfo = await ct.Customer.AsNoTracking().Where(x => x.Id == WorkorderInfo.CustomerId).Select(x => new { x.Active, x.Tags, x.EmailAddress }).FirstOrDefaultAsync();
|
||||||
|
if (custInfo != null && custInfo.Active && !string.IsNullOrWhiteSpace(custInfo.EmailAddress))//can this customer receive *any* customer notifications?
|
||||||
|
{
|
||||||
|
//-------- Customer is notifiable ------
|
||||||
|
|
||||||
|
//# 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.CustomerNotifySubscription.AsNoTracking().Where(z => z.EventType == NotifyEventType.WorkorderStatusChange && z.IdValue == oProposed.WorkOrderStatusId).OrderBy(z => z.Id).ToListAsync();
|
||||||
|
foreach (var sub in subs)
|
||||||
|
{
|
||||||
|
//Object tags must match and Customer tags must match
|
||||||
|
if (NotifyEventHelper.ObjectHasAllSubscriptionTags(WorkorderInfo.Tags, sub.Tags) && NotifyEventHelper.ObjectHasAllSubscriptionTags(custInfo.Tags, sub.CustomerTags))
|
||||||
|
{
|
||||||
|
CustomerNotifyEvent n = new CustomerNotifyEvent()
|
||||||
|
{
|
||||||
|
EventType = NotifyEventType.WorkorderStatusChange,
|
||||||
|
CustomerId = WorkorderInfo.CustomerId,
|
||||||
AyaType = AyaType.WorkOrder,
|
AyaType = AyaType.WorkOrder,
|
||||||
ObjectId = oProposed.WorkOrderId,
|
ObjectId = oProposed.WorkOrderId,
|
||||||
NotifySubscriptionId = sub.Id,
|
CustomerNotifySubscriptionId = sub.Id,
|
||||||
Name = $"{WorkorderInfo.Serial.ToString()} - {wos.Name}"
|
Name = WorkorderInfo.Serial.ToString()
|
||||||
};
|
};
|
||||||
await ct.NotifyEvent.AddAsync(n);
|
await ct.CustomerNotifyEvent.AddAsync(n);
|
||||||
log.LogDebug($"Adding NotifyEvent: [{n.ToString()}]");
|
log.LogDebug($"Adding CustomerNotifyEvent: [{n.ToString()}]");
|
||||||
await ct.SaveChangesAsync();
|
await ct.SaveChangesAsync();
|
||||||
|
break;//we have a match no need to process any further subs for this event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}//workorder 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.ClearPriorCustomerNotifyEventsForObject(ct, proposedObj.AyaType, proposedObj.Id, NotifyEventType.WorkorderStatusAge);
|
||||||
|
var subs = await ct.CustomerNotifySubscription.AsNoTracking().Where(z => z.EventType == NotifyEventType.WorkorderStatusAge && z.IdValue == oProposed.WorkOrderStatusId).OrderBy(z => z.Id).ToListAsync();
|
||||||
|
foreach (var sub in subs)
|
||||||
|
{
|
||||||
|
//Object tags must match and Customer tags must match
|
||||||
|
if (NotifyEventHelper.ObjectHasAllSubscriptionTags(WorkorderInfo.Tags, sub.Tags) && NotifyEventHelper.ObjectHasAllSubscriptionTags(custInfo.Tags, sub.CustomerTags))
|
||||||
|
{
|
||||||
|
CustomerNotifyEvent n = new CustomerNotifyEvent()
|
||||||
|
{
|
||||||
|
EventType = NotifyEventType.WorkorderStatusAge,
|
||||||
|
CustomerId = WorkorderInfo.CustomerId,
|
||||||
|
AyaType = AyaType.WorkOrder,
|
||||||
|
ObjectId = oProposed.WorkOrderId,
|
||||||
|
CustomerNotifySubscriptionId = sub.Id,
|
||||||
|
Name = WorkorderInfo.Serial.ToString()
|
||||||
|
};
|
||||||
|
await ct.CustomerNotifyEvent.AddAsync(n);
|
||||||
|
log.LogDebug($"Adding CustomerNotifyEvent: [{n.ToString()}]");
|
||||||
|
await ct.SaveChangesAsync();
|
||||||
|
break;//we have a match no need to process any further subs for this event
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}//workorder status age event
|
}//workorder status age event
|
||||||
|
|
||||||
|
|
||||||
//# COMPLETE BY OVERDUE
|
//# WorkorderCompleted
|
||||||
{
|
|
||||||
//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.WorkOrderId, NotifyEventType.WorkorderCompletedStatusOverdue);
|
|
||||||
}
|
|
||||||
}//workorder complete by overdue change event
|
|
||||||
|
|
||||||
|
|
||||||
//# WorkorderTotalExceedsThreshold / "The Andy"
|
|
||||||
{
|
{
|
||||||
if (wos.Completed)
|
if (wos.Completed)
|
||||||
{
|
{
|
||||||
|
var subs = await ct.CustomerNotifySubscription.AsNoTracking().Where(z => z.EventType == NotifyEventType.WorkorderCompleted).OrderBy(z => z.Id).ToListAsync();
|
||||||
//see if any subscribers to the workorder total exceeds notification
|
|
||||||
//that are active then proceed to fetch billed woitem children and total workorder and send notification if necessary
|
|
||||||
|
|
||||||
bool haveTotal = false;
|
|
||||||
decimal GrandTotal = 0m;
|
|
||||||
|
|
||||||
//look for potential subscribers
|
|
||||||
var subs = await ct.NotifySubscription.AsNoTracking().Where(z => z.EventType == NotifyEventType.WorkorderTotalExceedsThreshold).ToListAsync();
|
|
||||||
foreach (var sub in subs)
|
foreach (var sub in subs)
|
||||||
{
|
{
|
||||||
//not for inactive users
|
//Object tags must match and Customer tags must match
|
||||||
if (!await UserBiz.UserIsActive(sub.UserId)) continue;
|
if (NotifyEventHelper.ObjectHasAllSubscriptionTags(WorkorderInfo.Tags, sub.Tags) && NotifyEventHelper.ObjectHasAllSubscriptionTags(custInfo.Tags, sub.CustomerTags))
|
||||||
|
|
||||||
//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;
|
|
||||||
|
|
||||||
//get the total because we have at least one subscriber and matching tags
|
|
||||||
if (haveTotal == false)
|
|
||||||
{
|
{
|
||||||
GrandTotal = await WorkorderGrandTotalAsync(oProposed.WorkOrderId, ct);
|
|
||||||
haveTotal = true;
|
|
||||||
|
|
||||||
//Note: not a time delayed notification, however user could be flipping states quickly triggering multiple notifications that are in queue temporarily
|
CustomerNotifyEvent n = new CustomerNotifyEvent()
|
||||||
//so this will prevent that:
|
|
||||||
await NotifyEventHelper.ClearPriorEventsForObject(ct, AyaType.WorkOrder, oProposed.WorkOrderId, NotifyEventType.WorkorderTotalExceedsThreshold);
|
|
||||||
}
|
|
||||||
//Ok, we're here because there is a subscriber who is active and tags match so only check left is total against decvalue
|
|
||||||
if (sub.DecValue < GrandTotal)
|
|
||||||
{
|
|
||||||
//notification is a go
|
|
||||||
NotifyEvent n = new NotifyEvent()
|
|
||||||
{
|
{
|
||||||
EventType = NotifyEventType.WorkorderTotalExceedsThreshold,
|
EventType = NotifyEventType.WorkorderCompleted,
|
||||||
UserId = sub.UserId,
|
CustomerId = WorkorderInfo.CustomerId,
|
||||||
AyaType = AyaType.WorkOrder,
|
AyaType = AyaType.WorkOrder,
|
||||||
ObjectId = oProposed.WorkOrderId,
|
ObjectId = oProposed.WorkOrderId,
|
||||||
NotifySubscriptionId = sub.Id,
|
CustomerNotifySubscriptionId = sub.Id,
|
||||||
Name = $"{WorkorderInfo.Serial.ToString()}",
|
Name = WorkorderInfo.Serial.ToString()
|
||||||
DecValue = GrandTotal
|
|
||||||
};
|
};
|
||||||
await ct.NotifyEvent.AddAsync(n);
|
await ct.CustomerNotifyEvent.AddAsync(n);
|
||||||
log.LogDebug($"Adding NotifyEvent: [{n.ToString()}]");
|
log.LogDebug($"Adding CustomerNotifyEvent: [{n.ToString()}]");
|
||||||
await ct.SaveChangesAsync();
|
await ct.SaveChangesAsync();
|
||||||
|
break;//we have a match no need to process any further subs for this event
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}//"The Andy" for Dynamic Dental corp. notification
|
|
||||||
|
|
||||||
|
|
||||||
//# WorkorderCompleted - Customer AND User but customer only notifies if it's their workorder
|
|
||||||
{
|
|
||||||
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 workorder 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 workorder 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 workorder 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.WorkOrder,
|
|
||||||
ObjectId = oProposed.WorkOrderId,
|
|
||||||
NotifySubscriptionId = sub.Id,
|
|
||||||
Name = $"{WorkorderInfo.Serial.ToString()}"
|
|
||||||
};
|
|
||||||
await ct.NotifyEvent.AddAsync(n);
|
|
||||||
log.LogDebug($"Adding NotifyEvent: [{n.ToString()}]");
|
|
||||||
await ct.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}//WorkorderCompleted
|
}//WorkorderCompleted
|
||||||
|
|
||||||
|
//-----------------------
|
||||||
|
}//all customer proxy if notifiable
|
||||||
|
|
||||||
|
|
||||||
//## CUSTOMER "PROXY" NOTIFICATIONS
|
|
||||||
var custInfo = await ct.Customer.AsNoTracking().Where(x => x.Id == WorkorderInfo.CustomerId).Select(x => new { x.Active, x.Tags, x.EmailAddress }).FirstOrDefaultAsync();
|
|
||||||
if (custInfo != null && custInfo.Active && !string.IsNullOrWhiteSpace(custInfo.EmailAddress))//can this customer receive *any* customer notifications?
|
|
||||||
{
|
|
||||||
//-------- Customer is notifiable ------
|
|
||||||
|
|
||||||
//# 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.CustomerNotifySubscription.AsNoTracking().Where(z => z.EventType == NotifyEventType.WorkorderStatusChange && z.IdValue == oProposed.WorkOrderStatusId).OrderBy(z => z.Id).ToListAsync();
|
|
||||||
foreach (var sub in subs)
|
|
||||||
{
|
|
||||||
//Object tags must match and Customer tags must match
|
|
||||||
if (NotifyEventHelper.ObjectHasAllSubscriptionTags(WorkorderInfo.Tags, sub.Tags) && NotifyEventHelper.ObjectHasAllSubscriptionTags(custInfo.Tags, sub.CustomerTags))
|
|
||||||
{
|
|
||||||
CustomerNotifyEvent n = new CustomerNotifyEvent()
|
|
||||||
{
|
|
||||||
EventType = NotifyEventType.WorkorderStatusChange,
|
|
||||||
CustomerId = WorkorderInfo.CustomerId,
|
|
||||||
AyaType = AyaType.WorkOrder,
|
|
||||||
ObjectId = oProposed.WorkOrderId,
|
|
||||||
CustomerNotifySubscriptionId = sub.Id,
|
|
||||||
Name = WorkorderInfo.Serial.ToString()
|
|
||||||
};
|
|
||||||
await ct.CustomerNotifyEvent.AddAsync(n);
|
|
||||||
log.LogDebug($"Adding CustomerNotifyEvent: [{n.ToString()}]");
|
|
||||||
await ct.SaveChangesAsync();
|
|
||||||
break;//we have a match no need to process any further subs for this event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}//workorder 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.ClearPriorCustomerNotifyEventsForObject(ct, proposedObj.AyaType, proposedObj.Id, NotifyEventType.WorkorderStatusAge);
|
|
||||||
var subs = await ct.CustomerNotifySubscription.AsNoTracking().Where(z => z.EventType == NotifyEventType.WorkorderStatusAge && z.IdValue == oProposed.WorkOrderStatusId).OrderBy(z => z.Id).ToListAsync();
|
|
||||||
foreach (var sub in subs)
|
|
||||||
{
|
|
||||||
//Object tags must match and Customer tags must match
|
|
||||||
if (NotifyEventHelper.ObjectHasAllSubscriptionTags(WorkorderInfo.Tags, sub.Tags) && NotifyEventHelper.ObjectHasAllSubscriptionTags(custInfo.Tags, sub.CustomerTags))
|
|
||||||
{
|
|
||||||
CustomerNotifyEvent n = new CustomerNotifyEvent()
|
|
||||||
{
|
|
||||||
EventType = NotifyEventType.WorkorderStatusAge,
|
|
||||||
CustomerId = WorkorderInfo.CustomerId,
|
|
||||||
AyaType = AyaType.WorkOrder,
|
|
||||||
ObjectId = oProposed.WorkOrderId,
|
|
||||||
CustomerNotifySubscriptionId = sub.Id,
|
|
||||||
Name = WorkorderInfo.Serial.ToString()
|
|
||||||
};
|
|
||||||
await ct.CustomerNotifyEvent.AddAsync(n);
|
|
||||||
log.LogDebug($"Adding CustomerNotifyEvent: [{n.ToString()}]");
|
|
||||||
await ct.SaveChangesAsync();
|
|
||||||
break;//we have a match no need to process any further subs for this event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}//workorder status age event
|
|
||||||
|
|
||||||
|
|
||||||
//# WorkorderCompleted
|
|
||||||
{
|
|
||||||
if (wos.Completed)
|
|
||||||
{
|
|
||||||
var subs = await ct.CustomerNotifySubscription.AsNoTracking().Where(z => z.EventType == NotifyEventType.WorkorderCompleted).OrderBy(z => z.Id).ToListAsync();
|
|
||||||
foreach (var sub in subs)
|
|
||||||
{
|
|
||||||
//Object tags must match and Customer tags must match
|
|
||||||
if (NotifyEventHelper.ObjectHasAllSubscriptionTags(WorkorderInfo.Tags, sub.Tags) && NotifyEventHelper.ObjectHasAllSubscriptionTags(custInfo.Tags, sub.CustomerTags))
|
|
||||||
{
|
|
||||||
|
|
||||||
CustomerNotifyEvent n = new CustomerNotifyEvent()
|
|
||||||
{
|
|
||||||
EventType = NotifyEventType.WorkorderCompleted,
|
|
||||||
CustomerId = WorkorderInfo.CustomerId,
|
|
||||||
AyaType = AyaType.WorkOrder,
|
|
||||||
ObjectId = oProposed.WorkOrderId,
|
|
||||||
CustomerNotifySubscriptionId = sub.Id,
|
|
||||||
Name = WorkorderInfo.Serial.ToString()
|
|
||||||
};
|
|
||||||
await ct.CustomerNotifyEvent.AddAsync(n);
|
|
||||||
log.LogDebug($"Adding CustomerNotifyEvent: [{n.ToString()}]");
|
|
||||||
await ct.SaveChangesAsync();
|
|
||||||
break;//we have a match no need to process any further subs for this event
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}//WorkorderCompleted
|
|
||||||
|
|
||||||
//-----------------------
|
|
||||||
}//all customer proxy if notifiable
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}//end of process notifications
|
}//end of process notifications
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user