This commit is contained in:
2021-07-29 15:20:39 +00:00
parent 7bf025144a
commit 5af58d63e6
3 changed files with 533 additions and 437 deletions

View File

@@ -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();

View File

@@ -13,488 +13,488 @@ using System.Collections.Generic;
namespace AyaNova.Biz
{
#region v7 code for Generate service workorder from PM
/* /// <summary>
/// Generates a service workorder from a PM type Workorder
/// </summary>
/// <param name="SourceWorkorderID">ID of PM</param>
/// <returns>A new service workorder</returns>
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
/* /// <summary>
/// Generates a service workorder from a PM type Workorder
/// </summary>
/// <param name="SourceWorkorderID">ID of PM</param>
/// <returns>A new service workorder</returns>
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;
}
/// <summary>
/// Calculate generate date based on service date and
/// threshold span and unit
/// </summary>
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
}
/// <summary>
/// Calculate generate date based on service date and
/// threshold span and unit
/// </summary>
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<long> 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
/////////////////////////////////////////////////////////////////////

View File

@@ -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
{
/// <summary>
/// Preventive maintenance generator
/// turn PMs into Work orders
///
/// </summary>
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