Completed
Branch FET/extra-logging-when-trashin... (2b1ce3)
by
unknown
06:11 queued 04:18
created
core/db_classes/EE_Transaction.class.php 2 patches
Spacing   +22 added lines, -22 removed lines patch added patch discarded remove patch
@@ -53,7 +53,7 @@  discard block
 block discarded – undo
53 53
         $txn = $has_object
54 54
             ? $has_object
55 55
             : new self($props_n_values, false, $timezone, $date_formats);
56
-        if (! $has_object) {
56
+        if ( ! $has_object) {
57 57
             $txn->set_old_txn_status($txn->status_ID());
58 58
         }
59 59
         return $txn;
@@ -93,7 +93,7 @@  discard block
 block discarded – undo
93 93
     public function lock()
94 94
     {
95 95
         // attempt to set lock, but if that fails...
96
-        if (! $this->add_extra_meta('lock', time(), true)) {
96
+        if ( ! $this->add_extra_meta('lock', time(), true)) {
97 97
             // then attempt to remove the lock in case it is expired
98 98
             if ($this->_remove_expired_lock()) {
99 99
                 // if removal was successful, then try setting lock again
@@ -149,7 +149,7 @@  discard block
 block discarded – undo
149 149
     public function is_locked()
150 150
     {
151 151
         // if TXN is not locked, then return false immediately
152
-        if (! $this->_get_lock()) {
152
+        if ( ! $this->_get_lock()) {
153 153
             return false;
154 154
         }
155 155
         // if not, then let's try and remove the lock in case it's expired...
@@ -647,7 +647,7 @@  discard block
 block discarded – undo
647 647
                 $icon = $show_icons ? '<span class="dashicons dashicons-plus ee-icon-size-16 orange-text"></span>' : '';
648 648
                 break;
649 649
         }
650
-        return $icon . $status[ $this->status_ID() ];
650
+        return $icon.$status[$this->status_ID()];
651 651
     }
652 652
 
653 653
 
@@ -785,7 +785,7 @@  discard block
 block discarded – undo
785 785
     public function invoice_url($type = 'html')
786 786
     {
787 787
         $REG = $this->primary_registration();
788
-        if (! $REG instanceof EE_Registration) {
788
+        if ( ! $REG instanceof EE_Registration) {
789 789
             return '';
790 790
         }
791 791
         return $REG->invoice_url($type);
@@ -836,7 +836,7 @@  discard block
 block discarded – undo
836 836
     public function receipt_url($type = 'html')
837 837
     {
838 838
         $REG = $this->primary_registration();
839
-        if (! $REG instanceof EE_Registration) {
839
+        if ( ! $REG instanceof EE_Registration) {
840 840
             return '';
841 841
         }
842 842
         return $REG->receipt_url($type);
@@ -1025,7 +1025,7 @@  discard block
 block discarded – undo
1025 1025
     public function total_line_item($create_if_not_found = true)
1026 1026
     {
1027 1027
         $item = $this->get_first_related('Line_Item', array(array('LIN_type' => EEM_Line_Item::type_total)));
1028
-        if (! $item && $create_if_not_found) {
1028
+        if ( ! $item && $create_if_not_found) {
1029 1029
             $item = EEH_Line_Item::create_total_line_item($this);
1030 1030
         }
1031 1031
         return $item;
@@ -1082,7 +1082,7 @@  discard block
 block discarded – undo
1082 1082
     public function billing_info()
1083 1083
     {
1084 1084
         $payment_method = $this->payment_method();
1085
-        if (! $payment_method) {
1085
+        if ( ! $payment_method) {
1086 1086
             EE_Error::add_error(
1087 1087
                 esc_html__(
1088 1088
                     'Could not find billing info for transaction because no gateway has been used for it yet',
@@ -1095,7 +1095,7 @@  discard block
 block discarded – undo
1095 1095
             return null;
1096 1096
         }
1097 1097
         $primary_reg = $this->primary_registration();
1098
-        if (! $primary_reg) {
1098
+        if ( ! $primary_reg) {
1099 1099
             EE_Error::add_error(
1100 1100
                 esc_html__(
1101 1101
                     'Cannot get billing info for gateway %s on transaction because no primary registration exists',
@@ -1108,7 +1108,7 @@  discard block
 block discarded – undo
1108 1108
             return null;
1109 1109
         }
1110 1110
         $attendee = $primary_reg->attendee();
1111
-        if (! $attendee) {
1111
+        if ( ! $attendee) {
1112 1112
             EE_Error::add_error(
1113 1113
                 esc_html__(
1114 1114
                     'Cannot get billing info for gateway %s on transaction because the primary registration has no attendee exists',
@@ -1265,7 +1265,7 @@  discard block
 block discarded – undo
1265 1265
     public function update_based_on_payments()
1266 1266
     {
1267 1267
         EE_Error::doing_it_wrong(
1268
-            __CLASS__ . '::' . __FUNCTION__,
1268
+            __CLASS__.'::'.__FUNCTION__,
1269 1269
             sprintf(
1270 1270
                 esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
1271 1271
                 'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'
@@ -1333,13 +1333,13 @@  discard block
 block discarded – undo
1333 1333
     private function _reg_steps_completed($reg_step_slug = '', $check_all = true)
1334 1334
     {
1335 1335
         $reg_steps = $this->reg_steps();
1336
-        if (! is_array($reg_steps) || empty($reg_steps)) {
1336
+        if ( ! is_array($reg_steps) || empty($reg_steps)) {
1337 1337
             return false;
1338 1338
         }
1339 1339
         // loop thru reg steps array)
1340 1340
         foreach ($reg_steps as $slug => $reg_step_completed) {
1341 1341
             // if NOT checking ALL steps (only checking one step)
1342
-            if (! $check_all) {
1342
+            if ( ! $check_all) {
1343 1343
                 // and this is the one
1344 1344
                 if ($slug === $reg_step_slug) {
1345 1345
                     return $reg_step_completed;
@@ -1542,30 +1542,30 @@  discard block
 block discarded – undo
1542 1542
         // get reg steps array
1543 1543
         $txn_reg_steps = $this->reg_steps();
1544 1544
         // if reg step does NOT exist
1545
-        if (! isset($txn_reg_steps[ $reg_step_slug ])) {
1545
+        if ( ! isset($txn_reg_steps[$reg_step_slug])) {
1546 1546
             return false;
1547 1547
         }
1548 1548
         // if  we're trying to complete a step that is already completed
1549
-        if ($txn_reg_steps[ $reg_step_slug ] === true) {
1549
+        if ($txn_reg_steps[$reg_step_slug] === true) {
1550 1550
             return true;
1551 1551
         }
1552 1552
         // if  we're trying to complete a step that hasn't even started
1553
-        if ($status === true && $txn_reg_steps[ $reg_step_slug ] === false) {
1553
+        if ($status === true && $txn_reg_steps[$reg_step_slug] === false) {
1554 1554
             return false;
1555 1555
         }
1556 1556
         // if current status value matches the incoming value (no change)
1557 1557
         // type casting as int means values should collapse to either 0, 1, or a timestamp like 1234567890
1558
-        if ((int) $txn_reg_steps[ $reg_step_slug ] === (int) $status) {
1558
+        if ((int) $txn_reg_steps[$reg_step_slug] === (int) $status) {
1559 1559
             // this will happen in cases where multiple AJAX requests occur during the same step
1560 1560
             return true;
1561 1561
         }
1562 1562
         // if we're trying to set a start time, but it has already been set...
1563
-        if (is_numeric($status) && is_numeric($txn_reg_steps[ $reg_step_slug ])) {
1563
+        if (is_numeric($status) && is_numeric($txn_reg_steps[$reg_step_slug])) {
1564 1564
             // skip the update below, but don't return FALSE so that errors won't be displayed
1565 1565
             return true;
1566 1566
         }
1567 1567
         // update completed status
1568
-        $txn_reg_steps[ $reg_step_slug ] = $status;
1568
+        $txn_reg_steps[$reg_step_slug] = $status;
1569 1569
         $this->set_reg_steps($txn_reg_steps);
1570 1570
         $this->save();
1571 1571
         return true;
@@ -1589,7 +1589,7 @@  discard block
 block discarded – undo
1589 1589
     {
1590 1590
         // get reg steps array
1591 1591
         $txn_reg_steps = $this->reg_steps();
1592
-        unset($txn_reg_steps[ $reg_step_slug ]);
1592
+        unset($txn_reg_steps[$reg_step_slug]);
1593 1593
         $this->set_reg_steps($txn_reg_steps);
1594 1594
     }
1595 1595
 
@@ -1671,12 +1671,12 @@  discard block
 block discarded – undo
1671 1671
             return;
1672 1672
         }
1673 1673
         $payments = $this->get_many_related('Payment');
1674
-        if (! empty($payments)) {
1674
+        if ( ! empty($payments)) {
1675 1675
             foreach ($payments as $payment) {
1676 1676
                 if ($payment instanceof EE_Payment) {
1677 1677
                     // kk this TXN should NOT be abandoned
1678 1678
                     $this->update_status_based_on_total_paid();
1679
-                    if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1679
+                    if ( ! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1680 1680
                         EE_Error::add_attention(
1681 1681
                             sprintf(
1682 1682
                                 esc_html__(
Please login to merge, or discard this patch.
Indentation   +1727 added lines, -1727 removed lines patch added patch discarded remove patch
@@ -13,1731 +13,1731 @@
 block discarded – undo
13 13
 class EE_Transaction extends EE_Base_Class implements EEI_Transaction
14 14
 {
15 15
 
16
-    /**
17
-     * The length of time in seconds that a lock is applied before being considered expired.
18
-     * It is not long because a transaction should only be locked for the duration of the request that locked it
19
-     */
20
-    const LOCK_EXPIRATION = 2;
21
-
22
-    /**
23
-     * extra meta key for tracking when transactions are deleted and by who
24
-     *
25
-     * @type string
26
-     */
27
-    const EXTRA_META_KEY_TXN_DELETED = 'transaction-deleted';
28
-
29
-    /**
30
-     * txn status upon initial construction.
31
-     *
32
-     * @var string
33
-     */
34
-    protected $_old_txn_status;
35
-
36
-
37
-    /**
38
-     * @param array  $props_n_values          incoming values
39
-     * @param string $timezone                incoming timezone
40
-     *                                        (if not set the timezone set for the website will be used.)
41
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
42
-     *                                        date_format and the second value is the time format
43
-     * @return EE_Transaction
44
-     * @throws EE_Error
45
-     * @throws InvalidArgumentException
46
-     * @throws InvalidDataTypeException
47
-     * @throws InvalidInterfaceException
48
-     * @throws ReflectionException
49
-     */
50
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
51
-    {
52
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
53
-        $txn = $has_object
54
-            ? $has_object
55
-            : new self($props_n_values, false, $timezone, $date_formats);
56
-        if (! $has_object) {
57
-            $txn->set_old_txn_status($txn->status_ID());
58
-        }
59
-        return $txn;
60
-    }
61
-
62
-
63
-    /**
64
-     * @param array  $props_n_values  incoming values from the database
65
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
66
-     *                                the website will be used.
67
-     * @return EE_Transaction
68
-     * @throws EE_Error
69
-     * @throws InvalidArgumentException
70
-     * @throws InvalidDataTypeException
71
-     * @throws InvalidInterfaceException
72
-     * @throws ReflectionException
73
-     */
74
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
75
-    {
76
-        $txn = new self($props_n_values, true, $timezone);
77
-        $txn->set_old_txn_status($txn->status_ID());
78
-        return $txn;
79
-    }
80
-
81
-
82
-    /**
83
-     * Sets a meta field indicating that this TXN is locked and should not be updated in the db.
84
-     * If a lock has already been set, then we will attempt to remove it in case it has expired.
85
-     * If that also fails, then an exception is thrown.
86
-     *
87
-     * @throws EE_Error
88
-     * @throws InvalidArgumentException
89
-     * @throws InvalidDataTypeException
90
-     * @throws InvalidInterfaceException
91
-     * @throws ReflectionException
92
-     */
93
-    public function lock()
94
-    {
95
-        // attempt to set lock, but if that fails...
96
-        if (! $this->add_extra_meta('lock', time(), true)) {
97
-            // then attempt to remove the lock in case it is expired
98
-            if ($this->_remove_expired_lock()) {
99
-                // if removal was successful, then try setting lock again
100
-                $this->lock();
101
-            } else {
102
-                // but if the lock can not be removed, then throw an exception
103
-                throw new EE_Error(
104
-                    sprintf(
105
-                        esc_html__(
106
-                            'Could not lock Transaction %1$d because it is already locked, meaning another part of the system is currently editing it. It should already be unlocked by the time you read this, so please refresh the page and try again.',
107
-                            'event_espresso'
108
-                        ),
109
-                        $this->ID()
110
-                    )
111
-                );
112
-            }
113
-        }
114
-    }
115
-
116
-
117
-    /**
118
-     * removes transaction lock applied in EE_Transaction::lock()
119
-     *
120
-     * @return int
121
-     * @throws EE_Error
122
-     * @throws InvalidArgumentException
123
-     * @throws InvalidDataTypeException
124
-     * @throws InvalidInterfaceException
125
-     * @throws ReflectionException
126
-     */
127
-    public function unlock()
128
-    {
129
-        return $this->delete_extra_meta('lock');
130
-    }
131
-
132
-
133
-    /**
134
-     * Decides whether or not now is the right time to update the transaction.
135
-     * This is useful because we don't always know if it is safe to update the transaction
136
-     * and its related data. why?
137
-     * because it's possible that the transaction is being used in another
138
-     * request and could overwrite anything we save.
139
-     * So we want to only update the txn once we know that won't happen.
140
-     * We also check that the lock isn't expired, and remove it if it is
141
-     *
142
-     * @return boolean
143
-     * @throws EE_Error
144
-     * @throws InvalidArgumentException
145
-     * @throws InvalidDataTypeException
146
-     * @throws InvalidInterfaceException
147
-     * @throws ReflectionException
148
-     */
149
-    public function is_locked()
150
-    {
151
-        // if TXN is not locked, then return false immediately
152
-        if (! $this->_get_lock()) {
153
-            return false;
154
-        }
155
-        // if not, then let's try and remove the lock in case it's expired...
156
-        // _remove_expired_lock() returns 0 when lock is valid (ie: removed = false)
157
-        // and a positive number if the lock was removed (ie: number of locks deleted),
158
-        // so we need to return the opposite
159
-        return ! $this->_remove_expired_lock() ? true : false;
160
-    }
161
-
162
-
163
-    /**
164
-     * Gets the meta field indicating that this TXN is locked
165
-     *
166
-     * @return int
167
-     * @throws EE_Error
168
-     * @throws InvalidArgumentException
169
-     * @throws InvalidDataTypeException
170
-     * @throws InvalidInterfaceException
171
-     * @throws ReflectionException
172
-     */
173
-    protected function _get_lock()
174
-    {
175
-        return (int) $this->get_extra_meta('lock', true, 0);
176
-    }
177
-
178
-
179
-    /**
180
-     * If the lock on this transaction is expired, then we want to remove it so that the transaction can be updated
181
-     *
182
-     * @return int
183
-     * @throws EE_Error
184
-     * @throws InvalidArgumentException
185
-     * @throws InvalidDataTypeException
186
-     * @throws InvalidInterfaceException
187
-     * @throws ReflectionException
188
-     */
189
-    protected function _remove_expired_lock()
190
-    {
191
-        $locked = $this->_get_lock();
192
-        if ($locked && time() - EE_Transaction::LOCK_EXPIRATION > $locked) {
193
-            return $this->unlock();
194
-        }
195
-        return 0;
196
-    }
197
-
198
-
199
-    /**
200
-     * Set transaction total
201
-     *
202
-     * @param float $total total value of transaction
203
-     * @throws EE_Error
204
-     * @throws InvalidArgumentException
205
-     * @throws InvalidDataTypeException
206
-     * @throws InvalidInterfaceException
207
-     * @throws ReflectionException
208
-     */
209
-    public function set_total($total = 0.00)
210
-    {
211
-        $this->set('TXN_total', (float) $total);
212
-    }
213
-
214
-
215
-    /**
216
-     * Set Total Amount Paid to Date
217
-     *
218
-     * @param float $total_paid total amount paid to date (sum of all payments)
219
-     * @throws EE_Error
220
-     * @throws InvalidArgumentException
221
-     * @throws InvalidDataTypeException
222
-     * @throws InvalidInterfaceException
223
-     * @throws ReflectionException
224
-     */
225
-    public function set_paid($total_paid = 0.00)
226
-    {
227
-        $this->set('TXN_paid', (float) $total_paid);
228
-    }
229
-
230
-
231
-    /**
232
-     * Set transaction status
233
-     *
234
-     * @param string $status        whether the transaction is open, declined, accepted,
235
-     *                              or any number of custom values that can be set
236
-     * @throws EE_Error
237
-     * @throws InvalidArgumentException
238
-     * @throws InvalidDataTypeException
239
-     * @throws InvalidInterfaceException
240
-     * @throws ReflectionException
241
-     */
242
-    public function set_status($status = '')
243
-    {
244
-        $this->set('STS_ID', $status);
245
-    }
246
-
247
-
248
-    /**
249
-     * Set hash salt
250
-     *
251
-     * @param string $hash_salt required for some payment gateways
252
-     * @throws EE_Error
253
-     * @throws InvalidArgumentException
254
-     * @throws InvalidDataTypeException
255
-     * @throws InvalidInterfaceException
256
-     * @throws ReflectionException
257
-     */
258
-    public function set_hash_salt($hash_salt = '')
259
-    {
260
-        $this->set('TXN_hash_salt', $hash_salt);
261
-    }
262
-
263
-
264
-    /**
265
-     * Sets TXN_reg_steps array
266
-     *
267
-     * @param array $txn_reg_steps
268
-     * @throws EE_Error
269
-     * @throws InvalidArgumentException
270
-     * @throws InvalidDataTypeException
271
-     * @throws InvalidInterfaceException
272
-     * @throws ReflectionException
273
-     */
274
-    public function set_reg_steps(array $txn_reg_steps)
275
-    {
276
-        $this->set('TXN_reg_steps', $txn_reg_steps);
277
-    }
278
-
279
-
280
-    /**
281
-     * Gets TXN_reg_steps
282
-     *
283
-     * @return array
284
-     * @throws EE_Error
285
-     * @throws InvalidArgumentException
286
-     * @throws InvalidDataTypeException
287
-     * @throws InvalidInterfaceException
288
-     * @throws ReflectionException
289
-     */
290
-    public function reg_steps()
291
-    {
292
-        $TXN_reg_steps = $this->get('TXN_reg_steps');
293
-        return is_array($TXN_reg_steps) ? (array) $TXN_reg_steps : array();
294
-    }
295
-
296
-
297
-    /**
298
-     * @return string of transaction's total cost, with currency symbol and decimal
299
-     * @throws EE_Error
300
-     * @throws InvalidArgumentException
301
-     * @throws InvalidDataTypeException
302
-     * @throws InvalidInterfaceException
303
-     * @throws ReflectionException
304
-     */
305
-    public function pretty_total()
306
-    {
307
-        return $this->get_pretty('TXN_total');
308
-    }
309
-
310
-
311
-    /**
312
-     * Gets the amount paid in a pretty string (formatted and with currency symbol)
313
-     *
314
-     * @return string
315
-     * @throws EE_Error
316
-     * @throws InvalidArgumentException
317
-     * @throws InvalidDataTypeException
318
-     * @throws InvalidInterfaceException
319
-     * @throws ReflectionException
320
-     */
321
-    public function pretty_paid()
322
-    {
323
-        return $this->get_pretty('TXN_paid');
324
-    }
325
-
326
-
327
-    /**
328
-     * calculate the amount remaining for this transaction and return;
329
-     *
330
-     * @return float amount remaining
331
-     * @throws EE_Error
332
-     * @throws InvalidArgumentException
333
-     * @throws InvalidDataTypeException
334
-     * @throws InvalidInterfaceException
335
-     * @throws ReflectionException
336
-     */
337
-    public function remaining()
338
-    {
339
-        return $this->total() - $this->paid();
340
-    }
341
-
342
-
343
-    /**
344
-     * get Transaction Total
345
-     *
346
-     * @return float
347
-     * @throws EE_Error
348
-     * @throws InvalidArgumentException
349
-     * @throws InvalidDataTypeException
350
-     * @throws InvalidInterfaceException
351
-     * @throws ReflectionException
352
-     */
353
-    public function total()
354
-    {
355
-        return (float) $this->get('TXN_total');
356
-    }
357
-
358
-
359
-    /**
360
-     * get Total Amount Paid to Date
361
-     *
362
-     * @return float
363
-     * @throws EE_Error
364
-     * @throws InvalidArgumentException
365
-     * @throws InvalidDataTypeException
366
-     * @throws InvalidInterfaceException
367
-     * @throws ReflectionException
368
-     */
369
-    public function paid()
370
-    {
371
-        return (float) $this->get('TXN_paid');
372
-    }
373
-
374
-
375
-    /**
376
-     * @return mixed|null
377
-     * @throws EE_Error
378
-     * @throws InvalidArgumentException
379
-     * @throws InvalidDataTypeException
380
-     * @throws InvalidInterfaceException
381
-     * @throws ReflectionException
382
-     */
383
-    public function get_cart_session()
384
-    {
385
-        $session_data = (array) $this->get('TXN_session_data');
386
-        return isset($session_data['cart']) && $session_data['cart'] instanceof EE_Cart
387
-            ? $session_data['cart']
388
-            : null;
389
-    }
390
-
391
-
392
-    /**
393
-     * get Transaction session data
394
-     *
395
-     * @return array|mixed
396
-     * @throws EE_Error
397
-     * @throws InvalidArgumentException
398
-     * @throws InvalidDataTypeException
399
-     * @throws InvalidInterfaceException
400
-     * @throws ReflectionException
401
-     */
402
-    public function session_data()
403
-    {
404
-        $session_data = $this->get('TXN_session_data');
405
-        if (empty($session_data)) {
406
-            $session_data = array(
407
-                'id'            => null,
408
-                'user_id'       => null,
409
-                'ip_address'    => null,
410
-                'user_agent'    => null,
411
-                'init_access'   => null,
412
-                'last_access'   => null,
413
-                'pages_visited' => array(),
414
-            );
415
-        }
416
-        return $session_data;
417
-    }
418
-
419
-
420
-    /**
421
-     * Set session data within the TXN object
422
-     *
423
-     * @param EE_Session|array $session_data
424
-     * @throws EE_Error
425
-     * @throws InvalidArgumentException
426
-     * @throws InvalidDataTypeException
427
-     * @throws InvalidInterfaceException
428
-     * @throws ReflectionException
429
-     */
430
-    public function set_txn_session_data($session_data)
431
-    {
432
-        if ($session_data instanceof EE_Session) {
433
-            $this->set('TXN_session_data', $session_data->get_session_data(null, true));
434
-        } else {
435
-            $this->set('TXN_session_data', $session_data);
436
-        }
437
-    }
438
-
439
-
440
-    /**
441
-     * get Transaction hash salt
442
-     *
443
-     * @return mixed
444
-     * @throws EE_Error
445
-     * @throws InvalidArgumentException
446
-     * @throws InvalidDataTypeException
447
-     * @throws InvalidInterfaceException
448
-     * @throws ReflectionException
449
-     */
450
-    public function hash_salt_()
451
-    {
452
-        return $this->get('TXN_hash_salt');
453
-    }
454
-
455
-
456
-    /**
457
-     * Returns the transaction datetime as either:
458
-     *            - unix timestamp format ($format = false, $gmt = true)
459
-     *            - formatted date string including the UTC (timezone) offset ($format = true ($gmt
460
-     *              has no affect with this option)), this also may include a timezone abbreviation if the
461
-     *              set timezone in this class differs from what the timezone is on the blog.
462
-     *            - formatted date string including the UTC (timezone) offset (default).
463
-     *
464
-     * @param boolean $format   - whether to return a unix timestamp (default) or formatted date string
465
-     * @param boolean $gmt      - whether to return a unix timestamp with UTC offset applied (default)
466
-     *                          or no UTC offset applied
467
-     * @return string | int
468
-     * @throws EE_Error
469
-     * @throws InvalidArgumentException
470
-     * @throws InvalidDataTypeException
471
-     * @throws InvalidInterfaceException
472
-     * @throws ReflectionException
473
-     */
474
-    public function datetime($format = false, $gmt = false)
475
-    {
476
-        if ($format) {
477
-            return $this->get_pretty('TXN_timestamp');
478
-        }
479
-        if ($gmt) {
480
-            return $this->get_raw('TXN_timestamp');
481
-        }
482
-        return $this->get('TXN_timestamp');
483
-    }
484
-
485
-
486
-    /**
487
-     * Gets registrations on this transaction
488
-     *
489
-     * @param array   $query_params array of query parameters
490
-     * @param boolean $get_cached   TRUE to retrieve cached registrations or FALSE to pull from the db
491
-     * @return EE_Base_Class[]|EE_Registration[]
492
-     * @throws EE_Error
493
-     * @throws InvalidArgumentException
494
-     * @throws InvalidDataTypeException
495
-     * @throws InvalidInterfaceException
496
-     * @throws ReflectionException
497
-     */
498
-    public function registrations($query_params = array(), $get_cached = false)
499
-    {
500
-        $query_params = (empty($query_params) || ! is_array($query_params))
501
-            ? array(
502
-                'order_by' => array(
503
-                    'Event.EVT_name'     => 'ASC',
504
-                    'Attendee.ATT_lname' => 'ASC',
505
-                    'Attendee.ATT_fname' => 'ASC',
506
-                ),
507
-            )
508
-            : $query_params;
509
-        $query_params = $get_cached ? array() : $query_params;
510
-        return $this->get_many_related('Registration', $query_params);
511
-    }
512
-
513
-
514
-    /**
515
-     * Gets all the attendees for this transaction (handy for use with EE_Attendee's get_registrations_for_event
516
-     * function for getting attendees and how many registrations they each have for an event)
517
-     *
518
-     * @return mixed EE_Attendee[] by default, int if $output is set to 'COUNT'
519
-     * @throws EE_Error
520
-     * @throws InvalidArgumentException
521
-     * @throws InvalidDataTypeException
522
-     * @throws InvalidInterfaceException
523
-     * @throws ReflectionException
524
-     */
525
-    public function attendees()
526
-    {
527
-        return $this->get_many_related('Attendee', array(array('Registration.Transaction.TXN_ID' => $this->ID())));
528
-    }
529
-
530
-
531
-    /**
532
-     * Gets payments for this transaction. Unlike other such functions, order by 'DESC' by default
533
-     *
534
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
535
-     * @return EE_Base_Class[]|EE_Payment[]
536
-     * @throws EE_Error
537
-     * @throws InvalidArgumentException
538
-     * @throws InvalidDataTypeException
539
-     * @throws InvalidInterfaceException
540
-     * @throws ReflectionException
541
-     */
542
-    public function payments($query_params = array())
543
-    {
544
-        return $this->get_many_related('Payment', $query_params);
545
-    }
546
-
547
-
548
-    /**
549
-     * gets only approved payments for this transaction
550
-     *
551
-     * @return EE_Base_Class[]|EE_Payment[]
552
-     * @throws EE_Error
553
-     * @throws InvalidArgumentException
554
-     * @throws ReflectionException
555
-     * @throws InvalidDataTypeException
556
-     * @throws InvalidInterfaceException
557
-     */
558
-    public function approved_payments()
559
-    {
560
-        EE_Registry::instance()->load_model('Payment');
561
-        return $this->get_many_related(
562
-            'Payment',
563
-            array(
564
-                array('STS_ID' => EEM_Payment::status_id_approved),
565
-                'order_by' => array('PAY_timestamp' => 'DESC'),
566
-            )
567
-        );
568
-    }
569
-
570
-
571
-    /**
572
-     * Gets all payments which have not been approved
573
-     *
574
-     * @return EE_Base_Class[]|EEI_Payment[]
575
-     * @throws EE_Error if a model is misconfigured somehow
576
-     * @throws InvalidArgumentException
577
-     * @throws InvalidDataTypeException
578
-     * @throws InvalidInterfaceException
579
-     * @throws ReflectionException
580
-     */
581
-    public function pending_payments()
582
-    {
583
-        return $this->get_many_related(
584
-            'Payment',
585
-            array(
586
-                array(
587
-                    'STS_ID' => EEM_Payment::status_id_pending,
588
-                ),
589
-                'order_by' => array(
590
-                    'PAY_timestamp' => 'DESC',
591
-                ),
592
-            )
593
-        );
594
-    }
595
-
596
-
597
-    /**
598
-     * echoes $this->pretty_status()
599
-     *
600
-     * @param bool $show_icons
601
-     * @throws EE_Error
602
-     * @throws InvalidArgumentException
603
-     * @throws InvalidDataTypeException
604
-     * @throws InvalidInterfaceException
605
-     * @throws ReflectionException
606
-     */
607
-    public function e_pretty_status($show_icons = false)
608
-    {
609
-        echo $this->pretty_status($show_icons);
610
-    }
611
-
612
-
613
-    /**
614
-     * returns a pretty version of the status, good for displaying to users
615
-     *
616
-     * @param bool $show_icons
617
-     * @return string
618
-     * @throws EE_Error
619
-     * @throws InvalidArgumentException
620
-     * @throws InvalidDataTypeException
621
-     * @throws InvalidInterfaceException
622
-     * @throws ReflectionException
623
-     */
624
-    public function pretty_status($show_icons = false)
625
-    {
626
-        $status = EEM_Status::instance()->localized_status(
627
-            array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
628
-            false,
629
-            'sentence'
630
-        );
631
-        $icon = '';
632
-        switch ($this->status_ID()) {
633
-            case EEM_Transaction::complete_status_code:
634
-                $icon = $show_icons ? '<span class="dashicons dashicons-yes ee-icon-size-24 green-text"></span>' : '';
635
-                break;
636
-            case EEM_Transaction::incomplete_status_code:
637
-                $icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 lt-blue-text"></span>'
638
-                    : '';
639
-                break;
640
-            case EEM_Transaction::abandoned_status_code:
641
-                $icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 red-text"></span>' : '';
642
-                break;
643
-            case EEM_Transaction::failed_status_code:
644
-                $icon = $show_icons ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>' : '';
645
-                break;
646
-            case EEM_Transaction::overpaid_status_code:
647
-                $icon = $show_icons ? '<span class="dashicons dashicons-plus ee-icon-size-16 orange-text"></span>' : '';
648
-                break;
649
-        }
650
-        return $icon . $status[ $this->status_ID() ];
651
-    }
652
-
653
-
654
-    /**
655
-     * get Transaction Status
656
-     *
657
-     * @return mixed
658
-     * @throws EE_Error
659
-     * @throws InvalidArgumentException
660
-     * @throws InvalidDataTypeException
661
-     * @throws InvalidInterfaceException
662
-     * @throws ReflectionException
663
-     */
664
-    public function status_ID()
665
-    {
666
-        return $this->get('STS_ID');
667
-    }
668
-
669
-
670
-    /**
671
-     * Returns TRUE or FALSE for whether or not this transaction cost any money
672
-     *
673
-     * @return boolean
674
-     * @throws EE_Error
675
-     * @throws InvalidArgumentException
676
-     * @throws InvalidDataTypeException
677
-     * @throws InvalidInterfaceException
678
-     * @throws ReflectionException
679
-     */
680
-    public function is_free()
681
-    {
682
-        return EEH_Money::compare_floats($this->get('TXN_total'), 0, '==');
683
-    }
684
-
685
-
686
-    /**
687
-     * Returns whether this transaction is complete
688
-     * Useful in templates and other logic for deciding if we should ask for another payment...
689
-     *
690
-     * @return boolean
691
-     * @throws EE_Error
692
-     * @throws InvalidArgumentException
693
-     * @throws InvalidDataTypeException
694
-     * @throws InvalidInterfaceException
695
-     * @throws ReflectionException
696
-     */
697
-    public function is_completed()
698
-    {
699
-        return $this->status_ID() === EEM_Transaction::complete_status_code;
700
-    }
701
-
702
-
703
-    /**
704
-     * Returns whether this transaction is incomplete
705
-     * Useful in templates and other logic for deciding if we should ask for another payment...
706
-     *
707
-     * @return boolean
708
-     * @throws EE_Error
709
-     * @throws InvalidArgumentException
710
-     * @throws InvalidDataTypeException
711
-     * @throws InvalidInterfaceException
712
-     * @throws ReflectionException
713
-     */
714
-    public function is_incomplete()
715
-    {
716
-        return $this->status_ID() === EEM_Transaction::incomplete_status_code;
717
-    }
718
-
719
-
720
-    /**
721
-     * Returns whether this transaction is overpaid
722
-     * Useful in templates and other logic for deciding if monies need to be refunded
723
-     *
724
-     * @return boolean
725
-     * @throws EE_Error
726
-     * @throws InvalidArgumentException
727
-     * @throws InvalidDataTypeException
728
-     * @throws InvalidInterfaceException
729
-     * @throws ReflectionException
730
-     */
731
-    public function is_overpaid()
732
-    {
733
-        return $this->status_ID() === EEM_Transaction::overpaid_status_code;
734
-    }
735
-
736
-
737
-    /**
738
-     * Returns whether this transaction was abandoned
739
-     * meaning that the transaction/registration process was somehow interrupted and never completed
740
-     * but that contact information exists for at least one registrant
741
-     *
742
-     * @return boolean
743
-     * @throws EE_Error
744
-     * @throws InvalidArgumentException
745
-     * @throws InvalidDataTypeException
746
-     * @throws InvalidInterfaceException
747
-     * @throws ReflectionException
748
-     */
749
-    public function is_abandoned()
750
-    {
751
-        return $this->status_ID() === EEM_Transaction::abandoned_status_code;
752
-    }
753
-
754
-
755
-    /**
756
-     * Returns whether this transaction failed
757
-     * meaning that the transaction/registration process was somehow interrupted and never completed
758
-     * and that NO contact information exists for any registrants
759
-     *
760
-     * @return boolean
761
-     * @throws EE_Error
762
-     * @throws InvalidArgumentException
763
-     * @throws InvalidDataTypeException
764
-     * @throws InvalidInterfaceException
765
-     * @throws ReflectionException
766
-     */
767
-    public function failed()
768
-    {
769
-        return $this->status_ID() === EEM_Transaction::failed_status_code;
770
-    }
771
-
772
-
773
-    /**
774
-     * This returns the url for the invoice of this transaction
775
-     *
776
-     * @param string $type 'html' or 'pdf' (default is pdf)
777
-     * @return string
778
-     * @throws DomainException
779
-     * @throws EE_Error
780
-     * @throws InvalidArgumentException
781
-     * @throws InvalidDataTypeException
782
-     * @throws InvalidInterfaceException
783
-     * @throws ReflectionException
784
-     */
785
-    public function invoice_url($type = 'html')
786
-    {
787
-        $REG = $this->primary_registration();
788
-        if (! $REG instanceof EE_Registration) {
789
-            return '';
790
-        }
791
-        return $REG->invoice_url($type);
792
-    }
793
-
794
-
795
-    /**
796
-     * Gets the primary registration only
797
-     *
798
-     * @return EE_Base_Class|EE_Registration
799
-     * @throws EE_Error
800
-     * @throws InvalidArgumentException
801
-     * @throws InvalidDataTypeException
802
-     * @throws InvalidInterfaceException
803
-     * @throws ReflectionException
804
-     */
805
-    public function primary_registration()
806
-    {
807
-        $registrations = (array) $this->get_many_related(
808
-            'Registration',
809
-            array(array('REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT))
810
-        );
811
-        foreach ($registrations as $registration) {
812
-            // valid registration that is NOT cancelled or declined ?
813
-            if ($registration instanceof EE_Registration
814
-                && ! in_array($registration->status_ID(), EEM_Registration::closed_reg_statuses(), true)
815
-            ) {
816
-                return $registration;
817
-            }
818
-        }
819
-        // nothing valid found, so just return first thing from array of results
820
-        return reset($registrations);
821
-    }
822
-
823
-
824
-    /**
825
-     * Gets the URL for viewing the receipt
826
-     *
827
-     * @param string $type 'pdf' or 'html' (default is 'html')
828
-     * @return string
829
-     * @throws DomainException
830
-     * @throws EE_Error
831
-     * @throws InvalidArgumentException
832
-     * @throws InvalidDataTypeException
833
-     * @throws InvalidInterfaceException
834
-     * @throws ReflectionException
835
-     */
836
-    public function receipt_url($type = 'html')
837
-    {
838
-        $REG = $this->primary_registration();
839
-        if (! $REG instanceof EE_Registration) {
840
-            return '';
841
-        }
842
-        return $REG->receipt_url($type);
843
-    }
844
-
845
-
846
-    /**
847
-     * Gets the URL of the thank you page with this registration REG_url_link added as
848
-     * a query parameter
849
-     *
850
-     * @return string
851
-     * @throws EE_Error
852
-     * @throws InvalidArgumentException
853
-     * @throws InvalidDataTypeException
854
-     * @throws InvalidInterfaceException
855
-     * @throws ReflectionException
856
-     */
857
-    public function payment_overview_url()
858
-    {
859
-        $primary_registration = $this->primary_registration();
860
-        return $primary_registration instanceof EE_Registration ? $primary_registration->payment_overview_url() : false;
861
-    }
862
-
863
-
864
-    /**
865
-     * @return string
866
-     * @throws EE_Error
867
-     * @throws InvalidArgumentException
868
-     * @throws InvalidDataTypeException
869
-     * @throws InvalidInterfaceException
870
-     * @throws ReflectionException
871
-     */
872
-    public function gateway_response_on_transaction()
873
-    {
874
-        $payment = $this->get_first_related('Payment');
875
-        return $payment instanceof EE_Payment ? $payment->gateway_response() : '';
876
-    }
877
-
878
-
879
-    /**
880
-     * Get the status object of this object
881
-     *
882
-     * @return EE_Base_Class|EE_Status
883
-     * @throws EE_Error
884
-     * @throws InvalidArgumentException
885
-     * @throws InvalidDataTypeException
886
-     * @throws InvalidInterfaceException
887
-     * @throws ReflectionException
888
-     */
889
-    public function status_obj()
890
-    {
891
-        return $this->get_first_related('Status');
892
-    }
893
-
894
-
895
-    /**
896
-     * Gets all the extra meta info on this payment
897
-     *
898
-     * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
899
-     * @return EE_Base_Class[]|EE_Extra_Meta
900
-     * @throws EE_Error
901
-     * @throws InvalidArgumentException
902
-     * @throws InvalidDataTypeException
903
-     * @throws InvalidInterfaceException
904
-     * @throws ReflectionException
905
-     */
906
-    public function extra_meta($query_params = array())
907
-    {
908
-        return $this->get_many_related('Extra_Meta', $query_params);
909
-    }
910
-
911
-
912
-    /**
913
-     * Wrapper for _add_relation_to
914
-     *
915
-     * @param EE_Registration $registration
916
-     * @return EE_Base_Class the relation was added to
917
-     * @throws EE_Error
918
-     * @throws InvalidArgumentException
919
-     * @throws InvalidDataTypeException
920
-     * @throws InvalidInterfaceException
921
-     * @throws ReflectionException
922
-     */
923
-    public function add_registration(EE_Registration $registration)
924
-    {
925
-        return $this->_add_relation_to($registration, 'Registration');
926
-    }
927
-
928
-
929
-    /**
930
-     * Removes the given registration from being related (even before saving this transaction).
931
-     * If an ID/index is provided and this transaction isn't saved yet, removes it from list of cached relations
932
-     *
933
-     * @param int $registration_or_id
934
-     * @return EE_Base_Class that was removed from being related
935
-     * @throws EE_Error
936
-     * @throws InvalidArgumentException
937
-     * @throws InvalidDataTypeException
938
-     * @throws InvalidInterfaceException
939
-     * @throws ReflectionException
940
-     */
941
-    public function remove_registration_with_id($registration_or_id)
942
-    {
943
-        return $this->_remove_relation_to($registration_or_id, 'Registration');
944
-    }
945
-
946
-
947
-    /**
948
-     * Gets all the line items which are for ACTUAL items
949
-     *
950
-     * @return EE_Line_Item[]
951
-     * @throws EE_Error
952
-     * @throws InvalidArgumentException
953
-     * @throws InvalidDataTypeException
954
-     * @throws InvalidInterfaceException
955
-     * @throws ReflectionException
956
-     */
957
-    public function items_purchased()
958
-    {
959
-        return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_line_item)));
960
-    }
961
-
962
-
963
-    /**
964
-     * Wrapper for _add_relation_to
965
-     *
966
-     * @param EE_Line_Item $line_item
967
-     * @return EE_Base_Class the relation was added to
968
-     * @throws EE_Error
969
-     * @throws InvalidArgumentException
970
-     * @throws InvalidDataTypeException
971
-     * @throws InvalidInterfaceException
972
-     * @throws ReflectionException
973
-     */
974
-    public function add_line_item(EE_Line_Item $line_item)
975
-    {
976
-        return $this->_add_relation_to($line_item, 'Line_Item');
977
-    }
978
-
979
-
980
-    /**
981
-     * Gets ALL the line items related to this transaction (unstructured)
982
-     *
983
-     * @param array $query_params
984
-     * @return EE_Base_Class[]|EE_Line_Item[]
985
-     * @throws EE_Error
986
-     * @throws InvalidArgumentException
987
-     * @throws InvalidDataTypeException
988
-     * @throws InvalidInterfaceException
989
-     * @throws ReflectionException
990
-     */
991
-    public function line_items($query_params = array())
992
-    {
993
-        return $this->get_many_related('Line_Item', $query_params);
994
-    }
995
-
996
-
997
-    /**
998
-     * Gets all the line items which are taxes on the total
999
-     *
1000
-     * @return EE_Line_Item[]
1001
-     * @throws EE_Error
1002
-     * @throws InvalidArgumentException
1003
-     * @throws InvalidDataTypeException
1004
-     * @throws InvalidInterfaceException
1005
-     * @throws ReflectionException
1006
-     */
1007
-    public function tax_items()
1008
-    {
1009
-        return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_tax)));
1010
-    }
1011
-
1012
-
1013
-    /**
1014
-     * Gets the total line item (which is a parent of all other related line items,
1015
-     * meaning it takes them all into account on its total)
1016
-     *
1017
-     * @param bool $create_if_not_found
1018
-     * @return \EE_Line_Item
1019
-     * @throws EE_Error
1020
-     * @throws InvalidArgumentException
1021
-     * @throws InvalidDataTypeException
1022
-     * @throws InvalidInterfaceException
1023
-     * @throws ReflectionException
1024
-     */
1025
-    public function total_line_item($create_if_not_found = true)
1026
-    {
1027
-        $item = $this->get_first_related('Line_Item', array(array('LIN_type' => EEM_Line_Item::type_total)));
1028
-        if (! $item && $create_if_not_found) {
1029
-            $item = EEH_Line_Item::create_total_line_item($this);
1030
-        }
1031
-        return $item;
1032
-    }
1033
-
1034
-
1035
-    /**
1036
-     * Returns the total amount of tax on this transaction
1037
-     * (assumes there's only one tax subtotal line item)
1038
-     *
1039
-     * @return float
1040
-     * @throws EE_Error
1041
-     * @throws InvalidArgumentException
1042
-     * @throws InvalidDataTypeException
1043
-     * @throws InvalidInterfaceException
1044
-     * @throws ReflectionException
1045
-     */
1046
-    public function tax_total()
1047
-    {
1048
-        $tax_line_item = $this->tax_total_line_item();
1049
-        if ($tax_line_item) {
1050
-            return (float) $tax_line_item->total();
1051
-        }
1052
-        return (float) 0;
1053
-    }
1054
-
1055
-
1056
-    /**
1057
-     * Gets the tax subtotal line item (assumes there's only one)
1058
-     *
1059
-     * @return EE_Line_Item
1060
-     * @throws EE_Error
1061
-     * @throws InvalidArgumentException
1062
-     * @throws InvalidDataTypeException
1063
-     * @throws InvalidInterfaceException
1064
-     * @throws ReflectionException
1065
-     */
1066
-    public function tax_total_line_item()
1067
-    {
1068
-        return EEH_Line_Item::get_taxes_subtotal($this->total_line_item());
1069
-    }
1070
-
1071
-
1072
-    /**
1073
-     * Gets the array of billing info for the gateway and for this transaction's primary registration's attendee.
1074
-     *
1075
-     * @return EE_Form_Section_Proper
1076
-     * @throws EE_Error
1077
-     * @throws InvalidArgumentException
1078
-     * @throws InvalidDataTypeException
1079
-     * @throws InvalidInterfaceException
1080
-     * @throws ReflectionException
1081
-     */
1082
-    public function billing_info()
1083
-    {
1084
-        $payment_method = $this->payment_method();
1085
-        if (! $payment_method) {
1086
-            EE_Error::add_error(
1087
-                esc_html__(
1088
-                    'Could not find billing info for transaction because no gateway has been used for it yet',
1089
-                    'event_espresso'
1090
-                ),
1091
-                __FILE__,
1092
-                __FUNCTION__,
1093
-                __LINE__
1094
-            );
1095
-            return null;
1096
-        }
1097
-        $primary_reg = $this->primary_registration();
1098
-        if (! $primary_reg) {
1099
-            EE_Error::add_error(
1100
-                esc_html__(
1101
-                    'Cannot get billing info for gateway %s on transaction because no primary registration exists',
1102
-                    'event_espresso'
1103
-                ),
1104
-                __FILE__,
1105
-                __FUNCTION__,
1106
-                __LINE__
1107
-            );
1108
-            return null;
1109
-        }
1110
-        $attendee = $primary_reg->attendee();
1111
-        if (! $attendee) {
1112
-            EE_Error::add_error(
1113
-                esc_html__(
1114
-                    'Cannot get billing info for gateway %s on transaction because the primary registration has no attendee exists',
1115
-                    'event_espresso'
1116
-                ),
1117
-                __FILE__,
1118
-                __FUNCTION__,
1119
-                __LINE__
1120
-            );
1121
-            return null;
1122
-        }
1123
-        return $attendee->billing_info_for_payment_method($payment_method);
1124
-    }
1125
-
1126
-
1127
-    /**
1128
-     * Gets PMD_ID
1129
-     *
1130
-     * @return int
1131
-     * @throws EE_Error
1132
-     * @throws InvalidArgumentException
1133
-     * @throws InvalidDataTypeException
1134
-     * @throws InvalidInterfaceException
1135
-     * @throws ReflectionException
1136
-     */
1137
-    public function payment_method_ID()
1138
-    {
1139
-        return $this->get('PMD_ID');
1140
-    }
1141
-
1142
-
1143
-    /**
1144
-     * Sets PMD_ID
1145
-     *
1146
-     * @param int $PMD_ID
1147
-     * @throws EE_Error
1148
-     * @throws InvalidArgumentException
1149
-     * @throws InvalidDataTypeException
1150
-     * @throws InvalidInterfaceException
1151
-     * @throws ReflectionException
1152
-     */
1153
-    public function set_payment_method_ID($PMD_ID)
1154
-    {
1155
-        $this->set('PMD_ID', $PMD_ID);
1156
-    }
1157
-
1158
-
1159
-    /**
1160
-     * Gets the last-used payment method on this transaction
1161
-     * (we COULD just use the last-made payment, but some payment methods, namely
1162
-     * offline ones, dont' create payments)
1163
-     *
1164
-     * @return EE_Payment_Method
1165
-     * @throws EE_Error
1166
-     * @throws InvalidArgumentException
1167
-     * @throws InvalidDataTypeException
1168
-     * @throws InvalidInterfaceException
1169
-     * @throws ReflectionException
1170
-     */
1171
-    public function payment_method()
1172
-    {
1173
-        $pm = $this->get_first_related('Payment_Method');
1174
-        if ($pm instanceof EE_Payment_Method) {
1175
-            return $pm;
1176
-        }
1177
-        $last_payment = $this->last_payment();
1178
-        if ($last_payment instanceof EE_Payment && $last_payment->payment_method()) {
1179
-            return $last_payment->payment_method();
1180
-        }
1181
-        return null;
1182
-    }
1183
-
1184
-
1185
-    /**
1186
-     * Gets the last payment made
1187
-     *
1188
-     * @return EE_Base_Class|EE_Payment
1189
-     * @throws EE_Error
1190
-     * @throws InvalidArgumentException
1191
-     * @throws InvalidDataTypeException
1192
-     * @throws InvalidInterfaceException
1193
-     * @throws ReflectionException
1194
-     */
1195
-    public function last_payment()
1196
-    {
1197
-        return $this->get_first_related('Payment', array('order_by' => array('PAY_ID' => 'desc')));
1198
-    }
1199
-
1200
-
1201
-    /**
1202
-     * Gets all the line items which are unrelated to tickets on this transaction
1203
-     *
1204
-     * @return EE_Line_Item[]
1205
-     * @throws EE_Error
1206
-     * @throws InvalidArgumentException
1207
-     * @throws InvalidDataTypeException
1208
-     * @throws InvalidInterfaceException
1209
-     * @throws ReflectionException
1210
-     */
1211
-    public function non_ticket_line_items()
1212
-    {
1213
-        return EEM_Line_Item::instance()->get_all_non_ticket_line_items_for_transaction($this->ID());
1214
-    }
1215
-
1216
-
1217
-    /**
1218
-     * possibly toggles TXN status
1219
-     *
1220
-     * @param  boolean $update whether to save the TXN
1221
-     * @return bool whether the TXN was saved
1222
-     * @throws EE_Error
1223
-     * @throws InvalidArgumentException
1224
-     * @throws InvalidDataTypeException
1225
-     * @throws InvalidInterfaceException
1226
-     * @throws ReflectionException
1227
-     * @throws RuntimeException
1228
-     */
1229
-    public function update_status_based_on_total_paid($update = true)
1230
-    {
1231
-        // set transaction status based on comparison of TXN_paid vs TXN_total
1232
-        if (EEH_Money::compare_floats($this->paid(), $this->total(), '>')) {
1233
-            $new_txn_status = EEM_Transaction::overpaid_status_code;
1234
-        } elseif (EEH_Money::compare_floats($this->paid(), $this->total())) {
1235
-            $new_txn_status = EEM_Transaction::complete_status_code;
1236
-        } elseif (EEH_Money::compare_floats($this->paid(), $this->total(), '<')) {
1237
-            $new_txn_status = EEM_Transaction::incomplete_status_code;
1238
-        } else {
1239
-            throw new RuntimeException(
1240
-                esc_html__('The total paid calculation for this transaction is inaccurate.', 'event_espresso')
1241
-            );
1242
-        }
1243
-        if ($new_txn_status !== $this->status_ID()) {
1244
-            $this->set_status($new_txn_status);
1245
-            if ($update) {
1246
-                return $this->save() ? true : false;
1247
-            }
1248
-        }
1249
-        return false;
1250
-    }
1251
-
1252
-
1253
-    /**
1254
-     * Updates the transaction's status and total_paid based on all the payments
1255
-     * that apply to it
1256
-     *
1257
-     * @deprecated
1258
-     * @return array|bool
1259
-     * @throws EE_Error
1260
-     * @throws InvalidArgumentException
1261
-     * @throws ReflectionException
1262
-     * @throws InvalidDataTypeException
1263
-     * @throws InvalidInterfaceException
1264
-     */
1265
-    public function update_based_on_payments()
1266
-    {
1267
-        EE_Error::doing_it_wrong(
1268
-            __CLASS__ . '::' . __FUNCTION__,
1269
-            sprintf(
1270
-                esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
1271
-                'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'
1272
-            ),
1273
-            '4.6.0'
1274
-        );
1275
-        /** @type EE_Transaction_Processor $transaction_processor */
1276
-        $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
1277
-        return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment($this);
1278
-    }
1279
-
1280
-
1281
-    /**
1282
-     * @return string
1283
-     */
1284
-    public function old_txn_status()
1285
-    {
1286
-        return $this->_old_txn_status;
1287
-    }
1288
-
1289
-
1290
-    /**
1291
-     * @param string $old_txn_status
1292
-     */
1293
-    public function set_old_txn_status($old_txn_status)
1294
-    {
1295
-        // only set the first time
1296
-        if ($this->_old_txn_status === null) {
1297
-            $this->_old_txn_status = $old_txn_status;
1298
-        }
1299
-    }
1300
-
1301
-
1302
-    /**
1303
-     * reg_status_updated
1304
-     *
1305
-     * @return bool
1306
-     * @throws EE_Error
1307
-     * @throws InvalidArgumentException
1308
-     * @throws InvalidDataTypeException
1309
-     * @throws InvalidInterfaceException
1310
-     * @throws ReflectionException
1311
-     */
1312
-    public function txn_status_updated()
1313
-    {
1314
-        return $this->status_ID() !== $this->_old_txn_status && $this->_old_txn_status !== null;
1315
-    }
1316
-
1317
-
1318
-    /**
1319
-     * _reg_steps_completed
1320
-     * if $check_all is TRUE, then returns TRUE if ALL reg steps have been marked as completed,
1321
-     * if a $reg_step_slug is provided, then this step will be skipped when testing for completion
1322
-     * if $check_all is FALSE and a $reg_step_slug is provided, then ONLY that reg step will be tested for completion
1323
-     *
1324
-     * @param string $reg_step_slug
1325
-     * @param bool   $check_all
1326
-     * @return bool|int
1327
-     * @throws EE_Error
1328
-     * @throws InvalidArgumentException
1329
-     * @throws InvalidDataTypeException
1330
-     * @throws InvalidInterfaceException
1331
-     * @throws ReflectionException
1332
-     */
1333
-    private function _reg_steps_completed($reg_step_slug = '', $check_all = true)
1334
-    {
1335
-        $reg_steps = $this->reg_steps();
1336
-        if (! is_array($reg_steps) || empty($reg_steps)) {
1337
-            return false;
1338
-        }
1339
-        // loop thru reg steps array)
1340
-        foreach ($reg_steps as $slug => $reg_step_completed) {
1341
-            // if NOT checking ALL steps (only checking one step)
1342
-            if (! $check_all) {
1343
-                // and this is the one
1344
-                if ($slug === $reg_step_slug) {
1345
-                    return $reg_step_completed;
1346
-                }
1347
-                // skip to next reg step in loop
1348
-                continue;
1349
-            }
1350
-            // $check_all must be true, else we would never have gotten to this point
1351
-            if ($slug === $reg_step_slug) {
1352
-                // if we reach this point, then we are testing either:
1353
-                // all_reg_steps_completed_except() or
1354
-                // all_reg_steps_completed_except_final_step(),
1355
-                // and since this is the reg step EXCEPTION being tested
1356
-                // we want to return true (yes true) if this reg step is NOT completed
1357
-                // ie: "is everything completed except the final step?"
1358
-                // "that is correct... the final step is not completed, but all others are."
1359
-                return $reg_step_completed !== true;
1360
-            }
1361
-            if ($reg_step_completed !== true) {
1362
-                // if any reg step is NOT completed, then ALL steps are not completed
1363
-                return false;
1364
-            }
1365
-        }
1366
-        return true;
1367
-    }
1368
-
1369
-
1370
-    /**
1371
-     * all_reg_steps_completed
1372
-     * returns:
1373
-     *    true if ALL reg steps have been marked as completed
1374
-     *        or false if any step is not completed
1375
-     *
1376
-     * @return bool
1377
-     * @throws EE_Error
1378
-     * @throws InvalidArgumentException
1379
-     * @throws InvalidDataTypeException
1380
-     * @throws InvalidInterfaceException
1381
-     * @throws ReflectionException
1382
-     */
1383
-    public function all_reg_steps_completed()
1384
-    {
1385
-        return $this->_reg_steps_completed();
1386
-    }
1387
-
1388
-
1389
-    /**
1390
-     * all_reg_steps_completed_except
1391
-     * returns:
1392
-     *        true if ALL reg steps, except a particular step that you wish to skip over, have been marked as completed
1393
-     *        or false if any other step is not completed
1394
-     *        or false if ALL steps are completed including the exception you are testing !!!
1395
-     *
1396
-     * @param string $exception
1397
-     * @return bool
1398
-     * @throws EE_Error
1399
-     * @throws InvalidArgumentException
1400
-     * @throws InvalidDataTypeException
1401
-     * @throws InvalidInterfaceException
1402
-     * @throws ReflectionException
1403
-     */
1404
-    public function all_reg_steps_completed_except($exception = '')
1405
-    {
1406
-        return $this->_reg_steps_completed($exception);
1407
-    }
1408
-
1409
-
1410
-    /**
1411
-     * all_reg_steps_completed_except
1412
-     * returns:
1413
-     *        true if ALL reg steps, except the final step, have been marked as completed
1414
-     *        or false if any step is not completed
1415
-     *    or false if ALL steps are completed including the final step !!!
1416
-     *
1417
-     * @return bool
1418
-     * @throws EE_Error
1419
-     * @throws InvalidArgumentException
1420
-     * @throws InvalidDataTypeException
1421
-     * @throws InvalidInterfaceException
1422
-     * @throws ReflectionException
1423
-     */
1424
-    public function all_reg_steps_completed_except_final_step()
1425
-    {
1426
-        return $this->_reg_steps_completed('finalize_registration');
1427
-    }
1428
-
1429
-
1430
-    /**
1431
-     * reg_step_completed
1432
-     * returns:
1433
-     *    true if a specific reg step has been marked as completed
1434
-     *    a Unix timestamp if it has been initialized but not yet completed,
1435
-     *    or false if it has not yet been initialized
1436
-     *
1437
-     * @param string $reg_step_slug
1438
-     * @return bool|int
1439
-     * @throws EE_Error
1440
-     * @throws InvalidArgumentException
1441
-     * @throws InvalidDataTypeException
1442
-     * @throws InvalidInterfaceException
1443
-     * @throws ReflectionException
1444
-     */
1445
-    public function reg_step_completed($reg_step_slug)
1446
-    {
1447
-        return $this->_reg_steps_completed($reg_step_slug, false);
1448
-    }
1449
-
1450
-
1451
-    /**
1452
-     * completed_final_reg_step
1453
-     * returns:
1454
-     *    true if the finalize_registration reg step has been marked as completed
1455
-     *    a Unix timestamp if it has been initialized but not yet completed,
1456
-     *    or false if it has not yet been initialized
1457
-     *
1458
-     * @return bool|int
1459
-     * @throws EE_Error
1460
-     * @throws InvalidArgumentException
1461
-     * @throws InvalidDataTypeException
1462
-     * @throws InvalidInterfaceException
1463
-     * @throws ReflectionException
1464
-     */
1465
-    public function final_reg_step_completed()
1466
-    {
1467
-        return $this->_reg_steps_completed('finalize_registration', false);
1468
-    }
1469
-
1470
-
1471
-    /**
1472
-     * set_reg_step_initiated
1473
-     * given a valid TXN_reg_step, this sets it's value to a unix timestamp
1474
-     *
1475
-     * @param string $reg_step_slug
1476
-     * @return boolean
1477
-     * @throws EE_Error
1478
-     * @throws InvalidArgumentException
1479
-     * @throws InvalidDataTypeException
1480
-     * @throws InvalidInterfaceException
1481
-     * @throws ReflectionException
1482
-     */
1483
-    public function set_reg_step_initiated($reg_step_slug)
1484
-    {
1485
-        return $this->_set_reg_step_completed_status($reg_step_slug, time());
1486
-    }
1487
-
1488
-
1489
-    /**
1490
-     * set_reg_step_completed
1491
-     * given a valid TXN_reg_step, this sets the step as completed
1492
-     *
1493
-     * @param string $reg_step_slug
1494
-     * @return boolean
1495
-     * @throws EE_Error
1496
-     * @throws InvalidArgumentException
1497
-     * @throws InvalidDataTypeException
1498
-     * @throws InvalidInterfaceException
1499
-     * @throws ReflectionException
1500
-     */
1501
-    public function set_reg_step_completed($reg_step_slug)
1502
-    {
1503
-        return $this->_set_reg_step_completed_status($reg_step_slug, true);
1504
-    }
1505
-
1506
-
1507
-    /**
1508
-     * set_reg_step_completed
1509
-     * given a valid TXN_reg_step slug, this sets the step as NOT completed
1510
-     *
1511
-     * @param string $reg_step_slug
1512
-     * @return boolean
1513
-     * @throws EE_Error
1514
-     * @throws InvalidArgumentException
1515
-     * @throws InvalidDataTypeException
1516
-     * @throws InvalidInterfaceException
1517
-     * @throws ReflectionException
1518
-     */
1519
-    public function set_reg_step_not_completed($reg_step_slug)
1520
-    {
1521
-        return $this->_set_reg_step_completed_status($reg_step_slug, false);
1522
-    }
1523
-
1524
-
1525
-    /**
1526
-     * set_reg_step_completed
1527
-     * given a valid reg step slug, this sets the TXN_reg_step completed status which is either:
1528
-     *
1529
-     * @param  string      $reg_step_slug
1530
-     * @param  boolean|int $status
1531
-     * @return boolean
1532
-     * @throws EE_Error
1533
-     * @throws InvalidArgumentException
1534
-     * @throws InvalidDataTypeException
1535
-     * @throws InvalidInterfaceException
1536
-     * @throws ReflectionException
1537
-     */
1538
-    private function _set_reg_step_completed_status($reg_step_slug, $status)
1539
-    {
1540
-        // validate status
1541
-        $status = is_bool($status) || is_int($status) ? $status : false;
1542
-        // get reg steps array
1543
-        $txn_reg_steps = $this->reg_steps();
1544
-        // if reg step does NOT exist
1545
-        if (! isset($txn_reg_steps[ $reg_step_slug ])) {
1546
-            return false;
1547
-        }
1548
-        // if  we're trying to complete a step that is already completed
1549
-        if ($txn_reg_steps[ $reg_step_slug ] === true) {
1550
-            return true;
1551
-        }
1552
-        // if  we're trying to complete a step that hasn't even started
1553
-        if ($status === true && $txn_reg_steps[ $reg_step_slug ] === false) {
1554
-            return false;
1555
-        }
1556
-        // if current status value matches the incoming value (no change)
1557
-        // type casting as int means values should collapse to either 0, 1, or a timestamp like 1234567890
1558
-        if ((int) $txn_reg_steps[ $reg_step_slug ] === (int) $status) {
1559
-            // this will happen in cases where multiple AJAX requests occur during the same step
1560
-            return true;
1561
-        }
1562
-        // if we're trying to set a start time, but it has already been set...
1563
-        if (is_numeric($status) && is_numeric($txn_reg_steps[ $reg_step_slug ])) {
1564
-            // skip the update below, but don't return FALSE so that errors won't be displayed
1565
-            return true;
1566
-        }
1567
-        // update completed status
1568
-        $txn_reg_steps[ $reg_step_slug ] = $status;
1569
-        $this->set_reg_steps($txn_reg_steps);
1570
-        $this->save();
1571
-        return true;
1572
-    }
1573
-
1574
-
1575
-    /**
1576
-     * remove_reg_step
1577
-     * given a valid TXN_reg_step slug, this will remove (unset)
1578
-     * the reg step from the TXN reg step array
1579
-     *
1580
-     * @param string $reg_step_slug
1581
-     * @return void
1582
-     * @throws EE_Error
1583
-     * @throws InvalidArgumentException
1584
-     * @throws InvalidDataTypeException
1585
-     * @throws InvalidInterfaceException
1586
-     * @throws ReflectionException
1587
-     */
1588
-    public function remove_reg_step($reg_step_slug)
1589
-    {
1590
-        // get reg steps array
1591
-        $txn_reg_steps = $this->reg_steps();
1592
-        unset($txn_reg_steps[ $reg_step_slug ]);
1593
-        $this->set_reg_steps($txn_reg_steps);
1594
-    }
1595
-
1596
-
1597
-    /**
1598
-     * toggle_failed_transaction_status
1599
-     * upgrades a TXNs status from failed to abandoned,
1600
-     * meaning that contact information has been captured for at least one registrant
1601
-     *
1602
-     * @param bool $save
1603
-     * @return bool
1604
-     * @throws EE_Error
1605
-     * @throws InvalidArgumentException
1606
-     * @throws InvalidDataTypeException
1607
-     * @throws InvalidInterfaceException
1608
-     * @throws ReflectionException
1609
-     */
1610
-    public function toggle_failed_transaction_status($save = true)
1611
-    {
1612
-        // if TXN status is still set as "failed"...
1613
-        if ($this->status_ID() === EEM_Transaction::failed_status_code) {
1614
-            $this->set_status(EEM_Transaction::abandoned_status_code);
1615
-            if ($save) {
1616
-                $this->save();
1617
-            }
1618
-            return true;
1619
-        }
1620
-        return false;
1621
-    }
1622
-
1623
-
1624
-    /**
1625
-     * toggle_abandoned_transaction_status
1626
-     * upgrades a TXNs status from failed or abandoned to incomplete
1627
-     *
1628
-     * @return bool
1629
-     * @throws EE_Error
1630
-     * @throws InvalidArgumentException
1631
-     * @throws InvalidDataTypeException
1632
-     * @throws InvalidInterfaceException
1633
-     * @throws ReflectionException
1634
-     */
1635
-    public function toggle_abandoned_transaction_status()
1636
-    {
1637
-        // if TXN status has not been updated already due to a payment, and is still set as "failed" or "abandoned"...
1638
-        $txn_status = $this->status_ID();
1639
-        if ($txn_status === EEM_Transaction::failed_status_code
1640
-            || $txn_status === EEM_Transaction::abandoned_status_code
1641
-        ) {
1642
-            // if a contact record for the primary registrant has been created
1643
-            if ($this->primary_registration() instanceof EE_Registration
1644
-                && $this->primary_registration()->attendee() instanceof EE_Attendee
1645
-            ) {
1646
-                $this->set_status(EEM_Transaction::incomplete_status_code);
1647
-            } else {
1648
-                // no contact record? yer abandoned!
1649
-                $this->set_status(EEM_Transaction::abandoned_status_code);
1650
-            }
1651
-            return true;
1652
-        }
1653
-        return false;
1654
-    }
1655
-
1656
-
1657
-    /**
1658
-     * checks if an Abandoned TXN has any related payments, and if so,
1659
-     * updates the TXN status based on the amount paid
1660
-     *
1661
-     * @throws EE_Error
1662
-     * @throws InvalidArgumentException
1663
-     * @throws InvalidDataTypeException
1664
-     * @throws InvalidInterfaceException
1665
-     * @throws ReflectionException
1666
-     * @throws RuntimeException
1667
-     * @throws ReflectionException
1668
-     */
1669
-    public function verify_abandoned_transaction_status()
1670
-    {
1671
-        if ($this->status_ID() !== EEM_Transaction::abandoned_status_code) {
1672
-            return;
1673
-        }
1674
-        $payments = $this->get_many_related('Payment');
1675
-        if (! empty($payments)) {
1676
-            foreach ($payments as $payment) {
1677
-                if ($payment instanceof EE_Payment) {
1678
-                    // kk this TXN should NOT be abandoned
1679
-                    $this->update_status_based_on_total_paid();
1680
-                    if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1681
-                        EE_Error::add_attention(
1682
-                            sprintf(
1683
-                                esc_html__(
1684
-                                    'The status for Transaction #%1$d has been updated from "Abandoned" to "%2$s", because at least one payment has been made towards it. If the payment appears in the "Payment Details" table below, you may need to edit its status and/or other details as well.',
1685
-                                    'event_espresso'
1686
-                                ),
1687
-                                $this->ID(),
1688
-                                $this->pretty_status()
1689
-                            )
1690
-                        );
1691
-                    }
1692
-                    // get final reg step status
1693
-                    $finalized = $this->final_reg_step_completed();
1694
-                    // if the 'finalize_registration' step has been initiated (has a timestamp)
1695
-                    // but has not yet been fully completed (TRUE)
1696
-                    if (is_int($finalized) && $finalized !== false && $finalized !== true) {
1697
-                        $this->set_reg_step_completed('finalize_registration');
1698
-                        $this->save();
1699
-                    }
1700
-                }
1701
-            }
1702
-        }
1703
-    }
1704
-
1705
-
1706
-    /**
1707
-     * @since 4.10.4.p
1708
-     * @throws EE_Error
1709
-     * @throws InvalidArgumentException
1710
-     * @throws InvalidDataTypeException
1711
-     * @throws InvalidInterfaceException
1712
-     * @throws ReflectionException
1713
-     * @throws RuntimeException
1714
-     */
1715
-    public function recalculateLineItems()
1716
-    {
1717
-        $total_line_item = $this->total_line_item(false);
1718
-        if ($total_line_item instanceof EE_Line_Item) {
1719
-            EEH_Line_Item::resetIsTaxableForTickets($total_line_item);
1720
-            return EEH_Line_Item::apply_taxes($total_line_item, true);
1721
-        }
1722
-        return false;
1723
-	}
1724
-
1725
-
1726
-    /**
1727
-     * @param string $source function name that called this method
1728
-     * @return boolean | int
1729
-     */
1730
-    public function delete($source = 'unknown')
1731
-    {
1732
-        $current_user = wp_get_current_user();
1733
-        $this->add_extra_meta(
1734
-            EE_Transaction::EXTRA_META_KEY_TXN_DELETED,
1735
-            array(
1736
-                'deleted-by' => $current_user->ID ? $current_user->display_name : 'unauthed user',
1737
-                'timestamp'  => time(),
1738
-                'source'     => $source,
1739
-            )
1740
-        );
1741
-        return parent::delete();
1742
-    }
16
+	/**
17
+	 * The length of time in seconds that a lock is applied before being considered expired.
18
+	 * It is not long because a transaction should only be locked for the duration of the request that locked it
19
+	 */
20
+	const LOCK_EXPIRATION = 2;
21
+
22
+	/**
23
+	 * extra meta key for tracking when transactions are deleted and by who
24
+	 *
25
+	 * @type string
26
+	 */
27
+	const EXTRA_META_KEY_TXN_DELETED = 'transaction-deleted';
28
+
29
+	/**
30
+	 * txn status upon initial construction.
31
+	 *
32
+	 * @var string
33
+	 */
34
+	protected $_old_txn_status;
35
+
36
+
37
+	/**
38
+	 * @param array  $props_n_values          incoming values
39
+	 * @param string $timezone                incoming timezone
40
+	 *                                        (if not set the timezone set for the website will be used.)
41
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
42
+	 *                                        date_format and the second value is the time format
43
+	 * @return EE_Transaction
44
+	 * @throws EE_Error
45
+	 * @throws InvalidArgumentException
46
+	 * @throws InvalidDataTypeException
47
+	 * @throws InvalidInterfaceException
48
+	 * @throws ReflectionException
49
+	 */
50
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
51
+	{
52
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
53
+		$txn = $has_object
54
+			? $has_object
55
+			: new self($props_n_values, false, $timezone, $date_formats);
56
+		if (! $has_object) {
57
+			$txn->set_old_txn_status($txn->status_ID());
58
+		}
59
+		return $txn;
60
+	}
61
+
62
+
63
+	/**
64
+	 * @param array  $props_n_values  incoming values from the database
65
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
66
+	 *                                the website will be used.
67
+	 * @return EE_Transaction
68
+	 * @throws EE_Error
69
+	 * @throws InvalidArgumentException
70
+	 * @throws InvalidDataTypeException
71
+	 * @throws InvalidInterfaceException
72
+	 * @throws ReflectionException
73
+	 */
74
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
75
+	{
76
+		$txn = new self($props_n_values, true, $timezone);
77
+		$txn->set_old_txn_status($txn->status_ID());
78
+		return $txn;
79
+	}
80
+
81
+
82
+	/**
83
+	 * Sets a meta field indicating that this TXN is locked and should not be updated in the db.
84
+	 * If a lock has already been set, then we will attempt to remove it in case it has expired.
85
+	 * If that also fails, then an exception is thrown.
86
+	 *
87
+	 * @throws EE_Error
88
+	 * @throws InvalidArgumentException
89
+	 * @throws InvalidDataTypeException
90
+	 * @throws InvalidInterfaceException
91
+	 * @throws ReflectionException
92
+	 */
93
+	public function lock()
94
+	{
95
+		// attempt to set lock, but if that fails...
96
+		if (! $this->add_extra_meta('lock', time(), true)) {
97
+			// then attempt to remove the lock in case it is expired
98
+			if ($this->_remove_expired_lock()) {
99
+				// if removal was successful, then try setting lock again
100
+				$this->lock();
101
+			} else {
102
+				// but if the lock can not be removed, then throw an exception
103
+				throw new EE_Error(
104
+					sprintf(
105
+						esc_html__(
106
+							'Could not lock Transaction %1$d because it is already locked, meaning another part of the system is currently editing it. It should already be unlocked by the time you read this, so please refresh the page and try again.',
107
+							'event_espresso'
108
+						),
109
+						$this->ID()
110
+					)
111
+				);
112
+			}
113
+		}
114
+	}
115
+
116
+
117
+	/**
118
+	 * removes transaction lock applied in EE_Transaction::lock()
119
+	 *
120
+	 * @return int
121
+	 * @throws EE_Error
122
+	 * @throws InvalidArgumentException
123
+	 * @throws InvalidDataTypeException
124
+	 * @throws InvalidInterfaceException
125
+	 * @throws ReflectionException
126
+	 */
127
+	public function unlock()
128
+	{
129
+		return $this->delete_extra_meta('lock');
130
+	}
131
+
132
+
133
+	/**
134
+	 * Decides whether or not now is the right time to update the transaction.
135
+	 * This is useful because we don't always know if it is safe to update the transaction
136
+	 * and its related data. why?
137
+	 * because it's possible that the transaction is being used in another
138
+	 * request and could overwrite anything we save.
139
+	 * So we want to only update the txn once we know that won't happen.
140
+	 * We also check that the lock isn't expired, and remove it if it is
141
+	 *
142
+	 * @return boolean
143
+	 * @throws EE_Error
144
+	 * @throws InvalidArgumentException
145
+	 * @throws InvalidDataTypeException
146
+	 * @throws InvalidInterfaceException
147
+	 * @throws ReflectionException
148
+	 */
149
+	public function is_locked()
150
+	{
151
+		// if TXN is not locked, then return false immediately
152
+		if (! $this->_get_lock()) {
153
+			return false;
154
+		}
155
+		// if not, then let's try and remove the lock in case it's expired...
156
+		// _remove_expired_lock() returns 0 when lock is valid (ie: removed = false)
157
+		// and a positive number if the lock was removed (ie: number of locks deleted),
158
+		// so we need to return the opposite
159
+		return ! $this->_remove_expired_lock() ? true : false;
160
+	}
161
+
162
+
163
+	/**
164
+	 * Gets the meta field indicating that this TXN is locked
165
+	 *
166
+	 * @return int
167
+	 * @throws EE_Error
168
+	 * @throws InvalidArgumentException
169
+	 * @throws InvalidDataTypeException
170
+	 * @throws InvalidInterfaceException
171
+	 * @throws ReflectionException
172
+	 */
173
+	protected function _get_lock()
174
+	{
175
+		return (int) $this->get_extra_meta('lock', true, 0);
176
+	}
177
+
178
+
179
+	/**
180
+	 * If the lock on this transaction is expired, then we want to remove it so that the transaction can be updated
181
+	 *
182
+	 * @return int
183
+	 * @throws EE_Error
184
+	 * @throws InvalidArgumentException
185
+	 * @throws InvalidDataTypeException
186
+	 * @throws InvalidInterfaceException
187
+	 * @throws ReflectionException
188
+	 */
189
+	protected function _remove_expired_lock()
190
+	{
191
+		$locked = $this->_get_lock();
192
+		if ($locked && time() - EE_Transaction::LOCK_EXPIRATION > $locked) {
193
+			return $this->unlock();
194
+		}
195
+		return 0;
196
+	}
197
+
198
+
199
+	/**
200
+	 * Set transaction total
201
+	 *
202
+	 * @param float $total total value of transaction
203
+	 * @throws EE_Error
204
+	 * @throws InvalidArgumentException
205
+	 * @throws InvalidDataTypeException
206
+	 * @throws InvalidInterfaceException
207
+	 * @throws ReflectionException
208
+	 */
209
+	public function set_total($total = 0.00)
210
+	{
211
+		$this->set('TXN_total', (float) $total);
212
+	}
213
+
214
+
215
+	/**
216
+	 * Set Total Amount Paid to Date
217
+	 *
218
+	 * @param float $total_paid total amount paid to date (sum of all payments)
219
+	 * @throws EE_Error
220
+	 * @throws InvalidArgumentException
221
+	 * @throws InvalidDataTypeException
222
+	 * @throws InvalidInterfaceException
223
+	 * @throws ReflectionException
224
+	 */
225
+	public function set_paid($total_paid = 0.00)
226
+	{
227
+		$this->set('TXN_paid', (float) $total_paid);
228
+	}
229
+
230
+
231
+	/**
232
+	 * Set transaction status
233
+	 *
234
+	 * @param string $status        whether the transaction is open, declined, accepted,
235
+	 *                              or any number of custom values that can be set
236
+	 * @throws EE_Error
237
+	 * @throws InvalidArgumentException
238
+	 * @throws InvalidDataTypeException
239
+	 * @throws InvalidInterfaceException
240
+	 * @throws ReflectionException
241
+	 */
242
+	public function set_status($status = '')
243
+	{
244
+		$this->set('STS_ID', $status);
245
+	}
246
+
247
+
248
+	/**
249
+	 * Set hash salt
250
+	 *
251
+	 * @param string $hash_salt required for some payment gateways
252
+	 * @throws EE_Error
253
+	 * @throws InvalidArgumentException
254
+	 * @throws InvalidDataTypeException
255
+	 * @throws InvalidInterfaceException
256
+	 * @throws ReflectionException
257
+	 */
258
+	public function set_hash_salt($hash_salt = '')
259
+	{
260
+		$this->set('TXN_hash_salt', $hash_salt);
261
+	}
262
+
263
+
264
+	/**
265
+	 * Sets TXN_reg_steps array
266
+	 *
267
+	 * @param array $txn_reg_steps
268
+	 * @throws EE_Error
269
+	 * @throws InvalidArgumentException
270
+	 * @throws InvalidDataTypeException
271
+	 * @throws InvalidInterfaceException
272
+	 * @throws ReflectionException
273
+	 */
274
+	public function set_reg_steps(array $txn_reg_steps)
275
+	{
276
+		$this->set('TXN_reg_steps', $txn_reg_steps);
277
+	}
278
+
279
+
280
+	/**
281
+	 * Gets TXN_reg_steps
282
+	 *
283
+	 * @return array
284
+	 * @throws EE_Error
285
+	 * @throws InvalidArgumentException
286
+	 * @throws InvalidDataTypeException
287
+	 * @throws InvalidInterfaceException
288
+	 * @throws ReflectionException
289
+	 */
290
+	public function reg_steps()
291
+	{
292
+		$TXN_reg_steps = $this->get('TXN_reg_steps');
293
+		return is_array($TXN_reg_steps) ? (array) $TXN_reg_steps : array();
294
+	}
295
+
296
+
297
+	/**
298
+	 * @return string of transaction's total cost, with currency symbol and decimal
299
+	 * @throws EE_Error
300
+	 * @throws InvalidArgumentException
301
+	 * @throws InvalidDataTypeException
302
+	 * @throws InvalidInterfaceException
303
+	 * @throws ReflectionException
304
+	 */
305
+	public function pretty_total()
306
+	{
307
+		return $this->get_pretty('TXN_total');
308
+	}
309
+
310
+
311
+	/**
312
+	 * Gets the amount paid in a pretty string (formatted and with currency symbol)
313
+	 *
314
+	 * @return string
315
+	 * @throws EE_Error
316
+	 * @throws InvalidArgumentException
317
+	 * @throws InvalidDataTypeException
318
+	 * @throws InvalidInterfaceException
319
+	 * @throws ReflectionException
320
+	 */
321
+	public function pretty_paid()
322
+	{
323
+		return $this->get_pretty('TXN_paid');
324
+	}
325
+
326
+
327
+	/**
328
+	 * calculate the amount remaining for this transaction and return;
329
+	 *
330
+	 * @return float amount remaining
331
+	 * @throws EE_Error
332
+	 * @throws InvalidArgumentException
333
+	 * @throws InvalidDataTypeException
334
+	 * @throws InvalidInterfaceException
335
+	 * @throws ReflectionException
336
+	 */
337
+	public function remaining()
338
+	{
339
+		return $this->total() - $this->paid();
340
+	}
341
+
342
+
343
+	/**
344
+	 * get Transaction Total
345
+	 *
346
+	 * @return float
347
+	 * @throws EE_Error
348
+	 * @throws InvalidArgumentException
349
+	 * @throws InvalidDataTypeException
350
+	 * @throws InvalidInterfaceException
351
+	 * @throws ReflectionException
352
+	 */
353
+	public function total()
354
+	{
355
+		return (float) $this->get('TXN_total');
356
+	}
357
+
358
+
359
+	/**
360
+	 * get Total Amount Paid to Date
361
+	 *
362
+	 * @return float
363
+	 * @throws EE_Error
364
+	 * @throws InvalidArgumentException
365
+	 * @throws InvalidDataTypeException
366
+	 * @throws InvalidInterfaceException
367
+	 * @throws ReflectionException
368
+	 */
369
+	public function paid()
370
+	{
371
+		return (float) $this->get('TXN_paid');
372
+	}
373
+
374
+
375
+	/**
376
+	 * @return mixed|null
377
+	 * @throws EE_Error
378
+	 * @throws InvalidArgumentException
379
+	 * @throws InvalidDataTypeException
380
+	 * @throws InvalidInterfaceException
381
+	 * @throws ReflectionException
382
+	 */
383
+	public function get_cart_session()
384
+	{
385
+		$session_data = (array) $this->get('TXN_session_data');
386
+		return isset($session_data['cart']) && $session_data['cart'] instanceof EE_Cart
387
+			? $session_data['cart']
388
+			: null;
389
+	}
390
+
391
+
392
+	/**
393
+	 * get Transaction session data
394
+	 *
395
+	 * @return array|mixed
396
+	 * @throws EE_Error
397
+	 * @throws InvalidArgumentException
398
+	 * @throws InvalidDataTypeException
399
+	 * @throws InvalidInterfaceException
400
+	 * @throws ReflectionException
401
+	 */
402
+	public function session_data()
403
+	{
404
+		$session_data = $this->get('TXN_session_data');
405
+		if (empty($session_data)) {
406
+			$session_data = array(
407
+				'id'            => null,
408
+				'user_id'       => null,
409
+				'ip_address'    => null,
410
+				'user_agent'    => null,
411
+				'init_access'   => null,
412
+				'last_access'   => null,
413
+				'pages_visited' => array(),
414
+			);
415
+		}
416
+		return $session_data;
417
+	}
418
+
419
+
420
+	/**
421
+	 * Set session data within the TXN object
422
+	 *
423
+	 * @param EE_Session|array $session_data
424
+	 * @throws EE_Error
425
+	 * @throws InvalidArgumentException
426
+	 * @throws InvalidDataTypeException
427
+	 * @throws InvalidInterfaceException
428
+	 * @throws ReflectionException
429
+	 */
430
+	public function set_txn_session_data($session_data)
431
+	{
432
+		if ($session_data instanceof EE_Session) {
433
+			$this->set('TXN_session_data', $session_data->get_session_data(null, true));
434
+		} else {
435
+			$this->set('TXN_session_data', $session_data);
436
+		}
437
+	}
438
+
439
+
440
+	/**
441
+	 * get Transaction hash salt
442
+	 *
443
+	 * @return mixed
444
+	 * @throws EE_Error
445
+	 * @throws InvalidArgumentException
446
+	 * @throws InvalidDataTypeException
447
+	 * @throws InvalidInterfaceException
448
+	 * @throws ReflectionException
449
+	 */
450
+	public function hash_salt_()
451
+	{
452
+		return $this->get('TXN_hash_salt');
453
+	}
454
+
455
+
456
+	/**
457
+	 * Returns the transaction datetime as either:
458
+	 *            - unix timestamp format ($format = false, $gmt = true)
459
+	 *            - formatted date string including the UTC (timezone) offset ($format = true ($gmt
460
+	 *              has no affect with this option)), this also may include a timezone abbreviation if the
461
+	 *              set timezone in this class differs from what the timezone is on the blog.
462
+	 *            - formatted date string including the UTC (timezone) offset (default).
463
+	 *
464
+	 * @param boolean $format   - whether to return a unix timestamp (default) or formatted date string
465
+	 * @param boolean $gmt      - whether to return a unix timestamp with UTC offset applied (default)
466
+	 *                          or no UTC offset applied
467
+	 * @return string | int
468
+	 * @throws EE_Error
469
+	 * @throws InvalidArgumentException
470
+	 * @throws InvalidDataTypeException
471
+	 * @throws InvalidInterfaceException
472
+	 * @throws ReflectionException
473
+	 */
474
+	public function datetime($format = false, $gmt = false)
475
+	{
476
+		if ($format) {
477
+			return $this->get_pretty('TXN_timestamp');
478
+		}
479
+		if ($gmt) {
480
+			return $this->get_raw('TXN_timestamp');
481
+		}
482
+		return $this->get('TXN_timestamp');
483
+	}
484
+
485
+
486
+	/**
487
+	 * Gets registrations on this transaction
488
+	 *
489
+	 * @param array   $query_params array of query parameters
490
+	 * @param boolean $get_cached   TRUE to retrieve cached registrations or FALSE to pull from the db
491
+	 * @return EE_Base_Class[]|EE_Registration[]
492
+	 * @throws EE_Error
493
+	 * @throws InvalidArgumentException
494
+	 * @throws InvalidDataTypeException
495
+	 * @throws InvalidInterfaceException
496
+	 * @throws ReflectionException
497
+	 */
498
+	public function registrations($query_params = array(), $get_cached = false)
499
+	{
500
+		$query_params = (empty($query_params) || ! is_array($query_params))
501
+			? array(
502
+				'order_by' => array(
503
+					'Event.EVT_name'     => 'ASC',
504
+					'Attendee.ATT_lname' => 'ASC',
505
+					'Attendee.ATT_fname' => 'ASC',
506
+				),
507
+			)
508
+			: $query_params;
509
+		$query_params = $get_cached ? array() : $query_params;
510
+		return $this->get_many_related('Registration', $query_params);
511
+	}
512
+
513
+
514
+	/**
515
+	 * Gets all the attendees for this transaction (handy for use with EE_Attendee's get_registrations_for_event
516
+	 * function for getting attendees and how many registrations they each have for an event)
517
+	 *
518
+	 * @return mixed EE_Attendee[] by default, int if $output is set to 'COUNT'
519
+	 * @throws EE_Error
520
+	 * @throws InvalidArgumentException
521
+	 * @throws InvalidDataTypeException
522
+	 * @throws InvalidInterfaceException
523
+	 * @throws ReflectionException
524
+	 */
525
+	public function attendees()
526
+	{
527
+		return $this->get_many_related('Attendee', array(array('Registration.Transaction.TXN_ID' => $this->ID())));
528
+	}
529
+
530
+
531
+	/**
532
+	 * Gets payments for this transaction. Unlike other such functions, order by 'DESC' by default
533
+	 *
534
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
535
+	 * @return EE_Base_Class[]|EE_Payment[]
536
+	 * @throws EE_Error
537
+	 * @throws InvalidArgumentException
538
+	 * @throws InvalidDataTypeException
539
+	 * @throws InvalidInterfaceException
540
+	 * @throws ReflectionException
541
+	 */
542
+	public function payments($query_params = array())
543
+	{
544
+		return $this->get_many_related('Payment', $query_params);
545
+	}
546
+
547
+
548
+	/**
549
+	 * gets only approved payments for this transaction
550
+	 *
551
+	 * @return EE_Base_Class[]|EE_Payment[]
552
+	 * @throws EE_Error
553
+	 * @throws InvalidArgumentException
554
+	 * @throws ReflectionException
555
+	 * @throws InvalidDataTypeException
556
+	 * @throws InvalidInterfaceException
557
+	 */
558
+	public function approved_payments()
559
+	{
560
+		EE_Registry::instance()->load_model('Payment');
561
+		return $this->get_many_related(
562
+			'Payment',
563
+			array(
564
+				array('STS_ID' => EEM_Payment::status_id_approved),
565
+				'order_by' => array('PAY_timestamp' => 'DESC'),
566
+			)
567
+		);
568
+	}
569
+
570
+
571
+	/**
572
+	 * Gets all payments which have not been approved
573
+	 *
574
+	 * @return EE_Base_Class[]|EEI_Payment[]
575
+	 * @throws EE_Error if a model is misconfigured somehow
576
+	 * @throws InvalidArgumentException
577
+	 * @throws InvalidDataTypeException
578
+	 * @throws InvalidInterfaceException
579
+	 * @throws ReflectionException
580
+	 */
581
+	public function pending_payments()
582
+	{
583
+		return $this->get_many_related(
584
+			'Payment',
585
+			array(
586
+				array(
587
+					'STS_ID' => EEM_Payment::status_id_pending,
588
+				),
589
+				'order_by' => array(
590
+					'PAY_timestamp' => 'DESC',
591
+				),
592
+			)
593
+		);
594
+	}
595
+
596
+
597
+	/**
598
+	 * echoes $this->pretty_status()
599
+	 *
600
+	 * @param bool $show_icons
601
+	 * @throws EE_Error
602
+	 * @throws InvalidArgumentException
603
+	 * @throws InvalidDataTypeException
604
+	 * @throws InvalidInterfaceException
605
+	 * @throws ReflectionException
606
+	 */
607
+	public function e_pretty_status($show_icons = false)
608
+	{
609
+		echo $this->pretty_status($show_icons);
610
+	}
611
+
612
+
613
+	/**
614
+	 * returns a pretty version of the status, good for displaying to users
615
+	 *
616
+	 * @param bool $show_icons
617
+	 * @return string
618
+	 * @throws EE_Error
619
+	 * @throws InvalidArgumentException
620
+	 * @throws InvalidDataTypeException
621
+	 * @throws InvalidInterfaceException
622
+	 * @throws ReflectionException
623
+	 */
624
+	public function pretty_status($show_icons = false)
625
+	{
626
+		$status = EEM_Status::instance()->localized_status(
627
+			array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
628
+			false,
629
+			'sentence'
630
+		);
631
+		$icon = '';
632
+		switch ($this->status_ID()) {
633
+			case EEM_Transaction::complete_status_code:
634
+				$icon = $show_icons ? '<span class="dashicons dashicons-yes ee-icon-size-24 green-text"></span>' : '';
635
+				break;
636
+			case EEM_Transaction::incomplete_status_code:
637
+				$icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 lt-blue-text"></span>'
638
+					: '';
639
+				break;
640
+			case EEM_Transaction::abandoned_status_code:
641
+				$icon = $show_icons ? '<span class="dashicons dashicons-marker ee-icon-size-16 red-text"></span>' : '';
642
+				break;
643
+			case EEM_Transaction::failed_status_code:
644
+				$icon = $show_icons ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>' : '';
645
+				break;
646
+			case EEM_Transaction::overpaid_status_code:
647
+				$icon = $show_icons ? '<span class="dashicons dashicons-plus ee-icon-size-16 orange-text"></span>' : '';
648
+				break;
649
+		}
650
+		return $icon . $status[ $this->status_ID() ];
651
+	}
652
+
653
+
654
+	/**
655
+	 * get Transaction Status
656
+	 *
657
+	 * @return mixed
658
+	 * @throws EE_Error
659
+	 * @throws InvalidArgumentException
660
+	 * @throws InvalidDataTypeException
661
+	 * @throws InvalidInterfaceException
662
+	 * @throws ReflectionException
663
+	 */
664
+	public function status_ID()
665
+	{
666
+		return $this->get('STS_ID');
667
+	}
668
+
669
+
670
+	/**
671
+	 * Returns TRUE or FALSE for whether or not this transaction cost any money
672
+	 *
673
+	 * @return boolean
674
+	 * @throws EE_Error
675
+	 * @throws InvalidArgumentException
676
+	 * @throws InvalidDataTypeException
677
+	 * @throws InvalidInterfaceException
678
+	 * @throws ReflectionException
679
+	 */
680
+	public function is_free()
681
+	{
682
+		return EEH_Money::compare_floats($this->get('TXN_total'), 0, '==');
683
+	}
684
+
685
+
686
+	/**
687
+	 * Returns whether this transaction is complete
688
+	 * Useful in templates and other logic for deciding if we should ask for another payment...
689
+	 *
690
+	 * @return boolean
691
+	 * @throws EE_Error
692
+	 * @throws InvalidArgumentException
693
+	 * @throws InvalidDataTypeException
694
+	 * @throws InvalidInterfaceException
695
+	 * @throws ReflectionException
696
+	 */
697
+	public function is_completed()
698
+	{
699
+		return $this->status_ID() === EEM_Transaction::complete_status_code;
700
+	}
701
+
702
+
703
+	/**
704
+	 * Returns whether this transaction is incomplete
705
+	 * Useful in templates and other logic for deciding if we should ask for another payment...
706
+	 *
707
+	 * @return boolean
708
+	 * @throws EE_Error
709
+	 * @throws InvalidArgumentException
710
+	 * @throws InvalidDataTypeException
711
+	 * @throws InvalidInterfaceException
712
+	 * @throws ReflectionException
713
+	 */
714
+	public function is_incomplete()
715
+	{
716
+		return $this->status_ID() === EEM_Transaction::incomplete_status_code;
717
+	}
718
+
719
+
720
+	/**
721
+	 * Returns whether this transaction is overpaid
722
+	 * Useful in templates and other logic for deciding if monies need to be refunded
723
+	 *
724
+	 * @return boolean
725
+	 * @throws EE_Error
726
+	 * @throws InvalidArgumentException
727
+	 * @throws InvalidDataTypeException
728
+	 * @throws InvalidInterfaceException
729
+	 * @throws ReflectionException
730
+	 */
731
+	public function is_overpaid()
732
+	{
733
+		return $this->status_ID() === EEM_Transaction::overpaid_status_code;
734
+	}
735
+
736
+
737
+	/**
738
+	 * Returns whether this transaction was abandoned
739
+	 * meaning that the transaction/registration process was somehow interrupted and never completed
740
+	 * but that contact information exists for at least one registrant
741
+	 *
742
+	 * @return boolean
743
+	 * @throws EE_Error
744
+	 * @throws InvalidArgumentException
745
+	 * @throws InvalidDataTypeException
746
+	 * @throws InvalidInterfaceException
747
+	 * @throws ReflectionException
748
+	 */
749
+	public function is_abandoned()
750
+	{
751
+		return $this->status_ID() === EEM_Transaction::abandoned_status_code;
752
+	}
753
+
754
+
755
+	/**
756
+	 * Returns whether this transaction failed
757
+	 * meaning that the transaction/registration process was somehow interrupted and never completed
758
+	 * and that NO contact information exists for any registrants
759
+	 *
760
+	 * @return boolean
761
+	 * @throws EE_Error
762
+	 * @throws InvalidArgumentException
763
+	 * @throws InvalidDataTypeException
764
+	 * @throws InvalidInterfaceException
765
+	 * @throws ReflectionException
766
+	 */
767
+	public function failed()
768
+	{
769
+		return $this->status_ID() === EEM_Transaction::failed_status_code;
770
+	}
771
+
772
+
773
+	/**
774
+	 * This returns the url for the invoice of this transaction
775
+	 *
776
+	 * @param string $type 'html' or 'pdf' (default is pdf)
777
+	 * @return string
778
+	 * @throws DomainException
779
+	 * @throws EE_Error
780
+	 * @throws InvalidArgumentException
781
+	 * @throws InvalidDataTypeException
782
+	 * @throws InvalidInterfaceException
783
+	 * @throws ReflectionException
784
+	 */
785
+	public function invoice_url($type = 'html')
786
+	{
787
+		$REG = $this->primary_registration();
788
+		if (! $REG instanceof EE_Registration) {
789
+			return '';
790
+		}
791
+		return $REG->invoice_url($type);
792
+	}
793
+
794
+
795
+	/**
796
+	 * Gets the primary registration only
797
+	 *
798
+	 * @return EE_Base_Class|EE_Registration
799
+	 * @throws EE_Error
800
+	 * @throws InvalidArgumentException
801
+	 * @throws InvalidDataTypeException
802
+	 * @throws InvalidInterfaceException
803
+	 * @throws ReflectionException
804
+	 */
805
+	public function primary_registration()
806
+	{
807
+		$registrations = (array) $this->get_many_related(
808
+			'Registration',
809
+			array(array('REG_count' => EEM_Registration::PRIMARY_REGISTRANT_COUNT))
810
+		);
811
+		foreach ($registrations as $registration) {
812
+			// valid registration that is NOT cancelled or declined ?
813
+			if ($registration instanceof EE_Registration
814
+				&& ! in_array($registration->status_ID(), EEM_Registration::closed_reg_statuses(), true)
815
+			) {
816
+				return $registration;
817
+			}
818
+		}
819
+		// nothing valid found, so just return first thing from array of results
820
+		return reset($registrations);
821
+	}
822
+
823
+
824
+	/**
825
+	 * Gets the URL for viewing the receipt
826
+	 *
827
+	 * @param string $type 'pdf' or 'html' (default is 'html')
828
+	 * @return string
829
+	 * @throws DomainException
830
+	 * @throws EE_Error
831
+	 * @throws InvalidArgumentException
832
+	 * @throws InvalidDataTypeException
833
+	 * @throws InvalidInterfaceException
834
+	 * @throws ReflectionException
835
+	 */
836
+	public function receipt_url($type = 'html')
837
+	{
838
+		$REG = $this->primary_registration();
839
+		if (! $REG instanceof EE_Registration) {
840
+			return '';
841
+		}
842
+		return $REG->receipt_url($type);
843
+	}
844
+
845
+
846
+	/**
847
+	 * Gets the URL of the thank you page with this registration REG_url_link added as
848
+	 * a query parameter
849
+	 *
850
+	 * @return string
851
+	 * @throws EE_Error
852
+	 * @throws InvalidArgumentException
853
+	 * @throws InvalidDataTypeException
854
+	 * @throws InvalidInterfaceException
855
+	 * @throws ReflectionException
856
+	 */
857
+	public function payment_overview_url()
858
+	{
859
+		$primary_registration = $this->primary_registration();
860
+		return $primary_registration instanceof EE_Registration ? $primary_registration->payment_overview_url() : false;
861
+	}
862
+
863
+
864
+	/**
865
+	 * @return string
866
+	 * @throws EE_Error
867
+	 * @throws InvalidArgumentException
868
+	 * @throws InvalidDataTypeException
869
+	 * @throws InvalidInterfaceException
870
+	 * @throws ReflectionException
871
+	 */
872
+	public function gateway_response_on_transaction()
873
+	{
874
+		$payment = $this->get_first_related('Payment');
875
+		return $payment instanceof EE_Payment ? $payment->gateway_response() : '';
876
+	}
877
+
878
+
879
+	/**
880
+	 * Get the status object of this object
881
+	 *
882
+	 * @return EE_Base_Class|EE_Status
883
+	 * @throws EE_Error
884
+	 * @throws InvalidArgumentException
885
+	 * @throws InvalidDataTypeException
886
+	 * @throws InvalidInterfaceException
887
+	 * @throws ReflectionException
888
+	 */
889
+	public function status_obj()
890
+	{
891
+		return $this->get_first_related('Status');
892
+	}
893
+
894
+
895
+	/**
896
+	 * Gets all the extra meta info on this payment
897
+	 *
898
+	 * @param array $query_params @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
899
+	 * @return EE_Base_Class[]|EE_Extra_Meta
900
+	 * @throws EE_Error
901
+	 * @throws InvalidArgumentException
902
+	 * @throws InvalidDataTypeException
903
+	 * @throws InvalidInterfaceException
904
+	 * @throws ReflectionException
905
+	 */
906
+	public function extra_meta($query_params = array())
907
+	{
908
+		return $this->get_many_related('Extra_Meta', $query_params);
909
+	}
910
+
911
+
912
+	/**
913
+	 * Wrapper for _add_relation_to
914
+	 *
915
+	 * @param EE_Registration $registration
916
+	 * @return EE_Base_Class the relation was added to
917
+	 * @throws EE_Error
918
+	 * @throws InvalidArgumentException
919
+	 * @throws InvalidDataTypeException
920
+	 * @throws InvalidInterfaceException
921
+	 * @throws ReflectionException
922
+	 */
923
+	public function add_registration(EE_Registration $registration)
924
+	{
925
+		return $this->_add_relation_to($registration, 'Registration');
926
+	}
927
+
928
+
929
+	/**
930
+	 * Removes the given registration from being related (even before saving this transaction).
931
+	 * If an ID/index is provided and this transaction isn't saved yet, removes it from list of cached relations
932
+	 *
933
+	 * @param int $registration_or_id
934
+	 * @return EE_Base_Class that was removed from being related
935
+	 * @throws EE_Error
936
+	 * @throws InvalidArgumentException
937
+	 * @throws InvalidDataTypeException
938
+	 * @throws InvalidInterfaceException
939
+	 * @throws ReflectionException
940
+	 */
941
+	public function remove_registration_with_id($registration_or_id)
942
+	{
943
+		return $this->_remove_relation_to($registration_or_id, 'Registration');
944
+	}
945
+
946
+
947
+	/**
948
+	 * Gets all the line items which are for ACTUAL items
949
+	 *
950
+	 * @return EE_Line_Item[]
951
+	 * @throws EE_Error
952
+	 * @throws InvalidArgumentException
953
+	 * @throws InvalidDataTypeException
954
+	 * @throws InvalidInterfaceException
955
+	 * @throws ReflectionException
956
+	 */
957
+	public function items_purchased()
958
+	{
959
+		return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_line_item)));
960
+	}
961
+
962
+
963
+	/**
964
+	 * Wrapper for _add_relation_to
965
+	 *
966
+	 * @param EE_Line_Item $line_item
967
+	 * @return EE_Base_Class the relation was added to
968
+	 * @throws EE_Error
969
+	 * @throws InvalidArgumentException
970
+	 * @throws InvalidDataTypeException
971
+	 * @throws InvalidInterfaceException
972
+	 * @throws ReflectionException
973
+	 */
974
+	public function add_line_item(EE_Line_Item $line_item)
975
+	{
976
+		return $this->_add_relation_to($line_item, 'Line_Item');
977
+	}
978
+
979
+
980
+	/**
981
+	 * Gets ALL the line items related to this transaction (unstructured)
982
+	 *
983
+	 * @param array $query_params
984
+	 * @return EE_Base_Class[]|EE_Line_Item[]
985
+	 * @throws EE_Error
986
+	 * @throws InvalidArgumentException
987
+	 * @throws InvalidDataTypeException
988
+	 * @throws InvalidInterfaceException
989
+	 * @throws ReflectionException
990
+	 */
991
+	public function line_items($query_params = array())
992
+	{
993
+		return $this->get_many_related('Line_Item', $query_params);
994
+	}
995
+
996
+
997
+	/**
998
+	 * Gets all the line items which are taxes on the total
999
+	 *
1000
+	 * @return EE_Line_Item[]
1001
+	 * @throws EE_Error
1002
+	 * @throws InvalidArgumentException
1003
+	 * @throws InvalidDataTypeException
1004
+	 * @throws InvalidInterfaceException
1005
+	 * @throws ReflectionException
1006
+	 */
1007
+	public function tax_items()
1008
+	{
1009
+		return $this->line_items(array(array('LIN_type' => EEM_Line_Item::type_tax)));
1010
+	}
1011
+
1012
+
1013
+	/**
1014
+	 * Gets the total line item (which is a parent of all other related line items,
1015
+	 * meaning it takes them all into account on its total)
1016
+	 *
1017
+	 * @param bool $create_if_not_found
1018
+	 * @return \EE_Line_Item
1019
+	 * @throws EE_Error
1020
+	 * @throws InvalidArgumentException
1021
+	 * @throws InvalidDataTypeException
1022
+	 * @throws InvalidInterfaceException
1023
+	 * @throws ReflectionException
1024
+	 */
1025
+	public function total_line_item($create_if_not_found = true)
1026
+	{
1027
+		$item = $this->get_first_related('Line_Item', array(array('LIN_type' => EEM_Line_Item::type_total)));
1028
+		if (! $item && $create_if_not_found) {
1029
+			$item = EEH_Line_Item::create_total_line_item($this);
1030
+		}
1031
+		return $item;
1032
+	}
1033
+
1034
+
1035
+	/**
1036
+	 * Returns the total amount of tax on this transaction
1037
+	 * (assumes there's only one tax subtotal line item)
1038
+	 *
1039
+	 * @return float
1040
+	 * @throws EE_Error
1041
+	 * @throws InvalidArgumentException
1042
+	 * @throws InvalidDataTypeException
1043
+	 * @throws InvalidInterfaceException
1044
+	 * @throws ReflectionException
1045
+	 */
1046
+	public function tax_total()
1047
+	{
1048
+		$tax_line_item = $this->tax_total_line_item();
1049
+		if ($tax_line_item) {
1050
+			return (float) $tax_line_item->total();
1051
+		}
1052
+		return (float) 0;
1053
+	}
1054
+
1055
+
1056
+	/**
1057
+	 * Gets the tax subtotal line item (assumes there's only one)
1058
+	 *
1059
+	 * @return EE_Line_Item
1060
+	 * @throws EE_Error
1061
+	 * @throws InvalidArgumentException
1062
+	 * @throws InvalidDataTypeException
1063
+	 * @throws InvalidInterfaceException
1064
+	 * @throws ReflectionException
1065
+	 */
1066
+	public function tax_total_line_item()
1067
+	{
1068
+		return EEH_Line_Item::get_taxes_subtotal($this->total_line_item());
1069
+	}
1070
+
1071
+
1072
+	/**
1073
+	 * Gets the array of billing info for the gateway and for this transaction's primary registration's attendee.
1074
+	 *
1075
+	 * @return EE_Form_Section_Proper
1076
+	 * @throws EE_Error
1077
+	 * @throws InvalidArgumentException
1078
+	 * @throws InvalidDataTypeException
1079
+	 * @throws InvalidInterfaceException
1080
+	 * @throws ReflectionException
1081
+	 */
1082
+	public function billing_info()
1083
+	{
1084
+		$payment_method = $this->payment_method();
1085
+		if (! $payment_method) {
1086
+			EE_Error::add_error(
1087
+				esc_html__(
1088
+					'Could not find billing info for transaction because no gateway has been used for it yet',
1089
+					'event_espresso'
1090
+				),
1091
+				__FILE__,
1092
+				__FUNCTION__,
1093
+				__LINE__
1094
+			);
1095
+			return null;
1096
+		}
1097
+		$primary_reg = $this->primary_registration();
1098
+		if (! $primary_reg) {
1099
+			EE_Error::add_error(
1100
+				esc_html__(
1101
+					'Cannot get billing info for gateway %s on transaction because no primary registration exists',
1102
+					'event_espresso'
1103
+				),
1104
+				__FILE__,
1105
+				__FUNCTION__,
1106
+				__LINE__
1107
+			);
1108
+			return null;
1109
+		}
1110
+		$attendee = $primary_reg->attendee();
1111
+		if (! $attendee) {
1112
+			EE_Error::add_error(
1113
+				esc_html__(
1114
+					'Cannot get billing info for gateway %s on transaction because the primary registration has no attendee exists',
1115
+					'event_espresso'
1116
+				),
1117
+				__FILE__,
1118
+				__FUNCTION__,
1119
+				__LINE__
1120
+			);
1121
+			return null;
1122
+		}
1123
+		return $attendee->billing_info_for_payment_method($payment_method);
1124
+	}
1125
+
1126
+
1127
+	/**
1128
+	 * Gets PMD_ID
1129
+	 *
1130
+	 * @return int
1131
+	 * @throws EE_Error
1132
+	 * @throws InvalidArgumentException
1133
+	 * @throws InvalidDataTypeException
1134
+	 * @throws InvalidInterfaceException
1135
+	 * @throws ReflectionException
1136
+	 */
1137
+	public function payment_method_ID()
1138
+	{
1139
+		return $this->get('PMD_ID');
1140
+	}
1141
+
1142
+
1143
+	/**
1144
+	 * Sets PMD_ID
1145
+	 *
1146
+	 * @param int $PMD_ID
1147
+	 * @throws EE_Error
1148
+	 * @throws InvalidArgumentException
1149
+	 * @throws InvalidDataTypeException
1150
+	 * @throws InvalidInterfaceException
1151
+	 * @throws ReflectionException
1152
+	 */
1153
+	public function set_payment_method_ID($PMD_ID)
1154
+	{
1155
+		$this->set('PMD_ID', $PMD_ID);
1156
+	}
1157
+
1158
+
1159
+	/**
1160
+	 * Gets the last-used payment method on this transaction
1161
+	 * (we COULD just use the last-made payment, but some payment methods, namely
1162
+	 * offline ones, dont' create payments)
1163
+	 *
1164
+	 * @return EE_Payment_Method
1165
+	 * @throws EE_Error
1166
+	 * @throws InvalidArgumentException
1167
+	 * @throws InvalidDataTypeException
1168
+	 * @throws InvalidInterfaceException
1169
+	 * @throws ReflectionException
1170
+	 */
1171
+	public function payment_method()
1172
+	{
1173
+		$pm = $this->get_first_related('Payment_Method');
1174
+		if ($pm instanceof EE_Payment_Method) {
1175
+			return $pm;
1176
+		}
1177
+		$last_payment = $this->last_payment();
1178
+		if ($last_payment instanceof EE_Payment && $last_payment->payment_method()) {
1179
+			return $last_payment->payment_method();
1180
+		}
1181
+		return null;
1182
+	}
1183
+
1184
+
1185
+	/**
1186
+	 * Gets the last payment made
1187
+	 *
1188
+	 * @return EE_Base_Class|EE_Payment
1189
+	 * @throws EE_Error
1190
+	 * @throws InvalidArgumentException
1191
+	 * @throws InvalidDataTypeException
1192
+	 * @throws InvalidInterfaceException
1193
+	 * @throws ReflectionException
1194
+	 */
1195
+	public function last_payment()
1196
+	{
1197
+		return $this->get_first_related('Payment', array('order_by' => array('PAY_ID' => 'desc')));
1198
+	}
1199
+
1200
+
1201
+	/**
1202
+	 * Gets all the line items which are unrelated to tickets on this transaction
1203
+	 *
1204
+	 * @return EE_Line_Item[]
1205
+	 * @throws EE_Error
1206
+	 * @throws InvalidArgumentException
1207
+	 * @throws InvalidDataTypeException
1208
+	 * @throws InvalidInterfaceException
1209
+	 * @throws ReflectionException
1210
+	 */
1211
+	public function non_ticket_line_items()
1212
+	{
1213
+		return EEM_Line_Item::instance()->get_all_non_ticket_line_items_for_transaction($this->ID());
1214
+	}
1215
+
1216
+
1217
+	/**
1218
+	 * possibly toggles TXN status
1219
+	 *
1220
+	 * @param  boolean $update whether to save the TXN
1221
+	 * @return bool whether the TXN was saved
1222
+	 * @throws EE_Error
1223
+	 * @throws InvalidArgumentException
1224
+	 * @throws InvalidDataTypeException
1225
+	 * @throws InvalidInterfaceException
1226
+	 * @throws ReflectionException
1227
+	 * @throws RuntimeException
1228
+	 */
1229
+	public function update_status_based_on_total_paid($update = true)
1230
+	{
1231
+		// set transaction status based on comparison of TXN_paid vs TXN_total
1232
+		if (EEH_Money::compare_floats($this->paid(), $this->total(), '>')) {
1233
+			$new_txn_status = EEM_Transaction::overpaid_status_code;
1234
+		} elseif (EEH_Money::compare_floats($this->paid(), $this->total())) {
1235
+			$new_txn_status = EEM_Transaction::complete_status_code;
1236
+		} elseif (EEH_Money::compare_floats($this->paid(), $this->total(), '<')) {
1237
+			$new_txn_status = EEM_Transaction::incomplete_status_code;
1238
+		} else {
1239
+			throw new RuntimeException(
1240
+				esc_html__('The total paid calculation for this transaction is inaccurate.', 'event_espresso')
1241
+			);
1242
+		}
1243
+		if ($new_txn_status !== $this->status_ID()) {
1244
+			$this->set_status($new_txn_status);
1245
+			if ($update) {
1246
+				return $this->save() ? true : false;
1247
+			}
1248
+		}
1249
+		return false;
1250
+	}
1251
+
1252
+
1253
+	/**
1254
+	 * Updates the transaction's status and total_paid based on all the payments
1255
+	 * that apply to it
1256
+	 *
1257
+	 * @deprecated
1258
+	 * @return array|bool
1259
+	 * @throws EE_Error
1260
+	 * @throws InvalidArgumentException
1261
+	 * @throws ReflectionException
1262
+	 * @throws InvalidDataTypeException
1263
+	 * @throws InvalidInterfaceException
1264
+	 */
1265
+	public function update_based_on_payments()
1266
+	{
1267
+		EE_Error::doing_it_wrong(
1268
+			__CLASS__ . '::' . __FUNCTION__,
1269
+			sprintf(
1270
+				esc_html__('This method is deprecated. Please use "%s" instead', 'event_espresso'),
1271
+				'EE_Transaction_Processor::update_transaction_and_registrations_after_checkout_or_payment()'
1272
+			),
1273
+			'4.6.0'
1274
+		);
1275
+		/** @type EE_Transaction_Processor $transaction_processor */
1276
+		$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
1277
+		return $transaction_processor->update_transaction_and_registrations_after_checkout_or_payment($this);
1278
+	}
1279
+
1280
+
1281
+	/**
1282
+	 * @return string
1283
+	 */
1284
+	public function old_txn_status()
1285
+	{
1286
+		return $this->_old_txn_status;
1287
+	}
1288
+
1289
+
1290
+	/**
1291
+	 * @param string $old_txn_status
1292
+	 */
1293
+	public function set_old_txn_status($old_txn_status)
1294
+	{
1295
+		// only set the first time
1296
+		if ($this->_old_txn_status === null) {
1297
+			$this->_old_txn_status = $old_txn_status;
1298
+		}
1299
+	}
1300
+
1301
+
1302
+	/**
1303
+	 * reg_status_updated
1304
+	 *
1305
+	 * @return bool
1306
+	 * @throws EE_Error
1307
+	 * @throws InvalidArgumentException
1308
+	 * @throws InvalidDataTypeException
1309
+	 * @throws InvalidInterfaceException
1310
+	 * @throws ReflectionException
1311
+	 */
1312
+	public function txn_status_updated()
1313
+	{
1314
+		return $this->status_ID() !== $this->_old_txn_status && $this->_old_txn_status !== null;
1315
+	}
1316
+
1317
+
1318
+	/**
1319
+	 * _reg_steps_completed
1320
+	 * if $check_all is TRUE, then returns TRUE if ALL reg steps have been marked as completed,
1321
+	 * if a $reg_step_slug is provided, then this step will be skipped when testing for completion
1322
+	 * if $check_all is FALSE and a $reg_step_slug is provided, then ONLY that reg step will be tested for completion
1323
+	 *
1324
+	 * @param string $reg_step_slug
1325
+	 * @param bool   $check_all
1326
+	 * @return bool|int
1327
+	 * @throws EE_Error
1328
+	 * @throws InvalidArgumentException
1329
+	 * @throws InvalidDataTypeException
1330
+	 * @throws InvalidInterfaceException
1331
+	 * @throws ReflectionException
1332
+	 */
1333
+	private function _reg_steps_completed($reg_step_slug = '', $check_all = true)
1334
+	{
1335
+		$reg_steps = $this->reg_steps();
1336
+		if (! is_array($reg_steps) || empty($reg_steps)) {
1337
+			return false;
1338
+		}
1339
+		// loop thru reg steps array)
1340
+		foreach ($reg_steps as $slug => $reg_step_completed) {
1341
+			// if NOT checking ALL steps (only checking one step)
1342
+			if (! $check_all) {
1343
+				// and this is the one
1344
+				if ($slug === $reg_step_slug) {
1345
+					return $reg_step_completed;
1346
+				}
1347
+				// skip to next reg step in loop
1348
+				continue;
1349
+			}
1350
+			// $check_all must be true, else we would never have gotten to this point
1351
+			if ($slug === $reg_step_slug) {
1352
+				// if we reach this point, then we are testing either:
1353
+				// all_reg_steps_completed_except() or
1354
+				// all_reg_steps_completed_except_final_step(),
1355
+				// and since this is the reg step EXCEPTION being tested
1356
+				// we want to return true (yes true) if this reg step is NOT completed
1357
+				// ie: "is everything completed except the final step?"
1358
+				// "that is correct... the final step is not completed, but all others are."
1359
+				return $reg_step_completed !== true;
1360
+			}
1361
+			if ($reg_step_completed !== true) {
1362
+				// if any reg step is NOT completed, then ALL steps are not completed
1363
+				return false;
1364
+			}
1365
+		}
1366
+		return true;
1367
+	}
1368
+
1369
+
1370
+	/**
1371
+	 * all_reg_steps_completed
1372
+	 * returns:
1373
+	 *    true if ALL reg steps have been marked as completed
1374
+	 *        or false if any step is not completed
1375
+	 *
1376
+	 * @return bool
1377
+	 * @throws EE_Error
1378
+	 * @throws InvalidArgumentException
1379
+	 * @throws InvalidDataTypeException
1380
+	 * @throws InvalidInterfaceException
1381
+	 * @throws ReflectionException
1382
+	 */
1383
+	public function all_reg_steps_completed()
1384
+	{
1385
+		return $this->_reg_steps_completed();
1386
+	}
1387
+
1388
+
1389
+	/**
1390
+	 * all_reg_steps_completed_except
1391
+	 * returns:
1392
+	 *        true if ALL reg steps, except a particular step that you wish to skip over, have been marked as completed
1393
+	 *        or false if any other step is not completed
1394
+	 *        or false if ALL steps are completed including the exception you are testing !!!
1395
+	 *
1396
+	 * @param string $exception
1397
+	 * @return bool
1398
+	 * @throws EE_Error
1399
+	 * @throws InvalidArgumentException
1400
+	 * @throws InvalidDataTypeException
1401
+	 * @throws InvalidInterfaceException
1402
+	 * @throws ReflectionException
1403
+	 */
1404
+	public function all_reg_steps_completed_except($exception = '')
1405
+	{
1406
+		return $this->_reg_steps_completed($exception);
1407
+	}
1408
+
1409
+
1410
+	/**
1411
+	 * all_reg_steps_completed_except
1412
+	 * returns:
1413
+	 *        true if ALL reg steps, except the final step, have been marked as completed
1414
+	 *        or false if any step is not completed
1415
+	 *    or false if ALL steps are completed including the final step !!!
1416
+	 *
1417
+	 * @return bool
1418
+	 * @throws EE_Error
1419
+	 * @throws InvalidArgumentException
1420
+	 * @throws InvalidDataTypeException
1421
+	 * @throws InvalidInterfaceException
1422
+	 * @throws ReflectionException
1423
+	 */
1424
+	public function all_reg_steps_completed_except_final_step()
1425
+	{
1426
+		return $this->_reg_steps_completed('finalize_registration');
1427
+	}
1428
+
1429
+
1430
+	/**
1431
+	 * reg_step_completed
1432
+	 * returns:
1433
+	 *    true if a specific reg step has been marked as completed
1434
+	 *    a Unix timestamp if it has been initialized but not yet completed,
1435
+	 *    or false if it has not yet been initialized
1436
+	 *
1437
+	 * @param string $reg_step_slug
1438
+	 * @return bool|int
1439
+	 * @throws EE_Error
1440
+	 * @throws InvalidArgumentException
1441
+	 * @throws InvalidDataTypeException
1442
+	 * @throws InvalidInterfaceException
1443
+	 * @throws ReflectionException
1444
+	 */
1445
+	public function reg_step_completed($reg_step_slug)
1446
+	{
1447
+		return $this->_reg_steps_completed($reg_step_slug, false);
1448
+	}
1449
+
1450
+
1451
+	/**
1452
+	 * completed_final_reg_step
1453
+	 * returns:
1454
+	 *    true if the finalize_registration reg step has been marked as completed
1455
+	 *    a Unix timestamp if it has been initialized but not yet completed,
1456
+	 *    or false if it has not yet been initialized
1457
+	 *
1458
+	 * @return bool|int
1459
+	 * @throws EE_Error
1460
+	 * @throws InvalidArgumentException
1461
+	 * @throws InvalidDataTypeException
1462
+	 * @throws InvalidInterfaceException
1463
+	 * @throws ReflectionException
1464
+	 */
1465
+	public function final_reg_step_completed()
1466
+	{
1467
+		return $this->_reg_steps_completed('finalize_registration', false);
1468
+	}
1469
+
1470
+
1471
+	/**
1472
+	 * set_reg_step_initiated
1473
+	 * given a valid TXN_reg_step, this sets it's value to a unix timestamp
1474
+	 *
1475
+	 * @param string $reg_step_slug
1476
+	 * @return boolean
1477
+	 * @throws EE_Error
1478
+	 * @throws InvalidArgumentException
1479
+	 * @throws InvalidDataTypeException
1480
+	 * @throws InvalidInterfaceException
1481
+	 * @throws ReflectionException
1482
+	 */
1483
+	public function set_reg_step_initiated($reg_step_slug)
1484
+	{
1485
+		return $this->_set_reg_step_completed_status($reg_step_slug, time());
1486
+	}
1487
+
1488
+
1489
+	/**
1490
+	 * set_reg_step_completed
1491
+	 * given a valid TXN_reg_step, this sets the step as completed
1492
+	 *
1493
+	 * @param string $reg_step_slug
1494
+	 * @return boolean
1495
+	 * @throws EE_Error
1496
+	 * @throws InvalidArgumentException
1497
+	 * @throws InvalidDataTypeException
1498
+	 * @throws InvalidInterfaceException
1499
+	 * @throws ReflectionException
1500
+	 */
1501
+	public function set_reg_step_completed($reg_step_slug)
1502
+	{
1503
+		return $this->_set_reg_step_completed_status($reg_step_slug, true);
1504
+	}
1505
+
1506
+
1507
+	/**
1508
+	 * set_reg_step_completed
1509
+	 * given a valid TXN_reg_step slug, this sets the step as NOT completed
1510
+	 *
1511
+	 * @param string $reg_step_slug
1512
+	 * @return boolean
1513
+	 * @throws EE_Error
1514
+	 * @throws InvalidArgumentException
1515
+	 * @throws InvalidDataTypeException
1516
+	 * @throws InvalidInterfaceException
1517
+	 * @throws ReflectionException
1518
+	 */
1519
+	public function set_reg_step_not_completed($reg_step_slug)
1520
+	{
1521
+		return $this->_set_reg_step_completed_status($reg_step_slug, false);
1522
+	}
1523
+
1524
+
1525
+	/**
1526
+	 * set_reg_step_completed
1527
+	 * given a valid reg step slug, this sets the TXN_reg_step completed status which is either:
1528
+	 *
1529
+	 * @param  string      $reg_step_slug
1530
+	 * @param  boolean|int $status
1531
+	 * @return boolean
1532
+	 * @throws EE_Error
1533
+	 * @throws InvalidArgumentException
1534
+	 * @throws InvalidDataTypeException
1535
+	 * @throws InvalidInterfaceException
1536
+	 * @throws ReflectionException
1537
+	 */
1538
+	private function _set_reg_step_completed_status($reg_step_slug, $status)
1539
+	{
1540
+		// validate status
1541
+		$status = is_bool($status) || is_int($status) ? $status : false;
1542
+		// get reg steps array
1543
+		$txn_reg_steps = $this->reg_steps();
1544
+		// if reg step does NOT exist
1545
+		if (! isset($txn_reg_steps[ $reg_step_slug ])) {
1546
+			return false;
1547
+		}
1548
+		// if  we're trying to complete a step that is already completed
1549
+		if ($txn_reg_steps[ $reg_step_slug ] === true) {
1550
+			return true;
1551
+		}
1552
+		// if  we're trying to complete a step that hasn't even started
1553
+		if ($status === true && $txn_reg_steps[ $reg_step_slug ] === false) {
1554
+			return false;
1555
+		}
1556
+		// if current status value matches the incoming value (no change)
1557
+		// type casting as int means values should collapse to either 0, 1, or a timestamp like 1234567890
1558
+		if ((int) $txn_reg_steps[ $reg_step_slug ] === (int) $status) {
1559
+			// this will happen in cases where multiple AJAX requests occur during the same step
1560
+			return true;
1561
+		}
1562
+		// if we're trying to set a start time, but it has already been set...
1563
+		if (is_numeric($status) && is_numeric($txn_reg_steps[ $reg_step_slug ])) {
1564
+			// skip the update below, but don't return FALSE so that errors won't be displayed
1565
+			return true;
1566
+		}
1567
+		// update completed status
1568
+		$txn_reg_steps[ $reg_step_slug ] = $status;
1569
+		$this->set_reg_steps($txn_reg_steps);
1570
+		$this->save();
1571
+		return true;
1572
+	}
1573
+
1574
+
1575
+	/**
1576
+	 * remove_reg_step
1577
+	 * given a valid TXN_reg_step slug, this will remove (unset)
1578
+	 * the reg step from the TXN reg step array
1579
+	 *
1580
+	 * @param string $reg_step_slug
1581
+	 * @return void
1582
+	 * @throws EE_Error
1583
+	 * @throws InvalidArgumentException
1584
+	 * @throws InvalidDataTypeException
1585
+	 * @throws InvalidInterfaceException
1586
+	 * @throws ReflectionException
1587
+	 */
1588
+	public function remove_reg_step($reg_step_slug)
1589
+	{
1590
+		// get reg steps array
1591
+		$txn_reg_steps = $this->reg_steps();
1592
+		unset($txn_reg_steps[ $reg_step_slug ]);
1593
+		$this->set_reg_steps($txn_reg_steps);
1594
+	}
1595
+
1596
+
1597
+	/**
1598
+	 * toggle_failed_transaction_status
1599
+	 * upgrades a TXNs status from failed to abandoned,
1600
+	 * meaning that contact information has been captured for at least one registrant
1601
+	 *
1602
+	 * @param bool $save
1603
+	 * @return bool
1604
+	 * @throws EE_Error
1605
+	 * @throws InvalidArgumentException
1606
+	 * @throws InvalidDataTypeException
1607
+	 * @throws InvalidInterfaceException
1608
+	 * @throws ReflectionException
1609
+	 */
1610
+	public function toggle_failed_transaction_status($save = true)
1611
+	{
1612
+		// if TXN status is still set as "failed"...
1613
+		if ($this->status_ID() === EEM_Transaction::failed_status_code) {
1614
+			$this->set_status(EEM_Transaction::abandoned_status_code);
1615
+			if ($save) {
1616
+				$this->save();
1617
+			}
1618
+			return true;
1619
+		}
1620
+		return false;
1621
+	}
1622
+
1623
+
1624
+	/**
1625
+	 * toggle_abandoned_transaction_status
1626
+	 * upgrades a TXNs status from failed or abandoned to incomplete
1627
+	 *
1628
+	 * @return bool
1629
+	 * @throws EE_Error
1630
+	 * @throws InvalidArgumentException
1631
+	 * @throws InvalidDataTypeException
1632
+	 * @throws InvalidInterfaceException
1633
+	 * @throws ReflectionException
1634
+	 */
1635
+	public function toggle_abandoned_transaction_status()
1636
+	{
1637
+		// if TXN status has not been updated already due to a payment, and is still set as "failed" or "abandoned"...
1638
+		$txn_status = $this->status_ID();
1639
+		if ($txn_status === EEM_Transaction::failed_status_code
1640
+			|| $txn_status === EEM_Transaction::abandoned_status_code
1641
+		) {
1642
+			// if a contact record for the primary registrant has been created
1643
+			if ($this->primary_registration() instanceof EE_Registration
1644
+				&& $this->primary_registration()->attendee() instanceof EE_Attendee
1645
+			) {
1646
+				$this->set_status(EEM_Transaction::incomplete_status_code);
1647
+			} else {
1648
+				// no contact record? yer abandoned!
1649
+				$this->set_status(EEM_Transaction::abandoned_status_code);
1650
+			}
1651
+			return true;
1652
+		}
1653
+		return false;
1654
+	}
1655
+
1656
+
1657
+	/**
1658
+	 * checks if an Abandoned TXN has any related payments, and if so,
1659
+	 * updates the TXN status based on the amount paid
1660
+	 *
1661
+	 * @throws EE_Error
1662
+	 * @throws InvalidArgumentException
1663
+	 * @throws InvalidDataTypeException
1664
+	 * @throws InvalidInterfaceException
1665
+	 * @throws ReflectionException
1666
+	 * @throws RuntimeException
1667
+	 * @throws ReflectionException
1668
+	 */
1669
+	public function verify_abandoned_transaction_status()
1670
+	{
1671
+		if ($this->status_ID() !== EEM_Transaction::abandoned_status_code) {
1672
+			return;
1673
+		}
1674
+		$payments = $this->get_many_related('Payment');
1675
+		if (! empty($payments)) {
1676
+			foreach ($payments as $payment) {
1677
+				if ($payment instanceof EE_Payment) {
1678
+					// kk this TXN should NOT be abandoned
1679
+					$this->update_status_based_on_total_paid();
1680
+					if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1681
+						EE_Error::add_attention(
1682
+							sprintf(
1683
+								esc_html__(
1684
+									'The status for Transaction #%1$d has been updated from "Abandoned" to "%2$s", because at least one payment has been made towards it. If the payment appears in the "Payment Details" table below, you may need to edit its status and/or other details as well.',
1685
+									'event_espresso'
1686
+								),
1687
+								$this->ID(),
1688
+								$this->pretty_status()
1689
+							)
1690
+						);
1691
+					}
1692
+					// get final reg step status
1693
+					$finalized = $this->final_reg_step_completed();
1694
+					// if the 'finalize_registration' step has been initiated (has a timestamp)
1695
+					// but has not yet been fully completed (TRUE)
1696
+					if (is_int($finalized) && $finalized !== false && $finalized !== true) {
1697
+						$this->set_reg_step_completed('finalize_registration');
1698
+						$this->save();
1699
+					}
1700
+				}
1701
+			}
1702
+		}
1703
+	}
1704
+
1705
+
1706
+	/**
1707
+	 * @since 4.10.4.p
1708
+	 * @throws EE_Error
1709
+	 * @throws InvalidArgumentException
1710
+	 * @throws InvalidDataTypeException
1711
+	 * @throws InvalidInterfaceException
1712
+	 * @throws ReflectionException
1713
+	 * @throws RuntimeException
1714
+	 */
1715
+	public function recalculateLineItems()
1716
+	{
1717
+		$total_line_item = $this->total_line_item(false);
1718
+		if ($total_line_item instanceof EE_Line_Item) {
1719
+			EEH_Line_Item::resetIsTaxableForTickets($total_line_item);
1720
+			return EEH_Line_Item::apply_taxes($total_line_item, true);
1721
+		}
1722
+		return false;
1723
+	}
1724
+
1725
+
1726
+	/**
1727
+	 * @param string $source function name that called this method
1728
+	 * @return boolean | int
1729
+	 */
1730
+	public function delete($source = 'unknown')
1731
+	{
1732
+		$current_user = wp_get_current_user();
1733
+		$this->add_extra_meta(
1734
+			EE_Transaction::EXTRA_META_KEY_TXN_DELETED,
1735
+			array(
1736
+				'deleted-by' => $current_user->ID ? $current_user->display_name : 'unauthed user',
1737
+				'timestamp'  => time(),
1738
+				'source'     => $source,
1739
+			)
1740
+		);
1741
+		return parent::delete();
1742
+	}
1743 1743
 }
Please login to merge, or discard this patch.
core/domain/services/custom_post_types/RewriteRules.php 2 patches
Indentation   +27 added lines, -27 removed lines patch added patch discarded remove patch
@@ -13,35 +13,35 @@
 block discarded – undo
13 13
 class RewriteRules
14 14
 {
15 15
 
16
-    const OPTION_KEY_FLUSH_REWRITE_RULES = 'ee_flush_rewrite_rules';
16
+	const OPTION_KEY_FLUSH_REWRITE_RULES = 'ee_flush_rewrite_rules';
17 17
 
18 18
 
19
-    /**
20
-     * This will flush rewrite rules on demand.  This actually gets called around wp init priority level 100.
21
-     *
22
-     * @return void
23
-     */
24
-    public function flush()
25
-    {
26
-        update_option(RewriteRules::OPTION_KEY_FLUSH_REWRITE_RULES, true);
27
-    }
19
+	/**
20
+	 * This will flush rewrite rules on demand.  This actually gets called around wp init priority level 100.
21
+	 *
22
+	 * @return void
23
+	 */
24
+	public function flush()
25
+	{
26
+		update_option(RewriteRules::OPTION_KEY_FLUSH_REWRITE_RULES, true);
27
+	}
28 28
 
29 29
 
30
-    /**
31
-     * This will flush rewrite rules on demand.  This actually gets called around wp init priority level 100.
32
-     *
33
-     * @return void
34
-     */
35
-    public function flushRewriteRules()
36
-    {
37
-        if (get_option(RewriteRules::OPTION_KEY_FLUSH_REWRITE_RULES, true)) {
38
-            add_action(
39
-                'shutdown',
40
-                static function () {
41
-                    flush_rewrite_rules();
42
-                    update_option(RewriteRules::OPTION_KEY_FLUSH_REWRITE_RULES, false);
43
-                }
44
-            );
45
-        }
46
-    }
30
+	/**
31
+	 * This will flush rewrite rules on demand.  This actually gets called around wp init priority level 100.
32
+	 *
33
+	 * @return void
34
+	 */
35
+	public function flushRewriteRules()
36
+	{
37
+		if (get_option(RewriteRules::OPTION_KEY_FLUSH_REWRITE_RULES, true)) {
38
+			add_action(
39
+				'shutdown',
40
+				static function () {
41
+					flush_rewrite_rules();
42
+					update_option(RewriteRules::OPTION_KEY_FLUSH_REWRITE_RULES, false);
43
+				}
44
+			);
45
+		}
46
+	}
47 47
 }
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -37,7 +37,7 @@
 block discarded – undo
37 37
         if (get_option(RewriteRules::OPTION_KEY_FLUSH_REWRITE_RULES, true)) {
38 38
             add_action(
39 39
                 'shutdown',
40
-                static function () {
40
+                static function() {
41 41
                     flush_rewrite_rules();
42 42
                     update_option(RewriteRules::OPTION_KEY_FLUSH_REWRITE_RULES, false);
43 43
                 }
Please login to merge, or discard this patch.
espresso.php 1 patch
Indentation   +80 added lines, -80 removed lines patch added patch discarded remove patch
@@ -38,103 +38,103 @@
 block discarded – undo
38 38
  * @since           4.0
39 39
  */
40 40
 if (function_exists('espresso_version')) {
41
-    if (! function_exists('espresso_duplicate_plugin_error')) {
42
-        /**
43
-         *    espresso_duplicate_plugin_error
44
-         *    displays if more than one version of EE is activated at the same time
45
-         */
46
-        function espresso_duplicate_plugin_error()
47
-        {
48
-            ?>
41
+	if (! function_exists('espresso_duplicate_plugin_error')) {
42
+		/**
43
+		 *    espresso_duplicate_plugin_error
44
+		 *    displays if more than one version of EE is activated at the same time
45
+		 */
46
+		function espresso_duplicate_plugin_error()
47
+		{
48
+			?>
49 49
             <div class="error">
50 50
                 <p>
51 51
                     <?php
52
-                    echo esc_html__(
53
-                        'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
54
-                        'event_espresso'
55
-                    ); ?>
52
+					echo esc_html__(
53
+						'Can not run multiple versions of Event Espresso! One version has been automatically deactivated. Please verify that you have the correct version you want still active.',
54
+						'event_espresso'
55
+					); ?>
56 56
                 </p>
57 57
             </div>
58 58
             <?php
59
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
60
-        }
61
-    }
62
-    add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
59
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
60
+		}
61
+	}
62
+	add_action('admin_notices', 'espresso_duplicate_plugin_error', 1);
63 63
 } else {
64
-    define('EE_MIN_PHP_VER_REQUIRED', '5.6.2');
65
-    if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
66
-        /**
67
-         * espresso_minimum_php_version_error
68
-         *
69
-         * @return void
70
-         */
71
-        function espresso_minimum_php_version_error()
72
-        {
73
-            ?>
64
+	define('EE_MIN_PHP_VER_REQUIRED', '5.6.2');
65
+	if (! version_compare(PHP_VERSION, EE_MIN_PHP_VER_REQUIRED, '>=')) {
66
+		/**
67
+		 * espresso_minimum_php_version_error
68
+		 *
69
+		 * @return void
70
+		 */
71
+		function espresso_minimum_php_version_error()
72
+		{
73
+			?>
74 74
             <div class="error">
75 75
                 <p>
76 76
                     <?php
77
-                    printf(
78
-                        esc_html__(
79
-                            'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
80
-                            'event_espresso'
81
-                        ),
82
-                        EE_MIN_PHP_VER_REQUIRED,
83
-                        PHP_VERSION,
84
-                        '<br/>',
85
-                        '<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
86
-                    );
87
-                    ?>
77
+					printf(
78
+						esc_html__(
79
+							'We\'re sorry, but Event Espresso requires PHP version %1$s or greater in order to operate. You are currently running version %2$s.%3$sIn order to update your version of PHP, you will need to contact your current hosting provider.%3$sFor information on stable PHP versions, please go to %4$s.',
80
+							'event_espresso'
81
+						),
82
+						EE_MIN_PHP_VER_REQUIRED,
83
+						PHP_VERSION,
84
+						'<br/>',
85
+						'<a href="http://php.net/downloads.php">http://php.net/downloads.php</a>'
86
+					);
87
+					?>
88 88
                 </p>
89 89
             </div>
90 90
             <?php
91
-            espresso_deactivate_plugin(plugin_basename(__FILE__));
92
-        }
91
+			espresso_deactivate_plugin(plugin_basename(__FILE__));
92
+		}
93 93
 
94
-        add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
95
-    } else {
96
-        define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
97
-        /**
98
-         * espresso_version
99
-         * Returns the plugin version
100
-         *
101
-         * @return string
102
-         */
103
-        function espresso_version()
104
-        {
105
-            return apply_filters('FHEE__espresso__espresso_version', '4.10.13.rc.006');
106
-        }
94
+		add_action('admin_notices', 'espresso_minimum_php_version_error', 1);
95
+	} else {
96
+		define('EVENT_ESPRESSO_MAIN_FILE', __FILE__);
97
+		/**
98
+		 * espresso_version
99
+		 * Returns the plugin version
100
+		 *
101
+		 * @return string
102
+		 */
103
+		function espresso_version()
104
+		{
105
+			return apply_filters('FHEE__espresso__espresso_version', '4.10.13.rc.006');
106
+		}
107 107
 
108
-        /**
109
-         * espresso_plugin_activation
110
-         * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
111
-         */
112
-        function espresso_plugin_activation()
113
-        {
114
-            update_option('ee_espresso_activation', true);
115
-        }
108
+		/**
109
+		 * espresso_plugin_activation
110
+		 * adds a wp-option to indicate that EE has been activated via the WP admin plugins page
111
+		 */
112
+		function espresso_plugin_activation()
113
+		{
114
+			update_option('ee_espresso_activation', true);
115
+		}
116 116
 
117
-        register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
117
+		register_activation_hook(EVENT_ESPRESSO_MAIN_FILE, 'espresso_plugin_activation');
118 118
 
119
-        require_once __DIR__ . '/core/bootstrap_espresso.php';
120
-        bootstrap_espresso();
121
-    }
119
+		require_once __DIR__ . '/core/bootstrap_espresso.php';
120
+		bootstrap_espresso();
121
+	}
122 122
 }
123 123
 if (! function_exists('espresso_deactivate_plugin')) {
124
-    /**
125
-     *    deactivate_plugin
126
-     * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
127
-     *
128
-     * @access public
129
-     * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
130
-     * @return    void
131
-     */
132
-    function espresso_deactivate_plugin($plugin_basename = '')
133
-    {
134
-        if (! function_exists('deactivate_plugins')) {
135
-            require_once ABSPATH . 'wp-admin/includes/plugin.php';
136
-        }
137
-        unset($_GET['activate'], $_REQUEST['activate']);
138
-        deactivate_plugins($plugin_basename);
139
-    }
124
+	/**
125
+	 *    deactivate_plugin
126
+	 * usage:  espresso_deactivate_plugin( plugin_basename( __FILE__ ));
127
+	 *
128
+	 * @access public
129
+	 * @param string $plugin_basename - the results of plugin_basename( __FILE__ ) for the plugin's main file
130
+	 * @return    void
131
+	 */
132
+	function espresso_deactivate_plugin($plugin_basename = '')
133
+	{
134
+		if (! function_exists('deactivate_plugins')) {
135
+			require_once ABSPATH . 'wp-admin/includes/plugin.php';
136
+		}
137
+		unset($_GET['activate'], $_REQUEST['activate']);
138
+		deactivate_plugins($plugin_basename);
139
+	}
140 140
 }
Please login to merge, or discard this patch.
admin_pages/registrations/Registrations_Admin_Page.core.php 1 patch
Indentation   +3712 added lines, -3712 removed lines patch added patch discarded remove patch
@@ -19,2230 +19,2230 @@  discard block
 block discarded – undo
19 19
 class Registrations_Admin_Page extends EE_Admin_Page_CPT
20 20
 {
21 21
 
22
-    /**
23
-     * @var EE_Registration
24
-     */
25
-    private $_registration;
26
-
27
-    /**
28
-     * @var EE_Event
29
-     */
30
-    private $_reg_event;
31
-
32
-    /**
33
-     * @var EE_Session
34
-     */
35
-    private $_session;
36
-
37
-    private static $_reg_status;
38
-
39
-    /**
40
-     * Form for displaying the custom questions for this registration.
41
-     * This gets used a few times throughout the request so its best to cache it
42
-     *
43
-     * @var EE_Registration_Custom_Questions_Form
44
-     */
45
-    protected $_reg_custom_questions_form = null;
46
-
47
-    /**
48
-     * @var EEM_Registration $registration_model
49
-     */
50
-    private $registration_model;
51
-
52
-    /**
53
-     * @var EEM_Attendee $attendee_model
54
-     */
55
-    private $attendee_model;
56
-
57
-    /**
58
-     * @var EEM_Event $event_model
59
-     */
60
-    private $event_model;
61
-
62
-    /**
63
-     * @var EEM_Status $status_model
64
-     */
65
-    private $status_model;
66
-
67
-
68
-    /**
69
-     * @param bool $routing
70
-     * @throws EE_Error
71
-     * @throws InvalidArgumentException
72
-     * @throws InvalidDataTypeException
73
-     * @throws InvalidInterfaceException
74
-     * @throws ReflectionException
75
-     */
76
-    public function __construct($routing = true)
77
-    {
78
-        parent::__construct($routing);
79
-        add_action('wp_loaded', array($this, 'wp_loaded'));
80
-    }
81
-
82
-    /**
83
-     * @return EEM_Registration
84
-     * @throws InvalidArgumentException
85
-     * @throws InvalidDataTypeException
86
-     * @throws InvalidInterfaceException
87
-     * @since 4.10.2.p
88
-     */
89
-    protected function getRegistrationModel()
90
-    {
91
-        if (! $this->registration_model instanceof EEM_Registration) {
92
-            $this->registration_model = $this->getLoader()->getShared('EEM_Registration');
93
-        }
94
-        return $this->registration_model;
95
-    }
96
-
97
-    /**
98
-     * @return EEM_Attendee
99
-     * @throws InvalidArgumentException
100
-     * @throws InvalidDataTypeException
101
-     * @throws InvalidInterfaceException
102
-     * @since 4.10.2.p
103
-     */
104
-    protected function getAttendeeModel()
105
-    {
106
-        if (! $this->attendee_model instanceof EEM_Attendee) {
107
-            $this->attendee_model = $this->getLoader()->getShared('EEM_Attendee');
108
-        }
109
-        return $this->attendee_model;
110
-    }
111
-
112
-
113
-    /**
114
-     * @return EEM_Event
115
-     * @throws InvalidArgumentException
116
-     * @throws InvalidDataTypeException
117
-     * @throws InvalidInterfaceException
118
-     * @since 4.10.2.p
119
-     */
120
-    protected function getEventModel()
121
-    {
122
-        if (! $this->event_model instanceof EEM_Event) {
123
-            $this->event_model = $this->getLoader()->getShared('EEM_Event');
124
-        }
125
-        return $this->event_model;
126
-    }
127
-
128
-    /**
129
-     * @return EEM_Status
130
-     * @throws InvalidArgumentException
131
-     * @throws InvalidDataTypeException
132
-     * @throws InvalidInterfaceException
133
-     * @since 4.10.2.p
134
-     */
135
-    protected function getStatusModel()
136
-    {
137
-        if (! $this->status_model instanceof EEM_Status) {
138
-            $this->status_model = $this->getLoader()->getShared('EEM_Status');
139
-        }
140
-        return $this->status_model;
141
-    }
142
-
143
-
144
-    public function wp_loaded()
145
-    {
146
-        // when adding a new registration...
147
-        if (isset($this->_req_data['action']) && $this->_req_data['action'] === 'new_registration') {
148
-            EE_System::do_not_cache();
149
-            if (! isset($this->_req_data['processing_registration'])
150
-                || absint($this->_req_data['processing_registration']) !== 1
151
-            ) {
152
-                // and it's NOT the attendee information reg step
153
-                // force cookie expiration by setting time to last week
154
-                setcookie('ee_registration_added', 0, time() - WEEK_IN_SECONDS, '/');
155
-                // and update the global
156
-                $_COOKIE['ee_registration_added'] = 0;
157
-            }
158
-        }
159
-    }
160
-
161
-
162
-    protected function _init_page_props()
163
-    {
164
-        $this->page_slug = REG_PG_SLUG;
165
-        $this->_admin_base_url = REG_ADMIN_URL;
166
-        $this->_admin_base_path = REG_ADMIN;
167
-        $this->page_label = esc_html__('Registrations', 'event_espresso');
168
-        $this->_cpt_routes = array(
169
-            'add_new_attendee' => 'espresso_attendees',
170
-            'edit_attendee'    => 'espresso_attendees',
171
-            'insert_attendee'  => 'espresso_attendees',
172
-            'update_attendee'  => 'espresso_attendees',
173
-        );
174
-        $this->_cpt_model_names = array(
175
-            'add_new_attendee' => 'EEM_Attendee',
176
-            'edit_attendee'    => 'EEM_Attendee',
177
-        );
178
-        $this->_cpt_edit_routes = array(
179
-            'espresso_attendees' => 'edit_attendee',
180
-        );
181
-        $this->_pagenow_map = array(
182
-            'add_new_attendee' => 'post-new.php',
183
-            'edit_attendee'    => 'post.php',
184
-            'trash'            => 'post.php',
185
-        );
186
-        add_action('edit_form_after_title', array($this, 'after_title_form_fields'), 10);
187
-        // add filters so that the comment urls don't take users to a confusing 404 page
188
-        add_filter('get_comment_link', array($this, 'clear_comment_link'), 10, 3);
189
-    }
190
-
191
-
192
-    public function clear_comment_link($link, $comment, $args)
193
-    {
194
-        // gotta make sure this only happens on this route
195
-        $post_type = get_post_type($comment->comment_post_ID);
196
-        if ($post_type === 'espresso_attendees') {
197
-            return '#commentsdiv';
198
-        }
199
-        return $link;
200
-    }
201
-
202
-
203
-    protected function _ajax_hooks()
204
-    {
205
-        // todo: all hooks for registrations ajax goes in here
206
-        add_action('wp_ajax_toggle_checkin_status', array($this, 'toggle_checkin_status'));
207
-    }
208
-
209
-
210
-    protected function _define_page_props()
211
-    {
212
-        $this->_admin_page_title = $this->page_label;
213
-        $this->_labels = array(
214
-            'buttons'                      => array(
215
-                'add-registrant'      => esc_html__('Add New Registration', 'event_espresso'),
216
-                'add-attendee'        => esc_html__('Add Contact', 'event_espresso'),
217
-                'edit'                => esc_html__('Edit Contact', 'event_espresso'),
218
-                'report'              => esc_html__('Event Registrations CSV Report', 'event_espresso'),
219
-                'report_all'          => esc_html__('All Registrations CSV Report', 'event_espresso'),
220
-                'report_filtered'     => esc_html__('Filtered CSV Report', 'event_espresso'),
221
-                'contact_list_report' => esc_html__('Contact List Report', 'event_espresso'),
222
-                'contact_list_export' => esc_html__('Export Data', 'event_espresso'),
223
-            ),
224
-            'publishbox'                   => array(
225
-                'add_new_attendee' => esc_html__('Add Contact Record', 'event_espresso'),
226
-                'edit_attendee'    => esc_html__('Update Contact Record', 'event_espresso'),
227
-            ),
228
-            'hide_add_button_on_cpt_route' => array(
229
-                'edit_attendee' => true,
230
-            ),
231
-        );
232
-    }
233
-
234
-
235
-    /**
236
-     *        grab url requests and route them
237
-     *
238
-     * @access private
239
-     * @return void
240
-     * @throws EE_Error
241
-     */
242
-    public function _set_page_routes()
243
-    {
244
-        $this->_get_registration_status_array();
245
-        $reg_id = ! empty($this->_req_data['_REG_ID']) && ! is_array($this->_req_data['_REG_ID'])
246
-            ? $this->_req_data['_REG_ID'] : 0;
247
-        $reg_id = empty($reg_id) && ! empty($this->_req_data['reg_status_change_form']['REG_ID'])
248
-            ? $this->_req_data['reg_status_change_form']['REG_ID']
249
-            : $reg_id;
250
-        $att_id = ! empty($this->_req_data['ATT_ID']) && ! is_array($this->_req_data['ATT_ID'])
251
-            ? $this->_req_data['ATT_ID'] : 0;
252
-        $att_id = ! empty($this->_req_data['post']) && ! is_array($this->_req_data['post'])
253
-            ? $this->_req_data['post']
254
-            : $att_id;
255
-        $this->_page_routes = array(
256
-            'default'                             => array(
257
-                'func'       => '_registrations_overview_list_table',
258
-                'capability' => 'ee_read_registrations',
259
-            ),
260
-            'view_registration'                   => array(
261
-                'func'       => '_registration_details',
262
-                'capability' => 'ee_read_registration',
263
-                'obj_id'     => $reg_id,
264
-            ),
265
-            'edit_registration'                   => array(
266
-                'func'               => '_update_attendee_registration_form',
267
-                'noheader'           => true,
268
-                'headers_sent_route' => 'view_registration',
269
-                'capability'         => 'ee_edit_registration',
270
-                'obj_id'             => $reg_id,
271
-                '_REG_ID'            => $reg_id,
272
-            ),
273
-            'trash_registrations'                 => array(
274
-                'func'       => '_trash_or_restore_registrations',
275
-                'args'       => array('trash' => true),
276
-                'noheader'   => true,
277
-                'capability' => 'ee_delete_registrations',
278
-            ),
279
-            'restore_registrations'               => array(
280
-                'func'       => '_trash_or_restore_registrations',
281
-                'args'       => array('trash' => false),
282
-                'noheader'   => true,
283
-                'capability' => 'ee_delete_registrations',
284
-            ),
285
-            'delete_registrations'                => array(
286
-                'func'       => '_delete_registrations',
287
-                'noheader'   => true,
288
-                'capability' => 'ee_delete_registrations',
289
-            ),
290
-            'new_registration'                    => array(
291
-                'func'       => 'new_registration',
292
-                'capability' => 'ee_edit_registrations',
293
-            ),
294
-            'process_reg_step'                    => array(
295
-                'func'       => 'process_reg_step',
296
-                'noheader'   => true,
297
-                'capability' => 'ee_edit_registrations',
298
-            ),
299
-            'redirect_to_txn'                     => array(
300
-                'func'       => 'redirect_to_txn',
301
-                'noheader'   => true,
302
-                'capability' => 'ee_edit_registrations',
303
-            ),
304
-            'change_reg_status'                   => array(
305
-                'func'       => '_change_reg_status',
306
-                'noheader'   => true,
307
-                'capability' => 'ee_edit_registration',
308
-                'obj_id'     => $reg_id,
309
-            ),
310
-            'approve_registration'                => array(
311
-                'func'       => 'approve_registration',
312
-                'noheader'   => true,
313
-                'capability' => 'ee_edit_registration',
314
-                'obj_id'     => $reg_id,
315
-            ),
316
-            'approve_and_notify_registration'     => array(
317
-                'func'       => 'approve_registration',
318
-                'noheader'   => true,
319
-                'args'       => array(true),
320
-                'capability' => 'ee_edit_registration',
321
-                'obj_id'     => $reg_id,
322
-            ),
323
-            'approve_registrations'               => array(
324
-                'func'       => 'bulk_action_on_registrations',
325
-                'noheader'   => true,
326
-                'capability' => 'ee_edit_registrations',
327
-                'args'       => array('approve'),
328
-            ),
329
-            'approve_and_notify_registrations'    => array(
330
-                'func'       => 'bulk_action_on_registrations',
331
-                'noheader'   => true,
332
-                'capability' => 'ee_edit_registrations',
333
-                'args'       => array('approve', true),
334
-            ),
335
-            'decline_registration'                => array(
336
-                'func'       => 'decline_registration',
337
-                'noheader'   => true,
338
-                'capability' => 'ee_edit_registration',
339
-                'obj_id'     => $reg_id,
340
-            ),
341
-            'decline_and_notify_registration'     => array(
342
-                'func'       => 'decline_registration',
343
-                'noheader'   => true,
344
-                'args'       => array(true),
345
-                'capability' => 'ee_edit_registration',
346
-                'obj_id'     => $reg_id,
347
-            ),
348
-            'decline_registrations'               => array(
349
-                'func'       => 'bulk_action_on_registrations',
350
-                'noheader'   => true,
351
-                'capability' => 'ee_edit_registrations',
352
-                'args'       => array('decline'),
353
-            ),
354
-            'decline_and_notify_registrations'    => array(
355
-                'func'       => 'bulk_action_on_registrations',
356
-                'noheader'   => true,
357
-                'capability' => 'ee_edit_registrations',
358
-                'args'       => array('decline', true),
359
-            ),
360
-            'pending_registration'                => array(
361
-                'func'       => 'pending_registration',
362
-                'noheader'   => true,
363
-                'capability' => 'ee_edit_registration',
364
-                'obj_id'     => $reg_id,
365
-            ),
366
-            'pending_and_notify_registration'     => array(
367
-                'func'       => 'pending_registration',
368
-                'noheader'   => true,
369
-                'args'       => array(true),
370
-                'capability' => 'ee_edit_registration',
371
-                'obj_id'     => $reg_id,
372
-            ),
373
-            'pending_registrations'               => array(
374
-                'func'       => 'bulk_action_on_registrations',
375
-                'noheader'   => true,
376
-                'capability' => 'ee_edit_registrations',
377
-                'args'       => array('pending'),
378
-            ),
379
-            'pending_and_notify_registrations'    => array(
380
-                'func'       => 'bulk_action_on_registrations',
381
-                'noheader'   => true,
382
-                'capability' => 'ee_edit_registrations',
383
-                'args'       => array('pending', true),
384
-            ),
385
-            'no_approve_registration'             => array(
386
-                'func'       => 'not_approve_registration',
387
-                'noheader'   => true,
388
-                'capability' => 'ee_edit_registration',
389
-                'obj_id'     => $reg_id,
390
-            ),
391
-            'no_approve_and_notify_registration'  => array(
392
-                'func'       => 'not_approve_registration',
393
-                'noheader'   => true,
394
-                'args'       => array(true),
395
-                'capability' => 'ee_edit_registration',
396
-                'obj_id'     => $reg_id,
397
-            ),
398
-            'no_approve_registrations'            => array(
399
-                'func'       => 'bulk_action_on_registrations',
400
-                'noheader'   => true,
401
-                'capability' => 'ee_edit_registrations',
402
-                'args'       => array('not_approve'),
403
-            ),
404
-            'no_approve_and_notify_registrations' => array(
405
-                'func'       => 'bulk_action_on_registrations',
406
-                'noheader'   => true,
407
-                'capability' => 'ee_edit_registrations',
408
-                'args'       => array('not_approve', true),
409
-            ),
410
-            'cancel_registration'                 => array(
411
-                'func'       => 'cancel_registration',
412
-                'noheader'   => true,
413
-                'capability' => 'ee_edit_registration',
414
-                'obj_id'     => $reg_id,
415
-            ),
416
-            'cancel_and_notify_registration'      => array(
417
-                'func'       => 'cancel_registration',
418
-                'noheader'   => true,
419
-                'args'       => array(true),
420
-                'capability' => 'ee_edit_registration',
421
-                'obj_id'     => $reg_id,
422
-            ),
423
-            'cancel_registrations'                => array(
424
-                'func'       => 'bulk_action_on_registrations',
425
-                'noheader'   => true,
426
-                'capability' => 'ee_edit_registrations',
427
-                'args'       => array('cancel'),
428
-            ),
429
-            'cancel_and_notify_registrations'     => array(
430
-                'func'       => 'bulk_action_on_registrations',
431
-                'noheader'   => true,
432
-                'capability' => 'ee_edit_registrations',
433
-                'args'       => array('cancel', true),
434
-            ),
435
-            'wait_list_registration'              => array(
436
-                'func'       => 'wait_list_registration',
437
-                'noheader'   => true,
438
-                'capability' => 'ee_edit_registration',
439
-                'obj_id'     => $reg_id,
440
-            ),
441
-            'wait_list_and_notify_registration'   => array(
442
-                'func'       => 'wait_list_registration',
443
-                'noheader'   => true,
444
-                'args'       => array(true),
445
-                'capability' => 'ee_edit_registration',
446
-                'obj_id'     => $reg_id,
447
-            ),
448
-            'contact_list'                        => array(
449
-                'func'       => '_attendee_contact_list_table',
450
-                'capability' => 'ee_read_contacts',
451
-            ),
452
-            'add_new_attendee'                    => array(
453
-                'func' => '_create_new_cpt_item',
454
-                'args' => array(
455
-                    'new_attendee' => true,
456
-                    'capability'   => 'ee_edit_contacts',
457
-                ),
458
-            ),
459
-            'edit_attendee'                       => array(
460
-                'func'       => '_edit_cpt_item',
461
-                'capability' => 'ee_edit_contacts',
462
-                'obj_id'     => $att_id,
463
-            ),
464
-            'duplicate_attendee'                  => array(
465
-                'func'       => '_duplicate_attendee',
466
-                'noheader'   => true,
467
-                'capability' => 'ee_edit_contacts',
468
-                'obj_id'     => $att_id,
469
-            ),
470
-            'insert_attendee'                     => array(
471
-                'func'       => '_insert_or_update_attendee',
472
-                'args'       => array(
473
-                    'new_attendee' => true,
474
-                ),
475
-                'noheader'   => true,
476
-                'capability' => 'ee_edit_contacts',
477
-            ),
478
-            'update_attendee'                     => array(
479
-                'func'       => '_insert_or_update_attendee',
480
-                'args'       => array(
481
-                    'new_attendee' => false,
482
-                ),
483
-                'noheader'   => true,
484
-                'capability' => 'ee_edit_contacts',
485
-                'obj_id'     => $att_id,
486
-            ),
487
-            'trash_attendees'                     => array(
488
-                'func'       => '_trash_or_restore_attendees',
489
-                'args'       => array(
490
-                    'trash' => 'true',
491
-                ),
492
-                'noheader'   => true,
493
-                'capability' => 'ee_delete_contacts',
494
-            ),
495
-            'trash_attendee'                      => array(
496
-                'func'       => '_trash_or_restore_attendees',
497
-                'args'       => array(
498
-                    'trash' => true,
499
-                ),
500
-                'noheader'   => true,
501
-                'capability' => 'ee_delete_contacts',
502
-                'obj_id'     => $att_id,
503
-            ),
504
-            'restore_attendees'                   => array(
505
-                'func'       => '_trash_or_restore_attendees',
506
-                'args'       => array(
507
-                    'trash' => false,
508
-                ),
509
-                'noheader'   => true,
510
-                'capability' => 'ee_delete_contacts',
511
-                'obj_id'     => $att_id,
512
-            ),
513
-            'resend_registration'                 => array(
514
-                'func'       => '_resend_registration',
515
-                'noheader'   => true,
516
-                'capability' => 'ee_send_message',
517
-            ),
518
-            'registrations_report'                => array(
519
-                'func'       => '_registrations_report',
520
-                'noheader'   => true,
521
-                'capability' => 'ee_read_registrations',
522
-            ),
523
-            'contact_list_export'                 => array(
524
-                'func'       => '_contact_list_export',
525
-                'noheader'   => true,
526
-                'capability' => 'export',
527
-            ),
528
-            'contact_list_report'                 => array(
529
-                'func'       => '_contact_list_report',
530
-                'noheader'   => true,
531
-                'capability' => 'ee_read_contacts',
532
-            ),
533
-        );
534
-    }
535
-
536
-
537
-    protected function _set_page_config()
538
-    {
539
-        $this->_page_config = array(
540
-            'default'           => array(
541
-                'nav'           => array(
542
-                    'label' => esc_html__('Overview', 'event_espresso'),
543
-                    'order' => 5,
544
-                ),
545
-                'help_tabs'     => array(
546
-                    'registrations_overview_help_tab'                       => array(
547
-                        'title'    => esc_html__('Registrations Overview', 'event_espresso'),
548
-                        'filename' => 'registrations_overview',
549
-                    ),
550
-                    'registrations_overview_table_column_headings_help_tab' => array(
551
-                        'title'    => esc_html__('Registrations Table Column Headings', 'event_espresso'),
552
-                        'filename' => 'registrations_overview_table_column_headings',
553
-                    ),
554
-                    'registrations_overview_filters_help_tab'               => array(
555
-                        'title'    => esc_html__('Registration Filters', 'event_espresso'),
556
-                        'filename' => 'registrations_overview_filters',
557
-                    ),
558
-                    'registrations_overview_views_help_tab'                 => array(
559
-                        'title'    => esc_html__('Registration Views', 'event_espresso'),
560
-                        'filename' => 'registrations_overview_views',
561
-                    ),
562
-                    'registrations_regoverview_other_help_tab'              => array(
563
-                        'title'    => esc_html__('Registrations Other', 'event_espresso'),
564
-                        'filename' => 'registrations_overview_other',
565
-                    ),
566
-                ),
567
-                // disabled temporarily. see: https://github.com/eventespresso/eventsmart.com-website/issues/836
568
-                // 'help_tour'     => array('Registration_Overview_Help_Tour'),
569
-                'qtips'         => array('Registration_List_Table_Tips'),
570
-                'list_table'    => 'EE_Registrations_List_Table',
571
-                'require_nonce' => false,
572
-            ),
573
-            'view_registration' => array(
574
-                'nav'           => array(
575
-                    'label'      => esc_html__('REG Details', 'event_espresso'),
576
-                    'order'      => 15,
577
-                    'url'        => isset($this->_req_data['_REG_ID'])
578
-                        ? add_query_arg(array('_REG_ID' => $this->_req_data['_REG_ID']), $this->_current_page_view_url)
579
-                        : $this->_admin_base_url,
580
-                    'persistent' => false,
581
-                ),
582
-                'help_tabs'     => array(
583
-                    'registrations_details_help_tab'                    => array(
584
-                        'title'    => esc_html__('Registration Details', 'event_espresso'),
585
-                        'filename' => 'registrations_details',
586
-                    ),
587
-                    'registrations_details_table_help_tab'              => array(
588
-                        'title'    => esc_html__('Registration Details Table', 'event_espresso'),
589
-                        'filename' => 'registrations_details_table',
590
-                    ),
591
-                    'registrations_details_form_answers_help_tab'       => array(
592
-                        'title'    => esc_html__('Registration Form Answers', 'event_espresso'),
593
-                        'filename' => 'registrations_details_form_answers',
594
-                    ),
595
-                    'registrations_details_registrant_details_help_tab' => array(
596
-                        'title'    => esc_html__('Contact Details', 'event_espresso'),
597
-                        'filename' => 'registrations_details_registrant_details',
598
-                    ),
599
-                ),
600
-                // disabled temporarily. see: https://github.com/eventespresso/eventsmart.com-website/issues/836
601
-                // 'help_tour'     => array('Registration_Details_Help_Tour'),
602
-                'metaboxes'     => array_merge(
603
-                    $this->_default_espresso_metaboxes,
604
-                    array('_registration_details_metaboxes')
605
-                ),
606
-                'require_nonce' => false,
607
-            ),
608
-            'new_registration'  => array(
609
-                'nav'           => array(
610
-                    'label'      => esc_html__('Add New Registration', 'event_espresso'),
611
-                    'url'        => '#',
612
-                    'order'      => 15,
613
-                    'persistent' => false,
614
-                ),
615
-                'metaboxes'     => $this->_default_espresso_metaboxes,
616
-                'labels'        => array(
617
-                    'publishbox' => esc_html__('Save Registration', 'event_espresso'),
618
-                ),
619
-                'require_nonce' => false,
620
-            ),
621
-            'add_new_attendee'  => array(
622
-                'nav'           => array(
623
-                    'label'      => esc_html__('Add Contact', 'event_espresso'),
624
-                    'order'      => 15,
625
-                    'persistent' => false,
626
-                ),
627
-                'metaboxes'     => array_merge(
628
-                    $this->_default_espresso_metaboxes,
629
-                    array('_publish_post_box', 'attendee_editor_metaboxes')
630
-                ),
631
-                'require_nonce' => false,
632
-            ),
633
-            'edit_attendee'     => array(
634
-                'nav'           => array(
635
-                    'label'      => esc_html__('Edit Contact', 'event_espresso'),
636
-                    'order'      => 15,
637
-                    'persistent' => false,
638
-                    'url'        => isset($this->_req_data['ATT_ID'])
639
-                        ? add_query_arg(array('ATT_ID' => $this->_req_data['ATT_ID']), $this->_current_page_view_url)
640
-                        : $this->_admin_base_url,
641
-                ),
642
-                'metaboxes'     => array('attendee_editor_metaboxes'),
643
-                'require_nonce' => false,
644
-            ),
645
-            'contact_list'      => array(
646
-                'nav'           => array(
647
-                    'label' => esc_html__('Contact List', 'event_espresso'),
648
-                    'order' => 20,
649
-                ),
650
-                'list_table'    => 'EE_Attendee_Contact_List_Table',
651
-                'help_tabs'     => array(
652
-                    'registrations_contact_list_help_tab'                       => array(
653
-                        'title'    => esc_html__('Registrations Contact List', 'event_espresso'),
654
-                        'filename' => 'registrations_contact_list',
655
-                    ),
656
-                    'registrations_contact-list_table_column_headings_help_tab' => array(
657
-                        'title'    => esc_html__('Contact List Table Column Headings', 'event_espresso'),
658
-                        'filename' => 'registrations_contact_list_table_column_headings',
659
-                    ),
660
-                    'registrations_contact_list_views_help_tab'                 => array(
661
-                        'title'    => esc_html__('Contact List Views', 'event_espresso'),
662
-                        'filename' => 'registrations_contact_list_views',
663
-                    ),
664
-                    'registrations_contact_list_other_help_tab'                 => array(
665
-                        'title'    => esc_html__('Contact List Other', 'event_espresso'),
666
-                        'filename' => 'registrations_contact_list_other',
667
-                    ),
668
-                ),
669
-                // disabled temporarily. see: https://github.com/eventespresso/eventsmart.com-website/issues/836
670
-                // 'help_tour'     => array('Contact_List_Help_Tour'),
671
-                'metaboxes'     => array(),
672
-                'require_nonce' => false,
673
-            ),
674
-            // override default cpt routes
675
-            'create_new'        => '',
676
-            'edit'              => '',
677
-        );
678
-    }
679
-
680
-
681
-    /**
682
-     * The below methods aren't used by this class currently
683
-     */
684
-    protected function _add_screen_options()
685
-    {
686
-    }
687
-
688
-
689
-    protected function _add_feature_pointers()
690
-    {
691
-    }
692
-
693
-
694
-    public function admin_init()
695
-    {
696
-        EE_Registry::$i18n_js_strings['update_att_qstns'] = esc_html__(
697
-            'click "Update Registration Questions" to save your changes',
698
-            'event_espresso'
699
-        );
700
-    }
701
-
702
-
703
-    public function admin_notices()
704
-    {
705
-    }
706
-
707
-
708
-    public function admin_footer_scripts()
709
-    {
710
-    }
711
-
712
-
713
-    /**
714
-     *        get list of registration statuses
715
-     *
716
-     * @access private
717
-     * @return void
718
-     * @throws EE_Error
719
-     */
720
-    private function _get_registration_status_array()
721
-    {
722
-        self::$_reg_status = EEM_Registration::reg_status_array(array(), true);
723
-    }
724
-
725
-
726
-    /**
727
-     * @throws InvalidArgumentException
728
-     * @throws InvalidDataTypeException
729
-     * @throws InvalidInterfaceException
730
-     * @since 4.10.2.p
731
-     */
732
-    protected function _add_screen_options_default()
733
-    {
734
-        $this->_per_page_screen_option();
735
-    }
736
-
737
-
738
-    /**
739
-     * @throws InvalidArgumentException
740
-     * @throws InvalidDataTypeException
741
-     * @throws InvalidInterfaceException
742
-     * @since 4.10.2.p
743
-     */
744
-    protected function _add_screen_options_contact_list()
745
-    {
746
-        $page_title = $this->_admin_page_title;
747
-        $this->_admin_page_title = esc_html__('Contacts', 'event_espresso');
748
-        $this->_per_page_screen_option();
749
-        $this->_admin_page_title = $page_title;
750
-    }
751
-
752
-
753
-    public function load_scripts_styles()
754
-    {
755
-        // style
756
-        wp_register_style(
757
-            'espresso_reg',
758
-            REG_ASSETS_URL . 'espresso_registrations_admin.css',
759
-            array('ee-admin-css'),
760
-            EVENT_ESPRESSO_VERSION
761
-        );
762
-        wp_enqueue_style('espresso_reg');
763
-        // script
764
-        wp_register_script(
765
-            'espresso_reg',
766
-            REG_ASSETS_URL . 'espresso_registrations_admin.js',
767
-            array('jquery-ui-datepicker', 'jquery-ui-draggable', 'ee_admin_js'),
768
-            EVENT_ESPRESSO_VERSION,
769
-            true
770
-        );
771
-        wp_enqueue_script('espresso_reg');
772
-    }
773
-
774
-
775
-    /**
776
-     * @throws EE_Error
777
-     * @throws InvalidArgumentException
778
-     * @throws InvalidDataTypeException
779
-     * @throws InvalidInterfaceException
780
-     * @throws ReflectionException
781
-     * @since 4.10.2.p
782
-     */
783
-    public function load_scripts_styles_edit_attendee()
784
-    {
785
-        // stuff to only show up on our attendee edit details page.
786
-        $attendee_details_translations = array(
787
-            'att_publish_text' => sprintf(
788
-                /* translators: The date and time */
789
-                wp_strip_all_tags(__('Created on: %s', 'event_espresso')),
790
-                '<b>' . $this->_cpt_model_obj->get_datetime('ATT_created') . '</b>'
791
-            ),
792
-        );
793
-        wp_localize_script('espresso_reg', 'ATTENDEE_DETAILS', $attendee_details_translations);
794
-        wp_enqueue_script('jquery-validate');
795
-    }
796
-
797
-
798
-    /**
799
-     * @throws EE_Error
800
-     * @throws InvalidArgumentException
801
-     * @throws InvalidDataTypeException
802
-     * @throws InvalidInterfaceException
803
-     * @throws ReflectionException
804
-     * @since 4.10.2.p
805
-     */
806
-    public function load_scripts_styles_view_registration()
807
-    {
808
-        // styles
809
-        wp_enqueue_style('espresso-ui-theme');
810
-        // scripts
811
-        $this->_get_reg_custom_questions_form($this->_registration->ID());
812
-        $this->_reg_custom_questions_form->wp_enqueue_scripts(true);
813
-    }
814
-
815
-
816
-    public function load_scripts_styles_contact_list()
817
-    {
818
-        wp_dequeue_style('espresso_reg');
819
-        wp_register_style(
820
-            'espresso_att',
821
-            REG_ASSETS_URL . 'espresso_attendees_admin.css',
822
-            array('ee-admin-css'),
823
-            EVENT_ESPRESSO_VERSION
824
-        );
825
-        wp_enqueue_style('espresso_att');
826
-    }
827
-
828
-
829
-    public function load_scripts_styles_new_registration()
830
-    {
831
-        wp_register_script(
832
-            'ee-spco-for-admin',
833
-            REG_ASSETS_URL . 'spco_for_admin.js',
834
-            array('underscore', 'jquery'),
835
-            EVENT_ESPRESSO_VERSION,
836
-            true
837
-        );
838
-        wp_enqueue_script('ee-spco-for-admin');
839
-        add_filter('FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', '__return_true');
840
-        EE_Form_Section_Proper::wp_enqueue_scripts();
841
-        EED_Ticket_Selector::load_tckt_slctr_assets();
842
-        EE_Datepicker_Input::enqueue_styles_and_scripts();
843
-    }
844
-
845
-
846
-    public function AHEE__EE_Admin_Page__route_admin_request_resend_registration()
847
-    {
848
-        add_filter('FHEE_load_EE_messages', '__return_true');
849
-    }
850
-
851
-
852
-    public function AHEE__EE_Admin_Page__route_admin_request_approve_registration()
853
-    {
854
-        add_filter('FHEE_load_EE_messages', '__return_true');
855
-    }
856
-
857
-
858
-    /**
859
-     * @throws EE_Error
860
-     * @throws InvalidArgumentException
861
-     * @throws InvalidDataTypeException
862
-     * @throws InvalidInterfaceException
863
-     * @throws ReflectionException
864
-     * @since 4.10.2.p
865
-     */
866
-    protected function _set_list_table_views_default()
867
-    {
868
-        // for notification related bulk actions we need to make sure only active messengers have an option.
869
-        EED_Messages::set_autoloaders();
870
-        /** @type EE_Message_Resource_Manager $message_resource_manager */
871
-        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
872
-        $active_mts = $message_resource_manager->list_of_active_message_types();
873
-        // key= bulk_action_slug, value= message type.
874
-        $match_array = array(
875
-            'approve_registrations'    => 'registration',
876
-            'decline_registrations'    => 'declined_registration',
877
-            'pending_registrations'    => 'pending_approval',
878
-            'no_approve_registrations' => 'not_approved_registration',
879
-            'cancel_registrations'     => 'cancelled_registration',
880
-        );
881
-        $can_send = EE_Registry::instance()->CAP->current_user_can(
882
-            'ee_send_message',
883
-            'batch_send_messages'
884
-        );
885
-        /** setup reg status bulk actions **/
886
-        $def_reg_status_actions['approve_registrations'] = esc_html__('Approve Registrations', 'event_espresso');
887
-        if ($can_send && in_array($match_array['approve_registrations'], $active_mts, true)) {
888
-            $def_reg_status_actions['approve_and_notify_registrations'] = esc_html__(
889
-                'Approve and Notify Registrations',
890
-                'event_espresso'
891
-            );
892
-        }
893
-        $def_reg_status_actions['decline_registrations'] = esc_html__('Decline Registrations', 'event_espresso');
894
-        if ($can_send && in_array($match_array['decline_registrations'], $active_mts, true)) {
895
-            $def_reg_status_actions['decline_and_notify_registrations'] = esc_html__(
896
-                'Decline and Notify Registrations',
897
-                'event_espresso'
898
-            );
899
-        }
900
-        $def_reg_status_actions['pending_registrations'] = esc_html__(
901
-            'Set Registrations to Pending Payment',
902
-            'event_espresso'
903
-        );
904
-        if ($can_send && in_array($match_array['pending_registrations'], $active_mts, true)) {
905
-            $def_reg_status_actions['pending_and_notify_registrations'] = esc_html__(
906
-                'Set Registrations to Pending Payment and Notify',
907
-                'event_espresso'
908
-            );
909
-        }
910
-        $def_reg_status_actions['no_approve_registrations'] = esc_html__(
911
-            'Set Registrations to Not Approved',
912
-            'event_espresso'
913
-        );
914
-        if ($can_send && in_array($match_array['no_approve_registrations'], $active_mts, true)) {
915
-            $def_reg_status_actions['no_approve_and_notify_registrations'] = esc_html__(
916
-                'Set Registrations to Not Approved and Notify',
917
-                'event_espresso'
918
-            );
919
-        }
920
-        $def_reg_status_actions['cancel_registrations'] = esc_html__('Cancel Registrations', 'event_espresso');
921
-        if ($can_send && in_array($match_array['cancel_registrations'], $active_mts, true)) {
922
-            $def_reg_status_actions['cancel_and_notify_registrations'] = esc_html__(
923
-                'Cancel Registrations and Notify',
924
-                'event_espresso'
925
-            );
926
-        }
927
-        $def_reg_status_actions = apply_filters(
928
-            'FHEE__Registrations_Admin_Page___set_list_table_views_default__def_reg_status_actions_array',
929
-            $def_reg_status_actions,
930
-            $active_mts,
931
-            $can_send
932
-        );
933
-
934
-        $this->_views = array(
935
-            'all'   => array(
936
-                'slug'        => 'all',
937
-                'label'       => esc_html__('View All Registrations', 'event_espresso'),
938
-                'count'       => 0,
939
-                'bulk_action' => array_merge(
940
-                    $def_reg_status_actions,
941
-                    array(
942
-                        'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
943
-                    )
944
-                ),
945
-            ),
946
-            'month' => array(
947
-                'slug'        => 'month',
948
-                'label'       => esc_html__('This Month', 'event_espresso'),
949
-                'count'       => 0,
950
-                'bulk_action' => array_merge(
951
-                    $def_reg_status_actions,
952
-                    array(
953
-                        'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
954
-                    )
955
-                ),
956
-            ),
957
-            'today' => array(
958
-                'slug'        => 'today',
959
-                'label'       => sprintf(
960
-                    esc_html__('Today - %s', 'event_espresso'),
961
-                    date('M d, Y', current_time('timestamp'))
962
-                ),
963
-                'count'       => 0,
964
-                'bulk_action' => array_merge(
965
-                    $def_reg_status_actions,
966
-                    array(
967
-                        'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
968
-                    )
969
-                ),
970
-            ),
971
-        );
972
-        if (EE_Registry::instance()->CAP->current_user_can(
973
-            'ee_delete_registrations',
974
-            'espresso_registrations_delete_registration'
975
-        )) {
976
-            $this->_views['incomplete'] = array(
977
-                'slug'        => 'incomplete',
978
-                'label'       => esc_html__('Incomplete', 'event_espresso'),
979
-                'count'       => 0,
980
-                'bulk_action' => array(
981
-                    'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
982
-                ),
983
-            );
984
-            $this->_views['trash'] = array(
985
-                'slug'        => 'trash',
986
-                'label'       => esc_html__('Trash', 'event_espresso'),
987
-                'count'       => 0,
988
-                'bulk_action' => array(
989
-                    'restore_registrations' => esc_html__('Restore Registrations', 'event_espresso'),
990
-                    'delete_registrations'  => esc_html__('Delete Registrations Permanently', 'event_espresso'),
991
-                ),
992
-            );
993
-        }
994
-    }
995
-
996
-
997
-    protected function _set_list_table_views_contact_list()
998
-    {
999
-        $this->_views = array(
1000
-            'in_use' => array(
1001
-                'slug'        => 'in_use',
1002
-                'label'       => esc_html__('In Use', 'event_espresso'),
1003
-                'count'       => 0,
1004
-                'bulk_action' => array(
1005
-                    'trash_attendees' => esc_html__('Move to Trash', 'event_espresso'),
1006
-                ),
1007
-            ),
1008
-        );
1009
-        if (EE_Registry::instance()->CAP->current_user_can(
1010
-            'ee_delete_contacts',
1011
-            'espresso_registrations_trash_attendees'
1012
-        )
1013
-        ) {
1014
-            $this->_views['trash'] = array(
1015
-                'slug'        => 'trash',
1016
-                'label'       => esc_html__('Trash', 'event_espresso'),
1017
-                'count'       => 0,
1018
-                'bulk_action' => array(
1019
-                    'restore_attendees' => esc_html__('Restore from Trash', 'event_espresso'),
1020
-                ),
1021
-            );
1022
-        }
1023
-    }
1024
-
1025
-
1026
-    protected function _registration_legend_items()
1027
-    {
1028
-        $fc_items = array(
1029
-            'star-icon'        => array(
1030
-                'class' => 'dashicons dashicons-star-filled lt-blue-icon ee-icon-size-8',
1031
-                'desc'  => esc_html__('This is the Primary Registrant', 'event_espresso'),
1032
-            ),
1033
-            'view_details'     => array(
1034
-                'class' => 'dashicons dashicons-clipboard',
1035
-                'desc'  => esc_html__('View Registration Details', 'event_espresso'),
1036
-            ),
1037
-            'edit_attendee'    => array(
1038
-                'class' => 'ee-icon ee-icon-user-edit ee-icon-size-16',
1039
-                'desc'  => esc_html__('Edit Contact Details', 'event_espresso'),
1040
-            ),
1041
-            'view_transaction' => array(
1042
-                'class' => 'dashicons dashicons-cart',
1043
-                'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
1044
-            ),
1045
-            'view_invoice'     => array(
1046
-                'class' => 'dashicons dashicons-media-spreadsheet',
1047
-                'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
1048
-            ),
1049
-        );
1050
-        if (EE_Registry::instance()->CAP->current_user_can(
1051
-            'ee_send_message',
1052
-            'espresso_registrations_resend_registration'
1053
-        )) {
1054
-            $fc_items['resend_registration'] = array(
1055
-                'class' => 'dashicons dashicons-email-alt',
1056
-                'desc'  => esc_html__('Resend Registration Details', 'event_espresso'),
1057
-            );
1058
-        } else {
1059
-            $fc_items['blank'] = array('class' => 'blank', 'desc' => '');
1060
-        }
1061
-        if (EE_Registry::instance()->CAP->current_user_can(
1062
-            'ee_read_global_messages',
1063
-            'view_filtered_messages'
1064
-        )) {
1065
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
1066
-            if (is_array($related_for_icon) && isset($related_for_icon['css_class'], $related_for_icon['label'])) {
1067
-                $fc_items['view_related_messages'] = array(
1068
-                    'class' => $related_for_icon['css_class'],
1069
-                    'desc'  => $related_for_icon['label'],
1070
-                );
1071
-            }
1072
-        }
1073
-        $sc_items = array(
1074
-            'approved_status'   => array(
1075
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_approved,
1076
-                'desc'  => EEH_Template::pretty_status(
1077
-                    EEM_Registration::status_id_approved,
1078
-                    false,
1079
-                    'sentence'
1080
-                ),
1081
-            ),
1082
-            'pending_status'    => array(
1083
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_pending_payment,
1084
-                'desc'  => EEH_Template::pretty_status(
1085
-                    EEM_Registration::status_id_pending_payment,
1086
-                    false,
1087
-                    'sentence'
1088
-                ),
1089
-            ),
1090
-            'wait_list'         => array(
1091
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_wait_list,
1092
-                'desc'  => EEH_Template::pretty_status(
1093
-                    EEM_Registration::status_id_wait_list,
1094
-                    false,
1095
-                    'sentence'
1096
-                ),
1097
-            ),
1098
-            'incomplete_status' => array(
1099
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_incomplete,
1100
-                'desc'  => EEH_Template::pretty_status(
1101
-                    EEM_Registration::status_id_incomplete,
1102
-                    false,
1103
-                    'sentence'
1104
-                ),
1105
-            ),
1106
-            'not_approved'      => array(
1107
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_not_approved,
1108
-                'desc'  => EEH_Template::pretty_status(
1109
-                    EEM_Registration::status_id_not_approved,
1110
-                    false,
1111
-                    'sentence'
1112
-                ),
1113
-            ),
1114
-            'declined_status'   => array(
1115
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_declined,
1116
-                'desc'  => EEH_Template::pretty_status(
1117
-                    EEM_Registration::status_id_declined,
1118
-                    false,
1119
-                    'sentence'
1120
-                ),
1121
-            ),
1122
-            'cancelled_status'  => array(
1123
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_cancelled,
1124
-                'desc'  => EEH_Template::pretty_status(
1125
-                    EEM_Registration::status_id_cancelled,
1126
-                    false,
1127
-                    'sentence'
1128
-                ),
1129
-            ),
1130
-        );
1131
-        return array_merge($fc_items, $sc_items);
1132
-    }
1133
-
1134
-
1135
-
1136
-    /***************************************        REGISTRATION OVERVIEW        **************************************/
1137
-
1138
-
1139
-
1140
-    /**
1141
-     * @throws DomainException
1142
-     * @throws EE_Error
1143
-     * @throws InvalidArgumentException
1144
-     * @throws InvalidDataTypeException
1145
-     * @throws InvalidInterfaceException
1146
-     * @throws ReflectionException
1147
-     */
1148
-    protected function _registrations_overview_list_table()
1149
-    {
1150
-        $this->appendAddNewRegistrationButtonToPageTitle();
1151
-        $header_text = '';
1152
-        $admin_page_header_decorators = [
1153
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\AttendeeFilterHeader',
1154
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\EventFilterHeader',
1155
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\DateFilterHeader',
1156
-            'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\TicketFilterHeader',
1157
-        ];
1158
-        foreach ($admin_page_header_decorators as $admin_page_header_decorator) {
1159
-            $filter_header_decorator = $this->getLoader()->getNew($admin_page_header_decorator);
1160
-            $header_text = $filter_header_decorator->getHeaderText($header_text);
1161
-        }
1162
-        $this->_template_args['admin_page_header'] = $header_text;
1163
-        $this->_template_args['after_list_table'] = $this->_display_legend($this->_registration_legend_items());
1164
-        $this->display_admin_list_table_page_with_no_sidebar();
1165
-    }
1166
-
1167
-
1168
-    /**
1169
-     * @throws EE_Error
1170
-     * @throws InvalidArgumentException
1171
-     * @throws InvalidDataTypeException
1172
-     * @throws InvalidInterfaceException
1173
-     */
1174
-    private function appendAddNewRegistrationButtonToPageTitle()
1175
-    {
1176
-        $EVT_ID = ! empty($this->_req_data['event_id'])
1177
-            ? absint($this->_req_data['event_id'])
1178
-            : 0;
1179
-        if ($EVT_ID
1180
-            && EE_Registry::instance()->CAP->current_user_can(
1181
-                'ee_edit_registrations',
1182
-                'espresso_registrations_new_registration',
1183
-                $EVT_ID
1184
-            )
1185
-        ) {
1186
-            $this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
1187
-                'new_registration',
1188
-                'add-registrant',
1189
-                array('event_id' => $EVT_ID),
1190
-                'add-new-h2'
1191
-            );
1192
-        }
1193
-    }
1194
-
1195
-
1196
-    /**
1197
-     * This sets the _registration property for the registration details screen
1198
-     *
1199
-     * @access private
1200
-     * @return bool
1201
-     * @throws EE_Error
1202
-     * @throws InvalidArgumentException
1203
-     * @throws InvalidDataTypeException
1204
-     * @throws InvalidInterfaceException
1205
-     */
1206
-    private function _set_registration_object()
1207
-    {
1208
-        // get out if we've already set the object
1209
-        if ($this->_registration instanceof EE_Registration) {
1210
-            return true;
1211
-        }
1212
-        $REG_ID = (! empty($this->_req_data['_REG_ID'])) ? absint($this->_req_data['_REG_ID']) : false;
1213
-        if ($this->_registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID)) {
1214
-            return true;
1215
-        }
1216
-        $error_msg = sprintf(
1217
-            esc_html__(
1218
-                'An error occurred and the details for Registration ID #%s could not be retrieved.',
1219
-                'event_espresso'
1220
-            ),
1221
-            $REG_ID
1222
-        );
1223
-        EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
1224
-        $this->_registration = null;
1225
-        return false;
1226
-    }
1227
-
1228
-
1229
-    /**
1230
-     * Used to retrieve registrations for the list table.
1231
-     *
1232
-     * @param int  $per_page
1233
-     * @param bool $count
1234
-     * @param bool $this_month
1235
-     * @param bool $today
1236
-     * @return EE_Registration[]|int
1237
-     * @throws EE_Error
1238
-     * @throws InvalidArgumentException
1239
-     * @throws InvalidDataTypeException
1240
-     * @throws InvalidInterfaceException
1241
-     */
1242
-    public function get_registrations(
1243
-        $per_page = 10,
1244
-        $count = false,
1245
-        $this_month = false,
1246
-        $today = false
1247
-    ) {
1248
-        if ($this_month) {
1249
-            $this->_req_data['status'] = 'month';
1250
-        }
1251
-        if ($today) {
1252
-            $this->_req_data['status'] = 'today';
1253
-        }
1254
-        $query_params = $this->_get_registration_query_parameters($this->_req_data, $per_page, $count);
1255
-        /**
1256
-         * Override the default groupby added by EEM_Base so that sorts with multiple order bys work as expected
1257
-         *
1258
-         * @link https://events.codebasehq.com/projects/event-espresso/tickets/10093
1259
-         * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1260
-         *                             or if you have the development copy of EE you can view this at the path:
1261
-         *                             /docs/G--Model-System/model-query-params.md
1262
-         */
1263
-        $query_params['group_by'] = '';
1264
-
1265
-        return $count
1266
-            ? $this->getRegistrationModel()->count($query_params)
1267
-            /** @type EE_Registration[] */
1268
-            : $this->getRegistrationModel()->get_all($query_params);
1269
-    }
1270
-
1271
-
1272
-    /**
1273
-     * Retrieves the query parameters to be used by the Registration model for getting registrations.
1274
-     * Note: this listens to values on the request for some of the query parameters.
1275
-     *
1276
-     * @param array $request
1277
-     * @param int   $per_page
1278
-     * @param bool  $count
1279
-     * @return array
1280
-     * @throws EE_Error
1281
-     * @throws InvalidArgumentException
1282
-     * @throws InvalidDataTypeException
1283
-     * @throws InvalidInterfaceException
1284
-     */
1285
-    protected function _get_registration_query_parameters(
1286
-        $request = array(),
1287
-        $per_page = 10,
1288
-        $count = false
1289
-    ) {
1290
-        /** @var EventEspresso\core\domain\services\admin\registrations\list_table\QueryBuilder $list_table_query_builder */
1291
-        $list_table_query_builder = $this->getLoader()->getNew(
1292
-            'EventEspresso\core\domain\services\admin\registrations\list_table\QueryBuilder',
1293
-            [ $request ]
1294
-        );
1295
-        return $list_table_query_builder->getQueryParams($per_page, $count);
1296
-    }
1297
-
1298
-
1299
-    public function get_registration_status_array()
1300
-    {
1301
-        return self::$_reg_status;
1302
-    }
1303
-
1304
-
1305
-
1306
-
1307
-    /***************************************        REGISTRATION DETAILS        ***************************************/
1308
-    /**
1309
-     *        generates HTML for the View Registration Details Admin page
1310
-     *
1311
-     * @access protected
1312
-     * @return void
1313
-     * @throws DomainException
1314
-     * @throws EE_Error
1315
-     * @throws InvalidArgumentException
1316
-     * @throws InvalidDataTypeException
1317
-     * @throws InvalidInterfaceException
1318
-     * @throws EntityNotFoundException
1319
-     * @throws ReflectionException
1320
-     */
1321
-    protected function _registration_details()
1322
-    {
1323
-        $this->_template_args = array();
1324
-        $this->_set_registration_object();
1325
-        if (is_object($this->_registration)) {
1326
-            $transaction = $this->_registration->transaction()
1327
-                ? $this->_registration->transaction()
1328
-                : EE_Transaction::new_instance();
1329
-            $this->_session = $transaction->session_data();
1330
-            $event_id = $this->_registration->event_ID();
1331
-            $this->_template_args['reg_nmbr']['value'] = $this->_registration->ID();
1332
-            $this->_template_args['reg_nmbr']['label'] = esc_html__('Registration Number', 'event_espresso');
1333
-            $this->_template_args['reg_datetime']['value'] = $this->_registration->get_i18n_datetime('REG_date');
1334
-            $this->_template_args['reg_datetime']['label'] = esc_html__('Date', 'event_espresso');
1335
-            $this->_template_args['grand_total'] = $transaction->total();
1336
-            $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
1337
-            // link back to overview
1338
-            $this->_template_args['reg_overview_url'] = REG_ADMIN_URL;
1339
-            $this->_template_args['registration'] = $this->_registration;
1340
-            $this->_template_args['filtered_registrations_link'] = EE_Admin_Page::add_query_args_and_nonce(
1341
-                array(
1342
-                    'action'   => 'default',
1343
-                    'event_id' => $event_id,
1344
-                ),
1345
-                REG_ADMIN_URL
1346
-            );
1347
-            $this->_template_args['filtered_transactions_link'] = EE_Admin_Page::add_query_args_and_nonce(
1348
-                array(
1349
-                    'action' => 'default',
1350
-                    'EVT_ID' => $event_id,
1351
-                    'page'   => 'espresso_transactions',
1352
-                ),
1353
-                admin_url('admin.php')
1354
-            );
1355
-            $this->_template_args['event_link'] = EE_Admin_Page::add_query_args_and_nonce(
1356
-                array(
1357
-                    'page'   => 'espresso_events',
1358
-                    'action' => 'edit',
1359
-                    'post'   => $event_id,
1360
-                ),
1361
-                admin_url('admin.php')
1362
-            );
1363
-            // next and previous links
1364
-            $next_reg = $this->_registration->next(
1365
-                null,
1366
-                array(),
1367
-                'REG_ID'
1368
-            );
1369
-            $this->_template_args['next_registration'] = $next_reg
1370
-                ? $this->_next_link(
1371
-                    EE_Admin_Page::add_query_args_and_nonce(
1372
-                        array(
1373
-                            'action'  => 'view_registration',
1374
-                            '_REG_ID' => $next_reg['REG_ID'],
1375
-                        ),
1376
-                        REG_ADMIN_URL
1377
-                    ),
1378
-                    'dashicons dashicons-arrow-right ee-icon-size-22'
1379
-                )
1380
-                : '';
1381
-            $previous_reg = $this->_registration->previous(
1382
-                null,
1383
-                array(),
1384
-                'REG_ID'
1385
-            );
1386
-            $this->_template_args['previous_registration'] = $previous_reg
1387
-                ? $this->_previous_link(
1388
-                    EE_Admin_Page::add_query_args_and_nonce(
1389
-                        array(
1390
-                            'action'  => 'view_registration',
1391
-                            '_REG_ID' => $previous_reg['REG_ID'],
1392
-                        ),
1393
-                        REG_ADMIN_URL
1394
-                    ),
1395
-                    'dashicons dashicons-arrow-left ee-icon-size-22'
1396
-                )
1397
-                : '';
1398
-            // grab header
1399
-            $template_path = REG_TEMPLATE_PATH . 'reg_admin_details_header.template.php';
1400
-            $this->_template_args['REG_ID'] = $this->_registration->ID();
1401
-            $this->_template_args['admin_page_header'] = EEH_Template::display_template(
1402
-                $template_path,
1403
-                $this->_template_args,
1404
-                true
1405
-            );
1406
-        } else {
1407
-            $this->_template_args['admin_page_header'] = $this->display_espresso_notices();
1408
-        }
1409
-        // the details template wrapper
1410
-        $this->display_admin_page_with_sidebar();
1411
-    }
1412
-
1413
-
1414
-    /**
1415
-     * @throws EE_Error
1416
-     * @throws InvalidArgumentException
1417
-     * @throws InvalidDataTypeException
1418
-     * @throws InvalidInterfaceException
1419
-     * @throws ReflectionException
1420
-     * @since 4.10.2.p
1421
-     */
1422
-    protected function _registration_details_metaboxes()
1423
-    {
1424
-        do_action('AHEE__Registrations_Admin_Page___registration_details_metabox__start', $this);
1425
-        $this->_set_registration_object();
1426
-        $attendee = $this->_registration instanceof EE_Registration ? $this->_registration->attendee() : null;
1427
-        add_meta_box(
1428
-            'edit-reg-status-mbox',
1429
-            esc_html__('Registration Status', 'event_espresso'),
1430
-            array($this, 'set_reg_status_buttons_metabox'),
1431
-            $this->wp_page_slug,
1432
-            'normal',
1433
-            'high'
1434
-        );
1435
-        add_meta_box(
1436
-            'edit-reg-details-mbox',
1437
-            esc_html__('Registration Details', 'event_espresso'),
1438
-            array($this, '_reg_details_meta_box'),
1439
-            $this->wp_page_slug,
1440
-            'normal',
1441
-            'high'
1442
-        );
1443
-        if ($attendee instanceof EE_Attendee
1444
-            && EE_Registry::instance()->CAP->current_user_can(
1445
-                'ee_read_registration',
1446
-                'edit-reg-questions-mbox',
1447
-                $this->_registration->ID()
1448
-            )
1449
-        ) {
1450
-            add_meta_box(
1451
-                'edit-reg-questions-mbox',
1452
-                esc_html__('Registration Form Answers', 'event_espresso'),
1453
-                array($this, '_reg_questions_meta_box'),
1454
-                $this->wp_page_slug,
1455
-                'normal',
1456
-                'high'
1457
-            );
1458
-        }
1459
-        add_meta_box(
1460
-            'edit-reg-registrant-mbox',
1461
-            esc_html__('Contact Details', 'event_espresso'),
1462
-            array($this, '_reg_registrant_side_meta_box'),
1463
-            $this->wp_page_slug,
1464
-            'side',
1465
-            'high'
1466
-        );
1467
-        if ($this->_registration->group_size() > 1) {
1468
-            add_meta_box(
1469
-                'edit-reg-attendees-mbox',
1470
-                esc_html__('Other Registrations in this Transaction', 'event_espresso'),
1471
-                array($this, '_reg_attendees_meta_box'),
1472
-                $this->wp_page_slug,
1473
-                'normal',
1474
-                'high'
1475
-            );
1476
-        }
1477
-    }
1478
-
1479
-
1480
-    /**
1481
-     * set_reg_status_buttons_metabox
1482
-     *
1483
-     * @access protected
1484
-     * @return string
1485
-     * @throws EE_Error
1486
-     * @throws EntityNotFoundException
1487
-     * @throws InvalidArgumentException
1488
-     * @throws InvalidDataTypeException
1489
-     * @throws InvalidInterfaceException
1490
-     * @throws ReflectionException
1491
-     */
1492
-    public function set_reg_status_buttons_metabox()
1493
-    {
1494
-        $this->_set_registration_object();
1495
-        $change_reg_status_form = $this->_generate_reg_status_change_form();
1496
-        echo $change_reg_status_form->form_open(
1497
-            self::add_query_args_and_nonce(
1498
-                array(
1499
-                    'action' => 'change_reg_status',
1500
-                ),
1501
-                REG_ADMIN_URL
1502
-            )
1503
-        );
1504
-        echo $change_reg_status_form->get_html();
1505
-        echo $change_reg_status_form->form_close();
1506
-    }
1507
-
1508
-
1509
-    /**
1510
-     * @return EE_Form_Section_Proper
1511
-     * @throws EE_Error
1512
-     * @throws InvalidArgumentException
1513
-     * @throws InvalidDataTypeException
1514
-     * @throws InvalidInterfaceException
1515
-     * @throws EntityNotFoundException
1516
-     * @throws ReflectionException
1517
-     */
1518
-    protected function _generate_reg_status_change_form()
1519
-    {
1520
-        $reg_status_change_form_array = array(
1521
-            'name'            => 'reg_status_change_form',
1522
-            'html_id'         => 'reg-status-change-form',
1523
-            'layout_strategy' => new EE_Admin_Two_Column_Layout(),
1524
-            'subsections'     => array(
1525
-                'return'             => new EE_Hidden_Input(
1526
-                    array(
1527
-                        'name'    => 'return',
1528
-                        'default' => 'view_registration',
1529
-                    )
1530
-                ),
1531
-                'REG_ID'             => new EE_Hidden_Input(
1532
-                    array(
1533
-                        'name'    => 'REG_ID',
1534
-                        'default' => $this->_registration->ID(),
1535
-                    )
1536
-                ),
1537
-                'current_status'     => new EE_Form_Section_HTML(
1538
-                    EEH_HTML::table(
1539
-                        EEH_HTML::tr(
1540
-                            EEH_HTML::th(
1541
-                                EEH_HTML::label(
1542
-                                    EEH_HTML::strong(
1543
-                                        esc_html__('Current Registration Status', 'event_espresso')
1544
-                                    )
1545
-                                )
1546
-                            )
1547
-                            . EEH_HTML::td(
1548
-                                EEH_HTML::strong(
1549
-                                    $this->_registration->pretty_status(),
1550
-                                    '',
1551
-                                    'status-' . $this->_registration->status_ID(),
1552
-                                    'line-height: 1em; font-size: 1.5em; font-weight: bold;'
1553
-                                )
1554
-                            )
1555
-                        )
1556
-                    )
1557
-                )
1558
-            )
1559
-        );
1560
-        if (EE_Registry::instance()->CAP->current_user_can(
1561
-            'ee_edit_registration',
1562
-            'toggle_registration_status',
1563
-            $this->_registration->ID()
1564
-        )) {
1565
-            $reg_status_change_form_array['subsections']['reg_status'] = new EE_Select_Input(
1566
-                $this->_get_reg_statuses(),
1567
-                array(
1568
-                    'html_label_text' => esc_html__('Change Registration Status to', 'event_espresso'),
1569
-                    'default'         => $this->_registration->status_ID(),
1570
-                )
1571
-            );
1572
-            $reg_status_change_form_array['subsections']['send_notifications'] = new EE_Yes_No_Input(
1573
-                array(
1574
-                    'html_label_text' => esc_html__('Send Related Messages', 'event_espresso'),
1575
-                    'default'         => false,
1576
-                    'html_help_text'  => esc_html__(
1577
-                        'If set to "Yes", then the related messages will be sent to the registrant.',
1578
-                        'event_espresso'
1579
-                    )
1580
-                )
1581
-            );
1582
-            $reg_status_change_form_array['subsections']['submit'] = new EE_Submit_Input(
1583
-                array(
1584
-                    'html_class'      => 'button-primary',
1585
-                    'html_label_text' => '&nbsp;',
1586
-                    'default'         => esc_html__('Update Registration Status', 'event_espresso'),
1587
-                )
1588
-            );
1589
-        }
1590
-        return new EE_Form_Section_Proper($reg_status_change_form_array);
1591
-    }
1592
-
1593
-
1594
-    /**
1595
-     * Returns an array of all the buttons for the various statuses and switch status actions
1596
-     *
1597
-     * @return array
1598
-     * @throws EE_Error
1599
-     * @throws InvalidArgumentException
1600
-     * @throws InvalidDataTypeException
1601
-     * @throws InvalidInterfaceException
1602
-     * @throws EntityNotFoundException
1603
-     */
1604
-    protected function _get_reg_statuses()
1605
-    {
1606
-        $reg_status_array = $this->getRegistrationModel()->reg_status_array();
1607
-        unset($reg_status_array[ EEM_Registration::status_id_incomplete ]);
1608
-        // get current reg status
1609
-        $current_status = $this->_registration->status_ID();
1610
-        // is registration for free event? This will determine whether to display the pending payment option
1611
-        if ($current_status !== EEM_Registration::status_id_pending_payment
1612
-            && EEH_Money::compare_floats($this->_registration->ticket()->price(), 0.00)
1613
-        ) {
1614
-            unset($reg_status_array[ EEM_Registration::status_id_pending_payment ]);
1615
-        }
1616
-        return $this->getStatusModel()->localized_status($reg_status_array, false, 'sentence');
1617
-    }
1618
-
1619
-
1620
-    /**
1621
-     * This method is used when using _REG_ID from request which may or may not be an array of reg_ids.
1622
-     *
1623
-     * @param bool $status REG status given for changing registrations to.
1624
-     * @param bool $notify Whether to send messages notifications or not.
1625
-     * @return array (array with reg_id(s) updated and whether update was successful.
1626
-     * @throws DomainException
1627
-     * @throws EE_Error
1628
-     * @throws EntityNotFoundException
1629
-     * @throws InvalidArgumentException
1630
-     * @throws InvalidDataTypeException
1631
-     * @throws InvalidInterfaceException
1632
-     * @throws ReflectionException
1633
-     * @throws RuntimeException
1634
-     */
1635
-    protected function _set_registration_status_from_request($status = false, $notify = false)
1636
-    {
1637
-        if (isset($this->_req_data['reg_status_change_form'])) {
1638
-            $REG_IDs = isset($this->_req_data['reg_status_change_form']['REG_ID'])
1639
-                ? (array) $this->_req_data['reg_status_change_form']['REG_ID']
1640
-                : array();
1641
-        } else {
1642
-            $REG_IDs = isset($this->_req_data['_REG_ID'])
1643
-                ? (array) $this->_req_data['_REG_ID']
1644
-                : array();
1645
-        }
1646
-        // sanitize $REG_IDs
1647
-        $REG_IDs = array_map('absint', $REG_IDs);
1648
-        // and remove empty entries
1649
-        $REG_IDs = array_filter($REG_IDs);
1650
-
1651
-        $result = $this->_set_registration_status($REG_IDs, $status, $notify);
1652
-
1653
-        /**
1654
-         * Set and filter $_req_data['_REG_ID'] for any potential future messages notifications.
1655
-         * Currently this value is used downstream by the _process_resend_registration method.
1656
-         *
1657
-         * @param int|array                $registration_ids The registration ids that have had their status changed successfully.
1658
-         * @param bool                     $status           The status registrations were changed to.
1659
-         * @param bool                     $success          If the status was changed successfully for all registrations.
1660
-         * @param Registrations_Admin_Page $admin_page_object
1661
-         */
1662
-        $this->_req_data['_REG_ID'] = apply_filters(
1663
-            'FHEE__Registrations_Admin_Page___set_registration_status_from_request__REG_IDs',
1664
-            $result['REG_ID'],
1665
-            $status,
1666
-            $result['success'],
1667
-            $this
1668
-        );
1669
-
1670
-        // notify?
1671
-        if ($notify
1672
-            && $result['success']
1673
-            && ! empty($this->_req_data['_REG_ID'])
1674
-            && EE_Registry::instance()->CAP->current_user_can(
1675
-                'ee_send_message',
1676
-                'espresso_registrations_resend_registration'
1677
-            )
1678
-        ) {
1679
-            $this->_process_resend_registration();
1680
-        }
1681
-        return $result;
1682
-    }
1683
-
1684
-
1685
-    /**
1686
-     * Set the registration status for the given reg_id (which may or may not be an array, it gets typecast to an
1687
-     * array). Note, this method does NOT take care of possible notifications.  That is required by calling code.
1688
-     *
1689
-     * @param array  $REG_IDs
1690
-     * @param string $status
1691
-     * @param bool   $notify  Used to indicate whether notification was requested or not.  This determines the context
1692
-     *                        slug sent with setting the registration status.
1693
-     * @return array (an array with 'success' key representing whether status change was successful, and 'REG_ID' as
1694
-     * @throws EE_Error
1695
-     * @throws InvalidArgumentException
1696
-     * @throws InvalidDataTypeException
1697
-     * @throws InvalidInterfaceException
1698
-     * @throws ReflectionException
1699
-     * @throws RuntimeException
1700
-     * @throws EntityNotFoundException
1701
-     * @throws DomainException
1702
-     */
1703
-    protected function _set_registration_status($REG_IDs = array(), $status = '', $notify = false)
1704
-    {
1705
-        $success = false;
1706
-        // typecast $REG_IDs
1707
-        $REG_IDs = (array) $REG_IDs;
1708
-        if (! empty($REG_IDs)) {
1709
-            $success = true;
1710
-            // set default status if none is passed
1711
-            $status = $status ? $status : EEM_Registration::status_id_pending_payment;
1712
-            $status_context = $notify
1713
-                ? Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN_NOTIFY
1714
-                : Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN;
1715
-            // loop through REG_ID's and change status
1716
-            foreach ($REG_IDs as $REG_ID) {
1717
-                $registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
1718
-                if ($registration instanceof EE_Registration) {
1719
-                    $registration->set_status(
1720
-                        $status,
1721
-                        false,
1722
-                        new Context(
1723
-                            $status_context,
1724
-                            esc_html__(
1725
-                                'Manually triggered status change on a Registration Admin Page route.',
1726
-                                'event_espresso'
1727
-                            )
1728
-                        )
1729
-                    );
1730
-                    $result = $registration->save();
1731
-                    // verifying explicit fails because update *may* just return 0 for 0 rows affected
1732
-                    $success = $result !== false ? $success : false;
1733
-                }
1734
-            }
1735
-        }
1736
-
1737
-        // return $success and processed registrations
1738
-        return array('REG_ID' => $REG_IDs, 'success' => $success);
1739
-    }
1740
-
1741
-
1742
-    /**
1743
-     * Common logic for setting up success message and redirecting to appropriate route
1744
-     *
1745
-     * @param string $STS_ID status id for the registration changed to
1746
-     * @param bool   $notify indicates whether the _set_registration_status_from_request does notifications or not.
1747
-     * @return void
1748
-     * @throws DomainException
1749
-     * @throws EE_Error
1750
-     * @throws EntityNotFoundException
1751
-     * @throws InvalidArgumentException
1752
-     * @throws InvalidDataTypeException
1753
-     * @throws InvalidInterfaceException
1754
-     * @throws ReflectionException
1755
-     * @throws RuntimeException
1756
-     */
1757
-    protected function _reg_status_change_return($STS_ID, $notify = false)
1758
-    {
1759
-        $result = ! empty($STS_ID) ? $this->_set_registration_status_from_request($STS_ID, $notify)
1760
-            : array('success' => false);
1761
-        $success = isset($result['success']) && $result['success'];
1762
-        // setup success message
1763
-        if ($success) {
1764
-            if (is_array($result['REG_ID']) && count($result['REG_ID']) === 1) {
1765
-                $msg = sprintf(
1766
-                    esc_html__('Registration status has been set to %s', 'event_espresso'),
1767
-                    EEH_Template::pretty_status($STS_ID, false, 'lower')
1768
-                );
1769
-            } else {
1770
-                $msg = sprintf(
1771
-                    esc_html__('Registrations have been set to %s.', 'event_espresso'),
1772
-                    EEH_Template::pretty_status($STS_ID, false, 'lower')
1773
-                );
1774
-            }
1775
-            EE_Error::add_success($msg);
1776
-        } else {
1777
-            EE_Error::add_error(
1778
-                esc_html__(
1779
-                    'Something went wrong, and the status was not changed',
1780
-                    'event_espresso'
1781
-                ),
1782
-                __FILE__,
1783
-                __LINE__,
1784
-                __FUNCTION__
1785
-            );
1786
-        }
1787
-        if (isset($this->_req_data['return']) && $this->_req_data['return'] === 'view_registration') {
1788
-            $route = array('action' => 'view_registration', '_REG_ID' => reset($result['REG_ID']));
1789
-        } else {
1790
-            $route = array('action' => 'default');
1791
-        }
1792
-        $route = $this->mergeExistingRequestParamsWithRedirectArgs($route);
1793
-        $this->_redirect_after_action($success, '', '', $route, true);
1794
-    }
1795
-
1796
-
1797
-    /**
1798
-     * incoming reg status change from reg details page.
1799
-     *
1800
-     * @return void
1801
-     * @throws EE_Error
1802
-     * @throws EntityNotFoundException
1803
-     * @throws InvalidArgumentException
1804
-     * @throws InvalidDataTypeException
1805
-     * @throws InvalidInterfaceException
1806
-     * @throws ReflectionException
1807
-     * @throws RuntimeException
1808
-     * @throws DomainException
1809
-     */
1810
-    protected function _change_reg_status()
1811
-    {
1812
-        $this->_req_data['return'] = 'view_registration';
1813
-        // set notify based on whether the send notifications toggle is set or not
1814
-        $notify = ! empty($this->_req_data['reg_status_change_form']['send_notifications']);
1815
-        // $notify = ! empty( $this->_req_data['txn_reg_status_change']['send_notifications'] );
1816
-        $this->_req_data['reg_status_change_form']['reg_status'] = isset($this->_req_data['reg_status_change_form']['reg_status'])
1817
-            ? $this->_req_data['reg_status_change_form']['reg_status'] : '';
1818
-        switch ($this->_req_data['reg_status_change_form']['reg_status']) {
1819
-            case EEM_Registration::status_id_approved:
1820
-            case EEH_Template::pretty_status(EEM_Registration::status_id_approved, false, 'sentence'):
1821
-                $this->approve_registration($notify);
1822
-                break;
1823
-            case EEM_Registration::status_id_pending_payment:
1824
-            case EEH_Template::pretty_status(EEM_Registration::status_id_pending_payment, false, 'sentence'):
1825
-                $this->pending_registration($notify);
1826
-                break;
1827
-            case EEM_Registration::status_id_not_approved:
1828
-            case EEH_Template::pretty_status(EEM_Registration::status_id_not_approved, false, 'sentence'):
1829
-                $this->not_approve_registration($notify);
1830
-                break;
1831
-            case EEM_Registration::status_id_declined:
1832
-            case EEH_Template::pretty_status(EEM_Registration::status_id_declined, false, 'sentence'):
1833
-                $this->decline_registration($notify);
1834
-                break;
1835
-            case EEM_Registration::status_id_cancelled:
1836
-            case EEH_Template::pretty_status(EEM_Registration::status_id_cancelled, false, 'sentence'):
1837
-                $this->cancel_registration($notify);
1838
-                break;
1839
-            case EEM_Registration::status_id_wait_list:
1840
-            case EEH_Template::pretty_status(EEM_Registration::status_id_wait_list, false, 'sentence'):
1841
-                $this->wait_list_registration($notify);
1842
-                break;
1843
-            case EEM_Registration::status_id_incomplete:
1844
-            default:
1845
-                $result['success'] = false;
1846
-                unset($this->_req_data['return']);
1847
-                $this->_reg_status_change_return('', false);
1848
-                break;
1849
-        }
1850
-    }
1851
-
1852
-
1853
-    /**
1854
-     * Callback for bulk action routes.
1855
-     * Note: although we could just register the singular route callbacks for each bulk action route as well, this
1856
-     * method was chosen so there is one central place all the registration status bulk actions are going through.
1857
-     * Potentially, this provides an easier place to locate logic that is specific to these bulk actions (as opposed to
1858
-     * when an action is happening on just a single registration).
1859
-     *
1860
-     * @param      $action
1861
-     * @param bool $notify
1862
-     */
1863
-    protected function bulk_action_on_registrations($action, $notify = false)
1864
-    {
1865
-        do_action(
1866
-            'AHEE__Registrations_Admin_Page__bulk_action_on_registrations__before_execution',
1867
-            $this,
1868
-            $action,
1869
-            $notify
1870
-        );
1871
-        $method = $action . '_registration';
1872
-        if (method_exists($this, $method)) {
1873
-            $this->$method($notify);
1874
-        }
1875
-    }
1876
-
1877
-
1878
-    /**
1879
-     * approve_registration
1880
-     *
1881
-     * @access protected
1882
-     * @param bool $notify whether or not to notify the registrant about their approval.
1883
-     * @return void
1884
-     * @throws EE_Error
1885
-     * @throws EntityNotFoundException
1886
-     * @throws InvalidArgumentException
1887
-     * @throws InvalidDataTypeException
1888
-     * @throws InvalidInterfaceException
1889
-     * @throws ReflectionException
1890
-     * @throws RuntimeException
1891
-     * @throws DomainException
1892
-     */
1893
-    protected function approve_registration($notify = false)
1894
-    {
1895
-        $this->_reg_status_change_return(EEM_Registration::status_id_approved, $notify);
1896
-    }
1897
-
1898
-
1899
-    /**
1900
-     *        decline_registration
1901
-     *
1902
-     * @access protected
1903
-     * @param bool $notify whether or not to notify the registrant about their status change.
1904
-     * @return void
1905
-     * @throws EE_Error
1906
-     * @throws EntityNotFoundException
1907
-     * @throws InvalidArgumentException
1908
-     * @throws InvalidDataTypeException
1909
-     * @throws InvalidInterfaceException
1910
-     * @throws ReflectionException
1911
-     * @throws RuntimeException
1912
-     * @throws DomainException
1913
-     */
1914
-    protected function decline_registration($notify = false)
1915
-    {
1916
-        $this->_reg_status_change_return(EEM_Registration::status_id_declined, $notify);
1917
-    }
1918
-
1919
-
1920
-    /**
1921
-     *        cancel_registration
1922
-     *
1923
-     * @access protected
1924
-     * @param bool $notify whether or not to notify the registrant about their status change.
1925
-     * @return void
1926
-     * @throws EE_Error
1927
-     * @throws EntityNotFoundException
1928
-     * @throws InvalidArgumentException
1929
-     * @throws InvalidDataTypeException
1930
-     * @throws InvalidInterfaceException
1931
-     * @throws ReflectionException
1932
-     * @throws RuntimeException
1933
-     * @throws DomainException
1934
-     */
1935
-    protected function cancel_registration($notify = false)
1936
-    {
1937
-        $this->_reg_status_change_return(EEM_Registration::status_id_cancelled, $notify);
1938
-    }
1939
-
1940
-
1941
-    /**
1942
-     *        not_approve_registration
1943
-     *
1944
-     * @access protected
1945
-     * @param bool $notify whether or not to notify the registrant about their status change.
1946
-     * @return void
1947
-     * @throws EE_Error
1948
-     * @throws EntityNotFoundException
1949
-     * @throws InvalidArgumentException
1950
-     * @throws InvalidDataTypeException
1951
-     * @throws InvalidInterfaceException
1952
-     * @throws ReflectionException
1953
-     * @throws RuntimeException
1954
-     * @throws DomainException
1955
-     */
1956
-    protected function not_approve_registration($notify = false)
1957
-    {
1958
-        $this->_reg_status_change_return(EEM_Registration::status_id_not_approved, $notify);
1959
-    }
1960
-
1961
-
1962
-    /**
1963
-     *        decline_registration
1964
-     *
1965
-     * @access protected
1966
-     * @param bool $notify whether or not to notify the registrant about their status change.
1967
-     * @return void
1968
-     * @throws EE_Error
1969
-     * @throws EntityNotFoundException
1970
-     * @throws InvalidArgumentException
1971
-     * @throws InvalidDataTypeException
1972
-     * @throws InvalidInterfaceException
1973
-     * @throws ReflectionException
1974
-     * @throws RuntimeException
1975
-     * @throws DomainException
1976
-     */
1977
-    protected function pending_registration($notify = false)
1978
-    {
1979
-        $this->_reg_status_change_return(EEM_Registration::status_id_pending_payment, $notify);
1980
-    }
1981
-
1982
-
1983
-    /**
1984
-     * waitlist_registration
1985
-     *
1986
-     * @access protected
1987
-     * @param bool $notify whether or not to notify the registrant about their status change.
1988
-     * @return void
1989
-     * @throws EE_Error
1990
-     * @throws EntityNotFoundException
1991
-     * @throws InvalidArgumentException
1992
-     * @throws InvalidDataTypeException
1993
-     * @throws InvalidInterfaceException
1994
-     * @throws ReflectionException
1995
-     * @throws RuntimeException
1996
-     * @throws DomainException
1997
-     */
1998
-    protected function wait_list_registration($notify = false)
1999
-    {
2000
-        $this->_reg_status_change_return(EEM_Registration::status_id_wait_list, $notify);
2001
-    }
2002
-
2003
-
2004
-    /**
2005
-     *        generates HTML for the Registration main meta box
2006
-     *
2007
-     * @access public
2008
-     * @return void
2009
-     * @throws DomainException
2010
-     * @throws EE_Error
2011
-     * @throws InvalidArgumentException
2012
-     * @throws InvalidDataTypeException
2013
-     * @throws InvalidInterfaceException
2014
-     * @throws ReflectionException
2015
-     * @throws EntityNotFoundException
2016
-     */
2017
-    public function _reg_details_meta_box()
2018
-    {
2019
-        EEH_Autoloader::register_line_item_display_autoloaders();
2020
-        EEH_Autoloader::register_line_item_filter_autoloaders();
2021
-        EE_Registry::instance()->load_helper('Line_Item');
2022
-        $transaction = $this->_registration->transaction() ? $this->_registration->transaction()
2023
-            : EE_Transaction::new_instance();
2024
-        $this->_session = $transaction->session_data();
2025
-        $filters = new EE_Line_Item_Filter_Collection();
2026
-        $filters->add(new EE_Single_Registration_Line_Item_Filter($this->_registration));
2027
-        $filters->add(new EE_Non_Zero_Line_Item_Filter());
2028
-        $line_item_filter_processor = new EE_Line_Item_Filter_Processor(
2029
-            $filters,
2030
-            $transaction->total_line_item()
2031
-        );
2032
-        $filtered_line_item_tree = $line_item_filter_processor->process();
2033
-        $line_item_display = new EE_Line_Item_Display(
2034
-            'reg_admin_table',
2035
-            'EE_Admin_Table_Registration_Line_Item_Display_Strategy'
2036
-        );
2037
-        $this->_template_args['line_item_table'] = $line_item_display->display_line_item(
2038
-            $filtered_line_item_tree,
2039
-            array('EE_Registration' => $this->_registration)
2040
-        );
2041
-        $attendee = $this->_registration->attendee();
2042
-        if (EE_Registry::instance()->CAP->current_user_can(
2043
-            'ee_read_transaction',
2044
-            'espresso_transactions_view_transaction'
2045
-        )) {
2046
-            $this->_template_args['view_transaction_button'] = EEH_Template::get_button_or_link(
2047
-                EE_Admin_Page::add_query_args_and_nonce(
2048
-                    array(
2049
-                        'action' => 'view_transaction',
2050
-                        'TXN_ID' => $transaction->ID(),
2051
-                    ),
2052
-                    TXN_ADMIN_URL
2053
-                ),
2054
-                esc_html__(' View Transaction', 'event_espresso'),
2055
-                'button secondary-button right',
2056
-                'dashicons dashicons-cart'
2057
-            );
2058
-        } else {
2059
-            $this->_template_args['view_transaction_button'] = '';
2060
-        }
2061
-        if ($attendee instanceof EE_Attendee
2062
-            && EE_Registry::instance()->CAP->current_user_can(
2063
-                'ee_send_message',
2064
-                'espresso_registrations_resend_registration'
2065
-            )
2066
-        ) {
2067
-            $this->_template_args['resend_registration_button'] = EEH_Template::get_button_or_link(
2068
-                EE_Admin_Page::add_query_args_and_nonce(
2069
-                    array(
2070
-                        'action'      => 'resend_registration',
2071
-                        '_REG_ID'     => $this->_registration->ID(),
2072
-                        'redirect_to' => 'view_registration',
2073
-                    ),
2074
-                    REG_ADMIN_URL
2075
-                ),
2076
-                esc_html__(' Resend Registration', 'event_espresso'),
2077
-                'button secondary-button right',
2078
-                'dashicons dashicons-email-alt'
2079
-            );
2080
-        } else {
2081
-            $this->_template_args['resend_registration_button'] = '';
2082
-        }
2083
-        $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2084
-        $payment = $transaction->get_first_related('Payment');
2085
-        $payment = ! $payment instanceof EE_Payment
2086
-            ? EE_Payment::new_instance()
2087
-            : $payment;
2088
-        $payment_method = $payment->get_first_related('Payment_Method');
2089
-        $payment_method = ! $payment_method instanceof EE_Payment_Method
2090
-            ? EE_Payment_Method::new_instance()
2091
-            : $payment_method;
2092
-        $reg_details = array(
2093
-            'payment_method'       => $payment_method->name(),
2094
-            'response_msg'         => $payment->gateway_response(),
2095
-            'registration_id'      => $this->_registration->get('REG_code'),
2096
-            'registration_session' => $this->_registration->session_ID(),
2097
-            'ip_address'           => isset($this->_session['ip_address']) ? $this->_session['ip_address'] : '',
2098
-            'user_agent'           => isset($this->_session['user_agent']) ? $this->_session['user_agent'] : '',
2099
-        );
2100
-        if (isset($reg_details['registration_id'])) {
2101
-            $this->_template_args['reg_details']['registration_id']['value'] = $reg_details['registration_id'];
2102
-            $this->_template_args['reg_details']['registration_id']['label'] = esc_html__(
2103
-                'Registration ID',
2104
-                'event_espresso'
2105
-            );
2106
-            $this->_template_args['reg_details']['registration_id']['class'] = 'regular-text';
2107
-        }
2108
-        if (isset($reg_details['payment_method'])) {
2109
-            $this->_template_args['reg_details']['payment_method']['value'] = $reg_details['payment_method'];
2110
-            $this->_template_args['reg_details']['payment_method']['label'] = esc_html__(
2111
-                'Most Recent Payment Method',
2112
-                'event_espresso'
2113
-            );
2114
-            $this->_template_args['reg_details']['payment_method']['class'] = 'regular-text';
2115
-            $this->_template_args['reg_details']['response_msg']['value'] = $reg_details['response_msg'];
2116
-            $this->_template_args['reg_details']['response_msg']['label'] = esc_html__(
2117
-                'Payment method response',
2118
-                'event_espresso'
2119
-            );
2120
-            $this->_template_args['reg_details']['response_msg']['class'] = 'regular-text';
2121
-        }
2122
-        $this->_template_args['reg_details']['registration_session']['value'] = $reg_details['registration_session'];
2123
-        $this->_template_args['reg_details']['registration_session']['label'] = esc_html__(
2124
-            'Registration Session',
2125
-            'event_espresso'
2126
-        );
2127
-        $this->_template_args['reg_details']['registration_session']['class'] = 'regular-text';
2128
-        $this->_template_args['reg_details']['ip_address']['value'] = $reg_details['ip_address'];
2129
-        $this->_template_args['reg_details']['ip_address']['label'] = esc_html__(
2130
-            'Registration placed from IP',
2131
-            'event_espresso'
2132
-        );
2133
-        $this->_template_args['reg_details']['ip_address']['class'] = 'regular-text';
2134
-        $this->_template_args['reg_details']['user_agent']['value'] = $reg_details['user_agent'];
2135
-        $this->_template_args['reg_details']['user_agent']['label'] = esc_html__(
2136
-            'Registrant User Agent',
2137
-            'event_espresso'
2138
-        );
2139
-        $this->_template_args['reg_details']['user_agent']['class'] = 'large-text';
2140
-        $this->_template_args['event_link'] = EE_Admin_Page::add_query_args_and_nonce(
2141
-            array(
2142
-                'action'   => 'default',
2143
-                'event_id' => $this->_registration->event_ID(),
2144
-            ),
2145
-            REG_ADMIN_URL
2146
-        );
2147
-        $this->_template_args['REG_ID'] = $this->_registration->ID();
2148
-        $this->_template_args['event_id'] = $this->_registration->event_ID();
2149
-        $template_path =
2150
-            REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_details.template.php';
2151
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);
2152
-    }
2153
-
2154
-
2155
-    /**
2156
-     * generates HTML for the Registration Questions meta box.
2157
-     * If pre-4.8.32.rc.000 hooks are used, uses old methods (with its filters),
2158
-     * otherwise uses new forms system
2159
-     *
2160
-     * @access public
2161
-     * @return void
2162
-     * @throws DomainException
2163
-     * @throws EE_Error
2164
-     * @throws InvalidArgumentException
2165
-     * @throws InvalidDataTypeException
2166
-     * @throws InvalidInterfaceException
2167
-     * @throws ReflectionException
2168
-     */
2169
-    public function _reg_questions_meta_box()
2170
-    {
2171
-        // allow someone to override this method entirely
2172
-        if (apply_filters(
2173
-            'FHEE__Registrations_Admin_Page___reg_questions_meta_box__do_default',
2174
-            true,
2175
-            $this,
2176
-            $this->_registration
2177
-        )) {
2178
-            $form = $this->_get_reg_custom_questions_form(
2179
-                $this->_registration->ID()
2180
-            );
2181
-            $this->_template_args['att_questions'] = count($form->subforms()) > 0
2182
-                ? $form->get_html_and_js()
2183
-                : '';
2184
-            $this->_template_args['reg_questions_form_action'] = 'edit_registration';
2185
-            $this->_template_args['REG_ID'] = $this->_registration->ID();
2186
-            $template_path =
2187
-                REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_questions.template.php';
2188
-            echo EEH_Template::display_template($template_path, $this->_template_args, true);
2189
-        }
2190
-    }
2191
-
2192
-
2193
-    /**
2194
-     * form_before_question_group
2195
-     *
2196
-     * @deprecated    as of 4.8.32.rc.000
2197
-     * @access        public
2198
-     * @param        string $output
2199
-     * @return        string
2200
-     */
2201
-    public function form_before_question_group($output)
2202
-    {
2203
-        EE_Error::doing_it_wrong(
2204
-            __CLASS__ . '::' . __FUNCTION__,
2205
-            esc_html__(
2206
-                'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2207
-                'event_espresso'
2208
-            ),
2209
-            '4.8.32.rc.000'
2210
-        );
2211
-        return '
22
+	/**
23
+	 * @var EE_Registration
24
+	 */
25
+	private $_registration;
26
+
27
+	/**
28
+	 * @var EE_Event
29
+	 */
30
+	private $_reg_event;
31
+
32
+	/**
33
+	 * @var EE_Session
34
+	 */
35
+	private $_session;
36
+
37
+	private static $_reg_status;
38
+
39
+	/**
40
+	 * Form for displaying the custom questions for this registration.
41
+	 * This gets used a few times throughout the request so its best to cache it
42
+	 *
43
+	 * @var EE_Registration_Custom_Questions_Form
44
+	 */
45
+	protected $_reg_custom_questions_form = null;
46
+
47
+	/**
48
+	 * @var EEM_Registration $registration_model
49
+	 */
50
+	private $registration_model;
51
+
52
+	/**
53
+	 * @var EEM_Attendee $attendee_model
54
+	 */
55
+	private $attendee_model;
56
+
57
+	/**
58
+	 * @var EEM_Event $event_model
59
+	 */
60
+	private $event_model;
61
+
62
+	/**
63
+	 * @var EEM_Status $status_model
64
+	 */
65
+	private $status_model;
66
+
67
+
68
+	/**
69
+	 * @param bool $routing
70
+	 * @throws EE_Error
71
+	 * @throws InvalidArgumentException
72
+	 * @throws InvalidDataTypeException
73
+	 * @throws InvalidInterfaceException
74
+	 * @throws ReflectionException
75
+	 */
76
+	public function __construct($routing = true)
77
+	{
78
+		parent::__construct($routing);
79
+		add_action('wp_loaded', array($this, 'wp_loaded'));
80
+	}
81
+
82
+	/**
83
+	 * @return EEM_Registration
84
+	 * @throws InvalidArgumentException
85
+	 * @throws InvalidDataTypeException
86
+	 * @throws InvalidInterfaceException
87
+	 * @since 4.10.2.p
88
+	 */
89
+	protected function getRegistrationModel()
90
+	{
91
+		if (! $this->registration_model instanceof EEM_Registration) {
92
+			$this->registration_model = $this->getLoader()->getShared('EEM_Registration');
93
+		}
94
+		return $this->registration_model;
95
+	}
96
+
97
+	/**
98
+	 * @return EEM_Attendee
99
+	 * @throws InvalidArgumentException
100
+	 * @throws InvalidDataTypeException
101
+	 * @throws InvalidInterfaceException
102
+	 * @since 4.10.2.p
103
+	 */
104
+	protected function getAttendeeModel()
105
+	{
106
+		if (! $this->attendee_model instanceof EEM_Attendee) {
107
+			$this->attendee_model = $this->getLoader()->getShared('EEM_Attendee');
108
+		}
109
+		return $this->attendee_model;
110
+	}
111
+
112
+
113
+	/**
114
+	 * @return EEM_Event
115
+	 * @throws InvalidArgumentException
116
+	 * @throws InvalidDataTypeException
117
+	 * @throws InvalidInterfaceException
118
+	 * @since 4.10.2.p
119
+	 */
120
+	protected function getEventModel()
121
+	{
122
+		if (! $this->event_model instanceof EEM_Event) {
123
+			$this->event_model = $this->getLoader()->getShared('EEM_Event');
124
+		}
125
+		return $this->event_model;
126
+	}
127
+
128
+	/**
129
+	 * @return EEM_Status
130
+	 * @throws InvalidArgumentException
131
+	 * @throws InvalidDataTypeException
132
+	 * @throws InvalidInterfaceException
133
+	 * @since 4.10.2.p
134
+	 */
135
+	protected function getStatusModel()
136
+	{
137
+		if (! $this->status_model instanceof EEM_Status) {
138
+			$this->status_model = $this->getLoader()->getShared('EEM_Status');
139
+		}
140
+		return $this->status_model;
141
+	}
142
+
143
+
144
+	public function wp_loaded()
145
+	{
146
+		// when adding a new registration...
147
+		if (isset($this->_req_data['action']) && $this->_req_data['action'] === 'new_registration') {
148
+			EE_System::do_not_cache();
149
+			if (! isset($this->_req_data['processing_registration'])
150
+				|| absint($this->_req_data['processing_registration']) !== 1
151
+			) {
152
+				// and it's NOT the attendee information reg step
153
+				// force cookie expiration by setting time to last week
154
+				setcookie('ee_registration_added', 0, time() - WEEK_IN_SECONDS, '/');
155
+				// and update the global
156
+				$_COOKIE['ee_registration_added'] = 0;
157
+			}
158
+		}
159
+	}
160
+
161
+
162
+	protected function _init_page_props()
163
+	{
164
+		$this->page_slug = REG_PG_SLUG;
165
+		$this->_admin_base_url = REG_ADMIN_URL;
166
+		$this->_admin_base_path = REG_ADMIN;
167
+		$this->page_label = esc_html__('Registrations', 'event_espresso');
168
+		$this->_cpt_routes = array(
169
+			'add_new_attendee' => 'espresso_attendees',
170
+			'edit_attendee'    => 'espresso_attendees',
171
+			'insert_attendee'  => 'espresso_attendees',
172
+			'update_attendee'  => 'espresso_attendees',
173
+		);
174
+		$this->_cpt_model_names = array(
175
+			'add_new_attendee' => 'EEM_Attendee',
176
+			'edit_attendee'    => 'EEM_Attendee',
177
+		);
178
+		$this->_cpt_edit_routes = array(
179
+			'espresso_attendees' => 'edit_attendee',
180
+		);
181
+		$this->_pagenow_map = array(
182
+			'add_new_attendee' => 'post-new.php',
183
+			'edit_attendee'    => 'post.php',
184
+			'trash'            => 'post.php',
185
+		);
186
+		add_action('edit_form_after_title', array($this, 'after_title_form_fields'), 10);
187
+		// add filters so that the comment urls don't take users to a confusing 404 page
188
+		add_filter('get_comment_link', array($this, 'clear_comment_link'), 10, 3);
189
+	}
190
+
191
+
192
+	public function clear_comment_link($link, $comment, $args)
193
+	{
194
+		// gotta make sure this only happens on this route
195
+		$post_type = get_post_type($comment->comment_post_ID);
196
+		if ($post_type === 'espresso_attendees') {
197
+			return '#commentsdiv';
198
+		}
199
+		return $link;
200
+	}
201
+
202
+
203
+	protected function _ajax_hooks()
204
+	{
205
+		// todo: all hooks for registrations ajax goes in here
206
+		add_action('wp_ajax_toggle_checkin_status', array($this, 'toggle_checkin_status'));
207
+	}
208
+
209
+
210
+	protected function _define_page_props()
211
+	{
212
+		$this->_admin_page_title = $this->page_label;
213
+		$this->_labels = array(
214
+			'buttons'                      => array(
215
+				'add-registrant'      => esc_html__('Add New Registration', 'event_espresso'),
216
+				'add-attendee'        => esc_html__('Add Contact', 'event_espresso'),
217
+				'edit'                => esc_html__('Edit Contact', 'event_espresso'),
218
+				'report'              => esc_html__('Event Registrations CSV Report', 'event_espresso'),
219
+				'report_all'          => esc_html__('All Registrations CSV Report', 'event_espresso'),
220
+				'report_filtered'     => esc_html__('Filtered CSV Report', 'event_espresso'),
221
+				'contact_list_report' => esc_html__('Contact List Report', 'event_espresso'),
222
+				'contact_list_export' => esc_html__('Export Data', 'event_espresso'),
223
+			),
224
+			'publishbox'                   => array(
225
+				'add_new_attendee' => esc_html__('Add Contact Record', 'event_espresso'),
226
+				'edit_attendee'    => esc_html__('Update Contact Record', 'event_espresso'),
227
+			),
228
+			'hide_add_button_on_cpt_route' => array(
229
+				'edit_attendee' => true,
230
+			),
231
+		);
232
+	}
233
+
234
+
235
+	/**
236
+	 *        grab url requests and route them
237
+	 *
238
+	 * @access private
239
+	 * @return void
240
+	 * @throws EE_Error
241
+	 */
242
+	public function _set_page_routes()
243
+	{
244
+		$this->_get_registration_status_array();
245
+		$reg_id = ! empty($this->_req_data['_REG_ID']) && ! is_array($this->_req_data['_REG_ID'])
246
+			? $this->_req_data['_REG_ID'] : 0;
247
+		$reg_id = empty($reg_id) && ! empty($this->_req_data['reg_status_change_form']['REG_ID'])
248
+			? $this->_req_data['reg_status_change_form']['REG_ID']
249
+			: $reg_id;
250
+		$att_id = ! empty($this->_req_data['ATT_ID']) && ! is_array($this->_req_data['ATT_ID'])
251
+			? $this->_req_data['ATT_ID'] : 0;
252
+		$att_id = ! empty($this->_req_data['post']) && ! is_array($this->_req_data['post'])
253
+			? $this->_req_data['post']
254
+			: $att_id;
255
+		$this->_page_routes = array(
256
+			'default'                             => array(
257
+				'func'       => '_registrations_overview_list_table',
258
+				'capability' => 'ee_read_registrations',
259
+			),
260
+			'view_registration'                   => array(
261
+				'func'       => '_registration_details',
262
+				'capability' => 'ee_read_registration',
263
+				'obj_id'     => $reg_id,
264
+			),
265
+			'edit_registration'                   => array(
266
+				'func'               => '_update_attendee_registration_form',
267
+				'noheader'           => true,
268
+				'headers_sent_route' => 'view_registration',
269
+				'capability'         => 'ee_edit_registration',
270
+				'obj_id'             => $reg_id,
271
+				'_REG_ID'            => $reg_id,
272
+			),
273
+			'trash_registrations'                 => array(
274
+				'func'       => '_trash_or_restore_registrations',
275
+				'args'       => array('trash' => true),
276
+				'noheader'   => true,
277
+				'capability' => 'ee_delete_registrations',
278
+			),
279
+			'restore_registrations'               => array(
280
+				'func'       => '_trash_or_restore_registrations',
281
+				'args'       => array('trash' => false),
282
+				'noheader'   => true,
283
+				'capability' => 'ee_delete_registrations',
284
+			),
285
+			'delete_registrations'                => array(
286
+				'func'       => '_delete_registrations',
287
+				'noheader'   => true,
288
+				'capability' => 'ee_delete_registrations',
289
+			),
290
+			'new_registration'                    => array(
291
+				'func'       => 'new_registration',
292
+				'capability' => 'ee_edit_registrations',
293
+			),
294
+			'process_reg_step'                    => array(
295
+				'func'       => 'process_reg_step',
296
+				'noheader'   => true,
297
+				'capability' => 'ee_edit_registrations',
298
+			),
299
+			'redirect_to_txn'                     => array(
300
+				'func'       => 'redirect_to_txn',
301
+				'noheader'   => true,
302
+				'capability' => 'ee_edit_registrations',
303
+			),
304
+			'change_reg_status'                   => array(
305
+				'func'       => '_change_reg_status',
306
+				'noheader'   => true,
307
+				'capability' => 'ee_edit_registration',
308
+				'obj_id'     => $reg_id,
309
+			),
310
+			'approve_registration'                => array(
311
+				'func'       => 'approve_registration',
312
+				'noheader'   => true,
313
+				'capability' => 'ee_edit_registration',
314
+				'obj_id'     => $reg_id,
315
+			),
316
+			'approve_and_notify_registration'     => array(
317
+				'func'       => 'approve_registration',
318
+				'noheader'   => true,
319
+				'args'       => array(true),
320
+				'capability' => 'ee_edit_registration',
321
+				'obj_id'     => $reg_id,
322
+			),
323
+			'approve_registrations'               => array(
324
+				'func'       => 'bulk_action_on_registrations',
325
+				'noheader'   => true,
326
+				'capability' => 'ee_edit_registrations',
327
+				'args'       => array('approve'),
328
+			),
329
+			'approve_and_notify_registrations'    => array(
330
+				'func'       => 'bulk_action_on_registrations',
331
+				'noheader'   => true,
332
+				'capability' => 'ee_edit_registrations',
333
+				'args'       => array('approve', true),
334
+			),
335
+			'decline_registration'                => array(
336
+				'func'       => 'decline_registration',
337
+				'noheader'   => true,
338
+				'capability' => 'ee_edit_registration',
339
+				'obj_id'     => $reg_id,
340
+			),
341
+			'decline_and_notify_registration'     => array(
342
+				'func'       => 'decline_registration',
343
+				'noheader'   => true,
344
+				'args'       => array(true),
345
+				'capability' => 'ee_edit_registration',
346
+				'obj_id'     => $reg_id,
347
+			),
348
+			'decline_registrations'               => array(
349
+				'func'       => 'bulk_action_on_registrations',
350
+				'noheader'   => true,
351
+				'capability' => 'ee_edit_registrations',
352
+				'args'       => array('decline'),
353
+			),
354
+			'decline_and_notify_registrations'    => array(
355
+				'func'       => 'bulk_action_on_registrations',
356
+				'noheader'   => true,
357
+				'capability' => 'ee_edit_registrations',
358
+				'args'       => array('decline', true),
359
+			),
360
+			'pending_registration'                => array(
361
+				'func'       => 'pending_registration',
362
+				'noheader'   => true,
363
+				'capability' => 'ee_edit_registration',
364
+				'obj_id'     => $reg_id,
365
+			),
366
+			'pending_and_notify_registration'     => array(
367
+				'func'       => 'pending_registration',
368
+				'noheader'   => true,
369
+				'args'       => array(true),
370
+				'capability' => 'ee_edit_registration',
371
+				'obj_id'     => $reg_id,
372
+			),
373
+			'pending_registrations'               => array(
374
+				'func'       => 'bulk_action_on_registrations',
375
+				'noheader'   => true,
376
+				'capability' => 'ee_edit_registrations',
377
+				'args'       => array('pending'),
378
+			),
379
+			'pending_and_notify_registrations'    => array(
380
+				'func'       => 'bulk_action_on_registrations',
381
+				'noheader'   => true,
382
+				'capability' => 'ee_edit_registrations',
383
+				'args'       => array('pending', true),
384
+			),
385
+			'no_approve_registration'             => array(
386
+				'func'       => 'not_approve_registration',
387
+				'noheader'   => true,
388
+				'capability' => 'ee_edit_registration',
389
+				'obj_id'     => $reg_id,
390
+			),
391
+			'no_approve_and_notify_registration'  => array(
392
+				'func'       => 'not_approve_registration',
393
+				'noheader'   => true,
394
+				'args'       => array(true),
395
+				'capability' => 'ee_edit_registration',
396
+				'obj_id'     => $reg_id,
397
+			),
398
+			'no_approve_registrations'            => array(
399
+				'func'       => 'bulk_action_on_registrations',
400
+				'noheader'   => true,
401
+				'capability' => 'ee_edit_registrations',
402
+				'args'       => array('not_approve'),
403
+			),
404
+			'no_approve_and_notify_registrations' => array(
405
+				'func'       => 'bulk_action_on_registrations',
406
+				'noheader'   => true,
407
+				'capability' => 'ee_edit_registrations',
408
+				'args'       => array('not_approve', true),
409
+			),
410
+			'cancel_registration'                 => array(
411
+				'func'       => 'cancel_registration',
412
+				'noheader'   => true,
413
+				'capability' => 'ee_edit_registration',
414
+				'obj_id'     => $reg_id,
415
+			),
416
+			'cancel_and_notify_registration'      => array(
417
+				'func'       => 'cancel_registration',
418
+				'noheader'   => true,
419
+				'args'       => array(true),
420
+				'capability' => 'ee_edit_registration',
421
+				'obj_id'     => $reg_id,
422
+			),
423
+			'cancel_registrations'                => array(
424
+				'func'       => 'bulk_action_on_registrations',
425
+				'noheader'   => true,
426
+				'capability' => 'ee_edit_registrations',
427
+				'args'       => array('cancel'),
428
+			),
429
+			'cancel_and_notify_registrations'     => array(
430
+				'func'       => 'bulk_action_on_registrations',
431
+				'noheader'   => true,
432
+				'capability' => 'ee_edit_registrations',
433
+				'args'       => array('cancel', true),
434
+			),
435
+			'wait_list_registration'              => array(
436
+				'func'       => 'wait_list_registration',
437
+				'noheader'   => true,
438
+				'capability' => 'ee_edit_registration',
439
+				'obj_id'     => $reg_id,
440
+			),
441
+			'wait_list_and_notify_registration'   => array(
442
+				'func'       => 'wait_list_registration',
443
+				'noheader'   => true,
444
+				'args'       => array(true),
445
+				'capability' => 'ee_edit_registration',
446
+				'obj_id'     => $reg_id,
447
+			),
448
+			'contact_list'                        => array(
449
+				'func'       => '_attendee_contact_list_table',
450
+				'capability' => 'ee_read_contacts',
451
+			),
452
+			'add_new_attendee'                    => array(
453
+				'func' => '_create_new_cpt_item',
454
+				'args' => array(
455
+					'new_attendee' => true,
456
+					'capability'   => 'ee_edit_contacts',
457
+				),
458
+			),
459
+			'edit_attendee'                       => array(
460
+				'func'       => '_edit_cpt_item',
461
+				'capability' => 'ee_edit_contacts',
462
+				'obj_id'     => $att_id,
463
+			),
464
+			'duplicate_attendee'                  => array(
465
+				'func'       => '_duplicate_attendee',
466
+				'noheader'   => true,
467
+				'capability' => 'ee_edit_contacts',
468
+				'obj_id'     => $att_id,
469
+			),
470
+			'insert_attendee'                     => array(
471
+				'func'       => '_insert_or_update_attendee',
472
+				'args'       => array(
473
+					'new_attendee' => true,
474
+				),
475
+				'noheader'   => true,
476
+				'capability' => 'ee_edit_contacts',
477
+			),
478
+			'update_attendee'                     => array(
479
+				'func'       => '_insert_or_update_attendee',
480
+				'args'       => array(
481
+					'new_attendee' => false,
482
+				),
483
+				'noheader'   => true,
484
+				'capability' => 'ee_edit_contacts',
485
+				'obj_id'     => $att_id,
486
+			),
487
+			'trash_attendees'                     => array(
488
+				'func'       => '_trash_or_restore_attendees',
489
+				'args'       => array(
490
+					'trash' => 'true',
491
+				),
492
+				'noheader'   => true,
493
+				'capability' => 'ee_delete_contacts',
494
+			),
495
+			'trash_attendee'                      => array(
496
+				'func'       => '_trash_or_restore_attendees',
497
+				'args'       => array(
498
+					'trash' => true,
499
+				),
500
+				'noheader'   => true,
501
+				'capability' => 'ee_delete_contacts',
502
+				'obj_id'     => $att_id,
503
+			),
504
+			'restore_attendees'                   => array(
505
+				'func'       => '_trash_or_restore_attendees',
506
+				'args'       => array(
507
+					'trash' => false,
508
+				),
509
+				'noheader'   => true,
510
+				'capability' => 'ee_delete_contacts',
511
+				'obj_id'     => $att_id,
512
+			),
513
+			'resend_registration'                 => array(
514
+				'func'       => '_resend_registration',
515
+				'noheader'   => true,
516
+				'capability' => 'ee_send_message',
517
+			),
518
+			'registrations_report'                => array(
519
+				'func'       => '_registrations_report',
520
+				'noheader'   => true,
521
+				'capability' => 'ee_read_registrations',
522
+			),
523
+			'contact_list_export'                 => array(
524
+				'func'       => '_contact_list_export',
525
+				'noheader'   => true,
526
+				'capability' => 'export',
527
+			),
528
+			'contact_list_report'                 => array(
529
+				'func'       => '_contact_list_report',
530
+				'noheader'   => true,
531
+				'capability' => 'ee_read_contacts',
532
+			),
533
+		);
534
+	}
535
+
536
+
537
+	protected function _set_page_config()
538
+	{
539
+		$this->_page_config = array(
540
+			'default'           => array(
541
+				'nav'           => array(
542
+					'label' => esc_html__('Overview', 'event_espresso'),
543
+					'order' => 5,
544
+				),
545
+				'help_tabs'     => array(
546
+					'registrations_overview_help_tab'                       => array(
547
+						'title'    => esc_html__('Registrations Overview', 'event_espresso'),
548
+						'filename' => 'registrations_overview',
549
+					),
550
+					'registrations_overview_table_column_headings_help_tab' => array(
551
+						'title'    => esc_html__('Registrations Table Column Headings', 'event_espresso'),
552
+						'filename' => 'registrations_overview_table_column_headings',
553
+					),
554
+					'registrations_overview_filters_help_tab'               => array(
555
+						'title'    => esc_html__('Registration Filters', 'event_espresso'),
556
+						'filename' => 'registrations_overview_filters',
557
+					),
558
+					'registrations_overview_views_help_tab'                 => array(
559
+						'title'    => esc_html__('Registration Views', 'event_espresso'),
560
+						'filename' => 'registrations_overview_views',
561
+					),
562
+					'registrations_regoverview_other_help_tab'              => array(
563
+						'title'    => esc_html__('Registrations Other', 'event_espresso'),
564
+						'filename' => 'registrations_overview_other',
565
+					),
566
+				),
567
+				// disabled temporarily. see: https://github.com/eventespresso/eventsmart.com-website/issues/836
568
+				// 'help_tour'     => array('Registration_Overview_Help_Tour'),
569
+				'qtips'         => array('Registration_List_Table_Tips'),
570
+				'list_table'    => 'EE_Registrations_List_Table',
571
+				'require_nonce' => false,
572
+			),
573
+			'view_registration' => array(
574
+				'nav'           => array(
575
+					'label'      => esc_html__('REG Details', 'event_espresso'),
576
+					'order'      => 15,
577
+					'url'        => isset($this->_req_data['_REG_ID'])
578
+						? add_query_arg(array('_REG_ID' => $this->_req_data['_REG_ID']), $this->_current_page_view_url)
579
+						: $this->_admin_base_url,
580
+					'persistent' => false,
581
+				),
582
+				'help_tabs'     => array(
583
+					'registrations_details_help_tab'                    => array(
584
+						'title'    => esc_html__('Registration Details', 'event_espresso'),
585
+						'filename' => 'registrations_details',
586
+					),
587
+					'registrations_details_table_help_tab'              => array(
588
+						'title'    => esc_html__('Registration Details Table', 'event_espresso'),
589
+						'filename' => 'registrations_details_table',
590
+					),
591
+					'registrations_details_form_answers_help_tab'       => array(
592
+						'title'    => esc_html__('Registration Form Answers', 'event_espresso'),
593
+						'filename' => 'registrations_details_form_answers',
594
+					),
595
+					'registrations_details_registrant_details_help_tab' => array(
596
+						'title'    => esc_html__('Contact Details', 'event_espresso'),
597
+						'filename' => 'registrations_details_registrant_details',
598
+					),
599
+				),
600
+				// disabled temporarily. see: https://github.com/eventespresso/eventsmart.com-website/issues/836
601
+				// 'help_tour'     => array('Registration_Details_Help_Tour'),
602
+				'metaboxes'     => array_merge(
603
+					$this->_default_espresso_metaboxes,
604
+					array('_registration_details_metaboxes')
605
+				),
606
+				'require_nonce' => false,
607
+			),
608
+			'new_registration'  => array(
609
+				'nav'           => array(
610
+					'label'      => esc_html__('Add New Registration', 'event_espresso'),
611
+					'url'        => '#',
612
+					'order'      => 15,
613
+					'persistent' => false,
614
+				),
615
+				'metaboxes'     => $this->_default_espresso_metaboxes,
616
+				'labels'        => array(
617
+					'publishbox' => esc_html__('Save Registration', 'event_espresso'),
618
+				),
619
+				'require_nonce' => false,
620
+			),
621
+			'add_new_attendee'  => array(
622
+				'nav'           => array(
623
+					'label'      => esc_html__('Add Contact', 'event_espresso'),
624
+					'order'      => 15,
625
+					'persistent' => false,
626
+				),
627
+				'metaboxes'     => array_merge(
628
+					$this->_default_espresso_metaboxes,
629
+					array('_publish_post_box', 'attendee_editor_metaboxes')
630
+				),
631
+				'require_nonce' => false,
632
+			),
633
+			'edit_attendee'     => array(
634
+				'nav'           => array(
635
+					'label'      => esc_html__('Edit Contact', 'event_espresso'),
636
+					'order'      => 15,
637
+					'persistent' => false,
638
+					'url'        => isset($this->_req_data['ATT_ID'])
639
+						? add_query_arg(array('ATT_ID' => $this->_req_data['ATT_ID']), $this->_current_page_view_url)
640
+						: $this->_admin_base_url,
641
+				),
642
+				'metaboxes'     => array('attendee_editor_metaboxes'),
643
+				'require_nonce' => false,
644
+			),
645
+			'contact_list'      => array(
646
+				'nav'           => array(
647
+					'label' => esc_html__('Contact List', 'event_espresso'),
648
+					'order' => 20,
649
+				),
650
+				'list_table'    => 'EE_Attendee_Contact_List_Table',
651
+				'help_tabs'     => array(
652
+					'registrations_contact_list_help_tab'                       => array(
653
+						'title'    => esc_html__('Registrations Contact List', 'event_espresso'),
654
+						'filename' => 'registrations_contact_list',
655
+					),
656
+					'registrations_contact-list_table_column_headings_help_tab' => array(
657
+						'title'    => esc_html__('Contact List Table Column Headings', 'event_espresso'),
658
+						'filename' => 'registrations_contact_list_table_column_headings',
659
+					),
660
+					'registrations_contact_list_views_help_tab'                 => array(
661
+						'title'    => esc_html__('Contact List Views', 'event_espresso'),
662
+						'filename' => 'registrations_contact_list_views',
663
+					),
664
+					'registrations_contact_list_other_help_tab'                 => array(
665
+						'title'    => esc_html__('Contact List Other', 'event_espresso'),
666
+						'filename' => 'registrations_contact_list_other',
667
+					),
668
+				),
669
+				// disabled temporarily. see: https://github.com/eventespresso/eventsmart.com-website/issues/836
670
+				// 'help_tour'     => array('Contact_List_Help_Tour'),
671
+				'metaboxes'     => array(),
672
+				'require_nonce' => false,
673
+			),
674
+			// override default cpt routes
675
+			'create_new'        => '',
676
+			'edit'              => '',
677
+		);
678
+	}
679
+
680
+
681
+	/**
682
+	 * The below methods aren't used by this class currently
683
+	 */
684
+	protected function _add_screen_options()
685
+	{
686
+	}
687
+
688
+
689
+	protected function _add_feature_pointers()
690
+	{
691
+	}
692
+
693
+
694
+	public function admin_init()
695
+	{
696
+		EE_Registry::$i18n_js_strings['update_att_qstns'] = esc_html__(
697
+			'click "Update Registration Questions" to save your changes',
698
+			'event_espresso'
699
+		);
700
+	}
701
+
702
+
703
+	public function admin_notices()
704
+	{
705
+	}
706
+
707
+
708
+	public function admin_footer_scripts()
709
+	{
710
+	}
711
+
712
+
713
+	/**
714
+	 *        get list of registration statuses
715
+	 *
716
+	 * @access private
717
+	 * @return void
718
+	 * @throws EE_Error
719
+	 */
720
+	private function _get_registration_status_array()
721
+	{
722
+		self::$_reg_status = EEM_Registration::reg_status_array(array(), true);
723
+	}
724
+
725
+
726
+	/**
727
+	 * @throws InvalidArgumentException
728
+	 * @throws InvalidDataTypeException
729
+	 * @throws InvalidInterfaceException
730
+	 * @since 4.10.2.p
731
+	 */
732
+	protected function _add_screen_options_default()
733
+	{
734
+		$this->_per_page_screen_option();
735
+	}
736
+
737
+
738
+	/**
739
+	 * @throws InvalidArgumentException
740
+	 * @throws InvalidDataTypeException
741
+	 * @throws InvalidInterfaceException
742
+	 * @since 4.10.2.p
743
+	 */
744
+	protected function _add_screen_options_contact_list()
745
+	{
746
+		$page_title = $this->_admin_page_title;
747
+		$this->_admin_page_title = esc_html__('Contacts', 'event_espresso');
748
+		$this->_per_page_screen_option();
749
+		$this->_admin_page_title = $page_title;
750
+	}
751
+
752
+
753
+	public function load_scripts_styles()
754
+	{
755
+		// style
756
+		wp_register_style(
757
+			'espresso_reg',
758
+			REG_ASSETS_URL . 'espresso_registrations_admin.css',
759
+			array('ee-admin-css'),
760
+			EVENT_ESPRESSO_VERSION
761
+		);
762
+		wp_enqueue_style('espresso_reg');
763
+		// script
764
+		wp_register_script(
765
+			'espresso_reg',
766
+			REG_ASSETS_URL . 'espresso_registrations_admin.js',
767
+			array('jquery-ui-datepicker', 'jquery-ui-draggable', 'ee_admin_js'),
768
+			EVENT_ESPRESSO_VERSION,
769
+			true
770
+		);
771
+		wp_enqueue_script('espresso_reg');
772
+	}
773
+
774
+
775
+	/**
776
+	 * @throws EE_Error
777
+	 * @throws InvalidArgumentException
778
+	 * @throws InvalidDataTypeException
779
+	 * @throws InvalidInterfaceException
780
+	 * @throws ReflectionException
781
+	 * @since 4.10.2.p
782
+	 */
783
+	public function load_scripts_styles_edit_attendee()
784
+	{
785
+		// stuff to only show up on our attendee edit details page.
786
+		$attendee_details_translations = array(
787
+			'att_publish_text' => sprintf(
788
+				/* translators: The date and time */
789
+				wp_strip_all_tags(__('Created on: %s', 'event_espresso')),
790
+				'<b>' . $this->_cpt_model_obj->get_datetime('ATT_created') . '</b>'
791
+			),
792
+		);
793
+		wp_localize_script('espresso_reg', 'ATTENDEE_DETAILS', $attendee_details_translations);
794
+		wp_enqueue_script('jquery-validate');
795
+	}
796
+
797
+
798
+	/**
799
+	 * @throws EE_Error
800
+	 * @throws InvalidArgumentException
801
+	 * @throws InvalidDataTypeException
802
+	 * @throws InvalidInterfaceException
803
+	 * @throws ReflectionException
804
+	 * @since 4.10.2.p
805
+	 */
806
+	public function load_scripts_styles_view_registration()
807
+	{
808
+		// styles
809
+		wp_enqueue_style('espresso-ui-theme');
810
+		// scripts
811
+		$this->_get_reg_custom_questions_form($this->_registration->ID());
812
+		$this->_reg_custom_questions_form->wp_enqueue_scripts(true);
813
+	}
814
+
815
+
816
+	public function load_scripts_styles_contact_list()
817
+	{
818
+		wp_dequeue_style('espresso_reg');
819
+		wp_register_style(
820
+			'espresso_att',
821
+			REG_ASSETS_URL . 'espresso_attendees_admin.css',
822
+			array('ee-admin-css'),
823
+			EVENT_ESPRESSO_VERSION
824
+		);
825
+		wp_enqueue_style('espresso_att');
826
+	}
827
+
828
+
829
+	public function load_scripts_styles_new_registration()
830
+	{
831
+		wp_register_script(
832
+			'ee-spco-for-admin',
833
+			REG_ASSETS_URL . 'spco_for_admin.js',
834
+			array('underscore', 'jquery'),
835
+			EVENT_ESPRESSO_VERSION,
836
+			true
837
+		);
838
+		wp_enqueue_script('ee-spco-for-admin');
839
+		add_filter('FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', '__return_true');
840
+		EE_Form_Section_Proper::wp_enqueue_scripts();
841
+		EED_Ticket_Selector::load_tckt_slctr_assets();
842
+		EE_Datepicker_Input::enqueue_styles_and_scripts();
843
+	}
844
+
845
+
846
+	public function AHEE__EE_Admin_Page__route_admin_request_resend_registration()
847
+	{
848
+		add_filter('FHEE_load_EE_messages', '__return_true');
849
+	}
850
+
851
+
852
+	public function AHEE__EE_Admin_Page__route_admin_request_approve_registration()
853
+	{
854
+		add_filter('FHEE_load_EE_messages', '__return_true');
855
+	}
856
+
857
+
858
+	/**
859
+	 * @throws EE_Error
860
+	 * @throws InvalidArgumentException
861
+	 * @throws InvalidDataTypeException
862
+	 * @throws InvalidInterfaceException
863
+	 * @throws ReflectionException
864
+	 * @since 4.10.2.p
865
+	 */
866
+	protected function _set_list_table_views_default()
867
+	{
868
+		// for notification related bulk actions we need to make sure only active messengers have an option.
869
+		EED_Messages::set_autoloaders();
870
+		/** @type EE_Message_Resource_Manager $message_resource_manager */
871
+		$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
872
+		$active_mts = $message_resource_manager->list_of_active_message_types();
873
+		// key= bulk_action_slug, value= message type.
874
+		$match_array = array(
875
+			'approve_registrations'    => 'registration',
876
+			'decline_registrations'    => 'declined_registration',
877
+			'pending_registrations'    => 'pending_approval',
878
+			'no_approve_registrations' => 'not_approved_registration',
879
+			'cancel_registrations'     => 'cancelled_registration',
880
+		);
881
+		$can_send = EE_Registry::instance()->CAP->current_user_can(
882
+			'ee_send_message',
883
+			'batch_send_messages'
884
+		);
885
+		/** setup reg status bulk actions **/
886
+		$def_reg_status_actions['approve_registrations'] = esc_html__('Approve Registrations', 'event_espresso');
887
+		if ($can_send && in_array($match_array['approve_registrations'], $active_mts, true)) {
888
+			$def_reg_status_actions['approve_and_notify_registrations'] = esc_html__(
889
+				'Approve and Notify Registrations',
890
+				'event_espresso'
891
+			);
892
+		}
893
+		$def_reg_status_actions['decline_registrations'] = esc_html__('Decline Registrations', 'event_espresso');
894
+		if ($can_send && in_array($match_array['decline_registrations'], $active_mts, true)) {
895
+			$def_reg_status_actions['decline_and_notify_registrations'] = esc_html__(
896
+				'Decline and Notify Registrations',
897
+				'event_espresso'
898
+			);
899
+		}
900
+		$def_reg_status_actions['pending_registrations'] = esc_html__(
901
+			'Set Registrations to Pending Payment',
902
+			'event_espresso'
903
+		);
904
+		if ($can_send && in_array($match_array['pending_registrations'], $active_mts, true)) {
905
+			$def_reg_status_actions['pending_and_notify_registrations'] = esc_html__(
906
+				'Set Registrations to Pending Payment and Notify',
907
+				'event_espresso'
908
+			);
909
+		}
910
+		$def_reg_status_actions['no_approve_registrations'] = esc_html__(
911
+			'Set Registrations to Not Approved',
912
+			'event_espresso'
913
+		);
914
+		if ($can_send && in_array($match_array['no_approve_registrations'], $active_mts, true)) {
915
+			$def_reg_status_actions['no_approve_and_notify_registrations'] = esc_html__(
916
+				'Set Registrations to Not Approved and Notify',
917
+				'event_espresso'
918
+			);
919
+		}
920
+		$def_reg_status_actions['cancel_registrations'] = esc_html__('Cancel Registrations', 'event_espresso');
921
+		if ($can_send && in_array($match_array['cancel_registrations'], $active_mts, true)) {
922
+			$def_reg_status_actions['cancel_and_notify_registrations'] = esc_html__(
923
+				'Cancel Registrations and Notify',
924
+				'event_espresso'
925
+			);
926
+		}
927
+		$def_reg_status_actions = apply_filters(
928
+			'FHEE__Registrations_Admin_Page___set_list_table_views_default__def_reg_status_actions_array',
929
+			$def_reg_status_actions,
930
+			$active_mts,
931
+			$can_send
932
+		);
933
+
934
+		$this->_views = array(
935
+			'all'   => array(
936
+				'slug'        => 'all',
937
+				'label'       => esc_html__('View All Registrations', 'event_espresso'),
938
+				'count'       => 0,
939
+				'bulk_action' => array_merge(
940
+					$def_reg_status_actions,
941
+					array(
942
+						'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
943
+					)
944
+				),
945
+			),
946
+			'month' => array(
947
+				'slug'        => 'month',
948
+				'label'       => esc_html__('This Month', 'event_espresso'),
949
+				'count'       => 0,
950
+				'bulk_action' => array_merge(
951
+					$def_reg_status_actions,
952
+					array(
953
+						'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
954
+					)
955
+				),
956
+			),
957
+			'today' => array(
958
+				'slug'        => 'today',
959
+				'label'       => sprintf(
960
+					esc_html__('Today - %s', 'event_espresso'),
961
+					date('M d, Y', current_time('timestamp'))
962
+				),
963
+				'count'       => 0,
964
+				'bulk_action' => array_merge(
965
+					$def_reg_status_actions,
966
+					array(
967
+						'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
968
+					)
969
+				),
970
+			),
971
+		);
972
+		if (EE_Registry::instance()->CAP->current_user_can(
973
+			'ee_delete_registrations',
974
+			'espresso_registrations_delete_registration'
975
+		)) {
976
+			$this->_views['incomplete'] = array(
977
+				'slug'        => 'incomplete',
978
+				'label'       => esc_html__('Incomplete', 'event_espresso'),
979
+				'count'       => 0,
980
+				'bulk_action' => array(
981
+					'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
982
+				),
983
+			);
984
+			$this->_views['trash'] = array(
985
+				'slug'        => 'trash',
986
+				'label'       => esc_html__('Trash', 'event_espresso'),
987
+				'count'       => 0,
988
+				'bulk_action' => array(
989
+					'restore_registrations' => esc_html__('Restore Registrations', 'event_espresso'),
990
+					'delete_registrations'  => esc_html__('Delete Registrations Permanently', 'event_espresso'),
991
+				),
992
+			);
993
+		}
994
+	}
995
+
996
+
997
+	protected function _set_list_table_views_contact_list()
998
+	{
999
+		$this->_views = array(
1000
+			'in_use' => array(
1001
+				'slug'        => 'in_use',
1002
+				'label'       => esc_html__('In Use', 'event_espresso'),
1003
+				'count'       => 0,
1004
+				'bulk_action' => array(
1005
+					'trash_attendees' => esc_html__('Move to Trash', 'event_espresso'),
1006
+				),
1007
+			),
1008
+		);
1009
+		if (EE_Registry::instance()->CAP->current_user_can(
1010
+			'ee_delete_contacts',
1011
+			'espresso_registrations_trash_attendees'
1012
+		)
1013
+		) {
1014
+			$this->_views['trash'] = array(
1015
+				'slug'        => 'trash',
1016
+				'label'       => esc_html__('Trash', 'event_espresso'),
1017
+				'count'       => 0,
1018
+				'bulk_action' => array(
1019
+					'restore_attendees' => esc_html__('Restore from Trash', 'event_espresso'),
1020
+				),
1021
+			);
1022
+		}
1023
+	}
1024
+
1025
+
1026
+	protected function _registration_legend_items()
1027
+	{
1028
+		$fc_items = array(
1029
+			'star-icon'        => array(
1030
+				'class' => 'dashicons dashicons-star-filled lt-blue-icon ee-icon-size-8',
1031
+				'desc'  => esc_html__('This is the Primary Registrant', 'event_espresso'),
1032
+			),
1033
+			'view_details'     => array(
1034
+				'class' => 'dashicons dashicons-clipboard',
1035
+				'desc'  => esc_html__('View Registration Details', 'event_espresso'),
1036
+			),
1037
+			'edit_attendee'    => array(
1038
+				'class' => 'ee-icon ee-icon-user-edit ee-icon-size-16',
1039
+				'desc'  => esc_html__('Edit Contact Details', 'event_espresso'),
1040
+			),
1041
+			'view_transaction' => array(
1042
+				'class' => 'dashicons dashicons-cart',
1043
+				'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
1044
+			),
1045
+			'view_invoice'     => array(
1046
+				'class' => 'dashicons dashicons-media-spreadsheet',
1047
+				'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
1048
+			),
1049
+		);
1050
+		if (EE_Registry::instance()->CAP->current_user_can(
1051
+			'ee_send_message',
1052
+			'espresso_registrations_resend_registration'
1053
+		)) {
1054
+			$fc_items['resend_registration'] = array(
1055
+				'class' => 'dashicons dashicons-email-alt',
1056
+				'desc'  => esc_html__('Resend Registration Details', 'event_espresso'),
1057
+			);
1058
+		} else {
1059
+			$fc_items['blank'] = array('class' => 'blank', 'desc' => '');
1060
+		}
1061
+		if (EE_Registry::instance()->CAP->current_user_can(
1062
+			'ee_read_global_messages',
1063
+			'view_filtered_messages'
1064
+		)) {
1065
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
1066
+			if (is_array($related_for_icon) && isset($related_for_icon['css_class'], $related_for_icon['label'])) {
1067
+				$fc_items['view_related_messages'] = array(
1068
+					'class' => $related_for_icon['css_class'],
1069
+					'desc'  => $related_for_icon['label'],
1070
+				);
1071
+			}
1072
+		}
1073
+		$sc_items = array(
1074
+			'approved_status'   => array(
1075
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_approved,
1076
+				'desc'  => EEH_Template::pretty_status(
1077
+					EEM_Registration::status_id_approved,
1078
+					false,
1079
+					'sentence'
1080
+				),
1081
+			),
1082
+			'pending_status'    => array(
1083
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_pending_payment,
1084
+				'desc'  => EEH_Template::pretty_status(
1085
+					EEM_Registration::status_id_pending_payment,
1086
+					false,
1087
+					'sentence'
1088
+				),
1089
+			),
1090
+			'wait_list'         => array(
1091
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_wait_list,
1092
+				'desc'  => EEH_Template::pretty_status(
1093
+					EEM_Registration::status_id_wait_list,
1094
+					false,
1095
+					'sentence'
1096
+				),
1097
+			),
1098
+			'incomplete_status' => array(
1099
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_incomplete,
1100
+				'desc'  => EEH_Template::pretty_status(
1101
+					EEM_Registration::status_id_incomplete,
1102
+					false,
1103
+					'sentence'
1104
+				),
1105
+			),
1106
+			'not_approved'      => array(
1107
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_not_approved,
1108
+				'desc'  => EEH_Template::pretty_status(
1109
+					EEM_Registration::status_id_not_approved,
1110
+					false,
1111
+					'sentence'
1112
+				),
1113
+			),
1114
+			'declined_status'   => array(
1115
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_declined,
1116
+				'desc'  => EEH_Template::pretty_status(
1117
+					EEM_Registration::status_id_declined,
1118
+					false,
1119
+					'sentence'
1120
+				),
1121
+			),
1122
+			'cancelled_status'  => array(
1123
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_cancelled,
1124
+				'desc'  => EEH_Template::pretty_status(
1125
+					EEM_Registration::status_id_cancelled,
1126
+					false,
1127
+					'sentence'
1128
+				),
1129
+			),
1130
+		);
1131
+		return array_merge($fc_items, $sc_items);
1132
+	}
1133
+
1134
+
1135
+
1136
+	/***************************************        REGISTRATION OVERVIEW        **************************************/
1137
+
1138
+
1139
+
1140
+	/**
1141
+	 * @throws DomainException
1142
+	 * @throws EE_Error
1143
+	 * @throws InvalidArgumentException
1144
+	 * @throws InvalidDataTypeException
1145
+	 * @throws InvalidInterfaceException
1146
+	 * @throws ReflectionException
1147
+	 */
1148
+	protected function _registrations_overview_list_table()
1149
+	{
1150
+		$this->appendAddNewRegistrationButtonToPageTitle();
1151
+		$header_text = '';
1152
+		$admin_page_header_decorators = [
1153
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\AttendeeFilterHeader',
1154
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\EventFilterHeader',
1155
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\DateFilterHeader',
1156
+			'EventEspresso\core\domain\services\admin\registrations\list_table\page_header\TicketFilterHeader',
1157
+		];
1158
+		foreach ($admin_page_header_decorators as $admin_page_header_decorator) {
1159
+			$filter_header_decorator = $this->getLoader()->getNew($admin_page_header_decorator);
1160
+			$header_text = $filter_header_decorator->getHeaderText($header_text);
1161
+		}
1162
+		$this->_template_args['admin_page_header'] = $header_text;
1163
+		$this->_template_args['after_list_table'] = $this->_display_legend($this->_registration_legend_items());
1164
+		$this->display_admin_list_table_page_with_no_sidebar();
1165
+	}
1166
+
1167
+
1168
+	/**
1169
+	 * @throws EE_Error
1170
+	 * @throws InvalidArgumentException
1171
+	 * @throws InvalidDataTypeException
1172
+	 * @throws InvalidInterfaceException
1173
+	 */
1174
+	private function appendAddNewRegistrationButtonToPageTitle()
1175
+	{
1176
+		$EVT_ID = ! empty($this->_req_data['event_id'])
1177
+			? absint($this->_req_data['event_id'])
1178
+			: 0;
1179
+		if ($EVT_ID
1180
+			&& EE_Registry::instance()->CAP->current_user_can(
1181
+				'ee_edit_registrations',
1182
+				'espresso_registrations_new_registration',
1183
+				$EVT_ID
1184
+			)
1185
+		) {
1186
+			$this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
1187
+				'new_registration',
1188
+				'add-registrant',
1189
+				array('event_id' => $EVT_ID),
1190
+				'add-new-h2'
1191
+			);
1192
+		}
1193
+	}
1194
+
1195
+
1196
+	/**
1197
+	 * This sets the _registration property for the registration details screen
1198
+	 *
1199
+	 * @access private
1200
+	 * @return bool
1201
+	 * @throws EE_Error
1202
+	 * @throws InvalidArgumentException
1203
+	 * @throws InvalidDataTypeException
1204
+	 * @throws InvalidInterfaceException
1205
+	 */
1206
+	private function _set_registration_object()
1207
+	{
1208
+		// get out if we've already set the object
1209
+		if ($this->_registration instanceof EE_Registration) {
1210
+			return true;
1211
+		}
1212
+		$REG_ID = (! empty($this->_req_data['_REG_ID'])) ? absint($this->_req_data['_REG_ID']) : false;
1213
+		if ($this->_registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID)) {
1214
+			return true;
1215
+		}
1216
+		$error_msg = sprintf(
1217
+			esc_html__(
1218
+				'An error occurred and the details for Registration ID #%s could not be retrieved.',
1219
+				'event_espresso'
1220
+			),
1221
+			$REG_ID
1222
+		);
1223
+		EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
1224
+		$this->_registration = null;
1225
+		return false;
1226
+	}
1227
+
1228
+
1229
+	/**
1230
+	 * Used to retrieve registrations for the list table.
1231
+	 *
1232
+	 * @param int  $per_page
1233
+	 * @param bool $count
1234
+	 * @param bool $this_month
1235
+	 * @param bool $today
1236
+	 * @return EE_Registration[]|int
1237
+	 * @throws EE_Error
1238
+	 * @throws InvalidArgumentException
1239
+	 * @throws InvalidDataTypeException
1240
+	 * @throws InvalidInterfaceException
1241
+	 */
1242
+	public function get_registrations(
1243
+		$per_page = 10,
1244
+		$count = false,
1245
+		$this_month = false,
1246
+		$today = false
1247
+	) {
1248
+		if ($this_month) {
1249
+			$this->_req_data['status'] = 'month';
1250
+		}
1251
+		if ($today) {
1252
+			$this->_req_data['status'] = 'today';
1253
+		}
1254
+		$query_params = $this->_get_registration_query_parameters($this->_req_data, $per_page, $count);
1255
+		/**
1256
+		 * Override the default groupby added by EEM_Base so that sorts with multiple order bys work as expected
1257
+		 *
1258
+		 * @link https://events.codebasehq.com/projects/event-espresso/tickets/10093
1259
+		 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1260
+		 *                             or if you have the development copy of EE you can view this at the path:
1261
+		 *                             /docs/G--Model-System/model-query-params.md
1262
+		 */
1263
+		$query_params['group_by'] = '';
1264
+
1265
+		return $count
1266
+			? $this->getRegistrationModel()->count($query_params)
1267
+			/** @type EE_Registration[] */
1268
+			: $this->getRegistrationModel()->get_all($query_params);
1269
+	}
1270
+
1271
+
1272
+	/**
1273
+	 * Retrieves the query parameters to be used by the Registration model for getting registrations.
1274
+	 * Note: this listens to values on the request for some of the query parameters.
1275
+	 *
1276
+	 * @param array $request
1277
+	 * @param int   $per_page
1278
+	 * @param bool  $count
1279
+	 * @return array
1280
+	 * @throws EE_Error
1281
+	 * @throws InvalidArgumentException
1282
+	 * @throws InvalidDataTypeException
1283
+	 * @throws InvalidInterfaceException
1284
+	 */
1285
+	protected function _get_registration_query_parameters(
1286
+		$request = array(),
1287
+		$per_page = 10,
1288
+		$count = false
1289
+	) {
1290
+		/** @var EventEspresso\core\domain\services\admin\registrations\list_table\QueryBuilder $list_table_query_builder */
1291
+		$list_table_query_builder = $this->getLoader()->getNew(
1292
+			'EventEspresso\core\domain\services\admin\registrations\list_table\QueryBuilder',
1293
+			[ $request ]
1294
+		);
1295
+		return $list_table_query_builder->getQueryParams($per_page, $count);
1296
+	}
1297
+
1298
+
1299
+	public function get_registration_status_array()
1300
+	{
1301
+		return self::$_reg_status;
1302
+	}
1303
+
1304
+
1305
+
1306
+
1307
+	/***************************************        REGISTRATION DETAILS        ***************************************/
1308
+	/**
1309
+	 *        generates HTML for the View Registration Details Admin page
1310
+	 *
1311
+	 * @access protected
1312
+	 * @return void
1313
+	 * @throws DomainException
1314
+	 * @throws EE_Error
1315
+	 * @throws InvalidArgumentException
1316
+	 * @throws InvalidDataTypeException
1317
+	 * @throws InvalidInterfaceException
1318
+	 * @throws EntityNotFoundException
1319
+	 * @throws ReflectionException
1320
+	 */
1321
+	protected function _registration_details()
1322
+	{
1323
+		$this->_template_args = array();
1324
+		$this->_set_registration_object();
1325
+		if (is_object($this->_registration)) {
1326
+			$transaction = $this->_registration->transaction()
1327
+				? $this->_registration->transaction()
1328
+				: EE_Transaction::new_instance();
1329
+			$this->_session = $transaction->session_data();
1330
+			$event_id = $this->_registration->event_ID();
1331
+			$this->_template_args['reg_nmbr']['value'] = $this->_registration->ID();
1332
+			$this->_template_args['reg_nmbr']['label'] = esc_html__('Registration Number', 'event_espresso');
1333
+			$this->_template_args['reg_datetime']['value'] = $this->_registration->get_i18n_datetime('REG_date');
1334
+			$this->_template_args['reg_datetime']['label'] = esc_html__('Date', 'event_espresso');
1335
+			$this->_template_args['grand_total'] = $transaction->total();
1336
+			$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
1337
+			// link back to overview
1338
+			$this->_template_args['reg_overview_url'] = REG_ADMIN_URL;
1339
+			$this->_template_args['registration'] = $this->_registration;
1340
+			$this->_template_args['filtered_registrations_link'] = EE_Admin_Page::add_query_args_and_nonce(
1341
+				array(
1342
+					'action'   => 'default',
1343
+					'event_id' => $event_id,
1344
+				),
1345
+				REG_ADMIN_URL
1346
+			);
1347
+			$this->_template_args['filtered_transactions_link'] = EE_Admin_Page::add_query_args_and_nonce(
1348
+				array(
1349
+					'action' => 'default',
1350
+					'EVT_ID' => $event_id,
1351
+					'page'   => 'espresso_transactions',
1352
+				),
1353
+				admin_url('admin.php')
1354
+			);
1355
+			$this->_template_args['event_link'] = EE_Admin_Page::add_query_args_and_nonce(
1356
+				array(
1357
+					'page'   => 'espresso_events',
1358
+					'action' => 'edit',
1359
+					'post'   => $event_id,
1360
+				),
1361
+				admin_url('admin.php')
1362
+			);
1363
+			// next and previous links
1364
+			$next_reg = $this->_registration->next(
1365
+				null,
1366
+				array(),
1367
+				'REG_ID'
1368
+			);
1369
+			$this->_template_args['next_registration'] = $next_reg
1370
+				? $this->_next_link(
1371
+					EE_Admin_Page::add_query_args_and_nonce(
1372
+						array(
1373
+							'action'  => 'view_registration',
1374
+							'_REG_ID' => $next_reg['REG_ID'],
1375
+						),
1376
+						REG_ADMIN_URL
1377
+					),
1378
+					'dashicons dashicons-arrow-right ee-icon-size-22'
1379
+				)
1380
+				: '';
1381
+			$previous_reg = $this->_registration->previous(
1382
+				null,
1383
+				array(),
1384
+				'REG_ID'
1385
+			);
1386
+			$this->_template_args['previous_registration'] = $previous_reg
1387
+				? $this->_previous_link(
1388
+					EE_Admin_Page::add_query_args_and_nonce(
1389
+						array(
1390
+							'action'  => 'view_registration',
1391
+							'_REG_ID' => $previous_reg['REG_ID'],
1392
+						),
1393
+						REG_ADMIN_URL
1394
+					),
1395
+					'dashicons dashicons-arrow-left ee-icon-size-22'
1396
+				)
1397
+				: '';
1398
+			// grab header
1399
+			$template_path = REG_TEMPLATE_PATH . 'reg_admin_details_header.template.php';
1400
+			$this->_template_args['REG_ID'] = $this->_registration->ID();
1401
+			$this->_template_args['admin_page_header'] = EEH_Template::display_template(
1402
+				$template_path,
1403
+				$this->_template_args,
1404
+				true
1405
+			);
1406
+		} else {
1407
+			$this->_template_args['admin_page_header'] = $this->display_espresso_notices();
1408
+		}
1409
+		// the details template wrapper
1410
+		$this->display_admin_page_with_sidebar();
1411
+	}
1412
+
1413
+
1414
+	/**
1415
+	 * @throws EE_Error
1416
+	 * @throws InvalidArgumentException
1417
+	 * @throws InvalidDataTypeException
1418
+	 * @throws InvalidInterfaceException
1419
+	 * @throws ReflectionException
1420
+	 * @since 4.10.2.p
1421
+	 */
1422
+	protected function _registration_details_metaboxes()
1423
+	{
1424
+		do_action('AHEE__Registrations_Admin_Page___registration_details_metabox__start', $this);
1425
+		$this->_set_registration_object();
1426
+		$attendee = $this->_registration instanceof EE_Registration ? $this->_registration->attendee() : null;
1427
+		add_meta_box(
1428
+			'edit-reg-status-mbox',
1429
+			esc_html__('Registration Status', 'event_espresso'),
1430
+			array($this, 'set_reg_status_buttons_metabox'),
1431
+			$this->wp_page_slug,
1432
+			'normal',
1433
+			'high'
1434
+		);
1435
+		add_meta_box(
1436
+			'edit-reg-details-mbox',
1437
+			esc_html__('Registration Details', 'event_espresso'),
1438
+			array($this, '_reg_details_meta_box'),
1439
+			$this->wp_page_slug,
1440
+			'normal',
1441
+			'high'
1442
+		);
1443
+		if ($attendee instanceof EE_Attendee
1444
+			&& EE_Registry::instance()->CAP->current_user_can(
1445
+				'ee_read_registration',
1446
+				'edit-reg-questions-mbox',
1447
+				$this->_registration->ID()
1448
+			)
1449
+		) {
1450
+			add_meta_box(
1451
+				'edit-reg-questions-mbox',
1452
+				esc_html__('Registration Form Answers', 'event_espresso'),
1453
+				array($this, '_reg_questions_meta_box'),
1454
+				$this->wp_page_slug,
1455
+				'normal',
1456
+				'high'
1457
+			);
1458
+		}
1459
+		add_meta_box(
1460
+			'edit-reg-registrant-mbox',
1461
+			esc_html__('Contact Details', 'event_espresso'),
1462
+			array($this, '_reg_registrant_side_meta_box'),
1463
+			$this->wp_page_slug,
1464
+			'side',
1465
+			'high'
1466
+		);
1467
+		if ($this->_registration->group_size() > 1) {
1468
+			add_meta_box(
1469
+				'edit-reg-attendees-mbox',
1470
+				esc_html__('Other Registrations in this Transaction', 'event_espresso'),
1471
+				array($this, '_reg_attendees_meta_box'),
1472
+				$this->wp_page_slug,
1473
+				'normal',
1474
+				'high'
1475
+			);
1476
+		}
1477
+	}
1478
+
1479
+
1480
+	/**
1481
+	 * set_reg_status_buttons_metabox
1482
+	 *
1483
+	 * @access protected
1484
+	 * @return string
1485
+	 * @throws EE_Error
1486
+	 * @throws EntityNotFoundException
1487
+	 * @throws InvalidArgumentException
1488
+	 * @throws InvalidDataTypeException
1489
+	 * @throws InvalidInterfaceException
1490
+	 * @throws ReflectionException
1491
+	 */
1492
+	public function set_reg_status_buttons_metabox()
1493
+	{
1494
+		$this->_set_registration_object();
1495
+		$change_reg_status_form = $this->_generate_reg_status_change_form();
1496
+		echo $change_reg_status_form->form_open(
1497
+			self::add_query_args_and_nonce(
1498
+				array(
1499
+					'action' => 'change_reg_status',
1500
+				),
1501
+				REG_ADMIN_URL
1502
+			)
1503
+		);
1504
+		echo $change_reg_status_form->get_html();
1505
+		echo $change_reg_status_form->form_close();
1506
+	}
1507
+
1508
+
1509
+	/**
1510
+	 * @return EE_Form_Section_Proper
1511
+	 * @throws EE_Error
1512
+	 * @throws InvalidArgumentException
1513
+	 * @throws InvalidDataTypeException
1514
+	 * @throws InvalidInterfaceException
1515
+	 * @throws EntityNotFoundException
1516
+	 * @throws ReflectionException
1517
+	 */
1518
+	protected function _generate_reg_status_change_form()
1519
+	{
1520
+		$reg_status_change_form_array = array(
1521
+			'name'            => 'reg_status_change_form',
1522
+			'html_id'         => 'reg-status-change-form',
1523
+			'layout_strategy' => new EE_Admin_Two_Column_Layout(),
1524
+			'subsections'     => array(
1525
+				'return'             => new EE_Hidden_Input(
1526
+					array(
1527
+						'name'    => 'return',
1528
+						'default' => 'view_registration',
1529
+					)
1530
+				),
1531
+				'REG_ID'             => new EE_Hidden_Input(
1532
+					array(
1533
+						'name'    => 'REG_ID',
1534
+						'default' => $this->_registration->ID(),
1535
+					)
1536
+				),
1537
+				'current_status'     => new EE_Form_Section_HTML(
1538
+					EEH_HTML::table(
1539
+						EEH_HTML::tr(
1540
+							EEH_HTML::th(
1541
+								EEH_HTML::label(
1542
+									EEH_HTML::strong(
1543
+										esc_html__('Current Registration Status', 'event_espresso')
1544
+									)
1545
+								)
1546
+							)
1547
+							. EEH_HTML::td(
1548
+								EEH_HTML::strong(
1549
+									$this->_registration->pretty_status(),
1550
+									'',
1551
+									'status-' . $this->_registration->status_ID(),
1552
+									'line-height: 1em; font-size: 1.5em; font-weight: bold;'
1553
+								)
1554
+							)
1555
+						)
1556
+					)
1557
+				)
1558
+			)
1559
+		);
1560
+		if (EE_Registry::instance()->CAP->current_user_can(
1561
+			'ee_edit_registration',
1562
+			'toggle_registration_status',
1563
+			$this->_registration->ID()
1564
+		)) {
1565
+			$reg_status_change_form_array['subsections']['reg_status'] = new EE_Select_Input(
1566
+				$this->_get_reg_statuses(),
1567
+				array(
1568
+					'html_label_text' => esc_html__('Change Registration Status to', 'event_espresso'),
1569
+					'default'         => $this->_registration->status_ID(),
1570
+				)
1571
+			);
1572
+			$reg_status_change_form_array['subsections']['send_notifications'] = new EE_Yes_No_Input(
1573
+				array(
1574
+					'html_label_text' => esc_html__('Send Related Messages', 'event_espresso'),
1575
+					'default'         => false,
1576
+					'html_help_text'  => esc_html__(
1577
+						'If set to "Yes", then the related messages will be sent to the registrant.',
1578
+						'event_espresso'
1579
+					)
1580
+				)
1581
+			);
1582
+			$reg_status_change_form_array['subsections']['submit'] = new EE_Submit_Input(
1583
+				array(
1584
+					'html_class'      => 'button-primary',
1585
+					'html_label_text' => '&nbsp;',
1586
+					'default'         => esc_html__('Update Registration Status', 'event_espresso'),
1587
+				)
1588
+			);
1589
+		}
1590
+		return new EE_Form_Section_Proper($reg_status_change_form_array);
1591
+	}
1592
+
1593
+
1594
+	/**
1595
+	 * Returns an array of all the buttons for the various statuses and switch status actions
1596
+	 *
1597
+	 * @return array
1598
+	 * @throws EE_Error
1599
+	 * @throws InvalidArgumentException
1600
+	 * @throws InvalidDataTypeException
1601
+	 * @throws InvalidInterfaceException
1602
+	 * @throws EntityNotFoundException
1603
+	 */
1604
+	protected function _get_reg_statuses()
1605
+	{
1606
+		$reg_status_array = $this->getRegistrationModel()->reg_status_array();
1607
+		unset($reg_status_array[ EEM_Registration::status_id_incomplete ]);
1608
+		// get current reg status
1609
+		$current_status = $this->_registration->status_ID();
1610
+		// is registration for free event? This will determine whether to display the pending payment option
1611
+		if ($current_status !== EEM_Registration::status_id_pending_payment
1612
+			&& EEH_Money::compare_floats($this->_registration->ticket()->price(), 0.00)
1613
+		) {
1614
+			unset($reg_status_array[ EEM_Registration::status_id_pending_payment ]);
1615
+		}
1616
+		return $this->getStatusModel()->localized_status($reg_status_array, false, 'sentence');
1617
+	}
1618
+
1619
+
1620
+	/**
1621
+	 * This method is used when using _REG_ID from request which may or may not be an array of reg_ids.
1622
+	 *
1623
+	 * @param bool $status REG status given for changing registrations to.
1624
+	 * @param bool $notify Whether to send messages notifications or not.
1625
+	 * @return array (array with reg_id(s) updated and whether update was successful.
1626
+	 * @throws DomainException
1627
+	 * @throws EE_Error
1628
+	 * @throws EntityNotFoundException
1629
+	 * @throws InvalidArgumentException
1630
+	 * @throws InvalidDataTypeException
1631
+	 * @throws InvalidInterfaceException
1632
+	 * @throws ReflectionException
1633
+	 * @throws RuntimeException
1634
+	 */
1635
+	protected function _set_registration_status_from_request($status = false, $notify = false)
1636
+	{
1637
+		if (isset($this->_req_data['reg_status_change_form'])) {
1638
+			$REG_IDs = isset($this->_req_data['reg_status_change_form']['REG_ID'])
1639
+				? (array) $this->_req_data['reg_status_change_form']['REG_ID']
1640
+				: array();
1641
+		} else {
1642
+			$REG_IDs = isset($this->_req_data['_REG_ID'])
1643
+				? (array) $this->_req_data['_REG_ID']
1644
+				: array();
1645
+		}
1646
+		// sanitize $REG_IDs
1647
+		$REG_IDs = array_map('absint', $REG_IDs);
1648
+		// and remove empty entries
1649
+		$REG_IDs = array_filter($REG_IDs);
1650
+
1651
+		$result = $this->_set_registration_status($REG_IDs, $status, $notify);
1652
+
1653
+		/**
1654
+		 * Set and filter $_req_data['_REG_ID'] for any potential future messages notifications.
1655
+		 * Currently this value is used downstream by the _process_resend_registration method.
1656
+		 *
1657
+		 * @param int|array                $registration_ids The registration ids that have had their status changed successfully.
1658
+		 * @param bool                     $status           The status registrations were changed to.
1659
+		 * @param bool                     $success          If the status was changed successfully for all registrations.
1660
+		 * @param Registrations_Admin_Page $admin_page_object
1661
+		 */
1662
+		$this->_req_data['_REG_ID'] = apply_filters(
1663
+			'FHEE__Registrations_Admin_Page___set_registration_status_from_request__REG_IDs',
1664
+			$result['REG_ID'],
1665
+			$status,
1666
+			$result['success'],
1667
+			$this
1668
+		);
1669
+
1670
+		// notify?
1671
+		if ($notify
1672
+			&& $result['success']
1673
+			&& ! empty($this->_req_data['_REG_ID'])
1674
+			&& EE_Registry::instance()->CAP->current_user_can(
1675
+				'ee_send_message',
1676
+				'espresso_registrations_resend_registration'
1677
+			)
1678
+		) {
1679
+			$this->_process_resend_registration();
1680
+		}
1681
+		return $result;
1682
+	}
1683
+
1684
+
1685
+	/**
1686
+	 * Set the registration status for the given reg_id (which may or may not be an array, it gets typecast to an
1687
+	 * array). Note, this method does NOT take care of possible notifications.  That is required by calling code.
1688
+	 *
1689
+	 * @param array  $REG_IDs
1690
+	 * @param string $status
1691
+	 * @param bool   $notify  Used to indicate whether notification was requested or not.  This determines the context
1692
+	 *                        slug sent with setting the registration status.
1693
+	 * @return array (an array with 'success' key representing whether status change was successful, and 'REG_ID' as
1694
+	 * @throws EE_Error
1695
+	 * @throws InvalidArgumentException
1696
+	 * @throws InvalidDataTypeException
1697
+	 * @throws InvalidInterfaceException
1698
+	 * @throws ReflectionException
1699
+	 * @throws RuntimeException
1700
+	 * @throws EntityNotFoundException
1701
+	 * @throws DomainException
1702
+	 */
1703
+	protected function _set_registration_status($REG_IDs = array(), $status = '', $notify = false)
1704
+	{
1705
+		$success = false;
1706
+		// typecast $REG_IDs
1707
+		$REG_IDs = (array) $REG_IDs;
1708
+		if (! empty($REG_IDs)) {
1709
+			$success = true;
1710
+			// set default status if none is passed
1711
+			$status = $status ? $status : EEM_Registration::status_id_pending_payment;
1712
+			$status_context = $notify
1713
+				? Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN_NOTIFY
1714
+				: Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN;
1715
+			// loop through REG_ID's and change status
1716
+			foreach ($REG_IDs as $REG_ID) {
1717
+				$registration = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
1718
+				if ($registration instanceof EE_Registration) {
1719
+					$registration->set_status(
1720
+						$status,
1721
+						false,
1722
+						new Context(
1723
+							$status_context,
1724
+							esc_html__(
1725
+								'Manually triggered status change on a Registration Admin Page route.',
1726
+								'event_espresso'
1727
+							)
1728
+						)
1729
+					);
1730
+					$result = $registration->save();
1731
+					// verifying explicit fails because update *may* just return 0 for 0 rows affected
1732
+					$success = $result !== false ? $success : false;
1733
+				}
1734
+			}
1735
+		}
1736
+
1737
+		// return $success and processed registrations
1738
+		return array('REG_ID' => $REG_IDs, 'success' => $success);
1739
+	}
1740
+
1741
+
1742
+	/**
1743
+	 * Common logic for setting up success message and redirecting to appropriate route
1744
+	 *
1745
+	 * @param string $STS_ID status id for the registration changed to
1746
+	 * @param bool   $notify indicates whether the _set_registration_status_from_request does notifications or not.
1747
+	 * @return void
1748
+	 * @throws DomainException
1749
+	 * @throws EE_Error
1750
+	 * @throws EntityNotFoundException
1751
+	 * @throws InvalidArgumentException
1752
+	 * @throws InvalidDataTypeException
1753
+	 * @throws InvalidInterfaceException
1754
+	 * @throws ReflectionException
1755
+	 * @throws RuntimeException
1756
+	 */
1757
+	protected function _reg_status_change_return($STS_ID, $notify = false)
1758
+	{
1759
+		$result = ! empty($STS_ID) ? $this->_set_registration_status_from_request($STS_ID, $notify)
1760
+			: array('success' => false);
1761
+		$success = isset($result['success']) && $result['success'];
1762
+		// setup success message
1763
+		if ($success) {
1764
+			if (is_array($result['REG_ID']) && count($result['REG_ID']) === 1) {
1765
+				$msg = sprintf(
1766
+					esc_html__('Registration status has been set to %s', 'event_espresso'),
1767
+					EEH_Template::pretty_status($STS_ID, false, 'lower')
1768
+				);
1769
+			} else {
1770
+				$msg = sprintf(
1771
+					esc_html__('Registrations have been set to %s.', 'event_espresso'),
1772
+					EEH_Template::pretty_status($STS_ID, false, 'lower')
1773
+				);
1774
+			}
1775
+			EE_Error::add_success($msg);
1776
+		} else {
1777
+			EE_Error::add_error(
1778
+				esc_html__(
1779
+					'Something went wrong, and the status was not changed',
1780
+					'event_espresso'
1781
+				),
1782
+				__FILE__,
1783
+				__LINE__,
1784
+				__FUNCTION__
1785
+			);
1786
+		}
1787
+		if (isset($this->_req_data['return']) && $this->_req_data['return'] === 'view_registration') {
1788
+			$route = array('action' => 'view_registration', '_REG_ID' => reset($result['REG_ID']));
1789
+		} else {
1790
+			$route = array('action' => 'default');
1791
+		}
1792
+		$route = $this->mergeExistingRequestParamsWithRedirectArgs($route);
1793
+		$this->_redirect_after_action($success, '', '', $route, true);
1794
+	}
1795
+
1796
+
1797
+	/**
1798
+	 * incoming reg status change from reg details page.
1799
+	 *
1800
+	 * @return void
1801
+	 * @throws EE_Error
1802
+	 * @throws EntityNotFoundException
1803
+	 * @throws InvalidArgumentException
1804
+	 * @throws InvalidDataTypeException
1805
+	 * @throws InvalidInterfaceException
1806
+	 * @throws ReflectionException
1807
+	 * @throws RuntimeException
1808
+	 * @throws DomainException
1809
+	 */
1810
+	protected function _change_reg_status()
1811
+	{
1812
+		$this->_req_data['return'] = 'view_registration';
1813
+		// set notify based on whether the send notifications toggle is set or not
1814
+		$notify = ! empty($this->_req_data['reg_status_change_form']['send_notifications']);
1815
+		// $notify = ! empty( $this->_req_data['txn_reg_status_change']['send_notifications'] );
1816
+		$this->_req_data['reg_status_change_form']['reg_status'] = isset($this->_req_data['reg_status_change_form']['reg_status'])
1817
+			? $this->_req_data['reg_status_change_form']['reg_status'] : '';
1818
+		switch ($this->_req_data['reg_status_change_form']['reg_status']) {
1819
+			case EEM_Registration::status_id_approved:
1820
+			case EEH_Template::pretty_status(EEM_Registration::status_id_approved, false, 'sentence'):
1821
+				$this->approve_registration($notify);
1822
+				break;
1823
+			case EEM_Registration::status_id_pending_payment:
1824
+			case EEH_Template::pretty_status(EEM_Registration::status_id_pending_payment, false, 'sentence'):
1825
+				$this->pending_registration($notify);
1826
+				break;
1827
+			case EEM_Registration::status_id_not_approved:
1828
+			case EEH_Template::pretty_status(EEM_Registration::status_id_not_approved, false, 'sentence'):
1829
+				$this->not_approve_registration($notify);
1830
+				break;
1831
+			case EEM_Registration::status_id_declined:
1832
+			case EEH_Template::pretty_status(EEM_Registration::status_id_declined, false, 'sentence'):
1833
+				$this->decline_registration($notify);
1834
+				break;
1835
+			case EEM_Registration::status_id_cancelled:
1836
+			case EEH_Template::pretty_status(EEM_Registration::status_id_cancelled, false, 'sentence'):
1837
+				$this->cancel_registration($notify);
1838
+				break;
1839
+			case EEM_Registration::status_id_wait_list:
1840
+			case EEH_Template::pretty_status(EEM_Registration::status_id_wait_list, false, 'sentence'):
1841
+				$this->wait_list_registration($notify);
1842
+				break;
1843
+			case EEM_Registration::status_id_incomplete:
1844
+			default:
1845
+				$result['success'] = false;
1846
+				unset($this->_req_data['return']);
1847
+				$this->_reg_status_change_return('', false);
1848
+				break;
1849
+		}
1850
+	}
1851
+
1852
+
1853
+	/**
1854
+	 * Callback for bulk action routes.
1855
+	 * Note: although we could just register the singular route callbacks for each bulk action route as well, this
1856
+	 * method was chosen so there is one central place all the registration status bulk actions are going through.
1857
+	 * Potentially, this provides an easier place to locate logic that is specific to these bulk actions (as opposed to
1858
+	 * when an action is happening on just a single registration).
1859
+	 *
1860
+	 * @param      $action
1861
+	 * @param bool $notify
1862
+	 */
1863
+	protected function bulk_action_on_registrations($action, $notify = false)
1864
+	{
1865
+		do_action(
1866
+			'AHEE__Registrations_Admin_Page__bulk_action_on_registrations__before_execution',
1867
+			$this,
1868
+			$action,
1869
+			$notify
1870
+		);
1871
+		$method = $action . '_registration';
1872
+		if (method_exists($this, $method)) {
1873
+			$this->$method($notify);
1874
+		}
1875
+	}
1876
+
1877
+
1878
+	/**
1879
+	 * approve_registration
1880
+	 *
1881
+	 * @access protected
1882
+	 * @param bool $notify whether or not to notify the registrant about their approval.
1883
+	 * @return void
1884
+	 * @throws EE_Error
1885
+	 * @throws EntityNotFoundException
1886
+	 * @throws InvalidArgumentException
1887
+	 * @throws InvalidDataTypeException
1888
+	 * @throws InvalidInterfaceException
1889
+	 * @throws ReflectionException
1890
+	 * @throws RuntimeException
1891
+	 * @throws DomainException
1892
+	 */
1893
+	protected function approve_registration($notify = false)
1894
+	{
1895
+		$this->_reg_status_change_return(EEM_Registration::status_id_approved, $notify);
1896
+	}
1897
+
1898
+
1899
+	/**
1900
+	 *        decline_registration
1901
+	 *
1902
+	 * @access protected
1903
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1904
+	 * @return void
1905
+	 * @throws EE_Error
1906
+	 * @throws EntityNotFoundException
1907
+	 * @throws InvalidArgumentException
1908
+	 * @throws InvalidDataTypeException
1909
+	 * @throws InvalidInterfaceException
1910
+	 * @throws ReflectionException
1911
+	 * @throws RuntimeException
1912
+	 * @throws DomainException
1913
+	 */
1914
+	protected function decline_registration($notify = false)
1915
+	{
1916
+		$this->_reg_status_change_return(EEM_Registration::status_id_declined, $notify);
1917
+	}
1918
+
1919
+
1920
+	/**
1921
+	 *        cancel_registration
1922
+	 *
1923
+	 * @access protected
1924
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1925
+	 * @return void
1926
+	 * @throws EE_Error
1927
+	 * @throws EntityNotFoundException
1928
+	 * @throws InvalidArgumentException
1929
+	 * @throws InvalidDataTypeException
1930
+	 * @throws InvalidInterfaceException
1931
+	 * @throws ReflectionException
1932
+	 * @throws RuntimeException
1933
+	 * @throws DomainException
1934
+	 */
1935
+	protected function cancel_registration($notify = false)
1936
+	{
1937
+		$this->_reg_status_change_return(EEM_Registration::status_id_cancelled, $notify);
1938
+	}
1939
+
1940
+
1941
+	/**
1942
+	 *        not_approve_registration
1943
+	 *
1944
+	 * @access protected
1945
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1946
+	 * @return void
1947
+	 * @throws EE_Error
1948
+	 * @throws EntityNotFoundException
1949
+	 * @throws InvalidArgumentException
1950
+	 * @throws InvalidDataTypeException
1951
+	 * @throws InvalidInterfaceException
1952
+	 * @throws ReflectionException
1953
+	 * @throws RuntimeException
1954
+	 * @throws DomainException
1955
+	 */
1956
+	protected function not_approve_registration($notify = false)
1957
+	{
1958
+		$this->_reg_status_change_return(EEM_Registration::status_id_not_approved, $notify);
1959
+	}
1960
+
1961
+
1962
+	/**
1963
+	 *        decline_registration
1964
+	 *
1965
+	 * @access protected
1966
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1967
+	 * @return void
1968
+	 * @throws EE_Error
1969
+	 * @throws EntityNotFoundException
1970
+	 * @throws InvalidArgumentException
1971
+	 * @throws InvalidDataTypeException
1972
+	 * @throws InvalidInterfaceException
1973
+	 * @throws ReflectionException
1974
+	 * @throws RuntimeException
1975
+	 * @throws DomainException
1976
+	 */
1977
+	protected function pending_registration($notify = false)
1978
+	{
1979
+		$this->_reg_status_change_return(EEM_Registration::status_id_pending_payment, $notify);
1980
+	}
1981
+
1982
+
1983
+	/**
1984
+	 * waitlist_registration
1985
+	 *
1986
+	 * @access protected
1987
+	 * @param bool $notify whether or not to notify the registrant about their status change.
1988
+	 * @return void
1989
+	 * @throws EE_Error
1990
+	 * @throws EntityNotFoundException
1991
+	 * @throws InvalidArgumentException
1992
+	 * @throws InvalidDataTypeException
1993
+	 * @throws InvalidInterfaceException
1994
+	 * @throws ReflectionException
1995
+	 * @throws RuntimeException
1996
+	 * @throws DomainException
1997
+	 */
1998
+	protected function wait_list_registration($notify = false)
1999
+	{
2000
+		$this->_reg_status_change_return(EEM_Registration::status_id_wait_list, $notify);
2001
+	}
2002
+
2003
+
2004
+	/**
2005
+	 *        generates HTML for the Registration main meta box
2006
+	 *
2007
+	 * @access public
2008
+	 * @return void
2009
+	 * @throws DomainException
2010
+	 * @throws EE_Error
2011
+	 * @throws InvalidArgumentException
2012
+	 * @throws InvalidDataTypeException
2013
+	 * @throws InvalidInterfaceException
2014
+	 * @throws ReflectionException
2015
+	 * @throws EntityNotFoundException
2016
+	 */
2017
+	public function _reg_details_meta_box()
2018
+	{
2019
+		EEH_Autoloader::register_line_item_display_autoloaders();
2020
+		EEH_Autoloader::register_line_item_filter_autoloaders();
2021
+		EE_Registry::instance()->load_helper('Line_Item');
2022
+		$transaction = $this->_registration->transaction() ? $this->_registration->transaction()
2023
+			: EE_Transaction::new_instance();
2024
+		$this->_session = $transaction->session_data();
2025
+		$filters = new EE_Line_Item_Filter_Collection();
2026
+		$filters->add(new EE_Single_Registration_Line_Item_Filter($this->_registration));
2027
+		$filters->add(new EE_Non_Zero_Line_Item_Filter());
2028
+		$line_item_filter_processor = new EE_Line_Item_Filter_Processor(
2029
+			$filters,
2030
+			$transaction->total_line_item()
2031
+		);
2032
+		$filtered_line_item_tree = $line_item_filter_processor->process();
2033
+		$line_item_display = new EE_Line_Item_Display(
2034
+			'reg_admin_table',
2035
+			'EE_Admin_Table_Registration_Line_Item_Display_Strategy'
2036
+		);
2037
+		$this->_template_args['line_item_table'] = $line_item_display->display_line_item(
2038
+			$filtered_line_item_tree,
2039
+			array('EE_Registration' => $this->_registration)
2040
+		);
2041
+		$attendee = $this->_registration->attendee();
2042
+		if (EE_Registry::instance()->CAP->current_user_can(
2043
+			'ee_read_transaction',
2044
+			'espresso_transactions_view_transaction'
2045
+		)) {
2046
+			$this->_template_args['view_transaction_button'] = EEH_Template::get_button_or_link(
2047
+				EE_Admin_Page::add_query_args_and_nonce(
2048
+					array(
2049
+						'action' => 'view_transaction',
2050
+						'TXN_ID' => $transaction->ID(),
2051
+					),
2052
+					TXN_ADMIN_URL
2053
+				),
2054
+				esc_html__(' View Transaction', 'event_espresso'),
2055
+				'button secondary-button right',
2056
+				'dashicons dashicons-cart'
2057
+			);
2058
+		} else {
2059
+			$this->_template_args['view_transaction_button'] = '';
2060
+		}
2061
+		if ($attendee instanceof EE_Attendee
2062
+			&& EE_Registry::instance()->CAP->current_user_can(
2063
+				'ee_send_message',
2064
+				'espresso_registrations_resend_registration'
2065
+			)
2066
+		) {
2067
+			$this->_template_args['resend_registration_button'] = EEH_Template::get_button_or_link(
2068
+				EE_Admin_Page::add_query_args_and_nonce(
2069
+					array(
2070
+						'action'      => 'resend_registration',
2071
+						'_REG_ID'     => $this->_registration->ID(),
2072
+						'redirect_to' => 'view_registration',
2073
+					),
2074
+					REG_ADMIN_URL
2075
+				),
2076
+				esc_html__(' Resend Registration', 'event_espresso'),
2077
+				'button secondary-button right',
2078
+				'dashicons dashicons-email-alt'
2079
+			);
2080
+		} else {
2081
+			$this->_template_args['resend_registration_button'] = '';
2082
+		}
2083
+		$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2084
+		$payment = $transaction->get_first_related('Payment');
2085
+		$payment = ! $payment instanceof EE_Payment
2086
+			? EE_Payment::new_instance()
2087
+			: $payment;
2088
+		$payment_method = $payment->get_first_related('Payment_Method');
2089
+		$payment_method = ! $payment_method instanceof EE_Payment_Method
2090
+			? EE_Payment_Method::new_instance()
2091
+			: $payment_method;
2092
+		$reg_details = array(
2093
+			'payment_method'       => $payment_method->name(),
2094
+			'response_msg'         => $payment->gateway_response(),
2095
+			'registration_id'      => $this->_registration->get('REG_code'),
2096
+			'registration_session' => $this->_registration->session_ID(),
2097
+			'ip_address'           => isset($this->_session['ip_address']) ? $this->_session['ip_address'] : '',
2098
+			'user_agent'           => isset($this->_session['user_agent']) ? $this->_session['user_agent'] : '',
2099
+		);
2100
+		if (isset($reg_details['registration_id'])) {
2101
+			$this->_template_args['reg_details']['registration_id']['value'] = $reg_details['registration_id'];
2102
+			$this->_template_args['reg_details']['registration_id']['label'] = esc_html__(
2103
+				'Registration ID',
2104
+				'event_espresso'
2105
+			);
2106
+			$this->_template_args['reg_details']['registration_id']['class'] = 'regular-text';
2107
+		}
2108
+		if (isset($reg_details['payment_method'])) {
2109
+			$this->_template_args['reg_details']['payment_method']['value'] = $reg_details['payment_method'];
2110
+			$this->_template_args['reg_details']['payment_method']['label'] = esc_html__(
2111
+				'Most Recent Payment Method',
2112
+				'event_espresso'
2113
+			);
2114
+			$this->_template_args['reg_details']['payment_method']['class'] = 'regular-text';
2115
+			$this->_template_args['reg_details']['response_msg']['value'] = $reg_details['response_msg'];
2116
+			$this->_template_args['reg_details']['response_msg']['label'] = esc_html__(
2117
+				'Payment method response',
2118
+				'event_espresso'
2119
+			);
2120
+			$this->_template_args['reg_details']['response_msg']['class'] = 'regular-text';
2121
+		}
2122
+		$this->_template_args['reg_details']['registration_session']['value'] = $reg_details['registration_session'];
2123
+		$this->_template_args['reg_details']['registration_session']['label'] = esc_html__(
2124
+			'Registration Session',
2125
+			'event_espresso'
2126
+		);
2127
+		$this->_template_args['reg_details']['registration_session']['class'] = 'regular-text';
2128
+		$this->_template_args['reg_details']['ip_address']['value'] = $reg_details['ip_address'];
2129
+		$this->_template_args['reg_details']['ip_address']['label'] = esc_html__(
2130
+			'Registration placed from IP',
2131
+			'event_espresso'
2132
+		);
2133
+		$this->_template_args['reg_details']['ip_address']['class'] = 'regular-text';
2134
+		$this->_template_args['reg_details']['user_agent']['value'] = $reg_details['user_agent'];
2135
+		$this->_template_args['reg_details']['user_agent']['label'] = esc_html__(
2136
+			'Registrant User Agent',
2137
+			'event_espresso'
2138
+		);
2139
+		$this->_template_args['reg_details']['user_agent']['class'] = 'large-text';
2140
+		$this->_template_args['event_link'] = EE_Admin_Page::add_query_args_and_nonce(
2141
+			array(
2142
+				'action'   => 'default',
2143
+				'event_id' => $this->_registration->event_ID(),
2144
+			),
2145
+			REG_ADMIN_URL
2146
+		);
2147
+		$this->_template_args['REG_ID'] = $this->_registration->ID();
2148
+		$this->_template_args['event_id'] = $this->_registration->event_ID();
2149
+		$template_path =
2150
+			REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_details.template.php';
2151
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);
2152
+	}
2153
+
2154
+
2155
+	/**
2156
+	 * generates HTML for the Registration Questions meta box.
2157
+	 * If pre-4.8.32.rc.000 hooks are used, uses old methods (with its filters),
2158
+	 * otherwise uses new forms system
2159
+	 *
2160
+	 * @access public
2161
+	 * @return void
2162
+	 * @throws DomainException
2163
+	 * @throws EE_Error
2164
+	 * @throws InvalidArgumentException
2165
+	 * @throws InvalidDataTypeException
2166
+	 * @throws InvalidInterfaceException
2167
+	 * @throws ReflectionException
2168
+	 */
2169
+	public function _reg_questions_meta_box()
2170
+	{
2171
+		// allow someone to override this method entirely
2172
+		if (apply_filters(
2173
+			'FHEE__Registrations_Admin_Page___reg_questions_meta_box__do_default',
2174
+			true,
2175
+			$this,
2176
+			$this->_registration
2177
+		)) {
2178
+			$form = $this->_get_reg_custom_questions_form(
2179
+				$this->_registration->ID()
2180
+			);
2181
+			$this->_template_args['att_questions'] = count($form->subforms()) > 0
2182
+				? $form->get_html_and_js()
2183
+				: '';
2184
+			$this->_template_args['reg_questions_form_action'] = 'edit_registration';
2185
+			$this->_template_args['REG_ID'] = $this->_registration->ID();
2186
+			$template_path =
2187
+				REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_questions.template.php';
2188
+			echo EEH_Template::display_template($template_path, $this->_template_args, true);
2189
+		}
2190
+	}
2191
+
2192
+
2193
+	/**
2194
+	 * form_before_question_group
2195
+	 *
2196
+	 * @deprecated    as of 4.8.32.rc.000
2197
+	 * @access        public
2198
+	 * @param        string $output
2199
+	 * @return        string
2200
+	 */
2201
+	public function form_before_question_group($output)
2202
+	{
2203
+		EE_Error::doing_it_wrong(
2204
+			__CLASS__ . '::' . __FUNCTION__,
2205
+			esc_html__(
2206
+				'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2207
+				'event_espresso'
2208
+			),
2209
+			'4.8.32.rc.000'
2210
+		);
2211
+		return '
2212 2212
 	<table class="form-table ee-width-100">
2213 2213
 		<tbody>
2214 2214
 			';
2215
-    }
2216
-
2217
-
2218
-    /**
2219
-     * form_after_question_group
2220
-     *
2221
-     * @deprecated    as of 4.8.32.rc.000
2222
-     * @access        public
2223
-     * @param        string $output
2224
-     * @return        string
2225
-     */
2226
-    public function form_after_question_group($output)
2227
-    {
2228
-        EE_Error::doing_it_wrong(
2229
-            __CLASS__ . '::' . __FUNCTION__,
2230
-            esc_html__(
2231
-                'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2232
-                'event_espresso'
2233
-            ),
2234
-            '4.8.32.rc.000'
2235
-        );
2236
-        return '
2215
+	}
2216
+
2217
+
2218
+	/**
2219
+	 * form_after_question_group
2220
+	 *
2221
+	 * @deprecated    as of 4.8.32.rc.000
2222
+	 * @access        public
2223
+	 * @param        string $output
2224
+	 * @return        string
2225
+	 */
2226
+	public function form_after_question_group($output)
2227
+	{
2228
+		EE_Error::doing_it_wrong(
2229
+			__CLASS__ . '::' . __FUNCTION__,
2230
+			esc_html__(
2231
+				'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2232
+				'event_espresso'
2233
+			),
2234
+			'4.8.32.rc.000'
2235
+		);
2236
+		return '
2237 2237
 			<tr class="hide-if-no-js">
2238 2238
 				<th> </th>
2239 2239
 				<td class="reg-admin-edit-attendee-question-td">
2240 2240
 					<a class="reg-admin-edit-attendee-question-lnk" href="#" title="'
2241
-               . esc_attr__('click to edit question', 'event_espresso')
2242
-               . '">
2241
+			   . esc_attr__('click to edit question', 'event_espresso')
2242
+			   . '">
2243 2243
 						<span class="reg-admin-edit-question-group-spn lt-grey-txt">'
2244
-               . esc_html__('edit the above question group', 'event_espresso')
2245
-               . '</span>
2244
+			   . esc_html__('edit the above question group', 'event_espresso')
2245
+			   . '</span>
2246 2246
 						<div class="dashicons dashicons-edit"></div>
2247 2247
 					</a>
2248 2248
 				</td>
@@ -2250,646 +2250,646 @@  discard block
 block discarded – undo
2250 2250
 		</tbody>
2251 2251
 	</table>
2252 2252
 ';
2253
-    }
2254
-
2255
-
2256
-    /**
2257
-     * form_form_field_label_wrap
2258
-     *
2259
-     * @deprecated    as of 4.8.32.rc.000
2260
-     * @access        public
2261
-     * @param        string $label
2262
-     * @return        string
2263
-     */
2264
-    public function form_form_field_label_wrap($label)
2265
-    {
2266
-        EE_Error::doing_it_wrong(
2267
-            __CLASS__ . '::' . __FUNCTION__,
2268
-            esc_html__(
2269
-                'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2270
-                'event_espresso'
2271
-            ),
2272
-            '4.8.32.rc.000'
2273
-        );
2274
-        return '
2253
+	}
2254
+
2255
+
2256
+	/**
2257
+	 * form_form_field_label_wrap
2258
+	 *
2259
+	 * @deprecated    as of 4.8.32.rc.000
2260
+	 * @access        public
2261
+	 * @param        string $label
2262
+	 * @return        string
2263
+	 */
2264
+	public function form_form_field_label_wrap($label)
2265
+	{
2266
+		EE_Error::doing_it_wrong(
2267
+			__CLASS__ . '::' . __FUNCTION__,
2268
+			esc_html__(
2269
+				'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2270
+				'event_espresso'
2271
+			),
2272
+			'4.8.32.rc.000'
2273
+		);
2274
+		return '
2275 2275
 			<tr>
2276 2276
 				<th>
2277 2277
 					' . $label . '
2278 2278
 				</th>';
2279
-    }
2280
-
2281
-
2282
-    /**
2283
-     * form_form_field_input__wrap
2284
-     *
2285
-     * @deprecated    as of 4.8.32.rc.000
2286
-     * @access        public
2287
-     * @param        string $input
2288
-     * @return        string
2289
-     */
2290
-    public function form_form_field_input__wrap($input)
2291
-    {
2292
-        EE_Error::doing_it_wrong(
2293
-            __CLASS__ . '::' . __FUNCTION__,
2294
-            esc_html__(
2295
-                'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2296
-                'event_espresso'
2297
-            ),
2298
-            '4.8.32.rc.000'
2299
-        );
2300
-        return '
2279
+	}
2280
+
2281
+
2282
+	/**
2283
+	 * form_form_field_input__wrap
2284
+	 *
2285
+	 * @deprecated    as of 4.8.32.rc.000
2286
+	 * @access        public
2287
+	 * @param        string $input
2288
+	 * @return        string
2289
+	 */
2290
+	public function form_form_field_input__wrap($input)
2291
+	{
2292
+		EE_Error::doing_it_wrong(
2293
+			__CLASS__ . '::' . __FUNCTION__,
2294
+			esc_html__(
2295
+				'This method would have been protected but was used on a filter callback so needed to be public. Please discontinue usage as it will be removed soon.',
2296
+				'event_espresso'
2297
+			),
2298
+			'4.8.32.rc.000'
2299
+		);
2300
+		return '
2301 2301
 				<td class="reg-admin-attendee-questions-input-td disabled-input">
2302 2302
 					' . $input . '
2303 2303
 				</td>
2304 2304
 			</tr>';
2305
-    }
2306
-
2307
-
2308
-    /**
2309
-     * Updates the registration's custom questions according to the form info, if the form is submitted.
2310
-     * If it's not a post, the "view_registrations" route will be called next on the SAME request
2311
-     * to display the page
2312
-     *
2313
-     * @access protected
2314
-     * @return void
2315
-     * @throws EE_Error
2316
-     * @throws InvalidArgumentException
2317
-     * @throws InvalidDataTypeException
2318
-     * @throws InvalidInterfaceException
2319
-     * @throws ReflectionException
2320
-     */
2321
-    protected function _update_attendee_registration_form()
2322
-    {
2323
-        do_action('AHEE__Registrations_Admin_Page___update_attendee_registration_form__start', $this);
2324
-        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
2325
-            $REG_ID = isset($this->_req_data['_REG_ID']) ? absint($this->_req_data['_REG_ID']) : false;
2326
-            $success = $this->_save_reg_custom_questions_form($REG_ID);
2327
-            if ($success) {
2328
-                $what = esc_html__('Registration Form', 'event_espresso');
2329
-                $route = $REG_ID ? array('action' => 'view_registration', '_REG_ID' => $REG_ID)
2330
-                    : array('action' => 'default');
2331
-                $this->_redirect_after_action($success, $what, esc_html__('updated', 'event_espresso'), $route);
2332
-            }
2333
-        }
2334
-    }
2335
-
2336
-
2337
-    /**
2338
-     * Gets the form for saving registrations custom questions (if done
2339
-     * previously retrieves the cached form object, which may have validation errors in it)
2340
-     *
2341
-     * @param int $REG_ID
2342
-     * @return EE_Registration_Custom_Questions_Form
2343
-     * @throws EE_Error
2344
-     * @throws InvalidArgumentException
2345
-     * @throws InvalidDataTypeException
2346
-     * @throws InvalidInterfaceException
2347
-     */
2348
-    protected function _get_reg_custom_questions_form($REG_ID)
2349
-    {
2350
-        if (! $this->_reg_custom_questions_form) {
2351
-            require_once(REG_ADMIN . 'form_sections/EE_Registration_Custom_Questions_Form.form.php');
2352
-            $this->_reg_custom_questions_form = new EE_Registration_Custom_Questions_Form(
2353
-                $this->getRegistrationModel()->get_one_by_ID($REG_ID)
2354
-            );
2355
-            $this->_reg_custom_questions_form->_construct_finalize(null, null);
2356
-        }
2357
-        return $this->_reg_custom_questions_form;
2358
-    }
2359
-
2360
-
2361
-    /**
2362
-     * Saves
2363
-     *
2364
-     * @access private
2365
-     * @param bool $REG_ID
2366
-     * @return bool
2367
-     * @throws EE_Error
2368
-     * @throws InvalidArgumentException
2369
-     * @throws InvalidDataTypeException
2370
-     * @throws InvalidInterfaceException
2371
-     * @throws ReflectionException
2372
-     */
2373
-    private function _save_reg_custom_questions_form($REG_ID = false)
2374
-    {
2375
-        if (! $REG_ID) {
2376
-            EE_Error::add_error(
2377
-                esc_html__(
2378
-                    'An error occurred. No registration ID was received.',
2379
-                    'event_espresso'
2380
-                ),
2381
-                __FILE__,
2382
-                __FUNCTION__,
2383
-                __LINE__
2384
-            );
2385
-        }
2386
-        $form = $this->_get_reg_custom_questions_form($REG_ID);
2387
-        $form->receive_form_submission($this->_req_data);
2388
-        $success = false;
2389
-        if ($form->is_valid()) {
2390
-            foreach ($form->subforms() as $question_group_id => $question_group_form) {
2391
-                foreach ($question_group_form->inputs() as $question_id => $input) {
2392
-                    $where_conditions = array(
2393
-                        'QST_ID' => $question_id,
2394
-                        'REG_ID' => $REG_ID,
2395
-                    );
2396
-                    $possibly_new_values = array(
2397
-                        'ANS_value' => $input->normalized_value(),
2398
-                    );
2399
-                    $answer = EEM_Answer::instance()->get_one(array($where_conditions));
2400
-                    if ($answer instanceof EE_Answer) {
2401
-                        $success = $answer->save($possibly_new_values);
2402
-                    } else {
2403
-                        // insert it then
2404
-                        $cols_n_vals = array_merge($where_conditions, $possibly_new_values);
2405
-                        $answer = EE_Answer::new_instance($cols_n_vals);
2406
-                        $success = $answer->save();
2407
-                    }
2408
-                }
2409
-            }
2410
-        } else {
2411
-            EE_Error::add_error($form->get_validation_error_string(), __FILE__, __FUNCTION__, __LINE__);
2412
-        }
2413
-        return $success;
2414
-    }
2415
-
2416
-
2417
-    /**
2418
-     *        generates HTML for the Registration main meta box
2419
-     *
2420
-     * @access public
2421
-     * @return void
2422
-     * @throws DomainException
2423
-     * @throws EE_Error
2424
-     * @throws InvalidArgumentException
2425
-     * @throws InvalidDataTypeException
2426
-     * @throws InvalidInterfaceException
2427
-     * @throws ReflectionException
2428
-     */
2429
-    public function _reg_attendees_meta_box()
2430
-    {
2431
-        $REG = $this->getRegistrationModel();
2432
-        // get all other registrations on this transaction, and cache
2433
-        // the attendees for them so we don't have to run another query using force_join
2434
-        $registrations = $REG->get_all(
2435
-            array(
2436
-                array(
2437
-                    'TXN_ID' => $this->_registration->transaction_ID(),
2438
-                    'REG_ID' => array('!=', $this->_registration->ID()),
2439
-                ),
2440
-                'force_join' => array('Attendee'),
2441
-                'default_where_conditions' => 'other_models_only',
2442
-            )
2443
-        );
2444
-        $this->_template_args['attendees'] = array();
2445
-        $this->_template_args['attendee_notice'] = '';
2446
-        if (empty($registrations)
2447
-            || (is_array($registrations)
2448
-                && ! EEH_Array::get_one_item_from_array($registrations))
2449
-        ) {
2450
-            EE_Error::add_error(
2451
-                esc_html__(
2452
-                    'There are no records attached to this registration. Something may have gone wrong with the registration',
2453
-                    'event_espresso'
2454
-                ),
2455
-                __FILE__,
2456
-                __FUNCTION__,
2457
-                __LINE__
2458
-            );
2459
-            $this->_template_args['attendee_notice'] = EE_Error::get_notices();
2460
-        } else {
2461
-            $att_nmbr = 1;
2462
-            foreach ($registrations as $registration) {
2463
-                /* @var $registration EE_Registration */
2464
-                $attendee = $registration->attendee()
2465
-                    ? $registration->attendee()
2466
-                    : $this->getAttendeeModel()->create_default_object();
2467
-                $this->_template_args['attendees'][ $att_nmbr ]['STS_ID'] = $registration->status_ID();
2468
-                $this->_template_args['attendees'][ $att_nmbr ]['fname'] = $attendee->fname();
2469
-                $this->_template_args['attendees'][ $att_nmbr ]['lname'] = $attendee->lname();
2470
-                $this->_template_args['attendees'][ $att_nmbr ]['email'] = $attendee->email();
2471
-                $this->_template_args['attendees'][ $att_nmbr ]['final_price'] = $registration->final_price();
2472
-                $this->_template_args['attendees'][ $att_nmbr ]['address'] = implode(
2473
-                    ', ',
2474
-                    $attendee->full_address_as_array()
2475
-                );
2476
-                $this->_template_args['attendees'][ $att_nmbr ]['att_link'] = self::add_query_args_and_nonce(
2477
-                    array(
2478
-                        'action' => 'edit_attendee',
2479
-                        'post'   => $attendee->ID(),
2480
-                    ),
2481
-                    REG_ADMIN_URL
2482
-                );
2483
-                $this->_template_args['attendees'][ $att_nmbr ]['event_name'] = $registration->event_obj() instanceof EE_Event
2484
-                    ? $registration->event_obj()->name()
2485
-                    : '';
2486
-                $att_nmbr++;
2487
-            }
2488
-            $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2489
-        }
2490
-        $template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_attendees.template.php';
2491
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);
2492
-    }
2493
-
2494
-
2495
-    /**
2496
-     *        generates HTML for the Edit Registration side meta box
2497
-     *
2498
-     * @access public
2499
-     * @return void
2500
-     * @throws DomainException
2501
-     * @throws EE_Error
2502
-     * @throws InvalidArgumentException
2503
-     * @throws InvalidDataTypeException
2504
-     * @throws InvalidInterfaceException
2505
-     * @throws ReflectionException
2506
-     */
2507
-    public function _reg_registrant_side_meta_box()
2508
-    {
2509
-        /*@var $attendee EE_Attendee */
2510
-        $att_check = $this->_registration->attendee();
2511
-        $attendee = $att_check instanceof EE_Attendee
2512
-            ? $att_check
2513
-            : $this->getAttendeeModel()->create_default_object();
2514
-        // now let's determine if this is not the primary registration.  If it isn't then we set the
2515
-        // primary_registration object for reference BUT ONLY if the Attendee object loaded is not the same as the
2516
-        // primary registration object (that way we know if we need to show create button or not)
2517
-        if (! $this->_registration->is_primary_registrant()) {
2518
-            $primary_registration = $this->_registration->get_primary_registration();
2519
-            $primary_attendee = $primary_registration instanceof EE_Registration ? $primary_registration->attendee()
2520
-                : null;
2521
-            if (! $primary_attendee instanceof EE_Attendee || $attendee->ID() !== $primary_attendee->ID()) {
2522
-                // in here?  This means the displayed registration is not the primary registrant but ALREADY HAS its own
2523
-                // custom attendee object so let's not worry about the primary reg.
2524
-                $primary_registration = null;
2525
-            }
2526
-        } else {
2527
-            $primary_registration = null;
2528
-        }
2529
-        $this->_template_args['ATT_ID'] = $attendee->ID();
2530
-        $this->_template_args['fname'] = $attendee->fname();
2531
-        $this->_template_args['lname'] = $attendee->lname();
2532
-        $this->_template_args['email'] = $attendee->email();
2533
-        $this->_template_args['phone'] = $attendee->phone();
2534
-        $this->_template_args['formatted_address'] = EEH_Address::format($attendee);
2535
-        // edit link
2536
-        $this->_template_args['att_edit_link'] = EE_Admin_Page::add_query_args_and_nonce(
2537
-            array(
2538
-                'action' => 'edit_attendee',
2539
-                'post'   => $attendee->ID(),
2540
-            ),
2541
-            REG_ADMIN_URL
2542
-        );
2543
-        $this->_template_args['att_edit_label'] = esc_html__('View/Edit Contact', 'event_espresso');
2544
-        // create link
2545
-        $this->_template_args['create_link'] = $primary_registration instanceof EE_Registration
2546
-            ? EE_Admin_Page::add_query_args_and_nonce(
2547
-                array(
2548
-                    'action'  => 'duplicate_attendee',
2549
-                    '_REG_ID' => $this->_registration->ID(),
2550
-                ),
2551
-                REG_ADMIN_URL
2552
-            ) : '';
2553
-        $this->_template_args['create_label'] = esc_html__('Create Contact', 'event_espresso');
2554
-        $this->_template_args['att_check'] = $att_check;
2555
-        $template_path = REG_TEMPLATE_PATH . 'reg_admin_details_side_meta_box_registrant.template.php';
2556
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);
2557
-    }
2558
-
2559
-
2560
-    /**
2561
-     * trash or restore registrations
2562
-     *
2563
-     * @param  boolean $trash whether to archive or restore
2564
-     * @return void
2565
-     * @throws DomainException
2566
-     * @throws EE_Error
2567
-     * @throws EntityNotFoundException
2568
-     * @throws InvalidArgumentException
2569
-     * @throws InvalidDataTypeException
2570
-     * @throws InvalidInterfaceException
2571
-     * @throws ReflectionException
2572
-     * @throws RuntimeException
2573
-     * @throws UnexpectedEntityException
2574
-     * @access protected
2575
-     */
2576
-    protected function _trash_or_restore_registrations($trash = true)
2577
-    {
2578
-        // if empty _REG_ID then get out because there's nothing to do
2579
-        if (empty($this->_req_data['_REG_ID'])) {
2580
-            EE_Error::add_error(
2581
-                sprintf(
2582
-                    esc_html__(
2583
-                        'In order to %1$s registrations you must select which ones you wish to %1$s by clicking the checkboxes.',
2584
-                        'event_espresso'
2585
-                    ),
2586
-                    $trash ? 'trash' : 'restore'
2587
-                ),
2588
-                __FILE__,
2589
-                __LINE__,
2590
-                __FUNCTION__
2591
-            );
2592
-            $this->_redirect_after_action(false, '', '', array(), true);
2593
-        }
2594
-        $success = 0;
2595
-        $overwrite_msgs = false;
2596
-        // Checkboxes
2597
-        if (! is_array($this->_req_data['_REG_ID'])) {
2598
-            $this->_req_data['_REG_ID'] = array($this->_req_data['_REG_ID']);
2599
-        }
2600
-        $reg_count = count($this->_req_data['_REG_ID']);
2601
-        // cycle thru checkboxes
2602
-        foreach ($this->_req_data['_REG_ID'] as $REG_ID) {
2603
-            /** @var EE_Registration $REG */
2604
-            $REG = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
2605
-            $payments = $REG->registration_payments();
2606
-            if (! empty($payments)) {
2607
-                $name = $REG->attendee() instanceof EE_Attendee
2608
-                    ? $REG->attendee()->full_name()
2609
-                    : esc_html__('Unknown Attendee', 'event_espresso');
2610
-                $overwrite_msgs = true;
2611
-                EE_Error::add_error(
2612
-                    sprintf(
2613
-                        esc_html__(
2614
-                            'The registration for %s could not be trashed because it has payments attached to the related transaction.  If you wish to trash this registration you must first delete the payments on the related transaction.',
2615
-                            'event_espresso'
2616
-                        ),
2617
-                        $name
2618
-                    ),
2619
-                    __FILE__,
2620
-                    __FUNCTION__,
2621
-                    __LINE__
2622
-                );
2623
-                // can't trash this registration because it has payments.
2624
-                continue;
2625
-            }
2626
-            $updated = $trash ? $REG->delete(__METHOD__) : $REG->restore(__METHOD__);
2627
-            if ($updated) {
2628
-                $success++;
2629
-            }
2630
-        }
2631
-        $this->_redirect_after_action(
2632
-            $success === $reg_count, // were ALL registrations affected?
2633
-            $success > 1
2634
-                ? esc_html__('Registrations', 'event_espresso')
2635
-                : esc_html__('Registration', 'event_espresso'),
2636
-            $trash
2637
-                ? esc_html__('moved to the trash', 'event_espresso')
2638
-                : esc_html__('restored', 'event_espresso'),
2639
-            $this->mergeExistingRequestParamsWithRedirectArgs(array('action' => 'default')),
2640
-            $overwrite_msgs
2641
-        );
2642
-    }
2643
-
2644
-
2645
-    /**
2646
-     * This is used to permanently delete registrations.  Note, this will handle not only deleting permanently the
2647
-     * registration but also.
2648
-     * 1. Removing relations to EE_Attendee
2649
-     * 2. Deleting permanently the related transaction, but ONLY if all related registrations to the transaction are
2650
-     * ALSO trashed.
2651
-     * 3. Deleting permanently any related Line items but only if the above conditions are met.
2652
-     * 4. Removing relationships between all tickets and the related registrations
2653
-     * 5. Deleting permanently any related Answers (and the answers for other related registrations that were deleted.)
2654
-     * 6. Deleting permanently any related Checkins.
2655
-     *
2656
-     * @return void
2657
-     * @throws EE_Error
2658
-     * @throws InvalidArgumentException
2659
-     * @throws InvalidDataTypeException
2660
-     * @throws InvalidInterfaceException
2661
-     * @throws ReflectionException
2662
-     */
2663
-    protected function _delete_registrations()
2664
-    {
2665
-        $REG_MDL = $this->getRegistrationModel();
2666
-        $success = 1;
2667
-        // Checkboxes
2668
-        if (! empty($this->_req_data['_REG_ID']) && is_array($this->_req_data['_REG_ID'])) {
2669
-            // if array has more than one element than success message should be plural
2670
-            $success = count($this->_req_data['_REG_ID']) > 1 ? 2 : 1;
2671
-            // cycle thru checkboxes
2672
-            foreach ($this->_req_data['_REG_ID'] as $REG_ID) {
2673
-                $REG = $REG_MDL->get_one_by_ID($REG_ID);
2674
-                if (! $REG instanceof EE_Registration) {
2675
-                    continue;
2676
-                }
2677
-                $deleted = $this->_delete_registration($REG);
2678
-                if (! $deleted) {
2679
-                    $success = 0;
2680
-                }
2681
-            }
2682
-        } else {
2683
-            // grab single id and delete
2684
-            $REG_ID = $this->_req_data['_REG_ID'];
2685
-            /** @var EE_Registration $REG */
2686
-            $REG = $REG_MDL->get_one_by_ID($REG_ID);
2687
-            $deleted = $this->_delete_registration($REG);
2688
-            if (! $deleted) {
2689
-                $success = 0;
2690
-            }
2691
-        }
2692
-        $what = $success > 1
2693
-            ? esc_html__('Registrations', 'event_espresso')
2694
-            : esc_html__('Registration', 'event_espresso');
2695
-        $action_desc = esc_html__('permanently deleted.', 'event_espresso');
2696
-        $this->_redirect_after_action(
2697
-            $success,
2698
-            $what,
2699
-            $action_desc,
2700
-            $this->mergeExistingRequestParamsWithRedirectArgs(['action' => 'default']),
2701
-            true
2702
-        );
2703
-    }
2704
-
2705
-
2706
-    /**
2707
-     * handles the permanent deletion of a registration.  See comments with _delete_registrations() for details on what
2708
-     * models get affected.
2709
-     *
2710
-     * @param EE_Registration $REG registration to be deleted permanently
2711
-     * @return bool true = successful deletion, false = fail.
2712
-     * @throws EE_Error
2713
-     * @throws InvalidArgumentException
2714
-     * @throws InvalidDataTypeException
2715
-     * @throws InvalidInterfaceException
2716
-     * @throws ReflectionException
2717
-     */
2718
-    protected function _delete_registration(EE_Registration $REG)
2719
-    {
2720
-        // first we start with the transaction... ultimately, we WILL not delete permanently if there are any related
2721
-        // registrations on the transaction that are NOT trashed.
2722
-        $TXN = $REG->get_first_related('Transaction');
2723
-        if (! $TXN instanceof EE_Transaction) {
2724
-            EE_Error::add_error(
2725
-                sprintf(
2726
-                    esc_html__(
2727
-                        'Unable to permanently delete registration %d because its related transaction has already been deleted. If you can restore the related transaction to the database then this registration can be deleted.',
2728
-                        'event_espresso'
2729
-                    ),
2730
-                    $REG->id()
2731
-                ),
2732
-                __FILE__,
2733
-                __FUNCTION__,
2734
-                __LINE__
2735
-            );
2736
-            return false;
2737
-        }
2738
-        $REGS = $TXN->get_many_related('Registration');
2739
-        $all_trashed = true;
2740
-        foreach ($REGS as $registration) {
2741
-            if (! $registration->get('REG_deleted')) {
2742
-                $all_trashed = false;
2743
-            }
2744
-        }
2745
-        if (! $all_trashed) {
2746
-            EE_Error::add_error(
2747
-                esc_html__(
2748
-                    'Unable to permanently delete this registration. Before this registration can be permanently deleted, all registrations made in the same transaction must be trashed as well.  These registrations will be permanently deleted in the same action.',
2749
-                    'event_espresso'
2750
-                ),
2751
-                __FILE__,
2752
-                __FUNCTION__,
2753
-                __LINE__
2754
-            );
2755
-            return false;
2756
-        }
2757
-        // k made it here so that means we can delete all the related transactions and their answers (but let's do them
2758
-        // separately from THIS one).
2759
-        foreach ($REGS as $registration) {
2760
-            // delete related answers
2761
-            $registration->delete_related_permanently('Answer');
2762
-            // remove relationship to EE_Attendee (but we ALWAYS leave the contact record intact)
2763
-            $attendee = $registration->get_first_related('Attendee');
2764
-            if ($attendee instanceof EE_Attendee) {
2765
-                $registration->_remove_relation_to($attendee, 'Attendee');
2766
-            }
2767
-            // now remove relationships to tickets on this registration.
2768
-            $registration->_remove_relations('Ticket');
2769
-            // now delete permanently the checkins related to this registration.
2770
-            $registration->delete_related_permanently('Checkin');
2771
-            if ($registration->ID() === $REG->ID()) {
2772
-                continue;
2773
-            } //we don't want to delete permanently the existing registration just yet.
2774
-            // remove relation to transaction for these registrations if NOT the existing registrations
2775
-            $registration->_remove_relations('Transaction');
2776
-            // delete permanently any related messages.
2777
-            $registration->delete_related_permanently('Message');
2778
-            // now delete this registration permanently
2779
-            $registration->delete_permanently();
2780
-        }
2781
-        // now all related registrations on the transaction are handled.  So let's just handle this registration itself
2782
-        // (the transaction and line items should be all that's left).
2783
-        // delete the line items related to the transaction for this registration.
2784
-        $TXN->delete_related_permanently('Line_Item');
2785
-        // we need to remove all the relationships on the transaction
2786
-        $TXN->delete_related_permanently('Payment');
2787
-        $TXN->delete_related_permanently('Extra_Meta');
2788
-        $TXN->delete_related_permanently('Message');
2789
-        // now we can delete this REG permanently (and the transaction of course)
2790
-        $REG->delete_related_permanently('Transaction');
2791
-        return $REG->delete_permanently();
2792
-    }
2793
-
2794
-
2795
-    /**
2796
-     *    generates HTML for the Register New Attendee Admin page
2797
-     *
2798
-     * @access private
2799
-     * @throws DomainException
2800
-     * @throws EE_Error
2801
-     * @throws InvalidArgumentException
2802
-     * @throws InvalidDataTypeException
2803
-     * @throws InvalidInterfaceException
2804
-     * @throws ReflectionException
2805
-     */
2806
-    public function new_registration()
2807
-    {
2808
-        if (! $this->_set_reg_event()) {
2809
-            throw new EE_Error(
2810
-                esc_html__(
2811
-                    'Unable to continue with registering because there is no Event ID in the request',
2812
-                    'event_espresso'
2813
-                )
2814
-            );
2815
-        }
2816
-        EE_Registry::instance()->REQ->set_espresso_page(true);
2817
-        // gotta start with a clean slate if we're not coming here via ajax
2818
-        if (! defined('DOING_AJAX')
2819
-            && (! isset($this->_req_data['processing_registration']) || isset($this->_req_data['step_error']))
2820
-        ) {
2821
-            EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
2822
-        }
2823
-        $this->_template_args['event_name'] = '';
2824
-        // event name
2825
-        if ($this->_reg_event) {
2826
-            $this->_template_args['event_name'] = $this->_reg_event->name();
2827
-            $edit_event_url = self::add_query_args_and_nonce(
2828
-                array(
2829
-                    'action' => 'edit',
2830
-                    'post'   => $this->_reg_event->ID(),
2831
-                ),
2832
-                EVENTS_ADMIN_URL
2833
-            );
2834
-            $edit_event_lnk = '<a href="'
2835
-                              . $edit_event_url
2836
-                              . '" title="'
2837
-                              . esc_attr__('Edit ', 'event_espresso')
2838
-                              . $this->_reg_event->name()
2839
-                              . '">'
2840
-                              . esc_html__('Edit Event', 'event_espresso')
2841
-                              . '</a>';
2842
-            $this->_template_args['event_name'] .= ' <span class="admin-page-header-edit-lnk not-bold">'
2843
-                                                   . $edit_event_lnk
2844
-                                                   . '</span>';
2845
-        }
2846
-        $this->_template_args['step_content'] = $this->_get_registration_step_content();
2847
-        if (defined('DOING_AJAX')) {
2848
-            $this->_return_json();
2849
-        }
2850
-        // grab header
2851
-        $template_path =
2852
-            REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee.template.php';
2853
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
2854
-            $template_path,
2855
-            $this->_template_args,
2856
-            true
2857
-        );
2858
-        // $this->_set_publish_post_box_vars( NULL, FALSE, FALSE, NULL, FALSE );
2859
-        // the details template wrapper
2860
-        $this->display_admin_page_with_sidebar();
2861
-    }
2862
-
2863
-
2864
-    /**
2865
-     * This returns the content for a registration step
2866
-     *
2867
-     * @access protected
2868
-     * @return string html
2869
-     * @throws DomainException
2870
-     * @throws EE_Error
2871
-     * @throws InvalidArgumentException
2872
-     * @throws InvalidDataTypeException
2873
-     * @throws InvalidInterfaceException
2874
-     */
2875
-    protected function _get_registration_step_content()
2876
-    {
2877
-        if (isset($_COOKIE['ee_registration_added']) && $_COOKIE['ee_registration_added']) {
2878
-            $warning_msg = sprintf(
2879
-                esc_html__(
2880
-                    '%2$sWARNING!!!%3$s%1$sPlease do not use the back button to return to this page for the purpose of adding another registration.%1$sThis can result in lost and/or corrupted data.%1$sIf you wish to add another registration, then please click the%1$s%7$s"Add Another New Registration to Event"%8$s button%1$son the Transaction details page, after you are redirected.%1$s%1$s%4$s redirecting in %5$s seconds %6$s',
2881
-                    'event_espresso'
2882
-                ),
2883
-                '<br />',
2884
-                '<h3 class="important-notice">',
2885
-                '</h3>',
2886
-                '<div class="float-right">',
2887
-                '<span id="redirect_timer" class="important-notice">30</span>',
2888
-                '</div>',
2889
-                '<b>',
2890
-                '</b>'
2891
-            );
2892
-            return '
2305
+	}
2306
+
2307
+
2308
+	/**
2309
+	 * Updates the registration's custom questions according to the form info, if the form is submitted.
2310
+	 * If it's not a post, the "view_registrations" route will be called next on the SAME request
2311
+	 * to display the page
2312
+	 *
2313
+	 * @access protected
2314
+	 * @return void
2315
+	 * @throws EE_Error
2316
+	 * @throws InvalidArgumentException
2317
+	 * @throws InvalidDataTypeException
2318
+	 * @throws InvalidInterfaceException
2319
+	 * @throws ReflectionException
2320
+	 */
2321
+	protected function _update_attendee_registration_form()
2322
+	{
2323
+		do_action('AHEE__Registrations_Admin_Page___update_attendee_registration_form__start', $this);
2324
+		if ($_SERVER['REQUEST_METHOD'] === 'POST') {
2325
+			$REG_ID = isset($this->_req_data['_REG_ID']) ? absint($this->_req_data['_REG_ID']) : false;
2326
+			$success = $this->_save_reg_custom_questions_form($REG_ID);
2327
+			if ($success) {
2328
+				$what = esc_html__('Registration Form', 'event_espresso');
2329
+				$route = $REG_ID ? array('action' => 'view_registration', '_REG_ID' => $REG_ID)
2330
+					: array('action' => 'default');
2331
+				$this->_redirect_after_action($success, $what, esc_html__('updated', 'event_espresso'), $route);
2332
+			}
2333
+		}
2334
+	}
2335
+
2336
+
2337
+	/**
2338
+	 * Gets the form for saving registrations custom questions (if done
2339
+	 * previously retrieves the cached form object, which may have validation errors in it)
2340
+	 *
2341
+	 * @param int $REG_ID
2342
+	 * @return EE_Registration_Custom_Questions_Form
2343
+	 * @throws EE_Error
2344
+	 * @throws InvalidArgumentException
2345
+	 * @throws InvalidDataTypeException
2346
+	 * @throws InvalidInterfaceException
2347
+	 */
2348
+	protected function _get_reg_custom_questions_form($REG_ID)
2349
+	{
2350
+		if (! $this->_reg_custom_questions_form) {
2351
+			require_once(REG_ADMIN . 'form_sections/EE_Registration_Custom_Questions_Form.form.php');
2352
+			$this->_reg_custom_questions_form = new EE_Registration_Custom_Questions_Form(
2353
+				$this->getRegistrationModel()->get_one_by_ID($REG_ID)
2354
+			);
2355
+			$this->_reg_custom_questions_form->_construct_finalize(null, null);
2356
+		}
2357
+		return $this->_reg_custom_questions_form;
2358
+	}
2359
+
2360
+
2361
+	/**
2362
+	 * Saves
2363
+	 *
2364
+	 * @access private
2365
+	 * @param bool $REG_ID
2366
+	 * @return bool
2367
+	 * @throws EE_Error
2368
+	 * @throws InvalidArgumentException
2369
+	 * @throws InvalidDataTypeException
2370
+	 * @throws InvalidInterfaceException
2371
+	 * @throws ReflectionException
2372
+	 */
2373
+	private function _save_reg_custom_questions_form($REG_ID = false)
2374
+	{
2375
+		if (! $REG_ID) {
2376
+			EE_Error::add_error(
2377
+				esc_html__(
2378
+					'An error occurred. No registration ID was received.',
2379
+					'event_espresso'
2380
+				),
2381
+				__FILE__,
2382
+				__FUNCTION__,
2383
+				__LINE__
2384
+			);
2385
+		}
2386
+		$form = $this->_get_reg_custom_questions_form($REG_ID);
2387
+		$form->receive_form_submission($this->_req_data);
2388
+		$success = false;
2389
+		if ($form->is_valid()) {
2390
+			foreach ($form->subforms() as $question_group_id => $question_group_form) {
2391
+				foreach ($question_group_form->inputs() as $question_id => $input) {
2392
+					$where_conditions = array(
2393
+						'QST_ID' => $question_id,
2394
+						'REG_ID' => $REG_ID,
2395
+					);
2396
+					$possibly_new_values = array(
2397
+						'ANS_value' => $input->normalized_value(),
2398
+					);
2399
+					$answer = EEM_Answer::instance()->get_one(array($where_conditions));
2400
+					if ($answer instanceof EE_Answer) {
2401
+						$success = $answer->save($possibly_new_values);
2402
+					} else {
2403
+						// insert it then
2404
+						$cols_n_vals = array_merge($where_conditions, $possibly_new_values);
2405
+						$answer = EE_Answer::new_instance($cols_n_vals);
2406
+						$success = $answer->save();
2407
+					}
2408
+				}
2409
+			}
2410
+		} else {
2411
+			EE_Error::add_error($form->get_validation_error_string(), __FILE__, __FUNCTION__, __LINE__);
2412
+		}
2413
+		return $success;
2414
+	}
2415
+
2416
+
2417
+	/**
2418
+	 *        generates HTML for the Registration main meta box
2419
+	 *
2420
+	 * @access public
2421
+	 * @return void
2422
+	 * @throws DomainException
2423
+	 * @throws EE_Error
2424
+	 * @throws InvalidArgumentException
2425
+	 * @throws InvalidDataTypeException
2426
+	 * @throws InvalidInterfaceException
2427
+	 * @throws ReflectionException
2428
+	 */
2429
+	public function _reg_attendees_meta_box()
2430
+	{
2431
+		$REG = $this->getRegistrationModel();
2432
+		// get all other registrations on this transaction, and cache
2433
+		// the attendees for them so we don't have to run another query using force_join
2434
+		$registrations = $REG->get_all(
2435
+			array(
2436
+				array(
2437
+					'TXN_ID' => $this->_registration->transaction_ID(),
2438
+					'REG_ID' => array('!=', $this->_registration->ID()),
2439
+				),
2440
+				'force_join' => array('Attendee'),
2441
+				'default_where_conditions' => 'other_models_only',
2442
+			)
2443
+		);
2444
+		$this->_template_args['attendees'] = array();
2445
+		$this->_template_args['attendee_notice'] = '';
2446
+		if (empty($registrations)
2447
+			|| (is_array($registrations)
2448
+				&& ! EEH_Array::get_one_item_from_array($registrations))
2449
+		) {
2450
+			EE_Error::add_error(
2451
+				esc_html__(
2452
+					'There are no records attached to this registration. Something may have gone wrong with the registration',
2453
+					'event_espresso'
2454
+				),
2455
+				__FILE__,
2456
+				__FUNCTION__,
2457
+				__LINE__
2458
+			);
2459
+			$this->_template_args['attendee_notice'] = EE_Error::get_notices();
2460
+		} else {
2461
+			$att_nmbr = 1;
2462
+			foreach ($registrations as $registration) {
2463
+				/* @var $registration EE_Registration */
2464
+				$attendee = $registration->attendee()
2465
+					? $registration->attendee()
2466
+					: $this->getAttendeeModel()->create_default_object();
2467
+				$this->_template_args['attendees'][ $att_nmbr ]['STS_ID'] = $registration->status_ID();
2468
+				$this->_template_args['attendees'][ $att_nmbr ]['fname'] = $attendee->fname();
2469
+				$this->_template_args['attendees'][ $att_nmbr ]['lname'] = $attendee->lname();
2470
+				$this->_template_args['attendees'][ $att_nmbr ]['email'] = $attendee->email();
2471
+				$this->_template_args['attendees'][ $att_nmbr ]['final_price'] = $registration->final_price();
2472
+				$this->_template_args['attendees'][ $att_nmbr ]['address'] = implode(
2473
+					', ',
2474
+					$attendee->full_address_as_array()
2475
+				);
2476
+				$this->_template_args['attendees'][ $att_nmbr ]['att_link'] = self::add_query_args_and_nonce(
2477
+					array(
2478
+						'action' => 'edit_attendee',
2479
+						'post'   => $attendee->ID(),
2480
+					),
2481
+					REG_ADMIN_URL
2482
+				);
2483
+				$this->_template_args['attendees'][ $att_nmbr ]['event_name'] = $registration->event_obj() instanceof EE_Event
2484
+					? $registration->event_obj()->name()
2485
+					: '';
2486
+				$att_nmbr++;
2487
+			}
2488
+			$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2489
+		}
2490
+		$template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_attendees.template.php';
2491
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);
2492
+	}
2493
+
2494
+
2495
+	/**
2496
+	 *        generates HTML for the Edit Registration side meta box
2497
+	 *
2498
+	 * @access public
2499
+	 * @return void
2500
+	 * @throws DomainException
2501
+	 * @throws EE_Error
2502
+	 * @throws InvalidArgumentException
2503
+	 * @throws InvalidDataTypeException
2504
+	 * @throws InvalidInterfaceException
2505
+	 * @throws ReflectionException
2506
+	 */
2507
+	public function _reg_registrant_side_meta_box()
2508
+	{
2509
+		/*@var $attendee EE_Attendee */
2510
+		$att_check = $this->_registration->attendee();
2511
+		$attendee = $att_check instanceof EE_Attendee
2512
+			? $att_check
2513
+			: $this->getAttendeeModel()->create_default_object();
2514
+		// now let's determine if this is not the primary registration.  If it isn't then we set the
2515
+		// primary_registration object for reference BUT ONLY if the Attendee object loaded is not the same as the
2516
+		// primary registration object (that way we know if we need to show create button or not)
2517
+		if (! $this->_registration->is_primary_registrant()) {
2518
+			$primary_registration = $this->_registration->get_primary_registration();
2519
+			$primary_attendee = $primary_registration instanceof EE_Registration ? $primary_registration->attendee()
2520
+				: null;
2521
+			if (! $primary_attendee instanceof EE_Attendee || $attendee->ID() !== $primary_attendee->ID()) {
2522
+				// in here?  This means the displayed registration is not the primary registrant but ALREADY HAS its own
2523
+				// custom attendee object so let's not worry about the primary reg.
2524
+				$primary_registration = null;
2525
+			}
2526
+		} else {
2527
+			$primary_registration = null;
2528
+		}
2529
+		$this->_template_args['ATT_ID'] = $attendee->ID();
2530
+		$this->_template_args['fname'] = $attendee->fname();
2531
+		$this->_template_args['lname'] = $attendee->lname();
2532
+		$this->_template_args['email'] = $attendee->email();
2533
+		$this->_template_args['phone'] = $attendee->phone();
2534
+		$this->_template_args['formatted_address'] = EEH_Address::format($attendee);
2535
+		// edit link
2536
+		$this->_template_args['att_edit_link'] = EE_Admin_Page::add_query_args_and_nonce(
2537
+			array(
2538
+				'action' => 'edit_attendee',
2539
+				'post'   => $attendee->ID(),
2540
+			),
2541
+			REG_ADMIN_URL
2542
+		);
2543
+		$this->_template_args['att_edit_label'] = esc_html__('View/Edit Contact', 'event_espresso');
2544
+		// create link
2545
+		$this->_template_args['create_link'] = $primary_registration instanceof EE_Registration
2546
+			? EE_Admin_Page::add_query_args_and_nonce(
2547
+				array(
2548
+					'action'  => 'duplicate_attendee',
2549
+					'_REG_ID' => $this->_registration->ID(),
2550
+				),
2551
+				REG_ADMIN_URL
2552
+			) : '';
2553
+		$this->_template_args['create_label'] = esc_html__('Create Contact', 'event_espresso');
2554
+		$this->_template_args['att_check'] = $att_check;
2555
+		$template_path = REG_TEMPLATE_PATH . 'reg_admin_details_side_meta_box_registrant.template.php';
2556
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);
2557
+	}
2558
+
2559
+
2560
+	/**
2561
+	 * trash or restore registrations
2562
+	 *
2563
+	 * @param  boolean $trash whether to archive or restore
2564
+	 * @return void
2565
+	 * @throws DomainException
2566
+	 * @throws EE_Error
2567
+	 * @throws EntityNotFoundException
2568
+	 * @throws InvalidArgumentException
2569
+	 * @throws InvalidDataTypeException
2570
+	 * @throws InvalidInterfaceException
2571
+	 * @throws ReflectionException
2572
+	 * @throws RuntimeException
2573
+	 * @throws UnexpectedEntityException
2574
+	 * @access protected
2575
+	 */
2576
+	protected function _trash_or_restore_registrations($trash = true)
2577
+	{
2578
+		// if empty _REG_ID then get out because there's nothing to do
2579
+		if (empty($this->_req_data['_REG_ID'])) {
2580
+			EE_Error::add_error(
2581
+				sprintf(
2582
+					esc_html__(
2583
+						'In order to %1$s registrations you must select which ones you wish to %1$s by clicking the checkboxes.',
2584
+						'event_espresso'
2585
+					),
2586
+					$trash ? 'trash' : 'restore'
2587
+				),
2588
+				__FILE__,
2589
+				__LINE__,
2590
+				__FUNCTION__
2591
+			);
2592
+			$this->_redirect_after_action(false, '', '', array(), true);
2593
+		}
2594
+		$success = 0;
2595
+		$overwrite_msgs = false;
2596
+		// Checkboxes
2597
+		if (! is_array($this->_req_data['_REG_ID'])) {
2598
+			$this->_req_data['_REG_ID'] = array($this->_req_data['_REG_ID']);
2599
+		}
2600
+		$reg_count = count($this->_req_data['_REG_ID']);
2601
+		// cycle thru checkboxes
2602
+		foreach ($this->_req_data['_REG_ID'] as $REG_ID) {
2603
+			/** @var EE_Registration $REG */
2604
+			$REG = $this->getRegistrationModel()->get_one_by_ID($REG_ID);
2605
+			$payments = $REG->registration_payments();
2606
+			if (! empty($payments)) {
2607
+				$name = $REG->attendee() instanceof EE_Attendee
2608
+					? $REG->attendee()->full_name()
2609
+					: esc_html__('Unknown Attendee', 'event_espresso');
2610
+				$overwrite_msgs = true;
2611
+				EE_Error::add_error(
2612
+					sprintf(
2613
+						esc_html__(
2614
+							'The registration for %s could not be trashed because it has payments attached to the related transaction.  If you wish to trash this registration you must first delete the payments on the related transaction.',
2615
+							'event_espresso'
2616
+						),
2617
+						$name
2618
+					),
2619
+					__FILE__,
2620
+					__FUNCTION__,
2621
+					__LINE__
2622
+				);
2623
+				// can't trash this registration because it has payments.
2624
+				continue;
2625
+			}
2626
+			$updated = $trash ? $REG->delete(__METHOD__) : $REG->restore(__METHOD__);
2627
+			if ($updated) {
2628
+				$success++;
2629
+			}
2630
+		}
2631
+		$this->_redirect_after_action(
2632
+			$success === $reg_count, // were ALL registrations affected?
2633
+			$success > 1
2634
+				? esc_html__('Registrations', 'event_espresso')
2635
+				: esc_html__('Registration', 'event_espresso'),
2636
+			$trash
2637
+				? esc_html__('moved to the trash', 'event_espresso')
2638
+				: esc_html__('restored', 'event_espresso'),
2639
+			$this->mergeExistingRequestParamsWithRedirectArgs(array('action' => 'default')),
2640
+			$overwrite_msgs
2641
+		);
2642
+	}
2643
+
2644
+
2645
+	/**
2646
+	 * This is used to permanently delete registrations.  Note, this will handle not only deleting permanently the
2647
+	 * registration but also.
2648
+	 * 1. Removing relations to EE_Attendee
2649
+	 * 2. Deleting permanently the related transaction, but ONLY if all related registrations to the transaction are
2650
+	 * ALSO trashed.
2651
+	 * 3. Deleting permanently any related Line items but only if the above conditions are met.
2652
+	 * 4. Removing relationships between all tickets and the related registrations
2653
+	 * 5. Deleting permanently any related Answers (and the answers for other related registrations that were deleted.)
2654
+	 * 6. Deleting permanently any related Checkins.
2655
+	 *
2656
+	 * @return void
2657
+	 * @throws EE_Error
2658
+	 * @throws InvalidArgumentException
2659
+	 * @throws InvalidDataTypeException
2660
+	 * @throws InvalidInterfaceException
2661
+	 * @throws ReflectionException
2662
+	 */
2663
+	protected function _delete_registrations()
2664
+	{
2665
+		$REG_MDL = $this->getRegistrationModel();
2666
+		$success = 1;
2667
+		// Checkboxes
2668
+		if (! empty($this->_req_data['_REG_ID']) && is_array($this->_req_data['_REG_ID'])) {
2669
+			// if array has more than one element than success message should be plural
2670
+			$success = count($this->_req_data['_REG_ID']) > 1 ? 2 : 1;
2671
+			// cycle thru checkboxes
2672
+			foreach ($this->_req_data['_REG_ID'] as $REG_ID) {
2673
+				$REG = $REG_MDL->get_one_by_ID($REG_ID);
2674
+				if (! $REG instanceof EE_Registration) {
2675
+					continue;
2676
+				}
2677
+				$deleted = $this->_delete_registration($REG);
2678
+				if (! $deleted) {
2679
+					$success = 0;
2680
+				}
2681
+			}
2682
+		} else {
2683
+			// grab single id and delete
2684
+			$REG_ID = $this->_req_data['_REG_ID'];
2685
+			/** @var EE_Registration $REG */
2686
+			$REG = $REG_MDL->get_one_by_ID($REG_ID);
2687
+			$deleted = $this->_delete_registration($REG);
2688
+			if (! $deleted) {
2689
+				$success = 0;
2690
+			}
2691
+		}
2692
+		$what = $success > 1
2693
+			? esc_html__('Registrations', 'event_espresso')
2694
+			: esc_html__('Registration', 'event_espresso');
2695
+		$action_desc = esc_html__('permanently deleted.', 'event_espresso');
2696
+		$this->_redirect_after_action(
2697
+			$success,
2698
+			$what,
2699
+			$action_desc,
2700
+			$this->mergeExistingRequestParamsWithRedirectArgs(['action' => 'default']),
2701
+			true
2702
+		);
2703
+	}
2704
+
2705
+
2706
+	/**
2707
+	 * handles the permanent deletion of a registration.  See comments with _delete_registrations() for details on what
2708
+	 * models get affected.
2709
+	 *
2710
+	 * @param EE_Registration $REG registration to be deleted permanently
2711
+	 * @return bool true = successful deletion, false = fail.
2712
+	 * @throws EE_Error
2713
+	 * @throws InvalidArgumentException
2714
+	 * @throws InvalidDataTypeException
2715
+	 * @throws InvalidInterfaceException
2716
+	 * @throws ReflectionException
2717
+	 */
2718
+	protected function _delete_registration(EE_Registration $REG)
2719
+	{
2720
+		// first we start with the transaction... ultimately, we WILL not delete permanently if there are any related
2721
+		// registrations on the transaction that are NOT trashed.
2722
+		$TXN = $REG->get_first_related('Transaction');
2723
+		if (! $TXN instanceof EE_Transaction) {
2724
+			EE_Error::add_error(
2725
+				sprintf(
2726
+					esc_html__(
2727
+						'Unable to permanently delete registration %d because its related transaction has already been deleted. If you can restore the related transaction to the database then this registration can be deleted.',
2728
+						'event_espresso'
2729
+					),
2730
+					$REG->id()
2731
+				),
2732
+				__FILE__,
2733
+				__FUNCTION__,
2734
+				__LINE__
2735
+			);
2736
+			return false;
2737
+		}
2738
+		$REGS = $TXN->get_many_related('Registration');
2739
+		$all_trashed = true;
2740
+		foreach ($REGS as $registration) {
2741
+			if (! $registration->get('REG_deleted')) {
2742
+				$all_trashed = false;
2743
+			}
2744
+		}
2745
+		if (! $all_trashed) {
2746
+			EE_Error::add_error(
2747
+				esc_html__(
2748
+					'Unable to permanently delete this registration. Before this registration can be permanently deleted, all registrations made in the same transaction must be trashed as well.  These registrations will be permanently deleted in the same action.',
2749
+					'event_espresso'
2750
+				),
2751
+				__FILE__,
2752
+				__FUNCTION__,
2753
+				__LINE__
2754
+			);
2755
+			return false;
2756
+		}
2757
+		// k made it here so that means we can delete all the related transactions and their answers (but let's do them
2758
+		// separately from THIS one).
2759
+		foreach ($REGS as $registration) {
2760
+			// delete related answers
2761
+			$registration->delete_related_permanently('Answer');
2762
+			// remove relationship to EE_Attendee (but we ALWAYS leave the contact record intact)
2763
+			$attendee = $registration->get_first_related('Attendee');
2764
+			if ($attendee instanceof EE_Attendee) {
2765
+				$registration->_remove_relation_to($attendee, 'Attendee');
2766
+			}
2767
+			// now remove relationships to tickets on this registration.
2768
+			$registration->_remove_relations('Ticket');
2769
+			// now delete permanently the checkins related to this registration.
2770
+			$registration->delete_related_permanently('Checkin');
2771
+			if ($registration->ID() === $REG->ID()) {
2772
+				continue;
2773
+			} //we don't want to delete permanently the existing registration just yet.
2774
+			// remove relation to transaction for these registrations if NOT the existing registrations
2775
+			$registration->_remove_relations('Transaction');
2776
+			// delete permanently any related messages.
2777
+			$registration->delete_related_permanently('Message');
2778
+			// now delete this registration permanently
2779
+			$registration->delete_permanently();
2780
+		}
2781
+		// now all related registrations on the transaction are handled.  So let's just handle this registration itself
2782
+		// (the transaction and line items should be all that's left).
2783
+		// delete the line items related to the transaction for this registration.
2784
+		$TXN->delete_related_permanently('Line_Item');
2785
+		// we need to remove all the relationships on the transaction
2786
+		$TXN->delete_related_permanently('Payment');
2787
+		$TXN->delete_related_permanently('Extra_Meta');
2788
+		$TXN->delete_related_permanently('Message');
2789
+		// now we can delete this REG permanently (and the transaction of course)
2790
+		$REG->delete_related_permanently('Transaction');
2791
+		return $REG->delete_permanently();
2792
+	}
2793
+
2794
+
2795
+	/**
2796
+	 *    generates HTML for the Register New Attendee Admin page
2797
+	 *
2798
+	 * @access private
2799
+	 * @throws DomainException
2800
+	 * @throws EE_Error
2801
+	 * @throws InvalidArgumentException
2802
+	 * @throws InvalidDataTypeException
2803
+	 * @throws InvalidInterfaceException
2804
+	 * @throws ReflectionException
2805
+	 */
2806
+	public function new_registration()
2807
+	{
2808
+		if (! $this->_set_reg_event()) {
2809
+			throw new EE_Error(
2810
+				esc_html__(
2811
+					'Unable to continue with registering because there is no Event ID in the request',
2812
+					'event_espresso'
2813
+				)
2814
+			);
2815
+		}
2816
+		EE_Registry::instance()->REQ->set_espresso_page(true);
2817
+		// gotta start with a clean slate if we're not coming here via ajax
2818
+		if (! defined('DOING_AJAX')
2819
+			&& (! isset($this->_req_data['processing_registration']) || isset($this->_req_data['step_error']))
2820
+		) {
2821
+			EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
2822
+		}
2823
+		$this->_template_args['event_name'] = '';
2824
+		// event name
2825
+		if ($this->_reg_event) {
2826
+			$this->_template_args['event_name'] = $this->_reg_event->name();
2827
+			$edit_event_url = self::add_query_args_and_nonce(
2828
+				array(
2829
+					'action' => 'edit',
2830
+					'post'   => $this->_reg_event->ID(),
2831
+				),
2832
+				EVENTS_ADMIN_URL
2833
+			);
2834
+			$edit_event_lnk = '<a href="'
2835
+							  . $edit_event_url
2836
+							  . '" title="'
2837
+							  . esc_attr__('Edit ', 'event_espresso')
2838
+							  . $this->_reg_event->name()
2839
+							  . '">'
2840
+							  . esc_html__('Edit Event', 'event_espresso')
2841
+							  . '</a>';
2842
+			$this->_template_args['event_name'] .= ' <span class="admin-page-header-edit-lnk not-bold">'
2843
+												   . $edit_event_lnk
2844
+												   . '</span>';
2845
+		}
2846
+		$this->_template_args['step_content'] = $this->_get_registration_step_content();
2847
+		if (defined('DOING_AJAX')) {
2848
+			$this->_return_json();
2849
+		}
2850
+		// grab header
2851
+		$template_path =
2852
+			REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee.template.php';
2853
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
2854
+			$template_path,
2855
+			$this->_template_args,
2856
+			true
2857
+		);
2858
+		// $this->_set_publish_post_box_vars( NULL, FALSE, FALSE, NULL, FALSE );
2859
+		// the details template wrapper
2860
+		$this->display_admin_page_with_sidebar();
2861
+	}
2862
+
2863
+
2864
+	/**
2865
+	 * This returns the content for a registration step
2866
+	 *
2867
+	 * @access protected
2868
+	 * @return string html
2869
+	 * @throws DomainException
2870
+	 * @throws EE_Error
2871
+	 * @throws InvalidArgumentException
2872
+	 * @throws InvalidDataTypeException
2873
+	 * @throws InvalidInterfaceException
2874
+	 */
2875
+	protected function _get_registration_step_content()
2876
+	{
2877
+		if (isset($_COOKIE['ee_registration_added']) && $_COOKIE['ee_registration_added']) {
2878
+			$warning_msg = sprintf(
2879
+				esc_html__(
2880
+					'%2$sWARNING!!!%3$s%1$sPlease do not use the back button to return to this page for the purpose of adding another registration.%1$sThis can result in lost and/or corrupted data.%1$sIf you wish to add another registration, then please click the%1$s%7$s"Add Another New Registration to Event"%8$s button%1$son the Transaction details page, after you are redirected.%1$s%1$s%4$s redirecting in %5$s seconds %6$s',
2881
+					'event_espresso'
2882
+				),
2883
+				'<br />',
2884
+				'<h3 class="important-notice">',
2885
+				'</h3>',
2886
+				'<div class="float-right">',
2887
+				'<span id="redirect_timer" class="important-notice">30</span>',
2888
+				'</div>',
2889
+				'<b>',
2890
+				'</b>'
2891
+			);
2892
+			return '
2893 2893
 	<div id="ee-add-reg-back-button-dv"><p>' . $warning_msg . '</p></div>
2894 2894
 	<script >
2895 2895
 		// WHOAH !!! it appears that someone is using the back button from the Transaction admin page
@@ -2902,868 +2902,868 @@  discard block
 block discarded – undo
2902 2902
 	        }
2903 2903
 	    }, 800 );
2904 2904
 	</script >';
2905
-        }
2906
-        $template_args = array(
2907
-            'title'                    => '',
2908
-            'content'                  => '',
2909
-            'step_button_text'         => '',
2910
-            'show_notification_toggle' => false,
2911
-        );
2912
-        // to indicate we're processing a new registration
2913
-        $hidden_fields = array(
2914
-            'processing_registration' => array(
2915
-                'type'  => 'hidden',
2916
-                'value' => 0,
2917
-            ),
2918
-            'event_id'                => array(
2919
-                'type'  => 'hidden',
2920
-                'value' => $this->_reg_event->ID(),
2921
-            ),
2922
-        );
2923
-        // if the cart is empty then we know we're at step one so we'll display ticket selector
2924
-        $cart = EE_Registry::instance()->SSN->cart();
2925
-        $step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
2926
-        switch ($step) {
2927
-            case 'ticket':
2928
-                $hidden_fields['processing_registration']['value'] = 1;
2929
-                $template_args['title'] = esc_html__(
2930
-                    'Step One: Select the Ticket for this registration',
2931
-                    'event_espresso'
2932
-                );
2933
-                $template_args['content'] =
2934
-                    EED_Ticket_Selector::instance()->display_ticket_selector($this->_reg_event);
2935
-                $template_args['content'] .= '</div>';
2936
-                $template_args['step_button_text'] = esc_html__(
2937
-                    'Add Tickets and Continue to Registrant Details',
2938
-                    'event_espresso'
2939
-                );
2940
-                $template_args['show_notification_toggle'] = false;
2941
-                break;
2942
-            case 'questions':
2943
-                $hidden_fields['processing_registration']['value'] = 2;
2944
-                $template_args['title'] = esc_html__(
2945
-                    'Step Two: Add Registrant Details for this Registration',
2946
-                    'event_espresso'
2947
-                );
2948
-                // in theory we should be able to run EED_SPCO at this point because the cart should have been setup
2949
-                // properly by the first process_reg_step run.
2950
-                $template_args['content'] =
2951
-                    EED_Single_Page_Checkout::registration_checkout_for_admin();
2952
-                $template_args['step_button_text'] = esc_html__(
2953
-                    'Save Registration and Continue to Details',
2954
-                    'event_espresso'
2955
-                );
2956
-                $template_args['show_notification_toggle'] = true;
2957
-                break;
2958
-        }
2959
-        // we come back to the process_registration_step route.
2960
-        $this->_set_add_edit_form_tags('process_reg_step', $hidden_fields);
2961
-        return EEH_Template::display_template(
2962
-            REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee_step_content.template.php',
2963
-            $template_args,
2964
-            true
2965
-        );
2966
-    }
2967
-
2968
-
2969
-    /**
2970
-     *        set_reg_event
2971
-     *
2972
-     * @access private
2973
-     * @return bool
2974
-     * @throws EE_Error
2975
-     * @throws InvalidArgumentException
2976
-     * @throws InvalidDataTypeException
2977
-     * @throws InvalidInterfaceException
2978
-     */
2979
-    private function _set_reg_event()
2980
-    {
2981
-        if (is_object($this->_reg_event)) {
2982
-            return true;
2983
-        }
2984
-        $EVT_ID = (! empty($this->_req_data['event_id'])) ? absint($this->_req_data['event_id']) : false;
2985
-        if (! $EVT_ID) {
2986
-            return false;
2987
-        }
2988
-        $this->_reg_event = $this->getEventModel()->get_one_by_ID($EVT_ID);
2989
-        return true;
2990
-    }
2991
-
2992
-
2993
-    /**
2994
-     * process_reg_step
2995
-     *
2996
-     * @access        public
2997
-     * @return string
2998
-     * @throws DomainException
2999
-     * @throws EE_Error
3000
-     * @throws InvalidArgumentException
3001
-     * @throws InvalidDataTypeException
3002
-     * @throws InvalidInterfaceException
3003
-     * @throws ReflectionException
3004
-     * @throws RuntimeException
3005
-     */
3006
-    public function process_reg_step()
3007
-    {
3008
-        EE_System::do_not_cache();
3009
-        $this->_set_reg_event();
3010
-        EE_Registry::instance()->REQ->set_espresso_page(true);
3011
-        EE_Registry::instance()->REQ->set('uts', time());
3012
-        // what step are we on?
3013
-        $cart = EE_Registry::instance()->SSN->cart();
3014
-        $step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
3015
-        // if doing ajax then we need to verify the nonce
3016
-        if (defined('DOING_AJAX')) {
3017
-            $nonce = isset($this->_req_data[ $this->_req_nonce ])
3018
-                ? sanitize_text_field($this->_req_data[ $this->_req_nonce ]) : '';
3019
-            $this->_verify_nonce($nonce, $this->_req_nonce);
3020
-        }
3021
-        switch ($step) {
3022
-            case 'ticket':
3023
-                // process ticket selection
3024
-                $success = EED_Ticket_Selector::instance()->process_ticket_selections();
3025
-                if ($success) {
3026
-                    EE_Error::add_success(
3027
-                        esc_html__(
3028
-                            'Tickets Selected. Now complete the registration.',
3029
-                            'event_espresso'
3030
-                        )
3031
-                    );
3032
-                } else {
3033
-                    $query_args['step_error'] = $this->_req_data['step_error'] = true;
3034
-                }
3035
-                if (defined('DOING_AJAX')) {
3036
-                    $this->new_registration(); // display next step
3037
-                } else {
3038
-                    $query_args = array(
3039
-                        'action'                  => 'new_registration',
3040
-                        'processing_registration' => 1,
3041
-                        'event_id'                => $this->_reg_event->ID(),
3042
-                        'uts'                     => time(),
3043
-                    );
3044
-                    $this->_redirect_after_action(
3045
-                        false,
3046
-                        '',
3047
-                        '',
3048
-                        $query_args,
3049
-                        true
3050
-                    );
3051
-                }
3052
-                break;
3053
-            case 'questions':
3054
-                if (! isset(
3055
-                    $this->_req_data['txn_reg_status_change'],
3056
-                    $this->_req_data['txn_reg_status_change']['send_notifications']
3057
-                )
3058
-                ) {
3059
-                    add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_false', 15);
3060
-                }
3061
-                // process registration
3062
-                $transaction = EED_Single_Page_Checkout::instance()->process_registration_from_admin();
3063
-                if ($cart instanceof EE_Cart) {
3064
-                    $grand_total = $cart->get_cart_grand_total();
3065
-                    if ($grand_total instanceof EE_Line_Item) {
3066
-                        $grand_total->save_this_and_descendants_to_txn();
3067
-                    }
3068
-                }
3069
-                if (! $transaction instanceof EE_Transaction) {
3070
-                    $query_args = array(
3071
-                        'action'                  => 'new_registration',
3072
-                        'processing_registration' => 2,
3073
-                        'event_id'                => $this->_reg_event->ID(),
3074
-                        'uts'                     => time(),
3075
-                    );
3076
-                    if (defined('DOING_AJAX')) {
3077
-                        // display registration form again because there are errors (maybe validation?)
3078
-                        $this->new_registration();
3079
-                        return;
3080
-                    }
3081
-                    $this->_redirect_after_action(
3082
-                        false,
3083
-                        '',
3084
-                        '',
3085
-                        $query_args,
3086
-                        true
3087
-                    );
3088
-                    return;
3089
-                }
3090
-                // maybe update status, and make sure to save transaction if not done already
3091
-                if (! $transaction->update_status_based_on_total_paid()) {
3092
-                    $transaction->save();
3093
-                }
3094
-                EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3095
-                $this->_req_data = array();
3096
-                $query_args = array(
3097
-                    'action'        => 'redirect_to_txn',
3098
-                    'TXN_ID'        => $transaction->ID(),
3099
-                    'EVT_ID'        => $this->_reg_event->ID(),
3100
-                    'event_name'    => urlencode($this->_reg_event->name()),
3101
-                    'redirect_from' => 'new_registration',
3102
-                );
3103
-                $this->_redirect_after_action(false, '', '', $query_args, true);
3104
-                break;
3105
-        }
3106
-        // what are you looking here for?  Should be nothing to do at this point.
3107
-    }
3108
-
3109
-
3110
-    /**
3111
-     * redirect_to_txn
3112
-     *
3113
-     * @access public
3114
-     * @return void
3115
-     * @throws EE_Error
3116
-     * @throws InvalidArgumentException
3117
-     * @throws InvalidDataTypeException
3118
-     * @throws InvalidInterfaceException
3119
-     * @throws ReflectionException
3120
-     */
3121
-    public function redirect_to_txn()
3122
-    {
3123
-        EE_System::do_not_cache();
3124
-        EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3125
-        $query_args = array(
3126
-            'action' => 'view_transaction',
3127
-            'TXN_ID' => isset($this->_req_data['TXN_ID']) ? absint($this->_req_data['TXN_ID']) : 0,
3128
-            'page'   => 'espresso_transactions',
3129
-        );
3130
-        if (isset($this->_req_data['EVT_ID'], $this->_req_data['redirect_from'])) {
3131
-            $query_args['EVT_ID'] = $this->_req_data['EVT_ID'];
3132
-            $query_args['event_name'] = urlencode($this->_req_data['event_name']);
3133
-            $query_args['redirect_from'] = $this->_req_data['redirect_from'];
3134
-        }
3135
-        EE_Error::add_success(
3136
-            esc_html__(
3137
-                'Registration Created.  Please review the transaction and add any payments as necessary',
3138
-                'event_espresso'
3139
-            )
3140
-        );
3141
-        $this->_redirect_after_action(false, '', '', $query_args, true);
3142
-    }
3143
-
3144
-
3145
-    /**
3146
-     *        generates HTML for the Attendee Contact List
3147
-     *
3148
-     * @access protected
3149
-     * @return void
3150
-     * @throws DomainException
3151
-     * @throws EE_Error
3152
-     */
3153
-    protected function _attendee_contact_list_table()
3154
-    {
3155
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3156
-        $this->_search_btn_label = esc_html__('Contacts', 'event_espresso');
3157
-        $this->display_admin_list_table_page_with_no_sidebar();
3158
-    }
3159
-
3160
-
3161
-    /**
3162
-     *        get_attendees
3163
-     *
3164
-     * @param      $per_page
3165
-     * @param bool $count whether to return count or data.
3166
-     * @param bool $trash
3167
-     * @return array
3168
-     * @throws EE_Error
3169
-     * @throws InvalidArgumentException
3170
-     * @throws InvalidDataTypeException
3171
-     * @throws InvalidInterfaceException
3172
-     * @access public
3173
-     */
3174
-    public function get_attendees($per_page, $count = false, $trash = false)
3175
-    {
3176
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3177
-        require_once(REG_ADMIN . 'EE_Attendee_Contact_List_Table.class.php');
3178
-        $this->_req_data['orderby'] = ! empty($this->_req_data['orderby']) ? $this->_req_data['orderby'] : '';
3179
-        switch ($this->_req_data['orderby']) {
3180
-            case 'ATT_ID':
3181
-                $orderby = 'ATT_ID';
3182
-                break;
3183
-            case 'ATT_fname':
3184
-                $orderby = 'ATT_fname';
3185
-                break;
3186
-            case 'ATT_email':
3187
-                $orderby = 'ATT_email';
3188
-                break;
3189
-            case 'ATT_city':
3190
-                $orderby = 'ATT_city';
3191
-                break;
3192
-            case 'STA_ID':
3193
-                $orderby = 'STA_ID';
3194
-                break;
3195
-            case 'CNT_ID':
3196
-                $orderby = 'CNT_ID';
3197
-                break;
3198
-            case 'Registration_Count':
3199
-                $orderby = 'Registration_Count';
3200
-                break;
3201
-            default:
3202
-                $orderby = 'ATT_lname';
3203
-        }
3204
-        $sort = (isset($this->_req_data['order']) && ! empty($this->_req_data['order']))
3205
-            ? $this->_req_data['order']
3206
-            : 'ASC';
3207
-        $current_page = isset($this->_req_data['paged']) && ! empty($this->_req_data['paged'])
3208
-            ? $this->_req_data['paged']
3209
-            : 1;
3210
-        $per_page = isset($per_page) && ! empty($per_page) ? $per_page : 10;
3211
-        $per_page = isset($this->_req_data['perpage']) && ! empty($this->_req_data['perpage'])
3212
-            ? $this->_req_data['perpage']
3213
-            : $per_page;
3214
-        $_where = array();
3215
-        if (! empty($this->_req_data['s'])) {
3216
-            $sstr = '%' . $this->_req_data['s'] . '%';
3217
-            $_where['OR'] = array(
3218
-                'Registration.Event.EVT_name'       => array('LIKE', $sstr),
3219
-                'Registration.Event.EVT_desc'       => array('LIKE', $sstr),
3220
-                'Registration.Event.EVT_short_desc' => array('LIKE', $sstr),
3221
-                'ATT_fname'                         => array('LIKE', $sstr),
3222
-                'ATT_lname'                         => array('LIKE', $sstr),
3223
-                'ATT_short_bio'                     => array('LIKE', $sstr),
3224
-                'ATT_email'                         => array('LIKE', $sstr),
3225
-                'ATT_address'                       => array('LIKE', $sstr),
3226
-                'ATT_address2'                      => array('LIKE', $sstr),
3227
-                'ATT_city'                          => array('LIKE', $sstr),
3228
-                'Country.CNT_name'                  => array('LIKE', $sstr),
3229
-                'State.STA_name'                    => array('LIKE', $sstr),
3230
-                'ATT_phone'                         => array('LIKE', $sstr),
3231
-                'Registration.REG_final_price'      => array('LIKE', $sstr),
3232
-                'Registration.REG_code'             => array('LIKE', $sstr),
3233
-                'Registration.REG_group_size'       => array('LIKE', $sstr),
3234
-            );
3235
-        }
3236
-        $offset = ($current_page - 1) * $per_page;
3237
-        $limit = $count ? null : array($offset, $per_page);
3238
-        $query_args = array(
3239
-            $_where,
3240
-            'extra_selects' => array('Registration_Count' => array('Registration.REG_ID', 'count', '%d')),
3241
-            'limit'         => $limit,
3242
-        );
3243
-        if (! $count) {
3244
-            $query_args['order_by'] = array($orderby => $sort);
3245
-        }
3246
-        if ($trash) {
3247
-            $query_args[0]['status'] = array('!=', 'publish');
3248
-            $all_attendees = $count
3249
-                ? $this->getAttendeeModel()->count($query_args, 'ATT_ID', true)
3250
-                : $this->getAttendeeModel()->get_all($query_args);
3251
-        } else {
3252
-            $query_args[0]['status'] = array('IN', array('publish'));
3253
-            $all_attendees = $count
3254
-                ? $this->getAttendeeModel()->count($query_args, 'ATT_ID', true)
3255
-                : $this->getAttendeeModel()->get_all($query_args);
3256
-        }
3257
-        return $all_attendees;
3258
-    }
3259
-
3260
-
3261
-    /**
3262
-     * This is just taking care of resending the registration confirmation
3263
-     *
3264
-     * @access protected
3265
-     * @return void
3266
-     * @throws EE_Error
3267
-     * @throws InvalidArgumentException
3268
-     * @throws InvalidDataTypeException
3269
-     * @throws InvalidInterfaceException
3270
-     * @throws ReflectionException
3271
-     */
3272
-    protected function _resend_registration()
3273
-    {
3274
-        $this->_process_resend_registration();
3275
-        $query_args = isset($this->_req_data['redirect_to'])
3276
-            ? array('action' => $this->_req_data['redirect_to'], '_REG_ID' => $this->_req_data['_REG_ID'])
3277
-            : array('action' => 'default');
3278
-        $this->_redirect_after_action(false, '', '', $query_args, true);
3279
-    }
3280
-
3281
-    /**
3282
-     * Creates a registration report, but accepts the name of a method to use for preparing the query parameters
3283
-     * to use when selecting registrations
3284
-     *
3285
-     * @param string $method_name_for_getting_query_params the name of the method (on this class) to use for preparing
3286
-     *                                                     the query parameters from the request
3287
-     * @return void ends the request with a redirect or download
3288
-     */
3289
-    public function _registrations_report_base($method_name_for_getting_query_params)
3290
-    {
3291
-        if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3292
-            wp_redirect(
3293
-                EE_Admin_Page::add_query_args_and_nonce(
3294
-                    array(
3295
-                        'page'        => 'espresso_batch',
3296
-                        'batch'       => 'file',
3297
-                        'EVT_ID'      => isset($this->_req_data['EVT_ID']) ? $this->_req_data['EVT_ID'] : null,
3298
-                        'filters'     => urlencode(
3299
-                            serialize(
3300
-                                $this->$method_name_for_getting_query_params(
3301
-                                    EEH_Array::is_set(
3302
-                                        $this->_req_data,
3303
-                                        'filters',
3304
-                                        array()
3305
-                                    )
3306
-                                )
3307
-                            )
3308
-                        ),
3309
-                        'use_filters' => EEH_Array::is_set($this->_req_data, 'use_filters', false),
3310
-                        'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\RegistrationsReport'),
3311
-                        'return_url'  => urlencode($this->_req_data['return_url']),
3312
-                    )
3313
-                )
3314
-            );
3315
-        } else {
3316
-            $new_request_args = array(
3317
-                'export' => 'report',
3318
-                'action' => 'registrations_report_for_event',
3319
-                'EVT_ID' => isset($this->_req_data['EVT_ID']) ? $this->_req_data['EVT_ID'] : null,
3320
-            );
3321
-            $this->_req_data = array_merge($this->_req_data, $new_request_args);
3322
-            if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3323
-                require_once(EE_CLASSES . 'EE_Export.class.php');
3324
-                $EE_Export = EE_Export::instance($this->_req_data);
3325
-                $EE_Export->export();
3326
-            }
3327
-        }
3328
-    }
3329
-
3330
-
3331
-    /**
3332
-     * Creates a registration report using only query parameters in the request
3333
-     *
3334
-     * @return void
3335
-     */
3336
-    public function _registrations_report()
3337
-    {
3338
-        $this->_registrations_report_base('_get_registration_query_parameters');
3339
-    }
3340
-
3341
-
3342
-    public function _contact_list_export()
3343
-    {
3344
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3345
-            require_once(EE_CLASSES . 'EE_Export.class.php');
3346
-            $EE_Export = EE_Export::instance($this->_req_data);
3347
-            $EE_Export->export_attendees();
3348
-        }
3349
-    }
3350
-
3351
-
3352
-    public function _contact_list_report()
3353
-    {
3354
-        if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3355
-            wp_redirect(
3356
-                EE_Admin_Page::add_query_args_and_nonce(
3357
-                    array(
3358
-                        'page'        => 'espresso_batch',
3359
-                        'batch'       => 'file',
3360
-                        'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\AttendeesReport'),
3361
-                        'return_url'  => urlencode($this->_req_data['return_url']),
3362
-                    )
3363
-                )
3364
-            );
3365
-        } else {
3366
-            if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3367
-                require_once(EE_CLASSES . 'EE_Export.class.php');
3368
-                $EE_Export = EE_Export::instance($this->_req_data);
3369
-                $EE_Export->report_attendees();
3370
-            }
3371
-        }
3372
-    }
3373
-
3374
-
3375
-
3376
-
3377
-
3378
-    /***************************************        ATTENDEE DETAILS        ***************************************/
3379
-    /**
3380
-     * This duplicates the attendee object for the given incoming registration id and attendee_id.
3381
-     *
3382
-     * @return void
3383
-     * @throws EE_Error
3384
-     * @throws InvalidArgumentException
3385
-     * @throws InvalidDataTypeException
3386
-     * @throws InvalidInterfaceException
3387
-     * @throws ReflectionException
3388
-     */
3389
-    protected function _duplicate_attendee()
3390
-    {
3391
-        $action = ! empty($this->_req_data['return']) ? $this->_req_data['return'] : 'default';
3392
-        // verify we have necessary info
3393
-        if (empty($this->_req_data['_REG_ID'])) {
3394
-            EE_Error::add_error(
3395
-                esc_html__(
3396
-                    'Unable to create the contact for the registration because the required parameters are not present (_REG_ID )',
3397
-                    'event_espresso'
3398
-                ),
3399
-                __FILE__,
3400
-                __LINE__,
3401
-                __FUNCTION__
3402
-            );
3403
-            $query_args = array('action' => $action);
3404
-            $this->_redirect_after_action('', '', '', $query_args, true);
3405
-        }
3406
-        // okay necessary deets present... let's dupe the incoming attendee and attach to incoming registration.
3407
-        $registration = $this->getRegistrationModel()->get_one_by_ID($this->_req_data['_REG_ID']);
3408
-        $attendee = $registration->attendee();
3409
-        // remove relation of existing attendee on registration
3410
-        $registration->_remove_relation_to($attendee, 'Attendee');
3411
-        // new attendee
3412
-        $new_attendee = clone $attendee;
3413
-        $new_attendee->set('ATT_ID', 0);
3414
-        $new_attendee->save();
3415
-        // add new attendee to reg
3416
-        $registration->_add_relation_to($new_attendee, 'Attendee');
3417
-        EE_Error::add_success(
3418
-            esc_html__(
3419
-                'New Contact record created.  Now make any edits you wish to make for this contact.',
3420
-                'event_espresso'
3421
-            )
3422
-        );
3423
-        // redirect to edit page for attendee
3424
-        $query_args = array('post' => $new_attendee->ID(), 'action' => 'edit_attendee');
3425
-        $this->_redirect_after_action('', '', '', $query_args, true);
3426
-    }
3427
-
3428
-
3429
-    /**
3430
-     * Callback invoked by parent EE_Admin_CPT class hooked in on `save_post` wp hook.
3431
-     *
3432
-     * @param int     $post_id
3433
-     * @param WP_POST $post
3434
-     * @throws DomainException
3435
-     * @throws EE_Error
3436
-     * @throws InvalidArgumentException
3437
-     * @throws InvalidDataTypeException
3438
-     * @throws InvalidInterfaceException
3439
-     * @throws LogicException
3440
-     * @throws InvalidFormSubmissionException
3441
-     * @throws ReflectionException
3442
-     */
3443
-    protected function _insert_update_cpt_item($post_id, $post)
3444
-    {
3445
-        $success = true;
3446
-        $attendee = $post instanceof WP_Post && $post->post_type === 'espresso_attendees'
3447
-            ? $this->getAttendeeModel()->get_one_by_ID($post_id)
3448
-            : null;
3449
-        // for attendee updates
3450
-        if ($attendee instanceof EE_Attendee) {
3451
-            // note we should only be UPDATING attendees at this point.
3452
-            $updated_fields = array(
3453
-                'ATT_fname'     => $this->_req_data['ATT_fname'],
3454
-                'ATT_lname'     => $this->_req_data['ATT_lname'],
3455
-                'ATT_full_name' => $this->_req_data['ATT_fname'] . ' ' . $this->_req_data['ATT_lname'],
3456
-                'ATT_address'   => isset($this->_req_data['ATT_address']) ? $this->_req_data['ATT_address'] : '',
3457
-                'ATT_address2'  => isset($this->_req_data['ATT_address2']) ? $this->_req_data['ATT_address2'] : '',
3458
-                'ATT_city'      => isset($this->_req_data['ATT_city']) ? $this->_req_data['ATT_city'] : '',
3459
-                'STA_ID'        => isset($this->_req_data['STA_ID']) ? $this->_req_data['STA_ID'] : '',
3460
-                'CNT_ISO'       => isset($this->_req_data['CNT_ISO']) ? $this->_req_data['CNT_ISO'] : '',
3461
-                'ATT_zip'       => isset($this->_req_data['ATT_zip']) ? $this->_req_data['ATT_zip'] : '',
3462
-            );
3463
-            foreach ($updated_fields as $field => $value) {
3464
-                $attendee->set($field, $value);
3465
-            }
3466
-
3467
-            // process contact details metabox form handler (which will also save the attendee)
3468
-            $contact_details_form = $this->getAttendeeContactDetailsMetaboxFormHandler($attendee);
3469
-            $success = $contact_details_form->process($this->_req_data);
3470
-
3471
-            $attendee_update_callbacks = apply_filters(
3472
-                'FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update',
3473
-                array()
3474
-            );
3475
-            foreach ($attendee_update_callbacks as $a_callback) {
3476
-                if (false === call_user_func_array($a_callback, array($attendee, $this->_req_data))) {
3477
-                    throw new EE_Error(
3478
-                        sprintf(
3479
-                            esc_html__(
3480
-                                'The %s callback given for the "FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update" filter is not a valid callback.  Please check the spelling.',
3481
-                                'event_espresso'
3482
-                            ),
3483
-                            $a_callback
3484
-                        )
3485
-                    );
3486
-                }
3487
-            }
3488
-        }
3489
-
3490
-        if ($success === false) {
3491
-            EE_Error::add_error(
3492
-                esc_html__(
3493
-                    'Something went wrong with updating the meta table data for the registration.',
3494
-                    'event_espresso'
3495
-                ),
3496
-                __FILE__,
3497
-                __FUNCTION__,
3498
-                __LINE__
3499
-            );
3500
-        }
3501
-    }
3502
-
3503
-
3504
-    public function trash_cpt_item($post_id)
3505
-    {
3506
-    }
3507
-
3508
-
3509
-    public function delete_cpt_item($post_id)
3510
-    {
3511
-    }
3512
-
3513
-
3514
-    public function restore_cpt_item($post_id)
3515
-    {
3516
-    }
3517
-
3518
-
3519
-    protected function _restore_cpt_item($post_id, $revision_id)
3520
-    {
3521
-    }
3522
-
3523
-
3524
-    /**
3525
-     * @throws EE_Error
3526
-     * @since 4.10.2.p
3527
-     */
3528
-    public function attendee_editor_metaboxes()
3529
-    {
3530
-        $this->verify_cpt_object();
3531
-        remove_meta_box(
3532
-            'postexcerpt',
3533
-            $this->_cpt_routes[ $this->_req_action ],
3534
-            'normal'
3535
-        );
3536
-        remove_meta_box('commentstatusdiv', $this->_cpt_routes[ $this->_req_action ], 'normal', 'core');
3537
-        if (post_type_supports('espresso_attendees', 'excerpt')) {
3538
-            add_meta_box(
3539
-                'postexcerpt',
3540
-                esc_html__('Short Biography', 'event_espresso'),
3541
-                'post_excerpt_meta_box',
3542
-                $this->_cpt_routes[ $this->_req_action ],
3543
-                'normal'
3544
-            );
3545
-        }
3546
-        if (post_type_supports('espresso_attendees', 'comments')) {
3547
-            add_meta_box(
3548
-                'commentsdiv',
3549
-                esc_html__('Notes on the Contact', 'event_espresso'),
3550
-                'post_comment_meta_box',
3551
-                $this->_cpt_routes[ $this->_req_action ],
3552
-                'normal',
3553
-                'core'
3554
-            );
3555
-        }
3556
-        add_meta_box(
3557
-            'attendee_contact_info',
3558
-            esc_html__('Contact Info', 'event_espresso'),
3559
-            array($this, 'attendee_contact_info'),
3560
-            $this->_cpt_routes[ $this->_req_action ],
3561
-            'side',
3562
-            'core'
3563
-        );
3564
-        add_meta_box(
3565
-            'attendee_details_address',
3566
-            esc_html__('Address Details', 'event_espresso'),
3567
-            array($this, 'attendee_address_details'),
3568
-            $this->_cpt_routes[ $this->_req_action ],
3569
-            'normal',
3570
-            'core'
3571
-        );
3572
-        add_meta_box(
3573
-            'attendee_registrations',
3574
-            esc_html__('Registrations for this Contact', 'event_espresso'),
3575
-            array($this, 'attendee_registrations_meta_box'),
3576
-            $this->_cpt_routes[ $this->_req_action ],
3577
-            'normal',
3578
-            'high'
3579
-        );
3580
-    }
3581
-
3582
-
3583
-    /**
3584
-     * Metabox for attendee contact info
3585
-     *
3586
-     * @param  WP_Post $post wp post object
3587
-     * @return string attendee contact info ( and form )
3588
-     * @throws EE_Error
3589
-     * @throws InvalidArgumentException
3590
-     * @throws InvalidDataTypeException
3591
-     * @throws InvalidInterfaceException
3592
-     * @throws LogicException
3593
-     * @throws DomainException
3594
-     */
3595
-    public function attendee_contact_info($post)
3596
-    {
3597
-        // get attendee object ( should already have it )
3598
-        $form = $this->getAttendeeContactDetailsMetaboxFormHandler($this->_cpt_model_obj);
3599
-        $form->enqueueStylesAndScripts();
3600
-        echo $form->display();
3601
-    }
3602
-
3603
-
3604
-    /**
3605
-     * Return form handler for the contact details metabox
3606
-     *
3607
-     * @param EE_Attendee $attendee
3608
-     * @return AttendeeContactDetailsMetaboxFormHandler
3609
-     * @throws DomainException
3610
-     * @throws InvalidArgumentException
3611
-     * @throws InvalidDataTypeException
3612
-     * @throws InvalidInterfaceException
3613
-     */
3614
-    protected function getAttendeeContactDetailsMetaboxFormHandler(EE_Attendee $attendee)
3615
-    {
3616
-        return new AttendeeContactDetailsMetaboxFormHandler($attendee, EE_Registry::instance());
3617
-    }
3618
-
3619
-
3620
-    /**
3621
-     * Metabox for attendee details
3622
-     *
3623
-     * @param  WP_Post $post wp post object
3624
-     * @throws DomainException
3625
-     */
3626
-    public function attendee_address_details($post)
3627
-    {
3628
-        // get attendee object (should already have it)
3629
-        $this->_template_args['attendee'] = $this->_cpt_model_obj;
3630
-        $this->_template_args['state_html'] = EEH_Form_Fields::generate_form_input(
3631
-            new EE_Question_Form_Input(
3632
-                EE_Question::new_instance(
3633
-                    array(
3634
-                        'QST_ID'           => 0,
3635
-                        'QST_display_text' => esc_html__('State/Province', 'event_espresso'),
3636
-                        'QST_system'       => 'admin-state',
3637
-                    )
3638
-                ),
3639
-                EE_Answer::new_instance(
3640
-                    array(
3641
-                        'ANS_ID'    => 0,
3642
-                        'ANS_value' => $this->_cpt_model_obj->state_ID(),
3643
-                    )
3644
-                ),
3645
-                array(
3646
-                    'input_id'       => 'STA_ID',
3647
-                    'input_name'     => 'STA_ID',
3648
-                    'input_prefix'   => '',
3649
-                    'append_qstn_id' => false,
3650
-                )
3651
-            )
3652
-        );
3653
-        $this->_template_args['country_html'] = EEH_Form_Fields::generate_form_input(
3654
-            new EE_Question_Form_Input(
3655
-                EE_Question::new_instance(
3656
-                    array(
3657
-                        'QST_ID'           => 0,
3658
-                        'QST_display_text' => esc_html__('Country', 'event_espresso'),
3659
-                        'QST_system'       => 'admin-country',
3660
-                    )
3661
-                ),
3662
-                EE_Answer::new_instance(
3663
-                    array(
3664
-                        'ANS_ID'    => 0,
3665
-                        'ANS_value' => $this->_cpt_model_obj->country_ID(),
3666
-                    )
3667
-                ),
3668
-                array(
3669
-                    'input_id'       => 'CNT_ISO',
3670
-                    'input_name'     => 'CNT_ISO',
3671
-                    'input_prefix'   => '',
3672
-                    'append_qstn_id' => false,
3673
-                )
3674
-            )
3675
-        );
3676
-        $template =
3677
-            REG_TEMPLATE_PATH . 'attendee_address_details_metabox_content.template.php';
3678
-        EEH_Template::display_template($template, $this->_template_args);
3679
-    }
3680
-
3681
-
3682
-    /**
3683
-     *        _attendee_details
3684
-     *
3685
-     * @access protected
3686
-     * @param $post
3687
-     * @return void
3688
-     * @throws DomainException
3689
-     * @throws EE_Error
3690
-     * @throws InvalidArgumentException
3691
-     * @throws InvalidDataTypeException
3692
-     * @throws InvalidInterfaceException
3693
-     * @throws ReflectionException
3694
-     */
3695
-    public function attendee_registrations_meta_box($post)
3696
-    {
3697
-        $this->_template_args['attendee'] = $this->_cpt_model_obj;
3698
-        $this->_template_args['registrations'] = $this->_cpt_model_obj->get_many_related('Registration');
3699
-        $template =
3700
-            REG_TEMPLATE_PATH . 'attendee_registrations_main_meta_box.template.php';
3701
-        EEH_Template::display_template($template, $this->_template_args);
3702
-    }
3703
-
3704
-
3705
-    /**
3706
-     * add in the form fields for the attendee edit
3707
-     *
3708
-     * @param  WP_Post $post wp post object
3709
-     * @return string html for new form.
3710
-     * @throws DomainException
3711
-     */
3712
-    public function after_title_form_fields($post)
3713
-    {
3714
-        if ($post->post_type === 'espresso_attendees') {
3715
-            $template = REG_TEMPLATE_PATH . 'attendee_details_after_title_form_fields.template.php';
3716
-            $template_args['attendee'] = $this->_cpt_model_obj;
3717
-            EEH_Template::display_template($template, $template_args);
3718
-        }
3719
-    }
3720
-
3721
-
3722
-    /**
3723
-     *        _trash_or_restore_attendee
3724
-     *
3725
-     * @param boolean $trash - whether to move item to trash (TRUE) or restore it (FALSE)
3726
-     * @return void
3727
-     * @throws EE_Error
3728
-     * @throws InvalidArgumentException
3729
-     * @throws InvalidDataTypeException
3730
-     * @throws InvalidInterfaceException
3731
-     * @throws ReflectionException
3732
-     * @access protected
3733
-     */
3734
-    protected function _trash_or_restore_attendees($trash = true)
3735
-    {
3736
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3737
-        $success = 1;
3738
-        // Checkboxes
3739
-        if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
3740
-            // if array has more than one element than success message should be plural
3741
-            $success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
3742
-            // cycle thru checkboxes
3743
-            foreach ($this->_req_data['checkbox'] as $ATT_ID) {
3744
-                $updated = $trash ? $this->getAttendeeModel()->update_by_ID(array('status' => 'trash'), $ATT_ID)
3745
-                    : $this->getAttendeeModel()->update_by_ID(array('status' => 'publish'), $ATT_ID);
3746
-                if (! $updated) {
3747
-                    $success = 0;
3748
-                }
3749
-            }
3750
-        } else {
3751
-            // grab single id and delete
3752
-            $ATT_ID = absint($this->_req_data['ATT_ID']);
3753
-            // get attendee
3754
-            $att = $this->getAttendeeModel()->get_one_by_ID($ATT_ID);
3755
-            $updated = $trash ? $att->set_status('trash') : $att->set_status('publish');
3756
-            $updated = $att->save() && $updated;
3757
-            if (! $updated) {
3758
-                $success = 0;
3759
-            }
3760
-        }
3761
-        $what = $success > 1
3762
-            ? esc_html__('Contacts', 'event_espresso')
3763
-            : esc_html__('Contact', 'event_espresso');
3764
-        $action_desc = $trash
3765
-            ? esc_html__('moved to the trash', 'event_espresso')
3766
-            : esc_html__('restored', 'event_espresso');
3767
-        $this->_redirect_after_action($success, $what, $action_desc, array('action' => 'contact_list'));
3768
-    }
2905
+		}
2906
+		$template_args = array(
2907
+			'title'                    => '',
2908
+			'content'                  => '',
2909
+			'step_button_text'         => '',
2910
+			'show_notification_toggle' => false,
2911
+		);
2912
+		// to indicate we're processing a new registration
2913
+		$hidden_fields = array(
2914
+			'processing_registration' => array(
2915
+				'type'  => 'hidden',
2916
+				'value' => 0,
2917
+			),
2918
+			'event_id'                => array(
2919
+				'type'  => 'hidden',
2920
+				'value' => $this->_reg_event->ID(),
2921
+			),
2922
+		);
2923
+		// if the cart is empty then we know we're at step one so we'll display ticket selector
2924
+		$cart = EE_Registry::instance()->SSN->cart();
2925
+		$step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
2926
+		switch ($step) {
2927
+			case 'ticket':
2928
+				$hidden_fields['processing_registration']['value'] = 1;
2929
+				$template_args['title'] = esc_html__(
2930
+					'Step One: Select the Ticket for this registration',
2931
+					'event_espresso'
2932
+				);
2933
+				$template_args['content'] =
2934
+					EED_Ticket_Selector::instance()->display_ticket_selector($this->_reg_event);
2935
+				$template_args['content'] .= '</div>';
2936
+				$template_args['step_button_text'] = esc_html__(
2937
+					'Add Tickets and Continue to Registrant Details',
2938
+					'event_espresso'
2939
+				);
2940
+				$template_args['show_notification_toggle'] = false;
2941
+				break;
2942
+			case 'questions':
2943
+				$hidden_fields['processing_registration']['value'] = 2;
2944
+				$template_args['title'] = esc_html__(
2945
+					'Step Two: Add Registrant Details for this Registration',
2946
+					'event_espresso'
2947
+				);
2948
+				// in theory we should be able to run EED_SPCO at this point because the cart should have been setup
2949
+				// properly by the first process_reg_step run.
2950
+				$template_args['content'] =
2951
+					EED_Single_Page_Checkout::registration_checkout_for_admin();
2952
+				$template_args['step_button_text'] = esc_html__(
2953
+					'Save Registration and Continue to Details',
2954
+					'event_espresso'
2955
+				);
2956
+				$template_args['show_notification_toggle'] = true;
2957
+				break;
2958
+		}
2959
+		// we come back to the process_registration_step route.
2960
+		$this->_set_add_edit_form_tags('process_reg_step', $hidden_fields);
2961
+		return EEH_Template::display_template(
2962
+			REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee_step_content.template.php',
2963
+			$template_args,
2964
+			true
2965
+		);
2966
+	}
2967
+
2968
+
2969
+	/**
2970
+	 *        set_reg_event
2971
+	 *
2972
+	 * @access private
2973
+	 * @return bool
2974
+	 * @throws EE_Error
2975
+	 * @throws InvalidArgumentException
2976
+	 * @throws InvalidDataTypeException
2977
+	 * @throws InvalidInterfaceException
2978
+	 */
2979
+	private function _set_reg_event()
2980
+	{
2981
+		if (is_object($this->_reg_event)) {
2982
+			return true;
2983
+		}
2984
+		$EVT_ID = (! empty($this->_req_data['event_id'])) ? absint($this->_req_data['event_id']) : false;
2985
+		if (! $EVT_ID) {
2986
+			return false;
2987
+		}
2988
+		$this->_reg_event = $this->getEventModel()->get_one_by_ID($EVT_ID);
2989
+		return true;
2990
+	}
2991
+
2992
+
2993
+	/**
2994
+	 * process_reg_step
2995
+	 *
2996
+	 * @access        public
2997
+	 * @return string
2998
+	 * @throws DomainException
2999
+	 * @throws EE_Error
3000
+	 * @throws InvalidArgumentException
3001
+	 * @throws InvalidDataTypeException
3002
+	 * @throws InvalidInterfaceException
3003
+	 * @throws ReflectionException
3004
+	 * @throws RuntimeException
3005
+	 */
3006
+	public function process_reg_step()
3007
+	{
3008
+		EE_System::do_not_cache();
3009
+		$this->_set_reg_event();
3010
+		EE_Registry::instance()->REQ->set_espresso_page(true);
3011
+		EE_Registry::instance()->REQ->set('uts', time());
3012
+		// what step are we on?
3013
+		$cart = EE_Registry::instance()->SSN->cart();
3014
+		$step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
3015
+		// if doing ajax then we need to verify the nonce
3016
+		if (defined('DOING_AJAX')) {
3017
+			$nonce = isset($this->_req_data[ $this->_req_nonce ])
3018
+				? sanitize_text_field($this->_req_data[ $this->_req_nonce ]) : '';
3019
+			$this->_verify_nonce($nonce, $this->_req_nonce);
3020
+		}
3021
+		switch ($step) {
3022
+			case 'ticket':
3023
+				// process ticket selection
3024
+				$success = EED_Ticket_Selector::instance()->process_ticket_selections();
3025
+				if ($success) {
3026
+					EE_Error::add_success(
3027
+						esc_html__(
3028
+							'Tickets Selected. Now complete the registration.',
3029
+							'event_espresso'
3030
+						)
3031
+					);
3032
+				} else {
3033
+					$query_args['step_error'] = $this->_req_data['step_error'] = true;
3034
+				}
3035
+				if (defined('DOING_AJAX')) {
3036
+					$this->new_registration(); // display next step
3037
+				} else {
3038
+					$query_args = array(
3039
+						'action'                  => 'new_registration',
3040
+						'processing_registration' => 1,
3041
+						'event_id'                => $this->_reg_event->ID(),
3042
+						'uts'                     => time(),
3043
+					);
3044
+					$this->_redirect_after_action(
3045
+						false,
3046
+						'',
3047
+						'',
3048
+						$query_args,
3049
+						true
3050
+					);
3051
+				}
3052
+				break;
3053
+			case 'questions':
3054
+				if (! isset(
3055
+					$this->_req_data['txn_reg_status_change'],
3056
+					$this->_req_data['txn_reg_status_change']['send_notifications']
3057
+				)
3058
+				) {
3059
+					add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_false', 15);
3060
+				}
3061
+				// process registration
3062
+				$transaction = EED_Single_Page_Checkout::instance()->process_registration_from_admin();
3063
+				if ($cart instanceof EE_Cart) {
3064
+					$grand_total = $cart->get_cart_grand_total();
3065
+					if ($grand_total instanceof EE_Line_Item) {
3066
+						$grand_total->save_this_and_descendants_to_txn();
3067
+					}
3068
+				}
3069
+				if (! $transaction instanceof EE_Transaction) {
3070
+					$query_args = array(
3071
+						'action'                  => 'new_registration',
3072
+						'processing_registration' => 2,
3073
+						'event_id'                => $this->_reg_event->ID(),
3074
+						'uts'                     => time(),
3075
+					);
3076
+					if (defined('DOING_AJAX')) {
3077
+						// display registration form again because there are errors (maybe validation?)
3078
+						$this->new_registration();
3079
+						return;
3080
+					}
3081
+					$this->_redirect_after_action(
3082
+						false,
3083
+						'',
3084
+						'',
3085
+						$query_args,
3086
+						true
3087
+					);
3088
+					return;
3089
+				}
3090
+				// maybe update status, and make sure to save transaction if not done already
3091
+				if (! $transaction->update_status_based_on_total_paid()) {
3092
+					$transaction->save();
3093
+				}
3094
+				EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3095
+				$this->_req_data = array();
3096
+				$query_args = array(
3097
+					'action'        => 'redirect_to_txn',
3098
+					'TXN_ID'        => $transaction->ID(),
3099
+					'EVT_ID'        => $this->_reg_event->ID(),
3100
+					'event_name'    => urlencode($this->_reg_event->name()),
3101
+					'redirect_from' => 'new_registration',
3102
+				);
3103
+				$this->_redirect_after_action(false, '', '', $query_args, true);
3104
+				break;
3105
+		}
3106
+		// what are you looking here for?  Should be nothing to do at this point.
3107
+	}
3108
+
3109
+
3110
+	/**
3111
+	 * redirect_to_txn
3112
+	 *
3113
+	 * @access public
3114
+	 * @return void
3115
+	 * @throws EE_Error
3116
+	 * @throws InvalidArgumentException
3117
+	 * @throws InvalidDataTypeException
3118
+	 * @throws InvalidInterfaceException
3119
+	 * @throws ReflectionException
3120
+	 */
3121
+	public function redirect_to_txn()
3122
+	{
3123
+		EE_System::do_not_cache();
3124
+		EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3125
+		$query_args = array(
3126
+			'action' => 'view_transaction',
3127
+			'TXN_ID' => isset($this->_req_data['TXN_ID']) ? absint($this->_req_data['TXN_ID']) : 0,
3128
+			'page'   => 'espresso_transactions',
3129
+		);
3130
+		if (isset($this->_req_data['EVT_ID'], $this->_req_data['redirect_from'])) {
3131
+			$query_args['EVT_ID'] = $this->_req_data['EVT_ID'];
3132
+			$query_args['event_name'] = urlencode($this->_req_data['event_name']);
3133
+			$query_args['redirect_from'] = $this->_req_data['redirect_from'];
3134
+		}
3135
+		EE_Error::add_success(
3136
+			esc_html__(
3137
+				'Registration Created.  Please review the transaction and add any payments as necessary',
3138
+				'event_espresso'
3139
+			)
3140
+		);
3141
+		$this->_redirect_after_action(false, '', '', $query_args, true);
3142
+	}
3143
+
3144
+
3145
+	/**
3146
+	 *        generates HTML for the Attendee Contact List
3147
+	 *
3148
+	 * @access protected
3149
+	 * @return void
3150
+	 * @throws DomainException
3151
+	 * @throws EE_Error
3152
+	 */
3153
+	protected function _attendee_contact_list_table()
3154
+	{
3155
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3156
+		$this->_search_btn_label = esc_html__('Contacts', 'event_espresso');
3157
+		$this->display_admin_list_table_page_with_no_sidebar();
3158
+	}
3159
+
3160
+
3161
+	/**
3162
+	 *        get_attendees
3163
+	 *
3164
+	 * @param      $per_page
3165
+	 * @param bool $count whether to return count or data.
3166
+	 * @param bool $trash
3167
+	 * @return array
3168
+	 * @throws EE_Error
3169
+	 * @throws InvalidArgumentException
3170
+	 * @throws InvalidDataTypeException
3171
+	 * @throws InvalidInterfaceException
3172
+	 * @access public
3173
+	 */
3174
+	public function get_attendees($per_page, $count = false, $trash = false)
3175
+	{
3176
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3177
+		require_once(REG_ADMIN . 'EE_Attendee_Contact_List_Table.class.php');
3178
+		$this->_req_data['orderby'] = ! empty($this->_req_data['orderby']) ? $this->_req_data['orderby'] : '';
3179
+		switch ($this->_req_data['orderby']) {
3180
+			case 'ATT_ID':
3181
+				$orderby = 'ATT_ID';
3182
+				break;
3183
+			case 'ATT_fname':
3184
+				$orderby = 'ATT_fname';
3185
+				break;
3186
+			case 'ATT_email':
3187
+				$orderby = 'ATT_email';
3188
+				break;
3189
+			case 'ATT_city':
3190
+				$orderby = 'ATT_city';
3191
+				break;
3192
+			case 'STA_ID':
3193
+				$orderby = 'STA_ID';
3194
+				break;
3195
+			case 'CNT_ID':
3196
+				$orderby = 'CNT_ID';
3197
+				break;
3198
+			case 'Registration_Count':
3199
+				$orderby = 'Registration_Count';
3200
+				break;
3201
+			default:
3202
+				$orderby = 'ATT_lname';
3203
+		}
3204
+		$sort = (isset($this->_req_data['order']) && ! empty($this->_req_data['order']))
3205
+			? $this->_req_data['order']
3206
+			: 'ASC';
3207
+		$current_page = isset($this->_req_data['paged']) && ! empty($this->_req_data['paged'])
3208
+			? $this->_req_data['paged']
3209
+			: 1;
3210
+		$per_page = isset($per_page) && ! empty($per_page) ? $per_page : 10;
3211
+		$per_page = isset($this->_req_data['perpage']) && ! empty($this->_req_data['perpage'])
3212
+			? $this->_req_data['perpage']
3213
+			: $per_page;
3214
+		$_where = array();
3215
+		if (! empty($this->_req_data['s'])) {
3216
+			$sstr = '%' . $this->_req_data['s'] . '%';
3217
+			$_where['OR'] = array(
3218
+				'Registration.Event.EVT_name'       => array('LIKE', $sstr),
3219
+				'Registration.Event.EVT_desc'       => array('LIKE', $sstr),
3220
+				'Registration.Event.EVT_short_desc' => array('LIKE', $sstr),
3221
+				'ATT_fname'                         => array('LIKE', $sstr),
3222
+				'ATT_lname'                         => array('LIKE', $sstr),
3223
+				'ATT_short_bio'                     => array('LIKE', $sstr),
3224
+				'ATT_email'                         => array('LIKE', $sstr),
3225
+				'ATT_address'                       => array('LIKE', $sstr),
3226
+				'ATT_address2'                      => array('LIKE', $sstr),
3227
+				'ATT_city'                          => array('LIKE', $sstr),
3228
+				'Country.CNT_name'                  => array('LIKE', $sstr),
3229
+				'State.STA_name'                    => array('LIKE', $sstr),
3230
+				'ATT_phone'                         => array('LIKE', $sstr),
3231
+				'Registration.REG_final_price'      => array('LIKE', $sstr),
3232
+				'Registration.REG_code'             => array('LIKE', $sstr),
3233
+				'Registration.REG_group_size'       => array('LIKE', $sstr),
3234
+			);
3235
+		}
3236
+		$offset = ($current_page - 1) * $per_page;
3237
+		$limit = $count ? null : array($offset, $per_page);
3238
+		$query_args = array(
3239
+			$_where,
3240
+			'extra_selects' => array('Registration_Count' => array('Registration.REG_ID', 'count', '%d')),
3241
+			'limit'         => $limit,
3242
+		);
3243
+		if (! $count) {
3244
+			$query_args['order_by'] = array($orderby => $sort);
3245
+		}
3246
+		if ($trash) {
3247
+			$query_args[0]['status'] = array('!=', 'publish');
3248
+			$all_attendees = $count
3249
+				? $this->getAttendeeModel()->count($query_args, 'ATT_ID', true)
3250
+				: $this->getAttendeeModel()->get_all($query_args);
3251
+		} else {
3252
+			$query_args[0]['status'] = array('IN', array('publish'));
3253
+			$all_attendees = $count
3254
+				? $this->getAttendeeModel()->count($query_args, 'ATT_ID', true)
3255
+				: $this->getAttendeeModel()->get_all($query_args);
3256
+		}
3257
+		return $all_attendees;
3258
+	}
3259
+
3260
+
3261
+	/**
3262
+	 * This is just taking care of resending the registration confirmation
3263
+	 *
3264
+	 * @access protected
3265
+	 * @return void
3266
+	 * @throws EE_Error
3267
+	 * @throws InvalidArgumentException
3268
+	 * @throws InvalidDataTypeException
3269
+	 * @throws InvalidInterfaceException
3270
+	 * @throws ReflectionException
3271
+	 */
3272
+	protected function _resend_registration()
3273
+	{
3274
+		$this->_process_resend_registration();
3275
+		$query_args = isset($this->_req_data['redirect_to'])
3276
+			? array('action' => $this->_req_data['redirect_to'], '_REG_ID' => $this->_req_data['_REG_ID'])
3277
+			: array('action' => 'default');
3278
+		$this->_redirect_after_action(false, '', '', $query_args, true);
3279
+	}
3280
+
3281
+	/**
3282
+	 * Creates a registration report, but accepts the name of a method to use for preparing the query parameters
3283
+	 * to use when selecting registrations
3284
+	 *
3285
+	 * @param string $method_name_for_getting_query_params the name of the method (on this class) to use for preparing
3286
+	 *                                                     the query parameters from the request
3287
+	 * @return void ends the request with a redirect or download
3288
+	 */
3289
+	public function _registrations_report_base($method_name_for_getting_query_params)
3290
+	{
3291
+		if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3292
+			wp_redirect(
3293
+				EE_Admin_Page::add_query_args_and_nonce(
3294
+					array(
3295
+						'page'        => 'espresso_batch',
3296
+						'batch'       => 'file',
3297
+						'EVT_ID'      => isset($this->_req_data['EVT_ID']) ? $this->_req_data['EVT_ID'] : null,
3298
+						'filters'     => urlencode(
3299
+							serialize(
3300
+								$this->$method_name_for_getting_query_params(
3301
+									EEH_Array::is_set(
3302
+										$this->_req_data,
3303
+										'filters',
3304
+										array()
3305
+									)
3306
+								)
3307
+							)
3308
+						),
3309
+						'use_filters' => EEH_Array::is_set($this->_req_data, 'use_filters', false),
3310
+						'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\RegistrationsReport'),
3311
+						'return_url'  => urlencode($this->_req_data['return_url']),
3312
+					)
3313
+				)
3314
+			);
3315
+		} else {
3316
+			$new_request_args = array(
3317
+				'export' => 'report',
3318
+				'action' => 'registrations_report_for_event',
3319
+				'EVT_ID' => isset($this->_req_data['EVT_ID']) ? $this->_req_data['EVT_ID'] : null,
3320
+			);
3321
+			$this->_req_data = array_merge($this->_req_data, $new_request_args);
3322
+			if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3323
+				require_once(EE_CLASSES . 'EE_Export.class.php');
3324
+				$EE_Export = EE_Export::instance($this->_req_data);
3325
+				$EE_Export->export();
3326
+			}
3327
+		}
3328
+	}
3329
+
3330
+
3331
+	/**
3332
+	 * Creates a registration report using only query parameters in the request
3333
+	 *
3334
+	 * @return void
3335
+	 */
3336
+	public function _registrations_report()
3337
+	{
3338
+		$this->_registrations_report_base('_get_registration_query_parameters');
3339
+	}
3340
+
3341
+
3342
+	public function _contact_list_export()
3343
+	{
3344
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3345
+			require_once(EE_CLASSES . 'EE_Export.class.php');
3346
+			$EE_Export = EE_Export::instance($this->_req_data);
3347
+			$EE_Export->export_attendees();
3348
+		}
3349
+	}
3350
+
3351
+
3352
+	public function _contact_list_report()
3353
+	{
3354
+		if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3355
+			wp_redirect(
3356
+				EE_Admin_Page::add_query_args_and_nonce(
3357
+					array(
3358
+						'page'        => 'espresso_batch',
3359
+						'batch'       => 'file',
3360
+						'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\AttendeesReport'),
3361
+						'return_url'  => urlencode($this->_req_data['return_url']),
3362
+					)
3363
+				)
3364
+			);
3365
+		} else {
3366
+			if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3367
+				require_once(EE_CLASSES . 'EE_Export.class.php');
3368
+				$EE_Export = EE_Export::instance($this->_req_data);
3369
+				$EE_Export->report_attendees();
3370
+			}
3371
+		}
3372
+	}
3373
+
3374
+
3375
+
3376
+
3377
+
3378
+	/***************************************        ATTENDEE DETAILS        ***************************************/
3379
+	/**
3380
+	 * This duplicates the attendee object for the given incoming registration id and attendee_id.
3381
+	 *
3382
+	 * @return void
3383
+	 * @throws EE_Error
3384
+	 * @throws InvalidArgumentException
3385
+	 * @throws InvalidDataTypeException
3386
+	 * @throws InvalidInterfaceException
3387
+	 * @throws ReflectionException
3388
+	 */
3389
+	protected function _duplicate_attendee()
3390
+	{
3391
+		$action = ! empty($this->_req_data['return']) ? $this->_req_data['return'] : 'default';
3392
+		// verify we have necessary info
3393
+		if (empty($this->_req_data['_REG_ID'])) {
3394
+			EE_Error::add_error(
3395
+				esc_html__(
3396
+					'Unable to create the contact for the registration because the required parameters are not present (_REG_ID )',
3397
+					'event_espresso'
3398
+				),
3399
+				__FILE__,
3400
+				__LINE__,
3401
+				__FUNCTION__
3402
+			);
3403
+			$query_args = array('action' => $action);
3404
+			$this->_redirect_after_action('', '', '', $query_args, true);
3405
+		}
3406
+		// okay necessary deets present... let's dupe the incoming attendee and attach to incoming registration.
3407
+		$registration = $this->getRegistrationModel()->get_one_by_ID($this->_req_data['_REG_ID']);
3408
+		$attendee = $registration->attendee();
3409
+		// remove relation of existing attendee on registration
3410
+		$registration->_remove_relation_to($attendee, 'Attendee');
3411
+		// new attendee
3412
+		$new_attendee = clone $attendee;
3413
+		$new_attendee->set('ATT_ID', 0);
3414
+		$new_attendee->save();
3415
+		// add new attendee to reg
3416
+		$registration->_add_relation_to($new_attendee, 'Attendee');
3417
+		EE_Error::add_success(
3418
+			esc_html__(
3419
+				'New Contact record created.  Now make any edits you wish to make for this contact.',
3420
+				'event_espresso'
3421
+			)
3422
+		);
3423
+		// redirect to edit page for attendee
3424
+		$query_args = array('post' => $new_attendee->ID(), 'action' => 'edit_attendee');
3425
+		$this->_redirect_after_action('', '', '', $query_args, true);
3426
+	}
3427
+
3428
+
3429
+	/**
3430
+	 * Callback invoked by parent EE_Admin_CPT class hooked in on `save_post` wp hook.
3431
+	 *
3432
+	 * @param int     $post_id
3433
+	 * @param WP_POST $post
3434
+	 * @throws DomainException
3435
+	 * @throws EE_Error
3436
+	 * @throws InvalidArgumentException
3437
+	 * @throws InvalidDataTypeException
3438
+	 * @throws InvalidInterfaceException
3439
+	 * @throws LogicException
3440
+	 * @throws InvalidFormSubmissionException
3441
+	 * @throws ReflectionException
3442
+	 */
3443
+	protected function _insert_update_cpt_item($post_id, $post)
3444
+	{
3445
+		$success = true;
3446
+		$attendee = $post instanceof WP_Post && $post->post_type === 'espresso_attendees'
3447
+			? $this->getAttendeeModel()->get_one_by_ID($post_id)
3448
+			: null;
3449
+		// for attendee updates
3450
+		if ($attendee instanceof EE_Attendee) {
3451
+			// note we should only be UPDATING attendees at this point.
3452
+			$updated_fields = array(
3453
+				'ATT_fname'     => $this->_req_data['ATT_fname'],
3454
+				'ATT_lname'     => $this->_req_data['ATT_lname'],
3455
+				'ATT_full_name' => $this->_req_data['ATT_fname'] . ' ' . $this->_req_data['ATT_lname'],
3456
+				'ATT_address'   => isset($this->_req_data['ATT_address']) ? $this->_req_data['ATT_address'] : '',
3457
+				'ATT_address2'  => isset($this->_req_data['ATT_address2']) ? $this->_req_data['ATT_address2'] : '',
3458
+				'ATT_city'      => isset($this->_req_data['ATT_city']) ? $this->_req_data['ATT_city'] : '',
3459
+				'STA_ID'        => isset($this->_req_data['STA_ID']) ? $this->_req_data['STA_ID'] : '',
3460
+				'CNT_ISO'       => isset($this->_req_data['CNT_ISO']) ? $this->_req_data['CNT_ISO'] : '',
3461
+				'ATT_zip'       => isset($this->_req_data['ATT_zip']) ? $this->_req_data['ATT_zip'] : '',
3462
+			);
3463
+			foreach ($updated_fields as $field => $value) {
3464
+				$attendee->set($field, $value);
3465
+			}
3466
+
3467
+			// process contact details metabox form handler (which will also save the attendee)
3468
+			$contact_details_form = $this->getAttendeeContactDetailsMetaboxFormHandler($attendee);
3469
+			$success = $contact_details_form->process($this->_req_data);
3470
+
3471
+			$attendee_update_callbacks = apply_filters(
3472
+				'FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update',
3473
+				array()
3474
+			);
3475
+			foreach ($attendee_update_callbacks as $a_callback) {
3476
+				if (false === call_user_func_array($a_callback, array($attendee, $this->_req_data))) {
3477
+					throw new EE_Error(
3478
+						sprintf(
3479
+							esc_html__(
3480
+								'The %s callback given for the "FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update" filter is not a valid callback.  Please check the spelling.',
3481
+								'event_espresso'
3482
+							),
3483
+							$a_callback
3484
+						)
3485
+					);
3486
+				}
3487
+			}
3488
+		}
3489
+
3490
+		if ($success === false) {
3491
+			EE_Error::add_error(
3492
+				esc_html__(
3493
+					'Something went wrong with updating the meta table data for the registration.',
3494
+					'event_espresso'
3495
+				),
3496
+				__FILE__,
3497
+				__FUNCTION__,
3498
+				__LINE__
3499
+			);
3500
+		}
3501
+	}
3502
+
3503
+
3504
+	public function trash_cpt_item($post_id)
3505
+	{
3506
+	}
3507
+
3508
+
3509
+	public function delete_cpt_item($post_id)
3510
+	{
3511
+	}
3512
+
3513
+
3514
+	public function restore_cpt_item($post_id)
3515
+	{
3516
+	}
3517
+
3518
+
3519
+	protected function _restore_cpt_item($post_id, $revision_id)
3520
+	{
3521
+	}
3522
+
3523
+
3524
+	/**
3525
+	 * @throws EE_Error
3526
+	 * @since 4.10.2.p
3527
+	 */
3528
+	public function attendee_editor_metaboxes()
3529
+	{
3530
+		$this->verify_cpt_object();
3531
+		remove_meta_box(
3532
+			'postexcerpt',
3533
+			$this->_cpt_routes[ $this->_req_action ],
3534
+			'normal'
3535
+		);
3536
+		remove_meta_box('commentstatusdiv', $this->_cpt_routes[ $this->_req_action ], 'normal', 'core');
3537
+		if (post_type_supports('espresso_attendees', 'excerpt')) {
3538
+			add_meta_box(
3539
+				'postexcerpt',
3540
+				esc_html__('Short Biography', 'event_espresso'),
3541
+				'post_excerpt_meta_box',
3542
+				$this->_cpt_routes[ $this->_req_action ],
3543
+				'normal'
3544
+			);
3545
+		}
3546
+		if (post_type_supports('espresso_attendees', 'comments')) {
3547
+			add_meta_box(
3548
+				'commentsdiv',
3549
+				esc_html__('Notes on the Contact', 'event_espresso'),
3550
+				'post_comment_meta_box',
3551
+				$this->_cpt_routes[ $this->_req_action ],
3552
+				'normal',
3553
+				'core'
3554
+			);
3555
+		}
3556
+		add_meta_box(
3557
+			'attendee_contact_info',
3558
+			esc_html__('Contact Info', 'event_espresso'),
3559
+			array($this, 'attendee_contact_info'),
3560
+			$this->_cpt_routes[ $this->_req_action ],
3561
+			'side',
3562
+			'core'
3563
+		);
3564
+		add_meta_box(
3565
+			'attendee_details_address',
3566
+			esc_html__('Address Details', 'event_espresso'),
3567
+			array($this, 'attendee_address_details'),
3568
+			$this->_cpt_routes[ $this->_req_action ],
3569
+			'normal',
3570
+			'core'
3571
+		);
3572
+		add_meta_box(
3573
+			'attendee_registrations',
3574
+			esc_html__('Registrations for this Contact', 'event_espresso'),
3575
+			array($this, 'attendee_registrations_meta_box'),
3576
+			$this->_cpt_routes[ $this->_req_action ],
3577
+			'normal',
3578
+			'high'
3579
+		);
3580
+	}
3581
+
3582
+
3583
+	/**
3584
+	 * Metabox for attendee contact info
3585
+	 *
3586
+	 * @param  WP_Post $post wp post object
3587
+	 * @return string attendee contact info ( and form )
3588
+	 * @throws EE_Error
3589
+	 * @throws InvalidArgumentException
3590
+	 * @throws InvalidDataTypeException
3591
+	 * @throws InvalidInterfaceException
3592
+	 * @throws LogicException
3593
+	 * @throws DomainException
3594
+	 */
3595
+	public function attendee_contact_info($post)
3596
+	{
3597
+		// get attendee object ( should already have it )
3598
+		$form = $this->getAttendeeContactDetailsMetaboxFormHandler($this->_cpt_model_obj);
3599
+		$form->enqueueStylesAndScripts();
3600
+		echo $form->display();
3601
+	}
3602
+
3603
+
3604
+	/**
3605
+	 * Return form handler for the contact details metabox
3606
+	 *
3607
+	 * @param EE_Attendee $attendee
3608
+	 * @return AttendeeContactDetailsMetaboxFormHandler
3609
+	 * @throws DomainException
3610
+	 * @throws InvalidArgumentException
3611
+	 * @throws InvalidDataTypeException
3612
+	 * @throws InvalidInterfaceException
3613
+	 */
3614
+	protected function getAttendeeContactDetailsMetaboxFormHandler(EE_Attendee $attendee)
3615
+	{
3616
+		return new AttendeeContactDetailsMetaboxFormHandler($attendee, EE_Registry::instance());
3617
+	}
3618
+
3619
+
3620
+	/**
3621
+	 * Metabox for attendee details
3622
+	 *
3623
+	 * @param  WP_Post $post wp post object
3624
+	 * @throws DomainException
3625
+	 */
3626
+	public function attendee_address_details($post)
3627
+	{
3628
+		// get attendee object (should already have it)
3629
+		$this->_template_args['attendee'] = $this->_cpt_model_obj;
3630
+		$this->_template_args['state_html'] = EEH_Form_Fields::generate_form_input(
3631
+			new EE_Question_Form_Input(
3632
+				EE_Question::new_instance(
3633
+					array(
3634
+						'QST_ID'           => 0,
3635
+						'QST_display_text' => esc_html__('State/Province', 'event_espresso'),
3636
+						'QST_system'       => 'admin-state',
3637
+					)
3638
+				),
3639
+				EE_Answer::new_instance(
3640
+					array(
3641
+						'ANS_ID'    => 0,
3642
+						'ANS_value' => $this->_cpt_model_obj->state_ID(),
3643
+					)
3644
+				),
3645
+				array(
3646
+					'input_id'       => 'STA_ID',
3647
+					'input_name'     => 'STA_ID',
3648
+					'input_prefix'   => '',
3649
+					'append_qstn_id' => false,
3650
+				)
3651
+			)
3652
+		);
3653
+		$this->_template_args['country_html'] = EEH_Form_Fields::generate_form_input(
3654
+			new EE_Question_Form_Input(
3655
+				EE_Question::new_instance(
3656
+					array(
3657
+						'QST_ID'           => 0,
3658
+						'QST_display_text' => esc_html__('Country', 'event_espresso'),
3659
+						'QST_system'       => 'admin-country',
3660
+					)
3661
+				),
3662
+				EE_Answer::new_instance(
3663
+					array(
3664
+						'ANS_ID'    => 0,
3665
+						'ANS_value' => $this->_cpt_model_obj->country_ID(),
3666
+					)
3667
+				),
3668
+				array(
3669
+					'input_id'       => 'CNT_ISO',
3670
+					'input_name'     => 'CNT_ISO',
3671
+					'input_prefix'   => '',
3672
+					'append_qstn_id' => false,
3673
+				)
3674
+			)
3675
+		);
3676
+		$template =
3677
+			REG_TEMPLATE_PATH . 'attendee_address_details_metabox_content.template.php';
3678
+		EEH_Template::display_template($template, $this->_template_args);
3679
+	}
3680
+
3681
+
3682
+	/**
3683
+	 *        _attendee_details
3684
+	 *
3685
+	 * @access protected
3686
+	 * @param $post
3687
+	 * @return void
3688
+	 * @throws DomainException
3689
+	 * @throws EE_Error
3690
+	 * @throws InvalidArgumentException
3691
+	 * @throws InvalidDataTypeException
3692
+	 * @throws InvalidInterfaceException
3693
+	 * @throws ReflectionException
3694
+	 */
3695
+	public function attendee_registrations_meta_box($post)
3696
+	{
3697
+		$this->_template_args['attendee'] = $this->_cpt_model_obj;
3698
+		$this->_template_args['registrations'] = $this->_cpt_model_obj->get_many_related('Registration');
3699
+		$template =
3700
+			REG_TEMPLATE_PATH . 'attendee_registrations_main_meta_box.template.php';
3701
+		EEH_Template::display_template($template, $this->_template_args);
3702
+	}
3703
+
3704
+
3705
+	/**
3706
+	 * add in the form fields for the attendee edit
3707
+	 *
3708
+	 * @param  WP_Post $post wp post object
3709
+	 * @return string html for new form.
3710
+	 * @throws DomainException
3711
+	 */
3712
+	public function after_title_form_fields($post)
3713
+	{
3714
+		if ($post->post_type === 'espresso_attendees') {
3715
+			$template = REG_TEMPLATE_PATH . 'attendee_details_after_title_form_fields.template.php';
3716
+			$template_args['attendee'] = $this->_cpt_model_obj;
3717
+			EEH_Template::display_template($template, $template_args);
3718
+		}
3719
+	}
3720
+
3721
+
3722
+	/**
3723
+	 *        _trash_or_restore_attendee
3724
+	 *
3725
+	 * @param boolean $trash - whether to move item to trash (TRUE) or restore it (FALSE)
3726
+	 * @return void
3727
+	 * @throws EE_Error
3728
+	 * @throws InvalidArgumentException
3729
+	 * @throws InvalidDataTypeException
3730
+	 * @throws InvalidInterfaceException
3731
+	 * @throws ReflectionException
3732
+	 * @access protected
3733
+	 */
3734
+	protected function _trash_or_restore_attendees($trash = true)
3735
+	{
3736
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3737
+		$success = 1;
3738
+		// Checkboxes
3739
+		if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
3740
+			// if array has more than one element than success message should be plural
3741
+			$success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
3742
+			// cycle thru checkboxes
3743
+			foreach ($this->_req_data['checkbox'] as $ATT_ID) {
3744
+				$updated = $trash ? $this->getAttendeeModel()->update_by_ID(array('status' => 'trash'), $ATT_ID)
3745
+					: $this->getAttendeeModel()->update_by_ID(array('status' => 'publish'), $ATT_ID);
3746
+				if (! $updated) {
3747
+					$success = 0;
3748
+				}
3749
+			}
3750
+		} else {
3751
+			// grab single id and delete
3752
+			$ATT_ID = absint($this->_req_data['ATT_ID']);
3753
+			// get attendee
3754
+			$att = $this->getAttendeeModel()->get_one_by_ID($ATT_ID);
3755
+			$updated = $trash ? $att->set_status('trash') : $att->set_status('publish');
3756
+			$updated = $att->save() && $updated;
3757
+			if (! $updated) {
3758
+				$success = 0;
3759
+			}
3760
+		}
3761
+		$what = $success > 1
3762
+			? esc_html__('Contacts', 'event_espresso')
3763
+			: esc_html__('Contact', 'event_espresso');
3764
+		$action_desc = $trash
3765
+			? esc_html__('moved to the trash', 'event_espresso')
3766
+			: esc_html__('restored', 'event_espresso');
3767
+		$this->_redirect_after_action($success, $what, $action_desc, array('action' => 'contact_list'));
3768
+	}
3769 3769
 }
Please login to merge, or discard this patch.
core/db_classes/EE_Registration.class.php 2 patches
Indentation   +2521 added lines, -2521 removed lines patch added patch discarded remove patch
@@ -16,2525 +16,2525 @@
 block discarded – undo
16 16
 class EE_Registration extends EE_Soft_Delete_Base_Class implements EEI_Registration, EEI_Admin_Links
17 17
 {
18 18
 
19
-    /**
20
-     * Used to reference when a registration has never been checked in.
21
-     *
22
-     * @deprecated use \EE_Checkin::status_checked_never instead
23
-     * @type int
24
-     */
25
-    const checkin_status_never = 2;
26
-
27
-    /**
28
-     * Used to reference when a registration has been checked in.
29
-     *
30
-     * @deprecated use \EE_Checkin::status_checked_in instead
31
-     * @type int
32
-     */
33
-    const checkin_status_in = 1;
34
-
35
-    /**
36
-     * Used to reference when a registration has been checked out.
37
-     *
38
-     * @deprecated use \EE_Checkin::status_checked_out instead
39
-     * @type int
40
-     */
41
-    const checkin_status_out = 0;
42
-
43
-    /**
44
-     * extra meta key for tracking reg status os trashed registrations
45
-     *
46
-     * @type string
47
-     */
48
-    const PRE_TRASH_REG_STATUS_KEY = 'pre_trash_registration_status';
49
-
50
-    /**
51
-     * extra meta key for tracking if registration has reserved ticket
52
-     *
53
-     * @type string
54
-     */
55
-    const HAS_RESERVED_TICKET_KEY = 'has_reserved_ticket';
56
-
57
-    /**
58
-     * extra meta key for tracking when registrations are trashed and by who
59
-     *
60
-     * @type string
61
-     */
62
-    const EXTRA_META_KEY_REG_TRASHED = 'registration-trashed';
63
-
64
-    /**
65
-     * extra meta key for tracking when registrations are restored and by who
66
-     *
67
-     * @type string
68
-     */
69
-    const EXTRA_META_KEY_REG_RESTORED = 'registration-restored';
70
-
71
-
72
-    /**
73
-     * @param array  $props_n_values          incoming values
74
-     * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
75
-     *                                        used.)
76
-     * @param array  $date_formats            incoming date_formats in an array where the first value is the
77
-     *                                        date_format and the second value is the time format
78
-     * @return EE_Registration
79
-     * @throws EE_Error
80
-     * @throws InvalidArgumentException
81
-     * @throws InvalidDataTypeException
82
-     * @throws InvalidInterfaceException
83
-     * @throws ReflectionException
84
-     */
85
-    public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
86
-    {
87
-        $has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
88
-        return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
89
-    }
90
-
91
-
92
-    /**
93
-     * @param array  $props_n_values  incoming values from the database
94
-     * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
95
-     *                                the website will be used.
96
-     * @return EE_Registration
97
-     * @throws EE_Error
98
-     * @throws InvalidArgumentException
99
-     * @throws InvalidDataTypeException
100
-     * @throws InvalidInterfaceException
101
-     * @throws ReflectionException
102
-     */
103
-    public static function new_instance_from_db($props_n_values = array(), $timezone = null)
104
-    {
105
-        return new self($props_n_values, true, $timezone);
106
-    }
107
-
108
-
109
-    /**
110
-     *        Set Event ID
111
-     *
112
-     * @param        int $EVT_ID Event ID
113
-     * @throws DomainException
114
-     * @throws EE_Error
115
-     * @throws EntityNotFoundException
116
-     * @throws InvalidArgumentException
117
-     * @throws InvalidDataTypeException
118
-     * @throws InvalidInterfaceException
119
-     * @throws ReflectionException
120
-     * @throws RuntimeException
121
-     * @throws UnexpectedEntityException
122
-     */
123
-    public function set_event($EVT_ID = 0)
124
-    {
125
-        $this->set('EVT_ID', $EVT_ID);
126
-    }
127
-
128
-
129
-    /**
130
-     * Overrides parent set() method so that all calls to set( 'REG_code', $REG_code ) OR set( 'STS_ID', $STS_ID ) can
131
-     * be routed to internal methods
132
-     *
133
-     * @param string $field_name
134
-     * @param mixed  $field_value
135
-     * @param bool   $use_default
136
-     * @throws DomainException
137
-     * @throws EE_Error
138
-     * @throws EntityNotFoundException
139
-     * @throws InvalidArgumentException
140
-     * @throws InvalidDataTypeException
141
-     * @throws InvalidInterfaceException
142
-     * @throws ReflectionException
143
-     * @throws RuntimeException
144
-     * @throws UnexpectedEntityException
145
-     */
146
-    public function set($field_name, $field_value, $use_default = false)
147
-    {
148
-        switch ($field_name) {
149
-            case 'REG_code':
150
-                if (! empty($field_value) && $this->reg_code() === null) {
151
-                    $this->set_reg_code($field_value, $use_default);
152
-                }
153
-                break;
154
-            case 'STS_ID':
155
-                $this->set_status($field_value, $use_default);
156
-                break;
157
-            default:
158
-                parent::set($field_name, $field_value, $use_default);
159
-        }
160
-    }
161
-
162
-
163
-    /**
164
-     * Set Status ID
165
-     * updates the registration status and ALSO...
166
-     * calls reserve_registration_space() if the reg status changes TO approved from any other reg status
167
-     * calls release_registration_space() if the reg status changes FROM approved to any other reg status
168
-     *
169
-     * @param string                $new_STS_ID
170
-     * @param boolean               $use_default
171
-     * @param ContextInterface|null $context
172
-     * @return bool
173
-     * @throws DomainException
174
-     * @throws EE_Error
175
-     * @throws EntityNotFoundException
176
-     * @throws InvalidArgumentException
177
-     * @throws InvalidDataTypeException
178
-     * @throws InvalidInterfaceException
179
-     * @throws ReflectionException
180
-     * @throws RuntimeException
181
-     * @throws UnexpectedEntityException
182
-     */
183
-    public function set_status($new_STS_ID = null, $use_default = false, ContextInterface $context = null)
184
-    {
185
-        // get current REG_Status
186
-        $old_STS_ID = $this->status_ID();
187
-        // if status has changed
188
-        if ($old_STS_ID !== $new_STS_ID // and that status has actually changed
189
-            && ! empty($old_STS_ID) // and that old status is actually set
190
-            && ! empty($new_STS_ID) // as well as the new status
191
-            && $this->ID() // ensure registration is in the db
192
-        ) {
193
-            // update internal status first
194
-            parent::set('STS_ID', $new_STS_ID, $use_default);
195
-            // THEN handle other changes that occur when reg status changes
196
-            // TO approved
197
-            if ($new_STS_ID === EEM_Registration::status_id_approved) {
198
-                // reserve a space by incrementing ticket and datetime sold values
199
-                $this->reserveRegistrationSpace();
200
-                do_action('AHEE__EE_Registration__set_status__to_approved', $this, $old_STS_ID, $new_STS_ID, $context);
201
-                // OR FROM  approved
202
-            } elseif ($old_STS_ID === EEM_Registration::status_id_approved) {
203
-                // release a space by decrementing ticket and datetime sold values
204
-                $this->releaseRegistrationSpace();
205
-                do_action(
206
-                    'AHEE__EE_Registration__set_status__from_approved',
207
-                    $this,
208
-                    $old_STS_ID,
209
-                    $new_STS_ID,
210
-                    $context
211
-                );
212
-            }
213
-            // update status
214
-            parent::set('STS_ID', $new_STS_ID, $use_default);
215
-            $this->updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, $context);
216
-            if ($this->statusChangeUpdatesTransaction($context)) {
217
-                $this->updateTransactionAfterStatusChange();
218
-            }
219
-            do_action('AHEE__EE_Registration__set_status__after_update', $this, $old_STS_ID, $new_STS_ID, $context);
220
-            return true;
221
-        }
222
-        // even though the old value matches the new value, it's still good to
223
-        // allow the parent set method to have a say
224
-        parent::set('STS_ID', $new_STS_ID, $use_default);
225
-        return true;
226
-    }
227
-
228
-
229
-    /**
230
-     * update REGs and TXN when cancelled or declined registrations involved
231
-     *
232
-     * @param string                $new_STS_ID
233
-     * @param string                $old_STS_ID
234
-     * @param ContextInterface|null $context
235
-     * @throws EE_Error
236
-     * @throws InvalidArgumentException
237
-     * @throws InvalidDataTypeException
238
-     * @throws InvalidInterfaceException
239
-     * @throws ReflectionException
240
-     * @throws RuntimeException
241
-     */
242
-    private function updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, ContextInterface $context = null)
243
-    {
244
-        // these reg statuses should not be considered in any calculations involving monies owing
245
-        $closed_reg_statuses = EEM_Registration::closed_reg_statuses();
246
-        // true if registration has been cancelled or declined
247
-        $this->updateIfCanceled(
248
-            $closed_reg_statuses,
249
-            $new_STS_ID,
250
-            $old_STS_ID,
251
-            $context
252
-        );
253
-        $this->updateIfReinstated(
254
-            $closed_reg_statuses,
255
-            $new_STS_ID,
256
-            $old_STS_ID,
257
-            $context
258
-        );
259
-    }
260
-
261
-
262
-    /**
263
-     * update REGs and TXN when cancelled or declined registrations involved
264
-     *
265
-     * @param array                 $closed_reg_statuses
266
-     * @param string                $new_STS_ID
267
-     * @param string                $old_STS_ID
268
-     * @param ContextInterface|null $context
269
-     * @throws EE_Error
270
-     * @throws InvalidArgumentException
271
-     * @throws InvalidDataTypeException
272
-     * @throws InvalidInterfaceException
273
-     * @throws ReflectionException
274
-     * @throws RuntimeException
275
-     */
276
-    private function updateIfCanceled(
277
-        array $closed_reg_statuses,
278
-        $new_STS_ID,
279
-        $old_STS_ID,
280
-        ContextInterface $context = null
281
-    ) {
282
-        // true if registration has been cancelled or declined
283
-        if (in_array($new_STS_ID, $closed_reg_statuses, true)
284
-            && ! in_array($old_STS_ID, $closed_reg_statuses, true)
285
-        ) {
286
-            /** @type EE_Registration_Processor $registration_processor */
287
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
288
-            /** @type EE_Transaction_Processor $transaction_processor */
289
-            $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
290
-            // cancelled or declined registration
291
-            $registration_processor->update_registration_after_being_canceled_or_declined(
292
-                $this,
293
-                $closed_reg_statuses
294
-            );
295
-            $transaction_processor->update_transaction_after_canceled_or_declined_registration(
296
-                $this,
297
-                $closed_reg_statuses,
298
-                false
299
-            );
300
-            do_action(
301
-                'AHEE__EE_Registration__set_status__canceled_or_declined',
302
-                $this,
303
-                $old_STS_ID,
304
-                $new_STS_ID,
305
-                $context
306
-            );
307
-            return;
308
-        }
309
-    }
310
-
311
-
312
-    /**
313
-     * update REGs and TXN when cancelled or declined registrations involved
314
-     *
315
-     * @param array                 $closed_reg_statuses
316
-     * @param string                $new_STS_ID
317
-     * @param string                $old_STS_ID
318
-     * @param ContextInterface|null $context
319
-     * @throws EE_Error
320
-     * @throws InvalidArgumentException
321
-     * @throws InvalidDataTypeException
322
-     * @throws InvalidInterfaceException
323
-     * @throws ReflectionException
324
-     * @throws RuntimeException
325
-     */
326
-    private function updateIfReinstated(
327
-        array $closed_reg_statuses,
328
-        $new_STS_ID,
329
-        $old_STS_ID,
330
-        ContextInterface $context = null
331
-    ) {
332
-        // true if reinstating cancelled or declined registration
333
-        if (in_array($old_STS_ID, $closed_reg_statuses, true)
334
-            && ! in_array($new_STS_ID, $closed_reg_statuses, true)
335
-        ) {
336
-            /** @type EE_Registration_Processor $registration_processor */
337
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
338
-            /** @type EE_Transaction_Processor $transaction_processor */
339
-            $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
340
-            // reinstating cancelled or declined registration
341
-            $registration_processor->update_canceled_or_declined_registration_after_being_reinstated(
342
-                $this,
343
-                $closed_reg_statuses
344
-            );
345
-            $transaction_processor->update_transaction_after_reinstating_canceled_registration(
346
-                $this,
347
-                $closed_reg_statuses,
348
-                false
349
-            );
350
-            do_action(
351
-                'AHEE__EE_Registration__set_status__after_reinstated',
352
-                $this,
353
-                $old_STS_ID,
354
-                $new_STS_ID,
355
-                $context
356
-            );
357
-        }
358
-    }
359
-
360
-
361
-    /**
362
-     * @param ContextInterface|null $context
363
-     * @return bool
364
-     */
365
-    private function statusChangeUpdatesTransaction(ContextInterface $context = null)
366
-    {
367
-        $contexts_that_do_not_update_transaction = (array) apply_filters(
368
-            'AHEE__EE_Registration__statusChangeUpdatesTransaction__contexts_that_do_not_update_transaction',
369
-            array('spco_reg_step_attendee_information_process_registrations'),
370
-            $context,
371
-            $this
372
-        );
373
-        return ! (
374
-            $context instanceof ContextInterface
375
-            && in_array($context->slug(), $contexts_that_do_not_update_transaction, true)
376
-        );
377
-    }
378
-
379
-
380
-    /**
381
-     * @throws EE_Error
382
-     * @throws EntityNotFoundException
383
-     * @throws InvalidArgumentException
384
-     * @throws InvalidDataTypeException
385
-     * @throws InvalidInterfaceException
386
-     * @throws ReflectionException
387
-     * @throws RuntimeException
388
-     */
389
-    private function updateTransactionAfterStatusChange()
390
-    {
391
-        /** @type EE_Transaction_Payments $transaction_payments */
392
-        $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
393
-        $transaction_payments->recalculate_transaction_total($this->transaction(), false);
394
-        $this->transaction()->update_status_based_on_total_paid();
395
-    }
396
-
397
-
398
-    /**
399
-     * get Status ID
400
-     *
401
-     * @throws EE_Error
402
-     * @throws InvalidArgumentException
403
-     * @throws InvalidDataTypeException
404
-     * @throws InvalidInterfaceException
405
-     * @throws ReflectionException
406
-     */
407
-    public function status_ID()
408
-    {
409
-        return $this->get('STS_ID');
410
-    }
411
-
412
-
413
-    /**
414
-     * Gets the ticket this registration is for
415
-     *
416
-     * @param boolean $include_archived whether to include archived tickets or not.
417
-     * @return EE_Ticket|EE_Base_Class
418
-     * @throws EE_Error
419
-     * @throws InvalidArgumentException
420
-     * @throws InvalidDataTypeException
421
-     * @throws InvalidInterfaceException
422
-     * @throws ReflectionException
423
-     */
424
-    public function ticket($include_archived = true)
425
-    {
426
-        $query_params = array();
427
-        if ($include_archived) {
428
-            $query_params['default_where_conditions'] = 'none';
429
-        }
430
-        return $this->get_first_related('Ticket', $query_params);
431
-    }
432
-
433
-
434
-    /**
435
-     * Gets the event this registration is for
436
-     *
437
-     * @return EE_Event
438
-     * @throws EE_Error
439
-     * @throws EntityNotFoundException
440
-     * @throws InvalidArgumentException
441
-     * @throws InvalidDataTypeException
442
-     * @throws InvalidInterfaceException
443
-     * @throws ReflectionException
444
-     */
445
-    public function event()
446
-    {
447
-        $event = $this->get_first_related('Event');
448
-        if (! $event instanceof \EE_Event) {
449
-            throw new EntityNotFoundException('Event ID', $this->event_ID());
450
-        }
451
-        return $event;
452
-    }
453
-
454
-
455
-    /**
456
-     * Gets the "author" of the registration.  Note that for the purposes of registrations, the author will correspond
457
-     * with the author of the event this registration is for.
458
-     *
459
-     * @since 4.5.0
460
-     * @return int
461
-     * @throws EE_Error
462
-     * @throws EntityNotFoundException
463
-     * @throws InvalidArgumentException
464
-     * @throws InvalidDataTypeException
465
-     * @throws InvalidInterfaceException
466
-     * @throws ReflectionException
467
-     */
468
-    public function wp_user()
469
-    {
470
-        $event = $this->event();
471
-        if ($event instanceof EE_Event) {
472
-            return $event->wp_user();
473
-        }
474
-        return 0;
475
-    }
476
-
477
-
478
-    /**
479
-     * increments this registration's related ticket sold and corresponding datetime sold values
480
-     *
481
-     * @return void
482
-     * @throws DomainException
483
-     * @throws EE_Error
484
-     * @throws EntityNotFoundException
485
-     * @throws InvalidArgumentException
486
-     * @throws InvalidDataTypeException
487
-     * @throws InvalidInterfaceException
488
-     * @throws ReflectionException
489
-     * @throws UnexpectedEntityException
490
-     */
491
-    private function reserveRegistrationSpace()
492
-    {
493
-        // reserved ticket and datetime counts will be decremented as sold counts are incremented
494
-        // so stop tracking that this reg has a ticket reserved
495
-        $this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
496
-        $ticket = $this->ticket();
497
-        $ticket->increaseSold();
498
-        // possibly set event status to sold out
499
-        $this->event()->perform_sold_out_status_check();
500
-    }
501
-
502
-
503
-    /**
504
-     * decrements (subtracts) this registration's related ticket sold and corresponding datetime sold values
505
-     *
506
-     * @return void
507
-     * @throws DomainException
508
-     * @throws EE_Error
509
-     * @throws EntityNotFoundException
510
-     * @throws InvalidArgumentException
511
-     * @throws InvalidDataTypeException
512
-     * @throws InvalidInterfaceException
513
-     * @throws ReflectionException
514
-     * @throws UnexpectedEntityException
515
-     */
516
-    private function releaseRegistrationSpace()
517
-    {
518
-        $ticket = $this->ticket();
519
-        $ticket->decreaseSold();
520
-        // possibly change event status from sold out back to previous status
521
-        $this->event()->perform_sold_out_status_check();
522
-    }
523
-
524
-
525
-    /**
526
-     * tracks this registration's ticket reservation in extra meta
527
-     * and can increment related ticket reserved and corresponding datetime reserved values
528
-     *
529
-     * @param bool   $update_ticket if true, will increment ticket and datetime reserved count
530
-     * @param string $source
531
-     * @return void
532
-     * @throws EE_Error
533
-     * @throws InvalidArgumentException
534
-     * @throws InvalidDataTypeException
535
-     * @throws InvalidInterfaceException
536
-     * @throws ReflectionException
537
-     */
538
-    public function reserve_ticket($update_ticket = false, $source = 'unknown')
539
-    {
540
-        // only reserve ticket if space is not currently reserved
541
-        if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) !== true) {
542
-            $this->update_extra_meta('reserve_ticket', "{$this->ticket_ID()} from {$source}");
543
-            $reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
544
-            if ($reserved && $update_ticket) {
545
-                $ticket = $this->ticket();
546
-                $ticket->increaseReserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
547
-                $ticket->save();
548
-            }
549
-        }
550
-    }
551
-
552
-
553
-    /**
554
-     * stops tracking this registration's ticket reservation in extra meta
555
-     * decrements (subtracts) related ticket reserved and corresponding datetime reserved values
556
-     *
557
-     * @param bool   $update_ticket if true, will decrement ticket and datetime reserved count
558
-     * @param string $source
559
-     * @return void
560
-     * @throws EE_Error
561
-     * @throws InvalidArgumentException
562
-     * @throws InvalidDataTypeException
563
-     * @throws InvalidInterfaceException
564
-     * @throws ReflectionException
565
-     */
566
-    public function release_reserved_ticket($update_ticket = false, $source = 'unknown')
567
-    {
568
-        // only release ticket if space is currently reserved
569
-        if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) === true) {
570
-            $this->update_extra_meta('release_reserved_ticket', "{$this->ticket_ID()} from {$source}");
571
-            $reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, false);
572
-            if ($reserved && $update_ticket) {
573
-                $ticket = $this->ticket();
574
-                $ticket->decreaseReserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
575
-            }
576
-        }
577
-    }
578
-
579
-
580
-    /**
581
-     * Set Attendee ID
582
-     *
583
-     * @param        int $ATT_ID Attendee ID
584
-     * @throws DomainException
585
-     * @throws EE_Error
586
-     * @throws EntityNotFoundException
587
-     * @throws InvalidArgumentException
588
-     * @throws InvalidDataTypeException
589
-     * @throws InvalidInterfaceException
590
-     * @throws ReflectionException
591
-     * @throws RuntimeException
592
-     * @throws UnexpectedEntityException
593
-     */
594
-    public function set_attendee_id($ATT_ID = 0)
595
-    {
596
-        $this->set('ATT_ID', $ATT_ID);
597
-    }
598
-
599
-
600
-    /**
601
-     *        Set Transaction ID
602
-     *
603
-     * @param        int $TXN_ID Transaction ID
604
-     * @throws DomainException
605
-     * @throws EE_Error
606
-     * @throws EntityNotFoundException
607
-     * @throws InvalidArgumentException
608
-     * @throws InvalidDataTypeException
609
-     * @throws InvalidInterfaceException
610
-     * @throws ReflectionException
611
-     * @throws RuntimeException
612
-     * @throws UnexpectedEntityException
613
-     */
614
-    public function set_transaction_id($TXN_ID = 0)
615
-    {
616
-        $this->set('TXN_ID', $TXN_ID);
617
-    }
618
-
619
-
620
-    /**
621
-     *        Set Session
622
-     *
623
-     * @param    string $REG_session PHP Session ID
624
-     * @throws DomainException
625
-     * @throws EE_Error
626
-     * @throws EntityNotFoundException
627
-     * @throws InvalidArgumentException
628
-     * @throws InvalidDataTypeException
629
-     * @throws InvalidInterfaceException
630
-     * @throws ReflectionException
631
-     * @throws RuntimeException
632
-     * @throws UnexpectedEntityException
633
-     */
634
-    public function set_session($REG_session = '')
635
-    {
636
-        $this->set('REG_session', $REG_session);
637
-    }
638
-
639
-
640
-    /**
641
-     *        Set Registration URL Link
642
-     *
643
-     * @param    string $REG_url_link Registration URL Link
644
-     * @throws DomainException
645
-     * @throws EE_Error
646
-     * @throws EntityNotFoundException
647
-     * @throws InvalidArgumentException
648
-     * @throws InvalidDataTypeException
649
-     * @throws InvalidInterfaceException
650
-     * @throws ReflectionException
651
-     * @throws RuntimeException
652
-     * @throws UnexpectedEntityException
653
-     */
654
-    public function set_reg_url_link($REG_url_link = '')
655
-    {
656
-        $this->set('REG_url_link', $REG_url_link);
657
-    }
658
-
659
-
660
-    /**
661
-     *        Set Attendee Counter
662
-     *
663
-     * @param        int $REG_count Primary Attendee
664
-     * @throws DomainException
665
-     * @throws EE_Error
666
-     * @throws EntityNotFoundException
667
-     * @throws InvalidArgumentException
668
-     * @throws InvalidDataTypeException
669
-     * @throws InvalidInterfaceException
670
-     * @throws ReflectionException
671
-     * @throws RuntimeException
672
-     * @throws UnexpectedEntityException
673
-     */
674
-    public function set_count($REG_count = 1)
675
-    {
676
-        $this->set('REG_count', $REG_count);
677
-    }
678
-
679
-
680
-    /**
681
-     *        Set Group Size
682
-     *
683
-     * @param        boolean $REG_group_size Group Registration
684
-     * @throws DomainException
685
-     * @throws EE_Error
686
-     * @throws EntityNotFoundException
687
-     * @throws InvalidArgumentException
688
-     * @throws InvalidDataTypeException
689
-     * @throws InvalidInterfaceException
690
-     * @throws ReflectionException
691
-     * @throws RuntimeException
692
-     * @throws UnexpectedEntityException
693
-     */
694
-    public function set_group_size($REG_group_size = false)
695
-    {
696
-        $this->set('REG_group_size', $REG_group_size);
697
-    }
698
-
699
-
700
-    /**
701
-     *    is_not_approved -  convenience method that returns TRUE if REG status ID ==
702
-     *    EEM_Registration::status_id_not_approved
703
-     *
704
-     * @return        boolean
705
-     * @throws EE_Error
706
-     * @throws InvalidArgumentException
707
-     * @throws InvalidDataTypeException
708
-     * @throws InvalidInterfaceException
709
-     * @throws ReflectionException
710
-     */
711
-    public function is_not_approved()
712
-    {
713
-        return $this->status_ID() === EEM_Registration::status_id_not_approved;
714
-    }
715
-
716
-
717
-    /**
718
-     *    is_pending_payment -  convenience method that returns TRUE if REG status ID ==
719
-     *    EEM_Registration::status_id_pending_payment
720
-     *
721
-     * @return        boolean
722
-     * @throws EE_Error
723
-     * @throws InvalidArgumentException
724
-     * @throws InvalidDataTypeException
725
-     * @throws InvalidInterfaceException
726
-     * @throws ReflectionException
727
-     */
728
-    public function is_pending_payment()
729
-    {
730
-        return $this->status_ID() === EEM_Registration::status_id_pending_payment;
731
-    }
732
-
733
-
734
-    /**
735
-     *    is_approved -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_approved
736
-     *
737
-     * @return        boolean
738
-     * @throws EE_Error
739
-     * @throws InvalidArgumentException
740
-     * @throws InvalidDataTypeException
741
-     * @throws InvalidInterfaceException
742
-     * @throws ReflectionException
743
-     */
744
-    public function is_approved()
745
-    {
746
-        return $this->status_ID() === EEM_Registration::status_id_approved;
747
-    }
748
-
749
-
750
-    /**
751
-     *    is_cancelled -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_cancelled
752
-     *
753
-     * @return        boolean
754
-     * @throws EE_Error
755
-     * @throws InvalidArgumentException
756
-     * @throws InvalidDataTypeException
757
-     * @throws InvalidInterfaceException
758
-     * @throws ReflectionException
759
-     */
760
-    public function is_cancelled()
761
-    {
762
-        return $this->status_ID() === EEM_Registration::status_id_cancelled;
763
-    }
764
-
765
-
766
-    /**
767
-     *    is_declined -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_declined
768
-     *
769
-     * @return        boolean
770
-     * @throws EE_Error
771
-     * @throws InvalidArgumentException
772
-     * @throws InvalidDataTypeException
773
-     * @throws InvalidInterfaceException
774
-     * @throws ReflectionException
775
-     */
776
-    public function is_declined()
777
-    {
778
-        return $this->status_ID() === EEM_Registration::status_id_declined;
779
-    }
780
-
781
-
782
-    /**
783
-     *    is_incomplete -  convenience method that returns TRUE if REG status ID ==
784
-     *    EEM_Registration::status_id_incomplete
785
-     *
786
-     * @return        boolean
787
-     * @throws EE_Error
788
-     * @throws InvalidArgumentException
789
-     * @throws InvalidDataTypeException
790
-     * @throws InvalidInterfaceException
791
-     * @throws ReflectionException
792
-     */
793
-    public function is_incomplete()
794
-    {
795
-        return $this->status_ID() === EEM_Registration::status_id_incomplete;
796
-    }
797
-
798
-
799
-    /**
800
-     *        Set Registration Date
801
-     *
802
-     * @param        mixed ( int or string ) $REG_date Registration Date - Unix timestamp or string representation of
803
-     *                                                 Date
804
-     * @throws DomainException
805
-     * @throws EE_Error
806
-     * @throws EntityNotFoundException
807
-     * @throws InvalidArgumentException
808
-     * @throws InvalidDataTypeException
809
-     * @throws InvalidInterfaceException
810
-     * @throws ReflectionException
811
-     * @throws RuntimeException
812
-     * @throws UnexpectedEntityException
813
-     */
814
-    public function set_reg_date($REG_date = false)
815
-    {
816
-        $this->set('REG_date', $REG_date);
817
-    }
818
-
819
-
820
-    /**
821
-     *    Set final price owing for this registration after all ticket/price modifications
822
-     *
823
-     * @param    float $REG_final_price
824
-     * @throws DomainException
825
-     * @throws EE_Error
826
-     * @throws EntityNotFoundException
827
-     * @throws InvalidArgumentException
828
-     * @throws InvalidDataTypeException
829
-     * @throws InvalidInterfaceException
830
-     * @throws ReflectionException
831
-     * @throws RuntimeException
832
-     * @throws UnexpectedEntityException
833
-     */
834
-    public function set_final_price($REG_final_price = 0.00)
835
-    {
836
-        $this->set('REG_final_price', $REG_final_price);
837
-    }
838
-
839
-
840
-    /**
841
-     *    Set amount paid towards this registration's final price
842
-     *
843
-     * @param    float $REG_paid
844
-     * @throws DomainException
845
-     * @throws EE_Error
846
-     * @throws EntityNotFoundException
847
-     * @throws InvalidArgumentException
848
-     * @throws InvalidDataTypeException
849
-     * @throws InvalidInterfaceException
850
-     * @throws ReflectionException
851
-     * @throws RuntimeException
852
-     * @throws UnexpectedEntityException
853
-     */
854
-    public function set_paid($REG_paid = 0.00)
855
-    {
856
-        $this->set('REG_paid', $REG_paid);
857
-    }
858
-
859
-
860
-    /**
861
-     *        Attendee Is Going
862
-     *
863
-     * @param        boolean $REG_att_is_going Attendee Is Going
864
-     * @throws DomainException
865
-     * @throws EE_Error
866
-     * @throws EntityNotFoundException
867
-     * @throws InvalidArgumentException
868
-     * @throws InvalidDataTypeException
869
-     * @throws InvalidInterfaceException
870
-     * @throws ReflectionException
871
-     * @throws RuntimeException
872
-     * @throws UnexpectedEntityException
873
-     */
874
-    public function set_att_is_going($REG_att_is_going = false)
875
-    {
876
-        $this->set('REG_att_is_going', $REG_att_is_going);
877
-    }
878
-
879
-
880
-    /**
881
-     * Gets the related attendee
882
-     *
883
-     * @return EE_Attendee|EE_Base_Class
884
-     * @throws EE_Error
885
-     * @throws InvalidArgumentException
886
-     * @throws InvalidDataTypeException
887
-     * @throws InvalidInterfaceException
888
-     * @throws ReflectionException
889
-     */
890
-    public function attendee()
891
-    {
892
-        return $this->get_first_related('Attendee');
893
-    }
894
-
895
-    /**
896
-     * Gets the name of the attendee.
897
-     * @since 4.10.12.p
898
-     * @param bool $apply_html_entities set to true if you want to use HTML entities.
899
-     * @return string
900
-     * @throws EE_Error
901
-     * @throws InvalidArgumentException
902
-     * @throws InvalidDataTypeException
903
-     * @throws InvalidInterfaceException
904
-     * @throws ReflectionException
905
-     */
906
-    public function attendeeName($apply_html_entities = false)
907
-    {
908
-        $attendee = $this->get_first_related('Attendee');
909
-        if ($attendee instanceof EE_Attendee) {
910
-            $attendee_name = $attendee->full_name($apply_html_entities);
911
-        } else {
912
-            $attendee_name = esc_html__('Unknown', 'event_espresso');
913
-        }
914
-        return $attendee_name;
915
-    }
916
-
917
-
918
-    /**
919
-     *        get Event ID
920
-     */
921
-    public function event_ID()
922
-    {
923
-        return $this->get('EVT_ID');
924
-    }
925
-
926
-
927
-    /**
928
-     *        get Event ID
929
-     */
930
-    public function event_name()
931
-    {
932
-        $event = $this->event_obj();
933
-        if ($event) {
934
-            return $event->name();
935
-        } else {
936
-            return null;
937
-        }
938
-    }
939
-
940
-
941
-    /**
942
-     * Fetches the event this registration is for
943
-     *
944
-     * @return EE_Base_Class|EE_Event
945
-     * @throws EE_Error
946
-     * @throws InvalidArgumentException
947
-     * @throws InvalidDataTypeException
948
-     * @throws InvalidInterfaceException
949
-     * @throws ReflectionException
950
-     */
951
-    public function event_obj()
952
-    {
953
-        return $this->get_first_related('Event');
954
-    }
955
-
956
-
957
-    /**
958
-     *        get Attendee ID
959
-     */
960
-    public function attendee_ID()
961
-    {
962
-        return $this->get('ATT_ID');
963
-    }
964
-
965
-
966
-    /**
967
-     *        get PHP Session ID
968
-     */
969
-    public function session_ID()
970
-    {
971
-        return $this->get('REG_session');
972
-    }
973
-
974
-
975
-    /**
976
-     * Gets the string which represents the URL trigger for the receipt template in the message template system.
977
-     *
978
-     * @param string $messenger 'pdf' or 'html'.  Default 'html'.
979
-     * @return string
980
-     * @throws DomainException
981
-     * @throws EE_Error
982
-     * @throws InvalidArgumentException
983
-     * @throws InvalidDataTypeException
984
-     * @throws InvalidInterfaceException
985
-     * @throws ReflectionException
986
-     */
987
-    public function receipt_url($messenger = 'html')
988
-    {
989
-
990
-        /**
991
-         * The below will be deprecated one version after this.  We check first if there is a custom receipt template
992
-         * already in use on old system.  If there is then we just return the standard url for it.
993
-         *
994
-         * @since 4.5.0
995
-         */
996
-        $template_relative_path = 'modules/gateways/Invoice/lib/templates/receipt_body.template.php';
997
-        $has_custom = EEH_Template::locate_template(
998
-            $template_relative_path,
999
-            array(),
1000
-            true,
1001
-            true,
1002
-            true
1003
-        );
1004
-
1005
-        if ($has_custom) {
1006
-            return add_query_arg(array('receipt' => 'true'), $this->invoice_url('launch'));
1007
-        }
1008
-        return apply_filters('FHEE__EE_Registration__receipt_url__receipt_url', '', $this, $messenger, 'receipt');
1009
-    }
1010
-
1011
-
1012
-    /**
1013
-     * Gets the string which represents the URL trigger for the invoice template in the message template system.
1014
-     *
1015
-     * @param string $messenger 'pdf' or 'html'.  Default 'html'.
1016
-     * @return string
1017
-     * @throws DomainException
1018
-     * @throws EE_Error
1019
-     * @throws InvalidArgumentException
1020
-     * @throws InvalidDataTypeException
1021
-     * @throws InvalidInterfaceException
1022
-     * @throws ReflectionException
1023
-     */
1024
-    public function invoice_url($messenger = 'html')
1025
-    {
1026
-        /**
1027
-         * The below will be deprecated one version after this.  We check first if there is a custom invoice template
1028
-         * already in use on old system.  If there is then we just return the standard url for it.
1029
-         *
1030
-         * @since 4.5.0
1031
-         */
1032
-        $template_relative_path = 'modules/gateways/Invoice/lib/templates/invoice_body.template.php';
1033
-        $has_custom = EEH_Template::locate_template(
1034
-            $template_relative_path,
1035
-            array(),
1036
-            true,
1037
-            true,
1038
-            true
1039
-        );
1040
-
1041
-        if ($has_custom) {
1042
-            if ($messenger == 'html') {
1043
-                return $this->invoice_url('launch');
1044
-            }
1045
-            $route = $messenger == 'download' || $messenger == 'pdf' ? 'download_invoice' : 'launch_invoice';
1046
-
1047
-            $query_args = array('ee' => $route, 'id' => $this->reg_url_link());
1048
-            if ($messenger == 'html') {
1049
-                $query_args['html'] = true;
1050
-            }
1051
-            return add_query_arg($query_args, get_permalink(EE_Registry::instance()->CFG->core->thank_you_page_id));
1052
-        }
1053
-        return apply_filters('FHEE__EE_Registration__invoice_url__invoice_url', '', $this, $messenger, 'invoice');
1054
-    }
1055
-
1056
-
1057
-    /**
1058
-     * get Registration URL Link
1059
-     *
1060
-     * @return string
1061
-     * @throws EE_Error
1062
-     * @throws InvalidArgumentException
1063
-     * @throws InvalidDataTypeException
1064
-     * @throws InvalidInterfaceException
1065
-     * @throws ReflectionException
1066
-     */
1067
-    public function reg_url_link()
1068
-    {
1069
-        return (string) $this->get('REG_url_link');
1070
-    }
1071
-
1072
-
1073
-    /**
1074
-     * Echoes out invoice_url()
1075
-     *
1076
-     * @param string $type 'download','launch', or 'html' (default is 'launch')
1077
-     * @return void
1078
-     * @throws DomainException
1079
-     * @throws EE_Error
1080
-     * @throws InvalidArgumentException
1081
-     * @throws InvalidDataTypeException
1082
-     * @throws InvalidInterfaceException
1083
-     * @throws ReflectionException
1084
-     */
1085
-    public function e_invoice_url($type = 'launch')
1086
-    {
1087
-        echo $this->invoice_url($type);
1088
-    }
1089
-
1090
-
1091
-    /**
1092
-     * Echoes out payment_overview_url
1093
-     */
1094
-    public function e_payment_overview_url()
1095
-    {
1096
-        echo $this->payment_overview_url();
1097
-    }
1098
-
1099
-
1100
-    /**
1101
-     * Gets the URL for the checkout payment options reg step
1102
-     * with this registration's REG_url_link added as a query parameter
1103
-     *
1104
-     * @param bool $clear_session Set to true when you want to clear the session on revisiting the
1105
-     *                            payment overview url.
1106
-     * @return string
1107
-     * @throws EE_Error
1108
-     * @throws InvalidArgumentException
1109
-     * @throws InvalidDataTypeException
1110
-     * @throws InvalidInterfaceException
1111
-     * @throws ReflectionException
1112
-     */
1113
-    public function payment_overview_url($clear_session = false)
1114
-    {
1115
-        return add_query_arg(
1116
-            (array) apply_filters(
1117
-                'FHEE__EE_Registration__payment_overview_url__query_args',
1118
-                array(
1119
-                    'e_reg_url_link' => $this->reg_url_link(),
1120
-                    'step'           => 'payment_options',
1121
-                    'revisit'        => true,
1122
-                    'clear_session'  => (bool) $clear_session,
1123
-                ),
1124
-                $this
1125
-            ),
1126
-            EE_Registry::instance()->CFG->core->reg_page_url()
1127
-        );
1128
-    }
1129
-
1130
-
1131
-    /**
1132
-     * Gets the URL for the checkout attendee information reg step
1133
-     * with this registration's REG_url_link added as a query parameter
1134
-     *
1135
-     * @return string
1136
-     * @throws EE_Error
1137
-     * @throws InvalidArgumentException
1138
-     * @throws InvalidDataTypeException
1139
-     * @throws InvalidInterfaceException
1140
-     * @throws ReflectionException
1141
-     */
1142
-    public function edit_attendee_information_url()
1143
-    {
1144
-        return add_query_arg(
1145
-            (array) apply_filters(
1146
-                'FHEE__EE_Registration__edit_attendee_information_url__query_args',
1147
-                array(
1148
-                    'e_reg_url_link' => $this->reg_url_link(),
1149
-                    'step'           => 'attendee_information',
1150
-                    'revisit'        => true,
1151
-                ),
1152
-                $this
1153
-            ),
1154
-            EE_Registry::instance()->CFG->core->reg_page_url()
1155
-        );
1156
-    }
1157
-
1158
-
1159
-    /**
1160
-     * Simply generates and returns the appropriate admin_url link to edit this registration
1161
-     *
1162
-     * @return string
1163
-     * @throws EE_Error
1164
-     * @throws InvalidArgumentException
1165
-     * @throws InvalidDataTypeException
1166
-     * @throws InvalidInterfaceException
1167
-     * @throws ReflectionException
1168
-     */
1169
-    public function get_admin_edit_url()
1170
-    {
1171
-        return EEH_URL::add_query_args_and_nonce(
1172
-            array(
1173
-                'page'    => 'espresso_registrations',
1174
-                'action'  => 'view_registration',
1175
-                '_REG_ID' => $this->ID(),
1176
-            ),
1177
-            admin_url('admin.php')
1178
-        );
1179
-    }
1180
-
1181
-
1182
-    /**
1183
-     * is_primary_registrant?
1184
-     *
1185
-     * @throws EE_Error
1186
-     * @throws InvalidArgumentException
1187
-     * @throws InvalidDataTypeException
1188
-     * @throws InvalidInterfaceException
1189
-     * @throws ReflectionException
1190
-     */
1191
-    public function is_primary_registrant()
1192
-    {
1193
-        return (int) $this->get('REG_count') === 1;
1194
-    }
1195
-
1196
-
1197
-    /**
1198
-     * This returns the primary registration object for this registration group (which may be this object).
1199
-     *
1200
-     * @return EE_Registration
1201
-     * @throws EE_Error
1202
-     * @throws InvalidArgumentException
1203
-     * @throws InvalidDataTypeException
1204
-     * @throws InvalidInterfaceException
1205
-     * @throws ReflectionException
1206
-     */
1207
-    public function get_primary_registration()
1208
-    {
1209
-        if ($this->is_primary_registrant()) {
1210
-            return $this;
1211
-        }
1212
-
1213
-        // k reg_count !== 1 so let's get the EE_Registration object matching this txn_id and reg_count == 1
1214
-        /** @var EE_Registration $primary_registrant */
1215
-        $primary_registrant = EEM_Registration::instance()->get_one(
1216
-            array(
1217
-                array(
1218
-                    'TXN_ID'    => $this->transaction_ID(),
1219
-                    'REG_count' => 1,
1220
-                ),
1221
-            )
1222
-        );
1223
-        return $primary_registrant;
1224
-    }
1225
-
1226
-
1227
-    /**
1228
-     * get  Attendee Number
1229
-     *
1230
-     * @throws EE_Error
1231
-     * @throws InvalidArgumentException
1232
-     * @throws InvalidDataTypeException
1233
-     * @throws InvalidInterfaceException
1234
-     * @throws ReflectionException
1235
-     */
1236
-    public function count()
1237
-    {
1238
-        return $this->get('REG_count');
1239
-    }
1240
-
1241
-
1242
-    /**
1243
-     * get Group Size
1244
-     *
1245
-     * @throws EE_Error
1246
-     * @throws InvalidArgumentException
1247
-     * @throws InvalidDataTypeException
1248
-     * @throws InvalidInterfaceException
1249
-     * @throws ReflectionException
1250
-     */
1251
-    public function group_size()
1252
-    {
1253
-        return $this->get('REG_group_size');
1254
-    }
1255
-
1256
-
1257
-    /**
1258
-     * get Registration Date
1259
-     *
1260
-     * @throws EE_Error
1261
-     * @throws InvalidArgumentException
1262
-     * @throws InvalidDataTypeException
1263
-     * @throws InvalidInterfaceException
1264
-     * @throws ReflectionException
1265
-     */
1266
-    public function date()
1267
-    {
1268
-        return $this->get('REG_date');
1269
-    }
1270
-
1271
-
1272
-    /**
1273
-     * gets a pretty date
1274
-     *
1275
-     * @param string $date_format
1276
-     * @param string $time_format
1277
-     * @return string
1278
-     * @throws EE_Error
1279
-     * @throws InvalidArgumentException
1280
-     * @throws InvalidDataTypeException
1281
-     * @throws InvalidInterfaceException
1282
-     * @throws ReflectionException
1283
-     */
1284
-    public function pretty_date($date_format = null, $time_format = null)
1285
-    {
1286
-        return $this->get_datetime('REG_date', $date_format, $time_format);
1287
-    }
1288
-
1289
-
1290
-    /**
1291
-     * final_price
1292
-     * the registration's share of the transaction total, so that the
1293
-     * sum of all the transaction's REG_final_prices equal the transaction's total
1294
-     *
1295
-     * @return float
1296
-     * @throws EE_Error
1297
-     * @throws InvalidArgumentException
1298
-     * @throws InvalidDataTypeException
1299
-     * @throws InvalidInterfaceException
1300
-     * @throws ReflectionException
1301
-     */
1302
-    public function final_price()
1303
-    {
1304
-        return $this->get('REG_final_price');
1305
-    }
1306
-
1307
-
1308
-    /**
1309
-     * pretty_final_price
1310
-     *  final price as formatted string, with correct decimal places and currency symbol
1311
-     *
1312
-     * @return string
1313
-     * @throws EE_Error
1314
-     * @throws InvalidArgumentException
1315
-     * @throws InvalidDataTypeException
1316
-     * @throws InvalidInterfaceException
1317
-     * @throws ReflectionException
1318
-     */
1319
-    public function pretty_final_price()
1320
-    {
1321
-        return $this->get_pretty('REG_final_price');
1322
-    }
1323
-
1324
-
1325
-    /**
1326
-     * get paid (yeah)
1327
-     *
1328
-     * @return float
1329
-     * @throws EE_Error
1330
-     * @throws InvalidArgumentException
1331
-     * @throws InvalidDataTypeException
1332
-     * @throws InvalidInterfaceException
1333
-     * @throws ReflectionException
1334
-     */
1335
-    public function paid()
1336
-    {
1337
-        return $this->get('REG_paid');
1338
-    }
1339
-
1340
-
1341
-    /**
1342
-     * pretty_paid
1343
-     *
1344
-     * @return float
1345
-     * @throws EE_Error
1346
-     * @throws InvalidArgumentException
1347
-     * @throws InvalidDataTypeException
1348
-     * @throws InvalidInterfaceException
1349
-     * @throws ReflectionException
1350
-     */
1351
-    public function pretty_paid()
1352
-    {
1353
-        return $this->get_pretty('REG_paid');
1354
-    }
1355
-
1356
-
1357
-    /**
1358
-     * owes_monies_and_can_pay
1359
-     * whether or not this registration has monies owing and it's' status allows payment
1360
-     *
1361
-     * @param array $requires_payment
1362
-     * @return bool
1363
-     * @throws EE_Error
1364
-     * @throws InvalidArgumentException
1365
-     * @throws InvalidDataTypeException
1366
-     * @throws InvalidInterfaceException
1367
-     * @throws ReflectionException
1368
-     */
1369
-    public function owes_monies_and_can_pay($requires_payment = array())
1370
-    {
1371
-        // these reg statuses require payment (if event is not free)
1372
-        $requires_payment = ! empty($requires_payment)
1373
-            ? $requires_payment
1374
-            : EEM_Registration::reg_statuses_that_allow_payment();
1375
-        if ($this->final_price() !== 0 &&
1376
-            $this->final_price() !== $this->paid() &&
1377
-            in_array($this->status_ID(), $requires_payment, true)
1378
-        ) {
1379
-            return true;
1380
-        }
1381
-        return false;
1382
-    }
1383
-
1384
-
1385
-    /**
1386
-     * Prints out the return value of $this->pretty_status()
1387
-     *
1388
-     * @param bool $show_icons
1389
-     * @return void
1390
-     * @throws EE_Error
1391
-     * @throws InvalidArgumentException
1392
-     * @throws InvalidDataTypeException
1393
-     * @throws InvalidInterfaceException
1394
-     * @throws ReflectionException
1395
-     */
1396
-    public function e_pretty_status($show_icons = false)
1397
-    {
1398
-        echo $this->pretty_status($show_icons);
1399
-    }
1400
-
1401
-
1402
-    /**
1403
-     * Returns a nice version of the status for displaying to customers
1404
-     *
1405
-     * @param bool $show_icons
1406
-     * @return string
1407
-     * @throws EE_Error
1408
-     * @throws InvalidArgumentException
1409
-     * @throws InvalidDataTypeException
1410
-     * @throws InvalidInterfaceException
1411
-     * @throws ReflectionException
1412
-     */
1413
-    public function pretty_status($show_icons = false)
1414
-    {
1415
-        $status = EEM_Status::instance()->localized_status(
1416
-            array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
1417
-            false,
1418
-            'sentence'
1419
-        );
1420
-        $icon = '';
1421
-        switch ($this->status_ID()) {
1422
-            case EEM_Registration::status_id_approved:
1423
-                $icon = $show_icons
1424
-                    ? '<span class="dashicons dashicons-star-filled ee-icon-size-16 green-text"></span>'
1425
-                    : '';
1426
-                break;
1427
-            case EEM_Registration::status_id_pending_payment:
1428
-                $icon = $show_icons
1429
-                    ? '<span class="dashicons dashicons-star-half ee-icon-size-16 orange-text"></span>'
1430
-                    : '';
1431
-                break;
1432
-            case EEM_Registration::status_id_not_approved:
1433
-                $icon = $show_icons
1434
-                    ? '<span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>'
1435
-                    : '';
1436
-                break;
1437
-            case EEM_Registration::status_id_cancelled:
1438
-                $icon = $show_icons
1439
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
1440
-                    : '';
1441
-                break;
1442
-            case EEM_Registration::status_id_incomplete:
1443
-                $icon = $show_icons
1444
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-orange-text"></span>'
1445
-                    : '';
1446
-                break;
1447
-            case EEM_Registration::status_id_declined:
1448
-                $icon = $show_icons
1449
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
1450
-                    : '';
1451
-                break;
1452
-            case EEM_Registration::status_id_wait_list:
1453
-                $icon = $show_icons
1454
-                    ? '<span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>'
1455
-                    : '';
1456
-                break;
1457
-        }
1458
-        return $icon . $status[ $this->status_ID() ];
1459
-    }
1460
-
1461
-
1462
-    /**
1463
-     *        get Attendee Is Going
1464
-     */
1465
-    public function att_is_going()
1466
-    {
1467
-        return $this->get('REG_att_is_going');
1468
-    }
1469
-
1470
-
1471
-    /**
1472
-     * Gets related answers
1473
-     *
1474
-     * @param array $query_params @see
1475
-     *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1476
-     * @return EE_Answer[]|EE_Base_Class[]
1477
-     * @throws EE_Error
1478
-     * @throws InvalidArgumentException
1479
-     * @throws InvalidDataTypeException
1480
-     * @throws InvalidInterfaceException
1481
-     * @throws ReflectionException
1482
-     */
1483
-    public function answers($query_params = null)
1484
-    {
1485
-        return $this->get_many_related('Answer', $query_params);
1486
-    }
1487
-
1488
-
1489
-    /**
1490
-     * Gets the registration's answer value to the specified question
1491
-     * (either the question's ID or a question object)
1492
-     *
1493
-     * @param EE_Question|int $question
1494
-     * @param bool            $pretty_value
1495
-     * @return array|string if pretty_value= true, the result will always be a string
1496
-     * (because the answer might be an array of answer values, so passing pretty_value=true
1497
-     * will convert it into some kind of string)
1498
-     * @throws EE_Error
1499
-     * @throws InvalidArgumentException
1500
-     * @throws InvalidDataTypeException
1501
-     * @throws InvalidInterfaceException
1502
-     */
1503
-    public function answer_value_to_question($question, $pretty_value = true)
1504
-    {
1505
-        $question_id = EEM_Question::instance()->ensure_is_ID($question);
1506
-        return EEM_Answer::instance()->get_answer_value_to_question($this, $question_id, $pretty_value);
1507
-    }
1508
-
1509
-
1510
-    /**
1511
-     * question_groups
1512
-     * returns an array of EE_Question_Group objects for this registration
1513
-     *
1514
-     * @return EE_Question_Group[]
1515
-     * @throws EE_Error
1516
-     * @throws InvalidArgumentException
1517
-     * @throws InvalidDataTypeException
1518
-     * @throws InvalidInterfaceException
1519
-     * @throws ReflectionException
1520
-     */
1521
-    public function question_groups()
1522
-    {
1523
-        return EEM_Event::instance()->get_question_groups_for_event($this->event_ID(), $this);
1524
-    }
1525
-
1526
-
1527
-    /**
1528
-     * count_question_groups
1529
-     * returns a count of the number of EE_Question_Group objects for this registration
1530
-     *
1531
-     * @return int
1532
-     * @throws EE_Error
1533
-     * @throws EntityNotFoundException
1534
-     * @throws InvalidArgumentException
1535
-     * @throws InvalidDataTypeException
1536
-     * @throws InvalidInterfaceException
1537
-     * @throws ReflectionException
1538
-     */
1539
-    public function count_question_groups()
1540
-    {
1541
-        return EEM_Event::instance()->count_related(
1542
-            $this->event_ID(),
1543
-            'Question_Group',
1544
-            [
1545
-                [
1546
-                    'Event_Question_Group.'
1547
-                    . EEM_Event_Question_Group::instance()->fieldNameForContext($this->is_primary_registrant()) => true,
1548
-                ]
1549
-            ]
1550
-        );
1551
-    }
1552
-
1553
-
1554
-    /**
1555
-     * Returns the registration date in the 'standard' string format
1556
-     * (function may be improved in the future to allow for different formats and timezones)
1557
-     *
1558
-     * @return string
1559
-     * @throws EE_Error
1560
-     * @throws InvalidArgumentException
1561
-     * @throws InvalidDataTypeException
1562
-     * @throws InvalidInterfaceException
1563
-     * @throws ReflectionException
1564
-     */
1565
-    public function reg_date()
1566
-    {
1567
-        return $this->get_datetime('REG_date');
1568
-    }
1569
-
1570
-
1571
-    /**
1572
-     * Gets the datetime-ticket for this registration (ie, it can be used to isolate
1573
-     * the ticket this registration purchased, or the datetime they have registered
1574
-     * to attend)
1575
-     *
1576
-     * @return EE_Base_Class|EE_Datetime_Ticket
1577
-     * @throws EE_Error
1578
-     * @throws InvalidArgumentException
1579
-     * @throws InvalidDataTypeException
1580
-     * @throws InvalidInterfaceException
1581
-     * @throws ReflectionException
1582
-     */
1583
-    public function datetime_ticket()
1584
-    {
1585
-        return $this->get_first_related('Datetime_Ticket');
1586
-    }
1587
-
1588
-
1589
-    /**
1590
-     * Sets the registration's datetime_ticket.
1591
-     *
1592
-     * @param EE_Datetime_Ticket $datetime_ticket
1593
-     * @return EE_Base_Class|EE_Datetime_Ticket
1594
-     * @throws EE_Error
1595
-     * @throws InvalidArgumentException
1596
-     * @throws InvalidDataTypeException
1597
-     * @throws InvalidInterfaceException
1598
-     * @throws ReflectionException
1599
-     */
1600
-    public function set_datetime_ticket($datetime_ticket)
1601
-    {
1602
-        return $this->_add_relation_to($datetime_ticket, 'Datetime_Ticket');
1603
-    }
1604
-
1605
-
1606
-    /**
1607
-     * Gets deleted
1608
-     *
1609
-     * @return bool
1610
-     * @throws EE_Error
1611
-     * @throws InvalidArgumentException
1612
-     * @throws InvalidDataTypeException
1613
-     * @throws InvalidInterfaceException
1614
-     * @throws ReflectionException
1615
-     */
1616
-    public function deleted()
1617
-    {
1618
-        return $this->get('REG_deleted');
1619
-    }
1620
-
1621
-
1622
-    /**
1623
-     * Sets deleted
1624
-     *
1625
-     * @param boolean $deleted
1626
-     * @return void
1627
-     * @throws DomainException
1628
-     * @throws EE_Error
1629
-     * @throws EntityNotFoundException
1630
-     * @throws InvalidArgumentException
1631
-     * @throws InvalidDataTypeException
1632
-     * @throws InvalidInterfaceException
1633
-     * @throws ReflectionException
1634
-     * @throws RuntimeException
1635
-     * @throws UnexpectedEntityException
1636
-     */
1637
-    public function set_deleted($deleted)
1638
-    {
1639
-        if ($deleted) {
1640
-            $this->delete(__METHOD__);
1641
-        } else {
1642
-            $this->restore(__METHOD__);
1643
-        }
1644
-    }
1645
-
1646
-
1647
-    /**
1648
-     * Get the status object of this object
1649
-     *
1650
-     * @return EE_Base_Class|EE_Status
1651
-     * @throws EE_Error
1652
-     * @throws InvalidArgumentException
1653
-     * @throws InvalidDataTypeException
1654
-     * @throws InvalidInterfaceException
1655
-     * @throws ReflectionException
1656
-     */
1657
-    public function status_obj()
1658
-    {
1659
-        return $this->get_first_related('Status');
1660
-    }
1661
-
1662
-
1663
-    /**
1664
-     * Returns the number of times this registration has checked into any of the datetimes
1665
-     * its available for
1666
-     *
1667
-     * @return int
1668
-     * @throws EE_Error
1669
-     * @throws InvalidArgumentException
1670
-     * @throws InvalidDataTypeException
1671
-     * @throws InvalidInterfaceException
1672
-     * @throws ReflectionException
1673
-     */
1674
-    public function count_checkins()
1675
-    {
1676
-        return $this->get_model()->count_related($this, 'Checkin');
1677
-    }
1678
-
1679
-
1680
-    /**
1681
-     * Returns the number of current Check-ins this registration is checked into for any of the datetimes the
1682
-     * registration is for.  Note, this is ONLY checked in (does not include checkedout)
1683
-     *
1684
-     * @return int
1685
-     * @throws EE_Error
1686
-     * @throws InvalidArgumentException
1687
-     * @throws InvalidDataTypeException
1688
-     * @throws InvalidInterfaceException
1689
-     * @throws ReflectionException
1690
-     */
1691
-    public function count_checkins_not_checkedout()
1692
-    {
1693
-        return $this->get_model()->count_related($this, 'Checkin', array(array('CHK_in' => 1)));
1694
-    }
1695
-
1696
-
1697
-    /**
1698
-     * The purpose of this method is simply to check whether this registration can checkin to the given datetime.
1699
-     *
1700
-     * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1701
-     * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1702
-     *                                          consider registration status as well as datetime access.
1703
-     * @return bool
1704
-     * @throws EE_Error
1705
-     * @throws InvalidArgumentException
1706
-     * @throws InvalidDataTypeException
1707
-     * @throws InvalidInterfaceException
1708
-     * @throws ReflectionException
1709
-     */
1710
-    public function can_checkin($DTT_OR_ID, $check_approved = true)
1711
-    {
1712
-        $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1713
-        // first check registration status
1714
-        if (! $DTT_ID || ($check_approved && ! $this->is_approved())) {
1715
-            return false;
1716
-        }
1717
-        // is there a datetime ticket that matches this dtt_ID?
1718
-        if (! EEM_Datetime_Ticket::instance()->exists(
1719
-            array(
1720
-                array(
1721
-                    'TKT_ID' => $this->get('TKT_ID'),
1722
-                    'DTT_ID' => $DTT_ID,
1723
-                ),
1724
-            )
1725
-        )) {
1726
-            return false;
1727
-        }
1728
-
1729
-        // final check is against TKT_uses
1730
-        return $this->verify_can_checkin_against_TKT_uses($DTT_ID);
1731
-    }
1732
-
1733
-
1734
-    /**
1735
-     * This method verifies whether the user can checkin for the given datetime considering the max uses value set on
1736
-     * the ticket. To do this,  a query is done to get the count of the datetime records already checked into.  If the
1737
-     * datetime given does not have a check-in record and checking in for that datetime will exceed the allowed uses,
1738
-     * then return false.  Otherwise return true.
1739
-     *
1740
-     * @param int | EE_Datetime $DTT_OR_ID The datetime the registration is being checked against
1741
-     * @return bool true means can checkin.  false means cannot checkin.
1742
-     * @throws EE_Error
1743
-     * @throws InvalidArgumentException
1744
-     * @throws InvalidDataTypeException
1745
-     * @throws InvalidInterfaceException
1746
-     * @throws ReflectionException
1747
-     */
1748
-    public function verify_can_checkin_against_TKT_uses($DTT_OR_ID)
1749
-    {
1750
-        $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1751
-
1752
-        if (! $DTT_ID) {
1753
-            return false;
1754
-        }
1755
-
1756
-        $max_uses = $this->ticket() instanceof EE_Ticket ? $this->ticket()->uses() : EE_INF;
1757
-
1758
-        // if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1759
-        // check-in or not.
1760
-        if (! $max_uses || $max_uses === EE_INF) {
1761
-            return true;
1762
-        }
1763
-
1764
-        // does this datetime have a checkin record?  If so, then the dtt count has already been verified so we can just
1765
-        // go ahead and toggle.
1766
-        if (EEM_Checkin::instance()->exists(array(array('REG_ID' => $this->ID(), 'DTT_ID' => $DTT_ID)))) {
1767
-            return true;
1768
-        }
1769
-
1770
-        // made it here so the last check is whether the number of checkins per unique datetime on this registration
1771
-        // disallows further check-ins.
1772
-        $count_unique_dtt_checkins = EEM_Checkin::instance()->count(
1773
-            array(
1774
-                array(
1775
-                    'REG_ID' => $this->ID(),
1776
-                    'CHK_in' => true,
1777
-                ),
1778
-            ),
1779
-            'DTT_ID',
1780
-            true
1781
-        );
1782
-        // checkins have already reached their max number of uses
1783
-        // so registrant can NOT checkin
1784
-        if ($count_unique_dtt_checkins >= $max_uses) {
1785
-            EE_Error::add_error(
1786
-                esc_html__(
1787
-                    'Check-in denied because number of datetime uses for the ticket has been reached or exceeded.',
1788
-                    'event_espresso'
1789
-                ),
1790
-                __FILE__,
1791
-                __FUNCTION__,
1792
-                __LINE__
1793
-            );
1794
-            return false;
1795
-        }
1796
-        return true;
1797
-    }
1798
-
1799
-
1800
-    /**
1801
-     * toggle Check-in status for this registration
1802
-     * Check-ins are toggled in the following order:
1803
-     * never checked in -> checked in
1804
-     * checked in -> checked out
1805
-     * checked out -> checked in
1806
-     *
1807
-     * @param  int $DTT_ID  include specific datetime to toggle Check-in for.
1808
-     *                      If not included or null, then it is assumed latest datetime is being toggled.
1809
-     * @param bool $verify  If true then can_checkin() is used to verify whether the person
1810
-     *                      can be checked in or not.  Otherwise this forces change in checkin status.
1811
-     * @return bool|int     the chk_in status toggled to OR false if nothing got changed.
1812
-     * @throws EE_Error
1813
-     * @throws InvalidArgumentException
1814
-     * @throws InvalidDataTypeException
1815
-     * @throws InvalidInterfaceException
1816
-     * @throws ReflectionException
1817
-     */
1818
-    public function toggle_checkin_status($DTT_ID = null, $verify = false)
1819
-    {
1820
-        if (empty($DTT_ID)) {
1821
-            $datetime = $this->get_latest_related_datetime();
1822
-            $DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1823
-            // verify the registration can checkin for the given DTT_ID
1824
-        } elseif (! $this->can_checkin($DTT_ID, $verify)) {
1825
-            EE_Error::add_error(
1826
-                sprintf(
1827
-                    esc_html__(
1828
-                        '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',
1829
-                        'event_espresso'
1830
-                    ),
1831
-                    $this->ID(),
1832
-                    $DTT_ID
1833
-                ),
1834
-                __FILE__,
1835
-                __FUNCTION__,
1836
-                __LINE__
1837
-            );
1838
-            return false;
1839
-        }
1840
-        $status_paths = array(
1841
-            EE_Checkin::status_checked_never => EE_Checkin::status_checked_in,
1842
-            EE_Checkin::status_checked_in    => EE_Checkin::status_checked_out,
1843
-            EE_Checkin::status_checked_out   => EE_Checkin::status_checked_in,
1844
-        );
1845
-        // start by getting the current status so we know what status we'll be changing to.
1846
-        $cur_status = $this->check_in_status_for_datetime($DTT_ID);
1847
-        $status_to = $status_paths[ $cur_status ];
1848
-        // database only records true for checked IN or false for checked OUT
1849
-        // no record ( null ) means checked in NEVER, but we obviously don't save that
1850
-        $new_status = $status_to === EE_Checkin::status_checked_in;
1851
-        // add relation - note Check-ins are always creating new rows
1852
-        // because we are keeping track of Check-ins over time.
1853
-        // Eventually we'll probably want to show a list table
1854
-        // for the individual Check-ins so that they can be managed.
1855
-        $checkin = EE_Checkin::new_instance(
1856
-            array(
1857
-                'REG_ID' => $this->ID(),
1858
-                'DTT_ID' => $DTT_ID,
1859
-                'CHK_in' => $new_status,
1860
-            )
1861
-        );
1862
-        // if the record could not be saved then return false
1863
-        if ($checkin->save() === 0) {
1864
-            if (WP_DEBUG) {
1865
-                global $wpdb;
1866
-                $error = sprintf(
1867
-                    esc_html__(
1868
-                        'Registration check in update failed because of the following database error: %1$s%2$s',
1869
-                        'event_espresso'
1870
-                    ),
1871
-                    '<br />',
1872
-                    $wpdb->last_error
1873
-                );
1874
-            } else {
1875
-                $error = esc_html__(
1876
-                    'Registration check in update failed because of an unknown database error',
1877
-                    'event_espresso'
1878
-                );
1879
-            }
1880
-            EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
1881
-            return false;
1882
-        }
1883
-        // Fire a checked_in and checkout_out action.
1884
-        $checked_status = $status_to === EE_Checkin::status_checked_in ? 'checked_in' : 'checked_out';
1885
-        do_action("AHEE__EE_Registration__toggle_checkin_status__{$checked_status}", $this, $DTT_ID);
1886
-        return $status_to;
1887
-    }
1888
-
1889
-
1890
-    /**
1891
-     * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1892
-     * "Latest" is defined by the `DTT_EVT_start` column.
1893
-     *
1894
-     * @return EE_Datetime|null
1895
-     * @throws EE_Error
1896
-     * @throws InvalidArgumentException
1897
-     * @throws InvalidDataTypeException
1898
-     * @throws InvalidInterfaceException
1899
-     * @throws ReflectionException
1900
-     */
1901
-    public function get_latest_related_datetime()
1902
-    {
1903
-        return EEM_Datetime::instance()->get_one(
1904
-            array(
1905
-                array(
1906
-                    'Ticket.Registration.REG_ID' => $this->ID(),
1907
-                ),
1908
-                'order_by' => array('DTT_EVT_start' => 'DESC'),
1909
-            )
1910
-        );
1911
-    }
1912
-
1913
-
1914
-    /**
1915
-     * Returns the earliest datetime related to this registration (via the ticket attached to the registration).
1916
-     * "Earliest" is defined by the `DTT_EVT_start` column.
1917
-     *
1918
-     * @return EE_Base_Class|EE_Soft_Delete_Base_Class|NULL
1919
-     * @throws EE_Error
1920
-     * @throws InvalidArgumentException
1921
-     * @throws InvalidDataTypeException
1922
-     * @throws InvalidInterfaceException
1923
-     * @throws ReflectionException
1924
-     */
1925
-    public function get_earliest_related_datetime()
1926
-    {
1927
-        return EEM_Datetime::instance()->get_one(
1928
-            array(
1929
-                array(
1930
-                    'Ticket.Registration.REG_ID' => $this->ID(),
1931
-                ),
1932
-                'order_by' => array('DTT_EVT_start' => 'ASC'),
1933
-            )
1934
-        );
1935
-    }
1936
-
1937
-
1938
-    /**
1939
-     * This method simply returns the check-in status for this registration and the given datetime.
1940
-     * If neither the datetime nor the checkin values are provided as arguments,
1941
-     * then this will return the LATEST check-in status for the registration across all datetimes it belongs to.
1942
-     *
1943
-     * @param  int       $DTT_ID  The ID of the datetime we're checking against
1944
-     *                            (if empty we'll get the primary datetime for
1945
-     *                            this registration (via event) and use it's ID);
1946
-     * @param EE_Checkin $checkin If present, we use the given checkin object rather than the dtt_id.
1947
-     * @return int                Integer representing Check-in status.
1948
-     * @throws EE_Error
1949
-     * @throws InvalidArgumentException
1950
-     * @throws InvalidDataTypeException
1951
-     * @throws InvalidInterfaceException
1952
-     * @throws ReflectionException
1953
-     */
1954
-    public function check_in_status_for_datetime($DTT_ID = 0, $checkin = null)
1955
-    {
1956
-        $checkin_query_params = array(
1957
-            'order_by' => array('CHK_timestamp' => 'DESC'),
1958
-        );
1959
-
1960
-        if ($DTT_ID > 0) {
1961
-            $checkin_query_params[0] = array('DTT_ID' => $DTT_ID);
1962
-        }
1963
-
1964
-        // get checkin object (if exists)
1965
-        $checkin = $checkin instanceof EE_Checkin
1966
-            ? $checkin
1967
-            : $this->get_first_related('Checkin', $checkin_query_params);
1968
-        if ($checkin instanceof EE_Checkin) {
1969
-            if ($checkin->get('CHK_in')) {
1970
-                return EE_Checkin::status_checked_in; // checked in
1971
-            }
1972
-            return EE_Checkin::status_checked_out; // had checked in but is now checked out.
1973
-        }
1974
-        return EE_Checkin::status_checked_never; // never been checked in
1975
-    }
1976
-
1977
-
1978
-    /**
1979
-     * This method returns a localized message for the toggled Check-in message.
1980
-     *
1981
-     * @param  int $DTT_ID include specific datetime to get the correct Check-in message.  If not included or null,
1982
-     *                     then it is assumed Check-in for primary datetime was toggled.
1983
-     * @param bool $error  This just flags that you want an error message returned. This is put in so that the error
1984
-     *                     message can be customized with the attendee name.
1985
-     * @return string internationalized message
1986
-     * @throws EE_Error
1987
-     * @throws InvalidArgumentException
1988
-     * @throws InvalidDataTypeException
1989
-     * @throws InvalidInterfaceException
1990
-     * @throws ReflectionException
1991
-     */
1992
-    public function get_checkin_msg($DTT_ID, $error = false)
1993
-    {
1994
-        // let's get the attendee first so we can include the name of the attendee
1995
-        $attendee = $this->get_first_related('Attendee');
1996
-        if ($attendee instanceof EE_Attendee) {
1997
-            if ($error) {
1998
-                return sprintf(__("%s's check-in status was not changed.", 'event_espresso'), $attendee->full_name());
1999
-            }
2000
-            $cur_status = $this->check_in_status_for_datetime($DTT_ID);
2001
-            // what is the status message going to be?
2002
-            switch ($cur_status) {
2003
-                case EE_Checkin::status_checked_never:
2004
-                    return sprintf(
2005
-                        esc_html__('%s has been removed from Check-in records', 'event_espresso'),
2006
-                        $attendee->full_name()
2007
-                    );
2008
-                    break;
2009
-                case EE_Checkin::status_checked_in:
2010
-                    return sprintf(__('%s has been checked in', 'event_espresso'), $attendee->full_name());
2011
-                    break;
2012
-                case EE_Checkin::status_checked_out:
2013
-                    return sprintf(__('%s has been checked out', 'event_espresso'), $attendee->full_name());
2014
-                    break;
2015
-            }
2016
-        }
2017
-        return esc_html__('The check-in status could not be determined.', 'event_espresso');
2018
-    }
2019
-
2020
-
2021
-    /**
2022
-     * Returns the related EE_Transaction to this registration
2023
-     *
2024
-     * @return EE_Transaction
2025
-     * @throws EE_Error
2026
-     * @throws EntityNotFoundException
2027
-     * @throws InvalidArgumentException
2028
-     * @throws InvalidDataTypeException
2029
-     * @throws InvalidInterfaceException
2030
-     * @throws ReflectionException
2031
-     */
2032
-    public function transaction()
2033
-    {
2034
-        $transaction = $this->get_first_related('Transaction');
2035
-        if (! $transaction instanceof \EE_Transaction) {
2036
-            throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
2037
-        }
2038
-        return $transaction;
2039
-    }
2040
-
2041
-
2042
-    /**
2043
-     * get Registration Code
2044
-     *
2045
-     * @return mixed
2046
-     * @throws EE_Error
2047
-     * @throws InvalidArgumentException
2048
-     * @throws InvalidDataTypeException
2049
-     * @throws InvalidInterfaceException
2050
-     * @throws ReflectionException
2051
-     */
2052
-    public function reg_code()
2053
-    {
2054
-        return $this->get('REG_code');
2055
-    }
2056
-
2057
-
2058
-    /**
2059
-     * @return mixed
2060
-     * @throws EE_Error
2061
-     * @throws InvalidArgumentException
2062
-     * @throws InvalidDataTypeException
2063
-     * @throws InvalidInterfaceException
2064
-     * @throws ReflectionException
2065
-     */
2066
-    public function transaction_ID()
2067
-    {
2068
-        return $this->get('TXN_ID');
2069
-    }
2070
-
2071
-
2072
-    /**
2073
-     * @return int
2074
-     * @throws EE_Error
2075
-     * @throws InvalidArgumentException
2076
-     * @throws InvalidDataTypeException
2077
-     * @throws InvalidInterfaceException
2078
-     * @throws ReflectionException
2079
-     */
2080
-    public function ticket_ID()
2081
-    {
2082
-        return $this->get('TKT_ID');
2083
-    }
2084
-
2085
-
2086
-    /**
2087
-     * Set Registration Code
2088
-     *
2089
-     * @param    string  $REG_code Registration Code
2090
-     * @param    boolean $use_default
2091
-     * @throws EE_Error
2092
-     * @throws InvalidArgumentException
2093
-     * @throws InvalidDataTypeException
2094
-     * @throws InvalidInterfaceException
2095
-     * @throws ReflectionException
2096
-     */
2097
-    public function set_reg_code($REG_code, $use_default = false)
2098
-    {
2099
-        if (empty($REG_code)) {
2100
-            EE_Error::add_error(
2101
-                esc_html__('REG_code can not be empty.', 'event_espresso'),
2102
-                __FILE__,
2103
-                __FUNCTION__,
2104
-                __LINE__
2105
-            );
2106
-            return;
2107
-        }
2108
-        if (! $this->reg_code()) {
2109
-            parent::set('REG_code', $REG_code, $use_default);
2110
-        } else {
2111
-            EE_Error::doing_it_wrong(
2112
-                __CLASS__ . '::' . __FUNCTION__,
2113
-                esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
2114
-                '4.6.0'
2115
-            );
2116
-        }
2117
-    }
2118
-
2119
-
2120
-    /**
2121
-     * Returns all other registrations in the same group as this registrant who have the same ticket option.
2122
-     * Note, if you want to just get all registrations in the same transaction (group), use:
2123
-     *    $registration->transaction()->registrations();
2124
-     *
2125
-     * @since 4.5.0
2126
-     * @return EE_Registration[] or empty array if this isn't a group registration.
2127
-     * @throws EE_Error
2128
-     * @throws InvalidArgumentException
2129
-     * @throws InvalidDataTypeException
2130
-     * @throws InvalidInterfaceException
2131
-     * @throws ReflectionException
2132
-     */
2133
-    public function get_all_other_registrations_in_group()
2134
-    {
2135
-        if ($this->group_size() < 2) {
2136
-            return array();
2137
-        }
2138
-
2139
-        $query[0] = array(
2140
-            'TXN_ID' => $this->transaction_ID(),
2141
-            'REG_ID' => array('!=', $this->ID()),
2142
-            'TKT_ID' => $this->ticket_ID(),
2143
-        );
2144
-        /** @var EE_Registration[] $registrations */
2145
-        $registrations = $this->get_model()->get_all($query);
2146
-        return $registrations;
2147
-    }
2148
-
2149
-
2150
-    /**
2151
-     * Return the link to the admin details for the object.
2152
-     *
2153
-     * @return string
2154
-     * @throws EE_Error
2155
-     * @throws InvalidArgumentException
2156
-     * @throws InvalidDataTypeException
2157
-     * @throws InvalidInterfaceException
2158
-     * @throws ReflectionException
2159
-     */
2160
-    public function get_admin_details_link()
2161
-    {
2162
-        EE_Registry::instance()->load_helper('URL');
2163
-        return EEH_URL::add_query_args_and_nonce(
2164
-            array(
2165
-                'page'    => 'espresso_registrations',
2166
-                'action'  => 'view_registration',
2167
-                '_REG_ID' => $this->ID(),
2168
-            ),
2169
-            admin_url('admin.php')
2170
-        );
2171
-    }
2172
-
2173
-
2174
-    /**
2175
-     * Returns the link to the editor for the object.  Sometimes this is the same as the details.
2176
-     *
2177
-     * @return string
2178
-     * @throws EE_Error
2179
-     * @throws InvalidArgumentException
2180
-     * @throws InvalidDataTypeException
2181
-     * @throws InvalidInterfaceException
2182
-     * @throws ReflectionException
2183
-     */
2184
-    public function get_admin_edit_link()
2185
-    {
2186
-        return $this->get_admin_details_link();
2187
-    }
2188
-
2189
-
2190
-    /**
2191
-     * Returns the link to a settings page for the object.
2192
-     *
2193
-     * @return string
2194
-     * @throws EE_Error
2195
-     * @throws InvalidArgumentException
2196
-     * @throws InvalidDataTypeException
2197
-     * @throws InvalidInterfaceException
2198
-     * @throws ReflectionException
2199
-     */
2200
-    public function get_admin_settings_link()
2201
-    {
2202
-        return $this->get_admin_details_link();
2203
-    }
2204
-
2205
-
2206
-    /**
2207
-     * Returns the link to the "overview" for the object (typically the "list table" view).
2208
-     *
2209
-     * @return string
2210
-     * @throws EE_Error
2211
-     * @throws InvalidArgumentException
2212
-     * @throws InvalidDataTypeException
2213
-     * @throws InvalidInterfaceException
2214
-     * @throws ReflectionException
2215
-     */
2216
-    public function get_admin_overview_link()
2217
-    {
2218
-        EE_Registry::instance()->load_helper('URL');
2219
-        return EEH_URL::add_query_args_and_nonce(
2220
-            array(
2221
-                'page' => 'espresso_registrations',
2222
-            ),
2223
-            admin_url('admin.php')
2224
-        );
2225
-    }
2226
-
2227
-
2228
-    /**
2229
-     * @param array $query_params
2230
-     * @return EE_Base_Class[]|EE_Registration[]
2231
-     * @throws EE_Error
2232
-     * @throws InvalidArgumentException
2233
-     * @throws InvalidDataTypeException
2234
-     * @throws InvalidInterfaceException
2235
-     * @throws ReflectionException
2236
-     */
2237
-    public function payments($query_params = array())
2238
-    {
2239
-        return $this->get_many_related('Payment', $query_params);
2240
-    }
2241
-
2242
-
2243
-    /**
2244
-     * @param array $query_params
2245
-     * @return EE_Base_Class[]|EE_Registration_Payment[]
2246
-     * @throws EE_Error
2247
-     * @throws InvalidArgumentException
2248
-     * @throws InvalidDataTypeException
2249
-     * @throws InvalidInterfaceException
2250
-     * @throws ReflectionException
2251
-     */
2252
-    public function registration_payments($query_params = array())
2253
-    {
2254
-        return $this->get_many_related('Registration_Payment', $query_params);
2255
-    }
2256
-
2257
-
2258
-    /**
2259
-     * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
2260
-     * Note: if there are no payments on the registration there will be no payment method returned.
2261
-     *
2262
-     * @return EE_Payment|EE_Payment_Method|null
2263
-     * @throws EE_Error
2264
-     * @throws InvalidArgumentException
2265
-     * @throws InvalidDataTypeException
2266
-     * @throws InvalidInterfaceException
2267
-     */
2268
-    public function payment_method()
2269
-    {
2270
-        return EEM_Payment_Method::instance()->get_last_used_for_registration($this);
2271
-    }
2272
-
2273
-
2274
-    /**
2275
-     * @return \EE_Line_Item
2276
-     * @throws EE_Error
2277
-     * @throws EntityNotFoundException
2278
-     * @throws InvalidArgumentException
2279
-     * @throws InvalidDataTypeException
2280
-     * @throws InvalidInterfaceException
2281
-     * @throws ReflectionException
2282
-     */
2283
-    public function ticket_line_item()
2284
-    {
2285
-        $ticket = $this->ticket();
2286
-        $transaction = $this->transaction();
2287
-        $line_item = null;
2288
-        $ticket_line_items = \EEH_Line_Item::get_line_items_by_object_type_and_IDs(
2289
-            $transaction->total_line_item(),
2290
-            'Ticket',
2291
-            array($ticket->ID())
2292
-        );
2293
-        foreach ($ticket_line_items as $ticket_line_item) {
2294
-            if ($ticket_line_item instanceof \EE_Line_Item
2295
-                && $ticket_line_item->OBJ_type() === 'Ticket'
2296
-                && $ticket_line_item->OBJ_ID() === $ticket->ID()
2297
-            ) {
2298
-                $line_item = $ticket_line_item;
2299
-                break;
2300
-            }
2301
-        }
2302
-        if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
2303
-            throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
2304
-        }
2305
-        return $line_item;
2306
-    }
2307
-
2308
-
2309
-    /**
2310
-     * Soft Deletes this model object.
2311
-     *
2312
-     * @param string $source function name that called this method
2313
-     * @return boolean | int
2314
-     * @throws DomainException
2315
-     * @throws EE_Error
2316
-     * @throws EntityNotFoundException
2317
-     * @throws InvalidArgumentException
2318
-     * @throws InvalidDataTypeException
2319
-     * @throws InvalidInterfaceException
2320
-     * @throws ReflectionException
2321
-     * @throws RuntimeException
2322
-     * @throws UnexpectedEntityException
2323
-     */
2324
-    public function delete($source = 'unknown')
2325
-    {
2326
-        if ($this->update_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY, $this->status_ID()) === true) {
2327
-            $current_user = wp_get_current_user();
2328
-            $this->add_extra_meta(
2329
-                EE_Registration::EXTRA_META_KEY_REG_TRASHED,
2330
-                array(
2331
-                    'trashed-by' => $current_user->ID ? $current_user->display_name : 'unauthed user',
2332
-                    'timestamp'  => time(),
2333
-                    'source'     => $source,
2334
-                )
2335
-            );
2336
-            $this->set_status(EEM_Registration::status_id_cancelled);
2337
-        }
2338
-        return parent::delete();
2339
-    }
2340
-
2341
-
2342
-    /**
2343
-     * Restores whatever the previous status was on a registration before it was trashed (if possible)
2344
-     *
2345
-     * @param string $source function name that called this method
2346
-     * @return bool|int
2347
-     * @throws DomainException
2348
-     * @throws EE_Error
2349
-     * @throws EntityNotFoundException
2350
-     * @throws InvalidArgumentException
2351
-     * @throws InvalidDataTypeException
2352
-     * @throws InvalidInterfaceException
2353
-     * @throws ReflectionException
2354
-     * @throws RuntimeException
2355
-     * @throws UnexpectedEntityException
2356
-     */
2357
-    public function restore($source = 'unknown')
2358
-    {
2359
-        $previous_status = $this->get_extra_meta(
2360
-            EE_Registration::PRE_TRASH_REG_STATUS_KEY,
2361
-            true,
2362
-            EEM_Registration::status_id_cancelled
2363
-        );
2364
-        if ($previous_status) {
2365
-            $this->delete_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY);
2366
-            $this->set_status($previous_status);
2367
-        }
2368
-        $current_user = wp_get_current_user();
2369
-        $this->add_extra_meta(
2370
-            EE_Registration::EXTRA_META_KEY_REG_RESTORED,
2371
-            array(
2372
-                'restored-by' => $current_user->ID ? $current_user->display_name : 'unauthed user',
2373
-                'timestamp'   => time(),
2374
-                'source'      => $source,
2375
-            )
2376
-        );
2377
-        return parent::restore();
2378
-    }
2379
-
2380
-
2381
-    /**
2382
-     * possibly toggle Registration status based on comparison of REG_paid vs REG_final_price
2383
-     *
2384
-     * @param  boolean $trigger_set_status_logic EE_Registration::set_status() can trigger additional logic
2385
-     *                                           depending on whether the reg status changes to or from "Approved"
2386
-     * @return boolean whether the Registration status was updated
2387
-     * @throws DomainException
2388
-     * @throws EE_Error
2389
-     * @throws EntityNotFoundException
2390
-     * @throws InvalidArgumentException
2391
-     * @throws InvalidDataTypeException
2392
-     * @throws InvalidInterfaceException
2393
-     * @throws ReflectionException
2394
-     * @throws RuntimeException
2395
-     * @throws UnexpectedEntityException
2396
-     */
2397
-    public function updateStatusBasedOnTotalPaid($trigger_set_status_logic = true)
2398
-    {
2399
-        $paid = $this->paid();
2400
-        $price = $this->final_price();
2401
-        switch (true) {
2402
-            // overpaid or paid
2403
-            case EEH_Money::compare_floats($paid, $price, '>'):
2404
-            case EEH_Money::compare_floats($paid, $price):
2405
-                $new_status = EEM_Registration::status_id_approved;
2406
-                break;
2407
-            //  underpaid
2408
-            case EEH_Money::compare_floats($paid, $price, '<'):
2409
-                $new_status = EEM_Registration::status_id_pending_payment;
2410
-                break;
2411
-            // uhhh Houston...
2412
-            default:
2413
-                throw new RuntimeException(
2414
-                    esc_html__('The total paid calculation for this registration is inaccurate.', 'event_espresso')
2415
-                );
2416
-        }
2417
-        if ($new_status !== $this->status_ID()) {
2418
-            if ($trigger_set_status_logic) {
2419
-                return $this->set_status($new_status);
2420
-            }
2421
-            parent::set('STS_ID', $new_status);
2422
-            return true;
2423
-        }
2424
-        return false;
2425
-    }
2426
-
2427
-
2428
-    /*************************** DEPRECATED ***************************/
2429
-
2430
-
2431
-    /**
2432
-     * @deprecated
2433
-     * @since     4.7.0
2434
-     */
2435
-    public function price_paid()
2436
-    {
2437
-        EE_Error::doing_it_wrong(
2438
-            'EE_Registration::price_paid()',
2439
-            esc_html__(
2440
-                'This method is deprecated, please use EE_Registration::final_price() instead.',
2441
-                'event_espresso'
2442
-            ),
2443
-            '4.7.0'
2444
-        );
2445
-        return $this->final_price();
2446
-    }
2447
-
2448
-
2449
-    /**
2450
-     * @deprecated
2451
-     * @since     4.7.0
2452
-     * @param    float $REG_final_price
2453
-     * @throws EE_Error
2454
-     * @throws EntityNotFoundException
2455
-     * @throws InvalidArgumentException
2456
-     * @throws InvalidDataTypeException
2457
-     * @throws InvalidInterfaceException
2458
-     * @throws ReflectionException
2459
-     * @throws RuntimeException
2460
-     * @throws DomainException
2461
-     */
2462
-    public function set_price_paid($REG_final_price = 0.00)
2463
-    {
2464
-        EE_Error::doing_it_wrong(
2465
-            'EE_Registration::set_price_paid()',
2466
-            esc_html__(
2467
-                'This method is deprecated, please use EE_Registration::set_final_price() instead.',
2468
-                'event_espresso'
2469
-            ),
2470
-            '4.7.0'
2471
-        );
2472
-        $this->set_final_price($REG_final_price);
2473
-    }
2474
-
2475
-
2476
-    /**
2477
-     * @deprecated
2478
-     * @since 4.7.0
2479
-     * @return string
2480
-     * @throws EE_Error
2481
-     * @throws InvalidArgumentException
2482
-     * @throws InvalidDataTypeException
2483
-     * @throws InvalidInterfaceException
2484
-     * @throws ReflectionException
2485
-     */
2486
-    public function pretty_price_paid()
2487
-    {
2488
-        EE_Error::doing_it_wrong(
2489
-            'EE_Registration::pretty_price_paid()',
2490
-            esc_html__(
2491
-                'This method is deprecated, please use EE_Registration::pretty_final_price() instead.',
2492
-                'event_espresso'
2493
-            ),
2494
-            '4.7.0'
2495
-        );
2496
-        return $this->pretty_final_price();
2497
-    }
2498
-
2499
-
2500
-    /**
2501
-     * Gets the primary datetime related to this registration via the related Event to this registration
2502
-     *
2503
-     * @deprecated 4.9.17
2504
-     * @return EE_Datetime
2505
-     * @throws EE_Error
2506
-     * @throws EntityNotFoundException
2507
-     * @throws InvalidArgumentException
2508
-     * @throws InvalidDataTypeException
2509
-     * @throws InvalidInterfaceException
2510
-     * @throws ReflectionException
2511
-     */
2512
-    public function get_related_primary_datetime()
2513
-    {
2514
-        EE_Error::doing_it_wrong(
2515
-            __METHOD__,
2516
-            esc_html__(
2517
-                'Use EE_Registration::get_latest_related_datetime() or EE_Registration::get_earliest_related_datetime()',
2518
-                'event_espresso'
2519
-            ),
2520
-            '4.9.17',
2521
-            '5.0.0'
2522
-        );
2523
-        return $this->event()->primary_datetime();
2524
-    }
2525
-
2526
-    /**
2527
-     * Returns the contact's name (or "Unknown" if there is no contact.)
2528
-     * @since 4.10.12.p
2529
-     * @return string
2530
-     * @throws EE_Error
2531
-     * @throws InvalidArgumentException
2532
-     * @throws InvalidDataTypeException
2533
-     * @throws InvalidInterfaceException
2534
-     * @throws ReflectionException
2535
-     */
2536
-    public function name()
2537
-    {
2538
-        return $this->attendeeName();
2539
-    }
19
+	/**
20
+	 * Used to reference when a registration has never been checked in.
21
+	 *
22
+	 * @deprecated use \EE_Checkin::status_checked_never instead
23
+	 * @type int
24
+	 */
25
+	const checkin_status_never = 2;
26
+
27
+	/**
28
+	 * Used to reference when a registration has been checked in.
29
+	 *
30
+	 * @deprecated use \EE_Checkin::status_checked_in instead
31
+	 * @type int
32
+	 */
33
+	const checkin_status_in = 1;
34
+
35
+	/**
36
+	 * Used to reference when a registration has been checked out.
37
+	 *
38
+	 * @deprecated use \EE_Checkin::status_checked_out instead
39
+	 * @type int
40
+	 */
41
+	const checkin_status_out = 0;
42
+
43
+	/**
44
+	 * extra meta key for tracking reg status os trashed registrations
45
+	 *
46
+	 * @type string
47
+	 */
48
+	const PRE_TRASH_REG_STATUS_KEY = 'pre_trash_registration_status';
49
+
50
+	/**
51
+	 * extra meta key for tracking if registration has reserved ticket
52
+	 *
53
+	 * @type string
54
+	 */
55
+	const HAS_RESERVED_TICKET_KEY = 'has_reserved_ticket';
56
+
57
+	/**
58
+	 * extra meta key for tracking when registrations are trashed and by who
59
+	 *
60
+	 * @type string
61
+	 */
62
+	const EXTRA_META_KEY_REG_TRASHED = 'registration-trashed';
63
+
64
+	/**
65
+	 * extra meta key for tracking when registrations are restored and by who
66
+	 *
67
+	 * @type string
68
+	 */
69
+	const EXTRA_META_KEY_REG_RESTORED = 'registration-restored';
70
+
71
+
72
+	/**
73
+	 * @param array  $props_n_values          incoming values
74
+	 * @param string $timezone                incoming timezone (if not set the timezone set for the website will be
75
+	 *                                        used.)
76
+	 * @param array  $date_formats            incoming date_formats in an array where the first value is the
77
+	 *                                        date_format and the second value is the time format
78
+	 * @return EE_Registration
79
+	 * @throws EE_Error
80
+	 * @throws InvalidArgumentException
81
+	 * @throws InvalidDataTypeException
82
+	 * @throws InvalidInterfaceException
83
+	 * @throws ReflectionException
84
+	 */
85
+	public static function new_instance($props_n_values = array(), $timezone = null, $date_formats = array())
86
+	{
87
+		$has_object = parent::_check_for_object($props_n_values, __CLASS__, $timezone, $date_formats);
88
+		return $has_object ? $has_object : new self($props_n_values, false, $timezone, $date_formats);
89
+	}
90
+
91
+
92
+	/**
93
+	 * @param array  $props_n_values  incoming values from the database
94
+	 * @param string $timezone        incoming timezone as set by the model.  If not set the timezone for
95
+	 *                                the website will be used.
96
+	 * @return EE_Registration
97
+	 * @throws EE_Error
98
+	 * @throws InvalidArgumentException
99
+	 * @throws InvalidDataTypeException
100
+	 * @throws InvalidInterfaceException
101
+	 * @throws ReflectionException
102
+	 */
103
+	public static function new_instance_from_db($props_n_values = array(), $timezone = null)
104
+	{
105
+		return new self($props_n_values, true, $timezone);
106
+	}
107
+
108
+
109
+	/**
110
+	 *        Set Event ID
111
+	 *
112
+	 * @param        int $EVT_ID Event ID
113
+	 * @throws DomainException
114
+	 * @throws EE_Error
115
+	 * @throws EntityNotFoundException
116
+	 * @throws InvalidArgumentException
117
+	 * @throws InvalidDataTypeException
118
+	 * @throws InvalidInterfaceException
119
+	 * @throws ReflectionException
120
+	 * @throws RuntimeException
121
+	 * @throws UnexpectedEntityException
122
+	 */
123
+	public function set_event($EVT_ID = 0)
124
+	{
125
+		$this->set('EVT_ID', $EVT_ID);
126
+	}
127
+
128
+
129
+	/**
130
+	 * Overrides parent set() method so that all calls to set( 'REG_code', $REG_code ) OR set( 'STS_ID', $STS_ID ) can
131
+	 * be routed to internal methods
132
+	 *
133
+	 * @param string $field_name
134
+	 * @param mixed  $field_value
135
+	 * @param bool   $use_default
136
+	 * @throws DomainException
137
+	 * @throws EE_Error
138
+	 * @throws EntityNotFoundException
139
+	 * @throws InvalidArgumentException
140
+	 * @throws InvalidDataTypeException
141
+	 * @throws InvalidInterfaceException
142
+	 * @throws ReflectionException
143
+	 * @throws RuntimeException
144
+	 * @throws UnexpectedEntityException
145
+	 */
146
+	public function set($field_name, $field_value, $use_default = false)
147
+	{
148
+		switch ($field_name) {
149
+			case 'REG_code':
150
+				if (! empty($field_value) && $this->reg_code() === null) {
151
+					$this->set_reg_code($field_value, $use_default);
152
+				}
153
+				break;
154
+			case 'STS_ID':
155
+				$this->set_status($field_value, $use_default);
156
+				break;
157
+			default:
158
+				parent::set($field_name, $field_value, $use_default);
159
+		}
160
+	}
161
+
162
+
163
+	/**
164
+	 * Set Status ID
165
+	 * updates the registration status and ALSO...
166
+	 * calls reserve_registration_space() if the reg status changes TO approved from any other reg status
167
+	 * calls release_registration_space() if the reg status changes FROM approved to any other reg status
168
+	 *
169
+	 * @param string                $new_STS_ID
170
+	 * @param boolean               $use_default
171
+	 * @param ContextInterface|null $context
172
+	 * @return bool
173
+	 * @throws DomainException
174
+	 * @throws EE_Error
175
+	 * @throws EntityNotFoundException
176
+	 * @throws InvalidArgumentException
177
+	 * @throws InvalidDataTypeException
178
+	 * @throws InvalidInterfaceException
179
+	 * @throws ReflectionException
180
+	 * @throws RuntimeException
181
+	 * @throws UnexpectedEntityException
182
+	 */
183
+	public function set_status($new_STS_ID = null, $use_default = false, ContextInterface $context = null)
184
+	{
185
+		// get current REG_Status
186
+		$old_STS_ID = $this->status_ID();
187
+		// if status has changed
188
+		if ($old_STS_ID !== $new_STS_ID // and that status has actually changed
189
+			&& ! empty($old_STS_ID) // and that old status is actually set
190
+			&& ! empty($new_STS_ID) // as well as the new status
191
+			&& $this->ID() // ensure registration is in the db
192
+		) {
193
+			// update internal status first
194
+			parent::set('STS_ID', $new_STS_ID, $use_default);
195
+			// THEN handle other changes that occur when reg status changes
196
+			// TO approved
197
+			if ($new_STS_ID === EEM_Registration::status_id_approved) {
198
+				// reserve a space by incrementing ticket and datetime sold values
199
+				$this->reserveRegistrationSpace();
200
+				do_action('AHEE__EE_Registration__set_status__to_approved', $this, $old_STS_ID, $new_STS_ID, $context);
201
+				// OR FROM  approved
202
+			} elseif ($old_STS_ID === EEM_Registration::status_id_approved) {
203
+				// release a space by decrementing ticket and datetime sold values
204
+				$this->releaseRegistrationSpace();
205
+				do_action(
206
+					'AHEE__EE_Registration__set_status__from_approved',
207
+					$this,
208
+					$old_STS_ID,
209
+					$new_STS_ID,
210
+					$context
211
+				);
212
+			}
213
+			// update status
214
+			parent::set('STS_ID', $new_STS_ID, $use_default);
215
+			$this->updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, $context);
216
+			if ($this->statusChangeUpdatesTransaction($context)) {
217
+				$this->updateTransactionAfterStatusChange();
218
+			}
219
+			do_action('AHEE__EE_Registration__set_status__after_update', $this, $old_STS_ID, $new_STS_ID, $context);
220
+			return true;
221
+		}
222
+		// even though the old value matches the new value, it's still good to
223
+		// allow the parent set method to have a say
224
+		parent::set('STS_ID', $new_STS_ID, $use_default);
225
+		return true;
226
+	}
227
+
228
+
229
+	/**
230
+	 * update REGs and TXN when cancelled or declined registrations involved
231
+	 *
232
+	 * @param string                $new_STS_ID
233
+	 * @param string                $old_STS_ID
234
+	 * @param ContextInterface|null $context
235
+	 * @throws EE_Error
236
+	 * @throws InvalidArgumentException
237
+	 * @throws InvalidDataTypeException
238
+	 * @throws InvalidInterfaceException
239
+	 * @throws ReflectionException
240
+	 * @throws RuntimeException
241
+	 */
242
+	private function updateIfCanceledOrReinstated($new_STS_ID, $old_STS_ID, ContextInterface $context = null)
243
+	{
244
+		// these reg statuses should not be considered in any calculations involving monies owing
245
+		$closed_reg_statuses = EEM_Registration::closed_reg_statuses();
246
+		// true if registration has been cancelled or declined
247
+		$this->updateIfCanceled(
248
+			$closed_reg_statuses,
249
+			$new_STS_ID,
250
+			$old_STS_ID,
251
+			$context
252
+		);
253
+		$this->updateIfReinstated(
254
+			$closed_reg_statuses,
255
+			$new_STS_ID,
256
+			$old_STS_ID,
257
+			$context
258
+		);
259
+	}
260
+
261
+
262
+	/**
263
+	 * update REGs and TXN when cancelled or declined registrations involved
264
+	 *
265
+	 * @param array                 $closed_reg_statuses
266
+	 * @param string                $new_STS_ID
267
+	 * @param string                $old_STS_ID
268
+	 * @param ContextInterface|null $context
269
+	 * @throws EE_Error
270
+	 * @throws InvalidArgumentException
271
+	 * @throws InvalidDataTypeException
272
+	 * @throws InvalidInterfaceException
273
+	 * @throws ReflectionException
274
+	 * @throws RuntimeException
275
+	 */
276
+	private function updateIfCanceled(
277
+		array $closed_reg_statuses,
278
+		$new_STS_ID,
279
+		$old_STS_ID,
280
+		ContextInterface $context = null
281
+	) {
282
+		// true if registration has been cancelled or declined
283
+		if (in_array($new_STS_ID, $closed_reg_statuses, true)
284
+			&& ! in_array($old_STS_ID, $closed_reg_statuses, true)
285
+		) {
286
+			/** @type EE_Registration_Processor $registration_processor */
287
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
288
+			/** @type EE_Transaction_Processor $transaction_processor */
289
+			$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
290
+			// cancelled or declined registration
291
+			$registration_processor->update_registration_after_being_canceled_or_declined(
292
+				$this,
293
+				$closed_reg_statuses
294
+			);
295
+			$transaction_processor->update_transaction_after_canceled_or_declined_registration(
296
+				$this,
297
+				$closed_reg_statuses,
298
+				false
299
+			);
300
+			do_action(
301
+				'AHEE__EE_Registration__set_status__canceled_or_declined',
302
+				$this,
303
+				$old_STS_ID,
304
+				$new_STS_ID,
305
+				$context
306
+			);
307
+			return;
308
+		}
309
+	}
310
+
311
+
312
+	/**
313
+	 * update REGs and TXN when cancelled or declined registrations involved
314
+	 *
315
+	 * @param array                 $closed_reg_statuses
316
+	 * @param string                $new_STS_ID
317
+	 * @param string                $old_STS_ID
318
+	 * @param ContextInterface|null $context
319
+	 * @throws EE_Error
320
+	 * @throws InvalidArgumentException
321
+	 * @throws InvalidDataTypeException
322
+	 * @throws InvalidInterfaceException
323
+	 * @throws ReflectionException
324
+	 * @throws RuntimeException
325
+	 */
326
+	private function updateIfReinstated(
327
+		array $closed_reg_statuses,
328
+		$new_STS_ID,
329
+		$old_STS_ID,
330
+		ContextInterface $context = null
331
+	) {
332
+		// true if reinstating cancelled or declined registration
333
+		if (in_array($old_STS_ID, $closed_reg_statuses, true)
334
+			&& ! in_array($new_STS_ID, $closed_reg_statuses, true)
335
+		) {
336
+			/** @type EE_Registration_Processor $registration_processor */
337
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
338
+			/** @type EE_Transaction_Processor $transaction_processor */
339
+			$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
340
+			// reinstating cancelled or declined registration
341
+			$registration_processor->update_canceled_or_declined_registration_after_being_reinstated(
342
+				$this,
343
+				$closed_reg_statuses
344
+			);
345
+			$transaction_processor->update_transaction_after_reinstating_canceled_registration(
346
+				$this,
347
+				$closed_reg_statuses,
348
+				false
349
+			);
350
+			do_action(
351
+				'AHEE__EE_Registration__set_status__after_reinstated',
352
+				$this,
353
+				$old_STS_ID,
354
+				$new_STS_ID,
355
+				$context
356
+			);
357
+		}
358
+	}
359
+
360
+
361
+	/**
362
+	 * @param ContextInterface|null $context
363
+	 * @return bool
364
+	 */
365
+	private function statusChangeUpdatesTransaction(ContextInterface $context = null)
366
+	{
367
+		$contexts_that_do_not_update_transaction = (array) apply_filters(
368
+			'AHEE__EE_Registration__statusChangeUpdatesTransaction__contexts_that_do_not_update_transaction',
369
+			array('spco_reg_step_attendee_information_process_registrations'),
370
+			$context,
371
+			$this
372
+		);
373
+		return ! (
374
+			$context instanceof ContextInterface
375
+			&& in_array($context->slug(), $contexts_that_do_not_update_transaction, true)
376
+		);
377
+	}
378
+
379
+
380
+	/**
381
+	 * @throws EE_Error
382
+	 * @throws EntityNotFoundException
383
+	 * @throws InvalidArgumentException
384
+	 * @throws InvalidDataTypeException
385
+	 * @throws InvalidInterfaceException
386
+	 * @throws ReflectionException
387
+	 * @throws RuntimeException
388
+	 */
389
+	private function updateTransactionAfterStatusChange()
390
+	{
391
+		/** @type EE_Transaction_Payments $transaction_payments */
392
+		$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
393
+		$transaction_payments->recalculate_transaction_total($this->transaction(), false);
394
+		$this->transaction()->update_status_based_on_total_paid();
395
+	}
396
+
397
+
398
+	/**
399
+	 * get Status ID
400
+	 *
401
+	 * @throws EE_Error
402
+	 * @throws InvalidArgumentException
403
+	 * @throws InvalidDataTypeException
404
+	 * @throws InvalidInterfaceException
405
+	 * @throws ReflectionException
406
+	 */
407
+	public function status_ID()
408
+	{
409
+		return $this->get('STS_ID');
410
+	}
411
+
412
+
413
+	/**
414
+	 * Gets the ticket this registration is for
415
+	 *
416
+	 * @param boolean $include_archived whether to include archived tickets or not.
417
+	 * @return EE_Ticket|EE_Base_Class
418
+	 * @throws EE_Error
419
+	 * @throws InvalidArgumentException
420
+	 * @throws InvalidDataTypeException
421
+	 * @throws InvalidInterfaceException
422
+	 * @throws ReflectionException
423
+	 */
424
+	public function ticket($include_archived = true)
425
+	{
426
+		$query_params = array();
427
+		if ($include_archived) {
428
+			$query_params['default_where_conditions'] = 'none';
429
+		}
430
+		return $this->get_first_related('Ticket', $query_params);
431
+	}
432
+
433
+
434
+	/**
435
+	 * Gets the event this registration is for
436
+	 *
437
+	 * @return EE_Event
438
+	 * @throws EE_Error
439
+	 * @throws EntityNotFoundException
440
+	 * @throws InvalidArgumentException
441
+	 * @throws InvalidDataTypeException
442
+	 * @throws InvalidInterfaceException
443
+	 * @throws ReflectionException
444
+	 */
445
+	public function event()
446
+	{
447
+		$event = $this->get_first_related('Event');
448
+		if (! $event instanceof \EE_Event) {
449
+			throw new EntityNotFoundException('Event ID', $this->event_ID());
450
+		}
451
+		return $event;
452
+	}
453
+
454
+
455
+	/**
456
+	 * Gets the "author" of the registration.  Note that for the purposes of registrations, the author will correspond
457
+	 * with the author of the event this registration is for.
458
+	 *
459
+	 * @since 4.5.0
460
+	 * @return int
461
+	 * @throws EE_Error
462
+	 * @throws EntityNotFoundException
463
+	 * @throws InvalidArgumentException
464
+	 * @throws InvalidDataTypeException
465
+	 * @throws InvalidInterfaceException
466
+	 * @throws ReflectionException
467
+	 */
468
+	public function wp_user()
469
+	{
470
+		$event = $this->event();
471
+		if ($event instanceof EE_Event) {
472
+			return $event->wp_user();
473
+		}
474
+		return 0;
475
+	}
476
+
477
+
478
+	/**
479
+	 * increments this registration's related ticket sold and corresponding datetime sold values
480
+	 *
481
+	 * @return void
482
+	 * @throws DomainException
483
+	 * @throws EE_Error
484
+	 * @throws EntityNotFoundException
485
+	 * @throws InvalidArgumentException
486
+	 * @throws InvalidDataTypeException
487
+	 * @throws InvalidInterfaceException
488
+	 * @throws ReflectionException
489
+	 * @throws UnexpectedEntityException
490
+	 */
491
+	private function reserveRegistrationSpace()
492
+	{
493
+		// reserved ticket and datetime counts will be decremented as sold counts are incremented
494
+		// so stop tracking that this reg has a ticket reserved
495
+		$this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
496
+		$ticket = $this->ticket();
497
+		$ticket->increaseSold();
498
+		// possibly set event status to sold out
499
+		$this->event()->perform_sold_out_status_check();
500
+	}
501
+
502
+
503
+	/**
504
+	 * decrements (subtracts) this registration's related ticket sold and corresponding datetime sold values
505
+	 *
506
+	 * @return void
507
+	 * @throws DomainException
508
+	 * @throws EE_Error
509
+	 * @throws EntityNotFoundException
510
+	 * @throws InvalidArgumentException
511
+	 * @throws InvalidDataTypeException
512
+	 * @throws InvalidInterfaceException
513
+	 * @throws ReflectionException
514
+	 * @throws UnexpectedEntityException
515
+	 */
516
+	private function releaseRegistrationSpace()
517
+	{
518
+		$ticket = $this->ticket();
519
+		$ticket->decreaseSold();
520
+		// possibly change event status from sold out back to previous status
521
+		$this->event()->perform_sold_out_status_check();
522
+	}
523
+
524
+
525
+	/**
526
+	 * tracks this registration's ticket reservation in extra meta
527
+	 * and can increment related ticket reserved and corresponding datetime reserved values
528
+	 *
529
+	 * @param bool   $update_ticket if true, will increment ticket and datetime reserved count
530
+	 * @param string $source
531
+	 * @return void
532
+	 * @throws EE_Error
533
+	 * @throws InvalidArgumentException
534
+	 * @throws InvalidDataTypeException
535
+	 * @throws InvalidInterfaceException
536
+	 * @throws ReflectionException
537
+	 */
538
+	public function reserve_ticket($update_ticket = false, $source = 'unknown')
539
+	{
540
+		// only reserve ticket if space is not currently reserved
541
+		if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) !== true) {
542
+			$this->update_extra_meta('reserve_ticket', "{$this->ticket_ID()} from {$source}");
543
+			$reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
544
+			if ($reserved && $update_ticket) {
545
+				$ticket = $this->ticket();
546
+				$ticket->increaseReserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
547
+				$ticket->save();
548
+			}
549
+		}
550
+	}
551
+
552
+
553
+	/**
554
+	 * stops tracking this registration's ticket reservation in extra meta
555
+	 * decrements (subtracts) related ticket reserved and corresponding datetime reserved values
556
+	 *
557
+	 * @param bool   $update_ticket if true, will decrement ticket and datetime reserved count
558
+	 * @param string $source
559
+	 * @return void
560
+	 * @throws EE_Error
561
+	 * @throws InvalidArgumentException
562
+	 * @throws InvalidDataTypeException
563
+	 * @throws InvalidInterfaceException
564
+	 * @throws ReflectionException
565
+	 */
566
+	public function release_reserved_ticket($update_ticket = false, $source = 'unknown')
567
+	{
568
+		// only release ticket if space is currently reserved
569
+		if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) === true) {
570
+			$this->update_extra_meta('release_reserved_ticket', "{$this->ticket_ID()} from {$source}");
571
+			$reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, false);
572
+			if ($reserved && $update_ticket) {
573
+				$ticket = $this->ticket();
574
+				$ticket->decreaseReserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
575
+			}
576
+		}
577
+	}
578
+
579
+
580
+	/**
581
+	 * Set Attendee ID
582
+	 *
583
+	 * @param        int $ATT_ID Attendee ID
584
+	 * @throws DomainException
585
+	 * @throws EE_Error
586
+	 * @throws EntityNotFoundException
587
+	 * @throws InvalidArgumentException
588
+	 * @throws InvalidDataTypeException
589
+	 * @throws InvalidInterfaceException
590
+	 * @throws ReflectionException
591
+	 * @throws RuntimeException
592
+	 * @throws UnexpectedEntityException
593
+	 */
594
+	public function set_attendee_id($ATT_ID = 0)
595
+	{
596
+		$this->set('ATT_ID', $ATT_ID);
597
+	}
598
+
599
+
600
+	/**
601
+	 *        Set Transaction ID
602
+	 *
603
+	 * @param        int $TXN_ID Transaction ID
604
+	 * @throws DomainException
605
+	 * @throws EE_Error
606
+	 * @throws EntityNotFoundException
607
+	 * @throws InvalidArgumentException
608
+	 * @throws InvalidDataTypeException
609
+	 * @throws InvalidInterfaceException
610
+	 * @throws ReflectionException
611
+	 * @throws RuntimeException
612
+	 * @throws UnexpectedEntityException
613
+	 */
614
+	public function set_transaction_id($TXN_ID = 0)
615
+	{
616
+		$this->set('TXN_ID', $TXN_ID);
617
+	}
618
+
619
+
620
+	/**
621
+	 *        Set Session
622
+	 *
623
+	 * @param    string $REG_session PHP Session ID
624
+	 * @throws DomainException
625
+	 * @throws EE_Error
626
+	 * @throws EntityNotFoundException
627
+	 * @throws InvalidArgumentException
628
+	 * @throws InvalidDataTypeException
629
+	 * @throws InvalidInterfaceException
630
+	 * @throws ReflectionException
631
+	 * @throws RuntimeException
632
+	 * @throws UnexpectedEntityException
633
+	 */
634
+	public function set_session($REG_session = '')
635
+	{
636
+		$this->set('REG_session', $REG_session);
637
+	}
638
+
639
+
640
+	/**
641
+	 *        Set Registration URL Link
642
+	 *
643
+	 * @param    string $REG_url_link Registration URL Link
644
+	 * @throws DomainException
645
+	 * @throws EE_Error
646
+	 * @throws EntityNotFoundException
647
+	 * @throws InvalidArgumentException
648
+	 * @throws InvalidDataTypeException
649
+	 * @throws InvalidInterfaceException
650
+	 * @throws ReflectionException
651
+	 * @throws RuntimeException
652
+	 * @throws UnexpectedEntityException
653
+	 */
654
+	public function set_reg_url_link($REG_url_link = '')
655
+	{
656
+		$this->set('REG_url_link', $REG_url_link);
657
+	}
658
+
659
+
660
+	/**
661
+	 *        Set Attendee Counter
662
+	 *
663
+	 * @param        int $REG_count Primary Attendee
664
+	 * @throws DomainException
665
+	 * @throws EE_Error
666
+	 * @throws EntityNotFoundException
667
+	 * @throws InvalidArgumentException
668
+	 * @throws InvalidDataTypeException
669
+	 * @throws InvalidInterfaceException
670
+	 * @throws ReflectionException
671
+	 * @throws RuntimeException
672
+	 * @throws UnexpectedEntityException
673
+	 */
674
+	public function set_count($REG_count = 1)
675
+	{
676
+		$this->set('REG_count', $REG_count);
677
+	}
678
+
679
+
680
+	/**
681
+	 *        Set Group Size
682
+	 *
683
+	 * @param        boolean $REG_group_size Group Registration
684
+	 * @throws DomainException
685
+	 * @throws EE_Error
686
+	 * @throws EntityNotFoundException
687
+	 * @throws InvalidArgumentException
688
+	 * @throws InvalidDataTypeException
689
+	 * @throws InvalidInterfaceException
690
+	 * @throws ReflectionException
691
+	 * @throws RuntimeException
692
+	 * @throws UnexpectedEntityException
693
+	 */
694
+	public function set_group_size($REG_group_size = false)
695
+	{
696
+		$this->set('REG_group_size', $REG_group_size);
697
+	}
698
+
699
+
700
+	/**
701
+	 *    is_not_approved -  convenience method that returns TRUE if REG status ID ==
702
+	 *    EEM_Registration::status_id_not_approved
703
+	 *
704
+	 * @return        boolean
705
+	 * @throws EE_Error
706
+	 * @throws InvalidArgumentException
707
+	 * @throws InvalidDataTypeException
708
+	 * @throws InvalidInterfaceException
709
+	 * @throws ReflectionException
710
+	 */
711
+	public function is_not_approved()
712
+	{
713
+		return $this->status_ID() === EEM_Registration::status_id_not_approved;
714
+	}
715
+
716
+
717
+	/**
718
+	 *    is_pending_payment -  convenience method that returns TRUE if REG status ID ==
719
+	 *    EEM_Registration::status_id_pending_payment
720
+	 *
721
+	 * @return        boolean
722
+	 * @throws EE_Error
723
+	 * @throws InvalidArgumentException
724
+	 * @throws InvalidDataTypeException
725
+	 * @throws InvalidInterfaceException
726
+	 * @throws ReflectionException
727
+	 */
728
+	public function is_pending_payment()
729
+	{
730
+		return $this->status_ID() === EEM_Registration::status_id_pending_payment;
731
+	}
732
+
733
+
734
+	/**
735
+	 *    is_approved -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_approved
736
+	 *
737
+	 * @return        boolean
738
+	 * @throws EE_Error
739
+	 * @throws InvalidArgumentException
740
+	 * @throws InvalidDataTypeException
741
+	 * @throws InvalidInterfaceException
742
+	 * @throws ReflectionException
743
+	 */
744
+	public function is_approved()
745
+	{
746
+		return $this->status_ID() === EEM_Registration::status_id_approved;
747
+	}
748
+
749
+
750
+	/**
751
+	 *    is_cancelled -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_cancelled
752
+	 *
753
+	 * @return        boolean
754
+	 * @throws EE_Error
755
+	 * @throws InvalidArgumentException
756
+	 * @throws InvalidDataTypeException
757
+	 * @throws InvalidInterfaceException
758
+	 * @throws ReflectionException
759
+	 */
760
+	public function is_cancelled()
761
+	{
762
+		return $this->status_ID() === EEM_Registration::status_id_cancelled;
763
+	}
764
+
765
+
766
+	/**
767
+	 *    is_declined -  convenience method that returns TRUE if REG status ID == EEM_Registration::status_id_declined
768
+	 *
769
+	 * @return        boolean
770
+	 * @throws EE_Error
771
+	 * @throws InvalidArgumentException
772
+	 * @throws InvalidDataTypeException
773
+	 * @throws InvalidInterfaceException
774
+	 * @throws ReflectionException
775
+	 */
776
+	public function is_declined()
777
+	{
778
+		return $this->status_ID() === EEM_Registration::status_id_declined;
779
+	}
780
+
781
+
782
+	/**
783
+	 *    is_incomplete -  convenience method that returns TRUE if REG status ID ==
784
+	 *    EEM_Registration::status_id_incomplete
785
+	 *
786
+	 * @return        boolean
787
+	 * @throws EE_Error
788
+	 * @throws InvalidArgumentException
789
+	 * @throws InvalidDataTypeException
790
+	 * @throws InvalidInterfaceException
791
+	 * @throws ReflectionException
792
+	 */
793
+	public function is_incomplete()
794
+	{
795
+		return $this->status_ID() === EEM_Registration::status_id_incomplete;
796
+	}
797
+
798
+
799
+	/**
800
+	 *        Set Registration Date
801
+	 *
802
+	 * @param        mixed ( int or string ) $REG_date Registration Date - Unix timestamp or string representation of
803
+	 *                                                 Date
804
+	 * @throws DomainException
805
+	 * @throws EE_Error
806
+	 * @throws EntityNotFoundException
807
+	 * @throws InvalidArgumentException
808
+	 * @throws InvalidDataTypeException
809
+	 * @throws InvalidInterfaceException
810
+	 * @throws ReflectionException
811
+	 * @throws RuntimeException
812
+	 * @throws UnexpectedEntityException
813
+	 */
814
+	public function set_reg_date($REG_date = false)
815
+	{
816
+		$this->set('REG_date', $REG_date);
817
+	}
818
+
819
+
820
+	/**
821
+	 *    Set final price owing for this registration after all ticket/price modifications
822
+	 *
823
+	 * @param    float $REG_final_price
824
+	 * @throws DomainException
825
+	 * @throws EE_Error
826
+	 * @throws EntityNotFoundException
827
+	 * @throws InvalidArgumentException
828
+	 * @throws InvalidDataTypeException
829
+	 * @throws InvalidInterfaceException
830
+	 * @throws ReflectionException
831
+	 * @throws RuntimeException
832
+	 * @throws UnexpectedEntityException
833
+	 */
834
+	public function set_final_price($REG_final_price = 0.00)
835
+	{
836
+		$this->set('REG_final_price', $REG_final_price);
837
+	}
838
+
839
+
840
+	/**
841
+	 *    Set amount paid towards this registration's final price
842
+	 *
843
+	 * @param    float $REG_paid
844
+	 * @throws DomainException
845
+	 * @throws EE_Error
846
+	 * @throws EntityNotFoundException
847
+	 * @throws InvalidArgumentException
848
+	 * @throws InvalidDataTypeException
849
+	 * @throws InvalidInterfaceException
850
+	 * @throws ReflectionException
851
+	 * @throws RuntimeException
852
+	 * @throws UnexpectedEntityException
853
+	 */
854
+	public function set_paid($REG_paid = 0.00)
855
+	{
856
+		$this->set('REG_paid', $REG_paid);
857
+	}
858
+
859
+
860
+	/**
861
+	 *        Attendee Is Going
862
+	 *
863
+	 * @param        boolean $REG_att_is_going Attendee Is Going
864
+	 * @throws DomainException
865
+	 * @throws EE_Error
866
+	 * @throws EntityNotFoundException
867
+	 * @throws InvalidArgumentException
868
+	 * @throws InvalidDataTypeException
869
+	 * @throws InvalidInterfaceException
870
+	 * @throws ReflectionException
871
+	 * @throws RuntimeException
872
+	 * @throws UnexpectedEntityException
873
+	 */
874
+	public function set_att_is_going($REG_att_is_going = false)
875
+	{
876
+		$this->set('REG_att_is_going', $REG_att_is_going);
877
+	}
878
+
879
+
880
+	/**
881
+	 * Gets the related attendee
882
+	 *
883
+	 * @return EE_Attendee|EE_Base_Class
884
+	 * @throws EE_Error
885
+	 * @throws InvalidArgumentException
886
+	 * @throws InvalidDataTypeException
887
+	 * @throws InvalidInterfaceException
888
+	 * @throws ReflectionException
889
+	 */
890
+	public function attendee()
891
+	{
892
+		return $this->get_first_related('Attendee');
893
+	}
894
+
895
+	/**
896
+	 * Gets the name of the attendee.
897
+	 * @since 4.10.12.p
898
+	 * @param bool $apply_html_entities set to true if you want to use HTML entities.
899
+	 * @return string
900
+	 * @throws EE_Error
901
+	 * @throws InvalidArgumentException
902
+	 * @throws InvalidDataTypeException
903
+	 * @throws InvalidInterfaceException
904
+	 * @throws ReflectionException
905
+	 */
906
+	public function attendeeName($apply_html_entities = false)
907
+	{
908
+		$attendee = $this->get_first_related('Attendee');
909
+		if ($attendee instanceof EE_Attendee) {
910
+			$attendee_name = $attendee->full_name($apply_html_entities);
911
+		} else {
912
+			$attendee_name = esc_html__('Unknown', 'event_espresso');
913
+		}
914
+		return $attendee_name;
915
+	}
916
+
917
+
918
+	/**
919
+	 *        get Event ID
920
+	 */
921
+	public function event_ID()
922
+	{
923
+		return $this->get('EVT_ID');
924
+	}
925
+
926
+
927
+	/**
928
+	 *        get Event ID
929
+	 */
930
+	public function event_name()
931
+	{
932
+		$event = $this->event_obj();
933
+		if ($event) {
934
+			return $event->name();
935
+		} else {
936
+			return null;
937
+		}
938
+	}
939
+
940
+
941
+	/**
942
+	 * Fetches the event this registration is for
943
+	 *
944
+	 * @return EE_Base_Class|EE_Event
945
+	 * @throws EE_Error
946
+	 * @throws InvalidArgumentException
947
+	 * @throws InvalidDataTypeException
948
+	 * @throws InvalidInterfaceException
949
+	 * @throws ReflectionException
950
+	 */
951
+	public function event_obj()
952
+	{
953
+		return $this->get_first_related('Event');
954
+	}
955
+
956
+
957
+	/**
958
+	 *        get Attendee ID
959
+	 */
960
+	public function attendee_ID()
961
+	{
962
+		return $this->get('ATT_ID');
963
+	}
964
+
965
+
966
+	/**
967
+	 *        get PHP Session ID
968
+	 */
969
+	public function session_ID()
970
+	{
971
+		return $this->get('REG_session');
972
+	}
973
+
974
+
975
+	/**
976
+	 * Gets the string which represents the URL trigger for the receipt template in the message template system.
977
+	 *
978
+	 * @param string $messenger 'pdf' or 'html'.  Default 'html'.
979
+	 * @return string
980
+	 * @throws DomainException
981
+	 * @throws EE_Error
982
+	 * @throws InvalidArgumentException
983
+	 * @throws InvalidDataTypeException
984
+	 * @throws InvalidInterfaceException
985
+	 * @throws ReflectionException
986
+	 */
987
+	public function receipt_url($messenger = 'html')
988
+	{
989
+
990
+		/**
991
+		 * The below will be deprecated one version after this.  We check first if there is a custom receipt template
992
+		 * already in use on old system.  If there is then we just return the standard url for it.
993
+		 *
994
+		 * @since 4.5.0
995
+		 */
996
+		$template_relative_path = 'modules/gateways/Invoice/lib/templates/receipt_body.template.php';
997
+		$has_custom = EEH_Template::locate_template(
998
+			$template_relative_path,
999
+			array(),
1000
+			true,
1001
+			true,
1002
+			true
1003
+		);
1004
+
1005
+		if ($has_custom) {
1006
+			return add_query_arg(array('receipt' => 'true'), $this->invoice_url('launch'));
1007
+		}
1008
+		return apply_filters('FHEE__EE_Registration__receipt_url__receipt_url', '', $this, $messenger, 'receipt');
1009
+	}
1010
+
1011
+
1012
+	/**
1013
+	 * Gets the string which represents the URL trigger for the invoice template in the message template system.
1014
+	 *
1015
+	 * @param string $messenger 'pdf' or 'html'.  Default 'html'.
1016
+	 * @return string
1017
+	 * @throws DomainException
1018
+	 * @throws EE_Error
1019
+	 * @throws InvalidArgumentException
1020
+	 * @throws InvalidDataTypeException
1021
+	 * @throws InvalidInterfaceException
1022
+	 * @throws ReflectionException
1023
+	 */
1024
+	public function invoice_url($messenger = 'html')
1025
+	{
1026
+		/**
1027
+		 * The below will be deprecated one version after this.  We check first if there is a custom invoice template
1028
+		 * already in use on old system.  If there is then we just return the standard url for it.
1029
+		 *
1030
+		 * @since 4.5.0
1031
+		 */
1032
+		$template_relative_path = 'modules/gateways/Invoice/lib/templates/invoice_body.template.php';
1033
+		$has_custom = EEH_Template::locate_template(
1034
+			$template_relative_path,
1035
+			array(),
1036
+			true,
1037
+			true,
1038
+			true
1039
+		);
1040
+
1041
+		if ($has_custom) {
1042
+			if ($messenger == 'html') {
1043
+				return $this->invoice_url('launch');
1044
+			}
1045
+			$route = $messenger == 'download' || $messenger == 'pdf' ? 'download_invoice' : 'launch_invoice';
1046
+
1047
+			$query_args = array('ee' => $route, 'id' => $this->reg_url_link());
1048
+			if ($messenger == 'html') {
1049
+				$query_args['html'] = true;
1050
+			}
1051
+			return add_query_arg($query_args, get_permalink(EE_Registry::instance()->CFG->core->thank_you_page_id));
1052
+		}
1053
+		return apply_filters('FHEE__EE_Registration__invoice_url__invoice_url', '', $this, $messenger, 'invoice');
1054
+	}
1055
+
1056
+
1057
+	/**
1058
+	 * get Registration URL Link
1059
+	 *
1060
+	 * @return string
1061
+	 * @throws EE_Error
1062
+	 * @throws InvalidArgumentException
1063
+	 * @throws InvalidDataTypeException
1064
+	 * @throws InvalidInterfaceException
1065
+	 * @throws ReflectionException
1066
+	 */
1067
+	public function reg_url_link()
1068
+	{
1069
+		return (string) $this->get('REG_url_link');
1070
+	}
1071
+
1072
+
1073
+	/**
1074
+	 * Echoes out invoice_url()
1075
+	 *
1076
+	 * @param string $type 'download','launch', or 'html' (default is 'launch')
1077
+	 * @return void
1078
+	 * @throws DomainException
1079
+	 * @throws EE_Error
1080
+	 * @throws InvalidArgumentException
1081
+	 * @throws InvalidDataTypeException
1082
+	 * @throws InvalidInterfaceException
1083
+	 * @throws ReflectionException
1084
+	 */
1085
+	public function e_invoice_url($type = 'launch')
1086
+	{
1087
+		echo $this->invoice_url($type);
1088
+	}
1089
+
1090
+
1091
+	/**
1092
+	 * Echoes out payment_overview_url
1093
+	 */
1094
+	public function e_payment_overview_url()
1095
+	{
1096
+		echo $this->payment_overview_url();
1097
+	}
1098
+
1099
+
1100
+	/**
1101
+	 * Gets the URL for the checkout payment options reg step
1102
+	 * with this registration's REG_url_link added as a query parameter
1103
+	 *
1104
+	 * @param bool $clear_session Set to true when you want to clear the session on revisiting the
1105
+	 *                            payment overview url.
1106
+	 * @return string
1107
+	 * @throws EE_Error
1108
+	 * @throws InvalidArgumentException
1109
+	 * @throws InvalidDataTypeException
1110
+	 * @throws InvalidInterfaceException
1111
+	 * @throws ReflectionException
1112
+	 */
1113
+	public function payment_overview_url($clear_session = false)
1114
+	{
1115
+		return add_query_arg(
1116
+			(array) apply_filters(
1117
+				'FHEE__EE_Registration__payment_overview_url__query_args',
1118
+				array(
1119
+					'e_reg_url_link' => $this->reg_url_link(),
1120
+					'step'           => 'payment_options',
1121
+					'revisit'        => true,
1122
+					'clear_session'  => (bool) $clear_session,
1123
+				),
1124
+				$this
1125
+			),
1126
+			EE_Registry::instance()->CFG->core->reg_page_url()
1127
+		);
1128
+	}
1129
+
1130
+
1131
+	/**
1132
+	 * Gets the URL for the checkout attendee information reg step
1133
+	 * with this registration's REG_url_link added as a query parameter
1134
+	 *
1135
+	 * @return string
1136
+	 * @throws EE_Error
1137
+	 * @throws InvalidArgumentException
1138
+	 * @throws InvalidDataTypeException
1139
+	 * @throws InvalidInterfaceException
1140
+	 * @throws ReflectionException
1141
+	 */
1142
+	public function edit_attendee_information_url()
1143
+	{
1144
+		return add_query_arg(
1145
+			(array) apply_filters(
1146
+				'FHEE__EE_Registration__edit_attendee_information_url__query_args',
1147
+				array(
1148
+					'e_reg_url_link' => $this->reg_url_link(),
1149
+					'step'           => 'attendee_information',
1150
+					'revisit'        => true,
1151
+				),
1152
+				$this
1153
+			),
1154
+			EE_Registry::instance()->CFG->core->reg_page_url()
1155
+		);
1156
+	}
1157
+
1158
+
1159
+	/**
1160
+	 * Simply generates and returns the appropriate admin_url link to edit this registration
1161
+	 *
1162
+	 * @return string
1163
+	 * @throws EE_Error
1164
+	 * @throws InvalidArgumentException
1165
+	 * @throws InvalidDataTypeException
1166
+	 * @throws InvalidInterfaceException
1167
+	 * @throws ReflectionException
1168
+	 */
1169
+	public function get_admin_edit_url()
1170
+	{
1171
+		return EEH_URL::add_query_args_and_nonce(
1172
+			array(
1173
+				'page'    => 'espresso_registrations',
1174
+				'action'  => 'view_registration',
1175
+				'_REG_ID' => $this->ID(),
1176
+			),
1177
+			admin_url('admin.php')
1178
+		);
1179
+	}
1180
+
1181
+
1182
+	/**
1183
+	 * is_primary_registrant?
1184
+	 *
1185
+	 * @throws EE_Error
1186
+	 * @throws InvalidArgumentException
1187
+	 * @throws InvalidDataTypeException
1188
+	 * @throws InvalidInterfaceException
1189
+	 * @throws ReflectionException
1190
+	 */
1191
+	public function is_primary_registrant()
1192
+	{
1193
+		return (int) $this->get('REG_count') === 1;
1194
+	}
1195
+
1196
+
1197
+	/**
1198
+	 * This returns the primary registration object for this registration group (which may be this object).
1199
+	 *
1200
+	 * @return EE_Registration
1201
+	 * @throws EE_Error
1202
+	 * @throws InvalidArgumentException
1203
+	 * @throws InvalidDataTypeException
1204
+	 * @throws InvalidInterfaceException
1205
+	 * @throws ReflectionException
1206
+	 */
1207
+	public function get_primary_registration()
1208
+	{
1209
+		if ($this->is_primary_registrant()) {
1210
+			return $this;
1211
+		}
1212
+
1213
+		// k reg_count !== 1 so let's get the EE_Registration object matching this txn_id and reg_count == 1
1214
+		/** @var EE_Registration $primary_registrant */
1215
+		$primary_registrant = EEM_Registration::instance()->get_one(
1216
+			array(
1217
+				array(
1218
+					'TXN_ID'    => $this->transaction_ID(),
1219
+					'REG_count' => 1,
1220
+				),
1221
+			)
1222
+		);
1223
+		return $primary_registrant;
1224
+	}
1225
+
1226
+
1227
+	/**
1228
+	 * get  Attendee Number
1229
+	 *
1230
+	 * @throws EE_Error
1231
+	 * @throws InvalidArgumentException
1232
+	 * @throws InvalidDataTypeException
1233
+	 * @throws InvalidInterfaceException
1234
+	 * @throws ReflectionException
1235
+	 */
1236
+	public function count()
1237
+	{
1238
+		return $this->get('REG_count');
1239
+	}
1240
+
1241
+
1242
+	/**
1243
+	 * get Group Size
1244
+	 *
1245
+	 * @throws EE_Error
1246
+	 * @throws InvalidArgumentException
1247
+	 * @throws InvalidDataTypeException
1248
+	 * @throws InvalidInterfaceException
1249
+	 * @throws ReflectionException
1250
+	 */
1251
+	public function group_size()
1252
+	{
1253
+		return $this->get('REG_group_size');
1254
+	}
1255
+
1256
+
1257
+	/**
1258
+	 * get Registration Date
1259
+	 *
1260
+	 * @throws EE_Error
1261
+	 * @throws InvalidArgumentException
1262
+	 * @throws InvalidDataTypeException
1263
+	 * @throws InvalidInterfaceException
1264
+	 * @throws ReflectionException
1265
+	 */
1266
+	public function date()
1267
+	{
1268
+		return $this->get('REG_date');
1269
+	}
1270
+
1271
+
1272
+	/**
1273
+	 * gets a pretty date
1274
+	 *
1275
+	 * @param string $date_format
1276
+	 * @param string $time_format
1277
+	 * @return string
1278
+	 * @throws EE_Error
1279
+	 * @throws InvalidArgumentException
1280
+	 * @throws InvalidDataTypeException
1281
+	 * @throws InvalidInterfaceException
1282
+	 * @throws ReflectionException
1283
+	 */
1284
+	public function pretty_date($date_format = null, $time_format = null)
1285
+	{
1286
+		return $this->get_datetime('REG_date', $date_format, $time_format);
1287
+	}
1288
+
1289
+
1290
+	/**
1291
+	 * final_price
1292
+	 * the registration's share of the transaction total, so that the
1293
+	 * sum of all the transaction's REG_final_prices equal the transaction's total
1294
+	 *
1295
+	 * @return float
1296
+	 * @throws EE_Error
1297
+	 * @throws InvalidArgumentException
1298
+	 * @throws InvalidDataTypeException
1299
+	 * @throws InvalidInterfaceException
1300
+	 * @throws ReflectionException
1301
+	 */
1302
+	public function final_price()
1303
+	{
1304
+		return $this->get('REG_final_price');
1305
+	}
1306
+
1307
+
1308
+	/**
1309
+	 * pretty_final_price
1310
+	 *  final price as formatted string, with correct decimal places and currency symbol
1311
+	 *
1312
+	 * @return string
1313
+	 * @throws EE_Error
1314
+	 * @throws InvalidArgumentException
1315
+	 * @throws InvalidDataTypeException
1316
+	 * @throws InvalidInterfaceException
1317
+	 * @throws ReflectionException
1318
+	 */
1319
+	public function pretty_final_price()
1320
+	{
1321
+		return $this->get_pretty('REG_final_price');
1322
+	}
1323
+
1324
+
1325
+	/**
1326
+	 * get paid (yeah)
1327
+	 *
1328
+	 * @return float
1329
+	 * @throws EE_Error
1330
+	 * @throws InvalidArgumentException
1331
+	 * @throws InvalidDataTypeException
1332
+	 * @throws InvalidInterfaceException
1333
+	 * @throws ReflectionException
1334
+	 */
1335
+	public function paid()
1336
+	{
1337
+		return $this->get('REG_paid');
1338
+	}
1339
+
1340
+
1341
+	/**
1342
+	 * pretty_paid
1343
+	 *
1344
+	 * @return float
1345
+	 * @throws EE_Error
1346
+	 * @throws InvalidArgumentException
1347
+	 * @throws InvalidDataTypeException
1348
+	 * @throws InvalidInterfaceException
1349
+	 * @throws ReflectionException
1350
+	 */
1351
+	public function pretty_paid()
1352
+	{
1353
+		return $this->get_pretty('REG_paid');
1354
+	}
1355
+
1356
+
1357
+	/**
1358
+	 * owes_monies_and_can_pay
1359
+	 * whether or not this registration has monies owing and it's' status allows payment
1360
+	 *
1361
+	 * @param array $requires_payment
1362
+	 * @return bool
1363
+	 * @throws EE_Error
1364
+	 * @throws InvalidArgumentException
1365
+	 * @throws InvalidDataTypeException
1366
+	 * @throws InvalidInterfaceException
1367
+	 * @throws ReflectionException
1368
+	 */
1369
+	public function owes_monies_and_can_pay($requires_payment = array())
1370
+	{
1371
+		// these reg statuses require payment (if event is not free)
1372
+		$requires_payment = ! empty($requires_payment)
1373
+			? $requires_payment
1374
+			: EEM_Registration::reg_statuses_that_allow_payment();
1375
+		if ($this->final_price() !== 0 &&
1376
+			$this->final_price() !== $this->paid() &&
1377
+			in_array($this->status_ID(), $requires_payment, true)
1378
+		) {
1379
+			return true;
1380
+		}
1381
+		return false;
1382
+	}
1383
+
1384
+
1385
+	/**
1386
+	 * Prints out the return value of $this->pretty_status()
1387
+	 *
1388
+	 * @param bool $show_icons
1389
+	 * @return void
1390
+	 * @throws EE_Error
1391
+	 * @throws InvalidArgumentException
1392
+	 * @throws InvalidDataTypeException
1393
+	 * @throws InvalidInterfaceException
1394
+	 * @throws ReflectionException
1395
+	 */
1396
+	public function e_pretty_status($show_icons = false)
1397
+	{
1398
+		echo $this->pretty_status($show_icons);
1399
+	}
1400
+
1401
+
1402
+	/**
1403
+	 * Returns a nice version of the status for displaying to customers
1404
+	 *
1405
+	 * @param bool $show_icons
1406
+	 * @return string
1407
+	 * @throws EE_Error
1408
+	 * @throws InvalidArgumentException
1409
+	 * @throws InvalidDataTypeException
1410
+	 * @throws InvalidInterfaceException
1411
+	 * @throws ReflectionException
1412
+	 */
1413
+	public function pretty_status($show_icons = false)
1414
+	{
1415
+		$status = EEM_Status::instance()->localized_status(
1416
+			array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
1417
+			false,
1418
+			'sentence'
1419
+		);
1420
+		$icon = '';
1421
+		switch ($this->status_ID()) {
1422
+			case EEM_Registration::status_id_approved:
1423
+				$icon = $show_icons
1424
+					? '<span class="dashicons dashicons-star-filled ee-icon-size-16 green-text"></span>'
1425
+					: '';
1426
+				break;
1427
+			case EEM_Registration::status_id_pending_payment:
1428
+				$icon = $show_icons
1429
+					? '<span class="dashicons dashicons-star-half ee-icon-size-16 orange-text"></span>'
1430
+					: '';
1431
+				break;
1432
+			case EEM_Registration::status_id_not_approved:
1433
+				$icon = $show_icons
1434
+					? '<span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>'
1435
+					: '';
1436
+				break;
1437
+			case EEM_Registration::status_id_cancelled:
1438
+				$icon = $show_icons
1439
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
1440
+					: '';
1441
+				break;
1442
+			case EEM_Registration::status_id_incomplete:
1443
+				$icon = $show_icons
1444
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-orange-text"></span>'
1445
+					: '';
1446
+				break;
1447
+			case EEM_Registration::status_id_declined:
1448
+				$icon = $show_icons
1449
+					? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
1450
+					: '';
1451
+				break;
1452
+			case EEM_Registration::status_id_wait_list:
1453
+				$icon = $show_icons
1454
+					? '<span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>'
1455
+					: '';
1456
+				break;
1457
+		}
1458
+		return $icon . $status[ $this->status_ID() ];
1459
+	}
1460
+
1461
+
1462
+	/**
1463
+	 *        get Attendee Is Going
1464
+	 */
1465
+	public function att_is_going()
1466
+	{
1467
+		return $this->get('REG_att_is_going');
1468
+	}
1469
+
1470
+
1471
+	/**
1472
+	 * Gets related answers
1473
+	 *
1474
+	 * @param array $query_params @see
1475
+	 *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1476
+	 * @return EE_Answer[]|EE_Base_Class[]
1477
+	 * @throws EE_Error
1478
+	 * @throws InvalidArgumentException
1479
+	 * @throws InvalidDataTypeException
1480
+	 * @throws InvalidInterfaceException
1481
+	 * @throws ReflectionException
1482
+	 */
1483
+	public function answers($query_params = null)
1484
+	{
1485
+		return $this->get_many_related('Answer', $query_params);
1486
+	}
1487
+
1488
+
1489
+	/**
1490
+	 * Gets the registration's answer value to the specified question
1491
+	 * (either the question's ID or a question object)
1492
+	 *
1493
+	 * @param EE_Question|int $question
1494
+	 * @param bool            $pretty_value
1495
+	 * @return array|string if pretty_value= true, the result will always be a string
1496
+	 * (because the answer might be an array of answer values, so passing pretty_value=true
1497
+	 * will convert it into some kind of string)
1498
+	 * @throws EE_Error
1499
+	 * @throws InvalidArgumentException
1500
+	 * @throws InvalidDataTypeException
1501
+	 * @throws InvalidInterfaceException
1502
+	 */
1503
+	public function answer_value_to_question($question, $pretty_value = true)
1504
+	{
1505
+		$question_id = EEM_Question::instance()->ensure_is_ID($question);
1506
+		return EEM_Answer::instance()->get_answer_value_to_question($this, $question_id, $pretty_value);
1507
+	}
1508
+
1509
+
1510
+	/**
1511
+	 * question_groups
1512
+	 * returns an array of EE_Question_Group objects for this registration
1513
+	 *
1514
+	 * @return EE_Question_Group[]
1515
+	 * @throws EE_Error
1516
+	 * @throws InvalidArgumentException
1517
+	 * @throws InvalidDataTypeException
1518
+	 * @throws InvalidInterfaceException
1519
+	 * @throws ReflectionException
1520
+	 */
1521
+	public function question_groups()
1522
+	{
1523
+		return EEM_Event::instance()->get_question_groups_for_event($this->event_ID(), $this);
1524
+	}
1525
+
1526
+
1527
+	/**
1528
+	 * count_question_groups
1529
+	 * returns a count of the number of EE_Question_Group objects for this registration
1530
+	 *
1531
+	 * @return int
1532
+	 * @throws EE_Error
1533
+	 * @throws EntityNotFoundException
1534
+	 * @throws InvalidArgumentException
1535
+	 * @throws InvalidDataTypeException
1536
+	 * @throws InvalidInterfaceException
1537
+	 * @throws ReflectionException
1538
+	 */
1539
+	public function count_question_groups()
1540
+	{
1541
+		return EEM_Event::instance()->count_related(
1542
+			$this->event_ID(),
1543
+			'Question_Group',
1544
+			[
1545
+				[
1546
+					'Event_Question_Group.'
1547
+					. EEM_Event_Question_Group::instance()->fieldNameForContext($this->is_primary_registrant()) => true,
1548
+				]
1549
+			]
1550
+		);
1551
+	}
1552
+
1553
+
1554
+	/**
1555
+	 * Returns the registration date in the 'standard' string format
1556
+	 * (function may be improved in the future to allow for different formats and timezones)
1557
+	 *
1558
+	 * @return string
1559
+	 * @throws EE_Error
1560
+	 * @throws InvalidArgumentException
1561
+	 * @throws InvalidDataTypeException
1562
+	 * @throws InvalidInterfaceException
1563
+	 * @throws ReflectionException
1564
+	 */
1565
+	public function reg_date()
1566
+	{
1567
+		return $this->get_datetime('REG_date');
1568
+	}
1569
+
1570
+
1571
+	/**
1572
+	 * Gets the datetime-ticket for this registration (ie, it can be used to isolate
1573
+	 * the ticket this registration purchased, or the datetime they have registered
1574
+	 * to attend)
1575
+	 *
1576
+	 * @return EE_Base_Class|EE_Datetime_Ticket
1577
+	 * @throws EE_Error
1578
+	 * @throws InvalidArgumentException
1579
+	 * @throws InvalidDataTypeException
1580
+	 * @throws InvalidInterfaceException
1581
+	 * @throws ReflectionException
1582
+	 */
1583
+	public function datetime_ticket()
1584
+	{
1585
+		return $this->get_first_related('Datetime_Ticket');
1586
+	}
1587
+
1588
+
1589
+	/**
1590
+	 * Sets the registration's datetime_ticket.
1591
+	 *
1592
+	 * @param EE_Datetime_Ticket $datetime_ticket
1593
+	 * @return EE_Base_Class|EE_Datetime_Ticket
1594
+	 * @throws EE_Error
1595
+	 * @throws InvalidArgumentException
1596
+	 * @throws InvalidDataTypeException
1597
+	 * @throws InvalidInterfaceException
1598
+	 * @throws ReflectionException
1599
+	 */
1600
+	public function set_datetime_ticket($datetime_ticket)
1601
+	{
1602
+		return $this->_add_relation_to($datetime_ticket, 'Datetime_Ticket');
1603
+	}
1604
+
1605
+
1606
+	/**
1607
+	 * Gets deleted
1608
+	 *
1609
+	 * @return bool
1610
+	 * @throws EE_Error
1611
+	 * @throws InvalidArgumentException
1612
+	 * @throws InvalidDataTypeException
1613
+	 * @throws InvalidInterfaceException
1614
+	 * @throws ReflectionException
1615
+	 */
1616
+	public function deleted()
1617
+	{
1618
+		return $this->get('REG_deleted');
1619
+	}
1620
+
1621
+
1622
+	/**
1623
+	 * Sets deleted
1624
+	 *
1625
+	 * @param boolean $deleted
1626
+	 * @return void
1627
+	 * @throws DomainException
1628
+	 * @throws EE_Error
1629
+	 * @throws EntityNotFoundException
1630
+	 * @throws InvalidArgumentException
1631
+	 * @throws InvalidDataTypeException
1632
+	 * @throws InvalidInterfaceException
1633
+	 * @throws ReflectionException
1634
+	 * @throws RuntimeException
1635
+	 * @throws UnexpectedEntityException
1636
+	 */
1637
+	public function set_deleted($deleted)
1638
+	{
1639
+		if ($deleted) {
1640
+			$this->delete(__METHOD__);
1641
+		} else {
1642
+			$this->restore(__METHOD__);
1643
+		}
1644
+	}
1645
+
1646
+
1647
+	/**
1648
+	 * Get the status object of this object
1649
+	 *
1650
+	 * @return EE_Base_Class|EE_Status
1651
+	 * @throws EE_Error
1652
+	 * @throws InvalidArgumentException
1653
+	 * @throws InvalidDataTypeException
1654
+	 * @throws InvalidInterfaceException
1655
+	 * @throws ReflectionException
1656
+	 */
1657
+	public function status_obj()
1658
+	{
1659
+		return $this->get_first_related('Status');
1660
+	}
1661
+
1662
+
1663
+	/**
1664
+	 * Returns the number of times this registration has checked into any of the datetimes
1665
+	 * its available for
1666
+	 *
1667
+	 * @return int
1668
+	 * @throws EE_Error
1669
+	 * @throws InvalidArgumentException
1670
+	 * @throws InvalidDataTypeException
1671
+	 * @throws InvalidInterfaceException
1672
+	 * @throws ReflectionException
1673
+	 */
1674
+	public function count_checkins()
1675
+	{
1676
+		return $this->get_model()->count_related($this, 'Checkin');
1677
+	}
1678
+
1679
+
1680
+	/**
1681
+	 * Returns the number of current Check-ins this registration is checked into for any of the datetimes the
1682
+	 * registration is for.  Note, this is ONLY checked in (does not include checkedout)
1683
+	 *
1684
+	 * @return int
1685
+	 * @throws EE_Error
1686
+	 * @throws InvalidArgumentException
1687
+	 * @throws InvalidDataTypeException
1688
+	 * @throws InvalidInterfaceException
1689
+	 * @throws ReflectionException
1690
+	 */
1691
+	public function count_checkins_not_checkedout()
1692
+	{
1693
+		return $this->get_model()->count_related($this, 'Checkin', array(array('CHK_in' => 1)));
1694
+	}
1695
+
1696
+
1697
+	/**
1698
+	 * The purpose of this method is simply to check whether this registration can checkin to the given datetime.
1699
+	 *
1700
+	 * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1701
+	 * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1702
+	 *                                          consider registration status as well as datetime access.
1703
+	 * @return bool
1704
+	 * @throws EE_Error
1705
+	 * @throws InvalidArgumentException
1706
+	 * @throws InvalidDataTypeException
1707
+	 * @throws InvalidInterfaceException
1708
+	 * @throws ReflectionException
1709
+	 */
1710
+	public function can_checkin($DTT_OR_ID, $check_approved = true)
1711
+	{
1712
+		$DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1713
+		// first check registration status
1714
+		if (! $DTT_ID || ($check_approved && ! $this->is_approved())) {
1715
+			return false;
1716
+		}
1717
+		// is there a datetime ticket that matches this dtt_ID?
1718
+		if (! EEM_Datetime_Ticket::instance()->exists(
1719
+			array(
1720
+				array(
1721
+					'TKT_ID' => $this->get('TKT_ID'),
1722
+					'DTT_ID' => $DTT_ID,
1723
+				),
1724
+			)
1725
+		)) {
1726
+			return false;
1727
+		}
1728
+
1729
+		// final check is against TKT_uses
1730
+		return $this->verify_can_checkin_against_TKT_uses($DTT_ID);
1731
+	}
1732
+
1733
+
1734
+	/**
1735
+	 * This method verifies whether the user can checkin for the given datetime considering the max uses value set on
1736
+	 * the ticket. To do this,  a query is done to get the count of the datetime records already checked into.  If the
1737
+	 * datetime given does not have a check-in record and checking in for that datetime will exceed the allowed uses,
1738
+	 * then return false.  Otherwise return true.
1739
+	 *
1740
+	 * @param int | EE_Datetime $DTT_OR_ID The datetime the registration is being checked against
1741
+	 * @return bool true means can checkin.  false means cannot checkin.
1742
+	 * @throws EE_Error
1743
+	 * @throws InvalidArgumentException
1744
+	 * @throws InvalidDataTypeException
1745
+	 * @throws InvalidInterfaceException
1746
+	 * @throws ReflectionException
1747
+	 */
1748
+	public function verify_can_checkin_against_TKT_uses($DTT_OR_ID)
1749
+	{
1750
+		$DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1751
+
1752
+		if (! $DTT_ID) {
1753
+			return false;
1754
+		}
1755
+
1756
+		$max_uses = $this->ticket() instanceof EE_Ticket ? $this->ticket()->uses() : EE_INF;
1757
+
1758
+		// if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1759
+		// check-in or not.
1760
+		if (! $max_uses || $max_uses === EE_INF) {
1761
+			return true;
1762
+		}
1763
+
1764
+		// does this datetime have a checkin record?  If so, then the dtt count has already been verified so we can just
1765
+		// go ahead and toggle.
1766
+		if (EEM_Checkin::instance()->exists(array(array('REG_ID' => $this->ID(), 'DTT_ID' => $DTT_ID)))) {
1767
+			return true;
1768
+		}
1769
+
1770
+		// made it here so the last check is whether the number of checkins per unique datetime on this registration
1771
+		// disallows further check-ins.
1772
+		$count_unique_dtt_checkins = EEM_Checkin::instance()->count(
1773
+			array(
1774
+				array(
1775
+					'REG_ID' => $this->ID(),
1776
+					'CHK_in' => true,
1777
+				),
1778
+			),
1779
+			'DTT_ID',
1780
+			true
1781
+		);
1782
+		// checkins have already reached their max number of uses
1783
+		// so registrant can NOT checkin
1784
+		if ($count_unique_dtt_checkins >= $max_uses) {
1785
+			EE_Error::add_error(
1786
+				esc_html__(
1787
+					'Check-in denied because number of datetime uses for the ticket has been reached or exceeded.',
1788
+					'event_espresso'
1789
+				),
1790
+				__FILE__,
1791
+				__FUNCTION__,
1792
+				__LINE__
1793
+			);
1794
+			return false;
1795
+		}
1796
+		return true;
1797
+	}
1798
+
1799
+
1800
+	/**
1801
+	 * toggle Check-in status for this registration
1802
+	 * Check-ins are toggled in the following order:
1803
+	 * never checked in -> checked in
1804
+	 * checked in -> checked out
1805
+	 * checked out -> checked in
1806
+	 *
1807
+	 * @param  int $DTT_ID  include specific datetime to toggle Check-in for.
1808
+	 *                      If not included or null, then it is assumed latest datetime is being toggled.
1809
+	 * @param bool $verify  If true then can_checkin() is used to verify whether the person
1810
+	 *                      can be checked in or not.  Otherwise this forces change in checkin status.
1811
+	 * @return bool|int     the chk_in status toggled to OR false if nothing got changed.
1812
+	 * @throws EE_Error
1813
+	 * @throws InvalidArgumentException
1814
+	 * @throws InvalidDataTypeException
1815
+	 * @throws InvalidInterfaceException
1816
+	 * @throws ReflectionException
1817
+	 */
1818
+	public function toggle_checkin_status($DTT_ID = null, $verify = false)
1819
+	{
1820
+		if (empty($DTT_ID)) {
1821
+			$datetime = $this->get_latest_related_datetime();
1822
+			$DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1823
+			// verify the registration can checkin for the given DTT_ID
1824
+		} elseif (! $this->can_checkin($DTT_ID, $verify)) {
1825
+			EE_Error::add_error(
1826
+				sprintf(
1827
+					esc_html__(
1828
+						'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',
1829
+						'event_espresso'
1830
+					),
1831
+					$this->ID(),
1832
+					$DTT_ID
1833
+				),
1834
+				__FILE__,
1835
+				__FUNCTION__,
1836
+				__LINE__
1837
+			);
1838
+			return false;
1839
+		}
1840
+		$status_paths = array(
1841
+			EE_Checkin::status_checked_never => EE_Checkin::status_checked_in,
1842
+			EE_Checkin::status_checked_in    => EE_Checkin::status_checked_out,
1843
+			EE_Checkin::status_checked_out   => EE_Checkin::status_checked_in,
1844
+		);
1845
+		// start by getting the current status so we know what status we'll be changing to.
1846
+		$cur_status = $this->check_in_status_for_datetime($DTT_ID);
1847
+		$status_to = $status_paths[ $cur_status ];
1848
+		// database only records true for checked IN or false for checked OUT
1849
+		// no record ( null ) means checked in NEVER, but we obviously don't save that
1850
+		$new_status = $status_to === EE_Checkin::status_checked_in;
1851
+		// add relation - note Check-ins are always creating new rows
1852
+		// because we are keeping track of Check-ins over time.
1853
+		// Eventually we'll probably want to show a list table
1854
+		// for the individual Check-ins so that they can be managed.
1855
+		$checkin = EE_Checkin::new_instance(
1856
+			array(
1857
+				'REG_ID' => $this->ID(),
1858
+				'DTT_ID' => $DTT_ID,
1859
+				'CHK_in' => $new_status,
1860
+			)
1861
+		);
1862
+		// if the record could not be saved then return false
1863
+		if ($checkin->save() === 0) {
1864
+			if (WP_DEBUG) {
1865
+				global $wpdb;
1866
+				$error = sprintf(
1867
+					esc_html__(
1868
+						'Registration check in update failed because of the following database error: %1$s%2$s',
1869
+						'event_espresso'
1870
+					),
1871
+					'<br />',
1872
+					$wpdb->last_error
1873
+				);
1874
+			} else {
1875
+				$error = esc_html__(
1876
+					'Registration check in update failed because of an unknown database error',
1877
+					'event_espresso'
1878
+				);
1879
+			}
1880
+			EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
1881
+			return false;
1882
+		}
1883
+		// Fire a checked_in and checkout_out action.
1884
+		$checked_status = $status_to === EE_Checkin::status_checked_in ? 'checked_in' : 'checked_out';
1885
+		do_action("AHEE__EE_Registration__toggle_checkin_status__{$checked_status}", $this, $DTT_ID);
1886
+		return $status_to;
1887
+	}
1888
+
1889
+
1890
+	/**
1891
+	 * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1892
+	 * "Latest" is defined by the `DTT_EVT_start` column.
1893
+	 *
1894
+	 * @return EE_Datetime|null
1895
+	 * @throws EE_Error
1896
+	 * @throws InvalidArgumentException
1897
+	 * @throws InvalidDataTypeException
1898
+	 * @throws InvalidInterfaceException
1899
+	 * @throws ReflectionException
1900
+	 */
1901
+	public function get_latest_related_datetime()
1902
+	{
1903
+		return EEM_Datetime::instance()->get_one(
1904
+			array(
1905
+				array(
1906
+					'Ticket.Registration.REG_ID' => $this->ID(),
1907
+				),
1908
+				'order_by' => array('DTT_EVT_start' => 'DESC'),
1909
+			)
1910
+		);
1911
+	}
1912
+
1913
+
1914
+	/**
1915
+	 * Returns the earliest datetime related to this registration (via the ticket attached to the registration).
1916
+	 * "Earliest" is defined by the `DTT_EVT_start` column.
1917
+	 *
1918
+	 * @return EE_Base_Class|EE_Soft_Delete_Base_Class|NULL
1919
+	 * @throws EE_Error
1920
+	 * @throws InvalidArgumentException
1921
+	 * @throws InvalidDataTypeException
1922
+	 * @throws InvalidInterfaceException
1923
+	 * @throws ReflectionException
1924
+	 */
1925
+	public function get_earliest_related_datetime()
1926
+	{
1927
+		return EEM_Datetime::instance()->get_one(
1928
+			array(
1929
+				array(
1930
+					'Ticket.Registration.REG_ID' => $this->ID(),
1931
+				),
1932
+				'order_by' => array('DTT_EVT_start' => 'ASC'),
1933
+			)
1934
+		);
1935
+	}
1936
+
1937
+
1938
+	/**
1939
+	 * This method simply returns the check-in status for this registration and the given datetime.
1940
+	 * If neither the datetime nor the checkin values are provided as arguments,
1941
+	 * then this will return the LATEST check-in status for the registration across all datetimes it belongs to.
1942
+	 *
1943
+	 * @param  int       $DTT_ID  The ID of the datetime we're checking against
1944
+	 *                            (if empty we'll get the primary datetime for
1945
+	 *                            this registration (via event) and use it's ID);
1946
+	 * @param EE_Checkin $checkin If present, we use the given checkin object rather than the dtt_id.
1947
+	 * @return int                Integer representing Check-in status.
1948
+	 * @throws EE_Error
1949
+	 * @throws InvalidArgumentException
1950
+	 * @throws InvalidDataTypeException
1951
+	 * @throws InvalidInterfaceException
1952
+	 * @throws ReflectionException
1953
+	 */
1954
+	public function check_in_status_for_datetime($DTT_ID = 0, $checkin = null)
1955
+	{
1956
+		$checkin_query_params = array(
1957
+			'order_by' => array('CHK_timestamp' => 'DESC'),
1958
+		);
1959
+
1960
+		if ($DTT_ID > 0) {
1961
+			$checkin_query_params[0] = array('DTT_ID' => $DTT_ID);
1962
+		}
1963
+
1964
+		// get checkin object (if exists)
1965
+		$checkin = $checkin instanceof EE_Checkin
1966
+			? $checkin
1967
+			: $this->get_first_related('Checkin', $checkin_query_params);
1968
+		if ($checkin instanceof EE_Checkin) {
1969
+			if ($checkin->get('CHK_in')) {
1970
+				return EE_Checkin::status_checked_in; // checked in
1971
+			}
1972
+			return EE_Checkin::status_checked_out; // had checked in but is now checked out.
1973
+		}
1974
+		return EE_Checkin::status_checked_never; // never been checked in
1975
+	}
1976
+
1977
+
1978
+	/**
1979
+	 * This method returns a localized message for the toggled Check-in message.
1980
+	 *
1981
+	 * @param  int $DTT_ID include specific datetime to get the correct Check-in message.  If not included or null,
1982
+	 *                     then it is assumed Check-in for primary datetime was toggled.
1983
+	 * @param bool $error  This just flags that you want an error message returned. This is put in so that the error
1984
+	 *                     message can be customized with the attendee name.
1985
+	 * @return string internationalized message
1986
+	 * @throws EE_Error
1987
+	 * @throws InvalidArgumentException
1988
+	 * @throws InvalidDataTypeException
1989
+	 * @throws InvalidInterfaceException
1990
+	 * @throws ReflectionException
1991
+	 */
1992
+	public function get_checkin_msg($DTT_ID, $error = false)
1993
+	{
1994
+		// let's get the attendee first so we can include the name of the attendee
1995
+		$attendee = $this->get_first_related('Attendee');
1996
+		if ($attendee instanceof EE_Attendee) {
1997
+			if ($error) {
1998
+				return sprintf(__("%s's check-in status was not changed.", 'event_espresso'), $attendee->full_name());
1999
+			}
2000
+			$cur_status = $this->check_in_status_for_datetime($DTT_ID);
2001
+			// what is the status message going to be?
2002
+			switch ($cur_status) {
2003
+				case EE_Checkin::status_checked_never:
2004
+					return sprintf(
2005
+						esc_html__('%s has been removed from Check-in records', 'event_espresso'),
2006
+						$attendee->full_name()
2007
+					);
2008
+					break;
2009
+				case EE_Checkin::status_checked_in:
2010
+					return sprintf(__('%s has been checked in', 'event_espresso'), $attendee->full_name());
2011
+					break;
2012
+				case EE_Checkin::status_checked_out:
2013
+					return sprintf(__('%s has been checked out', 'event_espresso'), $attendee->full_name());
2014
+					break;
2015
+			}
2016
+		}
2017
+		return esc_html__('The check-in status could not be determined.', 'event_espresso');
2018
+	}
2019
+
2020
+
2021
+	/**
2022
+	 * Returns the related EE_Transaction to this registration
2023
+	 *
2024
+	 * @return EE_Transaction
2025
+	 * @throws EE_Error
2026
+	 * @throws EntityNotFoundException
2027
+	 * @throws InvalidArgumentException
2028
+	 * @throws InvalidDataTypeException
2029
+	 * @throws InvalidInterfaceException
2030
+	 * @throws ReflectionException
2031
+	 */
2032
+	public function transaction()
2033
+	{
2034
+		$transaction = $this->get_first_related('Transaction');
2035
+		if (! $transaction instanceof \EE_Transaction) {
2036
+			throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
2037
+		}
2038
+		return $transaction;
2039
+	}
2040
+
2041
+
2042
+	/**
2043
+	 * get Registration Code
2044
+	 *
2045
+	 * @return mixed
2046
+	 * @throws EE_Error
2047
+	 * @throws InvalidArgumentException
2048
+	 * @throws InvalidDataTypeException
2049
+	 * @throws InvalidInterfaceException
2050
+	 * @throws ReflectionException
2051
+	 */
2052
+	public function reg_code()
2053
+	{
2054
+		return $this->get('REG_code');
2055
+	}
2056
+
2057
+
2058
+	/**
2059
+	 * @return mixed
2060
+	 * @throws EE_Error
2061
+	 * @throws InvalidArgumentException
2062
+	 * @throws InvalidDataTypeException
2063
+	 * @throws InvalidInterfaceException
2064
+	 * @throws ReflectionException
2065
+	 */
2066
+	public function transaction_ID()
2067
+	{
2068
+		return $this->get('TXN_ID');
2069
+	}
2070
+
2071
+
2072
+	/**
2073
+	 * @return int
2074
+	 * @throws EE_Error
2075
+	 * @throws InvalidArgumentException
2076
+	 * @throws InvalidDataTypeException
2077
+	 * @throws InvalidInterfaceException
2078
+	 * @throws ReflectionException
2079
+	 */
2080
+	public function ticket_ID()
2081
+	{
2082
+		return $this->get('TKT_ID');
2083
+	}
2084
+
2085
+
2086
+	/**
2087
+	 * Set Registration Code
2088
+	 *
2089
+	 * @param    string  $REG_code Registration Code
2090
+	 * @param    boolean $use_default
2091
+	 * @throws EE_Error
2092
+	 * @throws InvalidArgumentException
2093
+	 * @throws InvalidDataTypeException
2094
+	 * @throws InvalidInterfaceException
2095
+	 * @throws ReflectionException
2096
+	 */
2097
+	public function set_reg_code($REG_code, $use_default = false)
2098
+	{
2099
+		if (empty($REG_code)) {
2100
+			EE_Error::add_error(
2101
+				esc_html__('REG_code can not be empty.', 'event_espresso'),
2102
+				__FILE__,
2103
+				__FUNCTION__,
2104
+				__LINE__
2105
+			);
2106
+			return;
2107
+		}
2108
+		if (! $this->reg_code()) {
2109
+			parent::set('REG_code', $REG_code, $use_default);
2110
+		} else {
2111
+			EE_Error::doing_it_wrong(
2112
+				__CLASS__ . '::' . __FUNCTION__,
2113
+				esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
2114
+				'4.6.0'
2115
+			);
2116
+		}
2117
+	}
2118
+
2119
+
2120
+	/**
2121
+	 * Returns all other registrations in the same group as this registrant who have the same ticket option.
2122
+	 * Note, if you want to just get all registrations in the same transaction (group), use:
2123
+	 *    $registration->transaction()->registrations();
2124
+	 *
2125
+	 * @since 4.5.0
2126
+	 * @return EE_Registration[] or empty array if this isn't a group registration.
2127
+	 * @throws EE_Error
2128
+	 * @throws InvalidArgumentException
2129
+	 * @throws InvalidDataTypeException
2130
+	 * @throws InvalidInterfaceException
2131
+	 * @throws ReflectionException
2132
+	 */
2133
+	public function get_all_other_registrations_in_group()
2134
+	{
2135
+		if ($this->group_size() < 2) {
2136
+			return array();
2137
+		}
2138
+
2139
+		$query[0] = array(
2140
+			'TXN_ID' => $this->transaction_ID(),
2141
+			'REG_ID' => array('!=', $this->ID()),
2142
+			'TKT_ID' => $this->ticket_ID(),
2143
+		);
2144
+		/** @var EE_Registration[] $registrations */
2145
+		$registrations = $this->get_model()->get_all($query);
2146
+		return $registrations;
2147
+	}
2148
+
2149
+
2150
+	/**
2151
+	 * Return the link to the admin details for the object.
2152
+	 *
2153
+	 * @return string
2154
+	 * @throws EE_Error
2155
+	 * @throws InvalidArgumentException
2156
+	 * @throws InvalidDataTypeException
2157
+	 * @throws InvalidInterfaceException
2158
+	 * @throws ReflectionException
2159
+	 */
2160
+	public function get_admin_details_link()
2161
+	{
2162
+		EE_Registry::instance()->load_helper('URL');
2163
+		return EEH_URL::add_query_args_and_nonce(
2164
+			array(
2165
+				'page'    => 'espresso_registrations',
2166
+				'action'  => 'view_registration',
2167
+				'_REG_ID' => $this->ID(),
2168
+			),
2169
+			admin_url('admin.php')
2170
+		);
2171
+	}
2172
+
2173
+
2174
+	/**
2175
+	 * Returns the link to the editor for the object.  Sometimes this is the same as the details.
2176
+	 *
2177
+	 * @return string
2178
+	 * @throws EE_Error
2179
+	 * @throws InvalidArgumentException
2180
+	 * @throws InvalidDataTypeException
2181
+	 * @throws InvalidInterfaceException
2182
+	 * @throws ReflectionException
2183
+	 */
2184
+	public function get_admin_edit_link()
2185
+	{
2186
+		return $this->get_admin_details_link();
2187
+	}
2188
+
2189
+
2190
+	/**
2191
+	 * Returns the link to a settings page for the object.
2192
+	 *
2193
+	 * @return string
2194
+	 * @throws EE_Error
2195
+	 * @throws InvalidArgumentException
2196
+	 * @throws InvalidDataTypeException
2197
+	 * @throws InvalidInterfaceException
2198
+	 * @throws ReflectionException
2199
+	 */
2200
+	public function get_admin_settings_link()
2201
+	{
2202
+		return $this->get_admin_details_link();
2203
+	}
2204
+
2205
+
2206
+	/**
2207
+	 * Returns the link to the "overview" for the object (typically the "list table" view).
2208
+	 *
2209
+	 * @return string
2210
+	 * @throws EE_Error
2211
+	 * @throws InvalidArgumentException
2212
+	 * @throws InvalidDataTypeException
2213
+	 * @throws InvalidInterfaceException
2214
+	 * @throws ReflectionException
2215
+	 */
2216
+	public function get_admin_overview_link()
2217
+	{
2218
+		EE_Registry::instance()->load_helper('URL');
2219
+		return EEH_URL::add_query_args_and_nonce(
2220
+			array(
2221
+				'page' => 'espresso_registrations',
2222
+			),
2223
+			admin_url('admin.php')
2224
+		);
2225
+	}
2226
+
2227
+
2228
+	/**
2229
+	 * @param array $query_params
2230
+	 * @return EE_Base_Class[]|EE_Registration[]
2231
+	 * @throws EE_Error
2232
+	 * @throws InvalidArgumentException
2233
+	 * @throws InvalidDataTypeException
2234
+	 * @throws InvalidInterfaceException
2235
+	 * @throws ReflectionException
2236
+	 */
2237
+	public function payments($query_params = array())
2238
+	{
2239
+		return $this->get_many_related('Payment', $query_params);
2240
+	}
2241
+
2242
+
2243
+	/**
2244
+	 * @param array $query_params
2245
+	 * @return EE_Base_Class[]|EE_Registration_Payment[]
2246
+	 * @throws EE_Error
2247
+	 * @throws InvalidArgumentException
2248
+	 * @throws InvalidDataTypeException
2249
+	 * @throws InvalidInterfaceException
2250
+	 * @throws ReflectionException
2251
+	 */
2252
+	public function registration_payments($query_params = array())
2253
+	{
2254
+		return $this->get_many_related('Registration_Payment', $query_params);
2255
+	}
2256
+
2257
+
2258
+	/**
2259
+	 * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
2260
+	 * Note: if there are no payments on the registration there will be no payment method returned.
2261
+	 *
2262
+	 * @return EE_Payment|EE_Payment_Method|null
2263
+	 * @throws EE_Error
2264
+	 * @throws InvalidArgumentException
2265
+	 * @throws InvalidDataTypeException
2266
+	 * @throws InvalidInterfaceException
2267
+	 */
2268
+	public function payment_method()
2269
+	{
2270
+		return EEM_Payment_Method::instance()->get_last_used_for_registration($this);
2271
+	}
2272
+
2273
+
2274
+	/**
2275
+	 * @return \EE_Line_Item
2276
+	 * @throws EE_Error
2277
+	 * @throws EntityNotFoundException
2278
+	 * @throws InvalidArgumentException
2279
+	 * @throws InvalidDataTypeException
2280
+	 * @throws InvalidInterfaceException
2281
+	 * @throws ReflectionException
2282
+	 */
2283
+	public function ticket_line_item()
2284
+	{
2285
+		$ticket = $this->ticket();
2286
+		$transaction = $this->transaction();
2287
+		$line_item = null;
2288
+		$ticket_line_items = \EEH_Line_Item::get_line_items_by_object_type_and_IDs(
2289
+			$transaction->total_line_item(),
2290
+			'Ticket',
2291
+			array($ticket->ID())
2292
+		);
2293
+		foreach ($ticket_line_items as $ticket_line_item) {
2294
+			if ($ticket_line_item instanceof \EE_Line_Item
2295
+				&& $ticket_line_item->OBJ_type() === 'Ticket'
2296
+				&& $ticket_line_item->OBJ_ID() === $ticket->ID()
2297
+			) {
2298
+				$line_item = $ticket_line_item;
2299
+				break;
2300
+			}
2301
+		}
2302
+		if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
2303
+			throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
2304
+		}
2305
+		return $line_item;
2306
+	}
2307
+
2308
+
2309
+	/**
2310
+	 * Soft Deletes this model object.
2311
+	 *
2312
+	 * @param string $source function name that called this method
2313
+	 * @return boolean | int
2314
+	 * @throws DomainException
2315
+	 * @throws EE_Error
2316
+	 * @throws EntityNotFoundException
2317
+	 * @throws InvalidArgumentException
2318
+	 * @throws InvalidDataTypeException
2319
+	 * @throws InvalidInterfaceException
2320
+	 * @throws ReflectionException
2321
+	 * @throws RuntimeException
2322
+	 * @throws UnexpectedEntityException
2323
+	 */
2324
+	public function delete($source = 'unknown')
2325
+	{
2326
+		if ($this->update_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY, $this->status_ID()) === true) {
2327
+			$current_user = wp_get_current_user();
2328
+			$this->add_extra_meta(
2329
+				EE_Registration::EXTRA_META_KEY_REG_TRASHED,
2330
+				array(
2331
+					'trashed-by' => $current_user->ID ? $current_user->display_name : 'unauthed user',
2332
+					'timestamp'  => time(),
2333
+					'source'     => $source,
2334
+				)
2335
+			);
2336
+			$this->set_status(EEM_Registration::status_id_cancelled);
2337
+		}
2338
+		return parent::delete();
2339
+	}
2340
+
2341
+
2342
+	/**
2343
+	 * Restores whatever the previous status was on a registration before it was trashed (if possible)
2344
+	 *
2345
+	 * @param string $source function name that called this method
2346
+	 * @return bool|int
2347
+	 * @throws DomainException
2348
+	 * @throws EE_Error
2349
+	 * @throws EntityNotFoundException
2350
+	 * @throws InvalidArgumentException
2351
+	 * @throws InvalidDataTypeException
2352
+	 * @throws InvalidInterfaceException
2353
+	 * @throws ReflectionException
2354
+	 * @throws RuntimeException
2355
+	 * @throws UnexpectedEntityException
2356
+	 */
2357
+	public function restore($source = 'unknown')
2358
+	{
2359
+		$previous_status = $this->get_extra_meta(
2360
+			EE_Registration::PRE_TRASH_REG_STATUS_KEY,
2361
+			true,
2362
+			EEM_Registration::status_id_cancelled
2363
+		);
2364
+		if ($previous_status) {
2365
+			$this->delete_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY);
2366
+			$this->set_status($previous_status);
2367
+		}
2368
+		$current_user = wp_get_current_user();
2369
+		$this->add_extra_meta(
2370
+			EE_Registration::EXTRA_META_KEY_REG_RESTORED,
2371
+			array(
2372
+				'restored-by' => $current_user->ID ? $current_user->display_name : 'unauthed user',
2373
+				'timestamp'   => time(),
2374
+				'source'      => $source,
2375
+			)
2376
+		);
2377
+		return parent::restore();
2378
+	}
2379
+
2380
+
2381
+	/**
2382
+	 * possibly toggle Registration status based on comparison of REG_paid vs REG_final_price
2383
+	 *
2384
+	 * @param  boolean $trigger_set_status_logic EE_Registration::set_status() can trigger additional logic
2385
+	 *                                           depending on whether the reg status changes to or from "Approved"
2386
+	 * @return boolean whether the Registration status was updated
2387
+	 * @throws DomainException
2388
+	 * @throws EE_Error
2389
+	 * @throws EntityNotFoundException
2390
+	 * @throws InvalidArgumentException
2391
+	 * @throws InvalidDataTypeException
2392
+	 * @throws InvalidInterfaceException
2393
+	 * @throws ReflectionException
2394
+	 * @throws RuntimeException
2395
+	 * @throws UnexpectedEntityException
2396
+	 */
2397
+	public function updateStatusBasedOnTotalPaid($trigger_set_status_logic = true)
2398
+	{
2399
+		$paid = $this->paid();
2400
+		$price = $this->final_price();
2401
+		switch (true) {
2402
+			// overpaid or paid
2403
+			case EEH_Money::compare_floats($paid, $price, '>'):
2404
+			case EEH_Money::compare_floats($paid, $price):
2405
+				$new_status = EEM_Registration::status_id_approved;
2406
+				break;
2407
+			//  underpaid
2408
+			case EEH_Money::compare_floats($paid, $price, '<'):
2409
+				$new_status = EEM_Registration::status_id_pending_payment;
2410
+				break;
2411
+			// uhhh Houston...
2412
+			default:
2413
+				throw new RuntimeException(
2414
+					esc_html__('The total paid calculation for this registration is inaccurate.', 'event_espresso')
2415
+				);
2416
+		}
2417
+		if ($new_status !== $this->status_ID()) {
2418
+			if ($trigger_set_status_logic) {
2419
+				return $this->set_status($new_status);
2420
+			}
2421
+			parent::set('STS_ID', $new_status);
2422
+			return true;
2423
+		}
2424
+		return false;
2425
+	}
2426
+
2427
+
2428
+	/*************************** DEPRECATED ***************************/
2429
+
2430
+
2431
+	/**
2432
+	 * @deprecated
2433
+	 * @since     4.7.0
2434
+	 */
2435
+	public function price_paid()
2436
+	{
2437
+		EE_Error::doing_it_wrong(
2438
+			'EE_Registration::price_paid()',
2439
+			esc_html__(
2440
+				'This method is deprecated, please use EE_Registration::final_price() instead.',
2441
+				'event_espresso'
2442
+			),
2443
+			'4.7.0'
2444
+		);
2445
+		return $this->final_price();
2446
+	}
2447
+
2448
+
2449
+	/**
2450
+	 * @deprecated
2451
+	 * @since     4.7.0
2452
+	 * @param    float $REG_final_price
2453
+	 * @throws EE_Error
2454
+	 * @throws EntityNotFoundException
2455
+	 * @throws InvalidArgumentException
2456
+	 * @throws InvalidDataTypeException
2457
+	 * @throws InvalidInterfaceException
2458
+	 * @throws ReflectionException
2459
+	 * @throws RuntimeException
2460
+	 * @throws DomainException
2461
+	 */
2462
+	public function set_price_paid($REG_final_price = 0.00)
2463
+	{
2464
+		EE_Error::doing_it_wrong(
2465
+			'EE_Registration::set_price_paid()',
2466
+			esc_html__(
2467
+				'This method is deprecated, please use EE_Registration::set_final_price() instead.',
2468
+				'event_espresso'
2469
+			),
2470
+			'4.7.0'
2471
+		);
2472
+		$this->set_final_price($REG_final_price);
2473
+	}
2474
+
2475
+
2476
+	/**
2477
+	 * @deprecated
2478
+	 * @since 4.7.0
2479
+	 * @return string
2480
+	 * @throws EE_Error
2481
+	 * @throws InvalidArgumentException
2482
+	 * @throws InvalidDataTypeException
2483
+	 * @throws InvalidInterfaceException
2484
+	 * @throws ReflectionException
2485
+	 */
2486
+	public function pretty_price_paid()
2487
+	{
2488
+		EE_Error::doing_it_wrong(
2489
+			'EE_Registration::pretty_price_paid()',
2490
+			esc_html__(
2491
+				'This method is deprecated, please use EE_Registration::pretty_final_price() instead.',
2492
+				'event_espresso'
2493
+			),
2494
+			'4.7.0'
2495
+		);
2496
+		return $this->pretty_final_price();
2497
+	}
2498
+
2499
+
2500
+	/**
2501
+	 * Gets the primary datetime related to this registration via the related Event to this registration
2502
+	 *
2503
+	 * @deprecated 4.9.17
2504
+	 * @return EE_Datetime
2505
+	 * @throws EE_Error
2506
+	 * @throws EntityNotFoundException
2507
+	 * @throws InvalidArgumentException
2508
+	 * @throws InvalidDataTypeException
2509
+	 * @throws InvalidInterfaceException
2510
+	 * @throws ReflectionException
2511
+	 */
2512
+	public function get_related_primary_datetime()
2513
+	{
2514
+		EE_Error::doing_it_wrong(
2515
+			__METHOD__,
2516
+			esc_html__(
2517
+				'Use EE_Registration::get_latest_related_datetime() or EE_Registration::get_earliest_related_datetime()',
2518
+				'event_espresso'
2519
+			),
2520
+			'4.9.17',
2521
+			'5.0.0'
2522
+		);
2523
+		return $this->event()->primary_datetime();
2524
+	}
2525
+
2526
+	/**
2527
+	 * Returns the contact's name (or "Unknown" if there is no contact.)
2528
+	 * @since 4.10.12.p
2529
+	 * @return string
2530
+	 * @throws EE_Error
2531
+	 * @throws InvalidArgumentException
2532
+	 * @throws InvalidDataTypeException
2533
+	 * @throws InvalidInterfaceException
2534
+	 * @throws ReflectionException
2535
+	 */
2536
+	public function name()
2537
+	{
2538
+		return $this->attendeeName();
2539
+	}
2540 2540
 }
Please login to merge, or discard this patch.
Spacing   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -147,7 +147,7 @@  discard block
 block discarded – undo
147 147
     {
148 148
         switch ($field_name) {
149 149
             case 'REG_code':
150
-                if (! empty($field_value) && $this->reg_code() === null) {
150
+                if ( ! empty($field_value) && $this->reg_code() === null) {
151 151
                     $this->set_reg_code($field_value, $use_default);
152 152
                 }
153 153
                 break;
@@ -445,7 +445,7 @@  discard block
 block discarded – undo
445 445
     public function event()
446 446
     {
447 447
         $event = $this->get_first_related('Event');
448
-        if (! $event instanceof \EE_Event) {
448
+        if ( ! $event instanceof \EE_Event) {
449 449
             throw new EntityNotFoundException('Event ID', $this->event_ID());
450 450
         }
451 451
         return $event;
@@ -492,7 +492,7 @@  discard block
 block discarded – undo
492 492
     {
493 493
         // reserved ticket and datetime counts will be decremented as sold counts are incremented
494 494
         // so stop tracking that this reg has a ticket reserved
495
-        $this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
495
+        $this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:".__LINE__.')');
496 496
         $ticket = $this->ticket();
497 497
         $ticket->increaseSold();
498 498
         // possibly set event status to sold out
@@ -543,7 +543,7 @@  discard block
 block discarded – undo
543 543
             $reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
544 544
             if ($reserved && $update_ticket) {
545 545
                 $ticket = $this->ticket();
546
-                $ticket->increaseReserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
546
+                $ticket->increaseReserved(1, "REG: {$this->ID()} (ln:".__LINE__.')');
547 547
                 $ticket->save();
548 548
             }
549 549
         }
@@ -571,7 +571,7 @@  discard block
 block discarded – undo
571 571
             $reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, false);
572 572
             if ($reserved && $update_ticket) {
573 573
                 $ticket = $this->ticket();
574
-                $ticket->decreaseReserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
574
+                $ticket->decreaseReserved(1, true, "REG: {$this->ID()} (ln:".__LINE__.')');
575 575
             }
576 576
         }
577 577
     }
@@ -1455,7 +1455,7 @@  discard block
 block discarded – undo
1455 1455
                     : '';
1456 1456
                 break;
1457 1457
         }
1458
-        return $icon . $status[ $this->status_ID() ];
1458
+        return $icon.$status[$this->status_ID()];
1459 1459
     }
1460 1460
 
1461 1461
 
@@ -1711,11 +1711,11 @@  discard block
 block discarded – undo
1711 1711
     {
1712 1712
         $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1713 1713
         // first check registration status
1714
-        if (! $DTT_ID || ($check_approved && ! $this->is_approved())) {
1714
+        if ( ! $DTT_ID || ($check_approved && ! $this->is_approved())) {
1715 1715
             return false;
1716 1716
         }
1717 1717
         // is there a datetime ticket that matches this dtt_ID?
1718
-        if (! EEM_Datetime_Ticket::instance()->exists(
1718
+        if ( ! EEM_Datetime_Ticket::instance()->exists(
1719 1719
             array(
1720 1720
                 array(
1721 1721
                     'TKT_ID' => $this->get('TKT_ID'),
@@ -1749,7 +1749,7 @@  discard block
 block discarded – undo
1749 1749
     {
1750 1750
         $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1751 1751
 
1752
-        if (! $DTT_ID) {
1752
+        if ( ! $DTT_ID) {
1753 1753
             return false;
1754 1754
         }
1755 1755
 
@@ -1757,7 +1757,7 @@  discard block
 block discarded – undo
1757 1757
 
1758 1758
         // if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1759 1759
         // check-in or not.
1760
-        if (! $max_uses || $max_uses === EE_INF) {
1760
+        if ( ! $max_uses || $max_uses === EE_INF) {
1761 1761
             return true;
1762 1762
         }
1763 1763
 
@@ -1821,7 +1821,7 @@  discard block
 block discarded – undo
1821 1821
             $datetime = $this->get_latest_related_datetime();
1822 1822
             $DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1823 1823
             // verify the registration can checkin for the given DTT_ID
1824
-        } elseif (! $this->can_checkin($DTT_ID, $verify)) {
1824
+        } elseif ( ! $this->can_checkin($DTT_ID, $verify)) {
1825 1825
             EE_Error::add_error(
1826 1826
                 sprintf(
1827 1827
                     esc_html__(
@@ -1844,7 +1844,7 @@  discard block
 block discarded – undo
1844 1844
         );
1845 1845
         // start by getting the current status so we know what status we'll be changing to.
1846 1846
         $cur_status = $this->check_in_status_for_datetime($DTT_ID);
1847
-        $status_to = $status_paths[ $cur_status ];
1847
+        $status_to = $status_paths[$cur_status];
1848 1848
         // database only records true for checked IN or false for checked OUT
1849 1849
         // no record ( null ) means checked in NEVER, but we obviously don't save that
1850 1850
         $new_status = $status_to === EE_Checkin::status_checked_in;
@@ -2032,7 +2032,7 @@  discard block
 block discarded – undo
2032 2032
     public function transaction()
2033 2033
     {
2034 2034
         $transaction = $this->get_first_related('Transaction');
2035
-        if (! $transaction instanceof \EE_Transaction) {
2035
+        if ( ! $transaction instanceof \EE_Transaction) {
2036 2036
             throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
2037 2037
         }
2038 2038
         return $transaction;
@@ -2105,11 +2105,11 @@  discard block
 block discarded – undo
2105 2105
             );
2106 2106
             return;
2107 2107
         }
2108
-        if (! $this->reg_code()) {
2108
+        if ( ! $this->reg_code()) {
2109 2109
             parent::set('REG_code', $REG_code, $use_default);
2110 2110
         } else {
2111 2111
             EE_Error::doing_it_wrong(
2112
-                __CLASS__ . '::' . __FUNCTION__,
2112
+                __CLASS__.'::'.__FUNCTION__,
2113 2113
                 esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
2114 2114
                 '4.6.0'
2115 2115
             );
@@ -2299,7 +2299,7 @@  discard block
 block discarded – undo
2299 2299
                 break;
2300 2300
             }
2301 2301
         }
2302
-        if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
2302
+        if ( ! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
2303 2303
             throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
2304 2304
         }
2305 2305
         return $line_item;
Please login to merge, or discard this patch.