Completed
Branch FET/11258/context-interface (f32e25)
by
unknown
117:29 queued 106:27
created
core/services/context/ContextChecker.php 2 patches
Indentation   +143 added lines, -143 removed lines patch added patch discarded remove patch
@@ -22,148 +22,148 @@
 block discarded – undo
22 22
 class ContextChecker
23 23
 {
24 24
 
25
-    /**
26
-     * A unique string used to identify where this ContextChecker is being employed
27
-     * Is currently only used within the hook name for the filterable return value of isAllowed().
28
-     *
29
-     * @var string $identifier
30
-     */
31
-    private $identifier;
32
-
33
-    /**
34
-     * A list of values to be compared against the slug of the Context class passed to isAllowed()
35
-     *
36
-     * @var array $acceptable_values
37
-     */
38
-    private $acceptable_values;
39
-
40
-    /**
41
-     * Closure that will be called to perform the evaluation within isAllowed().
42
-     * If none is provided, then a simple type sensitive in_array() check will be used
43
-     * and return true if the incoming Context::slug() is found within the array of $acceptable_values.
44
-     *
45
-     * @var Closure $evaluation_callback
46
-     */
47
-    private $evaluation_callback;
48
-
49
-
50
-    /**
51
-     * ContextChecker constructor.
52
-     *
53
-     * @param string       $identifier
54
-     * @param array        $acceptable_values
55
-     * @param Closure|null $evaluation_callback [optional]
56
-     */
57
-    public function __construct($identifier, array $acceptable_values, Closure $evaluation_callback = null)
58
-    {
59
-        $this->setIdentifier($identifier);
60
-        $this->setAcceptableValues($acceptable_values);
61
-        $this->setEvaluationCallback($evaluation_callback);
62
-    }
63
-
64
-
65
-    /**
66
-     * @param string $identifier
67
-     */
68
-    private function setIdentifier($identifier)
69
-    {
70
-        $this->identifier = sanitize_key($identifier);
71
-    }
72
-
73
-
74
-    /**
75
-     * @param array $acceptable_values
76
-     */
77
-    private function setAcceptableValues(array $acceptable_values)
78
-    {
79
-        $this->acceptable_values = $acceptable_values;
80
-    }
81
-
82
-
83
-    /**
84
-     * @param Closure $evaluation_callback
85
-     */
86
-    private function setEvaluationCallback(Closure $evaluation_callback = null)
87
-    {
88
-        $this->evaluation_callback = $evaluation_callback instanceof Closure
89
-            ? $evaluation_callback
90
-            : function (ContextInterface $context, $acceptable_values) {
91
-                return in_array($context->slug(), $acceptable_values, true);
92
-            };
93
-    }
94
-
95
-
96
-    /**
97
-     * @return string
98
-     */
99
-    protected function identifier()
100
-    {
101
-        return $this->identifier;
102
-    }
103
-
104
-
105
-    /**
106
-     * @return array
107
-     */
108
-    protected function acceptableValues()
109
-    {
110
-        return apply_filters(
111
-            "FHEE__EventEspresso_core_domain_entities_context_ContextChecker__{$this->identifier}__acceptableValues",
112
-            $this->acceptable_values
113
-        );
114
-    }
115
-
116
-
117
-    /**
118
-     * @return Closure
119
-     */
120
-    protected function evaluationCallback()
121
-    {
122
-        return $this->evaluation_callback;
123
-    }
124
-
125
-
126
-
127
-    /**
128
-     * Returns true if the incoming Context class slug matches one of the preset acceptable values.
129
-     * The result is filterable using the identifier for this ContextChecker.
130
-     * example:
131
-     * If this ContextChecker's $identifier was set to "registration-checkout-type",
132
-     * then the filter here would be named:
133
-     *  "FHEE__EventEspresso_core_domain_entities_context_ContextChecker__registration-checkout-type__isAllowed".
134
-     * Other code could hook into the filter in isAllowed() using the above name
135
-     * and test for additional acceptable values.
136
-     * So if the set of $acceptable_values was: [ "initial-visit",  "revisit" ]
137
-     * then adding a filter to
138
-     *  "FHEE__EventEspresso_core_domain_entities_context_ContextChecker__registration-checkout-type__isAllowed",
139
-     * would allow you to perform your own conditional and allow "wait-list-checkout" as an acceptable value.
140
-     *  example:
141
-     *      add_filter(
142
-     *          'FHEE__EventEspresso_core_domain_entities_context_ContextChecker__registration-checkout-type__isAllowed',
143
-     *          function ($is_allowed, ContextInterface $context) {
144
-     *              return $context->slug() === 'wait-list-checkout'
145
-     *                  ? true
146
-     *                  : $is_allowed;
147
-     *          },
148
-     *          10,
149
-     *          2
150
-     *      );
151
-     *
152
-     * @param ContextInterface $context
153
-     * @return boolean
154
-     */
155
-    public function isAllowed(ContextInterface $context)
156
-    {
157
-        $evaluation_callback = $this->evaluationCallback();
158
-        return filter_var(
159
-            apply_filters(
160
-                "FHEE__EventEspresso_core_domain_entities_context_ContextChecker__{$this->identifier}__isAllowed",
161
-                $evaluation_callback($context, $this->acceptableValues()),
162
-                $context,
163
-                $this
164
-            ),
165
-            FILTER_VALIDATE_BOOLEAN
166
-        );
167
-    }
25
+	/**
26
+	 * A unique string used to identify where this ContextChecker is being employed
27
+	 * Is currently only used within the hook name for the filterable return value of isAllowed().
28
+	 *
29
+	 * @var string $identifier
30
+	 */
31
+	private $identifier;
32
+
33
+	/**
34
+	 * A list of values to be compared against the slug of the Context class passed to isAllowed()
35
+	 *
36
+	 * @var array $acceptable_values
37
+	 */
38
+	private $acceptable_values;
39
+
40
+	/**
41
+	 * Closure that will be called to perform the evaluation within isAllowed().
42
+	 * If none is provided, then a simple type sensitive in_array() check will be used
43
+	 * and return true if the incoming Context::slug() is found within the array of $acceptable_values.
44
+	 *
45
+	 * @var Closure $evaluation_callback
46
+	 */
47
+	private $evaluation_callback;
48
+
49
+
50
+	/**
51
+	 * ContextChecker constructor.
52
+	 *
53
+	 * @param string       $identifier
54
+	 * @param array        $acceptable_values
55
+	 * @param Closure|null $evaluation_callback [optional]
56
+	 */
57
+	public function __construct($identifier, array $acceptable_values, Closure $evaluation_callback = null)
58
+	{
59
+		$this->setIdentifier($identifier);
60
+		$this->setAcceptableValues($acceptable_values);
61
+		$this->setEvaluationCallback($evaluation_callback);
62
+	}
63
+
64
+
65
+	/**
66
+	 * @param string $identifier
67
+	 */
68
+	private function setIdentifier($identifier)
69
+	{
70
+		$this->identifier = sanitize_key($identifier);
71
+	}
72
+
73
+
74
+	/**
75
+	 * @param array $acceptable_values
76
+	 */
77
+	private function setAcceptableValues(array $acceptable_values)
78
+	{
79
+		$this->acceptable_values = $acceptable_values;
80
+	}
81
+
82
+
83
+	/**
84
+	 * @param Closure $evaluation_callback
85
+	 */
86
+	private function setEvaluationCallback(Closure $evaluation_callback = null)
87
+	{
88
+		$this->evaluation_callback = $evaluation_callback instanceof Closure
89
+			? $evaluation_callback
90
+			: function (ContextInterface $context, $acceptable_values) {
91
+				return in_array($context->slug(), $acceptable_values, true);
92
+			};
93
+	}
94
+
95
+
96
+	/**
97
+	 * @return string
98
+	 */
99
+	protected function identifier()
100
+	{
101
+		return $this->identifier;
102
+	}
103
+
104
+
105
+	/**
106
+	 * @return array
107
+	 */
108
+	protected function acceptableValues()
109
+	{
110
+		return apply_filters(
111
+			"FHEE__EventEspresso_core_domain_entities_context_ContextChecker__{$this->identifier}__acceptableValues",
112
+			$this->acceptable_values
113
+		);
114
+	}
115
+
116
+
117
+	/**
118
+	 * @return Closure
119
+	 */
120
+	protected function evaluationCallback()
121
+	{
122
+		return $this->evaluation_callback;
123
+	}
124
+
125
+
126
+
127
+	/**
128
+	 * Returns true if the incoming Context class slug matches one of the preset acceptable values.
129
+	 * The result is filterable using the identifier for this ContextChecker.
130
+	 * example:
131
+	 * If this ContextChecker's $identifier was set to "registration-checkout-type",
132
+	 * then the filter here would be named:
133
+	 *  "FHEE__EventEspresso_core_domain_entities_context_ContextChecker__registration-checkout-type__isAllowed".
134
+	 * Other code could hook into the filter in isAllowed() using the above name
135
+	 * and test for additional acceptable values.
136
+	 * So if the set of $acceptable_values was: [ "initial-visit",  "revisit" ]
137
+	 * then adding a filter to
138
+	 *  "FHEE__EventEspresso_core_domain_entities_context_ContextChecker__registration-checkout-type__isAllowed",
139
+	 * would allow you to perform your own conditional and allow "wait-list-checkout" as an acceptable value.
140
+	 *  example:
141
+	 *      add_filter(
142
+	 *          'FHEE__EventEspresso_core_domain_entities_context_ContextChecker__registration-checkout-type__isAllowed',
143
+	 *          function ($is_allowed, ContextInterface $context) {
144
+	 *              return $context->slug() === 'wait-list-checkout'
145
+	 *                  ? true
146
+	 *                  : $is_allowed;
147
+	 *          },
148
+	 *          10,
149
+	 *          2
150
+	 *      );
151
+	 *
152
+	 * @param ContextInterface $context
153
+	 * @return boolean
154
+	 */
155
+	public function isAllowed(ContextInterface $context)
156
+	{
157
+		$evaluation_callback = $this->evaluationCallback();
158
+		return filter_var(
159
+			apply_filters(
160
+				"FHEE__EventEspresso_core_domain_entities_context_ContextChecker__{$this->identifier}__isAllowed",
161
+				$evaluation_callback($context, $this->acceptableValues()),
162
+				$context,
163
+				$this
164
+			),
165
+			FILTER_VALIDATE_BOOLEAN
166
+		);
167
+	}
168 168
 
169 169
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -87,7 +87,7 @@
 block discarded – undo
87 87
     {
88 88
         $this->evaluation_callback = $evaluation_callback instanceof Closure
89 89
             ? $evaluation_callback
90
-            : function (ContextInterface $context, $acceptable_values) {
90
+            : function(ContextInterface $context, $acceptable_values) {
91 91
                 return in_array($context->slug(), $acceptable_values, true);
92 92
             };
93 93
     }
Please login to merge, or discard this patch.
core/db_classes/EE_Registration.class.php 1 patch
Indentation   +1979 added lines, -1979 removed lines patch added patch discarded remove patch
@@ -18,1985 +18,1985 @@
 block discarded – undo
18 18
 {
19 19
 
20 20
 
21
-    /**
22
-     * Used to reference when a registration has never been checked in.
23
-     *
24
-     * @deprecated use \EE_Checkin::status_checked_never instead
25
-     * @type int
26
-     */
27
-    const checkin_status_never = 2;
28
-
29
-    /**
30
-     * Used to reference when a registration has been checked in.
31
-     *
32
-     * @deprecated use \EE_Checkin::status_checked_in instead
33
-     * @type int
34
-     */
35
-    const checkin_status_in = 1;
36
-
37
-
38
-    /**
39
-     * Used to reference when a registration has been checked out.
40
-     *
41
-     * @deprecated use \EE_Checkin::status_checked_out instead
42
-     * @type int
43
-     */
44
-    const checkin_status_out = 0;
45
-
46
-
47
-    /**
48
-     * extra meta key for tracking reg status os trashed registrations
49
-     *
50
-     * @type string
51
-     */
52
-    const PRE_TRASH_REG_STATUS_KEY = 'pre_trash_registration_status';
53
-
54
-
55
-    /**
56
-     * extra meta key for tracking if registration has reserved ticket
57
-     *
58
-     * @type string
59
-     */
60
-    const HAS_RESERVED_TICKET_KEY = 'has_reserved_ticket';
61
-
62
-
63
-    /**
64
-     * @param array  $props_n_values          incoming values
65
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
66
-     *                                        used.)
67
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
68
-     *                                        date_format and the second value is the time format
69
-     * @return EE_Registration
70
-     * @throws EE_Error
71
-     */
72
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
73
-    {
74
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
75
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
76
-    }
77
-
78
-
79
-    /**
80
-     * @param array  $props_n_values  incoming values from the database
81
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
82
-     *                                the website will be used.
83
-     * @return EE_Registration
84
-     */
85
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
86
-    {
87
-        return new self($props_n_values, true, $timezone);
88
-    }
89
-
90
-
91
-    /**
92
-     *        Set Event ID
93
-     *
94
-     * @param        int $EVT_ID Event ID
95
-     * @throws EE_Error
96
-     * @throws RuntimeException
97
-     */
98
-    public function set_event($EVT_ID = 0)
99
-    {
100
-        $this->set('EVT_ID', $EVT_ID);
101
-    }
102
-
103
-
104
-    /**
105
-     * Overrides parent set() method so that all calls to set( 'REG_code', $REG_code ) OR set( 'STS_ID', $STS_ID ) can
106
-     * be routed to internal methods
107
-     *
108
-     * @param string $field_name
109
-     * @param mixed  $field_value
110
-     * @param bool   $use_default
111
-     * @throws EE_Error
112
-     * @throws EntityNotFoundException
113
-     * @throws InvalidArgumentException
114
-     * @throws InvalidDataTypeException
115
-     * @throws InvalidInterfaceException
116
-     * @throws ReflectionException
117
-     * @throws RuntimeException
118
-     */
119
-    public function set($field_name, $field_value, $use_default = false)
120
-    {
121
-        switch ($field_name) {
122
-            case 'REG_code':
123
-                if (! empty($field_value) && $this->reg_code() === null) {
124
-                    $this->set_reg_code($field_value, $use_default);
125
-                }
126
-                break;
127
-            case 'STS_ID':
128
-                $this->set_status($field_value, $use_default);
129
-                break;
130
-            default:
131
-                parent::set($field_name, $field_value, $use_default);
132
-        }
133
-    }
134
-
135
-
136
-    /**
137
-     * Set Status ID
138
-     * updates the registration status and ALSO...
139
-     * calls reserve_registration_space() if the reg status changes TO approved from any other reg status
140
-     * calls release_registration_space() if the reg status changes FROM approved to any other reg status
141
-     *
142
-     * @param string       $new_STS_ID
143
-     * @param boolean      $use_default
144
-     * @param ContextInterface|null $context
145
-     * @return bool
146
-     * @throws EE_Error
147
-     * @throws EntityNotFoundException
148
-     * @throws InvalidArgumentException
149
-     * @throws ReflectionException
150
-     * @throws RuntimeException
151
-     * @throws InvalidDataTypeException
152
-     * @throws InvalidInterfaceException
153
-     */
154
-    public function set_status($new_STS_ID = null, $use_default = false, ContextInterface $context = null)
155
-    {
156
-        // get current REG_Status
157
-        $old_STS_ID = $this->status_ID();
158
-        // if status has changed
159
-        if ($old_STS_ID !== $new_STS_ID // and that status has actually changed
160
-            && ! empty($old_STS_ID) // and that old status is actually set
161
-            && ! empty($new_STS_ID) // as well as the new status
162
-            && $this->ID() // ensure registration is in the db
163
-        ) {
164
-            // TO approved
165
-            if ($new_STS_ID === EEM_Registration::status_id_approved) {
166
-                // reserve a space by incrementing ticket and datetime sold values
167
-                $this->_reserve_registration_space();
168
-                do_action('AHEE__EE_Registration__set_status__to_approved', $this, $old_STS_ID, $new_STS_ID, $context);
169
-                // OR FROM  approved
170
-            } elseif ($old_STS_ID === EEM_Registration::status_id_approved) {
171
-                // release a space by decrementing ticket and datetime sold values
172
-                $this->_release_registration_space();
173
-                do_action(
174
-                    'AHEE__EE_Registration__set_status__from_approved',
175
-                    $this,
176
-                    $old_STS_ID,
177
-                    $new_STS_ID,
178
-                    $context
179
-                );
180
-            }
181
-            // update status
182
-            parent::set('STS_ID', $new_STS_ID, $use_default);
183
-            $this->_update_if_canceled_or_declined($new_STS_ID, $old_STS_ID, $context);
184
-            if($this->statusChangeUpdatesTransaction($context)) {
185
-                $this->updateTransactionAfterStatusChange();
186
-            }
187
-            do_action('AHEE__EE_Registration__set_status__after_update', $this, $old_STS_ID, $new_STS_ID, $context);
188
-            return true;
189
-        }
190
-        //even though the old value matches the new value, it's still good to
191
-        //allow the parent set method to have a say
192
-        parent::set('STS_ID', $new_STS_ID, $use_default);
193
-        return true;
194
-    }
195
-
196
-
197
-    /**
198
-     * update REGs and TXN when cancelled or declined registrations involved
199
-     *
200
-     * @param string       $new_STS_ID
201
-     * @param string       $old_STS_ID
202
-     * @param ContextInterface|null $context
203
-     * @throws EE_Error
204
-     * @throws InvalidArgumentException
205
-     * @throws InvalidDataTypeException
206
-     * @throws InvalidInterfaceException
207
-     * @throws ReflectionException
208
-     */
209
-    private function _update_if_canceled_or_declined($new_STS_ID, $old_STS_ID, ContextInterface $context = null)
210
-    {
211
-        // these reg statuses should not be considered in any calculations involving monies owing
212
-        $closed_reg_statuses = EEM_Registration::closed_reg_statuses();
213
-        // true if registration has been cancelled or declined
214
-        $this->updateIfCanceled(
215
-            $closed_reg_statuses,
216
-            $new_STS_ID,
217
-            $old_STS_ID,
218
-            $context
219
-        );
220
-        $this->updateIfDeclined(
221
-            $closed_reg_statuses,
222
-            $new_STS_ID,
223
-            $old_STS_ID,
224
-            $context
225
-        );
226
-    }
227
-
228
-
229
-    /**
230
-     * update REGs and TXN when cancelled or declined registrations involved
231
-     *
232
-     * @param array        $closed_reg_statuses
233
-     * @param string       $new_STS_ID
234
-     * @param string       $old_STS_ID
235
-     * @param ContextInterface|null $context
236
-     * @throws EE_Error
237
-     * @throws InvalidArgumentException
238
-     * @throws InvalidDataTypeException
239
-     * @throws InvalidInterfaceException
240
-     * @throws ReflectionException
241
-     */
242
-    private function updateIfCanceled(array $closed_reg_statuses, $new_STS_ID, $old_STS_ID, ContextInterface $context = null)
243
-    {
244
-        // true if registration has been cancelled or declined
245
-        if (in_array($new_STS_ID, $closed_reg_statuses, true)
246
-            && ! in_array($old_STS_ID, $closed_reg_statuses, true)
247
-        ) {
248
-            /** @type EE_Registration_Processor $registration_processor */
249
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
250
-            /** @type EE_Transaction_Processor $transaction_processor */
251
-            $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
252
-            // cancelled or declined registration
253
-            $registration_processor->update_registration_after_being_canceled_or_declined(
254
-                $this,
255
-                $closed_reg_statuses
256
-            );
257
-            $transaction_processor->update_transaction_after_canceled_or_declined_registration(
258
-                $this,
259
-                $closed_reg_statuses,
260
-                false
261
-            );
262
-            do_action(
263
-                'AHEE__EE_Registration__set_status__canceled_or_declined',
264
-                $this,
265
-                $old_STS_ID,
266
-                $new_STS_ID,
267
-                $context
268
-            );
269
-            return;
270
-        }
271
-    }
272
-
273
-
274
-    /**
275
-     * update REGs and TXN when cancelled or declined registrations involved
276
-     *
277
-     * @param array        $closed_reg_statuses
278
-     * @param string       $new_STS_ID
279
-     * @param string       $old_STS_ID
280
-     * @param ContextInterface|null $context
281
-     * @throws EE_Error
282
-     * @throws InvalidArgumentException
283
-     * @throws InvalidDataTypeException
284
-     * @throws InvalidInterfaceException
285
-     * @throws ReflectionException
286
-     */
287
-    private function updateIfDeclined(array $closed_reg_statuses, $new_STS_ID, $old_STS_ID, ContextInterface $context = null)
288
-    {
289
-        // true if reinstating cancelled or declined registration
290
-        if (in_array($old_STS_ID, $closed_reg_statuses, true)
291
-            && ! in_array($new_STS_ID, $closed_reg_statuses, true)
292
-        ) {
293
-            /** @type EE_Registration_Processor $registration_processor */
294
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
295
-            /** @type EE_Transaction_Processor $transaction_processor */
296
-            $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
297
-            // reinstating cancelled or declined registration
298
-            $registration_processor->update_canceled_or_declined_registration_after_being_reinstated(
299
-                $this,
300
-                $closed_reg_statuses
301
-            );
302
-            $transaction_processor->update_transaction_after_reinstating_canceled_registration(
303
-                $this,
304
-                $closed_reg_statuses,
305
-                false
306
-            );
307
-            do_action(
308
-                'AHEE__EE_Registration__set_status__after_reinstated',
309
-                $this,
310
-                $old_STS_ID,
311
-                $new_STS_ID,
312
-                $context
313
-            );
314
-        }
315
-    }
316
-
317
-
318
-    /**
319
-     * @param ContextInterface|null $context
320
-     * @return bool
321
-     */
322
-    private function statusChangeUpdatesTransaction(ContextInterface $context = null)
323
-    {
324
-        $contexts_that_do_not_update_transaction = (array) apply_filters(
325
-            'AHEE__EE_Registration__statusChangeUpdatesTransaction__contexts_that_do_not_update_transaction',
326
-            array('spco_reg_step_attendee_information_process_registrations'),
327
-            $context,
328
-            $this
329
-        );
330
-        return ! (
331
-            $context instanceof ContextInterface
332
-            && in_array($context->slug(), $contexts_that_do_not_update_transaction, true)
333
-        );
334
-    }
335
-
336
-
337
-    /**
338
-     * @throws EE_Error
339
-     * @throws EntityNotFoundException
340
-     * @throws InvalidArgumentException
341
-     * @throws InvalidDataTypeException
342
-     * @throws InvalidInterfaceException
343
-     * @throws ReflectionException
344
-     * @throws RuntimeException
345
-     */
346
-    private function updateTransactionAfterStatusChange()
347
-    {
348
-        /** @type EE_Transaction_Payments $transaction_payments */
349
-        $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
350
-        $transaction_payments->recalculate_transaction_total($this->transaction(), false);
351
-        $this->transaction()->update_status_based_on_total_paid(true);
352
-    }
353
-
354
-
355
-    /**
356
-     *        get Status ID
357
-     */
358
-    public function status_ID()
359
-    {
360
-        return $this->get('STS_ID');
361
-    }
362
-
363
-
364
-    /**
365
-     * increments this registration's related ticket sold and corresponding datetime sold values
366
-     *
367
-     * @return void
368
-     * @throws EE_Error
369
-     * @throws EntityNotFoundException
370
-     */
371
-    private function _reserve_registration_space()
372
-    {
373
-        // reserved ticket and datetime counts will be decremented as sold counts are incremented
374
-        // so stop tracking that this reg has a ticket reserved
375
-        $this->release_reserved_ticket();
376
-        $ticket = $this->ticket();
377
-        $ticket->increase_sold();
378
-        $ticket->save();
379
-        // possibly set event status to sold out
380
-        $this->event()->perform_sold_out_status_check();
381
-    }
382
-
383
-
384
-    /**
385
-     * Gets the ticket this registration is for
386
-     *
387
-     * @param boolean $include_archived whether to include archived tickets or not.
388
-     *
389
-     * @return EE_Ticket|EE_Base_Class
390
-     * @throws EE_Error
391
-     */
392
-    public function ticket($include_archived = true)
393
-    {
394
-        $query_params = array();
395
-        if ($include_archived) {
396
-            $query_params['default_where_conditions'] = 'none';
397
-        }
398
-        return $this->get_first_related('Ticket', $query_params);
399
-    }
400
-
401
-
402
-    /**
403
-     * Gets the event this registration is for
404
-     *
405
-     * @return EE_Event
406
-     * @throws EE_Error
407
-     * @throws EntityNotFoundException
408
-     */
409
-    public function event()
410
-    {
411
-        $event = $this->get_first_related('Event');
412
-        if (! $event instanceof \EE_Event) {
413
-            throw new EntityNotFoundException('Event ID', $this->event_ID());
414
-        }
415
-        return $event;
416
-    }
417
-
418
-
419
-    /**
420
-     * Gets the "author" of the registration.  Note that for the purposes of registrations, the author will correspond
421
-     * with the author of the event this registration is for.
422
-     *
423
-     * @since 4.5.0
424
-     * @return int
425
-     * @throws EE_Error
426
-     * @throws EntityNotFoundException
427
-     */
428
-    public function wp_user()
429
-    {
430
-        $event = $this->event();
431
-        if ($event instanceof EE_Event) {
432
-            return $event->wp_user();
433
-        }
434
-        return 0;
435
-    }
436
-
437
-
438
-    /**
439
-     * decrements (subtracts) this registration's related ticket sold and corresponding datetime sold values
440
-     *
441
-     * @return void
442
-     * @throws EE_Error
443
-     */
444
-    private function _release_registration_space()
445
-    {
446
-        $ticket = $this->ticket();
447
-        $ticket->decrease_sold();
448
-        $ticket->save();
449
-    }
450
-
451
-
452
-    /**
453
-     * tracks this registration's ticket reservation in extra meta
454
-     * and can increment related ticket reserved and corresponding datetime reserved values
455
-     *
456
-     * @param bool $update_ticket if true, will increment ticket and datetime reserved count
457
-     *
458
-     * @return void
459
-     * @throws EE_Error
460
-     */
461
-    public function reserve_ticket($update_ticket = false)
462
-    {
463
-        if ($this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true, false) === false) {
464
-            // PLZ NOTE: although checking $update_ticket first would be more efficient,
465
-            // we NEED to ALWAYS call update_extra_meta(), which is why that is done first
466
-            if ($this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true, false) && $update_ticket) {
467
-                $ticket = $this->ticket();
468
-                $ticket->increase_reserved();
469
-                $ticket->save();
470
-            }
471
-        }
472
-    }
473
-
474
-
475
-    /**
476
-     * stops tracking this registration's ticket reservation in extra meta
477
-     * decrements (subtracts) related ticket reserved and corresponding datetime reserved values
478
-     *
479
-     * @param bool $update_ticket if true, will decrement ticket and datetime reserved count
480
-     *
481
-     * @return void
482
-     * @throws EE_Error
483
-     */
484
-    public function release_reserved_ticket($update_ticket = false)
485
-    {
486
-        if ($this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true, false) !== false) {
487
-            // PLZ NOTE: although checking $update_ticket first would be more efficient,
488
-            // we NEED to ALWAYS call delete_extra_meta(), which is why that is done first
489
-            if ($this->delete_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY) && $update_ticket) {
490
-                $ticket = $this->ticket();
491
-                $ticket->decrease_reserved();
492
-                $ticket->save();
493
-            }
494
-        }
495
-    }
496
-
497
-
498
-    /**
499
-     * Set Attendee ID
500
-     *
501
-     * @param        int $ATT_ID Attendee ID
502
-     * @throws EE_Error
503
-     * @throws RuntimeException
504
-     */
505
-    public function set_attendee_id($ATT_ID = 0)
506
-    {
507
-        $this->set('ATT_ID', $ATT_ID);
508
-    }
509
-
510
-
511
-    /**
512
-     *        Set Transaction ID
513
-     *
514
-     * @param        int $TXN_ID Transaction ID
515
-     * @throws EE_Error
516
-     * @throws RuntimeException
517
-     */
518
-    public function set_transaction_id($TXN_ID = 0)
519
-    {
520
-        $this->set('TXN_ID', $TXN_ID);
521
-    }
522
-
523
-
524
-    /**
525
-     *        Set Session
526
-     *
527
-     * @param    string $REG_session PHP Session ID
528
-     * @throws EE_Error
529
-     * @throws RuntimeException
530
-     */
531
-    public function set_session($REG_session = '')
532
-    {
533
-        $this->set('REG_session', $REG_session);
534
-    }
535
-
536
-
537
-    /**
538
-     *        Set Registration URL Link
539
-     *
540
-     * @param    string $REG_url_link Registration URL Link
541
-     * @throws EE_Error
542
-     * @throws RuntimeException
543
-     */
544
-    public function set_reg_url_link($REG_url_link = '')
545
-    {
546
-        $this->set('REG_url_link', $REG_url_link);
547
-    }
548
-
549
-
550
-    /**
551
-     *        Set Attendee Counter
552
-     *
553
-     * @param        int $REG_count Primary Attendee
554
-     * @throws EE_Error
555
-     * @throws RuntimeException
556
-     */
557
-    public function set_count($REG_count = 1)
558
-    {
559
-        $this->set('REG_count', $REG_count);
560
-    }
561
-
562
-
563
-    /**
564
-     *        Set Group Size
565
-     *
566
-     * @param        boolean $REG_group_size Group Registration
567
-     * @throws EE_Error
568
-     * @throws RuntimeException
569
-     */
570
-    public function set_group_size($REG_group_size = false)
571
-    {
572
-        $this->set('REG_group_size', $REG_group_size);
573
-    }
574
-
575
-
576
-    /**
577
-     *    is_not_approved -  convenience method that returns TRUE if REG status ID ==
578
-     *    EEM_Registration::status_id_not_approved
579
-     *
580
-     * @return        boolean
581
-     */
582
-    public function is_not_approved()
583
-    {
584
-        return $this->status_ID() == EEM_Registration::status_id_not_approved ? true : false;
585
-    }
586
-
587
-
588
-    /**
589
-     *    is_pending_payment -  convenience method that returns TRUE if REG status ID ==
590
-     *    EEM_Registration::status_id_pending_payment
591
-     *
592
-     * @return        boolean
593
-     */
594
-    public function is_pending_payment()
595
-    {
596
-        return $this->status_ID() == EEM_Registration::status_id_pending_payment ? true : false;
597
-    }
598
-
599
-
600
-    /**
601
-     *    is_approved -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_approved
602
-     *
603
-     * @return        boolean
604
-     */
605
-    public function is_approved()
606
-    {
607
-        return $this->status_ID() == EEM_Registration::status_id_approved ? true : false;
608
-    }
609
-
610
-
611
-    /**
612
-     *    is_cancelled -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_cancelled
613
-     *
614
-     * @return        boolean
615
-     */
616
-    public function is_cancelled()
617
-    {
618
-        return $this->status_ID() == EEM_Registration::status_id_cancelled ? true : false;
619
-    }
620
-
621
-
622
-    /**
623
-     *    is_declined -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_declined
624
-     *
625
-     * @return        boolean
626
-     */
627
-    public function is_declined()
628
-    {
629
-        return $this->status_ID() == EEM_Registration::status_id_declined ? true : false;
630
-    }
631
-
632
-
633
-    /**
634
-     *    is_incomplete -  convenience method that returns TRUE if REG status ID ==
635
-     *    EEM_Registration::status_id_incomplete
636
-     *
637
-     * @return        boolean
638
-     */
639
-    public function is_incomplete()
640
-    {
641
-        return $this->status_ID() == EEM_Registration::status_id_incomplete ? true : false;
642
-    }
643
-
644
-
645
-    /**
646
-     *        Set Registration Date
647
-     *
648
-     * @param        mixed ( int or string ) $REG_date Registration Date - Unix timestamp or string representation of
649
-     *                                                 Date
650
-     * @throws EE_Error
651
-     * @throws RuntimeException
652
-     */
653
-    public function set_reg_date($REG_date = false)
654
-    {
655
-        $this->set('REG_date', $REG_date);
656
-    }
657
-
658
-
659
-    /**
660
-     *    Set final price owing for this registration after all ticket/price modifications
661
-     *
662
-     * @access    public
663
-     * @param    float $REG_final_price
664
-     * @throws EE_Error
665
-     * @throws RuntimeException
666
-     */
667
-    public function set_final_price($REG_final_price = 0.00)
668
-    {
669
-        $this->set('REG_final_price', $REG_final_price);
670
-    }
671
-
672
-
673
-    /**
674
-     *    Set amount paid towards this registration's final price
675
-     *
676
-     * @access    public
677
-     * @param    float $REG_paid
678
-     * @throws EE_Error
679
-     * @throws RuntimeException
680
-     */
681
-    public function set_paid($REG_paid = 0.00)
682
-    {
683
-        $this->set('REG_paid', $REG_paid);
684
-    }
685
-
686
-
687
-    /**
688
-     *        Attendee Is Going
689
-     *
690
-     * @param        boolean $REG_att_is_going Attendee Is Going
691
-     * @throws EE_Error
692
-     * @throws RuntimeException
693
-     */
694
-    public function set_att_is_going($REG_att_is_going = false)
695
-    {
696
-        $this->set('REG_att_is_going', $REG_att_is_going);
697
-    }
698
-
699
-
700
-    /**
701
-     * Gets the related attendee
702
-     *
703
-     * @return EE_Attendee
704
-     * @throws EE_Error
705
-     */
706
-    public function attendee()
707
-    {
708
-        return $this->get_first_related('Attendee');
709
-    }
710
-
711
-
712
-    /**
713
-     *        get Event ID
714
-     */
715
-    public function event_ID()
716
-    {
717
-        return $this->get('EVT_ID');
718
-    }
719
-
720
-
721
-    /**
722
-     *        get Event ID
723
-     */
724
-    public function event_name()
725
-    {
726
-        $event = $this->event_obj();
727
-        if ($event) {
728
-            return $event->name();
729
-        } else {
730
-            return null;
731
-        }
732
-    }
733
-
734
-
735
-    /**
736
-     * Fetches the event this registration is for
737
-     *
738
-     * @return EE_Event
739
-     * @throws EE_Error
740
-     */
741
-    public function event_obj()
742
-    {
743
-        return $this->get_first_related('Event');
744
-    }
745
-
746
-
747
-    /**
748
-     *        get Attendee ID
749
-     */
750
-    public function attendee_ID()
751
-    {
752
-        return $this->get('ATT_ID');
753
-    }
754
-
755
-
756
-    /**
757
-     *        get PHP Session ID
758
-     */
759
-    public function session_ID()
760
-    {
761
-        return $this->get('REG_session');
762
-    }
763
-
764
-
765
-    /**
766
-     * Gets the string which represents the URL trigger for the receipt template in the message template system.
767
-     *
768
-     * @param string $messenger 'pdf' or 'html'.  Default 'html'.
769
-     * @return string
770
-     */
771
-    public function receipt_url($messenger = 'html')
772
-    {
773
-
774
-        /**
775
-         * The below will be deprecated one version after this.  We check first if there is a custom receipt template
776
-         * already in use on old system.  If there is then we just return the standard url for it.
777
-         *
778
-         * @since 4.5.0
779
-         */
780
-        $template_relative_path = 'modules/gateways/Invoice/lib/templates/receipt_body.template.php';
781
-        $has_custom             = EEH_Template::locate_template(
782
-            $template_relative_path,
783
-            array(),
784
-            true,
785
-            true,
786
-            true
787
-        );
788
-
789
-        if ($has_custom) {
790
-            return add_query_arg(array('receipt' => 'true'), $this->invoice_url('launch'));
791
-        }
792
-        return apply_filters('FHEE__EE_Registration__receipt_url__receipt_url', '', $this, $messenger, 'receipt');
793
-    }
794
-
795
-
796
-    /**
797
-     * Gets the string which represents the URL trigger for the invoice template in the message template system.
798
-     *
799
-     * @param string $messenger 'pdf' or 'html'.  Default 'html'.
800
-     * @return string
801
-     * @throws EE_Error
802
-     */
803
-    public function invoice_url($messenger = 'html')
804
-    {
805
-        /**
806
-         * The below will be deprecated one version after this.  We check first if there is a custom invoice template
807
-         * already in use on old system.  If there is then we just return the standard url for it.
808
-         *
809
-         * @since 4.5.0
810
-         */
811
-        $template_relative_path = 'modules/gateways/Invoice/lib/templates/invoice_body.template.php';
812
-        $has_custom             = EEH_Template::locate_template(
813
-            $template_relative_path,
814
-            array(),
815
-            true,
816
-            true,
817
-            true
818
-        );
819
-
820
-        if ($has_custom) {
821
-            if ($messenger == 'html') {
822
-                return $this->invoice_url('launch');
823
-            }
824
-            $route = $messenger == 'download' || $messenger == 'pdf' ? 'download_invoice' : 'launch_invoice';
825
-
826
-            $query_args = array('ee' => $route, 'id' => $this->reg_url_link());
827
-            if ($messenger == 'html') {
828
-                $query_args['html'] = true;
829
-            }
830
-            return add_query_arg($query_args, get_permalink(EE_Registry::instance()->CFG->core->thank_you_page_id));
831
-        }
832
-        return apply_filters('FHEE__EE_Registration__invoice_url__invoice_url', '', $this, $messenger, 'invoice');
833
-    }
834
-
835
-
836
-    /**
837
-     * get Registration URL Link
838
-     *
839
-     * @access public
840
-     * @return string
841
-     * @throws EE_Error
842
-     */
843
-    public function reg_url_link()
844
-    {
845
-        return (string) $this->get('REG_url_link');
846
-    }
847
-
848
-
849
-    /**
850
-     * Echoes out invoice_url()
851
-     *
852
-     * @param string $type 'download','launch', or 'html' (default is 'launch')
853
-     * @return void
854
-     * @throws EE_Error
855
-     */
856
-    public function e_invoice_url($type = 'launch')
857
-    {
858
-        echo $this->invoice_url($type);
859
-    }
860
-
861
-
862
-    /**
863
-     * Echoes out payment_overview_url
864
-     */
865
-    public function e_payment_overview_url()
866
-    {
867
-        echo $this->payment_overview_url();
868
-    }
869
-
870
-
871
-    /**
872
-     * Gets the URL of the thank you page with this registration REG_url_link added as
873
-     * a query parameter
874
-     *
875
-     * @param bool $clear_session Set to true when you want to clear the session on revisiting the
876
-     *                            payment overview url.
877
-     * @return string
878
-     * @throws EE_Error
879
-     */
880
-    public function payment_overview_url($clear_session = false)
881
-    {
882
-        return add_query_arg(array(
883
-            'e_reg_url_link' => $this->reg_url_link(),
884
-            'step'           => 'payment_options',
885
-            'revisit'        => true,
886
-            'clear_session' => (bool) $clear_session
887
-        ), EE_Registry::instance()->CFG->core->reg_page_url());
888
-    }
889
-
890
-
891
-    /**
892
-     * Gets the URL of the thank you page with this registration REG_url_link added as
893
-     * a query parameter
894
-     *
895
-     * @return string
896
-     * @throws EE_Error
897
-     */
898
-    public function edit_attendee_information_url()
899
-    {
900
-        return add_query_arg(array(
901
-            'e_reg_url_link' => $this->reg_url_link(),
902
-            'step'           => 'attendee_information',
903
-            'revisit'        => true,
904
-        ), EE_Registry::instance()->CFG->core->reg_page_url());
905
-    }
906
-
907
-
908
-    /**
909
-     * Simply generates and returns the appropriate admin_url link to edit this registration
910
-     *
911
-     * @return string
912
-     * @throws EE_Error
913
-     */
914
-    public function get_admin_edit_url()
915
-    {
916
-        return EEH_URL::add_query_args_and_nonce(array(
917
-            'page'    => 'espresso_registrations',
918
-            'action'  => 'view_registration',
919
-            '_REG_ID' => $this->ID(),
920
-        ), admin_url('admin.php'));
921
-    }
922
-
923
-
924
-    /**
925
-     *    is_primary_registrant?
926
-     */
927
-    public function is_primary_registrant()
928
-    {
929
-        return $this->get('REG_count') == 1 ? true : false;
930
-    }
931
-
932
-
933
-    /**
934
-     * This returns the primary registration object for this registration group (which may be this object).
935
-     *
936
-     * @return EE_Registration
937
-     * @throws EE_Error
938
-     */
939
-    public function get_primary_registration()
940
-    {
941
-        if ($this->is_primary_registrant()) {
942
-            return $this;
943
-        }
944
-
945
-        //k reg_count !== 1 so let's get the EE_Registration object matching this txn_id and reg_count == 1
946
-        /** @var EE_Registration $primary_registrant */
947
-        $primary_registrant = EEM_Registration::instance()->get_one(array(
948
-            array(
949
-                'TXN_ID'    => $this->transaction_ID(),
950
-                'REG_count' => 1,
951
-            ),
952
-        ));
953
-        return $primary_registrant;
954
-    }
955
-
956
-
957
-    /**
958
-     *        get  Attendee Number
959
-     *
960
-     * @access        public
961
-     */
962
-    public function count()
963
-    {
964
-        return $this->get('REG_count');
965
-    }
966
-
967
-
968
-    /**
969
-     *        get Group Size
970
-     */
971
-    public function group_size()
972
-    {
973
-        return $this->get('REG_group_size');
974
-    }
975
-
976
-
977
-    /**
978
-     *        get Registration Date
979
-     */
980
-    public function date()
981
-    {
982
-        return $this->get('REG_date');
983
-    }
984
-
985
-
986
-    /**
987
-     * gets a pretty date
988
-     *
989
-     * @param string $date_format
990
-     * @param string $time_format
991
-     * @return string
992
-     * @throws EE_Error
993
-     */
994
-    public function pretty_date($date_format = null, $time_format = null)
995
-    {
996
-        return $this->get_datetime('REG_date', $date_format, $time_format);
997
-    }
998
-
999
-
1000
-    /**
1001
-     * final_price
1002
-     * the registration's share of the transaction total, so that the
1003
-     * sum of all the transaction's REG_final_prices equal the transaction's total
1004
-     *
1005
-     * @return float
1006
-     * @throws EE_Error
1007
-     */
1008
-    public function final_price()
1009
-    {
1010
-        return $this->get('REG_final_price');
1011
-    }
1012
-
1013
-
1014
-    /**
1015
-     * pretty_final_price
1016
-     *  final price as formatted string, with correct decimal places and currency symbol
1017
-     *
1018
-     * @return string
1019
-     * @throws EE_Error
1020
-     */
1021
-    public function pretty_final_price()
1022
-    {
1023
-        return $this->get_pretty('REG_final_price');
1024
-    }
1025
-
1026
-
1027
-    /**
1028
-     * get paid (yeah)
1029
-     *
1030
-     * @return float
1031
-     * @throws EE_Error
1032
-     */
1033
-    public function paid()
1034
-    {
1035
-        return $this->get('REG_paid');
1036
-    }
1037
-
1038
-
1039
-    /**
1040
-     * pretty_paid
1041
-     *
1042
-     * @return float
1043
-     * @throws EE_Error
1044
-     */
1045
-    public function pretty_paid()
1046
-    {
1047
-        return $this->get_pretty('REG_paid');
1048
-    }
1049
-
1050
-
1051
-    /**
1052
-     * owes_monies_and_can_pay
1053
-     * whether or not this registration has monies owing and it's' status allows payment
1054
-     *
1055
-     * @param array $requires_payment
1056
-     * @return bool
1057
-     * @throws EE_Error
1058
-     */
1059
-    public function owes_monies_and_can_pay($requires_payment = array())
1060
-    {
1061
-        // these reg statuses require payment (if event is not free)
1062
-        $requires_payment = ! empty($requires_payment)
1063
-            ? $requires_payment
1064
-            : EEM_Registration::reg_statuses_that_allow_payment();
1065
-        if (in_array($this->status_ID(), $requires_payment) &&
1066
-            $this->final_price() != 0 &&
1067
-            $this->final_price() != $this->paid()
1068
-        ) {
1069
-            return true;
1070
-        } else {
1071
-            return false;
1072
-        }
1073
-    }
1074
-
1075
-
1076
-    /**
1077
-     * Prints out the return value of $this->pretty_status()
1078
-     *
1079
-     * @param bool $show_icons
1080
-     * @return void
1081
-     * @throws EE_Error
1082
-     */
1083
-    public function e_pretty_status($show_icons = false)
1084
-    {
1085
-        echo $this->pretty_status($show_icons);
1086
-    }
1087
-
1088
-
1089
-    /**
1090
-     * Returns a nice version of the status for displaying to customers
1091
-     *
1092
-     * @param bool $show_icons
1093
-     * @return string
1094
-     * @throws EE_Error
1095
-     */
1096
-    public function pretty_status($show_icons = false)
1097
-    {
1098
-        $status = EEM_Status::instance()->localized_status(
1099
-            array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
1100
-            false,
1101
-            'sentence'
1102
-        );
1103
-        $icon   = '';
1104
-        switch ($this->status_ID()) {
1105
-            case EEM_Registration::status_id_approved:
1106
-                $icon = $show_icons
1107
-                    ? '<span class="dashicons dashicons-star-filled ee-icon-size-16 green-text"></span>'
1108
-                    : '';
1109
-                break;
1110
-            case EEM_Registration::status_id_pending_payment:
1111
-                $icon = $show_icons
1112
-                    ? '<span class="dashicons dashicons-star-half ee-icon-size-16 orange-text"></span>'
1113
-                    : '';
1114
-                break;
1115
-            case EEM_Registration::status_id_not_approved:
1116
-                $icon = $show_icons
1117
-                    ? '<span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>'
1118
-                    : '';
1119
-                break;
1120
-            case EEM_Registration::status_id_cancelled:
1121
-                $icon = $show_icons
1122
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
1123
-                    : '';
1124
-                break;
1125
-            case EEM_Registration::status_id_incomplete:
1126
-                $icon = $show_icons
1127
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-orange-text"></span>'
1128
-                    : '';
1129
-                break;
1130
-            case EEM_Registration::status_id_declined:
1131
-                $icon = $show_icons
1132
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
1133
-                    : '';
1134
-                break;
1135
-            case EEM_Registration::status_id_wait_list:
1136
-                $icon = $show_icons
1137
-                    ? '<span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>'
1138
-                    : '';
1139
-                break;
1140
-        }
1141
-        return $icon . $status[$this->status_ID()];
1142
-    }
1143
-
1144
-
1145
-    /**
1146
-     *        get Attendee Is Going
1147
-     */
1148
-    public function att_is_going()
1149
-    {
1150
-        return $this->get('REG_att_is_going');
1151
-    }
1152
-
1153
-
1154
-    /**
1155
-     * Gets related answers
1156
-     *
1157
-     * @param array $query_params like EEM_Base::get_all
1158
-     * @return EE_Answer[]
1159
-     * @throws EE_Error
1160
-     */
1161
-    public function answers($query_params = null)
1162
-    {
1163
-        return $this->get_many_related('Answer', $query_params);
1164
-    }
1165
-
1166
-
1167
-    /**
1168
-     * Gets the registration's answer value to the specified question
1169
-     * (either the question's ID or a question object)
1170
-     *
1171
-     * @param EE_Question|int $question
1172
-     * @param bool            $pretty_value
1173
-     * @return array|string if pretty_value= true, the result will always be a string
1174
-     * (because the answer might be an array of answer values, so passing pretty_value=true
1175
-     * will convert it into some kind of string)
1176
-     * @throws EE_Error
1177
-     */
1178
-    public function answer_value_to_question($question, $pretty_value = true)
1179
-    {
1180
-        $question_id = EEM_Question::instance()->ensure_is_ID($question);
1181
-        return EEM_Answer::instance()->get_answer_value_to_question($this, $question_id, $pretty_value);
1182
-    }
1183
-
1184
-
1185
-    /**
1186
-     * question_groups
1187
-     * returns an array of EE_Question_Group objects for this registration
1188
-     *
1189
-     * @return EE_Question_Group[]
1190
-     * @throws EE_Error
1191
-     * @throws EntityNotFoundException
1192
-     */
1193
-    public function question_groups()
1194
-    {
1195
-        $question_groups = array();
1196
-        if ($this->event() instanceof EE_Event) {
1197
-            $question_groups = $this->event()->question_groups(
1198
-                array(
1199
-                    array(
1200
-                        'Event_Question_Group.EQG_primary' => $this->count() == 1 ? true : false,
1201
-                    ),
1202
-                    'order_by' => array('QSG_order' => 'ASC'),
1203
-                )
1204
-            );
1205
-        }
1206
-        return $question_groups;
1207
-    }
1208
-
1209
-
1210
-    /**
1211
-     * count_question_groups
1212
-     * returns a count of the number of EE_Question_Group objects for this registration
1213
-     *
1214
-     * @return int
1215
-     * @throws EE_Error
1216
-     * @throws EntityNotFoundException
1217
-     */
1218
-    public function count_question_groups()
1219
-    {
1220
-        $qg_count = 0;
1221
-        if ($this->event() instanceof EE_Event) {
1222
-            $qg_count = $this->event()->count_related(
1223
-                'Question_Group',
1224
-                array(
1225
-                    array(
1226
-                        'Event_Question_Group.EQG_primary' => $this->count() == 1 ? true : false,
1227
-                    ),
1228
-                )
1229
-            );
1230
-        }
1231
-        return $qg_count;
1232
-    }
1233
-
1234
-
1235
-    /**
1236
-     * Returns the registration date in the 'standard' string format
1237
-     * (function may be improved in the future to allow for different formats and timezones)
1238
-     *
1239
-     * @return string
1240
-     * @throws EE_Error
1241
-     */
1242
-    public function reg_date()
1243
-    {
1244
-        return $this->get_datetime('REG_date');
1245
-    }
1246
-
1247
-
1248
-    /**
1249
-     * Gets the datetime-ticket for this registration (ie, it can be used to isolate
1250
-     * the ticket this registration purchased, or the datetime they have registered
1251
-     * to attend)
1252
-     *
1253
-     * @return EE_Datetime_Ticket
1254
-     * @throws EE_Error
1255
-     */
1256
-    public function datetime_ticket()
1257
-    {
1258
-        return $this->get_first_related('Datetime_Ticket');
1259
-    }
1260
-
1261
-
1262
-    /**
1263
-     * Sets the registration's datetime_ticket.
1264
-     *
1265
-     * @param EE_Datetime_Ticket $datetime_ticket
1266
-     * @return EE_Datetime_Ticket
1267
-     * @throws EE_Error
1268
-     */
1269
-    public function set_datetime_ticket($datetime_ticket)
1270
-    {
1271
-        return $this->_add_relation_to($datetime_ticket, 'Datetime_Ticket');
1272
-    }
1273
-
1274
-    /**
1275
-     * Gets deleted
1276
-     *
1277
-     * @return bool
1278
-     * @throws EE_Error
1279
-     */
1280
-    public function deleted()
1281
-    {
1282
-        return $this->get('REG_deleted');
1283
-    }
1284
-
1285
-    /**
1286
-     * Sets deleted
1287
-     *
1288
-     * @param boolean $deleted
1289
-     * @return bool
1290
-     * @throws EE_Error
1291
-     * @throws RuntimeException
1292
-     */
1293
-    public function set_deleted($deleted)
1294
-    {
1295
-        if ($deleted) {
1296
-            $this->delete();
1297
-        } else {
1298
-            $this->restore();
1299
-        }
1300
-    }
1301
-
1302
-
1303
-    /**
1304
-     * Get the status object of this object
1305
-     *
1306
-     * @return EE_Status
1307
-     * @throws EE_Error
1308
-     */
1309
-    public function status_obj()
1310
-    {
1311
-        return $this->get_first_related('Status');
1312
-    }
1313
-
1314
-
1315
-    /**
1316
-     * Returns the number of times this registration has checked into any of the datetimes
1317
-     * its available for
1318
-     *
1319
-     * @return int
1320
-     * @throws EE_Error
1321
-     */
1322
-    public function count_checkins()
1323
-    {
1324
-        return $this->get_model()->count_related($this, 'Checkin');
1325
-    }
1326
-
1327
-
1328
-    /**
1329
-     * Returns the number of current Check-ins this registration is checked into for any of the datetimes the
1330
-     * registration is for.  Note, this is ONLY checked in (does not include checkedout)
1331
-     *
1332
-     * @return int
1333
-     * @throws EE_Error
1334
-     */
1335
-    public function count_checkins_not_checkedout()
1336
-    {
1337
-        return $this->get_model()->count_related($this, 'Checkin', array(array('CHK_in' => 1)));
1338
-    }
1339
-
1340
-
1341
-    /**
1342
-     * The purpose of this method is simply to check whether this registration can checkin to the given datetime.
1343
-     *
1344
-     * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1345
-     * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1346
-     *                                          consider registration status as well as datetime access.
1347
-     * @return bool
1348
-     * @throws EE_Error
1349
-     */
1350
-    public function can_checkin($DTT_OR_ID, $check_approved = true)
1351
-    {
1352
-        $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1353
-
1354
-        //first check registration status
1355
-        if (($check_approved && ! $this->is_approved()) || ! $DTT_ID) {
1356
-            return false;
1357
-        }
1358
-        //is there a datetime ticket that matches this dtt_ID?
1359
-        if (! (EEM_Datetime_Ticket::instance()->exists(array(
1360
-            array(
1361
-                'TKT_ID' => $this->get('TKT_ID'),
1362
-                'DTT_ID' => $DTT_ID,
1363
-            ),
1364
-        )))
1365
-        ) {
1366
-            return false;
1367
-        }
1368
-
1369
-        //final check is against TKT_uses
1370
-        return $this->verify_can_checkin_against_TKT_uses($DTT_ID);
1371
-    }
1372
-
1373
-
1374
-    /**
1375
-     * This method verifies whether the user can checkin for the given datetime considering the max uses value set on
1376
-     * the ticket. To do this,  a query is done to get the count of the datetime records already checked into.  If the
1377
-     * datetime given does not have a check-in record and checking in for that datetime will exceed the allowed uses,
1378
-     * then return false.  Otherwise return true.
1379
-     *
1380
-     * @param int | EE_Datetime $DTT_OR_ID The datetime the registration is being checked against
1381
-     * @return bool true means can checkin.  false means cannot checkin.
1382
-     * @throws EE_Error
1383
-     */
1384
-    public function verify_can_checkin_against_TKT_uses($DTT_OR_ID)
1385
-    {
1386
-        $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1387
-
1388
-        if (! $DTT_ID) {
1389
-            return false;
1390
-        }
1391
-
1392
-        $max_uses = $this->ticket() instanceof EE_Ticket ? $this->ticket()->uses() : EE_INF;
1393
-
1394
-        // if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1395
-        // check-in or not.
1396
-        if (! $max_uses || $max_uses === EE_INF) {
1397
-            return true;
1398
-        }
1399
-
1400
-        //does this datetime have a checkin record?  If so, then the dtt count has already been verified so we can just
1401
-        //go ahead and toggle.
1402
-        if (EEM_Checkin::instance()->exists(array(array('REG_ID' => $this->ID(), 'DTT_ID' => $DTT_ID)))) {
1403
-            return true;
1404
-        }
1405
-
1406
-        //made it here so the last check is whether the number of checkins per unique datetime on this registration
1407
-        //disallows further check-ins.
1408
-        $count_unique_dtt_checkins = EEM_Checkin::instance()->count(array(
1409
-            array(
1410
-                'REG_ID' => $this->ID(),
1411
-                'CHK_in' => true,
1412
-            ),
1413
-        ), 'DTT_ID', true);
1414
-        // checkins have already reached their max number of uses
1415
-        // so registrant can NOT checkin
1416
-        if ($count_unique_dtt_checkins >= $max_uses) {
1417
-            EE_Error::add_error(
1418
-                esc_html__(
1419
-                    'Check-in denied because number of datetime uses for the ticket has been reached or exceeded.',
1420
-                    'event_espresso'
1421
-                ),
1422
-                __FILE__,
1423
-                __FUNCTION__,
1424
-                __LINE__
1425
-            );
1426
-            return false;
1427
-        }
1428
-        return true;
1429
-    }
1430
-
1431
-
1432
-    /**
1433
-     * toggle Check-in status for this registration
1434
-     * Check-ins are toggled in the following order:
1435
-     * never checked in -> checked in
1436
-     * checked in -> checked out
1437
-     * checked out -> checked in
1438
-     *
1439
-     * @param  int $DTT_ID  include specific datetime to toggle Check-in for.
1440
-     *                      If not included or null, then it is assumed latest datetime is being toggled.
1441
-     * @param bool $verify  If true then can_checkin() is used to verify whether the person
1442
-     *                      can be checked in or not.  Otherwise this forces change in checkin status.
1443
-     * @return bool|int     the chk_in status toggled to OR false if nothing got changed.
1444
-     * @throws EE_Error
1445
-     */
1446
-    public function toggle_checkin_status($DTT_ID = null, $verify = false)
1447
-    {
1448
-        if (empty($DTT_ID)) {
1449
-            $datetime = $this->get_latest_related_datetime();
1450
-            $DTT_ID   = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1451
-            // verify the registration can checkin for the given DTT_ID
1452
-        } elseif (! $this->can_checkin($DTT_ID, $verify)) {
1453
-            EE_Error::add_error(
1454
-                sprintf(
1455
-                    esc_html__(
1456
-                        'The given registration (ID:%1$d) can not be checked in to the given DTT_ID (%2$d), because the registration does not have access',
1457
-                        'event_espresso'
1458
-                    ),
1459
-                    $this->ID(),
1460
-                    $DTT_ID
1461
-                ),
1462
-                __FILE__,
1463
-                __FUNCTION__,
1464
-                __LINE__
1465
-            );
1466
-            return false;
1467
-        }
1468
-        $status_paths = array(
1469
-            EE_Checkin::status_checked_never => EE_Checkin::status_checked_in,
1470
-            EE_Checkin::status_checked_in    => EE_Checkin::status_checked_out,
1471
-            EE_Checkin::status_checked_out   => EE_Checkin::status_checked_in,
1472
-        );
1473
-        //start by getting the current status so we know what status we'll be changing to.
1474
-        $cur_status = $this->check_in_status_for_datetime($DTT_ID, null);
1475
-        $status_to  = $status_paths[$cur_status];
1476
-        // database only records true for checked IN or false for checked OUT
1477
-        // no record ( null ) means checked in NEVER, but we obviously don't save that
1478
-        $new_status = $status_to === EE_Checkin::status_checked_in ? true : false;
1479
-        // add relation - note Check-ins are always creating new rows
1480
-        // because we are keeping track of Check-ins over time.
1481
-        // Eventually we'll probably want to show a list table
1482
-        // for the individual Check-ins so that they can be managed.
1483
-        $checkin = EE_Checkin::new_instance(array(
1484
-            'REG_ID' => $this->ID(),
1485
-            'DTT_ID' => $DTT_ID,
1486
-            'CHK_in' => $new_status,
1487
-        ));
1488
-        // if the record could not be saved then return false
1489
-        if ($checkin->save() === 0) {
1490
-            if (WP_DEBUG) {
1491
-                global $wpdb;
1492
-                $error = sprintf(
1493
-                    esc_html__(
1494
-                        'Registration check in update failed because of the following database error: %1$s%2$s',
1495
-                        'event_espresso'
1496
-                    ),
1497
-                    '<br />',
1498
-                    $wpdb->last_error
1499
-                );
1500
-            } else {
1501
-                $error = esc_html__(
1502
-                    'Registration check in update failed because of an unknown database error',
1503
-                    'event_espresso'
1504
-                );
1505
-            }
1506
-            EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
1507
-            return false;
1508
-        }
1509
-        return $status_to;
1510
-    }
1511
-
1512
-
1513
-    /**
1514
-     * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1515
-     * "Latest" is defined by the `DTT_EVT_start` column.
1516
-     *
1517
-     * @return EE_Datetime|null
1518
-     * @throws EE_Error
1519
-     */
1520
-    public function get_latest_related_datetime()
1521
-    {
1522
-        return EEM_Datetime::instance()->get_one(
1523
-            array(
1524
-                array(
1525
-                    'Ticket.Registration.REG_ID' => $this->ID(),
1526
-                ),
1527
-                'order_by' => array('DTT_EVT_start' => 'DESC'),
1528
-            )
1529
-        );
1530
-    }
1531
-
1532
-
1533
-    /**
1534
-     * Returns the earliest datetime related to this registration (via the ticket attached to the registration).
1535
-     * "Earliest" is defined by the `DTT_EVT_start` column.
1536
-     *
1537
-     * @throws EE_Error
1538
-     */
1539
-    public function get_earliest_related_datetime()
1540
-    {
1541
-        return EEM_Datetime::instance()->get_one(
1542
-            array(
1543
-                array(
1544
-                    'Ticket.Registration.REG_ID' => $this->ID(),
1545
-                ),
1546
-                'order_by' => array('DTT_EVT_start' => 'ASC'),
1547
-            )
1548
-        );
1549
-    }
1550
-
1551
-
1552
-    /**
1553
-     * This method simply returns the check-in status for this registration and the given datetime.
1554
-     * If neither the datetime nor the checkin values are provided as arguments,
1555
-     * then this will return the LATEST check-in status for the registration across all datetimes it belongs to.
1556
-     *
1557
-     * @param  int       $DTT_ID  The ID of the datetime we're checking against
1558
-     *                            (if empty we'll get the primary datetime for
1559
-     *                            this registration (via event) and use it's ID);
1560
-     * @param EE_Checkin $checkin If present, we use the given checkin object rather than the dtt_id.
1561
-     *
1562
-     * @return int                Integer representing Check-in status.
1563
-     * @throws EE_Error
1564
-     */
1565
-    public function check_in_status_for_datetime($DTT_ID = 0, $checkin = null)
1566
-    {
1567
-        $checkin_query_params = array(
1568
-            'order_by' => array('CHK_timestamp' => 'DESC'),
1569
-        );
1570
-
1571
-        if ($DTT_ID > 0) {
1572
-            $checkin_query_params[0] = array('DTT_ID' => $DTT_ID);
1573
-        }
1574
-
1575
-        //get checkin object (if exists)
1576
-        $checkin = $checkin instanceof EE_Checkin
1577
-            ? $checkin
1578
-            : $this->get_first_related('Checkin', $checkin_query_params);
1579
-        if ($checkin instanceof EE_Checkin) {
1580
-            if ($checkin->get('CHK_in')) {
1581
-                return EE_Checkin::status_checked_in; //checked in
1582
-            }
1583
-            return EE_Checkin::status_checked_out; //had checked in but is now checked out.
1584
-        }
1585
-        return EE_Checkin::status_checked_never; //never been checked in
1586
-    }
1587
-
1588
-
1589
-    /**
1590
-     * This method returns a localized message for the toggled Check-in message.
1591
-     *
1592
-     * @param  int $DTT_ID include specific datetime to get the correct Check-in message.  If not included or null,
1593
-     *                     then it is assumed Check-in for primary datetime was toggled.
1594
-     * @param bool $error  This just flags that you want an error message returned. This is put in so that the error
1595
-     *                     message can be customized with the attendee name.
1596
-     * @return string internationalized message
1597
-     * @throws EE_Error
1598
-     */
1599
-    public function get_checkin_msg($DTT_ID, $error = false)
1600
-    {
1601
-        //let's get the attendee first so we can include the name of the attendee
1602
-        $attendee = $this->get_first_related('Attendee');
1603
-        if ($attendee instanceof EE_Attendee) {
1604
-            if ($error) {
1605
-                return sprintf(__("%s's check-in status was not changed.", "event_espresso"), $attendee->full_name());
1606
-            }
1607
-            $cur_status = $this->check_in_status_for_datetime($DTT_ID);
1608
-            //what is the status message going to be?
1609
-            switch ($cur_status) {
1610
-                case EE_Checkin::status_checked_never:
1611
-                    return sprintf(__("%s has been removed from Check-in records", "event_espresso"),
1612
-                        $attendee->full_name());
1613
-                    break;
1614
-                case EE_Checkin::status_checked_in:
1615
-                    return sprintf(__('%s has been checked in', 'event_espresso'), $attendee->full_name());
1616
-                    break;
1617
-                case EE_Checkin::status_checked_out:
1618
-                    return sprintf(__('%s has been checked out', 'event_espresso'), $attendee->full_name());
1619
-                    break;
1620
-            }
1621
-        }
1622
-        return esc_html__("The check-in status could not be determined.", "event_espresso");
1623
-    }
1624
-
1625
-
1626
-    /**
1627
-     * Returns the related EE_Transaction to this registration
1628
-     *
1629
-     * @return EE_Transaction
1630
-     * @throws EE_Error
1631
-     * @throws EntityNotFoundException
1632
-     */
1633
-    public function transaction()
1634
-    {
1635
-        $transaction = $this->get_first_related('Transaction');
1636
-        if (! $transaction instanceof \EE_Transaction) {
1637
-            throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
1638
-        }
1639
-        return $transaction;
1640
-    }
1641
-
1642
-
1643
-    /**
1644
-     *        get Registration Code
1645
-     */
1646
-    public function reg_code()
1647
-    {
1648
-        return $this->get('REG_code');
1649
-    }
1650
-
1651
-
1652
-    /**
1653
-     *        get Transaction ID
1654
-     */
1655
-    public function transaction_ID()
1656
-    {
1657
-        return $this->get('TXN_ID');
1658
-    }
1659
-
1660
-
1661
-    /**
1662
-     * @return int
1663
-     * @throws EE_Error
1664
-     */
1665
-    public function ticket_ID()
1666
-    {
1667
-        return $this->get('TKT_ID');
1668
-    }
1669
-
1670
-
1671
-    /**
1672
-     *        Set Registration Code
1673
-     *
1674
-     * @access    public
1675
-     * @param    string  $REG_code Registration Code
1676
-     * @param    boolean $use_default
1677
-     * @throws EE_Error
1678
-     */
1679
-    public function set_reg_code($REG_code, $use_default = false)
1680
-    {
1681
-        if (empty($REG_code)) {
1682
-            EE_Error::add_error(
1683
-                esc_html__('REG_code can not be empty.', 'event_espresso'),
1684
-                __FILE__,
1685
-                __FUNCTION__,
1686
-                __LINE__
1687
-            );
1688
-            return;
1689
-        }
1690
-        if (! $this->reg_code()) {
1691
-            parent::set('REG_code', $REG_code, $use_default);
1692
-        } else {
1693
-            EE_Error::doing_it_wrong(
1694
-                __CLASS__ . '::' . __FUNCTION__,
1695
-                esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
1696
-                '4.6.0'
1697
-            );
1698
-        }
1699
-    }
1700
-
1701
-
1702
-    /**
1703
-     * Returns all other registrations in the same group as this registrant who have the same ticket option.
1704
-     * Note, if you want to just get all registrations in the same transaction (group), use:
1705
-     *    $registration->transaction()->registrations();
1706
-     *
1707
-     * @since 4.5.0
1708
-     * @return EE_Registration[] or empty array if this isn't a group registration.
1709
-     * @throws EE_Error
1710
-     */
1711
-    public function get_all_other_registrations_in_group()
1712
-    {
1713
-        if ($this->group_size() < 2) {
1714
-            return array();
1715
-        }
1716
-
1717
-        $query[0] = array(
1718
-            'TXN_ID' => $this->transaction_ID(),
1719
-            'REG_ID' => array('!=', $this->ID()),
1720
-            'TKT_ID' => $this->ticket_ID(),
1721
-        );
1722
-        /** @var EE_Registration[] $registrations */
1723
-        $registrations = $this->get_model()->get_all($query);
1724
-        return $registrations;
1725
-    }
1726
-
1727
-    /**
1728
-     * Return the link to the admin details for the object.
1729
-     *
1730
-     * @return string
1731
-     * @throws EE_Error
1732
-     */
1733
-    public function get_admin_details_link()
1734
-    {
1735
-        EE_Registry::instance()->load_helper('URL');
1736
-        return EEH_URL::add_query_args_and_nonce(
1737
-            array(
1738
-                'page'    => 'espresso_registrations',
1739
-                'action'  => 'view_registration',
1740
-                '_REG_ID' => $this->ID(),
1741
-            ),
1742
-            admin_url('admin.php')
1743
-        );
1744
-    }
1745
-
1746
-    /**
1747
-     * Returns the link to the editor for the object.  Sometimes this is the same as the details.
1748
-     *
1749
-     * @return string
1750
-     * @throws EE_Error
1751
-     */
1752
-    public function get_admin_edit_link()
1753
-    {
1754
-        return $this->get_admin_details_link();
1755
-    }
1756
-
1757
-    /**
1758
-     * Returns the link to a settings page for the object.
1759
-     *
1760
-     * @return string
1761
-     * @throws EE_Error
1762
-     */
1763
-    public function get_admin_settings_link()
1764
-    {
1765
-        return $this->get_admin_details_link();
1766
-    }
1767
-
1768
-    /**
1769
-     * Returns the link to the "overview" for the object (typically the "list table" view).
1770
-     *
1771
-     * @return string
1772
-     */
1773
-    public function get_admin_overview_link()
1774
-    {
1775
-        EE_Registry::instance()->load_helper('URL');
1776
-        return EEH_URL::add_query_args_and_nonce(
1777
-            array(
1778
-                'page' => 'espresso_registrations',
1779
-            ),
1780
-            admin_url('admin.php')
1781
-        );
1782
-    }
1783
-
1784
-
1785
-    /**
1786
-     * @param array $query_params
1787
-     *
1788
-     * @return \EE_Registration[]
1789
-     * @throws EE_Error
1790
-     */
1791
-    public function payments($query_params = array())
1792
-    {
1793
-        return $this->get_many_related('Payment', $query_params);
1794
-    }
1795
-
1796
-
1797
-    /**
1798
-     * @param array $query_params
1799
-     *
1800
-     * @return \EE_Registration_Payment[]
1801
-     * @throws EE_Error
1802
-     */
1803
-    public function registration_payments($query_params = array())
1804
-    {
1805
-        return $this->get_many_related('Registration_Payment', $query_params);
1806
-    }
1807
-
1808
-
1809
-    /**
1810
-     * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
1811
-     * Note: if there are no payments on the registration there will be no payment method returned.
1812
-     *
1813
-     * @return EE_Payment_Method|null
1814
-     */
1815
-    public function payment_method()
1816
-    {
1817
-        return EEM_Payment_Method::instance()->get_last_used_for_registration($this);
1818
-    }
1819
-
1820
-
1821
-    /**
1822
-     * @return \EE_Line_Item
1823
-     * @throws EntityNotFoundException
1824
-     * @throws EE_Error
1825
-     */
1826
-    public function ticket_line_item()
1827
-    {
1828
-        $ticket            = $this->ticket();
1829
-        $transaction       = $this->transaction();
1830
-        $line_item         = null;
1831
-        $ticket_line_items = \EEH_Line_Item::get_line_items_by_object_type_and_IDs(
1832
-            $transaction->total_line_item(),
1833
-            'Ticket',
1834
-            array($ticket->ID())
1835
-        );
1836
-        foreach ($ticket_line_items as $ticket_line_item) {
1837
-            if (
1838
-                $ticket_line_item instanceof \EE_Line_Item
1839
-                && $ticket_line_item->OBJ_type() === 'Ticket'
1840
-                && $ticket_line_item->OBJ_ID() === $ticket->ID()
1841
-            ) {
1842
-                $line_item = $ticket_line_item;
1843
-                break;
1844
-            }
1845
-        }
1846
-        if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
1847
-            throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
1848
-        }
1849
-        return $line_item;
1850
-    }
1851
-
1852
-
1853
-    /**
1854
-     * Soft Deletes this model object.
1855
-     *
1856
-     * @return boolean | int
1857
-     * @throws RuntimeException
1858
-     * @throws EE_Error
1859
-     */
1860
-    public function delete()
1861
-    {
1862
-        if ($this->update_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY, $this->status_ID()) === true) {
1863
-            $this->set_status(EEM_Registration::status_id_cancelled);
1864
-        }
1865
-        return parent::delete();
1866
-    }
1867
-
1868
-
1869
-    /**
1870
-     * Restores whatever the previous status was on a registration before it was trashed (if possible)
1871
-     *
1872
-     * @throws EE_Error
1873
-     * @throws RuntimeException
1874
-     */
1875
-    public function restore()
1876
-    {
1877
-        $previous_status = $this->get_extra_meta(
1878
-            EE_Registration::PRE_TRASH_REG_STATUS_KEY,
1879
-            true,
1880
-            EEM_Registration::status_id_cancelled
1881
-        );
1882
-        if ($previous_status) {
1883
-            $this->delete_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY);
1884
-            $this->set_status($previous_status);
1885
-        }
1886
-        return parent::restore();
1887
-    }
1888
-
1889
-
1890
-    /**
1891
-     * possibly toggle Registration status based on comparison of REG_paid vs REG_final_price
1892
-     *
1893
-     * @param  boolean $trigger_set_status_logic EE_Registration::set_status() can trigger additional logic
1894
-     *                                           depending on whether the reg status changes to or from "Approved"
1895
-     * @return boolean whether the Registration status was updated
1896
-     * @throws EE_Error
1897
-     * @throws RuntimeException
1898
-     */
1899
-    public function updateStatusBasedOnTotalPaid($trigger_set_status_logic = true)
1900
-    {
1901
-        $paid = $this->paid();
1902
-        $price = $this->final_price();
1903
-        switch(true) {
1904
-            // overpaid or paid
1905
-            case EEH_Money::compare_floats($paid, $price, '>'):
1906
-            case EEH_Money::compare_floats($paid, $price):
1907
-                $new_status = EEM_Registration::status_id_approved;
1908
-                break;
1909
-            //  underpaid
1910
-            case EEH_Money::compare_floats($paid, $price, '<'):
1911
-                $new_status = EEM_Registration::status_id_pending_payment;
1912
-                break;
1913
-            // uhhh Houston...
1914
-            default:
1915
-                throw new RuntimeException(
1916
-                    esc_html__('The total paid calculation for this registration is inaccurate.', 'event_espresso')
1917
-                );
1918
-        }
1919
-        if ($new_status !== $this->status_ID()) {
1920
-            if ($trigger_set_status_logic) {
1921
-                return $this->set_status($new_status);
1922
-            }
1923
-            parent::set('STS_ID', $new_status);
1924
-            return true;
1925
-        }
1926
-        return false;
1927
-    }
1928
-
1929
-
1930
-    /*************************** DEPRECATED ***************************/
1931
-
1932
-
1933
-    /**
1934
-     * @deprecated
1935
-     * @since     4.7.0
1936
-     * @access    public
1937
-     */
1938
-    public function price_paid()
1939
-    {
1940
-        EE_Error::doing_it_wrong('EE_Registration::price_paid()',
1941
-            esc_html__('This method is deprecated, please use EE_Registration::final_price() instead.', 'event_espresso'),
1942
-            '4.7.0');
1943
-        return $this->final_price();
1944
-    }
1945
-
1946
-
1947
-    /**
1948
-     * @deprecated
1949
-     * @since     4.7.0
1950
-     * @access    public
1951
-     * @param    float $REG_final_price
1952
-     * @throws EE_Error
1953
-     * @throws RuntimeException
1954
-     */
1955
-    public function set_price_paid($REG_final_price = 0.00)
1956
-    {
1957
-        EE_Error::doing_it_wrong('EE_Registration::set_price_paid()',
1958
-            esc_html__('This method is deprecated, please use EE_Registration::set_final_price() instead.', 'event_espresso'),
1959
-            '4.7.0');
1960
-        $this->set_final_price($REG_final_price);
1961
-    }
1962
-
1963
-
1964
-    /**
1965
-     * @deprecated
1966
-     * @since 4.7.0
1967
-     * @return string
1968
-     * @throws EE_Error
1969
-     */
1970
-    public function pretty_price_paid()
1971
-    {
1972
-        EE_Error::doing_it_wrong('EE_Registration::pretty_price_paid()',
1973
-            esc_html__('This method is deprecated, please use EE_Registration::pretty_final_price() instead.',
1974
-                'event_espresso'), '4.7.0');
1975
-        return $this->pretty_final_price();
1976
-    }
1977
-
1978
-
1979
-    /**
1980
-     * Gets the primary datetime related to this registration via the related Event to this registration
1981
-     *
1982
-     * @deprecated 4.9.17
1983
-     * @return EE_Datetime
1984
-     * @throws EE_Error
1985
-     * @throws EntityNotFoundException
1986
-     */
1987
-    public function get_related_primary_datetime()
1988
-    {
1989
-        EE_Error::doing_it_wrong(
1990
-            __METHOD__,
1991
-            esc_html__(
1992
-                'Use EE_Registration::get_latest_related_datetime() or EE_Registration::get_earliest_related_datetime()',
1993
-                'event_espresso'
1994
-            ),
1995
-            '4.9.17',
1996
-            '5.0.0'
1997
-        );
1998
-        return $this->event()->primary_datetime();
1999
-    }
21
+	/**
22
+	 * Used to reference when a registration has never been checked in.
23
+	 *
24
+	 * @deprecated use \EE_Checkin::status_checked_never instead
25
+	 * @type int
26
+	 */
27
+	const checkin_status_never = 2;
28
+
29
+	/**
30
+	 * Used to reference when a registration has been checked in.
31
+	 *
32
+	 * @deprecated use \EE_Checkin::status_checked_in instead
33
+	 * @type int
34
+	 */
35
+	const checkin_status_in = 1;
36
+
37
+
38
+	/**
39
+	 * Used to reference when a registration has been checked out.
40
+	 *
41
+	 * @deprecated use \EE_Checkin::status_checked_out instead
42
+	 * @type int
43
+	 */
44
+	const checkin_status_out = 0;
45
+
46
+
47
+	/**
48
+	 * extra meta key for tracking reg status os trashed registrations
49
+	 *
50
+	 * @type string
51
+	 */
52
+	const PRE_TRASH_REG_STATUS_KEY = 'pre_trash_registration_status';
53
+
54
+
55
+	/**
56
+	 * extra meta key for tracking if registration has reserved ticket
57
+	 *
58
+	 * @type string
59
+	 */
60
+	const HAS_RESERVED_TICKET_KEY = 'has_reserved_ticket';
61
+
62
+
63
+	/**
64
+	 * @param array  $props_n_values          incoming values
65
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
66
+	 *                                        used.)
67
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
68
+	 *                                        date_format and the second value is the time format
69
+	 * @return EE_Registration
70
+	 * @throws EE_Error
71
+	 */
72
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
73
+	{
74
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
75
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
76
+	}
77
+
78
+
79
+	/**
80
+	 * @param array  $props_n_values  incoming values from the database
81
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
82
+	 *                                the website will be used.
83
+	 * @return EE_Registration
84
+	 */
85
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
86
+	{
87
+		return new self($props_n_values, true, $timezone);
88
+	}
89
+
90
+
91
+	/**
92
+	 *        Set Event ID
93
+	 *
94
+	 * @param        int $EVT_ID Event ID
95
+	 * @throws EE_Error
96
+	 * @throws RuntimeException
97
+	 */
98
+	public function set_event($EVT_ID = 0)
99
+	{
100
+		$this->set('EVT_ID', $EVT_ID);
101
+	}
102
+
103
+
104
+	/**
105
+	 * Overrides parent set() method so that all calls to set( 'REG_code', $REG_code ) OR set( 'STS_ID', $STS_ID ) can
106
+	 * be routed to internal methods
107
+	 *
108
+	 * @param string $field_name
109
+	 * @param mixed  $field_value
110
+	 * @param bool   $use_default
111
+	 * @throws EE_Error
112
+	 * @throws EntityNotFoundException
113
+	 * @throws InvalidArgumentException
114
+	 * @throws InvalidDataTypeException
115
+	 * @throws InvalidInterfaceException
116
+	 * @throws ReflectionException
117
+	 * @throws RuntimeException
118
+	 */
119
+	public function set($field_name, $field_value, $use_default = false)
120
+	{
121
+		switch ($field_name) {
122
+			case 'REG_code':
123
+				if (! empty($field_value) && $this->reg_code() === null) {
124
+					$this->set_reg_code($field_value, $use_default);
125
+				}
126
+				break;
127
+			case 'STS_ID':
128
+				$this->set_status($field_value, $use_default);
129
+				break;
130
+			default:
131
+				parent::set($field_name, $field_value, $use_default);
132
+		}
133
+	}
134
+
135
+
136
+	/**
137
+	 * Set Status ID
138
+	 * updates the registration status and ALSO...
139
+	 * calls reserve_registration_space() if the reg status changes TO approved from any other reg status
140
+	 * calls release_registration_space() if the reg status changes FROM approved to any other reg status
141
+	 *
142
+	 * @param string       $new_STS_ID
143
+	 * @param boolean      $use_default
144
+	 * @param ContextInterface|null $context
145
+	 * @return bool
146
+	 * @throws EE_Error
147
+	 * @throws EntityNotFoundException
148
+	 * @throws InvalidArgumentException
149
+	 * @throws ReflectionException
150
+	 * @throws RuntimeException
151
+	 * @throws InvalidDataTypeException
152
+	 * @throws InvalidInterfaceException
153
+	 */
154
+	public function set_status($new_STS_ID = null, $use_default = false, ContextInterface $context = null)
155
+	{
156
+		// get current REG_Status
157
+		$old_STS_ID = $this->status_ID();
158
+		// if status has changed
159
+		if ($old_STS_ID !== $new_STS_ID // and that status has actually changed
160
+			&& ! empty($old_STS_ID) // and that old status is actually set
161
+			&& ! empty($new_STS_ID) // as well as the new status
162
+			&& $this->ID() // ensure registration is in the db
163
+		) {
164
+			// TO approved
165
+			if ($new_STS_ID === EEM_Registration::status_id_approved) {
166
+				// reserve a space by incrementing ticket and datetime sold values
167
+				$this->_reserve_registration_space();
168
+				do_action('AHEE__EE_Registration__set_status__to_approved', $this, $old_STS_ID, $new_STS_ID, $context);
169
+				// OR FROM  approved
170
+			} elseif ($old_STS_ID === EEM_Registration::status_id_approved) {
171
+				// release a space by decrementing ticket and datetime sold values
172
+				$this->_release_registration_space();
173
+				do_action(
174
+					'AHEE__EE_Registration__set_status__from_approved',
175
+					$this,
176
+					$old_STS_ID,
177
+					$new_STS_ID,
178
+					$context
179
+				);
180
+			}
181
+			// update status
182
+			parent::set('STS_ID', $new_STS_ID, $use_default);
183
+			$this->_update_if_canceled_or_declined($new_STS_ID, $old_STS_ID, $context);
184
+			if($this->statusChangeUpdatesTransaction($context)) {
185
+				$this->updateTransactionAfterStatusChange();
186
+			}
187
+			do_action('AHEE__EE_Registration__set_status__after_update', $this, $old_STS_ID, $new_STS_ID, $context);
188
+			return true;
189
+		}
190
+		//even though the old value matches the new value, it's still good to
191
+		//allow the parent set method to have a say
192
+		parent::set('STS_ID', $new_STS_ID, $use_default);
193
+		return true;
194
+	}
195
+
196
+
197
+	/**
198
+	 * update REGs and TXN when cancelled or declined registrations involved
199
+	 *
200
+	 * @param string       $new_STS_ID
201
+	 * @param string       $old_STS_ID
202
+	 * @param ContextInterface|null $context
203
+	 * @throws EE_Error
204
+	 * @throws InvalidArgumentException
205
+	 * @throws InvalidDataTypeException
206
+	 * @throws InvalidInterfaceException
207
+	 * @throws ReflectionException
208
+	 */
209
+	private function _update_if_canceled_or_declined($new_STS_ID, $old_STS_ID, ContextInterface $context = null)
210
+	{
211
+		// these reg statuses should not be considered in any calculations involving monies owing
212
+		$closed_reg_statuses = EEM_Registration::closed_reg_statuses();
213
+		// true if registration has been cancelled or declined
214
+		$this->updateIfCanceled(
215
+			$closed_reg_statuses,
216
+			$new_STS_ID,
217
+			$old_STS_ID,
218
+			$context
219
+		);
220
+		$this->updateIfDeclined(
221
+			$closed_reg_statuses,
222
+			$new_STS_ID,
223
+			$old_STS_ID,
224
+			$context
225
+		);
226
+	}
227
+
228
+
229
+	/**
230
+	 * update REGs and TXN when cancelled or declined registrations involved
231
+	 *
232
+	 * @param array        $closed_reg_statuses
233
+	 * @param string       $new_STS_ID
234
+	 * @param string       $old_STS_ID
235
+	 * @param ContextInterface|null $context
236
+	 * @throws EE_Error
237
+	 * @throws InvalidArgumentException
238
+	 * @throws InvalidDataTypeException
239
+	 * @throws InvalidInterfaceException
240
+	 * @throws ReflectionException
241
+	 */
242
+	private function updateIfCanceled(array $closed_reg_statuses, $new_STS_ID, $old_STS_ID, ContextInterface $context = null)
243
+	{
244
+		// true if registration has been cancelled or declined
245
+		if (in_array($new_STS_ID, $closed_reg_statuses, true)
246
+			&& ! in_array($old_STS_ID, $closed_reg_statuses, true)
247
+		) {
248
+			/** @type EE_Registration_Processor $registration_processor */
249
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
250
+			/** @type EE_Transaction_Processor $transaction_processor */
251
+			$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
252
+			// cancelled or declined registration
253
+			$registration_processor->update_registration_after_being_canceled_or_declined(
254
+				$this,
255
+				$closed_reg_statuses
256
+			);
257
+			$transaction_processor->update_transaction_after_canceled_or_declined_registration(
258
+				$this,
259
+				$closed_reg_statuses,
260
+				false
261
+			);
262
+			do_action(
263
+				'AHEE__EE_Registration__set_status__canceled_or_declined',
264
+				$this,
265
+				$old_STS_ID,
266
+				$new_STS_ID,
267
+				$context
268
+			);
269
+			return;
270
+		}
271
+	}
272
+
273
+
274
+	/**
275
+	 * update REGs and TXN when cancelled or declined registrations involved
276
+	 *
277
+	 * @param array        $closed_reg_statuses
278
+	 * @param string       $new_STS_ID
279
+	 * @param string       $old_STS_ID
280
+	 * @param ContextInterface|null $context
281
+	 * @throws EE_Error
282
+	 * @throws InvalidArgumentException
283
+	 * @throws InvalidDataTypeException
284
+	 * @throws InvalidInterfaceException
285
+	 * @throws ReflectionException
286
+	 */
287
+	private function updateIfDeclined(array $closed_reg_statuses, $new_STS_ID, $old_STS_ID, ContextInterface $context = null)
288
+	{
289
+		// true if reinstating cancelled or declined registration
290
+		if (in_array($old_STS_ID, $closed_reg_statuses, true)
291
+			&& ! in_array($new_STS_ID, $closed_reg_statuses, true)
292
+		) {
293
+			/** @type EE_Registration_Processor $registration_processor */
294
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
295
+			/** @type EE_Transaction_Processor $transaction_processor */
296
+			$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
297
+			// reinstating cancelled or declined registration
298
+			$registration_processor->update_canceled_or_declined_registration_after_being_reinstated(
299
+				$this,
300
+				$closed_reg_statuses
301
+			);
302
+			$transaction_processor->update_transaction_after_reinstating_canceled_registration(
303
+				$this,
304
+				$closed_reg_statuses,
305
+				false
306
+			);
307
+			do_action(
308
+				'AHEE__EE_Registration__set_status__after_reinstated',
309
+				$this,
310
+				$old_STS_ID,
311
+				$new_STS_ID,
312
+				$context
313
+			);
314
+		}
315
+	}
316
+
317
+
318
+	/**
319
+	 * @param ContextInterface|null $context
320
+	 * @return bool
321
+	 */
322
+	private function statusChangeUpdatesTransaction(ContextInterface $context = null)
323
+	{
324
+		$contexts_that_do_not_update_transaction = (array) apply_filters(
325
+			'AHEE__EE_Registration__statusChangeUpdatesTransaction__contexts_that_do_not_update_transaction',
326
+			array('spco_reg_step_attendee_information_process_registrations'),
327
+			$context,
328
+			$this
329
+		);
330
+		return ! (
331
+			$context instanceof ContextInterface
332
+			&& in_array($context->slug(), $contexts_that_do_not_update_transaction, true)
333
+		);
334
+	}
335
+
336
+
337
+	/**
338
+	 * @throws EE_Error
339
+	 * @throws EntityNotFoundException
340
+	 * @throws InvalidArgumentException
341
+	 * @throws InvalidDataTypeException
342
+	 * @throws InvalidInterfaceException
343
+	 * @throws ReflectionException
344
+	 * @throws RuntimeException
345
+	 */
346
+	private function updateTransactionAfterStatusChange()
347
+	{
348
+		/** @type EE_Transaction_Payments $transaction_payments */
349
+		$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
350
+		$transaction_payments->recalculate_transaction_total($this->transaction(), false);
351
+		$this->transaction()->update_status_based_on_total_paid(true);
352
+	}
353
+
354
+
355
+	/**
356
+	 *        get Status ID
357
+	 */
358
+	public function status_ID()
359
+	{
360
+		return $this->get('STS_ID');
361
+	}
362
+
363
+
364
+	/**
365
+	 * increments this registration's related ticket sold and corresponding datetime sold values
366
+	 *
367
+	 * @return void
368
+	 * @throws EE_Error
369
+	 * @throws EntityNotFoundException
370
+	 */
371
+	private function _reserve_registration_space()
372
+	{
373
+		// reserved ticket and datetime counts will be decremented as sold counts are incremented
374
+		// so stop tracking that this reg has a ticket reserved
375
+		$this->release_reserved_ticket();
376
+		$ticket = $this->ticket();
377
+		$ticket->increase_sold();
378
+		$ticket->save();
379
+		// possibly set event status to sold out
380
+		$this->event()->perform_sold_out_status_check();
381
+	}
382
+
383
+
384
+	/**
385
+	 * Gets the ticket this registration is for
386
+	 *
387
+	 * @param boolean $include_archived whether to include archived tickets or not.
388
+	 *
389
+	 * @return EE_Ticket|EE_Base_Class
390
+	 * @throws EE_Error
391
+	 */
392
+	public function ticket($include_archived = true)
393
+	{
394
+		$query_params = array();
395
+		if ($include_archived) {
396
+			$query_params['default_where_conditions'] = 'none';
397
+		}
398
+		return $this->get_first_related('Ticket', $query_params);
399
+	}
400
+
401
+
402
+	/**
403
+	 * Gets the event this registration is for
404
+	 *
405
+	 * @return EE_Event
406
+	 * @throws EE_Error
407
+	 * @throws EntityNotFoundException
408
+	 */
409
+	public function event()
410
+	{
411
+		$event = $this->get_first_related('Event');
412
+		if (! $event instanceof \EE_Event) {
413
+			throw new EntityNotFoundException('Event ID', $this->event_ID());
414
+		}
415
+		return $event;
416
+	}
417
+
418
+
419
+	/**
420
+	 * Gets the "author" of the registration.  Note that for the purposes of registrations, the author will correspond
421
+	 * with the author of the event this registration is for.
422
+	 *
423
+	 * @since 4.5.0
424
+	 * @return int
425
+	 * @throws EE_Error
426
+	 * @throws EntityNotFoundException
427
+	 */
428
+	public function wp_user()
429
+	{
430
+		$event = $this->event();
431
+		if ($event instanceof EE_Event) {
432
+			return $event->wp_user();
433
+		}
434
+		return 0;
435
+	}
436
+
437
+
438
+	/**
439
+	 * decrements (subtracts) this registration's related ticket sold and corresponding datetime sold values
440
+	 *
441
+	 * @return void
442
+	 * @throws EE_Error
443
+	 */
444
+	private function _release_registration_space()
445
+	{
446
+		$ticket = $this->ticket();
447
+		$ticket->decrease_sold();
448
+		$ticket->save();
449
+	}
450
+
451
+
452
+	/**
453
+	 * tracks this registration's ticket reservation in extra meta
454
+	 * and can increment related ticket reserved and corresponding datetime reserved values
455
+	 *
456
+	 * @param bool $update_ticket if true, will increment ticket and datetime reserved count
457
+	 *
458
+	 * @return void
459
+	 * @throws EE_Error
460
+	 */
461
+	public function reserve_ticket($update_ticket = false)
462
+	{
463
+		if ($this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true, false) === false) {
464
+			// PLZ NOTE: although checking $update_ticket first would be more efficient,
465
+			// we NEED to ALWAYS call update_extra_meta(), which is why that is done first
466
+			if ($this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true, false) && $update_ticket) {
467
+				$ticket = $this->ticket();
468
+				$ticket->increase_reserved();
469
+				$ticket->save();
470
+			}
471
+		}
472
+	}
473
+
474
+
475
+	/**
476
+	 * stops tracking this registration's ticket reservation in extra meta
477
+	 * decrements (subtracts) related ticket reserved and corresponding datetime reserved values
478
+	 *
479
+	 * @param bool $update_ticket if true, will decrement ticket and datetime reserved count
480
+	 *
481
+	 * @return void
482
+	 * @throws EE_Error
483
+	 */
484
+	public function release_reserved_ticket($update_ticket = false)
485
+	{
486
+		if ($this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true, false) !== false) {
487
+			// PLZ NOTE: although checking $update_ticket first would be more efficient,
488
+			// we NEED to ALWAYS call delete_extra_meta(), which is why that is done first
489
+			if ($this->delete_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY) && $update_ticket) {
490
+				$ticket = $this->ticket();
491
+				$ticket->decrease_reserved();
492
+				$ticket->save();
493
+			}
494
+		}
495
+	}
496
+
497
+
498
+	/**
499
+	 * Set Attendee ID
500
+	 *
501
+	 * @param        int $ATT_ID Attendee ID
502
+	 * @throws EE_Error
503
+	 * @throws RuntimeException
504
+	 */
505
+	public function set_attendee_id($ATT_ID = 0)
506
+	{
507
+		$this->set('ATT_ID', $ATT_ID);
508
+	}
509
+
510
+
511
+	/**
512
+	 *        Set Transaction ID
513
+	 *
514
+	 * @param        int $TXN_ID Transaction ID
515
+	 * @throws EE_Error
516
+	 * @throws RuntimeException
517
+	 */
518
+	public function set_transaction_id($TXN_ID = 0)
519
+	{
520
+		$this->set('TXN_ID', $TXN_ID);
521
+	}
522
+
523
+
524
+	/**
525
+	 *        Set Session
526
+	 *
527
+	 * @param    string $REG_session PHP Session ID
528
+	 * @throws EE_Error
529
+	 * @throws RuntimeException
530
+	 */
531
+	public function set_session($REG_session = '')
532
+	{
533
+		$this->set('REG_session', $REG_session);
534
+	}
535
+
536
+
537
+	/**
538
+	 *        Set Registration URL Link
539
+	 *
540
+	 * @param    string $REG_url_link Registration URL Link
541
+	 * @throws EE_Error
542
+	 * @throws RuntimeException
543
+	 */
544
+	public function set_reg_url_link($REG_url_link = '')
545
+	{
546
+		$this->set('REG_url_link', $REG_url_link);
547
+	}
548
+
549
+
550
+	/**
551
+	 *        Set Attendee Counter
552
+	 *
553
+	 * @param        int $REG_count Primary Attendee
554
+	 * @throws EE_Error
555
+	 * @throws RuntimeException
556
+	 */
557
+	public function set_count($REG_count = 1)
558
+	{
559
+		$this->set('REG_count', $REG_count);
560
+	}
561
+
562
+
563
+	/**
564
+	 *        Set Group Size
565
+	 *
566
+	 * @param        boolean $REG_group_size Group Registration
567
+	 * @throws EE_Error
568
+	 * @throws RuntimeException
569
+	 */
570
+	public function set_group_size($REG_group_size = false)
571
+	{
572
+		$this->set('REG_group_size', $REG_group_size);
573
+	}
574
+
575
+
576
+	/**
577
+	 *    is_not_approved -  convenience method that returns TRUE if REG status ID ==
578
+	 *    EEM_Registration::status_id_not_approved
579
+	 *
580
+	 * @return        boolean
581
+	 */
582
+	public function is_not_approved()
583
+	{
584
+		return $this->status_ID() == EEM_Registration::status_id_not_approved ? true : false;
585
+	}
586
+
587
+
588
+	/**
589
+	 *    is_pending_payment -  convenience method that returns TRUE if REG status ID ==
590
+	 *    EEM_Registration::status_id_pending_payment
591
+	 *
592
+	 * @return        boolean
593
+	 */
594
+	public function is_pending_payment()
595
+	{
596
+		return $this->status_ID() == EEM_Registration::status_id_pending_payment ? true : false;
597
+	}
598
+
599
+
600
+	/**
601
+	 *    is_approved -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_approved
602
+	 *
603
+	 * @return        boolean
604
+	 */
605
+	public function is_approved()
606
+	{
607
+		return $this->status_ID() == EEM_Registration::status_id_approved ? true : false;
608
+	}
609
+
610
+
611
+	/**
612
+	 *    is_cancelled -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_cancelled
613
+	 *
614
+	 * @return        boolean
615
+	 */
616
+	public function is_cancelled()
617
+	{
618
+		return $this->status_ID() == EEM_Registration::status_id_cancelled ? true : false;
619
+	}
620
+
621
+
622
+	/**
623
+	 *    is_declined -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_declined
624
+	 *
625
+	 * @return        boolean
626
+	 */
627
+	public function is_declined()
628
+	{
629
+		return $this->status_ID() == EEM_Registration::status_id_declined ? true : false;
630
+	}
631
+
632
+
633
+	/**
634
+	 *    is_incomplete -  convenience method that returns TRUE if REG status ID ==
635
+	 *    EEM_Registration::status_id_incomplete
636
+	 *
637
+	 * @return        boolean
638
+	 */
639
+	public function is_incomplete()
640
+	{
641
+		return $this->status_ID() == EEM_Registration::status_id_incomplete ? true : false;
642
+	}
643
+
644
+
645
+	/**
646
+	 *        Set Registration Date
647
+	 *
648
+	 * @param        mixed ( int or string ) $REG_date Registration Date - Unix timestamp or string representation of
649
+	 *                                                 Date
650
+	 * @throws EE_Error
651
+	 * @throws RuntimeException
652
+	 */
653
+	public function set_reg_date($REG_date = false)
654
+	{
655
+		$this->set('REG_date', $REG_date);
656
+	}
657
+
658
+
659
+	/**
660
+	 *    Set final price owing for this registration after all ticket/price modifications
661
+	 *
662
+	 * @access    public
663
+	 * @param    float $REG_final_price
664
+	 * @throws EE_Error
665
+	 * @throws RuntimeException
666
+	 */
667
+	public function set_final_price($REG_final_price = 0.00)
668
+	{
669
+		$this->set('REG_final_price', $REG_final_price);
670
+	}
671
+
672
+
673
+	/**
674
+	 *    Set amount paid towards this registration's final price
675
+	 *
676
+	 * @access    public
677
+	 * @param    float $REG_paid
678
+	 * @throws EE_Error
679
+	 * @throws RuntimeException
680
+	 */
681
+	public function set_paid($REG_paid = 0.00)
682
+	{
683
+		$this->set('REG_paid', $REG_paid);
684
+	}
685
+
686
+
687
+	/**
688
+	 *        Attendee Is Going
689
+	 *
690
+	 * @param        boolean $REG_att_is_going Attendee Is Going
691
+	 * @throws EE_Error
692
+	 * @throws RuntimeException
693
+	 */
694
+	public function set_att_is_going($REG_att_is_going = false)
695
+	{
696
+		$this->set('REG_att_is_going', $REG_att_is_going);
697
+	}
698
+
699
+
700
+	/**
701
+	 * Gets the related attendee
702
+	 *
703
+	 * @return EE_Attendee
704
+	 * @throws EE_Error
705
+	 */
706
+	public function attendee()
707
+	{
708
+		return $this->get_first_related('Attendee');
709
+	}
710
+
711
+
712
+	/**
713
+	 *        get Event ID
714
+	 */
715
+	public function event_ID()
716
+	{
717
+		return $this->get('EVT_ID');
718
+	}
719
+
720
+
721
+	/**
722
+	 *        get Event ID
723
+	 */
724
+	public function event_name()
725
+	{
726
+		$event = $this->event_obj();
727
+		if ($event) {
728
+			return $event->name();
729
+		} else {
730
+			return null;
731
+		}
732
+	}
733
+
734
+
735
+	/**
736
+	 * Fetches the event this registration is for
737
+	 *
738
+	 * @return EE_Event
739
+	 * @throws EE_Error
740
+	 */
741
+	public function event_obj()
742
+	{
743
+		return $this->get_first_related('Event');
744
+	}
745
+
746
+
747
+	/**
748
+	 *        get Attendee ID
749
+	 */
750
+	public function attendee_ID()
751
+	{
752
+		return $this->get('ATT_ID');
753
+	}
754
+
755
+
756
+	/**
757
+	 *        get PHP Session ID
758
+	 */
759
+	public function session_ID()
760
+	{
761
+		return $this->get('REG_session');
762
+	}
763
+
764
+
765
+	/**
766
+	 * Gets the string which represents the URL trigger for the receipt template in the message template system.
767
+	 *
768
+	 * @param string $messenger 'pdf' or 'html'.  Default 'html'.
769
+	 * @return string
770
+	 */
771
+	public function receipt_url($messenger = 'html')
772
+	{
773
+
774
+		/**
775
+		 * The below will be deprecated one version after this.  We check first if there is a custom receipt template
776
+		 * already in use on old system.  If there is then we just return the standard url for it.
777
+		 *
778
+		 * @since 4.5.0
779
+		 */
780
+		$template_relative_path = 'modules/gateways/Invoice/lib/templates/receipt_body.template.php';
781
+		$has_custom             = EEH_Template::locate_template(
782
+			$template_relative_path,
783
+			array(),
784
+			true,
785
+			true,
786
+			true
787
+		);
788
+
789
+		if ($has_custom) {
790
+			return add_query_arg(array('receipt' => 'true'), $this->invoice_url('launch'));
791
+		}
792
+		return apply_filters('FHEE__EE_Registration__receipt_url__receipt_url', '', $this, $messenger, 'receipt');
793
+	}
794
+
795
+
796
+	/**
797
+	 * Gets the string which represents the URL trigger for the invoice template in the message template system.
798
+	 *
799
+	 * @param string $messenger 'pdf' or 'html'.  Default 'html'.
800
+	 * @return string
801
+	 * @throws EE_Error
802
+	 */
803
+	public function invoice_url($messenger = 'html')
804
+	{
805
+		/**
806
+		 * The below will be deprecated one version after this.  We check first if there is a custom invoice template
807
+		 * already in use on old system.  If there is then we just return the standard url for it.
808
+		 *
809
+		 * @since 4.5.0
810
+		 */
811
+		$template_relative_path = 'modules/gateways/Invoice/lib/templates/invoice_body.template.php';
812
+		$has_custom             = EEH_Template::locate_template(
813
+			$template_relative_path,
814
+			array(),
815
+			true,
816
+			true,
817
+			true
818
+		);
819
+
820
+		if ($has_custom) {
821
+			if ($messenger == 'html') {
822
+				return $this->invoice_url('launch');
823
+			}
824
+			$route = $messenger == 'download' || $messenger == 'pdf' ? 'download_invoice' : 'launch_invoice';
825
+
826
+			$query_args = array('ee' => $route, 'id' => $this->reg_url_link());
827
+			if ($messenger == 'html') {
828
+				$query_args['html'] = true;
829
+			}
830
+			return add_query_arg($query_args, get_permalink(EE_Registry::instance()->CFG->core->thank_you_page_id));
831
+		}
832
+		return apply_filters('FHEE__EE_Registration__invoice_url__invoice_url', '', $this, $messenger, 'invoice');
833
+	}
834
+
835
+
836
+	/**
837
+	 * get Registration URL Link
838
+	 *
839
+	 * @access public
840
+	 * @return string
841
+	 * @throws EE_Error
842
+	 */
843
+	public function reg_url_link()
844
+	{
845
+		return (string) $this->get('REG_url_link');
846
+	}
847
+
848
+
849
+	/**
850
+	 * Echoes out invoice_url()
851
+	 *
852
+	 * @param string $type 'download','launch', or 'html' (default is 'launch')
853
+	 * @return void
854
+	 * @throws EE_Error
855
+	 */
856
+	public function e_invoice_url($type = 'launch')
857
+	{
858
+		echo $this->invoice_url($type);
859
+	}
860
+
861
+
862
+	/**
863
+	 * Echoes out payment_overview_url
864
+	 */
865
+	public function e_payment_overview_url()
866
+	{
867
+		echo $this->payment_overview_url();
868
+	}
869
+
870
+
871
+	/**
872
+	 * Gets the URL of the thank you page with this registration REG_url_link added as
873
+	 * a query parameter
874
+	 *
875
+	 * @param bool $clear_session Set to true when you want to clear the session on revisiting the
876
+	 *                            payment overview url.
877
+	 * @return string
878
+	 * @throws EE_Error
879
+	 */
880
+	public function payment_overview_url($clear_session = false)
881
+	{
882
+		return add_query_arg(array(
883
+			'e_reg_url_link' => $this->reg_url_link(),
884
+			'step'           => 'payment_options',
885
+			'revisit'        => true,
886
+			'clear_session' => (bool) $clear_session
887
+		), EE_Registry::instance()->CFG->core->reg_page_url());
888
+	}
889
+
890
+
891
+	/**
892
+	 * Gets the URL of the thank you page with this registration REG_url_link added as
893
+	 * a query parameter
894
+	 *
895
+	 * @return string
896
+	 * @throws EE_Error
897
+	 */
898
+	public function edit_attendee_information_url()
899
+	{
900
+		return add_query_arg(array(
901
+			'e_reg_url_link' => $this->reg_url_link(),
902
+			'step'           => 'attendee_information',
903
+			'revisit'        => true,
904
+		), EE_Registry::instance()->CFG->core->reg_page_url());
905
+	}
906
+
907
+
908
+	/**
909
+	 * Simply generates and returns the appropriate admin_url link to edit this registration
910
+	 *
911
+	 * @return string
912
+	 * @throws EE_Error
913
+	 */
914
+	public function get_admin_edit_url()
915
+	{
916
+		return EEH_URL::add_query_args_and_nonce(array(
917
+			'page'    => 'espresso_registrations',
918
+			'action'  => 'view_registration',
919
+			'_REG_ID' => $this->ID(),
920
+		), admin_url('admin.php'));
921
+	}
922
+
923
+
924
+	/**
925
+	 *    is_primary_registrant?
926
+	 */
927
+	public function is_primary_registrant()
928
+	{
929
+		return $this->get('REG_count') == 1 ? true : false;
930
+	}
931
+
932
+
933
+	/**
934
+	 * This returns the primary registration object for this registration group (which may be this object).
935
+	 *
936
+	 * @return EE_Registration
937
+	 * @throws EE_Error
938
+	 */
939
+	public function get_primary_registration()
940
+	{
941
+		if ($this->is_primary_registrant()) {
942
+			return $this;
943
+		}
944
+
945
+		//k reg_count !== 1 so let's get the EE_Registration object matching this txn_id and reg_count == 1
946
+		/** @var EE_Registration $primary_registrant */
947
+		$primary_registrant = EEM_Registration::instance()->get_one(array(
948
+			array(
949
+				'TXN_ID'    => $this->transaction_ID(),
950
+				'REG_count' => 1,
951
+			),
952
+		));
953
+		return $primary_registrant;
954
+	}
955
+
956
+
957
+	/**
958
+	 *        get  Attendee Number
959
+	 *
960
+	 * @access        public
961
+	 */
962
+	public function count()
963
+	{
964
+		return $this->get('REG_count');
965
+	}
966
+
967
+
968
+	/**
969
+	 *        get Group Size
970
+	 */
971
+	public function group_size()
972
+	{
973
+		return $this->get('REG_group_size');
974
+	}
975
+
976
+
977
+	/**
978
+	 *        get Registration Date
979
+	 */
980
+	public function date()
981
+	{
982
+		return $this->get('REG_date');
983
+	}
984
+
985
+
986
+	/**
987
+	 * gets a pretty date
988
+	 *
989
+	 * @param string $date_format
990
+	 * @param string $time_format
991
+	 * @return string
992
+	 * @throws EE_Error
993
+	 */
994
+	public function pretty_date($date_format = null, $time_format = null)
995
+	{
996
+		return $this->get_datetime('REG_date', $date_format, $time_format);
997
+	}
998
+
999
+
1000
+	/**
1001
+	 * final_price
1002
+	 * the registration's share of the transaction total, so that the
1003
+	 * sum of all the transaction's REG_final_prices equal the transaction's total
1004
+	 *
1005
+	 * @return float
1006
+	 * @throws EE_Error
1007
+	 */
1008
+	public function final_price()
1009
+	{
1010
+		return $this->get('REG_final_price');
1011
+	}
1012
+
1013
+
1014
+	/**
1015
+	 * pretty_final_price
1016
+	 *  final price as formatted string, with correct decimal places and currency symbol
1017
+	 *
1018
+	 * @return string
1019
+	 * @throws EE_Error
1020
+	 */
1021
+	public function pretty_final_price()
1022
+	{
1023
+		return $this->get_pretty('REG_final_price');
1024
+	}
1025
+
1026
+
1027
+	/**
1028
+	 * get paid (yeah)
1029
+	 *
1030
+	 * @return float
1031
+	 * @throws EE_Error
1032
+	 */
1033
+	public function paid()
1034
+	{
1035
+		return $this->get('REG_paid');
1036
+	}
1037
+
1038
+
1039
+	/**
1040
+	 * pretty_paid
1041
+	 *
1042
+	 * @return float
1043
+	 * @throws EE_Error
1044
+	 */
1045
+	public function pretty_paid()
1046
+	{
1047
+		return $this->get_pretty('REG_paid');
1048
+	}
1049
+
1050
+
1051
+	/**
1052
+	 * owes_monies_and_can_pay
1053
+	 * whether or not this registration has monies owing and it's' status allows payment
1054
+	 *
1055
+	 * @param array $requires_payment
1056
+	 * @return bool
1057
+	 * @throws EE_Error
1058
+	 */
1059
+	public function owes_monies_and_can_pay($requires_payment = array())
1060
+	{
1061
+		// these reg statuses require payment (if event is not free)
1062
+		$requires_payment = ! empty($requires_payment)
1063
+			? $requires_payment
1064
+			: EEM_Registration::reg_statuses_that_allow_payment();
1065
+		if (in_array($this->status_ID(), $requires_payment) &&
1066
+			$this->final_price() != 0 &&
1067
+			$this->final_price() != $this->paid()
1068
+		) {
1069
+			return true;
1070
+		} else {
1071
+			return false;
1072
+		}
1073
+	}
1074
+
1075
+
1076
+	/**
1077
+	 * Prints out the return value of $this->pretty_status()
1078
+	 *
1079
+	 * @param bool $show_icons
1080
+	 * @return void
1081
+	 * @throws EE_Error
1082
+	 */
1083
+	public function e_pretty_status($show_icons = false)
1084
+	{
1085
+		echo $this->pretty_status($show_icons);
1086
+	}
1087
+
1088
+
1089
+	/**
1090
+	 * Returns a nice version of the status for displaying to customers
1091
+	 *
1092
+	 * @param bool $show_icons
1093
+	 * @return string
1094
+	 * @throws EE_Error
1095
+	 */
1096
+	public function pretty_status($show_icons = false)
1097
+	{
1098
+		$status = EEM_Status::instance()->localized_status(
1099
+			array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
1100
+			false,
1101
+			'sentence'
1102
+		);
1103
+		$icon   = '';
1104
+		switch ($this->status_ID()) {
1105
+			case EEM_Registration::status_id_approved:
1106
+				$icon = $show_icons
1107
+					? '<span class="dashicons dashicons-star-filled ee-icon-size-16 green-text"></span>'
1108
+					: '';
1109
+				break;
1110
+			case EEM_Registration::status_id_pending_payment:
1111
+				$icon = $show_icons
1112
+					? '<span class="dashicons dashicons-star-half ee-icon-size-16 orange-text"></span>'
1113
+					: '';
1114
+				break;
1115
+			case EEM_Registration::status_id_not_approved:
1116
+				$icon = $show_icons
1117
+					? '<span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>'
1118
+					: '';
1119
+				break;
1120
+			case EEM_Registration::status_id_cancelled:
1121
+				$icon = $show_icons
1122
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
1123
+					: '';
1124
+				break;
1125
+			case EEM_Registration::status_id_incomplete:
1126
+				$icon = $show_icons
1127
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-orange-text"></span>'
1128
+					: '';
1129
+				break;
1130
+			case EEM_Registration::status_id_declined:
1131
+				$icon = $show_icons
1132
+					? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
1133
+					: '';
1134
+				break;
1135
+			case EEM_Registration::status_id_wait_list:
1136
+				$icon = $show_icons
1137
+					? '<span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>'
1138
+					: '';
1139
+				break;
1140
+		}
1141
+		return $icon . $status[$this->status_ID()];
1142
+	}
1143
+
1144
+
1145
+	/**
1146
+	 *        get Attendee Is Going
1147
+	 */
1148
+	public function att_is_going()
1149
+	{
1150
+		return $this->get('REG_att_is_going');
1151
+	}
1152
+
1153
+
1154
+	/**
1155
+	 * Gets related answers
1156
+	 *
1157
+	 * @param array $query_params like EEM_Base::get_all
1158
+	 * @return EE_Answer[]
1159
+	 * @throws EE_Error
1160
+	 */
1161
+	public function answers($query_params = null)
1162
+	{
1163
+		return $this->get_many_related('Answer', $query_params);
1164
+	}
1165
+
1166
+
1167
+	/**
1168
+	 * Gets the registration's answer value to the specified question
1169
+	 * (either the question's ID or a question object)
1170
+	 *
1171
+	 * @param EE_Question|int $question
1172
+	 * @param bool            $pretty_value
1173
+	 * @return array|string if pretty_value= true, the result will always be a string
1174
+	 * (because the answer might be an array of answer values, so passing pretty_value=true
1175
+	 * will convert it into some kind of string)
1176
+	 * @throws EE_Error
1177
+	 */
1178
+	public function answer_value_to_question($question, $pretty_value = true)
1179
+	{
1180
+		$question_id = EEM_Question::instance()->ensure_is_ID($question);
1181
+		return EEM_Answer::instance()->get_answer_value_to_question($this, $question_id, $pretty_value);
1182
+	}
1183
+
1184
+
1185
+	/**
1186
+	 * question_groups
1187
+	 * returns an array of EE_Question_Group objects for this registration
1188
+	 *
1189
+	 * @return EE_Question_Group[]
1190
+	 * @throws EE_Error
1191
+	 * @throws EntityNotFoundException
1192
+	 */
1193
+	public function question_groups()
1194
+	{
1195
+		$question_groups = array();
1196
+		if ($this->event() instanceof EE_Event) {
1197
+			$question_groups = $this->event()->question_groups(
1198
+				array(
1199
+					array(
1200
+						'Event_Question_Group.EQG_primary' => $this->count() == 1 ? true : false,
1201
+					),
1202
+					'order_by' => array('QSG_order' => 'ASC'),
1203
+				)
1204
+			);
1205
+		}
1206
+		return $question_groups;
1207
+	}
1208
+
1209
+
1210
+	/**
1211
+	 * count_question_groups
1212
+	 * returns a count of the number of EE_Question_Group objects for this registration
1213
+	 *
1214
+	 * @return int
1215
+	 * @throws EE_Error
1216
+	 * @throws EntityNotFoundException
1217
+	 */
1218
+	public function count_question_groups()
1219
+	{
1220
+		$qg_count = 0;
1221
+		if ($this->event() instanceof EE_Event) {
1222
+			$qg_count = $this->event()->count_related(
1223
+				'Question_Group',
1224
+				array(
1225
+					array(
1226
+						'Event_Question_Group.EQG_primary' => $this->count() == 1 ? true : false,
1227
+					),
1228
+				)
1229
+			);
1230
+		}
1231
+		return $qg_count;
1232
+	}
1233
+
1234
+
1235
+	/**
1236
+	 * Returns the registration date in the 'standard' string format
1237
+	 * (function may be improved in the future to allow for different formats and timezones)
1238
+	 *
1239
+	 * @return string
1240
+	 * @throws EE_Error
1241
+	 */
1242
+	public function reg_date()
1243
+	{
1244
+		return $this->get_datetime('REG_date');
1245
+	}
1246
+
1247
+
1248
+	/**
1249
+	 * Gets the datetime-ticket for this registration (ie, it can be used to isolate
1250
+	 * the ticket this registration purchased, or the datetime they have registered
1251
+	 * to attend)
1252
+	 *
1253
+	 * @return EE_Datetime_Ticket
1254
+	 * @throws EE_Error
1255
+	 */
1256
+	public function datetime_ticket()
1257
+	{
1258
+		return $this->get_first_related('Datetime_Ticket');
1259
+	}
1260
+
1261
+
1262
+	/**
1263
+	 * Sets the registration's datetime_ticket.
1264
+	 *
1265
+	 * @param EE_Datetime_Ticket $datetime_ticket
1266
+	 * @return EE_Datetime_Ticket
1267
+	 * @throws EE_Error
1268
+	 */
1269
+	public function set_datetime_ticket($datetime_ticket)
1270
+	{
1271
+		return $this->_add_relation_to($datetime_ticket, 'Datetime_Ticket');
1272
+	}
1273
+
1274
+	/**
1275
+	 * Gets deleted
1276
+	 *
1277
+	 * @return bool
1278
+	 * @throws EE_Error
1279
+	 */
1280
+	public function deleted()
1281
+	{
1282
+		return $this->get('REG_deleted');
1283
+	}
1284
+
1285
+	/**
1286
+	 * Sets deleted
1287
+	 *
1288
+	 * @param boolean $deleted
1289
+	 * @return bool
1290
+	 * @throws EE_Error
1291
+	 * @throws RuntimeException
1292
+	 */
1293
+	public function set_deleted($deleted)
1294
+	{
1295
+		if ($deleted) {
1296
+			$this->delete();
1297
+		} else {
1298
+			$this->restore();
1299
+		}
1300
+	}
1301
+
1302
+
1303
+	/**
1304
+	 * Get the status object of this object
1305
+	 *
1306
+	 * @return EE_Status
1307
+	 * @throws EE_Error
1308
+	 */
1309
+	public function status_obj()
1310
+	{
1311
+		return $this->get_first_related('Status');
1312
+	}
1313
+
1314
+
1315
+	/**
1316
+	 * Returns the number of times this registration has checked into any of the datetimes
1317
+	 * its available for
1318
+	 *
1319
+	 * @return int
1320
+	 * @throws EE_Error
1321
+	 */
1322
+	public function count_checkins()
1323
+	{
1324
+		return $this->get_model()->count_related($this, 'Checkin');
1325
+	}
1326
+
1327
+
1328
+	/**
1329
+	 * Returns the number of current Check-ins this registration is checked into for any of the datetimes the
1330
+	 * registration is for.  Note, this is ONLY checked in (does not include checkedout)
1331
+	 *
1332
+	 * @return int
1333
+	 * @throws EE_Error
1334
+	 */
1335
+	public function count_checkins_not_checkedout()
1336
+	{
1337
+		return $this->get_model()->count_related($this, 'Checkin', array(array('CHK_in' => 1)));
1338
+	}
1339
+
1340
+
1341
+	/**
1342
+	 * The purpose of this method is simply to check whether this registration can checkin to the given datetime.
1343
+	 *
1344
+	 * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1345
+	 * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1346
+	 *                                          consider registration status as well as datetime access.
1347
+	 * @return bool
1348
+	 * @throws EE_Error
1349
+	 */
1350
+	public function can_checkin($DTT_OR_ID, $check_approved = true)
1351
+	{
1352
+		$DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1353
+
1354
+		//first check registration status
1355
+		if (($check_approved && ! $this->is_approved()) || ! $DTT_ID) {
1356
+			return false;
1357
+		}
1358
+		//is there a datetime ticket that matches this dtt_ID?
1359
+		if (! (EEM_Datetime_Ticket::instance()->exists(array(
1360
+			array(
1361
+				'TKT_ID' => $this->get('TKT_ID'),
1362
+				'DTT_ID' => $DTT_ID,
1363
+			),
1364
+		)))
1365
+		) {
1366
+			return false;
1367
+		}
1368
+
1369
+		//final check is against TKT_uses
1370
+		return $this->verify_can_checkin_against_TKT_uses($DTT_ID);
1371
+	}
1372
+
1373
+
1374
+	/**
1375
+	 * This method verifies whether the user can checkin for the given datetime considering the max uses value set on
1376
+	 * the ticket. To do this,  a query is done to get the count of the datetime records already checked into.  If the
1377
+	 * datetime given does not have a check-in record and checking in for that datetime will exceed the allowed uses,
1378
+	 * then return false.  Otherwise return true.
1379
+	 *
1380
+	 * @param int | EE_Datetime $DTT_OR_ID The datetime the registration is being checked against
1381
+	 * @return bool true means can checkin.  false means cannot checkin.
1382
+	 * @throws EE_Error
1383
+	 */
1384
+	public function verify_can_checkin_against_TKT_uses($DTT_OR_ID)
1385
+	{
1386
+		$DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1387
+
1388
+		if (! $DTT_ID) {
1389
+			return false;
1390
+		}
1391
+
1392
+		$max_uses = $this->ticket() instanceof EE_Ticket ? $this->ticket()->uses() : EE_INF;
1393
+
1394
+		// if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1395
+		// check-in or not.
1396
+		if (! $max_uses || $max_uses === EE_INF) {
1397
+			return true;
1398
+		}
1399
+
1400
+		//does this datetime have a checkin record?  If so, then the dtt count has already been verified so we can just
1401
+		//go ahead and toggle.
1402
+		if (EEM_Checkin::instance()->exists(array(array('REG_ID' => $this->ID(), 'DTT_ID' => $DTT_ID)))) {
1403
+			return true;
1404
+		}
1405
+
1406
+		//made it here so the last check is whether the number of checkins per unique datetime on this registration
1407
+		//disallows further check-ins.
1408
+		$count_unique_dtt_checkins = EEM_Checkin::instance()->count(array(
1409
+			array(
1410
+				'REG_ID' => $this->ID(),
1411
+				'CHK_in' => true,
1412
+			),
1413
+		), 'DTT_ID', true);
1414
+		// checkins have already reached their max number of uses
1415
+		// so registrant can NOT checkin
1416
+		if ($count_unique_dtt_checkins >= $max_uses) {
1417
+			EE_Error::add_error(
1418
+				esc_html__(
1419
+					'Check-in denied because number of datetime uses for the ticket has been reached or exceeded.',
1420
+					'event_espresso'
1421
+				),
1422
+				__FILE__,
1423
+				__FUNCTION__,
1424
+				__LINE__
1425
+			);
1426
+			return false;
1427
+		}
1428
+		return true;
1429
+	}
1430
+
1431
+
1432
+	/**
1433
+	 * toggle Check-in status for this registration
1434
+	 * Check-ins are toggled in the following order:
1435
+	 * never checked in -> checked in
1436
+	 * checked in -> checked out
1437
+	 * checked out -> checked in
1438
+	 *
1439
+	 * @param  int $DTT_ID  include specific datetime to toggle Check-in for.
1440
+	 *                      If not included or null, then it is assumed latest datetime is being toggled.
1441
+	 * @param bool $verify  If true then can_checkin() is used to verify whether the person
1442
+	 *                      can be checked in or not.  Otherwise this forces change in checkin status.
1443
+	 * @return bool|int     the chk_in status toggled to OR false if nothing got changed.
1444
+	 * @throws EE_Error
1445
+	 */
1446
+	public function toggle_checkin_status($DTT_ID = null, $verify = false)
1447
+	{
1448
+		if (empty($DTT_ID)) {
1449
+			$datetime = $this->get_latest_related_datetime();
1450
+			$DTT_ID   = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1451
+			// verify the registration can checkin for the given DTT_ID
1452
+		} elseif (! $this->can_checkin($DTT_ID, $verify)) {
1453
+			EE_Error::add_error(
1454
+				sprintf(
1455
+					esc_html__(
1456
+						'The given registration (ID:%1$d) can not be checked in to the given DTT_ID (%2$d), because the registration does not have access',
1457
+						'event_espresso'
1458
+					),
1459
+					$this->ID(),
1460
+					$DTT_ID
1461
+				),
1462
+				__FILE__,
1463
+				__FUNCTION__,
1464
+				__LINE__
1465
+			);
1466
+			return false;
1467
+		}
1468
+		$status_paths = array(
1469
+			EE_Checkin::status_checked_never => EE_Checkin::status_checked_in,
1470
+			EE_Checkin::status_checked_in    => EE_Checkin::status_checked_out,
1471
+			EE_Checkin::status_checked_out   => EE_Checkin::status_checked_in,
1472
+		);
1473
+		//start by getting the current status so we know what status we'll be changing to.
1474
+		$cur_status = $this->check_in_status_for_datetime($DTT_ID, null);
1475
+		$status_to  = $status_paths[$cur_status];
1476
+		// database only records true for checked IN or false for checked OUT
1477
+		// no record ( null ) means checked in NEVER, but we obviously don't save that
1478
+		$new_status = $status_to === EE_Checkin::status_checked_in ? true : false;
1479
+		// add relation - note Check-ins are always creating new rows
1480
+		// because we are keeping track of Check-ins over time.
1481
+		// Eventually we'll probably want to show a list table
1482
+		// for the individual Check-ins so that they can be managed.
1483
+		$checkin = EE_Checkin::new_instance(array(
1484
+			'REG_ID' => $this->ID(),
1485
+			'DTT_ID' => $DTT_ID,
1486
+			'CHK_in' => $new_status,
1487
+		));
1488
+		// if the record could not be saved then return false
1489
+		if ($checkin->save() === 0) {
1490
+			if (WP_DEBUG) {
1491
+				global $wpdb;
1492
+				$error = sprintf(
1493
+					esc_html__(
1494
+						'Registration check in update failed because of the following database error: %1$s%2$s',
1495
+						'event_espresso'
1496
+					),
1497
+					'<br />',
1498
+					$wpdb->last_error
1499
+				);
1500
+			} else {
1501
+				$error = esc_html__(
1502
+					'Registration check in update failed because of an unknown database error',
1503
+					'event_espresso'
1504
+				);
1505
+			}
1506
+			EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
1507
+			return false;
1508
+		}
1509
+		return $status_to;
1510
+	}
1511
+
1512
+
1513
+	/**
1514
+	 * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1515
+	 * "Latest" is defined by the `DTT_EVT_start` column.
1516
+	 *
1517
+	 * @return EE_Datetime|null
1518
+	 * @throws EE_Error
1519
+	 */
1520
+	public function get_latest_related_datetime()
1521
+	{
1522
+		return EEM_Datetime::instance()->get_one(
1523
+			array(
1524
+				array(
1525
+					'Ticket.Registration.REG_ID' => $this->ID(),
1526
+				),
1527
+				'order_by' => array('DTT_EVT_start' => 'DESC'),
1528
+			)
1529
+		);
1530
+	}
1531
+
1532
+
1533
+	/**
1534
+	 * Returns the earliest datetime related to this registration (via the ticket attached to the registration).
1535
+	 * "Earliest" is defined by the `DTT_EVT_start` column.
1536
+	 *
1537
+	 * @throws EE_Error
1538
+	 */
1539
+	public function get_earliest_related_datetime()
1540
+	{
1541
+		return EEM_Datetime::instance()->get_one(
1542
+			array(
1543
+				array(
1544
+					'Ticket.Registration.REG_ID' => $this->ID(),
1545
+				),
1546
+				'order_by' => array('DTT_EVT_start' => 'ASC'),
1547
+			)
1548
+		);
1549
+	}
1550
+
1551
+
1552
+	/**
1553
+	 * This method simply returns the check-in status for this registration and the given datetime.
1554
+	 * If neither the datetime nor the checkin values are provided as arguments,
1555
+	 * then this will return the LATEST check-in status for the registration across all datetimes it belongs to.
1556
+	 *
1557
+	 * @param  int       $DTT_ID  The ID of the datetime we're checking against
1558
+	 *                            (if empty we'll get the primary datetime for
1559
+	 *                            this registration (via event) and use it's ID);
1560
+	 * @param EE_Checkin $checkin If present, we use the given checkin object rather than the dtt_id.
1561
+	 *
1562
+	 * @return int                Integer representing Check-in status.
1563
+	 * @throws EE_Error
1564
+	 */
1565
+	public function check_in_status_for_datetime($DTT_ID = 0, $checkin = null)
1566
+	{
1567
+		$checkin_query_params = array(
1568
+			'order_by' => array('CHK_timestamp' => 'DESC'),
1569
+		);
1570
+
1571
+		if ($DTT_ID > 0) {
1572
+			$checkin_query_params[0] = array('DTT_ID' => $DTT_ID);
1573
+		}
1574
+
1575
+		//get checkin object (if exists)
1576
+		$checkin = $checkin instanceof EE_Checkin
1577
+			? $checkin
1578
+			: $this->get_first_related('Checkin', $checkin_query_params);
1579
+		if ($checkin instanceof EE_Checkin) {
1580
+			if ($checkin->get('CHK_in')) {
1581
+				return EE_Checkin::status_checked_in; //checked in
1582
+			}
1583
+			return EE_Checkin::status_checked_out; //had checked in but is now checked out.
1584
+		}
1585
+		return EE_Checkin::status_checked_never; //never been checked in
1586
+	}
1587
+
1588
+
1589
+	/**
1590
+	 * This method returns a localized message for the toggled Check-in message.
1591
+	 *
1592
+	 * @param  int $DTT_ID include specific datetime to get the correct Check-in message.  If not included or null,
1593
+	 *                     then it is assumed Check-in for primary datetime was toggled.
1594
+	 * @param bool $error  This just flags that you want an error message returned. This is put in so that the error
1595
+	 *                     message can be customized with the attendee name.
1596
+	 * @return string internationalized message
1597
+	 * @throws EE_Error
1598
+	 */
1599
+	public function get_checkin_msg($DTT_ID, $error = false)
1600
+	{
1601
+		//let's get the attendee first so we can include the name of the attendee
1602
+		$attendee = $this->get_first_related('Attendee');
1603
+		if ($attendee instanceof EE_Attendee) {
1604
+			if ($error) {
1605
+				return sprintf(__("%s's check-in status was not changed.", "event_espresso"), $attendee->full_name());
1606
+			}
1607
+			$cur_status = $this->check_in_status_for_datetime($DTT_ID);
1608
+			//what is the status message going to be?
1609
+			switch ($cur_status) {
1610
+				case EE_Checkin::status_checked_never:
1611
+					return sprintf(__("%s has been removed from Check-in records", "event_espresso"),
1612
+						$attendee->full_name());
1613
+					break;
1614
+				case EE_Checkin::status_checked_in:
1615
+					return sprintf(__('%s has been checked in', 'event_espresso'), $attendee->full_name());
1616
+					break;
1617
+				case EE_Checkin::status_checked_out:
1618
+					return sprintf(__('%s has been checked out', 'event_espresso'), $attendee->full_name());
1619
+					break;
1620
+			}
1621
+		}
1622
+		return esc_html__("The check-in status could not be determined.", "event_espresso");
1623
+	}
1624
+
1625
+
1626
+	/**
1627
+	 * Returns the related EE_Transaction to this registration
1628
+	 *
1629
+	 * @return EE_Transaction
1630
+	 * @throws EE_Error
1631
+	 * @throws EntityNotFoundException
1632
+	 */
1633
+	public function transaction()
1634
+	{
1635
+		$transaction = $this->get_first_related('Transaction');
1636
+		if (! $transaction instanceof \EE_Transaction) {
1637
+			throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
1638
+		}
1639
+		return $transaction;
1640
+	}
1641
+
1642
+
1643
+	/**
1644
+	 *        get Registration Code
1645
+	 */
1646
+	public function reg_code()
1647
+	{
1648
+		return $this->get('REG_code');
1649
+	}
1650
+
1651
+
1652
+	/**
1653
+	 *        get Transaction ID
1654
+	 */
1655
+	public function transaction_ID()
1656
+	{
1657
+		return $this->get('TXN_ID');
1658
+	}
1659
+
1660
+
1661
+	/**
1662
+	 * @return int
1663
+	 * @throws EE_Error
1664
+	 */
1665
+	public function ticket_ID()
1666
+	{
1667
+		return $this->get('TKT_ID');
1668
+	}
1669
+
1670
+
1671
+	/**
1672
+	 *        Set Registration Code
1673
+	 *
1674
+	 * @access    public
1675
+	 * @param    string  $REG_code Registration Code
1676
+	 * @param    boolean $use_default
1677
+	 * @throws EE_Error
1678
+	 */
1679
+	public function set_reg_code($REG_code, $use_default = false)
1680
+	{
1681
+		if (empty($REG_code)) {
1682
+			EE_Error::add_error(
1683
+				esc_html__('REG_code can not be empty.', 'event_espresso'),
1684
+				__FILE__,
1685
+				__FUNCTION__,
1686
+				__LINE__
1687
+			);
1688
+			return;
1689
+		}
1690
+		if (! $this->reg_code()) {
1691
+			parent::set('REG_code', $REG_code, $use_default);
1692
+		} else {
1693
+			EE_Error::doing_it_wrong(
1694
+				__CLASS__ . '::' . __FUNCTION__,
1695
+				esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
1696
+				'4.6.0'
1697
+			);
1698
+		}
1699
+	}
1700
+
1701
+
1702
+	/**
1703
+	 * Returns all other registrations in the same group as this registrant who have the same ticket option.
1704
+	 * Note, if you want to just get all registrations in the same transaction (group), use:
1705
+	 *    $registration->transaction()->registrations();
1706
+	 *
1707
+	 * @since 4.5.0
1708
+	 * @return EE_Registration[] or empty array if this isn't a group registration.
1709
+	 * @throws EE_Error
1710
+	 */
1711
+	public function get_all_other_registrations_in_group()
1712
+	{
1713
+		if ($this->group_size() < 2) {
1714
+			return array();
1715
+		}
1716
+
1717
+		$query[0] = array(
1718
+			'TXN_ID' => $this->transaction_ID(),
1719
+			'REG_ID' => array('!=', $this->ID()),
1720
+			'TKT_ID' => $this->ticket_ID(),
1721
+		);
1722
+		/** @var EE_Registration[] $registrations */
1723
+		$registrations = $this->get_model()->get_all($query);
1724
+		return $registrations;
1725
+	}
1726
+
1727
+	/**
1728
+	 * Return the link to the admin details for the object.
1729
+	 *
1730
+	 * @return string
1731
+	 * @throws EE_Error
1732
+	 */
1733
+	public function get_admin_details_link()
1734
+	{
1735
+		EE_Registry::instance()->load_helper('URL');
1736
+		return EEH_URL::add_query_args_and_nonce(
1737
+			array(
1738
+				'page'    => 'espresso_registrations',
1739
+				'action'  => 'view_registration',
1740
+				'_REG_ID' => $this->ID(),
1741
+			),
1742
+			admin_url('admin.php')
1743
+		);
1744
+	}
1745
+
1746
+	/**
1747
+	 * Returns the link to the editor for the object.  Sometimes this is the same as the details.
1748
+	 *
1749
+	 * @return string
1750
+	 * @throws EE_Error
1751
+	 */
1752
+	public function get_admin_edit_link()
1753
+	{
1754
+		return $this->get_admin_details_link();
1755
+	}
1756
+
1757
+	/**
1758
+	 * Returns the link to a settings page for the object.
1759
+	 *
1760
+	 * @return string
1761
+	 * @throws EE_Error
1762
+	 */
1763
+	public function get_admin_settings_link()
1764
+	{
1765
+		return $this->get_admin_details_link();
1766
+	}
1767
+
1768
+	/**
1769
+	 * Returns the link to the "overview" for the object (typically the "list table" view).
1770
+	 *
1771
+	 * @return string
1772
+	 */
1773
+	public function get_admin_overview_link()
1774
+	{
1775
+		EE_Registry::instance()->load_helper('URL');
1776
+		return EEH_URL::add_query_args_and_nonce(
1777
+			array(
1778
+				'page' => 'espresso_registrations',
1779
+			),
1780
+			admin_url('admin.php')
1781
+		);
1782
+	}
1783
+
1784
+
1785
+	/**
1786
+	 * @param array $query_params
1787
+	 *
1788
+	 * @return \EE_Registration[]
1789
+	 * @throws EE_Error
1790
+	 */
1791
+	public function payments($query_params = array())
1792
+	{
1793
+		return $this->get_many_related('Payment', $query_params);
1794
+	}
1795
+
1796
+
1797
+	/**
1798
+	 * @param array $query_params
1799
+	 *
1800
+	 * @return \EE_Registration_Payment[]
1801
+	 * @throws EE_Error
1802
+	 */
1803
+	public function registration_payments($query_params = array())
1804
+	{
1805
+		return $this->get_many_related('Registration_Payment', $query_params);
1806
+	}
1807
+
1808
+
1809
+	/**
1810
+	 * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
1811
+	 * Note: if there are no payments on the registration there will be no payment method returned.
1812
+	 *
1813
+	 * @return EE_Payment_Method|null
1814
+	 */
1815
+	public function payment_method()
1816
+	{
1817
+		return EEM_Payment_Method::instance()->get_last_used_for_registration($this);
1818
+	}
1819
+
1820
+
1821
+	/**
1822
+	 * @return \EE_Line_Item
1823
+	 * @throws EntityNotFoundException
1824
+	 * @throws EE_Error
1825
+	 */
1826
+	public function ticket_line_item()
1827
+	{
1828
+		$ticket            = $this->ticket();
1829
+		$transaction       = $this->transaction();
1830
+		$line_item         = null;
1831
+		$ticket_line_items = \EEH_Line_Item::get_line_items_by_object_type_and_IDs(
1832
+			$transaction->total_line_item(),
1833
+			'Ticket',
1834
+			array($ticket->ID())
1835
+		);
1836
+		foreach ($ticket_line_items as $ticket_line_item) {
1837
+			if (
1838
+				$ticket_line_item instanceof \EE_Line_Item
1839
+				&& $ticket_line_item->OBJ_type() === 'Ticket'
1840
+				&& $ticket_line_item->OBJ_ID() === $ticket->ID()
1841
+			) {
1842
+				$line_item = $ticket_line_item;
1843
+				break;
1844
+			}
1845
+		}
1846
+		if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
1847
+			throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
1848
+		}
1849
+		return $line_item;
1850
+	}
1851
+
1852
+
1853
+	/**
1854
+	 * Soft Deletes this model object.
1855
+	 *
1856
+	 * @return boolean | int
1857
+	 * @throws RuntimeException
1858
+	 * @throws EE_Error
1859
+	 */
1860
+	public function delete()
1861
+	{
1862
+		if ($this->update_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY, $this->status_ID()) === true) {
1863
+			$this->set_status(EEM_Registration::status_id_cancelled);
1864
+		}
1865
+		return parent::delete();
1866
+	}
1867
+
1868
+
1869
+	/**
1870
+	 * Restores whatever the previous status was on a registration before it was trashed (if possible)
1871
+	 *
1872
+	 * @throws EE_Error
1873
+	 * @throws RuntimeException
1874
+	 */
1875
+	public function restore()
1876
+	{
1877
+		$previous_status = $this->get_extra_meta(
1878
+			EE_Registration::PRE_TRASH_REG_STATUS_KEY,
1879
+			true,
1880
+			EEM_Registration::status_id_cancelled
1881
+		);
1882
+		if ($previous_status) {
1883
+			$this->delete_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY);
1884
+			$this->set_status($previous_status);
1885
+		}
1886
+		return parent::restore();
1887
+	}
1888
+
1889
+
1890
+	/**
1891
+	 * possibly toggle Registration status based on comparison of REG_paid vs REG_final_price
1892
+	 *
1893
+	 * @param  boolean $trigger_set_status_logic EE_Registration::set_status() can trigger additional logic
1894
+	 *                                           depending on whether the reg status changes to or from "Approved"
1895
+	 * @return boolean whether the Registration status was updated
1896
+	 * @throws EE_Error
1897
+	 * @throws RuntimeException
1898
+	 */
1899
+	public function updateStatusBasedOnTotalPaid($trigger_set_status_logic = true)
1900
+	{
1901
+		$paid = $this->paid();
1902
+		$price = $this->final_price();
1903
+		switch(true) {
1904
+			// overpaid or paid
1905
+			case EEH_Money::compare_floats($paid, $price, '>'):
1906
+			case EEH_Money::compare_floats($paid, $price):
1907
+				$new_status = EEM_Registration::status_id_approved;
1908
+				break;
1909
+			//  underpaid
1910
+			case EEH_Money::compare_floats($paid, $price, '<'):
1911
+				$new_status = EEM_Registration::status_id_pending_payment;
1912
+				break;
1913
+			// uhhh Houston...
1914
+			default:
1915
+				throw new RuntimeException(
1916
+					esc_html__('The total paid calculation for this registration is inaccurate.', 'event_espresso')
1917
+				);
1918
+		}
1919
+		if ($new_status !== $this->status_ID()) {
1920
+			if ($trigger_set_status_logic) {
1921
+				return $this->set_status($new_status);
1922
+			}
1923
+			parent::set('STS_ID', $new_status);
1924
+			return true;
1925
+		}
1926
+		return false;
1927
+	}
1928
+
1929
+
1930
+	/*************************** DEPRECATED ***************************/
1931
+
1932
+
1933
+	/**
1934
+	 * @deprecated
1935
+	 * @since     4.7.0
1936
+	 * @access    public
1937
+	 */
1938
+	public function price_paid()
1939
+	{
1940
+		EE_Error::doing_it_wrong('EE_Registration::price_paid()',
1941
+			esc_html__('This method is deprecated, please use EE_Registration::final_price() instead.', 'event_espresso'),
1942
+			'4.7.0');
1943
+		return $this->final_price();
1944
+	}
1945
+
1946
+
1947
+	/**
1948
+	 * @deprecated
1949
+	 * @since     4.7.0
1950
+	 * @access    public
1951
+	 * @param    float $REG_final_price
1952
+	 * @throws EE_Error
1953
+	 * @throws RuntimeException
1954
+	 */
1955
+	public function set_price_paid($REG_final_price = 0.00)
1956
+	{
1957
+		EE_Error::doing_it_wrong('EE_Registration::set_price_paid()',
1958
+			esc_html__('This method is deprecated, please use EE_Registration::set_final_price() instead.', 'event_espresso'),
1959
+			'4.7.0');
1960
+		$this->set_final_price($REG_final_price);
1961
+	}
1962
+
1963
+
1964
+	/**
1965
+	 * @deprecated
1966
+	 * @since 4.7.0
1967
+	 * @return string
1968
+	 * @throws EE_Error
1969
+	 */
1970
+	public function pretty_price_paid()
1971
+	{
1972
+		EE_Error::doing_it_wrong('EE_Registration::pretty_price_paid()',
1973
+			esc_html__('This method is deprecated, please use EE_Registration::pretty_final_price() instead.',
1974
+				'event_espresso'), '4.7.0');
1975
+		return $this->pretty_final_price();
1976
+	}
1977
+
1978
+
1979
+	/**
1980
+	 * Gets the primary datetime related to this registration via the related Event to this registration
1981
+	 *
1982
+	 * @deprecated 4.9.17
1983
+	 * @return EE_Datetime
1984
+	 * @throws EE_Error
1985
+	 * @throws EntityNotFoundException
1986
+	 */
1987
+	public function get_related_primary_datetime()
1988
+	{
1989
+		EE_Error::doing_it_wrong(
1990
+			__METHOD__,
1991
+			esc_html__(
1992
+				'Use EE_Registration::get_latest_related_datetime() or EE_Registration::get_earliest_related_datetime()',
1993
+				'event_espresso'
1994
+			),
1995
+			'4.9.17',
1996
+			'5.0.0'
1997
+		);
1998
+		return $this->event()->primary_datetime();
1999
+	}
2000 2000
 
