-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathStartScenarioRequest.cs
More file actions
165 lines (138 loc) · 6.48 KB
/
Copy pathStartScenarioRequest.cs
File metadata and controls
165 lines (138 loc) · 6.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
using System.ComponentModel.DataAnnotations;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Automation.UI.Models;
public class StartScenarioRequest : IValidatableObject
{
public Guid? ScenarioId { get; set; }
[Required]
public AutomationScenarioKind Scenario { get; set; }
/// <summary>
/// How the report is triggered: Adhoc, ScheduledReport, or RegenerateReport.
/// </summary>
public ReportMethod ReportMethod { get; set; } = ReportMethod.Adhoc;
// Zero is permitted: a scenario with imported patients only (no cohorts) generates
// nothing and relies entirely on the imported-patient list. The run will fail
// separately if neither generated nor imported patients are configured.
[Range(0, 10000)]
public int? PatientCount { get; set; }
[Range(1, int.MaxValue)]
public int? ResourcesPerPatient { get; set; }
[Range(1, int.MaxValue)]
public int? Seed { get; set; }
[StringLength(120)]
public string? ScenarioName { get; set; }
public string? RunConfigurationJson { get; set; }
/// <summary>
/// Remove facility config, soft-delete reports, DA logs, and query dispatch config after the run.
/// </summary>
public bool? CleanupServiceData { get; set; }
/// <summary>
/// Expunge all data from the FHIR server after the run.
/// </summary>
public bool? CleanupFhirData { get; set; }
/// <summary>
/// Measures selected for this run. When multiple measures are selected, the report
/// is generated with all of them as report types, and qualifying patients must
/// qualify for every selected measure.
/// </summary>
public List<ProfiledMeasureType> SelectedMeasures { get; set; } = [];
public List<PatientCohortDefinition>? PatientCohorts { get; set; }
/// <summary>
/// Patients to fetch from the FHIR server by ID and include alongside the generated pool.
/// </summary>
public List<ImportedPatientInput>? ImportedPatientIds { get; set; }
/// <summary>
/// Patients supplied as FHIR transaction bundles (one bundle per patient).
/// </summary>
public List<ImportedPatientInput>? ImportedPatientBundles { get; set; }
/// <summary>
/// Reporting period start (UTC). When null, the system default is used.
/// </summary>
public DateTimeOffset? ReportPeriodStart { get; set; }
/// <summary>
/// Reporting period end (UTC). When null, the system default is used.
/// </summary>
public DateTimeOffset? ReportPeriodEnd { get; set; }
/// <summary>
/// Configured NHSN reporting Organization ID for this run.
/// </summary>
public string? NhsnOrganizationId { get; set; }
/// <summary>
/// Optional query plan template ID. When set, the run uses this template's
/// query plan instead of the built-in defaults. When null, the system default is used.
/// </summary>
public Guid? QueryPlanTemplateId { get; set; }
/// <summary>
/// Optional normalization suite ID. When set, the run uses this suite's
/// operations for normalization configuration. When null, the system default suite is used.
/// </summary>
public Guid? NormalizationSuiteId { get; set; }
/// <summary>
/// Optional organization-resource-map template ID. When set, the run uses this
/// template's DataAcquisition organization-location mapping conditions.
/// When null, the system default template is used.
/// </summary>
public Guid? OrganizationResourceMapTemplateId { get; set; }
/// <summary>
/// When true, a ScheduledReport run holds a short live window and accepts
/// Admit/Discharge injections before finalizing the report.
/// </summary>
public bool IsLiveSimulation { get; set; }
/// <summary>Live reporting window length in minutes (typically 5, 10, or 15).</summary>
[Range(1, 60)]
public int? ReportingWindowMinutes { get; set; }
/// <summary>Optional number of generated patients to admit when the live window opens.</summary>
[Range(0, 10000)]
public int? SeedPatientCount { get; set; }
/// <summary>
/// Cross-field validation. Rejects inverted report windows
/// (<see cref="ReportPeriodStart"/> > <see cref="ReportPeriodEnd"/>) at the request
/// boundary so that invalid windows are never forwarded to
/// <c>StartScenarioRequestResolver</c> or downstream pipeline stages.
/// </summary>
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (ReportPeriodStart.HasValue && ReportPeriodEnd.HasValue
&& ReportPeriodStart.Value > ReportPeriodEnd.Value)
{
yield return new ValidationResult(
"ReportPeriodStart must be on or before ReportPeriodEnd.",
new[] { nameof(ReportPeriodStart), nameof(ReportPeriodEnd) });
}
}
public static StartScenarioRequest FromScenario(TestScenarioDefinition scenario) => new()
{
Scenario = AutomationScenarioKind.Custom,
ScenarioName = scenario.Name,
RunConfigurationJson = SerializeScenarioConfiguration(scenario),
ReportMethod = scenario.ReportMethod,
Seed = scenario.Seed,
PatientCount = scenario.PatientCount,
CleanupServiceData = scenario.CleanupServiceData,
CleanupFhirData = scenario.CleanupFhirData,
SelectedMeasures = scenario.SelectedMeasures,
PatientCohorts = scenario.PatientCohorts,
ImportedPatientIds = scenario.ImportedPatientIds,
ImportedPatientBundles = scenario.ImportedPatientBundles,
ReportPeriodStart = scenario.ReportPeriodStart,
ReportPeriodEnd = scenario.ReportPeriodEnd,
NhsnOrganizationId = scenario.NhsnOrganizationId,
QueryPlanTemplateId = scenario.QueryPlanTemplateId,
NormalizationSuiteId = scenario.NormalizationSuiteId,
OrganizationResourceMapTemplateId = scenario.OrganizationResourceMapTemplateId,
IsLiveSimulation = scenario.IsLiveSimulation,
ReportingWindowMinutes = scenario.ReportingWindowMinutes,
SeedPatientCount = scenario.SeedPatientCount,
};
private static string SerializeScenarioConfiguration(TestScenarioDefinition scenario)
{
var options = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
};
options.Converters.Add(new JsonStringEnumConverter());
return JsonSerializer.Serialize(scenario, options);
}
}