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 |
|
| NotifyHealthCheck | Automatic daily "ping" notification to confirm notification and Generator system is active at server |
|
||||||
| BackupStatus | Result of last Backup operation 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 |
|
| 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 |
|
| 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 |
|
| UnitWarrantyExpiry | A Unit's warranty expiration date is reached |
|
||||||
| UnitMeterReadingMultipleExceeded | A meter readingn *multiple* exceeds selected threshold (e.g. every 10,000 etc) |
|
| 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
|
// "The Andy" notification helper
|
||||||
// //
|
//
|
||||||
// //
|
// (for now this is only for the notification exceeds total so only need one grand total of
|
||||||
// private async Task<WorkOrder> ProcessChangeOfContractAsync(long woId)
|
// line totals, if in future need more can return a Record object instead with split out
|
||||||
// {
|
// taxes, net etc etc)
|
||||||
// //contract has changed, update entire graph pricing and potentially response time stuff as well here now
|
//
|
||||||
// //iterate graph calling *SetListPrice on each item
|
private async Task<decimal> WorkorderTotalAsync(long workOrderId, AyContext ct)
|
||||||
// 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);
|
|
||||||
|
|
||||||
|
|
||||||
// //If Contract has response time then set CompleteByDate
|
var wo = await ct.WorkOrder.AsNoTracking().AsSplitQuery()
|
||||||
// if (mContractInEffect != null && mContractInEffect.ResponseTime != TimeSpan.Zero)
|
.Include(w => w.Items.OrderBy(item => item.Sequence))
|
||||||
// {
|
.ThenInclude(wi => wi.Expenses)
|
||||||
// wo.CompleteByDate = DateTime.UtcNow.Add(mContractInEffect.ResponseTime);
|
.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
|
decimal GrandTotal = 0m;
|
||||||
// // foreach (WorkOrderItem wi in wo.Items)
|
//update pricing
|
||||||
// // {
|
foreach (WorkOrderItem wi in wo.Items)
|
||||||
// // // foreach (WorkOrderItemLabor o in wi.Labors)
|
{
|
||||||
// // // await LaborSetPrice(o, mContractInEffect);
|
foreach (WorkOrderItemExpense o in wi.Expenses)
|
||||||
// // foreach (WorkOrderItemTravel o in wi.Travels)
|
await ExpensePopulateVizFields(o, true);
|
||||||
// // TravelSetListPrice(o, mContractInEffect);
|
foreach (WorkOrderItemLabor o in wi.Labors)
|
||||||
// // foreach (WorkOrderItemPart o in wi.Parts)
|
await LaborPopulateVizFields(o, true);
|
||||||
// // PartSetListPrice(o, mContractInEffect);
|
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();
|
foreach (WorkOrderItem wi in wo.Items)
|
||||||
// return wo;
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1148,7 +1157,6 @@ namespace AyaNova.Biz
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
}//end of process notifications
|
}//end of process notifications
|
||||||
|
|
||||||
|
|
||||||
@@ -1417,6 +1425,53 @@ namespace AyaNova.Biz
|
|||||||
}
|
}
|
||||||
}//workorder complete by overdue change event
|
}//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
|
}//end of process notifications
|
||||||
@@ -1973,11 +2028,13 @@ namespace AyaNova.Biz
|
|||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//VIZ POPULATE
|
//VIZ POPULATE
|
||||||
//
|
//
|
||||||
private async Task ExpensePopulateVizFields(WorkOrderItemExpense o)
|
private async Task ExpensePopulateVizFields(WorkOrderItemExpense o, bool calculateTotalsOnly = false)
|
||||||
|
{
|
||||||
|
if (calculateTotalsOnly == false)
|
||||||
{
|
{
|
||||||
if (o.UserId != null)
|
if (o.UserId != null)
|
||||||
o.UserViz = await ct.User.AsNoTracking().Where(x => x.Id == o.UserId).Select(x => x.Name).FirstOrDefaultAsync();
|
o.UserViz = await ct.User.AsNoTracking().Where(x => x.Id == o.UserId).Select(x => x.Name).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
TaxCode Tax = null;
|
TaxCode Tax = null;
|
||||||
if (o.ChargeTaxCodeId != null)
|
if (o.ChargeTaxCodeId != null)
|
||||||
Tax = await ct.TaxCode.AsNoTracking().FirstOrDefaultAsync(z => z.Id == o.ChargeTaxCodeId);
|
Tax = await ct.TaxCode.AsNoTracking().FirstOrDefaultAsync(z => z.Id == o.ChargeTaxCodeId);
|
||||||
@@ -2314,10 +2371,13 @@ namespace AyaNova.Biz
|
|||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//VIZ POPULATE
|
//VIZ POPULATE
|
||||||
//
|
//
|
||||||
private async Task LaborPopulateVizFields(WorkOrderItemLabor o)
|
private async Task LaborPopulateVizFields(WorkOrderItemLabor o, bool calculateTotalsOnly = false)
|
||||||
|
{
|
||||||
|
if (calculateTotalsOnly == false)
|
||||||
{
|
{
|
||||||
if (o.UserId != null)
|
if (o.UserId != null)
|
||||||
o.UserViz = await ct.User.AsNoTracking().Where(x => x.Id == o.UserId).Select(x => x.Name).FirstOrDefaultAsync();
|
o.UserViz = await ct.User.AsNoTracking().Where(x => x.Id == o.UserId).Select(x => x.Name).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
ServiceRate Rate = null;
|
ServiceRate Rate = null;
|
||||||
if (o.ServiceRateId != null)
|
if (o.ServiceRateId != null)
|
||||||
{
|
{
|
||||||
@@ -2799,7 +2859,9 @@ namespace AyaNova.Biz
|
|||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//VIZ POPULATE
|
//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 (calculateTotalsOnly == false)
|
||||||
{
|
{
|
||||||
if (loanUnitRateEnumList == null)
|
if (loanUnitRateEnumList == null)
|
||||||
loanUnitRateEnumList = await AyaNova.Api.Controllers.EnumListController.GetEnumList(
|
loanUnitRateEnumList = await AyaNova.Api.Controllers.EnumListController.GetEnumList(
|
||||||
@@ -2807,6 +2869,7 @@ namespace AyaNova.Biz
|
|||||||
UserTranslationId,
|
UserTranslationId,
|
||||||
CurrentUserRoles);
|
CurrentUserRoles);
|
||||||
o.UnitOfMeasureViz = loanUnitRateEnumList.Where(x => x.Id == (long)o.Rate).Select(x => x.Name).First();
|
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);
|
LoanUnit loanUnit = await ct.LoanUnit.AsNoTracking().FirstOrDefaultAsync(x => x.Id == o.LoanUnitId);
|
||||||
o.LoanUnitViz = loanUnit.Name;
|
o.LoanUnitViz = loanUnit.Name;
|
||||||
@@ -3182,7 +3245,9 @@ namespace AyaNova.Biz
|
|||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//VIZ POPULATE
|
//VIZ POPULATE
|
||||||
//
|
//
|
||||||
private async Task OutsideServicePopulateVizFields(WorkOrderItemOutsideService o)
|
private async Task OutsideServicePopulateVizFields(WorkOrderItemOutsideService o, bool calculateTotalsOnly = false)
|
||||||
|
{
|
||||||
|
if (calculateTotalsOnly == false)
|
||||||
{
|
{
|
||||||
if (o.UnitId != 0)
|
if (o.UnitId != 0)
|
||||||
o.UnitViz = await ct.Unit.AsNoTracking().Where(x => x.Id == o.UnitId).Select(x => x.Serial).FirstOrDefaultAsync();
|
o.UnitViz = await ct.Unit.AsNoTracking().Where(x => x.Id == o.UnitId).Select(x => x.Serial).FirstOrDefaultAsync();
|
||||||
@@ -3190,6 +3255,7 @@ namespace AyaNova.Biz
|
|||||||
o.VendorSentToViz = await ct.Vendor.AsNoTracking().Where(x => x.Id == o.VendorSentToId).Select(x => x.Name).FirstOrDefaultAsync();
|
o.VendorSentToViz = await ct.Vendor.AsNoTracking().Where(x => x.Id == o.VendorSentToId).Select(x => x.Name).FirstOrDefaultAsync();
|
||||||
if (o.VendorSentViaId != null)
|
if (o.VendorSentViaId != null)
|
||||||
o.VendorSentViaViz = await ct.Vendor.AsNoTracking().Where(x => x.Id == o.VendorSentViaId).Select(x => x.Name).FirstOrDefaultAsync();
|
o.VendorSentViaViz = await ct.Vendor.AsNoTracking().Where(x => x.Id == o.VendorSentViaId).Select(x => x.Name).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
|
|
||||||
TaxCode Tax = null;
|
TaxCode Tax = null;
|
||||||
if (o.TaxCodeId != null)
|
if (o.TaxCodeId != null)
|
||||||
@@ -3662,13 +3728,19 @@ namespace AyaNova.Biz
|
|||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//VIZ POPULATE
|
//VIZ POPULATE
|
||||||
//
|
//
|
||||||
private async Task PartPopulateVizFields(WorkOrderItemPart o)
|
private async Task PartPopulateVizFields(WorkOrderItemPart o, bool calculateTotalsOnly = false)
|
||||||
|
{
|
||||||
|
if (calculateTotalsOnly == false)
|
||||||
{
|
{
|
||||||
if (o.PartWarehouseId != 0)
|
if (o.PartWarehouseId != 0)
|
||||||
o.PartWarehouseViz = await ct.PartWarehouse.AsNoTracking().Where(x => x.Id == o.PartWarehouseId).Select(x => x.Name).FirstOrDefaultAsync();
|
o.PartWarehouseViz = await ct.PartWarehouse.AsNoTracking().Where(x => x.Id == o.PartWarehouseId).Select(x => x.Name).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
Part part = null;
|
Part part = null;
|
||||||
if (o.PartId != 0)
|
if (o.PartId != 0)
|
||||||
part = await ct.Part.AsNoTracking().FirstOrDefaultAsync(x => x.Id == o.PartId);
|
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.PartViz = part.PartNumber;
|
||||||
|
|
||||||
o.UpcViz = part.UPC;
|
o.UpcViz = part.UPC;
|
||||||
@@ -5095,10 +5167,13 @@ namespace AyaNova.Biz
|
|||||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//VIZ POPULATE
|
//VIZ POPULATE
|
||||||
//
|
//
|
||||||
private async Task TravelPopulateVizFields(WorkOrderItemTravel o)
|
private async Task TravelPopulateVizFields(WorkOrderItemTravel o, bool calculateTotalsOnly = false)
|
||||||
|
{
|
||||||
|
if (calculateTotalsOnly == false)
|
||||||
{
|
{
|
||||||
if (o.UserId != null)
|
if (o.UserId != null)
|
||||||
o.UserViz = await ct.User.AsNoTracking().Where(x => x.Id == o.UserId).Select(x => x.Name).FirstOrDefaultAsync();
|
o.UserViz = await ct.User.AsNoTracking().Where(x => x.Id == o.UserId).Select(x => x.Name).FirstOrDefaultAsync();
|
||||||
|
}
|
||||||
TravelRate Rate = null;
|
TravelRate Rate = null;
|
||||||
if (o.TravelRateId != null)
|
if (o.TravelRateId != null)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user