2001 2001
 
2002 2002
 }
Please login to merge, or discard this patch.
core/domain/entities/Context.php 1 patch
Indentation   +58 added lines, -58 removed lines patch added patch discarded remove patch
@@ -17,64 +17,64 @@
 block discarded – undo
17 17
 class Context implements ContextInterface
18 18
 {
19 19
 
20
-    /**
21
-     * @var string $slug
22
-     */
23
-    private $slug;
24
-
25
-    /**
26
-     * @var string $description
27
-     */
28
-    private $description;
29
-
30
-
31
-    /**
32
-     * Context constructor.
33
-     *
34
-     * @param string $slug
35
-     * @param string $description
36
-     */
37
-    public function __construct($slug, $description)
38
-    {
39
-        $this->setSlug($slug);
40
-        $this->setDescription($description);
41
-    }
42
-
43
-
44
-    /**
45
-     * @return string
46
-     */
47
-    public function slug()
48
-    {
49
-        return $this->slug;
50
-    }
51
-
52
-
53
-    /**
54
-     * @param string $slug
55
-     */
56
-    private function setSlug($slug)
57
-    {
58
-        $this->slug = sanitize_key($slug);
59
-    }
60
-
61
-
62
-    /**
63
-     * @return string
64
-     */
65
-    public function description()
66
-    {
67
-        return $this->description;
68
-    }
69
-
70
-
71
-    /**
72
-     * @param string $description
73
-     */
74
-    private function setDescription($description)
75
-    {
76
-        $this->description = sanitize_text_field($description);
77
-    }
20
+	/**
21
+	 * @var string $slug
22
+	 */
23
+	private $slug;
24
+
25
+	/**
26
+	 * @var string $description
27
+	 */
28
+	private $description;
29
+
30
+
31
+	/**
32
+	 * Context constructor.
33
+	 *
34
+	 * @param string $slug
35
+	 * @param string $description
36
+	 */
37
+	public function __construct($slug, $description)
38
+	{
39
+		$this->setSlug($slug);
40
+		$this->setDescription($description);
41
+	}
42
+
43
+
44
+	/**
45
+	 * @return string
46
+	 */
47
+	public function slug()
48
+	{
49
+		return $this->slug;
50
+	}
51
+
52
+
53
+	/**
54
+	 * @param string $slug
55
+	 */
56
+	private function setSlug($slug)
57
+	{
58
+		$this->slug = sanitize_key($slug);
59
+	}
60
+
61
+
62
+	/**
63
+	 * @return string
64
+	 */
65
+	public function description()
66
+	{
67
+		return $this->description;
68
+	}
69
+
70
+
71
+	/**
72
+	 * @param string $description
73
+	 */
74
+	private function setDescription($description)
75
+	{
76
+		$this->description = sanitize_text_field($description);
77
+	}
78 78
 
79 79
 }
