This commit is contained in:
@@ -94,7 +94,7 @@ There are no settings adjustable for in app General notifications, however Users
|
||||
| NotifyHealthCheck | Automatic daily "ping" notification to confirm notification and Generator system is active at server |
|
||||
| BackupStatus | Result of last Backup operation at server |
|
||||
| CustomerServiceImminent | Scheduled service date / time is about to be reached. Intended for Customer type User |
|
||||
| WorkorderTotalExceedsThreshold | The balance of a Work order has exceeded a threshold (aka the "Andy") |
|
||||
| WorkorderTotalExceedsThreshold | The balance of a Work order has exceeded a threshold (the "Andy") |
|
||||
| WorkorderStatusAge | A Workorder has been sitting at the selected status for longer than the selected time frame |
|
||||
| UnitWarrantyExpiry | A Unit's warranty expiration date is reached |
|
||||
| UnitMeterReadingMultipleExceeded | A meter readingn *multiple* exceeds selected threshold (e.g. every 10,000 etc) |
|
||||
|
||||
@@ -574,62 +574,71 @@ namespace AyaNova.Biz
|
||||
|
||||
|
||||
|
||||
//NOTE: REMOVED WHEN REMOVED STATIC PRICING
|
||||
// ////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// //CONTRACT CHANGE HANDLER
|
||||
// //
|
||||
// //
|
||||
// private async Task<WorkOrder> ProcessChangeOfContractAsync(long woId)
|
||||
// {
|
||||
// //contract has changed, update entire graph pricing and potentially response time stuff as well here now
|
||||
// //iterate graph calling *SetListPrice on each item
|
||||
// var wo = await ct.WorkOrder.AsSplitQuery()
|
||||
// .Include(s => s.States)
|
||||
// .Include(w => w.Items.OrderBy(item => item.Sequence))
|
||||
// .ThenInclude(wi => wi.Expenses)
|
||||
// .Include(w => w.Items)
|
||||
// .ThenInclude(wi => wi.Labors)
|
||||
// .Include(w => w.Items)
|
||||
// .ThenInclude(wi => wi.Loans)
|
||||
// .Include(w => w.Items)
|
||||
// .ThenInclude(wi => wi.Parts)
|
||||
// .Include(w => w.Items)
|
||||
// .ThenInclude(wi => wi.PartRequests)
|
||||
// .Include(w => w.Items)
|
||||
// .ThenInclude(wi => wi.ScheduledUsers)
|
||||
// .Include(w => w.Items)
|
||||
// .ThenInclude(wi => wi.Tasks.OrderBy(t => t.Sequence))
|
||||
// .Include(w => w.Items)
|
||||
// .ThenInclude(wi => wi.Travels)
|
||||
// .Include(w => w.Items)
|
||||
// .ThenInclude(wi => wi.Units)
|
||||
// .Include(w => w.Items)
|
||||
// .ThenInclude(wi => wi.OutsideServices)
|
||||
// .SingleOrDefaultAsync(z => z.Id == woId);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// "The Andy" notification helper
|
||||
//
|
||||
// (for now this is only for the notification exceeds total so only need one grand total of
|
||||
// line totals, if in future need more can return a Record object instead with split out
|
||||
// taxes, net etc etc)
|
||||
//
|
||||
private async Task<decimal> WorkorderTotalAsync(long workOrderId, AyContext ct)
|
||||
{
|
||||
|
||||
|
||||
// //If Contract has response time then set CompleteByDate
|
||||
// if (mContractInEffect != null && mContractInEffect.ResponseTime != TimeSpan.Zero)
|
||||
// {
|
||||
// wo.CompleteByDate = DateTime.UtcNow.Add(mContractInEffect.ResponseTime);
|
||||
// }
|
||||
var wo = await ct.WorkOrder.AsNoTracking().AsSplitQuery()
|
||||
.Include(w => w.Items.OrderBy(item => item.Sequence))
|
||||
.ThenInclude(wi => wi.Expenses)
|
||||
.Include(w => w.Items)
|
||||
.ThenInclude(wi => wi.Labors)
|
||||
.Include(w => w.Items)
|
||||
.ThenInclude(wi => wi.Loans)
|
||||
.Include(w => w.Items)
|
||||
.ThenInclude(wi => wi.Parts)
|
||||
.Include(w => w.Items)
|
||||
.ThenInclude(wi => wi.Travels)
|
||||
.Include(w => w.Items)
|
||||
.ThenInclude(wi => wi.OutsideServices)
|
||||
.SingleOrDefaultAsync(z => z.Id == workOrderId);
|
||||
|
||||
if (wo == null) return 0m;
|
||||
|
||||
// // //update pricing
|
||||
// // foreach (WorkOrderItem wi in wo.Items)
|
||||
// // {
|
||||
// // // foreach (WorkOrderItemLabor o in wi.Labors)
|
||||
// // // await LaborSetPrice(o, mContractInEffect);
|
||||
// // foreach (WorkOrderItemTravel o in wi.Travels)
|
||||
// // TravelSetListPrice(o, mContractInEffect);
|
||||
// // foreach (WorkOrderItemPart o in wi.Parts)
|
||||
// // PartSetListPrice(o, mContractInEffect);
|
||||
// // }
|
||||
decimal GrandTotal = 0m;
|
||||
//update pricing
|
||||
foreach (WorkOrderItem wi in wo.Items)
|
||||
{
|
||||
foreach (WorkOrderItemExpense o in wi.Expenses)
|
||||
await ExpensePopulateVizFields(o, true);
|
||||
foreach (WorkOrderItemLabor o in wi.Labors)
|
||||
await LaborPopulateVizFields(o, true);
|
||||
foreach (WorkOrderItemLoan o in wi.Loans)
|
||||
await LoanPopulateVizFields(o, null, true);
|
||||
foreach (WorkOrderItemPart o in wi.Parts)
|
||||
await PartPopulateVizFields(o, true);
|
||||
foreach (WorkOrderItemTravel o in wi.Travels)
|
||||
await TravelPopulateVizFields(o, true);
|
||||
foreach (WorkOrderItemOutsideService o in wi.OutsideServices)
|
||||
await OutsideServicePopulateVizFields(o, true);
|
||||
}
|
||||
|
||||
// await ct.SaveChangesAsync();
|
||||
// return wo;
|
||||
foreach (WorkOrderItem wi in wo.Items)
|
||||
{
|
||||
foreach (WorkOrderItemExpense o in wi.Expenses)
|
||||
GrandTotal += o.LineTotalViz;
|
||||
foreach (WorkOrderItemLabor o in wi.Labors)
|
||||
GrandTotal += o.LineTotalViz;
|
||||
foreach (WorkOrderItemLoan o in wi.Loans)
|
||||
GrandTotal += o.LineTotalViz;
|
||||
foreach (WorkOrderItemPart o in wi.Parts)
|
||||
GrandTotal += o.LineTotalViz;
|
||||
foreach (WorkOrderItemTravel o in wi.Travels)
|
||||
GrandTotal += o.LineTotalViz;
|
||||
foreach (WorkOrderItemOutsideService o in wi.OutsideServices)
|
||||
GrandTotal += o.LineTotalViz;
|
||||
}
|
||||
|
||||
// }
|
||||
return GrandTotal;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1146,8 +1155,7 @@ namespace AyaNova.Biz
|
||||
|
||||
}//CustomerServiceImminent
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
}//end of process notifications
|
||||
|
||||
@@ -1417,6 +1425,53 @@ namespace AyaNova.Biz
|
||||
}
|
||||
}//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 total = 0m;
|
||||
|
||||
//look for potential subscribers
|
||||
var subs = await ct.NotifySubscription.AsNoTracking().Where(z => z.EventType == NotifyEventType.WorkorderTotalExceedsThreshold).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)
|
||||
//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)
|
||||
{
|
||||
long WorkOrderId = 0;
|
||||
if (ayaType == AyaType.WorkOrder)
|
||||
WorkOrderId = id;
|
||||
else
|
||||
WorkOrderId = await GetWorkOrderIdFromRelativeAsync(ayaType, id, ct);
|
||||
|
||||
//clear out any existing ones as they may have *just* been set from a save and we don't want a workorder save of a bunch of items to trigger 10,000 notifications
|
||||
//Always clear any old ones for this object as they are all irrelevant the moment changed:
|
||||
await NotifyEventHelper.ClearPriorEventsForObject(ct, AyaType.WorkOrder, WorkOrderId, NotifyEventType.WorkorderTotalExceedsThreshold);
|
||||
|
||||
//total workorder
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}//The Andy notification
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
}//end of process notifications
|
||||
@@ -1973,11 +2028,13 @@ namespace AyaNova.Biz
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//VIZ POPULATE
|
||||
//
|
||||
private async Task ExpensePopulateVizFields(WorkOrderItemExpense o)
|
||||
private async Task ExpensePopulateVizFields(WorkOrderItemExpense o, bool calculateTotalsOnly = false)
|
||||
{
|
||||
if (o.UserId != null)
|
||||
o.UserViz = await ct.User.AsNoTracking().Where(x => x.Id == o.UserId).Select(x => x.Name).FirstOrDefaultAsync();
|
||||
|
||||
if (calculateTotalsOnly == false)
|
||||
{
|
||||
if (o.UserId != null)
|
||||
o.UserViz = await ct.User.AsNoTracking().Where(x => x.Id == o.UserId).Select(x => x.Name).FirstOrDefaultAsync();
|
||||
}
|
||||
TaxCode Tax = null;
|
||||
if (o.ChargeTaxCodeId != null)
|
||||
Tax = await ct.TaxCode.AsNoTracking().FirstOrDefaultAsync(z => z.Id == o.ChargeTaxCodeId);
|
||||
@@ -2314,10 +2371,13 @@ namespace AyaNova.Biz
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//VIZ POPULATE
|
||||
//
|
||||
private async Task LaborPopulateVizFields(WorkOrderItemLabor o)
|
||||
private async Task LaborPopulateVizFields(WorkOrderItemLabor o, bool calculateTotalsOnly = false)
|
||||
{
|
||||
if (o.UserId != null)
|
||||
o.UserViz = await ct.User.AsNoTracking().Where(x => x.Id == o.UserId).Select(x => x.Name).FirstOrDefaultAsync();
|
||||
if (calculateTotalsOnly == false)
|
||||
{
|
||||
if (o.UserId != null)
|
||||
o.UserViz = await ct.User.AsNoTracking().Where(x => x.Id == o.UserId).Select(x => x.Name).FirstOrDefaultAsync();
|
||||
}
|
||||
ServiceRate Rate = null;
|
||||
if (o.ServiceRateId != null)
|
||||
{
|
||||
@@ -2799,14 +2859,17 @@ namespace AyaNova.Biz
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//VIZ POPULATE
|
||||
//
|
||||
private async Task LoanPopulateVizFields(WorkOrderItemLoan o, List<NameIdItem> loanUnitRateEnumList = null)
|
||||
private async Task LoanPopulateVizFields(WorkOrderItemLoan o, List<NameIdItem> loanUnitRateEnumList = null, bool calculateTotalsOnly = false)
|
||||
{
|
||||
if (loanUnitRateEnumList == null)
|
||||
loanUnitRateEnumList = await AyaNova.Api.Controllers.EnumListController.GetEnumList(
|
||||
StringUtil.TrimTypeName(typeof(LoanUnitRateUnit).ToString()),
|
||||
UserTranslationId,
|
||||
CurrentUserRoles);
|
||||
o.UnitOfMeasureViz = loanUnitRateEnumList.Where(x => x.Id == (long)o.Rate).Select(x => x.Name).First();
|
||||
if (calculateTotalsOnly == false)
|
||||
{
|
||||
if (loanUnitRateEnumList == null)
|
||||
loanUnitRateEnumList = await AyaNova.Api.Controllers.EnumListController.GetEnumList(
|
||||
StringUtil.TrimTypeName(typeof(LoanUnitRateUnit).ToString()),
|
||||
UserTranslationId,
|
||||
CurrentUserRoles);
|
||||
o.UnitOfMeasureViz = loanUnitRateEnumList.Where(x => x.Id == (long)o.Rate).Select(x => x.Name).First();
|
||||
}
|
||||
|
||||
LoanUnit loanUnit = await ct.LoanUnit.AsNoTracking().FirstOrDefaultAsync(x => x.Id == o.LoanUnitId);
|
||||
o.LoanUnitViz = loanUnit.Name;
|
||||
@@ -3182,14 +3245,17 @@ namespace AyaNova.Biz
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//VIZ POPULATE
|
||||
//
|
||||
private async Task OutsideServicePopulateVizFields(WorkOrderItemOutsideService o)
|
||||
private async Task OutsideServicePopulateVizFields(WorkOrderItemOutsideService o, bool calculateTotalsOnly = false)
|
||||
{
|
||||
if (o.UnitId != 0)
|
||||
o.UnitViz = await ct.Unit.AsNoTracking().Where(x => x.Id == o.UnitId).Select(x => x.Serial).FirstOrDefaultAsync();
|
||||
if (o.VendorSentToId != null)
|
||||
o.VendorSentToViz = await ct.Vendor.AsNoTracking().Where(x => x.Id == o.VendorSentToId).Select(x => x.Name).FirstOrDefaultAsync();
|
||||
if (o.VendorSentViaId != null)
|
||||
o.VendorSentViaViz = await ct.Vendor.AsNoTracking().Where(x => x.Id == o.VendorSentViaId).Select(x => x.Name).FirstOrDefaultAsync();
|
||||
if (calculateTotalsOnly == false)
|
||||
{
|
||||
if (o.UnitId != 0)
|
||||
o.UnitViz = await ct.Unit.AsNoTracking().Where(x => x.Id == o.UnitId).Select(x => x.Serial).FirstOrDefaultAsync();
|
||||
if (o.VendorSentToId != null)
|
||||
o.VendorSentToViz = await ct.Vendor.AsNoTracking().Where(x => x.Id == o.VendorSentToId).Select(x => x.Name).FirstOrDefaultAsync();
|
||||
if (o.VendorSentViaId != null)
|
||||
o.VendorSentViaViz = await ct.Vendor.AsNoTracking().Where(x => x.Id == o.VendorSentViaId).Select(x => x.Name).FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
TaxCode Tax = null;
|
||||
if (o.TaxCodeId != null)
|
||||
@@ -3662,13 +3728,19 @@ namespace AyaNova.Biz
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//VIZ POPULATE
|
||||
//
|
||||
private async Task PartPopulateVizFields(WorkOrderItemPart o)
|
||||
private async Task PartPopulateVizFields(WorkOrderItemPart o, bool calculateTotalsOnly = false)
|
||||
{
|
||||
if (o.PartWarehouseId != 0)
|
||||
o.PartWarehouseViz = await ct.PartWarehouse.AsNoTracking().Where(x => x.Id == o.PartWarehouseId).Select(x => x.Name).FirstOrDefaultAsync();
|
||||
if (calculateTotalsOnly == false)
|
||||
{
|
||||
if (o.PartWarehouseId != 0)
|
||||
o.PartWarehouseViz = await ct.PartWarehouse.AsNoTracking().Where(x => x.Id == o.PartWarehouseId).Select(x => x.Name).FirstOrDefaultAsync();
|
||||
}
|
||||
Part part = null;
|
||||
if (o.PartId != 0)
|
||||
part = await ct.Part.AsNoTracking().FirstOrDefaultAsync(x => x.Id == o.PartId);
|
||||
else
|
||||
return;//this should never happen but this is insurance in case it does
|
||||
|
||||
o.PartViz = part.PartNumber;
|
||||
|
||||
o.UpcViz = part.UPC;
|
||||
@@ -5095,10 +5167,13 @@ namespace AyaNova.Biz
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//VIZ POPULATE
|
||||
//
|
||||
private async Task TravelPopulateVizFields(WorkOrderItemTravel o)
|
||||
private async Task TravelPopulateVizFields(WorkOrderItemTravel o, bool calculateTotalsOnly = false)
|
||||
{
|
||||
if (o.UserId != null)
|
||||
o.UserViz = await ct.User.AsNoTracking().Where(x => x.Id == o.UserId).Select(x => x.Name).FirstOrDefaultAsync();
|
||||
if (calculateTotalsOnly == false)
|
||||
{
|
||||
if (o.UserId != null)
|
||||
o.UserViz = await ct.User.AsNoTracking().Where(x => x.Id == o.UserId).Select(x => x.Name).FirstOrDefaultAsync();
|
||||
}
|
||||
TravelRate Rate = null;
|
||||
if (o.TravelRateId != null)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user