1- // <copyright>
1+ // <copyright>
22// Copyright by the Spark Development Network
33//
44// Licensed under the Rock Community License (the "License");
1717using System ;
1818using System . Linq ;
1919
20+ using Rock . Model . Event . RegistrationTemplate . Options ;
21+
2022namespace Rock . Model
2123{
2224 /// <summary>
@@ -53,22 +55,57 @@ internal RegistrantEligibilityEvaluator( RegistrationTemplate registrationTempla
5355 }
5456
5557 /// <summary>
56- /// Determines whether the specified registrant meets the eligibility criteria defined by the current settings.
58+ /// Determines whether the specified registrant meets the eligibility criteria defined by
59+ /// the current settings using <see cref="RegistrantEligibilityEvaluationMode.Strict"/> mode.
5760 /// </summary>
5861 /// <param name="registrantPerson">The person to evaluate for eligibility. Returns <see langword="false"/> if <see langword="null"/>.</param>
5962 /// <returns><see langword="true"/> if the registrant meets all eligibility requirements; otherwise, <see langword="false"/>.</returns>
6063 public bool Evaluate ( Person registrantPerson )
6164 {
62- return Evaluate ( registrantPerson , out var _ ) ;
65+ return Evaluate ( registrantPerson , options : null , out var _ ) ;
6366 }
6467
6568 /// <summary>
66- /// Determines whether the specified registrant meets the eligibility criteria defined by the current settings.
69+ /// Determines whether the specified registrant meets the eligibility criteria defined by
70+ /// the current settings using <see cref="RegistrantEligibilityEvaluationMode.Strict"/> mode.
6771 /// </summary>
6872 /// <param name="registrantPerson">The person to evaluate for eligibility. Returns <see langword="false"/> if <see langword="null"/>.</param>
6973 /// <param name="error">The first friendly error explaining why the person is not eligible.</param>
7074 /// <returns><see langword="true"/> if the registrant meets all eligibility requirements; otherwise, <see langword="false"/>.</returns>
7175 public bool Evaluate ( Person registrantPerson , out string error )
76+ {
77+ return Evaluate ( registrantPerson , options : null , out error ) ;
78+ }
79+
80+ /// <summary>
81+ /// Determines whether the specified registrant meets the eligibility criteria defined by
82+ /// the current settings, using the supplied <paramref name="options"/> to control how
83+ /// missing-data scenarios are handled.
84+ /// </summary>
85+ /// <param name="registrantPerson">The person to evaluate for eligibility. Returns <see langword="false"/> if <see langword="null"/>.</param>
86+ /// <param name="options">
87+ /// Options that control how the evaluator treats missing data on the person. If
88+ /// <see langword="null"/>, defaults to <see cref="RegistrantEligibilityEvaluationMode.Strict"/>.
89+ /// </param>
90+ /// <returns><see langword="true"/> if the registrant meets all eligibility requirements; otherwise, <see langword="false"/>.</returns>
91+ public bool Evaluate ( Person registrantPerson , RegistrantEligibilityEvaluationOptions options )
92+ {
93+ return Evaluate ( registrantPerson , options , out var _ ) ;
94+ }
95+
96+ /// <summary>
97+ /// Determines whether the specified registrant meets the eligibility criteria defined by
98+ /// the current settings, using the supplied <paramref name="options"/> to control how
99+ /// missing-data scenarios are handled.
100+ /// </summary>
101+ /// <param name="registrantPerson">The person to evaluate for eligibility. Returns <see langword="false"/> if <see langword="null"/>.</param>
102+ /// <param name="options">
103+ /// Options that control how the evaluator treats missing data on the person. If
104+ /// <see langword="null"/>, defaults to <see cref="RegistrantEligibilityEvaluationMode.Strict"/>.
105+ /// </param>
106+ /// <param name="error">The first friendly error explaining why the person is not eligible.</param>
107+ /// <returns><see langword="true"/> if the registrant meets all eligibility requirements; otherwise, <see langword="false"/>.</returns>
108+ public bool Evaluate ( Person registrantPerson , RegistrantEligibilityEvaluationOptions options , out string error )
72109 {
73110 error = null ;
74111
@@ -86,18 +123,25 @@ public bool Evaluate( Person registrantPerson, out string error )
86123 return true ;
87124 }
88125
126+ // Resolve the evaluation mode. A null options instance falls back to the default
127+ // (Strict), preserving the behavior of the parameterless Evaluate overloads.
128+ var evaluationMode = ( options ?? new RegistrantEligibilityEvaluationOptions ( ) ) . Mode ;
129+
89130 // Minimum Age
90131 if ( _registrantEligibilitySettings . MinimumAge . HasValue )
91132 {
92133 var minAgeError = $ "{ registrantPerson . FullName } does not meet the minimum age requirement for this { _registrationTemplate . RegistrationTerm } ({ _registrantEligibilitySettings . MinimumAge . Value } years old or older).";
93134
94135 if ( ! registrantPerson . Age . HasValue )
95136 {
96- error = minAgeError ;
97- return false ;
137+ // Age is required to evaluate this rule. Strict mode rejects, Lax mode skips.
138+ if ( evaluationMode == RegistrantEligibilityEvaluationMode . Strict )
139+ {
140+ error = minAgeError ;
141+ return false ;
142+ }
98143 }
99-
100- if ( registrantPerson . Age . Value < _registrantEligibilitySettings . MinimumAge . Value )
144+ else if ( registrantPerson . Age . Value < _registrantEligibilitySettings . MinimumAge . Value )
101145 {
102146 error = minAgeError ;
103147 return false ;
@@ -107,16 +151,19 @@ public bool Evaluate( Person registrantPerson, out string error )
107151 // Maximum Age
108152 if ( _registrantEligibilitySettings . MaximumAge . HasValue )
109153 {
110- var isMaxAgeInteger = _registrantEligibilitySettings . MaximumAge . Value . IsInteger ( ) ;
154+ var isMaxAgeAnInteger = _registrantEligibilitySettings . MaximumAge . Value . IsInteger ( ) ;
111155 var maxAgeError = $ "{ registrantPerson . FullName } does not meet the maximum age requirement for this { _registrationTemplate . RegistrationTerm } ({ _registrantEligibilitySettings . MaximumAge . Value } years old or younger).";
112156
113157 if ( ! registrantPerson . Age . HasValue )
114158 {
115- error = maxAgeError ;
116- return false ;
159+ // Age is required to evaluate this rule. Strict mode rejects, Lax mode skips.
160+ if ( evaluationMode == RegistrantEligibilityEvaluationMode . Strict )
161+ {
162+ error = maxAgeError ;
163+ return false ;
164+ }
117165 }
118-
119- if ( isMaxAgeInteger )
166+ else if ( isMaxAgeAnInteger )
120167 {
121168 // If max age is an integer number of years old, then treat it as "up to and including that age".
122169 // So if max age is 18, then a registrant who is 18 years and 11 months old would still be eligible,
@@ -139,13 +186,13 @@ public bool Evaluate( Person registrantPerson, out string error )
139186 }
140187 }
141188 }
142-
189+
143190 // Age Classification
144191 if ( _registrantEligibilitySettings . AgeClassification . HasValue )
145192 {
146193 // Typically age classification is set in the person save hook,
147194 // but that won't run until a running transaction is committed.
148- // Resolve it here so we can determine registrant eligibility when a new person is created for a registration.
195+ // Resolve it here using the same logic so we can determine registrant eligibility when a new person is created for a registration.
149196 var resolvedAgeClassification = registrantPerson . AgeClassification ;
150197 if ( resolvedAgeClassification == AgeClassification . Unknown && registrantPerson . Age . HasValue )
151198 {
@@ -159,9 +206,21 @@ public bool Evaluate( Person registrantPerson, out string error )
159206 }
160207 }
161208
162- if ( resolvedAgeClassification != _registrantEligibilitySettings . AgeClassification . Value )
209+ var ageClassificationError = $ "{ registrantPerson . FullName } does not meet the age requirement for this { _registrationTemplate . RegistrationTerm } ({ _registrantEligibilitySettings . AgeClassification . GetDisplayName ( ) } ).";
210+
211+ if ( resolvedAgeClassification == AgeClassification . Unknown )
163212 {
164- error = $ "{ registrantPerson . FullName } does not meet the age requirement for this { _registrationTemplate . RegistrationTerm } ({ _registrantEligibilitySettings . AgeClassification . GetDisplayName ( ) } ).";
213+ // Age classification could not be determined (no explicit value and no age to derive it).
214+ // Strict mode rejects, Lax mode skips this rule.
215+ if ( evaluationMode == RegistrantEligibilityEvaluationMode . Strict )
216+ {
217+ error = ageClassificationError ;
218+ return false ;
219+ }
220+ }
221+ else if ( resolvedAgeClassification != _registrantEligibilitySettings . AgeClassification . Value )
222+ {
223+ error = ageClassificationError ;
165224 return false ;
166225 }
167226 }
@@ -170,14 +229,17 @@ public bool Evaluate( Person registrantPerson, out string error )
170229 if ( _registrantEligibilitySettings . MaximumGradeOffset . HasValue )
171230 {
172231 var minGradeError = $ "{ registrantPerson . FullName } does not meet the minimum grade requirement for this { _registrationTemplate . RegistrationTerm } .";
173-
232+
174233 if ( ! registrantPerson . GradeOffset . HasValue )
175234 {
176- error = minGradeError ;
177- return false ;
235+ // Grade is required to evaluate this rule. Strict mode rejects, Lax mode skips.
236+ if ( evaluationMode == RegistrantEligibilityEvaluationMode . Strict )
237+ {
238+ error = minGradeError ;
239+ return false ;
240+ }
178241 }
179-
180- if ( registrantPerson . GradeOffset . Value > _registrantEligibilitySettings . MaximumGradeOffset . Value )
242+ else if ( registrantPerson . GradeOffset . Value > _registrantEligibilitySettings . MaximumGradeOffset . Value )
181243 {
182244 error = minGradeError ;
183245 return false ;
@@ -188,14 +250,17 @@ public bool Evaluate( Person registrantPerson, out string error )
188250 if ( _registrantEligibilitySettings . MinimumGradeOffset . HasValue )
189251 {
190252 var maxGradeError = $ "{ registrantPerson . FullName } does not meet the maximum grade requirement for this { _registrationTemplate . RegistrationTerm } .";
191-
253+
192254 if ( ! registrantPerson . GradeOffset . HasValue )
193255 {
194- error = maxGradeError ;
195- return false ;
256+ // Grade is required to evaluate this rule. Strict mode rejects, Lax mode skips.
257+ if ( evaluationMode == RegistrantEligibilityEvaluationMode . Strict )
258+ {
259+ error = maxGradeError ;
260+ return false ;
261+ }
196262 }
197-
198- if ( registrantPerson . GradeOffset . Value < _registrantEligibilitySettings . MinimumGradeOffset . Value )
263+ else if ( registrantPerson . GradeOffset . Value < _registrantEligibilitySettings . MinimumGradeOffset . Value )
199264 {
200265 error = maxGradeError ;
201266 return false ;
@@ -205,14 +270,27 @@ public bool Evaluate( Person registrantPerson, out string error )
205270 // Gender
206271 if ( _registrantEligibilitySettings . Gender . HasValue )
207272 {
208- if ( registrantPerson . Gender != _registrantEligibilitySettings . Gender . Value )
273+ var genderError = $ "{ registrantPerson . FullName } does not meet the gender requirement for this { _registrationTemplate . RegistrationTerm } ({ _registrantEligibilitySettings . Gender . Value . GetDisplayName ( ) } ).";
274+
275+ if ( registrantPerson . Gender == Gender . Unknown )
276+ {
277+ // Gender is required to evaluate this rule. Strict mode rejects, Lax mode skips.
278+ if ( evaluationMode == RegistrantEligibilityEvaluationMode . Strict )
279+ {
280+ error = genderError ;
281+ return false ;
282+ }
283+ }
284+ else if ( registrantPerson . Gender != _registrantEligibilitySettings . Gender . Value )
209285 {
210- error = $ " { registrantPerson . FullName } does not meet the gender requirement for this { _registrationTemplate . RegistrationTerm } ( { _registrantEligibilitySettings . Gender . Value . GetDisplayName ( ) } )." ;
286+ error = genderError ;
211287 return false ;
212288 }
213289 }
214290
215291 // Data View
292+ // The Data View check is based on concrete membership in a configured query rather than
293+ // missing-data semantics, so it is enforced regardless of the evaluation mode.
216294 if ( _eligibleDataViewPersonQuery != null )
217295 {
218296 if ( ! _eligibleDataViewPersonQuery . Any ( p => p . Id == registrantPerson . Id ) )
0 commit comments