80 80
 // Location: Context.php
Please login to merge, or discard this patch.
core/domain/entities/contexts/Context.php 1 patch
Indentation   +58 added lines, -58 removed lines patch added patch discarded remove patch
@@ -18,64 +18,64 @@
 block discarded – undo
18 18
 class Context implements ContextInterface
19 19
 {
20 20
 
21
-    /**
22
-     * @var string $slug
23
-     */
24
-    private $slug;
25
-
26
-    /**
27
-     * @var string $description
28
-     */
29
-    private $description;
30
-
31
-
32
-    /**
33
-     * Context constructor.
34
-     *
35
-     * @param string $slug
36
-     * @param string $description
37
-     */
38
-    public function __construct($slug, $description)
39
-    {
40
-        $this->setSlug($slug);
41
-        $this->setDescription($description);
42
-    }
43
-
44
-
45
-    /**
46
-     * @return string
47
-     */
48
-    public function slug()
49
-    {
50
-        return $this->slug;
51
-    }
52
-
53
-
54
-    /**
55
-     * @param string $slug
56
-     */
57
-    private function setSlug($slug)
58
-    {
59
-        $this->slug = sanitize_key($slug);
60
-    }
61
-
62
-
63
-    /**
64
-     * @return string
65
-     */
66
-    public function description()
67
-    {
68
-        return $this->description;
69
-    }
70
-
71
-
72
-    /**
73
-     * @param string $description
74
-     */
75
-    private function setDescription($description)
76
-    {
77
-        $this->description = sanitize_text_field($description);
78
-    }
21
+	/**
22
+	 * @var string $slug
23
+	 */
24
+	private $slug;
25
+
26
+	/**
27
+	 * @var string $description
28
+	 */
29
+	private $description;
30
+
31
+
32
+	/**
33
+	 * Context constructor.
34
+	 *
35
+	 * @param string $slug
36
+	 * @param string $description
37
+	 */
38
+	public function __construct($slug, $description)
39
+	{
40
+		$this->setSlug($slug);
41
+		$this->setDescription($description);
42
+	}
43
+
44
+
45
+	/**
46
+	 * @return string
47
+	 */
48
+	public function slug()
49
+	{
50
+		return $this->slug;
51
+	}
52
+
53
+
54
+	/**
55
+	 * @param string $slug
56
+	 */
57
+	private function setSlug($slug)
58
+	{
59
+		$this->slug = sanitize_key($slug);
60
+	}
61
+
62
+
63
+	/**
64
+	 * @return string
65
+	 */
66
+	public function description()
67
+	{
68
+		return $this->description;
69
+	}
70
+
71
+
72
+	/**
73
+	 * @param string $description
74
+	 */
75
+	private function setDescription($description)
76
+	{
77
+		$this->description = sanitize_text_field($description);
78
+	}
79 79
 
80 80
 }
