|
@@ -16,6 +16,8 @@ using InABox.Scripting;
|
|
|
using InABox.Wpf.Reports;
|
|
|
using InABox.WPF;
|
|
|
using PRSDesktop.Configuration;
|
|
|
+using System.Diagnostics;
|
|
|
+using System.Threading.Tasks;
|
|
|
|
|
|
namespace PRSDesktop
|
|
|
{
|
|
@@ -50,6 +52,8 @@ namespace PRSDesktop
|
|
|
[NullEditor]
|
|
|
public DateTime Processed { get; set; }
|
|
|
|
|
|
+ [NullEditor]
|
|
|
+ public Guid ParentID { get; set; }
|
|
|
}
|
|
|
|
|
|
public class DigitalFormDockGrid : DynamicGrid<DigitalFormDockModel>
|
|
@@ -98,7 +102,8 @@ namespace PRSDesktop
|
|
|
.Add(x => x.Form.Description, x => x.FormName)
|
|
|
.Add(x => x.FormCompleted, x => x.Completed)
|
|
|
.Add(x => x.FormCompletedBy.UserID, x => x.CompletedBy)
|
|
|
- .Add(x => x.FormProcessed, x => x.Processed);
|
|
|
+ .Add(x => x.FormProcessed, x => x.Processed)
|
|
|
+ .Add(x => x.Parent.ID, x => x.ParentID);
|
|
|
|
|
|
_query = new MultiQuery();
|
|
|
|
|
@@ -194,7 +199,6 @@ namespace PRSDesktop
|
|
|
);
|
|
|
}
|
|
|
|
|
|
-
|
|
|
if (modules.Any())
|
|
|
column.AddSeparator();
|
|
|
|
|
@@ -205,8 +209,8 @@ namespace PRSDesktop
|
|
|
PRSDesktop.Resources.lock_sml,
|
|
|
(row) =>
|
|
|
{
|
|
|
- var form = Activator.CreateInstance(formType) as IDigitalFormInstance;
|
|
|
- form.ID = row.Get<DigitalFormDockModel, Guid>(x => x.ID);
|
|
|
+ var form = (Activator.CreateInstance(formType) as IDigitalFormInstance)!;
|
|
|
+ form.ID = row!.Get<DigitalFormDockModel, Guid>(x => x.ID);
|
|
|
form.FormProcessed = row.Get<DigitalFormDockModel, DateTime>(x => x.Processed);
|
|
|
form.CommitChanges();
|
|
|
form.FormProcessed = DateTime.Now;
|
|
@@ -225,8 +229,8 @@ namespace PRSDesktop
|
|
|
PRSDesktop.Resources.lock_sml,
|
|
|
(row) =>
|
|
|
{
|
|
|
- var form = Activator.CreateInstance(formType) as IDigitalFormInstance;
|
|
|
- form.ID = row.Get<DigitalFormDockModel, Guid>(x => x.ID);
|
|
|
+ var form = (Activator.CreateInstance(formType) as IDigitalFormInstance)!;
|
|
|
+ form.ID = row!.Get<DigitalFormDockModel, Guid>(x => x.ID);
|
|
|
form.FormProcessed = row.Get<DigitalFormDockModel, DateTime>(x => x.Processed);
|
|
|
form.CommitChanges();
|
|
|
form.FormProcessed = DateTime.MinValue;
|
|
@@ -239,6 +243,107 @@ namespace PRSDesktop
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+ var entityType = DFUtils.FormEntityType(formType);
|
|
|
+ if(entityType.HasInterface<IJobScopedItem>())
|
|
|
+ {
|
|
|
+ var entityID = row.Get<DigitalFormDockModel, Guid>(x => x.ParentID);
|
|
|
+ column.AddSeparator();
|
|
|
+ column.AddItem("Set Job", PRSDesktop.Resources.project, (row) =>
|
|
|
+ {
|
|
|
+ var entity = (Client.Create(entityType)
|
|
|
+ .Query(
|
|
|
+ Filter.Create<Entity>(entityType, x => x.ID).IsEqualTo(entityID),
|
|
|
+ LookupFactory.DefineFilterColumns(typeof(Job), entityType)
|
|
|
+ .Add<Entity>(x => x.ID)
|
|
|
+ .Add<IJobScopedItem>(x => x.JobLink.ID)
|
|
|
+ .Add<IJobScopedItem>(x => x.JobLink.JobNumber))
|
|
|
+ .ToObjects(entityType).First() as Entity)!;
|
|
|
+ var item = (entity as IJobScopedItem)!;
|
|
|
+
|
|
|
+ var window = new MultiSelectDialog<Job>(
|
|
|
+ LookupFactory.DefineFilter<Job>(entityType, CoreUtils.One(entity)),
|
|
|
+ new Columns<Job>(x => x.DefaultScope.ID).Add(x => x.JobNumber),
|
|
|
+ multiselect: false);
|
|
|
+ if (!window.ShowDialog(nameof(Job.JobNumber), item.JobLink.JobNumber, Syncfusion.Data.FilterType.Equals))
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ var job = window.Data().ToObjects<Job>().First();
|
|
|
+ item.JobLink.ID = job.ID;
|
|
|
+ item.JobLink.Synchronise(job);
|
|
|
+
|
|
|
+ Client.Create(entityType).Save(entity, "Linked job set by user from Digital forms dock.");
|
|
|
+ MessageBox.Show($"{entityType.Name} has been assigned to job {job.JobNumber}.");
|
|
|
+ });
|
|
|
+ column.AddItem("Set Job Scope", PRSDesktop.Resources.project, (row) =>
|
|
|
+ {
|
|
|
+ var entity = (Client.Create(entityType)
|
|
|
+ .Query(
|
|
|
+ Filter.Create<Entity>(entityType, x => x.ID).IsEqualTo(entityID),
|
|
|
+ LookupFactory.DefineFilterColumns(typeof(JobScope), entityType)
|
|
|
+ .Add<Entity>(x => x.ID)
|
|
|
+ .Add<IJobScopedItem>(x => x.JobLink.ID)
|
|
|
+ .Add<IJobScopedItem>(x => x.JobScope.ID)
|
|
|
+ .Add<IJobScopedItem>(x => x.JobScope.Number))
|
|
|
+ .ToObjects(entityType).First() as Entity)!;
|
|
|
+ var item = (entity as IJobScopedItem)!;
|
|
|
+ if(item.JobLink.ID == Guid.Empty)
|
|
|
+ {
|
|
|
+ MessageBox.Show($"{entityType.Name} is not linked to a job. Please select a job first.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ var window = new MultiSelectDialog<JobScope>(
|
|
|
+ new Filters<JobScope>()
|
|
|
+ .Add(LookupFactory.DefineFilter<JobScope>(entityType, CoreUtils.One(entity)))
|
|
|
+ .Add(new Filter<JobScope>(x => x.Job.ID).IsEqualTo(item.JobLink.ID))
|
|
|
+ .Combine(),
|
|
|
+ new Columns<JobScope>(x => x.ID).Add(x => x.Number),
|
|
|
+ multiselect: false);
|
|
|
+ if (!window.ShowDialog(nameof(JobScope.Number), item.JobScope.Number, Syncfusion.Data.FilterType.Equals))
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ var scope = window.Data().ToObjects<JobScope>().First();
|
|
|
+ item.JobScope.ID = scope.ID;
|
|
|
+
|
|
|
+ Client.Create(entityType).Save(entity, "Linked scope set by user from Digital forms dock.");
|
|
|
+ MessageBox.Show($"{entityType.Name} has been assigned to scope {scope.Number}.");
|
|
|
+ });
|
|
|
+ }
|
|
|
+ else if(entityType == typeof(Job) && formType == typeof(JobForm))
|
|
|
+ {
|
|
|
+ column.AddSeparator();
|
|
|
+ column.AddItem("Set Job Scope", PRSDesktop.Resources.project, (row) =>
|
|
|
+ {
|
|
|
+ var instance = Client.Query(
|
|
|
+ new Filter<JobForm>(x => x.ID).IsEqualTo(instanceID),
|
|
|
+ LookupFactory.DefineFilterColumns<JobForm, JobScope>()
|
|
|
+ .Add(x => x.ID)
|
|
|
+ .Add(x => x.Parent.ID))
|
|
|
+ .ToObjects<JobForm>().First();
|
|
|
+ var job = Client.Query(
|
|
|
+ new Filter<Job>(x => x.ID).IsEqualTo(instance.Parent.ID),
|
|
|
+ LookupFactory.DefineFilterColumns<Job, JobScope>()).ToObjects<Job>().First();
|
|
|
+
|
|
|
+ var window = new MultiSelectDialog<JobScope>(
|
|
|
+ new Filters<JobScope>()
|
|
|
+ .Add(LookupFactory.DefineFilter<Job, JobScope>(new Job[] { job }))
|
|
|
+ .Add(new Filter<JobScope>(x => x.Job.ID).IsEqualTo(instance.Parent.ID))
|
|
|
+ .Combine(),
|
|
|
+ new Columns<JobScope>(x => x.ID).Add(x => x.Number), multiselect: false);
|
|
|
+ if (!window.ShowDialog())
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ var scope = window.Data().ToObjects<JobScope>().First();
|
|
|
+ instance.JobScope.ID = scope.ID;
|
|
|
+
|
|
|
+ Client.Save(instance, "Linked scope set by user from Digital forms dock.");
|
|
|
+ MessageBox.Show($"Form has been assigned to scope {scope.Number}.");
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
if (Security.IsAllowed<CanCustomiseModules>())
|
|
|
{
|
|
@@ -263,6 +368,165 @@ namespace PRSDesktop
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /*private void AttachToScope(CoreRow row, Type formType, DataModel model)
|
|
|
+ {
|
|
|
+ var instance = Client.Create(formType)
|
|
|
+ .Query(
|
|
|
+ Filter.Create<IDigitalFormInstance>(formType, x => x.ID).IsEqualTo(row.Get<DigitalFormDockModel, Guid>(x => x.ID)),
|
|
|
+ Columns.Create<IDigitalFormInstance>(formType)
|
|
|
+ .Add<IDigitalFormInstance>(x => x.ID)
|
|
|
+ .Add<IDigitalFormInstance>(x => x.Number))
|
|
|
+ .Rows.FirstOrDefault()
|
|
|
+ ?.ToObject(formType) as IDigitalFormInstance;
|
|
|
+ if (instance is null)
|
|
|
+ {
|
|
|
+ MessageBox.Show("Form does not exist!");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ var formID = row.Get<DigitalFormDockModel, Guid>(x => x.FormID);
|
|
|
+
|
|
|
+ var entityColumns = JobScopeForms.GetEntityColumns(formType)?.Add<Entity>(x => x.ID);
|
|
|
+ var entityObj = Client.Create(instance.ParentType())
|
|
|
+ .Query(
|
|
|
+ Filter.Create<Entity>(instance.ParentType(), x => x.ID).IsEqualTo(row.Get<DigitalFormDockModel, Guid>(x => x.ParentID)),
|
|
|
+ entityColumns).ToObjects(instance.ParentType()).FirstOrDefault();
|
|
|
+ if (entityObj is not Entity entity)
|
|
|
+ {
|
|
|
+ MessageBox.Show($"Attached {instance.ParentType().Name} does not exist!");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ #region Selecting Scope
|
|
|
+
|
|
|
+ // JobScopes obviously can't have an empty ID, so it's fine that I turn null into Guid.Empty here.
|
|
|
+ var scopeID = JobScopeForms.GetJobScopeID(formType, instance, entity) ?? Guid.Empty;
|
|
|
+ if(scopeID == Guid.Empty)
|
|
|
+ {
|
|
|
+ // JobScopes can't have an empty job, so it's fine that I turn null into Guid.Empty here.
|
|
|
+ var jobID = JobScopeForms.GetJobID(formType, instance, entity) ?? Guid.Empty;
|
|
|
+ if(jobID == Guid.Empty)
|
|
|
+ {
|
|
|
+ var jobs = new MultiSelectDialog<Job>(null, null, multiselect: false);
|
|
|
+ if(!jobs.ShowDialog("Select a job"))
|
|
|
+ {
|
|
|
+ MessageBox.Show("No job selected; process cancelled.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ jobID = jobs.IDs().First();
|
|
|
+ }
|
|
|
+
|
|
|
+ var scopes = new MultiSelectDialog<JobScope>(new Filter<JobScope>(x => x.Job.ID).IsEqualTo(jobID), null, multiselect: false);
|
|
|
+ if (!scopes.ShowDialog("Select a scope"))
|
|
|
+ {
|
|
|
+ MessageBox.Show("Process cancelled.");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ scopeID = scopes.IDs().First();
|
|
|
+ }
|
|
|
+
|
|
|
+ var scopeTask = Task.Run(() => Client.QueryMultiple(
|
|
|
+ new KeyedQueryDef<JobScope>(
|
|
|
+ new Filter<JobScope>(x => x.ID).IsEqualTo(scopeID),
|
|
|
+ new Columns<JobScope>(x => x.ID).Add(x => x.Number)),
|
|
|
+ new KeyedQueryDef<Job>(
|
|
|
+ new Filter<Job>(x => x.ID).InQuery(new Filter<JobScope>(x => x.ID).IsEqualTo(scopeID), x => x.Job.ID),
|
|
|
+ new Columns<Job>(x => x.JobNumber))));
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region Selecting Report
|
|
|
+
|
|
|
+ var reports = new List<ReportTemplate>();
|
|
|
+ Progress.ShowModal("Loading Document", (progress) =>
|
|
|
+ {
|
|
|
+ reports = ReportUtils.LoadReports(formID.ToString(), model).ToList();
|
|
|
+ });
|
|
|
+
|
|
|
+ ReportTemplate report;
|
|
|
+ if (reports.Count == 0)
|
|
|
+ {
|
|
|
+ ReportTemplate reportTemplate = null!;
|
|
|
+ Progress.ShowModal("Loading form layout", (progress) =>
|
|
|
+ {
|
|
|
+ progress.Report("Loading form layout");
|
|
|
+ var layouts = Client.Query(
|
|
|
+ new Filter<DigitalFormLayout>(x => x.Form.ID).IsEqualTo(formID),
|
|
|
+ new Columns<DigitalFormLayout>(x => x.Layout)
|
|
|
+ .Add(x => x.Code)
|
|
|
+ .Add(x => x.Type)
|
|
|
+ .Add(x => x.Description))
|
|
|
+ .ToObjects<DigitalFormLayout>().ToArray();
|
|
|
+ var layout = layouts.FirstOrDefault(x => x.Type == DFLayoutType.Desktop) ?? layouts.FirstOrDefault();
|
|
|
+ if (layout is null)
|
|
|
+ {
|
|
|
+ MessageBox.Show("This form has no report or layout, so it cannot be attached to a job scope!");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ progress.Report("Generating report");
|
|
|
+
|
|
|
+ report = new ReportTemplate
|
|
|
+ {
|
|
|
+ DataModel = model.Name,
|
|
|
+ Name = layout.Description.NotWhiteSpaceOr(layout.Code),
|
|
|
+ RDL = DigitalFormUtils.GenerateReport(layout, model)?.SaveToString()
|
|
|
+ };
|
|
|
+ });
|
|
|
+ report = reportTemplate;
|
|
|
+ }
|
|
|
+ else if (reports.Count == 1)
|
|
|
+ {
|
|
|
+ report = reports[0];
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var selectedReports = new MultiSelectDialog<ReportTemplate>(
|
|
|
+ ReportUtils.GetReportFilter(formID.ToString(), model),
|
|
|
+ null,
|
|
|
+ multiselect: false);
|
|
|
+ if (!selectedReports.ShowDialog())
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ report = selectedReports.Items().First();
|
|
|
+ }
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ Document document = null!;
|
|
|
+
|
|
|
+ Progress.ShowModal("Loading Document", (progress) =>
|
|
|
+ {
|
|
|
+ progress.Report("Generating Document");
|
|
|
+
|
|
|
+ var data = ReportUtils.ReportToPDF(report, model, true);
|
|
|
+
|
|
|
+ progress.Report("Saving Document");
|
|
|
+
|
|
|
+ document = new Document
|
|
|
+ {
|
|
|
+ FileName = $"{instance.Number}: {report.Name}.pdf",
|
|
|
+ Data = data,
|
|
|
+ CRC = CoreUtils.CalculateCRC(data)
|
|
|
+ };
|
|
|
+ Client.Save(document, "");
|
|
|
+
|
|
|
+ progress.Report("Creating Job Scope Document");
|
|
|
+
|
|
|
+ var jobScopeDocument = new JobScopeDocument();
|
|
|
+ jobScopeDocument.DocumentLink.ID = document.ID;
|
|
|
+ jobScopeDocument.EntityLink.ID = scopeID;
|
|
|
+ Client.Save(jobScopeDocument, $"Generated from form: {instance.Number}");
|
|
|
+ });
|
|
|
+
|
|
|
+ scopeTask.Wait();
|
|
|
+ var scopeResults = scopeTask.Result;
|
|
|
+ var scope = scopeResults.GetObjects<JobScope>().First();
|
|
|
+ var job = scopeResults.GetObjects<Job>().First();
|
|
|
+
|
|
|
+ MessageBox.Show($"Attached as '{document.FileName}' to job scope {scope.Number} for job {job.JobNumber}");
|
|
|
+ }*/
|
|
|
+
|
|
|
private DynamicMenuStatus MenuStatus(CoreRow row)
|
|
|
{
|
|
|
if (row == null) return DynamicMenuStatus.Hidden;
|
|
@@ -281,6 +545,7 @@ namespace PRSDesktop
|
|
|
|
|
|
var cols = Columns.Create<IDigitalFormInstance>(type)
|
|
|
.Add<IDigitalFormInstance>(c => c.ID)
|
|
|
+ .Add<IDigitalFormInstance>(c => c.Parent.ID)
|
|
|
.Add<IDigitalFormInstance>(c => c.Form.ID)
|
|
|
.Add<IDigitalFormInstance>(c => c.Number)
|
|
|
.Add<IDigitalFormInstance>(c => c.Form.Description)
|