diff --git a/server/AyaNova/biz/JobsBiz.cs b/server/AyaNova/biz/JobsBiz.cs index 49e9d2fa..0cf05e15 100644 --- a/server/AyaNova/biz/JobsBiz.cs +++ b/server/AyaNova/biz/JobsBiz.cs @@ -206,6 +206,9 @@ namespace AyaNova.Biz await CoreJobNotify.DoWorkAsync(); await CoreNotificationSweeper.DoWorkAsync(); + //PM GENERATION + await CoreJobPMGenerate.DoWorkAsync(); + //JOB SWEEPER / AND USER COUNT CHECK await CoreJobSweeper.DoWorkAsync(); diff --git a/server/AyaNova/biz/PMBiz.cs b/server/AyaNova/biz/PMBiz.cs index 79a02ff9..499e1236 100644 --- a/server/AyaNova/biz/PMBiz.cs +++ b/server/AyaNova/biz/PMBiz.cs @@ -13,488 +13,488 @@ using System.Collections.Generic; namespace AyaNova.Biz { - #region v7 code for Generate service workorder from PM - /* /// - /// Generates a service workorder from a PM type Workorder - /// - /// ID of PM - /// A new service workorder - public static Workorder NewServiceWorkorderFromPM(Guid SourceWorkorderID) - { - //Fetch the source workorder and verify it's a PM - Workorder source = Workorder.GetItemNoMRU(SourceWorkorderID); - if (source.WorkorderType != WorkorderTypes.PreventiveMaintenance) - throw new NotSupportedException(LocalizedTextTable.GetLocalizedTextDirect("Workorder.Label.Error.SourceInvalidType")); - - //if it's inactive then there is nothing to Process - //this is a backstop, the list the pm is being generated off of - //should have already selected only active items that have not reached their - //expiry date - if (source.WorkorderPreventiveMaintenance.Active == false) - { - throw new System.ApplicationException("NewServiceWorkorderFromPM: source PM workorder is not active"); - } - - if (source.WorkorderPreventiveMaintenance.StopGeneratingDate != System.DBNull.Value && - source.WorkorderPreventiveMaintenance.dtStopGeneratingDate < DBUtil.CurrentWorkingDateTime) - { - throw new System.ApplicationException("NewServiceWorkorderFromPM: source PM workorder is past StopGeneratingDate"); - } - - //Ok, so far so good, create the new one - bool bUseInventory = AyaBizUtils.GlobalSettings.UseInventory; - - //case 1387 - Workorder dest = Workorder.NewItem(WorkorderTypes.Service); - - ////NOTE: THIS DOESN'T CALL THE SHARED NEW ITEM METHOD - //Workorder dest = new Workorder(); - //dest.WorkorderType=WorkorderTypes.Service; - //dest.mService=WorkorderService.NewItem(dest); - - #region copy workorder data - - //WORKORDER HEADER - dest.ClientID = source.ClientID; - dest.CustomerContactName = source.CustomerContactName; - dest.CustomerReferenceNumber = source.CustomerReferenceNumber; - dest.mFromPMID = source.WorkorderPreventiveMaintenance.ID; - dest.InternalReferenceNumber = source.InternalReferenceNumber; - dest.Onsite = source.Onsite; - dest.ProjectID = source.ProjectID; - //dest.RegionID=source.RegionID; - dest.Summary = source.Summary; - dest.WorkorderCategoryID = source.WorkorderCategoryID; - - //PM SPECIFIC - dest.WorkorderService.WorkorderStatusID = source.WorkorderPreventiveMaintenance.WorkorderStatusID; - //Date stuff (note that date is assumed to have been advanced the last time a workorder was - //generated off the pm (see bottom of this method for that)) - dest.WorkorderService.ServiceDate = source.WorkorderPreventiveMaintenance.NextServiceDate; - - - //WORKORDERITEMS - foreach (WorkorderItem wisource in source.WorkorderItems) - { - WorkorderItem widest = dest.WorkorderItems.Add(dest); - widest.Custom0 = wisource.Custom0; - widest.Custom1 = wisource.Custom1; - widest.Custom2 = wisource.Custom2; - widest.Custom3 = wisource.Custom3; - widest.Custom4 = wisource.Custom4; - widest.Custom5 = wisource.Custom5; - widest.Custom6 = wisource.Custom6; - widest.Custom7 = wisource.Custom7; - widest.Custom8 = wisource.Custom8; - widest.Custom9 = wisource.Custom9; - widest.PriorityID = wisource.PriorityID; - widest.RequestDate = wisource.RequestDate; - widest.Summary = wisource.Summary; - widest.TechNotes = wisource.TechNotes; - widest.TypeID = wisource.TypeID; - widest.UnitID = wisource.UnitID; - widest.WarrantyService = wisource.WarrantyService; - widest.WorkorderItemUnitServiceTypeID = wisource.WorkorderItemUnitServiceTypeID; - widest.WorkorderStatusID = wisource.WorkorderStatusID; - - //PARTS - foreach (WorkorderItemPart partsource in wisource.Parts) - { - WorkorderItemPart partdest = widest.Parts.Add(widest); - partdest.Cost = partsource.Cost; - partdest.Description = partsource.Description; - partdest.Discount = partsource.Discount; - partdest.DiscountType = partsource.DiscountType; - partdest.PartID = partsource.PartID; - partdest.PartWarehouseID = partsource.PartWarehouseID; - partdest.Price = partsource.Price; - if (bUseInventory) - { - partdest.QuantityReserved = partsource.Quantity; - partdest.Quantity = 0; - } - else - partdest.Quantity = partsource.Quantity; - partdest.TaxPartSaleID = partsource.TaxPartSaleID; - - - } - - //********************************************************** - //Part requests would be here if copying a service workorder - //********************************************************** - - //SCHEDULED USERS - foreach (WorkorderItemScheduledUser usersource in wisource.ScheduledUsers) - { - WorkorderItemScheduledUser userdest = widest.ScheduledUsers.Add(widest); - userdest.EstimatedQuantity = usersource.EstimatedQuantity; - userdest.ServiceRateID = usersource.ServiceRateID; - userdest.StartDate = usersource.StartDate; - userdest.StopDate = usersource.StopDate; - userdest.UserID = usersource.UserID; - - } - - //LABOR - foreach (WorkorderItemLabor laborsource in wisource.Labors) - { - WorkorderItemLabor labordest = widest.Labors.Add(widest); - labordest.NoChargeQuantity = laborsource.NoChargeQuantity; - labordest.ServiceDetails = laborsource.ServiceDetails; - labordest.ServiceRateID = laborsource.ServiceRateID; - labordest.ServiceRateQuantity = laborsource.ServiceRateQuantity; - labordest.ServiceStartDate = laborsource.ServiceStartDate; - labordest.ServiceStopDate = laborsource.ServiceStopDate; - labordest.TaxRateSaleID = laborsource.TaxRateSaleID; - labordest.UserID = laborsource.UserID; - - } - - //********************************************************** - //Expenses would be here if copying a service workorder - //********************************************************** - - - //********************************************************** - //Loans would be here if copying a service workorder - //********************************************************** - - //TRAVEL - foreach (WorkorderItemTravel travelsource in wisource.Travels) - { - WorkorderItemTravel traveldest = widest.Travels.Add(widest); - traveldest.TravelDetails = travelsource.TravelDetails; - traveldest.TravelRateID = travelsource.TravelRateID; - traveldest.TravelRateQuantity = travelsource.TravelRateQuantity; - traveldest.TravelStartDate = travelsource.TravelStartDate; - traveldest.TravelStopDate = travelsource.TravelStopDate; - traveldest.TaxRateSaleID = travelsource.TaxRateSaleID; - traveldest.UserID = travelsource.UserID; - traveldest.Distance = travelsource.Distance; - traveldest.Notes = travelsource.Notes; - traveldest.NoChargeQuantity = travelsource.NoChargeQuantity; - } - - - - //TASKS - foreach (WorkorderItemTask tasksource in wisource.Tasks) - { - WorkorderItemTask taskdest = widest.Tasks.Add(widest); - taskdest.TaskGroupID = tasksource.TaskGroupID; - taskdest.TaskID = tasksource.TaskID; - - } - - //********************************************************** - //Outside service would be here if copying a service workorder - //********************************************************** - - }//foreach workorderitem loop + #region v7 code for Generate service workorder from PM + /* /// + /// Generates a service workorder from a PM type Workorder + /// + /// ID of PM + /// A new service workorder + public static Workorder NewServiceWorkorderFromPM(Guid SourceWorkorderID) + { + //Fetch the source workorder and verify it's a PM + Workorder source = Workorder.GetItemNoMRU(SourceWorkorderID); + if (source.WorkorderType != WorkorderTypes.PreventiveMaintenance) + throw new NotSupportedException(LocalizedTextTable.GetLocalizedTextDirect("Workorder.Label.Error.SourceInvalidType")); + + //if it's inactive then there is nothing to Process + //this is a backstop, the list the pm is being generated off of + //should have already selected only active items that have not reached their + //expiry date + if (source.WorkorderPreventiveMaintenance.Active == false) + { + throw new System.ApplicationException("NewServiceWorkorderFromPM: source PM workorder is not active"); + } + + if (source.WorkorderPreventiveMaintenance.StopGeneratingDate != System.DBNull.Value && + source.WorkorderPreventiveMaintenance.dtStopGeneratingDate < DBUtil.CurrentWorkingDateTime) + { + throw new System.ApplicationException("NewServiceWorkorderFromPM: source PM workorder is past StopGeneratingDate"); + } + + //Ok, so far so good, create the new one + bool bUseInventory = AyaBizUtils.GlobalSettings.UseInventory; + + //case 1387 + Workorder dest = Workorder.NewItem(WorkorderTypes.Service); + + ////NOTE: THIS DOESN'T CALL THE SHARED NEW ITEM METHOD + //Workorder dest = new Workorder(); + //dest.WorkorderType=WorkorderTypes.Service; + //dest.mService=WorkorderService.NewItem(dest); + + #region copy workorder data + + //WORKORDER HEADER + dest.ClientID = source.ClientID; + dest.CustomerContactName = source.CustomerContactName; + dest.CustomerReferenceNumber = source.CustomerReferenceNumber; + dest.mFromPMID = source.WorkorderPreventiveMaintenance.ID; + dest.InternalReferenceNumber = source.InternalReferenceNumber; + dest.Onsite = source.Onsite; + dest.ProjectID = source.ProjectID; + //dest.RegionID=source.RegionID; + dest.Summary = source.Summary; + dest.WorkorderCategoryID = source.WorkorderCategoryID; + + //PM SPECIFIC + dest.WorkorderService.WorkorderStatusID = source.WorkorderPreventiveMaintenance.WorkorderStatusID; + //Date stuff (note that date is assumed to have been advanced the last time a workorder was + //generated off the pm (see bottom of this method for that)) + dest.WorkorderService.ServiceDate = source.WorkorderPreventiveMaintenance.NextServiceDate; + + + //WORKORDERITEMS + foreach (WorkorderItem wisource in source.WorkorderItems) + { + WorkorderItem widest = dest.WorkorderItems.Add(dest); + widest.Custom0 = wisource.Custom0; + widest.Custom1 = wisource.Custom1; + widest.Custom2 = wisource.Custom2; + widest.Custom3 = wisource.Custom3; + widest.Custom4 = wisource.Custom4; + widest.Custom5 = wisource.Custom5; + widest.Custom6 = wisource.Custom6; + widest.Custom7 = wisource.Custom7; + widest.Custom8 = wisource.Custom8; + widest.Custom9 = wisource.Custom9; + widest.PriorityID = wisource.PriorityID; + widest.RequestDate = wisource.RequestDate; + widest.Summary = wisource.Summary; + widest.TechNotes = wisource.TechNotes; + widest.TypeID = wisource.TypeID; + widest.UnitID = wisource.UnitID; + widest.WarrantyService = wisource.WarrantyService; + widest.WorkorderItemUnitServiceTypeID = wisource.WorkorderItemUnitServiceTypeID; + widest.WorkorderStatusID = wisource.WorkorderStatusID; + + //PARTS + foreach (WorkorderItemPart partsource in wisource.Parts) + { + WorkorderItemPart partdest = widest.Parts.Add(widest); + partdest.Cost = partsource.Cost; + partdest.Description = partsource.Description; + partdest.Discount = partsource.Discount; + partdest.DiscountType = partsource.DiscountType; + partdest.PartID = partsource.PartID; + partdest.PartWarehouseID = partsource.PartWarehouseID; + partdest.Price = partsource.Price; + if (bUseInventory) + { + partdest.QuantityReserved = partsource.Quantity; + partdest.Quantity = 0; + } + else + partdest.Quantity = partsource.Quantity; + partdest.TaxPartSaleID = partsource.TaxPartSaleID; + + + } + + //********************************************************** + //Part requests would be here if copying a service workorder + //********************************************************** + + //SCHEDULED USERS + foreach (WorkorderItemScheduledUser usersource in wisource.ScheduledUsers) + { + WorkorderItemScheduledUser userdest = widest.ScheduledUsers.Add(widest); + userdest.EstimatedQuantity = usersource.EstimatedQuantity; + userdest.ServiceRateID = usersource.ServiceRateID; + userdest.StartDate = usersource.StartDate; + userdest.StopDate = usersource.StopDate; + userdest.UserID = usersource.UserID; + + } + + //LABOR + foreach (WorkorderItemLabor laborsource in wisource.Labors) + { + WorkorderItemLabor labordest = widest.Labors.Add(widest); + labordest.NoChargeQuantity = laborsource.NoChargeQuantity; + labordest.ServiceDetails = laborsource.ServiceDetails; + labordest.ServiceRateID = laborsource.ServiceRateID; + labordest.ServiceRateQuantity = laborsource.ServiceRateQuantity; + labordest.ServiceStartDate = laborsource.ServiceStartDate; + labordest.ServiceStopDate = laborsource.ServiceStopDate; + labordest.TaxRateSaleID = laborsource.TaxRateSaleID; + labordest.UserID = laborsource.UserID; + + } + + //********************************************************** + //Expenses would be here if copying a service workorder + //********************************************************** + + + //********************************************************** + //Loans would be here if copying a service workorder + //********************************************************** + + //TRAVEL + foreach (WorkorderItemTravel travelsource in wisource.Travels) + { + WorkorderItemTravel traveldest = widest.Travels.Add(widest); + traveldest.TravelDetails = travelsource.TravelDetails; + traveldest.TravelRateID = travelsource.TravelRateID; + traveldest.TravelRateQuantity = travelsource.TravelRateQuantity; + traveldest.TravelStartDate = travelsource.TravelStartDate; + traveldest.TravelStopDate = travelsource.TravelStopDate; + traveldest.TaxRateSaleID = travelsource.TaxRateSaleID; + traveldest.UserID = travelsource.UserID; + traveldest.Distance = travelsource.Distance; + traveldest.Notes = travelsource.Notes; + traveldest.NoChargeQuantity = travelsource.NoChargeQuantity; + } + + + + //TASKS + foreach (WorkorderItemTask tasksource in wisource.Tasks) + { + WorkorderItemTask taskdest = widest.Tasks.Add(widest); + taskdest.TaskGroupID = tasksource.TaskGroupID; + taskdest.TaskID = tasksource.TaskID; + + } + + //********************************************************** + //Outside service would be here if copying a service workorder + //********************************************************** + + }//foreach workorderitem loop - //case 1387 + //case 1387 - //Delete the auto-created dummy workorder item - //if there are more than it present - if (dest.WorkorderItems.Count > 1) - dest.WorkorderItems.RemoveAt(0); + //Delete the auto-created dummy workorder item + //if there are more than it present + if (dest.WorkorderItems.Count > 1) + dest.WorkorderItems.RemoveAt(0); - #endregion copy workorder data + #endregion copy workorder data - //Now save it to ensure it was created properly so - //that we know it's now safe to advance the next service date and all others + //Now save it to ensure it was created properly so + //that we know it's now safe to advance the next service date and all others - //case 868 previously didn't set dest to result of save causing it to be a copy - dest = (Workorder)dest.Save(); + //case 868 previously didn't set dest to result of save causing it to be a copy + dest = (Workorder)dest.Save(); - #region Calculate reschedule dates - //Get the current next service date for calcs - DateTime dtNext = GetDateFromSpanAndUnit(source.WorkorderPreventiveMaintenance.dtNextServiceDate, - source.WorkorderPreventiveMaintenance.GenerateSpanUnit, - source.WorkorderPreventiveMaintenance.GenerateSpan); + #region Calculate reschedule dates + //Get the current next service date for calcs + DateTime dtNext = GetDateFromSpanAndUnit(source.WorkorderPreventiveMaintenance.dtNextServiceDate, + source.WorkorderPreventiveMaintenance.GenerateSpanUnit, + source.WorkorderPreventiveMaintenance.GenerateSpan); - //Get to the desired day of the week if necessary... - if (source.mWorkorderPreventiveMaintenance.DayOfTheWeek != AyaDayOfWeek.AnyDayOfWeek) - { - DayOfWeek desired = AyaToSystemDayOfWeek(source.mWorkorderPreventiveMaintenance.DayOfTheWeek); - while (dtNext.DayOfWeek != desired) - { - dtNext = dtNext.AddDays(1); - } + //Get to the desired day of the week if necessary... + if (source.mWorkorderPreventiveMaintenance.DayOfTheWeek != AyaDayOfWeek.AnyDayOfWeek) + { + DayOfWeek desired = AyaToSystemDayOfWeek(source.mWorkorderPreventiveMaintenance.DayOfTheWeek); + while (dtNext.DayOfWeek != desired) + { + dtNext = dtNext.AddDays(1); + } - } + } - //Get the time span to add to all the other relevant dates on teh workorder to match - //the amount the next service date has been advanced - System.TimeSpan tsToNext = dtNext - source.WorkorderPreventiveMaintenance.dtNextServiceDate; + //Get the time span to add to all the other relevant dates on teh workorder to match + //the amount the next service date has been advanced + System.TimeSpan tsToNext = dtNext - source.WorkorderPreventiveMaintenance.dtNextServiceDate; - #endregion + #endregion - //Will the next workorder service date fall after the - //stop generating date? - if (source.WorkorderPreventiveMaintenance.StopGeneratingDate != System.DBNull.Value && - source.WorkorderPreventiveMaintenance.dtStopGeneratingDate < dtNext) - { - //Yes it will, so set it to inactive and bail out - source.WorkorderPreventiveMaintenance.Active = false; - source.Save(); - return dest; - } + //Will the next workorder service date fall after the + //stop generating date? + if (source.WorkorderPreventiveMaintenance.StopGeneratingDate != System.DBNull.Value && + source.WorkorderPreventiveMaintenance.dtStopGeneratingDate < dtNext) + { + //Yes it will, so set it to inactive and bail out + source.WorkorderPreventiveMaintenance.Active = false; + source.Save(); + return dest; + } - #region Reschedule PM + #region Reschedule PM - source.WorkorderPreventiveMaintenance.dtNextServiceDate = dtNext; - //Calcs the generate date (threshold date) - source.WorkorderPreventiveMaintenance.SetGenerateDate(); - //WORKORDERITEMS - foreach (WorkorderItem wisource in source.WorkorderItems) - { + source.WorkorderPreventiveMaintenance.dtNextServiceDate = dtNext; + //Calcs the generate date (threshold date) + source.WorkorderPreventiveMaintenance.SetGenerateDate(); + //WORKORDERITEMS + foreach (WorkorderItem wisource in source.WorkorderItems) + { - wisource.RequestDate = wisource.RequestDate; + wisource.RequestDate = wisource.RequestDate; - //PARTS - //no date changes required + //PARTS + //no date changes required - //SCHEDULED USERS - foreach (WorkorderItemScheduledUser usersource in wisource.ScheduledUsers) - { - //Changed: 2-Oct-2006 - //check to not add a date if the original date was empty - if (usersource.StartDate != System.DBNull.Value) - usersource.dtStartDate = usersource.dtStartDate.Add(tsToNext); + //SCHEDULED USERS + foreach (WorkorderItemScheduledUser usersource in wisource.ScheduledUsers) + { + //Changed: 2-Oct-2006 + //check to not add a date if the original date was empty + if (usersource.StartDate != System.DBNull.Value) + usersource.dtStartDate = usersource.dtStartDate.Add(tsToNext); - if (usersource.StopDate != System.DBNull.Value) - usersource.dtStopDate = usersource.dtStopDate.Add(tsToNext); + if (usersource.StopDate != System.DBNull.Value) + usersource.dtStopDate = usersource.dtStopDate.Add(tsToNext); - } + } - //LABOR - foreach (WorkorderItemLabor laborsource in wisource.Labors) - { - //Changed: 2-Oct-2006 - //check to not add a date if the original date was empty - if (laborsource.ServiceStartDate != System.DBNull.Value) - laborsource.dtServiceStartDate = laborsource.dtServiceStartDate.Add(tsToNext); + //LABOR + foreach (WorkorderItemLabor laborsource in wisource.Labors) + { + //Changed: 2-Oct-2006 + //check to not add a date if the original date was empty + if (laborsource.ServiceStartDate != System.DBNull.Value) + laborsource.dtServiceStartDate = laborsource.dtServiceStartDate.Add(tsToNext); - if (laborsource.ServiceStopDate != System.DBNull.Value) - laborsource.dtServiceStopDate = laborsource.dtServiceStopDate.Add(tsToNext); + if (laborsource.ServiceStopDate != System.DBNull.Value) + laborsource.dtServiceStopDate = laborsource.dtServiceStopDate.Add(tsToNext); - } + } - //********************************************************** - //Expenses would be here if copying a service workorder - //********************************************************** + //********************************************************** + //Expenses would be here if copying a service workorder + //********************************************************** - //********************************************************** - //Loans would be here if copying a service workorder - //********************************************************** + //********************************************************** + //Loans would be here if copying a service workorder + //********************************************************** - //TRAVEL - foreach (WorkorderItemTravel travelsource in wisource.Travels) - { - //Changed: 2-Oct-2006 - //check to not add a date if the original date was empty - if (travelsource.TravelStartDate != DBNull.Value) - travelsource.dtTravelStartDate = travelsource.dtTravelStartDate.Add(tsToNext); + //TRAVEL + foreach (WorkorderItemTravel travelsource in wisource.Travels) + { + //Changed: 2-Oct-2006 + //check to not add a date if the original date was empty + if (travelsource.TravelStartDate != DBNull.Value) + travelsource.dtTravelStartDate = travelsource.dtTravelStartDate.Add(tsToNext); - if (travelsource.TravelStopDate != DBNull.Value) - travelsource.dtTravelStopDate = travelsource.dtTravelStopDate.Add(tsToNext); + if (travelsource.TravelStopDate != DBNull.Value) + travelsource.dtTravelStopDate = travelsource.dtTravelStopDate.Add(tsToNext); - } + } - //TASKS + //TASKS - //********************************************************** - //Outside service would be here if copying a service workorder - //********************************************************** + //********************************************************** + //Outside service would be here if copying a service workorder + //********************************************************** - }//foreach workorderitem loop - #endregion reschedule pm + }//foreach workorderitem loop + #endregion reschedule pm - //Ok, Source PM is now rescheduled, save it + //Ok, Source PM is now rescheduled, save it - //case 1959 try catch block added to prevent infinite generation issue - try - { - source = (Workorder)source.Save(); - } - catch (Exception exx) - { - dest.Delete(); - dest.Save(); - //crack the exception - while (exx.InnerException != null) - exx = exx.InnerException; - - Memo mwarn = Memo.NewItem(); - mwarn.ToID = User.AdministratorID; - - //case 3826 - if (User.CurrentUserType == UserTypes.Utility) - { - //Utility accounts should not be sending memos, it fucks up downstream - //trying to view the memo, also it's confusing - mwarn.FromID = User.AdministratorID; - } - else - { - mwarn.FromID = User.CurrentThreadUserID; - } - - - mwarn.Subject = "SYSTEM WARNING: Preventive Maintenance WO PROBLEM"; - StringBuilder sb = new StringBuilder(); - sb.AppendLine("This is an automated message sent on behalf of the current user from the \"NewServiceWorkorderFromPM\" module."); - sb.AppendLine("This message concerns Preventive Maintenance workorder number " + source.WorkorderPreventiveMaintenance.PreventiveMaintenanceNumber.ToString()); - sb.AppendLine("The Preventive Maintenance workorder had an error when trying to save it during generation of a service workorder."); - sb.AppendLine("This kind of problem could result in loop which generates a very large number of identical service workorders."); - sb.AppendLine("In order to prevent this the operation has been stopped and this message generated so you can fix the problem with the source PM workorder."); - sb.AppendLine("See below for details and examine the PM workorder for problems or contact support@ayanova.com for help with the information in this message."); - sb.AppendLine("Here are the details of the error preventing save:"); - sb.AppendLine("================================="); - sb.AppendLine("Exception saving source PM:"); - sb.AppendLine(exx.Message); - sb.AppendLine("================================="); - string sSourceErr = source.GetBrokenRulesString(); - if (!string.IsNullOrWhiteSpace(sSourceErr)) - { - sb.AppendLine("Broken business rules on PM object:"); - sb.AppendLine(sSourceErr); - sb.AppendLine("=============================="); - } - mwarn.Message = sb.ToString(); - mwarn.Save(); - throw new System.ApplicationException("Workorder->NewServiceWorkorderFromPM: Error during service workorder generation. Memo with details sent to Administrator account."); - - - - } + //case 1959 try catch block added to prevent infinite generation issue + try + { + source = (Workorder)source.Save(); + } + catch (Exception exx) + { + dest.Delete(); + dest.Save(); + //crack the exception + while (exx.InnerException != null) + exx = exx.InnerException; + + Memo mwarn = Memo.NewItem(); + mwarn.ToID = User.AdministratorID; + + //case 3826 + if (User.CurrentUserType == UserTypes.Utility) + { + //Utility accounts should not be sending memos, it fucks up downstream + //trying to view the memo, also it's confusing + mwarn.FromID = User.AdministratorID; + } + else + { + mwarn.FromID = User.CurrentThreadUserID; + } - //case 1630 - //copy wikipage from pm to service workorder - if (dest.CanWiki && source.HasWiki) - { - try - { - WikiPage wpSource = WikiPage.GetItem(new TypeAndID(RootObjectTypes.WorkorderPreventiveMaintenance, source.ID)); - WikiPage wpDest = WikiPage.GetItem(new TypeAndID(RootObjectTypes.WorkorderService, dest.ID)); - wpDest.SetContent(wpSource.GetContent()); - wpDest.Save(); - } - catch { }; - - } - - return dest; - - - - - - } - - - - /// - /// Calculate generate date based on service date and - /// threshold span and unit - /// - internal void SetGenerateDate() - { - if (this.mNextServiceDate.IsEmpty) return; - if (this.mThresholdSpan == 0) - { - this.mGenerateDate = this.mNextServiceDate; - MarkDirty(); - return; - } - mGenerateDate = new SmartDate(Workorder.GetDateFromSpanAndUnit(mNextServiceDate.Date, this.mThresholdSpanUnit, -mThresholdSpan)); - MarkDirty(); - } - - - #region Date time calcs helpers - //Takes an AyaNova day of week and returns - //a System.DayOfWeek - //Assumes that AyaDayOfWeek is NOT "AnyDay" - internal static System.DayOfWeek AyaToSystemDayOfWeek(AyaDayOfWeek day) - { - switch (day) - { - case AyaDayOfWeek.Monday: - return DayOfWeek.Monday; - case AyaDayOfWeek.Tuesday: - return DayOfWeek.Tuesday; - case AyaDayOfWeek.Wednesday: - return DayOfWeek.Wednesday; - case AyaDayOfWeek.Thursday: - return DayOfWeek.Thursday; - case AyaDayOfWeek.Friday: - return DayOfWeek.Friday; - case AyaDayOfWeek.Saturday: - return DayOfWeek.Saturday; - case AyaDayOfWeek.Sunday: - return DayOfWeek.Sunday; - - - - } - - throw new System.ArgumentOutOfRangeException("DayOfWeekConverter: AyaDayOfWeek.AnyDayOfWeek is not supported"); - } - - - internal static DateTime GetDateFromSpanAndUnit(DateTime StartDate, AyaUnitsOfTime unit, int multiple) - { - switch (unit) - { - case AyaUnitsOfTime.Seconds: - return StartDate.AddSeconds(multiple); - - case AyaUnitsOfTime.Minutes: - return StartDate.AddMinutes(multiple); - case AyaUnitsOfTime.Hours: - return StartDate.AddHours(multiple); + mwarn.Subject = "SYSTEM WARNING: Preventive Maintenance WO PROBLEM"; + StringBuilder sb = new StringBuilder(); + sb.AppendLine("This is an automated message sent on behalf of the current user from the \"NewServiceWorkorderFromPM\" module."); + sb.AppendLine("This message concerns Preventive Maintenance workorder number " + source.WorkorderPreventiveMaintenance.PreventiveMaintenanceNumber.ToString()); + sb.AppendLine("The Preventive Maintenance workorder had an error when trying to save it during generation of a service workorder."); + sb.AppendLine("This kind of problem could result in loop which generates a very large number of identical service workorders."); + sb.AppendLine("In order to prevent this the operation has been stopped and this message generated so you can fix the problem with the source PM workorder."); + sb.AppendLine("See below for details and examine the PM workorder for problems or contact support@ayanova.com for help with the information in this message."); + sb.AppendLine("Here are the details of the error preventing save:"); + sb.AppendLine("================================="); + sb.AppendLine("Exception saving source PM:"); + sb.AppendLine(exx.Message); + sb.AppendLine("================================="); + string sSourceErr = source.GetBrokenRulesString(); + if (!string.IsNullOrWhiteSpace(sSourceErr)) + { + sb.AppendLine("Broken business rules on PM object:"); + sb.AppendLine(sSourceErr); + sb.AppendLine("=============================="); + } + mwarn.Message = sb.ToString(); + mwarn.Save(); + throw new System.ApplicationException("Workorder->NewServiceWorkorderFromPM: Error during service workorder generation. Memo with details sent to Administrator account."); - case AyaUnitsOfTime.Days: - return StartDate.AddDays(multiple); - case AyaUnitsOfTime.Weeks: - throw new System.NotSupportedException("GetDateFromSpanAndUnit: Weeks not supported"); - case AyaUnitsOfTime.Months: - return StartDate.AddMonths(multiple); + } - case AyaUnitsOfTime.Years: - return StartDate.AddYears(multiple); + //case 1630 + //copy wikipage from pm to service workorder + if (dest.CanWiki && source.HasWiki) + { + try + { + WikiPage wpSource = WikiPage.GetItem(new TypeAndID(RootObjectTypes.WorkorderPreventiveMaintenance, source.ID)); + WikiPage wpDest = WikiPage.GetItem(new TypeAndID(RootObjectTypes.WorkorderService, dest.ID)); + wpDest.SetContent(wpSource.GetContent()); + wpDest.Save(); + } + catch { }; + } - } + return dest; - //fail safe: - return StartDate; - } - -*/ - #endregion gen service wo from pm + + + + + } + + + + /// + /// Calculate generate date based on service date and + /// threshold span and unit + /// + internal void SetGenerateDate() + { + if (this.mNextServiceDate.IsEmpty) return; + if (this.mThresholdSpan == 0) + { + this.mGenerateDate = this.mNextServiceDate; + MarkDirty(); + return; + } + mGenerateDate = new SmartDate(Workorder.GetDateFromSpanAndUnit(mNextServiceDate.Date, this.mThresholdSpanUnit, -mThresholdSpan)); + MarkDirty(); + } + + + #region Date time calcs helpers + //Takes an AyaNova day of week and returns + //a System.DayOfWeek + //Assumes that AyaDayOfWeek is NOT "AnyDay" + internal static System.DayOfWeek AyaToSystemDayOfWeek(AyaDayOfWeek day) + { + switch (day) + { + case AyaDayOfWeek.Monday: + return DayOfWeek.Monday; + case AyaDayOfWeek.Tuesday: + return DayOfWeek.Tuesday; + case AyaDayOfWeek.Wednesday: + return DayOfWeek.Wednesday; + case AyaDayOfWeek.Thursday: + return DayOfWeek.Thursday; + case AyaDayOfWeek.Friday: + return DayOfWeek.Friday; + case AyaDayOfWeek.Saturday: + return DayOfWeek.Saturday; + case AyaDayOfWeek.Sunday: + return DayOfWeek.Sunday; + + + + } + + throw new System.ArgumentOutOfRangeException("DayOfWeekConverter: AyaDayOfWeek.AnyDayOfWeek is not supported"); + } + + + internal static DateTime GetDateFromSpanAndUnit(DateTime StartDate, AyaUnitsOfTime unit, int multiple) + { + switch (unit) + { + case AyaUnitsOfTime.Seconds: + return StartDate.AddSeconds(multiple); + + case AyaUnitsOfTime.Minutes: + return StartDate.AddMinutes(multiple); + + case AyaUnitsOfTime.Hours: + return StartDate.AddHours(multiple); + + case AyaUnitsOfTime.Days: + return StartDate.AddDays(multiple); + + case AyaUnitsOfTime.Weeks: + throw new System.NotSupportedException("GetDateFromSpanAndUnit: Weeks not supported"); + + case AyaUnitsOfTime.Months: + return StartDate.AddMonths(multiple); + + case AyaUnitsOfTime.Years: + return StartDate.AddYears(multiple); + + + } + + //fail safe: + return StartDate; + } + + */ + #endregion gen service wo from pm internal class PMBiz : BizObject, IJobObject, ISearchAbleObject, IReportAbleObject, IExportAbleObject { @@ -1027,16 +1027,6 @@ namespace AyaNova.Biz - // //////////////////////////////////////////////////////////////////////////////////////////////// - // //GET WORKORDER ID FOR WORK ORDER NUMBER - // // - // internal static async Task GetPMIdForNumberAsync(long woNumber, AyContext ct) - // { - // return await ct.PM.AsNoTracking() - // .Where(z => z.Serial == woNumber) - // .Select(z => z.Id) - // .SingleOrDefaultAsync(); - // } @@ -1156,7 +1146,7 @@ namespace AyaNova.Biz return;//this is a completely disqualifying error } - + /* todo: quote status list first, it's a table of created items, keep properties from v7 but add the following properties: @@ -5644,7 +5634,30 @@ namespace AyaNova.Biz + #region GENERATION + //////////////////////////////////////////////////////////////////////////////////////////////// + // Process generation of pms to workorders + // + internal static async Task Generate(AyContext ct, ILogger log) + { +#if (DEBUG) + log.LogInformation("PMBiz - Generating"); +#endif + //Get a list of items + + //process those items + //make new workorder + //fixup dates and update pm + + //dummy query to turn off errors + var v = await ct.PM.AsNoTracking() + .Where(z => z.Serial == 1) + .Select(z => z.Id) + .SingleOrDefaultAsync(); + + } + #endregion ///////////////////////////////////////////////////////////////////// diff --git a/server/AyaNova/generator/CoreJobPMGenerate.cs b/server/AyaNova/generator/CoreJobPMGenerate.cs new file mode 100644 index 00000000..242752b5 --- /dev/null +++ b/server/AyaNova/generator/CoreJobPMGenerate.cs @@ -0,0 +1,80 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using AyaNova.Models; +using AyaNova.Util; + +namespace AyaNova.Biz +{ + + /// + /// Preventive maintenance generator + /// turn PMs into Work orders + /// + /// + internal static class CoreJobPMGenerate + { + private static bool IsRunning = false; + private static ILogger log = AyaNova.Util.ApplicationLogging.CreateLogger("CoreJobPMGenerate"); + private static DateTime lastRun = DateTime.MinValue; + + +#if (DEBUG) + private static TimeSpan RUN_EVERY_INTERVAL = new TimeSpan(0, 0, 20);//no more frequently than once every 20 seconds +#else + private static TimeSpan RUN_EVERY_INTERVAL = new TimeSpan(0, 5, 0);//no more frequently than once every 5 minutes +#endif + + + public static async Task DoWorkAsync() + { + log.LogTrace("Checking if PMGenerate should run"); + if (IsRunning) + { + log.LogTrace("PMGenerate is running already exiting this cycle"); + return; + } + //This will get triggered roughly every minute, but we don't want to deliver that frequently + if (DateTime.UtcNow - lastRun < RUN_EVERY_INTERVAL) + { + log.LogTrace($"PMGenerate ran less than {RUN_EVERY_INTERVAL} ago, exiting this cycle"); + return; + } + try + { + IsRunning = true; + log.LogTrace("PMGenerate set to RUNNING state and starting now"); + + using (AyContext ct = AyaNova.Util.ServiceProviderProvider.DBContext) + { + await PMBiz.Generate(ct, log); + } + } + catch (Exception ex) + { + log.LogError(ex, $"Error processing PMGenerate "); + } + finally + { + log.LogTrace("PMGenerate has completed; setting to not running state and tagging lastRun timestamp"); + lastRun = DateTime.UtcNow; + IsRunning = false; + + } + + } + + + + + + ///////////////////////////////////////////////////////////////////// + + }//eoc + + +}//eons +