Certificate/wireless plugins; major refactoring

Migrate much of BI to Services.
Added Wireless Profile Provider plugin feature.
Added Certificate Authority Provider plugin feature.
Modified Certificate Provider plugin feature.
Database migration v17, for Device Profiles.
Enrolment Client Updated to support CA Certificates, Wireless Profiles
and Hardware Info.
New Client Enrolment Protocol to support new features.
Plugin Manifest Generator added to main solution.
Improved AD search performance.
This commit is contained in:
Gary Sharp
2016-09-28 20:16:25 +10:00
parent 489a5df7cc
commit 27c21175d7
210 changed files with 9822 additions and 6675 deletions
+725
View File
@@ -0,0 +1,725 @@
using Disco.Data.Repository;
using Disco.Models.BI.Config;
using Disco.Models.Repository;
using Disco.Services.Authorization;
using Disco.Services.Plugins;
using Disco.Services.Plugins.Features.RepairProvider;
using Disco.Services.Plugins.Features.WarrantyProvider;
using Disco.Services.Users;
using Exceptionless;
using System;
using System.Collections.Generic;
using System.Linq;
using DiscoServicesJobs = Disco.Services.Interop.DiscoServices.Jobs;
using PublishJobResult = Disco.Models.Services.Interop.DiscoServices.PublishJobResult;
namespace Disco.Services
{
public static class JobActionExtensions
{
#region Create
public static bool CanCreate()
{
if (!UserService.CurrentAuthorization.Has(Claims.Job.Actions.Create))
return false;
if (!UserService.CurrentAuthorization.HasAny(Claims.Job.Types.CreateHMisc, Claims.Job.Types.CreateHNWar, Claims.Job.Types.CreateHWar, Claims.Job.Types.CreateSApp, Claims.Job.Types.CreateSImg, Claims.Job.Types.CreateSOS, Claims.Job.Types.CreateUMgmt))
return false;
return true;
}
#endregion
#region Device Held
public static bool CanDeviceHeld(this Job j)
{
if (!UserService.CurrentAuthorization.Has(Claims.Job.Properties.DeviceHeld))
return false;
return (!j.ClosedDate.HasValue) && (j.DeviceSerialNumber != null) &&
(!j.DeviceHeld.HasValue || j.DeviceReturnedDate.HasValue);
}
public static void OnDeviceHeld(this Job j, User Technician)
{
if (!j.CanDeviceHeld())
throw new InvalidOperationException("Holding Device was Denied");
j.DeviceHeld = DateTime.Now;
j.DeviceHeldTechUserId = Technician.UserId;
j.DeviceReadyForReturn = null;
j.DeviceReadyForReturnTechUserId = null;
j.DeviceReturnedDate = null;
j.DeviceReturnedTechUserId = null;
}
#endregion
#region Device Ready for Return
public static bool CanDeviceReadyForReturn(this Job j)
{
if (!UserService.CurrentAuthorization.Has(Claims.Job.Properties.DeviceReadyForReturn))
return false;
return (!j.ClosedDate.HasValue) && j.DeviceHeld.HasValue &&
!j.DeviceReadyForReturn.HasValue && !j.DeviceReturnedDate.HasValue;
}
public static void OnDeviceReadyForReturn(this Job j, User Technician)
{
if (!j.CanDeviceReadyForReturn())
throw new InvalidOperationException("Device Ready for Return was Denied");
j.DeviceReadyForReturn = DateTime.Now;
j.DeviceReadyForReturnTechUserId = Technician.UserId;
}
#endregion
#region Device Returned
public static bool CanDeviceReturned(this Job j)
{
if (!UserService.CurrentAuthorization.Has(Claims.Job.Properties.DeviceReturned))
return false;
return (!j.ClosedDate.HasValue) && j.DeviceHeld.HasValue &&
!j.DeviceReturnedDate.HasValue;
}
public static void OnDeviceReturned(this Job j, User Technician)
{
if (!j.CanDeviceReturned())
throw new InvalidOperationException("Device Return was Denied");
j.DeviceReturnedDate = DateTime.Now;
j.DeviceReturnedTechUserId = Technician.UserId;
}
#endregion
#region Waiting For User Action
public static bool CanWaitingForUserAction(this Job j)
{
if (!UserService.CurrentAuthorization.Has(Claims.Job.Properties.WaitingForUserAction))
return false;
return !j.ClosedDate.HasValue && (j.UserId != null) && !j.WaitingForUserAction.HasValue;
}
public static void OnWaitingForUserAction(this Job j, DiscoDataContext Database, User Technician, string Reason)
{
if (!j.CanWaitingForUserAction())
throw new InvalidOperationException("Waiting for User Action was Denied");
j.WaitingForUserAction = DateTime.Now;
// Write Log
JobLog jobLog = new JobLog()
{
JobId = j.Id,
TechUserId = Technician.UserId,
Timestamp = DateTime.Now,
Comments = string.Format("# Waiting on User Action\r\n{0}", string.IsNullOrWhiteSpace(Reason) ? "<no reason provided>" : Reason)
};
Database.JobLogs.Add(jobLog);
}
#endregion
#region Not Waiting For User Action
public static bool CanNotWaitingForUserAction(this Job j)
{
if (!UserService.CurrentAuthorization.Has(Claims.Job.Properties.NotWaitingForUserAction))
return false;
return j.WaitingForUserAction.HasValue;
}
public static void OnNotWaitingForUserAction(this Job j, DiscoDataContext Database, User Technician, string Resolution)
{
if (!j.CanNotWaitingForUserAction())
throw new InvalidOperationException("Not Waiting for User Action was Denied");
j.WaitingForUserAction = null;
// Write Log
JobLog jobLog = new JobLog()
{
JobId = j.Id,
TechUserId = Technician.UserId,
Timestamp = DateTime.Now,
Comments = string.Format("# User Action Resolved\r\n{0}", string.IsNullOrWhiteSpace(Resolution) ? "<no comment provided>" : Resolution)
};
Database.JobLogs.Add(jobLog);
}
#endregion
#region Log Warranty
public static bool CanLogWarranty(this Job j)
{
if (!UserService.CurrentAuthorization.Has(Claims.Job.Actions.LogWarranty))
return false;
return !j.ClosedDate.HasValue &&
(j.DeviceSerialNumber != null) &&
j.JobTypeId == JobType.JobTypeIds.HWar &&
!j.JobMetaWarranty.ExternalLoggedDate.HasValue;
}
public static void OnLogWarranty(this Job j, DiscoDataContext Database, string FaultDescription, List<JobAttachment> SendAttachments, PluginFeatureManifest WarrantyProviderDefinition, OrganisationAddress Address, User TechUser, Dictionary<string, string> WarrantyProviderProperties)
{
if (!j.CanLogWarranty())
throw new InvalidOperationException("Log Warranty was Denied");
PublishJobResult publishJobResult = null;
using (WarrantyProviderFeature WarrantyProvider = WarrantyProviderDefinition.CreateInstance<WarrantyProviderFeature>())
{
if (SendAttachments != null && SendAttachments.Count > 0)
{
publishJobResult = DiscoServicesJobs.Publish(
Database,
j,
TechUser,
WarrantyProvider.WarrantyProviderId,
null,
FaultDescription,
SendAttachments,
AttachmentDataStoreExtensions.RepositoryFilename);
if (!publishJobResult.Success)
throw new Exception(string.Format("Disco ICT Online Services failed with the following message: ", publishJobResult.ErrorMessage));
if (string.IsNullOrWhiteSpace(FaultDescription))
FaultDescription = publishJobResult.PublishMessage;
else
FaultDescription = string.Concat(FaultDescription, Environment.NewLine, "___", Environment.NewLine, publishJobResult.PublishMessage);
}
string submitDescription;
if (string.IsNullOrWhiteSpace(FaultDescription))
submitDescription = j.GenerateFaultDescriptionFooter(Database, WarrantyProviderDefinition);
else
submitDescription = string.Concat(FaultDescription, Environment.NewLine, Environment.NewLine, j.GenerateFaultDescriptionFooter(Database, WarrantyProviderDefinition));
string providerRef = WarrantyProvider.SubmitJob(Database, j, Address, TechUser, submitDescription, WarrantyProviderProperties);
j.JobMetaWarranty.ExternalLoggedDate = DateTime.Now;
j.JobMetaWarranty.ExternalName = WarrantyProvider.WarrantyProviderId;
if (providerRef != null && providerRef.Length > 100)
j.JobMetaWarranty.ExternalReference = providerRef.Substring(0, 100);
else
j.JobMetaWarranty.ExternalReference = providerRef;
// Write Log
JobLog jobLog = new JobLog()
{
JobId = j.Id,
TechUserId = TechUser.UserId,
Timestamp = DateTime.Now,
Comments = string.Format("# Warranty Claim Submitted\r\nProvider: **{0}**\r\nAddress: **{1}**\r\nReference: **{2}**\r\n___\r\n```{3}```", WarrantyProvider.Manifest.Name, Address.Name, providerRef, FaultDescription)
};
Database.JobLogs.Add(jobLog);
if (publishJobResult != null)
{
try
{
DiscoServicesJobs.UpdateRecipientReference(Database, j, publishJobResult.Id, publishJobResult.Secret, j.JobMetaWarranty.ExternalReference);
}
catch (Exception ex) { ex.ToExceptionless().Submit(); } // Ignore Errors as this is not completely necessary
}
}
}
public static void OnLogWarranty(this Job j, DiscoDataContext Database, string FaultDescription, string ManualProviderName, string ManualProviderReference, OrganisationAddress Address, User TechUser)
{
if (!j.CanLogWarranty())
throw new InvalidOperationException("Log Warranty was Denied");
j.JobMetaWarranty.ExternalLoggedDate = DateTime.Now;
j.JobMetaWarranty.ExternalName = ManualProviderName;
if (ManualProviderReference != null && ManualProviderReference.Length > 100)
j.JobMetaWarranty.ExternalReference = ManualProviderReference.Substring(0, 100);
else
j.JobMetaWarranty.ExternalReference = ManualProviderReference;
// Write Log
JobLog jobLog = new JobLog()
{
JobId = j.Id,
TechUserId = TechUser.UserId,
Timestamp = DateTime.Now,
Comments = string.Format("# Manual Warranty Claim Submitted\r\nProvider: **{0}**\r\nAddress: **{1}**\r\nReference: **{2}**\r\n___\r\n```{3}```", ManualProviderName, Address.Name, ManualProviderReference ?? "<none>", FaultDescription)
};
Database.JobLogs.Add(jobLog);
}
#endregion
#region Convert HWar to HNWar
public static bool CanConvertHWarToHNWar(this Job j)
{
if (!UserService.CurrentAuthorization.Has(Claims.Job.Actions.ConvertHWarToHNWar))
return false;
return !j.ClosedDate.HasValue && (j.DeviceSerialNumber != null) &&
j.JobTypeId == JobType.JobTypeIds.HWar && string.IsNullOrEmpty(j.JobMetaWarranty.ExternalReference);
}
public static void OnConvertHWarToHNWar(this Job j, DiscoDataContext Database)
{
if (!j.CanConvertHWarToHNWar())
throw new InvalidOperationException("Convert HWar to HNWar was Denied");
var techUser = UserService.CurrentUser;
// Remove JobMetaWarranty
if (j.JobMetaWarranty != null)
Database.JobMetaWarranties.Remove(j.JobMetaWarranty);
// Add JobMetaNonWarranty
var metaHNWar = new JobMetaNonWarranty() { Job = j };
Database.JobMetaNonWarranties.Add(metaHNWar);
// Swap Job Sub Types
List<string> jobSubTypes = j.JobSubTypes.Select(jst => jst.Id).ToList();
j.JobSubTypes.Clear();
foreach (var jst in Database.JobSubTypes.Where(i => i.JobTypeId == JobType.JobTypeIds.HNWar && jobSubTypes.Contains(i.Id)))
j.JobSubTypes.Add(jst);
// Add Components
var components = Database.DeviceComponents.Include("JobSubTypes").Where(c => !c.DeviceModelId.HasValue || c.DeviceModelId == j.Device.DeviceModelId);
var jobComponents = new List<DeviceComponent>();
foreach (var component in components)
{
if (component.JobSubTypes.Count == 0)
{
jobComponents.Add(component);
}
else
{
foreach (var st in component.JobSubTypes)
{
foreach (var jst in j.JobSubTypes)
{
if (st.JobTypeId == jst.JobTypeId && st.Id == jst.Id)
{
jobComponents.Add(component);
break;
}
}
if (jobComponents.Contains(component))
break;
}
}
}
foreach (var component in jobComponents)
{
Database.JobComponents.Add(new JobComponent()
{
Job = j,
TechUserId = techUser.UserId,
Cost = component.Cost,
Description = component.Description
});
}
// Write Log
JobLog jobLog = new JobLog()
{
JobId = j.Id,
TechUserId = techUser.UserId,
Timestamp = DateTime.Now,
Comments = string.Format("# Job Type Converted\r\nFrom: **{0}**\r\nTo: **{1}**", Database.JobTypes.Find(JobType.JobTypeIds.HWar), Database.JobTypes.Find(JobType.JobTypeIds.HNWar))
};
Database.JobLogs.Add(jobLog);
j.JobTypeId = JobType.JobTypeIds.HNWar;
}
#endregion
#region Warranty Completed
public static bool CanWarrantyCompleted(this Job j)
{
return (j.JobTypeId == JobType.JobTypeIds.HWar) &&
j.JobMetaWarranty.ExternalLoggedDate.HasValue &&
!j.JobMetaWarranty.ExternalCompletedDate.HasValue;
}
public static void OnWarrantyCompleted(this Job j)
{
if (!j.CanWarrantyCompleted())
throw new InvalidOperationException("Warranty Completed was Denied");
j.JobMetaWarranty.ExternalCompletedDate = DateTime.Now;
}
#endregion
#region Insurance Claim Form Sent
public static bool CanInsuranceClaimFormSent(this Job j)
{
if (!UserService.CurrentAuthorization.Has(Claims.Job.Properties.NonWarrantyProperties.InsuranceClaimFormSent))
return false;
return (j.JobTypeId == JobType.JobTypeIds.HNWar) &&
j.JobMetaNonWarranty.IsInsuranceClaim &&
!j.JobMetaInsurance.ClaimFormSentDate.HasValue;
}
public static void OnInsuranceClaimFormSent(this Job j)
{
if (!j.CanInsuranceClaimFormSent())
throw new InvalidOperationException("Insurance Claim Form Sent was Denied");
var techUser = UserService.CurrentUser;
j.JobMetaInsurance.ClaimFormSentDate = DateTime.Now;
j.JobMetaInsurance.ClaimFormSentUserId = techUser.UserId;
}
#endregion
#region Log Repair
public static bool CanLogRepair(this Job j)
{
if (!UserService.CurrentAuthorization.Has(Claims.Job.Actions.LogRepair))
return false;
return (j.JobTypeId == JobType.JobTypeIds.HNWar) &&
(j.DeviceSerialNumber != null) &&
!j.JobMetaNonWarranty.RepairerLoggedDate.HasValue &&
!j.JobMetaNonWarranty.RepairerCompletedDate.HasValue;
}
public static void OnLogRepair(this Job j, DiscoDataContext Database, string RepairDescription, List<JobAttachment> SendAttachments, PluginFeatureManifest RepairProviderDefinition, OrganisationAddress Address, User TechUser, Dictionary<string, string> RepairProviderProperties)
{
if (!j.CanLogRepair())
throw new InvalidOperationException("Log Repair was Denied");
PublishJobResult publishJobResult = null;
using (RepairProviderFeature RepairProvider = RepairProviderDefinition.CreateInstance<RepairProviderFeature>())
{
if (SendAttachments != null && SendAttachments.Count > 0)
{
publishJobResult = DiscoServicesJobs.Publish(
Database,
j,
TechUser,
RepairProvider.ProviderId,
null,
RepairDescription,
SendAttachments,
AttachmentDataStoreExtensions.RepositoryFilename);
if (!publishJobResult.Success)
throw new Exception(string.Format("Disco ICT Online Services failed with the following message: ", publishJobResult.ErrorMessage));
if (string.IsNullOrWhiteSpace(RepairDescription))
RepairDescription = publishJobResult.PublishMessage;
else
RepairDescription = string.Concat(RepairDescription, Environment.NewLine, "___", Environment.NewLine, publishJobResult.PublishMessage);
}
string submitDescription;
if (string.IsNullOrWhiteSpace(RepairDescription))
submitDescription = j.GenerateFaultDescriptionFooter(Database, RepairProviderDefinition);
else
submitDescription = string.Concat(RepairDescription, Environment.NewLine, Environment.NewLine, j.GenerateFaultDescriptionFooter(Database, RepairProviderDefinition));
string providerRef = RepairProvider.SubmitJob(Database, j, Address, TechUser, submitDescription, RepairProviderProperties);
j.JobMetaNonWarranty.RepairerLoggedDate = DateTime.Now;
j.JobMetaNonWarranty.RepairerName = RepairProvider.ProviderId;
if (providerRef != null && providerRef.Length > 100)
j.JobMetaNonWarranty.RepairerReference = providerRef.Substring(0, 100);
else
j.JobMetaNonWarranty.RepairerReference = providerRef;
// Write Log
JobLog jobLog = new JobLog()
{
JobId = j.Id,
TechUserId = TechUser.UserId,
Timestamp = DateTime.Now,
Comments = string.Format("# Repair Request Submitted\r\nProvider: **{0}**\r\nAddress: **{1}**\r\nReference: **{2}**\r\n___\r\n```{3}```", RepairProvider.Manifest.Name, Address.Name, providerRef, RepairDescription)
};
Database.JobLogs.Add(jobLog);
if (publishJobResult != null)
{
try
{
DiscoServicesJobs.UpdateRecipientReference(Database, j, publishJobResult.Id, publishJobResult.Secret, j.JobMetaNonWarranty.RepairerReference);
}
catch (Exception ex) { ex.ToExceptionless().Submit(); } // Ignore Errors as this is not completely necessary
}
}
}
public static void OnLogRepair(this Job j, DiscoDataContext Database, string FaultDescription, string ManualProviderName, string ManualProviderReference, OrganisationAddress Address, User TechUser)
{
if (!j.CanLogRepair())
throw new InvalidOperationException("Log Repair was Denied");
j.JobMetaNonWarranty.RepairerLoggedDate = DateTime.Now;
j.JobMetaNonWarranty.RepairerName = ManualProviderName;
if (ManualProviderReference != null && ManualProviderReference.Length > 100)
j.JobMetaNonWarranty.RepairerReference = ManualProviderReference.Substring(0, 100);
else
j.JobMetaNonWarranty.RepairerReference = ManualProviderReference;
// Write Log
JobLog jobLog = new JobLog()
{
JobId = j.Id,
TechUserId = TechUser.UserId,
Timestamp = DateTime.Now,
Comments = string.Format("# Manual Repair Request Submitted\r\nProvider: **{0}**\r\nAddress: **{1}**\r\nReference: **{2}**\r\n___\r\n```{3}```", ManualProviderName, Address.Name, ManualProviderReference ?? "<none>", FaultDescription)
};
Database.JobLogs.Add(jobLog);
}
#endregion
#region Repair Complete
public static bool CanRepairComplete(this Job j)
{
if (!UserService.CurrentAuthorization.Has(Claims.Job.Properties.NonWarrantyProperties.RepairerCompletedDate))
return false;
return (j.JobTypeId == JobType.JobTypeIds.HNWar) &&
j.JobMetaNonWarranty.RepairerLoggedDate.HasValue &&
!j.JobMetaNonWarranty.RepairerCompletedDate.HasValue;
}
public static void OnRepairComplete(this Job j)
{
if (!j.CanRepairComplete())
throw new InvalidOperationException("Repair Complete was Denied");
j.JobMetaNonWarranty.RepairerCompletedDate = DateTime.Now;
}
#endregion
#region Close
public static void OnCloseNormally(this Job j, User Technician)
{
if (!j.CanCloseNormally())
throw new InvalidOperationException("Close was Denied");
j.ClosedDate = DateTime.Now;
j.ClosedTechUserId = Technician.UserId;
}
private static bool CanCloseNever(this Job j, JobQueueJob IgnoreJobQueueJob = null)
{
if (!UserService.CurrentAuthorization.Has(Claims.Job.Actions.Close))
return true;
if (j.ClosedDate.HasValue)
return true; // Job already Closed
if (j.DeviceHeld.HasValue && !j.DeviceReturnedDate.HasValue)
return true; // Device not returned to User
if (j.WaitingForUserAction.HasValue)
return true; // Job waiting on User Action
if (j.JobQueues != null)
{
if (IgnoreJobQueueJob == null)
{
if (j.JobQueues.Any(jqj => !jqj.RemovedDate.HasValue))
return true; // Job associated with a Job Queue
}
else
{
if (j.JobQueues.Any(jqj => jqj.Id != IgnoreJobQueueJob.Id && !jqj.RemovedDate.HasValue))
return true; // Job associated with a Job Queue
}
}
return false;
}
public static bool CanCloseNormally(this Job j)
{
if (j.CanCloseNever())
return false;
return j.CanCloseNormallyInternal();
}
private static bool CanCloseNormallyInternal(this Job j)
{
switch (j.JobTypeId)
{
case JobType.JobTypeIds.HWar:
if (!string.IsNullOrEmpty(j.JobMetaWarranty.ExternalReference) && !j.JobMetaWarranty.ExternalCompletedDate.HasValue)
return false; // Job Logged (Warranty) but not completed
break;
case JobType.JobTypeIds.HNWar:
if (j.JobMetaNonWarranty.RepairerLoggedDate.HasValue && !j.JobMetaNonWarranty.RepairerCompletedDate.HasValue)
return false; // Job Logged (Repair) but not completed
if (j.JobMetaNonWarranty.AccountingChargeRequiredDate.HasValue && !j.JobMetaNonWarranty.AccountingChargeAddedDate.HasValue)
return false; // Accounting Charge Required, but not added
if ((j.JobMetaNonWarranty.AccountingChargeRequiredDate.HasValue || j.JobMetaNonWarranty.AccountingChargeAddedDate.HasValue) && !j.JobMetaNonWarranty.AccountingChargePaidDate.HasValue)
return false; // Accounting Charge Required or Added, but not paid
if (j.JobMetaNonWarranty.IsInsuranceClaim && !j.JobMetaInsurance.ClaimFormSentDate.HasValue)
return false; // Is Insurance Claim, but claim form not sent
break;
}
return true;
}
public static bool CanCloseJobNormallyAfterRemoved(this JobQueueJob jqj)
{
if (jqj.Job.CanCloseNever(jqj))
return false;
return jqj.Job.CanCloseNormallyInternal();
}
#endregion
#region Force Close
public static bool CanCloseForced(this Job j)
{
List<string> reasons;
return CanCloseForced(j, out reasons);
}
public static bool CanCloseForced(this Job j, out List<string> Reasons)
{
Reasons = null;
if (!UserService.CurrentAuthorization.Has(Claims.Job.Actions.ForceClose))
return false;
if (j.CanCloseNever())
return false;
if (j.CanCloseNormally())
return false;
Reasons = new List<string>();
switch (j.JobTypeId)
{
case JobType.JobTypeIds.HWar:
if (!string.IsNullOrEmpty(j.JobMetaWarranty.ExternalReference) && !j.JobMetaWarranty.ExternalCompletedDate.HasValue)
Reasons.Add("Warranty Job Not Completed"); // Job Logged (Warranty) but not completed
break;
case JobType.JobTypeIds.HNWar:
if (j.JobMetaNonWarranty.RepairerLoggedDate.HasValue && !j.JobMetaNonWarranty.RepairerCompletedDate.HasValue)
Reasons.Add("Repair Job Not Completed"); // Job Logged (Repair) but not completed
if (j.JobMetaNonWarranty.AccountingChargeRequiredDate.HasValue && (!j.JobMetaNonWarranty.AccountingChargeAddedDate.HasValue && !j.JobMetaNonWarranty.AccountingChargePaidDate.HasValue))
Reasons.Add("Accounting Charge Required But Not Added Or Paid"); // Accounting Charge Required, but not added or paid
else if (j.JobMetaNonWarranty.AccountingChargeRequiredDate.HasValue && !j.JobMetaNonWarranty.AccountingChargeAddedDate.HasValue)
Reasons.Add("Accounting Charge Required But Not Added"); // Accounting Charge Required, but not added
else if (j.JobMetaNonWarranty.AccountingChargeAddedDate.HasValue && !j.JobMetaNonWarranty.AccountingChargePaidDate.HasValue)
Reasons.Add("Accounting Charge Added But Not Paid"); // Accounting Charge Added, but not paid
else if (j.JobMetaNonWarranty.AccountingChargeRequiredDate.HasValue && !j.JobMetaNonWarranty.AccountingChargePaidDate.HasValue)
Reasons.Add("Accounting Charge Required But Not Paid"); // Accounting Charge Required, but not paid
if (j.JobMetaNonWarranty.IsInsuranceClaim && !j.JobMetaInsurance.ClaimFormSentDate.HasValue)
Reasons.Add("Insurance Claim Form Not Sent"); // Is Insurance Claim, but claim form not sent
break;
}
return (Reasons.Count > 0);
}
public static void OnCloseForced(this Job j, DiscoDataContext Database, User Technician, string Reason)
{
if (!j.CanCloseForced())
throw new InvalidOperationException("Force Close was Denied");
// Write Log
JobLog jobLog = new JobLog()
{
JobId = j.Id,
TechUserId = Technician.UserId,
Timestamp = DateTime.Now,
Comments = string.Format("# Job Forcibly Closed\r\n{0}", string.IsNullOrWhiteSpace(Reason) ? "<no reason provided>" : Reason)
};
Database.JobLogs.Add(jobLog);
j.ClosedDate = DateTime.Now;
j.ClosedTechUserId = Technician.UserId;
}
#endregion
#region Reopen
public static bool CanReopen(this Job j)
{
if (!UserService.CurrentAuthorization.Has(Claims.Job.Actions.Reopen))
return false;
return j.ClosedDate.HasValue;
}
public static void OnReopen(this Job j)
{
if (!j.CanReopen())
throw new InvalidOperationException("Reopen was Denied");
j.ClosedDate = null;
j.ClosedTechUserId = null;
}
#endregion
#region Delete
public static bool CanDelete(this Job j)
{
if (!UserService.CurrentAuthorization.Has(Claims.Job.Actions.Delete))
return false;
return j.ClosedDate.HasValue;
}
public static void OnDelete(this Job j, DiscoDataContext Database)
{
// Job Sub Types
j.JobSubTypes.Clear();
// Job Attachments
foreach (var ja in j.JobAttachments.ToArray())
ja.OnDelete(Database);
j.JobAttachments.Clear();
// Job Components
foreach (var jc in j.JobComponents.ToArray())
Database.JobComponents.Remove(jc);
j.JobComponents.Clear();
// Job Queue Jobs
foreach (var jqj in j.JobQueues.ToArray())
Database.JobQueueJobs.Remove(jqj);
j.JobQueues.Clear();
// Job Logs
foreach (var jl in j.JobLogs.ToArray())
Database.JobLogs.Remove(jl);
j.JobLogs.Clear();
// Job Meta
if (j.JobMetaInsurance != null)
{
Database.JobMetaInsurances.Remove(j.JobMetaInsurance);
j.JobMetaInsurance = null;
}
if (j.JobMetaNonWarranty != null)
{
Database.JobMetaNonWarranties.Remove(j.JobMetaNonWarranty);
j.JobMetaNonWarranty = null;
}
if (j.JobMetaWarranty != null)
{
Database.JobMetaWarranties.Remove(j.JobMetaWarranty);
j.JobMetaWarranty = null;
}
// Job
Database.Jobs.Remove(j);
}
#endregion
}
}
+190 -2
View File
@@ -1,11 +1,14 @@
using Disco.Models.Repository;
using Disco.Data.Repository;
using Disco.Models.Repository;
using Disco.Models.Services.Documents;
using Disco.Models.Services.Jobs.JobLists;
using Disco.Services.Authorization;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Plugins;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Disco.Services
{
@@ -195,5 +198,190 @@ namespace Disco.Services
var statusId = j.CalculateStatusId();
return new Tuple<string, string>(statusId, JobStatusDescription(statusId, j));
}
public static List<DocumentTemplate> AvailableDocumentTemplates(this Job j, DiscoDataContext Database, User User, DateTime TimeStamp)
{
var dts = Database.DocumentTemplates.Include("JobSubTypes")
.Where(dt => dt.Scope == DocumentTemplate.DocumentTemplateScopes.Job)
.ToList();
foreach (var dt in dts.ToArray())
{
if (dt.JobSubTypes.Count != 0)
{ // Filter Applied
bool match = false;
foreach (var st in j.JobSubTypes)
{
if (dt.JobSubTypes.Contains(st))
{
match = true;
break;
}
}
if (!match)
dts.Remove(dt);
}
}
// Evaluate Filters
dts = dts.Where(dt => dt.FilterExpressionMatches(j, Database, User, TimeStamp, DocumentState.DefaultState())).ToList();
return dts;
}
public static DateTime ValidateDateAfterOpened(this Job j, DateTime d)
{
if (d < j.OpenedDate)
{
if (d > j.OpenedDate.AddMinutes(-1))
return j.OpenedDate;
else
throw new ArgumentException("The Date must be >= the Open Date.", "d");
}
return d;
}
public static string GenerateFaultDescription(this Job j, DiscoDataContext Database)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("Faulty Components:");
foreach (var jst in j.JobSubTypes)
sb.Append("- ").AppendLine(jst.Description).AppendLine(" - ");
return sb.ToString();
}
public static string GenerateFaultDescriptionFooter(this Job j, DiscoDataContext Database, PluginFeatureManifest WarrantyProviderDefinition)
{
var versionDisco = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
return string.Format("Automation by Disco v{0}.{1}.{2:0000}.{3:0000} (Provider: {4} v{5})",
versionDisco.Major, versionDisco.Minor, versionDisco.Build, versionDisco.Revision, WarrantyProviderDefinition.Id, WarrantyProviderDefinition.PluginManifest.Version.ToString(4));
}
public static void UpdateSubTypes(this Job j, DiscoDataContext Database, List<JobSubType> SubTypes, bool AddComponents, User TechUser)
{
if (SubTypes == null || SubTypes.Count == 0)
throw new ArgumentException("The Job must contain at least one Sub Type");
List<JobSubType> addedSubTypes = new List<JobSubType>();
List<JobSubType> removedSubTypes = new List<JobSubType>();
// Removed Sub Types
foreach (var t in j.JobSubTypes.ToArray())
if (!SubTypes.Contains(t))
{
removedSubTypes.Add(t);
j.JobSubTypes.Remove(t);
}
// Added Sub Types
foreach (var t in SubTypes)
if (!j.JobSubTypes.Contains(t))
{
addedSubTypes.Add(t);
j.JobSubTypes.Add(t);
}
// Write Log
if (addedSubTypes.Count > 0 || removedSubTypes.Count > 0)
{
StringBuilder logBuilder = new StringBuilder();
logBuilder.AppendLine("# Updated Job Sub Types");
if (removedSubTypes.Count > 0)
{
logBuilder.AppendLine().AppendLine("Removed:");
foreach (var t in removedSubTypes)
logBuilder.Append("- **").Append(t.ToString()).AppendLine("**");
}
if (addedSubTypes.Count > 0)
{
logBuilder.AppendLine().AppendLine("Added:");
foreach (var t in addedSubTypes)
logBuilder.Append("- **").Append(t.ToString()).AppendLine("**");
}
Database.JobLogs.Add(new JobLog()
{
JobId = j.Id,
TechUserId = TechUser.UserId,
Timestamp = DateTime.Now,
Comments = logBuilder.ToString()
});
}
// Add Components
if (AddComponents && addedSubTypes.Count > 0 && j.DeviceSerialNumber != null)
{
var components = Database.DeviceComponents.Include("JobSubTypes").Where(c => !c.DeviceModelId.HasValue || c.DeviceModelId == j.Device.DeviceModelId);
var addedComponents = new List<DeviceComponent>();
foreach (var c in components)
{
foreach (var st in c.JobSubTypes)
{
foreach (var jst in addedSubTypes)
{
if (st.JobTypeId == jst.JobTypeId && st.Id == jst.Id)
{
addedComponents.Add(c);
break;
}
}
if (addedComponents.Contains(c))
break;
}
}
foreach (var c in addedComponents)
{
if (!j.JobComponents.Any(jc => jc.Description.Equals(c.Description, StringComparison.OrdinalIgnoreCase)))
{ // Job Component with matching Description doesn't exist.
Database.JobComponents.Add(new JobComponent()
{
Job = j,
TechUserId = TechUser.UserId,
Cost = c.Cost,
Description = c.Description
});
}
}
}
}
private static List<string> FilterCreatableTypePermissions(AuthorizationToken Authorization)
{
if (!Authorization.HasAll(Claims.Job.Types.CreateHMisc, Claims.Job.Types.CreateHNWar, Claims.Job.Types.CreateHWar, Claims.Job.Types.CreateSApp, Claims.Job.Types.CreateSImg, Claims.Job.Types.CreateSOS, Claims.Job.Types.CreateUMgmt))
{
// Must Filter
List<string> allowedTypes = new List<string>(6);
if (Authorization.Has(Claims.Job.Types.CreateHMisc))
allowedTypes.Add(JobType.JobTypeIds.HMisc);
if (Authorization.Has(Claims.Job.Types.CreateHNWar))
allowedTypes.Add(JobType.JobTypeIds.HNWar);
if (Authorization.Has(Claims.Job.Types.CreateHWar))
allowedTypes.Add(JobType.JobTypeIds.HWar);
if (Authorization.Has(Claims.Job.Types.CreateSApp))
allowedTypes.Add(JobType.JobTypeIds.SApp);
if (Authorization.Has(Claims.Job.Types.CreateSImg))
allowedTypes.Add(JobType.JobTypeIds.SImg);
if (Authorization.Has(Claims.Job.Types.CreateSOS))
allowedTypes.Add(JobType.JobTypeIds.SOS);
if (Authorization.Has(Claims.Job.Types.CreateUMgmt))
allowedTypes.Add(JobType.JobTypeIds.UMgmt);
return allowedTypes;
}
return null;
}
public static IQueryable<JobType> FilterCreatableTypePermissions(this IQueryable<JobType> JobTypes, AuthorizationToken Authorization)
{
var allowedTypes = FilterCreatableTypePermissions(Authorization);
if (allowedTypes != null)
{
return JobTypes.Where(jt => allowedTypes.Contains(jt.Id));
}
return JobTypes;
}
}
}
+79
View File
@@ -0,0 +1,79 @@
using Disco.Models.Repository;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace Disco.Services
{
public static class JobFlagExtensions
{
private static Dictionary<string, Dictionary<long, string>> allFlags;
private static void CacheAllFlags()
{
if (allFlags == null)
{
var fType = typeof(Job.UserManagementFlags);
var fMembers = fType.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
var flags = new Dictionary<string, Dictionary<long, string>>();
foreach (var f in fMembers)
{
DisplayAttribute display = (DisplayAttribute)(f.GetCustomAttributes(typeof(DisplayAttribute), false)[0]);
string gn = display.GroupName;
Dictionary<long, string> g;
if (!flags.TryGetValue(gn, out g))
{
g = new Dictionary<long, string>();
flags.Add(gn, g);
}
g[(long)f.GetRawConstantValue()] = display.Name;
}
allFlags = flags;
}
}
public static Dictionary<string, List<Tuple<long, string, bool>>> ValidFlagsGrouped(this Job j)
{
Dictionary<string, List<Tuple<long, string, bool>>> validFlags = new Dictionary<string, List<Tuple<long, string, bool>>>();
CacheAllFlags();
var currentFlags = (long)(j.Flags ?? 0);
foreach (var jt in j.JobSubTypes)
{
Dictionary<long, string> g;
if (allFlags.TryGetValue(jt.Id, out g))
{
validFlags[jt.Id] = g.Select(f => new Tuple<long, string, bool>(f.Key, f.Value, ((currentFlags & f.Key) == f.Key))).ToList();
}
else
{
validFlags[jt.Id] = null;
}
}
return validFlags;
}
public static Dictionary<long, Tuple<string, bool>> ValidFlags(this Job j)
{
Dictionary<long, Tuple<string, bool>> validFlags = new Dictionary<long, Tuple<string, bool>>();
CacheAllFlags();
var currentFlags = (long)(j.Flags ?? 0);
foreach (var jt in j.JobSubTypes)
{
Dictionary<long, string> g;
if (allFlags.TryGetValue(jt.Id, out g))
{
foreach (var f in g)
validFlags[f.Key] = new Tuple<string, bool>(string.Format("{0}: {1}", jt.Description, f.Value), ((currentFlags & f.Key) == f.Key));
}
}
return validFlags;
}
}
}
@@ -0,0 +1,213 @@
using Disco.Data.Repository;
using Disco.Models.Repository;
using Disco.Services.Authorization;
using Disco.Services.Jobs.JobQueues;
using Disco.Services.Users;
using System;
using System.Linq;
namespace Disco.Services
{
public static class JobQueueExtensions
{
#region Edit Sla
public static bool CanEditSla(this JobQueueJob jqj)
{
if (jqj.RemovedDate.HasValue)
return false;
if (UserService.CurrentAuthorization.Has(Claims.Job.Properties.JobQueueProperties.EditAnySLA))
{
// Can edit ANY queue
return true;
}
else if (UserService.CurrentAuthorization.Has(Claims.Job.Properties.JobQueueProperties.EditOwnSLA))
{
// Can edit from OWN queue
return JobQueueService.UsersQueues(UserService.CurrentUser).Any(q => q.JobQueue.Id == jqj.JobQueueId);
}
else
{
return false;
}
}
public static void OnEditSla(this JobQueueJob jqj, DateTime? SlaExpiresDate)
{
if (!jqj.CanEditSla())
throw new InvalidOperationException("Editing job SLA for this queue is denied");
if (SlaExpiresDate.HasValue && jqj.AddedDate > SlaExpiresDate.Value)
throw new ArgumentException("The SLA Expires Date must be greater than the Added Date", "SLAExpiresDate");
jqj.SLAExpiresDate = SlaExpiresDate;
}
#endregion
#region Edit Priority
public static bool CanEditPriority(this JobQueueJob jqj)
{
if (jqj.RemovedDate.HasValue)
return false;
if (UserService.CurrentAuthorization.Has(Claims.Job.Properties.JobQueueProperties.EditAnyPriority))
{
// Can edit ANY queue
return true;
}
else if (UserService.CurrentAuthorization.Has(Claims.Job.Properties.JobQueueProperties.EditOwnPriority))
{
// Can edit from OWN queue
return JobQueueService.UsersQueues(UserService.CurrentUser).Any(q => q.JobQueue.Id == jqj.JobQueueId);
}
else
{
return false;
}
}
public static void OnEditPriority(this JobQueueJob jqj, JobQueuePriority Priority)
{
if (!jqj.CanEditPriority())
throw new InvalidOperationException("Editing job priority for this queue is denied");
jqj.Priority = Priority;
}
#endregion
#region Edit Comments
private static bool CanEditComments(this JobQueueJob jqj)
{
if (UserService.CurrentAuthorization.Has(Claims.Job.Properties.JobQueueProperties.EditAnyComments))
{
// Can edit ANY queue
return true;
}
else if (UserService.CurrentAuthorization.Has(Claims.Job.Properties.JobQueueProperties.EditOwnComments))
{
// Can edit from OWN queue
return JobQueueService.UsersQueues(UserService.CurrentUser).Any(q => q.JobQueue.Id == jqj.JobQueueId);
}
else
{
return false;
}
}
public static bool CanEditAddedComment(this JobQueueJob jqj)
{
return jqj.CanEditComments();
}
public static bool CanEditRemovedComment(this JobQueueJob jqj)
{
if (!jqj.RemovedDate.HasValue)
return false;
return jqj.CanEditComments();
}
public static void OnEditAddedComment(this JobQueueJob jqj, string AddedComment)
{
if (!jqj.CanEditAddedComment())
throw new InvalidOperationException("Editing job added comments for this queue is denied");
jqj.AddedComment = string.IsNullOrWhiteSpace(AddedComment) ? null : AddedComment.Trim();
}
public static void OnEditRemovedComment(this JobQueueJob jqj, string RemovedComment)
{
if (!jqj.CanEditRemovedComment())
throw new InvalidOperationException("Editing job removed comments for this queue is denied");
jqj.RemovedComment = string.IsNullOrWhiteSpace(RemovedComment) ? null : RemovedComment.Trim();
}
#endregion
#region Remove
public static bool CanRemove(this JobQueueJob jqj)
{
if (jqj.RemovedDate.HasValue)
return false;
if (UserService.CurrentAuthorization.Has(Claims.Job.Actions.RemoveAnyQueues))
{
// Can remove from ANY queue
return true;
}
else if (UserService.CurrentAuthorization.Has(Claims.Job.Actions.RemoveOwnQueues))
{
// Can remove from OWN queue
return JobQueueService.UsersQueues(UserService.CurrentUser).Any(q => q.JobQueue.Id == jqj.JobQueueId);
}
else
{
return false;
}
}
public static void OnRemove(this JobQueueJob jqj, User Technician, string Comment)
{
if (!jqj.CanRemove())
throw new InvalidOperationException("Removing job from queue is denied");
jqj.RemovedDate = DateTime.Now;
jqj.RemovedUserId = Technician.UserId;
jqj.RemovedComment = string.IsNullOrWhiteSpace(Comment) ? null : Comment.Trim();
}
#endregion
#region Add
public static bool CanAddQueues(this Job j)
{
// Job Closed?
if (j.ClosedDate.HasValue)
return false;
if (UserService.CurrentAuthorization.HasAny(Claims.Job.Actions.AddAnyQueues, Claims.Job.Actions.AddOwnQueues))
return true;
return false;
}
public static bool CanAddQueue(this Job j, JobQueue jq)
{
// Shortcut
if (!j.CanAddQueues())
return false;
// Already in Queue?
if (j.JobQueues.Any(jjq => !jjq.RemovedDate.HasValue && jjq.JobQueueId == jq.Id))
return false;
// Can add ANY queue
if (UserService.CurrentAuthorization.Has(Claims.Job.Actions.AddAnyQueues))
return true;
// Can add OWN queue
if (UserService.CurrentAuthorization.Has(Claims.Job.Actions.AddOwnQueues))
{
return JobQueueService.UsersQueues(UserService.CurrentUser).Any(q => q.JobQueue.Id == jq.Id);
}
return false;
}
public static JobQueueJob OnAddQueue(this Job j, DiscoDataContext Database, JobQueue jq, User Technician, string Comment, DateTime? SLAExpires, JobQueuePriority Priority)
{
if (!j.CanAddQueue(jq))
throw new InvalidOperationException("Adding job to queue is denied");
if (SLAExpires.HasValue && SLAExpires.Value < DateTime.Now)
throw new ArgumentException("The SLA Date must be greater than the current time", "SLAExpires");
var jqj = new JobQueueJob()
{
JobQueueId = jq.Id,
JobId = j.Id,
AddedDate = DateTime.Now,
AddedUserId = Technician.UserId,
AddedComment = string.IsNullOrWhiteSpace(Comment) ? null : Comment.Trim(),
SLAExpiresDate = SLAExpires,
Priority = Priority
};
Database.JobQueueJobs.Add(jqj);
return jqj;
}
#endregion
}
}
+124
View File
@@ -0,0 +1,124 @@
using Disco.Data.Repository;
using Disco.Models.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Disco.Services.Jobs
{
public static class Jobs
{
public static Job Create(DiscoDataContext Database, Device device, User user, JobType type, List<JobSubType> subTypes, User initialTech, bool addAutoQueues = true)
{
Job j = new Job()
{
JobType = type,
OpenedTechUserId = initialTech.UserId,
OpenedTechUser = initialTech,
OpenedDate = DateTime.Now
};
// Device
if (device != null)
{
j.Device = device;
j.DeviceSerialNumber = device.SerialNumber;
}
// User
if (user != null)
{
j.User = user;
j.UserId = user.UserId;
}
// Sub Types
List<JobSubType> jobSubTypes = subTypes.ToList();
j.JobSubTypes = jobSubTypes;
Database.Jobs.Add(j);
// Job Queues
if (addAutoQueues)
{
var queues = from st in subTypes
from jq in st.JobQueues
group st by jq into g
select new { queue = g.Key, subTypes = g };
foreach (var queue in queues)
{
var commentBuilder = new StringBuilder("Automatically added by:").AppendLine();
foreach (var subType in queue.subTypes)
{
commentBuilder.AppendLine().Append("* ").Append(subType.Description);
}
var jqj = new JobQueueJob()
{
JobQueueId = queue.queue.Id,
Job = j,
AddedDate = DateTime.Now,
AddedUserId = initialTech.UserId,
AddedComment = commentBuilder.ToString(),
SLAExpiresDate = queue.queue.DefaultSLAExpiry.HasValue ? (DateTime?)DateTime.Now.AddMinutes(queue.queue.DefaultSLAExpiry.Value) : null,
Priority = JobQueuePriority.Normal
};
Database.JobQueueJobs.Add(jqj);
}
}
switch (type.Id)
{
case JobType.JobTypeIds.HWar:
Database.JobMetaWarranties.Add(new JobMetaWarranty() { Job = j });
break;
case JobType.JobTypeIds.HNWar:
Database.JobMetaNonWarranties.Add(new JobMetaNonWarranty() { Job = j });
if (device != null)
{
// Add Job Components
var components = Database.DeviceComponents.Include("JobSubTypes").Where(c => !c.DeviceModelId.HasValue || c.DeviceModelId == j.Device.DeviceModelId);
var addedComponents = new List<DeviceComponent>();
foreach (var c in components)
{
if (c.JobSubTypes.Count == 0)
{ // No Filter
addedComponents.Add(c);
}
else
{
foreach (var st in c.JobSubTypes)
{
foreach (var jst in jobSubTypes)
{
if (st.JobTypeId == jst.JobTypeId && st.Id == jst.Id)
{
addedComponents.Add(c);
break;
}
}
if (addedComponents.Contains(c))
break;
}
}
}
foreach (var c in addedComponents)
Database.JobComponents.Add(new JobComponent()
{
Job = j,
TechUserId = initialTech.UserId,
Cost = c.Cost,
Description = c.Description
});
}
break;
}
return j;
}
}
}
@@ -0,0 +1,172 @@
using Disco.Data.Repository;
using Disco.Data.Repository.Monitor;
using Disco.Models.Repository;
using Disco.Models.Services.Job.Statistics;
using Disco.Services.Tasks;
using Quartz;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
namespace Disco.Services.Jobs.Statistics
{
public class DailyOpenedClosed : ScheduledTask
{
private static List<DailyOpenedClosedItem> _data;
private static object _dataLock = new object();
private static IDisposable _streamSubscription;
public override string TaskName { get { return "Job Statistics - Daily Opened/Closed Task"; } }
public override bool SingleInstanceTask { get { return true; } }
public override bool CancelInitiallySupported { get { return false; } }
public override bool LogExceptionsOnly { get { return true; } }
public override void InitalizeScheduledTask(DiscoDataContext Database)
{
// Trigger Daily @ 12:29am
TriggerBuilder triggerBuilder = TriggerBuilder.Create().WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(0, 29));
this.ScheduleTask(triggerBuilder);
}
protected override void ExecuteTask()
{
using (var database = new DiscoDataContext())
{
UpdateDataHistory(database, true);
}
}
private static void UpdateDataHistory(DiscoDataContext Database, bool Refresh = false)
{
DateTime historyEnd = DateTime.Now.Date;
if (Refresh || _data == null || _data.Count == 0 || _data.Last().Timestamp < historyEnd)
{
lock (_dataLock)
{
if (Refresh || _data == null || _data.Count == 0 || _data.Last().Timestamp < historyEnd)
{
DateTime historyStart = DateTime.Now.AddDays(-28).Date;
// Initialize Memory Store
List<DailyOpenedClosedItem> resultData;
if (Refresh || _data == null)
resultData = new List<DailyOpenedClosedItem>();
else
resultData = _data;
// Remove Old Data
while (resultData.Count > 0 && resultData[0].Timestamp < historyStart)
resultData.RemoveAt(0);
// Calculate Update Scope
DateTime processDate = historyStart;
if (resultData.Count > 0)
processDate = resultData.Last().Timestamp.AddDays(-1);
// Cache Data
while (processDate <= historyEnd)
{
resultData.Add(Data(Database, processDate));
processDate = processDate.AddDays(1);
}
_data = resultData;
// Subscribe to Live Repository Events
if (_streamSubscription != null)
_streamSubscription.Dispose();
_streamSubscription = RepositoryMonitor.StreamBeforeCommit.Where(
e => e.EntityType == typeof(Job) &&
(e.EventType == RepositoryMonitorEventType.Added || (e.EventType == RepositoryMonitorEventType.Modified && e.ModifiedProperties.Contains("ClosedDate")))).Subscribe(RepositoryEvent_JobChange);
}
}
}
}
private static void RepositoryEvent_JobChange(RepositoryMonitorEvent e)
{
if (e.EventType == RepositoryMonitorEventType.Added)
{
// New Job
var todaysStats = _data.Last();
todaysStats.OpenedJobs += 1;
todaysStats.TotalJobs += 1;
}
else
{
DateTime? previousValue = e.GetPreviousPropertyValue<DateTime?>("ClosedDate");
if (previousValue.HasValue)
{
// Remove Statistics
var statItem = _data.FirstOrDefault(i => i.Timestamp == previousValue.Value.Date);
if (statItem != null)
{
statItem.ClosedJobs -= 1;
statItem.TotalJobs += 1;
}
foreach (var affectedStat in _data.Where(i => i.Timestamp > previousValue))
{
affectedStat.TotalJobs += 1;
}
}
}
DateTime? currentValue = e.GetCurrentPropertyValue<DateTime?>("ClosedDate");
if (currentValue.HasValue)
{
// Add Statistics
// Remove Statistics
var statItem = _data.FirstOrDefault(i => i.Timestamp == currentValue.Value.Date);
if (statItem != null)
{
statItem.ClosedJobs += 1;
statItem.TotalJobs -= 1;
}
foreach (var affectedStat in _data.Where(i => i.Timestamp > currentValue))
{
affectedStat.TotalJobs -= 1;
}
}
}
private static DailyOpenedClosedItem Data(DiscoDataContext Database, DateTime ProcessDate)
{
DateTime processDateStart = ProcessDate;
DateTime processDateEnd = ProcessDate.AddDays(1);
int totalJobs = Database.Jobs.Where(j => j.OpenedDate < processDateEnd && (!j.ClosedDate.HasValue || j.ClosedDate > processDateEnd)).Count();
int openedJobs = Database.Jobs.Where(j => j.OpenedDate > processDateStart && j.OpenedDate < processDateEnd).Count();
int closedJobs = Database.Jobs.Where(j => j.ClosedDate > processDateStart && j.ClosedDate < processDateEnd).Count();
return new DailyOpenedClosedItem()
{
Timestamp = ProcessDate,
TotalJobs = totalJobs,
OpenedJobs = openedJobs,
ClosedJobs = closedJobs
};
}
public static List<DailyOpenedClosedItem> Data(DiscoDataContext Database, bool FilterUnimportantWeekends = false)
{
List<DailyOpenedClosedItem> resultData;
UpdateDataHistory(Database);
if (FilterUnimportantWeekends)
resultData = _data.Where(i => (i.Timestamp.DayOfWeek != DayOfWeek.Saturday && i.Timestamp.DayOfWeek != DayOfWeek.Sunday) ||
(i.OpenedJobs > 0 || i.ClosedJobs > 0)).ToList();
else
resultData = _data.ToList();
return resultData;
}
}
}