diff --git a/server/AyaNova/biz/JobsBiz.cs b/server/AyaNova/biz/JobsBiz.cs index b79f4d87..77cafad5 100644 --- a/server/AyaNova/biz/JobsBiz.cs +++ b/server/AyaNova/biz/JobsBiz.cs @@ -156,6 +156,22 @@ namespace AyaNova.Biz #region PROCESSOR + internal static bool KeepOnWorking() + { + ApiServerState serverState = ServiceProviderProvider.ServerState; + + //system lock (no license) is a complete deal breaker for continuation beyond here + if (serverState.IsSystemLocked) return false; + + if (serverState.IsMigrateMode) + { + log.LogDebug("Server is in migrate mode, skipping processing jobs"); + return false; + } + return true; + } + + static bool ActivelyProcessing = false; /// /// Process all jobs (stock jobs and those found in operations table) @@ -169,6 +185,7 @@ namespace AyaNova.Biz log.LogTrace("ProcessJobs called but actively processing other jobs so returning"); return; } + if (!KeepOnWorking()) return; ActivelyProcessing = true; log.LogDebug("Processing internal jobs"); try @@ -184,39 +201,38 @@ namespace AyaNova.Biz //### Server state dependent jobs ApiServerState serverState = ServiceProviderProvider.ServerState; - //system lock (no license) is a complete deal breaker for continuation beyond here - if (serverState.IsSystemLocked) return; - - if (serverState.IsMigrateMode){ - log.LogDebug("Server is in migrate mode, skipping non-critical internal jobs"); - return; - } - + if (!KeepOnWorking()) return; log.LogTrace("Processing level 2 internal jobs"); -// #if (DEBUG) -// log.LogInformation("Processing semi-critical internal jobs (backup, pm, notification etc)"); -// #endif + // #if (DEBUG) + // log.LogInformation("Processing semi-critical internal jobs (backup, pm, notification etc)"); + // #endif //BACKUP await CoreJobBackup.DoWorkAsync(); - + if (!KeepOnWorking()) return; //NOTIFICATIONS await CoreJobNotify.DoWorkAsync(); + if (!KeepOnWorking()) return; await CoreNotificationSweeper.DoWorkAsync(); + if (!KeepOnWorking()) return; //PM GENERATION await CoreJobPMGenerate.DoWorkAsync(); + if (!KeepOnWorking()) return; //PM INVENTORY CHECK if (AyaNova.Util.ServerGlobalBizSettings.Cache.UseInventory) await CoreJobPMInventoryCheck.DoWorkAsync(); + if (!KeepOnWorking()) return; //JOB SWEEPER / AND USER COUNT CHECK await CoreJobSweeper.DoWorkAsync(); + if (!KeepOnWorking()) return; //Clean temp folder CoreJobTempFolderCleanup.DoWork(); + if (!KeepOnWorking()) return; log.LogTrace("Processing exclusive dynamic jobs"); @@ -226,6 +242,7 @@ namespace AyaNova.Biz List exclusiveJobs = await GetReadyJobsExclusiveOnlyAsync(); foreach (OpsJob j in exclusiveJobs) { + if (!KeepOnWorking()) return; try { await ProcessJobAsync(j); @@ -250,11 +267,12 @@ namespace AyaNova.Biz //NON-EXCLUSIVE JOBS // log.LogTrace("Processing non-exclusive dynamic jobs"); - + if (!KeepOnWorking()) return; //These fire and forget but use a technique to bubble up exceptions anyway List sharedJobs = await GetReadyJobsNotExlusiveOnlyAsync(); foreach (OpsJob j in sharedJobs) { + if (!KeepOnWorking()) return; try { //System.Diagnostics.Debug.WriteLine($"JobsBiz processing NON-exclusive biz job {j.Name}"); diff --git a/server/AyaNova/biz/PMBiz.cs b/server/AyaNova/biz/PMBiz.cs index ef261d17..6d8993d3 100644 --- a/server/AyaNova/biz/PMBiz.cs +++ b/server/AyaNova/biz/PMBiz.cs @@ -4700,6 +4700,22 @@ namespace AyaNova.Biz public decimal QuantityRequired { get; set; } } + internal static bool KeepOnWorking(ILogger log) + { + ApiServerState serverState = ServiceProviderProvider.ServerState; + + //system lock (no license) is a complete deal breaker for continuation beyond here + if (serverState.IsSystemLocked) return false; + + if (serverState.IsMigrateMode) + { + log.LogInformation("Server is in migrate mode, skipping processing further PM's"); + return false; + } + return true; + } + + //////////////////////////////////////////////////////////////////////////////////////////////// // Process generation of pms to workorders // @@ -4721,6 +4737,11 @@ namespace AyaNova.Biz //process those pms foreach (long pmid in l) { + + + if(!KeepOnWorking(log)) return; + + #if (DEBUG) log.LogInformation($"processing pm id {pmid}"); #endif diff --git a/server/AyaNova/biz/PartInventoryBiz.cs b/server/AyaNova/biz/PartInventoryBiz.cs index 37e5638d..b679acfd 100644 --- a/server/AyaNova/biz/PartInventoryBiz.cs +++ b/server/AyaNova/biz/PartInventoryBiz.cs @@ -82,7 +82,7 @@ namespace AyaNova.Biz //////////////////////////////////////////////////////////////////////////////////////////////// - //CREATE (internal version) + //CREATE (internal version only called from within a transaction) // internal async Task CreateAsync(dtInternalPartInventory newDtObject) { @@ -90,7 +90,7 @@ namespace AyaNova.Biz var LastEntry = await ct.PartInventory.OrderByDescending(m => m.EntryDate).FirstOrDefaultAsync(m => m.PartId == newDtObject.PartId && m.PartWarehouseId == newDtObject.PartWarehouseId); PartInventory newObject = new PartInventory(); newObject.Description = newDtObject.Description; - newObject.EntryDate = DateTime.UtcNow; + newObject.PartId = newDtObject.PartId; newObject.PartWarehouseId = newDtObject.PartWarehouseId; newObject.SourceId = newDtObject.SourceId; @@ -107,7 +107,7 @@ namespace AyaNova.Biz { newObject.Balance = newObject.Quantity; } - + newObject.EntryDate = DateTime.UtcNow;//validate is saying this is older than lastentrydate in a huge test migration on a crappy vm which is weird so moved here to last millisecond before validation await ValidateAsync(newObject); if (HasErrors) return null; @@ -229,10 +229,10 @@ namespace AyaNova.Biz } - //date is newer than last entry date? + //Last entry date is newer than current entry date? if (proposedObj.LastEntryDate != null && proposedObj.LastEntryDate > proposedObj.EntryDate) { - AddError(ApiErrorCode.VALIDATION_STARTDATE_AFTER_ENDDATE, "generalerror", "LastEntryDate is newer than EntryDate"); + AddError(ApiErrorCode.VALIDATION_STARTDATE_AFTER_ENDDATE, "generalerror", $"LastEntryDate ({proposedObj.LastEntryDate.ToString()}) is newer than EntryDate ({proposedObj.EntryDate.ToString()})"); return; } diff --git a/server/AyaNova/biz/WorkOrderBiz.cs b/server/AyaNova/biz/WorkOrderBiz.cs index 677f26f2..16d8d62e 100644 --- a/server/AyaNova/biz/WorkOrderBiz.cs +++ b/server/AyaNova/biz/WorkOrderBiz.cs @@ -3691,7 +3691,10 @@ namespace AyaNova.Biz { await PartValidateAsync(newObject, null); if (HasErrors) + { + await transaction.RollbackAsync(); return null; + } else { await PartBizActionsAsync(AyaEvent.Created, newObject, null); @@ -4029,13 +4032,13 @@ namespace AyaNova.Biz { if (pib.HasErrors) { - foreach (var e in pib.Errors) + if (pib.Errors.Count == 1 && pib.Errors[0].Code == ApiErrorCode.INSUFFICIENT_INVENTORY) { - if (e.Code == ApiErrorCode.INSUFFICIENT_INVENTORY) - AddError(e.Code, "Quantity", e.Message); - else - AddError(e.Code, e.Target, e.Message); + AddError(pib.Errors[0].Code, "Quantity", pib.Errors[0].Message); + return; } + AddError(ApiErrorCode.API_SERVER_ERROR, "generalerror", $"Error updating inventory ({pi.Description}):{pib.GetErrorsAsString()}"); + return; } return; } @@ -4101,10 +4104,8 @@ namespace AyaNova.Biz { if (pib.HasErrors) { - foreach (var e in pib.Errors) - { - AddError(e.Code, e.Target, e.Message); - } + AddError(ApiErrorCode.API_SERVER_ERROR, "generalerror", $"Error updating inventory ({pi.Description}):{pib.GetErrorsAsString()}"); + return; } return; } @@ -4118,6 +4119,7 @@ namespace AyaNova.Biz } else { + //MAIN ROUTE DURING MIGRATE //CONSUME INVENTORY dtInternalPartInventory pi = new dtInternalPartInventory @@ -4133,13 +4135,13 @@ namespace AyaNova.Biz { if (pib.HasErrors) { - foreach (var e in pib.Errors) + if (pib.Errors.Count == 1 && pib.Errors[0].Code == ApiErrorCode.INSUFFICIENT_INVENTORY) { - if (e.Code == ApiErrorCode.INSUFFICIENT_INVENTORY) - AddError(e.Code, "Quantity", e.Message); - else - AddError(e.Code, e.Target, e.Message); + AddError(pib.Errors[0].Code, "Quantity", pib.Errors[0].Message); + return; } + AddError(ApiErrorCode.API_SERVER_ERROR, "generalerror", $"Error updating inventory ({pi.Description}):{pib.GetErrorsAsString()}"); + return; } return; } @@ -4179,13 +4181,13 @@ namespace AyaNova.Biz { if (pib.HasErrors) { - foreach (var e in pib.Errors) + if (pib.Errors.Count == 1 && pib.Errors[0].Code == ApiErrorCode.INSUFFICIENT_INVENTORY) { - if (e.Code == ApiErrorCode.INSUFFICIENT_INVENTORY) - AddError(e.Code, "Quantity", e.Message); - else - AddError(e.Code, e.Target, e.Message); + AddError(pib.Errors[0].Code, "Quantity", pib.Errors[0].Message); + return; } + AddError(ApiErrorCode.API_SERVER_ERROR, "generalerror", $"Error updating inventory ({pi.Description}):{pib.GetErrorsAsString()}"); + return; } return; } @@ -4241,10 +4243,8 @@ namespace AyaNova.Biz { if (pib.HasErrors) { - foreach (var e in pib.Errors) - { - AddError(e.Code, e.Target, e.Message); - } + AddError(ApiErrorCode.API_SERVER_ERROR, "generalerror", $"Error updating inventory ({pi.Description}):{pib.GetErrorsAsString()}"); + return; } return; } @@ -4271,8 +4271,18 @@ namespace AyaNova.Biz if (await pib.CreateAsync(piNew) == null) { - AddError(ApiErrorCode.API_SERVER_ERROR, "generalerror", $"Error updating inventory ({piNew.Description}):{pib.GetErrorsAsString()}"); - return; + // AddError(ApiErrorCode.API_SERVER_ERROR, "generalerror", $"Error updating inventory ({piNew.Description}):{pib.GetErrorsAsString()}"); + // return; + if (pib.HasErrors) + { + if (pib.Errors.Count == 1 && pib.Errors[0].Code == ApiErrorCode.INSUFFICIENT_INVENTORY) + { + AddError(pib.Errors[0].Code, "Quantity", pib.Errors[0].Message); + return; + } + AddError(ApiErrorCode.API_SERVER_ERROR, "generalerror", $"Error updating inventory ({piNew.Description}):{pib.GetErrorsAsString()}"); + return; + } } else { //Consume serial numbers from part @@ -5851,7 +5861,7 @@ namespace AyaNova.Biz .FirstOrDefaultAsync(); o.UnitViz = unitInfo.Serial; o.UnitDescriptionViz = unitInfo.Description; - o.UnitMeteredViz=unitInfo.Metered; + o.UnitMeteredViz = unitInfo.Metered; if (populateForReporting) { o.AddressViz = unitInfo.Address;