81 81
 // Location: Context.php
Please login to merge, or discard this patch.
core/domain/entities/contexts/ContextInterface.php 1 patch
Indentation   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -18,14 +18,14 @@
 block discarded – undo
18 18
 interface ContextInterface
19 19
 {
20 20
 
21
-    /**
22
-     * @return string
23
-     */
24
-    public function slug();
21
+	/**
22
+	 * @return string
23
+	 */
24
+	public function slug();
25 25
 
26 26
 
27
-    /**
28
-     * @return string
29
-     */
30
-    public function description();
27
+	/**
28
+	 * @return string
29
+	 */
30
+	public function description();
31 31
 }
Please login to merge, or discard this patch.
core/business/EE_Registration_Processor.class.php 1 patch
Indentation   +775 added lines, -775 removed lines patch added patch discarded remove patch
@@ -27,781 +27,781 @@
 block discarded – undo
27 27
 class EE_Registration_Processor extends EE_Processor_Base
28 28
 {
29 29
 
30
-    /**
31
-     * @var EE_Registration_Processor $_instance
32
-     * @access    private
33
-     */
34
-    private static $_instance;
35
-
36
-    /**
37
-     * initial reg status at the beginning of this request.
38
-     * indexed by registration ID
39
-     *
40
-     * @var array
41
-     */
42
-    protected $_old_reg_status = array();
43
-
44
-    /**
45
-     * reg status at the end of the request after all processing.
46
-     * indexed by registration ID
47
-     *
48
-     * @var array
49
-     */
50
-    protected $_new_reg_status = array();
51
-
52
-    /**
53
-     * amounts paid at the end of the request after all processing.
54
-     * indexed by registration ID
55
-     *
56
-     * @var array
57
-     */
58
-    protected static $_amount_paid = array();
59
-
60
-    /**
61
-     * Cache of the reg final price for registrations corresponding to a ticket line item
62
-     *
63
-     * @deprecated
64
-     * @var array @see EEH_Line_Item::calculate_reg_final_prices_per_line_item()'s return value
65
-     */
66
-    protected $_reg_final_price_per_tkt_line_item;
67
-
68
-    /**
69
-     * @var EE_Request $request
70
-     */
71
-    protected $request;
72
-
73
-
74
-
75
-    /**
76
-     * @singleton method used to instantiate class object
77
-     * @param EE_Request|null $request
78
-     * @return EE_Registration_Processor instance
79
-     * @throws \InvalidArgumentException
80
-     * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
81
-     * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
82
-     */
83
-    public static function instance(EE_Request $request = null)
84
-    {
85
-        // check if class object is instantiated
86
-        if (! self::$_instance instanceof EE_Registration_Processor) {
87
-            if(! $request instanceof EE_Request) {
88
-                $request = LoaderFactory::getLoader()->getShared('EE_Request');
89
-            }
90
-            self::$_instance = new self($request);
91
-        }
92
-        return self::$_instance;
93
-    }
94
-
95
-
96
-    /**
97
-     * EE_Registration_Processor constructor.
98
-     *
99
-     * @param EE_Request $request
100
-     */
101
-    public function __construct(EE_Request $request)
102
-    {
103
-        $this->request = $request;
104
-    }
105
-
106
-
107
-
108
-    /**
109
-     * @param int $REG_ID
110
-     * @return string
111
-     */
112
-    public function old_reg_status($REG_ID)
113
-    {
114
-        return isset($this->_old_reg_status[$REG_ID]) ? $this->_old_reg_status[$REG_ID] : null;
115
-    }
116
-
117
-
118
-
119
-    /**
120
-     * @param int    $REG_ID
121
-     * @param string $old_reg_status
122
-     */
123
-    public function set_old_reg_status($REG_ID, $old_reg_status)
124
-    {
125
-        // only set the first time
126
-        if (! isset($this->_old_reg_status[$REG_ID])) {
127
-            $this->_old_reg_status[$REG_ID] = $old_reg_status;
128
-        }
129
-    }
130
-
131
-
132
-
133
-    /**
134
-     * @param int $REG_ID
135
-     * @return string
136
-     */
137
-    public function new_reg_status($REG_ID)
138
-    {
139
-        return isset($this->_new_reg_status[$REG_ID]) ? $this->_new_reg_status[$REG_ID] : null;
140
-    }
141
-
142
-
143
-
144
-    /**
145
-     * @param int    $REG_ID
146
-     * @param string $new_reg_status
147
-     */
148
-    public function set_new_reg_status($REG_ID, $new_reg_status)
149
-    {
150
-        $this->_new_reg_status[$REG_ID] = $new_reg_status;
151
-    }
152
-
153
-
154
-
155
-    /**
156
-     * reg_status_updated
157
-     *
158
-     * @param int $REG_ID
159
-     * @return bool
160
-     */
161
-    public function reg_status_updated($REG_ID)
162
-    {
163
-        return $this->new_reg_status($REG_ID) !== $this->old_reg_status($REG_ID);
164
-    }
165
-
166
-
167
-
168
-    /**
169
-     * @param EE_Registration $registration
170
-     * @throws EE_Error
171
-     * @throws EntityNotFoundException
172
-     * @throws InvalidArgumentException
173
-     * @throws InvalidDataTypeException
174
-     * @throws InvalidInterfaceException
175
-     * @throws ReflectionException
176
-     * @throws RuntimeException
177
-     */
178
-    public function update_registration_status_and_trigger_notifications(EE_Registration $registration)
179
-    {
180
-        $this->toggle_incomplete_registration_status_to_default($registration, false);
181
-        $this->toggle_registration_status_for_default_approved_events($registration, false);
182
-        $this->toggle_registration_status_if_no_monies_owing($registration, false);
183
-        $registration->save();
184
-        // trigger notifications
185
-        $this->trigger_registration_update_notifications($registration);
186
-    }
187
-
188
-
189
-
190
-    /**
191
-     *    manually_update_registration_status
192
-     *
193
-     * @access public
194
-     * @param EE_Registration $registration
195
-     * @param string          $new_reg_status
196
-     * @param bool            $save TRUE will save the registration if the status is updated, FALSE will leave that up
197
-     *                              to client code
198
-     * @return bool
199
-     * @throws EE_Error
200
-     * @throws EntityNotFoundException
201
-     * @throws InvalidArgumentException
202
-     * @throws InvalidDataTypeException
203
-     * @throws InvalidInterfaceException
204
-     * @throws ReflectionException
205
-     * @throws RuntimeException
206
-     */
207
-    public function manually_update_registration_status(
208
-        EE_Registration $registration,
209
-        $new_reg_status = '',
210
-        $save = true
211
-    ) {
212
-        // set initial REG_Status
213
-        $this->set_old_reg_status($registration->ID(), $registration->status_ID());
214
-        // set incoming REG_Status
215
-        $this->set_new_reg_status($registration->ID(), $new_reg_status);
216
-        // toggle reg status but only if it has changed and the user can do so
217
-        if (
218
-            $this->reg_status_updated($registration->ID())
219
-            && (
220
-                (! $this->request->isAdmin() || $this->request->isFrontAjax())
221
-                || EE_Registry::instance()->CAP->current_user_can(
222
-                    'ee_edit_registration',
223
-                    'toggle_registration_status',
224
-                    $registration->ID()
225
-                )
226
-            )
227
-        ) {
228
-            // change status to new value
229
-            $updated = $registration->set_status($this->new_reg_status($registration->ID()));
230
-            if ($updated && $save) {
231
-                $registration->save();
232
-            }
233
-            return true;
234
-        }
235
-        return false;
236
-    }
237
-
238
-
239
-
240
-    /**
241
-     *    toggle_incomplete_registration_status_to_default
242
-     *        changes any incomplete registrations to either the event or global default registration status
243
-     *
244
-     * @access public
245
-     * @param EE_Registration $registration
246
-     * @param bool            $save TRUE will save the registration if the status is updated, FALSE will leave that up
247
-     *                              to client code
248
-     * @param ContextInterface|null    $context
249
-     * @return void
250
-     * @throws EE_Error
251
-     * @throws InvalidArgumentException
252
-     * @throws ReflectionException
253
-     * @throws RuntimeException
254
-     * @throws EntityNotFoundException
255
-     * @throws InvalidDataTypeException
256
-     * @throws InvalidInterfaceException
257
-     */
258
-    public function toggle_incomplete_registration_status_to_default(
259
-        EE_Registration $registration,
260
-        $save = true,
261
-        ContextInterface $context = null
262
-    ) {
263
-        $existing_reg_status = $registration->status_ID();
264
-        // set initial REG_Status
265
-        $this->set_old_reg_status($registration->ID(), $existing_reg_status);
266
-        // is the registration currently incomplete ?
267
-        if ($registration->status_ID() === EEM_Registration::status_id_incomplete) {
268
-            // grab default reg status for the event, if set
269
-            $event_default_registration_status = $registration->event()->default_registration_status();
270
-            // if no default reg status is set for the event, then use the global value
271
-            $STS_ID = ! empty($event_default_registration_status)
272
-                ? $event_default_registration_status
273
-                : EE_Registry::instance()->CFG->registration->default_STS_ID;
274
-            // if the event default reg status is approved, then downgrade temporarily to payment pending to ensure that payments are triggered
275
-            $STS_ID = $STS_ID === EEM_Registration::status_id_approved ? EEM_Registration::status_id_pending_payment
276
-                : $STS_ID;
277
-            // set incoming REG_Status
278
-            $this->set_new_reg_status($registration->ID(), $STS_ID);
279
-            $registration->set_status($STS_ID, false, $context);
280
-            if ($save) {
281
-                $registration->save();
282
-            }
283
-            // don't trigger notifications during IPNs because they will get triggered by EE_Payment_Processor
284
-            if (! EE_Processor_Base::$IPN) {
285
-                // otherwise, send out notifications
286
-                add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true', 10);
287
-            }
288
-            // DEBUG LOG
289
-            //$this->log(
290
-            //	__CLASS__, __FUNCTION__, __LINE__,
291
-            //	$registration->transaction(),
292
-            //	array(
293
-            //		'IPN'                   => EE_Processor_Base::$IPN,
294
-            //		'deliver_notifications' => has_filter( 'FHEE__EED_Messages___maybe_registration__deliver_notifications' ),
295
-            //	)
296
-            //);
297
-        }
298
-    }
299
-
300
-
301
-
302
-    /**
303
-     *    toggle_registration_status_for_default_approved_events
304
-     *
305
-     * @access public
306
-     * @param EE_Registration $registration
307
-     * @param bool            $save TRUE will save the registration if the status is updated, FALSE will leave that up
308
-     *                              to client code
309
-     * @return bool
310
-     * @throws EE_Error
311
-     * @throws EntityNotFoundException
312
-     * @throws InvalidArgumentException
313
-     * @throws InvalidDataTypeException
314
-     * @throws InvalidInterfaceException
315
-     * @throws ReflectionException
316
-     * @throws RuntimeException
317
-     */
318
-    public function toggle_registration_status_for_default_approved_events(EE_Registration $registration, $save = true)
319
-    {
320
-        $reg_status = $registration->status_ID();
321
-        // set initial REG_Status
322
-        $this->set_old_reg_status($registration->ID(), $reg_status);
323
-        // if not already, toggle reg status to approved IF the event default reg status is approved
324
-        // ( as long as the registration wasn't cancelled or declined at some point )
325
-        if (
326
-            $reg_status !== EEM_Registration::status_id_cancelled
327
-            && $reg_status
328
-               !== EEM_Registration::status_id_declined
329
-            && $reg_status !== EEM_Registration::status_id_approved
330
-            && $registration->event()->default_registration_status() === EEM_Registration::status_id_approved
331
-        ) {
332
-            // set incoming REG_Status
333
-            $this->set_new_reg_status($registration->ID(), EEM_Registration::status_id_approved);
334
-            // toggle status to approved
335
-            $registration->set_status(EEM_Registration::status_id_approved);
336
-            if ($save) {
337
-                $registration->save();
338
-            }
339
-            // don't trigger notifications during IPNs because they will get triggered by EE_Payment_Processor
340
-            if (! EE_Processor_Base::$IPN) {
341
-                // otherwise, send out notifications
342
-                add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true', 10);
343
-            }
344
-            // DEBUG LOG
345
-            //$this->log(
346
-            //	__CLASS__, __FUNCTION__, __LINE__,
347
-            //	$registration->transaction(),
348
-            //	array(
349
-            //		'IPN'                   => EE_Processor_Base::$IPN,
350
-            //		'deliver_notifications' => has_filter( 'FHEE__EED_Messages___maybe_registration__deliver_notifications' ),
351
-            //	)
352
-            //);
353
-            return true;
354
-        }
355
-        return false;
356
-    }
357
-
358
-
359
-
360
-    /**
361
-     *    toggle_registration_statuses_if_no_monies_owing
362
-     *
363
-     * @access public
364
-     * @param EE_Registration $registration
365
-     * @param bool            $save TRUE will save the registration if the status is updated, FALSE will leave that up
366
-     *                              to client code
367
-     * @param array           $additional_details
368
-     * @return bool
369
-     * @throws EE_Error
370
-     * @throws EntityNotFoundException
371
-     * @throws InvalidArgumentException
372
-     * @throws InvalidDataTypeException
373
-     * @throws InvalidInterfaceException
374
-     * @throws ReflectionException
375
-     * @throws RuntimeException
376
-     */
377
-    public function toggle_registration_status_if_no_monies_owing(
378
-        EE_Registration $registration,
379
-        $save = true,
380
-        array $additional_details = array()
381
-    ) {
382
-        // set initial REG_Status
383
-        $this->set_old_reg_status($registration->ID(), $registration->status_ID());
384
-        // was a payment just made ?
385
-        $payment    = isset($additional_details['payment_updates'], $additional_details['last_payment'])
386
-                      && $additional_details['payment_updates']
387
-                      && $additional_details['last_payment'] instanceof EE_Payment
388
-            ? $additional_details['last_payment']
389
-            : null;
390
-        $total_paid = array_sum(self::$_amount_paid);
391
-        // toggle reg status to approved IF
392
-        if (
393
-            // REG status is pending payment
394
-            $registration->status_ID() === EEM_Registration::status_id_pending_payment
395
-            // AND no monies are owing
396
-            && (
397
-                (
398
-                    $registration->transaction()->is_completed()
399
-                    || $registration->transaction()->is_overpaid()
400
-                    || $registration->transaction()->is_free()
401
-                    || apply_filters(
402
-                        'FHEE__EE_Registration_Processor__toggle_registration_status_if_no_monies_owing',
403
-                        false,
404
-                        $registration
405
-                    )
406
-                )
407
-                || (
408
-                    $payment instanceof EE_Payment && $payment->is_approved()
409
-                    && // this specific registration has not yet been paid for
410
-                    ! isset(self::$_amount_paid[$registration->ID()])
411
-                    && // payment amount, less what we have already attributed to other registrations, is greater than this reg's final price
412
-                    $payment->amount() - $total_paid >= $registration->final_price()
413
-                )
414
-            )
415
-        ) {
416
-            // mark as paid
417
-            self::$_amount_paid[$registration->ID()] = $registration->final_price();
418
-            // track new REG_Status
419
-            $this->set_new_reg_status($registration->ID(), EEM_Registration::status_id_approved);
420
-            // toggle status to approved
421
-            $registration->set_status(EEM_Registration::status_id_approved);
422
-            if ($save) {
423
-                $registration->save();
424
-            }
425
-            // don't trigger notifications during IPNs because they will get triggered by EE_Payment_Processor
426
-            if (! EE_Processor_Base::$IPN) {
427
-                // otherwise, send out notifications
428
-                add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true', 10);
429
-            }
430
-            // DEBUG LOG
431
-            //$this->log(
432
-            //	__CLASS__, __FUNCTION__, __LINE__,
433
-            //	$registration->transaction(),
434
-            //	array(
435
-            //		'IPN'                   => EE_Processor_Base::$IPN,
436
-            //		'deliver_notifications' => has_filter( 'FHEE__EED_Messages___maybe_registration__deliver_notifications' ),
437
-            //	)
438
-            //);
439
-            return true;
440
-        }
441
-        return false;
442
-    }
443
-
444
-
445
-
446
-    /**
447
-     *    registration_status_changed
448
-     *
449
-     * @access public
450
-     * @param EE_Registration $registration
451
-     * @param array           $additional_details
452
-     * @return void
453
-     */
454
-    public function trigger_registration_update_notifications($registration, array $additional_details = array())
455
-    {
456
-        try {
457
-            if (! $registration instanceof EE_Registration) {
458
-                throw new EE_Error(
459
-                    esc_html__('An invalid registration was received.', 'event_espresso')
460
-                );
461
-            }
462
-            // EE_Registry::instance()->load_helper( 'Debug_Tools' );
463
-            // EEH_Debug_Tools::log(
464
-            // 	__CLASS__,
465
-            // 	__FUNCTION__,
466
-            // 	__LINE__,
467
-            // 	array( $registration->transaction(), $additional_details ),
468
-            // 	false,
469
-            // 	'EE_Transaction: ' . $registration->transaction()->ID()
470
-            // );
471
-            if (! $registration->is_primary_registrant()) {
472
-                return;
473
-            }
474
-            do_action(
475
-                'AHEE__EE_Registration_Processor__trigger_registration_update_notifications',
476
-                $registration,
477
-                $additional_details
478
-            );
479
-        } catch (Exception $e) {
480
-            EE_Error::add_error($e->getMessage(), $e->getFile(), 'unknown_function_from_exception', $e->getLine());
481
-        }
482
-    }
483
-
484
-
485
-
486
-    /**
487
-     * sets reg status based either on passed param or on transaction status and event pre-approval setting
488
-     *
489
-     * @param EE_Registration $registration
490
-     * @param array           $additional_details
491
-     * @return bool
492
-     * @throws EE_Error
493
-     * @throws EntityNotFoundException
494
-     * @throws InvalidArgumentException
495
-     * @throws InvalidDataTypeException
496
-     * @throws InvalidInterfaceException
497
-     * @throws ReflectionException
498
-     * @throws RuntimeException
499
-     */
500
-    public function update_registration_after_checkout_or_payment(
501
-        EE_Registration $registration,
502
-        array $additional_details = array()
503
-    ) {
504
-        // set initial REG_Status
505
-        $this->set_old_reg_status($registration->ID(), $registration->status_ID());
506
-        // if the registration status gets updated, then save the registration
507
-        if (
508
-            $this->toggle_registration_status_for_default_approved_events($registration, false)
509
-            || $this->toggle_registration_status_if_no_monies_owing(
510
-                $registration,
511
-                false,
512
-                $additional_details
513
-            )
514
-        ) {
515
-            $registration->save();
516
-        }
517
-        // set new  REG_Status
518
-        $this->set_new_reg_status($registration->ID(), $registration->status_ID());
519
-        return $this->reg_status_updated($registration->ID())
520
-               && $this->new_reg_status($registration->ID()) === EEM_Registration::status_id_approved;
521
-    }
522
-
523
-
524
-
525
-    /**
526
-     * Updates the registration' final prices based on the current line item tree (taking into account
527
-     * discounts, taxes, and other line items unrelated to tickets.)
528
-     *
529
-     * @param EE_Transaction $transaction
530
-     * @param boolean        $save_regs whether to immediately save registrations in this function or not
531
-     * @return void
532
-     * @throws EE_Error
533
-     * @throws InvalidArgumentException
534
-     * @throws InvalidDataTypeException
535
-     * @throws InvalidInterfaceException
536
-     * @throws RuntimeException
537
-     */
538
-    public function update_registration_final_prices($transaction, $save_regs = true)
539
-    {
540
-        $reg_final_price_per_ticket_line_item = EEH_Line_Item::calculate_reg_final_prices_per_line_item(
541
-            $transaction->total_line_item()
542
-        );
543
-        foreach ($transaction->registrations() as $registration) {
544
-            /** @var EE_Line_Item $line_item */
545
-            $line_item = EEM_Line_Item::instance()->get_line_item_for_registration($registration);
546
-            if (isset($reg_final_price_per_ticket_line_item[$line_item->ID()])) {
547
-                $registration->set_final_price($reg_final_price_per_ticket_line_item[$line_item->ID()]);
548
-                if ($save_regs) {
549
-                    $registration->save();
550
-                }
551
-            }
552
-        }
553
-        //and make sure there's no rounding problem
554
-        $this->fix_reg_final_price_rounding_issue($transaction);
555
-    }
556
-
557
-
558
-
559
-    /**
560
-     * Makes sure there is no rounding errors for the REG_final_prices.
561
-     * Eg, if we have 3 registrations for $1, and there is a $0.01 discount between the three of them,
562
-     * they will each be for $0.99333333, which gets rounded to $1 again.
563
-     * So the transaction total will be $2.99, but each registration will be for $1,
564
-     * so if each registrant paid individually they will have overpaid by $0.01.
565
-     * So in order to overcome this, we check for any difference, and if there is a difference
566
-     * we just grab one registrant at random and make them responsible for it.
567
-     * This should be used after setting REG_final_prices (it's done automatically as part of
568
-     * EE_Registration_Processor::update_registration_final_prices())
569
-     *
570
-     * @param EE_Transaction $transaction
571
-     * @return bool success verifying that there is NO difference after this method is done
572
-     * @throws EE_Error
573
-     * @throws InvalidArgumentException
574
-     * @throws InvalidDataTypeException
575
-     * @throws InvalidInterfaceException
576
-     */
577
-    public function fix_reg_final_price_rounding_issue($transaction)
578
-    {
579
-        $reg_final_price_sum = EEM_Registration::instance()->sum(
580
-            array(
581
-                array(
582
-                    'TXN_ID' => $transaction->ID(),
583
-                ),
584
-            ),
585
-            'REG_final_price'
586
-        );
587
-        $diff = $transaction->total() - $reg_final_price_sum;
588
-        //ok then, just grab one of the registrations
589
-        if ($diff !== 0) {
590
-            $a_reg   = EEM_Registration::instance()->get_one(
591
-                array(
592
-                    array(
593
-                        'TXN_ID' => $transaction->ID(),
594
-                    ),
595
-                )
596
-            );
597
-            return $a_reg instanceof EE_Registration
598
-                ? (bool) $a_reg->save(array('REG_final_price' => $a_reg->final_price() + $diff))
599
-                : false;
600
-        }
601
-        return true;
602
-    }
603
-
604
-
605
-
606
-    /**
607
-     * update_registration_after_being_canceled_or_declined
608
-     *
609
-     * @param EE_Registration $registration
610
-     * @param array           $closed_reg_statuses
611
-     * @param bool            $update_reg
612
-     * @return bool
613
-     * @throws EE_Error
614
-     * @throws RuntimeException
615
-     */
616
-    public function update_registration_after_being_canceled_or_declined(
617
-        EE_Registration $registration,
618
-        array $closed_reg_statuses = array(),
619
-        $update_reg = true
620
-    ) {
621
-        // these reg statuses should not be considered in any calculations involving monies owing
622
-        $closed_reg_statuses = ! empty($closed_reg_statuses)
623
-            ? $closed_reg_statuses
624
-            : EEM_Registration::closed_reg_statuses();
625
-        if (! in_array($registration->status_ID(), $closed_reg_statuses, true)) {
626
-            return false;
627
-        }
628
-        // release a reserved ticket by decrementing ticket and datetime reserved values
629
-        $registration->release_reserved_ticket(true);
630
-        $registration->set_final_price(0);
631
-        if ($update_reg) {
632
-            $registration->save();
633
-        }
634
-        return true;
635
-    }
636
-
637
-
638
-
639
-    /**
640
-     * update_canceled_or_declined_registration_after_being_reinstated
641
-     *
642
-     * @param EE_Registration $registration
643
-     * @param array           $closed_reg_statuses
644
-     * @param bool            $update_reg
645
-     * @return bool
646
-     * @throws EE_Error
647
-     * @throws RuntimeException
648
-     */
649
-    public function update_canceled_or_declined_registration_after_being_reinstated(
650
-        EE_Registration $registration,
651
-        array $closed_reg_statuses = array(),
652
-        $update_reg = true
653
-    ) {
654
-        // these reg statuses should not be considered in any calculations involving monies owing
655
-        $closed_reg_statuses = ! empty($closed_reg_statuses) ? $closed_reg_statuses
656
-            : EEM_Registration::closed_reg_statuses();
657
-        if (in_array($registration->status_ID(), $closed_reg_statuses, true)) {
658
-            return false;
659
-        }
660
-        $ticket = $registration->ticket();
661
-        if (! $ticket instanceof EE_Ticket) {
662
-            throw new EE_Error(
663
-                sprintf(
664
-                    esc_html__(
665
-                        'The Ticket for Registration %1$d was not found or is invalid.',
666
-                        'event_espresso'
667
-                    ),
668
-                    $registration->ticket_ID()
669
-                )
670
-            );
671
-        }
672
-        $registration->set_final_price($ticket->price());
673
-        if ($update_reg) {
674
-            $registration->save();
675
-        }
676
-        return true;
677
-    }
678
-
679
-
680
-
681
-    /**
682
-     * generate_ONE_registration_from_line_item
683
-     * Although a ticket line item may have a quantity greater than 1,
684
-     * this method will ONLY CREATE ONE REGISTRATION !!!
685
-     * Regardless of the ticket line item quantity.
686
-     * This means that any code calling this method is responsible for ensuring
687
-     * that the final registration count matches the ticket line item quantity.
688
-     * This was done to make it easier to match the number of registrations
689
-     * to the number of tickets in the cart, when the cart has been edited
690
-     * after SPCO has already been initialized. So if an additional ticket was added to the cart, you can simply pass
691
-     * the line item to this method to add a second ticket, and in this case, you would not want to add 2 tickets.
692
-     *
693
-     * @deprecated
694
-     * @since 4.9.1
695
-     * @param EE_Line_Item    $line_item
696
-     * @param \EE_Transaction $transaction
697
-     * @param int             $att_nmbr
698
-     * @param int             $total_ticket_count
699
-     * @return EE_Registration | null
700
-     * @throws \OutOfRangeException
701
-     * @throws \EventEspresso\core\exceptions\UnexpectedEntityException
702
-     * @throws \EE_Error
703
-     */
704
-    public function generate_ONE_registration_from_line_item(
705
-        EE_Line_Item $line_item,
706
-        EE_Transaction $transaction,
707
-        $att_nmbr = 1,
708
-        $total_ticket_count = 1
709
-    ) {
710
-        EE_Error::doing_it_wrong(
711
-            __CLASS__ . '::' . __FUNCTION__,
712
-            sprintf(
713
-                esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
714
-                '\EventEspresso\core\domain\services\registration\CreateRegistrationService::create()'
715
-            ),
716
-            '4.9.1',
717
-            '5.0.0'
718
-        );
719
-        // grab the related ticket object for this line_item
720
-        $ticket = $line_item->ticket();
721
-        if (! $ticket instanceof EE_Ticket) {
722
-            EE_Error::add_error(
723
-                sprintf(
724
-                    esc_html__('Line item %s did not contain a valid ticket', 'event_espresso'),
725
-                    $line_item->ID()
726
-                ),
727
-                __FILE__,
728
-                __FUNCTION__,
729
-                __LINE__
730
-            );
731
-            return null;
732
-        }
733
-        $registration_service = new CreateRegistrationService();
734
-        // then generate a new registration from that
735
-        return $registration_service->create(
736
-            $ticket->get_related_event(),
737
-            $transaction,
738
-            $ticket,
739
-            $line_item,
740
-            $att_nmbr,
741
-            $total_ticket_count
742
-        );
743
-    }
744
-
745
-
746
-
747
-    /**
748
-     * generates reg_url_link
749
-     *
750
-     * @deprecated
751
-     * @since 4.9.1
752
-     * @param int                   $att_nmbr
753
-     * @param EE_Line_Item | string $item
754
-     * @return string
755
-     * @throws InvalidArgumentException
756
-     */
757
-    public function generate_reg_url_link($att_nmbr, $item)
758
-    {
759
-        EE_Error::doing_it_wrong(
760
-            __CLASS__ . '::' . __FUNCTION__,
761
-            sprintf(
762
-                esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
763
-                'EventEspresso\core\domain\entities\RegUrlLink'
764
-            ),
765
-            '4.9.1',
766
-            '5.0.0'
767
-        );
768
-        return new RegUrlLink($att_nmbr, $item);
769
-    }
770
-
771
-
772
-
773
-    /**
774
-     * generates reg code
775
-     *
776
-     * @deprecated
777
-     * @since 4.9.1
778
-     * @param EE_Registration $registration
779
-     * @return string
780
-     * @throws EE_Error
781
-     * @throws EntityNotFoundException
782
-     * @throws InvalidArgumentException
783
-     */
784
-    public function generate_reg_code(EE_Registration $registration)
785
-    {
786
-        EE_Error::doing_it_wrong(
787
-            __CLASS__ . '::' . __FUNCTION__,
788
-            sprintf(
789
-                esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
790
-                'EventEspresso\core\domain\entities\RegCode'
791
-            ),
792
-            '4.9.1',
793
-            '5.0.0'
794
-        );
795
-        return apply_filters(
796
-            'FHEE__EE_Registration_Processor___generate_reg_code__new_reg_code',
797
-            new RegCode(
798
-                RegUrlLink::fromRegistration($registration),
799
-                $registration->transaction(),
800
-                $registration->ticket()
801
-            ),
802
-            $registration
803
-        );
804
-    }
30
+	/**
31
+	 * @var EE_Registration_Processor $_instance
32
+	 * @access    private
33
+	 */
34
+	private static $_instance;
35
+
36
+	/**
37
+	 * initial reg status at the beginning of this request.
38
+	 * indexed by registration ID
39
+	 *
40
+	 * @var array
41
+	 */
42
+	protected $_old_reg_status = array();
43
+
44
+	/**
45
+	 * reg status at the end of the request after all processing.
46
+	 * indexed by registration ID
47
+	 *
48
+	 * @var array
49
+	 */
50
+	protected $_new_reg_status = array();
51
+
52
+	/**
53
+	 * amounts paid at the end of the request after all processing.
54
+	 * indexed by registration ID
55
+	 *
56
+	 * @var array
57
+	 */
58
+	protected static $_amount_paid = array();
59
+
60
+	/**
61
+	 * Cache of the reg final price for registrations corresponding to a ticket line item
62
+	 *
63
+	 * @deprecated
64
+	 * @var array @see EEH_Line_Item::calculate_reg_final_prices_per_line_item()'s return value
65
+	 */
66
+	protected $_reg_final_price_per_tkt_line_item;
67
+
68
+	/**
69
+	 * @var EE_Request $request
70
+	 */
71
+	protected $request;
72
+
73
+
74
+
75
+	/**
76
+	 * @singleton method used to instantiate class object
77
+	 * @param EE_Request|null $request
78
+	 * @return EE_Registration_Processor instance
79
+	 * @throws \InvalidArgumentException
80
+	 * @throws \EventEspresso\core\exceptions\InvalidInterfaceException
81
+	 * @throws \EventEspresso\core\exceptions\InvalidDataTypeException
82
+	 */
83
+	public static function instance(EE_Request $request = null)
84
+	{
85
+		// check if class object is instantiated
86
+		if (! self::$_instance instanceof EE_Registration_Processor) {
87
+			if(! $request instanceof EE_Request) {
88
+				$request = LoaderFactory::getLoader()->getShared('EE_Request');
89
+			}
90
+			self::$_instance = new self($request);
91
+		}
92
+		return self::$_instance;
93
+	}
94
+
95
+
96
+	/**
97
+	 * EE_Registration_Processor constructor.
98
+	 *
99
+	 * @param EE_Request $request
100
+	 */
101
+	public function __construct(EE_Request $request)
102
+	{
103
+		$this->request = $request;
104
+	}
105
+
106
+
107
+
108
+	/**
109
+	 * @param int $REG_ID
110
+	 * @return string
111
+	 */
112
+	public function old_reg_status($REG_ID)
113
+	{
114
+		return isset($this->_old_reg_status[$REG_ID]) ? $this->_old_reg_status[$REG_ID] : null;
115
+	}
116
+
117
+
118
+
119
+	/**
120
+	 * @param int    $REG_ID
121
+	 * @param string $old_reg_status
122
+	 */
123
+	public function set_old_reg_status($REG_ID, $old_reg_status)
124
+	{
125
+		// only set the first time
126
+		if (! isset($this->_old_reg_status[$REG_ID])) {
127
+			$this->_old_reg_status[$REG_ID] = $old_reg_status;
128
+		}
129
+	}
130
+
131
+
132
+
133
+	/**
134
+	 * @param int $REG_ID
135
+	 * @return string
136
+	 */
137
+	public function new_reg_status($REG_ID)
138
+	{
139
+		return isset($this->_new_reg_status[$REG_ID]) ? $this->_new_reg_status[$REG_ID] : null;
140
+	}
141
+
142
+
143
+
144
+	/**
145
+	 * @param int    $REG_ID
146
+	 * @param string $new_reg_status
147
+	 */
148
+	public function set_new_reg_status($REG_ID, $new_reg_status)
149
+	{
150
+		$this->_new_reg_status[$REG_ID] = $new_reg_status;
151
+	}
152
+
153
+
154
+
155
+	/**
156
+	 * reg_status_updated
157
+	 *
158
+	 * @param int $REG_ID
159
+	 * @return bool
160
+	 */
161
+	public function reg_status_updated($REG_ID)
162
+	{
163
+		return $this->new_reg_status($REG_ID) !== $this->old_reg_status($REG_ID);
164
+	}
165
+
166
+
167
+
168
+	/**
169
+	 * @param EE_Registration $registration
170
+	 * @throws EE_Error
171
+	 * @throws EntityNotFoundException
172
+	 * @throws InvalidArgumentException
173
+	 * @throws InvalidDataTypeException
174
+	 * @throws InvalidInterfaceException
175
+	 * @throws ReflectionException
176
+	 * @throws RuntimeException
177
+	 */
178
+	public function update_registration_status_and_trigger_notifications(EE_Registration $registration)
179
+	{
180
+		$this->toggle_incomplete_registration_status_to_default($registration, false);
181
+		$this->toggle_registration_status_for_default_approved_events($registration, false);
182
+		$this->toggle_registration_status_if_no_monies_owing($registration, false);
183
+		$registration->save();
184
+		// trigger notifications
185
+		$this->trigger_registration_update_notifications($registration);
186
+	}
187
+
188
+
189
+
190
+	/**
191
+	 *    manually_update_registration_status
192
+	 *
193
+	 * @access public
194
+	 * @param EE_Registration $registration
195
+	 * @param string          $new_reg_status
196
+	 * @param bool            $save TRUE will save the registration if the status is updated, FALSE will leave that up
197
+	 *                              to client code
198
+	 * @return bool
199
+	 * @throws EE_Error
200
+	 * @throws EntityNotFoundException
201
+	 * @throws InvalidArgumentException
202
+	 * @throws InvalidDataTypeException
203
+	 * @throws InvalidInterfaceException
204
+	 * @throws ReflectionException
205
+	 * @throws RuntimeException
206
+	 */
207
+	public function manually_update_registration_status(
208
+		EE_Registration $registration,
209
+		$new_reg_status = '',
210
+		$save = true
211
+	) {
212
+		// set initial REG_Status
213
+		$this->set_old_reg_status($registration->ID(), $registration->status_ID());
214
+		// set incoming REG_Status
215
+		$this->set_new_reg_status($registration->ID(), $new_reg_status);
216
+		// toggle reg status but only if it has changed and the user can do so
217
+		if (
218
+			$this->reg_status_updated($registration->ID())
219
+			&& (
220
+				(! $this->request->isAdmin() || $this->request->isFrontAjax())
221
+				|| EE_Registry::instance()->CAP->current_user_can(
222
+					'ee_edit_registration',
223
+					'toggle_registration_status',
224
+					$registration->ID()
225
+				)
226
+			)
227
+		) {
228
+			// change status to new value
229
+			$updated = $registration->set_status($this->new_reg_status($registration->ID()));
230
+			if ($updated && $save) {
231
+				$registration->save();
232
+			}
233
+			return true;
234
+		}
235
+		return false;
236
+	}
237
+
238
+
239
+
240
+	/**
241
+	 *    toggle_incomplete_registration_status_to_default
242
+	 *        changes any incomplete registrations to either the event or global default registration status
243
+	 *
244
+	 * @access public
245
+	 * @param EE_Registration $registration
246
+	 * @param bool            $save TRUE will save the registration if the status is updated, FALSE will leave that up
247
+	 *                              to client code
248
+	 * @param ContextInterface|null    $context
249
+	 * @return void
250
+	 * @throws EE_Error
251
+	 * @throws InvalidArgumentException
252
+	 * @throws ReflectionException
253
+	 * @throws RuntimeException
254
+	 * @throws EntityNotFoundException
255
+	 * @throws InvalidDataTypeException
256
+	 * @throws InvalidInterfaceException
257
+	 */
258
+	public function toggle_incomplete_registration_status_to_default(
259
+		EE_Registration $registration,
260
+		$save = true,
261
+		ContextInterface $context = null
262
+	) {
263
+		$existing_reg_status = $registration->status_ID();
264
+		// set initial REG_Status
265
+		$this->set_old_reg_status($registration->ID(), $existing_reg_status);
266
+		// is the registration currently incomplete ?
267
+		if ($registration->status_ID() === EEM_Registration::status_id_incomplete) {
268
+			// grab default reg status for the event, if set
269
+			$event_default_registration_status = $registration->event()->default_registration_status();
270
+			// if no default reg status is set for the event, then use the global value
271
+			$STS_ID = ! empty($event_default_registration_status)
272
+				? $event_default_registration_status
273
+				: EE_Registry::instance()->CFG->registration->default_STS_ID;
274
+			// if the event default reg status is approved, then downgrade temporarily to payment pending to ensure that payments are triggered
275
+			$STS_ID = $STS_ID === EEM_Registration::status_id_approved ? EEM_Registration::status_id_pending_payment
276
+				: $STS_ID;
277
+			// set incoming REG_Status
278
+			$this->set_new_reg_status($registration->ID(), $STS_ID);
279
+			$registration->set_status($STS_ID, false, $context);
280
+			if ($save) {
281
+				$registration->save();
282
+			}
283
+			// don't trigger notifications during IPNs because they will get triggered by EE_Payment_Processor
284
+			if (! EE_Processor_Base::$IPN) {
285
+				// otherwise, send out notifications
286
+				add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true', 10);
287
+			}
288
+			// DEBUG LOG
289
+			//$this->log(
290
+			//	__CLASS__, __FUNCTION__, __LINE__,
291
+			//	$registration->transaction(),
292
+			//	array(
293
+			//		'IPN'                   => EE_Processor_Base::$IPN,
294
+			//		'deliver_notifications' => has_filter( 'FHEE__EED_Messages___maybe_registration__deliver_notifications' ),
295
+			//	)
296
+			//);
297
+		}
298
+	}
299
+
300
+
301
+
302
+	/**
303
+	 *    toggle_registration_status_for_default_approved_events
304
+	 *
305
+	 * @access public
306
+	 * @param EE_Registration $registration
307
+	 * @param bool            $save TRUE will save the registration if the status is updated, FALSE will leave that up
308
+	 *                              to client code
309
+	 * @return bool
310
+	 * @throws EE_Error
311
+	 * @throws EntityNotFoundException
312
+	 * @throws InvalidArgumentException
313
+	 * @throws InvalidDataTypeException
314
+	 * @throws InvalidInterfaceException
315
+	 * @throws ReflectionException
316
+	 * @throws RuntimeException
317
+	 */
318
+	public function toggle_registration_status_for_default_approved_events(EE_Registration $registration, $save = true)
319
+	{
320
+		$reg_status = $registration->status_ID();
321
+		// set initial REG_Status
322
+		$this->set_old_reg_status($registration->ID(), $reg_status);
323
+		// if not already, toggle reg status to approved IF the event default reg status is approved
324
+		// ( as long as the registration wasn't cancelled or declined at some point )
325
+		if (
326
+			$reg_status !== EEM_Registration::status_id_cancelled
327
+			&& $reg_status
328
+			   !== EEM_Registration::status_id_declined
329
+			&& $reg_status !== EEM_Registration::status_id_approved
330
+			&& $registration->event()->default_registration_status() === EEM_Registration::status_id_approved
331
+		) {
332
+			// set incoming REG_Status
333
+			$this->set_new_reg_status($registration->ID(), EEM_Registration::status_id_approved);
334
+			// toggle status to approved
335
+			$registration->set_status(EEM_Registration::status_id_approved);
336
+			if ($save) {
337
+				$registration->save();
338
+			}
339
+			// don't trigger notifications during IPNs because they will get triggered by EE_Payment_Processor
340
+			if (! EE_Processor_Base::$IPN) {
341
+				// otherwise, send out notifications
342
+				add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true', 10);
343
+			}
344
+			// DEBUG LOG
345
+			//$this->log(
346
+			//	__CLASS__, __FUNCTION__, __LINE__,
347
+			//	$registration->transaction(),
348
+			//	array(
349
+			//		'IPN'                   => EE_Processor_Base::$IPN,
350
+			//		'deliver_notifications' => has_filter( 'FHEE__EED_Messages___maybe_registration__deliver_notifications' ),
351
+			//	)
352
+			//);
353
+			return true;
354
+		}
355
+		return false;
356
+	}
357
+
358
+
359
+
360
+	/**
361
+	 *    toggle_registration_statuses_if_no_monies_owing
362
+	 *
363
+	 * @access public
364
+	 * @param EE_Registration $registration
365
+	 * @param bool            $save TRUE will save the registration if the status is updated, FALSE will leave that up
366
+	 *                              to client code
367
+	 * @param array           $additional_details
368
+	 * @return bool
369
+	 * @throws EE_Error
370
+	 * @throws EntityNotFoundException
371
+	 * @throws InvalidArgumentException
372
+	 * @throws InvalidDataTypeException
373
+	 * @throws InvalidInterfaceException
374
+	 * @throws ReflectionException
375
+	 * @throws RuntimeException
376
+	 */
377
+	public function toggle_registration_status_if_no_monies_owing(
378
+		EE_Registration $registration,
379
+		$save = true,
380
+		array $additional_details = array()
381
+	) {
382
+		// set initial REG_Status
383
+		$this->set_old_reg_status($registration->ID(), $registration->status_ID());
384
+		// was a payment just made ?
385
+		$payment    = isset($additional_details['payment_updates'], $additional_details['last_payment'])
386
+					  && $additional_details['payment_updates']
387
+					  && $additional_details['last_payment'] instanceof EE_Payment
388
+			? $additional_details['last_payment']
389
+			: null;
390
+		$total_paid = array_sum(self::$_amount_paid);
391
+		// toggle reg status to approved IF
392
+		if (
393
+			// REG status is pending payment
394
+			$registration->status_ID() === EEM_Registration::status_id_pending_payment
395
+			// AND no monies are owing
396
+			&& (
397
+				(
398
+					$registration->transaction()->is_completed()
399
+					|| $registration->transaction()->is_overpaid()
400
+					|| $registration->transaction()->is_free()
401
+					|| apply_filters(
402
+						'FHEE__EE_Registration_Processor__toggle_registration_status_if_no_monies_owing',
403
+						false,
404
+						$registration
405
+					)
406
+				)
407
+				|| (
408
+					$payment instanceof EE_Payment && $payment->is_approved()
409
+					&& // this specific registration has not yet been paid for
410
+					! isset(self::$_amount_paid[$registration->ID()])
411
+					&& // payment amount, less what we have already attributed to other registrations, is greater than this reg's final price
412
+					$payment->amount() - $total_paid >= $registration->final_price()
413
+				)
414
+			)
415
+		) {
416
+			// mark as paid
417
+			self::$_amount_paid[$registration->ID()] = $registration->final_price();
418
+			// track new REG_Status
419
+			$this->set_new_reg_status($registration->ID(), EEM_Registration::status_id_approved);
420
+			// toggle status to approved
421
+			$registration->set_status(EEM_Registration::status_id_approved);
422
+			if ($save) {
423
+				$registration->save();
424
+			}
425
+			// don't trigger notifications during IPNs because they will get triggered by EE_Payment_Processor
426
+			if (! EE_Processor_Base::$IPN) {
427
+				// otherwise, send out notifications
428
+				add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_true', 10);
429
+			}
430
+			// DEBUG LOG
431
+			//$this->log(
432
+			//	__CLASS__, __FUNCTION__, __LINE__,
433
+			//	$registration->transaction(),
434
+			//	array(
435
+			//		'IPN'                   => EE_Processor_Base::$IPN,
436
+			//		'deliver_notifications' => has_filter( 'FHEE__EED_Messages___maybe_registration__deliver_notifications' ),
437
+			//	)
438
+			//);
439
+			return true;
440
+		}
441
+		return false;
442
+	}
443
+
444
+
445
+
446
+	/**
447
+	 *    registration_status_changed
448
+	 *
449
+	 * @access public
450
+	 * @param EE_Registration $registration
451
+	 * @param array           $additional_details
452
+	 * @return void
453
+	 */
454
+	public function trigger_registration_update_notifications($registration, array $additional_details = array())
455
+	{
456
+		try {
457
+			if (! $registration instanceof EE_Registration) {
458
+				throw new EE_Error(
459
+					esc_html__('An invalid registration was received.', 'event_espresso')
460
+				);
461
+			}
462
+			// EE_Registry::instance()->load_helper( 'Debug_Tools' );
463
+			// EEH_Debug_Tools::log(
464
+			// 	__CLASS__,
465
+			// 	__FUNCTION__,
466
+			// 	__LINE__,
467
+			// 	array( $registration->transaction(), $additional_details ),
468
+			// 	false,
469
+			// 	'EE_Transaction: ' . $registration->transaction()->ID()
470
+			// );
471
+			if (! $registration->is_primary_registrant()) {
472
+				return;
473
+			}
474
+			do_action(
475
+				'AHEE__EE_Registration_Processor__trigger_registration_update_notifications',
476
+				$registration,
477
+				$additional_details
478
+			);
479
+		} catch (Exception $e) {
480
+			EE_Error::add_error($e->getMessage(), $e->getFile(), 'unknown_function_from_exception', $e->getLine());
481
+		}
482
+	}
483
+
484
+
485
+
486
+	/**
487
+	 * sets reg status based either on passed param or on transaction status and event pre-approval setting
488
+	 *
489
+	 * @param EE_Registration $registration
490
+	 * @param array           $additional_details
491
+	 * @return bool
492
+	 * @throws EE_Error
493
+	 * @throws EntityNotFoundException
494
+	 * @throws InvalidArgumentException
495
+	 * @throws InvalidDataTypeException
496
+	 * @throws InvalidInterfaceException
497
+	 * @throws ReflectionException
498
+	 * @throws RuntimeException
499
+	 */
500
+	public function update_registration_after_checkout_or_payment(
501
+		EE_Registration $registration,
502
+		array $additional_details = array()
503
+	) {
504
+		// set initial REG_Status
505
+		$this->set_old_reg_status($registration->ID(), $registration->status_ID());
506
+		// if the registration status gets updated, then save the registration
507
+		if (
508
+			$this->toggle_registration_status_for_default_approved_events($registration, false)
509
+			|| $this->toggle_registration_status_if_no_monies_owing(
510
+				$registration,
511
+				false,
512
+				$additional_details
513
+			)
514
+		) {
515
+			$registration->save();
516
+		}
517
+		// set new  REG_Status
518
+		$this->set_new_reg_status($registration->ID(), $registration->status_ID());
519
+		return $this->reg_status_updated($registration->ID())
520
+			   && $this->new_reg_status($registration->ID()) === EEM_Registration::status_id_approved;
521
+	}
522
+
523
+
524
+
525
+	/**
526
+	 * Updates the registration' final prices based on the current line item tree (taking into account
527
+	 * discounts, taxes, and other line items unrelated to tickets.)
528
+	 *
529
+	 * @param EE_Transaction $transaction
530
+	 * @param boolean        $save_regs whether to immediately save registrations in this function or not
531
+	 * @return void
532
+	 * @throws EE_Error
533
+	 * @throws InvalidArgumentException
534
+	 * @throws InvalidDataTypeException
535
+	 * @throws InvalidInterfaceException
536
+	 * @throws RuntimeException
537
+	 */
538
+	public function update_registration_final_prices($transaction, $save_regs = true)
539
+	{
540
+		$reg_final_price_per_ticket_line_item = EEH_Line_Item::calculate_reg_final_prices_per_line_item(
541
+			$transaction->total_line_item()
542
+		);
543
+		foreach ($transaction->registrations() as $registration) {
544
+			/** @var EE_Line_Item $line_item */
545
+			$line_item = EEM_Line_Item::instance()->get_line_item_for_registration($registration);
546
+			if (isset($reg_final_price_per_ticket_line_item[$line_item->ID()])) {
547
+				$registration->set_final_price($reg_final_price_per_ticket_line_item[$line_item->ID()]);
548
+				if ($save_regs) {
549
+					$registration->save();
550
+				}
551
+			}
552
+		}
553
+		//and make sure there's no rounding problem
554
+		$this->fix_reg_final_price_rounding_issue($transaction);
555
+	}
556
+
557
+
558
+
559
+	/**
560
+	 * Makes sure there is no rounding errors for the REG_final_prices.
561
+	 * Eg, if we have 3 registrations for $1, and there is a $0.01 discount between the three of them,
562
+	 * they will each be for $0.99333333, which gets rounded to $1 again.
563
+	 * So the transaction total will be $2.99, but each registration will be for $1,
564
+	 * so if each registrant paid individually they will have overpaid by $0.01.
565
+	 * So in order to overcome this, we check for any difference, and if there is a difference
566
+	 * we just grab one registrant at random and make them responsible for it.
567
+	 * This should be used after setting REG_final_prices (it's done automatically as part of
568
+	 * EE_Registration_Processor::update_registration_final_prices())
569
+	 *
570
+	 * @param EE_Transaction $transaction
571
+	 * @return bool success verifying that there is NO difference after this method is done
572
+	 * @throws EE_Error
573
+	 * @throws InvalidArgumentException
574
+	 * @throws InvalidDataTypeException
575
+	 * @throws InvalidInterfaceException
576
+	 */
577
+	public function fix_reg_final_price_rounding_issue($transaction)
578
+	{
579
+		$reg_final_price_sum = EEM_Registration::instance()->sum(
580
+			array(
581
+				array(
582
+					'TXN_ID' => $transaction->ID(),
583
+				),
584
+			),
585
+			'REG_final_price'
586
+		);
587
+		$diff = $transaction->total() - $reg_final_price_sum;
588
+		//ok then, just grab one of the registrations
589
+		if ($diff !== 0) {
590
+			$a_reg   = EEM_Registration::instance()->get_one(
591
+				array(
592
+					array(
593
+						'TXN_ID' => $transaction->ID(),
594
+					),
595
+				)
596
+			);
597
+			return $a_reg instanceof EE_Registration
598
+				? (bool) $a_reg->save(array('REG_final_price' => $a_reg->final_price() + $diff))
599
+				: false;
600
+		}
601
+		return true;
602
+	}
603
+
604
+
605
+
606
+	/**
607
+	 * update_registration_after_being_canceled_or_declined
608
+	 *
609
+	 * @param EE_Registration $registration
610
+	 * @param array           $closed_reg_statuses
611
+	 * @param bool            $update_reg
612
+	 * @return bool
613
+	 * @throws EE_Error
614
+	 * @throws RuntimeException
615
+	 */
616
+	public function update_registration_after_being_canceled_or_declined(
617
+		EE_Registration $registration,
618
+		array $closed_reg_statuses = array(),
619
+		$update_reg = true
620
+	) {
621
+		// these reg statuses should not be considered in any calculations involving monies owing
622
+		$closed_reg_statuses = ! empty($closed_reg_statuses)
623
+			? $closed_reg_statuses
624
+			: EEM_Registration::closed_reg_statuses();
625
+		if (! in_array($registration->status_ID(), $closed_reg_statuses, true)) {
626
+			return false;
627
+		}
628
+		// release a reserved ticket by decrementing ticket and datetime reserved values
629
+		$registration->release_reserved_ticket(true);
630
+		$registration->set_final_price(0);
631
+		if ($update_reg) {
632
+			$registration->save();
633
+		}
634
+		return true;
635
+	}
636
+
637
+
638
+
639
+	/**
640
+	 * update_canceled_or_declined_registration_after_being_reinstated
641
+	 *
642
+	 * @param EE_Registration $registration
643
+	 * @param array           $closed_reg_statuses
644
+	 * @param bool            $update_reg
645
+	 * @return bool
646
+	 * @throws EE_Error
647
+	 * @throws RuntimeException
648
+	 */
649
+	public function update_canceled_or_declined_registration_after_being_reinstated(
650
+		EE_Registration $registration,
651
+		array $closed_reg_statuses = array(),
652
+		$update_reg = true
653
+	) {
654
+		// these reg statuses should not be considered in any calculations involving monies owing
655
+		$closed_reg_statuses = ! empty($closed_reg_statuses) ? $closed_reg_statuses
656
+			: EEM_Registration::closed_reg_statuses();
657
+		if (in_array($registration->status_ID(), $closed_reg_statuses, true)) {
658
+			return false;
659
+		}
660
+		$ticket = $registration->ticket();
661
+		if (! $ticket instanceof EE_Ticket) {
662
+			throw new EE_Error(
663
+				sprintf(
664
+					esc_html__(
665
+						'The Ticket for Registration %1$d was not found or is invalid.',
666
+						'event_espresso'
667
+					),
668
+					$registration->ticket_ID()
669
+				)
670
+			);
671
+		}
672
+		$registration->set_final_price($ticket->price());
673
+		if ($update_reg) {
674
+			$registration->save();
675
+		}
676
+		return true;
677
+	}
678
+
679
+
680
+
681
+	/**
682
+	 * generate_ONE_registration_from_line_item
683
+	 * Although a ticket line item may have a quantity greater than 1,
684
+	 * this method will ONLY CREATE ONE REGISTRATION !!!
685
+	 * Regardless of the ticket line item quantity.
686
+	 * This means that any code calling this method is responsible for ensuring
687
+	 * that the final registration count matches the ticket line item quantity.
688
+	 * This was done to make it easier to match the number of registrations
689
+	 * to the number of tickets in the cart, when the cart has been edited
690
+	 * after SPCO has already been initialized. So if an additional ticket was added to the cart, you can simply pass
691
+	 * the line item to this method to add a second ticket, and in this case, you would not want to add 2 tickets.
692
+	 *
693
+	 * @deprecated
694
+	 * @since 4.9.1
695
+	 * @param EE_Line_Item    $line_item
696
+	 * @param \EE_Transaction $transaction
697
+	 * @param int             $att_nmbr
698
+	 * @param int             $total_ticket_count
699
+	 * @return EE_Registration | null
700
+	 * @throws \OutOfRangeException
701
+	 * @throws \EventEspresso\core\exceptions\UnexpectedEntityException
702
+	 * @throws \EE_Error
703
+	 */
704
+	public function generate_ONE_registration_from_line_item(
705
+		EE_Line_Item $line_item,
706
+		EE_Transaction $transaction,
707
+		$att_nmbr = 1,
708
+		$total_ticket_count = 1
709
+	) {
710
+		EE_Error::doing_it_wrong(
711
+			__CLASS__ . '::' . __FUNCTION__,
712
+			sprintf(
713
+				esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
714
+				'\EventEspresso\core\domain\services\registration\CreateRegistrationService::create()'
715
+			),
716
+			'4.9.1',
717
+			'5.0.0'
718
+		);
719
+		// grab the related ticket object for this line_item
720
+		$ticket = $line_item->ticket();
721
+		if (! $ticket instanceof EE_Ticket) {
722
+			EE_Error::add_error(
723
+				sprintf(
724
+					esc_html__('Line item %s did not contain a valid ticket', 'event_espresso'),
725
+					$line_item->ID()
726
+				),
727
+				__FILE__,
728
+				__FUNCTION__,
729
+				__LINE__
730
+			);
731
+			return null;
732
+		}
733
+		$registration_service = new CreateRegistrationService();
734
+		// then generate a new registration from that
735
+		return $registration_service->create(
736
+			$ticket->get_related_event(),
737
+			$transaction,
738
+			$ticket,
739
+			$line_item,
740
+			$att_nmbr,
741
+			$total_ticket_count
742
+		);
743
+	}
744
+
745
+
746
+
747
+	/**
748
+	 * generates reg_url_link
749
+	 *
750
+	 * @deprecated
751
+	 * @since 4.9.1
752
+	 * @param int                   $att_nmbr
753
+	 * @param EE_Line_Item | string $item
754
+	 * @return string
755
+	 * @throws InvalidArgumentException
756
+	 */
757
+	public function generate_reg_url_link($att_nmbr, $item)
758
+	{
759
+		EE_Error::doing_it_wrong(
760
+			__CLASS__ . '::' . __FUNCTION__,
761
+			sprintf(
762
+				esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
763
+				'EventEspresso\core\domain\entities\RegUrlLink'
764
+			),
765
+			'4.9.1',
766
+			'5.0.0'
767
+		);
768
+		return new RegUrlLink($att_nmbr, $item);
769
+	}
770
+
771
+
772
+
773
+	/**
774
+	 * generates reg code
775
+	 *
776
+	 * @deprecated
777
+	 * @since 4.9.1
778
+	 * @param EE_Registration $registration
779
+	 * @return string
780
+	 * @throws EE_Error
781
+	 * @throws EntityNotFoundException
782
+	 * @throws InvalidArgumentException
783
+	 */
784
+	public function generate_reg_code(EE_Registration $registration)
785
+	{
786
+		EE_Error::doing_it_wrong(
787
+			__CLASS__ . '::' . __FUNCTION__,
788
+			sprintf(
789
+				esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
790
+				'EventEspresso\core\domain\entities\RegCode'
791
+			),
792
+			'4.9.1',
793
+			'5.0.0'
794
+		);
795
+		return apply_filters(
796
+			'FHEE__EE_Registration_Processor___generate_reg_code__new_reg_code',
797
+			new RegCode(
798
+				RegUrlLink::fromRegistration($registration),
799
+				$registration->transaction(),
800
+				$registration->ticket()
801
+			),
802
+			$registration
803
+		);
804
+	}
805 805
 
806 806
 
807 807
 
Please login to merge, or discard this patch.