Completed
Branch FET/extra-logging-when-trashin... (b6e112)
by
unknown
09:18 queued 33s
created
core/db_classes/EE_Transaction.class.php 3 patches
Doc Comments   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -366,7 +366,7 @@  discard block
 block discarded – undo
366 366
 
367 367
 
368 368
     /**
369
-     * @return mixed|null
369
+     * @return EE_Cart|null
370 370
      * @throws EE_Error
371 371
      * @throws InvalidArgumentException
372 372
      * @throws InvalidDataTypeException
@@ -508,7 +508,7 @@  discard block
 block discarded – undo
508 508
      * Gets all the attendees for this transaction (handy for use with EE_Attendee's get_registrations_for_event
509 509
      * function for getting attendees and how many registrations they each have for an event)
510 510
      *
511
-     * @return mixed EE_Attendee[] by default, int if $output is set to 'COUNT'
511
+     * @return EE_Base_Class[] EE_Attendee[] by default, int if $output is set to 'COUNT'
512 512
      * @throws EE_Error
513 513
      * @throws InvalidArgumentException
514 514
      * @throws InvalidDataTypeException
@@ -564,7 +564,7 @@  discard block
 block discarded – undo
564 564
     /**
565 565
      * Gets all payments which have not been approved
566 566
      *
567
-     * @return EE_Base_Class[]|EEI_Payment[]
567
+     * @return EE_Base_Class[]
568 568
      * @throws EE_Error if a model is misconfigured somehow
569 569
      * @throws InvalidArgumentException
570 570
      * @throws InvalidDataTypeException
Please login to merge, or discard this patch.
Indentation   +1712 added lines, -1712 removed lines patch added patch discarded remove patch
@@ -13,1716 +13,1716 @@
 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
-     */
1668
-    public function verify_abandoned_transaction_status()
1669
-    {
1670
-        if ($this->status_ID() !== EEM_Transaction::abandoned_status_code) {
1671
-            return;
1672
-        }
1673
-        $payments = $this->get_many_related('Payment');
1674
-        if (! empty($payments)) {
1675
-            foreach ($payments as $payment) {
1676
-                if ($payment instanceof EE_Payment) {
1677
-                    // kk this TXN should NOT be abandoned
1678
-                    $this->update_status_based_on_total_paid();
1679
-                    if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1680
-                        EE_Error::add_attention(
1681
-                            sprintf(
1682
-                                esc_html__(
1683
-                                    '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.',
1684
-                                    'event_espresso'
1685
-                                ),
1686
-                                $this->ID(),
1687
-                                $this->pretty_status()
1688
-                            )
1689
-                        );
1690
-                    }
1691
-                    // get final reg step status
1692
-                    $finalized = $this->final_reg_step_completed();
1693
-                    // if the 'finalize_registration' step has been initiated (has a timestamp)
1694
-                    // but has not yet been fully completed (TRUE)
1695
-                    if (is_int($finalized) && $finalized !== false && $finalized !== true) {
1696
-                        $this->set_reg_step_completed('finalize_registration');
1697
-                        $this->save();
1698
-                    }
1699
-                }
1700
-            }
1701
-        }
1702
-    }
1703
-
1704
-
1705
-    /**
1706
-     * @param string $source function name that called this method
1707
-     * @return boolean | int
1708
-     * @throws EE_Error
1709
-     * @throws InvalidArgumentException
1710
-     * @throws InvalidDataTypeException
1711
-     * @throws InvalidInterfaceException
1712
-     * @throws ReflectionException
1713
-     * @throws RuntimeException
1714
-     */
1715
-    public function delete($source = 'unknown')
1716
-    {
1717
-        $current_user = wp_get_current_user();
1718
-        $this->add_extra_meta(
1719
-            EE_Transaction::EXTRA_META_KEY_TXN_DELETED,
1720
-            array(
1721
-                'deleted-by' => $current_user->ID ? $current_user->display_name : 'unauthed user',
1722
-                'timestamp'  => time(),
1723
-                'source'     => $source,
1724
-            )
1725
-        );
1726
-        return parent::delete();
1727
-    }
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
+	 */
1668
+	public function verify_abandoned_transaction_status()
1669
+	{
1670
+		if ($this->status_ID() !== EEM_Transaction::abandoned_status_code) {
1671
+			return;
1672
+		}
1673
+		$payments = $this->get_many_related('Payment');
1674
+		if (! empty($payments)) {
1675
+			foreach ($payments as $payment) {
1676
+				if ($payment instanceof EE_Payment) {
1677
+					// kk this TXN should NOT be abandoned
1678
+					$this->update_status_based_on_total_paid();
1679
+					if (! (defined('DOING_AJAX') && DOING_AJAX) && is_admin()) {
1680
+						EE_Error::add_attention(
1681
+							sprintf(
1682
+								esc_html__(
1683
+									'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.',
1684
+									'event_espresso'
1685
+								),
1686
+								$this->ID(),
1687
+								$this->pretty_status()
1688
+							)
1689
+						);
1690
+					}
1691
+					// get final reg step status
1692
+					$finalized = $this->final_reg_step_completed();
1693
+					// if the 'finalize_registration' step has been initiated (has a timestamp)
1694
+					// but has not yet been fully completed (TRUE)
1695
+					if (is_int($finalized) && $finalized !== false && $finalized !== true) {
1696
+						$this->set_reg_step_completed('finalize_registration');
1697
+						$this->save();
1698
+					}
1699
+				}
1700
+			}
1701
+		}
1702
+	}
1703
+
1704
+
1705
+	/**
1706
+	 * @param string $source function name that called this method
1707
+	 * @return boolean | int
1708
+	 * @throws EE_Error
1709
+	 * @throws InvalidArgumentException
1710
+	 * @throws InvalidDataTypeException
1711
+	 * @throws InvalidInterfaceException
1712
+	 * @throws ReflectionException
1713
+	 * @throws RuntimeException
1714
+	 */
1715
+	public function delete($source = 'unknown')
1716
+	{
1717
+		$current_user = wp_get_current_user();
1718
+		$this->add_extra_meta(
1719
+			EE_Transaction::EXTRA_META_KEY_TXN_DELETED,
1720
+			array(
1721
+				'deleted-by' => $current_user->ID ? $current_user->display_name : 'unauthed user',
1722
+				'timestamp'  => time(),
1723
+				'source'     => $source,
1724
+			)
1725
+		);
1726
+		return parent::delete();
1727
+	}
1728 1728
 }
Please login to merge, or discard this patch.
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.
core/db_classes/EE_Registration.class.php 3 patches
Doc Comments   +3 added lines, -2 removed lines patch added patch discarded remove patch
@@ -1688,6 +1688,7 @@  discard block
 block discarded – undo
1688 1688
      * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1689 1689
      * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1690 1690
      *                                          consider registration status as well as datetime access.
1691
+     * @param integer $DTT_OR_ID
1691 1692
      * @return bool
1692 1693
      * @throws EE_Error
1693 1694
      * @throws InvalidArgumentException
@@ -1876,7 +1877,7 @@  discard block
 block discarded – undo
1876 1877
      * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1877 1878
      * "Latest" is defined by the `DTT_EVT_start` column.
1878 1879
      *
1879
-     * @return EE_Datetime|null
1880
+     * @return null|EE_Base_Class
1880 1881
      * @throws EE_Error
1881 1882
      * @throws InvalidArgumentException
1882 1883
      * @throws InvalidDataTypeException
@@ -2244,7 +2245,7 @@  discard block
 block discarded – undo
2244 2245
      * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
2245 2246
      * Note: if there are no payments on the registration there will be no payment method returned.
2246 2247
      *
2247
-     * @return EE_Payment|EE_Payment_Method|null
2248
+     * @return null|EE_Base_Class
2248 2249
      * @throws EE_Error
2249 2250
      * @throws InvalidArgumentException
2250 2251
      * @throws InvalidDataTypeException
Please login to merge, or discard this patch.
Indentation   +2491 added lines, -2491 removed lines patch added patch discarded remove patch
@@ -16,2495 +16,2495 @@
 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
-            // TO approved
194
-            if ($new_STS_ID === EEM_Registration::status_id_approved) {
195
-                // reserve a space by incrementing ticket and datetime sold values
196
-                $this->_reserve_registration_space();
197
-                do_action('AHEE__EE_Registration__set_status__to_approved', $this, $old_STS_ID, $new_STS_ID, $context);
198
-                // OR FROM  approved
199
-            } elseif ($old_STS_ID === EEM_Registration::status_id_approved) {
200
-                // release a space by decrementing ticket and datetime sold values
201
-                $this->_release_registration_space();
202
-                do_action(
203
-                    'AHEE__EE_Registration__set_status__from_approved',
204
-                    $this,
205
-                    $old_STS_ID,
206
-                    $new_STS_ID,
207
-                    $context
208
-                );
209
-            }
210
-            // update status
211
-            parent::set('STS_ID', $new_STS_ID, $use_default);
212
-            $this->_update_if_canceled_or_declined($new_STS_ID, $old_STS_ID, $context);
213
-            if ($this->statusChangeUpdatesTransaction($context)) {
214
-                $this->updateTransactionAfterStatusChange();
215
-            }
216
-            do_action('AHEE__EE_Registration__set_status__after_update', $this, $old_STS_ID, $new_STS_ID, $context);
217
-            return true;
218
-        }
219
-        // even though the old value matches the new value, it's still good to
220
-        // allow the parent set method to have a say
221
-        parent::set('STS_ID', $new_STS_ID, $use_default);
222
-        return true;
223
-    }
224
-
225
-
226
-    /**
227
-     * update REGs and TXN when cancelled or declined registrations involved
228
-     *
229
-     * @param string                $new_STS_ID
230
-     * @param string                $old_STS_ID
231
-     * @param ContextInterface|null $context
232
-     * @throws EE_Error
233
-     * @throws InvalidArgumentException
234
-     * @throws InvalidDataTypeException
235
-     * @throws InvalidInterfaceException
236
-     * @throws ReflectionException
237
-     * @throws RuntimeException
238
-     */
239
-    private function _update_if_canceled_or_declined($new_STS_ID, $old_STS_ID, ContextInterface $context = null)
240
-    {
241
-        // these reg statuses should not be considered in any calculations involving monies owing
242
-        $closed_reg_statuses = EEM_Registration::closed_reg_statuses();
243
-        // true if registration has been cancelled or declined
244
-        $this->updateIfCanceled(
245
-            $closed_reg_statuses,
246
-            $new_STS_ID,
247
-            $old_STS_ID,
248
-            $context
249
-        );
250
-        $this->updateIfDeclined(
251
-            $closed_reg_statuses,
252
-            $new_STS_ID,
253
-            $old_STS_ID,
254
-            $context
255
-        );
256
-    }
257
-
258
-
259
-    /**
260
-     * update REGs and TXN when cancelled or declined registrations involved
261
-     *
262
-     * @param array                 $closed_reg_statuses
263
-     * @param string                $new_STS_ID
264
-     * @param string                $old_STS_ID
265
-     * @param ContextInterface|null $context
266
-     * @throws EE_Error
267
-     * @throws InvalidArgumentException
268
-     * @throws InvalidDataTypeException
269
-     * @throws InvalidInterfaceException
270
-     * @throws ReflectionException
271
-     * @throws RuntimeException
272
-     */
273
-    private function updateIfCanceled(
274
-        array $closed_reg_statuses,
275
-        $new_STS_ID,
276
-        $old_STS_ID,
277
-        ContextInterface $context = null
278
-    ) {
279
-        // true if registration has been cancelled or declined
280
-        if (in_array($new_STS_ID, $closed_reg_statuses, true)
281
-            && ! in_array($old_STS_ID, $closed_reg_statuses, true)
282
-        ) {
283
-            /** @type EE_Registration_Processor $registration_processor */
284
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
285
-            /** @type EE_Transaction_Processor $transaction_processor */
286
-            $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
287
-            // cancelled or declined registration
288
-            $registration_processor->update_registration_after_being_canceled_or_declined(
289
-                $this,
290
-                $closed_reg_statuses
291
-            );
292
-            $transaction_processor->update_transaction_after_canceled_or_declined_registration(
293
-                $this,
294
-                $closed_reg_statuses,
295
-                false
296
-            );
297
-            do_action(
298
-                'AHEE__EE_Registration__set_status__canceled_or_declined',
299
-                $this,
300
-                $old_STS_ID,
301
-                $new_STS_ID,
302
-                $context
303
-            );
304
-            return;
305
-        }
306
-    }
307
-
308
-
309
-    /**
310
-     * update REGs and TXN when cancelled or declined registrations involved
311
-     *
312
-     * @param array                 $closed_reg_statuses
313
-     * @param string                $new_STS_ID
314
-     * @param string                $old_STS_ID
315
-     * @param ContextInterface|null $context
316
-     * @throws EE_Error
317
-     * @throws InvalidArgumentException
318
-     * @throws InvalidDataTypeException
319
-     * @throws InvalidInterfaceException
320
-     * @throws ReflectionException
321
-     * @throws RuntimeException
322
-     */
323
-    private function updateIfDeclined(
324
-        array $closed_reg_statuses,
325
-        $new_STS_ID,
326
-        $old_STS_ID,
327
-        ContextInterface $context = null
328
-    ) {
329
-        // true if reinstating cancelled or declined registration
330
-        if (in_array($old_STS_ID, $closed_reg_statuses, true)
331
-            && ! in_array($new_STS_ID, $closed_reg_statuses, true)
332
-        ) {
333
-            /** @type EE_Registration_Processor $registration_processor */
334
-            $registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
335
-            /** @type EE_Transaction_Processor $transaction_processor */
336
-            $transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
337
-            // reinstating cancelled or declined registration
338
-            $registration_processor->update_canceled_or_declined_registration_after_being_reinstated(
339
-                $this,
340
-                $closed_reg_statuses
341
-            );
342
-            $transaction_processor->update_transaction_after_reinstating_canceled_registration(
343
-                $this,
344
-                $closed_reg_statuses,
345
-                false
346
-            );
347
-            do_action(
348
-                'AHEE__EE_Registration__set_status__after_reinstated',
349
-                $this,
350
-                $old_STS_ID,
351
-                $new_STS_ID,
352
-                $context
353
-            );
354
-        }
355
-    }
356
-
357
-
358
-    /**
359
-     * @param ContextInterface|null $context
360
-     * @return bool
361
-     */
362
-    private function statusChangeUpdatesTransaction(ContextInterface $context = null)
363
-    {
364
-        $contexts_that_do_not_update_transaction = (array) apply_filters(
365
-            'AHEE__EE_Registration__statusChangeUpdatesTransaction__contexts_that_do_not_update_transaction',
366
-            array('spco_reg_step_attendee_information_process_registrations'),
367
-            $context,
368
-            $this
369
-        );
370
-        return ! (
371
-            $context instanceof ContextInterface
372
-            && in_array($context->slug(), $contexts_that_do_not_update_transaction, true)
373
-        );
374
-    }
375
-
376
-
377
-    /**
378
-     * @throws EE_Error
379
-     * @throws EntityNotFoundException
380
-     * @throws InvalidArgumentException
381
-     * @throws InvalidDataTypeException
382
-     * @throws InvalidInterfaceException
383
-     * @throws ReflectionException
384
-     * @throws RuntimeException
385
-     */
386
-    private function updateTransactionAfterStatusChange()
387
-    {
388
-        /** @type EE_Transaction_Payments $transaction_payments */
389
-        $transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
390
-        $transaction_payments->recalculate_transaction_total($this->transaction(), false);
391
-        $this->transaction()->update_status_based_on_total_paid();
392
-    }
393
-
394
-
395
-    /**
396
-     * get Status ID
397
-     *
398
-     * @throws EE_Error
399
-     * @throws InvalidArgumentException
400
-     * @throws InvalidDataTypeException
401
-     * @throws InvalidInterfaceException
402
-     * @throws ReflectionException
403
-     */
404
-    public function status_ID()
405
-    {
406
-        return $this->get('STS_ID');
407
-    }
408
-
409
-
410
-    /**
411
-     * Gets the ticket this registration is for
412
-     *
413
-     * @param boolean $include_archived whether to include archived tickets or not.
414
-     * @return EE_Ticket|EE_Base_Class
415
-     * @throws EE_Error
416
-     * @throws InvalidArgumentException
417
-     * @throws InvalidDataTypeException
418
-     * @throws InvalidInterfaceException
419
-     * @throws ReflectionException
420
-     */
421
-    public function ticket($include_archived = true)
422
-    {
423
-        $query_params = array();
424
-        if ($include_archived) {
425
-            $query_params['default_where_conditions'] = 'none';
426
-        }
427
-        return $this->get_first_related('Ticket', $query_params);
428
-    }
429
-
430
-
431
-    /**
432
-     * Gets the event this registration is for
433
-     *
434
-     * @return EE_Event
435
-     * @throws EE_Error
436
-     * @throws EntityNotFoundException
437
-     * @throws InvalidArgumentException
438
-     * @throws InvalidDataTypeException
439
-     * @throws InvalidInterfaceException
440
-     * @throws ReflectionException
441
-     */
442
-    public function event()
443
-    {
444
-        $event = $this->get_first_related('Event');
445
-        if (! $event instanceof \EE_Event) {
446
-            throw new EntityNotFoundException('Event ID', $this->event_ID());
447
-        }
448
-        return $event;
449
-    }
450
-
451
-
452
-    /**
453
-     * Gets the "author" of the registration.  Note that for the purposes of registrations, the author will correspond
454
-     * with the author of the event this registration is for.
455
-     *
456
-     * @since 4.5.0
457
-     * @return int
458
-     * @throws EE_Error
459
-     * @throws EntityNotFoundException
460
-     * @throws InvalidArgumentException
461
-     * @throws InvalidDataTypeException
462
-     * @throws InvalidInterfaceException
463
-     * @throws ReflectionException
464
-     */
465
-    public function wp_user()
466
-    {
467
-        $event = $this->event();
468
-        if ($event instanceof EE_Event) {
469
-            return $event->wp_user();
470
-        }
471
-        return 0;
472
-    }
473
-
474
-
475
-    /**
476
-     * increments this registration's related ticket sold and corresponding datetime sold values
477
-     *
478
-     * @return void
479
-     * @throws DomainException
480
-     * @throws EE_Error
481
-     * @throws EntityNotFoundException
482
-     * @throws InvalidArgumentException
483
-     * @throws InvalidDataTypeException
484
-     * @throws InvalidInterfaceException
485
-     * @throws ReflectionException
486
-     * @throws UnexpectedEntityException
487
-     */
488
-    private function _reserve_registration_space()
489
-    {
490
-        // reserved ticket and datetime counts will be decremented as sold counts are incremented
491
-        // so stop tracking that this reg has a ticket reserved
492
-        $this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
493
-        $ticket = $this->ticket();
494
-        $ticket->increase_sold();
495
-        $ticket->save();
496
-        // possibly set event status to sold out
497
-        $this->event()->perform_sold_out_status_check();
498
-    }
499
-
500
-
501
-    /**
502
-     * decrements (subtracts) this registration's related ticket sold and corresponding datetime sold values
503
-     *
504
-     * @return void
505
-     * @throws DomainException
506
-     * @throws EE_Error
507
-     * @throws EntityNotFoundException
508
-     * @throws InvalidArgumentException
509
-     * @throws InvalidDataTypeException
510
-     * @throws InvalidInterfaceException
511
-     * @throws ReflectionException
512
-     * @throws UnexpectedEntityException
513
-     */
514
-    private function _release_registration_space()
515
-    {
516
-        $ticket = $this->ticket();
517
-        $ticket->decrease_sold();
518
-        $ticket->save();
519
-        // possibly change event status from sold out back to previous status
520
-        $this->event()->perform_sold_out_status_check();
521
-    }
522
-
523
-
524
-    /**
525
-     * tracks this registration's ticket reservation in extra meta
526
-     * and can increment related ticket reserved and corresponding datetime reserved values
527
-     *
528
-     * @param bool   $update_ticket if true, will increment ticket and datetime reserved count
529
-     * @param string $source
530
-     * @return void
531
-     * @throws EE_Error
532
-     * @throws InvalidArgumentException
533
-     * @throws InvalidDataTypeException
534
-     * @throws InvalidInterfaceException
535
-     * @throws ReflectionException
536
-     */
537
-    public function reserve_ticket($update_ticket = false, $source = 'unknown')
538
-    {
539
-        // only reserve ticket if space is not currently reserved
540
-        if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) !== true) {
541
-            $this->update_extra_meta('reserve_ticket', "{$this->ticket_ID()} from {$source}");
542
-            $reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
543
-            if ($reserved && $update_ticket) {
544
-                $ticket = $this->ticket();
545
-                $ticket->increase_reserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
546
-                $ticket->save();
547
-            }
548
-        }
549
-    }
550
-
551
-
552
-    /**
553
-     * stops tracking this registration's ticket reservation in extra meta
554
-     * decrements (subtracts) related ticket reserved and corresponding datetime reserved values
555
-     *
556
-     * @param bool   $update_ticket if true, will decrement ticket and datetime reserved count
557
-     * @param string $source
558
-     * @return void
559
-     * @throws EE_Error
560
-     * @throws InvalidArgumentException
561
-     * @throws InvalidDataTypeException
562
-     * @throws InvalidInterfaceException
563
-     * @throws ReflectionException
564
-     */
565
-    public function release_reserved_ticket($update_ticket = false, $source = 'unknown')
566
-    {
567
-        // only release ticket if space is currently reserved
568
-        if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) === true) {
569
-            $this->update_extra_meta('release_reserved_ticket', "{$this->ticket_ID()} from {$source}");
570
-            $reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, false);
571
-            if ($reserved && $update_ticket) {
572
-                $ticket = $this->ticket();
573
-                $ticket->decrease_reserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
574
-                $ticket->save();
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
-    /**
897
-     *        get Event ID
898
-     */
899
-    public function event_ID()
900
-    {
901
-        return $this->get('EVT_ID');
902
-    }
903
-
904
-
905
-    /**
906
-     *        get Event ID
907
-     */
908
-    public function event_name()
909
-    {
910
-        $event = $this->event_obj();
911
-        if ($event) {
912
-            return $event->name();
913
-        } else {
914
-            return null;
915
-        }
916
-    }
917
-
918
-
919
-    /**
920
-     * Fetches the event this registration is for
921
-     *
922
-     * @return EE_Base_Class|EE_Event
923
-     * @throws EE_Error
924
-     * @throws InvalidArgumentException
925
-     * @throws InvalidDataTypeException
926
-     * @throws InvalidInterfaceException
927
-     * @throws ReflectionException
928
-     */
929
-    public function event_obj()
930
-    {
931
-        return $this->get_first_related('Event');
932
-    }
933
-
934
-
935
-    /**
936
-     *        get Attendee ID
937
-     */
938
-    public function attendee_ID()
939
-    {
940
-        return $this->get('ATT_ID');
941
-    }
942
-
943
-
944
-    /**
945
-     *        get PHP Session ID
946
-     */
947
-    public function session_ID()
948
-    {
949
-        return $this->get('REG_session');
950
-    }
951
-
952
-
953
-    /**
954
-     * Gets the string which represents the URL trigger for the receipt template in the message template system.
955
-     *
956
-     * @param string $messenger 'pdf' or 'html'.  Default 'html'.
957
-     * @return string
958
-     * @throws DomainException
959
-     * @throws EE_Error
960
-     * @throws InvalidArgumentException
961
-     * @throws InvalidDataTypeException
962
-     * @throws InvalidInterfaceException
963
-     * @throws ReflectionException
964
-     */
965
-    public function receipt_url($messenger = 'html')
966
-    {
967
-
968
-        /**
969
-         * The below will be deprecated one version after this.  We check first if there is a custom receipt template
970
-         * already in use on old system.  If there is then we just return the standard url for it.
971
-         *
972
-         * @since 4.5.0
973
-         */
974
-        $template_relative_path = 'modules/gateways/Invoice/lib/templates/receipt_body.template.php';
975
-        $has_custom = EEH_Template::locate_template(
976
-            $template_relative_path,
977
-            array(),
978
-            true,
979
-            true,
980
-            true
981
-        );
982
-
983
-        if ($has_custom) {
984
-            return add_query_arg(array('receipt' => 'true'), $this->invoice_url('launch'));
985
-        }
986
-        return apply_filters('FHEE__EE_Registration__receipt_url__receipt_url', '', $this, $messenger, 'receipt');
987
-    }
988
-
989
-
990
-    /**
991
-     * Gets the string which represents the URL trigger for the invoice template in the message template system.
992
-     *
993
-     * @param string $messenger 'pdf' or 'html'.  Default 'html'.
994
-     * @return string
995
-     * @throws DomainException
996
-     * @throws EE_Error
997
-     * @throws InvalidArgumentException
998
-     * @throws InvalidDataTypeException
999
-     * @throws InvalidInterfaceException
1000
-     * @throws ReflectionException
1001
-     */
1002
-    public function invoice_url($messenger = 'html')
1003
-    {
1004
-        /**
1005
-         * The below will be deprecated one version after this.  We check first if there is a custom invoice template
1006
-         * already in use on old system.  If there is then we just return the standard url for it.
1007
-         *
1008
-         * @since 4.5.0
1009
-         */
1010
-        $template_relative_path = 'modules/gateways/Invoice/lib/templates/invoice_body.template.php';
1011
-        $has_custom = EEH_Template::locate_template(
1012
-            $template_relative_path,
1013
-            array(),
1014
-            true,
1015
-            true,
1016
-            true
1017
-        );
1018
-
1019
-        if ($has_custom) {
1020
-            if ($messenger == 'html') {
1021
-                return $this->invoice_url('launch');
1022
-            }
1023
-            $route = $messenger == 'download' || $messenger == 'pdf' ? 'download_invoice' : 'launch_invoice';
1024
-
1025
-            $query_args = array('ee' => $route, 'id' => $this->reg_url_link());
1026
-            if ($messenger == 'html') {
1027
-                $query_args['html'] = true;
1028
-            }
1029
-            return add_query_arg($query_args, get_permalink(EE_Registry::instance()->CFG->core->thank_you_page_id));
1030
-        }
1031
-        return apply_filters('FHEE__EE_Registration__invoice_url__invoice_url', '', $this, $messenger, 'invoice');
1032
-    }
1033
-
1034
-
1035
-    /**
1036
-     * get Registration URL Link
1037
-     *
1038
-     * @return string
1039
-     * @throws EE_Error
1040
-     * @throws InvalidArgumentException
1041
-     * @throws InvalidDataTypeException
1042
-     * @throws InvalidInterfaceException
1043
-     * @throws ReflectionException
1044
-     */
1045
-    public function reg_url_link()
1046
-    {
1047
-        return (string) $this->get('REG_url_link');
1048
-    }
1049
-
1050
-
1051
-    /**
1052
-     * Echoes out invoice_url()
1053
-     *
1054
-     * @param string $type 'download','launch', or 'html' (default is 'launch')
1055
-     * @return void
1056
-     * @throws DomainException
1057
-     * @throws EE_Error
1058
-     * @throws InvalidArgumentException
1059
-     * @throws InvalidDataTypeException
1060
-     * @throws InvalidInterfaceException
1061
-     * @throws ReflectionException
1062
-     */
1063
-    public function e_invoice_url($type = 'launch')
1064
-    {
1065
-        echo $this->invoice_url($type);
1066
-    }
1067
-
1068
-
1069
-    /**
1070
-     * Echoes out payment_overview_url
1071
-     */
1072
-    public function e_payment_overview_url()
1073
-    {
1074
-        echo $this->payment_overview_url();
1075
-    }
1076
-
1077
-
1078
-    /**
1079
-     * Gets the URL for the checkout payment options reg step
1080
-     * with this registration's REG_url_link added as a query parameter
1081
-     *
1082
-     * @param bool $clear_session Set to true when you want to clear the session on revisiting the
1083
-     *                            payment overview url.
1084
-     * @return string
1085
-     * @throws EE_Error
1086
-     * @throws InvalidArgumentException
1087
-     * @throws InvalidDataTypeException
1088
-     * @throws InvalidInterfaceException
1089
-     * @throws ReflectionException
1090
-     */
1091
-    public function payment_overview_url($clear_session = false)
1092
-    {
1093
-        return add_query_arg(
1094
-            (array) apply_filters(
1095
-                'FHEE__EE_Registration__payment_overview_url__query_args',
1096
-                array(
1097
-                    'e_reg_url_link' => $this->reg_url_link(),
1098
-                    'step'           => 'payment_options',
1099
-                    'revisit'        => true,
1100
-                    'clear_session'  => (bool) $clear_session,
1101
-                ),
1102
-                $this
1103
-            ),
1104
-            EE_Registry::instance()->CFG->core->reg_page_url()
1105
-        );
1106
-    }
1107
-
1108
-
1109
-    /**
1110
-     * Gets the URL for the checkout attendee information reg step
1111
-     * with this registration's REG_url_link added as a query parameter
1112
-     *
1113
-     * @return string
1114
-     * @throws EE_Error
1115
-     * @throws InvalidArgumentException
1116
-     * @throws InvalidDataTypeException
1117
-     * @throws InvalidInterfaceException
1118
-     * @throws ReflectionException
1119
-     */
1120
-    public function edit_attendee_information_url()
1121
-    {
1122
-        return add_query_arg(
1123
-            (array) apply_filters(
1124
-                'FHEE__EE_Registration__edit_attendee_information_url__query_args',
1125
-                array(
1126
-                    'e_reg_url_link' => $this->reg_url_link(),
1127
-                    'step'           => 'attendee_information',
1128
-                    'revisit'        => true,
1129
-                ),
1130
-                $this
1131
-            ),
1132
-            EE_Registry::instance()->CFG->core->reg_page_url()
1133
-        );
1134
-    }
1135
-
1136
-
1137
-    /**
1138
-     * Simply generates and returns the appropriate admin_url link to edit this registration
1139
-     *
1140
-     * @return string
1141
-     * @throws EE_Error
1142
-     * @throws InvalidArgumentException
1143
-     * @throws InvalidDataTypeException
1144
-     * @throws InvalidInterfaceException
1145
-     * @throws ReflectionException
1146
-     */
1147
-    public function get_admin_edit_url()
1148
-    {
1149
-        return EEH_URL::add_query_args_and_nonce(
1150
-            array(
1151
-                'page'    => 'espresso_registrations',
1152
-                'action'  => 'view_registration',
1153
-                '_REG_ID' => $this->ID(),
1154
-            ),
1155
-            admin_url('admin.php')
1156
-        );
1157
-    }
1158
-
1159
-
1160
-    /**
1161
-     * is_primary_registrant?
1162
-     *
1163
-     * @throws EE_Error
1164
-     * @throws InvalidArgumentException
1165
-     * @throws InvalidDataTypeException
1166
-     * @throws InvalidInterfaceException
1167
-     * @throws ReflectionException
1168
-     */
1169
-    public function is_primary_registrant()
1170
-    {
1171
-        return (int) $this->get('REG_count') === 1;
1172
-    }
1173
-
1174
-
1175
-    /**
1176
-     * This returns the primary registration object for this registration group (which may be this object).
1177
-     *
1178
-     * @return EE_Registration
1179
-     * @throws EE_Error
1180
-     * @throws InvalidArgumentException
1181
-     * @throws InvalidDataTypeException
1182
-     * @throws InvalidInterfaceException
1183
-     * @throws ReflectionException
1184
-     */
1185
-    public function get_primary_registration()
1186
-    {
1187
-        if ($this->is_primary_registrant()) {
1188
-            return $this;
1189
-        }
1190
-
1191
-        // k reg_count !== 1 so let's get the EE_Registration object matching this txn_id and reg_count == 1
1192
-        /** @var EE_Registration $primary_registrant */
1193
-        $primary_registrant = EEM_Registration::instance()->get_one(
1194
-            array(
1195
-                array(
1196
-                    'TXN_ID'    => $this->transaction_ID(),
1197
-                    'REG_count' => 1,
1198
-                ),
1199
-            )
1200
-        );
1201
-        return $primary_registrant;
1202
-    }
1203
-
1204
-
1205
-    /**
1206
-     * get  Attendee Number
1207
-     *
1208
-     * @throws EE_Error
1209
-     * @throws InvalidArgumentException
1210
-     * @throws InvalidDataTypeException
1211
-     * @throws InvalidInterfaceException
1212
-     * @throws ReflectionException
1213
-     */
1214
-    public function count()
1215
-    {
1216
-        return $this->get('REG_count');
1217
-    }
1218
-
1219
-
1220
-    /**
1221
-     * get Group Size
1222
-     *
1223
-     * @throws EE_Error
1224
-     * @throws InvalidArgumentException
1225
-     * @throws InvalidDataTypeException
1226
-     * @throws InvalidInterfaceException
1227
-     * @throws ReflectionException
1228
-     */
1229
-    public function group_size()
1230
-    {
1231
-        return $this->get('REG_group_size');
1232
-    }
1233
-
1234
-
1235
-    /**
1236
-     * get Registration Date
1237
-     *
1238
-     * @throws EE_Error
1239
-     * @throws InvalidArgumentException
1240
-     * @throws InvalidDataTypeException
1241
-     * @throws InvalidInterfaceException
1242
-     * @throws ReflectionException
1243
-     */
1244
-    public function date()
1245
-    {
1246
-        return $this->get('REG_date');
1247
-    }
1248
-
1249
-
1250
-    /**
1251
-     * gets a pretty date
1252
-     *
1253
-     * @param string $date_format
1254
-     * @param string $time_format
1255
-     * @return string
1256
-     * @throws EE_Error
1257
-     * @throws InvalidArgumentException
1258
-     * @throws InvalidDataTypeException
1259
-     * @throws InvalidInterfaceException
1260
-     * @throws ReflectionException
1261
-     */
1262
-    public function pretty_date($date_format = null, $time_format = null)
1263
-    {
1264
-        return $this->get_datetime('REG_date', $date_format, $time_format);
1265
-    }
1266
-
1267
-
1268
-    /**
1269
-     * final_price
1270
-     * the registration's share of the transaction total, so that the
1271
-     * sum of all the transaction's REG_final_prices equal the transaction's total
1272
-     *
1273
-     * @return float
1274
-     * @throws EE_Error
1275
-     * @throws InvalidArgumentException
1276
-     * @throws InvalidDataTypeException
1277
-     * @throws InvalidInterfaceException
1278
-     * @throws ReflectionException
1279
-     */
1280
-    public function final_price()
1281
-    {
1282
-        return $this->get('REG_final_price');
1283
-    }
1284
-
1285
-
1286
-    /**
1287
-     * pretty_final_price
1288
-     *  final price as formatted string, with correct decimal places and currency symbol
1289
-     *
1290
-     * @return string
1291
-     * @throws EE_Error
1292
-     * @throws InvalidArgumentException
1293
-     * @throws InvalidDataTypeException
1294
-     * @throws InvalidInterfaceException
1295
-     * @throws ReflectionException
1296
-     */
1297
-    public function pretty_final_price()
1298
-    {
1299
-        return $this->get_pretty('REG_final_price');
1300
-    }
1301
-
1302
-
1303
-    /**
1304
-     * get paid (yeah)
1305
-     *
1306
-     * @return float
1307
-     * @throws EE_Error
1308
-     * @throws InvalidArgumentException
1309
-     * @throws InvalidDataTypeException
1310
-     * @throws InvalidInterfaceException
1311
-     * @throws ReflectionException
1312
-     */
1313
-    public function paid()
1314
-    {
1315
-        return $this->get('REG_paid');
1316
-    }
1317
-
1318
-
1319
-    /**
1320
-     * pretty_paid
1321
-     *
1322
-     * @return float
1323
-     * @throws EE_Error
1324
-     * @throws InvalidArgumentException
1325
-     * @throws InvalidDataTypeException
1326
-     * @throws InvalidInterfaceException
1327
-     * @throws ReflectionException
1328
-     */
1329
-    public function pretty_paid()
1330
-    {
1331
-        return $this->get_pretty('REG_paid');
1332
-    }
1333
-
1334
-
1335
-    /**
1336
-     * owes_monies_and_can_pay
1337
-     * whether or not this registration has monies owing and it's' status allows payment
1338
-     *
1339
-     * @param array $requires_payment
1340
-     * @return bool
1341
-     * @throws EE_Error
1342
-     * @throws InvalidArgumentException
1343
-     * @throws InvalidDataTypeException
1344
-     * @throws InvalidInterfaceException
1345
-     * @throws ReflectionException
1346
-     */
1347
-    public function owes_monies_and_can_pay($requires_payment = array())
1348
-    {
1349
-        // these reg statuses require payment (if event is not free)
1350
-        $requires_payment = ! empty($requires_payment)
1351
-            ? $requires_payment
1352
-            : EEM_Registration::reg_statuses_that_allow_payment();
1353
-        if ($this->final_price() !== 0 &&
1354
-            $this->final_price() !== $this->paid() &&
1355
-            in_array($this->status_ID(), $requires_payment, true)
1356
-        ) {
1357
-            return true;
1358
-        }
1359
-        return false;
1360
-    }
1361
-
1362
-
1363
-    /**
1364
-     * Prints out the return value of $this->pretty_status()
1365
-     *
1366
-     * @param bool $show_icons
1367
-     * @return void
1368
-     * @throws EE_Error
1369
-     * @throws InvalidArgumentException
1370
-     * @throws InvalidDataTypeException
1371
-     * @throws InvalidInterfaceException
1372
-     * @throws ReflectionException
1373
-     */
1374
-    public function e_pretty_status($show_icons = false)
1375
-    {
1376
-        echo $this->pretty_status($show_icons);
1377
-    }
1378
-
1379
-
1380
-    /**
1381
-     * Returns a nice version of the status for displaying to customers
1382
-     *
1383
-     * @param bool $show_icons
1384
-     * @return string
1385
-     * @throws EE_Error
1386
-     * @throws InvalidArgumentException
1387
-     * @throws InvalidDataTypeException
1388
-     * @throws InvalidInterfaceException
1389
-     * @throws ReflectionException
1390
-     */
1391
-    public function pretty_status($show_icons = false)
1392
-    {
1393
-        $status = EEM_Status::instance()->localized_status(
1394
-            array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
1395
-            false,
1396
-            'sentence'
1397
-        );
1398
-        $icon = '';
1399
-        switch ($this->status_ID()) {
1400
-            case EEM_Registration::status_id_approved:
1401
-                $icon = $show_icons
1402
-                    ? '<span class="dashicons dashicons-star-filled ee-icon-size-16 green-text"></span>'
1403
-                    : '';
1404
-                break;
1405
-            case EEM_Registration::status_id_pending_payment:
1406
-                $icon = $show_icons
1407
-                    ? '<span class="dashicons dashicons-star-half ee-icon-size-16 orange-text"></span>'
1408
-                    : '';
1409
-                break;
1410
-            case EEM_Registration::status_id_not_approved:
1411
-                $icon = $show_icons
1412
-                    ? '<span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>'
1413
-                    : '';
1414
-                break;
1415
-            case EEM_Registration::status_id_cancelled:
1416
-                $icon = $show_icons
1417
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
1418
-                    : '';
1419
-                break;
1420
-            case EEM_Registration::status_id_incomplete:
1421
-                $icon = $show_icons
1422
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 lt-orange-text"></span>'
1423
-                    : '';
1424
-                break;
1425
-            case EEM_Registration::status_id_declined:
1426
-                $icon = $show_icons
1427
-                    ? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
1428
-                    : '';
1429
-                break;
1430
-            case EEM_Registration::status_id_wait_list:
1431
-                $icon = $show_icons
1432
-                    ? '<span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>'
1433
-                    : '';
1434
-                break;
1435
-        }
1436
-        return $icon . $status[ $this->status_ID() ];
1437
-    }
1438
-
1439
-
1440
-    /**
1441
-     *        get Attendee Is Going
1442
-     */
1443
-    public function att_is_going()
1444
-    {
1445
-        return $this->get('REG_att_is_going');
1446
-    }
1447
-
1448
-
1449
-    /**
1450
-     * Gets related answers
1451
-     *
1452
-     * @param array $query_params @see
1453
-     *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1454
-     * @return EE_Answer[]|EE_Base_Class[]
1455
-     * @throws EE_Error
1456
-     * @throws InvalidArgumentException
1457
-     * @throws InvalidDataTypeException
1458
-     * @throws InvalidInterfaceException
1459
-     * @throws ReflectionException
1460
-     */
1461
-    public function answers($query_params = null)
1462
-    {
1463
-        return $this->get_many_related('Answer', $query_params);
1464
-    }
1465
-
1466
-
1467
-    /**
1468
-     * Gets the registration's answer value to the specified question
1469
-     * (either the question's ID or a question object)
1470
-     *
1471
-     * @param EE_Question|int $question
1472
-     * @param bool            $pretty_value
1473
-     * @return array|string if pretty_value= true, the result will always be a string
1474
-     * (because the answer might be an array of answer values, so passing pretty_value=true
1475
-     * will convert it into some kind of string)
1476
-     * @throws EE_Error
1477
-     * @throws InvalidArgumentException
1478
-     * @throws InvalidDataTypeException
1479
-     * @throws InvalidInterfaceException
1480
-     */
1481
-    public function answer_value_to_question($question, $pretty_value = true)
1482
-    {
1483
-        $question_id = EEM_Question::instance()->ensure_is_ID($question);
1484
-        return EEM_Answer::instance()->get_answer_value_to_question($this, $question_id, $pretty_value);
1485
-    }
1486
-
1487
-
1488
-    /**
1489
-     * question_groups
1490
-     * returns an array of EE_Question_Group objects for this registration
1491
-     *
1492
-     * @return EE_Question_Group[]
1493
-     * @throws EE_Error
1494
-     * @throws EntityNotFoundException
1495
-     * @throws InvalidArgumentException
1496
-     * @throws InvalidDataTypeException
1497
-     * @throws InvalidInterfaceException
1498
-     * @throws ReflectionException
1499
-     */
1500
-    public function question_groups()
1501
-    {
1502
-        $question_groups = [];
1503
-        if ($this->event() instanceof EE_Event) {
1504
-            $question_groups = $this->event()->question_groups(
1505
-                [
1506
-                    ['Event_Question_Group.EQG_primary' => $this->count() === 1],
1507
-                    'order_by' => ['QSG_order' => 'ASC'],
1508
-                ]
1509
-            );
1510
-        }
1511
-        return $question_groups;
1512
-    }
1513
-
1514
-
1515
-    /**
1516
-     * count_question_groups
1517
-     * returns a count of the number of EE_Question_Group objects for this registration
1518
-     *
1519
-     * @return int
1520
-     * @throws EE_Error
1521
-     * @throws EntityNotFoundException
1522
-     * @throws InvalidArgumentException
1523
-     * @throws InvalidDataTypeException
1524
-     * @throws InvalidInterfaceException
1525
-     * @throws ReflectionException
1526
-     */
1527
-    public function count_question_groups()
1528
-    {
1529
-        $qg_count = 0;
1530
-        if ($this->event() instanceof EE_Event) {
1531
-            $qg_count = $this->event()->count_related(
1532
-                'Question_Group',
1533
-                [
1534
-                    ['Event_Question_Group.EQG_primary' => $this->count() === 1],
1535
-                ]
1536
-            );
1537
-        }
1538
-        return $qg_count;
1539
-    }
1540
-
1541
-
1542
-    /**
1543
-     * Returns the registration date in the 'standard' string format
1544
-     * (function may be improved in the future to allow for different formats and timezones)
1545
-     *
1546
-     * @return string
1547
-     * @throws EE_Error
1548
-     * @throws InvalidArgumentException
1549
-     * @throws InvalidDataTypeException
1550
-     * @throws InvalidInterfaceException
1551
-     * @throws ReflectionException
1552
-     */
1553
-    public function reg_date()
1554
-    {
1555
-        return $this->get_datetime('REG_date');
1556
-    }
1557
-
1558
-
1559
-    /**
1560
-     * Gets the datetime-ticket for this registration (ie, it can be used to isolate
1561
-     * the ticket this registration purchased, or the datetime they have registered
1562
-     * to attend)
1563
-     *
1564
-     * @return EE_Base_Class|EE_Datetime_Ticket
1565
-     * @throws EE_Error
1566
-     * @throws InvalidArgumentException
1567
-     * @throws InvalidDataTypeException
1568
-     * @throws InvalidInterfaceException
1569
-     * @throws ReflectionException
1570
-     */
1571
-    public function datetime_ticket()
1572
-    {
1573
-        return $this->get_first_related('Datetime_Ticket');
1574
-    }
1575
-
1576
-
1577
-    /**
1578
-     * Sets the registration's datetime_ticket.
1579
-     *
1580
-     * @param EE_Datetime_Ticket $datetime_ticket
1581
-     * @return EE_Base_Class|EE_Datetime_Ticket
1582
-     * @throws EE_Error
1583
-     * @throws InvalidArgumentException
1584
-     * @throws InvalidDataTypeException
1585
-     * @throws InvalidInterfaceException
1586
-     * @throws ReflectionException
1587
-     */
1588
-    public function set_datetime_ticket($datetime_ticket)
1589
-    {
1590
-        return $this->_add_relation_to($datetime_ticket, 'Datetime_Ticket');
1591
-    }
1592
-
1593
-
1594
-    /**
1595
-     * Gets deleted
1596
-     *
1597
-     * @return bool
1598
-     * @throws EE_Error
1599
-     * @throws InvalidArgumentException
1600
-     * @throws InvalidDataTypeException
1601
-     * @throws InvalidInterfaceException
1602
-     * @throws ReflectionException
1603
-     */
1604
-    public function deleted()
1605
-    {
1606
-        return $this->get('REG_deleted');
1607
-    }
1608
-
1609
-
1610
-    /**
1611
-     * Sets deleted
1612
-     *
1613
-     * @param boolean $deleted
1614
-     * @return void
1615
-     * @throws DomainException
1616
-     * @throws EE_Error
1617
-     * @throws EntityNotFoundException
1618
-     * @throws InvalidArgumentException
1619
-     * @throws InvalidDataTypeException
1620
-     * @throws InvalidInterfaceException
1621
-     * @throws ReflectionException
1622
-     * @throws RuntimeException
1623
-     * @throws UnexpectedEntityException
1624
-     */
1625
-    public function set_deleted($deleted)
1626
-    {
1627
-        if ($deleted) {
1628
-            $this->delete(__METHOD__);
1629
-        } else {
1630
-            $this->restore(__METHOD__);
1631
-        }
1632
-    }
1633
-
1634
-
1635
-    /**
1636
-     * Get the status object of this object
1637
-     *
1638
-     * @return EE_Base_Class|EE_Status
1639
-     * @throws EE_Error
1640
-     * @throws InvalidArgumentException
1641
-     * @throws InvalidDataTypeException
1642
-     * @throws InvalidInterfaceException
1643
-     * @throws ReflectionException
1644
-     */
1645
-    public function status_obj()
1646
-    {
1647
-        return $this->get_first_related('Status');
1648
-    }
1649
-
1650
-
1651
-    /**
1652
-     * Returns the number of times this registration has checked into any of the datetimes
1653
-     * its available for
1654
-     *
1655
-     * @return int
1656
-     * @throws EE_Error
1657
-     * @throws InvalidArgumentException
1658
-     * @throws InvalidDataTypeException
1659
-     * @throws InvalidInterfaceException
1660
-     * @throws ReflectionException
1661
-     */
1662
-    public function count_checkins()
1663
-    {
1664
-        return $this->get_model()->count_related($this, 'Checkin');
1665
-    }
1666
-
1667
-
1668
-    /**
1669
-     * Returns the number of current Check-ins this registration is checked into for any of the datetimes the
1670
-     * registration is for.  Note, this is ONLY checked in (does not include checkedout)
1671
-     *
1672
-     * @return int
1673
-     * @throws EE_Error
1674
-     * @throws InvalidArgumentException
1675
-     * @throws InvalidDataTypeException
1676
-     * @throws InvalidInterfaceException
1677
-     * @throws ReflectionException
1678
-     */
1679
-    public function count_checkins_not_checkedout()
1680
-    {
1681
-        return $this->get_model()->count_related($this, 'Checkin', array(array('CHK_in' => 1)));
1682
-    }
1683
-
1684
-
1685
-    /**
1686
-     * The purpose of this method is simply to check whether this registration can checkin to the given datetime.
1687
-     *
1688
-     * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1689
-     * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1690
-     *                                          consider registration status as well as datetime access.
1691
-     * @return bool
1692
-     * @throws EE_Error
1693
-     * @throws InvalidArgumentException
1694
-     * @throws InvalidDataTypeException
1695
-     * @throws InvalidInterfaceException
1696
-     * @throws ReflectionException
1697
-     */
1698
-    public function can_checkin($DTT_OR_ID, $check_approved = true)
1699
-    {
1700
-        $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1701
-        // first check registration status
1702
-        if (! $DTT_ID || ($check_approved && ! $this->is_approved())) {
1703
-            return false;
1704
-        }
1705
-        // is there a datetime ticket that matches this dtt_ID?
1706
-        if (! EEM_Datetime_Ticket::instance()->exists(
1707
-            array(
1708
-                array(
1709
-                    'TKT_ID' => $this->get('TKT_ID'),
1710
-                    'DTT_ID' => $DTT_ID,
1711
-                ),
1712
-            )
1713
-        )) {
1714
-            return false;
1715
-        }
1716
-
1717
-        // final check is against TKT_uses
1718
-        return $this->verify_can_checkin_against_TKT_uses($DTT_ID);
1719
-    }
1720
-
1721
-
1722
-    /**
1723
-     * This method verifies whether the user can checkin for the given datetime considering the max uses value set on
1724
-     * the ticket. To do this,  a query is done to get the count of the datetime records already checked into.  If the
1725
-     * datetime given does not have a check-in record and checking in for that datetime will exceed the allowed uses,
1726
-     * then return false.  Otherwise return true.
1727
-     *
1728
-     * @param int | EE_Datetime $DTT_OR_ID The datetime the registration is being checked against
1729
-     * @return bool true means can checkin.  false means cannot checkin.
1730
-     * @throws EE_Error
1731
-     * @throws InvalidArgumentException
1732
-     * @throws InvalidDataTypeException
1733
-     * @throws InvalidInterfaceException
1734
-     * @throws ReflectionException
1735
-     */
1736
-    public function verify_can_checkin_against_TKT_uses($DTT_OR_ID)
1737
-    {
1738
-        $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1739
-
1740
-        if (! $DTT_ID) {
1741
-            return false;
1742
-        }
1743
-
1744
-        $max_uses = $this->ticket() instanceof EE_Ticket ? $this->ticket()->uses() : EE_INF;
1745
-
1746
-        // if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1747
-        // check-in or not.
1748
-        if (! $max_uses || $max_uses === EE_INF) {
1749
-            return true;
1750
-        }
1751
-
1752
-        // does this datetime have a checkin record?  If so, then the dtt count has already been verified so we can just
1753
-        // go ahead and toggle.
1754
-        if (EEM_Checkin::instance()->exists(array(array('REG_ID' => $this->ID(), 'DTT_ID' => $DTT_ID)))) {
1755
-            return true;
1756
-        }
1757
-
1758
-        // made it here so the last check is whether the number of checkins per unique datetime on this registration
1759
-        // disallows further check-ins.
1760
-        $count_unique_dtt_checkins = EEM_Checkin::instance()->count(
1761
-            array(
1762
-                array(
1763
-                    'REG_ID' => $this->ID(),
1764
-                    'CHK_in' => true,
1765
-                ),
1766
-            ),
1767
-            'DTT_ID',
1768
-            true
1769
-        );
1770
-        // checkins have already reached their max number of uses
1771
-        // so registrant can NOT checkin
1772
-        if ($count_unique_dtt_checkins >= $max_uses) {
1773
-            EE_Error::add_error(
1774
-                esc_html__(
1775
-                    'Check-in denied because number of datetime uses for the ticket has been reached or exceeded.',
1776
-                    'event_espresso'
1777
-                ),
1778
-                __FILE__,
1779
-                __FUNCTION__,
1780
-                __LINE__
1781
-            );
1782
-            return false;
1783
-        }
1784
-        return true;
1785
-    }
1786
-
1787
-
1788
-    /**
1789
-     * toggle Check-in status for this registration
1790
-     * Check-ins are toggled in the following order:
1791
-     * never checked in -> checked in
1792
-     * checked in -> checked out
1793
-     * checked out -> checked in
1794
-     *
1795
-     * @param  int $DTT_ID  include specific datetime to toggle Check-in for.
1796
-     *                      If not included or null, then it is assumed latest datetime is being toggled.
1797
-     * @param bool $verify  If true then can_checkin() is used to verify whether the person
1798
-     *                      can be checked in or not.  Otherwise this forces change in checkin status.
1799
-     * @return bool|int     the chk_in status toggled to OR false if nothing got changed.
1800
-     * @throws EE_Error
1801
-     * @throws InvalidArgumentException
1802
-     * @throws InvalidDataTypeException
1803
-     * @throws InvalidInterfaceException
1804
-     * @throws ReflectionException
1805
-     */
1806
-    public function toggle_checkin_status($DTT_ID = null, $verify = false)
1807
-    {
1808
-        if (empty($DTT_ID)) {
1809
-            $datetime = $this->get_latest_related_datetime();
1810
-            $DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1811
-            // verify the registration can checkin for the given DTT_ID
1812
-        } elseif (! $this->can_checkin($DTT_ID, $verify)) {
1813
-            EE_Error::add_error(
1814
-                sprintf(
1815
-                    esc_html__(
1816
-                        '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',
1817
-                        'event_espresso'
1818
-                    ),
1819
-                    $this->ID(),
1820
-                    $DTT_ID
1821
-                ),
1822
-                __FILE__,
1823
-                __FUNCTION__,
1824
-                __LINE__
1825
-            );
1826
-            return false;
1827
-        }
1828
-        $status_paths = array(
1829
-            EE_Checkin::status_checked_never => EE_Checkin::status_checked_in,
1830
-            EE_Checkin::status_checked_in    => EE_Checkin::status_checked_out,
1831
-            EE_Checkin::status_checked_out   => EE_Checkin::status_checked_in,
1832
-        );
1833
-        // start by getting the current status so we know what status we'll be changing to.
1834
-        $cur_status = $this->check_in_status_for_datetime($DTT_ID);
1835
-        $status_to = $status_paths[ $cur_status ];
1836
-        // database only records true for checked IN or false for checked OUT
1837
-        // no record ( null ) means checked in NEVER, but we obviously don't save that
1838
-        $new_status = $status_to === EE_Checkin::status_checked_in;
1839
-        // add relation - note Check-ins are always creating new rows
1840
-        // because we are keeping track of Check-ins over time.
1841
-        // Eventually we'll probably want to show a list table
1842
-        // for the individual Check-ins so that they can be managed.
1843
-        $checkin = EE_Checkin::new_instance(
1844
-            array(
1845
-                'REG_ID' => $this->ID(),
1846
-                'DTT_ID' => $DTT_ID,
1847
-                'CHK_in' => $new_status,
1848
-            )
1849
-        );
1850
-        // if the record could not be saved then return false
1851
-        if ($checkin->save() === 0) {
1852
-            if (WP_DEBUG) {
1853
-                global $wpdb;
1854
-                $error = sprintf(
1855
-                    esc_html__(
1856
-                        'Registration check in update failed because of the following database error: %1$s%2$s',
1857
-                        'event_espresso'
1858
-                    ),
1859
-                    '<br />',
1860
-                    $wpdb->last_error
1861
-                );
1862
-            } else {
1863
-                $error = esc_html__(
1864
-                    'Registration check in update failed because of an unknown database error',
1865
-                    'event_espresso'
1866
-                );
1867
-            }
1868
-            EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
1869
-            return false;
1870
-        }
1871
-        return $status_to;
1872
-    }
1873
-
1874
-
1875
-    /**
1876
-     * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1877
-     * "Latest" is defined by the `DTT_EVT_start` column.
1878
-     *
1879
-     * @return EE_Datetime|null
1880
-     * @throws EE_Error
1881
-     * @throws InvalidArgumentException
1882
-     * @throws InvalidDataTypeException
1883
-     * @throws InvalidInterfaceException
1884
-     * @throws ReflectionException
1885
-     */
1886
-    public function get_latest_related_datetime()
1887
-    {
1888
-        return EEM_Datetime::instance()->get_one(
1889
-            array(
1890
-                array(
1891
-                    'Ticket.Registration.REG_ID' => $this->ID(),
1892
-                ),
1893
-                'order_by' => array('DTT_EVT_start' => 'DESC'),
1894
-            )
1895
-        );
1896
-    }
1897
-
1898
-
1899
-    /**
1900
-     * Returns the earliest datetime related to this registration (via the ticket attached to the registration).
1901
-     * "Earliest" is defined by the `DTT_EVT_start` column.
1902
-     *
1903
-     * @return EE_Base_Class|EE_Soft_Delete_Base_Class|NULL
1904
-     * @throws EE_Error
1905
-     * @throws InvalidArgumentException
1906
-     * @throws InvalidDataTypeException
1907
-     * @throws InvalidInterfaceException
1908
-     * @throws ReflectionException
1909
-     */
1910
-    public function get_earliest_related_datetime()
1911
-    {
1912
-        return EEM_Datetime::instance()->get_one(
1913
-            array(
1914
-                array(
1915
-                    'Ticket.Registration.REG_ID' => $this->ID(),
1916
-                ),
1917
-                'order_by' => array('DTT_EVT_start' => 'ASC'),
1918
-            )
1919
-        );
1920
-    }
1921
-
1922
-
1923
-    /**
1924
-     * This method simply returns the check-in status for this registration and the given datetime.
1925
-     * If neither the datetime nor the checkin values are provided as arguments,
1926
-     * then this will return the LATEST check-in status for the registration across all datetimes it belongs to.
1927
-     *
1928
-     * @param  int       $DTT_ID  The ID of the datetime we're checking against
1929
-     *                            (if empty we'll get the primary datetime for
1930
-     *                            this registration (via event) and use it's ID);
1931
-     * @param EE_Checkin $checkin If present, we use the given checkin object rather than the dtt_id.
1932
-     * @return int                Integer representing Check-in status.
1933
-     * @throws EE_Error
1934
-     * @throws InvalidArgumentException
1935
-     * @throws InvalidDataTypeException
1936
-     * @throws InvalidInterfaceException
1937
-     * @throws ReflectionException
1938
-     */
1939
-    public function check_in_status_for_datetime($DTT_ID = 0, $checkin = null)
1940
-    {
1941
-        $checkin_query_params = array(
1942
-            'order_by' => array('CHK_timestamp' => 'DESC'),
1943
-        );
1944
-
1945
-        if ($DTT_ID > 0) {
1946
-            $checkin_query_params[0] = array('DTT_ID' => $DTT_ID);
1947
-        }
1948
-
1949
-        // get checkin object (if exists)
1950
-        $checkin = $checkin instanceof EE_Checkin
1951
-            ? $checkin
1952
-            : $this->get_first_related('Checkin', $checkin_query_params);
1953
-        if ($checkin instanceof EE_Checkin) {
1954
-            if ($checkin->get('CHK_in')) {
1955
-                return EE_Checkin::status_checked_in; // checked in
1956
-            }
1957
-            return EE_Checkin::status_checked_out; // had checked in but is now checked out.
1958
-        }
1959
-        return EE_Checkin::status_checked_never; // never been checked in
1960
-    }
1961
-
1962
-
1963
-    /**
1964
-     * This method returns a localized message for the toggled Check-in message.
1965
-     *
1966
-     * @param  int $DTT_ID include specific datetime to get the correct Check-in message.  If not included or null,
1967
-     *                     then it is assumed Check-in for primary datetime was toggled.
1968
-     * @param bool $error  This just flags that you want an error message returned. This is put in so that the error
1969
-     *                     message can be customized with the attendee name.
1970
-     * @return string internationalized message
1971
-     * @throws EE_Error
1972
-     * @throws InvalidArgumentException
1973
-     * @throws InvalidDataTypeException
1974
-     * @throws InvalidInterfaceException
1975
-     * @throws ReflectionException
1976
-     */
1977
-    public function get_checkin_msg($DTT_ID, $error = false)
1978
-    {
1979
-        // let's get the attendee first so we can include the name of the attendee
1980
-        $attendee = $this->get_first_related('Attendee');
1981
-        if ($attendee instanceof EE_Attendee) {
1982
-            if ($error) {
1983
-                return sprintf(__("%s's check-in status was not changed.", 'event_espresso'), $attendee->full_name());
1984
-            }
1985
-            $cur_status = $this->check_in_status_for_datetime($DTT_ID);
1986
-            // what is the status message going to be?
1987
-            switch ($cur_status) {
1988
-                case EE_Checkin::status_checked_never:
1989
-                    return sprintf(
1990
-                        esc_html__('%s has been removed from Check-in records', 'event_espresso'),
1991
-                        $attendee->full_name()
1992
-                    );
1993
-                    break;
1994
-                case EE_Checkin::status_checked_in:
1995
-                    return sprintf(__('%s has been checked in', 'event_espresso'), $attendee->full_name());
1996
-                    break;
1997
-                case EE_Checkin::status_checked_out:
1998
-                    return sprintf(__('%s has been checked out', 'event_espresso'), $attendee->full_name());
1999
-                    break;
2000
-            }
2001
-        }
2002
-        return esc_html__('The check-in status could not be determined.', 'event_espresso');
2003
-    }
2004
-
2005
-
2006
-    /**
2007
-     * Returns the related EE_Transaction to this registration
2008
-     *
2009
-     * @return EE_Transaction
2010
-     * @throws EE_Error
2011
-     * @throws EntityNotFoundException
2012
-     * @throws InvalidArgumentException
2013
-     * @throws InvalidDataTypeException
2014
-     * @throws InvalidInterfaceException
2015
-     * @throws ReflectionException
2016
-     */
2017
-    public function transaction()
2018
-    {
2019
-        $transaction = $this->get_first_related('Transaction');
2020
-        if (! $transaction instanceof \EE_Transaction) {
2021
-            throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
2022
-        }
2023
-        return $transaction;
2024
-    }
2025
-
2026
-
2027
-    /**
2028
-     * get Registration Code
2029
-     *
2030
-     * @return mixed
2031
-     * @throws EE_Error
2032
-     * @throws InvalidArgumentException
2033
-     * @throws InvalidDataTypeException
2034
-     * @throws InvalidInterfaceException
2035
-     * @throws ReflectionException
2036
-     */
2037
-    public function reg_code()
2038
-    {
2039
-        return $this->get('REG_code');
2040
-    }
2041
-
2042
-
2043
-    /**
2044
-     * @return mixed
2045
-     * @throws EE_Error
2046
-     * @throws InvalidArgumentException
2047
-     * @throws InvalidDataTypeException
2048
-     * @throws InvalidInterfaceException
2049
-     * @throws ReflectionException
2050
-     */
2051
-    public function transaction_ID()
2052
-    {
2053
-        return $this->get('TXN_ID');
2054
-    }
2055
-
2056
-
2057
-    /**
2058
-     * @return int
2059
-     * @throws EE_Error
2060
-     * @throws InvalidArgumentException
2061
-     * @throws InvalidDataTypeException
2062
-     * @throws InvalidInterfaceException
2063
-     * @throws ReflectionException
2064
-     */
2065
-    public function ticket_ID()
2066
-    {
2067
-        return $this->get('TKT_ID');
2068
-    }
2069
-
2070
-
2071
-    /**
2072
-     * Set Registration Code
2073
-     *
2074
-     * @param    string  $REG_code Registration Code
2075
-     * @param    boolean $use_default
2076
-     * @throws EE_Error
2077
-     * @throws InvalidArgumentException
2078
-     * @throws InvalidDataTypeException
2079
-     * @throws InvalidInterfaceException
2080
-     * @throws ReflectionException
2081
-     */
2082
-    public function set_reg_code($REG_code, $use_default = false)
2083
-    {
2084
-        if (empty($REG_code)) {
2085
-            EE_Error::add_error(
2086
-                esc_html__('REG_code can not be empty.', 'event_espresso'),
2087
-                __FILE__,
2088
-                __FUNCTION__,
2089
-                __LINE__
2090
-            );
2091
-            return;
2092
-        }
2093
-        if (! $this->reg_code()) {
2094
-            parent::set('REG_code', $REG_code, $use_default);
2095
-        } else {
2096
-            EE_Error::doing_it_wrong(
2097
-                __CLASS__ . '::' . __FUNCTION__,
2098
-                esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
2099
-                '4.6.0'
2100
-            );
2101
-        }
2102
-    }
2103
-
2104
-
2105
-    /**
2106
-     * Returns all other registrations in the same group as this registrant who have the same ticket option.
2107
-     * Note, if you want to just get all registrations in the same transaction (group), use:
2108
-     *    $registration->transaction()->registrations();
2109
-     *
2110
-     * @since 4.5.0
2111
-     * @return EE_Registration[] or empty array if this isn't a group registration.
2112
-     * @throws EE_Error
2113
-     * @throws InvalidArgumentException
2114
-     * @throws InvalidDataTypeException
2115
-     * @throws InvalidInterfaceException
2116
-     * @throws ReflectionException
2117
-     */
2118
-    public function get_all_other_registrations_in_group()
2119
-    {
2120
-        if ($this->group_size() < 2) {
2121
-            return array();
2122
-        }
2123
-
2124
-        $query[0] = array(
2125
-            'TXN_ID' => $this->transaction_ID(),
2126
-            'REG_ID' => array('!=', $this->ID()),
2127
-            'TKT_ID' => $this->ticket_ID(),
2128
-        );
2129
-        /** @var EE_Registration[] $registrations */
2130
-        $registrations = $this->get_model()->get_all($query);
2131
-        return $registrations;
2132
-    }
2133
-
2134
-
2135
-    /**
2136
-     * Return the link to the admin details for the object.
2137
-     *
2138
-     * @return string
2139
-     * @throws EE_Error
2140
-     * @throws InvalidArgumentException
2141
-     * @throws InvalidDataTypeException
2142
-     * @throws InvalidInterfaceException
2143
-     * @throws ReflectionException
2144
-     */
2145
-    public function get_admin_details_link()
2146
-    {
2147
-        EE_Registry::instance()->load_helper('URL');
2148
-        return EEH_URL::add_query_args_and_nonce(
2149
-            array(
2150
-                'page'    => 'espresso_registrations',
2151
-                'action'  => 'view_registration',
2152
-                '_REG_ID' => $this->ID(),
2153
-            ),
2154
-            admin_url('admin.php')
2155
-        );
2156
-    }
2157
-
2158
-
2159
-    /**
2160
-     * Returns the link to the editor for the object.  Sometimes this is the same as the details.
2161
-     *
2162
-     * @return string
2163
-     * @throws EE_Error
2164
-     * @throws InvalidArgumentException
2165
-     * @throws InvalidDataTypeException
2166
-     * @throws InvalidInterfaceException
2167
-     * @throws ReflectionException
2168
-     */
2169
-    public function get_admin_edit_link()
2170
-    {
2171
-        return $this->get_admin_details_link();
2172
-    }
2173
-
2174
-
2175
-    /**
2176
-     * Returns the link to a settings page for the object.
2177
-     *
2178
-     * @return string
2179
-     * @throws EE_Error
2180
-     * @throws InvalidArgumentException
2181
-     * @throws InvalidDataTypeException
2182
-     * @throws InvalidInterfaceException
2183
-     * @throws ReflectionException
2184
-     */
2185
-    public function get_admin_settings_link()
2186
-    {
2187
-        return $this->get_admin_details_link();
2188
-    }
2189
-
2190
-
2191
-    /**
2192
-     * Returns the link to the "overview" for the object (typically the "list table" view).
2193
-     *
2194
-     * @return string
2195
-     * @throws EE_Error
2196
-     * @throws InvalidArgumentException
2197
-     * @throws InvalidDataTypeException
2198
-     * @throws InvalidInterfaceException
2199
-     * @throws ReflectionException
2200
-     */
2201
-    public function get_admin_overview_link()
2202
-    {
2203
-        EE_Registry::instance()->load_helper('URL');
2204
-        return EEH_URL::add_query_args_and_nonce(
2205
-            array(
2206
-                'page' => 'espresso_registrations',
2207
-            ),
2208
-            admin_url('admin.php')
2209
-        );
2210
-    }
2211
-
2212
-
2213
-    /**
2214
-     * @param array $query_params
2215
-     * @return EE_Base_Class[]|EE_Registration[]
2216
-     * @throws EE_Error
2217
-     * @throws InvalidArgumentException
2218
-     * @throws InvalidDataTypeException
2219
-     * @throws InvalidInterfaceException
2220
-     * @throws ReflectionException
2221
-     */
2222
-    public function payments($query_params = array())
2223
-    {
2224
-        return $this->get_many_related('Payment', $query_params);
2225
-    }
2226
-
2227
-
2228
-    /**
2229
-     * @param array $query_params
2230
-     * @return EE_Base_Class[]|EE_Registration_Payment[]
2231
-     * @throws EE_Error
2232
-     * @throws InvalidArgumentException
2233
-     * @throws InvalidDataTypeException
2234
-     * @throws InvalidInterfaceException
2235
-     * @throws ReflectionException
2236
-     */
2237
-    public function registration_payments($query_params = array())
2238
-    {
2239
-        return $this->get_many_related('Registration_Payment', $query_params);
2240
-    }
2241
-
2242
-
2243
-    /**
2244
-     * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
2245
-     * Note: if there are no payments on the registration there will be no payment method returned.
2246
-     *
2247
-     * @return EE_Payment|EE_Payment_Method|null
2248
-     * @throws EE_Error
2249
-     * @throws InvalidArgumentException
2250
-     * @throws InvalidDataTypeException
2251
-     * @throws InvalidInterfaceException
2252
-     */
2253
-    public function payment_method()
2254
-    {
2255
-        return EEM_Payment_Method::instance()->get_last_used_for_registration($this);
2256
-    }
2257
-
2258
-
2259
-    /**
2260
-     * @return \EE_Line_Item
2261
-     * @throws EE_Error
2262
-     * @throws EntityNotFoundException
2263
-     * @throws InvalidArgumentException
2264
-     * @throws InvalidDataTypeException
2265
-     * @throws InvalidInterfaceException
2266
-     * @throws ReflectionException
2267
-     */
2268
-    public function ticket_line_item()
2269
-    {
2270
-        $ticket = $this->ticket();
2271
-        $transaction = $this->transaction();
2272
-        $line_item = null;
2273
-        $ticket_line_items = \EEH_Line_Item::get_line_items_by_object_type_and_IDs(
2274
-            $transaction->total_line_item(),
2275
-            'Ticket',
2276
-            array($ticket->ID())
2277
-        );
2278
-        foreach ($ticket_line_items as $ticket_line_item) {
2279
-            if ($ticket_line_item instanceof \EE_Line_Item
2280
-                && $ticket_line_item->OBJ_type() === 'Ticket'
2281
-                && $ticket_line_item->OBJ_ID() === $ticket->ID()
2282
-            ) {
2283
-                $line_item = $ticket_line_item;
2284
-                break;
2285
-            }
2286
-        }
2287
-        if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
2288
-            throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
2289
-        }
2290
-        return $line_item;
2291
-    }
2292
-
2293
-
2294
-    /**
2295
-     * Soft Deletes this model object.
2296
-     *
2297
-     * @param string $source function name that called this method
2298
-     * @return boolean | int
2299
-     * @throws DomainException
2300
-     * @throws EE_Error
2301
-     * @throws EntityNotFoundException
2302
-     * @throws InvalidArgumentException
2303
-     * @throws InvalidDataTypeException
2304
-     * @throws InvalidInterfaceException
2305
-     * @throws ReflectionException
2306
-     * @throws RuntimeException
2307
-     * @throws UnexpectedEntityException
2308
-     */
2309
-    public function delete($source = 'unknown')
2310
-    {
2311
-        if ($this->update_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY, $this->status_ID()) === true) {
2312
-            $current_user = wp_get_current_user();
2313
-            $this->add_extra_meta(
2314
-                EE_Registration::EXTRA_META_KEY_REG_TRASHED,
2315
-                array(
2316
-                    'trashed-by' => $current_user->ID ? $current_user->display_name : 'unauthed user',
2317
-                    'timestamp'  => time(),
2318
-                    'source'     => $source,
2319
-                )
2320
-            );
2321
-            $this->set_status(EEM_Registration::status_id_cancelled);
2322
-        }
2323
-        return parent::delete();
2324
-    }
2325
-
2326
-
2327
-    /**
2328
-     * Restores whatever the previous status was on a registration before it was trashed (if possible)
2329
-     *
2330
-     * @param string $source function name that called this method
2331
-     * @return bool|int
2332
-     * @throws DomainException
2333
-     * @throws EE_Error
2334
-     * @throws EntityNotFoundException
2335
-     * @throws InvalidArgumentException
2336
-     * @throws InvalidDataTypeException
2337
-     * @throws InvalidInterfaceException
2338
-     * @throws ReflectionException
2339
-     * @throws RuntimeException
2340
-     * @throws UnexpectedEntityException
2341
-     */
2342
-    public function restore($source = 'unknown')
2343
-    {
2344
-        $previous_status = $this->get_extra_meta(
2345
-            EE_Registration::PRE_TRASH_REG_STATUS_KEY,
2346
-            true,
2347
-            EEM_Registration::status_id_cancelled
2348
-        );
2349
-        if ($previous_status) {
2350
-            $this->delete_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY);
2351
-            $this->set_status($previous_status);
2352
-        }
2353
-        $current_user = wp_get_current_user();
2354
-        $this->add_extra_meta(
2355
-            EE_Registration::EXTRA_META_KEY_REG_RESTORED,
2356
-            array(
2357
-                'restored-by' => $current_user->ID ? $current_user->display_name : 'unauthed user',
2358
-                'timestamp'   => time(),
2359
-                'source'      => $source,
2360
-            )
2361
-        );
2362
-        return parent::restore();
2363
-    }
2364
-
2365
-
2366
-    /**
2367
-     * possibly toggle Registration status based on comparison of REG_paid vs REG_final_price
2368
-     *
2369
-     * @param  boolean $trigger_set_status_logic EE_Registration::set_status() can trigger additional logic
2370
-     *                                           depending on whether the reg status changes to or from "Approved"
2371
-     * @return boolean whether the Registration status was updated
2372
-     * @throws DomainException
2373
-     * @throws EE_Error
2374
-     * @throws EntityNotFoundException
2375
-     * @throws InvalidArgumentException
2376
-     * @throws InvalidDataTypeException
2377
-     * @throws InvalidInterfaceException
2378
-     * @throws ReflectionException
2379
-     * @throws RuntimeException
2380
-     * @throws UnexpectedEntityException
2381
-     */
2382
-    public function updateStatusBasedOnTotalPaid($trigger_set_status_logic = true)
2383
-    {
2384
-        $paid = $this->paid();
2385
-        $price = $this->final_price();
2386
-        switch (true) {
2387
-            // overpaid or paid
2388
-            case EEH_Money::compare_floats($paid, $price, '>'):
2389
-            case EEH_Money::compare_floats($paid, $price):
2390
-                $new_status = EEM_Registration::status_id_approved;
2391
-                break;
2392
-            //  underpaid
2393
-            case EEH_Money::compare_floats($paid, $price, '<'):
2394
-                $new_status = EEM_Registration::status_id_pending_payment;
2395
-                break;
2396
-            // uhhh Houston...
2397
-            default:
2398
-                throw new RuntimeException(
2399
-                    esc_html__('The total paid calculation for this registration is inaccurate.', 'event_espresso')
2400
-                );
2401
-        }
2402
-        if ($new_status !== $this->status_ID()) {
2403
-            if ($trigger_set_status_logic) {
2404
-                return $this->set_status($new_status);
2405
-            }
2406
-            parent::set('STS_ID', $new_status);
2407
-            return true;
2408
-        }
2409
-        return false;
2410
-    }
2411
-
2412
-
2413
-    /*************************** DEPRECATED ***************************/
2414
-
2415
-
2416
-    /**
2417
-     * @deprecated
2418
-     * @since     4.7.0
2419
-     */
2420
-    public function price_paid()
2421
-    {
2422
-        EE_Error::doing_it_wrong(
2423
-            'EE_Registration::price_paid()',
2424
-            esc_html__(
2425
-                'This method is deprecated, please use EE_Registration::final_price() instead.',
2426
-                'event_espresso'
2427
-            ),
2428
-            '4.7.0'
2429
-        );
2430
-        return $this->final_price();
2431
-    }
2432
-
2433
-
2434
-    /**
2435
-     * @deprecated
2436
-     * @since     4.7.0
2437
-     * @param    float $REG_final_price
2438
-     * @throws EE_Error
2439
-     * @throws EntityNotFoundException
2440
-     * @throws InvalidArgumentException
2441
-     * @throws InvalidDataTypeException
2442
-     * @throws InvalidInterfaceException
2443
-     * @throws ReflectionException
2444
-     * @throws RuntimeException
2445
-     * @throws DomainException
2446
-     */
2447
-    public function set_price_paid($REG_final_price = 0.00)
2448
-    {
2449
-        EE_Error::doing_it_wrong(
2450
-            'EE_Registration::set_price_paid()',
2451
-            esc_html__(
2452
-                'This method is deprecated, please use EE_Registration::set_final_price() instead.',
2453
-                'event_espresso'
2454
-            ),
2455
-            '4.7.0'
2456
-        );
2457
-        $this->set_final_price($REG_final_price);
2458
-    }
2459
-
2460
-
2461
-    /**
2462
-     * @deprecated
2463
-     * @since 4.7.0
2464
-     * @return string
2465
-     * @throws EE_Error
2466
-     * @throws InvalidArgumentException
2467
-     * @throws InvalidDataTypeException
2468
-     * @throws InvalidInterfaceException
2469
-     * @throws ReflectionException
2470
-     */
2471
-    public function pretty_price_paid()
2472
-    {
2473
-        EE_Error::doing_it_wrong(
2474
-            'EE_Registration::pretty_price_paid()',
2475
-            esc_html__(
2476
-                'This method is deprecated, please use EE_Registration::pretty_final_price() instead.',
2477
-                'event_espresso'
2478
-            ),
2479
-            '4.7.0'
2480
-        );
2481
-        return $this->pretty_final_price();
2482
-    }
2483
-
2484
-
2485
-    /**
2486
-     * Gets the primary datetime related to this registration via the related Event to this registration
2487
-     *
2488
-     * @deprecated 4.9.17
2489
-     * @return EE_Datetime
2490
-     * @throws EE_Error
2491
-     * @throws EntityNotFoundException
2492
-     * @throws InvalidArgumentException
2493
-     * @throws InvalidDataTypeException
2494
-     * @throws InvalidInterfaceException
2495
-     * @throws ReflectionException
2496
-     */
2497
-    public function get_related_primary_datetime()
2498
-    {
2499
-        EE_Error::doing_it_wrong(
2500
-            __METHOD__,
2501
-            esc_html__(
2502
-                'Use EE_Registration::get_latest_related_datetime() or EE_Registration::get_earliest_related_datetime()',
2503
-                'event_espresso'
2504
-            ),
2505
-            '4.9.17',
2506
-            '5.0.0'
2507
-        );
2508
-        return $this->event()->primary_datetime();
2509
-    }
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
+			// TO approved
194
+			if ($new_STS_ID === EEM_Registration::status_id_approved) {
195
+				// reserve a space by incrementing ticket and datetime sold values
196
+				$this->_reserve_registration_space();
197
+				do_action('AHEE__EE_Registration__set_status__to_approved', $this, $old_STS_ID, $new_STS_ID, $context);
198
+				// OR FROM  approved
199
+			} elseif ($old_STS_ID === EEM_Registration::status_id_approved) {
200
+				// release a space by decrementing ticket and datetime sold values
201
+				$this->_release_registration_space();
202
+				do_action(
203
+					'AHEE__EE_Registration__set_status__from_approved',
204
+					$this,
205
+					$old_STS_ID,
206
+					$new_STS_ID,
207
+					$context
208
+				);
209
+			}
210
+			// update status
211
+			parent::set('STS_ID', $new_STS_ID, $use_default);
212
+			$this->_update_if_canceled_or_declined($new_STS_ID, $old_STS_ID, $context);
213
+			if ($this->statusChangeUpdatesTransaction($context)) {
214
+				$this->updateTransactionAfterStatusChange();
215
+			}
216
+			do_action('AHEE__EE_Registration__set_status__after_update', $this, $old_STS_ID, $new_STS_ID, $context);
217
+			return true;
218
+		}
219
+		// even though the old value matches the new value, it's still good to
220
+		// allow the parent set method to have a say
221
+		parent::set('STS_ID', $new_STS_ID, $use_default);
222
+		return true;
223
+	}
224
+
225
+
226
+	/**
227
+	 * update REGs and TXN when cancelled or declined registrations involved
228
+	 *
229
+	 * @param string                $new_STS_ID
230
+	 * @param string                $old_STS_ID
231
+	 * @param ContextInterface|null $context
232
+	 * @throws EE_Error
233
+	 * @throws InvalidArgumentException
234
+	 * @throws InvalidDataTypeException
235
+	 * @throws InvalidInterfaceException
236
+	 * @throws ReflectionException
237
+	 * @throws RuntimeException
238
+	 */
239
+	private function _update_if_canceled_or_declined($new_STS_ID, $old_STS_ID, ContextInterface $context = null)
240
+	{
241
+		// these reg statuses should not be considered in any calculations involving monies owing
242
+		$closed_reg_statuses = EEM_Registration::closed_reg_statuses();
243
+		// true if registration has been cancelled or declined
244
+		$this->updateIfCanceled(
245
+			$closed_reg_statuses,
246
+			$new_STS_ID,
247
+			$old_STS_ID,
248
+			$context
249
+		);
250
+		$this->updateIfDeclined(
251
+			$closed_reg_statuses,
252
+			$new_STS_ID,
253
+			$old_STS_ID,
254
+			$context
255
+		);
256
+	}
257
+
258
+
259
+	/**
260
+	 * update REGs and TXN when cancelled or declined registrations involved
261
+	 *
262
+	 * @param array                 $closed_reg_statuses
263
+	 * @param string                $new_STS_ID
264
+	 * @param string                $old_STS_ID
265
+	 * @param ContextInterface|null $context
266
+	 * @throws EE_Error
267
+	 * @throws InvalidArgumentException
268
+	 * @throws InvalidDataTypeException
269
+	 * @throws InvalidInterfaceException
270
+	 * @throws ReflectionException
271
+	 * @throws RuntimeException
272
+	 */
273
+	private function updateIfCanceled(
274
+		array $closed_reg_statuses,
275
+		$new_STS_ID,
276
+		$old_STS_ID,
277
+		ContextInterface $context = null
278
+	) {
279
+		// true if registration has been cancelled or declined
280
+		if (in_array($new_STS_ID, $closed_reg_statuses, true)
281
+			&& ! in_array($old_STS_ID, $closed_reg_statuses, true)
282
+		) {
283
+			/** @type EE_Registration_Processor $registration_processor */
284
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
285
+			/** @type EE_Transaction_Processor $transaction_processor */
286
+			$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
287
+			// cancelled or declined registration
288
+			$registration_processor->update_registration_after_being_canceled_or_declined(
289
+				$this,
290
+				$closed_reg_statuses
291
+			);
292
+			$transaction_processor->update_transaction_after_canceled_or_declined_registration(
293
+				$this,
294
+				$closed_reg_statuses,
295
+				false
296
+			);
297
+			do_action(
298
+				'AHEE__EE_Registration__set_status__canceled_or_declined',
299
+				$this,
300
+				$old_STS_ID,
301
+				$new_STS_ID,
302
+				$context
303
+			);
304
+			return;
305
+		}
306
+	}
307
+
308
+
309
+	/**
310
+	 * update REGs and TXN when cancelled or declined registrations involved
311
+	 *
312
+	 * @param array                 $closed_reg_statuses
313
+	 * @param string                $new_STS_ID
314
+	 * @param string                $old_STS_ID
315
+	 * @param ContextInterface|null $context
316
+	 * @throws EE_Error
317
+	 * @throws InvalidArgumentException
318
+	 * @throws InvalidDataTypeException
319
+	 * @throws InvalidInterfaceException
320
+	 * @throws ReflectionException
321
+	 * @throws RuntimeException
322
+	 */
323
+	private function updateIfDeclined(
324
+		array $closed_reg_statuses,
325
+		$new_STS_ID,
326
+		$old_STS_ID,
327
+		ContextInterface $context = null
328
+	) {
329
+		// true if reinstating cancelled or declined registration
330
+		if (in_array($old_STS_ID, $closed_reg_statuses, true)
331
+			&& ! in_array($new_STS_ID, $closed_reg_statuses, true)
332
+		) {
333
+			/** @type EE_Registration_Processor $registration_processor */
334
+			$registration_processor = EE_Registry::instance()->load_class('Registration_Processor');
335
+			/** @type EE_Transaction_Processor $transaction_processor */
336
+			$transaction_processor = EE_Registry::instance()->load_class('Transaction_Processor');
337
+			// reinstating cancelled or declined registration
338
+			$registration_processor->update_canceled_or_declined_registration_after_being_reinstated(
339
+				$this,
340
+				$closed_reg_statuses
341
+			);
342
+			$transaction_processor->update_transaction_after_reinstating_canceled_registration(
343
+				$this,
344
+				$closed_reg_statuses,
345
+				false
346
+			);
347
+			do_action(
348
+				'AHEE__EE_Registration__set_status__after_reinstated',
349
+				$this,
350
+				$old_STS_ID,
351
+				$new_STS_ID,
352
+				$context
353
+			);
354
+		}
355
+	}
356
+
357
+
358
+	/**
359
+	 * @param ContextInterface|null $context
360
+	 * @return bool
361
+	 */
362
+	private function statusChangeUpdatesTransaction(ContextInterface $context = null)
363
+	{
364
+		$contexts_that_do_not_update_transaction = (array) apply_filters(
365
+			'AHEE__EE_Registration__statusChangeUpdatesTransaction__contexts_that_do_not_update_transaction',
366
+			array('spco_reg_step_attendee_information_process_registrations'),
367
+			$context,
368
+			$this
369
+		);
370
+		return ! (
371
+			$context instanceof ContextInterface
372
+			&& in_array($context->slug(), $contexts_that_do_not_update_transaction, true)
373
+		);
374
+	}
375
+
376
+
377
+	/**
378
+	 * @throws EE_Error
379
+	 * @throws EntityNotFoundException
380
+	 * @throws InvalidArgumentException
381
+	 * @throws InvalidDataTypeException
382
+	 * @throws InvalidInterfaceException
383
+	 * @throws ReflectionException
384
+	 * @throws RuntimeException
385
+	 */
386
+	private function updateTransactionAfterStatusChange()
387
+	{
388
+		/** @type EE_Transaction_Payments $transaction_payments */
389
+		$transaction_payments = EE_Registry::instance()->load_class('Transaction_Payments');
390
+		$transaction_payments->recalculate_transaction_total($this->transaction(), false);
391
+		$this->transaction()->update_status_based_on_total_paid();
392
+	}
393
+
394
+
395
+	/**
396
+	 * get Status ID
397
+	 *
398
+	 * @throws EE_Error
399
+	 * @throws InvalidArgumentException
400
+	 * @throws InvalidDataTypeException
401
+	 * @throws InvalidInterfaceException
402
+	 * @throws ReflectionException
403
+	 */
404
+	public function status_ID()
405
+	{
406
+		return $this->get('STS_ID');
407
+	}
408
+
409
+
410
+	/**
411
+	 * Gets the ticket this registration is for
412
+	 *
413
+	 * @param boolean $include_archived whether to include archived tickets or not.
414
+	 * @return EE_Ticket|EE_Base_Class
415
+	 * @throws EE_Error
416
+	 * @throws InvalidArgumentException
417
+	 * @throws InvalidDataTypeException
418
+	 * @throws InvalidInterfaceException
419
+	 * @throws ReflectionException
420
+	 */
421
+	public function ticket($include_archived = true)
422
+	{
423
+		$query_params = array();
424
+		if ($include_archived) {
425
+			$query_params['default_where_conditions'] = 'none';
426
+		}
427
+		return $this->get_first_related('Ticket', $query_params);
428
+	}
429
+
430
+
431
+	/**
432
+	 * Gets the event this registration is for
433
+	 *
434
+	 * @return EE_Event
435
+	 * @throws EE_Error
436
+	 * @throws EntityNotFoundException
437
+	 * @throws InvalidArgumentException
438
+	 * @throws InvalidDataTypeException
439
+	 * @throws InvalidInterfaceException
440
+	 * @throws ReflectionException
441
+	 */
442
+	public function event()
443
+	{
444
+		$event = $this->get_first_related('Event');
445
+		if (! $event instanceof \EE_Event) {
446
+			throw new EntityNotFoundException('Event ID', $this->event_ID());
447
+		}
448
+		return $event;
449
+	}
450
+
451
+
452
+	/**
453
+	 * Gets the "author" of the registration.  Note that for the purposes of registrations, the author will correspond
454
+	 * with the author of the event this registration is for.
455
+	 *
456
+	 * @since 4.5.0
457
+	 * @return int
458
+	 * @throws EE_Error
459
+	 * @throws EntityNotFoundException
460
+	 * @throws InvalidArgumentException
461
+	 * @throws InvalidDataTypeException
462
+	 * @throws InvalidInterfaceException
463
+	 * @throws ReflectionException
464
+	 */
465
+	public function wp_user()
466
+	{
467
+		$event = $this->event();
468
+		if ($event instanceof EE_Event) {
469
+			return $event->wp_user();
470
+		}
471
+		return 0;
472
+	}
473
+
474
+
475
+	/**
476
+	 * increments this registration's related ticket sold and corresponding datetime sold values
477
+	 *
478
+	 * @return void
479
+	 * @throws DomainException
480
+	 * @throws EE_Error
481
+	 * @throws EntityNotFoundException
482
+	 * @throws InvalidArgumentException
483
+	 * @throws InvalidDataTypeException
484
+	 * @throws InvalidInterfaceException
485
+	 * @throws ReflectionException
486
+	 * @throws UnexpectedEntityException
487
+	 */
488
+	private function _reserve_registration_space()
489
+	{
490
+		// reserved ticket and datetime counts will be decremented as sold counts are incremented
491
+		// so stop tracking that this reg has a ticket reserved
492
+		$this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
493
+		$ticket = $this->ticket();
494
+		$ticket->increase_sold();
495
+		$ticket->save();
496
+		// possibly set event status to sold out
497
+		$this->event()->perform_sold_out_status_check();
498
+	}
499
+
500
+
501
+	/**
502
+	 * decrements (subtracts) this registration's related ticket sold and corresponding datetime sold values
503
+	 *
504
+	 * @return void
505
+	 * @throws DomainException
506
+	 * @throws EE_Error
507
+	 * @throws EntityNotFoundException
508
+	 * @throws InvalidArgumentException
509
+	 * @throws InvalidDataTypeException
510
+	 * @throws InvalidInterfaceException
511
+	 * @throws ReflectionException
512
+	 * @throws UnexpectedEntityException
513
+	 */
514
+	private function _release_registration_space()
515
+	{
516
+		$ticket = $this->ticket();
517
+		$ticket->decrease_sold();
518
+		$ticket->save();
519
+		// possibly change event status from sold out back to previous status
520
+		$this->event()->perform_sold_out_status_check();
521
+	}
522
+
523
+
524
+	/**
525
+	 * tracks this registration's ticket reservation in extra meta
526
+	 * and can increment related ticket reserved and corresponding datetime reserved values
527
+	 *
528
+	 * @param bool   $update_ticket if true, will increment ticket and datetime reserved count
529
+	 * @param string $source
530
+	 * @return void
531
+	 * @throws EE_Error
532
+	 * @throws InvalidArgumentException
533
+	 * @throws InvalidDataTypeException
534
+	 * @throws InvalidInterfaceException
535
+	 * @throws ReflectionException
536
+	 */
537
+	public function reserve_ticket($update_ticket = false, $source = 'unknown')
538
+	{
539
+		// only reserve ticket if space is not currently reserved
540
+		if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) !== true) {
541
+			$this->update_extra_meta('reserve_ticket', "{$this->ticket_ID()} from {$source}");
542
+			$reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
543
+			if ($reserved && $update_ticket) {
544
+				$ticket = $this->ticket();
545
+				$ticket->increase_reserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
546
+				$ticket->save();
547
+			}
548
+		}
549
+	}
550
+
551
+
552
+	/**
553
+	 * stops tracking this registration's ticket reservation in extra meta
554
+	 * decrements (subtracts) related ticket reserved and corresponding datetime reserved values
555
+	 *
556
+	 * @param bool   $update_ticket if true, will decrement ticket and datetime reserved count
557
+	 * @param string $source
558
+	 * @return void
559
+	 * @throws EE_Error
560
+	 * @throws InvalidArgumentException
561
+	 * @throws InvalidDataTypeException
562
+	 * @throws InvalidInterfaceException
563
+	 * @throws ReflectionException
564
+	 */
565
+	public function release_reserved_ticket($update_ticket = false, $source = 'unknown')
566
+	{
567
+		// only release ticket if space is currently reserved
568
+		if ((bool) $this->get_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true) === true) {
569
+			$this->update_extra_meta('release_reserved_ticket', "{$this->ticket_ID()} from {$source}");
570
+			$reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, false);
571
+			if ($reserved && $update_ticket) {
572
+				$ticket = $this->ticket();
573
+				$ticket->decrease_reserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
574
+				$ticket->save();
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
+	/**
897
+	 *        get Event ID
898
+	 */
899
+	public function event_ID()
900
+	{
901
+		return $this->get('EVT_ID');
902
+	}
903
+
904
+
905
+	/**
906
+	 *        get Event ID
907
+	 */
908
+	public function event_name()
909
+	{
910
+		$event = $this->event_obj();
911
+		if ($event) {
912
+			return $event->name();
913
+		} else {
914
+			return null;
915
+		}
916
+	}
917
+
918
+
919
+	/**
920
+	 * Fetches the event this registration is for
921
+	 *
922
+	 * @return EE_Base_Class|EE_Event
923
+	 * @throws EE_Error
924
+	 * @throws InvalidArgumentException
925
+	 * @throws InvalidDataTypeException
926
+	 * @throws InvalidInterfaceException
927
+	 * @throws ReflectionException
928
+	 */
929
+	public function event_obj()
930
+	{
931
+		return $this->get_first_related('Event');
932
+	}
933
+
934
+
935
+	/**
936
+	 *        get Attendee ID
937
+	 */
938
+	public function attendee_ID()
939
+	{
940
+		return $this->get('ATT_ID');
941
+	}
942
+
943
+
944
+	/**
945
+	 *        get PHP Session ID
946
+	 */
947
+	public function session_ID()
948
+	{
949
+		return $this->get('REG_session');
950
+	}
951
+
952
+
953
+	/**
954
+	 * Gets the string which represents the URL trigger for the receipt template in the message template system.
955
+	 *
956
+	 * @param string $messenger 'pdf' or 'html'.  Default 'html'.
957
+	 * @return string
958
+	 * @throws DomainException
959
+	 * @throws EE_Error
960
+	 * @throws InvalidArgumentException
961
+	 * @throws InvalidDataTypeException
962
+	 * @throws InvalidInterfaceException
963
+	 * @throws ReflectionException
964
+	 */
965
+	public function receipt_url($messenger = 'html')
966
+	{
967
+
968
+		/**
969
+		 * The below will be deprecated one version after this.  We check first if there is a custom receipt template
970
+		 * already in use on old system.  If there is then we just return the standard url for it.
971
+		 *
972
+		 * @since 4.5.0
973
+		 */
974
+		$template_relative_path = 'modules/gateways/Invoice/lib/templates/receipt_body.template.php';
975
+		$has_custom = EEH_Template::locate_template(
976
+			$template_relative_path,
977
+			array(),
978
+			true,
979
+			true,
980
+			true
981
+		);
982
+
983
+		if ($has_custom) {
984
+			return add_query_arg(array('receipt' => 'true'), $this->invoice_url('launch'));
985
+		}
986
+		return apply_filters('FHEE__EE_Registration__receipt_url__receipt_url', '', $this, $messenger, 'receipt');
987
+	}
988
+
989
+
990
+	/**
991
+	 * Gets the string which represents the URL trigger for the invoice template in the message template system.
992
+	 *
993
+	 * @param string $messenger 'pdf' or 'html'.  Default 'html'.
994
+	 * @return string
995
+	 * @throws DomainException
996
+	 * @throws EE_Error
997
+	 * @throws InvalidArgumentException
998
+	 * @throws InvalidDataTypeException
999
+	 * @throws InvalidInterfaceException
1000
+	 * @throws ReflectionException
1001
+	 */
1002
+	public function invoice_url($messenger = 'html')
1003
+	{
1004
+		/**
1005
+		 * The below will be deprecated one version after this.  We check first if there is a custom invoice template
1006
+		 * already in use on old system.  If there is then we just return the standard url for it.
1007
+		 *
1008
+		 * @since 4.5.0
1009
+		 */
1010
+		$template_relative_path = 'modules/gateways/Invoice/lib/templates/invoice_body.template.php';
1011
+		$has_custom = EEH_Template::locate_template(
1012
+			$template_relative_path,
1013
+			array(),
1014
+			true,
1015
+			true,
1016
+			true
1017
+		);
1018
+
1019
+		if ($has_custom) {
1020
+			if ($messenger == 'html') {
1021
+				return $this->invoice_url('launch');
1022
+			}
1023
+			$route = $messenger == 'download' || $messenger == 'pdf' ? 'download_invoice' : 'launch_invoice';
1024
+
1025
+			$query_args = array('ee' => $route, 'id' => $this->reg_url_link());
1026
+			if ($messenger == 'html') {
1027
+				$query_args['html'] = true;
1028
+			}
1029
+			return add_query_arg($query_args, get_permalink(EE_Registry::instance()->CFG->core->thank_you_page_id));
1030
+		}
1031
+		return apply_filters('FHEE__EE_Registration__invoice_url__invoice_url', '', $this, $messenger, 'invoice');
1032
+	}
1033
+
1034
+
1035
+	/**
1036
+	 * get Registration URL Link
1037
+	 *
1038
+	 * @return string
1039
+	 * @throws EE_Error
1040
+	 * @throws InvalidArgumentException
1041
+	 * @throws InvalidDataTypeException
1042
+	 * @throws InvalidInterfaceException
1043
+	 * @throws ReflectionException
1044
+	 */
1045
+	public function reg_url_link()
1046
+	{
1047
+		return (string) $this->get('REG_url_link');
1048
+	}
1049
+
1050
+
1051
+	/**
1052
+	 * Echoes out invoice_url()
1053
+	 *
1054
+	 * @param string $type 'download','launch', or 'html' (default is 'launch')
1055
+	 * @return void
1056
+	 * @throws DomainException
1057
+	 * @throws EE_Error
1058
+	 * @throws InvalidArgumentException
1059
+	 * @throws InvalidDataTypeException
1060
+	 * @throws InvalidInterfaceException
1061
+	 * @throws ReflectionException
1062
+	 */
1063
+	public function e_invoice_url($type = 'launch')
1064
+	{
1065
+		echo $this->invoice_url($type);
1066
+	}
1067
+
1068
+
1069
+	/**
1070
+	 * Echoes out payment_overview_url
1071
+	 */
1072
+	public function e_payment_overview_url()
1073
+	{
1074
+		echo $this->payment_overview_url();
1075
+	}
1076
+
1077
+
1078
+	/**
1079
+	 * Gets the URL for the checkout payment options reg step
1080
+	 * with this registration's REG_url_link added as a query parameter
1081
+	 *
1082
+	 * @param bool $clear_session Set to true when you want to clear the session on revisiting the
1083
+	 *                            payment overview url.
1084
+	 * @return string
1085
+	 * @throws EE_Error
1086
+	 * @throws InvalidArgumentException
1087
+	 * @throws InvalidDataTypeException
1088
+	 * @throws InvalidInterfaceException
1089
+	 * @throws ReflectionException
1090
+	 */
1091
+	public function payment_overview_url($clear_session = false)
1092
+	{
1093
+		return add_query_arg(
1094
+			(array) apply_filters(
1095
+				'FHEE__EE_Registration__payment_overview_url__query_args',
1096
+				array(
1097
+					'e_reg_url_link' => $this->reg_url_link(),
1098
+					'step'           => 'payment_options',
1099
+					'revisit'        => true,
1100
+					'clear_session'  => (bool) $clear_session,
1101
+				),
1102
+				$this
1103
+			),
1104
+			EE_Registry::instance()->CFG->core->reg_page_url()
1105
+		);
1106
+	}
1107
+
1108
+
1109
+	/**
1110
+	 * Gets the URL for the checkout attendee information reg step
1111
+	 * with this registration's REG_url_link added as a query parameter
1112
+	 *
1113
+	 * @return string
1114
+	 * @throws EE_Error
1115
+	 * @throws InvalidArgumentException
1116
+	 * @throws InvalidDataTypeException
1117
+	 * @throws InvalidInterfaceException
1118
+	 * @throws ReflectionException
1119
+	 */
1120
+	public function edit_attendee_information_url()
1121
+	{
1122
+		return add_query_arg(
1123
+			(array) apply_filters(
1124
+				'FHEE__EE_Registration__edit_attendee_information_url__query_args',
1125
+				array(
1126
+					'e_reg_url_link' => $this->reg_url_link(),
1127
+					'step'           => 'attendee_information',
1128
+					'revisit'        => true,
1129
+				),
1130
+				$this
1131
+			),
1132
+			EE_Registry::instance()->CFG->core->reg_page_url()
1133
+		);
1134
+	}
1135
+
1136
+
1137
+	/**
1138
+	 * Simply generates and returns the appropriate admin_url link to edit this registration
1139
+	 *
1140
+	 * @return string
1141
+	 * @throws EE_Error
1142
+	 * @throws InvalidArgumentException
1143
+	 * @throws InvalidDataTypeException
1144
+	 * @throws InvalidInterfaceException
1145
+	 * @throws ReflectionException
1146
+	 */
1147
+	public function get_admin_edit_url()
1148
+	{
1149
+		return EEH_URL::add_query_args_and_nonce(
1150
+			array(
1151
+				'page'    => 'espresso_registrations',
1152
+				'action'  => 'view_registration',
1153
+				'_REG_ID' => $this->ID(),
1154
+			),
1155
+			admin_url('admin.php')
1156
+		);
1157
+	}
1158
+
1159
+
1160
+	/**
1161
+	 * is_primary_registrant?
1162
+	 *
1163
+	 * @throws EE_Error
1164
+	 * @throws InvalidArgumentException
1165
+	 * @throws InvalidDataTypeException
1166
+	 * @throws InvalidInterfaceException
1167
+	 * @throws ReflectionException
1168
+	 */
1169
+	public function is_primary_registrant()
1170
+	{
1171
+		return (int) $this->get('REG_count') === 1;
1172
+	}
1173
+
1174
+
1175
+	/**
1176
+	 * This returns the primary registration object for this registration group (which may be this object).
1177
+	 *
1178
+	 * @return EE_Registration
1179
+	 * @throws EE_Error
1180
+	 * @throws InvalidArgumentException
1181
+	 * @throws InvalidDataTypeException
1182
+	 * @throws InvalidInterfaceException
1183
+	 * @throws ReflectionException
1184
+	 */
1185
+	public function get_primary_registration()
1186
+	{
1187
+		if ($this->is_primary_registrant()) {
1188
+			return $this;
1189
+		}
1190
+
1191
+		// k reg_count !== 1 so let's get the EE_Registration object matching this txn_id and reg_count == 1
1192
+		/** @var EE_Registration $primary_registrant */
1193
+		$primary_registrant = EEM_Registration::instance()->get_one(
1194
+			array(
1195
+				array(
1196
+					'TXN_ID'    => $this->transaction_ID(),
1197
+					'REG_count' => 1,
1198
+				),
1199
+			)
1200
+		);
1201
+		return $primary_registrant;
1202
+	}
1203
+
1204
+
1205
+	/**
1206
+	 * get  Attendee Number
1207
+	 *
1208
+	 * @throws EE_Error
1209
+	 * @throws InvalidArgumentException
1210
+	 * @throws InvalidDataTypeException
1211
+	 * @throws InvalidInterfaceException
1212
+	 * @throws ReflectionException
1213
+	 */
1214
+	public function count()
1215
+	{
1216
+		return $this->get('REG_count');
1217
+	}
1218
+
1219
+
1220
+	/**
1221
+	 * get Group Size
1222
+	 *
1223
+	 * @throws EE_Error
1224
+	 * @throws InvalidArgumentException
1225
+	 * @throws InvalidDataTypeException
1226
+	 * @throws InvalidInterfaceException
1227
+	 * @throws ReflectionException
1228
+	 */
1229
+	public function group_size()
1230
+	{
1231
+		return $this->get('REG_group_size');
1232
+	}
1233
+
1234
+
1235
+	/**
1236
+	 * get Registration Date
1237
+	 *
1238
+	 * @throws EE_Error
1239
+	 * @throws InvalidArgumentException
1240
+	 * @throws InvalidDataTypeException
1241
+	 * @throws InvalidInterfaceException
1242
+	 * @throws ReflectionException
1243
+	 */
1244
+	public function date()
1245
+	{
1246
+		return $this->get('REG_date');
1247
+	}
1248
+
1249
+
1250
+	/**
1251
+	 * gets a pretty date
1252
+	 *
1253
+	 * @param string $date_format
1254
+	 * @param string $time_format
1255
+	 * @return string
1256
+	 * @throws EE_Error
1257
+	 * @throws InvalidArgumentException
1258
+	 * @throws InvalidDataTypeException
1259
+	 * @throws InvalidInterfaceException
1260
+	 * @throws ReflectionException
1261
+	 */
1262
+	public function pretty_date($date_format = null, $time_format = null)
1263
+	{
1264
+		return $this->get_datetime('REG_date', $date_format, $time_format);
1265
+	}
1266
+
1267
+
1268
+	/**
1269
+	 * final_price
1270
+	 * the registration's share of the transaction total, so that the
1271
+	 * sum of all the transaction's REG_final_prices equal the transaction's total
1272
+	 *
1273
+	 * @return float
1274
+	 * @throws EE_Error
1275
+	 * @throws InvalidArgumentException
1276
+	 * @throws InvalidDataTypeException
1277
+	 * @throws InvalidInterfaceException
1278
+	 * @throws ReflectionException
1279
+	 */
1280
+	public function final_price()
1281
+	{
1282
+		return $this->get('REG_final_price');
1283
+	}
1284
+
1285
+
1286
+	/**
1287
+	 * pretty_final_price
1288
+	 *  final price as formatted string, with correct decimal places and currency symbol
1289
+	 *
1290
+	 * @return string
1291
+	 * @throws EE_Error
1292
+	 * @throws InvalidArgumentException
1293
+	 * @throws InvalidDataTypeException
1294
+	 * @throws InvalidInterfaceException
1295
+	 * @throws ReflectionException
1296
+	 */
1297
+	public function pretty_final_price()
1298
+	{
1299
+		return $this->get_pretty('REG_final_price');
1300
+	}
1301
+
1302
+
1303
+	/**
1304
+	 * get paid (yeah)
1305
+	 *
1306
+	 * @return float
1307
+	 * @throws EE_Error
1308
+	 * @throws InvalidArgumentException
1309
+	 * @throws InvalidDataTypeException
1310
+	 * @throws InvalidInterfaceException
1311
+	 * @throws ReflectionException
1312
+	 */
1313
+	public function paid()
1314
+	{
1315
+		return $this->get('REG_paid');
1316
+	}
1317
+
1318
+
1319
+	/**
1320
+	 * pretty_paid
1321
+	 *
1322
+	 * @return float
1323
+	 * @throws EE_Error
1324
+	 * @throws InvalidArgumentException
1325
+	 * @throws InvalidDataTypeException
1326
+	 * @throws InvalidInterfaceException
1327
+	 * @throws ReflectionException
1328
+	 */
1329
+	public function pretty_paid()
1330
+	{
1331
+		return $this->get_pretty('REG_paid');
1332
+	}
1333
+
1334
+
1335
+	/**
1336
+	 * owes_monies_and_can_pay
1337
+	 * whether or not this registration has monies owing and it's' status allows payment
1338
+	 *
1339
+	 * @param array $requires_payment
1340
+	 * @return bool
1341
+	 * @throws EE_Error
1342
+	 * @throws InvalidArgumentException
1343
+	 * @throws InvalidDataTypeException
1344
+	 * @throws InvalidInterfaceException
1345
+	 * @throws ReflectionException
1346
+	 */
1347
+	public function owes_monies_and_can_pay($requires_payment = array())
1348
+	{
1349
+		// these reg statuses require payment (if event is not free)
1350
+		$requires_payment = ! empty($requires_payment)
1351
+			? $requires_payment
1352
+			: EEM_Registration::reg_statuses_that_allow_payment();
1353
+		if ($this->final_price() !== 0 &&
1354
+			$this->final_price() !== $this->paid() &&
1355
+			in_array($this->status_ID(), $requires_payment, true)
1356
+		) {
1357
+			return true;
1358
+		}
1359
+		return false;
1360
+	}
1361
+
1362
+
1363
+	/**
1364
+	 * Prints out the return value of $this->pretty_status()
1365
+	 *
1366
+	 * @param bool $show_icons
1367
+	 * @return void
1368
+	 * @throws EE_Error
1369
+	 * @throws InvalidArgumentException
1370
+	 * @throws InvalidDataTypeException
1371
+	 * @throws InvalidInterfaceException
1372
+	 * @throws ReflectionException
1373
+	 */
1374
+	public function e_pretty_status($show_icons = false)
1375
+	{
1376
+		echo $this->pretty_status($show_icons);
1377
+	}
1378
+
1379
+
1380
+	/**
1381
+	 * Returns a nice version of the status for displaying to customers
1382
+	 *
1383
+	 * @param bool $show_icons
1384
+	 * @return string
1385
+	 * @throws EE_Error
1386
+	 * @throws InvalidArgumentException
1387
+	 * @throws InvalidDataTypeException
1388
+	 * @throws InvalidInterfaceException
1389
+	 * @throws ReflectionException
1390
+	 */
1391
+	public function pretty_status($show_icons = false)
1392
+	{
1393
+		$status = EEM_Status::instance()->localized_status(
1394
+			array($this->status_ID() => esc_html__('unknown', 'event_espresso')),
1395
+			false,
1396
+			'sentence'
1397
+		);
1398
+		$icon = '';
1399
+		switch ($this->status_ID()) {
1400
+			case EEM_Registration::status_id_approved:
1401
+				$icon = $show_icons
1402
+					? '<span class="dashicons dashicons-star-filled ee-icon-size-16 green-text"></span>'
1403
+					: '';
1404
+				break;
1405
+			case EEM_Registration::status_id_pending_payment:
1406
+				$icon = $show_icons
1407
+					? '<span class="dashicons dashicons-star-half ee-icon-size-16 orange-text"></span>'
1408
+					: '';
1409
+				break;
1410
+			case EEM_Registration::status_id_not_approved:
1411
+				$icon = $show_icons
1412
+					? '<span class="dashicons dashicons-marker ee-icon-size-16 orange-text"></span>'
1413
+					: '';
1414
+				break;
1415
+			case EEM_Registration::status_id_cancelled:
1416
+				$icon = $show_icons
1417
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-grey-text"></span>'
1418
+					: '';
1419
+				break;
1420
+			case EEM_Registration::status_id_incomplete:
1421
+				$icon = $show_icons
1422
+					? '<span class="dashicons dashicons-no ee-icon-size-16 lt-orange-text"></span>'
1423
+					: '';
1424
+				break;
1425
+			case EEM_Registration::status_id_declined:
1426
+				$icon = $show_icons
1427
+					? '<span class="dashicons dashicons-no ee-icon-size-16 red-text"></span>'
1428
+					: '';
1429
+				break;
1430
+			case EEM_Registration::status_id_wait_list:
1431
+				$icon = $show_icons
1432
+					? '<span class="dashicons dashicons-clipboard ee-icon-size-16 purple-text"></span>'
1433
+					: '';
1434
+				break;
1435
+		}
1436
+		return $icon . $status[ $this->status_ID() ];
1437
+	}
1438
+
1439
+
1440
+	/**
1441
+	 *        get Attendee Is Going
1442
+	 */
1443
+	public function att_is_going()
1444
+	{
1445
+		return $this->get('REG_att_is_going');
1446
+	}
1447
+
1448
+
1449
+	/**
1450
+	 * Gets related answers
1451
+	 *
1452
+	 * @param array $query_params @see
1453
+	 *                            https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1454
+	 * @return EE_Answer[]|EE_Base_Class[]
1455
+	 * @throws EE_Error
1456
+	 * @throws InvalidArgumentException
1457
+	 * @throws InvalidDataTypeException
1458
+	 * @throws InvalidInterfaceException
1459
+	 * @throws ReflectionException
1460
+	 */
1461
+	public function answers($query_params = null)
1462
+	{
1463
+		return $this->get_many_related('Answer', $query_params);
1464
+	}
1465
+
1466
+
1467
+	/**
1468
+	 * Gets the registration's answer value to the specified question
1469
+	 * (either the question's ID or a question object)
1470
+	 *
1471
+	 * @param EE_Question|int $question
1472
+	 * @param bool            $pretty_value
1473
+	 * @return array|string if pretty_value= true, the result will always be a string
1474
+	 * (because the answer might be an array of answer values, so passing pretty_value=true
1475
+	 * will convert it into some kind of string)
1476
+	 * @throws EE_Error
1477
+	 * @throws InvalidArgumentException
1478
+	 * @throws InvalidDataTypeException
1479
+	 * @throws InvalidInterfaceException
1480
+	 */
1481
+	public function answer_value_to_question($question, $pretty_value = true)
1482
+	{
1483
+		$question_id = EEM_Question::instance()->ensure_is_ID($question);
1484
+		return EEM_Answer::instance()->get_answer_value_to_question($this, $question_id, $pretty_value);
1485
+	}
1486
+
1487
+
1488
+	/**
1489
+	 * question_groups
1490
+	 * returns an array of EE_Question_Group objects for this registration
1491
+	 *
1492
+	 * @return EE_Question_Group[]
1493
+	 * @throws EE_Error
1494
+	 * @throws EntityNotFoundException
1495
+	 * @throws InvalidArgumentException
1496
+	 * @throws InvalidDataTypeException
1497
+	 * @throws InvalidInterfaceException
1498
+	 * @throws ReflectionException
1499
+	 */
1500
+	public function question_groups()
1501
+	{
1502
+		$question_groups = [];
1503
+		if ($this->event() instanceof EE_Event) {
1504
+			$question_groups = $this->event()->question_groups(
1505
+				[
1506
+					['Event_Question_Group.EQG_primary' => $this->count() === 1],
1507
+					'order_by' => ['QSG_order' => 'ASC'],
1508
+				]
1509
+			);
1510
+		}
1511
+		return $question_groups;
1512
+	}
1513
+
1514
+
1515
+	/**
1516
+	 * count_question_groups
1517
+	 * returns a count of the number of EE_Question_Group objects for this registration
1518
+	 *
1519
+	 * @return int
1520
+	 * @throws EE_Error
1521
+	 * @throws EntityNotFoundException
1522
+	 * @throws InvalidArgumentException
1523
+	 * @throws InvalidDataTypeException
1524
+	 * @throws InvalidInterfaceException
1525
+	 * @throws ReflectionException
1526
+	 */
1527
+	public function count_question_groups()
1528
+	{
1529
+		$qg_count = 0;
1530
+		if ($this->event() instanceof EE_Event) {
1531
+			$qg_count = $this->event()->count_related(
1532
+				'Question_Group',
1533
+				[
1534
+					['Event_Question_Group.EQG_primary' => $this->count() === 1],
1535
+				]
1536
+			);
1537
+		}
1538
+		return $qg_count;
1539
+	}
1540
+
1541
+
1542
+	/**
1543
+	 * Returns the registration date in the 'standard' string format
1544
+	 * (function may be improved in the future to allow for different formats and timezones)
1545
+	 *
1546
+	 * @return string
1547
+	 * @throws EE_Error
1548
+	 * @throws InvalidArgumentException
1549
+	 * @throws InvalidDataTypeException
1550
+	 * @throws InvalidInterfaceException
1551
+	 * @throws ReflectionException
1552
+	 */
1553
+	public function reg_date()
1554
+	{
1555
+		return $this->get_datetime('REG_date');
1556
+	}
1557
+
1558
+
1559
+	/**
1560
+	 * Gets the datetime-ticket for this registration (ie, it can be used to isolate
1561
+	 * the ticket this registration purchased, or the datetime they have registered
1562
+	 * to attend)
1563
+	 *
1564
+	 * @return EE_Base_Class|EE_Datetime_Ticket
1565
+	 * @throws EE_Error
1566
+	 * @throws InvalidArgumentException
1567
+	 * @throws InvalidDataTypeException
1568
+	 * @throws InvalidInterfaceException
1569
+	 * @throws ReflectionException
1570
+	 */
1571
+	public function datetime_ticket()
1572
+	{
1573
+		return $this->get_first_related('Datetime_Ticket');
1574
+	}
1575
+
1576
+
1577
+	/**
1578
+	 * Sets the registration's datetime_ticket.
1579
+	 *
1580
+	 * @param EE_Datetime_Ticket $datetime_ticket
1581
+	 * @return EE_Base_Class|EE_Datetime_Ticket
1582
+	 * @throws EE_Error
1583
+	 * @throws InvalidArgumentException
1584
+	 * @throws InvalidDataTypeException
1585
+	 * @throws InvalidInterfaceException
1586
+	 * @throws ReflectionException
1587
+	 */
1588
+	public function set_datetime_ticket($datetime_ticket)
1589
+	{
1590
+		return $this->_add_relation_to($datetime_ticket, 'Datetime_Ticket');
1591
+	}
1592
+
1593
+
1594
+	/**
1595
+	 * Gets deleted
1596
+	 *
1597
+	 * @return bool
1598
+	 * @throws EE_Error
1599
+	 * @throws InvalidArgumentException
1600
+	 * @throws InvalidDataTypeException
1601
+	 * @throws InvalidInterfaceException
1602
+	 * @throws ReflectionException
1603
+	 */
1604
+	public function deleted()
1605
+	{
1606
+		return $this->get('REG_deleted');
1607
+	}
1608
+
1609
+
1610
+	/**
1611
+	 * Sets deleted
1612
+	 *
1613
+	 * @param boolean $deleted
1614
+	 * @return void
1615
+	 * @throws DomainException
1616
+	 * @throws EE_Error
1617
+	 * @throws EntityNotFoundException
1618
+	 * @throws InvalidArgumentException
1619
+	 * @throws InvalidDataTypeException
1620
+	 * @throws InvalidInterfaceException
1621
+	 * @throws ReflectionException
1622
+	 * @throws RuntimeException
1623
+	 * @throws UnexpectedEntityException
1624
+	 */
1625
+	public function set_deleted($deleted)
1626
+	{
1627
+		if ($deleted) {
1628
+			$this->delete(__METHOD__);
1629
+		} else {
1630
+			$this->restore(__METHOD__);
1631
+		}
1632
+	}
1633
+
1634
+
1635
+	/**
1636
+	 * Get the status object of this object
1637
+	 *
1638
+	 * @return EE_Base_Class|EE_Status
1639
+	 * @throws EE_Error
1640
+	 * @throws InvalidArgumentException
1641
+	 * @throws InvalidDataTypeException
1642
+	 * @throws InvalidInterfaceException
1643
+	 * @throws ReflectionException
1644
+	 */
1645
+	public function status_obj()
1646
+	{
1647
+		return $this->get_first_related('Status');
1648
+	}
1649
+
1650
+
1651
+	/**
1652
+	 * Returns the number of times this registration has checked into any of the datetimes
1653
+	 * its available for
1654
+	 *
1655
+	 * @return int
1656
+	 * @throws EE_Error
1657
+	 * @throws InvalidArgumentException
1658
+	 * @throws InvalidDataTypeException
1659
+	 * @throws InvalidInterfaceException
1660
+	 * @throws ReflectionException
1661
+	 */
1662
+	public function count_checkins()
1663
+	{
1664
+		return $this->get_model()->count_related($this, 'Checkin');
1665
+	}
1666
+
1667
+
1668
+	/**
1669
+	 * Returns the number of current Check-ins this registration is checked into for any of the datetimes the
1670
+	 * registration is for.  Note, this is ONLY checked in (does not include checkedout)
1671
+	 *
1672
+	 * @return int
1673
+	 * @throws EE_Error
1674
+	 * @throws InvalidArgumentException
1675
+	 * @throws InvalidDataTypeException
1676
+	 * @throws InvalidInterfaceException
1677
+	 * @throws ReflectionException
1678
+	 */
1679
+	public function count_checkins_not_checkedout()
1680
+	{
1681
+		return $this->get_model()->count_related($this, 'Checkin', array(array('CHK_in' => 1)));
1682
+	}
1683
+
1684
+
1685
+	/**
1686
+	 * The purpose of this method is simply to check whether this registration can checkin to the given datetime.
1687
+	 *
1688
+	 * @param int | EE_Datetime $DTT_OR_ID      The datetime the registration is being checked against
1689
+	 * @param bool              $check_approved This is used to indicate whether the caller wants can_checkin to also
1690
+	 *                                          consider registration status as well as datetime access.
1691
+	 * @return bool
1692
+	 * @throws EE_Error
1693
+	 * @throws InvalidArgumentException
1694
+	 * @throws InvalidDataTypeException
1695
+	 * @throws InvalidInterfaceException
1696
+	 * @throws ReflectionException
1697
+	 */
1698
+	public function can_checkin($DTT_OR_ID, $check_approved = true)
1699
+	{
1700
+		$DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1701
+		// first check registration status
1702
+		if (! $DTT_ID || ($check_approved && ! $this->is_approved())) {
1703
+			return false;
1704
+		}
1705
+		// is there a datetime ticket that matches this dtt_ID?
1706
+		if (! EEM_Datetime_Ticket::instance()->exists(
1707
+			array(
1708
+				array(
1709
+					'TKT_ID' => $this->get('TKT_ID'),
1710
+					'DTT_ID' => $DTT_ID,
1711
+				),
1712
+			)
1713
+		)) {
1714
+			return false;
1715
+		}
1716
+
1717
+		// final check is against TKT_uses
1718
+		return $this->verify_can_checkin_against_TKT_uses($DTT_ID);
1719
+	}
1720
+
1721
+
1722
+	/**
1723
+	 * This method verifies whether the user can checkin for the given datetime considering the max uses value set on
1724
+	 * the ticket. To do this,  a query is done to get the count of the datetime records already checked into.  If the
1725
+	 * datetime given does not have a check-in record and checking in for that datetime will exceed the allowed uses,
1726
+	 * then return false.  Otherwise return true.
1727
+	 *
1728
+	 * @param int | EE_Datetime $DTT_OR_ID The datetime the registration is being checked against
1729
+	 * @return bool true means can checkin.  false means cannot checkin.
1730
+	 * @throws EE_Error
1731
+	 * @throws InvalidArgumentException
1732
+	 * @throws InvalidDataTypeException
1733
+	 * @throws InvalidInterfaceException
1734
+	 * @throws ReflectionException
1735
+	 */
1736
+	public function verify_can_checkin_against_TKT_uses($DTT_OR_ID)
1737
+	{
1738
+		$DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1739
+
1740
+		if (! $DTT_ID) {
1741
+			return false;
1742
+		}
1743
+
1744
+		$max_uses = $this->ticket() instanceof EE_Ticket ? $this->ticket()->uses() : EE_INF;
1745
+
1746
+		// if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1747
+		// check-in or not.
1748
+		if (! $max_uses || $max_uses === EE_INF) {
1749
+			return true;
1750
+		}
1751
+
1752
+		// does this datetime have a checkin record?  If so, then the dtt count has already been verified so we can just
1753
+		// go ahead and toggle.
1754
+		if (EEM_Checkin::instance()->exists(array(array('REG_ID' => $this->ID(), 'DTT_ID' => $DTT_ID)))) {
1755
+			return true;
1756
+		}
1757
+
1758
+		// made it here so the last check is whether the number of checkins per unique datetime on this registration
1759
+		// disallows further check-ins.
1760
+		$count_unique_dtt_checkins = EEM_Checkin::instance()->count(
1761
+			array(
1762
+				array(
1763
+					'REG_ID' => $this->ID(),
1764
+					'CHK_in' => true,
1765
+				),
1766
+			),
1767
+			'DTT_ID',
1768
+			true
1769
+		);
1770
+		// checkins have already reached their max number of uses
1771
+		// so registrant can NOT checkin
1772
+		if ($count_unique_dtt_checkins >= $max_uses) {
1773
+			EE_Error::add_error(
1774
+				esc_html__(
1775
+					'Check-in denied because number of datetime uses for the ticket has been reached or exceeded.',
1776
+					'event_espresso'
1777
+				),
1778
+				__FILE__,
1779
+				__FUNCTION__,
1780
+				__LINE__
1781
+			);
1782
+			return false;
1783
+		}
1784
+		return true;
1785
+	}
1786
+
1787
+
1788
+	/**
1789
+	 * toggle Check-in status for this registration
1790
+	 * Check-ins are toggled in the following order:
1791
+	 * never checked in -> checked in
1792
+	 * checked in -> checked out
1793
+	 * checked out -> checked in
1794
+	 *
1795
+	 * @param  int $DTT_ID  include specific datetime to toggle Check-in for.
1796
+	 *                      If not included or null, then it is assumed latest datetime is being toggled.
1797
+	 * @param bool $verify  If true then can_checkin() is used to verify whether the person
1798
+	 *                      can be checked in or not.  Otherwise this forces change in checkin status.
1799
+	 * @return bool|int     the chk_in status toggled to OR false if nothing got changed.
1800
+	 * @throws EE_Error
1801
+	 * @throws InvalidArgumentException
1802
+	 * @throws InvalidDataTypeException
1803
+	 * @throws InvalidInterfaceException
1804
+	 * @throws ReflectionException
1805
+	 */
1806
+	public function toggle_checkin_status($DTT_ID = null, $verify = false)
1807
+	{
1808
+		if (empty($DTT_ID)) {
1809
+			$datetime = $this->get_latest_related_datetime();
1810
+			$DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1811
+			// verify the registration can checkin for the given DTT_ID
1812
+		} elseif (! $this->can_checkin($DTT_ID, $verify)) {
1813
+			EE_Error::add_error(
1814
+				sprintf(
1815
+					esc_html__(
1816
+						'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',
1817
+						'event_espresso'
1818
+					),
1819
+					$this->ID(),
1820
+					$DTT_ID
1821
+				),
1822
+				__FILE__,
1823
+				__FUNCTION__,
1824
+				__LINE__
1825
+			);
1826
+			return false;
1827
+		}
1828
+		$status_paths = array(
1829
+			EE_Checkin::status_checked_never => EE_Checkin::status_checked_in,
1830
+			EE_Checkin::status_checked_in    => EE_Checkin::status_checked_out,
1831
+			EE_Checkin::status_checked_out   => EE_Checkin::status_checked_in,
1832
+		);
1833
+		// start by getting the current status so we know what status we'll be changing to.
1834
+		$cur_status = $this->check_in_status_for_datetime($DTT_ID);
1835
+		$status_to = $status_paths[ $cur_status ];
1836
+		// database only records true for checked IN or false for checked OUT
1837
+		// no record ( null ) means checked in NEVER, but we obviously don't save that
1838
+		$new_status = $status_to === EE_Checkin::status_checked_in;
1839
+		// add relation - note Check-ins are always creating new rows
1840
+		// because we are keeping track of Check-ins over time.
1841
+		// Eventually we'll probably want to show a list table
1842
+		// for the individual Check-ins so that they can be managed.
1843
+		$checkin = EE_Checkin::new_instance(
1844
+			array(
1845
+				'REG_ID' => $this->ID(),
1846
+				'DTT_ID' => $DTT_ID,
1847
+				'CHK_in' => $new_status,
1848
+			)
1849
+		);
1850
+		// if the record could not be saved then return false
1851
+		if ($checkin->save() === 0) {
1852
+			if (WP_DEBUG) {
1853
+				global $wpdb;
1854
+				$error = sprintf(
1855
+					esc_html__(
1856
+						'Registration check in update failed because of the following database error: %1$s%2$s',
1857
+						'event_espresso'
1858
+					),
1859
+					'<br />',
1860
+					$wpdb->last_error
1861
+				);
1862
+			} else {
1863
+				$error = esc_html__(
1864
+					'Registration check in update failed because of an unknown database error',
1865
+					'event_espresso'
1866
+				);
1867
+			}
1868
+			EE_Error::add_error($error, __FILE__, __FUNCTION__, __LINE__);
1869
+			return false;
1870
+		}
1871
+		return $status_to;
1872
+	}
1873
+
1874
+
1875
+	/**
1876
+	 * Returns the latest datetime related to this registration (via the ticket attached to the registration).
1877
+	 * "Latest" is defined by the `DTT_EVT_start` column.
1878
+	 *
1879
+	 * @return EE_Datetime|null
1880
+	 * @throws EE_Error
1881
+	 * @throws InvalidArgumentException
1882
+	 * @throws InvalidDataTypeException
1883
+	 * @throws InvalidInterfaceException
1884
+	 * @throws ReflectionException
1885
+	 */
1886
+	public function get_latest_related_datetime()
1887
+	{
1888
+		return EEM_Datetime::instance()->get_one(
1889
+			array(
1890
+				array(
1891
+					'Ticket.Registration.REG_ID' => $this->ID(),
1892
+				),
1893
+				'order_by' => array('DTT_EVT_start' => 'DESC'),
1894
+			)
1895
+		);
1896
+	}
1897
+
1898
+
1899
+	/**
1900
+	 * Returns the earliest datetime related to this registration (via the ticket attached to the registration).
1901
+	 * "Earliest" is defined by the `DTT_EVT_start` column.
1902
+	 *
1903
+	 * @return EE_Base_Class|EE_Soft_Delete_Base_Class|NULL
1904
+	 * @throws EE_Error
1905
+	 * @throws InvalidArgumentException
1906
+	 * @throws InvalidDataTypeException
1907
+	 * @throws InvalidInterfaceException
1908
+	 * @throws ReflectionException
1909
+	 */
1910
+	public function get_earliest_related_datetime()
1911
+	{
1912
+		return EEM_Datetime::instance()->get_one(
1913
+			array(
1914
+				array(
1915
+					'Ticket.Registration.REG_ID' => $this->ID(),
1916
+				),
1917
+				'order_by' => array('DTT_EVT_start' => 'ASC'),
1918
+			)
1919
+		);
1920
+	}
1921
+
1922
+
1923
+	/**
1924
+	 * This method simply returns the check-in status for this registration and the given datetime.
1925
+	 * If neither the datetime nor the checkin values are provided as arguments,
1926
+	 * then this will return the LATEST check-in status for the registration across all datetimes it belongs to.
1927
+	 *
1928
+	 * @param  int       $DTT_ID  The ID of the datetime we're checking against
1929
+	 *                            (if empty we'll get the primary datetime for
1930
+	 *                            this registration (via event) and use it's ID);
1931
+	 * @param EE_Checkin $checkin If present, we use the given checkin object rather than the dtt_id.
1932
+	 * @return int                Integer representing Check-in status.
1933
+	 * @throws EE_Error
1934
+	 * @throws InvalidArgumentException
1935
+	 * @throws InvalidDataTypeException
1936
+	 * @throws InvalidInterfaceException
1937
+	 * @throws ReflectionException
1938
+	 */
1939
+	public function check_in_status_for_datetime($DTT_ID = 0, $checkin = null)
1940
+	{
1941
+		$checkin_query_params = array(
1942
+			'order_by' => array('CHK_timestamp' => 'DESC'),
1943
+		);
1944
+
1945
+		if ($DTT_ID > 0) {
1946
+			$checkin_query_params[0] = array('DTT_ID' => $DTT_ID);
1947
+		}
1948
+
1949
+		// get checkin object (if exists)
1950
+		$checkin = $checkin instanceof EE_Checkin
1951
+			? $checkin
1952
+			: $this->get_first_related('Checkin', $checkin_query_params);
1953
+		if ($checkin instanceof EE_Checkin) {
1954
+			if ($checkin->get('CHK_in')) {
1955
+				return EE_Checkin::status_checked_in; // checked in
1956
+			}
1957
+			return EE_Checkin::status_checked_out; // had checked in but is now checked out.
1958
+		}
1959
+		return EE_Checkin::status_checked_never; // never been checked in
1960
+	}
1961
+
1962
+
1963
+	/**
1964
+	 * This method returns a localized message for the toggled Check-in message.
1965
+	 *
1966
+	 * @param  int $DTT_ID include specific datetime to get the correct Check-in message.  If not included or null,
1967
+	 *                     then it is assumed Check-in for primary datetime was toggled.
1968
+	 * @param bool $error  This just flags that you want an error message returned. This is put in so that the error
1969
+	 *                     message can be customized with the attendee name.
1970
+	 * @return string internationalized message
1971
+	 * @throws EE_Error
1972
+	 * @throws InvalidArgumentException
1973
+	 * @throws InvalidDataTypeException
1974
+	 * @throws InvalidInterfaceException
1975
+	 * @throws ReflectionException
1976
+	 */
1977
+	public function get_checkin_msg($DTT_ID, $error = false)
1978
+	{
1979
+		// let's get the attendee first so we can include the name of the attendee
1980
+		$attendee = $this->get_first_related('Attendee');
1981
+		if ($attendee instanceof EE_Attendee) {
1982
+			if ($error) {
1983
+				return sprintf(__("%s's check-in status was not changed.", 'event_espresso'), $attendee->full_name());
1984
+			}
1985
+			$cur_status = $this->check_in_status_for_datetime($DTT_ID);
1986
+			// what is the status message going to be?
1987
+			switch ($cur_status) {
1988
+				case EE_Checkin::status_checked_never:
1989
+					return sprintf(
1990
+						esc_html__('%s has been removed from Check-in records', 'event_espresso'),
1991
+						$attendee->full_name()
1992
+					);
1993
+					break;
1994
+				case EE_Checkin::status_checked_in:
1995
+					return sprintf(__('%s has been checked in', 'event_espresso'), $attendee->full_name());
1996
+					break;
1997
+				case EE_Checkin::status_checked_out:
1998
+					return sprintf(__('%s has been checked out', 'event_espresso'), $attendee->full_name());
1999
+					break;
2000
+			}
2001
+		}
2002
+		return esc_html__('The check-in status could not be determined.', 'event_espresso');
2003
+	}
2004
+
2005
+
2006
+	/**
2007
+	 * Returns the related EE_Transaction to this registration
2008
+	 *
2009
+	 * @return EE_Transaction
2010
+	 * @throws EE_Error
2011
+	 * @throws EntityNotFoundException
2012
+	 * @throws InvalidArgumentException
2013
+	 * @throws InvalidDataTypeException
2014
+	 * @throws InvalidInterfaceException
2015
+	 * @throws ReflectionException
2016
+	 */
2017
+	public function transaction()
2018
+	{
2019
+		$transaction = $this->get_first_related('Transaction');
2020
+		if (! $transaction instanceof \EE_Transaction) {
2021
+			throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
2022
+		}
2023
+		return $transaction;
2024
+	}
2025
+
2026
+
2027
+	/**
2028
+	 * get Registration Code
2029
+	 *
2030
+	 * @return mixed
2031
+	 * @throws EE_Error
2032
+	 * @throws InvalidArgumentException
2033
+	 * @throws InvalidDataTypeException
2034
+	 * @throws InvalidInterfaceException
2035
+	 * @throws ReflectionException
2036
+	 */
2037
+	public function reg_code()
2038
+	{
2039
+		return $this->get('REG_code');
2040
+	}
2041
+
2042
+
2043
+	/**
2044
+	 * @return mixed
2045
+	 * @throws EE_Error
2046
+	 * @throws InvalidArgumentException
2047
+	 * @throws InvalidDataTypeException
2048
+	 * @throws InvalidInterfaceException
2049
+	 * @throws ReflectionException
2050
+	 */
2051
+	public function transaction_ID()
2052
+	{
2053
+		return $this->get('TXN_ID');
2054
+	}
2055
+
2056
+
2057
+	/**
2058
+	 * @return int
2059
+	 * @throws EE_Error
2060
+	 * @throws InvalidArgumentException
2061
+	 * @throws InvalidDataTypeException
2062
+	 * @throws InvalidInterfaceException
2063
+	 * @throws ReflectionException
2064
+	 */
2065
+	public function ticket_ID()
2066
+	{
2067
+		return $this->get('TKT_ID');
2068
+	}
2069
+
2070
+
2071
+	/**
2072
+	 * Set Registration Code
2073
+	 *
2074
+	 * @param    string  $REG_code Registration Code
2075
+	 * @param    boolean $use_default
2076
+	 * @throws EE_Error
2077
+	 * @throws InvalidArgumentException
2078
+	 * @throws InvalidDataTypeException
2079
+	 * @throws InvalidInterfaceException
2080
+	 * @throws ReflectionException
2081
+	 */
2082
+	public function set_reg_code($REG_code, $use_default = false)
2083
+	{
2084
+		if (empty($REG_code)) {
2085
+			EE_Error::add_error(
2086
+				esc_html__('REG_code can not be empty.', 'event_espresso'),
2087
+				__FILE__,
2088
+				__FUNCTION__,
2089
+				__LINE__
2090
+			);
2091
+			return;
2092
+		}
2093
+		if (! $this->reg_code()) {
2094
+			parent::set('REG_code', $REG_code, $use_default);
2095
+		} else {
2096
+			EE_Error::doing_it_wrong(
2097
+				__CLASS__ . '::' . __FUNCTION__,
2098
+				esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
2099
+				'4.6.0'
2100
+			);
2101
+		}
2102
+	}
2103
+
2104
+
2105
+	/**
2106
+	 * Returns all other registrations in the same group as this registrant who have the same ticket option.
2107
+	 * Note, if you want to just get all registrations in the same transaction (group), use:
2108
+	 *    $registration->transaction()->registrations();
2109
+	 *
2110
+	 * @since 4.5.0
2111
+	 * @return EE_Registration[] or empty array if this isn't a group registration.
2112
+	 * @throws EE_Error
2113
+	 * @throws InvalidArgumentException
2114
+	 * @throws InvalidDataTypeException
2115
+	 * @throws InvalidInterfaceException
2116
+	 * @throws ReflectionException
2117
+	 */
2118
+	public function get_all_other_registrations_in_group()
2119
+	{
2120
+		if ($this->group_size() < 2) {
2121
+			return array();
2122
+		}
2123
+
2124
+		$query[0] = array(
2125
+			'TXN_ID' => $this->transaction_ID(),
2126
+			'REG_ID' => array('!=', $this->ID()),
2127
+			'TKT_ID' => $this->ticket_ID(),
2128
+		);
2129
+		/** @var EE_Registration[] $registrations */
2130
+		$registrations = $this->get_model()->get_all($query);
2131
+		return $registrations;
2132
+	}
2133
+
2134
+
2135
+	/**
2136
+	 * Return the link to the admin details for the object.
2137
+	 *
2138
+	 * @return string
2139
+	 * @throws EE_Error
2140
+	 * @throws InvalidArgumentException
2141
+	 * @throws InvalidDataTypeException
2142
+	 * @throws InvalidInterfaceException
2143
+	 * @throws ReflectionException
2144
+	 */
2145
+	public function get_admin_details_link()
2146
+	{
2147
+		EE_Registry::instance()->load_helper('URL');
2148
+		return EEH_URL::add_query_args_and_nonce(
2149
+			array(
2150
+				'page'    => 'espresso_registrations',
2151
+				'action'  => 'view_registration',
2152
+				'_REG_ID' => $this->ID(),
2153
+			),
2154
+			admin_url('admin.php')
2155
+		);
2156
+	}
2157
+
2158
+
2159
+	/**
2160
+	 * Returns the link to the editor for the object.  Sometimes this is the same as the details.
2161
+	 *
2162
+	 * @return string
2163
+	 * @throws EE_Error
2164
+	 * @throws InvalidArgumentException
2165
+	 * @throws InvalidDataTypeException
2166
+	 * @throws InvalidInterfaceException
2167
+	 * @throws ReflectionException
2168
+	 */
2169
+	public function get_admin_edit_link()
2170
+	{
2171
+		return $this->get_admin_details_link();
2172
+	}
2173
+
2174
+
2175
+	/**
2176
+	 * Returns the link to a settings page for the object.
2177
+	 *
2178
+	 * @return string
2179
+	 * @throws EE_Error
2180
+	 * @throws InvalidArgumentException
2181
+	 * @throws InvalidDataTypeException
2182
+	 * @throws InvalidInterfaceException
2183
+	 * @throws ReflectionException
2184
+	 */
2185
+	public function get_admin_settings_link()
2186
+	{
2187
+		return $this->get_admin_details_link();
2188
+	}
2189
+
2190
+
2191
+	/**
2192
+	 * Returns the link to the "overview" for the object (typically the "list table" view).
2193
+	 *
2194
+	 * @return string
2195
+	 * @throws EE_Error
2196
+	 * @throws InvalidArgumentException
2197
+	 * @throws InvalidDataTypeException
2198
+	 * @throws InvalidInterfaceException
2199
+	 * @throws ReflectionException
2200
+	 */
2201
+	public function get_admin_overview_link()
2202
+	{
2203
+		EE_Registry::instance()->load_helper('URL');
2204
+		return EEH_URL::add_query_args_and_nonce(
2205
+			array(
2206
+				'page' => 'espresso_registrations',
2207
+			),
2208
+			admin_url('admin.php')
2209
+		);
2210
+	}
2211
+
2212
+
2213
+	/**
2214
+	 * @param array $query_params
2215
+	 * @return EE_Base_Class[]|EE_Registration[]
2216
+	 * @throws EE_Error
2217
+	 * @throws InvalidArgumentException
2218
+	 * @throws InvalidDataTypeException
2219
+	 * @throws InvalidInterfaceException
2220
+	 * @throws ReflectionException
2221
+	 */
2222
+	public function payments($query_params = array())
2223
+	{
2224
+		return $this->get_many_related('Payment', $query_params);
2225
+	}
2226
+
2227
+
2228
+	/**
2229
+	 * @param array $query_params
2230
+	 * @return EE_Base_Class[]|EE_Registration_Payment[]
2231
+	 * @throws EE_Error
2232
+	 * @throws InvalidArgumentException
2233
+	 * @throws InvalidDataTypeException
2234
+	 * @throws InvalidInterfaceException
2235
+	 * @throws ReflectionException
2236
+	 */
2237
+	public function registration_payments($query_params = array())
2238
+	{
2239
+		return $this->get_many_related('Registration_Payment', $query_params);
2240
+	}
2241
+
2242
+
2243
+	/**
2244
+	 * This grabs the payment method corresponding to the last payment made for the amount owing on the registration.
2245
+	 * Note: if there are no payments on the registration there will be no payment method returned.
2246
+	 *
2247
+	 * @return EE_Payment|EE_Payment_Method|null
2248
+	 * @throws EE_Error
2249
+	 * @throws InvalidArgumentException
2250
+	 * @throws InvalidDataTypeException
2251
+	 * @throws InvalidInterfaceException
2252
+	 */
2253
+	public function payment_method()
2254
+	{
2255
+		return EEM_Payment_Method::instance()->get_last_used_for_registration($this);
2256
+	}
2257
+
2258
+
2259
+	/**
2260
+	 * @return \EE_Line_Item
2261
+	 * @throws EE_Error
2262
+	 * @throws EntityNotFoundException
2263
+	 * @throws InvalidArgumentException
2264
+	 * @throws InvalidDataTypeException
2265
+	 * @throws InvalidInterfaceException
2266
+	 * @throws ReflectionException
2267
+	 */
2268
+	public function ticket_line_item()
2269
+	{
2270
+		$ticket = $this->ticket();
2271
+		$transaction = $this->transaction();
2272
+		$line_item = null;
2273
+		$ticket_line_items = \EEH_Line_Item::get_line_items_by_object_type_and_IDs(
2274
+			$transaction->total_line_item(),
2275
+			'Ticket',
2276
+			array($ticket->ID())
2277
+		);
2278
+		foreach ($ticket_line_items as $ticket_line_item) {
2279
+			if ($ticket_line_item instanceof \EE_Line_Item
2280
+				&& $ticket_line_item->OBJ_type() === 'Ticket'
2281
+				&& $ticket_line_item->OBJ_ID() === $ticket->ID()
2282
+			) {
2283
+				$line_item = $ticket_line_item;
2284
+				break;
2285
+			}
2286
+		}
2287
+		if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
2288
+			throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
2289
+		}
2290
+		return $line_item;
2291
+	}
2292
+
2293
+
2294
+	/**
2295
+	 * Soft Deletes this model object.
2296
+	 *
2297
+	 * @param string $source function name that called this method
2298
+	 * @return boolean | int
2299
+	 * @throws DomainException
2300
+	 * @throws EE_Error
2301
+	 * @throws EntityNotFoundException
2302
+	 * @throws InvalidArgumentException
2303
+	 * @throws InvalidDataTypeException
2304
+	 * @throws InvalidInterfaceException
2305
+	 * @throws ReflectionException
2306
+	 * @throws RuntimeException
2307
+	 * @throws UnexpectedEntityException
2308
+	 */
2309
+	public function delete($source = 'unknown')
2310
+	{
2311
+		if ($this->update_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY, $this->status_ID()) === true) {
2312
+			$current_user = wp_get_current_user();
2313
+			$this->add_extra_meta(
2314
+				EE_Registration::EXTRA_META_KEY_REG_TRASHED,
2315
+				array(
2316
+					'trashed-by' => $current_user->ID ? $current_user->display_name : 'unauthed user',
2317
+					'timestamp'  => time(),
2318
+					'source'     => $source,
2319
+				)
2320
+			);
2321
+			$this->set_status(EEM_Registration::status_id_cancelled);
2322
+		}
2323
+		return parent::delete();
2324
+	}
2325
+
2326
+
2327
+	/**
2328
+	 * Restores whatever the previous status was on a registration before it was trashed (if possible)
2329
+	 *
2330
+	 * @param string $source function name that called this method
2331
+	 * @return bool|int
2332
+	 * @throws DomainException
2333
+	 * @throws EE_Error
2334
+	 * @throws EntityNotFoundException
2335
+	 * @throws InvalidArgumentException
2336
+	 * @throws InvalidDataTypeException
2337
+	 * @throws InvalidInterfaceException
2338
+	 * @throws ReflectionException
2339
+	 * @throws RuntimeException
2340
+	 * @throws UnexpectedEntityException
2341
+	 */
2342
+	public function restore($source = 'unknown')
2343
+	{
2344
+		$previous_status = $this->get_extra_meta(
2345
+			EE_Registration::PRE_TRASH_REG_STATUS_KEY,
2346
+			true,
2347
+			EEM_Registration::status_id_cancelled
2348
+		);
2349
+		if ($previous_status) {
2350
+			$this->delete_extra_meta(EE_Registration::PRE_TRASH_REG_STATUS_KEY);
2351
+			$this->set_status($previous_status);
2352
+		}
2353
+		$current_user = wp_get_current_user();
2354
+		$this->add_extra_meta(
2355
+			EE_Registration::EXTRA_META_KEY_REG_RESTORED,
2356
+			array(
2357
+				'restored-by' => $current_user->ID ? $current_user->display_name : 'unauthed user',
2358
+				'timestamp'   => time(),
2359
+				'source'      => $source,
2360
+			)
2361
+		);
2362
+		return parent::restore();
2363
+	}
2364
+
2365
+
2366
+	/**
2367
+	 * possibly toggle Registration status based on comparison of REG_paid vs REG_final_price
2368
+	 *
2369
+	 * @param  boolean $trigger_set_status_logic EE_Registration::set_status() can trigger additional logic
2370
+	 *                                           depending on whether the reg status changes to or from "Approved"
2371
+	 * @return boolean whether the Registration status was updated
2372
+	 * @throws DomainException
2373
+	 * @throws EE_Error
2374
+	 * @throws EntityNotFoundException
2375
+	 * @throws InvalidArgumentException
2376
+	 * @throws InvalidDataTypeException
2377
+	 * @throws InvalidInterfaceException
2378
+	 * @throws ReflectionException
2379
+	 * @throws RuntimeException
2380
+	 * @throws UnexpectedEntityException
2381
+	 */
2382
+	public function updateStatusBasedOnTotalPaid($trigger_set_status_logic = true)
2383
+	{
2384
+		$paid = $this->paid();
2385
+		$price = $this->final_price();
2386
+		switch (true) {
2387
+			// overpaid or paid
2388
+			case EEH_Money::compare_floats($paid, $price, '>'):
2389
+			case EEH_Money::compare_floats($paid, $price):
2390
+				$new_status = EEM_Registration::status_id_approved;
2391
+				break;
2392
+			//  underpaid
2393
+			case EEH_Money::compare_floats($paid, $price, '<'):
2394
+				$new_status = EEM_Registration::status_id_pending_payment;
2395
+				break;
2396
+			// uhhh Houston...
2397
+			default:
2398
+				throw new RuntimeException(
2399
+					esc_html__('The total paid calculation for this registration is inaccurate.', 'event_espresso')
2400
+				);
2401
+		}
2402
+		if ($new_status !== $this->status_ID()) {
2403
+			if ($trigger_set_status_logic) {
2404
+				return $this->set_status($new_status);
2405
+			}
2406
+			parent::set('STS_ID', $new_status);
2407
+			return true;
2408
+		}
2409
+		return false;
2410
+	}
2411
+
2412
+
2413
+	/*************************** DEPRECATED ***************************/
2414
+
2415
+
2416
+	/**
2417
+	 * @deprecated
2418
+	 * @since     4.7.0
2419
+	 */
2420
+	public function price_paid()
2421
+	{
2422
+		EE_Error::doing_it_wrong(
2423
+			'EE_Registration::price_paid()',
2424
+			esc_html__(
2425
+				'This method is deprecated, please use EE_Registration::final_price() instead.',
2426
+				'event_espresso'
2427
+			),
2428
+			'4.7.0'
2429
+		);
2430
+		return $this->final_price();
2431
+	}
2432
+
2433
+
2434
+	/**
2435
+	 * @deprecated
2436
+	 * @since     4.7.0
2437
+	 * @param    float $REG_final_price
2438
+	 * @throws EE_Error
2439
+	 * @throws EntityNotFoundException
2440
+	 * @throws InvalidArgumentException
2441
+	 * @throws InvalidDataTypeException
2442
+	 * @throws InvalidInterfaceException
2443
+	 * @throws ReflectionException
2444
+	 * @throws RuntimeException
2445
+	 * @throws DomainException
2446
+	 */
2447
+	public function set_price_paid($REG_final_price = 0.00)
2448
+	{
2449
+		EE_Error::doing_it_wrong(
2450
+			'EE_Registration::set_price_paid()',
2451
+			esc_html__(
2452
+				'This method is deprecated, please use EE_Registration::set_final_price() instead.',
2453
+				'event_espresso'
2454
+			),
2455
+			'4.7.0'
2456
+		);
2457
+		$this->set_final_price($REG_final_price);
2458
+	}
2459
+
2460
+
2461
+	/**
2462
+	 * @deprecated
2463
+	 * @since 4.7.0
2464
+	 * @return string
2465
+	 * @throws EE_Error
2466
+	 * @throws InvalidArgumentException
2467
+	 * @throws InvalidDataTypeException
2468
+	 * @throws InvalidInterfaceException
2469
+	 * @throws ReflectionException
2470
+	 */
2471
+	public function pretty_price_paid()
2472
+	{
2473
+		EE_Error::doing_it_wrong(
2474
+			'EE_Registration::pretty_price_paid()',
2475
+			esc_html__(
2476
+				'This method is deprecated, please use EE_Registration::pretty_final_price() instead.',
2477
+				'event_espresso'
2478
+			),
2479
+			'4.7.0'
2480
+		);
2481
+		return $this->pretty_final_price();
2482
+	}
2483
+
2484
+
2485
+	/**
2486
+	 * Gets the primary datetime related to this registration via the related Event to this registration
2487
+	 *
2488
+	 * @deprecated 4.9.17
2489
+	 * @return EE_Datetime
2490
+	 * @throws EE_Error
2491
+	 * @throws EntityNotFoundException
2492
+	 * @throws InvalidArgumentException
2493
+	 * @throws InvalidDataTypeException
2494
+	 * @throws InvalidInterfaceException
2495
+	 * @throws ReflectionException
2496
+	 */
2497
+	public function get_related_primary_datetime()
2498
+	{
2499
+		EE_Error::doing_it_wrong(
2500
+			__METHOD__,
2501
+			esc_html__(
2502
+				'Use EE_Registration::get_latest_related_datetime() or EE_Registration::get_earliest_related_datetime()',
2503
+				'event_espresso'
2504
+			),
2505
+			'4.9.17',
2506
+			'5.0.0'
2507
+		);
2508
+		return $this->event()->primary_datetime();
2509
+	}
2510 2510
 }
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;
@@ -442,7 +442,7 @@  discard block
 block discarded – undo
442 442
     public function event()
443 443
     {
444 444
         $event = $this->get_first_related('Event');
445
-        if (! $event instanceof \EE_Event) {
445
+        if ( ! $event instanceof \EE_Event) {
446 446
             throw new EntityNotFoundException('Event ID', $this->event_ID());
447 447
         }
448 448
         return $event;
@@ -489,7 +489,7 @@  discard block
 block discarded – undo
489 489
     {
490 490
         // reserved ticket and datetime counts will be decremented as sold counts are incremented
491 491
         // so stop tracking that this reg has a ticket reserved
492
-        $this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
492
+        $this->release_reserved_ticket(false, "REG: {$this->ID()} (ln:".__LINE__.')');
493 493
         $ticket = $this->ticket();
494 494
         $ticket->increase_sold();
495 495
         $ticket->save();
@@ -542,7 +542,7 @@  discard block
 block discarded – undo
542 542
             $reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, true);
543 543
             if ($reserved && $update_ticket) {
544 544
                 $ticket = $this->ticket();
545
-                $ticket->increase_reserved(1, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
545
+                $ticket->increase_reserved(1, "REG: {$this->ID()} (ln:".__LINE__.')');
546 546
                 $ticket->save();
547 547
             }
548 548
         }
@@ -570,7 +570,7 @@  discard block
 block discarded – undo
570 570
             $reserved = $this->update_extra_meta(EE_Registration::HAS_RESERVED_TICKET_KEY, false);
571 571
             if ($reserved && $update_ticket) {
572 572
                 $ticket = $this->ticket();
573
-                $ticket->decrease_reserved(1, true, "REG: {$this->ID()} (ln:" . __LINE__ . ')');
573
+                $ticket->decrease_reserved(1, true, "REG: {$this->ID()} (ln:".__LINE__.')');
574 574
                 $ticket->save();
575 575
             }
576 576
         }
@@ -1433,7 +1433,7 @@  discard block
 block discarded – undo
1433 1433
                     : '';
1434 1434
                 break;
1435 1435
         }
1436
-        return $icon . $status[ $this->status_ID() ];
1436
+        return $icon.$status[$this->status_ID()];
1437 1437
     }
1438 1438
 
1439 1439
 
@@ -1699,11 +1699,11 @@  discard block
 block discarded – undo
1699 1699
     {
1700 1700
         $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1701 1701
         // first check registration status
1702
-        if (! $DTT_ID || ($check_approved && ! $this->is_approved())) {
1702
+        if ( ! $DTT_ID || ($check_approved && ! $this->is_approved())) {
1703 1703
             return false;
1704 1704
         }
1705 1705
         // is there a datetime ticket that matches this dtt_ID?
1706
-        if (! EEM_Datetime_Ticket::instance()->exists(
1706
+        if ( ! EEM_Datetime_Ticket::instance()->exists(
1707 1707
             array(
1708 1708
                 array(
1709 1709
                     'TKT_ID' => $this->get('TKT_ID'),
@@ -1737,7 +1737,7 @@  discard block
 block discarded – undo
1737 1737
     {
1738 1738
         $DTT_ID = EEM_Datetime::instance()->ensure_is_ID($DTT_OR_ID);
1739 1739
 
1740
-        if (! $DTT_ID) {
1740
+        if ( ! $DTT_ID) {
1741 1741
             return false;
1742 1742
         }
1743 1743
 
@@ -1745,7 +1745,7 @@  discard block
 block discarded – undo
1745 1745
 
1746 1746
         // if max uses is not set or equals infinity then return true cause its not a factor for whether user can
1747 1747
         // check-in or not.
1748
-        if (! $max_uses || $max_uses === EE_INF) {
1748
+        if ( ! $max_uses || $max_uses === EE_INF) {
1749 1749
             return true;
1750 1750
         }
1751 1751
 
@@ -1809,7 +1809,7 @@  discard block
 block discarded – undo
1809 1809
             $datetime = $this->get_latest_related_datetime();
1810 1810
             $DTT_ID = $datetime instanceof EE_Datetime ? $datetime->ID() : 0;
1811 1811
             // verify the registration can checkin for the given DTT_ID
1812
-        } elseif (! $this->can_checkin($DTT_ID, $verify)) {
1812
+        } elseif ( ! $this->can_checkin($DTT_ID, $verify)) {
1813 1813
             EE_Error::add_error(
1814 1814
                 sprintf(
1815 1815
                     esc_html__(
@@ -1832,7 +1832,7 @@  discard block
 block discarded – undo
1832 1832
         );
1833 1833
         // start by getting the current status so we know what status we'll be changing to.
1834 1834
         $cur_status = $this->check_in_status_for_datetime($DTT_ID);
1835
-        $status_to = $status_paths[ $cur_status ];
1835
+        $status_to = $status_paths[$cur_status];
1836 1836
         // database only records true for checked IN or false for checked OUT
1837 1837
         // no record ( null ) means checked in NEVER, but we obviously don't save that
1838 1838
         $new_status = $status_to === EE_Checkin::status_checked_in;
@@ -2017,7 +2017,7 @@  discard block
 block discarded – undo
2017 2017
     public function transaction()
2018 2018
     {
2019 2019
         $transaction = $this->get_first_related('Transaction');
2020
-        if (! $transaction instanceof \EE_Transaction) {
2020
+        if ( ! $transaction instanceof \EE_Transaction) {
2021 2021
             throw new EntityNotFoundException('Transaction ID', $this->transaction_ID());
2022 2022
         }
2023 2023
         return $transaction;
@@ -2090,11 +2090,11 @@  discard block
 block discarded – undo
2090 2090
             );
2091 2091
             return;
2092 2092
         }
2093
-        if (! $this->reg_code()) {
2093
+        if ( ! $this->reg_code()) {
2094 2094
             parent::set('REG_code', $REG_code, $use_default);
2095 2095
         } else {
2096 2096
             EE_Error::doing_it_wrong(
2097
-                __CLASS__ . '::' . __FUNCTION__,
2097
+                __CLASS__.'::'.__FUNCTION__,
2098 2098
                 esc_html__('Can not change a registration REG_code once it has been set.', 'event_espresso'),
2099 2099
                 '4.6.0'
2100 2100
             );
@@ -2284,7 +2284,7 @@  discard block
 block discarded – undo
2284 2284
                 break;
2285 2285
             }
2286 2286
         }
2287
-        if (! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
2287
+        if ( ! ($line_item instanceof \EE_Line_Item && $line_item->OBJ_type() === 'Ticket')) {
2288 2288
             throw new EntityNotFoundException('Line Item Ticket ID', $ticket->ID());
2289 2289
         }
2290 2290
         return $line_item;
Please login to merge, or discard this patch.
admin_pages/registrations/Registrations_Admin_Page.core.php 1 patch
Indentation   +3835 added lines, -3835 removed lines patch added patch discarded remove patch
@@ -20,2406 +20,2406 @@  discard block
 block discarded – undo
20 20
 class Registrations_Admin_Page extends EE_Admin_Page_CPT
21 21
 {
22 22
 
23
-    /**
24
-     * @var EE_Registration
25
-     */
26
-    private $_registration;
27
-
28
-    /**
29
-     * @var EE_Event
30
-     */
31
-    private $_reg_event;
32
-
33
-    /**
34
-     * @var EE_Session
35
-     */
36
-    private $_session;
37
-
38
-    private static $_reg_status;
39
-
40
-    /**
41
-     * Form for displaying the custom questions for this registration.
42
-     * This gets used a few times throughout the request so its best to cache it
43
-     *
44
-     * @var EE_Registration_Custom_Questions_Form
45
-     */
46
-    protected $_reg_custom_questions_form = null;
47
-
48
-
49
-    /**
50
-     *        constructor
51
-     *
52
-     * @Constructor
53
-     * @access public
54
-     * @param bool $routing
55
-     * @return Registrations_Admin_Page
56
-     */
57
-    public function __construct($routing = true)
58
-    {
59
-        parent::__construct($routing);
60
-        add_action('wp_loaded', array($this, 'wp_loaded'));
61
-    }
62
-
63
-
64
-    public function wp_loaded()
65
-    {
66
-        // when adding a new registration...
67
-        if (isset($this->_req_data['action']) && $this->_req_data['action'] === 'new_registration') {
68
-            EE_System::do_not_cache();
69
-            if (! isset($this->_req_data['processing_registration'])
70
-                || absint($this->_req_data['processing_registration']) !== 1
71
-            ) {
72
-                // and it's NOT the attendee information reg step
73
-                // force cookie expiration by setting time to last week
74
-                setcookie('ee_registration_added', 0, time() - WEEK_IN_SECONDS, '/');
75
-                // and update the global
76
-                $_COOKIE['ee_registration_added'] = 0;
77
-            }
78
-        }
79
-    }
80
-
81
-
82
-    protected function _init_page_props()
83
-    {
84
-        $this->page_slug = REG_PG_SLUG;
85
-        $this->_admin_base_url = REG_ADMIN_URL;
86
-        $this->_admin_base_path = REG_ADMIN;
87
-        $this->page_label = esc_html__('Registrations', 'event_espresso');
88
-        $this->_cpt_routes = array(
89
-            'add_new_attendee' => 'espresso_attendees',
90
-            'edit_attendee'    => 'espresso_attendees',
91
-            'insert_attendee'  => 'espresso_attendees',
92
-            'update_attendee'  => 'espresso_attendees',
93
-        );
94
-        $this->_cpt_model_names = array(
95
-            'add_new_attendee' => 'EEM_Attendee',
96
-            'edit_attendee'    => 'EEM_Attendee',
97
-        );
98
-        $this->_cpt_edit_routes = array(
99
-            'espresso_attendees' => 'edit_attendee',
100
-        );
101
-        $this->_pagenow_map = array(
102
-            'add_new_attendee' => 'post-new.php',
103
-            'edit_attendee'    => 'post.php',
104
-            'trash'            => 'post.php',
105
-        );
106
-        add_action('edit_form_after_title', array($this, 'after_title_form_fields'), 10);
107
-        // add filters so that the comment urls don't take users to a confusing 404 page
108
-        add_filter('get_comment_link', array($this, 'clear_comment_link'), 10, 3);
109
-    }
110
-
111
-
112
-    public function clear_comment_link($link, $comment, $args)
113
-    {
114
-        // gotta make sure this only happens on this route
115
-        $post_type = get_post_type($comment->comment_post_ID);
116
-        if ($post_type === 'espresso_attendees') {
117
-            return '#commentsdiv';
118
-        }
119
-        return $link;
120
-    }
121
-
122
-
123
-    protected function _ajax_hooks()
124
-    {
125
-        // todo: all hooks for registrations ajax goes in here
126
-        add_action('wp_ajax_toggle_checkin_status', array($this, 'toggle_checkin_status'));
127
-    }
128
-
129
-
130
-    protected function _define_page_props()
131
-    {
132
-        $this->_admin_page_title = $this->page_label;
133
-        $this->_labels = array(
134
-            'buttons'                      => array(
135
-                'add-registrant'      => esc_html__('Add New Registration', 'event_espresso'),
136
-                'add-attendee'        => esc_html__('Add Contact', 'event_espresso'),
137
-                'edit'                => esc_html__('Edit Contact', 'event_espresso'),
138
-                'report'              => esc_html__("Event Registrations CSV Report", "event_espresso"),
139
-                'report_all'          => esc_html__('All Registrations CSV Report', 'event_espresso'),
140
-                'report_filtered'     => esc_html__('Filtered CSV Report', 'event_espresso'),
141
-                'contact_list_report' => esc_html__('Contact List Report', 'event_espresso'),
142
-                'contact_list_export' => esc_html__("Export Data", "event_espresso"),
143
-            ),
144
-            'publishbox'                   => array(
145
-                'add_new_attendee' => esc_html__("Add Contact Record", 'event_espresso'),
146
-                'edit_attendee'    => esc_html__("Update Contact Record", 'event_espresso'),
147
-            ),
148
-            'hide_add_button_on_cpt_route' => array(
149
-                'edit_attendee' => true,
150
-            ),
151
-        );
152
-    }
153
-
154
-
155
-    /**
156
-     *        grab url requests and route them
157
-     *
158
-     * @access private
159
-     * @return void
160
-     */
161
-    public function _set_page_routes()
162
-    {
163
-        $this->_get_registration_status_array();
164
-        $reg_id = ! empty($this->_req_data['_REG_ID']) && ! is_array($this->_req_data['_REG_ID'])
165
-            ? $this->_req_data['_REG_ID'] : 0;
166
-        $reg_id = empty($reg_id) && ! empty($this->_req_data['reg_status_change_form']['REG_ID'])
167
-            ? $this->_req_data['reg_status_change_form']['REG_ID']
168
-            : $reg_id;
169
-        $att_id = ! empty($this->_req_data['ATT_ID']) && ! is_array($this->_req_data['ATT_ID'])
170
-            ? $this->_req_data['ATT_ID'] : 0;
171
-        $att_id = ! empty($this->_req_data['post']) && ! is_array($this->_req_data['post'])
172
-            ? $this->_req_data['post']
173
-            : $att_id;
174
-        $this->_page_routes = array(
175
-            'default'                             => array(
176
-                'func'       => '_registrations_overview_list_table',
177
-                'capability' => 'ee_read_registrations',
178
-            ),
179
-            'view_registration'                   => array(
180
-                'func'       => '_registration_details',
181
-                'capability' => 'ee_read_registration',
182
-                'obj_id'     => $reg_id,
183
-            ),
184
-            'edit_registration'                   => array(
185
-                'func'               => '_update_attendee_registration_form',
186
-                'noheader'           => true,
187
-                'headers_sent_route' => 'view_registration',
188
-                'capability'         => 'ee_edit_registration',
189
-                'obj_id'             => $reg_id,
190
-                '_REG_ID'            => $reg_id,
191
-            ),
192
-            'trash_registrations'                 => array(
193
-                'func'       => '_trash_or_restore_registrations',
194
-                'args'       => array('trash' => true),
195
-                'noheader'   => true,
196
-                'capability' => 'ee_delete_registrations',
197
-            ),
198
-            'restore_registrations'               => array(
199
-                'func'       => '_trash_or_restore_registrations',
200
-                'args'       => array('trash' => false),
201
-                'noheader'   => true,
202
-                'capability' => 'ee_delete_registrations',
203
-            ),
204
-            'delete_registrations'                => array(
205
-                'func'       => '_delete_registrations',
206
-                'noheader'   => true,
207
-                'capability' => 'ee_delete_registrations',
208
-            ),
209
-            'new_registration'                    => array(
210
-                'func'       => 'new_registration',
211
-                'capability' => 'ee_edit_registrations',
212
-            ),
213
-            'process_reg_step'                    => array(
214
-                'func'       => 'process_reg_step',
215
-                'noheader'   => true,
216
-                'capability' => 'ee_edit_registrations',
217
-            ),
218
-            'redirect_to_txn'                     => array(
219
-                'func'       => 'redirect_to_txn',
220
-                'noheader'   => true,
221
-                'capability' => 'ee_edit_registrations',
222
-            ),
223
-            'change_reg_status'                   => array(
224
-                'func'       => '_change_reg_status',
225
-                'noheader'   => true,
226
-                'capability' => 'ee_edit_registration',
227
-                'obj_id'     => $reg_id,
228
-            ),
229
-            'approve_registration'                => array(
230
-                'func'       => 'approve_registration',
231
-                'noheader'   => true,
232
-                'capability' => 'ee_edit_registration',
233
-                'obj_id'     => $reg_id,
234
-            ),
235
-            'approve_and_notify_registration'     => array(
236
-                'func'       => 'approve_registration',
237
-                'noheader'   => true,
238
-                'args'       => array(true),
239
-                'capability' => 'ee_edit_registration',
240
-                'obj_id'     => $reg_id,
241
-            ),
242
-            'approve_registrations'               => array(
243
-                'func'       => 'bulk_action_on_registrations',
244
-                'noheader'   => true,
245
-                'capability' => 'ee_edit_registrations',
246
-                'args'       => array('approve'),
247
-            ),
248
-            'approve_and_notify_registrations'    => array(
249
-                'func'       => 'bulk_action_on_registrations',
250
-                'noheader'   => true,
251
-                'capability' => 'ee_edit_registrations',
252
-                'args'       => array('approve', true),
253
-            ),
254
-            'decline_registration'                => array(
255
-                'func'       => 'decline_registration',
256
-                'noheader'   => true,
257
-                'capability' => 'ee_edit_registration',
258
-                'obj_id'     => $reg_id,
259
-            ),
260
-            'decline_and_notify_registration'     => array(
261
-                'func'       => 'decline_registration',
262
-                'noheader'   => true,
263
-                'args'       => array(true),
264
-                'capability' => 'ee_edit_registration',
265
-                'obj_id'     => $reg_id,
266
-            ),
267
-            'decline_registrations'               => array(
268
-                'func'       => 'bulk_action_on_registrations',
269
-                'noheader'   => true,
270
-                'capability' => 'ee_edit_registrations',
271
-                'args'       => array('decline'),
272
-            ),
273
-            'decline_and_notify_registrations'    => array(
274
-                'func'       => 'bulk_action_on_registrations',
275
-                'noheader'   => true,
276
-                'capability' => 'ee_edit_registrations',
277
-                'args'       => array('decline', true),
278
-            ),
279
-            'pending_registration'                => array(
280
-                'func'       => 'pending_registration',
281
-                'noheader'   => true,
282
-                'capability' => 'ee_edit_registration',
283
-                'obj_id'     => $reg_id,
284
-            ),
285
-            'pending_and_notify_registration'     => array(
286
-                'func'       => 'pending_registration',
287
-                'noheader'   => true,
288
-                'args'       => array(true),
289
-                'capability' => 'ee_edit_registration',
290
-                'obj_id'     => $reg_id,
291
-            ),
292
-            'pending_registrations'               => array(
293
-                'func'       => 'bulk_action_on_registrations',
294
-                'noheader'   => true,
295
-                'capability' => 'ee_edit_registrations',
296
-                'args'       => array('pending'),
297
-            ),
298
-            'pending_and_notify_registrations'    => array(
299
-                'func'       => 'bulk_action_on_registrations',
300
-                'noheader'   => true,
301
-                'capability' => 'ee_edit_registrations',
302
-                'args'       => array('pending', true),
303
-            ),
304
-            'no_approve_registration'             => array(
305
-                'func'       => 'not_approve_registration',
306
-                'noheader'   => true,
307
-                'capability' => 'ee_edit_registration',
308
-                'obj_id'     => $reg_id,
309
-            ),
310
-            'no_approve_and_notify_registration'  => array(
311
-                'func'       => 'not_approve_registration',
312
-                'noheader'   => true,
313
-                'args'       => array(true),
314
-                'capability' => 'ee_edit_registration',
315
-                'obj_id'     => $reg_id,
316
-            ),
317
-            'no_approve_registrations'            => array(
318
-                'func'       => 'bulk_action_on_registrations',
319
-                'noheader'   => true,
320
-                'capability' => 'ee_edit_registrations',
321
-                'args'       => array('not_approve'),
322
-            ),
323
-            'no_approve_and_notify_registrations' => array(
324
-                'func'       => 'bulk_action_on_registrations',
325
-                'noheader'   => true,
326
-                'capability' => 'ee_edit_registrations',
327
-                'args'       => array('not_approve', true),
328
-            ),
329
-            'cancel_registration'                 => array(
330
-                'func'       => 'cancel_registration',
331
-                'noheader'   => true,
332
-                'capability' => 'ee_edit_registration',
333
-                'obj_id'     => $reg_id,
334
-            ),
335
-            'cancel_and_notify_registration'      => array(
336
-                'func'       => 'cancel_registration',
337
-                'noheader'   => true,
338
-                'args'       => array(true),
339
-                'capability' => 'ee_edit_registration',
340
-                'obj_id'     => $reg_id,
341
-            ),
342
-            'cancel_registrations'                => array(
343
-                'func'       => 'bulk_action_on_registrations',
344
-                'noheader'   => true,
345
-                'capability' => 'ee_edit_registrations',
346
-                'args'       => array('cancel'),
347
-            ),
348
-            'cancel_and_notify_registrations'     => array(
349
-                'func'       => 'bulk_action_on_registrations',
350
-                'noheader'   => true,
351
-                'capability' => 'ee_edit_registrations',
352
-                'args'       => array('cancel', true),
353
-            ),
354
-            'wait_list_registration'              => array(
355
-                'func'       => 'wait_list_registration',
356
-                'noheader'   => true,
357
-                'capability' => 'ee_edit_registration',
358
-                'obj_id'     => $reg_id,
359
-            ),
360
-            'wait_list_and_notify_registration'   => array(
361
-                'func'       => 'wait_list_registration',
362
-                'noheader'   => true,
363
-                'args'       => array(true),
364
-                'capability' => 'ee_edit_registration',
365
-                'obj_id'     => $reg_id,
366
-            ),
367
-            'contact_list'                        => array(
368
-                'func'       => '_attendee_contact_list_table',
369
-                'capability' => 'ee_read_contacts',
370
-            ),
371
-            'add_new_attendee'                    => array(
372
-                'func' => '_create_new_cpt_item',
373
-                'args' => array(
374
-                    'new_attendee' => true,
375
-                    'capability'   => 'ee_edit_contacts',
376
-                ),
377
-            ),
378
-            'edit_attendee'                       => array(
379
-                'func'       => '_edit_cpt_item',
380
-                'capability' => 'ee_edit_contacts',
381
-                'obj_id'     => $att_id,
382
-            ),
383
-            'duplicate_attendee'                  => array(
384
-                'func'       => '_duplicate_attendee',
385
-                'noheader'   => true,
386
-                'capability' => 'ee_edit_contacts',
387
-                'obj_id'     => $att_id,
388
-            ),
389
-            'insert_attendee'                     => array(
390
-                'func'       => '_insert_or_update_attendee',
391
-                'args'       => array(
392
-                    'new_attendee' => true,
393
-                ),
394
-                'noheader'   => true,
395
-                'capability' => 'ee_edit_contacts',
396
-            ),
397
-            'update_attendee'                     => array(
398
-                'func'       => '_insert_or_update_attendee',
399
-                'args'       => array(
400
-                    'new_attendee' => false,
401
-                ),
402
-                'noheader'   => true,
403
-                'capability' => 'ee_edit_contacts',
404
-                'obj_id'     => $att_id,
405
-            ),
406
-            'trash_attendees'                     => array(
407
-                'func'       => '_trash_or_restore_attendees',
408
-                'args'       => array(
409
-                    'trash' => 'true',
410
-                ),
411
-                'noheader'   => true,
412
-                'capability' => 'ee_delete_contacts',
413
-            ),
414
-            'trash_attendee'                      => array(
415
-                'func'       => '_trash_or_restore_attendees',
416
-                'args'       => array(
417
-                    'trash' => true,
418
-                ),
419
-                'noheader'   => true,
420
-                'capability' => 'ee_delete_contacts',
421
-                'obj_id'     => $att_id,
422
-            ),
423
-            'restore_attendees'                   => array(
424
-                'func'       => '_trash_or_restore_attendees',
425
-                'args'       => array(
426
-                    'trash' => false,
427
-                ),
428
-                'noheader'   => true,
429
-                'capability' => 'ee_delete_contacts',
430
-                'obj_id'     => $att_id,
431
-            ),
432
-            'resend_registration'                 => array(
433
-                'func'       => '_resend_registration',
434
-                'noheader'   => true,
435
-                'capability' => 'ee_send_message',
436
-            ),
437
-            'registrations_report'                => array(
438
-                'func'       => '_registrations_report',
439
-                'noheader'   => true,
440
-                'capability' => 'ee_read_registrations',
441
-            ),
442
-            'contact_list_export'                 => array(
443
-                'func'       => '_contact_list_export',
444
-                'noheader'   => true,
445
-                'capability' => 'export',
446
-            ),
447
-            'contact_list_report'                 => array(
448
-                'func'       => '_contact_list_report',
449
-                'noheader'   => true,
450
-                'capability' => 'ee_read_contacts',
451
-            ),
452
-        );
453
-    }
454
-
455
-
456
-    protected function _set_page_config()
457
-    {
458
-        $this->_page_config = array(
459
-            'default'           => array(
460
-                'nav'           => array(
461
-                    'label' => esc_html__('Overview', 'event_espresso'),
462
-                    'order' => 5,
463
-                ),
464
-                'help_tabs'     => array(
465
-                    'registrations_overview_help_tab'                       => array(
466
-                        'title'    => esc_html__('Registrations Overview', 'event_espresso'),
467
-                        'filename' => 'registrations_overview',
468
-                    ),
469
-                    'registrations_overview_table_column_headings_help_tab' => array(
470
-                        'title'    => esc_html__('Registrations Table Column Headings', 'event_espresso'),
471
-                        'filename' => 'registrations_overview_table_column_headings',
472
-                    ),
473
-                    'registrations_overview_filters_help_tab'               => array(
474
-                        'title'    => esc_html__('Registration Filters', 'event_espresso'),
475
-                        'filename' => 'registrations_overview_filters',
476
-                    ),
477
-                    'registrations_overview_views_help_tab'                 => array(
478
-                        'title'    => esc_html__('Registration Views', 'event_espresso'),
479
-                        'filename' => 'registrations_overview_views',
480
-                    ),
481
-                    'registrations_regoverview_other_help_tab'              => array(
482
-                        'title'    => esc_html__('Registrations Other', 'event_espresso'),
483
-                        'filename' => 'registrations_overview_other',
484
-                    ),
485
-                ),
486
-                'help_tour'     => array('Registration_Overview_Help_Tour'),
487
-                'qtips'         => array('Registration_List_Table_Tips'),
488
-                'list_table'    => 'EE_Registrations_List_Table',
489
-                'require_nonce' => false,
490
-            ),
491
-            'view_registration' => array(
492
-                'nav'           => array(
493
-                    'label'      => esc_html__('REG Details', 'event_espresso'),
494
-                    'order'      => 15,
495
-                    'url'        => isset($this->_req_data['_REG_ID'])
496
-                        ? add_query_arg(array('_REG_ID' => $this->_req_data['_REG_ID']), $this->_current_page_view_url)
497
-                        : $this->_admin_base_url,
498
-                    'persistent' => false,
499
-                ),
500
-                'help_tabs'     => array(
501
-                    'registrations_details_help_tab'                    => array(
502
-                        'title'    => esc_html__('Registration Details', 'event_espresso'),
503
-                        'filename' => 'registrations_details',
504
-                    ),
505
-                    'registrations_details_table_help_tab'              => array(
506
-                        'title'    => esc_html__('Registration Details Table', 'event_espresso'),
507
-                        'filename' => 'registrations_details_table',
508
-                    ),
509
-                    'registrations_details_form_answers_help_tab'       => array(
510
-                        'title'    => esc_html__('Registration Form Answers', 'event_espresso'),
511
-                        'filename' => 'registrations_details_form_answers',
512
-                    ),
513
-                    'registrations_details_registrant_details_help_tab' => array(
514
-                        'title'    => esc_html__('Contact Details', 'event_espresso'),
515
-                        'filename' => 'registrations_details_registrant_details',
516
-                    ),
517
-                ),
518
-                'help_tour'     => array('Registration_Details_Help_Tour'),
519
-                'metaboxes'     => array_merge(
520
-                    $this->_default_espresso_metaboxes,
521
-                    array('_registration_details_metaboxes')
522
-                ),
523
-                'require_nonce' => false,
524
-            ),
525
-            'new_registration'  => array(
526
-                'nav'           => array(
527
-                    'label'      => esc_html__('Add New Registration', 'event_espresso'),
528
-                    'url'        => '#',
529
-                    'order'      => 15,
530
-                    'persistent' => false,
531
-                ),
532
-                'metaboxes'     => $this->_default_espresso_metaboxes,
533
-                'labels'        => array(
534
-                    'publishbox' => esc_html__('Save Registration', 'event_espresso'),
535
-                ),
536
-                'require_nonce' => false,
537
-            ),
538
-            'add_new_attendee'  => array(
539
-                'nav'           => array(
540
-                    'label'      => esc_html__('Add Contact', 'event_espresso'),
541
-                    'order'      => 15,
542
-                    'persistent' => false,
543
-                ),
544
-                'metaboxes'     => array_merge(
545
-                    $this->_default_espresso_metaboxes,
546
-                    array('_publish_post_box', 'attendee_editor_metaboxes')
547
-                ),
548
-                'require_nonce' => false,
549
-            ),
550
-            'edit_attendee'     => array(
551
-                'nav'           => array(
552
-                    'label'      => esc_html__('Edit Contact', 'event_espresso'),
553
-                    'order'      => 15,
554
-                    'persistent' => false,
555
-                    'url'        => isset($this->_req_data['ATT_ID'])
556
-                        ? add_query_arg(array('ATT_ID' => $this->_req_data['ATT_ID']), $this->_current_page_view_url)
557
-                        : $this->_admin_base_url,
558
-                ),
559
-                'metaboxes'     => array('attendee_editor_metaboxes'),
560
-                'require_nonce' => false,
561
-            ),
562
-            'contact_list'      => array(
563
-                'nav'           => array(
564
-                    'label' => esc_html__('Contact List', 'event_espresso'),
565
-                    'order' => 20,
566
-                ),
567
-                'list_table'    => 'EE_Attendee_Contact_List_Table',
568
-                'help_tabs'     => array(
569
-                    'registrations_contact_list_help_tab'                       => array(
570
-                        'title'    => esc_html__('Registrations Contact List', 'event_espresso'),
571
-                        'filename' => 'registrations_contact_list',
572
-                    ),
573
-                    'registrations_contact-list_table_column_headings_help_tab' => array(
574
-                        'title'    => esc_html__('Contact List Table Column Headings', 'event_espresso'),
575
-                        'filename' => 'registrations_contact_list_table_column_headings',
576
-                    ),
577
-                    'registrations_contact_list_views_help_tab'                 => array(
578
-                        'title'    => esc_html__('Contact List Views', 'event_espresso'),
579
-                        'filename' => 'registrations_contact_list_views',
580
-                    ),
581
-                    'registrations_contact_list_other_help_tab'                 => array(
582
-                        'title'    => esc_html__('Contact List Other', 'event_espresso'),
583
-                        'filename' => 'registrations_contact_list_other',
584
-                    ),
585
-                ),
586
-                'help_tour'     => array('Contact_List_Help_Tour'),
587
-                'metaboxes'     => array(),
588
-                'require_nonce' => false,
589
-            ),
590
-            // override default cpt routes
591
-            'create_new'        => '',
592
-            'edit'              => '',
593
-        );
594
-    }
595
-
596
-
597
-    /**
598
-     * The below methods aren't used by this class currently
599
-     */
600
-    protected function _add_screen_options()
601
-    {
602
-    }
603
-
604
-
605
-    protected function _add_feature_pointers()
606
-    {
607
-    }
608
-
609
-
610
-    public function admin_init()
611
-    {
612
-        EE_Registry::$i18n_js_strings['update_att_qstns'] = esc_html__(
613
-            'click "Update Registration Questions" to save your changes',
614
-            'event_espresso'
615
-        );
616
-    }
617
-
618
-
619
-    public function admin_notices()
620
-    {
621
-    }
622
-
623
-
624
-    public function admin_footer_scripts()
625
-    {
626
-    }
627
-
628
-
629
-    /**
630
-     *        get list of registration statuses
631
-     *
632
-     * @access private
633
-     * @return void
634
-     * @throws EE_Error
635
-     */
636
-    private function _get_registration_status_array()
637
-    {
638
-        self::$_reg_status = EEM_Registration::reg_status_array(array(), true);
639
-    }
640
-
641
-
642
-    protected function _add_screen_options_default()
643
-    {
644
-        $this->_per_page_screen_option();
645
-    }
646
-
647
-
648
-    protected function _add_screen_options_contact_list()
649
-    {
650
-        $page_title = $this->_admin_page_title;
651
-        $this->_admin_page_title = esc_html__("Contacts", 'event_espresso');
652
-        $this->_per_page_screen_option();
653
-        $this->_admin_page_title = $page_title;
654
-    }
655
-
656
-
657
-    public function load_scripts_styles()
658
-    {
659
-        // style
660
-        wp_register_style(
661
-            'espresso_reg',
662
-            REG_ASSETS_URL . 'espresso_registrations_admin.css',
663
-            array('ee-admin-css'),
664
-            EVENT_ESPRESSO_VERSION
665
-        );
666
-        wp_enqueue_style('espresso_reg');
667
-        // script
668
-        wp_register_script(
669
-            'espresso_reg',
670
-            REG_ASSETS_URL . 'espresso_registrations_admin.js',
671
-            array('jquery-ui-datepicker', 'jquery-ui-draggable', 'ee_admin_js'),
672
-            EVENT_ESPRESSO_VERSION,
673
-            true
674
-        );
675
-        wp_enqueue_script('espresso_reg');
676
-    }
677
-
678
-
679
-    public function load_scripts_styles_edit_attendee()
680
-    {
681
-        // stuff to only show up on our attendee edit details page.
682
-        $attendee_details_translations = array(
683
-            'att_publish_text' => sprintf(
684
-                esc_html__('Created on: <b>%1$s</b>', 'event_espresso'),
685
-                $this->_cpt_model_obj->get_datetime('ATT_created')
686
-            ),
687
-        );
688
-        wp_localize_script('espresso_reg', 'ATTENDEE_DETAILS', $attendee_details_translations);
689
-        wp_enqueue_script('jquery-validate');
690
-    }
691
-
692
-
693
-    public function load_scripts_styles_view_registration()
694
-    {
695
-        // styles
696
-        wp_enqueue_style('espresso-ui-theme');
697
-        // scripts
698
-        $this->_get_reg_custom_questions_form($this->_registration->ID());
699
-        $this->_reg_custom_questions_form->wp_enqueue_scripts(true);
700
-    }
701
-
702
-
703
-    public function load_scripts_styles_contact_list()
704
-    {
705
-        wp_dequeue_style('espresso_reg');
706
-        wp_register_style(
707
-            'espresso_att',
708
-            REG_ASSETS_URL . 'espresso_attendees_admin.css',
709
-            array('ee-admin-css'),
710
-            EVENT_ESPRESSO_VERSION
711
-        );
712
-        wp_enqueue_style('espresso_att');
713
-    }
714
-
715
-
716
-    public function load_scripts_styles_new_registration()
717
-    {
718
-        wp_register_script(
719
-            'ee-spco-for-admin',
720
-            REG_ASSETS_URL . 'spco_for_admin.js',
721
-            array('underscore', 'jquery'),
722
-            EVENT_ESPRESSO_VERSION,
723
-            true
724
-        );
725
-        wp_enqueue_script('ee-spco-for-admin');
726
-        add_filter('FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', '__return_true');
727
-        EE_Form_Section_Proper::wp_enqueue_scripts();
728
-        EED_Ticket_Selector::load_tckt_slctr_assets();
729
-        EE_Datepicker_Input::enqueue_styles_and_scripts();
730
-    }
731
-
732
-
733
-    public function AHEE__EE_Admin_Page__route_admin_request_resend_registration()
734
-    {
735
-        add_filter('FHEE_load_EE_messages', '__return_true');
736
-    }
737
-
738
-
739
-    public function AHEE__EE_Admin_Page__route_admin_request_approve_registration()
740
-    {
741
-        add_filter('FHEE_load_EE_messages', '__return_true');
742
-    }
743
-
744
-
745
-    protected function _set_list_table_views_default()
746
-    {
747
-        // for notification related bulk actions we need to make sure only active messengers have an option.
748
-        EED_Messages::set_autoloaders();
749
-        /** @type EE_Message_Resource_Manager $message_resource_manager */
750
-        $message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
751
-        $active_mts = $message_resource_manager->list_of_active_message_types();
752
-        // key= bulk_action_slug, value= message type.
753
-        $match_array = array(
754
-            'approve_registrations'    => 'registration',
755
-            'decline_registrations'    => 'declined_registration',
756
-            'pending_registrations'    => 'pending_approval',
757
-            'no_approve_registrations' => 'not_approved_registration',
758
-            'cancel_registrations'     => 'cancelled_registration',
759
-        );
760
-        $can_send = EE_Registry::instance()->CAP->current_user_can(
761
-            'ee_send_message',
762
-            'batch_send_messages'
763
-        );
764
-        /** setup reg status bulk actions **/
765
-        $def_reg_status_actions['approve_registrations'] = esc_html__('Approve Registrations', 'event_espresso');
766
-        if ($can_send && in_array($match_array['approve_registrations'], $active_mts, true)) {
767
-            $def_reg_status_actions['approve_and_notify_registrations'] = esc_html__(
768
-                'Approve and Notify Registrations',
769
-                'event_espresso'
770
-            );
771
-        }
772
-        $def_reg_status_actions['decline_registrations'] = esc_html__('Decline Registrations', 'event_espresso');
773
-        if ($can_send && in_array($match_array['decline_registrations'], $active_mts, true)) {
774
-            $def_reg_status_actions['decline_and_notify_registrations'] = esc_html__(
775
-                'Decline and Notify Registrations',
776
-                'event_espresso'
777
-            );
778
-        }
779
-        $def_reg_status_actions['pending_registrations'] = esc_html__(
780
-            'Set Registrations to Pending Payment',
781
-            'event_espresso'
782
-        );
783
-        if ($can_send && in_array($match_array['pending_registrations'], $active_mts, true)) {
784
-            $def_reg_status_actions['pending_and_notify_registrations'] = esc_html__(
785
-                'Set Registrations to Pending Payment and Notify',
786
-                'event_espresso'
787
-            );
788
-        }
789
-        $def_reg_status_actions['no_approve_registrations'] = esc_html__(
790
-            'Set Registrations to Not Approved',
791
-            'event_espresso'
792
-        );
793
-        if ($can_send && in_array($match_array['no_approve_registrations'], $active_mts, true)) {
794
-            $def_reg_status_actions['no_approve_and_notify_registrations'] = esc_html__(
795
-                'Set Registrations to Not Approved and Notify',
796
-                'event_espresso'
797
-            );
798
-        }
799
-        $def_reg_status_actions['cancel_registrations'] = esc_html__('Cancel Registrations', 'event_espresso');
800
-        if ($can_send && in_array($match_array['cancel_registrations'], $active_mts, true)) {
801
-            $def_reg_status_actions['cancel_and_notify_registrations'] = esc_html__(
802
-                'Cancel Registrations and Notify',
803
-                'event_espresso'
804
-            );
805
-        }
806
-        $def_reg_status_actions = apply_filters(
807
-            'FHEE__Registrations_Admin_Page___set_list_table_views_default__def_reg_status_actions_array',
808
-            $def_reg_status_actions,
809
-            $active_mts,
810
-            $can_send
811
-        );
812
-
813
-        $this->_views = array(
814
-            'all'   => array(
815
-                'slug'        => 'all',
816
-                'label'       => esc_html__('View All Registrations', 'event_espresso'),
817
-                'count'       => 0,
818
-                'bulk_action' => array_merge(
819
-                    $def_reg_status_actions,
820
-                    array(
821
-                        'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
822
-                    )
823
-                ),
824
-            ),
825
-            'month' => array(
826
-                'slug'        => 'month',
827
-                'label'       => esc_html__('This Month', 'event_espresso'),
828
-                'count'       => 0,
829
-                'bulk_action' => array_merge(
830
-                    $def_reg_status_actions,
831
-                    array(
832
-                        'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
833
-                    )
834
-                ),
835
-            ),
836
-            'today' => array(
837
-                'slug'        => 'today',
838
-                'label'       => sprintf(
839
-                    esc_html__('Today - %s', 'event_espresso'),
840
-                    date('M d, Y', current_time('timestamp'))
841
-                ),
842
-                'count'       => 0,
843
-                'bulk_action' => array_merge(
844
-                    $def_reg_status_actions,
845
-                    array(
846
-                        'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
847
-                    )
848
-                ),
849
-            ),
850
-        );
851
-        if (EE_Registry::instance()->CAP->current_user_can(
852
-            'ee_delete_registrations',
853
-            'espresso_registrations_delete_registration'
854
-        )) {
855
-            $this->_views['incomplete'] = array(
856
-                'slug'        => 'incomplete',
857
-                'label'       => esc_html__('Incomplete', 'event_espresso'),
858
-                'count'       => 0,
859
-                'bulk_action' => array(
860
-                    'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
861
-                ),
862
-            );
863
-            $this->_views['trash'] = array(
864
-                'slug'        => 'trash',
865
-                'label'       => esc_html__('Trash', 'event_espresso'),
866
-                'count'       => 0,
867
-                'bulk_action' => array(
868
-                    'restore_registrations' => esc_html__('Restore Registrations', 'event_espresso'),
869
-                    'delete_registrations'  => esc_html__('Delete Registrations Permanently', 'event_espresso'),
870
-                ),
871
-            );
872
-        }
873
-    }
874
-
875
-
876
-    protected function _set_list_table_views_contact_list()
877
-    {
878
-        $this->_views = array(
879
-            'in_use' => array(
880
-                'slug'        => 'in_use',
881
-                'label'       => esc_html__('In Use', 'event_espresso'),
882
-                'count'       => 0,
883
-                'bulk_action' => array(
884
-                    'trash_attendees' => esc_html__('Move to Trash', 'event_espresso'),
885
-                ),
886
-            ),
887
-        );
888
-        if (EE_Registry::instance()->CAP->current_user_can(
889
-            'ee_delete_contacts',
890
-            'espresso_registrations_trash_attendees'
891
-        )
892
-        ) {
893
-            $this->_views['trash'] = array(
894
-                'slug'        => 'trash',
895
-                'label'       => esc_html__('Trash', 'event_espresso'),
896
-                'count'       => 0,
897
-                'bulk_action' => array(
898
-                    'restore_attendees' => esc_html__('Restore from Trash', 'event_espresso'),
899
-                ),
900
-            );
901
-        }
902
-    }
903
-
904
-
905
-    protected function _registration_legend_items()
906
-    {
907
-        $fc_items = array(
908
-            'star-icon'        => array(
909
-                'class' => 'dashicons dashicons-star-filled lt-blue-icon ee-icon-size-8',
910
-                'desc'  => esc_html__('This is the Primary Registrant', 'event_espresso'),
911
-            ),
912
-            'view_details'     => array(
913
-                'class' => 'dashicons dashicons-clipboard',
914
-                'desc'  => esc_html__('View Registration Details', 'event_espresso'),
915
-            ),
916
-            'edit_attendee'    => array(
917
-                'class' => 'ee-icon ee-icon-user-edit ee-icon-size-16',
918
-                'desc'  => esc_html__('Edit Contact Details', 'event_espresso'),
919
-            ),
920
-            'view_transaction' => array(
921
-                'class' => 'dashicons dashicons-cart',
922
-                'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
923
-            ),
924
-            'view_invoice'     => array(
925
-                'class' => 'dashicons dashicons-media-spreadsheet',
926
-                'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
927
-            ),
928
-        );
929
-        if (EE_Registry::instance()->CAP->current_user_can(
930
-            'ee_send_message',
931
-            'espresso_registrations_resend_registration'
932
-        )) {
933
-            $fc_items['resend_registration'] = array(
934
-                'class' => 'dashicons dashicons-email-alt',
935
-                'desc'  => esc_html__('Resend Registration Details', 'event_espresso'),
936
-            );
937
-        } else {
938
-            $fc_items['blank'] = array('class' => 'blank', 'desc' => '');
939
-        }
940
-        if (EE_Registry::instance()->CAP->current_user_can(
941
-            'ee_read_global_messages',
942
-            'view_filtered_messages'
943
-        )) {
944
-            $related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
945
-            if (isset($related_for_icon['css_class']) && isset($related_for_icon['label'])) {
946
-                $fc_items['view_related_messages'] = array(
947
-                    'class' => $related_for_icon['css_class'],
948
-                    'desc'  => $related_for_icon['label'],
949
-                );
950
-            }
951
-        }
952
-        $sc_items = array(
953
-            'approved_status'   => array(
954
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_approved,
955
-                'desc'  => EEH_Template::pretty_status(
956
-                    EEM_Registration::status_id_approved,
957
-                    false,
958
-                    'sentence'
959
-                ),
960
-            ),
961
-            'pending_status'    => array(
962
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_pending_payment,
963
-                'desc'  => EEH_Template::pretty_status(
964
-                    EEM_Registration::status_id_pending_payment,
965
-                    false,
966
-                    'sentence'
967
-                ),
968
-            ),
969
-            'wait_list'         => array(
970
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_wait_list,
971
-                'desc'  => EEH_Template::pretty_status(
972
-                    EEM_Registration::status_id_wait_list,
973
-                    false,
974
-                    'sentence'
975
-                ),
976
-            ),
977
-            'incomplete_status' => array(
978
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_incomplete,
979
-                'desc'  => EEH_Template::pretty_status(
980
-                    EEM_Registration::status_id_incomplete,
981
-                    false,
982
-                    'sentence'
983
-                ),
984
-            ),
985
-            'not_approved'      => array(
986
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_not_approved,
987
-                'desc'  => EEH_Template::pretty_status(
988
-                    EEM_Registration::status_id_not_approved,
989
-                    false,
990
-                    'sentence'
991
-                ),
992
-            ),
993
-            'declined_status'   => array(
994
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_declined,
995
-                'desc'  => EEH_Template::pretty_status(
996
-                    EEM_Registration::status_id_declined,
997
-                    false,
998
-                    'sentence'
999
-                ),
1000
-            ),
1001
-            'cancelled_status'  => array(
1002
-                'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_cancelled,
1003
-                'desc'  => EEH_Template::pretty_status(
1004
-                    EEM_Registration::status_id_cancelled,
1005
-                    false,
1006
-                    'sentence'
1007
-                ),
1008
-            ),
1009
-        );
1010
-        return array_merge($fc_items, $sc_items);
1011
-    }
1012
-
1013
-
1014
-
1015
-    /***************************************        REGISTRATION OVERVIEW        **************************************/
1016
-    /**
1017
-     * @throws \EE_Error
1018
-     */
1019
-    protected function _registrations_overview_list_table()
1020
-    {
1021
-        $this->_template_args['admin_page_header'] = '';
1022
-        $EVT_ID = ! empty($this->_req_data['event_id'])
1023
-            ? absint($this->_req_data['event_id'])
1024
-            : 0;
1025
-        $ATT_ID = ! empty($this->_req_data['ATT_ID'])
1026
-            ? absint($this->_req_data['ATT_ID'])
1027
-            : 0;
1028
-        if ($ATT_ID) {
1029
-            $attendee = EEM_Attendee::instance()->get_one_by_ID($ATT_ID);
1030
-            if ($attendee instanceof EE_Attendee) {
1031
-                $this->_template_args['admin_page_header'] = sprintf(
1032
-                    esc_html__(
1033
-                        '%1$s Viewing registrations for %2$s%3$s',
1034
-                        'event_espresso'
1035
-                    ),
1036
-                    '<h3 style="line-height:1.5em;">',
1037
-                    '<a href="' . EE_Admin_Page::add_query_args_and_nonce(
1038
-                        array(
1039
-                            'action' => 'edit_attendee',
1040
-                            'post'   => $ATT_ID,
1041
-                        ),
1042
-                        REG_ADMIN_URL
1043
-                    ) . '">' . $attendee->full_name() . '</a>',
1044
-                    '</h3>'
1045
-                );
1046
-            }
1047
-        }
1048
-        if ($EVT_ID) {
1049
-            if (EE_Registry::instance()->CAP->current_user_can(
1050
-                'ee_edit_registrations',
1051
-                'espresso_registrations_new_registration',
1052
-                $EVT_ID
1053
-            )) {
1054
-                $this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
1055
-                    'new_registration',
1056
-                    'add-registrant',
1057
-                    array('event_id' => $EVT_ID),
1058
-                    'add-new-h2'
1059
-                );
1060
-            }
1061
-            $event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
1062
-            if ($event instanceof EE_Event) {
1063
-                $this->_template_args['admin_page_header'] = sprintf(
1064
-                    esc_html__(
1065
-                        '%s Viewing registrations for the event: %s%s',
1066
-                        'event_espresso'
1067
-                    ),
1068
-                    '<h3 style="line-height:1.5em;">',
1069
-                    '<br /><a href="'
1070
-                    . EE_Admin_Page::add_query_args_and_nonce(
1071
-                        array(
1072
-                            'action' => 'edit',
1073
-                            'post'   => $event->ID(),
1074
-                        ),
1075
-                        EVENTS_ADMIN_URL
1076
-                    )
1077
-                    . '">&nbsp;'
1078
-                    . $event->get('EVT_name')
1079
-                    . '&nbsp;</a>&nbsp;',
1080
-                    '</h3>'
1081
-                );
1082
-            }
1083
-            $DTT_ID = ! empty($this->_req_data['datetime_id']) ? absint($this->_req_data['datetime_id']) : 0;
1084
-            $datetime = EEM_Datetime::instance()->get_one_by_ID($DTT_ID);
1085
-            if ($datetime instanceof EE_Datetime && $this->_template_args['admin_page_header'] !== '') {
1086
-                $this->_template_args['admin_page_header'] = substr(
1087
-                    $this->_template_args['admin_page_header'],
1088
-                    0,
1089
-                    -5
1090
-                );
1091
-                $this->_template_args['admin_page_header'] .= ' &nbsp;<span class="drk-grey-text">';
1092
-                $this->_template_args['admin_page_header'] .= '<span class="dashicons dashicons-calendar"></span>';
1093
-                $this->_template_args['admin_page_header'] .= $datetime->name();
1094
-                $this->_template_args['admin_page_header'] .= ' ( ' . $datetime->start_date() . ' )';
1095
-                $this->_template_args['admin_page_header'] .= '</span></h3>';
1096
-            }
1097
-        }
1098
-        $this->_template_args['after_list_table'] = $this->_display_legend($this->_registration_legend_items());
1099
-        $this->display_admin_list_table_page_with_no_sidebar();
1100
-    }
1101
-
1102
-
1103
-    /**
1104
-     * This sets the _registration property for the registration details screen
1105
-     *
1106
-     * @access private
1107
-     * @return bool
1108
-     * @throws EE_Error
1109
-     * @throws InvalidArgumentException
1110
-     * @throws InvalidDataTypeException
1111
-     * @throws InvalidInterfaceException
1112
-     */
1113
-    private function _set_registration_object()
1114
-    {
1115
-        // get out if we've already set the object
1116
-        if ($this->_registration instanceof EE_Registration) {
1117
-            return true;
1118
-        }
1119
-        $REG = EEM_Registration::instance();
1120
-        $REG_ID = (! empty($this->_req_data['_REG_ID'])) ? absint($this->_req_data['_REG_ID']) : false;
1121
-        if ($this->_registration = $REG->get_one_by_ID($REG_ID)) {
1122
-            return true;
1123
-        } else {
1124
-            $error_msg = sprintf(
1125
-                esc_html__(
1126
-                    'An error occurred and the details for Registration ID #%s could not be retrieved.',
1127
-                    'event_espresso'
1128
-                ),
1129
-                $REG_ID
1130
-            );
1131
-            EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
1132
-            $this->_registration = null;
1133
-            return false;
1134
-        }
1135
-    }
1136
-
1137
-
1138
-    /**
1139
-     * Used to retrieve registrations for the list table.
1140
-     *
1141
-     * @param int  $per_page
1142
-     * @param bool $count
1143
-     * @param bool $this_month
1144
-     * @param bool $today
1145
-     * @return EE_Registration[]|int
1146
-     * @throws EE_Error
1147
-     * @throws InvalidArgumentException
1148
-     * @throws InvalidDataTypeException
1149
-     * @throws InvalidInterfaceException
1150
-     */
1151
-    public function get_registrations(
1152
-        $per_page = 10,
1153
-        $count = false,
1154
-        $this_month = false,
1155
-        $today = false
1156
-    ) {
1157
-        if ($this_month) {
1158
-            $this->_req_data['status'] = 'month';
1159
-        }
1160
-        if ($today) {
1161
-            $this->_req_data['status'] = 'today';
1162
-        }
1163
-        $query_params = $this->_get_registration_query_parameters($this->_req_data, $per_page, $count);
1164
-        /**
1165
-         * Override the default groupby added by EEM_Base so that sorts with multiple order bys work as expected
1166
-         *
1167
-         * @link https://events.codebasehq.com/projects/event-espresso/tickets/10093
1168
-         * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1169
-         *                             or if you have the development copy of EE you can view this at the path:
1170
-         *                             /docs/G--Model-System/model-query-params.md
1171
-         */
1172
-        $query_params['group_by'] = '';
1173
-
1174
-        return $count
1175
-            ? EEM_Registration::instance()->count($query_params)
1176
-            /** @type EE_Registration[] */
1177
-            : EEM_Registration::instance()->get_all($query_params);
1178
-    }
1179
-
1180
-
1181
-    /**
1182
-     * Retrieves the query parameters to be used by the Registration model for getting registrations.
1183
-     * Note: this listens to values on the request for some of the query parameters.
1184
-     *
1185
-     * @param array $request
1186
-     * @param int   $per_page
1187
-     * @param bool  $count
1188
-     * @return array
1189
-     * @throws EE_Error
1190
-     */
1191
-    protected function _get_registration_query_parameters(
1192
-        $request = array(),
1193
-        $per_page = 10,
1194
-        $count = false
1195
-    ) {
1196
-
1197
-        $query_params = array(
1198
-            0                          => $this->_get_where_conditions_for_registrations_query(
1199
-                $request
1200
-            ),
1201
-            'caps'                     => EEM_Registration::caps_read_admin,
1202
-            'default_where_conditions' => 'this_model_only',
1203
-        );
1204
-        if (! $count) {
1205
-            $query_params = array_merge(
1206
-                $query_params,
1207
-                $this->_get_orderby_for_registrations_query(),
1208
-                $this->_get_limit($per_page)
1209
-            );
1210
-        }
1211
-
1212
-        return $query_params;
1213
-    }
1214
-
1215
-
1216
-    /**
1217
-     * This will add ATT_ID to the provided $where array for EE model query parameters.
1218
-     *
1219
-     * @param array $request usually the same as $this->_req_data but not necessarily
1220
-     * @return array
1221
-     */
1222
-    protected function addAttendeeIdToWhereConditions(array $request)
1223
-    {
1224
-        $where = array();
1225
-        if (! empty($request['ATT_ID'])) {
1226
-            $where['ATT_ID'] = absint($request['ATT_ID']);
1227
-        }
1228
-        return $where;
1229
-    }
1230
-
1231
-
1232
-    /**
1233
-     * This will add EVT_ID to the provided $where array for EE model query parameters.
1234
-     *
1235
-     * @param array $request usually the same as $this->_req_data but not necessarily
1236
-     * @return array
1237
-     */
1238
-    protected function _add_event_id_to_where_conditions(array $request)
1239
-    {
1240
-        $where = array();
1241
-        if (! empty($request['event_id'])) {
1242
-            $where['EVT_ID'] = absint($request['event_id']);
1243
-        }
1244
-        return $where;
1245
-    }
1246
-
1247
-
1248
-    /**
1249
-     * Adds category ID if it exists in the request to the where conditions for the registrations query.
1250
-     *
1251
-     * @param array $request usually the same as $this->_req_data but not necessarily
1252
-     * @return array
1253
-     */
1254
-    protected function _add_category_id_to_where_conditions(array $request)
1255
-    {
1256
-        $where = array();
1257
-        if (! empty($request['EVT_CAT']) && (int) $request['EVT_CAT'] !== -1) {
1258
-            $where['Event.Term_Taxonomy.term_id'] = absint($request['EVT_CAT']);
1259
-        }
1260
-        return $where;
1261
-    }
1262
-
1263
-
1264
-    /**
1265
-     * Adds the datetime ID if it exists in the request to the where conditions for the registrations query.
1266
-     *
1267
-     * @param array $request usually the same as $this->_req_data but not necessarily
1268
-     * @return array
1269
-     */
1270
-    protected function _add_datetime_id_to_where_conditions(array $request)
1271
-    {
1272
-        $where = array();
1273
-        if (! empty($request['datetime_id'])) {
1274
-            $where['Ticket.Datetime.DTT_ID'] = absint($request['datetime_id']);
1275
-        }
1276
-        if (! empty($request['DTT_ID'])) {
1277
-            $where['Ticket.Datetime.DTT_ID'] = absint($request['DTT_ID']);
1278
-        }
1279
-        return $where;
1280
-    }
1281
-
1282
-
1283
-    /**
1284
-     * Adds the correct registration status to the where conditions for the registrations query.
1285
-     *
1286
-     * @param array $request usually the same as $this->_req_data but not necessarily
1287
-     * @return array
1288
-     */
1289
-    protected function _add_registration_status_to_where_conditions(array $request)
1290
-    {
1291
-        $where = array();
1292
-        $view = EEH_Array::is_set($request, 'status', '');
1293
-        $registration_status = ! empty($request['_reg_status'])
1294
-            ? sanitize_text_field($request['_reg_status'])
1295
-            : '';
1296
-
1297
-        /*
23
+	/**
24
+	 * @var EE_Registration
25
+	 */
26
+	private $_registration;
27
+
28
+	/**
29
+	 * @var EE_Event
30
+	 */
31
+	private $_reg_event;
32
+
33
+	/**
34
+	 * @var EE_Session
35
+	 */
36
+	private $_session;
37
+
38
+	private static $_reg_status;
39
+
40
+	/**
41
+	 * Form for displaying the custom questions for this registration.
42
+	 * This gets used a few times throughout the request so its best to cache it
43
+	 *
44
+	 * @var EE_Registration_Custom_Questions_Form
45
+	 */
46
+	protected $_reg_custom_questions_form = null;
47
+
48
+
49
+	/**
50
+	 *        constructor
51
+	 *
52
+	 * @Constructor
53
+	 * @access public
54
+	 * @param bool $routing
55
+	 * @return Registrations_Admin_Page
56
+	 */
57
+	public function __construct($routing = true)
58
+	{
59
+		parent::__construct($routing);
60
+		add_action('wp_loaded', array($this, 'wp_loaded'));
61
+	}
62
+
63
+
64
+	public function wp_loaded()
65
+	{
66
+		// when adding a new registration...
67
+		if (isset($this->_req_data['action']) && $this->_req_data['action'] === 'new_registration') {
68
+			EE_System::do_not_cache();
69
+			if (! isset($this->_req_data['processing_registration'])
70
+				|| absint($this->_req_data['processing_registration']) !== 1
71
+			) {
72
+				// and it's NOT the attendee information reg step
73
+				// force cookie expiration by setting time to last week
74
+				setcookie('ee_registration_added', 0, time() - WEEK_IN_SECONDS, '/');
75
+				// and update the global
76
+				$_COOKIE['ee_registration_added'] = 0;
77
+			}
78
+		}
79
+	}
80
+
81
+
82
+	protected function _init_page_props()
83
+	{
84
+		$this->page_slug = REG_PG_SLUG;
85
+		$this->_admin_base_url = REG_ADMIN_URL;
86
+		$this->_admin_base_path = REG_ADMIN;
87
+		$this->page_label = esc_html__('Registrations', 'event_espresso');
88
+		$this->_cpt_routes = array(
89
+			'add_new_attendee' => 'espresso_attendees',
90
+			'edit_attendee'    => 'espresso_attendees',
91
+			'insert_attendee'  => 'espresso_attendees',
92
+			'update_attendee'  => 'espresso_attendees',
93
+		);
94
+		$this->_cpt_model_names = array(
95
+			'add_new_attendee' => 'EEM_Attendee',
96
+			'edit_attendee'    => 'EEM_Attendee',
97
+		);
98
+		$this->_cpt_edit_routes = array(
99
+			'espresso_attendees' => 'edit_attendee',
100
+		);
101
+		$this->_pagenow_map = array(
102
+			'add_new_attendee' => 'post-new.php',
103
+			'edit_attendee'    => 'post.php',
104
+			'trash'            => 'post.php',
105
+		);
106
+		add_action('edit_form_after_title', array($this, 'after_title_form_fields'), 10);
107
+		// add filters so that the comment urls don't take users to a confusing 404 page
108
+		add_filter('get_comment_link', array($this, 'clear_comment_link'), 10, 3);
109
+	}
110
+
111
+
112
+	public function clear_comment_link($link, $comment, $args)
113
+	{
114
+		// gotta make sure this only happens on this route
115
+		$post_type = get_post_type($comment->comment_post_ID);
116
+		if ($post_type === 'espresso_attendees') {
117
+			return '#commentsdiv';
118
+		}
119
+		return $link;
120
+	}
121
+
122
+
123
+	protected function _ajax_hooks()
124
+	{
125
+		// todo: all hooks for registrations ajax goes in here
126
+		add_action('wp_ajax_toggle_checkin_status', array($this, 'toggle_checkin_status'));
127
+	}
128
+
129
+
130
+	protected function _define_page_props()
131
+	{
132
+		$this->_admin_page_title = $this->page_label;
133
+		$this->_labels = array(
134
+			'buttons'                      => array(
135
+				'add-registrant'      => esc_html__('Add New Registration', 'event_espresso'),
136
+				'add-attendee'        => esc_html__('Add Contact', 'event_espresso'),
137
+				'edit'                => esc_html__('Edit Contact', 'event_espresso'),
138
+				'report'              => esc_html__("Event Registrations CSV Report", "event_espresso"),
139
+				'report_all'          => esc_html__('All Registrations CSV Report', 'event_espresso'),
140
+				'report_filtered'     => esc_html__('Filtered CSV Report', 'event_espresso'),
141
+				'contact_list_report' => esc_html__('Contact List Report', 'event_espresso'),
142
+				'contact_list_export' => esc_html__("Export Data", "event_espresso"),
143
+			),
144
+			'publishbox'                   => array(
145
+				'add_new_attendee' => esc_html__("Add Contact Record", 'event_espresso'),
146
+				'edit_attendee'    => esc_html__("Update Contact Record", 'event_espresso'),
147
+			),
148
+			'hide_add_button_on_cpt_route' => array(
149
+				'edit_attendee' => true,
150
+			),
151
+		);
152
+	}
153
+
154
+
155
+	/**
156
+	 *        grab url requests and route them
157
+	 *
158
+	 * @access private
159
+	 * @return void
160
+	 */
161
+	public function _set_page_routes()
162
+	{
163
+		$this->_get_registration_status_array();
164
+		$reg_id = ! empty($this->_req_data['_REG_ID']) && ! is_array($this->_req_data['_REG_ID'])
165
+			? $this->_req_data['_REG_ID'] : 0;
166
+		$reg_id = empty($reg_id) && ! empty($this->_req_data['reg_status_change_form']['REG_ID'])
167
+			? $this->_req_data['reg_status_change_form']['REG_ID']
168
+			: $reg_id;
169
+		$att_id = ! empty($this->_req_data['ATT_ID']) && ! is_array($this->_req_data['ATT_ID'])
170
+			? $this->_req_data['ATT_ID'] : 0;
171
+		$att_id = ! empty($this->_req_data['post']) && ! is_array($this->_req_data['post'])
172
+			? $this->_req_data['post']
173
+			: $att_id;
174
+		$this->_page_routes = array(
175
+			'default'                             => array(
176
+				'func'       => '_registrations_overview_list_table',
177
+				'capability' => 'ee_read_registrations',
178
+			),
179
+			'view_registration'                   => array(
180
+				'func'       => '_registration_details',
181
+				'capability' => 'ee_read_registration',
182
+				'obj_id'     => $reg_id,
183
+			),
184
+			'edit_registration'                   => array(
185
+				'func'               => '_update_attendee_registration_form',
186
+				'noheader'           => true,
187
+				'headers_sent_route' => 'view_registration',
188
+				'capability'         => 'ee_edit_registration',
189
+				'obj_id'             => $reg_id,
190
+				'_REG_ID'            => $reg_id,
191
+			),
192
+			'trash_registrations'                 => array(
193
+				'func'       => '_trash_or_restore_registrations',
194
+				'args'       => array('trash' => true),
195
+				'noheader'   => true,
196
+				'capability' => 'ee_delete_registrations',
197
+			),
198
+			'restore_registrations'               => array(
199
+				'func'       => '_trash_or_restore_registrations',
200
+				'args'       => array('trash' => false),
201
+				'noheader'   => true,
202
+				'capability' => 'ee_delete_registrations',
203
+			),
204
+			'delete_registrations'                => array(
205
+				'func'       => '_delete_registrations',
206
+				'noheader'   => true,
207
+				'capability' => 'ee_delete_registrations',
208
+			),
209
+			'new_registration'                    => array(
210
+				'func'       => 'new_registration',
211
+				'capability' => 'ee_edit_registrations',
212
+			),
213
+			'process_reg_step'                    => array(
214
+				'func'       => 'process_reg_step',
215
+				'noheader'   => true,
216
+				'capability' => 'ee_edit_registrations',
217
+			),
218
+			'redirect_to_txn'                     => array(
219
+				'func'       => 'redirect_to_txn',
220
+				'noheader'   => true,
221
+				'capability' => 'ee_edit_registrations',
222
+			),
223
+			'change_reg_status'                   => array(
224
+				'func'       => '_change_reg_status',
225
+				'noheader'   => true,
226
+				'capability' => 'ee_edit_registration',
227
+				'obj_id'     => $reg_id,
228
+			),
229
+			'approve_registration'                => array(
230
+				'func'       => 'approve_registration',
231
+				'noheader'   => true,
232
+				'capability' => 'ee_edit_registration',
233
+				'obj_id'     => $reg_id,
234
+			),
235
+			'approve_and_notify_registration'     => array(
236
+				'func'       => 'approve_registration',
237
+				'noheader'   => true,
238
+				'args'       => array(true),
239
+				'capability' => 'ee_edit_registration',
240
+				'obj_id'     => $reg_id,
241
+			),
242
+			'approve_registrations'               => array(
243
+				'func'       => 'bulk_action_on_registrations',
244
+				'noheader'   => true,
245
+				'capability' => 'ee_edit_registrations',
246
+				'args'       => array('approve'),
247
+			),
248
+			'approve_and_notify_registrations'    => array(
249
+				'func'       => 'bulk_action_on_registrations',
250
+				'noheader'   => true,
251
+				'capability' => 'ee_edit_registrations',
252
+				'args'       => array('approve', true),
253
+			),
254
+			'decline_registration'                => array(
255
+				'func'       => 'decline_registration',
256
+				'noheader'   => true,
257
+				'capability' => 'ee_edit_registration',
258
+				'obj_id'     => $reg_id,
259
+			),
260
+			'decline_and_notify_registration'     => array(
261
+				'func'       => 'decline_registration',
262
+				'noheader'   => true,
263
+				'args'       => array(true),
264
+				'capability' => 'ee_edit_registration',
265
+				'obj_id'     => $reg_id,
266
+			),
267
+			'decline_registrations'               => array(
268
+				'func'       => 'bulk_action_on_registrations',
269
+				'noheader'   => true,
270
+				'capability' => 'ee_edit_registrations',
271
+				'args'       => array('decline'),
272
+			),
273
+			'decline_and_notify_registrations'    => array(
274
+				'func'       => 'bulk_action_on_registrations',
275
+				'noheader'   => true,
276
+				'capability' => 'ee_edit_registrations',
277
+				'args'       => array('decline', true),
278
+			),
279
+			'pending_registration'                => array(
280
+				'func'       => 'pending_registration',
281
+				'noheader'   => true,
282
+				'capability' => 'ee_edit_registration',
283
+				'obj_id'     => $reg_id,
284
+			),
285
+			'pending_and_notify_registration'     => array(
286
+				'func'       => 'pending_registration',
287
+				'noheader'   => true,
288
+				'args'       => array(true),
289
+				'capability' => 'ee_edit_registration',
290
+				'obj_id'     => $reg_id,
291
+			),
292
+			'pending_registrations'               => array(
293
+				'func'       => 'bulk_action_on_registrations',
294
+				'noheader'   => true,
295
+				'capability' => 'ee_edit_registrations',
296
+				'args'       => array('pending'),
297
+			),
298
+			'pending_and_notify_registrations'    => array(
299
+				'func'       => 'bulk_action_on_registrations',
300
+				'noheader'   => true,
301
+				'capability' => 'ee_edit_registrations',
302
+				'args'       => array('pending', true),
303
+			),
304
+			'no_approve_registration'             => array(
305
+				'func'       => 'not_approve_registration',
306
+				'noheader'   => true,
307
+				'capability' => 'ee_edit_registration',
308
+				'obj_id'     => $reg_id,
309
+			),
310
+			'no_approve_and_notify_registration'  => array(
311
+				'func'       => 'not_approve_registration',
312
+				'noheader'   => true,
313
+				'args'       => array(true),
314
+				'capability' => 'ee_edit_registration',
315
+				'obj_id'     => $reg_id,
316
+			),
317
+			'no_approve_registrations'            => array(
318
+				'func'       => 'bulk_action_on_registrations',
319
+				'noheader'   => true,
320
+				'capability' => 'ee_edit_registrations',
321
+				'args'       => array('not_approve'),
322
+			),
323
+			'no_approve_and_notify_registrations' => array(
324
+				'func'       => 'bulk_action_on_registrations',
325
+				'noheader'   => true,
326
+				'capability' => 'ee_edit_registrations',
327
+				'args'       => array('not_approve', true),
328
+			),
329
+			'cancel_registration'                 => array(
330
+				'func'       => 'cancel_registration',
331
+				'noheader'   => true,
332
+				'capability' => 'ee_edit_registration',
333
+				'obj_id'     => $reg_id,
334
+			),
335
+			'cancel_and_notify_registration'      => array(
336
+				'func'       => 'cancel_registration',
337
+				'noheader'   => true,
338
+				'args'       => array(true),
339
+				'capability' => 'ee_edit_registration',
340
+				'obj_id'     => $reg_id,
341
+			),
342
+			'cancel_registrations'                => array(
343
+				'func'       => 'bulk_action_on_registrations',
344
+				'noheader'   => true,
345
+				'capability' => 'ee_edit_registrations',
346
+				'args'       => array('cancel'),
347
+			),
348
+			'cancel_and_notify_registrations'     => array(
349
+				'func'       => 'bulk_action_on_registrations',
350
+				'noheader'   => true,
351
+				'capability' => 'ee_edit_registrations',
352
+				'args'       => array('cancel', true),
353
+			),
354
+			'wait_list_registration'              => array(
355
+				'func'       => 'wait_list_registration',
356
+				'noheader'   => true,
357
+				'capability' => 'ee_edit_registration',
358
+				'obj_id'     => $reg_id,
359
+			),
360
+			'wait_list_and_notify_registration'   => array(
361
+				'func'       => 'wait_list_registration',
362
+				'noheader'   => true,
363
+				'args'       => array(true),
364
+				'capability' => 'ee_edit_registration',
365
+				'obj_id'     => $reg_id,
366
+			),
367
+			'contact_list'                        => array(
368
+				'func'       => '_attendee_contact_list_table',
369
+				'capability' => 'ee_read_contacts',
370
+			),
371
+			'add_new_attendee'                    => array(
372
+				'func' => '_create_new_cpt_item',
373
+				'args' => array(
374
+					'new_attendee' => true,
375
+					'capability'   => 'ee_edit_contacts',
376
+				),
377
+			),
378
+			'edit_attendee'                       => array(
379
+				'func'       => '_edit_cpt_item',
380
+				'capability' => 'ee_edit_contacts',
381
+				'obj_id'     => $att_id,
382
+			),
383
+			'duplicate_attendee'                  => array(
384
+				'func'       => '_duplicate_attendee',
385
+				'noheader'   => true,
386
+				'capability' => 'ee_edit_contacts',
387
+				'obj_id'     => $att_id,
388
+			),
389
+			'insert_attendee'                     => array(
390
+				'func'       => '_insert_or_update_attendee',
391
+				'args'       => array(
392
+					'new_attendee' => true,
393
+				),
394
+				'noheader'   => true,
395
+				'capability' => 'ee_edit_contacts',
396
+			),
397
+			'update_attendee'                     => array(
398
+				'func'       => '_insert_or_update_attendee',
399
+				'args'       => array(
400
+					'new_attendee' => false,
401
+				),
402
+				'noheader'   => true,
403
+				'capability' => 'ee_edit_contacts',
404
+				'obj_id'     => $att_id,
405
+			),
406
+			'trash_attendees'                     => array(
407
+				'func'       => '_trash_or_restore_attendees',
408
+				'args'       => array(
409
+					'trash' => 'true',
410
+				),
411
+				'noheader'   => true,
412
+				'capability' => 'ee_delete_contacts',
413
+			),
414
+			'trash_attendee'                      => array(
415
+				'func'       => '_trash_or_restore_attendees',
416
+				'args'       => array(
417
+					'trash' => true,
418
+				),
419
+				'noheader'   => true,
420
+				'capability' => 'ee_delete_contacts',
421
+				'obj_id'     => $att_id,
422
+			),
423
+			'restore_attendees'                   => array(
424
+				'func'       => '_trash_or_restore_attendees',
425
+				'args'       => array(
426
+					'trash' => false,
427
+				),
428
+				'noheader'   => true,
429
+				'capability' => 'ee_delete_contacts',
430
+				'obj_id'     => $att_id,
431
+			),
432
+			'resend_registration'                 => array(
433
+				'func'       => '_resend_registration',
434
+				'noheader'   => true,
435
+				'capability' => 'ee_send_message',
436
+			),
437
+			'registrations_report'                => array(
438
+				'func'       => '_registrations_report',
439
+				'noheader'   => true,
440
+				'capability' => 'ee_read_registrations',
441
+			),
442
+			'contact_list_export'                 => array(
443
+				'func'       => '_contact_list_export',
444
+				'noheader'   => true,
445
+				'capability' => 'export',
446
+			),
447
+			'contact_list_report'                 => array(
448
+				'func'       => '_contact_list_report',
449
+				'noheader'   => true,
450
+				'capability' => 'ee_read_contacts',
451
+			),
452
+		);
453
+	}
454
+
455
+
456
+	protected function _set_page_config()
457
+	{
458
+		$this->_page_config = array(
459
+			'default'           => array(
460
+				'nav'           => array(
461
+					'label' => esc_html__('Overview', 'event_espresso'),
462
+					'order' => 5,
463
+				),
464
+				'help_tabs'     => array(
465
+					'registrations_overview_help_tab'                       => array(
466
+						'title'    => esc_html__('Registrations Overview', 'event_espresso'),
467
+						'filename' => 'registrations_overview',
468
+					),
469
+					'registrations_overview_table_column_headings_help_tab' => array(
470
+						'title'    => esc_html__('Registrations Table Column Headings', 'event_espresso'),
471
+						'filename' => 'registrations_overview_table_column_headings',
472
+					),
473
+					'registrations_overview_filters_help_tab'               => array(
474
+						'title'    => esc_html__('Registration Filters', 'event_espresso'),
475
+						'filename' => 'registrations_overview_filters',
476
+					),
477
+					'registrations_overview_views_help_tab'                 => array(
478
+						'title'    => esc_html__('Registration Views', 'event_espresso'),
479
+						'filename' => 'registrations_overview_views',
480
+					),
481
+					'registrations_regoverview_other_help_tab'              => array(
482
+						'title'    => esc_html__('Registrations Other', 'event_espresso'),
483
+						'filename' => 'registrations_overview_other',
484
+					),
485
+				),
486
+				'help_tour'     => array('Registration_Overview_Help_Tour'),
487
+				'qtips'         => array('Registration_List_Table_Tips'),
488
+				'list_table'    => 'EE_Registrations_List_Table',
489
+				'require_nonce' => false,
490
+			),
491
+			'view_registration' => array(
492
+				'nav'           => array(
493
+					'label'      => esc_html__('REG Details', 'event_espresso'),
494
+					'order'      => 15,
495
+					'url'        => isset($this->_req_data['_REG_ID'])
496
+						? add_query_arg(array('_REG_ID' => $this->_req_data['_REG_ID']), $this->_current_page_view_url)
497
+						: $this->_admin_base_url,
498
+					'persistent' => false,
499
+				),
500
+				'help_tabs'     => array(
501
+					'registrations_details_help_tab'                    => array(
502
+						'title'    => esc_html__('Registration Details', 'event_espresso'),
503
+						'filename' => 'registrations_details',
504
+					),
505
+					'registrations_details_table_help_tab'              => array(
506
+						'title'    => esc_html__('Registration Details Table', 'event_espresso'),
507
+						'filename' => 'registrations_details_table',
508
+					),
509
+					'registrations_details_form_answers_help_tab'       => array(
510
+						'title'    => esc_html__('Registration Form Answers', 'event_espresso'),
511
+						'filename' => 'registrations_details_form_answers',
512
+					),
513
+					'registrations_details_registrant_details_help_tab' => array(
514
+						'title'    => esc_html__('Contact Details', 'event_espresso'),
515
+						'filename' => 'registrations_details_registrant_details',
516
+					),
517
+				),
518
+				'help_tour'     => array('Registration_Details_Help_Tour'),
519
+				'metaboxes'     => array_merge(
520
+					$this->_default_espresso_metaboxes,
521
+					array('_registration_details_metaboxes')
522
+				),
523
+				'require_nonce' => false,
524
+			),
525
+			'new_registration'  => array(
526
+				'nav'           => array(
527
+					'label'      => esc_html__('Add New Registration', 'event_espresso'),
528
+					'url'        => '#',
529
+					'order'      => 15,
530
+					'persistent' => false,
531
+				),
532
+				'metaboxes'     => $this->_default_espresso_metaboxes,
533
+				'labels'        => array(
534
+					'publishbox' => esc_html__('Save Registration', 'event_espresso'),
535
+				),
536
+				'require_nonce' => false,
537
+			),
538
+			'add_new_attendee'  => array(
539
+				'nav'           => array(
540
+					'label'      => esc_html__('Add Contact', 'event_espresso'),
541
+					'order'      => 15,
542
+					'persistent' => false,
543
+				),
544
+				'metaboxes'     => array_merge(
545
+					$this->_default_espresso_metaboxes,
546
+					array('_publish_post_box', 'attendee_editor_metaboxes')
547
+				),
548
+				'require_nonce' => false,
549
+			),
550
+			'edit_attendee'     => array(
551
+				'nav'           => array(
552
+					'label'      => esc_html__('Edit Contact', 'event_espresso'),
553
+					'order'      => 15,
554
+					'persistent' => false,
555
+					'url'        => isset($this->_req_data['ATT_ID'])
556
+						? add_query_arg(array('ATT_ID' => $this->_req_data['ATT_ID']), $this->_current_page_view_url)
557
+						: $this->_admin_base_url,
558
+				),
559
+				'metaboxes'     => array('attendee_editor_metaboxes'),
560
+				'require_nonce' => false,
561
+			),
562
+			'contact_list'      => array(
563
+				'nav'           => array(
564
+					'label' => esc_html__('Contact List', 'event_espresso'),
565
+					'order' => 20,
566
+				),
567
+				'list_table'    => 'EE_Attendee_Contact_List_Table',
568
+				'help_tabs'     => array(
569
+					'registrations_contact_list_help_tab'                       => array(
570
+						'title'    => esc_html__('Registrations Contact List', 'event_espresso'),
571
+						'filename' => 'registrations_contact_list',
572
+					),
573
+					'registrations_contact-list_table_column_headings_help_tab' => array(
574
+						'title'    => esc_html__('Contact List Table Column Headings', 'event_espresso'),
575
+						'filename' => 'registrations_contact_list_table_column_headings',
576
+					),
577
+					'registrations_contact_list_views_help_tab'                 => array(
578
+						'title'    => esc_html__('Contact List Views', 'event_espresso'),
579
+						'filename' => 'registrations_contact_list_views',
580
+					),
581
+					'registrations_contact_list_other_help_tab'                 => array(
582
+						'title'    => esc_html__('Contact List Other', 'event_espresso'),
583
+						'filename' => 'registrations_contact_list_other',
584
+					),
585
+				),
586
+				'help_tour'     => array('Contact_List_Help_Tour'),
587
+				'metaboxes'     => array(),
588
+				'require_nonce' => false,
589
+			),
590
+			// override default cpt routes
591
+			'create_new'        => '',
592
+			'edit'              => '',
593
+		);
594
+	}
595
+
596
+
597
+	/**
598
+	 * The below methods aren't used by this class currently
599
+	 */
600
+	protected function _add_screen_options()
601
+	{
602
+	}
603
+
604
+
605
+	protected function _add_feature_pointers()
606
+	{
607
+	}
608
+
609
+
610
+	public function admin_init()
611
+	{
612
+		EE_Registry::$i18n_js_strings['update_att_qstns'] = esc_html__(
613
+			'click "Update Registration Questions" to save your changes',
614
+			'event_espresso'
615
+		);
616
+	}
617
+
618
+
619
+	public function admin_notices()
620
+	{
621
+	}
622
+
623
+
624
+	public function admin_footer_scripts()
625
+	{
626
+	}
627
+
628
+
629
+	/**
630
+	 *        get list of registration statuses
631
+	 *
632
+	 * @access private
633
+	 * @return void
634
+	 * @throws EE_Error
635
+	 */
636
+	private function _get_registration_status_array()
637
+	{
638
+		self::$_reg_status = EEM_Registration::reg_status_array(array(), true);
639
+	}
640
+
641
+
642
+	protected function _add_screen_options_default()
643
+	{
644
+		$this->_per_page_screen_option();
645
+	}
646
+
647
+
648
+	protected function _add_screen_options_contact_list()
649
+	{
650
+		$page_title = $this->_admin_page_title;
651
+		$this->_admin_page_title = esc_html__("Contacts", 'event_espresso');
652
+		$this->_per_page_screen_option();
653
+		$this->_admin_page_title = $page_title;
654
+	}
655
+
656
+
657
+	public function load_scripts_styles()
658
+	{
659
+		// style
660
+		wp_register_style(
661
+			'espresso_reg',
662
+			REG_ASSETS_URL . 'espresso_registrations_admin.css',
663
+			array('ee-admin-css'),
664
+			EVENT_ESPRESSO_VERSION
665
+		);
666
+		wp_enqueue_style('espresso_reg');
667
+		// script
668
+		wp_register_script(
669
+			'espresso_reg',
670
+			REG_ASSETS_URL . 'espresso_registrations_admin.js',
671
+			array('jquery-ui-datepicker', 'jquery-ui-draggable', 'ee_admin_js'),
672
+			EVENT_ESPRESSO_VERSION,
673
+			true
674
+		);
675
+		wp_enqueue_script('espresso_reg');
676
+	}
677
+
678
+
679
+	public function load_scripts_styles_edit_attendee()
680
+	{
681
+		// stuff to only show up on our attendee edit details page.
682
+		$attendee_details_translations = array(
683
+			'att_publish_text' => sprintf(
684
+				esc_html__('Created on: <b>%1$s</b>', 'event_espresso'),
685
+				$this->_cpt_model_obj->get_datetime('ATT_created')
686
+			),
687
+		);
688
+		wp_localize_script('espresso_reg', 'ATTENDEE_DETAILS', $attendee_details_translations);
689
+		wp_enqueue_script('jquery-validate');
690
+	}
691
+
692
+
693
+	public function load_scripts_styles_view_registration()
694
+	{
695
+		// styles
696
+		wp_enqueue_style('espresso-ui-theme');
697
+		// scripts
698
+		$this->_get_reg_custom_questions_form($this->_registration->ID());
699
+		$this->_reg_custom_questions_form->wp_enqueue_scripts(true);
700
+	}
701
+
702
+
703
+	public function load_scripts_styles_contact_list()
704
+	{
705
+		wp_dequeue_style('espresso_reg');
706
+		wp_register_style(
707
+			'espresso_att',
708
+			REG_ASSETS_URL . 'espresso_attendees_admin.css',
709
+			array('ee-admin-css'),
710
+			EVENT_ESPRESSO_VERSION
711
+		);
712
+		wp_enqueue_style('espresso_att');
713
+	}
714
+
715
+
716
+	public function load_scripts_styles_new_registration()
717
+	{
718
+		wp_register_script(
719
+			'ee-spco-for-admin',
720
+			REG_ASSETS_URL . 'spco_for_admin.js',
721
+			array('underscore', 'jquery'),
722
+			EVENT_ESPRESSO_VERSION,
723
+			true
724
+		);
725
+		wp_enqueue_script('ee-spco-for-admin');
726
+		add_filter('FHEE__EED_Ticket_Selector__load_tckt_slctr_assets', '__return_true');
727
+		EE_Form_Section_Proper::wp_enqueue_scripts();
728
+		EED_Ticket_Selector::load_tckt_slctr_assets();
729
+		EE_Datepicker_Input::enqueue_styles_and_scripts();
730
+	}
731
+
732
+
733
+	public function AHEE__EE_Admin_Page__route_admin_request_resend_registration()
734
+	{
735
+		add_filter('FHEE_load_EE_messages', '__return_true');
736
+	}
737
+
738
+
739
+	public function AHEE__EE_Admin_Page__route_admin_request_approve_registration()
740
+	{
741
+		add_filter('FHEE_load_EE_messages', '__return_true');
742
+	}
743
+
744
+
745
+	protected function _set_list_table_views_default()
746
+	{
747
+		// for notification related bulk actions we need to make sure only active messengers have an option.
748
+		EED_Messages::set_autoloaders();
749
+		/** @type EE_Message_Resource_Manager $message_resource_manager */
750
+		$message_resource_manager = EE_Registry::instance()->load_lib('Message_Resource_Manager');
751
+		$active_mts = $message_resource_manager->list_of_active_message_types();
752
+		// key= bulk_action_slug, value= message type.
753
+		$match_array = array(
754
+			'approve_registrations'    => 'registration',
755
+			'decline_registrations'    => 'declined_registration',
756
+			'pending_registrations'    => 'pending_approval',
757
+			'no_approve_registrations' => 'not_approved_registration',
758
+			'cancel_registrations'     => 'cancelled_registration',
759
+		);
760
+		$can_send = EE_Registry::instance()->CAP->current_user_can(
761
+			'ee_send_message',
762
+			'batch_send_messages'
763
+		);
764
+		/** setup reg status bulk actions **/
765
+		$def_reg_status_actions['approve_registrations'] = esc_html__('Approve Registrations', 'event_espresso');
766
+		if ($can_send && in_array($match_array['approve_registrations'], $active_mts, true)) {
767
+			$def_reg_status_actions['approve_and_notify_registrations'] = esc_html__(
768
+				'Approve and Notify Registrations',
769
+				'event_espresso'
770
+			);
771
+		}
772
+		$def_reg_status_actions['decline_registrations'] = esc_html__('Decline Registrations', 'event_espresso');
773
+		if ($can_send && in_array($match_array['decline_registrations'], $active_mts, true)) {
774
+			$def_reg_status_actions['decline_and_notify_registrations'] = esc_html__(
775
+				'Decline and Notify Registrations',
776
+				'event_espresso'
777
+			);
778
+		}
779
+		$def_reg_status_actions['pending_registrations'] = esc_html__(
780
+			'Set Registrations to Pending Payment',
781
+			'event_espresso'
782
+		);
783
+		if ($can_send && in_array($match_array['pending_registrations'], $active_mts, true)) {
784
+			$def_reg_status_actions['pending_and_notify_registrations'] = esc_html__(
785
+				'Set Registrations to Pending Payment and Notify',
786
+				'event_espresso'
787
+			);
788
+		}
789
+		$def_reg_status_actions['no_approve_registrations'] = esc_html__(
790
+			'Set Registrations to Not Approved',
791
+			'event_espresso'
792
+		);
793
+		if ($can_send && in_array($match_array['no_approve_registrations'], $active_mts, true)) {
794
+			$def_reg_status_actions['no_approve_and_notify_registrations'] = esc_html__(
795
+				'Set Registrations to Not Approved and Notify',
796
+				'event_espresso'
797
+			);
798
+		}
799
+		$def_reg_status_actions['cancel_registrations'] = esc_html__('Cancel Registrations', 'event_espresso');
800
+		if ($can_send && in_array($match_array['cancel_registrations'], $active_mts, true)) {
801
+			$def_reg_status_actions['cancel_and_notify_registrations'] = esc_html__(
802
+				'Cancel Registrations and Notify',
803
+				'event_espresso'
804
+			);
805
+		}
806
+		$def_reg_status_actions = apply_filters(
807
+			'FHEE__Registrations_Admin_Page___set_list_table_views_default__def_reg_status_actions_array',
808
+			$def_reg_status_actions,
809
+			$active_mts,
810
+			$can_send
811
+		);
812
+
813
+		$this->_views = array(
814
+			'all'   => array(
815
+				'slug'        => 'all',
816
+				'label'       => esc_html__('View All Registrations', 'event_espresso'),
817
+				'count'       => 0,
818
+				'bulk_action' => array_merge(
819
+					$def_reg_status_actions,
820
+					array(
821
+						'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
822
+					)
823
+				),
824
+			),
825
+			'month' => array(
826
+				'slug'        => 'month',
827
+				'label'       => esc_html__('This Month', 'event_espresso'),
828
+				'count'       => 0,
829
+				'bulk_action' => array_merge(
830
+					$def_reg_status_actions,
831
+					array(
832
+						'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
833
+					)
834
+				),
835
+			),
836
+			'today' => array(
837
+				'slug'        => 'today',
838
+				'label'       => sprintf(
839
+					esc_html__('Today - %s', 'event_espresso'),
840
+					date('M d, Y', current_time('timestamp'))
841
+				),
842
+				'count'       => 0,
843
+				'bulk_action' => array_merge(
844
+					$def_reg_status_actions,
845
+					array(
846
+						'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
847
+					)
848
+				),
849
+			),
850
+		);
851
+		if (EE_Registry::instance()->CAP->current_user_can(
852
+			'ee_delete_registrations',
853
+			'espresso_registrations_delete_registration'
854
+		)) {
855
+			$this->_views['incomplete'] = array(
856
+				'slug'        => 'incomplete',
857
+				'label'       => esc_html__('Incomplete', 'event_espresso'),
858
+				'count'       => 0,
859
+				'bulk_action' => array(
860
+					'trash_registrations' => esc_html__('Trash Registrations', 'event_espresso'),
861
+				),
862
+			);
863
+			$this->_views['trash'] = array(
864
+				'slug'        => 'trash',
865
+				'label'       => esc_html__('Trash', 'event_espresso'),
866
+				'count'       => 0,
867
+				'bulk_action' => array(
868
+					'restore_registrations' => esc_html__('Restore Registrations', 'event_espresso'),
869
+					'delete_registrations'  => esc_html__('Delete Registrations Permanently', 'event_espresso'),
870
+				),
871
+			);
872
+		}
873
+	}
874
+
875
+
876
+	protected function _set_list_table_views_contact_list()
877
+	{
878
+		$this->_views = array(
879
+			'in_use' => array(
880
+				'slug'        => 'in_use',
881
+				'label'       => esc_html__('In Use', 'event_espresso'),
882
+				'count'       => 0,
883
+				'bulk_action' => array(
884
+					'trash_attendees' => esc_html__('Move to Trash', 'event_espresso'),
885
+				),
886
+			),
887
+		);
888
+		if (EE_Registry::instance()->CAP->current_user_can(
889
+			'ee_delete_contacts',
890
+			'espresso_registrations_trash_attendees'
891
+		)
892
+		) {
893
+			$this->_views['trash'] = array(
894
+				'slug'        => 'trash',
895
+				'label'       => esc_html__('Trash', 'event_espresso'),
896
+				'count'       => 0,
897
+				'bulk_action' => array(
898
+					'restore_attendees' => esc_html__('Restore from Trash', 'event_espresso'),
899
+				),
900
+			);
901
+		}
902
+	}
903
+
904
+
905
+	protected function _registration_legend_items()
906
+	{
907
+		$fc_items = array(
908
+			'star-icon'        => array(
909
+				'class' => 'dashicons dashicons-star-filled lt-blue-icon ee-icon-size-8',
910
+				'desc'  => esc_html__('This is the Primary Registrant', 'event_espresso'),
911
+			),
912
+			'view_details'     => array(
913
+				'class' => 'dashicons dashicons-clipboard',
914
+				'desc'  => esc_html__('View Registration Details', 'event_espresso'),
915
+			),
916
+			'edit_attendee'    => array(
917
+				'class' => 'ee-icon ee-icon-user-edit ee-icon-size-16',
918
+				'desc'  => esc_html__('Edit Contact Details', 'event_espresso'),
919
+			),
920
+			'view_transaction' => array(
921
+				'class' => 'dashicons dashicons-cart',
922
+				'desc'  => esc_html__('View Transaction Details', 'event_espresso'),
923
+			),
924
+			'view_invoice'     => array(
925
+				'class' => 'dashicons dashicons-media-spreadsheet',
926
+				'desc'  => esc_html__('View Transaction Invoice', 'event_espresso'),
927
+			),
928
+		);
929
+		if (EE_Registry::instance()->CAP->current_user_can(
930
+			'ee_send_message',
931
+			'espresso_registrations_resend_registration'
932
+		)) {
933
+			$fc_items['resend_registration'] = array(
934
+				'class' => 'dashicons dashicons-email-alt',
935
+				'desc'  => esc_html__('Resend Registration Details', 'event_espresso'),
936
+			);
937
+		} else {
938
+			$fc_items['blank'] = array('class' => 'blank', 'desc' => '');
939
+		}
940
+		if (EE_Registry::instance()->CAP->current_user_can(
941
+			'ee_read_global_messages',
942
+			'view_filtered_messages'
943
+		)) {
944
+			$related_for_icon = EEH_MSG_Template::get_message_action_icon('see_notifications_for');
945
+			if (isset($related_for_icon['css_class']) && isset($related_for_icon['label'])) {
946
+				$fc_items['view_related_messages'] = array(
947
+					'class' => $related_for_icon['css_class'],
948
+					'desc'  => $related_for_icon['label'],
949
+				);
950
+			}
951
+		}
952
+		$sc_items = array(
953
+			'approved_status'   => array(
954
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_approved,
955
+				'desc'  => EEH_Template::pretty_status(
956
+					EEM_Registration::status_id_approved,
957
+					false,
958
+					'sentence'
959
+				),
960
+			),
961
+			'pending_status'    => array(
962
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_pending_payment,
963
+				'desc'  => EEH_Template::pretty_status(
964
+					EEM_Registration::status_id_pending_payment,
965
+					false,
966
+					'sentence'
967
+				),
968
+			),
969
+			'wait_list'         => array(
970
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_wait_list,
971
+				'desc'  => EEH_Template::pretty_status(
972
+					EEM_Registration::status_id_wait_list,
973
+					false,
974
+					'sentence'
975
+				),
976
+			),
977
+			'incomplete_status' => array(
978
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_incomplete,
979
+				'desc'  => EEH_Template::pretty_status(
980
+					EEM_Registration::status_id_incomplete,
981
+					false,
982
+					'sentence'
983
+				),
984
+			),
985
+			'not_approved'      => array(
986
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_not_approved,
987
+				'desc'  => EEH_Template::pretty_status(
988
+					EEM_Registration::status_id_not_approved,
989
+					false,
990
+					'sentence'
991
+				),
992
+			),
993
+			'declined_status'   => array(
994
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_declined,
995
+				'desc'  => EEH_Template::pretty_status(
996
+					EEM_Registration::status_id_declined,
997
+					false,
998
+					'sentence'
999
+				),
1000
+			),
1001
+			'cancelled_status'  => array(
1002
+				'class' => 'ee-status-legend ee-status-legend-' . EEM_Registration::status_id_cancelled,
1003
+				'desc'  => EEH_Template::pretty_status(
1004
+					EEM_Registration::status_id_cancelled,
1005
+					false,
1006
+					'sentence'
1007
+				),
1008
+			),
1009
+		);
1010
+		return array_merge($fc_items, $sc_items);
1011
+	}
1012
+
1013
+
1014
+
1015
+	/***************************************        REGISTRATION OVERVIEW        **************************************/
1016
+	/**
1017
+	 * @throws \EE_Error
1018
+	 */
1019
+	protected function _registrations_overview_list_table()
1020
+	{
1021
+		$this->_template_args['admin_page_header'] = '';
1022
+		$EVT_ID = ! empty($this->_req_data['event_id'])
1023
+			? absint($this->_req_data['event_id'])
1024
+			: 0;
1025
+		$ATT_ID = ! empty($this->_req_data['ATT_ID'])
1026
+			? absint($this->_req_data['ATT_ID'])
1027
+			: 0;
1028
+		if ($ATT_ID) {
1029
+			$attendee = EEM_Attendee::instance()->get_one_by_ID($ATT_ID);
1030
+			if ($attendee instanceof EE_Attendee) {
1031
+				$this->_template_args['admin_page_header'] = sprintf(
1032
+					esc_html__(
1033
+						'%1$s Viewing registrations for %2$s%3$s',
1034
+						'event_espresso'
1035
+					),
1036
+					'<h3 style="line-height:1.5em;">',
1037
+					'<a href="' . EE_Admin_Page::add_query_args_and_nonce(
1038
+						array(
1039
+							'action' => 'edit_attendee',
1040
+							'post'   => $ATT_ID,
1041
+						),
1042
+						REG_ADMIN_URL
1043
+					) . '">' . $attendee->full_name() . '</a>',
1044
+					'</h3>'
1045
+				);
1046
+			}
1047
+		}
1048
+		if ($EVT_ID) {
1049
+			if (EE_Registry::instance()->CAP->current_user_can(
1050
+				'ee_edit_registrations',
1051
+				'espresso_registrations_new_registration',
1052
+				$EVT_ID
1053
+			)) {
1054
+				$this->_admin_page_title .= ' ' . $this->get_action_link_or_button(
1055
+					'new_registration',
1056
+					'add-registrant',
1057
+					array('event_id' => $EVT_ID),
1058
+					'add-new-h2'
1059
+				);
1060
+			}
1061
+			$event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
1062
+			if ($event instanceof EE_Event) {
1063
+				$this->_template_args['admin_page_header'] = sprintf(
1064
+					esc_html__(
1065
+						'%s Viewing registrations for the event: %s%s',
1066
+						'event_espresso'
1067
+					),
1068
+					'<h3 style="line-height:1.5em;">',
1069
+					'<br /><a href="'
1070
+					. EE_Admin_Page::add_query_args_and_nonce(
1071
+						array(
1072
+							'action' => 'edit',
1073
+							'post'   => $event->ID(),
1074
+						),
1075
+						EVENTS_ADMIN_URL
1076
+					)
1077
+					. '">&nbsp;'
1078
+					. $event->get('EVT_name')
1079
+					. '&nbsp;</a>&nbsp;',
1080
+					'</h3>'
1081
+				);
1082
+			}
1083
+			$DTT_ID = ! empty($this->_req_data['datetime_id']) ? absint($this->_req_data['datetime_id']) : 0;
1084
+			$datetime = EEM_Datetime::instance()->get_one_by_ID($DTT_ID);
1085
+			if ($datetime instanceof EE_Datetime && $this->_template_args['admin_page_header'] !== '') {
1086
+				$this->_template_args['admin_page_header'] = substr(
1087
+					$this->_template_args['admin_page_header'],
1088
+					0,
1089
+					-5
1090
+				);
1091
+				$this->_template_args['admin_page_header'] .= ' &nbsp;<span class="drk-grey-text">';
1092
+				$this->_template_args['admin_page_header'] .= '<span class="dashicons dashicons-calendar"></span>';
1093
+				$this->_template_args['admin_page_header'] .= $datetime->name();
1094
+				$this->_template_args['admin_page_header'] .= ' ( ' . $datetime->start_date() . ' )';
1095
+				$this->_template_args['admin_page_header'] .= '</span></h3>';
1096
+			}
1097
+		}
1098
+		$this->_template_args['after_list_table'] = $this->_display_legend($this->_registration_legend_items());
1099
+		$this->display_admin_list_table_page_with_no_sidebar();
1100
+	}
1101
+
1102
+
1103
+	/**
1104
+	 * This sets the _registration property for the registration details screen
1105
+	 *
1106
+	 * @access private
1107
+	 * @return bool
1108
+	 * @throws EE_Error
1109
+	 * @throws InvalidArgumentException
1110
+	 * @throws InvalidDataTypeException
1111
+	 * @throws InvalidInterfaceException
1112
+	 */
1113
+	private function _set_registration_object()
1114
+	{
1115
+		// get out if we've already set the object
1116
+		if ($this->_registration instanceof EE_Registration) {
1117
+			return true;
1118
+		}
1119
+		$REG = EEM_Registration::instance();
1120
+		$REG_ID = (! empty($this->_req_data['_REG_ID'])) ? absint($this->_req_data['_REG_ID']) : false;
1121
+		if ($this->_registration = $REG->get_one_by_ID($REG_ID)) {
1122
+			return true;
1123
+		} else {
1124
+			$error_msg = sprintf(
1125
+				esc_html__(
1126
+					'An error occurred and the details for Registration ID #%s could not be retrieved.',
1127
+					'event_espresso'
1128
+				),
1129
+				$REG_ID
1130
+			);
1131
+			EE_Error::add_error($error_msg, __FILE__, __FUNCTION__, __LINE__);
1132
+			$this->_registration = null;
1133
+			return false;
1134
+		}
1135
+	}
1136
+
1137
+
1138
+	/**
1139
+	 * Used to retrieve registrations for the list table.
1140
+	 *
1141
+	 * @param int  $per_page
1142
+	 * @param bool $count
1143
+	 * @param bool $this_month
1144
+	 * @param bool $today
1145
+	 * @return EE_Registration[]|int
1146
+	 * @throws EE_Error
1147
+	 * @throws InvalidArgumentException
1148
+	 * @throws InvalidDataTypeException
1149
+	 * @throws InvalidInterfaceException
1150
+	 */
1151
+	public function get_registrations(
1152
+		$per_page = 10,
1153
+		$count = false,
1154
+		$this_month = false,
1155
+		$today = false
1156
+	) {
1157
+		if ($this_month) {
1158
+			$this->_req_data['status'] = 'month';
1159
+		}
1160
+		if ($today) {
1161
+			$this->_req_data['status'] = 'today';
1162
+		}
1163
+		$query_params = $this->_get_registration_query_parameters($this->_req_data, $per_page, $count);
1164
+		/**
1165
+		 * Override the default groupby added by EEM_Base so that sorts with multiple order bys work as expected
1166
+		 *
1167
+		 * @link https://events.codebasehq.com/projects/event-espresso/tickets/10093
1168
+		 * @see https://github.com/eventespresso/event-espresso-core/tree/master/docs/G--Model-System/model-query-params.md
1169
+		 *                             or if you have the development copy of EE you can view this at the path:
1170
+		 *                             /docs/G--Model-System/model-query-params.md
1171
+		 */
1172
+		$query_params['group_by'] = '';
1173
+
1174
+		return $count
1175
+			? EEM_Registration::instance()->count($query_params)
1176
+			/** @type EE_Registration[] */
1177
+			: EEM_Registration::instance()->get_all($query_params);
1178
+	}
1179
+
1180
+
1181
+	/**
1182
+	 * Retrieves the query parameters to be used by the Registration model for getting registrations.
1183
+	 * Note: this listens to values on the request for some of the query parameters.
1184
+	 *
1185
+	 * @param array $request
1186
+	 * @param int   $per_page
1187
+	 * @param bool  $count
1188
+	 * @return array
1189
+	 * @throws EE_Error
1190
+	 */
1191
+	protected function _get_registration_query_parameters(
1192
+		$request = array(),
1193
+		$per_page = 10,
1194
+		$count = false
1195
+	) {
1196
+
1197
+		$query_params = array(
1198
+			0                          => $this->_get_where_conditions_for_registrations_query(
1199
+				$request
1200
+			),
1201
+			'caps'                     => EEM_Registration::caps_read_admin,
1202
+			'default_where_conditions' => 'this_model_only',
1203
+		);
1204
+		if (! $count) {
1205
+			$query_params = array_merge(
1206
+				$query_params,
1207
+				$this->_get_orderby_for_registrations_query(),
1208
+				$this->_get_limit($per_page)
1209
+			);
1210
+		}
1211
+
1212
+		return $query_params;
1213
+	}
1214
+
1215
+
1216
+	/**
1217
+	 * This will add ATT_ID to the provided $where array for EE model query parameters.
1218
+	 *
1219
+	 * @param array $request usually the same as $this->_req_data but not necessarily
1220
+	 * @return array
1221
+	 */
1222
+	protected function addAttendeeIdToWhereConditions(array $request)
1223
+	{
1224
+		$where = array();
1225
+		if (! empty($request['ATT_ID'])) {
1226
+			$where['ATT_ID'] = absint($request['ATT_ID']);
1227
+		}
1228
+		return $where;
1229
+	}
1230
+
1231
+
1232
+	/**
1233
+	 * This will add EVT_ID to the provided $where array for EE model query parameters.
1234
+	 *
1235
+	 * @param array $request usually the same as $this->_req_data but not necessarily
1236
+	 * @return array
1237
+	 */
1238
+	protected function _add_event_id_to_where_conditions(array $request)
1239
+	{
1240
+		$where = array();
1241
+		if (! empty($request['event_id'])) {
1242
+			$where['EVT_ID'] = absint($request['event_id']);
1243
+		}
1244
+		return $where;
1245
+	}
1246
+
1247
+
1248
+	/**
1249
+	 * Adds category ID if it exists in the request to the where conditions for the registrations query.
1250
+	 *
1251
+	 * @param array $request usually the same as $this->_req_data but not necessarily
1252
+	 * @return array
1253
+	 */
1254
+	protected function _add_category_id_to_where_conditions(array $request)
1255
+	{
1256
+		$where = array();
1257
+		if (! empty($request['EVT_CAT']) && (int) $request['EVT_CAT'] !== -1) {
1258
+			$where['Event.Term_Taxonomy.term_id'] = absint($request['EVT_CAT']);
1259
+		}
1260
+		return $where;
1261
+	}
1262
+
1263
+
1264
+	/**
1265
+	 * Adds the datetime ID if it exists in the request to the where conditions for the registrations query.
1266
+	 *
1267
+	 * @param array $request usually the same as $this->_req_data but not necessarily
1268
+	 * @return array
1269
+	 */
1270
+	protected function _add_datetime_id_to_where_conditions(array $request)
1271
+	{
1272
+		$where = array();
1273
+		if (! empty($request['datetime_id'])) {
1274
+			$where['Ticket.Datetime.DTT_ID'] = absint($request['datetime_id']);
1275
+		}
1276
+		if (! empty($request['DTT_ID'])) {
1277
+			$where['Ticket.Datetime.DTT_ID'] = absint($request['DTT_ID']);
1278
+		}
1279
+		return $where;
1280
+	}
1281
+
1282
+
1283
+	/**
1284
+	 * Adds the correct registration status to the where conditions for the registrations query.
1285
+	 *
1286
+	 * @param array $request usually the same as $this->_req_data but not necessarily
1287
+	 * @return array
1288
+	 */
1289
+	protected function _add_registration_status_to_where_conditions(array $request)
1290
+	{
1291
+		$where = array();
1292
+		$view = EEH_Array::is_set($request, 'status', '');
1293
+		$registration_status = ! empty($request['_reg_status'])
1294
+			? sanitize_text_field($request['_reg_status'])
1295
+			: '';
1296
+
1297
+		/*
1298 1298
          * If filtering by registration status, then we show registrations matching that status.
1299 1299
          * If not filtering by specified status, then we show all registrations excluding incomplete registrations
1300 1300
          * UNLESS viewing trashed registrations.
1301 1301
          */
1302
-        if (! empty($registration_status)) {
1303
-            $where['STS_ID'] = $registration_status;
1304
-        } else {
1305
-            // make sure we exclude incomplete registrations, but only if not trashed.
1306
-            if ($view === 'trash') {
1307
-                $where['REG_deleted'] = true;
1308
-            } elseif ($view === 'incomplete') {
1309
-                $where['STS_ID'] = EEM_Registration::status_id_incomplete;
1310
-            } else {
1311
-                $where['STS_ID'] = array('!=', EEM_Registration::status_id_incomplete);
1312
-            }
1313
-        }
1314
-        return $where;
1315
-    }
1316
-
1317
-
1318
-    /**
1319
-     * Adds any provided date restraints to the where conditions for the registrations query.
1320
-     *
1321
-     * @param array $request usually the same as $this->_req_data but not necessarily
1322
-     * @return array
1323
-     * @throws EE_Error
1324
-     * @throws InvalidArgumentException
1325
-     * @throws InvalidDataTypeException
1326
-     * @throws InvalidInterfaceException
1327
-     */
1328
-    protected function _add_date_to_where_conditions(array $request)
1329
-    {
1330
-        $where = array();
1331
-        $view = EEH_Array::is_set($request, 'status', '');
1332
-        $month_range = ! empty($request['month_range'])
1333
-            ? sanitize_text_field($request['month_range'])
1334
-            : '';
1335
-        $retrieve_for_today = $view === 'today';
1336
-        $retrieve_for_this_month = $view === 'month';
1337
-
1338
-        if ($retrieve_for_today) {
1339
-            $now = date('Y-m-d', current_time('timestamp'));
1340
-            $where['REG_date'] = array(
1341
-                'BETWEEN',
1342
-                array(
1343
-                    EEM_Registration::instance()->convert_datetime_for_query(
1344
-                        'REG_date',
1345
-                        $now . ' 00:00:00',
1346
-                        'Y-m-d H:i:s'
1347
-                    ),
1348
-                    EEM_Registration::instance()->convert_datetime_for_query(
1349
-                        'REG_date',
1350
-                        $now . ' 23:59:59',
1351
-                        'Y-m-d H:i:s'
1352
-                    ),
1353
-                ),
1354
-            );
1355
-        } elseif ($retrieve_for_this_month) {
1356
-            $current_year_and_month = date('Y-m', current_time('timestamp'));
1357
-            $days_this_month = date('t', current_time('timestamp'));
1358
-            $where['REG_date'] = array(
1359
-                'BETWEEN',
1360
-                array(
1361
-                    EEM_Registration::instance()->convert_datetime_for_query(
1362
-                        'REG_date',
1363
-                        $current_year_and_month . '-01 00:00:00',
1364
-                        'Y-m-d H:i:s'
1365
-                    ),
1366
-                    EEM_Registration::instance()->convert_datetime_for_query(
1367
-                        'REG_date',
1368
-                        $current_year_and_month . '-' . $days_this_month . ' 23:59:59',
1369
-                        'Y-m-d H:i:s'
1370
-                    ),
1371
-                ),
1372
-            );
1373
-        } elseif ($month_range) {
1374
-            $pieces = explode(' ', $month_range, 3);
1375
-            $month_requested = ! empty($pieces[0])
1376
-                ? date('m', \EEH_DTT_Helper::first_of_month_timestamp($pieces[0]))
1377
-                : '';
1378
-            $year_requested = ! empty($pieces[1])
1379
-                ? $pieces[1]
1380
-                : '';
1381
-            // if there is not a month or year then we can't go further
1382
-            if ($month_requested && $year_requested) {
1383
-                $days_in_month = date('t', strtotime($year_requested . '-' . $month_requested . '-' . '01'));
1384
-                $where['REG_date'] = array(
1385
-                    'BETWEEN',
1386
-                    array(
1387
-                        EEM_Registration::instance()->convert_datetime_for_query(
1388
-                            'REG_date',
1389
-                            $year_requested . '-' . $month_requested . '-01 00:00:00',
1390
-                            'Y-m-d H:i:s'
1391
-                        ),
1392
-                        EEM_Registration::instance()->convert_datetime_for_query(
1393
-                            'REG_date',
1394
-                            $year_requested . '-' . $month_requested . '-' . $days_in_month . ' 23:59:59',
1395
-                            'Y-m-d H:i:s'
1396
-                        ),
1397
-                    ),
1398
-                );
1399
-            }
1400
-        }
1401
-        return $where;
1402
-    }
1403
-
1404
-
1405
-    /**
1406
-     * Adds any provided search restraints to the where conditions for the registrations query
1407
-     *
1408
-     * @param array $request usually the same as $this->_req_data but not necessarily
1409
-     * @return array
1410
-     */
1411
-    protected function _add_search_to_where_conditions(array $request)
1412
-    {
1413
-        $where = array();
1414
-        if (! empty($request['s'])) {
1415
-            $search_string = '%' . sanitize_text_field($request['s']) . '%';
1416
-            $where['OR*search_conditions'] = array(
1417
-                'Event.EVT_name'                          => array('LIKE', $search_string),
1418
-                'Event.EVT_desc'                          => array('LIKE', $search_string),
1419
-                'Event.EVT_short_desc'                    => array('LIKE', $search_string),
1420
-                'Attendee.ATT_full_name'                  => array('LIKE', $search_string),
1421
-                'Attendee.ATT_fname'                      => array('LIKE', $search_string),
1422
-                'Attendee.ATT_lname'                      => array('LIKE', $search_string),
1423
-                'Attendee.ATT_short_bio'                  => array('LIKE', $search_string),
1424
-                'Attendee.ATT_email'                      => array('LIKE', $search_string),
1425
-                'Attendee.ATT_address'                    => array('LIKE', $search_string),
1426
-                'Attendee.ATT_address2'                   => array('LIKE', $search_string),
1427
-                'Attendee.ATT_city'                       => array('LIKE', $search_string),
1428
-                'REG_final_price'                         => array('LIKE', $search_string),
1429
-                'REG_code'                                => array('LIKE', $search_string),
1430
-                'REG_count'                               => array('LIKE', $search_string),
1431
-                'REG_group_size'                          => array('LIKE', $search_string),
1432
-                'Ticket.TKT_name'                         => array('LIKE', $search_string),
1433
-                'Ticket.TKT_description'                  => array('LIKE', $search_string),
1434
-                'Transaction.Payment.PAY_txn_id_chq_nmbr' => array('LIKE', $search_string),
1435
-            );
1436
-        }
1437
-        return $where;
1438
-    }
1439
-
1440
-
1441
-    /**
1442
-     * Sets up the where conditions for the registrations query.
1443
-     *
1444
-     * @param array $request
1445
-     * @return array
1446
-     * @throws EE_Error
1447
-     */
1448
-    protected function _get_where_conditions_for_registrations_query($request)
1449
-    {
1450
-        return apply_filters(
1451
-            'FHEE__Registrations_Admin_Page___get_where_conditions_for_registrations_query',
1452
-            array_merge(
1453
-                $this->addAttendeeIdToWhereConditions($request),
1454
-                $this->_add_event_id_to_where_conditions($request),
1455
-                $this->_add_category_id_to_where_conditions($request),
1456
-                $this->_add_datetime_id_to_where_conditions($request),
1457
-                $this->_add_registration_status_to_where_conditions($request),
1458
-                $this->_add_date_to_where_conditions($request),
1459
-                $this->_add_search_to_where_conditions($request)
1460
-            ),
1461
-            $request
1462
-        );
1463
-    }
1464
-
1465
-
1466
-    /**
1467
-     * Sets up the orderby for the registrations query.
1468
-     *
1469
-     * @return array
1470
-     */
1471
-    protected function _get_orderby_for_registrations_query()
1472
-    {
1473
-        $orderby_field = ! empty($this->_req_data['orderby'])
1474
-            ? sanitize_text_field($this->_req_data['orderby'])
1475
-            : '_REG_date';
1476
-        switch ($orderby_field) {
1477
-            case '_REG_ID':
1478
-                $orderby = array('REG_ID');
1479
-                break;
1480
-            case '_Reg_status':
1481
-                $orderby = array('STS_ID');
1482
-                break;
1483
-            case 'ATT_fname':
1484
-                $orderby = array('Attendee.ATT_fname', 'Attendee.ATT_lname');
1485
-                break;
1486
-            case 'ATT_lname':
1487
-                $orderby = array('Attendee.ATT_lname', 'Attendee.ATT_fname');
1488
-                break;
1489
-            case 'event_name':
1490
-                $orderby = array('Event.EVT_name');
1491
-                break;
1492
-            case 'DTT_EVT_start':
1493
-                $orderby = array('Event.Datetime.DTT_EVT_start');
1494
-                break;
1495
-            case '_REG_date':
1496
-                $orderby = array('REG_date');
1497
-                break;
1498
-            default:
1499
-                $orderby = array($orderby_field);
1500
-                break;
1501
-        }
1502
-
1503
-        // order
1504
-        $order = ! empty($this->_req_data['order'])
1505
-            ? sanitize_text_field($this->_req_data['order'])
1506
-            : 'DESC';
1507
-        $orderby = array_combine(
1508
-            $orderby,
1509
-            array_fill(0, count($orderby), $order)
1510
-        );
1511
-        // because there are many registrations with the same date, define
1512
-        // a secondary way to order them, otherwise MySQL seems to be a bit random
1513
-        if (empty($orderby['REG_ID'])) {
1514
-            $orderby['REG_ID'] = $order;
1515
-        }
1516
-
1517
-        $orderby = apply_filters(
1518
-            'FHEE__Registrations_Admin_Page___get_orderby_for_registrations_query',
1519
-            $orderby,
1520
-            $this->_req_data
1521
-        );
1522
-
1523
-        return array('order_by' => $orderby);
1524
-    }
1525
-
1526
-
1527
-    /**
1528
-     * Sets up the limit for the registrations query.
1529
-     *
1530
-     * @param $per_page
1531
-     * @return array
1532
-     */
1533
-    protected function _get_limit($per_page)
1534
-    {
1535
-        $current_page = ! empty($this->_req_data['paged'])
1536
-            ? absint($this->_req_data['paged'])
1537
-            : 1;
1538
-        $per_page = ! empty($this->_req_data['perpage'])
1539
-            ? $this->_req_data['perpage']
1540
-            : $per_page;
1541
-
1542
-        // -1 means return all results so get out if that's set.
1543
-        if ((int) $per_page === -1) {
1544
-            return array();
1545
-        }
1546
-        $per_page = absint($per_page);
1547
-        $offset = ($current_page - 1) * $per_page;
1548
-        return array('limit' => array($offset, $per_page));
1549
-    }
1550
-
1551
-
1552
-    public function get_registration_status_array()
1553
-    {
1554
-        return self::$_reg_status;
1555
-    }
1556
-
1557
-
1558
-
1559
-
1560
-    /***************************************        REGISTRATION DETAILS        ***************************************/
1561
-    /**
1562
-     *        generates HTML for the View Registration Details Admin page
1563
-     *
1564
-     * @access protected
1565
-     * @return void
1566
-     * @throws DomainException
1567
-     * @throws EE_Error
1568
-     * @throws InvalidArgumentException
1569
-     * @throws InvalidDataTypeException
1570
-     * @throws InvalidInterfaceException
1571
-     * @throws EntityNotFoundException
1572
-     */
1573
-    protected function _registration_details()
1574
-    {
1575
-        $this->_template_args = array();
1576
-        $this->_set_registration_object();
1577
-        if (is_object($this->_registration)) {
1578
-            $transaction = $this->_registration->transaction()
1579
-                ? $this->_registration->transaction()
1580
-                : EE_Transaction::new_instance();
1581
-            $this->_session = $transaction->session_data();
1582
-            $event_id = $this->_registration->event_ID();
1583
-            $this->_template_args['reg_nmbr']['value'] = $this->_registration->ID();
1584
-            $this->_template_args['reg_nmbr']['label'] = esc_html__('Registration Number', 'event_espresso');
1585
-            $this->_template_args['reg_datetime']['value'] = $this->_registration->get_i18n_datetime('REG_date');
1586
-            $this->_template_args['reg_datetime']['label'] = esc_html__('Date', 'event_espresso');
1587
-            $this->_template_args['grand_total'] = $transaction->total();
1588
-            $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
1589
-            // link back to overview
1590
-            $this->_template_args['reg_overview_url'] = REG_ADMIN_URL;
1591
-            $this->_template_args['registration'] = $this->_registration;
1592
-            $this->_template_args['filtered_registrations_link'] = EE_Admin_Page::add_query_args_and_nonce(
1593
-                array(
1594
-                    'action'   => 'default',
1595
-                    'event_id' => $event_id,
1596
-                ),
1597
-                REG_ADMIN_URL
1598
-            );
1599
-            $this->_template_args['filtered_transactions_link'] = EE_Admin_Page::add_query_args_and_nonce(
1600
-                array(
1601
-                    'action' => 'default',
1602
-                    'EVT_ID' => $event_id,
1603
-                    'page'   => 'espresso_transactions',
1604
-                ),
1605
-                admin_url('admin.php')
1606
-            );
1607
-            $this->_template_args['event_link'] = EE_Admin_Page::add_query_args_and_nonce(
1608
-                array(
1609
-                    'page'   => 'espresso_events',
1610
-                    'action' => 'edit',
1611
-                    'post'   => $event_id,
1612
-                ),
1613
-                admin_url('admin.php')
1614
-            );
1615
-            // next and previous links
1616
-            $next_reg = $this->_registration->next(
1617
-                null,
1618
-                array(),
1619
-                'REG_ID'
1620
-            );
1621
-            $this->_template_args['next_registration'] = $next_reg
1622
-                ? $this->_next_link(
1623
-                    EE_Admin_Page::add_query_args_and_nonce(
1624
-                        array(
1625
-                            'action'  => 'view_registration',
1626
-                            '_REG_ID' => $next_reg['REG_ID'],
1627
-                        ),
1628
-                        REG_ADMIN_URL
1629
-                    ),
1630
-                    'dashicons dashicons-arrow-right ee-icon-size-22'
1631
-                )
1632
-                : '';
1633
-            $previous_reg = $this->_registration->previous(
1634
-                null,
1635
-                array(),
1636
-                'REG_ID'
1637
-            );
1638
-            $this->_template_args['previous_registration'] = $previous_reg
1639
-                ? $this->_previous_link(
1640
-                    EE_Admin_Page::add_query_args_and_nonce(
1641
-                        array(
1642
-                            'action'  => 'view_registration',
1643
-                            '_REG_ID' => $previous_reg['REG_ID'],
1644
-                        ),
1645
-                        REG_ADMIN_URL
1646
-                    ),
1647
-                    'dashicons dashicons-arrow-left ee-icon-size-22'
1648
-                )
1649
-                : '';
1650
-            // grab header
1651
-            $template_path = REG_TEMPLATE_PATH . 'reg_admin_details_header.template.php';
1652
-            $this->_template_args['REG_ID'] = $this->_registration->ID();
1653
-            $this->_template_args['admin_page_header'] = EEH_Template::display_template(
1654
-                $template_path,
1655
-                $this->_template_args,
1656
-                true
1657
-            );
1658
-        } else {
1659
-            $this->_template_args['admin_page_header'] = $this->display_espresso_notices();
1660
-        }
1661
-        // the details template wrapper
1662
-        $this->display_admin_page_with_sidebar();
1663
-    }
1664
-
1665
-
1666
-    protected function _registration_details_metaboxes()
1667
-    {
1668
-        do_action('AHEE__Registrations_Admin_Page___registration_details_metabox__start', $this);
1669
-        $this->_set_registration_object();
1670
-        $attendee = $this->_registration instanceof EE_Registration ? $this->_registration->attendee() : null;
1671
-        add_meta_box(
1672
-            'edit-reg-status-mbox',
1673
-            esc_html__('Registration Status', 'event_espresso'),
1674
-            array($this, 'set_reg_status_buttons_metabox'),
1675
-            $this->wp_page_slug,
1676
-            'normal',
1677
-            'high'
1678
-        );
1679
-        add_meta_box(
1680
-            'edit-reg-details-mbox',
1681
-            esc_html__('Registration Details', 'event_espresso'),
1682
-            array($this, '_reg_details_meta_box'),
1683
-            $this->wp_page_slug,
1684
-            'normal',
1685
-            'high'
1686
-        );
1687
-        if ($attendee instanceof EE_Attendee
1688
-            && EE_Registry::instance()->CAP->current_user_can(
1689
-                'ee_read_registration',
1690
-                'edit-reg-questions-mbox',
1691
-                $this->_registration->ID()
1692
-            )
1693
-        ) {
1694
-            add_meta_box(
1695
-                'edit-reg-questions-mbox',
1696
-                esc_html__('Registration Form Answers', 'event_espresso'),
1697
-                array($this, '_reg_questions_meta_box'),
1698
-                $this->wp_page_slug,
1699
-                'normal',
1700
-                'high'
1701
-            );
1702
-        }
1703
-        add_meta_box(
1704
-            'edit-reg-registrant-mbox',
1705
-            esc_html__('Contact Details', 'event_espresso'),
1706
-            array($this, '_reg_registrant_side_meta_box'),
1707
-            $this->wp_page_slug,
1708
-            'side',
1709
-            'high'
1710
-        );
1711
-        if ($this->_registration->group_size() > 1) {
1712
-            add_meta_box(
1713
-                'edit-reg-attendees-mbox',
1714
-                esc_html__('Other Registrations in this Transaction', 'event_espresso'),
1715
-                array($this, '_reg_attendees_meta_box'),
1716
-                $this->wp_page_slug,
1717
-                'normal',
1718
-                'high'
1719
-            );
1720
-        }
1721
-    }
1722
-
1723
-
1724
-    /**
1725
-     * set_reg_status_buttons_metabox
1726
-     *
1727
-     * @access protected
1728
-     * @return string
1729
-     * @throws \EE_Error
1730
-     */
1731
-    public function set_reg_status_buttons_metabox()
1732
-    {
1733
-        $this->_set_registration_object();
1734
-        $change_reg_status_form = $this->_generate_reg_status_change_form();
1735
-        echo $change_reg_status_form->form_open(
1736
-            self::add_query_args_and_nonce(
1737
-                array(
1738
-                    'action' => 'change_reg_status',
1739
-                ),
1740
-                REG_ADMIN_URL
1741
-            )
1742
-        );
1743
-        echo $change_reg_status_form->get_html();
1744
-        echo $change_reg_status_form->form_close();
1745
-    }
1746
-
1747
-
1748
-    /**
1749
-     * @return EE_Form_Section_Proper
1750
-     * @throws EE_Error
1751
-     * @throws InvalidArgumentException
1752
-     * @throws InvalidDataTypeException
1753
-     * @throws InvalidInterfaceException
1754
-     * @throws \EventEspresso\core\exceptions\EntityNotFoundException
1755
-     */
1756
-    protected function _generate_reg_status_change_form()
1757
-    {
1758
-        $reg_status_change_form_array = array(
1759
-            'name'            => 'reg_status_change_form',
1760
-            'html_id'         => 'reg-status-change-form',
1761
-            'layout_strategy' => new EE_Admin_Two_Column_Layout(),
1762
-            'subsections'     => array(
1763
-                'return'             => new EE_Hidden_Input(
1764
-                    array(
1765
-                        'name'    => 'return',
1766
-                        'default' => 'view_registration',
1767
-                    )
1768
-                ),
1769
-                'REG_ID'             => new EE_Hidden_Input(
1770
-                    array(
1771
-                        'name'    => 'REG_ID',
1772
-                        'default' => $this->_registration->ID(),
1773
-                    )
1774
-                ),
1775
-                'current_status'     => new EE_Form_Section_HTML(
1776
-                    EEH_HTML::tr(
1777
-                        EEH_HTML::th(
1778
-                            EEH_HTML::label(
1779
-                                EEH_HTML::strong(
1780
-                                    esc_html__('Current Registration Status', 'event_espresso')
1781
-                                )
1782
-                            )
1783
-                        )
1784
-                        . EEH_HTML::td(
1785
-                            EEH_HTML::strong(
1786
-                                $this->_registration->pretty_status(),
1787
-                                '',
1788
-                                'status-' . $this->_registration->status_ID(),
1789
-                                'line-height: 1em; font-size: 1.5em; font-weight: bold;'
1790
-                            )
1791
-                        )
1792
-                    )
1793
-                )
1794
-            )
1795
-        );
1796
-        if (EE_Registry::instance()->CAP->current_user_can(
1797
-            'ee_edit_registration',
1798
-            'toggle_registration_status',
1799
-            $this->_registration->ID()
1800
-        )) {
1801
-            $reg_status_change_form_array['subsections']['reg_status'] = new EE_Select_Input(
1802
-                $this->_get_reg_statuses(),
1803
-                array(
1804
-                    'html_label_text' => esc_html__('Change Registration Status to', 'event_espresso'),
1805
-                    'default'         => $this->_registration->status_ID(),
1806
-                )
1807
-            );
1808
-            $reg_status_change_form_array['subsections']['send_notifications'] = new EE_Yes_No_Input(
1809
-                array(
1810
-                    'html_label_text' => esc_html__('Send Related Messages', 'event_espresso'),
1811
-                    'default'         => false,
1812
-                    'html_help_text'  => esc_html__(
1813
-                        'If set to "Yes", then the related messages will be sent to the registrant.',
1814
-                        'event_espresso'
1815
-                    )
1816
-                )
1817
-            );
1818
-            $reg_status_change_form_array['subsections']['submit'] = new EE_Submit_Input(
1819
-                array(
1820
-                    'html_class'      => 'button-primary',
1821
-                    'html_label_text' => '&nbsp;',
1822
-                    'default'         => esc_html__('Update Registration Status', 'event_espresso'),
1823
-                )
1824
-            );
1825
-        }
1826
-        return new EE_Form_Section_Proper($reg_status_change_form_array);
1827
-    }
1828
-
1829
-
1830
-    /**
1831
-     * Returns an array of all the buttons for the various statuses and switch status actions
1832
-     *
1833
-     * @return array
1834
-     * @throws EE_Error
1835
-     * @throws InvalidArgumentException
1836
-     * @throws InvalidDataTypeException
1837
-     * @throws InvalidInterfaceException
1838
-     * @throws EntityNotFoundException
1839
-     */
1840
-    protected function _get_reg_statuses()
1841
-    {
1842
-        $reg_status_array = EEM_Registration::instance()->reg_status_array();
1843
-        unset($reg_status_array[ EEM_Registration::status_id_incomplete ]);
1844
-        // get current reg status
1845
-        $current_status = $this->_registration->status_ID();
1846
-        // is registration for free event? This will determine whether to display the pending payment option
1847
-        if ($current_status !== EEM_Registration::status_id_pending_payment
1848
-            && EEH_Money::compare_floats($this->_registration->ticket()->price(), 0.00)
1849
-        ) {
1850
-            unset($reg_status_array[ EEM_Registration::status_id_pending_payment ]);
1851
-        }
1852
-        return EEM_Status::instance()->localized_status($reg_status_array, false, 'sentence');
1853
-    }
1854
-
1855
-
1856
-    /**
1857
-     * This method is used when using _REG_ID from request which may or may not be an array of reg_ids.
1858
-     *
1859
-     * @param bool $status REG status given for changing registrations to.
1860
-     * @param bool $notify Whether to send messages notifications or not.
1861
-     * @return array (array with reg_id(s) updated and whether update was successful.
1862
-     * @throws EE_Error
1863
-     * @throws InvalidArgumentException
1864
-     * @throws InvalidDataTypeException
1865
-     * @throws InvalidInterfaceException
1866
-     * @throws ReflectionException
1867
-     * @throws RuntimeException
1868
-     * @throws EntityNotFoundException
1869
-     */
1870
-    protected function _set_registration_status_from_request($status = false, $notify = false)
1871
-    {
1872
-        if (isset($this->_req_data['reg_status_change_form'])) {
1873
-            $REG_IDs = isset($this->_req_data['reg_status_change_form']['REG_ID'])
1874
-                ? (array) $this->_req_data['reg_status_change_form']['REG_ID']
1875
-                : array();
1876
-        } else {
1877
-            $REG_IDs = isset($this->_req_data['_REG_ID'])
1878
-                ? (array) $this->_req_data['_REG_ID']
1879
-                : array();
1880
-        }
1881
-        // sanitize $REG_IDs
1882
-        $REG_IDs = array_map('absint', $REG_IDs);
1883
-        // and remove empty entries
1884
-        $REG_IDs = array_filter($REG_IDs);
1885
-
1886
-        $result = $this->_set_registration_status($REG_IDs, $status, $notify);
1887
-
1888
-        /**
1889
-         * Set and filter $_req_data['_REG_ID'] for any potential future messages notifications.
1890
-         * Currently this value is used downstream by the _process_resend_registration method.
1891
-         *
1892
-         * @param int|array                $registration_ids The registration ids that have had their status changed successfully.
1893
-         * @param bool                     $status           The status registrations were changed to.
1894
-         * @param bool                     $success          If the status was changed successfully for all registrations.
1895
-         * @param Registrations_Admin_Page $admin_page_object
1896
-         */
1897
-        $this->_req_data['_REG_ID'] = apply_filters(
1898
-            'FHEE__Registrations_Admin_Page___set_registration_status_from_request__REG_IDs',
1899
-            $result['REG_ID'],
1900
-            $status,
1901
-            $result['success'],
1902
-            $this
1903
-        );
1904
-
1905
-        // notify?
1906
-        if ($notify
1907
-            && $result['success']
1908
-            && ! empty($this->_req_data['_REG_ID'])
1909
-            && EE_Registry::instance()->CAP->current_user_can(
1910
-                'ee_send_message',
1911
-                'espresso_registrations_resend_registration'
1912
-            )
1913
-        ) {
1914
-            $this->_process_resend_registration();
1915
-        }
1916
-        return $result;
1917
-    }
1918
-
1919
-
1920
-    /**
1921
-     * Set the registration status for the given reg_id (which may or may not be an array, it gets typecast to an
1922
-     * array). Note, this method does NOT take care of possible notifications.  That is required by calling code.
1923
-     *
1924
-     * @param array  $REG_IDs
1925
-     * @param string $status
1926
-     * @param bool   $notify  Used to indicate whether notification was requested or not.  This determines the context
1927
-     *                        slug sent with setting the registration status.
1928
-     * @return array (an array with 'success' key representing whether status change was successful, and 'REG_ID' as
1929
-     * @throws EE_Error
1930
-     * @throws InvalidArgumentException
1931
-     * @throws InvalidDataTypeException
1932
-     * @throws InvalidInterfaceException
1933
-     * @throws ReflectionException
1934
-     * @throws RuntimeException
1935
-     * @throws EntityNotFoundException
1936
-     */
1937
-    protected function _set_registration_status($REG_IDs = array(), $status = '', $notify = false)
1938
-    {
1939
-        $success = false;
1940
-        // typecast $REG_IDs
1941
-        $REG_IDs = (array) $REG_IDs;
1942
-        if (! empty($REG_IDs)) {
1943
-            $success = true;
1944
-            // set default status if none is passed
1945
-            $status = $status ? $status : EEM_Registration::status_id_pending_payment;
1946
-            $status_context = $notify
1947
-                ? Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN_NOTIFY
1948
-                : Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN;
1949
-            // loop through REG_ID's and change status
1950
-            foreach ($REG_IDs as $REG_ID) {
1951
-                $registration = EEM_Registration::instance()->get_one_by_ID($REG_ID);
1952
-                if ($registration instanceof EE_Registration) {
1953
-                    $registration->set_status(
1954
-                        $status,
1955
-                        false,
1956
-                        new Context(
1957
-                            $status_context,
1958
-                            esc_html__(
1959
-                                'Manually triggered status change on a Registration Admin Page route.',
1960
-                                'event_espresso'
1961
-                            )
1962
-                        )
1963
-                    );
1964
-                    $result = $registration->save();
1965
-                    // verifying explicit fails because update *may* just return 0 for 0 rows affected
1966
-                    $success = $result !== false ? $success : false;
1967
-                }
1968
-            }
1969
-        }
1970
-
1971
-        // return $success and processed registrations
1972
-        return array('REG_ID' => $REG_IDs, 'success' => $success);
1973
-    }
1974
-
1975
-
1976
-    /**
1977
-     * Common logic for setting up success message and redirecting to appropriate route
1978
-     *
1979
-     * @param  string $STS_ID status id for the registration changed to
1980
-     * @param   bool  $notify indicates whether the _set_registration_status_from_request does notifications or not.
1981
-     * @return void
1982
-     * @throws EE_Error
1983
-     */
1984
-    protected function _reg_status_change_return($STS_ID, $notify = false)
1985
-    {
1986
-        $result = ! empty($STS_ID) ? $this->_set_registration_status_from_request($STS_ID, $notify)
1987
-            : array('success' => false);
1988
-        $success = isset($result['success']) && $result['success'];
1989
-        // setup success message
1990
-        if ($success) {
1991
-            if (is_array($result['REG_ID']) && count($result['REG_ID']) === 1) {
1992
-                $msg = sprintf(
1993
-                    esc_html__('Registration status has been set to %s', 'event_espresso'),
1994
-                    EEH_Template::pretty_status($STS_ID, false, 'lower')
1995
-                );
1996
-            } else {
1997
-                $msg = sprintf(
1998
-                    esc_html__('Registrations have been set to %s.', 'event_espresso'),
1999
-                    EEH_Template::pretty_status($STS_ID, false, 'lower')
2000
-                );
2001
-            }
2002
-            EE_Error::add_success($msg);
2003
-        } else {
2004
-            EE_Error::add_error(
2005
-                esc_html__(
2006
-                    'Something went wrong, and the status was not changed',
2007
-                    'event_espresso'
2008
-                ),
2009
-                __FILE__,
2010
-                __LINE__,
2011
-                __FUNCTION__
2012
-            );
2013
-        }
2014
-        if (isset($this->_req_data['return']) && $this->_req_data['return'] == 'view_registration') {
2015
-            $route = array('action' => 'view_registration', '_REG_ID' => reset($result['REG_ID']));
2016
-        } else {
2017
-            $route = array('action' => 'default');
2018
-        }
2019
-        // unset nonces
2020
-        foreach ($this->_req_data as $ref => $value) {
2021
-            if (strpos($ref, 'nonce') !== false) {
2022
-                unset($this->_req_data[ $ref ]);
2023
-                continue;
2024
-            }
2025
-            $value = is_array($value) ? array_map('urlencode', $value) : urlencode($value);
2026
-            $this->_req_data[ $ref ] = $value;
2027
-        }
2028
-        // merge request vars so that the reloaded list table contains any existing filter query params
2029
-        $route = array_merge($this->_req_data, $route);
2030
-        $this->_redirect_after_action($success, '', '', $route, true);
2031
-    }
2032
-
2033
-
2034
-    /**
2035
-     * incoming reg status change from reg details page.
2036
-     *
2037
-     * @return void
2038
-     */
2039
-    protected function _change_reg_status()
2040
-    {
2041
-        $this->_req_data['return'] = 'view_registration';
2042
-        // set notify based on whether the send notifications toggle is set or not
2043
-        $notify = ! empty($this->_req_data['reg_status_change_form']['send_notifications']);
2044
-        // $notify = ! empty( $this->_req_data['txn_reg_status_change']['send_notifications'] );
2045
-        $this->_req_data['reg_status_change_form']['reg_status'] = isset($this->_req_data['reg_status_change_form']['reg_status'])
2046
-            ? $this->_req_data['reg_status_change_form']['reg_status'] : '';
2047
-        switch ($this->_req_data['reg_status_change_form']['reg_status']) {
2048
-            case EEM_Registration::status_id_approved:
2049
-            case EEH_Template::pretty_status(EEM_Registration::status_id_approved, false, 'sentence'):
2050
-                $this->approve_registration($notify);
2051
-                break;
2052
-            case EEM_Registration::status_id_pending_payment:
2053
-            case EEH_Template::pretty_status(EEM_Registration::status_id_pending_payment, false, 'sentence'):
2054
-                $this->pending_registration($notify);
2055
-                break;
2056
-            case EEM_Registration::status_id_not_approved:
2057
-            case EEH_Template::pretty_status(EEM_Registration::status_id_not_approved, false, 'sentence'):
2058
-                $this->not_approve_registration($notify);
2059
-                break;
2060
-            case EEM_Registration::status_id_declined:
2061
-            case EEH_Template::pretty_status(EEM_Registration::status_id_declined, false, 'sentence'):
2062
-                $this->decline_registration($notify);
2063
-                break;
2064
-            case EEM_Registration::status_id_cancelled:
2065
-            case EEH_Template::pretty_status(EEM_Registration::status_id_cancelled, false, 'sentence'):
2066
-                $this->cancel_registration($notify);
2067
-                break;
2068
-            case EEM_Registration::status_id_wait_list:
2069
-            case EEH_Template::pretty_status(EEM_Registration::status_id_wait_list, false, 'sentence'):
2070
-                $this->wait_list_registration($notify);
2071
-                break;
2072
-            case EEM_Registration::status_id_incomplete:
2073
-            default:
2074
-                $result['success'] = false;
2075
-                unset($this->_req_data['return']);
2076
-                $this->_reg_status_change_return('', false);
2077
-                break;
2078
-        }
2079
-    }
2080
-
2081
-
2082
-    /**
2083
-     * Callback for bulk action routes.
2084
-     * Note: although we could just register the singular route callbacks for each bulk action route as well, this
2085
-     * method was chosen so there is one central place all the registration status bulk actions are going through.
2086
-     * Potentially, this provides an easier place to locate logic that is specific to these bulk actions (as opposed to
2087
-     * when an action is happening on just a single registration).
2088
-     *
2089
-     * @param      $action
2090
-     * @param bool $notify
2091
-     */
2092
-    protected function bulk_action_on_registrations($action, $notify = false)
2093
-    {
2094
-        do_action(
2095
-            'AHEE__Registrations_Admin_Page__bulk_action_on_registrations__before_execution',
2096
-            $this,
2097
-            $action,
2098
-            $notify
2099
-        );
2100
-        $method = $action . '_registration';
2101
-        if (method_exists($this, $method)) {
2102
-            $this->$method($notify);
2103
-        }
2104
-    }
2105
-
2106
-
2107
-    /**
2108
-     * approve_registration
2109
-     *
2110
-     * @access protected
2111
-     * @param bool $notify whether or not to notify the registrant about their approval.
2112
-     * @return void
2113
-     */
2114
-    protected function approve_registration($notify = false)
2115
-    {
2116
-        $this->_reg_status_change_return(EEM_Registration::status_id_approved, $notify);
2117
-    }
2118
-
2119
-
2120
-    /**
2121
-     *        decline_registration
2122
-     *
2123
-     * @access protected
2124
-     * @param bool $notify whether or not to notify the registrant about their status change.
2125
-     * @return void
2126
-     */
2127
-    protected function decline_registration($notify = false)
2128
-    {
2129
-        $this->_reg_status_change_return(EEM_Registration::status_id_declined, $notify);
2130
-    }
2131
-
2132
-
2133
-    /**
2134
-     *        cancel_registration
2135
-     *
2136
-     * @access protected
2137
-     * @param bool $notify whether or not to notify the registrant about their status change.
2138
-     * @return void
2139
-     */
2140
-    protected function cancel_registration($notify = false)
2141
-    {
2142
-        $this->_reg_status_change_return(EEM_Registration::status_id_cancelled, $notify);
2143
-    }
2144
-
2145
-
2146
-    /**
2147
-     *        not_approve_registration
2148
-     *
2149
-     * @access protected
2150
-     * @param bool $notify whether or not to notify the registrant about their status change.
2151
-     * @return void
2152
-     */
2153
-    protected function not_approve_registration($notify = false)
2154
-    {
2155
-        $this->_reg_status_change_return(EEM_Registration::status_id_not_approved, $notify);
2156
-    }
2157
-
2158
-
2159
-    /**
2160
-     *        decline_registration
2161
-     *
2162
-     * @access protected
2163
-     * @param bool $notify whether or not to notify the registrant about their status change.
2164
-     * @return void
2165
-     */
2166
-    protected function pending_registration($notify = false)
2167
-    {
2168
-        $this->_reg_status_change_return(EEM_Registration::status_id_pending_payment, $notify);
2169
-    }
2170
-
2171
-
2172
-    /**
2173
-     * waitlist_registration
2174
-     *
2175
-     * @access protected
2176
-     * @param bool $notify whether or not to notify the registrant about their status change.
2177
-     * @return void
2178
-     */
2179
-    protected function wait_list_registration($notify = false)
2180
-    {
2181
-        $this->_reg_status_change_return(EEM_Registration::status_id_wait_list, $notify);
2182
-    }
2183
-
2184
-
2185
-    /**
2186
-     *        generates HTML for the Registration main meta box
2187
-     *
2188
-     * @access public
2189
-     * @return void
2190
-     * @throws DomainException
2191
-     * @throws EE_Error
2192
-     * @throws InvalidArgumentException
2193
-     * @throws InvalidDataTypeException
2194
-     * @throws InvalidInterfaceException
2195
-     * @throws ReflectionException
2196
-     * @throws EntityNotFoundException
2197
-     */
2198
-    public function _reg_details_meta_box()
2199
-    {
2200
-        EEH_Autoloader::register_line_item_display_autoloaders();
2201
-        EEH_Autoloader::register_line_item_filter_autoloaders();
2202
-        EE_Registry::instance()->load_helper('Line_Item');
2203
-        $transaction = $this->_registration->transaction() ? $this->_registration->transaction()
2204
-            : EE_Transaction::new_instance();
2205
-        $this->_session = $transaction->session_data();
2206
-        $filters = new EE_Line_Item_Filter_Collection();
2207
-        // $filters->add( new EE_Non_Zero_Line_Item_Filter() );
2208
-        $filters->add(new EE_Single_Registration_Line_Item_Filter($this->_registration));
2209
-        $line_item_filter_processor = new EE_Line_Item_Filter_Processor(
2210
-            $filters,
2211
-            $transaction->total_line_item()
2212
-        );
2213
-        $filtered_line_item_tree = $line_item_filter_processor->process();
2214
-        $line_item_display = new EE_Line_Item_Display(
2215
-            'reg_admin_table',
2216
-            'EE_Admin_Table_Registration_Line_Item_Display_Strategy'
2217
-        );
2218
-        $this->_template_args['line_item_table'] = $line_item_display->display_line_item(
2219
-            $filtered_line_item_tree,
2220
-            array('EE_Registration' => $this->_registration)
2221
-        );
2222
-        $attendee = $this->_registration->attendee();
2223
-        if (EE_Registry::instance()->CAP->current_user_can(
2224
-            'ee_read_transaction',
2225
-            'espresso_transactions_view_transaction'
2226
-        )) {
2227
-            $this->_template_args['view_transaction_button'] = EEH_Template::get_button_or_link(
2228
-                EE_Admin_Page::add_query_args_and_nonce(
2229
-                    array(
2230
-                        'action' => 'view_transaction',
2231
-                        'TXN_ID' => $transaction->ID(),
2232
-                    ),
2233
-                    TXN_ADMIN_URL
2234
-                ),
2235
-                esc_html__(' View Transaction', 'event_espresso'),
2236
-                'button secondary-button right',
2237
-                'dashicons dashicons-cart'
2238
-            );
2239
-        } else {
2240
-            $this->_template_args['view_transaction_button'] = '';
2241
-        }
2242
-        if ($attendee instanceof EE_Attendee
2243
-            && EE_Registry::instance()->CAP->current_user_can(
2244
-                'ee_send_message',
2245
-                'espresso_registrations_resend_registration'
2246
-            )
2247
-        ) {
2248
-            $this->_template_args['resend_registration_button'] = EEH_Template::get_button_or_link(
2249
-                EE_Admin_Page::add_query_args_and_nonce(
2250
-                    array(
2251
-                        'action'      => 'resend_registration',
2252
-                        '_REG_ID'     => $this->_registration->ID(),
2253
-                        'redirect_to' => 'view_registration',
2254
-                    ),
2255
-                    REG_ADMIN_URL
2256
-                ),
2257
-                esc_html__(' Resend Registration', 'event_espresso'),
2258
-                'button secondary-button right',
2259
-                'dashicons dashicons-email-alt'
2260
-            );
2261
-        } else {
2262
-            $this->_template_args['resend_registration_button'] = '';
2263
-        }
2264
-        $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2265
-        $payment = $transaction->get_first_related('Payment');
2266
-        $payment = ! $payment instanceof EE_Payment
2267
-            ? EE_Payment::new_instance()
2268
-            : $payment;
2269
-        $payment_method = $payment->get_first_related('Payment_Method');
2270
-        $payment_method = ! $payment_method instanceof EE_Payment_Method
2271
-            ? EE_Payment_Method::new_instance()
2272
-            : $payment_method;
2273
-        $reg_details = array(
2274
-            'payment_method'       => $payment_method->name(),
2275
-            'response_msg'         => $payment->gateway_response(),
2276
-            'registration_id'      => $this->_registration->get('REG_code'),
2277
-            'registration_session' => $this->_registration->session_ID(),
2278
-            'ip_address'           => isset($this->_session['ip_address']) ? $this->_session['ip_address'] : '',
2279
-            'user_agent'           => isset($this->_session['user_agent']) ? $this->_session['user_agent'] : '',
2280
-        );
2281
-        if (isset($reg_details['registration_id'])) {
2282
-            $this->_template_args['reg_details']['registration_id']['value'] = $reg_details['registration_id'];
2283
-            $this->_template_args['reg_details']['registration_id']['label'] = esc_html__(
2284
-                'Registration ID',
2285
-                'event_espresso'
2286
-            );
2287
-            $this->_template_args['reg_details']['registration_id']['class'] = 'regular-text';
2288
-        }
2289
-        if (isset($reg_details['payment_method'])) {
2290
-            $this->_template_args['reg_details']['payment_method']['value'] = $reg_details['payment_method'];
2291
-            $this->_template_args['reg_details']['payment_method']['label'] = esc_html__(
2292
-                'Most Recent Payment Method',
2293
-                'event_espresso'
2294
-            );
2295
-            $this->_template_args['reg_details']['payment_method']['class'] = 'regular-text';
2296
-            $this->_template_args['reg_details']['response_msg']['value'] = $reg_details['response_msg'];
2297
-            $this->_template_args['reg_details']['response_msg']['label'] = esc_html__(
2298
-                'Payment method response',
2299
-                'event_espresso'
2300
-            );
2301
-            $this->_template_args['reg_details']['response_msg']['class'] = 'regular-text';
2302
-        }
2303
-        $this->_template_args['reg_details']['registration_session']['value'] = $reg_details['registration_session'];
2304
-        $this->_template_args['reg_details']['registration_session']['label'] = esc_html__(
2305
-            'Registration Session',
2306
-            'event_espresso'
2307
-        );
2308
-        $this->_template_args['reg_details']['registration_session']['class'] = 'regular-text';
2309
-        $this->_template_args['reg_details']['ip_address']['value'] = $reg_details['ip_address'];
2310
-        $this->_template_args['reg_details']['ip_address']['label'] = esc_html__(
2311
-            'Registration placed from IP',
2312
-            'event_espresso'
2313
-        );
2314
-        $this->_template_args['reg_details']['ip_address']['class'] = 'regular-text';
2315
-        $this->_template_args['reg_details']['user_agent']['value'] = $reg_details['user_agent'];
2316
-        $this->_template_args['reg_details']['user_agent']['label'] = esc_html__(
2317
-            'Registrant User Agent',
2318
-            'event_espresso'
2319
-        );
2320
-        $this->_template_args['reg_details']['user_agent']['class'] = 'large-text';
2321
-        $this->_template_args['event_link'] = EE_Admin_Page::add_query_args_and_nonce(
2322
-            array(
2323
-                'action'   => 'default',
2324
-                'event_id' => $this->_registration->event_ID(),
2325
-            ),
2326
-            REG_ADMIN_URL
2327
-        );
2328
-        $this->_template_args['REG_ID'] = $this->_registration->ID();
2329
-        $this->_template_args['event_id'] = $this->_registration->event_ID();
2330
-        $template_path =
2331
-            REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_details.template.php';
2332
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);
2333
-    }
2334
-
2335
-
2336
-    /**
2337
-     * generates HTML for the Registration Questions meta box.
2338
-     * If pre-4.8.32.rc.000 hooks are used, uses old methods (with its filters),
2339
-     * otherwise uses new forms system
2340
-     *
2341
-     * @access public
2342
-     * @return void
2343
-     * @throws DomainException
2344
-     * @throws EE_Error
2345
-     */
2346
-    public function _reg_questions_meta_box()
2347
-    {
2348
-        // allow someone to override this method entirely
2349
-        if (apply_filters(
2350
-            'FHEE__Registrations_Admin_Page___reg_questions_meta_box__do_default',
2351
-            true,
2352
-            $this,
2353
-            $this->_registration
2354
-        )) {
2355
-            $form = $this->_get_reg_custom_questions_form(
2356
-                $this->_registration->ID()
2357
-            );
2358
-            $this->_template_args['att_questions'] = count($form->subforms()) > 0
2359
-                ? $form->get_html_and_js()
2360
-                : '';
2361
-            $this->_template_args['reg_questions_form_action'] = 'edit_registration';
2362
-            $this->_template_args['REG_ID'] = $this->_registration->ID();
2363
-            $template_path =
2364
-                REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_questions.template.php';
2365
-            echo EEH_Template::display_template($template_path, $this->_template_args, true);
2366
-        }
2367
-    }
2368
-
2369
-
2370
-    /**
2371
-     * form_before_question_group
2372
-     *
2373
-     * @deprecated    as of 4.8.32.rc.000
2374
-     * @access        public
2375
-     * @param        string $output
2376
-     * @return        string
2377
-     */
2378
-    public function form_before_question_group($output)
2379
-    {
2380
-        EE_Error::doing_it_wrong(
2381
-            __CLASS__ . '::' . __FUNCTION__,
2382
-            esc_html__(
2383
-                '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.',
2384
-                'event_espresso'
2385
-            ),
2386
-            '4.8.32.rc.000'
2387
-        );
2388
-        return '
1302
+		if (! empty($registration_status)) {
1303
+			$where['STS_ID'] = $registration_status;
1304
+		} else {
1305
+			// make sure we exclude incomplete registrations, but only if not trashed.
1306
+			if ($view === 'trash') {
1307
+				$where['REG_deleted'] = true;
1308
+			} elseif ($view === 'incomplete') {
1309
+				$where['STS_ID'] = EEM_Registration::status_id_incomplete;
1310
+			} else {
1311
+				$where['STS_ID'] = array('!=', EEM_Registration::status_id_incomplete);
1312
+			}
1313
+		}
1314
+		return $where;
1315
+	}
1316
+
1317
+
1318
+	/**
1319
+	 * Adds any provided date restraints to the where conditions for the registrations query.
1320
+	 *
1321
+	 * @param array $request usually the same as $this->_req_data but not necessarily
1322
+	 * @return array
1323
+	 * @throws EE_Error
1324
+	 * @throws InvalidArgumentException
1325
+	 * @throws InvalidDataTypeException
1326
+	 * @throws InvalidInterfaceException
1327
+	 */
1328
+	protected function _add_date_to_where_conditions(array $request)
1329
+	{
1330
+		$where = array();
1331
+		$view = EEH_Array::is_set($request, 'status', '');
1332
+		$month_range = ! empty($request['month_range'])
1333
+			? sanitize_text_field($request['month_range'])
1334
+			: '';
1335
+		$retrieve_for_today = $view === 'today';
1336
+		$retrieve_for_this_month = $view === 'month';
1337
+
1338
+		if ($retrieve_for_today) {
1339
+			$now = date('Y-m-d', current_time('timestamp'));
1340
+			$where['REG_date'] = array(
1341
+				'BETWEEN',
1342
+				array(
1343
+					EEM_Registration::instance()->convert_datetime_for_query(
1344
+						'REG_date',
1345
+						$now . ' 00:00:00',
1346
+						'Y-m-d H:i:s'
1347
+					),
1348
+					EEM_Registration::instance()->convert_datetime_for_query(
1349
+						'REG_date',
1350
+						$now . ' 23:59:59',
1351
+						'Y-m-d H:i:s'
1352
+					),
1353
+				),
1354
+			);
1355
+		} elseif ($retrieve_for_this_month) {
1356
+			$current_year_and_month = date('Y-m', current_time('timestamp'));
1357
+			$days_this_month = date('t', current_time('timestamp'));
1358
+			$where['REG_date'] = array(
1359
+				'BETWEEN',
1360
+				array(
1361
+					EEM_Registration::instance()->convert_datetime_for_query(
1362
+						'REG_date',
1363
+						$current_year_and_month . '-01 00:00:00',
1364
+						'Y-m-d H:i:s'
1365
+					),
1366
+					EEM_Registration::instance()->convert_datetime_for_query(
1367
+						'REG_date',
1368
+						$current_year_and_month . '-' . $days_this_month . ' 23:59:59',
1369
+						'Y-m-d H:i:s'
1370
+					),
1371
+				),
1372
+			);
1373
+		} elseif ($month_range) {
1374
+			$pieces = explode(' ', $month_range, 3);
1375
+			$month_requested = ! empty($pieces[0])
1376
+				? date('m', \EEH_DTT_Helper::first_of_month_timestamp($pieces[0]))
1377
+				: '';
1378
+			$year_requested = ! empty($pieces[1])
1379
+				? $pieces[1]
1380
+				: '';
1381
+			// if there is not a month or year then we can't go further
1382
+			if ($month_requested && $year_requested) {
1383
+				$days_in_month = date('t', strtotime($year_requested . '-' . $month_requested . '-' . '01'));
1384
+				$where['REG_date'] = array(
1385
+					'BETWEEN',
1386
+					array(
1387
+						EEM_Registration::instance()->convert_datetime_for_query(
1388
+							'REG_date',
1389
+							$year_requested . '-' . $month_requested . '-01 00:00:00',
1390
+							'Y-m-d H:i:s'
1391
+						),
1392
+						EEM_Registration::instance()->convert_datetime_for_query(
1393
+							'REG_date',
1394
+							$year_requested . '-' . $month_requested . '-' . $days_in_month . ' 23:59:59',
1395
+							'Y-m-d H:i:s'
1396
+						),
1397
+					),
1398
+				);
1399
+			}
1400
+		}
1401
+		return $where;
1402
+	}
1403
+
1404
+
1405
+	/**
1406
+	 * Adds any provided search restraints to the where conditions for the registrations query
1407
+	 *
1408
+	 * @param array $request usually the same as $this->_req_data but not necessarily
1409
+	 * @return array
1410
+	 */
1411
+	protected function _add_search_to_where_conditions(array $request)
1412
+	{
1413
+		$where = array();
1414
+		if (! empty($request['s'])) {
1415
+			$search_string = '%' . sanitize_text_field($request['s']) . '%';
1416
+			$where['OR*search_conditions'] = array(
1417
+				'Event.EVT_name'                          => array('LIKE', $search_string),
1418
+				'Event.EVT_desc'                          => array('LIKE', $search_string),
1419
+				'Event.EVT_short_desc'                    => array('LIKE', $search_string),
1420
+				'Attendee.ATT_full_name'                  => array('LIKE', $search_string),
1421
+				'Attendee.ATT_fname'                      => array('LIKE', $search_string),
1422
+				'Attendee.ATT_lname'                      => array('LIKE', $search_string),
1423
+				'Attendee.ATT_short_bio'                  => array('LIKE', $search_string),
1424
+				'Attendee.ATT_email'                      => array('LIKE', $search_string),
1425
+				'Attendee.ATT_address'                    => array('LIKE', $search_string),
1426
+				'Attendee.ATT_address2'                   => array('LIKE', $search_string),
1427
+				'Attendee.ATT_city'                       => array('LIKE', $search_string),
1428
+				'REG_final_price'                         => array('LIKE', $search_string),
1429
+				'REG_code'                                => array('LIKE', $search_string),
1430
+				'REG_count'                               => array('LIKE', $search_string),
1431
+				'REG_group_size'                          => array('LIKE', $search_string),
1432
+				'Ticket.TKT_name'                         => array('LIKE', $search_string),
1433
+				'Ticket.TKT_description'                  => array('LIKE', $search_string),
1434
+				'Transaction.Payment.PAY_txn_id_chq_nmbr' => array('LIKE', $search_string),
1435
+			);
1436
+		}
1437
+		return $where;
1438
+	}
1439
+
1440
+
1441
+	/**
1442
+	 * Sets up the where conditions for the registrations query.
1443
+	 *
1444
+	 * @param array $request
1445
+	 * @return array
1446
+	 * @throws EE_Error
1447
+	 */
1448
+	protected function _get_where_conditions_for_registrations_query($request)
1449
+	{
1450
+		return apply_filters(
1451
+			'FHEE__Registrations_Admin_Page___get_where_conditions_for_registrations_query',
1452
+			array_merge(
1453
+				$this->addAttendeeIdToWhereConditions($request),
1454
+				$this->_add_event_id_to_where_conditions($request),
1455
+				$this->_add_category_id_to_where_conditions($request),
1456
+				$this->_add_datetime_id_to_where_conditions($request),
1457
+				$this->_add_registration_status_to_where_conditions($request),
1458
+				$this->_add_date_to_where_conditions($request),
1459
+				$this->_add_search_to_where_conditions($request)
1460
+			),
1461
+			$request
1462
+		);
1463
+	}
1464
+
1465
+
1466
+	/**
1467
+	 * Sets up the orderby for the registrations query.
1468
+	 *
1469
+	 * @return array
1470
+	 */
1471
+	protected function _get_orderby_for_registrations_query()
1472
+	{
1473
+		$orderby_field = ! empty($this->_req_data['orderby'])
1474
+			? sanitize_text_field($this->_req_data['orderby'])
1475
+			: '_REG_date';
1476
+		switch ($orderby_field) {
1477
+			case '_REG_ID':
1478
+				$orderby = array('REG_ID');
1479
+				break;
1480
+			case '_Reg_status':
1481
+				$orderby = array('STS_ID');
1482
+				break;
1483
+			case 'ATT_fname':
1484
+				$orderby = array('Attendee.ATT_fname', 'Attendee.ATT_lname');
1485
+				break;
1486
+			case 'ATT_lname':
1487
+				$orderby = array('Attendee.ATT_lname', 'Attendee.ATT_fname');
1488
+				break;
1489
+			case 'event_name':
1490
+				$orderby = array('Event.EVT_name');
1491
+				break;
1492
+			case 'DTT_EVT_start':
1493
+				$orderby = array('Event.Datetime.DTT_EVT_start');
1494
+				break;
1495
+			case '_REG_date':
1496
+				$orderby = array('REG_date');
1497
+				break;
1498
+			default:
1499
+				$orderby = array($orderby_field);
1500
+				break;
1501
+		}
1502
+
1503
+		// order
1504
+		$order = ! empty($this->_req_data['order'])
1505
+			? sanitize_text_field($this->_req_data['order'])
1506
+			: 'DESC';
1507
+		$orderby = array_combine(
1508
+			$orderby,
1509
+			array_fill(0, count($orderby), $order)
1510
+		);
1511
+		// because there are many registrations with the same date, define
1512
+		// a secondary way to order them, otherwise MySQL seems to be a bit random
1513
+		if (empty($orderby['REG_ID'])) {
1514
+			$orderby['REG_ID'] = $order;
1515
+		}
1516
+
1517
+		$orderby = apply_filters(
1518
+			'FHEE__Registrations_Admin_Page___get_orderby_for_registrations_query',
1519
+			$orderby,
1520
+			$this->_req_data
1521
+		);
1522
+
1523
+		return array('order_by' => $orderby);
1524
+	}
1525
+
1526
+
1527
+	/**
1528
+	 * Sets up the limit for the registrations query.
1529
+	 *
1530
+	 * @param $per_page
1531
+	 * @return array
1532
+	 */
1533
+	protected function _get_limit($per_page)
1534
+	{
1535
+		$current_page = ! empty($this->_req_data['paged'])
1536
+			? absint($this->_req_data['paged'])
1537
+			: 1;
1538
+		$per_page = ! empty($this->_req_data['perpage'])
1539
+			? $this->_req_data['perpage']
1540
+			: $per_page;
1541
+
1542
+		// -1 means return all results so get out if that's set.
1543
+		if ((int) $per_page === -1) {
1544
+			return array();
1545
+		}
1546
+		$per_page = absint($per_page);
1547
+		$offset = ($current_page - 1) * $per_page;
1548
+		return array('limit' => array($offset, $per_page));
1549
+	}
1550
+
1551
+
1552
+	public function get_registration_status_array()
1553
+	{
1554
+		return self::$_reg_status;
1555
+	}
1556
+
1557
+
1558
+
1559
+
1560
+	/***************************************        REGISTRATION DETAILS        ***************************************/
1561
+	/**
1562
+	 *        generates HTML for the View Registration Details Admin page
1563
+	 *
1564
+	 * @access protected
1565
+	 * @return void
1566
+	 * @throws DomainException
1567
+	 * @throws EE_Error
1568
+	 * @throws InvalidArgumentException
1569
+	 * @throws InvalidDataTypeException
1570
+	 * @throws InvalidInterfaceException
1571
+	 * @throws EntityNotFoundException
1572
+	 */
1573
+	protected function _registration_details()
1574
+	{
1575
+		$this->_template_args = array();
1576
+		$this->_set_registration_object();
1577
+		if (is_object($this->_registration)) {
1578
+			$transaction = $this->_registration->transaction()
1579
+				? $this->_registration->transaction()
1580
+				: EE_Transaction::new_instance();
1581
+			$this->_session = $transaction->session_data();
1582
+			$event_id = $this->_registration->event_ID();
1583
+			$this->_template_args['reg_nmbr']['value'] = $this->_registration->ID();
1584
+			$this->_template_args['reg_nmbr']['label'] = esc_html__('Registration Number', 'event_espresso');
1585
+			$this->_template_args['reg_datetime']['value'] = $this->_registration->get_i18n_datetime('REG_date');
1586
+			$this->_template_args['reg_datetime']['label'] = esc_html__('Date', 'event_espresso');
1587
+			$this->_template_args['grand_total'] = $transaction->total();
1588
+			$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
1589
+			// link back to overview
1590
+			$this->_template_args['reg_overview_url'] = REG_ADMIN_URL;
1591
+			$this->_template_args['registration'] = $this->_registration;
1592
+			$this->_template_args['filtered_registrations_link'] = EE_Admin_Page::add_query_args_and_nonce(
1593
+				array(
1594
+					'action'   => 'default',
1595
+					'event_id' => $event_id,
1596
+				),
1597
+				REG_ADMIN_URL
1598
+			);
1599
+			$this->_template_args['filtered_transactions_link'] = EE_Admin_Page::add_query_args_and_nonce(
1600
+				array(
1601
+					'action' => 'default',
1602
+					'EVT_ID' => $event_id,
1603
+					'page'   => 'espresso_transactions',
1604
+				),
1605
+				admin_url('admin.php')
1606
+			);
1607
+			$this->_template_args['event_link'] = EE_Admin_Page::add_query_args_and_nonce(
1608
+				array(
1609
+					'page'   => 'espresso_events',
1610
+					'action' => 'edit',
1611
+					'post'   => $event_id,
1612
+				),
1613
+				admin_url('admin.php')
1614
+			);
1615
+			// next and previous links
1616
+			$next_reg = $this->_registration->next(
1617
+				null,
1618
+				array(),
1619
+				'REG_ID'
1620
+			);
1621
+			$this->_template_args['next_registration'] = $next_reg
1622
+				? $this->_next_link(
1623
+					EE_Admin_Page::add_query_args_and_nonce(
1624
+						array(
1625
+							'action'  => 'view_registration',
1626
+							'_REG_ID' => $next_reg['REG_ID'],
1627
+						),
1628
+						REG_ADMIN_URL
1629
+					),
1630
+					'dashicons dashicons-arrow-right ee-icon-size-22'
1631
+				)
1632
+				: '';
1633
+			$previous_reg = $this->_registration->previous(
1634
+				null,
1635
+				array(),
1636
+				'REG_ID'
1637
+			);
1638
+			$this->_template_args['previous_registration'] = $previous_reg
1639
+				? $this->_previous_link(
1640
+					EE_Admin_Page::add_query_args_and_nonce(
1641
+						array(
1642
+							'action'  => 'view_registration',
1643
+							'_REG_ID' => $previous_reg['REG_ID'],
1644
+						),
1645
+						REG_ADMIN_URL
1646
+					),
1647
+					'dashicons dashicons-arrow-left ee-icon-size-22'
1648
+				)
1649
+				: '';
1650
+			// grab header
1651
+			$template_path = REG_TEMPLATE_PATH . 'reg_admin_details_header.template.php';
1652
+			$this->_template_args['REG_ID'] = $this->_registration->ID();
1653
+			$this->_template_args['admin_page_header'] = EEH_Template::display_template(
1654
+				$template_path,
1655
+				$this->_template_args,
1656
+				true
1657
+			);
1658
+		} else {
1659
+			$this->_template_args['admin_page_header'] = $this->display_espresso_notices();
1660
+		}
1661
+		// the details template wrapper
1662
+		$this->display_admin_page_with_sidebar();
1663
+	}
1664
+
1665
+
1666
+	protected function _registration_details_metaboxes()
1667
+	{
1668
+		do_action('AHEE__Registrations_Admin_Page___registration_details_metabox__start', $this);
1669
+		$this->_set_registration_object();
1670
+		$attendee = $this->_registration instanceof EE_Registration ? $this->_registration->attendee() : null;
1671
+		add_meta_box(
1672
+			'edit-reg-status-mbox',
1673
+			esc_html__('Registration Status', 'event_espresso'),
1674
+			array($this, 'set_reg_status_buttons_metabox'),
1675
+			$this->wp_page_slug,
1676
+			'normal',
1677
+			'high'
1678
+		);
1679
+		add_meta_box(
1680
+			'edit-reg-details-mbox',
1681
+			esc_html__('Registration Details', 'event_espresso'),
1682
+			array($this, '_reg_details_meta_box'),
1683
+			$this->wp_page_slug,
1684
+			'normal',
1685
+			'high'
1686
+		);
1687
+		if ($attendee instanceof EE_Attendee
1688
+			&& EE_Registry::instance()->CAP->current_user_can(
1689
+				'ee_read_registration',
1690
+				'edit-reg-questions-mbox',
1691
+				$this->_registration->ID()
1692
+			)
1693
+		) {
1694
+			add_meta_box(
1695
+				'edit-reg-questions-mbox',
1696
+				esc_html__('Registration Form Answers', 'event_espresso'),
1697
+				array($this, '_reg_questions_meta_box'),
1698
+				$this->wp_page_slug,
1699
+				'normal',
1700
+				'high'
1701
+			);
1702
+		}
1703
+		add_meta_box(
1704
+			'edit-reg-registrant-mbox',
1705
+			esc_html__('Contact Details', 'event_espresso'),
1706
+			array($this, '_reg_registrant_side_meta_box'),
1707
+			$this->wp_page_slug,
1708
+			'side',
1709
+			'high'
1710
+		);
1711
+		if ($this->_registration->group_size() > 1) {
1712
+			add_meta_box(
1713
+				'edit-reg-attendees-mbox',
1714
+				esc_html__('Other Registrations in this Transaction', 'event_espresso'),
1715
+				array($this, '_reg_attendees_meta_box'),
1716
+				$this->wp_page_slug,
1717
+				'normal',
1718
+				'high'
1719
+			);
1720
+		}
1721
+	}
1722
+
1723
+
1724
+	/**
1725
+	 * set_reg_status_buttons_metabox
1726
+	 *
1727
+	 * @access protected
1728
+	 * @return string
1729
+	 * @throws \EE_Error
1730
+	 */
1731
+	public function set_reg_status_buttons_metabox()
1732
+	{
1733
+		$this->_set_registration_object();
1734
+		$change_reg_status_form = $this->_generate_reg_status_change_form();
1735
+		echo $change_reg_status_form->form_open(
1736
+			self::add_query_args_and_nonce(
1737
+				array(
1738
+					'action' => 'change_reg_status',
1739
+				),
1740
+				REG_ADMIN_URL
1741
+			)
1742
+		);
1743
+		echo $change_reg_status_form->get_html();
1744
+		echo $change_reg_status_form->form_close();
1745
+	}
1746
+
1747
+
1748
+	/**
1749
+	 * @return EE_Form_Section_Proper
1750
+	 * @throws EE_Error
1751
+	 * @throws InvalidArgumentException
1752
+	 * @throws InvalidDataTypeException
1753
+	 * @throws InvalidInterfaceException
1754
+	 * @throws \EventEspresso\core\exceptions\EntityNotFoundException
1755
+	 */
1756
+	protected function _generate_reg_status_change_form()
1757
+	{
1758
+		$reg_status_change_form_array = array(
1759
+			'name'            => 'reg_status_change_form',
1760
+			'html_id'         => 'reg-status-change-form',
1761
+			'layout_strategy' => new EE_Admin_Two_Column_Layout(),
1762
+			'subsections'     => array(
1763
+				'return'             => new EE_Hidden_Input(
1764
+					array(
1765
+						'name'    => 'return',
1766
+						'default' => 'view_registration',
1767
+					)
1768
+				),
1769
+				'REG_ID'             => new EE_Hidden_Input(
1770
+					array(
1771
+						'name'    => 'REG_ID',
1772
+						'default' => $this->_registration->ID(),
1773
+					)
1774
+				),
1775
+				'current_status'     => new EE_Form_Section_HTML(
1776
+					EEH_HTML::tr(
1777
+						EEH_HTML::th(
1778
+							EEH_HTML::label(
1779
+								EEH_HTML::strong(
1780
+									esc_html__('Current Registration Status', 'event_espresso')
1781
+								)
1782
+							)
1783
+						)
1784
+						. EEH_HTML::td(
1785
+							EEH_HTML::strong(
1786
+								$this->_registration->pretty_status(),
1787
+								'',
1788
+								'status-' . $this->_registration->status_ID(),
1789
+								'line-height: 1em; font-size: 1.5em; font-weight: bold;'
1790
+							)
1791
+						)
1792
+					)
1793
+				)
1794
+			)
1795
+		);
1796
+		if (EE_Registry::instance()->CAP->current_user_can(
1797
+			'ee_edit_registration',
1798
+			'toggle_registration_status',
1799
+			$this->_registration->ID()
1800
+		)) {
1801
+			$reg_status_change_form_array['subsections']['reg_status'] = new EE_Select_Input(
1802
+				$this->_get_reg_statuses(),
1803
+				array(
1804
+					'html_label_text' => esc_html__('Change Registration Status to', 'event_espresso'),
1805
+					'default'         => $this->_registration->status_ID(),
1806
+				)
1807
+			);
1808
+			$reg_status_change_form_array['subsections']['send_notifications'] = new EE_Yes_No_Input(
1809
+				array(
1810
+					'html_label_text' => esc_html__('Send Related Messages', 'event_espresso'),
1811
+					'default'         => false,
1812
+					'html_help_text'  => esc_html__(
1813
+						'If set to "Yes", then the related messages will be sent to the registrant.',
1814
+						'event_espresso'
1815
+					)
1816
+				)
1817
+			);
1818
+			$reg_status_change_form_array['subsections']['submit'] = new EE_Submit_Input(
1819
+				array(
1820
+					'html_class'      => 'button-primary',
1821
+					'html_label_text' => '&nbsp;',
1822
+					'default'         => esc_html__('Update Registration Status', 'event_espresso'),
1823
+				)
1824
+			);
1825
+		}
1826
+		return new EE_Form_Section_Proper($reg_status_change_form_array);
1827
+	}
1828
+
1829
+
1830
+	/**
1831
+	 * Returns an array of all the buttons for the various statuses and switch status actions
1832
+	 *
1833
+	 * @return array
1834
+	 * @throws EE_Error
1835
+	 * @throws InvalidArgumentException
1836
+	 * @throws InvalidDataTypeException
1837
+	 * @throws InvalidInterfaceException
1838
+	 * @throws EntityNotFoundException
1839
+	 */
1840
+	protected function _get_reg_statuses()
1841
+	{
1842
+		$reg_status_array = EEM_Registration::instance()->reg_status_array();
1843
+		unset($reg_status_array[ EEM_Registration::status_id_incomplete ]);
1844
+		// get current reg status
1845
+		$current_status = $this->_registration->status_ID();
1846
+		// is registration for free event? This will determine whether to display the pending payment option
1847
+		if ($current_status !== EEM_Registration::status_id_pending_payment
1848
+			&& EEH_Money::compare_floats($this->_registration->ticket()->price(), 0.00)
1849
+		) {
1850
+			unset($reg_status_array[ EEM_Registration::status_id_pending_payment ]);
1851
+		}
1852
+		return EEM_Status::instance()->localized_status($reg_status_array, false, 'sentence');
1853
+	}
1854
+
1855
+
1856
+	/**
1857
+	 * This method is used when using _REG_ID from request which may or may not be an array of reg_ids.
1858
+	 *
1859
+	 * @param bool $status REG status given for changing registrations to.
1860
+	 * @param bool $notify Whether to send messages notifications or not.
1861
+	 * @return array (array with reg_id(s) updated and whether update was successful.
1862
+	 * @throws EE_Error
1863
+	 * @throws InvalidArgumentException
1864
+	 * @throws InvalidDataTypeException
1865
+	 * @throws InvalidInterfaceException
1866
+	 * @throws ReflectionException
1867
+	 * @throws RuntimeException
1868
+	 * @throws EntityNotFoundException
1869
+	 */
1870
+	protected function _set_registration_status_from_request($status = false, $notify = false)
1871
+	{
1872
+		if (isset($this->_req_data['reg_status_change_form'])) {
1873
+			$REG_IDs = isset($this->_req_data['reg_status_change_form']['REG_ID'])
1874
+				? (array) $this->_req_data['reg_status_change_form']['REG_ID']
1875
+				: array();
1876
+		} else {
1877
+			$REG_IDs = isset($this->_req_data['_REG_ID'])
1878
+				? (array) $this->_req_data['_REG_ID']
1879
+				: array();
1880
+		}
1881
+		// sanitize $REG_IDs
1882
+		$REG_IDs = array_map('absint', $REG_IDs);
1883
+		// and remove empty entries
1884
+		$REG_IDs = array_filter($REG_IDs);
1885
+
1886
+		$result = $this->_set_registration_status($REG_IDs, $status, $notify);
1887
+
1888
+		/**
1889
+		 * Set and filter $_req_data['_REG_ID'] for any potential future messages notifications.
1890
+		 * Currently this value is used downstream by the _process_resend_registration method.
1891
+		 *
1892
+		 * @param int|array                $registration_ids The registration ids that have had their status changed successfully.
1893
+		 * @param bool                     $status           The status registrations were changed to.
1894
+		 * @param bool                     $success          If the status was changed successfully for all registrations.
1895
+		 * @param Registrations_Admin_Page $admin_page_object
1896
+		 */
1897
+		$this->_req_data['_REG_ID'] = apply_filters(
1898
+			'FHEE__Registrations_Admin_Page___set_registration_status_from_request__REG_IDs',
1899
+			$result['REG_ID'],
1900
+			$status,
1901
+			$result['success'],
1902
+			$this
1903
+		);
1904
+
1905
+		// notify?
1906
+		if ($notify
1907
+			&& $result['success']
1908
+			&& ! empty($this->_req_data['_REG_ID'])
1909
+			&& EE_Registry::instance()->CAP->current_user_can(
1910
+				'ee_send_message',
1911
+				'espresso_registrations_resend_registration'
1912
+			)
1913
+		) {
1914
+			$this->_process_resend_registration();
1915
+		}
1916
+		return $result;
1917
+	}
1918
+
1919
+
1920
+	/**
1921
+	 * Set the registration status for the given reg_id (which may or may not be an array, it gets typecast to an
1922
+	 * array). Note, this method does NOT take care of possible notifications.  That is required by calling code.
1923
+	 *
1924
+	 * @param array  $REG_IDs
1925
+	 * @param string $status
1926
+	 * @param bool   $notify  Used to indicate whether notification was requested or not.  This determines the context
1927
+	 *                        slug sent with setting the registration status.
1928
+	 * @return array (an array with 'success' key representing whether status change was successful, and 'REG_ID' as
1929
+	 * @throws EE_Error
1930
+	 * @throws InvalidArgumentException
1931
+	 * @throws InvalidDataTypeException
1932
+	 * @throws InvalidInterfaceException
1933
+	 * @throws ReflectionException
1934
+	 * @throws RuntimeException
1935
+	 * @throws EntityNotFoundException
1936
+	 */
1937
+	protected function _set_registration_status($REG_IDs = array(), $status = '', $notify = false)
1938
+	{
1939
+		$success = false;
1940
+		// typecast $REG_IDs
1941
+		$REG_IDs = (array) $REG_IDs;
1942
+		if (! empty($REG_IDs)) {
1943
+			$success = true;
1944
+			// set default status if none is passed
1945
+			$status = $status ? $status : EEM_Registration::status_id_pending_payment;
1946
+			$status_context = $notify
1947
+				? Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN_NOTIFY
1948
+				: Domain::CONTEXT_REGISTRATION_STATUS_CHANGE_REGISTRATION_ADMIN;
1949
+			// loop through REG_ID's and change status
1950
+			foreach ($REG_IDs as $REG_ID) {
1951
+				$registration = EEM_Registration::instance()->get_one_by_ID($REG_ID);
1952
+				if ($registration instanceof EE_Registration) {
1953
+					$registration->set_status(
1954
+						$status,
1955
+						false,
1956
+						new Context(
1957
+							$status_context,
1958
+							esc_html__(
1959
+								'Manually triggered status change on a Registration Admin Page route.',
1960
+								'event_espresso'
1961
+							)
1962
+						)
1963
+					);
1964
+					$result = $registration->save();
1965
+					// verifying explicit fails because update *may* just return 0 for 0 rows affected
1966
+					$success = $result !== false ? $success : false;
1967
+				}
1968
+			}
1969
+		}
1970
+
1971
+		// return $success and processed registrations
1972
+		return array('REG_ID' => $REG_IDs, 'success' => $success);
1973
+	}
1974
+
1975
+
1976
+	/**
1977
+	 * Common logic for setting up success message and redirecting to appropriate route
1978
+	 *
1979
+	 * @param  string $STS_ID status id for the registration changed to
1980
+	 * @param   bool  $notify indicates whether the _set_registration_status_from_request does notifications or not.
1981
+	 * @return void
1982
+	 * @throws EE_Error
1983
+	 */
1984
+	protected function _reg_status_change_return($STS_ID, $notify = false)
1985
+	{
1986
+		$result = ! empty($STS_ID) ? $this->_set_registration_status_from_request($STS_ID, $notify)
1987
+			: array('success' => false);
1988
+		$success = isset($result['success']) && $result['success'];
1989
+		// setup success message
1990
+		if ($success) {
1991
+			if (is_array($result['REG_ID']) && count($result['REG_ID']) === 1) {
1992
+				$msg = sprintf(
1993
+					esc_html__('Registration status has been set to %s', 'event_espresso'),
1994
+					EEH_Template::pretty_status($STS_ID, false, 'lower')
1995
+				);
1996
+			} else {
1997
+				$msg = sprintf(
1998
+					esc_html__('Registrations have been set to %s.', 'event_espresso'),
1999
+					EEH_Template::pretty_status($STS_ID, false, 'lower')
2000
+				);
2001
+			}
2002
+			EE_Error::add_success($msg);
2003
+		} else {
2004
+			EE_Error::add_error(
2005
+				esc_html__(
2006
+					'Something went wrong, and the status was not changed',
2007
+					'event_espresso'
2008
+				),
2009
+				__FILE__,
2010
+				__LINE__,
2011
+				__FUNCTION__
2012
+			);
2013
+		}
2014
+		if (isset($this->_req_data['return']) && $this->_req_data['return'] == 'view_registration') {
2015
+			$route = array('action' => 'view_registration', '_REG_ID' => reset($result['REG_ID']));
2016
+		} else {
2017
+			$route = array('action' => 'default');
2018
+		}
2019
+		// unset nonces
2020
+		foreach ($this->_req_data as $ref => $value) {
2021
+			if (strpos($ref, 'nonce') !== false) {
2022
+				unset($this->_req_data[ $ref ]);
2023
+				continue;
2024
+			}
2025
+			$value = is_array($value) ? array_map('urlencode', $value) : urlencode($value);
2026
+			$this->_req_data[ $ref ] = $value;
2027
+		}
2028
+		// merge request vars so that the reloaded list table contains any existing filter query params
2029
+		$route = array_merge($this->_req_data, $route);
2030
+		$this->_redirect_after_action($success, '', '', $route, true);
2031
+	}
2032
+
2033
+
2034
+	/**
2035
+	 * incoming reg status change from reg details page.
2036
+	 *
2037
+	 * @return void
2038
+	 */
2039
+	protected function _change_reg_status()
2040
+	{
2041
+		$this->_req_data['return'] = 'view_registration';
2042
+		// set notify based on whether the send notifications toggle is set or not
2043
+		$notify = ! empty($this->_req_data['reg_status_change_form']['send_notifications']);
2044
+		// $notify = ! empty( $this->_req_data['txn_reg_status_change']['send_notifications'] );
2045
+		$this->_req_data['reg_status_change_form']['reg_status'] = isset($this->_req_data['reg_status_change_form']['reg_status'])
2046
+			? $this->_req_data['reg_status_change_form']['reg_status'] : '';
2047
+		switch ($this->_req_data['reg_status_change_form']['reg_status']) {
2048
+			case EEM_Registration::status_id_approved:
2049
+			case EEH_Template::pretty_status(EEM_Registration::status_id_approved, false, 'sentence'):
2050
+				$this->approve_registration($notify);
2051
+				break;
2052
+			case EEM_Registration::status_id_pending_payment:
2053
+			case EEH_Template::pretty_status(EEM_Registration::status_id_pending_payment, false, 'sentence'):
2054
+				$this->pending_registration($notify);
2055
+				break;
2056
+			case EEM_Registration::status_id_not_approved:
2057
+			case EEH_Template::pretty_status(EEM_Registration::status_id_not_approved, false, 'sentence'):
2058
+				$this->not_approve_registration($notify);
2059
+				break;
2060
+			case EEM_Registration::status_id_declined:
2061
+			case EEH_Template::pretty_status(EEM_Registration::status_id_declined, false, 'sentence'):
2062
+				$this->decline_registration($notify);
2063
+				break;
2064
+			case EEM_Registration::status_id_cancelled:
2065
+			case EEH_Template::pretty_status(EEM_Registration::status_id_cancelled, false, 'sentence'):
2066
+				$this->cancel_registration($notify);
2067
+				break;
2068
+			case EEM_Registration::status_id_wait_list:
2069
+			case EEH_Template::pretty_status(EEM_Registration::status_id_wait_list, false, 'sentence'):
2070
+				$this->wait_list_registration($notify);
2071
+				break;
2072
+			case EEM_Registration::status_id_incomplete:
2073
+			default:
2074
+				$result['success'] = false;
2075
+				unset($this->_req_data['return']);
2076
+				$this->_reg_status_change_return('', false);
2077
+				break;
2078
+		}
2079
+	}
2080
+
2081
+
2082
+	/**
2083
+	 * Callback for bulk action routes.
2084
+	 * Note: although we could just register the singular route callbacks for each bulk action route as well, this
2085
+	 * method was chosen so there is one central place all the registration status bulk actions are going through.
2086
+	 * Potentially, this provides an easier place to locate logic that is specific to these bulk actions (as opposed to
2087
+	 * when an action is happening on just a single registration).
2088
+	 *
2089
+	 * @param      $action
2090
+	 * @param bool $notify
2091
+	 */
2092
+	protected function bulk_action_on_registrations($action, $notify = false)
2093
+	{
2094
+		do_action(
2095
+			'AHEE__Registrations_Admin_Page__bulk_action_on_registrations__before_execution',
2096
+			$this,
2097
+			$action,
2098
+			$notify
2099
+		);
2100
+		$method = $action . '_registration';
2101
+		if (method_exists($this, $method)) {
2102
+			$this->$method($notify);
2103
+		}
2104
+	}
2105
+
2106
+
2107
+	/**
2108
+	 * approve_registration
2109
+	 *
2110
+	 * @access protected
2111
+	 * @param bool $notify whether or not to notify the registrant about their approval.
2112
+	 * @return void
2113
+	 */
2114
+	protected function approve_registration($notify = false)
2115
+	{
2116
+		$this->_reg_status_change_return(EEM_Registration::status_id_approved, $notify);
2117
+	}
2118
+
2119
+
2120
+	/**
2121
+	 *        decline_registration
2122
+	 *
2123
+	 * @access protected
2124
+	 * @param bool $notify whether or not to notify the registrant about their status change.
2125
+	 * @return void
2126
+	 */
2127
+	protected function decline_registration($notify = false)
2128
+	{
2129
+		$this->_reg_status_change_return(EEM_Registration::status_id_declined, $notify);
2130
+	}
2131
+
2132
+
2133
+	/**
2134
+	 *        cancel_registration
2135
+	 *
2136
+	 * @access protected
2137
+	 * @param bool $notify whether or not to notify the registrant about their status change.
2138
+	 * @return void
2139
+	 */
2140
+	protected function cancel_registration($notify = false)
2141
+	{
2142
+		$this->_reg_status_change_return(EEM_Registration::status_id_cancelled, $notify);
2143
+	}
2144
+
2145
+
2146
+	/**
2147
+	 *        not_approve_registration
2148
+	 *
2149
+	 * @access protected
2150
+	 * @param bool $notify whether or not to notify the registrant about their status change.
2151
+	 * @return void
2152
+	 */
2153
+	protected function not_approve_registration($notify = false)
2154
+	{
2155
+		$this->_reg_status_change_return(EEM_Registration::status_id_not_approved, $notify);
2156
+	}
2157
+
2158
+
2159
+	/**
2160
+	 *        decline_registration
2161
+	 *
2162
+	 * @access protected
2163
+	 * @param bool $notify whether or not to notify the registrant about their status change.
2164
+	 * @return void
2165
+	 */
2166
+	protected function pending_registration($notify = false)
2167
+	{
2168
+		$this->_reg_status_change_return(EEM_Registration::status_id_pending_payment, $notify);
2169
+	}
2170
+
2171
+
2172
+	/**
2173
+	 * waitlist_registration
2174
+	 *
2175
+	 * @access protected
2176
+	 * @param bool $notify whether or not to notify the registrant about their status change.
2177
+	 * @return void
2178
+	 */
2179
+	protected function wait_list_registration($notify = false)
2180
+	{
2181
+		$this->_reg_status_change_return(EEM_Registration::status_id_wait_list, $notify);
2182
+	}
2183
+
2184
+
2185
+	/**
2186
+	 *        generates HTML for the Registration main meta box
2187
+	 *
2188
+	 * @access public
2189
+	 * @return void
2190
+	 * @throws DomainException
2191
+	 * @throws EE_Error
2192
+	 * @throws InvalidArgumentException
2193
+	 * @throws InvalidDataTypeException
2194
+	 * @throws InvalidInterfaceException
2195
+	 * @throws ReflectionException
2196
+	 * @throws EntityNotFoundException
2197
+	 */
2198
+	public function _reg_details_meta_box()
2199
+	{
2200
+		EEH_Autoloader::register_line_item_display_autoloaders();
2201
+		EEH_Autoloader::register_line_item_filter_autoloaders();
2202
+		EE_Registry::instance()->load_helper('Line_Item');
2203
+		$transaction = $this->_registration->transaction() ? $this->_registration->transaction()
2204
+			: EE_Transaction::new_instance();
2205
+		$this->_session = $transaction->session_data();
2206
+		$filters = new EE_Line_Item_Filter_Collection();
2207
+		// $filters->add( new EE_Non_Zero_Line_Item_Filter() );
2208
+		$filters->add(new EE_Single_Registration_Line_Item_Filter($this->_registration));
2209
+		$line_item_filter_processor = new EE_Line_Item_Filter_Processor(
2210
+			$filters,
2211
+			$transaction->total_line_item()
2212
+		);
2213
+		$filtered_line_item_tree = $line_item_filter_processor->process();
2214
+		$line_item_display = new EE_Line_Item_Display(
2215
+			'reg_admin_table',
2216
+			'EE_Admin_Table_Registration_Line_Item_Display_Strategy'
2217
+		);
2218
+		$this->_template_args['line_item_table'] = $line_item_display->display_line_item(
2219
+			$filtered_line_item_tree,
2220
+			array('EE_Registration' => $this->_registration)
2221
+		);
2222
+		$attendee = $this->_registration->attendee();
2223
+		if (EE_Registry::instance()->CAP->current_user_can(
2224
+			'ee_read_transaction',
2225
+			'espresso_transactions_view_transaction'
2226
+		)) {
2227
+			$this->_template_args['view_transaction_button'] = EEH_Template::get_button_or_link(
2228
+				EE_Admin_Page::add_query_args_and_nonce(
2229
+					array(
2230
+						'action' => 'view_transaction',
2231
+						'TXN_ID' => $transaction->ID(),
2232
+					),
2233
+					TXN_ADMIN_URL
2234
+				),
2235
+				esc_html__(' View Transaction', 'event_espresso'),
2236
+				'button secondary-button right',
2237
+				'dashicons dashicons-cart'
2238
+			);
2239
+		} else {
2240
+			$this->_template_args['view_transaction_button'] = '';
2241
+		}
2242
+		if ($attendee instanceof EE_Attendee
2243
+			&& EE_Registry::instance()->CAP->current_user_can(
2244
+				'ee_send_message',
2245
+				'espresso_registrations_resend_registration'
2246
+			)
2247
+		) {
2248
+			$this->_template_args['resend_registration_button'] = EEH_Template::get_button_or_link(
2249
+				EE_Admin_Page::add_query_args_and_nonce(
2250
+					array(
2251
+						'action'      => 'resend_registration',
2252
+						'_REG_ID'     => $this->_registration->ID(),
2253
+						'redirect_to' => 'view_registration',
2254
+					),
2255
+					REG_ADMIN_URL
2256
+				),
2257
+				esc_html__(' Resend Registration', 'event_espresso'),
2258
+				'button secondary-button right',
2259
+				'dashicons dashicons-email-alt'
2260
+			);
2261
+		} else {
2262
+			$this->_template_args['resend_registration_button'] = '';
2263
+		}
2264
+		$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2265
+		$payment = $transaction->get_first_related('Payment');
2266
+		$payment = ! $payment instanceof EE_Payment
2267
+			? EE_Payment::new_instance()
2268
+			: $payment;
2269
+		$payment_method = $payment->get_first_related('Payment_Method');
2270
+		$payment_method = ! $payment_method instanceof EE_Payment_Method
2271
+			? EE_Payment_Method::new_instance()
2272
+			: $payment_method;
2273
+		$reg_details = array(
2274
+			'payment_method'       => $payment_method->name(),
2275
+			'response_msg'         => $payment->gateway_response(),
2276
+			'registration_id'      => $this->_registration->get('REG_code'),
2277
+			'registration_session' => $this->_registration->session_ID(),
2278
+			'ip_address'           => isset($this->_session['ip_address']) ? $this->_session['ip_address'] : '',
2279
+			'user_agent'           => isset($this->_session['user_agent']) ? $this->_session['user_agent'] : '',
2280
+		);
2281
+		if (isset($reg_details['registration_id'])) {
2282
+			$this->_template_args['reg_details']['registration_id']['value'] = $reg_details['registration_id'];
2283
+			$this->_template_args['reg_details']['registration_id']['label'] = esc_html__(
2284
+				'Registration ID',
2285
+				'event_espresso'
2286
+			);
2287
+			$this->_template_args['reg_details']['registration_id']['class'] = 'regular-text';
2288
+		}
2289
+		if (isset($reg_details['payment_method'])) {
2290
+			$this->_template_args['reg_details']['payment_method']['value'] = $reg_details['payment_method'];
2291
+			$this->_template_args['reg_details']['payment_method']['label'] = esc_html__(
2292
+				'Most Recent Payment Method',
2293
+				'event_espresso'
2294
+			);
2295
+			$this->_template_args['reg_details']['payment_method']['class'] = 'regular-text';
2296
+			$this->_template_args['reg_details']['response_msg']['value'] = $reg_details['response_msg'];
2297
+			$this->_template_args['reg_details']['response_msg']['label'] = esc_html__(
2298
+				'Payment method response',
2299
+				'event_espresso'
2300
+			);
2301
+			$this->_template_args['reg_details']['response_msg']['class'] = 'regular-text';
2302
+		}
2303
+		$this->_template_args['reg_details']['registration_session']['value'] = $reg_details['registration_session'];
2304
+		$this->_template_args['reg_details']['registration_session']['label'] = esc_html__(
2305
+			'Registration Session',
2306
+			'event_espresso'
2307
+		);
2308
+		$this->_template_args['reg_details']['registration_session']['class'] = 'regular-text';
2309
+		$this->_template_args['reg_details']['ip_address']['value'] = $reg_details['ip_address'];
2310
+		$this->_template_args['reg_details']['ip_address']['label'] = esc_html__(
2311
+			'Registration placed from IP',
2312
+			'event_espresso'
2313
+		);
2314
+		$this->_template_args['reg_details']['ip_address']['class'] = 'regular-text';
2315
+		$this->_template_args['reg_details']['user_agent']['value'] = $reg_details['user_agent'];
2316
+		$this->_template_args['reg_details']['user_agent']['label'] = esc_html__(
2317
+			'Registrant User Agent',
2318
+			'event_espresso'
2319
+		);
2320
+		$this->_template_args['reg_details']['user_agent']['class'] = 'large-text';
2321
+		$this->_template_args['event_link'] = EE_Admin_Page::add_query_args_and_nonce(
2322
+			array(
2323
+				'action'   => 'default',
2324
+				'event_id' => $this->_registration->event_ID(),
2325
+			),
2326
+			REG_ADMIN_URL
2327
+		);
2328
+		$this->_template_args['REG_ID'] = $this->_registration->ID();
2329
+		$this->_template_args['event_id'] = $this->_registration->event_ID();
2330
+		$template_path =
2331
+			REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_details.template.php';
2332
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);
2333
+	}
2334
+
2335
+
2336
+	/**
2337
+	 * generates HTML for the Registration Questions meta box.
2338
+	 * If pre-4.8.32.rc.000 hooks are used, uses old methods (with its filters),
2339
+	 * otherwise uses new forms system
2340
+	 *
2341
+	 * @access public
2342
+	 * @return void
2343
+	 * @throws DomainException
2344
+	 * @throws EE_Error
2345
+	 */
2346
+	public function _reg_questions_meta_box()
2347
+	{
2348
+		// allow someone to override this method entirely
2349
+		if (apply_filters(
2350
+			'FHEE__Registrations_Admin_Page___reg_questions_meta_box__do_default',
2351
+			true,
2352
+			$this,
2353
+			$this->_registration
2354
+		)) {
2355
+			$form = $this->_get_reg_custom_questions_form(
2356
+				$this->_registration->ID()
2357
+			);
2358
+			$this->_template_args['att_questions'] = count($form->subforms()) > 0
2359
+				? $form->get_html_and_js()
2360
+				: '';
2361
+			$this->_template_args['reg_questions_form_action'] = 'edit_registration';
2362
+			$this->_template_args['REG_ID'] = $this->_registration->ID();
2363
+			$template_path =
2364
+				REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_reg_questions.template.php';
2365
+			echo EEH_Template::display_template($template_path, $this->_template_args, true);
2366
+		}
2367
+	}
2368
+
2369
+
2370
+	/**
2371
+	 * form_before_question_group
2372
+	 *
2373
+	 * @deprecated    as of 4.8.32.rc.000
2374
+	 * @access        public
2375
+	 * @param        string $output
2376
+	 * @return        string
2377
+	 */
2378
+	public function form_before_question_group($output)
2379
+	{
2380
+		EE_Error::doing_it_wrong(
2381
+			__CLASS__ . '::' . __FUNCTION__,
2382
+			esc_html__(
2383
+				'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.',
2384
+				'event_espresso'
2385
+			),
2386
+			'4.8.32.rc.000'
2387
+		);
2388
+		return '
2389 2389
 	<table class="form-table ee-width-100">
2390 2390
 		<tbody>
2391 2391
 			';
2392
-    }
2393
-
2394
-
2395
-    /**
2396
-     * form_after_question_group
2397
-     *
2398
-     * @deprecated    as of 4.8.32.rc.000
2399
-     * @access        public
2400
-     * @param        string $output
2401
-     * @return        string
2402
-     */
2403
-    public function form_after_question_group($output)
2404
-    {
2405
-        EE_Error::doing_it_wrong(
2406
-            __CLASS__ . '::' . __FUNCTION__,
2407
-            esc_html__(
2408
-                '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.',
2409
-                'event_espresso'
2410
-            ),
2411
-            '4.8.32.rc.000'
2412
-        );
2413
-        return '
2392
+	}
2393
+
2394
+
2395
+	/**
2396
+	 * form_after_question_group
2397
+	 *
2398
+	 * @deprecated    as of 4.8.32.rc.000
2399
+	 * @access        public
2400
+	 * @param        string $output
2401
+	 * @return        string
2402
+	 */
2403
+	public function form_after_question_group($output)
2404
+	{
2405
+		EE_Error::doing_it_wrong(
2406
+			__CLASS__ . '::' . __FUNCTION__,
2407
+			esc_html__(
2408
+				'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.',
2409
+				'event_espresso'
2410
+			),
2411
+			'4.8.32.rc.000'
2412
+		);
2413
+		return '
2414 2414
 			<tr class="hide-if-no-js">
2415 2415
 				<th> </th>
2416 2416
 				<td class="reg-admin-edit-attendee-question-td">
2417 2417
 					<a class="reg-admin-edit-attendee-question-lnk" href="#" title="'
2418
-               . esc_attr__('click to edit question', 'event_espresso')
2419
-               . '">
2418
+			   . esc_attr__('click to edit question', 'event_espresso')
2419
+			   . '">
2420 2420
 						<span class="reg-admin-edit-question-group-spn lt-grey-txt">'
2421
-               . esc_html__('edit the above question group', 'event_espresso')
2422
-               . '</span>
2421
+			   . esc_html__('edit the above question group', 'event_espresso')
2422
+			   . '</span>
2423 2423
 						<div class="dashicons dashicons-edit"></div>
2424 2424
 					</a>
2425 2425
 				</td>
@@ -2427,610 +2427,610 @@  discard block
 block discarded – undo
2427 2427
 		</tbody>
2428 2428
 	</table>
2429 2429
 ';
2430
-    }
2431
-
2432
-
2433
-    /**
2434
-     * form_form_field_label_wrap
2435
-     *
2436
-     * @deprecated    as of 4.8.32.rc.000
2437
-     * @access        public
2438
-     * @param        string $label
2439
-     * @return        string
2440
-     */
2441
-    public function form_form_field_label_wrap($label)
2442
-    {
2443
-        EE_Error::doing_it_wrong(
2444
-            __CLASS__ . '::' . __FUNCTION__,
2445
-            esc_html__(
2446
-                '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.',
2447
-                'event_espresso'
2448
-            ),
2449
-            '4.8.32.rc.000'
2450
-        );
2451
-        return '
2430
+	}
2431
+
2432
+
2433
+	/**
2434
+	 * form_form_field_label_wrap
2435
+	 *
2436
+	 * @deprecated    as of 4.8.32.rc.000
2437
+	 * @access        public
2438
+	 * @param        string $label
2439
+	 * @return        string
2440
+	 */
2441
+	public function form_form_field_label_wrap($label)
2442
+	{
2443
+		EE_Error::doing_it_wrong(
2444
+			__CLASS__ . '::' . __FUNCTION__,
2445
+			esc_html__(
2446
+				'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.',
2447
+				'event_espresso'
2448
+			),
2449
+			'4.8.32.rc.000'
2450
+		);
2451
+		return '
2452 2452
 			<tr>
2453 2453
 				<th>
2454 2454
 					' . $label . '
2455 2455
 				</th>';
2456
-    }
2457
-
2458
-
2459
-    /**
2460
-     * form_form_field_input__wrap
2461
-     *
2462
-     * @deprecated    as of 4.8.32.rc.000
2463
-     * @access        public
2464
-     * @param        string $input
2465
-     * @return        string
2466
-     */
2467
-    public function form_form_field_input__wrap($input)
2468
-    {
2469
-        EE_Error::doing_it_wrong(
2470
-            __CLASS__ . '::' . __FUNCTION__,
2471
-            esc_html__(
2472
-                '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.',
2473
-                'event_espresso'
2474
-            ),
2475
-            '4.8.32.rc.000'
2476
-        );
2477
-        return '
2456
+	}
2457
+
2458
+
2459
+	/**
2460
+	 * form_form_field_input__wrap
2461
+	 *
2462
+	 * @deprecated    as of 4.8.32.rc.000
2463
+	 * @access        public
2464
+	 * @param        string $input
2465
+	 * @return        string
2466
+	 */
2467
+	public function form_form_field_input__wrap($input)
2468
+	{
2469
+		EE_Error::doing_it_wrong(
2470
+			__CLASS__ . '::' . __FUNCTION__,
2471
+			esc_html__(
2472
+				'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.',
2473
+				'event_espresso'
2474
+			),
2475
+			'4.8.32.rc.000'
2476
+		);
2477
+		return '
2478 2478
 				<td class="reg-admin-attendee-questions-input-td disabled-input">
2479 2479
 					' . $input . '
2480 2480
 				</td>
2481 2481
 			</tr>';
2482
-    }
2483
-
2484
-
2485
-    /**
2486
-     * Updates the registration's custom questions according to the form info, if the form is submitted.
2487
-     * If it's not a post, the "view_registrations" route will be called next on the SAME request
2488
-     * to display the page
2489
-     *
2490
-     * @access protected
2491
-     * @return void
2492
-     * @throws EE_Error
2493
-     */
2494
-    protected function _update_attendee_registration_form()
2495
-    {
2496
-        do_action('AHEE__Registrations_Admin_Page___update_attendee_registration_form__start', $this);
2497
-        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
2498
-            $REG_ID = isset($this->_req_data['_REG_ID']) ? absint($this->_req_data['_REG_ID']) : false;
2499
-            $success = $this->_save_reg_custom_questions_form($REG_ID);
2500
-            if ($success) {
2501
-                $what = esc_html__('Registration Form', 'event_espresso');
2502
-                $route = $REG_ID ? array('action' => 'view_registration', '_REG_ID' => $REG_ID)
2503
-                    : array('action' => 'default');
2504
-                $this->_redirect_after_action($success, $what, esc_html__('updated', 'event_espresso'), $route);
2505
-            }
2506
-        }
2507
-    }
2508
-
2509
-
2510
-    /**
2511
-     * Gets the form for saving registrations custom questions (if done
2512
-     * previously retrieves the cached form object, which may have validation errors in it)
2513
-     *
2514
-     * @param int $REG_ID
2515
-     * @return EE_Registration_Custom_Questions_Form
2516
-     * @throws EE_Error
2517
-     * @throws InvalidArgumentException
2518
-     * @throws InvalidDataTypeException
2519
-     * @throws InvalidInterfaceException
2520
-     */
2521
-    protected function _get_reg_custom_questions_form($REG_ID)
2522
-    {
2523
-        if (! $this->_reg_custom_questions_form) {
2524
-            require_once(REG_ADMIN . 'form_sections' . DS . 'EE_Registration_Custom_Questions_Form.form.php');
2525
-            $this->_reg_custom_questions_form = new EE_Registration_Custom_Questions_Form(
2526
-                EEM_Registration::instance()->get_one_by_ID($REG_ID)
2527
-            );
2528
-            $this->_reg_custom_questions_form->_construct_finalize(null, null);
2529
-        }
2530
-        return $this->_reg_custom_questions_form;
2531
-    }
2532
-
2533
-
2534
-    /**
2535
-     * Saves
2536
-     *
2537
-     * @access private
2538
-     * @param bool $REG_ID
2539
-     * @return bool
2540
-     * @throws EE_Error
2541
-     * @throws InvalidArgumentException
2542
-     * @throws InvalidDataTypeException
2543
-     * @throws InvalidInterfaceException
2544
-     */
2545
-    private function _save_reg_custom_questions_form($REG_ID = false)
2546
-    {
2547
-        if (! $REG_ID) {
2548
-            EE_Error::add_error(
2549
-                esc_html__(
2550
-                    'An error occurred. No registration ID was received.',
2551
-                    'event_espresso'
2552
-                ),
2553
-                __FILE__,
2554
-                __FUNCTION__,
2555
-                __LINE__
2556
-            );
2557
-        }
2558
-        $form = $this->_get_reg_custom_questions_form($REG_ID);
2559
-        $form->receive_form_submission($this->_req_data);
2560
-        $success = false;
2561
-        if ($form->is_valid()) {
2562
-            foreach ($form->subforms() as $question_group_id => $question_group_form) {
2563
-                foreach ($question_group_form->inputs() as $question_id => $input) {
2564
-                    $where_conditions = array(
2565
-                        'QST_ID' => $question_id,
2566
-                        'REG_ID' => $REG_ID,
2567
-                    );
2568
-                    $possibly_new_values = array(
2569
-                        'ANS_value' => $input->normalized_value(),
2570
-                    );
2571
-                    $answer = EEM_Answer::instance()->get_one(array($where_conditions));
2572
-                    if ($answer instanceof EE_Answer) {
2573
-                        $success = $answer->save($possibly_new_values);
2574
-                    } else {
2575
-                        // insert it then
2576
-                        $cols_n_vals = array_merge($where_conditions, $possibly_new_values);
2577
-                        $answer = EE_Answer::new_instance($cols_n_vals);
2578
-                        $success = $answer->save();
2579
-                    }
2580
-                }
2581
-            }
2582
-        } else {
2583
-            EE_Error::add_error($form->get_validation_error_string(), __FILE__, __FUNCTION__, __LINE__);
2584
-        }
2585
-        return $success;
2586
-    }
2587
-
2588
-
2589
-    /**
2590
-     *        generates HTML for the Registration main meta box
2591
-     *
2592
-     * @access public
2593
-     * @return void
2594
-     * @throws DomainException
2595
-     * @throws EE_Error
2596
-     * @throws InvalidArgumentException
2597
-     * @throws InvalidDataTypeException
2598
-     * @throws InvalidInterfaceException
2599
-     */
2600
-    public function _reg_attendees_meta_box()
2601
-    {
2602
-        $REG = EEM_Registration::instance();
2603
-        // get all other registrations on this transaction, and cache
2604
-        // the attendees for them so we don't have to run another query using force_join
2605
-        $registrations = $REG->get_all(
2606
-            array(
2607
-                array(
2608
-                    'TXN_ID' => $this->_registration->transaction_ID(),
2609
-                    'REG_ID' => array('!=', $this->_registration->ID()),
2610
-                ),
2611
-                'force_join' => array('Attendee'),
2612
-            )
2613
-        );
2614
-        $this->_template_args['attendees'] = array();
2615
-        $this->_template_args['attendee_notice'] = '';
2616
-        if (empty($registrations)
2617
-            || (is_array($registrations)
2618
-                && ! EEH_Array::get_one_item_from_array($registrations))
2619
-        ) {
2620
-            EE_Error::add_error(
2621
-                esc_html__(
2622
-                    'There are no records attached to this registration. Something may have gone wrong with the registration',
2623
-                    'event_espresso'
2624
-                ),
2625
-                __FILE__,
2626
-                __FUNCTION__,
2627
-                __LINE__
2628
-            );
2629
-            $this->_template_args['attendee_notice'] = EE_Error::get_notices();
2630
-        } else {
2631
-            $att_nmbr = 1;
2632
-            foreach ($registrations as $registration) {
2633
-                /* @var $registration EE_Registration */
2634
-                $attendee = $registration->attendee()
2635
-                    ? $registration->attendee()
2636
-                    : EEM_Attendee::instance()
2637
-                                  ->create_default_object();
2638
-                $this->_template_args['attendees'][ $att_nmbr ]['STS_ID'] = $registration->status_ID();
2639
-                $this->_template_args['attendees'][ $att_nmbr ]['fname'] = $attendee->fname();
2640
-                $this->_template_args['attendees'][ $att_nmbr ]['lname'] = $attendee->lname();
2641
-                $this->_template_args['attendees'][ $att_nmbr ]['email'] = $attendee->email();
2642
-                $this->_template_args['attendees'][ $att_nmbr ]['final_price'] = $registration->final_price();
2643
-                $this->_template_args['attendees'][ $att_nmbr ]['address'] = implode(
2644
-                    ', ',
2645
-                    $attendee->full_address_as_array()
2646
-                );
2647
-                $this->_template_args['attendees'][ $att_nmbr ]['att_link'] = self::add_query_args_and_nonce(
2648
-                    array(
2649
-                        'action' => 'edit_attendee',
2650
-                        'post'   => $attendee->ID(),
2651
-                    ),
2652
-                    REG_ADMIN_URL
2653
-                );
2654
-                $this->_template_args['attendees'][ $att_nmbr ]['event_name'] = $registration->event_obj()->name();
2655
-                $att_nmbr++;
2656
-            }
2657
-            $this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2658
-        }
2659
-        $template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_attendees.template.php';
2660
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);
2661
-    }
2662
-
2663
-
2664
-    /**
2665
-     *        generates HTML for the Edit Registration side meta box
2666
-     *
2667
-     * @access public
2668
-     * @return void
2669
-     * @throws DomainException
2670
-     * @throws EE_Error
2671
-     * @throws InvalidArgumentException
2672
-     * @throws InvalidDataTypeException
2673
-     * @throws InvalidInterfaceException
2674
-     */
2675
-    public function _reg_registrant_side_meta_box()
2676
-    {
2677
-        /*@var $attendee EE_Attendee */
2678
-        $att_check = $this->_registration->attendee();
2679
-        $attendee = $att_check instanceof EE_Attendee ? $att_check : EEM_Attendee::instance()->create_default_object();
2680
-        // now let's determine if this is not the primary registration.  If it isn't then we set the
2681
-        // primary_registration object for reference BUT ONLY if the Attendee object loaded is not the same as the
2682
-        // primary registration object (that way we know if we need to show create button or not)
2683
-        if (! $this->_registration->is_primary_registrant()) {
2684
-            $primary_registration = $this->_registration->get_primary_registration();
2685
-            $primary_attendee = $primary_registration instanceof EE_Registration ? $primary_registration->attendee()
2686
-                : null;
2687
-            if (! $primary_attendee instanceof EE_Attendee || $attendee->ID() !== $primary_attendee->ID()) {
2688
-                // in here?  This means the displayed registration is not the primary registrant but ALREADY HAS its own
2689
-                // custom attendee object so let's not worry about the primary reg.
2690
-                $primary_registration = null;
2691
-            }
2692
-        } else {
2693
-            $primary_registration = null;
2694
-        }
2695
-        $this->_template_args['ATT_ID'] = $attendee->ID();
2696
-        $this->_template_args['fname'] = $attendee->fname();
2697
-        $this->_template_args['lname'] = $attendee->lname();
2698
-        $this->_template_args['email'] = $attendee->email();
2699
-        $this->_template_args['phone'] = $attendee->phone();
2700
-        $this->_template_args['formatted_address'] = EEH_Address::format($attendee);
2701
-        // edit link
2702
-        $this->_template_args['att_edit_link'] = EE_Admin_Page::add_query_args_and_nonce(
2703
-            array(
2704
-                'action' => 'edit_attendee',
2705
-                'post'   => $attendee->ID(),
2706
-            ),
2707
-            REG_ADMIN_URL
2708
-        );
2709
-        $this->_template_args['att_edit_label'] = esc_html__('View/Edit Contact', 'event_espresso');
2710
-        // create link
2711
-        $this->_template_args['create_link'] = $primary_registration instanceof EE_Registration
2712
-            ? EE_Admin_Page::add_query_args_and_nonce(
2713
-                array(
2714
-                    'action'  => 'duplicate_attendee',
2715
-                    '_REG_ID' => $this->_registration->ID(),
2716
-                ),
2717
-                REG_ADMIN_URL
2718
-            ) : '';
2719
-        $this->_template_args['create_label'] = esc_html__('Create Contact', 'event_espresso');
2720
-        $this->_template_args['att_check'] = $att_check;
2721
-        $template_path = REG_TEMPLATE_PATH . 'reg_admin_details_side_meta_box_registrant.template.php';
2722
-        echo EEH_Template::display_template($template_path, $this->_template_args, true);
2723
-    }
2724
-
2725
-
2726
-    /**
2727
-     * trash or restore registrations
2728
-     *
2729
-     * @param  boolean $trash whether to archive or restore
2730
-     * @return void
2731
-     * @throws DomainException
2732
-     * @throws EE_Error
2733
-     * @throws EntityNotFoundException
2734
-     * @throws InvalidArgumentException
2735
-     * @throws InvalidDataTypeException
2736
-     * @throws InvalidInterfaceException
2737
-     * @throws ReflectionException
2738
-     * @throws RuntimeException
2739
-     * @throws UnexpectedEntityException
2740
-     * @access protected
2741
-     */
2742
-    protected function _trash_or_restore_registrations($trash = true)
2743
-    {
2744
-        // if empty _REG_ID then get out because there's nothing to do
2745
-        if (empty($this->_req_data['_REG_ID'])) {
2746
-            EE_Error::add_error(
2747
-                sprintf(
2748
-                    esc_html__(
2749
-                        'In order to %1$s registrations you must select which ones you wish to %1$s by clicking the checkboxes.',
2750
-                        'event_espresso'
2751
-                    ),
2752
-                    $trash ? 'trash' : 'restore'
2753
-                ),
2754
-                __FILE__,
2755
-                __LINE__,
2756
-                __FUNCTION__
2757
-            );
2758
-            $this->_redirect_after_action(false, '', '', array(), true);
2759
-        }
2760
-        $success = 0;
2761
-        $overwrite_msgs = false;
2762
-        // Checkboxes
2763
-        if (! is_array($this->_req_data['_REG_ID'])) {
2764
-            $this->_req_data['_REG_ID'] = array($this->_req_data['_REG_ID']);
2765
-        }
2766
-        $reg_count = count($this->_req_data['_REG_ID']);
2767
-        // cycle thru checkboxes
2768
-        foreach ($this->_req_data['_REG_ID'] as $REG_ID) {
2769
-            /** @var EE_Registration $REG */
2770
-            $REG = EEM_Registration::instance()->get_one_by_ID($REG_ID);
2771
-            $payments = $REG->registration_payments();
2772
-            if (! empty($payments)) {
2773
-                $name = $REG->attendee() instanceof EE_Attendee
2774
-                    ? $REG->attendee()->full_name()
2775
-                    : esc_html__('Unknown Attendee', 'event_espresso');
2776
-                $overwrite_msgs = true;
2777
-                EE_Error::add_error(
2778
-                    sprintf(
2779
-                        esc_html__(
2780
-                            '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.',
2781
-                            'event_espresso'
2782
-                        ),
2783
-                        $name
2784
-                    ),
2785
-                    __FILE__,
2786
-                    __FUNCTION__,
2787
-                    __LINE__
2788
-                );
2789
-                // can't trash this registration because it has payments.
2790
-                continue;
2791
-            }
2792
-            $updated = $trash ? $REG->delete(__METHOD__) : $REG->restore(__METHOD__);
2793
-            if ($updated) {
2794
-                $success++;
2795
-            }
2796
-        }
2797
-        $this->_redirect_after_action(
2798
-            $success === $reg_count, // were ALL registrations affected?
2799
-            $success > 1
2800
-                ? esc_html__('Registrations', 'event_espresso')
2801
-                : esc_html__('Registration', 'event_espresso'),
2802
-            $trash
2803
-                ? esc_html__('moved to the trash', 'event_espresso')
2804
-                : esc_html__('restored', 'event_espresso'),
2805
-            array('action' => 'default'),
2806
-            $overwrite_msgs
2807
-        );
2808
-    }
2809
-
2810
-
2811
-    /**
2812
-     * This is used to permanently delete registrations.  Note, this will handle not only deleting permanently the
2813
-     * registration but also.
2814
-     * 1. Removing relations to EE_Attendee
2815
-     * 2. Deleting permanently the related transaction, but ONLY if all related registrations to the transaction are
2816
-     * ALSO trashed.
2817
-     * 3. Deleting permanently any related Line items but only if the above conditions are met.
2818
-     * 4. Removing relationships between all tickets and the related registrations
2819
-     * 5. Deleting permanently any related Answers (and the answers for other related registrations that were deleted.)
2820
-     * 6. Deleting permanently any related Checkins.
2821
-     *
2822
-     * @return void
2823
-     * @throws EE_Error
2824
-     * @throws InvalidArgumentException
2825
-     * @throws InvalidDataTypeException
2826
-     * @throws InvalidInterfaceException
2827
-     */
2828
-    protected function _delete_registrations()
2829
-    {
2830
-        $REG_MDL = EEM_Registration::instance();
2831
-        $success = 1;
2832
-        // Checkboxes
2833
-        if (! empty($this->_req_data['_REG_ID']) && is_array($this->_req_data['_REG_ID'])) {
2834
-            // if array has more than one element than success message should be plural
2835
-            $success = count($this->_req_data['_REG_ID']) > 1 ? 2 : 1;
2836
-            // cycle thru checkboxes
2837
-            while (list($ind, $REG_ID) = each($this->_req_data['_REG_ID'])) {
2838
-                $REG = $REG_MDL->get_one_by_ID($REG_ID);
2839
-                if (! $REG instanceof EE_Registration) {
2840
-                    continue;
2841
-                }
2842
-                $deleted = $this->_delete_registration($REG);
2843
-                if (! $deleted) {
2844
-                    $success = 0;
2845
-                }
2846
-            }
2847
-        } else {
2848
-            // grab single id and delete
2849
-            $REG_ID = $this->_req_data['_REG_ID'];
2850
-            $REG = $REG_MDL->get_one_by_ID($REG_ID);
2851
-            $deleted = $this->_delete_registration($REG);
2852
-            if (! $deleted) {
2853
-                $success = 0;
2854
-            }
2855
-        }
2856
-        $what = $success > 1
2857
-            ? esc_html__('Registrations', 'event_espresso')
2858
-            : esc_html__('Registration', 'event_espresso');
2859
-        $action_desc = esc_html__('permanently deleted.', 'event_espresso');
2860
-        $this->_redirect_after_action(
2861
-            $success,
2862
-            $what,
2863
-            $action_desc,
2864
-            array('action' => 'default'),
2865
-            true
2866
-        );
2867
-    }
2868
-
2869
-
2870
-    /**
2871
-     * handles the permanent deletion of a registration.  See comments with _delete_registrations() for details on what
2872
-     * models get affected.
2873
-     *
2874
-     * @param  EE_Registration $REG registration to be deleted permenantly
2875
-     * @return bool true = successful deletion, false = fail.
2876
-     * @throws EE_Error
2877
-     */
2878
-    protected function _delete_registration(EE_Registration $REG)
2879
-    {
2880
-        // first we start with the transaction... ultimately, we WILL not delete permanently if there are any related
2881
-        // registrations on the transaction that are NOT trashed.
2882
-        $TXN = $REG->get_first_related('Transaction');
2883
-        $REGS = $TXN->get_many_related('Registration');
2884
-        $all_trashed = true;
2885
-        foreach ($REGS as $registration) {
2886
-            if (! $registration->get('REG_deleted')) {
2887
-                $all_trashed = false;
2888
-            }
2889
-        }
2890
-        if (! $all_trashed) {
2891
-            EE_Error::add_error(
2892
-                esc_html__(
2893
-                    '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.',
2894
-                    'event_espresso'
2895
-                ),
2896
-                __FILE__,
2897
-                __FUNCTION__,
2898
-                __LINE__
2899
-            );
2900
-            return false;
2901
-        }
2902
-        // k made it here so that means we can delete all the related transactions and their answers (but let's do them
2903
-        // separately from THIS one).
2904
-        foreach ($REGS as $registration) {
2905
-            // delete related answers
2906
-            $registration->delete_related_permanently('Answer');
2907
-            // remove relationship to EE_Attendee (but we ALWAYS leave the contact record intact)
2908
-            $attendee = $registration->get_first_related('Attendee');
2909
-            if ($attendee instanceof EE_Attendee) {
2910
-                $registration->_remove_relation_to($attendee, 'Attendee');
2911
-            }
2912
-            // now remove relationships to tickets on this registration.
2913
-            $registration->_remove_relations('Ticket');
2914
-            // now delete permanently the checkins related to this registration.
2915
-            $registration->delete_related_permanently('Checkin');
2916
-            if ($registration->ID() === $REG->ID()) {
2917
-                continue;
2918
-            } //we don't want to delete permanently the existing registration just yet.
2919
-            // remove relation to transaction for these registrations if NOT the existing registrations
2920
-            $registration->_remove_relations('Transaction');
2921
-            // delete permanently any related messages.
2922
-            $registration->delete_related_permanently('Message');
2923
-            // now delete this registration permanently
2924
-            $registration->delete_permanently();
2925
-        }
2926
-        // now all related registrations on the transaction are handled.  So let's just handle this registration itself
2927
-        // (the transaction and line items should be all that's left).
2928
-        // delete the line items related to the transaction for this registration.
2929
-        $TXN->delete_related_permanently('Line_Item');
2930
-        // we need to remove all the relationships on the transaction
2931
-        $TXN->delete_related_permanently('Payment');
2932
-        $TXN->delete_related_permanently('Extra_Meta');
2933
-        $TXN->delete_related_permanently('Message');
2934
-        // now we can delete this REG permanently (and the transaction of course)
2935
-        $REG->delete_related_permanently('Transaction');
2936
-        return $REG->delete_permanently();
2937
-    }
2938
-
2939
-
2940
-    /**
2941
-     *    generates HTML for the Register New Attendee Admin page
2942
-     *
2943
-     * @access private
2944
-     * @throws DomainException
2945
-     * @throws EE_Error
2946
-     */
2947
-    public function new_registration()
2948
-    {
2949
-        if (! $this->_set_reg_event()) {
2950
-            throw new EE_Error(
2951
-                esc_html__(
2952
-                    'Unable to continue with registering because there is no Event ID in the request',
2953
-                    'event_espresso'
2954
-                )
2955
-            );
2956
-        }
2957
-        EE_Registry::instance()->REQ->set_espresso_page(true);
2958
-        // gotta start with a clean slate if we're not coming here via ajax
2959
-        if (! defined('DOING_AJAX')
2960
-            && (! isset($this->_req_data['processing_registration']) || isset($this->_req_data['step_error']))
2961
-        ) {
2962
-            EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
2963
-        }
2964
-        $this->_template_args['event_name'] = '';
2965
-        // event name
2966
-        if ($this->_reg_event) {
2967
-            $this->_template_args['event_name'] = $this->_reg_event->name();
2968
-            $edit_event_url = self::add_query_args_and_nonce(
2969
-                array(
2970
-                    'action' => 'edit',
2971
-                    'post'   => $this->_reg_event->ID(),
2972
-                ),
2973
-                EVENTS_ADMIN_URL
2974
-            );
2975
-            $edit_event_lnk = '<a href="'
2976
-                              . $edit_event_url
2977
-                              . '" title="'
2978
-                              . esc_attr__('Edit ', 'event_espresso')
2979
-                              . $this->_reg_event->name()
2980
-                              . '">'
2981
-                              . esc_html__('Edit Event', 'event_espresso')
2982
-                              . '</a>';
2983
-            $this->_template_args['event_name'] .= ' <span class="admin-page-header-edit-lnk not-bold">'
2984
-                                                   . $edit_event_lnk
2985
-                                                   . '</span>';
2986
-        }
2987
-        $this->_template_args['step_content'] = $this->_get_registration_step_content();
2988
-        if (defined('DOING_AJAX')) {
2989
-            $this->_return_json();
2990
-        }
2991
-        // grab header
2992
-        $template_path =
2993
-            REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee.template.php';
2994
-        $this->_template_args['admin_page_content'] = EEH_Template::display_template(
2995
-            $template_path,
2996
-            $this->_template_args,
2997
-            true
2998
-        );
2999
-        // $this->_set_publish_post_box_vars( NULL, FALSE, FALSE, NULL, FALSE );
3000
-        // the details template wrapper
3001
-        $this->display_admin_page_with_sidebar();
3002
-    }
3003
-
3004
-
3005
-    /**
3006
-     * This returns the content for a registration step
3007
-     *
3008
-     * @access protected
3009
-     * @return string html
3010
-     * @throws DomainException
3011
-     * @throws EE_Error
3012
-     * @throws InvalidArgumentException
3013
-     * @throws InvalidDataTypeException
3014
-     * @throws InvalidInterfaceException
3015
-     */
3016
-    protected function _get_registration_step_content()
3017
-    {
3018
-        if (isset($_COOKIE['ee_registration_added']) && $_COOKIE['ee_registration_added']) {
3019
-            $warning_msg = sprintf(
3020
-                esc_html__(
3021
-                    '%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',
3022
-                    'event_espresso'
3023
-                ),
3024
-                '<br />',
3025
-                '<h3 class="important-notice">',
3026
-                '</h3>',
3027
-                '<div class="float-right">',
3028
-                '<span id="redirect_timer" class="important-notice">30</span>',
3029
-                '</div>',
3030
-                '<b>',
3031
-                '</b>'
3032
-            );
3033
-            return '
2482
+	}
2483
+
2484
+
2485
+	/**
2486
+	 * Updates the registration's custom questions according to the form info, if the form is submitted.
2487
+	 * If it's not a post, the "view_registrations" route will be called next on the SAME request
2488
+	 * to display the page
2489
+	 *
2490
+	 * @access protected
2491
+	 * @return void
2492
+	 * @throws EE_Error
2493
+	 */
2494
+	protected function _update_attendee_registration_form()
2495
+	{
2496
+		do_action('AHEE__Registrations_Admin_Page___update_attendee_registration_form__start', $this);
2497
+		if ($_SERVER['REQUEST_METHOD'] == 'POST') {
2498
+			$REG_ID = isset($this->_req_data['_REG_ID']) ? absint($this->_req_data['_REG_ID']) : false;
2499
+			$success = $this->_save_reg_custom_questions_form($REG_ID);
2500
+			if ($success) {
2501
+				$what = esc_html__('Registration Form', 'event_espresso');
2502
+				$route = $REG_ID ? array('action' => 'view_registration', '_REG_ID' => $REG_ID)
2503
+					: array('action' => 'default');
2504
+				$this->_redirect_after_action($success, $what, esc_html__('updated', 'event_espresso'), $route);
2505
+			}
2506
+		}
2507
+	}
2508
+
2509
+
2510
+	/**
2511
+	 * Gets the form for saving registrations custom questions (if done
2512
+	 * previously retrieves the cached form object, which may have validation errors in it)
2513
+	 *
2514
+	 * @param int $REG_ID
2515
+	 * @return EE_Registration_Custom_Questions_Form
2516
+	 * @throws EE_Error
2517
+	 * @throws InvalidArgumentException
2518
+	 * @throws InvalidDataTypeException
2519
+	 * @throws InvalidInterfaceException
2520
+	 */
2521
+	protected function _get_reg_custom_questions_form($REG_ID)
2522
+	{
2523
+		if (! $this->_reg_custom_questions_form) {
2524
+			require_once(REG_ADMIN . 'form_sections' . DS . 'EE_Registration_Custom_Questions_Form.form.php');
2525
+			$this->_reg_custom_questions_form = new EE_Registration_Custom_Questions_Form(
2526
+				EEM_Registration::instance()->get_one_by_ID($REG_ID)
2527
+			);
2528
+			$this->_reg_custom_questions_form->_construct_finalize(null, null);
2529
+		}
2530
+		return $this->_reg_custom_questions_form;
2531
+	}
2532
+
2533
+
2534
+	/**
2535
+	 * Saves
2536
+	 *
2537
+	 * @access private
2538
+	 * @param bool $REG_ID
2539
+	 * @return bool
2540
+	 * @throws EE_Error
2541
+	 * @throws InvalidArgumentException
2542
+	 * @throws InvalidDataTypeException
2543
+	 * @throws InvalidInterfaceException
2544
+	 */
2545
+	private function _save_reg_custom_questions_form($REG_ID = false)
2546
+	{
2547
+		if (! $REG_ID) {
2548
+			EE_Error::add_error(
2549
+				esc_html__(
2550
+					'An error occurred. No registration ID was received.',
2551
+					'event_espresso'
2552
+				),
2553
+				__FILE__,
2554
+				__FUNCTION__,
2555
+				__LINE__
2556
+			);
2557
+		}
2558
+		$form = $this->_get_reg_custom_questions_form($REG_ID);
2559
+		$form->receive_form_submission($this->_req_data);
2560
+		$success = false;
2561
+		if ($form->is_valid()) {
2562
+			foreach ($form->subforms() as $question_group_id => $question_group_form) {
2563
+				foreach ($question_group_form->inputs() as $question_id => $input) {
2564
+					$where_conditions = array(
2565
+						'QST_ID' => $question_id,
2566
+						'REG_ID' => $REG_ID,
2567
+					);
2568
+					$possibly_new_values = array(
2569
+						'ANS_value' => $input->normalized_value(),
2570
+					);
2571
+					$answer = EEM_Answer::instance()->get_one(array($where_conditions));
2572
+					if ($answer instanceof EE_Answer) {
2573
+						$success = $answer->save($possibly_new_values);
2574
+					} else {
2575
+						// insert it then
2576
+						$cols_n_vals = array_merge($where_conditions, $possibly_new_values);
2577
+						$answer = EE_Answer::new_instance($cols_n_vals);
2578
+						$success = $answer->save();
2579
+					}
2580
+				}
2581
+			}
2582
+		} else {
2583
+			EE_Error::add_error($form->get_validation_error_string(), __FILE__, __FUNCTION__, __LINE__);
2584
+		}
2585
+		return $success;
2586
+	}
2587
+
2588
+
2589
+	/**
2590
+	 *        generates HTML for the Registration main meta box
2591
+	 *
2592
+	 * @access public
2593
+	 * @return void
2594
+	 * @throws DomainException
2595
+	 * @throws EE_Error
2596
+	 * @throws InvalidArgumentException
2597
+	 * @throws InvalidDataTypeException
2598
+	 * @throws InvalidInterfaceException
2599
+	 */
2600
+	public function _reg_attendees_meta_box()
2601
+	{
2602
+		$REG = EEM_Registration::instance();
2603
+		// get all other registrations on this transaction, and cache
2604
+		// the attendees for them so we don't have to run another query using force_join
2605
+		$registrations = $REG->get_all(
2606
+			array(
2607
+				array(
2608
+					'TXN_ID' => $this->_registration->transaction_ID(),
2609
+					'REG_ID' => array('!=', $this->_registration->ID()),
2610
+				),
2611
+				'force_join' => array('Attendee'),
2612
+			)
2613
+		);
2614
+		$this->_template_args['attendees'] = array();
2615
+		$this->_template_args['attendee_notice'] = '';
2616
+		if (empty($registrations)
2617
+			|| (is_array($registrations)
2618
+				&& ! EEH_Array::get_one_item_from_array($registrations))
2619
+		) {
2620
+			EE_Error::add_error(
2621
+				esc_html__(
2622
+					'There are no records attached to this registration. Something may have gone wrong with the registration',
2623
+					'event_espresso'
2624
+				),
2625
+				__FILE__,
2626
+				__FUNCTION__,
2627
+				__LINE__
2628
+			);
2629
+			$this->_template_args['attendee_notice'] = EE_Error::get_notices();
2630
+		} else {
2631
+			$att_nmbr = 1;
2632
+			foreach ($registrations as $registration) {
2633
+				/* @var $registration EE_Registration */
2634
+				$attendee = $registration->attendee()
2635
+					? $registration->attendee()
2636
+					: EEM_Attendee::instance()
2637
+								  ->create_default_object();
2638
+				$this->_template_args['attendees'][ $att_nmbr ]['STS_ID'] = $registration->status_ID();
2639
+				$this->_template_args['attendees'][ $att_nmbr ]['fname'] = $attendee->fname();
2640
+				$this->_template_args['attendees'][ $att_nmbr ]['lname'] = $attendee->lname();
2641
+				$this->_template_args['attendees'][ $att_nmbr ]['email'] = $attendee->email();
2642
+				$this->_template_args['attendees'][ $att_nmbr ]['final_price'] = $registration->final_price();
2643
+				$this->_template_args['attendees'][ $att_nmbr ]['address'] = implode(
2644
+					', ',
2645
+					$attendee->full_address_as_array()
2646
+				);
2647
+				$this->_template_args['attendees'][ $att_nmbr ]['att_link'] = self::add_query_args_and_nonce(
2648
+					array(
2649
+						'action' => 'edit_attendee',
2650
+						'post'   => $attendee->ID(),
2651
+					),
2652
+					REG_ADMIN_URL
2653
+				);
2654
+				$this->_template_args['attendees'][ $att_nmbr ]['event_name'] = $registration->event_obj()->name();
2655
+				$att_nmbr++;
2656
+			}
2657
+			$this->_template_args['currency_sign'] = EE_Registry::instance()->CFG->currency->sign;
2658
+		}
2659
+		$template_path = REG_TEMPLATE_PATH . 'reg_admin_details_main_meta_box_attendees.template.php';
2660
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);
2661
+	}
2662
+
2663
+
2664
+	/**
2665
+	 *        generates HTML for the Edit Registration side meta box
2666
+	 *
2667
+	 * @access public
2668
+	 * @return void
2669
+	 * @throws DomainException
2670
+	 * @throws EE_Error
2671
+	 * @throws InvalidArgumentException
2672
+	 * @throws InvalidDataTypeException
2673
+	 * @throws InvalidInterfaceException
2674
+	 */
2675
+	public function _reg_registrant_side_meta_box()
2676
+	{
2677
+		/*@var $attendee EE_Attendee */
2678
+		$att_check = $this->_registration->attendee();
2679
+		$attendee = $att_check instanceof EE_Attendee ? $att_check : EEM_Attendee::instance()->create_default_object();
2680
+		// now let's determine if this is not the primary registration.  If it isn't then we set the
2681
+		// primary_registration object for reference BUT ONLY if the Attendee object loaded is not the same as the
2682
+		// primary registration object (that way we know if we need to show create button or not)
2683
+		if (! $this->_registration->is_primary_registrant()) {
2684
+			$primary_registration = $this->_registration->get_primary_registration();
2685
+			$primary_attendee = $primary_registration instanceof EE_Registration ? $primary_registration->attendee()
2686
+				: null;
2687
+			if (! $primary_attendee instanceof EE_Attendee || $attendee->ID() !== $primary_attendee->ID()) {
2688
+				// in here?  This means the displayed registration is not the primary registrant but ALREADY HAS its own
2689
+				// custom attendee object so let's not worry about the primary reg.
2690
+				$primary_registration = null;
2691
+			}
2692
+		} else {
2693
+			$primary_registration = null;
2694
+		}
2695
+		$this->_template_args['ATT_ID'] = $attendee->ID();
2696
+		$this->_template_args['fname'] = $attendee->fname();
2697
+		$this->_template_args['lname'] = $attendee->lname();
2698
+		$this->_template_args['email'] = $attendee->email();
2699
+		$this->_template_args['phone'] = $attendee->phone();
2700
+		$this->_template_args['formatted_address'] = EEH_Address::format($attendee);
2701
+		// edit link
2702
+		$this->_template_args['att_edit_link'] = EE_Admin_Page::add_query_args_and_nonce(
2703
+			array(
2704
+				'action' => 'edit_attendee',
2705
+				'post'   => $attendee->ID(),
2706
+			),
2707
+			REG_ADMIN_URL
2708
+		);
2709
+		$this->_template_args['att_edit_label'] = esc_html__('View/Edit Contact', 'event_espresso');
2710
+		// create link
2711
+		$this->_template_args['create_link'] = $primary_registration instanceof EE_Registration
2712
+			? EE_Admin_Page::add_query_args_and_nonce(
2713
+				array(
2714
+					'action'  => 'duplicate_attendee',
2715
+					'_REG_ID' => $this->_registration->ID(),
2716
+				),
2717
+				REG_ADMIN_URL
2718
+			) : '';
2719
+		$this->_template_args['create_label'] = esc_html__('Create Contact', 'event_espresso');
2720
+		$this->_template_args['att_check'] = $att_check;
2721
+		$template_path = REG_TEMPLATE_PATH . 'reg_admin_details_side_meta_box_registrant.template.php';
2722
+		echo EEH_Template::display_template($template_path, $this->_template_args, true);
2723
+	}
2724
+
2725
+
2726
+	/**
2727
+	 * trash or restore registrations
2728
+	 *
2729
+	 * @param  boolean $trash whether to archive or restore
2730
+	 * @return void
2731
+	 * @throws DomainException
2732
+	 * @throws EE_Error
2733
+	 * @throws EntityNotFoundException
2734
+	 * @throws InvalidArgumentException
2735
+	 * @throws InvalidDataTypeException
2736
+	 * @throws InvalidInterfaceException
2737
+	 * @throws ReflectionException
2738
+	 * @throws RuntimeException
2739
+	 * @throws UnexpectedEntityException
2740
+	 * @access protected
2741
+	 */
2742
+	protected function _trash_or_restore_registrations($trash = true)
2743
+	{
2744
+		// if empty _REG_ID then get out because there's nothing to do
2745
+		if (empty($this->_req_data['_REG_ID'])) {
2746
+			EE_Error::add_error(
2747
+				sprintf(
2748
+					esc_html__(
2749
+						'In order to %1$s registrations you must select which ones you wish to %1$s by clicking the checkboxes.',
2750
+						'event_espresso'
2751
+					),
2752
+					$trash ? 'trash' : 'restore'
2753
+				),
2754
+				__FILE__,
2755
+				__LINE__,
2756
+				__FUNCTION__
2757
+			);
2758
+			$this->_redirect_after_action(false, '', '', array(), true);
2759
+		}
2760
+		$success = 0;
2761
+		$overwrite_msgs = false;
2762
+		// Checkboxes
2763
+		if (! is_array($this->_req_data['_REG_ID'])) {
2764
+			$this->_req_data['_REG_ID'] = array($this->_req_data['_REG_ID']);
2765
+		}
2766
+		$reg_count = count($this->_req_data['_REG_ID']);
2767
+		// cycle thru checkboxes
2768
+		foreach ($this->_req_data['_REG_ID'] as $REG_ID) {
2769
+			/** @var EE_Registration $REG */
2770
+			$REG = EEM_Registration::instance()->get_one_by_ID($REG_ID);
2771
+			$payments = $REG->registration_payments();
2772
+			if (! empty($payments)) {
2773
+				$name = $REG->attendee() instanceof EE_Attendee
2774
+					? $REG->attendee()->full_name()
2775
+					: esc_html__('Unknown Attendee', 'event_espresso');
2776
+				$overwrite_msgs = true;
2777
+				EE_Error::add_error(
2778
+					sprintf(
2779
+						esc_html__(
2780
+							'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.',
2781
+							'event_espresso'
2782
+						),
2783
+						$name
2784
+					),
2785
+					__FILE__,
2786
+					__FUNCTION__,
2787
+					__LINE__
2788
+				);
2789
+				// can't trash this registration because it has payments.
2790
+				continue;
2791
+			}
2792
+			$updated = $trash ? $REG->delete(__METHOD__) : $REG->restore(__METHOD__);
2793
+			if ($updated) {
2794
+				$success++;
2795
+			}
2796
+		}
2797
+		$this->_redirect_after_action(
2798
+			$success === $reg_count, // were ALL registrations affected?
2799
+			$success > 1
2800
+				? esc_html__('Registrations', 'event_espresso')
2801
+				: esc_html__('Registration', 'event_espresso'),
2802
+			$trash
2803
+				? esc_html__('moved to the trash', 'event_espresso')
2804
+				: esc_html__('restored', 'event_espresso'),
2805
+			array('action' => 'default'),
2806
+			$overwrite_msgs
2807
+		);
2808
+	}
2809
+
2810
+
2811
+	/**
2812
+	 * This is used to permanently delete registrations.  Note, this will handle not only deleting permanently the
2813
+	 * registration but also.
2814
+	 * 1. Removing relations to EE_Attendee
2815
+	 * 2. Deleting permanently the related transaction, but ONLY if all related registrations to the transaction are
2816
+	 * ALSO trashed.
2817
+	 * 3. Deleting permanently any related Line items but only if the above conditions are met.
2818
+	 * 4. Removing relationships between all tickets and the related registrations
2819
+	 * 5. Deleting permanently any related Answers (and the answers for other related registrations that were deleted.)
2820
+	 * 6. Deleting permanently any related Checkins.
2821
+	 *
2822
+	 * @return void
2823
+	 * @throws EE_Error
2824
+	 * @throws InvalidArgumentException
2825
+	 * @throws InvalidDataTypeException
2826
+	 * @throws InvalidInterfaceException
2827
+	 */
2828
+	protected function _delete_registrations()
2829
+	{
2830
+		$REG_MDL = EEM_Registration::instance();
2831
+		$success = 1;
2832
+		// Checkboxes
2833
+		if (! empty($this->_req_data['_REG_ID']) && is_array($this->_req_data['_REG_ID'])) {
2834
+			// if array has more than one element than success message should be plural
2835
+			$success = count($this->_req_data['_REG_ID']) > 1 ? 2 : 1;
2836
+			// cycle thru checkboxes
2837
+			while (list($ind, $REG_ID) = each($this->_req_data['_REG_ID'])) {
2838
+				$REG = $REG_MDL->get_one_by_ID($REG_ID);
2839
+				if (! $REG instanceof EE_Registration) {
2840
+					continue;
2841
+				}
2842
+				$deleted = $this->_delete_registration($REG);
2843
+				if (! $deleted) {
2844
+					$success = 0;
2845
+				}
2846
+			}
2847
+		} else {
2848
+			// grab single id and delete
2849
+			$REG_ID = $this->_req_data['_REG_ID'];
2850
+			$REG = $REG_MDL->get_one_by_ID($REG_ID);
2851
+			$deleted = $this->_delete_registration($REG);
2852
+			if (! $deleted) {
2853
+				$success = 0;
2854
+			}
2855
+		}
2856
+		$what = $success > 1
2857
+			? esc_html__('Registrations', 'event_espresso')
2858
+			: esc_html__('Registration', 'event_espresso');
2859
+		$action_desc = esc_html__('permanently deleted.', 'event_espresso');
2860
+		$this->_redirect_after_action(
2861
+			$success,
2862
+			$what,
2863
+			$action_desc,
2864
+			array('action' => 'default'),
2865
+			true
2866
+		);
2867
+	}
2868
+
2869
+
2870
+	/**
2871
+	 * handles the permanent deletion of a registration.  See comments with _delete_registrations() for details on what
2872
+	 * models get affected.
2873
+	 *
2874
+	 * @param  EE_Registration $REG registration to be deleted permenantly
2875
+	 * @return bool true = successful deletion, false = fail.
2876
+	 * @throws EE_Error
2877
+	 */
2878
+	protected function _delete_registration(EE_Registration $REG)
2879
+	{
2880
+		// first we start with the transaction... ultimately, we WILL not delete permanently if there are any related
2881
+		// registrations on the transaction that are NOT trashed.
2882
+		$TXN = $REG->get_first_related('Transaction');
2883
+		$REGS = $TXN->get_many_related('Registration');
2884
+		$all_trashed = true;
2885
+		foreach ($REGS as $registration) {
2886
+			if (! $registration->get('REG_deleted')) {
2887
+				$all_trashed = false;
2888
+			}
2889
+		}
2890
+		if (! $all_trashed) {
2891
+			EE_Error::add_error(
2892
+				esc_html__(
2893
+					'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.',
2894
+					'event_espresso'
2895
+				),
2896
+				__FILE__,
2897
+				__FUNCTION__,
2898
+				__LINE__
2899
+			);
2900
+			return false;
2901
+		}
2902
+		// k made it here so that means we can delete all the related transactions and their answers (but let's do them
2903
+		// separately from THIS one).
2904
+		foreach ($REGS as $registration) {
2905
+			// delete related answers
2906
+			$registration->delete_related_permanently('Answer');
2907
+			// remove relationship to EE_Attendee (but we ALWAYS leave the contact record intact)
2908
+			$attendee = $registration->get_first_related('Attendee');
2909
+			if ($attendee instanceof EE_Attendee) {
2910
+				$registration->_remove_relation_to($attendee, 'Attendee');
2911
+			}
2912
+			// now remove relationships to tickets on this registration.
2913
+			$registration->_remove_relations('Ticket');
2914
+			// now delete permanently the checkins related to this registration.
2915
+			$registration->delete_related_permanently('Checkin');
2916
+			if ($registration->ID() === $REG->ID()) {
2917
+				continue;
2918
+			} //we don't want to delete permanently the existing registration just yet.
2919
+			// remove relation to transaction for these registrations if NOT the existing registrations
2920
+			$registration->_remove_relations('Transaction');
2921
+			// delete permanently any related messages.
2922
+			$registration->delete_related_permanently('Message');
2923
+			// now delete this registration permanently
2924
+			$registration->delete_permanently();
2925
+		}
2926
+		// now all related registrations on the transaction are handled.  So let's just handle this registration itself
2927
+		// (the transaction and line items should be all that's left).
2928
+		// delete the line items related to the transaction for this registration.
2929
+		$TXN->delete_related_permanently('Line_Item');
2930
+		// we need to remove all the relationships on the transaction
2931
+		$TXN->delete_related_permanently('Payment');
2932
+		$TXN->delete_related_permanently('Extra_Meta');
2933
+		$TXN->delete_related_permanently('Message');
2934
+		// now we can delete this REG permanently (and the transaction of course)
2935
+		$REG->delete_related_permanently('Transaction');
2936
+		return $REG->delete_permanently();
2937
+	}
2938
+
2939
+
2940
+	/**
2941
+	 *    generates HTML for the Register New Attendee Admin page
2942
+	 *
2943
+	 * @access private
2944
+	 * @throws DomainException
2945
+	 * @throws EE_Error
2946
+	 */
2947
+	public function new_registration()
2948
+	{
2949
+		if (! $this->_set_reg_event()) {
2950
+			throw new EE_Error(
2951
+				esc_html__(
2952
+					'Unable to continue with registering because there is no Event ID in the request',
2953
+					'event_espresso'
2954
+				)
2955
+			);
2956
+		}
2957
+		EE_Registry::instance()->REQ->set_espresso_page(true);
2958
+		// gotta start with a clean slate if we're not coming here via ajax
2959
+		if (! defined('DOING_AJAX')
2960
+			&& (! isset($this->_req_data['processing_registration']) || isset($this->_req_data['step_error']))
2961
+		) {
2962
+			EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
2963
+		}
2964
+		$this->_template_args['event_name'] = '';
2965
+		// event name
2966
+		if ($this->_reg_event) {
2967
+			$this->_template_args['event_name'] = $this->_reg_event->name();
2968
+			$edit_event_url = self::add_query_args_and_nonce(
2969
+				array(
2970
+					'action' => 'edit',
2971
+					'post'   => $this->_reg_event->ID(),
2972
+				),
2973
+				EVENTS_ADMIN_URL
2974
+			);
2975
+			$edit_event_lnk = '<a href="'
2976
+							  . $edit_event_url
2977
+							  . '" title="'
2978
+							  . esc_attr__('Edit ', 'event_espresso')
2979
+							  . $this->_reg_event->name()
2980
+							  . '">'
2981
+							  . esc_html__('Edit Event', 'event_espresso')
2982
+							  . '</a>';
2983
+			$this->_template_args['event_name'] .= ' <span class="admin-page-header-edit-lnk not-bold">'
2984
+												   . $edit_event_lnk
2985
+												   . '</span>';
2986
+		}
2987
+		$this->_template_args['step_content'] = $this->_get_registration_step_content();
2988
+		if (defined('DOING_AJAX')) {
2989
+			$this->_return_json();
2990
+		}
2991
+		// grab header
2992
+		$template_path =
2993
+			REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee.template.php';
2994
+		$this->_template_args['admin_page_content'] = EEH_Template::display_template(
2995
+			$template_path,
2996
+			$this->_template_args,
2997
+			true
2998
+		);
2999
+		// $this->_set_publish_post_box_vars( NULL, FALSE, FALSE, NULL, FALSE );
3000
+		// the details template wrapper
3001
+		$this->display_admin_page_with_sidebar();
3002
+	}
3003
+
3004
+
3005
+	/**
3006
+	 * This returns the content for a registration step
3007
+	 *
3008
+	 * @access protected
3009
+	 * @return string html
3010
+	 * @throws DomainException
3011
+	 * @throws EE_Error
3012
+	 * @throws InvalidArgumentException
3013
+	 * @throws InvalidDataTypeException
3014
+	 * @throws InvalidInterfaceException
3015
+	 */
3016
+	protected function _get_registration_step_content()
3017
+	{
3018
+		if (isset($_COOKIE['ee_registration_added']) && $_COOKIE['ee_registration_added']) {
3019
+			$warning_msg = sprintf(
3020
+				esc_html__(
3021
+					'%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',
3022
+					'event_espresso'
3023
+				),
3024
+				'<br />',
3025
+				'<h3 class="important-notice">',
3026
+				'</h3>',
3027
+				'<div class="float-right">',
3028
+				'<span id="redirect_timer" class="important-notice">30</span>',
3029
+				'</div>',
3030
+				'<b>',
3031
+				'</b>'
3032
+			);
3033
+			return '
3034 3034
 	<div id="ee-add-reg-back-button-dv"><p>' . $warning_msg . '</p></div>
3035 3035
 	<script >
3036 3036
 		// WHOAH !!! it appears that someone is using the back button from the Transaction admin page
@@ -3043,855 +3043,855 @@  discard block
 block discarded – undo
3043 3043
 	        }
3044 3044
 	    }, 800 );
3045 3045
 	</script >';
3046
-        }
3047
-        $template_args = array(
3048
-            'title'                    => '',
3049
-            'content'                  => '',
3050
-            'step_button_text'         => '',
3051
-            'show_notification_toggle' => false,
3052
-        );
3053
-        // to indicate we're processing a new registration
3054
-        $hidden_fields = array(
3055
-            'processing_registration' => array(
3056
-                'type'  => 'hidden',
3057
-                'value' => 0,
3058
-            ),
3059
-            'event_id'                => array(
3060
-                'type'  => 'hidden',
3061
-                'value' => $this->_reg_event->ID(),
3062
-            ),
3063
-        );
3064
-        // if the cart is empty then we know we're at step one so we'll display ticket selector
3065
-        $cart = EE_Registry::instance()->SSN->cart();
3066
-        $step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
3067
-        switch ($step) {
3068
-            case 'ticket':
3069
-                $hidden_fields['processing_registration']['value'] = 1;
3070
-                $template_args['title'] = esc_html__(
3071
-                    'Step One: Select the Ticket for this registration',
3072
-                    'event_espresso'
3073
-                );
3074
-                $template_args['content'] =
3075
-                    EED_Ticket_Selector::instance()->display_ticket_selector($this->_reg_event);
3076
-                $template_args['step_button_text'] = esc_html__(
3077
-                    'Add Tickets and Continue to Registrant Details',
3078
-                    'event_espresso'
3079
-                );
3080
-                $template_args['show_notification_toggle'] = false;
3081
-                break;
3082
-            case 'questions':
3083
-                $hidden_fields['processing_registration']['value'] = 2;
3084
-                $template_args['title'] = esc_html__(
3085
-                    'Step Two: Add Registrant Details for this Registration',
3086
-                    'event_espresso'
3087
-                );
3088
-                // in theory we should be able to run EED_SPCO at this point because the cart should have been setup
3089
-                // properly by the first process_reg_step run.
3090
-                $template_args['content'] =
3091
-                    EED_Single_Page_Checkout::registration_checkout_for_admin();
3092
-                $template_args['step_button_text'] = esc_html__(
3093
-                    'Save Registration and Continue to Details',
3094
-                    'event_espresso'
3095
-                );
3096
-                $template_args['show_notification_toggle'] = true;
3097
-                break;
3098
-        }
3099
-        // we come back to the process_registration_step route.
3100
-        $this->_set_add_edit_form_tags('process_reg_step', $hidden_fields);
3101
-        return EEH_Template::display_template(
3102
-            REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee_step_content.template.php',
3103
-            $template_args,
3104
-            true
3105
-        );
3106
-    }
3107
-
3108
-
3109
-    /**
3110
-     *        set_reg_event
3111
-     *
3112
-     * @access private
3113
-     * @return bool
3114
-     * @throws EE_Error
3115
-     * @throws InvalidArgumentException
3116
-     * @throws InvalidDataTypeException
3117
-     * @throws InvalidInterfaceException
3118
-     */
3119
-    private function _set_reg_event()
3120
-    {
3121
-        if (is_object($this->_reg_event)) {
3122
-            return true;
3123
-        }
3124
-        $EVT_ID = (! empty($this->_req_data['event_id'])) ? absint($this->_req_data['event_id']) : false;
3125
-        if (! $EVT_ID) {
3126
-            return false;
3127
-        }
3128
-        $this->_reg_event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
3129
-        return true;
3130
-    }
3131
-
3132
-
3133
-    /**
3134
-     * process_reg_step
3135
-     *
3136
-     * @access        public
3137
-     * @return string
3138
-     * @throws DomainException
3139
-     * @throws EE_Error
3140
-     * @throws InvalidArgumentException
3141
-     * @throws InvalidDataTypeException
3142
-     * @throws InvalidInterfaceException
3143
-     * @throws ReflectionException
3144
-     * @throws RuntimeException
3145
-     */
3146
-    public function process_reg_step()
3147
-    {
3148
-        EE_System::do_not_cache();
3149
-        $this->_set_reg_event();
3150
-        EE_Registry::instance()->REQ->set_espresso_page(true);
3151
-        EE_Registry::instance()->REQ->set('uts', time());
3152
-        // what step are we on?
3153
-        $cart = EE_Registry::instance()->SSN->cart();
3154
-        $step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
3155
-        // if doing ajax then we need to verify the nonce
3156
-        if (defined('DOING_AJAX')) {
3157
-            $nonce = isset($this->_req_data[ $this->_req_nonce ])
3158
-                ? sanitize_text_field($this->_req_data[ $this->_req_nonce ]) : '';
3159
-            $this->_verify_nonce($nonce, $this->_req_nonce);
3160
-        }
3161
-        switch ($step) {
3162
-            case 'ticket':
3163
-                // process ticket selection
3164
-                $success = EED_Ticket_Selector::instance()->process_ticket_selections();
3165
-                if ($success) {
3166
-                    EE_Error::add_success(
3167
-                        esc_html__(
3168
-                            'Tickets Selected. Now complete the registration.',
3169
-                            'event_espresso'
3170
-                        )
3171
-                    );
3172
-                } else {
3173
-                    $query_args['step_error'] = $this->_req_data['step_error'] = true;
3174
-                }
3175
-                if (defined('DOING_AJAX')) {
3176
-                    $this->new_registration(); // display next step
3177
-                } else {
3178
-                    $query_args = array(
3179
-                        'action'                  => 'new_registration',
3180
-                        'processing_registration' => 1,
3181
-                        'event_id'                => $this->_reg_event->ID(),
3182
-                        'uts'                     => time(),
3183
-                    );
3184
-                    $this->_redirect_after_action(
3185
-                        false,
3186
-                        '',
3187
-                        '',
3188
-                        $query_args,
3189
-                        true
3190
-                    );
3191
-                }
3192
-                break;
3193
-            case 'questions':
3194
-                if (! isset(
3195
-                    $this->_req_data['txn_reg_status_change'],
3196
-                    $this->_req_data['txn_reg_status_change']['send_notifications']
3197
-                )
3198
-                ) {
3199
-                    add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_false', 15);
3200
-                }
3201
-                // process registration
3202
-                $transaction = EED_Single_Page_Checkout::instance()->process_registration_from_admin();
3203
-                if ($cart instanceof EE_Cart) {
3204
-                    $grand_total = $cart->get_cart_grand_total();
3205
-                    if ($grand_total instanceof EE_Line_Item) {
3206
-                        $grand_total->save_this_and_descendants_to_txn();
3207
-                    }
3208
-                }
3209
-                if (! $transaction instanceof EE_Transaction) {
3210
-                    $query_args = array(
3211
-                        'action'                  => 'new_registration',
3212
-                        'processing_registration' => 2,
3213
-                        'event_id'                => $this->_reg_event->ID(),
3214
-                        'uts'                     => time(),
3215
-                    );
3216
-                    if (defined('DOING_AJAX')) {
3217
-                        // display registration form again because there are errors (maybe validation?)
3218
-                        $this->new_registration();
3219
-                        return;
3220
-                    } else {
3221
-                        $this->_redirect_after_action(
3222
-                            false,
3223
-                            '',
3224
-                            '',
3225
-                            $query_args,
3226
-                            true
3227
-                        );
3228
-                        return;
3229
-                    }
3230
-                }
3231
-                // maybe update status, and make sure to save transaction if not done already
3232
-                if (! $transaction->update_status_based_on_total_paid()) {
3233
-                    $transaction->save();
3234
-                }
3235
-                EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3236
-                $this->_req_data = array();
3237
-                $query_args = array(
3238
-                    'action'        => 'redirect_to_txn',
3239
-                    'TXN_ID'        => $transaction->ID(),
3240
-                    'EVT_ID'        => $this->_reg_event->ID(),
3241
-                    'event_name'    => urlencode($this->_reg_event->name()),
3242
-                    'redirect_from' => 'new_registration',
3243
-                );
3244
-                $this->_redirect_after_action(false, '', '', $query_args, true);
3245
-                break;
3246
-        }
3247
-        // what are you looking here for?  Should be nothing to do at this point.
3248
-    }
3249
-
3250
-
3251
-    /**
3252
-     * redirect_to_txn
3253
-     *
3254
-     * @access public
3255
-     * @return void
3256
-     * @throws EE_Error
3257
-     * @throws InvalidArgumentException
3258
-     * @throws InvalidDataTypeException
3259
-     * @throws InvalidInterfaceException
3260
-     */
3261
-    public function redirect_to_txn()
3262
-    {
3263
-        EE_System::do_not_cache();
3264
-        EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3265
-        $query_args = array(
3266
-            'action' => 'view_transaction',
3267
-            'TXN_ID' => isset($this->_req_data['TXN_ID']) ? absint($this->_req_data['TXN_ID']) : 0,
3268
-            'page'   => 'espresso_transactions',
3269
-        );
3270
-        if (isset($this->_req_data['EVT_ID'], $this->_req_data['redirect_from'])) {
3271
-            $query_args['EVT_ID'] = $this->_req_data['EVT_ID'];
3272
-            $query_args['event_name'] = urlencode($this->_req_data['event_name']);
3273
-            $query_args['redirect_from'] = $this->_req_data['redirect_from'];
3274
-        }
3275
-        EE_Error::add_success(
3276
-            esc_html__(
3277
-                'Registration Created.  Please review the transaction and add any payments as necessary',
3278
-                'event_espresso'
3279
-            )
3280
-        );
3281
-        $this->_redirect_after_action(false, '', '', $query_args, true);
3282
-    }
3283
-
3284
-
3285
-    /**
3286
-     *        generates HTML for the Attendee Contact List
3287
-     *
3288
-     * @access protected
3289
-     * @return void
3290
-     */
3291
-    protected function _attendee_contact_list_table()
3292
-    {
3293
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3294
-        $this->_search_btn_label = esc_html__('Contacts', 'event_espresso');
3295
-        $this->display_admin_list_table_page_with_no_sidebar();
3296
-    }
3297
-
3298
-
3299
-    /**
3300
-     *        get_attendees
3301
-     *
3302
-     * @param      $per_page
3303
-     * @param bool $count whether to return count or data.
3304
-     * @param bool $trash
3305
-     * @return array
3306
-     * @throws EE_Error
3307
-     * @throws InvalidArgumentException
3308
-     * @throws InvalidDataTypeException
3309
-     * @throws InvalidInterfaceException
3310
-     * @access public
3311
-     */
3312
-    public function get_attendees($per_page, $count = false, $trash = false)
3313
-    {
3314
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3315
-        require_once(REG_ADMIN . 'EE_Attendee_Contact_List_Table.class.php');
3316
-        $ATT_MDL = EEM_Attendee::instance();
3317
-        $this->_req_data['orderby'] = ! empty($this->_req_data['orderby']) ? $this->_req_data['orderby'] : '';
3318
-        switch ($this->_req_data['orderby']) {
3319
-            case 'ATT_ID':
3320
-                $orderby = 'ATT_ID';
3321
-                break;
3322
-            case 'ATT_fname':
3323
-                $orderby = 'ATT_fname';
3324
-                break;
3325
-            case 'ATT_email':
3326
-                $orderby = 'ATT_email';
3327
-                break;
3328
-            case 'ATT_city':
3329
-                $orderby = 'ATT_city';
3330
-                break;
3331
-            case 'STA_ID':
3332
-                $orderby = 'STA_ID';
3333
-                break;
3334
-            case 'CNT_ID':
3335
-                $orderby = 'CNT_ID';
3336
-                break;
3337
-            case 'Registration_Count':
3338
-                $orderby = 'Registration_Count';
3339
-                break;
3340
-            default:
3341
-                $orderby = 'ATT_lname';
3342
-        }
3343
-        $sort = (isset($this->_req_data['order']) && ! empty($this->_req_data['order']))
3344
-            ? $this->_req_data['order']
3345
-            : 'ASC';
3346
-        $current_page = isset($this->_req_data['paged']) && ! empty($this->_req_data['paged'])
3347
-            ? $this->_req_data['paged']
3348
-            : 1;
3349
-        $per_page = isset($per_page) && ! empty($per_page) ? $per_page : 10;
3350
-        $per_page = isset($this->_req_data['perpage']) && ! empty($this->_req_data['perpage'])
3351
-            ? $this->_req_data['perpage']
3352
-            : $per_page;
3353
-        $_where = array();
3354
-        if (! empty($this->_req_data['s'])) {
3355
-            $sstr = '%' . $this->_req_data['s'] . '%';
3356
-            $_where['OR'] = array(
3357
-                'Registration.Event.EVT_name'       => array('LIKE', $sstr),
3358
-                'Registration.Event.EVT_desc'       => array('LIKE', $sstr),
3359
-                'Registration.Event.EVT_short_desc' => array('LIKE', $sstr),
3360
-                'ATT_fname'                         => array('LIKE', $sstr),
3361
-                'ATT_lname'                         => array('LIKE', $sstr),
3362
-                'ATT_short_bio'                     => array('LIKE', $sstr),
3363
-                'ATT_email'                         => array('LIKE', $sstr),
3364
-                'ATT_address'                       => array('LIKE', $sstr),
3365
-                'ATT_address2'                      => array('LIKE', $sstr),
3366
-                'ATT_city'                          => array('LIKE', $sstr),
3367
-                'Country.CNT_name'                  => array('LIKE', $sstr),
3368
-                'State.STA_name'                    => array('LIKE', $sstr),
3369
-                'ATT_phone'                         => array('LIKE', $sstr),
3370
-                'Registration.REG_final_price'      => array('LIKE', $sstr),
3371
-                'Registration.REG_code'             => array('LIKE', $sstr),
3372
-                'Registration.REG_group_size'       => array('LIKE', $sstr),
3373
-            );
3374
-        }
3375
-        $offset = ($current_page - 1) * $per_page;
3376
-        $limit = $count ? null : array($offset, $per_page);
3377
-        $query_args = array(
3378
-            $_where,
3379
-            'extra_selects' => array('Registration_Count' => array('Registration.REG_ID', 'count', '%d')),
3380
-            'limit'         => $limit,
3381
-        );
3382
-        if (! $count) {
3383
-            $query_args['order_by'] = array($orderby => $sort);
3384
-        }
3385
-        if ($trash) {
3386
-            $query_args[0]['status'] = array('!=', 'publish');
3387
-            $all_attendees = $count
3388
-                ? $ATT_MDL->count($query_args, 'ATT_ID', true)
3389
-                : $ATT_MDL->get_all($query_args);
3390
-        } else {
3391
-            $query_args[0]['status'] = array('IN', array('publish'));
3392
-            $all_attendees = $count
3393
-                ? $ATT_MDL->count($query_args, 'ATT_ID', true)
3394
-                : $ATT_MDL->get_all($query_args);
3395
-        }
3396
-        return $all_attendees;
3397
-    }
3398
-
3399
-
3400
-    /**
3401
-     * This is just taking care of resending the registration confirmation
3402
-     *
3403
-     * @access protected
3404
-     * @return void
3405
-     */
3406
-    protected function _resend_registration()
3407
-    {
3408
-        $this->_process_resend_registration();
3409
-        $query_args = isset($this->_req_data['redirect_to'])
3410
-            ? array('action' => $this->_req_data['redirect_to'], '_REG_ID' => $this->_req_data['_REG_ID'])
3411
-            : array('action' => 'default');
3412
-        $this->_redirect_after_action(false, '', '', $query_args, true);
3413
-    }
3414
-
3415
-    /**
3416
-     * Creates a registration report, but accepts the name of a method to use for preparing the query parameters
3417
-     * to use when selecting registrations
3418
-     *
3419
-     * @param string $method_name_for_getting_query_params the name of the method (on this class) to use for preparing
3420
-     *                                                     the query parameters from the request
3421
-     * @return void ends the request with a redirect or download
3422
-     */
3423
-    public function _registrations_report_base($method_name_for_getting_query_params)
3424
-    {
3425
-        if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3426
-            wp_redirect(
3427
-                EE_Admin_Page::add_query_args_and_nonce(
3428
-                    array(
3429
-                        'page'        => 'espresso_batch',
3430
-                        'batch'       => 'file',
3431
-                        'EVT_ID'      => isset($this->_req_data['EVT_ID']) ? $this->_req_data['EVT_ID'] : null,
3432
-                        'filters'     => urlencode(
3433
-                            serialize(
3434
-                                call_user_func(
3435
-                                    array($this, $method_name_for_getting_query_params),
3436
-                                    EEH_Array::is_set(
3437
-                                        $this->_req_data,
3438
-                                        'filters',
3439
-                                        array()
3440
-                                    )
3441
-                                )
3442
-                            )
3443
-                        ),
3444
-                        'use_filters' => EEH_Array::is_set($this->_req_data, 'use_filters', false),
3445
-                        'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\RegistrationsReport'),
3446
-                        'return_url'  => urlencode($this->_req_data['return_url']),
3447
-                    )
3448
-                )
3449
-            );
3450
-        } else {
3451
-            $new_request_args = array(
3452
-                'export' => 'report',
3453
-                'action' => 'registrations_report_for_event',
3454
-                'EVT_ID' => isset($this->_req_data['EVT_ID']) ? $this->_req_data['EVT_ID'] : null,
3455
-            );
3456
-            $this->_req_data = array_merge($this->_req_data, $new_request_args);
3457
-            if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3458
-                require_once(EE_CLASSES . 'EE_Export.class.php');
3459
-                $EE_Export = EE_Export::instance($this->_req_data);
3460
-                $EE_Export->export();
3461
-            }
3462
-        }
3463
-    }
3464
-
3465
-
3466
-    /**
3467
-     * Creates a registration report using only query parameters in the request
3468
-     *
3469
-     * @return void
3470
-     */
3471
-    public function _registrations_report()
3472
-    {
3473
-        $this->_registrations_report_base('_get_registration_query_parameters');
3474
-    }
3475
-
3476
-
3477
-    public function _contact_list_export()
3478
-    {
3479
-        if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3480
-            require_once(EE_CLASSES . 'EE_Export.class.php');
3481
-            $EE_Export = EE_Export::instance($this->_req_data);
3482
-            $EE_Export->export_attendees();
3483
-        }
3484
-    }
3485
-
3486
-
3487
-    public function _contact_list_report()
3488
-    {
3489
-        if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3490
-            wp_redirect(
3491
-                EE_Admin_Page::add_query_args_and_nonce(
3492
-                    array(
3493
-                        'page'        => 'espresso_batch',
3494
-                        'batch'       => 'file',
3495
-                        'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\AttendeesReport'),
3496
-                        'return_url'  => urlencode($this->_req_data['return_url']),
3497
-                    )
3498
-                )
3499
-            );
3500
-        } else {
3501
-            if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3502
-                require_once(EE_CLASSES . 'EE_Export.class.php');
3503
-                $EE_Export = EE_Export::instance($this->_req_data);
3504
-                $EE_Export->report_attendees();
3505
-            }
3506
-        }
3507
-    }
3508
-
3509
-
3510
-
3511
-
3512
-
3513
-    /***************************************        ATTENDEE DETAILS        ***************************************/
3514
-    /**
3515
-     * This duplicates the attendee object for the given incoming registration id and attendee_id.
3516
-     *
3517
-     * @return void
3518
-     * @throws EE_Error
3519
-     * @throws InvalidArgumentException
3520
-     * @throws InvalidDataTypeException
3521
-     * @throws InvalidInterfaceException
3522
-     */
3523
-    protected function _duplicate_attendee()
3524
-    {
3525
-        $action = ! empty($this->_req_data['return']) ? $this->_req_data['return'] : 'default';
3526
-        // verify we have necessary info
3527
-        if (empty($this->_req_data['_REG_ID'])) {
3528
-            EE_Error::add_error(
3529
-                esc_html__(
3530
-                    'Unable to create the contact for the registration because the required parameters are not present (_REG_ID )',
3531
-                    'event_espresso'
3532
-                ),
3533
-                __FILE__,
3534
-                __LINE__,
3535
-                __FUNCTION__
3536
-            );
3537
-            $query_args = array('action' => $action);
3538
-            $this->_redirect_after_action('', '', '', $query_args, true);
3539
-        }
3540
-        // okay necessary deets present... let's dupe the incoming attendee and attach to incoming registration.
3541
-        $registration = EEM_Registration::instance()->get_one_by_ID($this->_req_data['_REG_ID']);
3542
-        $attendee = $registration->attendee();
3543
-        // remove relation of existing attendee on registration
3544
-        $registration->_remove_relation_to($attendee, 'Attendee');
3545
-        // new attendee
3546
-        $new_attendee = clone $attendee;
3547
-        $new_attendee->set('ATT_ID', 0);
3548
-        $new_attendee->save();
3549
-        // add new attendee to reg
3550
-        $registration->_add_relation_to($new_attendee, 'Attendee');
3551
-        EE_Error::add_success(
3552
-            esc_html__(
3553
-                'New Contact record created.  Now make any edits you wish to make for this contact.',
3554
-                'event_espresso'
3555
-            )
3556
-        );
3557
-        // redirect to edit page for attendee
3558
-        $query_args = array('post' => $new_attendee->ID(), 'action' => 'edit_attendee');
3559
-        $this->_redirect_after_action('', '', '', $query_args, true);
3560
-    }
3561
-
3562
-
3563
-    /**
3564
-     * Callback invoked by parent EE_Admin_CPT class hooked in on `save_post` wp hook.
3565
-     *
3566
-     * @param int     $post_id
3567
-     * @param WP_POST $post
3568
-     * @throws DomainException
3569
-     * @throws EE_Error
3570
-     * @throws InvalidArgumentException
3571
-     * @throws InvalidDataTypeException
3572
-     * @throws InvalidInterfaceException
3573
-     * @throws LogicException
3574
-     * @throws InvalidFormSubmissionException
3575
-     */
3576
-    protected function _insert_update_cpt_item($post_id, $post)
3577
-    {
3578
-        $success = true;
3579
-        $attendee = $post instanceof WP_Post && $post->post_type === 'espresso_attendees'
3580
-            ? EEM_Attendee::instance()->get_one_by_ID($post_id)
3581
-            : null;
3582
-        // for attendee updates
3583
-        if ($attendee instanceof EE_Attendee) {
3584
-            // note we should only be UPDATING attendees at this point.
3585
-            $updated_fields = array(
3586
-                'ATT_fname'     => $this->_req_data['ATT_fname'],
3587
-                'ATT_lname'     => $this->_req_data['ATT_lname'],
3588
-                'ATT_full_name' => $this->_req_data['ATT_fname'] . ' ' . $this->_req_data['ATT_lname'],
3589
-                'ATT_address'   => isset($this->_req_data['ATT_address']) ? $this->_req_data['ATT_address'] : '',
3590
-                'ATT_address2'  => isset($this->_req_data['ATT_address2']) ? $this->_req_data['ATT_address2'] : '',
3591
-                'ATT_city'      => isset($this->_req_data['ATT_city']) ? $this->_req_data['ATT_city'] : '',
3592
-                'STA_ID'        => isset($this->_req_data['STA_ID']) ? $this->_req_data['STA_ID'] : '',
3593
-                'CNT_ISO'       => isset($this->_req_data['CNT_ISO']) ? $this->_req_data['CNT_ISO'] : '',
3594
-                'ATT_zip'       => isset($this->_req_data['ATT_zip']) ? $this->_req_data['ATT_zip'] : '',
3595
-            );
3596
-            foreach ($updated_fields as $field => $value) {
3597
-                $attendee->set($field, $value);
3598
-            }
3599
-
3600
-            // process contact details metabox form handler (which will also save the attendee)
3601
-            $contact_details_form = $this->getAttendeeContactDetailsMetaboxFormHandler($attendee);
3602
-            $success = $contact_details_form->process($this->_req_data);
3603
-
3604
-            $attendee_update_callbacks = apply_filters(
3605
-                'FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update',
3606
-                array()
3607
-            );
3608
-            foreach ($attendee_update_callbacks as $a_callback) {
3609
-                if (false === call_user_func_array($a_callback, array($attendee, $this->_req_data))) {
3610
-                    throw new EE_Error(
3611
-                        sprintf(
3612
-                            esc_html__(
3613
-                                '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.',
3614
-                                'event_espresso'
3615
-                            ),
3616
-                            $a_callback
3617
-                        )
3618
-                    );
3619
-                }
3620
-            }
3621
-        }
3622
-
3623
-        if ($success === false) {
3624
-            EE_Error::add_error(
3625
-                esc_html__(
3626
-                    'Something went wrong with updating the meta table data for the registration.',
3627
-                    'event_espresso'
3628
-                ),
3629
-                __FILE__,
3630
-                __FUNCTION__,
3631
-                __LINE__
3632
-            );
3633
-        }
3634
-    }
3635
-
3636
-
3637
-    public function trash_cpt_item($post_id)
3638
-    {
3639
-    }
3640
-
3641
-
3642
-    public function delete_cpt_item($post_id)
3643
-    {
3644
-    }
3645
-
3646
-
3647
-    public function restore_cpt_item($post_id)
3648
-    {
3649
-    }
3650
-
3651
-
3652
-    protected function _restore_cpt_item($post_id, $revision_id)
3653
-    {
3654
-    }
3655
-
3656
-
3657
-    public function attendee_editor_metaboxes()
3658
-    {
3659
-        $this->verify_cpt_object();
3660
-        remove_meta_box(
3661
-            'postexcerpt',
3662
-            esc_html__('Excerpt', 'event_espresso'),
3663
-            'post_excerpt_meta_box',
3664
-            $this->_cpt_routes[ $this->_req_action ],
3665
-            'normal',
3666
-            'core'
3667
-        );
3668
-        remove_meta_box('commentstatusdiv', $this->_cpt_routes[ $this->_req_action ], 'normal', 'core');
3669
-        if (post_type_supports('espresso_attendees', 'excerpt')) {
3670
-            add_meta_box(
3671
-                'postexcerpt',
3672
-                esc_html__('Short Biography', 'event_espresso'),
3673
-                'post_excerpt_meta_box',
3674
-                $this->_cpt_routes[ $this->_req_action ],
3675
-                'normal'
3676
-            );
3677
-        }
3678
-        if (post_type_supports('espresso_attendees', 'comments')) {
3679
-            add_meta_box(
3680
-                'commentsdiv',
3681
-                esc_html__('Notes on the Contact', 'event_espresso'),
3682
-                'post_comment_meta_box',
3683
-                $this->_cpt_routes[ $this->_req_action ],
3684
-                'normal',
3685
-                'core'
3686
-            );
3687
-        }
3688
-        add_meta_box(
3689
-            'attendee_contact_info',
3690
-            esc_html__('Contact Info', 'event_espresso'),
3691
-            array($this, 'attendee_contact_info'),
3692
-            $this->_cpt_routes[ $this->_req_action ],
3693
-            'side',
3694
-            'core'
3695
-        );
3696
-        add_meta_box(
3697
-            'attendee_details_address',
3698
-            esc_html__('Address Details', 'event_espresso'),
3699
-            array($this, 'attendee_address_details'),
3700
-            $this->_cpt_routes[ $this->_req_action ],
3701
-            'normal',
3702
-            'core'
3703
-        );
3704
-        add_meta_box(
3705
-            'attendee_registrations',
3706
-            esc_html__('Registrations for this Contact', 'event_espresso'),
3707
-            array($this, 'attendee_registrations_meta_box'),
3708
-            $this->_cpt_routes[ $this->_req_action ],
3709
-            'normal',
3710
-            'high'
3711
-        );
3712
-    }
3713
-
3714
-
3715
-    /**
3716
-     * Metabox for attendee contact info
3717
-     *
3718
-     * @param  WP_Post $post wp post object
3719
-     * @return string attendee contact info ( and form )
3720
-     * @throws EE_Error
3721
-     * @throws InvalidArgumentException
3722
-     * @throws InvalidDataTypeException
3723
-     * @throws InvalidInterfaceException
3724
-     * @throws LogicException
3725
-     * @throws DomainException
3726
-     */
3727
-    public function attendee_contact_info($post)
3728
-    {
3729
-        // get attendee object ( should already have it )
3730
-        $form = $this->getAttendeeContactDetailsMetaboxFormHandler($this->_cpt_model_obj);
3731
-        $form->enqueueStylesAndScripts();
3732
-        echo $form->display();
3733
-    }
3734
-
3735
-
3736
-    /**
3737
-     * Return form handler for the contact details metabox
3738
-     *
3739
-     * @param EE_Attendee $attendee
3740
-     * @return AttendeeContactDetailsMetaboxFormHandler
3741
-     * @throws DomainException
3742
-     * @throws InvalidArgumentException
3743
-     * @throws InvalidDataTypeException
3744
-     * @throws InvalidInterfaceException
3745
-     */
3746
-    protected function getAttendeeContactDetailsMetaboxFormHandler(EE_Attendee $attendee)
3747
-    {
3748
-        return new AttendeeContactDetailsMetaboxFormHandler($attendee, EE_Registry::instance());
3749
-    }
3750
-
3751
-
3752
-    /**
3753
-     * Metabox for attendee details
3754
-     *
3755
-     * @param  WP_Post $post wp post object
3756
-     * @throws DomainException
3757
-     */
3758
-    public function attendee_address_details($post)
3759
-    {
3760
-        // get attendee object (should already have it)
3761
-        $this->_template_args['attendee'] = $this->_cpt_model_obj;
3762
-        $this->_template_args['state_html'] = EEH_Form_Fields::generate_form_input(
3763
-            new EE_Question_Form_Input(
3764
-                EE_Question::new_instance(
3765
-                    array(
3766
-                        'QST_ID'           => 0,
3767
-                        'QST_display_text' => esc_html__('State/Province', 'event_espresso'),
3768
-                        'QST_system'       => 'admin-state',
3769
-                    )
3770
-                ),
3771
-                EE_Answer::new_instance(
3772
-                    array(
3773
-                        'ANS_ID'    => 0,
3774
-                        'ANS_value' => $this->_cpt_model_obj->state_ID(),
3775
-                    )
3776
-                ),
3777
-                array(
3778
-                    'input_id'       => 'STA_ID',
3779
-                    'input_name'     => 'STA_ID',
3780
-                    'input_prefix'   => '',
3781
-                    'append_qstn_id' => false,
3782
-                )
3783
-            )
3784
-        );
3785
-        $this->_template_args['country_html'] = EEH_Form_Fields::generate_form_input(
3786
-            new EE_Question_Form_Input(
3787
-                EE_Question::new_instance(
3788
-                    array(
3789
-                        'QST_ID'           => 0,
3790
-                        'QST_display_text' => esc_html__('Country', 'event_espresso'),
3791
-                        'QST_system'       => 'admin-country',
3792
-                    )
3793
-                ),
3794
-                EE_Answer::new_instance(
3795
-                    array(
3796
-                        'ANS_ID'    => 0,
3797
-                        'ANS_value' => $this->_cpt_model_obj->country_ID(),
3798
-                    )
3799
-                ),
3800
-                array(
3801
-                    'input_id'       => 'CNT_ISO',
3802
-                    'input_name'     => 'CNT_ISO',
3803
-                    'input_prefix'   => '',
3804
-                    'append_qstn_id' => false,
3805
-                )
3806
-            )
3807
-        );
3808
-        $template =
3809
-            REG_TEMPLATE_PATH . 'attendee_address_details_metabox_content.template.php';
3810
-        EEH_Template::display_template($template, $this->_template_args);
3811
-    }
3812
-
3813
-
3814
-    /**
3815
-     *        _attendee_details
3816
-     *
3817
-     * @access protected
3818
-     * @param $post
3819
-     * @return void
3820
-     * @throws DomainException
3821
-     * @throws EE_Error
3822
-     */
3823
-    public function attendee_registrations_meta_box($post)
3824
-    {
3825
-        $this->_template_args['attendee'] = $this->_cpt_model_obj;
3826
-        $this->_template_args['registrations'] = $this->_cpt_model_obj->get_many_related('Registration');
3827
-        $template =
3828
-            REG_TEMPLATE_PATH . 'attendee_registrations_main_meta_box.template.php';
3829
-        EEH_Template::display_template($template, $this->_template_args);
3830
-    }
3831
-
3832
-
3833
-    /**
3834
-     * add in the form fields for the attendee edit
3835
-     *
3836
-     * @param  WP_Post $post wp post object
3837
-     * @return string html for new form.
3838
-     * @throws DomainException
3839
-     */
3840
-    public function after_title_form_fields($post)
3841
-    {
3842
-        if ($post->post_type == 'espresso_attendees') {
3843
-            $template = REG_TEMPLATE_PATH . 'attendee_details_after_title_form_fields.template.php';
3844
-            $template_args['attendee'] = $this->_cpt_model_obj;
3845
-            EEH_Template::display_template($template, $template_args);
3846
-        }
3847
-    }
3848
-
3849
-
3850
-    /**
3851
-     *        _trash_or_restore_attendee
3852
-     *
3853
-     * @param boolean $trash - whether to move item to trash (TRUE) or restore it (FALSE)
3854
-     * @return void
3855
-     * @throws EE_Error
3856
-     * @throws InvalidArgumentException
3857
-     * @throws InvalidDataTypeException
3858
-     * @throws InvalidInterfaceException
3859
-     * @access protected
3860
-     */
3861
-    protected function _trash_or_restore_attendees($trash = true)
3862
-    {
3863
-        do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3864
-        $ATT_MDL = EEM_Attendee::instance();
3865
-        $success = 1;
3866
-        // Checkboxes
3867
-        if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
3868
-            // if array has more than one element than success message should be plural
3869
-            $success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
3870
-            // cycle thru checkboxes
3871
-            while (list($ATT_ID, $value) = each($this->_req_data['checkbox'])) {
3872
-                $updated = $trash ? $ATT_MDL->update_by_ID(array('status' => 'trash'), $ATT_ID)
3873
-                    : $ATT_MDL->update_by_ID(array('status' => 'publish'), $ATT_ID);
3874
-                if (! $updated) {
3875
-                    $success = 0;
3876
-                }
3877
-            }
3878
-        } else {
3879
-            // grab single id and delete
3880
-            $ATT_ID = absint($this->_req_data['ATT_ID']);
3881
-            // get attendee
3882
-            $att = $ATT_MDL->get_one_by_ID($ATT_ID);
3883
-            $updated = $trash ? $att->set_status('trash') : $att->set_status('publish');
3884
-            $updated = $att->save();
3885
-            if (! $updated) {
3886
-                $success = 0;
3887
-            }
3888
-        }
3889
-        $what = $success > 1
3890
-            ? esc_html__('Contacts', 'event_espresso')
3891
-            : esc_html__('Contact', 'event_espresso');
3892
-        $action_desc = $trash
3893
-            ? esc_html__('moved to the trash', 'event_espresso')
3894
-            : esc_html__('restored', 'event_espresso');
3895
-        $this->_redirect_after_action($success, $what, $action_desc, array('action' => 'contact_list'));
3896
-    }
3046
+		}
3047
+		$template_args = array(
3048
+			'title'                    => '',
3049
+			'content'                  => '',
3050
+			'step_button_text'         => '',
3051
+			'show_notification_toggle' => false,
3052
+		);
3053
+		// to indicate we're processing a new registration
3054
+		$hidden_fields = array(
3055
+			'processing_registration' => array(
3056
+				'type'  => 'hidden',
3057
+				'value' => 0,
3058
+			),
3059
+			'event_id'                => array(
3060
+				'type'  => 'hidden',
3061
+				'value' => $this->_reg_event->ID(),
3062
+			),
3063
+		);
3064
+		// if the cart is empty then we know we're at step one so we'll display ticket selector
3065
+		$cart = EE_Registry::instance()->SSN->cart();
3066
+		$step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
3067
+		switch ($step) {
3068
+			case 'ticket':
3069
+				$hidden_fields['processing_registration']['value'] = 1;
3070
+				$template_args['title'] = esc_html__(
3071
+					'Step One: Select the Ticket for this registration',
3072
+					'event_espresso'
3073
+				);
3074
+				$template_args['content'] =
3075
+					EED_Ticket_Selector::instance()->display_ticket_selector($this->_reg_event);
3076
+				$template_args['step_button_text'] = esc_html__(
3077
+					'Add Tickets and Continue to Registrant Details',
3078
+					'event_espresso'
3079
+				);
3080
+				$template_args['show_notification_toggle'] = false;
3081
+				break;
3082
+			case 'questions':
3083
+				$hidden_fields['processing_registration']['value'] = 2;
3084
+				$template_args['title'] = esc_html__(
3085
+					'Step Two: Add Registrant Details for this Registration',
3086
+					'event_espresso'
3087
+				);
3088
+				// in theory we should be able to run EED_SPCO at this point because the cart should have been setup
3089
+				// properly by the first process_reg_step run.
3090
+				$template_args['content'] =
3091
+					EED_Single_Page_Checkout::registration_checkout_for_admin();
3092
+				$template_args['step_button_text'] = esc_html__(
3093
+					'Save Registration and Continue to Details',
3094
+					'event_espresso'
3095
+				);
3096
+				$template_args['show_notification_toggle'] = true;
3097
+				break;
3098
+		}
3099
+		// we come back to the process_registration_step route.
3100
+		$this->_set_add_edit_form_tags('process_reg_step', $hidden_fields);
3101
+		return EEH_Template::display_template(
3102
+			REG_TEMPLATE_PATH . 'reg_admin_register_new_attendee_step_content.template.php',
3103
+			$template_args,
3104
+			true
3105
+		);
3106
+	}
3107
+
3108
+
3109
+	/**
3110
+	 *        set_reg_event
3111
+	 *
3112
+	 * @access private
3113
+	 * @return bool
3114
+	 * @throws EE_Error
3115
+	 * @throws InvalidArgumentException
3116
+	 * @throws InvalidDataTypeException
3117
+	 * @throws InvalidInterfaceException
3118
+	 */
3119
+	private function _set_reg_event()
3120
+	{
3121
+		if (is_object($this->_reg_event)) {
3122
+			return true;
3123
+		}
3124
+		$EVT_ID = (! empty($this->_req_data['event_id'])) ? absint($this->_req_data['event_id']) : false;
3125
+		if (! $EVT_ID) {
3126
+			return false;
3127
+		}
3128
+		$this->_reg_event = EEM_Event::instance()->get_one_by_ID($EVT_ID);
3129
+		return true;
3130
+	}
3131
+
3132
+
3133
+	/**
3134
+	 * process_reg_step
3135
+	 *
3136
+	 * @access        public
3137
+	 * @return string
3138
+	 * @throws DomainException
3139
+	 * @throws EE_Error
3140
+	 * @throws InvalidArgumentException
3141
+	 * @throws InvalidDataTypeException
3142
+	 * @throws InvalidInterfaceException
3143
+	 * @throws ReflectionException
3144
+	 * @throws RuntimeException
3145
+	 */
3146
+	public function process_reg_step()
3147
+	{
3148
+		EE_System::do_not_cache();
3149
+		$this->_set_reg_event();
3150
+		EE_Registry::instance()->REQ->set_espresso_page(true);
3151
+		EE_Registry::instance()->REQ->set('uts', time());
3152
+		// what step are we on?
3153
+		$cart = EE_Registry::instance()->SSN->cart();
3154
+		$step = ! $cart instanceof EE_Cart ? 'ticket' : 'questions';
3155
+		// if doing ajax then we need to verify the nonce
3156
+		if (defined('DOING_AJAX')) {
3157
+			$nonce = isset($this->_req_data[ $this->_req_nonce ])
3158
+				? sanitize_text_field($this->_req_data[ $this->_req_nonce ]) : '';
3159
+			$this->_verify_nonce($nonce, $this->_req_nonce);
3160
+		}
3161
+		switch ($step) {
3162
+			case 'ticket':
3163
+				// process ticket selection
3164
+				$success = EED_Ticket_Selector::instance()->process_ticket_selections();
3165
+				if ($success) {
3166
+					EE_Error::add_success(
3167
+						esc_html__(
3168
+							'Tickets Selected. Now complete the registration.',
3169
+							'event_espresso'
3170
+						)
3171
+					);
3172
+				} else {
3173
+					$query_args['step_error'] = $this->_req_data['step_error'] = true;
3174
+				}
3175
+				if (defined('DOING_AJAX')) {
3176
+					$this->new_registration(); // display next step
3177
+				} else {
3178
+					$query_args = array(
3179
+						'action'                  => 'new_registration',
3180
+						'processing_registration' => 1,
3181
+						'event_id'                => $this->_reg_event->ID(),
3182
+						'uts'                     => time(),
3183
+					);
3184
+					$this->_redirect_after_action(
3185
+						false,
3186
+						'',
3187
+						'',
3188
+						$query_args,
3189
+						true
3190
+					);
3191
+				}
3192
+				break;
3193
+			case 'questions':
3194
+				if (! isset(
3195
+					$this->_req_data['txn_reg_status_change'],
3196
+					$this->_req_data['txn_reg_status_change']['send_notifications']
3197
+				)
3198
+				) {
3199
+					add_filter('FHEE__EED_Messages___maybe_registration__deliver_notifications', '__return_false', 15);
3200
+				}
3201
+				// process registration
3202
+				$transaction = EED_Single_Page_Checkout::instance()->process_registration_from_admin();
3203
+				if ($cart instanceof EE_Cart) {
3204
+					$grand_total = $cart->get_cart_grand_total();
3205
+					if ($grand_total instanceof EE_Line_Item) {
3206
+						$grand_total->save_this_and_descendants_to_txn();
3207
+					}
3208
+				}
3209
+				if (! $transaction instanceof EE_Transaction) {
3210
+					$query_args = array(
3211
+						'action'                  => 'new_registration',
3212
+						'processing_registration' => 2,
3213
+						'event_id'                => $this->_reg_event->ID(),
3214
+						'uts'                     => time(),
3215
+					);
3216
+					if (defined('DOING_AJAX')) {
3217
+						// display registration form again because there are errors (maybe validation?)
3218
+						$this->new_registration();
3219
+						return;
3220
+					} else {
3221
+						$this->_redirect_after_action(
3222
+							false,
3223
+							'',
3224
+							'',
3225
+							$query_args,
3226
+							true
3227
+						);
3228
+						return;
3229
+					}
3230
+				}
3231
+				// maybe update status, and make sure to save transaction if not done already
3232
+				if (! $transaction->update_status_based_on_total_paid()) {
3233
+					$transaction->save();
3234
+				}
3235
+				EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3236
+				$this->_req_data = array();
3237
+				$query_args = array(
3238
+					'action'        => 'redirect_to_txn',
3239
+					'TXN_ID'        => $transaction->ID(),
3240
+					'EVT_ID'        => $this->_reg_event->ID(),
3241
+					'event_name'    => urlencode($this->_reg_event->name()),
3242
+					'redirect_from' => 'new_registration',
3243
+				);
3244
+				$this->_redirect_after_action(false, '', '', $query_args, true);
3245
+				break;
3246
+		}
3247
+		// what are you looking here for?  Should be nothing to do at this point.
3248
+	}
3249
+
3250
+
3251
+	/**
3252
+	 * redirect_to_txn
3253
+	 *
3254
+	 * @access public
3255
+	 * @return void
3256
+	 * @throws EE_Error
3257
+	 * @throws InvalidArgumentException
3258
+	 * @throws InvalidDataTypeException
3259
+	 * @throws InvalidInterfaceException
3260
+	 */
3261
+	public function redirect_to_txn()
3262
+	{
3263
+		EE_System::do_not_cache();
3264
+		EE_Registry::instance()->SSN->clear_session(__CLASS__, __FUNCTION__);
3265
+		$query_args = array(
3266
+			'action' => 'view_transaction',
3267
+			'TXN_ID' => isset($this->_req_data['TXN_ID']) ? absint($this->_req_data['TXN_ID']) : 0,
3268
+			'page'   => 'espresso_transactions',
3269
+		);
3270
+		if (isset($this->_req_data['EVT_ID'], $this->_req_data['redirect_from'])) {
3271
+			$query_args['EVT_ID'] = $this->_req_data['EVT_ID'];
3272
+			$query_args['event_name'] = urlencode($this->_req_data['event_name']);
3273
+			$query_args['redirect_from'] = $this->_req_data['redirect_from'];
3274
+		}
3275
+		EE_Error::add_success(
3276
+			esc_html__(
3277
+				'Registration Created.  Please review the transaction and add any payments as necessary',
3278
+				'event_espresso'
3279
+			)
3280
+		);
3281
+		$this->_redirect_after_action(false, '', '', $query_args, true);
3282
+	}
3283
+
3284
+
3285
+	/**
3286
+	 *        generates HTML for the Attendee Contact List
3287
+	 *
3288
+	 * @access protected
3289
+	 * @return void
3290
+	 */
3291
+	protected function _attendee_contact_list_table()
3292
+	{
3293
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3294
+		$this->_search_btn_label = esc_html__('Contacts', 'event_espresso');
3295
+		$this->display_admin_list_table_page_with_no_sidebar();
3296
+	}
3297
+
3298
+
3299
+	/**
3300
+	 *        get_attendees
3301
+	 *
3302
+	 * @param      $per_page
3303
+	 * @param bool $count whether to return count or data.
3304
+	 * @param bool $trash
3305
+	 * @return array
3306
+	 * @throws EE_Error
3307
+	 * @throws InvalidArgumentException
3308
+	 * @throws InvalidDataTypeException
3309
+	 * @throws InvalidInterfaceException
3310
+	 * @access public
3311
+	 */
3312
+	public function get_attendees($per_page, $count = false, $trash = false)
3313
+	{
3314
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3315
+		require_once(REG_ADMIN . 'EE_Attendee_Contact_List_Table.class.php');
3316
+		$ATT_MDL = EEM_Attendee::instance();
3317
+		$this->_req_data['orderby'] = ! empty($this->_req_data['orderby']) ? $this->_req_data['orderby'] : '';
3318
+		switch ($this->_req_data['orderby']) {
3319
+			case 'ATT_ID':
3320
+				$orderby = 'ATT_ID';
3321
+				break;
3322
+			case 'ATT_fname':
3323
+				$orderby = 'ATT_fname';
3324
+				break;
3325
+			case 'ATT_email':
3326
+				$orderby = 'ATT_email';
3327
+				break;
3328
+			case 'ATT_city':
3329
+				$orderby = 'ATT_city';
3330
+				break;
3331
+			case 'STA_ID':
3332
+				$orderby = 'STA_ID';
3333
+				break;
3334
+			case 'CNT_ID':
3335
+				$orderby = 'CNT_ID';
3336
+				break;
3337
+			case 'Registration_Count':
3338
+				$orderby = 'Registration_Count';
3339
+				break;
3340
+			default:
3341
+				$orderby = 'ATT_lname';
3342
+		}
3343
+		$sort = (isset($this->_req_data['order']) && ! empty($this->_req_data['order']))
3344
+			? $this->_req_data['order']
3345
+			: 'ASC';
3346
+		$current_page = isset($this->_req_data['paged']) && ! empty($this->_req_data['paged'])
3347
+			? $this->_req_data['paged']
3348
+			: 1;
3349
+		$per_page = isset($per_page) && ! empty($per_page) ? $per_page : 10;
3350
+		$per_page = isset($this->_req_data['perpage']) && ! empty($this->_req_data['perpage'])
3351
+			? $this->_req_data['perpage']
3352
+			: $per_page;
3353
+		$_where = array();
3354
+		if (! empty($this->_req_data['s'])) {
3355
+			$sstr = '%' . $this->_req_data['s'] . '%';
3356
+			$_where['OR'] = array(
3357
+				'Registration.Event.EVT_name'       => array('LIKE', $sstr),
3358
+				'Registration.Event.EVT_desc'       => array('LIKE', $sstr),
3359
+				'Registration.Event.EVT_short_desc' => array('LIKE', $sstr),
3360
+				'ATT_fname'                         => array('LIKE', $sstr),
3361
+				'ATT_lname'                         => array('LIKE', $sstr),
3362
+				'ATT_short_bio'                     => array('LIKE', $sstr),
3363
+				'ATT_email'                         => array('LIKE', $sstr),
3364
+				'ATT_address'                       => array('LIKE', $sstr),
3365
+				'ATT_address2'                      => array('LIKE', $sstr),
3366
+				'ATT_city'                          => array('LIKE', $sstr),
3367
+				'Country.CNT_name'                  => array('LIKE', $sstr),
3368
+				'State.STA_name'                    => array('LIKE', $sstr),
3369
+				'ATT_phone'                         => array('LIKE', $sstr),
3370
+				'Registration.REG_final_price'      => array('LIKE', $sstr),
3371
+				'Registration.REG_code'             => array('LIKE', $sstr),
3372
+				'Registration.REG_group_size'       => array('LIKE', $sstr),
3373
+			);
3374
+		}
3375
+		$offset = ($current_page - 1) * $per_page;
3376
+		$limit = $count ? null : array($offset, $per_page);
3377
+		$query_args = array(
3378
+			$_where,
3379
+			'extra_selects' => array('Registration_Count' => array('Registration.REG_ID', 'count', '%d')),
3380
+			'limit'         => $limit,
3381
+		);
3382
+		if (! $count) {
3383
+			$query_args['order_by'] = array($orderby => $sort);
3384
+		}
3385
+		if ($trash) {
3386
+			$query_args[0]['status'] = array('!=', 'publish');
3387
+			$all_attendees = $count
3388
+				? $ATT_MDL->count($query_args, 'ATT_ID', true)
3389
+				: $ATT_MDL->get_all($query_args);
3390
+		} else {
3391
+			$query_args[0]['status'] = array('IN', array('publish'));
3392
+			$all_attendees = $count
3393
+				? $ATT_MDL->count($query_args, 'ATT_ID', true)
3394
+				: $ATT_MDL->get_all($query_args);
3395
+		}
3396
+		return $all_attendees;
3397
+	}
3398
+
3399
+
3400
+	/**
3401
+	 * This is just taking care of resending the registration confirmation
3402
+	 *
3403
+	 * @access protected
3404
+	 * @return void
3405
+	 */
3406
+	protected function _resend_registration()
3407
+	{
3408
+		$this->_process_resend_registration();
3409
+		$query_args = isset($this->_req_data['redirect_to'])
3410
+			? array('action' => $this->_req_data['redirect_to'], '_REG_ID' => $this->_req_data['_REG_ID'])
3411
+			: array('action' => 'default');
3412
+		$this->_redirect_after_action(false, '', '', $query_args, true);
3413
+	}
3414
+
3415
+	/**
3416
+	 * Creates a registration report, but accepts the name of a method to use for preparing the query parameters
3417
+	 * to use when selecting registrations
3418
+	 *
3419
+	 * @param string $method_name_for_getting_query_params the name of the method (on this class) to use for preparing
3420
+	 *                                                     the query parameters from the request
3421
+	 * @return void ends the request with a redirect or download
3422
+	 */
3423
+	public function _registrations_report_base($method_name_for_getting_query_params)
3424
+	{
3425
+		if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3426
+			wp_redirect(
3427
+				EE_Admin_Page::add_query_args_and_nonce(
3428
+					array(
3429
+						'page'        => 'espresso_batch',
3430
+						'batch'       => 'file',
3431
+						'EVT_ID'      => isset($this->_req_data['EVT_ID']) ? $this->_req_data['EVT_ID'] : null,
3432
+						'filters'     => urlencode(
3433
+							serialize(
3434
+								call_user_func(
3435
+									array($this, $method_name_for_getting_query_params),
3436
+									EEH_Array::is_set(
3437
+										$this->_req_data,
3438
+										'filters',
3439
+										array()
3440
+									)
3441
+								)
3442
+							)
3443
+						),
3444
+						'use_filters' => EEH_Array::is_set($this->_req_data, 'use_filters', false),
3445
+						'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\RegistrationsReport'),
3446
+						'return_url'  => urlencode($this->_req_data['return_url']),
3447
+					)
3448
+				)
3449
+			);
3450
+		} else {
3451
+			$new_request_args = array(
3452
+				'export' => 'report',
3453
+				'action' => 'registrations_report_for_event',
3454
+				'EVT_ID' => isset($this->_req_data['EVT_ID']) ? $this->_req_data['EVT_ID'] : null,
3455
+			);
3456
+			$this->_req_data = array_merge($this->_req_data, $new_request_args);
3457
+			if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3458
+				require_once(EE_CLASSES . 'EE_Export.class.php');
3459
+				$EE_Export = EE_Export::instance($this->_req_data);
3460
+				$EE_Export->export();
3461
+			}
3462
+		}
3463
+	}
3464
+
3465
+
3466
+	/**
3467
+	 * Creates a registration report using only query parameters in the request
3468
+	 *
3469
+	 * @return void
3470
+	 */
3471
+	public function _registrations_report()
3472
+	{
3473
+		$this->_registrations_report_base('_get_registration_query_parameters');
3474
+	}
3475
+
3476
+
3477
+	public function _contact_list_export()
3478
+	{
3479
+		if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3480
+			require_once(EE_CLASSES . 'EE_Export.class.php');
3481
+			$EE_Export = EE_Export::instance($this->_req_data);
3482
+			$EE_Export->export_attendees();
3483
+		}
3484
+	}
3485
+
3486
+
3487
+	public function _contact_list_report()
3488
+	{
3489
+		if (! defined('EE_USE_OLD_CSV_REPORT_CLASS')) {
3490
+			wp_redirect(
3491
+				EE_Admin_Page::add_query_args_and_nonce(
3492
+					array(
3493
+						'page'        => 'espresso_batch',
3494
+						'batch'       => 'file',
3495
+						'job_handler' => urlencode('EventEspressoBatchRequest\JobHandlers\AttendeesReport'),
3496
+						'return_url'  => urlencode($this->_req_data['return_url']),
3497
+					)
3498
+				)
3499
+			);
3500
+		} else {
3501
+			if (is_readable(EE_CLASSES . 'EE_Export.class.php')) {
3502
+				require_once(EE_CLASSES . 'EE_Export.class.php');
3503
+				$EE_Export = EE_Export::instance($this->_req_data);
3504
+				$EE_Export->report_attendees();
3505
+			}
3506
+		}
3507
+	}
3508
+
3509
+
3510
+
3511
+
3512
+
3513
+	/***************************************        ATTENDEE DETAILS        ***************************************/
3514
+	/**
3515
+	 * This duplicates the attendee object for the given incoming registration id and attendee_id.
3516
+	 *
3517
+	 * @return void
3518
+	 * @throws EE_Error
3519
+	 * @throws InvalidArgumentException
3520
+	 * @throws InvalidDataTypeException
3521
+	 * @throws InvalidInterfaceException
3522
+	 */
3523
+	protected function _duplicate_attendee()
3524
+	{
3525
+		$action = ! empty($this->_req_data['return']) ? $this->_req_data['return'] : 'default';
3526
+		// verify we have necessary info
3527
+		if (empty($this->_req_data['_REG_ID'])) {
3528
+			EE_Error::add_error(
3529
+				esc_html__(
3530
+					'Unable to create the contact for the registration because the required parameters are not present (_REG_ID )',
3531
+					'event_espresso'
3532
+				),
3533
+				__FILE__,
3534
+				__LINE__,
3535
+				__FUNCTION__
3536
+			);
3537
+			$query_args = array('action' => $action);
3538
+			$this->_redirect_after_action('', '', '', $query_args, true);
3539
+		}
3540
+		// okay necessary deets present... let's dupe the incoming attendee and attach to incoming registration.
3541
+		$registration = EEM_Registration::instance()->get_one_by_ID($this->_req_data['_REG_ID']);
3542
+		$attendee = $registration->attendee();
3543
+		// remove relation of existing attendee on registration
3544
+		$registration->_remove_relation_to($attendee, 'Attendee');
3545
+		// new attendee
3546
+		$new_attendee = clone $attendee;
3547
+		$new_attendee->set('ATT_ID', 0);
3548
+		$new_attendee->save();
3549
+		// add new attendee to reg
3550
+		$registration->_add_relation_to($new_attendee, 'Attendee');
3551
+		EE_Error::add_success(
3552
+			esc_html__(
3553
+				'New Contact record created.  Now make any edits you wish to make for this contact.',
3554
+				'event_espresso'
3555
+			)
3556
+		);
3557
+		// redirect to edit page for attendee
3558
+		$query_args = array('post' => $new_attendee->ID(), 'action' => 'edit_attendee');
3559
+		$this->_redirect_after_action('', '', '', $query_args, true);
3560
+	}
3561
+
3562
+
3563
+	/**
3564
+	 * Callback invoked by parent EE_Admin_CPT class hooked in on `save_post` wp hook.
3565
+	 *
3566
+	 * @param int     $post_id
3567
+	 * @param WP_POST $post
3568
+	 * @throws DomainException
3569
+	 * @throws EE_Error
3570
+	 * @throws InvalidArgumentException
3571
+	 * @throws InvalidDataTypeException
3572
+	 * @throws InvalidInterfaceException
3573
+	 * @throws LogicException
3574
+	 * @throws InvalidFormSubmissionException
3575
+	 */
3576
+	protected function _insert_update_cpt_item($post_id, $post)
3577
+	{
3578
+		$success = true;
3579
+		$attendee = $post instanceof WP_Post && $post->post_type === 'espresso_attendees'
3580
+			? EEM_Attendee::instance()->get_one_by_ID($post_id)
3581
+			: null;
3582
+		// for attendee updates
3583
+		if ($attendee instanceof EE_Attendee) {
3584
+			// note we should only be UPDATING attendees at this point.
3585
+			$updated_fields = array(
3586
+				'ATT_fname'     => $this->_req_data['ATT_fname'],
3587
+				'ATT_lname'     => $this->_req_data['ATT_lname'],
3588
+				'ATT_full_name' => $this->_req_data['ATT_fname'] . ' ' . $this->_req_data['ATT_lname'],
3589
+				'ATT_address'   => isset($this->_req_data['ATT_address']) ? $this->_req_data['ATT_address'] : '',
3590
+				'ATT_address2'  => isset($this->_req_data['ATT_address2']) ? $this->_req_data['ATT_address2'] : '',
3591
+				'ATT_city'      => isset($this->_req_data['ATT_city']) ? $this->_req_data['ATT_city'] : '',
3592
+				'STA_ID'        => isset($this->_req_data['STA_ID']) ? $this->_req_data['STA_ID'] : '',
3593
+				'CNT_ISO'       => isset($this->_req_data['CNT_ISO']) ? $this->_req_data['CNT_ISO'] : '',
3594
+				'ATT_zip'       => isset($this->_req_data['ATT_zip']) ? $this->_req_data['ATT_zip'] : '',
3595
+			);
3596
+			foreach ($updated_fields as $field => $value) {
3597
+				$attendee->set($field, $value);
3598
+			}
3599
+
3600
+			// process contact details metabox form handler (which will also save the attendee)
3601
+			$contact_details_form = $this->getAttendeeContactDetailsMetaboxFormHandler($attendee);
3602
+			$success = $contact_details_form->process($this->_req_data);
3603
+
3604
+			$attendee_update_callbacks = apply_filters(
3605
+				'FHEE__Registrations_Admin_Page__insert_update_cpt_item__attendee_update',
3606
+				array()
3607
+			);
3608
+			foreach ($attendee_update_callbacks as $a_callback) {
3609
+				if (false === call_user_func_array($a_callback, array($attendee, $this->_req_data))) {
3610
+					throw new EE_Error(
3611
+						sprintf(
3612
+							esc_html__(
3613
+								'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.',
3614
+								'event_espresso'
3615
+							),
3616
+							$a_callback
3617
+						)
3618
+					);
3619
+				}
3620
+			}
3621
+		}
3622
+
3623
+		if ($success === false) {
3624
+			EE_Error::add_error(
3625
+				esc_html__(
3626
+					'Something went wrong with updating the meta table data for the registration.',
3627
+					'event_espresso'
3628
+				),
3629
+				__FILE__,
3630
+				__FUNCTION__,
3631
+				__LINE__
3632
+			);
3633
+		}
3634
+	}
3635
+
3636
+
3637
+	public function trash_cpt_item($post_id)
3638
+	{
3639
+	}
3640
+
3641
+
3642
+	public function delete_cpt_item($post_id)
3643
+	{
3644
+	}
3645
+
3646
+
3647
+	public function restore_cpt_item($post_id)
3648
+	{
3649
+	}
3650
+
3651
+
3652
+	protected function _restore_cpt_item($post_id, $revision_id)
3653
+	{
3654
+	}
3655
+
3656
+
3657
+	public function attendee_editor_metaboxes()
3658
+	{
3659
+		$this->verify_cpt_object();
3660
+		remove_meta_box(
3661
+			'postexcerpt',
3662
+			esc_html__('Excerpt', 'event_espresso'),
3663
+			'post_excerpt_meta_box',
3664
+			$this->_cpt_routes[ $this->_req_action ],
3665
+			'normal',
3666
+			'core'
3667
+		);
3668
+		remove_meta_box('commentstatusdiv', $this->_cpt_routes[ $this->_req_action ], 'normal', 'core');
3669
+		if (post_type_supports('espresso_attendees', 'excerpt')) {
3670
+			add_meta_box(
3671
+				'postexcerpt',
3672
+				esc_html__('Short Biography', 'event_espresso'),
3673
+				'post_excerpt_meta_box',
3674
+				$this->_cpt_routes[ $this->_req_action ],
3675
+				'normal'
3676
+			);
3677
+		}
3678
+		if (post_type_supports('espresso_attendees', 'comments')) {
3679
+			add_meta_box(
3680
+				'commentsdiv',
3681
+				esc_html__('Notes on the Contact', 'event_espresso'),
3682
+				'post_comment_meta_box',
3683
+				$this->_cpt_routes[ $this->_req_action ],
3684
+				'normal',
3685
+				'core'
3686
+			);
3687
+		}
3688
+		add_meta_box(
3689
+			'attendee_contact_info',
3690
+			esc_html__('Contact Info', 'event_espresso'),
3691
+			array($this, 'attendee_contact_info'),
3692
+			$this->_cpt_routes[ $this->_req_action ],
3693
+			'side',
3694
+			'core'
3695
+		);
3696
+		add_meta_box(
3697
+			'attendee_details_address',
3698
+			esc_html__('Address Details', 'event_espresso'),
3699
+			array($this, 'attendee_address_details'),
3700
+			$this->_cpt_routes[ $this->_req_action ],
3701
+			'normal',
3702
+			'core'
3703
+		);
3704
+		add_meta_box(
3705
+			'attendee_registrations',
3706
+			esc_html__('Registrations for this Contact', 'event_espresso'),
3707
+			array($this, 'attendee_registrations_meta_box'),
3708
+			$this->_cpt_routes[ $this->_req_action ],
3709
+			'normal',
3710
+			'high'
3711
+		);
3712
+	}
3713
+
3714
+
3715
+	/**
3716
+	 * Metabox for attendee contact info
3717
+	 *
3718
+	 * @param  WP_Post $post wp post object
3719
+	 * @return string attendee contact info ( and form )
3720
+	 * @throws EE_Error
3721
+	 * @throws InvalidArgumentException
3722
+	 * @throws InvalidDataTypeException
3723
+	 * @throws InvalidInterfaceException
3724
+	 * @throws LogicException
3725
+	 * @throws DomainException
3726
+	 */
3727
+	public function attendee_contact_info($post)
3728
+	{
3729
+		// get attendee object ( should already have it )
3730
+		$form = $this->getAttendeeContactDetailsMetaboxFormHandler($this->_cpt_model_obj);
3731
+		$form->enqueueStylesAndScripts();
3732
+		echo $form->display();
3733
+	}
3734
+
3735
+
3736
+	/**
3737
+	 * Return form handler for the contact details metabox
3738
+	 *
3739
+	 * @param EE_Attendee $attendee
3740
+	 * @return AttendeeContactDetailsMetaboxFormHandler
3741
+	 * @throws DomainException
3742
+	 * @throws InvalidArgumentException
3743
+	 * @throws InvalidDataTypeException
3744
+	 * @throws InvalidInterfaceException
3745
+	 */
3746
+	protected function getAttendeeContactDetailsMetaboxFormHandler(EE_Attendee $attendee)
3747
+	{
3748
+		return new AttendeeContactDetailsMetaboxFormHandler($attendee, EE_Registry::instance());
3749
+	}
3750
+
3751
+
3752
+	/**
3753
+	 * Metabox for attendee details
3754
+	 *
3755
+	 * @param  WP_Post $post wp post object
3756
+	 * @throws DomainException
3757
+	 */
3758
+	public function attendee_address_details($post)
3759
+	{
3760
+		// get attendee object (should already have it)
3761
+		$this->_template_args['attendee'] = $this->_cpt_model_obj;
3762
+		$this->_template_args['state_html'] = EEH_Form_Fields::generate_form_input(
3763
+			new EE_Question_Form_Input(
3764
+				EE_Question::new_instance(
3765
+					array(
3766
+						'QST_ID'           => 0,
3767
+						'QST_display_text' => esc_html__('State/Province', 'event_espresso'),
3768
+						'QST_system'       => 'admin-state',
3769
+					)
3770
+				),
3771
+				EE_Answer::new_instance(
3772
+					array(
3773
+						'ANS_ID'    => 0,
3774
+						'ANS_value' => $this->_cpt_model_obj->state_ID(),
3775
+					)
3776
+				),
3777
+				array(
3778
+					'input_id'       => 'STA_ID',
3779
+					'input_name'     => 'STA_ID',
3780
+					'input_prefix'   => '',
3781
+					'append_qstn_id' => false,
3782
+				)
3783
+			)
3784
+		);
3785
+		$this->_template_args['country_html'] = EEH_Form_Fields::generate_form_input(
3786
+			new EE_Question_Form_Input(
3787
+				EE_Question::new_instance(
3788
+					array(
3789
+						'QST_ID'           => 0,
3790
+						'QST_display_text' => esc_html__('Country', 'event_espresso'),
3791
+						'QST_system'       => 'admin-country',
3792
+					)
3793
+				),
3794
+				EE_Answer::new_instance(
3795
+					array(
3796
+						'ANS_ID'    => 0,
3797
+						'ANS_value' => $this->_cpt_model_obj->country_ID(),
3798
+					)
3799
+				),
3800
+				array(
3801
+					'input_id'       => 'CNT_ISO',
3802
+					'input_name'     => 'CNT_ISO',
3803
+					'input_prefix'   => '',
3804
+					'append_qstn_id' => false,
3805
+				)
3806
+			)
3807
+		);
3808
+		$template =
3809
+			REG_TEMPLATE_PATH . 'attendee_address_details_metabox_content.template.php';
3810
+		EEH_Template::display_template($template, $this->_template_args);
3811
+	}
3812
+
3813
+
3814
+	/**
3815
+	 *        _attendee_details
3816
+	 *
3817
+	 * @access protected
3818
+	 * @param $post
3819
+	 * @return void
3820
+	 * @throws DomainException
3821
+	 * @throws EE_Error
3822
+	 */
3823
+	public function attendee_registrations_meta_box($post)
3824
+	{
3825
+		$this->_template_args['attendee'] = $this->_cpt_model_obj;
3826
+		$this->_template_args['registrations'] = $this->_cpt_model_obj->get_many_related('Registration');
3827
+		$template =
3828
+			REG_TEMPLATE_PATH . 'attendee_registrations_main_meta_box.template.php';
3829
+		EEH_Template::display_template($template, $this->_template_args);
3830
+	}
3831
+
3832
+
3833
+	/**
3834
+	 * add in the form fields for the attendee edit
3835
+	 *
3836
+	 * @param  WP_Post $post wp post object
3837
+	 * @return string html for new form.
3838
+	 * @throws DomainException
3839
+	 */
3840
+	public function after_title_form_fields($post)
3841
+	{
3842
+		if ($post->post_type == 'espresso_attendees') {
3843
+			$template = REG_TEMPLATE_PATH . 'attendee_details_after_title_form_fields.template.php';
3844
+			$template_args['attendee'] = $this->_cpt_model_obj;
3845
+			EEH_Template::display_template($template, $template_args);
3846
+		}
3847
+	}
3848
+
3849
+
3850
+	/**
3851
+	 *        _trash_or_restore_attendee
3852
+	 *
3853
+	 * @param boolean $trash - whether to move item to trash (TRUE) or restore it (FALSE)
3854
+	 * @return void
3855
+	 * @throws EE_Error
3856
+	 * @throws InvalidArgumentException
3857
+	 * @throws InvalidDataTypeException
3858
+	 * @throws InvalidInterfaceException
3859
+	 * @access protected
3860
+	 */
3861
+	protected function _trash_or_restore_attendees($trash = true)
3862
+	{
3863
+		do_action('AHEE_log', __FILE__, __FUNCTION__, '');
3864
+		$ATT_MDL = EEM_Attendee::instance();
3865
+		$success = 1;
3866
+		// Checkboxes
3867
+		if (! empty($this->_req_data['checkbox']) && is_array($this->_req_data['checkbox'])) {
3868
+			// if array has more than one element than success message should be plural
3869
+			$success = count($this->_req_data['checkbox']) > 1 ? 2 : 1;
3870
+			// cycle thru checkboxes
3871
+			while (list($ATT_ID, $value) = each($this->_req_data['checkbox'])) {
3872
+				$updated = $trash ? $ATT_MDL->update_by_ID(array('status' => 'trash'), $ATT_ID)
3873
+					: $ATT_MDL->update_by_ID(array('status' => 'publish'), $ATT_ID);
3874
+				if (! $updated) {
3875
+					$success = 0;
3876
+				}
3877
+			}
3878
+		} else {
3879
+			// grab single id and delete
3880
+			$ATT_ID = absint($this->_req_data['ATT_ID']);
3881
+			// get attendee
3882
+			$att = $ATT_MDL->get_one_by_ID($ATT_ID);
3883
+			$updated = $trash ? $att->set_status('trash') : $att->set_status('publish');
3884
+			$updated = $att->save();
3885
+			if (! $updated) {
3886
+				$success = 0;
3887
+			}
3888
+		}
3889
+		$what = $success > 1
3890
+			? esc_html__('Contacts', 'event_espresso')
3891
+			: esc_html__('Contact', 'event_espresso');
3892
+		$action_desc = $trash
3893
+			? esc_html__('moved to the trash', 'event_espresso')
3894
+			: esc_html__('restored', 'event_espresso');
3895
+		$this->_redirect_after_action($success, $what, $action_desc, array('action' => 'contact_list'));
3896
+	}
3897 3897
 }
Please login to merge, or discard this patch.